Calling Win32 API Method from Java

Calling Win32 API method from Java

  1. JNA seems the industry standard of what you want, "provides Java programs easy access to native shared libraries (DLLs on Windows) without writing anything but Java code—no JNI or native code is required"

  2. There is also Java Foreign Function Interface -
    example usage

    If is ok for you, you could embed the JRuby interpreter and call winapi via jruby-ffi wich is a lot easier, see here, here, and here

Accessing Windows API from a Java application - JNI or JNA?

For general-purpose invocation of native code, JNA tends to be much easier, because you don't have to write a C/C++ stub.

However, it's not always possible to do what you need via JNA. Let me explain why:

I think that for what you want to do, JNI is going to be required.
The issue is that SetWindowsHookEx takes parameters including a pointer to the hook procedure and a handle to the DLL that contains the hook procedure. Windows will be using that info to invoke the hook procedure. As you might imagine, Windows is not going to be able call directly into a method of an object in the JVM.

So, I believe that you're going to have to use JNI to write a dll that will sit between your java app and the Windows API. That dll will contain the actual hook process, and will invoke SetWindowsHookEx for you. The dll's hook process can then use JNI to invoke your java object.

Using winapi in java application

You need to create a wrapper that will call those functions in the User32 library. Don't call them directly. Take a look at this tutorial http://www.ibm.com/developerworks/java/tutorials/j-jni/.

There are more steps involved then simply loading the library and called the function. Also must note that if you do this, you remove one of the best things of Java. Being able to write once run anywhere. You will be tethered to Windows. If this isnt a problem for you, then no big deal. Are you sure this isnt something you can't do from Java directly. JNI should really be a last resort.

Also, from my experience with JNI, it can lead to unstable applications if not used carefully.

JNA call Win32 API method IShellFolder::GetUIObjectOf

When you get an Invalid Memory Access error, it's a clue that you need to properly allocate Native memory. Your code above only declares a Java-side Pointer array.

Arrays in C use contiguous memory. This means you must allocate a single block of native memory large enough for the array; it is not enough to collect a bunch of individual allocations (which is what declaring a single Pointer variable in Java does).

You have two primary options for allocating this block of native memory:

Option 1. Use JNA's Memory class to explicitly allocate the size of memory you will need. If you allocating an array of Pointers, you will allocate like this: Memory m = new Memory(numberOfElements * Native.POINTER_SIZE); When you get the returned value into this memory you will use offsets to pull the appropriate pointer from the array, e.g., for the 0-indexed ith pointer, do Pointer p = m.getPointer(i * Native.POINTER_SIZE);

Option 2. Create a Structure of the appropriate size (in this case, containing a single element which is a Pointer) and use Structure.toArray() to allocate the Structure array. So you could define:

    @FieldOrder ({"childId"})
class PCUITEMID_CHILD extends Structure {
public Pointer childId;
}

And then allocate the array

PCUITEM_CHILD[] pcuItemIdArray = new PCUITEMID_CHILD().toArray(numberOfElements);

Then you can pass this array variable, and access its result using traditional array syntax.

Pointer p = pcuItemIdArray[0].childId;

Is there a Java library to access the native Windows API?

You could try these two, I have seen success with both.

http://jawinproject.sourceforge.net

The Java/Win32 integration project
(Jawin) is a free, open source
architecture for interoperation
between Java and components exposed
through Microsoft's Component Object
Model (COM) or through Win32 Dynamic
Link Libraries (DLLs).

https://github.com/twall/jna/

JNA provides Java programs easy access
to native shared libraries (DLLs on
Windows) without writing anything but
Java code—no JNI or native code is
required. This functionality is
comparable to Windows' Platform/Invoke
and Python's ctypes. Access is dynamic
at runtime without code generation.

JNA allows you to call directly into
native functions using natural Java
method invocation. The Java call looks
just like it does in native code. Most
calls require no special handling or
configuration; no boilerplate or
generated code is required.

Also read up here:

http://en.wikipedia.org/wiki/Java_Native_Interface

The Java Native Interface (JNI) is a
programming framework that allows Java
code running in a Java Virtual Machine
(JVM) to call and to be called1 by
native applications (programs specific
to a hardware and operating system
platform) and libraries written in
other languages, such as C, C++ and
assembly.

http://en.wikipedia.org/wiki/Java_Native_Access

Java Native Access provides Java
programs easy access to native shared
libraries without using the Java
Native Interface. JNA's design aims to
provide native access in a natural way
with a minimum of effort. No
boilerplate or generated glue code is
required.

How to display message using WTSSendMessage?

According to the link you provided, a service can

Display a dialog box in the user's session using the WTSSendMessage function.

JNA is comprised of the base functionality in the jna artifact and user-contributed mappings in the jna-platform artifact. While the Wtsapi32 class exists in JNA, only some of that dll's functions have been mapped, but not WTSSendMessage.

I note you linked the docs to the -A suffixed version: this is the "ANSI" mapping that does not apply to any modern version of windows. If you map the un-suffixed version using the WinAPI default type mapper, it will automatically choose the correct -A or -W suffixed version (the difference is that -W uses UTF16 wide strings while -A uses 8-bit ASCII). But for your convenience you can just map the -W version, WTSSendMessageW.

Looking down the list of arguments, you need:

  • A HANDLE obtained from WTSOpenServer
  • The session to send to (you can use the current session)
  • A title bar string you can create
  • A message you can create
  • A style (you can just use the "OK" version)
  • A timeout
  • A pointer to receive the response value

For the server handle, the docs for WTSOpenServer state

You do not need to open a handle for operations performed on the RD Session Host server on which your application is running. Use the constant WTS_CURRENT_SERVER_HANDLE instead.

This is already mapped in JNA (it's a HANDLE wrapping null).

So you just need to map the WTSSendMessage function. The type mappings are straightforward. HANDLE and LPWSTR are mapped in JNA, and you should use int for the DWORD args and boolean for BOOL. You'll use an interface, and extend the existing JNA mapping to obtain access to its functions:

public interface MyWtsapi32 extends com.sun.jna.platform.win32.Wtsapi32 {
// Your own instance to access your functions
MyWtsapi32 INSTANCE = Native.load("Wtsapi32", Wtsapi32.class, W32APIOptions.DEFAULT_OPTIONS);

// From https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messagebox
int MB_OK = 0;

// The function to send the message
boolean WTSSendMessageW(HANDLE hServer, int SessionId,
LPWSTR pTitle, int TitleLength,
LPWSTR pMessage, int MessageLength,
int Style, int Timeout, IntByReference pResponse, boolean bWait);
}

Then use the functions. We can use the current server handle, the current session, create our strings to pass, use the "OK" style, and ignore the timeout/response by passing false as the wait parameter.

LPWSTR pTitle = new LPWSTR("Message box title");
int titleLength = ("Message box title".length() + 1) * Native.WCHAR_SIZE;
LPWSTR pMessage = new LPWSTR("Hello World!");
int messageLength = ("Hello World!".length() + 1) * Native.WCHAR_SIZE;
IntByReference pResponse = new IntByReference();

MyWtsapi32.INSTANCE.WTSSendMessageW(
WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION,
pTitle, titleLength,
pMessage, messageLength,
MB_OK, 0, pResponse, false);
// should return IDASYNC in pResponse.getValue()

This is all untested. You'll need appropriate imports.

Call methods from a very complicated C++ Win32 DLL with tons of classes by Java process via JNA

JNA only works with C functions, not C++. The only C++ functions you'll be able to map must have been externalized with extern "C". If they are not, and you are unable to change the DLL, you may have to write your own DLL wrapper which has extern "C" versions.

How to call with JNA such functions:

You must map them to a Java interface. For example:

public interface ComplicatedAndBigLibrary {
// Create an instance to access the mapped functions with
// the String in quotes is the filename, minus .dll
ComplicatedAndBigLibrary INSTANCE =
(ComplicatedAndBigLibrary) Native.load("compbiglib", W32APIOptions.DEFAULT_OPTIONS);

// Map the C structures or typedefs
// Use "extends" as needed for parents
@FieldOrder({"field1", "field2"})
class Dummy_State extends Structure {
// map structure fields here
public int field1;
public byte field2;
}

class Dummy_Handle extends WinNT.HANDLE {
// any overrides you need
}

// Map your functions (that were externalized)
boolean NiceFunction(
Dummy_State ModuleState, Dummy_Handle Handle, Dummy_Exception ExceptionPointer,
LPCTSTR name, DWORD timer);
}

Take a look at the JNA source code in the com.sun.jna.platform.win32 package for many types of examples based on Windows DLLs. You're essentially doing the same thing for your DLL.

Use those objects somehow direct in my java process

ComplicatedAndBigLibrary CABL = ComplicatedAndBigLibrary.INSTANCE;
CABL.NiceFunction(foo, bar, ...)

Also called two additional DLLs and widely used a data from them

You'll need to map the other DLL's similarly (create an interface, use Native.load() and map functions/constants/etc.)



Related Topics



Leave a reply



Submit