How can I tell whether a DLL has been registered?


A customer pointed out that you can use regsvr32 to register a DLL or to unregister it, but how do you query whether a DLL has been registered?

DLL registration (via regsvr32) is not declarative; it is procedural. A DLL does not provide a manifest of things it would like to happen when installed. Instead, the DLL merely provides two functions for regsvr32 to call, one for registration (DllRegisterServer) and another for unregistration (DllUnregisterServer). All the regsvr32 function does is call those functions.

How those functions perform their registration and unregistration is not specified. Most of the time, those functions merely write some registry settings, but the DllRegisterServer is not limited to that. For example, the DllRegisterServer function might write some values only conditionally, say, only if the user is running a specific version of Windows. Or it might back up the old value of a registry key before it overwrites it. It might create or modify files as part of its installation or configure your firewall settings or look for and uninstall previous versions of the same DLL.

By convention, the DllRegisterServer performs whatever operations are necessary for DLL registration, and the DllUnregisterServer reverses those operations, but since those functions are provided by the DLL, there's no guarantee that that's what actually happens. Who knows, maybe DllRegisterServer formats your hard drive. A DllRegisterServer function might just return S_OK without doing anything. How can you tell whether a function with no side effects has been called?

Given that DLL registration can encompass arbitrary operations, there is no general-purpose way of determining whether registration has taken place for an arbitrary DLL.

To determine whether a DLL has been registered, you need to bring in domain-specific knowledge. If you know that a DLL registers a COM object with a particular CLSID, you can check whether that CLSID is indeed registered.

Comments (27)
  1. Mike says:

    Now I wonder if there's something special about regsvr32 that's different from using, e.g. rundll to call the same functions, or using LoadLibraryEx to load the Dll and then call those functions. I realize there isn't going to be anything special about the operations themselves, but is there any kind of contextual privilege or environmental artifact offered by regsvr32?

  2. JM says:

    In other words, regsvr32 is like rundll32. Except that it uses two entry points with specific names. And a different calling convention. And it has a help function with usage information. And it reports the result back to the user. On second thought, it's not like rundll32 at all except that these both call functions from DLLs. And their names are vaguely similar.

    That's my shallow thought for today, we now return to more substantial contributions.

  3. Paul M. Parks says:

    @Mike: You do realize that DllRegisterServer and DllUnregisterServer should not be called by rundll32, right?

    One advantage of using regsvr32 that comes to mind is abstraction. If the documented way for an installer or end user to register a DLL is by using the regsvr32 utility, then Microsoft has the option of modifying that utility at some point to call other DLL exports. DLL vendors may then implement those exports to take advantage of whatever new functionality is provided by that form of registration, and installers and end users are blissfully unaware of the change. On the other hand, if installers and end users call those exports directly, then they are hard-coded into a specific registration implementation.

  4. George says:

    @Mike

    I remember the recent posts from Raymond about the abuse of rundll. DLLRegisterServer is not a function supposed to be called from rundll32. It is defined as HRESULT __stdcall DllRegisterServer(void); but rundll32 accepts functions defined as void CALLBACK

      EntryPointW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine,

                  int nCmdShow);

    Pretty big difference!

    Correct me if I am wrong.

  5. waleri says:

    regsvr32 also handles both 32 and 64 bits DLLs… Ons second thought, I won't be surprised if rundll32 can handle both DLLs as well.

  6. Jonathan says:

    The DLLRegisterServer system is woefully under-engineered. There's no ref-counting (hence the unanswerable "other programs may be using this file, do you want to delete it?"), no way to know what it actually does, etc.

    I do wish is was declarative. Actually, MFC COM servers are declarative, with a .RGS file as the manifest – but the code that parses it is statically-linked in the COM server. No big improvement here.

    But, I guess it was acceptable for when it was designed (Win3.1? Win95?).

    [Um, it is refcounted. The unanswerable question appears when the refcount goes to zero. Another case of saying "Windows is stupid for not doing X" when in fact it did X all along. -Raymond]
  7. Phil W says:

    The Windows Installer rule is that you always install your Dll to the same location with the same MSI Component Guid. That's what ref counts it – when the count for that guid goes to zero Windows removes it, to expand on Raymond's point. This is one of those "it just works" things as long as you follow that rule. Incidentally it's not recommended that you call DllRegister/Unregister at install time (see the docs for the SelfReg table). Most "real" install tools will extract COM registration at build time and write it to the system when the Dll is installed, all ref counted.  In the bad old days the ref count was a bit more primitive (Shared Dll ref count).

  8. Crescens2k says:

    @George

    Not wrong, but needs a little bit of clarification. support.microsoft.com/…/164787 this should explain everything.

    (The clarification is that rundll32 also accepts the form void CALLBACK Entrypoint(HWND, HINSTANCE, LPSTR, int); on NT versions)

    @waleri

    Both regsvr32 and rundll32 handles 64 bit dlls on x64 versions of Windows. (Not sure about the IA64 versions, but I don't see why it wouldn't). The way it works is that it detects the DLL type first, and if it is found to be of the alternate architectures (so x86 for x64 native regsvr32 or rundll32, and x64 for the wow64 native version) then it will just launch the other version of the command with the same parameters.

    Just in case that was unclear, suppose you run c:windowssystem32regsvr32 myx86component.dll. It will read the DLL type, find that it is a 32 bit component and then launch c:windowssyswow64regsvr32 myx86component.dll. The same goes with x64 versions of DLLs with the x86 version of regsvr32 (and the same with rundll32).

    (Of course the actual mechanism is unknown, all I know is that no matter what version of regsvr32 I use, I can register both types of DLL.)

  9. Ivan K says:

    Actually, thanks to Raymond's work rundll32 can be used to successfully call Dll[Unr|R]egisterServer.

  10. Dave says:

    Here's my favourite implementation of DllRegisterServer():

    STDAPI DllRegisterServer( void ) {

     MessageBox( NULL, "Why are you trying to register this DLL? It's an ordinary Windows DLL, there's nothing to be registered", "1d10t Error", MB_ICONQUESTION | MB_OK );

     return( E_NOINTERFACE );

     }

  11. Cheong says:

    @Dave: If your DLL is not mean to be registered, it shouldn't contain DllRegisterServer() at all, especially if you're developing 3rd party components.

    I remember some installer will always defaults to autoregister the DLL if it see's there is DllRegisterServer() in it. I think will be quite annoying if the customer found the installation always fail because the installer calls registration and see your E_NOINTERFACE return code.

  12. Joshua says:

    From the referenced link that I would have answered then had I been around then:

    [Office definitely shouldn't be calling undocumented APIs; if they are let me know and I will go beat up somebody. I think SQL Server lives on the application side of the fence as well. Not sure about Hyper-V. -Raymond]

    As of about Office 2000 the calls to undocumented APIs had been removed.

  13. xpclient says:

    If all regsvr32 operations require elevation on Vista and up, why doesn't it show a UAC prompt when launched from a non-elevated cmd prompt or Run dialog?

  14. Crescens2k says:

    @xpclient

    They don't, you can have per user COM component installations. I have around 11 user only components installed on my system (Windows 7 Ultimate x64) and they are truely per user (no per machine keys at all) and I can instantiate instances of those components with no problems at all.

  15. MIke says:

    Thanks, all, for answering my wonderings. :)

    And, Paul, the point on abstraction is very well taken.

  16. Maurits says:

    How can I tell whether a DLL has been registered?

    You try to use it (CoCreateInstance the object you want to use and try to use it.)

    If it works, the .dll was probably registered, or maybe it never needed to be registered, or maybe it just looks like it works and it will bite you later on.

    If it doesn't work, maybe the .dll wasn't registered.  Or maybe something else is wrong.  You could try registering the .dll.  Usually the operation of registering a .dll is idempotent.  But not always.  In which case maybe it was working except for temporary problem and now you just broke it.  So maybe before registering it you should unregister it first, usually unregistering a not-registered .dll does no harm.  But not always… (etc. etc. ad infinitum ad astra)

  17. Dave says:

    @cheong00:

    If your DLL is not mean to be registered, it shouldn't contain DllRegisterServer()

    at all, especially if you're developing 3rd party components.

    And then we get support emails from people asking why they get an error when they try and register the DLL.  We put that in there specifically because people were trying to register a DLL that should never be registered in the first place, and then calling us to complain when it failed.

  18. TC says:

    @Dave: but why make it display a message? Why not just do nothing and return success?

  19. Dave says:

    @TC:

    but why make it display a message? Why not just do nothing and return success?

    Think about this for a second.  People are using the DLL incorrectly, and your suggestion would lead them to believe that their incorrect usage was OK.  What happens at the next step, when they try a CoCreateInstance()?

  20. 640k says:

    And again, a program could EASILY make a copy of the current system, start a VM with the copy, run DllRegisterServer, and check if there's any new guids in VM's registry.

    If there is, return true, else false.

  21. Tim says:

    @640k: From the article you just read: "How can you tell whether a function with no side effects has been called?"

  22. 640k says:

    In a theory, DllRegisterServer could of course ask the user for a 128-bit number, which is written into registry, and which com hosts use to instantiate the object. Then there's no way to figure out what will be used.

    In this case though, I can bet the customer has a com dll compiled by a common compiler like VS or VB. A compiler which MS has the source for. The autogenerated DllRegisterServer is mostly declarative, or at least MS should be able to figure it out because it's likely their own tools are 100% responsible for generating the guid.

  23. 640k says:

    Or you could scan the registry for the dll file name :)

  24. Given that the Dll[Un]RegisterServer functions can perform a number of operations, the answer to "is this registered" is not really binary.  I register a DLL, which (in the simple case) writes a bunch of settings to HKCR.  Something then modifies or deletes ONE of those settings.  The DLL is still mostly registered, but not entirely, right?

  25. 640k says:

    You first has to define what "registered" and "com dll" are. If DllRegisterServer has conditional logic, I wouldn't call that dll 100% com compatible. If it waits 1000 years to write the guid, I would call it buggy.

  26. Phil W says:

    @Aaron M: "Something then modifies or deletes ONE of those settings.  The DLL is still mostly registered, but not entirely, right" Well you're supposed to put the registry entries in the MSI file, NOT call DllRegisterServer at install time. Then if you get missing entries Winows Installer will repair them for you. If people choose an unfortunate way to install COM registration then they get unfortunate results sometimes.

  27. @Phil W — what you say sounds like a good idea, but I don't recall ever seeing that guidance before for COM components.  COM components are generally supposed to be self-registering.  Suppose I bundle components from a third party library — am I supposed to figure out all the registry values it writes (on 32- and 64-bit versions of Windows) and add those to my MSI?  Or do I just install the components and then register them?

Comments are closed.