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

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.

Related

Is File.Open directory behavior different in x86 vs x64

I am working on a application built in VB.Net that allows a document to be uploaded and saved into a database. I did not build this application, but I do maintain it, put enhancements in it here and there. The target framework is .Net4
One of the functionalities within this process when uploading and saving the document it uses the method File.Open() to access the file and run other methods to compress it. The method that uses File.Open takes in a parameter that passes just the filename, not the entire path of where it came from.
When this application is running on an x64 machine I receive an error (System.IO.FileNotFoundException) when the code hits the File.Open method, complaining that it cannot find the file to open. It is expecting the file to be in the programs executing directory, which does make sense because it is only given the filename to go off, not the entire directory that it came from.
What's getting to me, is that this exact same application (exact same built assemblies) will run fine when run on an x86 system. It does not fail on File.Open() It still passes just the filename, but somehow, it will know the directory information.
How is this possible?
It's worth noting, that the method that contains the File.Open() method is in a different project in the same solution. It's a referenced DLL. e.g. MyApp.exe (Windows Form Application) references MyUtil.dll (Class Library). I have built against x86, x64 and AnyCPU configurations.
I understand that the fix to this would be to just pass the entire directory to the method, but what I need to know is how this is even possible? I want to better understand why this would happen, and hopefully this would help someone else better understand how assemblies may differ between different system environments.
EDIT: Using an absolute path did fix the underlying issue. See the comments below for some good information on this scenario
Windows has special handling for certain folder names on 64bit systems depending on whether you have a 32bit or 64bit process. Notably, the Program Files folder and the System32 folders map differently depending on what kind of process you have.
Note that this is a difference in Windows itself. It's not a behavior that is unique to .Net or Visual Basic. Any program platform that uses Windows native file handling will give you these results.
This is why you should use appropriate relative paths or the SpecialFolders enumeration, rather than hard-coding full path names, and be careful about where you put things you expect to reference later; you might find they end up in a different location than you expected. Often, the AppData or ProgramData folders are the more correct location, instead of the Windows or Program Files folders.

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

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.

Sharing a common dll between binaries in different directories

I have multiple dll, living in different subdirectories, which depend on another 3rd party dll called common.dll. I would like to set up those dlls so that they know where to find common.dll without making common.dll visible to other programs to avoid clashes.
For example:
foo/bar.dll
foo/bar/fubar.dll
common/common.dll
With both bar.dll and fubar.dll depending on common.dll
I have the following constraints:
While I have complete control on the dlls, I don't have control of the calling executable, so modifying PATH is not an option.
it has to work on every windows from XP up to 7
I cannot install the common.dll in a "known" location used by windows
modifying the dlls code to set up paths through an API is not desirable
IOW, something like unix rpath + ORIGIN on my dlls would be the ideal solution
I was hoping that using manifest could help, but it looks very complicated or not availble for windows xp.
Assuming that that you're using windows a common approach I use is to create a symbolic link to the physical location of the file, in some directory. Then the the caller only has to know some 'known directory' where you put the link and windows magically redirects to the correct file...
real file c:\blah\common\xxx.dll
link : c:\MyDir\xxx.dll
now callers can use c:\MyDir\xxx.dll and they get to c:\blah\common\xxx.dll
syntax on windows is : mklink c:\MyDir\xxx.dll c:\blah\common\xxx.dll

How to access a temporary Exe or DLL from a DLL Custom action (C++ DLL) in MSI/WIX project?

I have two use cases: 1) loading a temporary DLL during a custom action and 2) executing a temporary EXE from a custom action. The custom action DLL is unmanaged C++. I cannot figure out how to get this working correctly. Including the DLL is easy enough but LoadLibrary is failing as it cannot find the DLL. I also cannot seem to get the physical path of the extracted DLL in order to specify full path in LoadLibrary. Any help is appreciated. I'm using WIX btw for this work.
If you have included the dll and the exe in the Binary Table of the msi, the files will be physically present in the %Temp% folder of the currently logged in user which gets mapped to SUPPORTDIR property of Windows Installer.
You need to use MsiGetProperty to get the SUPPORTDIR and use that in the LoadLibrary.
One thing to remember - Windows Installer usually extracts files from Binary table to %TEMP%, however - the current work directory is often set to c:\windows\installer.
My suggestion - extract the temporary .dll from Binary table yourself when you need it. This gives you the control of when it's saved to. Just remember that you need write permission to the location, so usually some subdir of %temp% is the best choice.

VB.net Setup Issue

While creating the setup for VB.net application I am getting the following warning:
"Warning 1 'msado15.dll' should be excluded because its source file 'C:\Program Files\Common Files\System\ado\msado15.dll" is under Windows System File Protection.
Please suggest me how to over come this type of issue.
Thanks,
This is a classic case of IDE components not talking to each other.
One component says "you reference msado15.dll in your code, therefore I should include it in the project".
An unrelated component says "msado15.dll is on my list of protected DLLs, therefore I should warn you not to include it".
However, no component thinks like a human and says "hang on, this DLL is part of the framework, therefore I should silently remove it from the installer".
It's up to you to do the last part yourself.
That means that file is normally already on the operating system, so it should not be necessary to install it. If you remove the user's original protected file in your app uninstall, it can cause problems on the user machine.