Running 32 bit app on Windows 7 with dependent DLLs - windows

I have a simple 32 bit app running. It uses Qt and other libraries. Having figured out manifests, I have a folder containing the app , manifests and dependent DLLs. Running this on the target machine under Windows 7 64 bit straight from a USB stick works. Copying this to a folder on the D:\ drive and it works.
Copying this to a folder under Program files (x86) and I get :
R6034. An application has made an attempt to load the C runtime library incorrectly.
I have a manifest for my executable. I also have the manifest for the msvc*.dll's in the folder as suggested elsewhere in this forum. So, why does this work everywhere except in the place it's supposed to be?

Dependency Walker will help here - run it on your .exe when it's in a working state and when it's not and compare the locations of the C runtime library your app is attempting to use (I believe it should be msvcrt.dll if you're in release, msvcrtd.dll if you're not) and you'll hopefully be able to spot a difference.
I'm not certain where you could go from there - perhaps deploy the correct version of the dll into the same folder as your .exe?

Related

Why does my dll end up in AppData\Local\Temp\

I have a small SWT based java application. On installation swt-win32-*.dll is installed with my application in C:\Program Files\myapp\win32.
When I looked at my application in process explorer I noticed that the dll is loaded from:
C:\Users\[Username]\AppData\Local\Temp\swtlib-32\swt-win32-*.dll
On Windows XP it ends up in:
C:\Documents and Settings\[Username]\Local Settings\Temp\swt-win32-*.dll
Whenever I delete it from the temp folder and restart my application the dll is copied there again. The other dlls my application depends on don't show this behaviour.
Who copies the dll (my application doesn't)?
What's the reason behind it?
I don't know Java very well, but if it's inside the JAR (or any kind of archive, really), then it has to be extracted into real file before it can be loaded (because OS provides no other supported way to do it).

Are there reasons why DLL redirection won't work other than the presence of a manifest?

We have a legacy VB6 application that uses Crystal Reports XI to generate printed reports. We've found through experience that the Crystal Reports print engine crashes if it picks up the wrong version of usp10.dll (the Windows Uniscribe library).
One customer is consistently having printing issues on their Windows 7 machines (running Windows 7 Enterprise, 32-bit). However, we have a few other customers running various editions of Windows 7 that are not having any problems.
On one of the machines that was having printing issues, I noticed that there was an older version of usp10.dll (one incompatible with Crystal Reports XI) in the folder C:\Program Files\Common Files\Microsoft Shared\Office10\. I'm not sure what application installed these files, because the customer doesn't have Office 2002 installed (so I assume another application installed them). However, I temporarily renamed the file and our application was able to print correctly, so it seems that our application was loading that version of the file originally, which was causing the crashes.
The crash only happens the moment the user tries to print a report. Our application has direct dependencies on craxdrt.dll (the Crystal Reports ActiveX Designer Runtime library) and crviewer.dll (the Crystal ActiveX Report Viewer library), and the crash happens whether we print directly through craxdrt.dll or through the Report Viewer control.
In the past, we have resolved this issue by copying a known good version of usp10.dll into our application's directory and creating an .local file to enable DLL redirection. At the customer site, I tried this, and also tried the alternate approach of creating a .local folder for our EXE and placing the usp10.dll in there, but neither approach worked on the machine I was connected to.
I did notice that usp10.dll is a "known" DLL in Windows (it has an entry in HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\KnownDLLs), but I tested our application on another Windows 7 machine (running Professional Edition, 32-bit) here that also had the DLL listed as a known DLL in the registry, and by using Dependency Walker, I could see that the redirection was working on that computer. This is somewhat confusing, since the Microsoft documentation states that known DLL's cannot be redirected. Also, as I implied in the question title, our main EXE does not use a manifest file (the Microsoft documentation states that the presence of a manifest, embedded or standalone, disables DLL redirection).
So, my question is, is there any other reason why DLL redirection would work on some machines and not others, and does this have anything to do with differences between Windows 7 and Windows XP? I had considered deleting everything in the KnownDLLs registry key, but since the redirection was working on a machine here that had the same set of KnownDLLs, I'm not sure that would actually resolve the issue, and I don't want to delete that key if I don't need to. I haven't yet had a chance to connect to the customer's machine again to run Dependency Walker, but I'm not sure I would be able to interpret its logs anyway (even on the machine where it was working, I saw a lot of LoadLibrary calls for usp10.dll pointing to a folder other than the redirected folder, but some calls were apparently redirected, so I'm not sure what that means either).
EDIT: I should have also mentioned that every computer we've checked also has another copy of usp10.dll in the System32 folder. Looking at Chris's answer and this blog post by Larry Osterman explaining a bit more about how known DLLs work, I realized that that probably doesn't factor into the problem at all, since our program isn't loading the copy of usp10.dll that is in the System32 folder.
EDIT #2: After playing around with Dependency Walker some more on my VB6 development machine (Windows XP SP3), where the printing has always worked, I was able to glean some information. I profiled our application in Dependency Walker and set it to log full path names, and it looks like one of the Crystal Reports dependencies (another Crystal Reports DLL) tries to load usp10.dll from multiple (hard-coded) paths before giving up and just asking for it by filename. It turns out that it tries to load it from the Crystal Reports bin folder first, then tries to load it from from C:\Program Files\Common Files\Microsoft Shared\Office10\usp10.dll. If it can't find it at either location, it just asks Windows for usp10.dll (which will grab the one in System32). But even this isn't consistent. Sometimes it asks for the file in the Office10 folder, and then appears to ignore the fact that it couldn't find the file, while other times there are a series of LoadLibrary calls where it looks like the Crystal Reports code is actively looking for alternate copies of the file in different locations. Even more confusing is that at least one of the Crystal Reports components looks like it actually has a load-time dependency on usp10.dll, so that component always seems to get the copy in System32.
I'm still not 100% clear why the .local redirection wouldn't work in this situation on this customer's computers, but I think that partly explains why this particular customer is having problems, since all of the computers with the problem have an Office10 folder with an apparently incompatible version of usp10.dll in it.
But, once again, I'm still left with the basic question: if these components are looking for this file in so many different places, how can I guarantee that they will all use the same copy?
My first thought: .manifest files and all they imply were added to windows XP in 2002/2003.
Why the ##$% does your app - and the libraries your app uses for that matter - not use this technology to solve this little "dll-hell". It is exactly the scenario they were developed to solve.
Next, im pretty sure that "KnownDlls" only covers dlls that the OS actually finds in System32. Finding dll's in random path locations (as in a Office2002 folder) i would hope at least would fail some internal sanity check (is-the-dll-a-real-KnownDlls-candidate) test. And the PATH is searched after system folders, so by the time a usp10.dll is found in ...\Office10\ - it' cant be a real known dll (by definition).
Next, Im also sure that the .local file isn't doing what you think it is. The documentation for .local files makes no sense at all because all it really says is, the search order for dlls after a .local file is applies, is exactly the default search order for dll's normally - the exe folder is always searched BEFORE system folders anyway.
The only time .local actually makes a potential difference is when an application uses an explicit path to load a dll in a call to loadLibrary (or uses the altered search path flag to LoadLibrary or uses the SetDllSearchDirectory API). All cases where the exe or dll doing the loading is choosing a very specific dll - that you the app author wants to override in some way. .local files cannot (Seem to me anyway) change the search behaviour for any dll files that are specified by just their name.
So, if usp10.dll is installed into system32, its probably going to be picked up as a KnownDll and then used - despite your local copy (and .local file).
If its somewhere else on the path, the copy in your exe's folder should be used first anyway - (assuming LoadLibrary("usp10.dll") is the way the dll is loaded).
Even if you go to all the effort of creating an assembly to contain your known-good usp10.dll, and then made your app dependent on that, I still think that a fully qualified path passed to LoadLibrary will defeat any search logic at all - including looking for the dll in the list of dependent assemblies.
So, your problem confuses me. The usp10.dll used should be
the one in system32 if present (because of KnownDlls overring the one in your exe's folder)
the one in your application folder, because search logic will always find this one first if KnownDlls is a miss.
unless usp10.dll is actually a com dll, or there is a fully qualified path to it in the registry that consumers use to load it, in which case the one loaded should be :
the one in your application folder, because this seems to be the one case where .local files might apply.
Given that the presence of the DLL in KnownDLLs is inhibiting the functionality of .local, and given that Crystal reports dlls are pathalogical ...
All I can suggest is:
This thread contains a function called PatchIAT - import it into your code.
Before using any functionality in the Crystal Reports dlls (That causes them to go looking for usp10.dll) - call LoadLibrary to get a handle to the dll, then call PatchIAT on the handle, to redirect the dll's call to LoadLibrary to a function your EXE implements.
In your EXEs LoadLibraryThunk procedure, pass on any calls to the system's LoadLibrary, unless its for an explicit path to usp10.dll - on those calls - return an error code.
Disable antialiasing for a specific GDI device context
The solution was actually pretty simple, but it took me a while to figure out why it worked.
On the customer machine, I copied usp10.dll from C:\Windows\System32 (which is known-good version) into the folder C:\Program Files\Common Files\Business Objects\3.0\bin (where most of the Crystal components are installed). I then ran a crdeploy.reg file that was already present in in the bin folder: this file adds a HKEY_LOCAL_MACHINE\SOFTWARE\Business Objects\Suite 11.0\Crystal Reports key to the Registry and sets the value CommonFiles to C:\Program Files\Common Files\Business Objects\3.0\bin.
Since I couldn't connect to the customer's machine earlier today, I did some more testing of the issue on a Windows 7 virtual machine. Like I mentioned in one of my edits, on this computer Crystal Reports never looked in the C:\Program Files\Common Files\Business Objects\3.0\bin directory for usp10.dll, so it would immediately try to load the copy in the C:\Program Files\Common Files\Microsoft Shared\Office10 folder.
It turns out the when Crystal Reports calls LoadLibrary, it checks the following folders for usp10.dll:
If HKEY_LOCAL_MACHINE\SOFTWARE\Business Objects\Suite 11.0\Crystal Reports\CommonFiles is present in the Registry, it calls LoadLibrary using that path.
If the registry key is not present, or usp10.dll doesn't exist in that folder, Crystal Reports will call LoadLibrary with C:\Program Files\Common Files\Microsoft Shared\Office10\usp10.dll as the path.
If the file isn't found in the Office10 folder, it passes just the filename (usp10.dll) to LoadLibrary, which then causes Windows to load the copy in System32.
So, on my test Windows 7 machine, I didn't have the CommonFiles registry key set, so Crystal Reports always loaded the version of usp10.dll that was in the Office10 folder, even after putting a copy of usp10.dll in C:\Program Files\Common Files\Business Objects\3.0\bin. Once I set the registry key to point to the right place, Crystal Reports loaded the correct version of the file.
On the customer's machine, the registry already had the CommonFiles path set to the right folder, but our application's setup program wasn't installing usp10.dll to that folder, so it was still picking up the copy in the Office10 folder.
The final workaround given to the customer was stupidly simple:
Copy the version of usp10.dll from the System32 into C:\Program Files\Common Files\Business Objects\3.0\bin.
Run the crdeploy.reg file in the bin folder to ensure that the CommonFiles registry key exists and is pointing to C:\Program Files\Common Files\Business Objects\3.0\bin.
I had originally thought putting a copy of usp10.dll into the bin folder would fix the problem on the customer's machines, but like I said, this didn't work on my Windows 7 test machine because I was missing the CommonFiles registry key, so I was hesitant to consider the issued fixed.
Also, in case it helps anyone else experiencing this problem, the versions of usp10.dll involved were:
1.405.2416.1: This is the version in the Office10 folder, and the one that causes Crystal Reports to crash. When you print a report, an access violation occurs when Crystal Reports calls one of the functions in usp10.dll (I don't have the original stacktrace, but I think it was the ScriptApplyDigitSubstitution function).
1.626.7600.16385: This is a known good version that works correctly with Crystal Reports. This version seems to be the one installed in Windows 7 by default.
There are other versions, such as installed by default in Windows XP in the System32 folder that also work fine with Crystal Reports.
I just had a similar issue on a TS running Server 2008 R2. Error from Event log:
Log Name: Application
Source: Application Error
Date: 5/23/2012 10:32:37 AM
Event ID: 1000
Task Category: (100)
Level: Error
Keywords: Classic
User: N/A
Computer:
Description:
Faulting application name: crw32.exe, version: 11.0.0.1282, time stamp: 0x422d5c77
Faulting module name: usp10.dll, version: 1.420.2600.5969, time stamp: 0x4bc88269
Exception code: 0xc0000005
Fault offset: 0x00014ee4
Faulting process id: 0x1744
Faulting application start time: 0x01cd38f8ce57fbd5
Faulting application path: C:\Program Files (x86)\Business Objects\Crystal Reports 11\crw32.exe
Faulting module path: C:\Program Files (x86)\Common Files\Microsoft Shared\Office10\usp10.dll
I tried copying usp10.dll from \Windows\System32 into C:\Program Files (x86)\Common Files\Business Objects\3.0\bin. Then ran the crdeploy.reg file but had to manually update the regkey to include (x86) due to 64bit OS on server. The Crystal Reports app still wouldn't recognize the DLL, it kept looking in the \Office10 folder. So I just renamed the copy of the DLL in that folder then copied from \System32 again. That worked like a charm, also the file versions on the DLL were exactly the same that Mike Spross posted.
It does not seem like a good idea to me to have extra copies that windows does not know about (How will it get updated?)
Why can't you call LoadLibrary("usp10.dll") yourself as the first thing you do at startup?

Where to install shared DLLs on Windows

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.

Including MS C++ runtime in VS2005 generated MSI

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...

what is the diff between dependencies and manually add a dll/ocx in vs installer 6?

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.

Resources