在SWT Extension中,引入了Function這個類。基本上所有的Win32 JNI庫都有這個類,用來直接操縱Win32 的部分API。有了這個Class,我們不用編寫JNI,就可以實現(xiàn)某些簡單的,甚至是較復(fù)雜的Win32 API。這里我們就以EnumWindows這個API舉例,看看怎么Java來執(zhí)行這個Win32 API。
private static final String FUNTION_ENUMWINDOWS = "EnumWindows";
private static final String USER32_LIB = "user32";
private static List windowsList = new ArrayList();
public static int[] enumWindows()
{
windowsList.clear();
Callback callback = new Callback(Windows.class, "enumWindowsProc", 2);
int address = callback.getAddress();
if (address != 0)
{
try
{
Function function = new Function(USER32_LIB, FUNTION_ENUMWINDOWS);
function.invoke_I(address, 0);
function.close();
} catch (Exception e)
{
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
}
callback.dispose();
}
int[] handles = new int[windowsList.size()];
for (int i = 0; i < windowsList.size(); i++)
handles[i] = ((LONG) windowsList.get(i)).value;
return handles;
}
private static int enumWindowsProc(int hwnd, int lParam)
{
windowsList.add(new LONG(hwnd));
return 1;
}
EnumWindows是用來遍歷Windows窗口的API,它需要傳入一個返回boolean值的callback的地址作為參數(shù)。實際上在C里面,一個boolean值無非就是是否非0,如果為0,則為false,不為0,則為true。我們只需要new 一個function實例,傳入這個API所在的Lib和API名字,然后執(zhí)行invoke方法就OK了,在Function里面,可以最多執(zhí)行含有4個簡單類型參數(shù)的API。
讓我們再來看看FindWindowEx這個API,它需要傳入2個int變量和2個字符串指針,根據(jù)SWT的設(shè)計,我們是可以將Java的字符串轉(zhuǎn)換為指針的,因此通過Function我們也可以實現(xiàn)這個API:
private static final String FUNTION_FINDWINDOWEX = Extension.IsUnicode ? "FindWindowExW"
: "FindWindowExA";
private static final String USER32_LIB = "user32";
public static int findWindowEx(int parent, int hwndChildAfter, String className,
String windowName)
{
int result = 0;
int lpClassName = 0;
int lpWindowName = 0;
int hHeap = Extension.GetProcessHeap();
if (className != null)
{
TCHAR buffer = new TCHAR(0, className, true);
int byteCount = buffer.length() * TCHAR.sizeof;
lpClassName = Extension.HeapAlloc(hHeap, Extension.HEAP_ZERO_MEMORY, byteCount);
Extension.MoveMemory(lpClassName, buffer, byteCount);
}
if (windowName != null)
{
TCHAR buffer = new TCHAR(0, windowName, true);
int byteCount = buffer.length() * TCHAR.sizeof;
lpWindowName = Extension.HeapAlloc(hHeap, Extension.HEAP_ZERO_MEMORY, byteCount);
Extension.MoveMemory(lpWindowName, buffer, byteCount);
}
try
{
Function function = new Function(USER32_LIB, FUNTION_FINDWINDOWEX);
result = function.invoke_I(parent, hwndChildAfter, lpClassName, lpWindowName);
function.close();
} catch (Exception e)
{
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
}
if (lpClassName != 0) Extension.HeapFree(hHeap, 0, lpClassName);
if (lpWindowName != 0) Extension.HeapFree(hHeap, 0, lpWindowName);
return result;
}
其實像這種簡單參數(shù)類型的API,Win32 里還有很多,我們完全不必為其專門編寫JNI,只需使用熟悉的Java即可。雖然不是調(diào)用全部的API,但大部分常用的API都是沒有問題的,關(guān)鍵是如何靈活運用。現(xiàn)在的大型商業(yè)RCP應(yīng)用中,其實多多少少都參和了JNI,用于提升對用戶的友好性和軟件的執(zhí)行性能,畢竟Java天生就是客戶端開發(fā)的矮子。對于JNI,我們既不能一味排斥,也不能濫用,要把握一個平衡點,使之成為Java客戶端開發(fā)的利器。