I've been trying to determine what this function does, however I cannot seem to find it anywhere under the MSDN documentation of the CComModule class.
Could anyone tell me what it is used for?
This function is for DllCanUnloadNow() to work properly.
You know that when you call CoCreateInstance() for an in-proc server COM automagically calls LoadLibraryEx() to load the COM server DLL if necessary. But how long is the DLL kept loaded? In fact COM calls DllCanUnloadNow() for every loaded COM server DLL periodically. If it returns S_OK COM is allowed to call FreeLibrary().
When is it safe to unload the DLL? Obviously you can't unload it until all the objects implemented by the DLL are destroyed. So here comes "lock count" - an global integer variable counting the number of live objects implemented by the DLL.
When a new COM object is created - CComModule::Lock() is called from its constructor (usually CComObject constructor) and increments the variable, when an object is destroyed - CComModule::Unlock() is called from its destructor and decrements the variable. When CComModule::GetLockCount() returns zero it means that there no live objects and it's safe to unload the DLL.
So the lock count is very similar to the reference count implemented by IUnknown. The reference count is per object, the lock count is per COM in-proc server.
Related
This is not for production code, this is for a unit test.
We have a legacy DLL which frees resources on a DLL_PROCESS_DETACH event. We had a crash scenario in the static destruction phase of an executable because the destructor of a static variable was trying to access resources unmapped by the DLL (dangling reference).
I'd like to reproduce this crash scenario in a unit test so I can prove I've fixed it.
You may be able to get a handle to the module with GetModuleHandle(LPCTSTR lpModuleName), and pass that to FreeLibrary().
The documentation for GetModuleHandle() states:
The GetModuleHandle function returns a handle to a mapped module without incrementing its reference count. However, if this handle is passed to the FreeLibrary function, the reference count of the mapped module will be decremented. Therefore, do not pass a handle returned by GetModuleHandle to the FreeLibrary function. Doing so can cause a DLL module to be unmapped prematurely.
Despite the warning not to do so, that sounds like it is exactly what you are looking to do. This should be fairly easy to test in your scenario, to verify that it does what you want.
Here's the scenario:
-COM DLL, loaded into the address space of the process that uses the DLL.
-Inside the DLL couple global variables exist (lets say var a, var b) and a global function.
-Process starts up, calls the global function and initializes globals a, b and calls CoInitialize(NULL) - The thread is an STA.
-Then same global function creates an STA COM object
Later in the program, same thread (the thread that called CoInitialize above and created STA COM object) calls same global C-Function (lets call it func()) in this DLL. In the scope of the C-function the state of the global variables is exactly as expected (ie. correctly initialized).
The minute the function func() invokes a COM method on the existing STA COM object, the COM object being in the same DLL sees completely different copies of the global variables (var a, var b). I took the address of both variables and they are completely different in the C-func as opposed to invoked COM objects function.
What is going on? I thought globals in same address space should be visible across the board.
It's possible that two instances of your DLL are being loaded -- one explicitly by the application that hosts your DLL, and the second through the COM subsystem via CoCreateInstance. The former will look in the DLL search path for the application's process, while the latter will look in the registry for the location of the COM component that implements your COCLASS.
If your DLL has a DllMain (or the InitInstance function if it's an MFC-based DLL), then you can breakpoint it and look at the hinstance argument (or AfxGetInstanceHandle if MFC) to see if (a) you initialize twice and (b) you see two different DLL instance handles. If so, then you're definitely loading twice.
The DLL's location in the file system matters, so you should see if there are copies in separate locations that might be separately loaded based on the rules I mentioned above.
In general, a COM DLL should never be loaded directly. You should break your functionality up into two DLLs, with a COM server DLL dedicated to the COM stuff. You can provide yourself an internal COCLASS interface that will enable you to pass your globals to the COM DLL, if you so wish.
What's the cheapest way for a JavaScript like setTimeout-function in C++?
I would need this:
5000 miliseconds from now, start function xy (no parameters, no return value).
The reason for this is I need to initialize COM for text to speech, but when I do it on dll attach, it crashes.
It works fine however if I do not call CoInitialize from dllmain.
I just need to call CoInitialize and CoCreateInstance, and then use the instance in other functions. I can catch the uninitialized instance by checking for NULL, but I need to initialize COM - without crashing.
Calling CoInitialize() from DllMain() is a bad thing to do; there are LOTS of restrictions on what you can do from DllMain(); see here: http://blogs.msdn.com/larryosterman/archive/2004/04/23/118979.aspx
Even if it DID work reliably then initialising COM from within DllMain() isn't an especially nice thing to do as COM is initialised per thread and you don't know what the application itself wants to do with regards to COM apartments for the thread that you want to initialise COM for... This means that you might initialise COM in one way and then the application might need to initialise it in another way and might fail because of what your DLL had done...
You COULD spin up a thread in DllMain() as long as you are careful (see here http://blogs.msdn.com/oldnewthing/archive/2007/09/04/4731478.aspx) and then initialise COM on that thread and do all your COM related work on that thread. You would need to marshal whatever data you need to use COM with from whatever thread you're called on to your own COM thread and make the COM call from there...
And then there's the question of whether the instance of the COM object that you create (could you reliably do what you want to do) would be usable from the thread that was calling into your DLL to make the call... You do understand how you'd have to marshal the interface pointer if required, etc?
Alternatively you should expose YOUR functionality via COM and then have the application load your DLL as a COM DLL and everything will work just fine. You can specify the apartment type that you need and the app is responsible for setting things up for you correctly.
So, in summary, you don't need the answer to your question.
When it is OK to stop the execution for 5 seconds entirely, you can use the Winapi Sleep function. Beware that the documentation of Sleep minds some possible problems with CoInitialize and Messages.
currently I'm struggling trying to use a COM dll on a simple system that I've made. Everything compiles successfully, but in runtime the CoCreateInstace is returning S_OK, but somehow my object pointer is returning NULL.
This interface pointer is created on my class header. The weirdest thing is that instantiating this same pointer type on the method stack results in a correct object, but subsequent calls to __hook turn on an access violation when trying to create a BASE com class.
Some other aspects that might be useful:
Tried to run the program with CoInitalizeEx started as COINIT_MULTITHREADED and COINIT_APARTMENTTHREADED
The project is a dll which uses the COM dll in it
I've tried the same method without starting a new thread and the error persists
I've made a test program ( no threads, executable ) and the object is created normally, and hooked correctly. So my guess it is something related to it being a DLL itself or threaded related.
PS: As bonus question, why google doesn't return anything favorable related to COM? :)
It sounds like a bug in the COM object's implementation of IUnknown::QueryInterface - not setting the output pointer but returning S_OK.
CoCreateInstance for an in-proc server is basically:
Load the DLL into memory
Call DllGetClassObject to get the class factory
Call IClassFactory::CreateInstance from the class factory which allocates a new object
Call IUnknown::QueryInterface on the new object to get the desired interface.
Returning NULL but S_OK at any step should result in a crash, except for the QI call at the end.
Found the problem: The module attribute was defined on a static library, and that made the COM object go crazy; Moving it to the DLL source resolved the problem.
How can I ensure a dll is not unloaded while any objects in it exist?
The problem is, when I was using explict memory management I could delete the dll objects before freeing the dll, however with smart pointers I have no controll over the order there destroyed, meaning the dll may be freed first causeing a crash when trying to free one of the other objects:
FlPtr is a simple refrence counting class thats calls AddRef and Release as needed
ExampleDll *dll = LoadDll(L"bin\\example.dll");
IObject *obj = dll->CreateObject();
...
obj->Release();
delete dll;//fine because all objects already deleted
return 0;
auto_ptr<ExampleDll> dll = LoadDll(L"bin\\example.dll");
FlPtr<IObject> obj = dll->CreateObject();
...
return 0;//crash if dll is destructed before obj since Object::Release needs to call into the dll
I tried making the dll handle unloading itsself, ie only unload after all objects have been deleted. This work by creating a new object IExampleDll which the dll implements. This is like the ExampleDll object from before but lives in the dll rather than the exe and is also refrence counted. Each object in the dll increments this refrence on contruction and deincrements it on destruction. This means the refrence count only reaches zero when the exe has Released its refrences AND all the dlls objects have been destroyed. It then deletes itsself calling FreeLibrary(GetModuleHandle()) in its destructor.
This however crashes at the FreeLibrary, im asuming because the thread is still in the dlls code that is being unloaded...
I'm at a loss now how to make sure the dll is only unloaded when there are no remaining objects, apart from going back to freeing the dll explicitly after everything else should have been deleted;
int main()
{
ExampleDll *dll = LoadDll("bin\\example.dll");
restOfProgram();
delete dll;
}
This approach becomes difficult when dlls need to be loaded/unloaded mid program saftly, ie if the user changed from d3d to openGL in options.
Assuming you do not want to terminate the thread when unloading the library (otherwise, see MSalters), you need to free the library from the caller that loaded it.
COM solves that by an in-DLL instance counter (much like yours, if I understand you correctly), and regulary checking it by calling a global exported CanUnloadNow function.
Another option is to have your object/interface smart pointers ALSO reference the DLL they came from. This would increase the client data size, but you wouldn't need to touch the DLL. You might even recycle the LoadLibrary/FreeLibrary reference counter, however that might hit performance.
Also, none of these schemes help much if you get circular DLL dependencies (Component DllA.X references DllB.Y, which references DllA.Z). I haven't yet fould a good solution to that that doesn#t requrie global knowledge.
For the case where the DLL is switched at run time, I'd avoid the smart pointer system for objects created by the DLL and use a system like this:
|-----------------------| |--------------------------|
| Abstraction Interface | | Implementation Interface |
|-----------------------| |--------------------------|
^ ^
| |
|-------------|1 *|-------------------|* *|----------------|
| Application |-------| Abstraction Layer |--------| Implementation |
|-------------| |-------------------| |----------------|
\------------- Main Program ------------------/ \-------- DLL --------/
The application holds a list of all the allocated abstraction layer objects. The abstraction layer objects are the only objects that are allowed to own pointers to objects created by the implementation layer. When swapping DLLs, first iterate all abstraction layer objects and tell them to release the implementation specific data. Then unload the DLL and load the new DLL. Then iterate the abstraction layer objects again and tell them to create new implementation specific data.
MSDN is explicit on this topic: "A thread that must unload the DLL in which it is executing and then terminate itself should call FreeLibraryAndExitThread instead of calling FreeLibrary and ExitThread separately. Otherwise, a race condition can occur. For details, see the Remarks section of FreeLibraryAndExitThread.
Ok I think the best choice is to use the COM approach of polling the dll to see if it can be unloaded. How can I go about doing this though so that I can continue polling the dll after everything else has closed down (ie the main thread has terminated)? Do I need to create a completly seperate process to do this, in which case how do I do it so this seperate process knows about all the loaded dlls, and in a way which has VERY little impact on proformance?
Mayby I could just create the polling system when all the DllPtr's are out of scope and terminate it as soon as it has free the dll? That way it only exists for as long as it takes for any remaing smart pointers to be destroyed.