Home
  · Order
  · Resellers
  · Contact us
  · Web tips
  · About
Shareware
  · PMVR
  · SlideShow
  · GoRound
Java Tools
  · JexePack
  · Jobfuscate
  · MakeInstall
Affordware
  · PhotoFinder
  · PrintEnvelope
  · WinOpen
  · Label
Java Applets
  · Reference
  · Scripting
  · ControlPad
Learning + Fun
  · NX 101
  · Pano Help
  · Bug Free C
  · Space Rocks
 
DuckwareQuality by Design
 You are here: Duckware » Technology Ramblings » Java 6 and msvcr71.dll   Contact us  
Java 6 and msvcr71.dll

Java 6 Missing msvcr71.dll problem: Duckware produces a Java EXE packager, JexePack, and after Java 6 was released I started to get complaints from customers that generated EXE's were reporting that msvcr71.dll was not found:
A quick search of Google turned up this relevant content:
  • Sun's Java 6 web notes which states "SE 6 applications that use custom launchers must be installed with msvcr71.dll in the same directory as the launcher executable"
  • Java Bug #6509291 - "Launching java using the jvm.dll no longer works without msvcr71.dll in the system path"
Sun's advice: Is Sun right? Must an EXE that launches the JVM include msvcr71.dll in the EXE directory? Sun could have statically linked to the C runtime and totally eliminated the the requirement for msvcr71.dll, but Sun chose not to. Sun could have created a stub JVM loader DLL, which loads needed DLLs like msvcr71.dll and calls the real Java VM, but Sun chose not to. Instead of fixing the problem once for all Java developers world wide, Sun decided to push the problem out to be fixed by all Java developers. Typical Sun attitude that I have seen first hand for over 8 years.

Worse yet: Sun places a java.exe into the Windows system32 folder. So Sun should be following its own advice and place a msvcr71.dll next to java.exe, right? No, they don't. So, when java.exe is run from there, it will fail, right? No, it works. So what is going on? Clearly Sun's java.exe is not following their own advice. Even stranger still is that when there IS a msvcr71.dll right next to java.exe in the system32 folder, it is not used. The msvcr71.dll in the Java installation bin folder is used instead. That seems to violate how LoadLibrary() works. There are many clues that point to the fact that just BEFORE a LoadLibrary("<path>\jvm.dll") that Sun's java.exe is performing a LoadLibrary("<path>\jvm.dll\..\..\msvcrt71.dll"). I can understand why Sun does not publish this fact. It is pretty hard core to preload a DLL by specific name because that will break in the future. Sun uses it because they assume they can keep the java.exe in the system32 folder in sync with the version of Java that is installed on the computer.

The bottom line: Sun's points to a Microsoft article for the reason why they are telling us to copy msvcr71.dll into the same directory as the EXE. That advice is not very good, and certainly is not 'future proof'. EXE's are breaking now. Sun's fix is to copy msvcr71.dll next to the EXE (which Sun does not do for their java.exe). But in the future, when Sun moves on to another msvcr##.dll version, your EXE will still work, right? NO. Sun has learned nothing from this experience because they are recommending a course of action where they know that EXE's will once again break in the future.

The Issue: We want LoadLibrary() on the JVM to work on the Java 6 VM without moving msvcr71.dll next to the application EXE. Can that be done? After all, msvcr71.dll is needed by the Java VM, not the EXE. Under Windows, you can use LoadLibrary() to load the Java VM. But how do you force msvcr71.dll, located in the Java bin folder, to be found and used before any other msvcr71.dll on the system? Finding another msvcr71.dll on the computer (like windows system32) is very likely just fine, but we want to be 100% safe and use the one in the Java installation folder.

Strange enough, on all of my XP and Vista machines, there in the Windows System32 folder is msvcr71.dll. How did it get there? On one of the XP machines, I renamed msvcr71.dll, restarted Windows, and upon startup, an Adobe component complained about msvcr71.dll not being found. I then tried to run Adobe Reader, and it reinstalled itself on the fly, recovering from the 'lost' DLL.
DLL directory search order: When LoadLibary is used, the directory search order is (reference):
  1. The application (EXE) directory or LoadLibraryEx() alternate order
  2. SetDllDirectory()¹ or if NULL and SafeDllSearchMode² is OFF the GetCurrentDirectory()
  3. GetSystemDirectory() folder (eg: C:\Windows\System32)
  4. The 16-bit system directory (eg: c:\Windows\System)
  5. GetWindowsDirectory() folder (eg: C:\Windows)
  6. If SafeDllSearchMode² is ON, GetCurrentDirectory()
  7. Directories in the PATH environment variable
¹SetDllDirectory is new to Windows XP SP1 and Windows Server 2003
²SafeDllSearchMode is ON by default on Windows XP SP2, Server 2003, Vista
One Possible Solution: We can easily modify the PATH to include the Java bin folder via GetEnvironmentVariable() and SetEnvironmentVariable() before calling LoadLibrary(). It works! But, what if there is a msvcr71.dll in the Windows system32 folder? It would be found and used first. Technically, we need to force the msvcr71.dll located in the Java bin folder to be found first and used.

Strategy: As can be seen from the first search step above, if all of Sun's Java DLL's were in the Java bin folder, the best option would have been to simply use LoadLibraryEx() with the alternate search strategy. But this will not work since the JVM.DLL is in a 'client' or 'server' sub-folder of the Java 'bin' folder. That leaves the second search step above and SetDllDirectory(). But since SetDllDirectory() is a new Windows function, we also need the backup method of GetCurrentDirectory() to work on older Windows computers. So...

The Final Solution: The final solution, which will work work no matter what DLL dependencies Sun adds to the Java VM in the future, provided Sun does not change the 'bin' folder layout is:
  1. Call SetCurrentDirectory() and SetDllDirectory() to the Java bin folder
  2. Call LoadLibrary() on the full path to the jvm.dll
  3. Call SetCurrentDirectory(old-dir) and SetDllDirectory(NULL)
If there is a msvcr71.dll in the Java bin folder, it will be found and used first. Otherwise, if there is one in the windows system32 folder, it will be found and used. Note that SetDllDirectory() only exists on XP SP1 (and later), so dynamically bind to the function (and use only if found) for compatibility on older versions of Windows.
// Dynamic binding to SetDllDirectory()
typedef BOOL (WINAPI *LPFNSDD)(LPCTSTR lpPathname);
HINSTANCE hKernel32 = GetModuleHandle("kernel32");
LPFNSDD lpfn = (LPFNSDD)GetProcAddress(hKernel32, "SetDllDirectoryA");
Please note that this solution relies upon Sun properly placing any DLL's that they depend upon into the 'Java installation bin folder'. If Sun changes the folder layout, they will obviously break things once again. Since the 'bin folder' layout with client/server/hotspot sub folders applies to Java 1.3, 1.4, 1.5, and now Java 1.6 hopefully common sense will prevail and Sun will continue to keep the layout the same and all dependent DLL's in the 'bin' folder.

Sun, are you listening?


Copyright © 2000-2008 Duckware