本文介绍了在这种情况下,我什么时候需要调用 CoInitialize()?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在 Delphi XE2 中构建多线程 Windows 服务应用程序,它使用 ADO 数据库组件连接到 SQL Server.我在内部线程之前多次使用 CoInitialize(nil);,但在这种情况下,我有一个我不确定的函数.

I'm building a multi-threaded windows service application in Delphi XE2 which uses ADO database components to connect to SQL Server. I've used CoInitialize(nil); plenty times before inside threads, but in this case, I have a function which I'm unsure about.

这个函数被称为TryConnect,它尝试使用给定的连接字符串连接到数据库.它在连接成功时返回 true 或 false.问题是这个函数会在主服务线程内部和外部使用,它会创建自己的临时TADOConnection组件,这需要CoInitialize...

This function is called TryConnect which attempts to connect to a database with a given connection string. It returns true or false on the connection success. The problem is that this function will be used both inside and outside the main service thread, and it will be creating its own temporary TADOConnection component, which requires CoInitialize...

我的问题是我还需要在这个函数中调用 CoInitialize 吗?如果我这样做了,而且由于服务的执行过程也使用 CoInitialize,如果我从服务内部调用这个函数,它们会干扰吗?TryConnect 函数位于从主服务线程创建的对象内部(但最终将移动到其自己的线程).我需要知道从同一个线程(和 CoUninitialize)调用两次 CoInitialize() 是否会干扰 - 以及如何正确处理这种情况.

My question is do I need to call CoInitialize inside this function also? If I do, and since the service's execute procedure uses CoInitialize also, will they interfere if I call this function from within the service? The TryConnect function is inside of an object which is created from the main service thread (but will eventually be moved to its own thread). I need to know if calling CoInitialize() twice from the same thread (and CoUninitialize) will interfere - and how to handle this scenario properly.

这是下面的代码...

//This is the service app's execute procedure
procedure TJDRMSvr.ServiceExecute(Sender: TService);
begin
  try
    CoInitialize(nil);
    Startup;
    try
      while not Terminated do begin
        DoSomeWork;
        ServiceThread.ProcessRequests(False);
      end;
    finally
      Cleanup;
      CoUninitialize;
    end;
  except
    on e: exception do begin
      PostLog('EXCEPTION in Execute: '+e.Message);
    end;
  end;
end;

//TryConnect might be called from same service thread and another thread
function TDBPool.TryConnect(const AConnStr: String): Bool;
var
  DB: TADOConnection; //Do I need CoInitialize in this function?
begin
  Result:= False;
  DB:= TADOConnection.Create(nil);
  try
    DB.LoginPrompt:= False;
    DB.ConnectionString:= AConnStr;
    try
      DB.Connected:= True;
      Result:= True;
    except
      on e: exception do begin
      end;
    end;
    DB.Connected:= False;
  finally
    DB.Free;
  end;
end;

所以为了澄清它真正在做什么,我可能会遇到这样的情况:

So to clarify what it's really doing, I might have an occasion of this:

CoInitialize(nil);
try
  CoInitialize(nil);
  try
    //Do some ADO work
  finally
    CoUninitialize;
  end;
finally
  CoUninitialize;
end;

推荐答案

CoInitialize 必须在每个使用 COM 的线程中调用,无论它是什么线程,或者它是否有父级线程或子线程.如果线程使用 COM,它必须调用 CoInitialize.

CoInitialize has to be called in every single thread that uses COM, regardless of what thread it is, or whether it has a parent thread or child threads. If the thread uses COM, it must call CoInitialize.

这里的正确答案是视情况而定".由于您知道服务线程调用了 CoInitialize,如果从服务线程调用 TryConnect,则不需要再次调用它.如果可以调用它的其他线程也调用了CoInitialize,则不需要调用它,因为该函数将在调用线程下运行.

The correct answer here is "it depends". Since you know the service thread has called CoInitialize, if TryConnect is called from the service thread it won't need to be called again. If the other threads that could call it have also called CoInitialize, it won't need to be called, as the function will run under the calling thread.

MSDN 文档专门解决了这个问题(强调):

The MSDN documentation specifically addresses this question (emphasis added):

通常,COM 库仅在线程上初始化一次.在同一线程上对 CoInitialize 或 CoInitializeEx 的后续调用将成功,只要它们不尝试更改并发模型,但将返回 S_FALSE.为了优雅地关闭 COM 库,对 CoInitialize 或 CoInitializeEx 的每次成功调用,包括那些返回 S_FALSE 的调用,都必须通过对 CoUninitialize 的相应调用来平衡.CoInitializeEx 和 COINIT_APARTMENTTHREADED) 必须是调用 CoUninitialize 的最后一个线程.否则,后续在 STA 上调用 CoInitialize 将失败,应用程序将无法运行.

所以答案是:如果您不确定,请调用 CoInitialize.在 try..finally 块中执行此操作,并在 finally 中调用 CoUnitialize,或在构造函数中初始化并在析构函数中取消初始化.

So the answer is: If you're not sure, call CoInitialize. Do it in a try..finally block, and call CoUnitialize in the finally, or initialize in a constructor and uninitialize in the destructor.

这篇关于在这种情况下,我什么时候需要调用 CoInitialize()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

05-26 16:34