0

I have a c++ dll library with header files provided, without implementation. And I implement JNA call for this library functions. And I have the problem with only 1 function (other, even similar works fine). This is declaration from .h file:

int CALLINGCONV SMIMESignML(
  const char* pin,
  unsigned long slot,
  const char* szOutputFilePath,
  const char* szFrom,
  const char* szTo,
  const char* szSubject,
  const char* szOtherHeaders,
  const char* szBody,
  const char* szAttachments,
  unsigned long dwFlags,
  int bInitialize
);

Java code:

public interface Dll extends StdCallLibrary {
  public String JNA_LIBRARY_NAME = "libname.dll";
  int SMIMESignML(String pPin, int slot, String pOut, String pFrom, String pTo,
    String pSubject, String pHeaders, String pBody, String pAttachments, int flags,
    int init);
}

public class Test {
  private static final Dll dll = (Dll) Native.loadLibrary(Dll.JNA_LIBRARY_NAME, Dll.class, W32APIOptions.ASCII_OPTIONS);

  public static void main(String[] args) {
    String pOut = "";
    String pFrom = "";
    String pTo = "";
    String pBody = "";
    String pAttachments = "";

    int code = dll.SMIMESignML(null, 0, pOut, pFrom, pTo, null, null, pBody, pAttachments, 0, 0);
    System.out.println(code);
  }
}

The function should return different int error codes, but it always return code 0xFFFF.

I can check it with the same code in Pascal:

unit dll;
interface
const
  JNA_LIBRARY_NAME = 'libname.dll';

function SMIMESignML(pPin: PChar; slot: integer; pOut: PChar; pFrom: PChar; pTo: PChar;
  pSubject: PChar; pHeaders: PChar; pBody: PChar; pAttachments: PChar; flags: integer;
  init: integer): integer; stdcall; external JNA_LIBRARY_NAME;
implementation
end.

program Hello;
uses dll;
var 
  code: integer;
begin
  code := SMIMESignML(nil, 0, '', '', '', nil, nil, '' , '', 0, 0);
  writeln(code);
end.

Pascal code returns 2, Java code return 65535. Moreover, Pascal std calls work right, changing arguments we get different error codes (0=OK and others), but Java with the same arguments is not working, it always returns 0xFFFF. How can I debug it to understand the problem?

P.S. Moreover, in the same library I has this function and it works from JNA without any problems:

int CALLINGCONV PKCS7SignML(
  const char *pin,
  unsigned long slot,
  const char* szInputFileName,
  const char* szOutputFileName,
  int bInitialize);

The OS is Win8 x64, JavaOracle7x86, library is x32. "unsigned long" should not be the problem, as it should be 4 bytes on windows.

What am I doing wrong, if the same STD call returns different results in this two examples? And How can I debug it?

  • I'm not sure this would affect it but I believe int on 64bit would actually be 8 bytes. int32_t would guarantee 4 bytes. – Richard Jul 16 '15 at 07:55
  • Could the C function be returning -1? – Richard Jul 16 '15 at 07:56
  • C function seems to return only positive numbers, 0 - is SUCCESS, > 0 some error code, 0xFFFF - Unknown Error. – Dmitrii Stebliuk Jul 16 '15 at 07:58
  • if I provide Java long for "unsigned long" - I get memory error. The library is x32 bit, and it seems like "unsigned long" is 4 bytes. I tried NativeLong instead of Java int, but the result is the same as with "int". – Dmitrii Stebliuk Jul 16 '15 at 07:59
  • Please note that this is C, not C++ – technomage Jul 16 '15 at 13:00
  • Use String directly rather than futzing about with Memory and buffers, JNA will do the translation for you. – technomage Jul 16 '15 at 13:05
  • Thank you, I will try use String, it can simplify code, but I am not sure this is the problem. Because I tried to load and call this from C++, and get the same problem as in JNA - the function always returns 0xFFFF and is not working. I tried to wrap working Pascal code with own DLL without parameters, and when I use it with JNA it's not working... (but still working in Pascal)... – Dmitrii Stebliuk Jul 16 '15 at 13:19
  • No, String usage is _not_ the cause. What may me different is that pascal is promoting the return value differently. It looks like a 16-bit -1 value, which may be a perfectly valid return code. – technomage Jul 16 '15 at 13:30
  • @Richard native long is 32 bits on 32- and 64-bit OSes. Most _other_ OSes map native long to the size of a pointer. – technomage Jul 16 '15 at 15:46
  • If the call from C returns the same value, then there is no issue with JNA, since they use the same mechanism to make calls. – technomage Jul 16 '15 at 15:49
  • @technomage Yes. This function reads key from smartcard, creates file, and sign it with the key. Pascal code with other attributes returns code 0=OK, and the file is created. JNA and C code always returns 0xFFFF, and nothings happens. In this simplest example Pascal returns 2=Smart Card is not initialized. So this is the problem: the same stdlib with the same parameters behaves differently in Java and Pascal. – Dmitrii Stebliuk Jul 16 '15 at 16:17
  • Are your inputs identical in the Java/C and Pascal cases? – technomage Jul 16 '15 at 16:21
  • @technomage Yes, of course. It looks like in Java/C case code is not running, like some exception is throwing in the most beginning, and unknown error code is returning... – Dmitrii Stebliuk Jul 16 '15 at 16:27
  • @technomage And the problem is not in parameters, because I created dll in Pascal without any input parameters, that call this function with hardcoded values. When I call the new function without parameters from JNA, it returns me the same 0xFFFF and nothing happens. If I do it from Pascal, it returns 0=Ok and creates signed file... – Dmitrii Stebliuk Jul 16 '15 at 16:36
  • What error code do you get when you call via JNA with _real_ parameters? Obviously you had to at least give your call from pascal a valid filename, which you're not doing in the JNA call. – technomage Jul 16 '15 at 16:39
  • @technomage For example: these parameters are valid "('12345678', 0, 'C:\myfolder\email.eml', '', '', nil, nil, '' , '', 0, 1)", and it returns 65536 in JNA and 0=Ok in Pascal (and calling from pascal file email.eml is created). – Dmitrii Stebliuk Jul 16 '15 at 17:10
  • @technomage Last parameter means "auto initialize smartcard", in question example it is 0, so we get error_code=2(NOT_INITED). If we provide 1 for it, without providing pin (first parameter), Pascal code throws memory error, whilest Java code runs without error and just returns 65535 as always. – Dmitrii Stebliuk Jul 16 '15 at 17:12
  • Perhaps there's some [auto-initialization code](http://stackoverflow.com/questions/4618650/delphi-unit-initialization-not-always-called) for the library that only gets invoked when loaded from a Pascal context? Use [Dependency Walker](http://dependencywalker.com) to see if there are some other exported init/deinit methods. – technomage Jul 16 '15 at 19:40
  • @technomage offtop: I tried using String instead of Pointer for PIN field, PIN length is 8, Pointer is created with length 10, and after this change function always returns me error code "wrong PIN". With Pointer it is working. So I think I can't use Strings instead of Pointers. – Dmitrii Stebliuk Jul 17 '15 at 08:44
  • That's because you're using `W32API.DEFAULT_OPTIONS`, which uses wide (unicode) strings (`wchar_t*` in the native). You need to use the `ASCII_OPTIONS` instead. – technomage Jul 17 '15 at 11:21
  • @technomage It works, thank you! – Dmitrii Stebliuk Jul 17 '15 at 12:21
  • I just realized that incorrect string mapping would also affect the data the DLL sees, which might cause a different error code. Did `ASCII_OPTIONS` fix your other issue? That wouldn't explain why `C` access fails, though. – technomage Jul 17 '15 at 13:47
  • @technomage Unfortunately nope – Dmitrii Stebliuk Jul 17 '15 at 15:13

0 Answers0