View Full Version : Unbalanced CoInitialize ?
Chris K
21st April 2009, 10:07
Hi,
My application uses a simple player based on MCI commands. This works fine and can play most any video clip and also Avisynth scripts. Video clips go fine all the way but when the MCI player closes a Avisynth script, my application looses the ability to drop files on. It looks like Avisynth exits unbalanced.
I can reactivate drop for my app with a CoInitialize(0) or OleInitialize(0) call but then probably introduce a new unbalance. I checked the Avisynth source on it and it seems ok but I can't follow the whole chain from open to exit.
I assume Avisynth runs in a separate thread when my app calls it but it looks like it stores the thread id of my app.
Can someone shine some light on it ?
Thanks,
Chris
IanB
21st April 2009, 11:20
There has been a lot of discussion over the year about Avisynth calling CoInitialize(). :search:
Theoretically Avisynth should not need to initialise COM, it is supposed to be the job of the parent application, however it seems many apps simply do not, and as some internal components need COM as a courtesy Avisynth attempts to initialises COM. If it was already initialised it simply releases the use count and does nothing else. If it succeeds, it keeps the use count and it also remembers the current ThreadId. On Avisynth shutdown, if it holds a valid use count for COM, the current ThreadId is compared with the saved ThreadId, if the ID matches COM is released with a call to CoUninitialize(). If the ID does not match nothing is done and the process probably will leak a COM instance. You should only ever call Avisynth (or VfW) from 1 thread.
This is the current behaviour of version 2.5.8, previous versions have varying different behaviour.
If your application is correctly initialising COM on the thread that is calling Avisynth before it calls Avisynth then there should be no problem. You are probably calling Avisynth though the VfW AviFile interface. You must init COM before making any VfW related calls.
neuron2
21st April 2009, 12:31
Now I know why I was having issues with COM and CUVID in my Avisynth source filters (that I worked around with the CUVID server)!
Chris K
21st April 2009, 17:08
If your application is correctly initialising COM on the thread that is calling Avisynth before it calls Avisynth then there should be no problem. You are probably calling Avisynth though the VfW AviFile interface. You must init COM before making any VfW related calls.
Thanks for the hints!
Actually the app I use is a gui script interpreter that allows me to add my own dll's.
In one of these I have a function that calls "mciSendString". Although the WinAPI docs
don't mention that the mci interface needs a CoInitialize, It looks like I could fix
the problem (?) by adding CoInitialize(0) at DLL_init and CoUnitialize() at DLL_free.
Thanks again,
Chris.
IanB
21st April 2009, 23:26
Now I know why I was having issues with COM and CUVID in my Avisynth source filters (that I worked around with the CUVID server)!Got any cool details to share?
Actually the app I use is a gui script interpreter that allows me to add my own dll's.
In one of these I have a function that calls "mciSendString". Although the WinAPI docs
don't mention that the mci interface needs a CoInitialize, It looks like I could fix
the problem (?) by adding CoInitialize(0) at DLL_init and CoUnitialize() at DLL_free.Well "mciSendString" may not need COM itself, but any number of things that it invoke for support just might.
Make sure the implementation of this does not result in CoInitialize(0)/CoUnitialize() being called in DllMain(), apparently this can result in a deadlock as the COM code tries to take a lock that the library loader code already has before spawning your DllMain() routine. Also you do not have control over which thread actually runs the DllMain() code, so it is impossible to guarantee the correct thread ends up running the CoUnitialize().
neuron2
22nd April 2009, 00:47
Actually it was guess. I haven't actually tested anything yet. I'll report on the results. I do know that the source filter was starting and running and then trying to init COM inside. That violates the order you said: init COM before doing any Avisynth stuff.
Chris K
22nd April 2009, 10:11
Make sure the implementation of this does not result in CoInitialize(0)/CoUnitialize() being called in DllMain(), apparently this can result in a deadlock as the COM code tries to take a lock that the library loader code already has before spawning your DllMain() routine. Also you do not have control over which thread actually runs the DllMain() code, so it is impossible to guarantee the correct thread ends up running the CoUnitialize().
I understand! Not recommended. I removed it and decided to take a closer look at what is happening.
if(mciSendString(command, mci_retStr, sizeof(mci_retStr), 0)) return 1; // error
coflag = CoInitialize(0);
if (coflag == S_FALSE) { gcPrintf("======== %s", command); CoUninitialize(); }
if (coflag == S_OK) { gcPrintf("++++++++ %s", command); }
I added print-out of debug info that shows after which mci command COM init seems to return unbalanced.
At the ++++++ printout CoInitialize(0) returns S_OK so there has become an unbalance.
This is the print-out for a Avisynth script:
======== open "G:\VirtualDub Capture3\xxx2.avs" type mpegVideo alias temp
======== set temp time format milliseconds
======== status temp length
======== status temp frame rate
======== where temp source
++++++++ close temp
You can see that CoInitialize(0) is triggered after a close command which doesn't happen with a regular avi clip.
IMO this means there is definitely a unbalanced return after mci closes the script.
But I agree the Avisynth code is correct so it seems that something else in the chain did it.
-
EDIT:
In addition, I found that the COM init unbalance only occurs one single time for the whole session duration of the main app. Always the first time a Avisynth script is played. Thereafter I can play as many scripts as I like without the problem. Unfortunately the main window then already has lost its drop ability.
OleInitialize (drag/drop) is related to coInitialize. Possibly a conflict introduced by the Windows OS itself.
IanB
22nd April 2009, 14:25
AFAIK OleInitialize is a superset of CoInitialize, i.e. OleInitialize calls CoInitialize.
Seems most people when they suffer from this malady, just say dang it and call CoInitialize a number of time at the beginning of their code, to counter any unexpected CoUninitialize's. In the exit path they call CoUninitialize a matching number of times.
It is a fairly common problem for people to misinterpret or just plain ignore the return codes from CoInitialize. They then just blindly call CoUninitialize on the way out and screw the world.
IIRC the error that stuffs most people is something about "cannot change mode". It means COM was already initialised and will work correctly but you did not increment the use count and you must not call CoUninitialize.
squid_80
22nd April 2009, 17:02
Now I know why I was having issues with COM and CUVID in my Avisynth source filters (that I worked around with the CUVID server)!
cuvidCreateDecoder calls CoInitialize() internally. I sent NVIDIA a bug report (which they promptly fixed) because it wasn't checking the return value and always called CoUninitialize() regardless (IanB's post explains why this is bad). It's still a hassle though because you have to be sure cuvidCreateDecoder and cuvidDestroyDecoder are called from the same thread. IMO it would be better if cuvidCreateDecoder simply failed if COM wasn't initialized, but that's another story.
vBulletin® v3.8.5, Copyright ©2000-2012, Jelsoft Enterprises Ltd.