Zach
Zach

Reputation: 2155

How Do I use LoadLibrary in COM Accross Multiple Threads?

Let's say that I have the following code that's run in one thread of a multi-threaded COM application:

// Thread 1
struct foo {
    int (*DoSomething)(void ** parm);
};

HMODULE fooHandle = LoadLibrary("pathToFoo");
typedef int (*loadUpFooFP)(foo ** fooPtrPtr);
loadUpFooFP loadUpFoo;
loadUpFoo = (loadUpFooFP)GetProcAddress(fooHandle, "fooLoader");
foo * myFoo;
loadUpFoo(&myFoo);

This all works great and I can then call

myFoo->DoSomething(&parmPtr);

This works, too! Now, another thread comes along and loads up its foo:

// Thread 2
foo * myFooInThread2;
loadUpFoo(&myFooInThread2);

And this, too, works great. In thread 2 I can call DoSomething:

// Thread 2
myFooInThread2->DoSomething(&anotherParmPtr);

Now, when thread 1 eventually goes away, I have a problem. I notice that debugging in Visual Studio that the address of DoSomething can no longer be evaluated. After the first thread dies, when I call:

myFooInThread2->DoSomething(&anotherParmPtr);

I get an access violation. The myFooInThread2 pointer is still valid, but the function pointer was not. This function pointer was set by a call into loadUpFoo which in turn was in a dll loaded by LoadLibrary.

My question is: where do I start looking for the reason this is failing? Is it some problem with the way the external DLL (that I load with LoadLibrary) is setting the function pointer in my foo struct? Or is it something to do with differing threads using the same library? Or, could it somehow be related to my usage of COM in this application (would calling CoUninitialize in the first thread somehow free this memory or library)?

I can provide more details on the COM setup if that looks like it could be responsible. Thanks!

edit: Thanks for the suggestions so far. The foo struct is opaque - I don't really know much about its implementation. The foo struct is declared in a header I import. There are no reference counting methods that I explicitly call and there are no other interactions with the library that's loaded with LoadLibrary. I'm pretty sure the foo struct is not memory mapped to some COM class, but like I said it's opaque and I can't say for sure.

The foo pointers' lifetimes are properly managed (not deleted).

The foo structure is an encryption library, so I'm not at liberty to divulge any more. At this point, I'm confident that there is nothing inherently wrong with my usage of LoadLibrary across different threads and within a COM application (and I suppose that the function pointer memory cleanup is being caused by something in the library itself outside of my control).

Upvotes: 1

Views: 2069

Answers (3)

Adrian McCarthy
Adrian McCarthy

Reputation: 47982

By any chance, is Thread 1 calling FreeLibrary (or ExitThreadAndFreeLibrary) when it shuts down? If so, you're trying to call code that's no longer mapped into the process. Your object still looks good, because the instance data still exists, but the code for its methods would be gone.

If this is the problem, you can change Thread 1 to not free the library.

Or, you could have the second thread also call LoadLibrary. LoadLibrary and FreeLibrary use reference counting, so if you load a DLL 3 times, it won't unload until you free it 3 times. The reference counting is per process, so you can load the same library from different threads. The additional loads are very low cost.

Upvotes: 2

MSalters
MSalters

Reputation: 179917

The value of DoSomething is determined by the library you load. You should be able to determine where it's pointing. Look at the debug output in Visual Studio. It will tell you not just when, but also where DLLs are loaded. Does your function really point into te DLL you think it should point to?

Upvotes: 0

Franci Penov
Franci Penov

Reputation: 76001

There's nothing COM related in the code you've shown. LoadLibrary is not thread-specific, so once you have the handle to the lib, you can reuse it from all your threads. Same applies to the pointer to the fooLoader method.

However, there certainly could be something COM-specific inside fooLoader. Also, what's not clear here is what is the lifetime control of the foo instances.

From the fact that you mention COM and the funky behavior you see, I have the sneaky suspicion that foo is actually a memory map of a COM object's vtable and fooLoader is DllGetClassObject or another factory method that creates COM objects.. :-)

In any case, the most probable explanation for the foo instance becoming invalid would be that it is ref-counted and DoSomething calls AddRef()/Release() causing it to self-destroy.

To pinpoint exactly what's going on, you'll have to provide a bit more information on what fooLoader does and why you think your code is COM related.

Upvotes: 3

Related Questions