Hi all,
Some shell namespace extensions only work if COM is initialized (For instance the brand-new shell instance objects ;) Go download the free (as in beer) Shell Object Editor from www.tropictech.de if you want to try them.). On WinXP those work without the application calling CoInitialize in SHBrowseForFolder and in the file dialogs. I assume this means there is a CoInitialize/CoUninitialize pair guarding SHBrowseForFolder.
For the attached browse.c test program (meant to be compiled with borland's free compiler - sorry) on can browse into shell instance objects on winxp, but the call to GetDisplayNameOf fails with CO_E_NOTINITIALIZED. This means COM is initialized inside SHBrowseForFolder, but un-initialized after the call returns. If you remove the '//' in front of the CoInitialize call and compile again, GetDisplayNameOf succeeds.
On wine, you can't currently browse into shell instance objects, if COM is not initialized. If you add CoInitialize/CoUninitialize to SHBrowseForFolder (see attached patch), it exhibits the same behaviour as winxp.
How expensive is COM un-/initialization? Any objections against adding CoInitialize/CoUnitialize to SHBrowseForFolder and the file dialogs?
Bye,
Michael Jung wrote:
Hi all,
Some shell namespace extensions only work if COM is initialized (For instance the brand-new shell instance objects ;) Go download the free (as in beer) Shell Object Editor from www.tropictech.de if you want to try them.). On WinXP those work without the application calling CoInitialize in SHBrowseForFolder and in the file dialogs. I assume this means there is a CoInitialize/CoUninitialize pair guarding SHBrowseForFolder.
For the attached browse.c test program (meant to be compiled with borland's free compiler - sorry) on can browse into shell instance objects on winxp, but the call to GetDisplayNameOf fails with CO_E_NOTINITIALIZED. This means COM is initialized inside SHBrowseForFolder, but un-initialized after the call returns. If you remove the '//' in front of the CoInitialize call and compile again, GetDisplayNameOf succeeds.
On wine, you can't currently browse into shell instance objects, if COM is not initialized. If you add CoInitialize/CoUninitialize to SHBrowseForFolder (see attached patch), it exhibits the same behaviour as winxp.
How expensive is COM un-/initialization?
It depends on the threading model you specify. Apartment threading is more expensive than multi-threaded because it involves the creation of a window, but both are fairly cheap (although I haven't got any numbers to back this up). It is even cheaper if the thread has already initialized COM.
Any objections against adding CoInitialize/CoUnitialize to SHBrowseForFolder and the file dialogs?
The only objection is that in general it is bad to force a threading model and that the caller should be the one specifying it. However, if this is what native shell32 does then we should also do it.
Hi Rob,
On Tuesday 08 November 2005 19:59, Robert Shearman wrote:
The only objection is that in general it is bad to force a threading model and that the caller should be the one specifying it.
I guess that's not a problem.
If COM isn't initialized prior to the call to SHBrowseForFolder it will also be uninitialized after the call. The caller can then call CoInitializeEx afterwards (I'm assuming here that it's ok to do CoInitializeEx(COINIT_APARTMENTTHREADED, NULL); CoUnintialize(); CoInitializeEx(COINIT_MULTITHREADED, NULL); Is that correct?).
If COM is already initialized with the same threading model as specified in SHBrowseForFolder's CoInitializeEx, it will succeed with S_FALSE.
If COM is already initialized with a different threading model, CoInitializeEx will fail. But then, it's already initialized anyway and everything is fine. And we won't call CoUninitialize before returning from SHBrowseForFolder in this case.
Did I understand this stuff correctly?
Thanks for your reply.
Michael Jung wrote:
Hi Rob,
On Tuesday 08 November 2005 19:59, Robert Shearman wrote:
The only objection is that in general it is bad to force a threading model and that the caller should be the one specifying it.
I guess that's not a problem.
If COM isn't initialized prior to the call to SHBrowseForFolder it will also be uninitialized after the call. The caller can then call CoInitializeEx afterwards (I'm assuming here that it's ok to do CoInitializeEx(COINIT_APARTMENTTHREADED, NULL); CoUnintialize(); CoInitializeEx(COINIT_MULTITHREADED, NULL); Is that correct?).
If COM is already initialized with the same threading model as specified in SHBrowseForFolder's CoInitializeEx, it will succeed with S_FALSE.
If COM is already initialized with a different threading model, CoInitializeEx will fail. But then, it's already initialized anyway and everything is fine. And we won't call CoUninitialize before returning from SHBrowseForFolder in this case.
Did I understand this stuff correctly?
Yes. That is all correct.
Thanks for your reply.
I ran into similar problems in shell32/shellole.c, function SHCoCreateInstance. Shouldn't when both bLoadFromShell32 and bLoadWithoutCOM are false call CoInitialize before CoCreateInstance (I got once a program needing it) ? A+
Hi Eric,
On Friday 11 November 2005 09:37, Eric Pouech wrote:
I ran into similar problems in shell32/shellole.c, function SHCoCreateInstance. Shouldn't when both bLoadFromShell32 and bLoadWithoutCOM are false call CoInitialize before CoCreateInstance (I got once a program needing it) ?
It's not obvious to me where we would call CoUninitialize in this case. As I understand it, we have to keep COM initialized until the created object is destroyed again. The short test program, which I've sent with the initial mail, seems to indicate that while COM is initialized inside SHBrowseForFolder, it's un-initialized again afterwards.
Bye,
Michael Jung wrote:
Hi Eric,
On Friday 11 November 2005 09:37, Eric Pouech wrote:
I ran into similar problems in shell32/shellole.c, function SHCoCreateInstance. Shouldn't when both bLoadFromShell32 and bLoadWithoutCOM are false call CoInitialize before CoCreateInstance (I got once a program needing it) ?
It's not obvious to me where we would call CoUninitialize in this case. As I understand it, we have to keep COM initialized until the created object is destroyed again. The short test program, which I've sent with the initial mail, seems to indicate that while COM is initialized inside SHBrowseForFolder, it's un-initialized again afterwards.
Bye,
I was more referring to the missing call to CoInitialize... I don't think it's reasonable here to call CoUninitialize here ;-)
A+
Eric Pouech wrote:
Michael Jung wrote:
Hi Eric,
On Friday 11 November 2005 09:37, Eric Pouech wrote:
I ran into similar problems in shell32/shellole.c, function SHCoCreateInstance. Shouldn't when both bLoadFromShell32 and bLoadWithoutCOM are false call CoInitialize before CoCreateInstance (I got once a program needing it) ?
It's not obvious to me where we would call CoUninitialize in this case. As I understand it, we have to keep COM initialized until the created object is destroyed again. The short test program, which I've sent with the initial mail, seems to indicate that while COM is initialized inside SHBrowseForFolder, it's un-initialized again afterwards.
Bye,
I was more referring to the missing call to CoInitialize... I don't think it's reasonable here to call CoUninitialize here ;-)
The point is that it is reasonable to call CoInitialize if you need it to use some objects and don't expose those objects to the caller, as long as you call CoUninitialize afterwards. However, it is bad to call CoInitialize without calling CoUninitialize because the caller may now want to call CoInitialize with a different threading model and this will fail, potentially causing errors if it tries to use objects from a different apartment. Not calling CoUninitialize is also bad because it can cause deadlocks on thread destruction in some cases if there are still objects lying around. One further thing to note is that you can't call CoUninitialize in SHCoCreateInstance because if the returned object is a proxy then it will be automatically disconnected and hence become unusable.