4

I'm working on a program with a plugin-based architecture. All the plugins are DLLs, and some of them can have dependencies on other plugin DLLs. I'd like to be able to do the following:

  • At program startup time, scan the plugins folder.
  • For each plugin found, check if that plugin is already loaded. (Which it could be, if a previously-loaded plugin caused it to be loaded as a dependency).
  • If not, load it.

The first and third steps are trivial, but how do I do the second? Is there a winapi call that, given a filename of a DLL, will tell me if that DLL is currently loaded into the current process? (Or perhaps one that takes a filename and a process handle?)

Please, no answers saying "just load it anyway." I know that will work. I'm trying to avoid that.

Mason Wheeler
  • 82,511
  • 50
  • 270
  • 477
  • Execute listdlls.exe and parse the result ;) – Qiau Aug 13 '12 at 17:31
  • @Qiau: I'd prefer not to have to rely on an external utility, particularly not one that the end-user may not (and probably won't) have on his system. – Mason Wheeler Aug 13 '12 at 17:32
  • http://stackoverflow.com/questions/1553603/how-to-know-if-a-given-dll-is-loaded-by-a-given-process or http://stackoverflow.com/questions/450039/how-to-programmatically-get-dll-dependencies might answer your question? – Qiau Aug 13 '12 at 17:33
  • 1
    I'm a bit curious as to why you don't "just load it". If you don't call LoadLibrary and actually have to use the DLL, then it seems there would be no guarantee it would stay loaded. If you retrieved the handle via GetModuleHandle then retrieved an entrypoint via GetProcAddress, there is no real guarantee the DLL will stay loaded when you need to call the entrypoint. If the other DLL that loaded the one in question decided to unload it, the reference count would go to zero and Windows would be free to remove it from underneath your application. – Mark Wilkins Aug 13 '12 at 17:42
  • 1
    @MarkWilkins: I don't "just load it" because it would complicate cleanup. There's only one entrypoint I look for with GetProcAddress. If it has this, it retrieves metadata from that routine, which will get cleaned up when the plugin is unloaded. If not, it will immediately unload the library again, because that means it's found something that's only meant as a lower-level dependency library. This way, I can simply unload the top-level plugins with confidence that all dependencies will be cleaned up in the proper order, without the EXE holding a reference to them and thus b0rking the refcount. – Mason Wheeler Aug 13 '12 at 17:52
  • 1
    @MasonWheeler: Heh heh. As soon as you mention cleanup, then I can understand why you might jump through hoops. I have spent days at a time dealing with DLL unload order issues and various cleanup problems. – Mark Wilkins Aug 13 '12 at 17:57
  • DLLs and modules already have some form of reference counting in place. `LoadLibrary()` only does it if it's not already loaded, and the `DllMain` calls only come into play on first load/unload. – Deanna Aug 14 '12 at 11:09

1 Answers1

5

GetModuleHandle API gives you HMODULE for the loaded DLL, or otherwise NULL if it is not loaded. Note that you can omit path, if desired. You can also get HMODULE for a name without path, and then GetModuleFileName using this handle in order to obtain full path to compare to what you expect.

If lpModuleName does not include a path and there is more than one loaded module with the same base name and extension, you cannot predict which module handle will be returned. To work around this problem, you could specify a path, use side-by-side assemblies, or use GetModuleHandleEx to specify a memory location rather than a DLL name.

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.

Enumerating loaded libraries in the process with EnumProcessModules is also possible, but might be a bit of an overkill for the task you described. You might be good with these plain and simple functions without PSAPI.

Roman R.
  • 68,205
  • 6
  • 94
  • 158