The J/Direct Message Box example didn't mention a subtle but important fact: USER32 does not export a function named MessageBox. Because the MessageBox function takes a String, it deals with Strings like all other Win32 functions do: by calling either the ANSI version or the Unicode version (named MessageBoxA and MessageBoxW, respectively). When you call MessageBox in C or C++, you actually are calling a macro that expands to either MessageBoxA or MessageBoxW, depending on whether the Unicode macro is defined.
By excluding or including modifiers to @dll.import, call the ANSI, Unicode, or optimal version of a DLL function.
The com.ms.dll package includes several classes (especially DllLib) that contain useful methods for extracting strings from native memory blocks, mapping raw pointers onto @dll.struct classes, copying bytes between various types, and other tasks.
By default, the Microsoft VM assumes that the ANSI version of MessageBox is the one needed. If you import the MessageBox function using @dll.import without a modifier as follows:
/** @dll.import("USER32") */ static native int MessageBox(int hwnd, String text, String title, int style);
The Microsoft VM goes through the following steps.
If you want to call the Unicode version of MessageBox, use the unicode modifier with the @dll.import directive:
/** @dll.import("USER32",unicode) */ static native int MessageBox(int hwnd, String text, String title, int style);
Because the unicode modifier is present, the Microsoft VM will go through the following steps.
You might not always know in advance whether the ANSI or Unicode version is the best in a particular situation. Both have advantages and disadvantages. The default ANSI mode allows your code to run on any Win32 platform, but this causes unnecessary performance penalties on fully Unicode systems such as Microsoft® Windows NT®. The unicode modifier removes the performance penalty, but this restricts you to running on systems that implement the Unicode API.
The auto modifier lets the Microsoft VM decide which version of a DLL function is optimal based on the host operating system. The following example shows how to call the optimal version of the MessageBox function.
/** @dll.import("USER32",auto) */ static native int MessageBox(int hwnd, String text, String title, int style);
When the auto modifier is present, the Microsoft VM determines at runtime whether the underlying platform supports the Unicode APIs. If Unicode is supported, the Microsoft VM acts as if the unicode modifier had been specified. Otherwise, the Microsoft VM behaves as if the ansi modifier had been specified. Thus, the auto modifier allows you to generate a single binary that runs well on both ANSI and Unicode Windows systems using the optimal API set available on the particular platform.
You can programmatically learn whether the auto modifier will select Unicode or ANSI on a particular platform by inspecting the system class com.ms.dll.DllLib. This class has a public integer field named systemDefaultCharSize. Its value is set to 1 (for ANSI) or 2 (for Unicode).
In general, the auto modifier should be used whenever you call Windows API functions. If you are calling your own DLLs, select either ansi (the default) or unicode depending on your needs.
The following shows how the Microsoft VM decides whether to use ANSI or Unicode when you use the auto modifier.
2 - ANSI: Always uses the ANSI version.
3 - Unicode: Always uses the Unicode version.
4 - Platform: Uses ANSI or Unicode depending on the platform.
It is not necessary to set the DllImportDefaultType registry key yourself. That key's main purpose is to allow the installation program to set the appropriate choice on future Windows platforms. You can programmatically query the preferred mode on your platform by reading the com.ms.dll.DllLib.systemDefaultCharSize field. This field will be set to 1 on ANSI systems, 2 on Unicode systems.
The ansi, unicode, and auto modifiers can also be used with the @dll.struct directive.