WIX: COM registration fails when installing COM dll into another folder - com

I am using heat to harvest the COM dll and tlb files (let's call them MyLib.*, developed in VB.NET) to do the COM registration. Everything was working fine, when I install MyLib.dll and MyLib.tlb into my application's installation folder, i.e., INSTALLDIR. However, since we want to allow different versions of our SW to be installed on the same machine, and if they are using the same version of COM component, only one copy of the dll (I think each version of our SW should have its own tlb, please correct me if I am wrong) should be installed, we now want to install MyLib.dll into another folder, specifically PROGRAM_FILES\Common Files\SHARED_FOLDER_NAME, so now if one version of our SW is uninstalled, the MyLib.dll will not be removed and can still be used by other versions.
But here comes the problem: my COM registration is just simply not working any more after I install this dll into this another folder, and it keeps saying that can't find file specified when I am calling the COM function which indicates registration failure. In the WIX installer project, everything is the same except this folder for MyLib.dll.
Here is the registry structure after installation:
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}, these keys are of course 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.
As I mentioned, the only difference is the CodeBase, which stores where MyLib.dll is located. In order to verify that, I did two tests: 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.
Please help, thanks!

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.

Related

InstallShield UseDLL() doesn't find dll dependencies in the same directory

I have 1 dll file which I try to load during the installation with UseDLL() in one of my installscripts.
this dll has 2 dlls it depends on. they both located on the same directory of the main dll.
When in build the installation with an older installshield - it find it's dependencies and works fine.
When I try to build it with IS2016, it fails because it doesn't find it's dependencies. (If I put these 2 dlls in SysWOW64 - it finds them and works fine).
What is the problem?
Thanks,
Dudi
It looks like InstallShield 2018 makes this easier through a new Enable/Disable flag called DLL_DIRECTORY_SUPPORTDIR. But in InstallShield 2016 there's a good chance you can add the following InstallScript code to find dependencies in SUPPORTDIR. If your DLLs are in a different directory, substitute that instead.
// Add prototype for SetDllDirectory(); this typically goes near the top of your script
prototype number kernel32.SetDllDirectoryW(wstring);
// Call it; this goes in a function called before your UseDLL call
SetDllDirectoryW(SUPPORTDIR);
Note that doing this removes some protection against DLL planting, so it is safest to do this only if you ensure the DLLs in question are either proactively resistant to such things, or if you vet and secure the directory in question. (I'm uncertain whether InstallShield does this for you.)

SDL2_ttf can't find entry point unless libfreetype-6.dll is in proj folder

I am working with SDL2 and its add-on libraries SDL2_image and SDL2_ttf, using Visual Studio 2017. The libraries, and the .dll files that come with them, are in another folder (C:\SDL2.0\lib\x86), which is in the system path.
When I run, it fails, with this error message:
The procedure entry point InterlockedCompareExchange#12 could not be located in the dynamic link library C:\SDL2.0\lib\x86\SDL2.ttf.dll.
I can fix this by putting libfreetype-6.dll, which comes with SDL2_ttf, in the same folder as the .vcxproj file; or in the Debug folder. I can also fix it by putting the .dll into c:\windows\SysWOW64. But I want to distribute my code, and I don't want to put that file in each folder or require users to have admin access (to access c:\windows\SysWOW64); I want Windows to find it in the PATH, as it does with the other .dll files it's using here.
A few things I tried as I looked around the web for solution (to no effect):
Recompiling libfreetype-6.dll
Downloading the latest versions of all associated libraries
Rearranging the .lib files in Project Properties, Linker, Input, Additional Dependencies. Admittedly I may not have tried all possible arrangements as there are several dependencies
regsvr32 libfreetype-6.dll. This led to a different error message:
The module "libfreetype-6.dll" may not be compatible with the version of Windows that you're running. Check if the module is compatible with an x86 (32-bit) or x64 (64-bit) version of regsvr32.exe.
I saw here that maybe I should use the version of regsvr32 in the system32 folder; when I do that, I get
The module "libfreetype-6.dll" was loaded but the entry-point DllRegisterServer was not found. Make sure that "libfreetype-6.dll" is a valid DLL or OCX file and then try again.
So: is there a way to get the program to find libfreetype-6.dll in another folder in the PATH, and eliminate the error message about the procedure entry point?
The program I'm testing on now is from the TrueType tutorial from the LazyFoo website (source).

Getting out of DLL Hell with Microsoft.VC90.CRT?

I've built a inproc com server dll which I can package as 1 file or many via the build utility py2exe. When I allow all the dependencies to remain external, I have no issues, but bundling as 1 file produces problems.
When the dll is utilized (either registering it or instantiating a com object from it), it immediately loads MSVCR90.DLL from the path c:\windows\winsxs\x86_microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.6871_none_50944e7cbcb706e5\MSVCR90.DLL no matter what I do, I can't change that. There is no information that I can find (using Dependency Walker) to indicate what is causing that to load. It just happens magically...
Then, later on it loads that dll again via an explicit call to LoadLibraryA("MSVCR90.dll") (part of some py2exe black box?), but this time it does not look into the winsxs manifests / directory. Instead it looks to the system path and/or will respect a dll redirection. That's when the problem occurs. If I set the system path to start with c:\windows\winsxs\x86_microsoft.vc90.crt...\ it will load the exact same dll and be happy - but if ANY other file is utilized - inclusive of a copy of the EXACT same dll - but at a different path - then the whole thing blows up. It can't handle using two different files.
How can I fix this? Ideally, I've love to make the initial magic loading of the dll draw upon a private assembly, but no matter what I do with manifests or .dll.local etc it will not respect that until this second dll loading takes place.
Note that with the non-bundled dll (external dependencies) it always uses the winsxs MSVCR90.DLL.
I can "fix" my failure to use the dll by forcing the system path to load the winsxs copy, but that is pretty useless for a deployable com server!
The reason is that you DLL has a manifest that tells the module loader to search also in the SxS storage.
You have several choices
Build your DLL using static linkage. Not using any of the MFC-DLLs (see project settings)
Don't use a side by side manifest for the DLL and still use the MFC DLLs. But beware you have to ship those DLL with your DLL in the local path (see DLL search sequence docs)
Use a later build of VS. Later versions of VS don't use the SxS storage any more and there are no manifests for those DLLs any more.
For the 2. see this article in code project. There is an update for VS-2008 [here].
2
Build your DLL

Cannot find the reference specified-Visual Basic 2013

I've got a new system. I am trying to connect to and run the system through a 64-bit Windows 7 PC. The company sent me a Visual Basic project for that. It uses .NET framework 4 and Windows Form Applications. The target CPU is x86.
In the References tab, next to three of the COM references there are "The system cannot find the reference specified" statements. When built, the project gives the namespace errors and warnings because of these objects. The other references work fine. I've then seen those .dll files in the debug folder. I think they are generated by the company before sending me. They also exist in the bin\debug folder.
I've removed the three from the references list in the project and tried the following separately:
1) In the project, refer to the .dll files that exist in the debug folder. (Seems a fake way, but removes all the errors when the project is built. When debug, it gives the "Retrieving the COM class factory for component with CLSID ... failed due to the following error: 80040154" error.)
2) Copy the .dll files in the debug folder to C:\Windows\SysWOW64 folder, then register through regsvr32 "name.dll" in the console as admin. This way, I get the ".dll was loaded, but the DllRegisterServer entry point was not found" error. (In the regedit window, the registry editor cannot find the ID's of those references that are seen in the project properties in VB.)
3) Do the item (2), but with the C:\Windows\System32 folder instead of SysWOW64. The same error when registering.
4) Changed the solution platform to x86 and tried the items 1,2, and 3. Still the same errors.
Do I have to register these dll files? And, am I supposed to register exactly these dll files that exist in the debug folder? Or are they supposed to be generated after build by referring to some 'missing' type libraries in the references tab? I don't have these type libraries, though.
All suggestions are welcome ASAP. Thanks in advance.
You have three Interop dlls for your project, correct? These dlls just allow you to use a COM dll without having to talk directly to the COM dlls yourself.
Referencing the dlls in the bin/Debug directory should be fine, since those are probably the correct dlls that the project was built with. However, you will want to move them to another folder before continuing.
What you need to get from the company that sent you the project is the original COM dlls and their dependencies, if any. Usually an interop dll is called Microsoft.Phone.Interop.dll where it is performing interop with Microsoft.Phone.dll. Microsoft.Phone.dll needs to be registered on your computer using regsvr32 and then you just need a reference to the interop dll.

Can more than .DLL of the same name be registered on a machine?

Can more than .DLL of the same name be registered on a machine?
Eg. If I have MyDLL.dll in both c:\ and c:\MyDLLs, is it possible to register both MyDLL.dll files? If I do this, which MyDLL.dll will be used if an application tries to access MyDLL.dll?
Most likely your question around DLL which implements a COM component. It actually uses a GUID (globally unique identifier) which it looks up in the registry under hkey_classes_root/clsid and there in the sub-keys is a scheme for pointing to the physical location.
To start understanding this, open the regedit, and do a control-f find the full path to both of the DLLs in question - you'll see exactly what I'm talking about.
(Source: http://www.codenewsgroups.net/vb/t2754-dll-hell-query.aspx)
If they have the same file name then they cannot co-exist in the same
directory. One will have to be renamed, or moved. If they're ActiveX DLLs
then the file name is less important than the associated ProgID/ClsID used
for registration -- except that renaming it might upset a subsequent
uninstall or re-install of the software from that vendor.
Assuming they have different ProgIDs and ClsIDs then there should be no
problem in registering them. But if you can try to avoid this.
P.S. Check the link above for some good insight.