A module can be unloaded, so how can I tell for sure if it is still in memory? I have a handle to it, obtained from GetModuleHandle. When I tried calling GetHandleInformation on it I see error 0xc0000008 - "An invalid HANDLE was specified." This happened before it could have been unloaded.
The term "handle" is a bit overloaded here - lots of different classes of objects in the Win32 API are called "Handles".
GetHandleInformation is used for handles to kernel objects - files, registry keys, mutexes, etc.
The HMODULE returned by GetModuleHandle is used by the loader and is not an actual kernel object, hence GetHandleInformation fails. Neither of the flags you get in GetHandleInformation makes sense for HMODULE though.
If you want to check if the HMODULE is still loaded in memory, you can just call GetModuleHandle - this API should be quick enough to call many times. However, the result of GetModuleHandle can be invalid the moment it returns - another thread could have called FreeLibrary. It is better to ensure that the DLL does stay loaded. You can do this by calling LoadLibrary yourself, or by calling GetModuleHandleEx which will increment the reference count of the DLL.
Two solutions:
1
Call GetModuleFileName() on the HMODULE. If the module is loaded you will get a valid filename. If it is not loaded, you won't get a valid filename. Be sure to either set the first byte of the returned filename array to '\0' before you call GetModuleFileName() or to check the return value. If you set the first byte before the call you can effectively ignore the return value and just treat the zero length string as a "not loaded" signal.
TCHAR szModName[MAX_PATH + 1];
szModName[0] = _T('\0');
GetModuleFileName(hMod, szModName, MAX_PATH);
// zero length string if not loaded, valid DLL name if still loaded
2
Call VirtualQuery() passing the HMODULE as the address to query. As an experiment do this on a loaded library and on a library you know to be freed. You will find they have very differentl results for the returned MEMORY_BASIC_INFORMATION. I leave it to you to work out a suitable algorithm to determine the difference between the two.
Caveat
Of course, the caveat that another thread may unload the library while you are running eiher of these tests applies. In my experience, this is highly unlikely to happen, but that depends very much on what you are doing, why you are doing it, and when you are doing it the program's execution path. Use with care.