问题描述
我正在 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()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!