ShellExecuteEx and Coinitialize in VCL thread
Asked Answered
J

3

5

Do I need to call Coinitialize in the main/VCL thread in Delphi before using ShellExecuteEx?

For a thread, yes but for the VCL thread ?

Jalousie answered 14/11, 2013 at 17:53 Comment(0)
M
5

No need to call CoInitialize for Windows Forms Applications. This is done for you in the main thread. More specific TApplication.Create in Forms.Pas:

...
if not IsLibrary then
 FNeedToUninitialize := Succeeded(OleInitialize(nil));
...
Mackoff answered 14/11, 2013 at 18:7 Comment(5)
Isn't the initialization done in an InitProc during Application.Initialize?Phylloid
@DavidHeffernan: This is the only COM related initialization I could find in the source startup code(Delphi XE here).Mackoff
I bet you'll find a call to CoInitializeEx in an initial proc.Phylloid
@DavidHeffernan: I did a Grep on the source code, if you found something else, feel free to add it. Anyway OleInitialize calls CoInitializeEx internally.Mackoff
I've added some more details in an answer of my own. I just want to do that for extra information. I take nothing away from your answer. The initialization that you highlight is the one that counts. +1Phylloid
L
3

If in doubt, do it. In either case, CoInitialize() will return a hr : HRESULT which you should check, because you need to CoUninitialize() on SUCCEEDED(hr), but not when FAILED(hr). A failed result usually indicates that it already has been called.

Cited from your MSDN ref:

Nonetheless, it is good practice to always initalize COM before using this function.

Lazarolazaruk answered 14/11, 2013 at 18:7 Comment(6)
The question specifically asks to remove the doubt.Phylloid
... which can be done easily by checking the HRESULT.Lazarolazaruk
Which would be the wrong way to do it. Trial and error is never better than easily discoverable and demonstrable facts.Phylloid
@JensG, MSDN writes: "To close the COM library gracefully on a thread, each successful call to CoInitialize or CoInitializeEx, including any call that returns S_FALSE, must be balanced by a corresponding call to CoUninitialize", so that CoUninitialize must be called for both S_OK and S_FALSE results of CoInitialize[Ex]Cilo
@ALZ: Exactly, that's why we have macros/functions like SUCCEEDED()and FAILED() which you should use. And S_FALSE is an success code, thus SUCCEEDED(S_FALSE) evaluates to true.Lazarolazaruk
@JensG, Thanks! I didn't know that "SUCCEEDED(S_FALSE) evaluates to true." Live a century - learn a century! :)Cilo
P
3

In the RTL/VCL source, COM is initialized in the following ways:

  1. By a call to OleInitialize made from Forms.TApplication.Create. So this call will be made for all VCL forms applications, but not, for example, for service applications.
  2. By a call to CoInitialize or CoInitializeEx in ComObj.InitComObj. This is registered as an InitProc in the initialization section of the ComObj unit. In turn, the call to Application.Initialize in your project .dpr file's code will invoke ComObj.InitComObj.
  3. In many and various other locations around the RTL/VCL. Including, but not limited to, Datasnap, ComServ, Soap, System.Win.Sensors, Winapi.DirectShow9. Some of these areas of code are more recent than Delphi 7.

Now, of these various COM initializations, the ones that count are 1 and 2. In any standard VCL forms application, both of these will run at startup in the main thread. Item 1 runs first and so gets to initialize COM first. That's the initialization that counts. Item 2 runs after and returns S_FALSE meaning that COM was already initialized.

So, to your question:

Do I need to call Coinitialize in the main/VCL thread?

No you do not. You can be sure that COM has already been initialized in a VCL application's main thread.

Phylloid answered 16/11, 2013 at 13:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.