Convert Java->Native DLL call to C#

R

Richard A. Lowe

Hi all (sorry I haven't been around lately for those who know me, life
happens :)

I have to call a native DLL (written > 5 years ago, not by me, and all
source lost) that is currently being called from a Java application also
written about 5 years ago (I think Borland JBuilder 4 was the IDE - Java 1.2
perhaps?). The Java declaration looks like this:

public static native int EncryptStuff(String publicKeyFile, String data,
int dataLength, String encryptedFilePath) throws Exception; {
try { }
catch (Exception excp) {
System.out.println(excp.toString());
}
}

It encrypts a string when passed the public key and the length of the string
and writes it to the encryptedFilePath. I found a signature that can be
successfully called (returns code 0), but it does not produce the same
output file when given the *exact same input data*:

[DllImport("Crypt.dll")]
public static extern int EncryptStuff(
[MarshalAs(UnmanagedType.AnsiBStr)] string publicKeyFile,
[MarshalAs(UnmanagedType.AnsiBStr)] string data,
int dataLength,
[MarshalAs(UnmanagedType.AnsiBStr)] string encryptedFilePath);

I think all other UnmanagedType options on the string parameters cause an
error return code. I do not know how Java marshals its parameters by
default - how can I declare my external function to match the Java one, so I
can produce the same output? What other directions could I take in
approaching this problem? I do not have a debuggable version of the Java
app, but I do have the source files of the public key, data and the output
encrypted file I am trying to create. You help is humbly requested and
greatly needed!

Thanks,
Richard
 
C

Chris R. Timmons

Hi all (sorry I haven't been around lately for those who know
me, life happens :)

I have to call a native DLL (written > 5 years ago, not by me,
and all source lost) that is currently being called from a Java
application also written about 5 years ago (I think Borland
JBuilder 4 was the IDE - Java 1.2 perhaps?). The Java
declaration looks like this:

public static native int EncryptStuff(String publicKeyFile,
String data,
int dataLength, String encryptedFilePath) throws Exception;
{
try { }
catch (Exception excp) {
System.out.println(excp.toString());
}
}

It encrypts a string when passed the public key and the length
of the string and writes it to the encryptedFilePath. I found a
signature that can be successfully called (returns code 0), but
it does not produce the same output file when given the *exact
same input data*:

[DllImport("Crypt.dll")]
public static extern int EncryptStuff(
[MarshalAs(UnmanagedType.AnsiBStr)] string publicKeyFile,
[MarshalAs(UnmanagedType.AnsiBStr)] string data,
int dataLength,
[MarshalAs(UnmanagedType.AnsiBStr)] string
encryptedFilePath);

I think all other UnmanagedType options on the string parameters
cause an error return code. I do not know how Java marshals its
parameters by default - how can I declare my external function
to match the Java one, so I can produce the same output? What
other directions could I take in approaching this problem? I do
not have a debuggable version of the Java app, but I do have the
source files of the public key, data and the output encrypted
file I am trying to create. You help is humbly requested and
greatly needed!

Thanks,
Richard

Richard,

Even though the source for the DLL has been lost, do you know what
language it was written in? If it was C or C++, then you will need
to specify the cdecl calling convention in the DllImport attribute.
(DllImportAttribute.CallingConvention defaults to StdCall).

Also, I have the best luck with string parameters by not specifying a
MarshalAs attribute. The P/Invoke marshaller is pretty good at
guessing what needs to be done.

In short, I would try this:

[DllImport("Crypt.dll"
CallingConvention = CallingConvention.Cdecl)]
public static extern int EncryptStuff(
string publicKeyFile,
string data,
int dataLength,
string encryptedFilePath);
 
A

arixto

You might have some luck using javaH on the class file. This will
regenerated the C stub. You will then have all the call signatures
to the underlying native code. I am not sure, but I don't belive you
need the java source to run the javah tool, it uses the class file
directly (saves on parsing!)

Depending on how the native code was written, you have have to create
a dummy jenv* class that will handle the creating of strings and
accessing other java elements.

Hope this helps.
 
R

Richard A. Lowe

Thanks Chris, it's nice to not have to use the MarshalAs attributes - you
were right that they were unnecessary (and I'm not certain how I got
convinced they were necessary).

My output still differs from the Java one, but with your suggestion I tried
a number of different attribute cominations that has me convinced that what
I expected to get - a byte-for-byte idential output file - might not be a
reasonable expectation due to minor diffences in the input, not in the
marshaling, which does appear to be working.

Richard

--
C#, .NET and Complex Adaptive Systems:
http://blogs.geekdojo.net/Richard
Chris R. Timmons said:
Hi all (sorry I haven't been around lately for those who know
me, life happens :)

I have to call a native DLL (written > 5 years ago, not by me,
and all source lost) that is currently being called from a Java
application also written about 5 years ago (I think Borland
JBuilder 4 was the IDE - Java 1.2 perhaps?). The Java
declaration looks like this:

public static native int EncryptStuff(String publicKeyFile,
String data,
int dataLength, String encryptedFilePath) throws Exception;
{
try { }
catch (Exception excp) {
System.out.println(excp.toString());
}
}

It encrypts a string when passed the public key and the length
of the string and writes it to the encryptedFilePath. I found a
signature that can be successfully called (returns code 0), but
it does not produce the same output file when given the *exact
same input data*:

[DllImport("Crypt.dll")]
public static extern int EncryptStuff(
[MarshalAs(UnmanagedType.AnsiBStr)] string publicKeyFile,
[MarshalAs(UnmanagedType.AnsiBStr)] string data,
int dataLength,
[MarshalAs(UnmanagedType.AnsiBStr)] string
encryptedFilePath);

I think all other UnmanagedType options on the string parameters
cause an error return code. I do not know how Java marshals its
parameters by default - how can I declare my external function
to match the Java one, so I can produce the same output? What
other directions could I take in approaching this problem? I do
not have a debuggable version of the Java app, but I do have the
source files of the public key, data and the output encrypted
file I am trying to create. You help is humbly requested and
greatly needed!

Thanks,
Richard

Richard,

Even though the source for the DLL has been lost, do you know what
language it was written in? If it was C or C++, then you will need
to specify the cdecl calling convention in the DllImport attribute.
(DllImportAttribute.CallingConvention defaults to StdCall).

Also, I have the best luck with string parameters by not specifying a
MarshalAs attribute. The P/Invoke marshaller is pretty good at
guessing what needs to be done.

In short, I would try this:

[DllImport("Crypt.dll"
CallingConvention = CallingConvention.Cdecl)]
public static extern int EncryptStuff(
string publicKeyFile,
string data,
int dataLength,
string encryptedFilePath);
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top