I have a driver which can be installed on Windows (XP/Vista/7). It's accessed via a native C++ DLL that 3rd-party applications link to, and which is also a Winsock Provider (WSP). It used to be installed under System32, but having seen advice not to, I changed it to install under ProgramFiles instead.
Now, the problem is that people are having to either copy it back into System32 or copy it into the application directory whenever they want to use it in their own applications, because Windows won't search the install directory under ProgramFiles when the application tries to load the DLL.
I've been unable to find any Microsoft documentation discussing this issue, so if System32 shouldn't be used then where should shared DLLs be installed?
The Windows side-by-side cache. Backgrounder info is here, technical reference is here.
I haven't seen anybody actually do this yet, other than Microsoft. Quite notable is that MSFT gave up on winsxs deployment for the C/C++ CRT and MFC runtime DLLs for VS2010, it was causing too many problems. They're back in c:\windows\system32. The managed equivalent of this (the GAC) is going strong though. Better tool support, probably.
I'm fairly sure that by a large margin everybody chooses app-local deployment.
Since it's a DLL linked to your driver maybe it's less of an issue, but I'd be wary of trying to share the DLL and would instead try to get all developers of client apps to keep their own version of the dll in their applications folders.
I've had too much fun in DLL Hell to want any more weird bugs because AppX overwrote the DLL with an old version that breaks AppY etc.
Anywhere on the path would work.
If this is only to be used with your set of apps (eg Qt4.dll) then in the root of "c:\program files\my company" would be good, or have a 'shared' folder below that.
If it's to be used by other apps that you don't know about (eg a video codec) then system32 makes sense (you will need admin rights when you install)
Fixed filesystem location
One possibility would be to install them in a sub-directory of Program Files, as already suggested by #Martin Beckett.
Variable filesystem location, fixed entry in Registry
If you don't want to install them at a fixed location, you could also store their location in the Windows Registry. You'd install some keys under HKEY_LOCAL_MACHINE\SOFTWARE that your applications could read to find out where the DLLs are located. Then the DLLs can be loaded at run-time.
P.S.: Preventing orphaned DLLs
You could go one step further and use the Registry, or some other storage (a file, say), to store information about which of your applications uses which of your DLLs. For example:
FooCommon.dll <- FooApp1, FooApp2, FooApp3
FooBar.dll <- FooApp1, FooApp3
FooBaz.dll <- FooApp2, FooApp3
Whenever one of your applications is un-installed, it removes itself from this map. Any uninstaller can then safely delete a DLL that is no longer in use by any application. That method is akin to reference-counting, and the idea is to prevent orphaned DLLs from accumulating on users' filesystem.
Native DLLs can be stored as side-by-side assemblies. See this reference for more information. This is separate from the .NET Global Assembly Cache, but it uses similar concepts. This blog post also has quite a few useful details about how DLLs get resolved as side-by-side assemblies.
Related
To my astonishment I found VB6 code that uses Declare statements to define functions in a .dll that lives in the Program Folder without it being registered on Windows. This seems like a supersimple way to avoid the .dll hell without having to resort to using Side by side manifests. Can I read some more about this somewhere? Are there snags?
The Declare statement is used to do "just in time" binding to non-ActiveX DLLs. Until your program "touches" a Declared entrypoint no attempt is made to load the library.
It basically has nothing at all to do with the topic of DLL Hell.
Muddled thinking can even lead people to plop ActiveX DLLs "next to" the EXE which actually can result in DLL Hell because people who tend to do this also use poor techniques for installing and uninstalling applications.
Poorly designed application A deployment plops a commonly shared DLL or OCX next to the EXE.
Poorly designed application is run, the VB6 runtime can't find the classes in the registry, does a DLL Search using Windows heuristics, immediately locates the DLL next to the EXE and calls its self-registration entrypoint.
Innocent, properly designed applications B, C, D are later installed that use the same DLL/OCX and their installers find the library already registered.
Poorly designed application A is uninstalled, typically by simply deleteing its folder in Program Files.
Applications B, C, and D (and any future applications using the library) are now broken - due to orphaned component registration pointing to a non-existant library.
Moral of the story:
Never, never, never put DLLs "next to" your VB6 application on installation. If you have private DLLs that are not shared with other applications even then put them into a libs, etc. folder under the application folder. Possible exception might be non-COM DLLs, such as those you expect to use Declare with.
There is also a great deal of misunderstanding about manifests, of which there are multiple kinds. The ones you are probably thinking of are application and assembly manifests.
These can be used for selecting among different versions of a library installed Side by Side, or they can be used to isolate applications and assemblies which is the part that has bearing on DLL Hell.
Of course application manifests can be used to specify quite a few other things about how Windows should run the application.
Windows searches in a well-documented sequence of folders for LoadLibrary (which VB6 uses behind the scenes to resolve Declare declarations). Since the first location on the list of search folders is the app's own folder, your discovery makes perfect sense.
It doesn't resolve the "DLL hell" issue for the most part, though. It can't work for system DLLs, for instance, because Windows preloads most of them. Also, if a DLL is already loaded into memory, Windows may use that copy of the DLL (not sharing data, but code can be reused).
That's part of the reason that manifests were created; they allow an application to strictly define required versions of system DLLs in order to provide certain functionality. VB6's technique is old fashioned (just like VB6).
I've got a project that depends on a particular version of MSVCR80.dll (the MS Visual C Runtime) and I'm running into problems where, depending on the particular system configuration, my app doesn't always get the right version of that file. It's been a bit of a crap shoot as to what path it takes to find a file with that name, and it's not always right...
Is there a way, when creating a Deployment Project in VS2005, to ensure that my app will always use the runtime that I provided?? When I add the runtime file to the project, it asks about creating a merge module...but not really sure what that does. And regardless of creating one, the issue remains.
Martin Richter wrote an article about that on CodeProject:
Create projects easily with private MFC, ATL and CRT assemblies
This solution does not rely on your MSI packages but on the application that uses the CRT files.
I am not sure if it is your application after installation that doesn't work, or if it is a dll you use as part of the installation that doesn't work?
To make a very long story, very short: new versions of the C / C++ runtimes are installed as Win32 assemblies, or side-by-side installation. This means the files will go into folders under C:\Windows\winsxs - the Win32 equivalent of the GAC, and several versions of the same file can co-exist here.
Applications compiled with Visual Studio 2005 / 2008 will put a manifest file into the binary, and this manifest specifies what side-by-side runtime version to bind to. It doesn't matter if you put the MSVCR80.dll next to your EXE or even in system32 - the manifest embedded in the EXE will load the file from C:\Windows\winsxs.
This is all "full circle". In the old days runtimes went to System32. This caused the original dll-hell: applications overwriting each other's global runtime files. To remedy all this the idea was to "isolate changes" to each application. Hence the new approach was to isolate a local copy of the runtime file next to the EXE. Now this caused an entirely new problem: how do you make sure security updates for the isolated dll was deployed? In most cases this never happened, and you had lots of applications running with local, unsafe dll's. So what to do? The decision was to introduce the second coming of dll-hell: the side-by-side assembly approach. In this approach runtimes are not local, but global - with the critical difference of supporting side-by-side installations. This way, in theory, applications can function without overwriting each other's runtime dlls.
So that was the quick summary of "how to make runtime deployment complicated". I am not positive it is still possible to do, but did you check whether you can statically link to the runtime? Sometimes old-school really is easier...
I want to put my dependent files in the app directory.
I seem to remember that you can force VB6 to use the files in the local directory only.
Any hints?
You may also want to try setting up Reg-Free COM for your project. There's a freeware called Unattended Make My Manifest that will do most of the work for you.
Placing component libraries in the EXE folder (with or without .local files) can be deleterious to the hygiene of target machines too.
VB6 programs will register the components here via the self-reg entrypoint behind your back if they are not previously registered. Then if the application is moved or removed you leave the user with a broken reigistration - possibly fatal to subsequently installed applications using some of the same components. This is probably fine though for application specific components, i.e. your own DLL or OCX that will never be needed by another application.
The .local trick was really not meant for use with VB6 programs and if it is used your installer needs to be aware and properly install and register the components if they are not already on the machine. It was meant as a manual hack to get around DLL version compatibility problems on individual machines, not a deployment strategy.
Move up to SxS application and assembly manifests (Reg-Free COM and more) for a better solution. DLL/COM Redirection (.local) was a good try but it has many warts.
Clay Nichol's answer about the search order is not quite correct. That search order only applies to non-COM components. I.e. only some DLLs, and not OCXs. If you register your COM objects, they will be used from the directory where they are registered regardless of what's in the local directory, unless you use reg-free COM or a .local file.
EDIT:
MakeMyManifest is well spoken of as an automatic tool for creating manifests for VB6 projects, haven't tried it myself.
DirectCOM also has fans, again I haven't tried it.
EDIT The MMM website is down. I see here that the author was having trouble with their hosting and has provided another location to get Make My Manifest - download it here.
There is a semi-automatic technique to generate reg-free COM manifests. You can create the manifests with Visual Studio 2008 (you can use a free version like Visual Basic Express Edition). Then make a couple of edits by hand to make the manifests suitable for use from VB6. See this section of this MSDN article for step-by-step instructions - ignore the rest of the article which is about ClickOnce.
It can be sort of confusing because every version of windows, the rules change. Older versions of Windows search the path before the current directory.
A simple solution without manifests:
If your executable file is A.EXE, add a (0-byte, empty) file in the same directory named A.EXE.local -- for older versions of Windows this puts the app directory ahead of the path in the search order.
Found it myself:
Windows does look in the App Directory first:
If SafeDllSearchMode is enabled, the search order is as follows:
The directory from which the application loaded.
The system directory. Use the GetSystemDirectory function to get the path of this directory.
The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched.
The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
The current directory.
The directories that are listed in the PATH environment variable. Note that this does not include the per-application path specified by the App Paths registry key. The App Paths key is not used when computing the DLL search path.
If SafeDllSearchMode is disabled, the search order is as follows:
1. The directory from which the application loaded.
2. The current directory.
3. The system directory. Use the GetSystemDirectory function to get the path of this directory.
4. The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched.
5. The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
6. The directories that are listed in the PATH environment variable. Note that this does not include the per-application path specified by the App Paths registry key. The App Paths key is not used when computing the DLL search path.
according to : http://msdn.microsoft.com/en-us/library/ms682586.aspx
But you can redirect where it looks for .dll's using a Manifest:
http://msdn.microsoft.com/en-us/library/aa375365(VS.85).aspx
i'm using vs installer to build a setup package for my vb6 app.
and the problem is i can see that under the project explorer there's a list of dependencies attached to my exe file.
alt text http://img505.imageshack.us/img505/9696/croppercapture259lr8.png
and under the file system on target machine treeview, i can actually store the dll/ocx on a folder or in the windows system folder itself[the left window].
alt text http://img101.imageshack.us/img101/9224/croppercapture251qm1.png
so what i don't understand is .. is there actually a difference?
if i just set the dependencies and didn't add the dll or ocx to the folder or win sys folder, does the dll automatically get copied over too?
It is not guaranteed that all those dlls will be present on the system that the software is being installed on. So they need to be included in your installer. From there you have two choices.
You can install them in your windows system folders or in your application folder. The difference is that if you install them in your application folder you can set things up on XP and Vista so that the different version of the software with different version of the components can be fired up and run side by side. Installing them into the system folder will break any older version that depend on older version of the components.
Installing in the application folder rarely doesn't work if a component depends on other components that can't be updated. When this occurs it is usually with with Microsoft libraries. They have gotten better over the years on this issue.
You can read more about the issues involving side by side execution here
Finally the dependencies need to be in your installer so that they are registered in the Windows Registry. Unlike most .NET assemblies any ActiveX/COM application needs to have the component registered in order to use it even if you are using CreateObject and Variant types to access it.
I will admit the whole process is idiosyncratic and is one of the sources for the stories about DLL Hell. Start with the MSDN article, use wikipedia, and of course ask further questions here.
You should usually not have a "dlls" folder under the app folder for a normal Installer package but there are many factors involved (private standard DLLs, Reg-Free COM, etc.). Yes, the dependencies get included (unless you exclude them). They should each have a property that determines where they install on the target systems.
You also have a number of components in that list that are either not redistributable this way because they are OS-dependent system components, MDAC components, or not licensed for redist (fm20.dll for example).
Sadly this is an example of the type of package that can lead directly to DLL Hell for your users' systems. Fixing this can mean researching every MS component in MS KB articles to determine what can or should be redistributed and how.
Deployment can be a messy business to get right.
I have a VB6 application that needs to be installed on Windows Vista as a Standard User. Using Visual Studio 2005 I have created a setup project that will place the application in a standard user safe place or folder. I also have a dll that I want to install and register to the users application data folder. Once my windows installer is created in VS'05 I flipped the word count properties' 3rd bit using msiinfo.exe so that Vista will not prompt Admin credentials when it runs the msi. The application installs without any problems until it tries to register the dll to the users application data folder. When it reaches that point it throws an error stating that it cannot register the type library for the dll. It appears the installer does not have the authority to register a dll to the users folder. Is this correct? My understanding was that Vista only complained about standard users updating or changing items that affected all users of a machine. Any ideas? Thoughts? Suggestions?
Steve
My suggestion is, if you are able, to use regfree com / manifest files instead of registering the ocx/dll files, which as you mention is a real chore under a basic user account.
There is an excellent free app you can use to build the manifest for you as well here: http://mmm4vb6.atom5.com/
We have been using this for a few years now, with no issues.
EDIT The MMM website is down. I see here that the author was having trouble with their hosting and has provided another location to get Make My Manifest - download it here.
Instead of registering your DLL files directly, you can use RegFree COM.
This involves creating an XML manifest file for your app, so Windows will look for your DLL files in the application folder, instead of using the system registry to find them.
This means your app will run properly without your installer having to register DLLs.
These links have more info:
http://msdn.microsoft.com/en-us/magazine/cc188708.aspx
http://www.devx.com/vb/Article/32888/1954
You can use the free Make My Manifest software to create the manifest files you need:
http://mmm4vb6.atom5.com/
Generally I agree to what Joel Coehoorn says in his answer.
However, knowing how the registry works in this regard, I can make the suggestion that you try to manually register your DLL to HKEY_CURRENT_USER\SOFTWARE\Classes, basically repeating what regsvr32.exe would do to HKEY_LOCAL_MACHINE\SOFTWARE\Classes.
It's a bit of a hack, and maybe it won't work, but you can try it.
related post on MSDN: http://msdn.microsoft.com/en-us/library/ms693350.aspx (thanks to MarkJ pointing this out in the comments)
related post on vbforums.com: http://www.vbforums.com/showthread.php?t=507228
Unattended Make My Manifest is a remake of MMM that can be used to generate manifests in automated builds. It uses a script file to add depended COM components.
Registry-free COM: MakeMyManifest is well spoken of. It is an automatic tool for creating manifests for VB6 projects: I haven't tried it myself.
DirectCOM is an alternative to registry-free COM. It also has fans, again I haven't tried it.
EDIT The MMM website is down. I see here that the author was having trouble with their hosting and has provided another location to get Make My Manifest - download it here.
There is a semi-automatic technique for creating manifests for registry-free COM. You can create the manifests with Visual Studio 2008 (you can use a free version like Visual Basic Express Edition). Then make a couple of edits by hand to make the manifests suitable for use from VB6. See this section of this MSDN article for step-by-step instructions - ignore the rest of the article which is about ClickOnce.
Registering a DLL does impact all users (DLLs are registered globally) and therefore requires Admin permissions. There is no way around that.
The solution for newer programming environments is that the DLL doesn't need to be registered to be used. However, since vb6 relies on COM you're probably out of luck.