I have a Java web application myproject.war
deployed to JBoss. A portion of the application uses JNI to connect to a C++ DLL, which calls functions from a set of third-party libraries. We are migrating this application from a x32 server to a x64 server.
Prior Environment Build
- 32-bit Windows Server 2003
- JBoss 6.X
- Java 1.6.X
New Environment Build
- 64-bit Windows Server 2008 R2, SP1 (6.1.7601)
- JBoss AS 7.2.0 Final "Janus"
- Java Runtime 1.7.0_45-b18.
- Visual Studio 2010 Redistributable x64 installed
On the old system, the custom DLL and third-party libraries were unceremoniously dumped into C:\Windows\System32\
and the application was able to successfully connect to them via JNI. The third-party libraries include several DLLs, some ICC Profiles, and a Resource folder with sub-folders of files including True-type fonts, configurations and other files.
For the migration, a JBoss module was created to contain the JNI code. The Java / JNI code was moved to MyModule.jar
, and MyDriver.dll
was recompiled to x64. x64 versions of the third-party libraries were obtained.
I have
- recompiled
MyDriver.dll
for 64-bit using Visual Studio 2010 (10.0.40219.1 SP1Rel) - placed
MyDriver.dll
and 64-bit versions of the third-party DLLs and resource folder into the module folder..\main\lib\win-x86_64\
- copied the module files to a path under the
modules
folder - created
module.xml
- with the appropriate resource
MyModule.jar
.- which has class
MyDriverLoader
which loadsMyDriver.dll
.
- which has class
- with a reference to module
sun.jdk
which I am not 100% certain is needed for JNI.
- with the appropriate resource
The DLL is compiled with
- Use of MFC: Use Standard Windows Libraries
No matter what I do, when starting the application, JBoss throws the following Java Error:
java.lang.UnsatisfiedLinkError: D:\Jboss\jboss-7.2.0.Final\modules\com\mymodule\main\lib\win-x86_64\MyDriver.dll: Can't find dependent libraries
What this tells me is
- JBoss can detect the correct DLL from the module and therefore I've configured the module correctly.
- Some dependent library is not in the path of JBoss.
I have tried the following solutions, but none of them worked and the Error persists:
- I have installed Visual Studio 2010 Redistributable x64, which was probably already packaged in anyway.
- I have explicitly added
{JBOSS_HOME}\modules\com\mymodule\main\lib\win-x86_64
to Windows environment variablePATH
and confirmed this withecho %PATH%
which includes:D:\Java\jdk1.7.0_45\bin;D:\Jboss\jboss-7.2.0.Final\modules\com\mymodule\main\lib\win-x86_64;
. - I've run x64 Dependency Walker, which tells me
MSVCP100D.DLL
,MSVCR100D.DLL
andIESHIMS.DLL
are not found. I have found bothMSCV*.DLL
files in bothc:\Windows\System32
andC:\Windows\SysWOW64
folders, but they are different file sizes in each. Dependency Walker has detected the paths of other files to reside insystem32
, so I do not understand why it isn't finding theMSCV*.DLL
files. To test, I threw them into the same folder...\lib\win-x86_64
asMyDriver.dll
, but this changed nothing.
What can I do to resolve this?
module.xml
<module xmlns="urn:jboss:module:1.1" name="com.mymodule">
<main-class name="com.mymodule.DriverClassName"/>
<resources>
<resource-root path="MyModule.jar"/>
</resources>
<dependencies>
<module name="sun.jdk"/>
</dependencies>
</module>
MyDriverLoader.java
public class MyDriverLoader {
/**
* Load C++ Library
*/
static {
System.loadLibrary("MyDriver");
}
/**
* Native Method to return the version of the C++ DLL.
*/
public native static String getVersion();
/**
* Main method calls getVersion.
*
* @param args
*/
public static void main(String args[]) {
System.out.println("MyDriverLoader calling MyDriver.dll version " + getVersion());
}
}
jboss-deployment-structure
<jboss-deployment-structure>
<deployment>
<dependencies>
<module name="com.mymodule" />
</dependencies>
</deployment>
</jboss-deployment-structure>
folder structure of module mymodule
:
{JBOSS_HOME}\modules\com\mymodule\main
- MyModule.jar
- module.xml
- \lib\win-x86_64\
- MyDriver.dll
- ThirdPartyA.dll
- ThirdPartyB.dll
- ThirdPartyC.dll
- ThirdPartyD.dll
- \Resource\Data\Settings\
- foo.optionfile
- bar.optionfile
I figured it out, and here is how.
I first took the DLL out of JBoss and tried to access it directly from a call to a native method via JNI on the x64 dev/qa server. This failed with the same error. This meant it was not JBoss.
I stripped references to the third-party libraries from the DLL and tried to access it again. This also failed with the same error. This meant it was not the third-party libraries or a path issue with them.
I created a plain DLL which did nothing but spit out a string and tried to access it in the same way as the prior two times. It also failed. This meant it was not my code.
I had been compiling the DLL in VS 2010 as Debug. I recompiled the DLL as Release. This solved the issue.
I found a SO answer that helped that I cannot find again, otherwise I would link it.
As I now understand it, if you compile a DLL in Debug, it should not be redistributable. This was not the case with the x32 DLLs that I compiled in Debug and used on my x32 development servers, but was certainly the case with the complied x64 DLL. I compiled as Release and was able to use the DLL throughout my application.
I have changed the routine for building future development deployables.