Craig Ringer
Craig Ringer

Reputation: 324375

JNA throws java.lang.UnsatisfiedLinkError for a Windows API function in the correct DLL with the correct name

JNA is throwing:

java.lang.UnsatisfiedLinkError: Error looking up function 'DsMakeSpn': The specified procedure could not be found

for a mapping where I've verified that DsMakeSpn exists in ntdsapi.dll according to MSDN and I'm on Windows Server 2008, so the function is available. JNA loads ntdsapi.dll without error.

I've extended StdCallLibrary since it's a WINAPI function; it isn't a linkage issue.

This makes very little sense.

The code with javadoc trimmed for brevity:

import com.sun.jna.LastErrorException;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.PointerByReference;
import com.sun.jna.win32.StdCallLibrary;

interface NTDSAPI extends StdCallLibrary {

    NTDSAPI instance = (NTDSAPI)
            Native.loadLibrary("NTDSAPI", NTDSAPI.class);

    int DsMakeSpn(
            String serviceClass, /* in */
            String serviceName, /* in */
            String instanceName, /* in, optional, may be null */
            short instancePort, /* in */
            String referrer, /* in, optional, may be null */
            IntByReference spnLength, /* in: length of buffer spn; out: chars written */
            byte[] spn /* out string */
            )
        throws LastErrorException;

    public final int 
        ERROR_SUCCESS = 0,
        ERROR_INVALID_PARAMETER = 87,
        ERROR_BUFFER_OVERFLOW = 111;

}

Upvotes: 0

Views: 404

Answers (1)

Craig Ringer
Craig Ringer

Reputation: 324375

The issue is that ntdsapi.dll actually exposes two variants of DsMakeSpn, as shown by Dependency Walker:

screenshot from dependency walker

There's an ANSI and a Wide (unicode) variant.

MSVC will resolve these automatically. JNA won't. So you need to explicitly declare your mapping, declaring DsMakeSpnW and using WStrings. e.g.:

    int DsMakeSpnW(
            WString serviceClass, /* in */
            WString serviceName, /* in */
            WString instanceName, /* in, optional, may be null */
            short instancePort, /* in */
            WString referrer, /* in, optional, may be null */
            IntByReference spnLength, /* in: length of buffer spn; out: chars written */
            char[] spn /* out string */
            )
        throws LastErrorException;

Note the change of buffer from byte[] to char[] for unicode calls.

See https://github.com/twall/jna/issues/377 for issue report.

If you want to expose both variants you can use the W32APIFunctionMapper.

Upvotes: 1

Related Questions