COM registration fails: "Automation error: the system cannot find the file specified", when installing dll into other folder than the tlb file

11,691

Solution 1

It turned out that MyLib.dll is using some other libraries, which are still installed in the MyApp installation folder. And so in that case that MyLib.dll is installed in the shared folder, it tries to find those libraries in the same libraries, which of course fails. When I install those libraries in the shared folder too, it is working.

BTW I found fulogvw.exe very helpful when tracking down the assembly loading problem. For example in my case in the failed log it says can't load file xxx.dll in SHARED_FOLDER, the xxx.dll is some library that MyLib.dll is using, and I had no idea that MyLib.dll needs it until I see the log.

Solution 2

I don't understand exactly how COM reference works for Access application,

How com objects works for windows is the same since this stuff appeared in 1990. So we talking about a meat and potatoes mainstay or technology that been around for 22 years (and it was around long before how objects are created in .net).

So how com works is the same in regards to Access, or Delphi, or FoxPro or VB6 or any system that is able to consume a com object.

Next up it is important to keep in mind that for such com objects the registry of such objects on a computer is GLOBAL in nature.

There is NOTHING close to the concept of dynamic linking of objects placed in the same folder as you have in .net.

So the way.net works does not require a global registration (in fact you don't require any registration!).

However in.net you CAN register an object in the global assembly if you wish (GAC). So this is choice you have but such a choice is not a standard windows com object but that of a .net object. So those.net objects have ZERO AND NOTHING to do with standard windows com objects we had for 22 years now.

So most objects in .net are in fact local to the dir, but this is not a choice for standard window com objects.

So to correctly convert a .net object or assembly into a useable and working windows com object, then the object has to registered GLOBAL to the computer. Those means you not using regsvr32, but in fact are going to use the .net registration tool called regasm (which in effect does do a regsvr32 eventually for you after building a com object bridge for you). Also keep in mind you need to compile for the correct bit version here.

And if you deploying to other computers, then set your project to produce a 2.0 object so you have a great chance of the .net library(s) having been installed on the target computer. So, during deployment you have to use regasm:

This one: C:\Windows\Microsoft.NET\Framework\v2.0.50727\RegAsm.exe

MOST IMPORTANT is do NOT forget to add the /codebase to the command line use of regasm.exe since you MUST registry the .net object in the GAC (Global Assembly Cache). If you don't do this, then non .net applications that support windows com objects will not see noir be able to use the assembly as a standard windows com object.

So when talking about non .net objects there is no concept of registering ActiveX or what is common referred to as a windows com object on a folder by folder bases – it is always global in nature.

As such it is a moot point as to what directory or folder you place the .dll into. Once you correctly register that .dll then it will be available to all systems that support com objects.

This also means that during the registration process in .net then you have to use the global assembly registry option (else it will not work).

Share:
11,691
tete
Author by

tete

Updated on June 05, 2022

Comments

  • tete
    tete almost 2 years

    We have a COM component (let's call it MyLib) developed in VB.NET, for our Access application (let's call it MyApp) to use. In order to do that, we need to do COM registration using the generated MyLib.dll and MyLib.tlb files. When I am installing both files into our MyApp's folder, everything is working fine, the COM function is invoked correctly. However, I am having an error mentioned in the title when I am installing the dll into a common folder - the reason I am doing it is because we want to allow different versions of MyApp to be installed on the same machine. So if the COM component doesn't change, we of course want to share it among these different versions and let Windows do the reference count.

    I am not sure where I should put the MyLib.tlb file, either in MyApp's installation folder, or the same common folder as MyLib.dll. But anyway, I tried both locations, and they all gave the same error. I tried to compare the registry files between the case when I put MyLib.* into MyApp's folder, and the case when I put MyLib.dll into common folder. I can't see any difference except of course the CodeBase of the Class I am trying to register under HKCR\Wow6432nodes\CLSID{MYCLSID}\InprocServer32. Another thing I don't understand is there is no sub-key named TypeLib under HKCR\Wow6432nodes\CLSID{MYCLSID} in both cases, which in my understanding is the way to link the TypeLib to the dll (but why is is still working when I put tlb and dll into the same folder?) since in MyApp it only knows that there is a reference we add by reference of MyLib.tlb.

    I don't understand exactly how COM reference works for Access application, so if I am wrong please correct me. Can anybody tell me what I did wrong? What is the correct way to register a shared COM dll (whether put both dll and tlb into shared folder or not)? Thanks!

    UPDATE:

    Regarding the COM registration, I am using WIX to create a Windows installer and heat.exe to harvest the information from dll and tlb files. The generated file includes the information of Class, ProgID, TypeLib, and Registry tags. As I mentioned, the only difference between my two cases, from WIX configuration's point of view, is the location where I put MyLib.dll file (I assume putting MyLib.tlb file in MyApp installation folder is the correct way, again, please correct my if I am wrong), and when I put both dll and tlb files into application's installation folder, it does work. Here is some registry structure after the registration

    Firstly I have HKCR\CLSID\{MYCLSIDs}, each of them represents one of my COM class. in the sub-key named "InprocServer32", I have Assembly, Class, CodeBase, RuntimeVersion, threadingModel. And the CodeBase is either common file folder (not working) or MyApp's installation folder(working), which is the different locations I put the dll. I thought there would be another sub-key TypeLib under {MYCLSIDs}, since Access only sees the TypeLib and I think there should be some link from the TypeLib to the actual dll, however, at both cases this sub-key is missing but in the second case it is still working. Is there a problem of it?

    Secondly I have HKLM\Software\Classes\CLSID\{MYCLSIDs}, this key has the same structure as described above.

    Thirdly, the HKCR\{MYPROGIDs}, these are just ProgIDs of my classes

    Fourthly, HKCR\Typelib\{LibID}, which includes the information from tlb file, and this ID is from the Assembly GUID of COM component project.

    Finally, the HKEY_CLASSES_ROOT\Interface\{InterfaceID}, there is sub-keys named ProxyStubClsid32 with value {00020424-0000-0000-C000-000000000046}, and the one named TypeLib and the value is my LibID.

    It seems the only difference is the CodeBase in the first items (I could be wrong but that is what I see). please let me know if you can see any problem. Thanks!

    SECOND UPDATE:

    After I install MyLib.dll into the shared folder, the COM calling fails. But if I replace all the CodeBase values for SHARED_FOLDER\MyLib.dll to INSTALLDIR\MyLib.dll, and copy MyLib.dll into INSTALLDIR, it actually works. Vise versa, after I install MyLib.dll into INSTALLDIR(in which case COM is working), I change the CodeBase values from INSTALLDIR\MyLib.dll to SHARED_FOLDER\MyLib.dll, and make a copy to SHARED_FOLDER, this time it fails. So it seems that it is exactly the installation location's problem, which is the opposite to my understanding of COM. And I don't think there is a permission issue for the SHARED_FOLDER(I could be wrong) since it is in a folder that my installer creates.

    • paulsm4
      paulsm4 almost 12 years
      Did you run "regsrvr32" to register the COM server (and it's directory)?
    • tete
      tete almost 12 years
      @paulsm4 , thanks for your comment. Please see my update to the original post.
    • Albert D. Kallal
      Albert D. Kallal almost 12 years
      Great stuff – now you know why .net is so nice! As for your follow up – I still don't have much to add. <<I assume putting MyLib.tlb file in MyApp installation folder is the correct way, again, please correct my if I am wrong>>. From a .net point of view, placing the .dll in the same .net app folder helps but from an Access Accdb/windows point of view the folder location does not matter at all since such a registration is available to all windows programs able to consume the com object(s). So windows com registration is different than .net and folder location not important to Access.
    • tete
      tete almost 12 years
      @AlbertD.Kallal I added a second update, please see. You mentioned the the folder location doesn't make a difference, but I got the opposite result.
  • tete
    tete almost 12 years
    Thanks Albert. From practices's point of view, can you see any problem from my description of registry structure after the registration? I added some update in the original post.
  • StayOnTarget
    StayOnTarget almost 7 years
    This answer overlooks Windows side-by-side (SXS) deployment capabilities which allow you to use COM DLLs without global registration. That still doesn't make it fully equivalent to how .NET deployment works but it was a big step when it was introduced.