在SWT Extension中,引入了Function這個(gè)類(lèi)。基本上所有的Win32 JNI庫(kù)都有這個(gè)類(lèi),用來(lái)直接操縱Win32 的部分API。有了這個(gè)Class,我們不用編寫(xiě)JNI,就可以實(shí)現(xiàn)某些簡(jiǎn)單的,甚至是較復(fù)雜的Win32 API。這里我們就以EnumWindows這個(gè)API舉例,看看怎么Java來(lái)執(zhí)行這個(gè)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是用來(lái)遍歷Windows窗口的API,它需要傳入一個(gè)返回boolean值的callback的地址作為參數(shù)。實(shí)際上在C里面,一個(gè)boolean值無(wú)非就是是否非0,如果為0,則為false,不為0,則為true。我們只需要new 一個(gè)function實(shí)例,傳入這個(gè)API所在的Lib和API名字,然后執(zhí)行invoke方法就OK了,在Function里面,可以最多執(zhí)行含有4個(gè)簡(jiǎn)單類(lèi)型參數(shù)的API。
讓我們?cè)賮?lái)看看FindWindowEx這個(gè)API,它需要傳入2個(gè)int變量和2個(gè)字符串指針,根據(jù)SWT的設(shè)計(jì),我們是可以將Java的字符串轉(zhuǎn)換為指針的,因此通過(guò)Function我們也可以實(shí)現(xiàn)這個(gè)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í)像這種簡(jiǎn)單參數(shù)類(lèi)型的API,Win32 里還有很多,我們完全不必為其專(zhuān)門(mén)編寫(xiě)JNI,只需使用熟悉的Java即可。雖然不是調(diào)用全部的API,但大部分常用的API都是沒(méi)有問(wèn)題的,關(guān)鍵是如何靈活運(yùn)用。現(xiàn)在的大型商業(yè)RCP應(yīng)用中,其實(shí)多多少少都參和了JNI,用于提升對(duì)用戶(hù)的友好性和軟件的執(zhí)行性能,畢竟Java天生就是客戶(hù)端開(kāi)發(fā)的矮子。對(duì)于JNI,我們既不能一味排斥,也不能濫用,要把握一個(gè)平衡點(diǎn),使之成為Java客戶(hù)端開(kāi)發(fā)的利器。