通过Function类来实现Win32 API,让Java代码代替JNI

通过Function类来实现Win32 API,让Java代码代替JNI
在SWT Extension中,引入了Function这个类。基本上所有的Win32 JNI库都有这个类,用来直接操纵Win32 的部分API。有了这个Class,我们不用编写JNI,就可以实现某些简单的,甚至是较复杂的Win32 API。这里我们就以EnumWindows这个API举例,看看怎么Java来执行这个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的地址作为参数。实际上在C里面,一个boolean值无非就是是否非0,如果为0,则为false,不为0,则为true。我们只需要new 一个function实例,传入这个API所在的Lib和API名字,然后执行invoke方法就OK了,在Function里面,可以最多执行含有4个简单类型参数的API。

让我们再来看看FindWindowEx这个API,它需要传入2个int变量和2个字符串指针,根据SWT的设计,我们是可以将Java的字符串转换为指针的,因此通过Function我们也可以实现这个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;
    }
其实像这种简单参数类型的API,Win32 里还有很多,我们完全不必为其专门编写JNI,只需使用熟悉的Java即可。虽然不是调用全部的API,但大部分常用的API都是没有问题的,关键是如何灵活运用。现在的大型商业RCP应用中,其实多多少少都参和了JNI,用于提升对用户的友好性和软件的执行性能,毕竟Java天生就是客户端开发的矮子。对于JNI,我们既不能一味排斥,也不能滥用,要把握一个平衡点,使之成为Java客户端开发的利器。

你可能感兴趣的:(通过Function类来实现Win32 API,让Java代码代替JNI)