Feeling

    三人行,必有我师焉

   ::  :: 新随笔 :: 联系 ::  :: 管理 ::
  85 随笔 :: 0 文章 :: 392 评论 :: 0 Trackbacks
在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客户端开发的利器。
posted on 2008-05-11 19:31 三人行,必有我师焉 阅读(5687) 评论(7)  编辑  收藏

评论

# re: 通过Function类来实现Win32 API,让Java代码代替JNI 2008-05-11 21:00 隔叶黄莺
程序编写上好像也没怎么变简单,同样需要了解 win32 api 的用法,只是用不着再拉进来一个写 C++ 的人罢,可是对 C++ 的理解还是免不了的。

作为对 C++, Win32 API 有所掌握的人还是愿意用 JNI 来写。  回复  更多评论
  

# re: 通过Function类来实现Win32 API,让Java代码代替JNI 2008-05-11 22:32 三人行,必有我师焉
是的,代码量并没有减少。
但是对于一个Java开发人员来说,了解Win32 API不难,难的是掌握C++的各种语法,以及指针。就像能使用VB的人很多,能使用VC的人不多一样。毕竟C++太强大也太灵活了,有时候过于灵活反而不是一件好事。因为我本人就是这种人,我看Win32的API一般都去找VB的例子,尽管没有学过VB,但是很容易看懂,相比VC,VB太简单了。我相信同样的API,用Java实现和用C++实现,对Java程序员来说一定是有很大区别的。  回复  更多评论
  

# re: 通过Function类来实现Win32 API,让Java代码代替JNI 2008-05-12 19:00 银河使者
虽然是用Function类可以调用部分api,但要使用swt,是不是还得带上swt的库和dll(linux是.so)啊。

如果想使用JNI的话,可以选择使用自己熟悉的语言调用api,然后再用jni调用。如delphi也可以编写api。不一定非得要c++。

这个不绝对,根据自己掌握的知识、能力以及喜好做出选择吧。多元化世界当然得有多元化的选择了。只有适合自己的才是最好的!!  回复  更多评论
  

# re: 通过Function类来实现Win32 API,让Java代码代替JNI[未登录] 2008-07-01 09:01 johnson
请问swt-extension可以用在swing里面吗  回复  更多评论
  

# re: 通过Function类来实现Win32 API,让Java代码代替JNI 2008-07-01 11:09 三人行,必有我师焉
@johnson
不可以,是以swt作为基础的。用swing的JNI工具,应该有很多的。  回复  更多评论
  

# re: 通过Function类来实现Win32 API,让Java代码代替JNI 2009-09-27 09:31 sillycat
在eclipse 3.4.2环境下,使用org.sf.feeling.swt.win32.extension_1.0.5.v20081205.jar作为插件的lib,运行遍历窗口的代码,报下面的错误,有遇到相同情况的么?请问如何解决,谢谢!
java.lang.UnsatisfiedLinkError: org.sf.feeling.swt.win32.internal.extension.Extension.InvokeII_I(III)I  回复  更多评论
  

# re: 通过Function类来实现Win32 API,让Java代码代替JNI 2011-07-27 18:41 yj
jna可能更好哦  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航:
 
GitHub |  开源中国社区 |  maven仓库 |  文件格式转换