您的位置:首页 >> 编程开发 >> Java >> Java基础 >> Eclipse >> 正文
Eclipse RSS
 

集成Windows本地应用到Eclipse RCP 程序中

http://www.rdxx.com 08年06月10日 00:00 我要投稿

关键词: 集成 , 本地 , Windows , Eclipse , 程序 , 应用 , IP

   cl -I%java_home%\include -I%java_home%\include\win32 -LD HelloWorld.cpp –Fehelloworld.dll

    注 意:生成的 dll 文件名在选项 -Fe 后面配置,这里是 helloworld.dll,因为前面我们在 HelloWorld.java 文件中 loadLibary 的时候使用的名字是 helloworld。所以要保证这里的名字和前面 load 的名字一致。另外需要将 -I%java_home%\include -I%java_home%\include\win32 参数加上,因为在第四步里面编写本地方法的时候引入了 jni.h 文件,所以在这里需要加入这些头文件的路径。

    完成了这些步骤之后就可以运行这个程序:java HelloWorld,运行的结果就是在控制台输出字符串“HelloWorld”。


    实现窗口 Reparent

    前面部分介绍了如何使用 JNI,接下来介绍如何通过 JNI 启动一个 Windows 的本地应用程序并且将其主窗口设置为指定窗口的子窗口。首先创建一个 Java 类,如下面的清单所示:

    public class ReparentUtil { static{  System.loadLibrary("reparent"); } public static native int startAndReparent(int parentWnd,             String command,String wndClass);}


    其中 System.loadLibrary("reparent") 是用来加载名为 reparent 的动态库,我们会在这个动态库中具体实现方法 startAndReparent(…)。

    startAndReparent 定义方法来启动 Windows 程序,并且将其窗口 reparent 到我们指定的窗口。其中:

    int parentWnd: 父窗口句柄
    String command:Windows 程序启动命令
    String wndClass:Windows 程序主窗口类型
    由于有的程序启动后会创建多个顶级窗口,所以我们在这里要指定一个主窗口类型来区分不同的顶级窗口。这个方法是一个本地方法,我们会用 C++ 生成为一个叫 reparent.dll 的动态库,这个方法即存在于这个动态库中。

    这 个 Java 函数对应的的 C++ 函数是 Java_com_reparent_ReparentUtil_startAndReparent(JNIEnv *env, jclass classobj, jint parent, jstring command, jstring wndClass), 这个函数主要实现两部分的功能:

    启动 Windows 应用程序;
    获取 Windows 应用程序的主窗口句柄;
    将 Windows 应用主窗口设置成指定窗口的子窗口。
    启动 Windows 应用程序

    下面我们来看看启动 Windows 应用程序的实现. 我们先将函数传入的 Java 字符串参数转化成 C 字符串。这个过程主要通过 GetStringChars() 来实现。

    JNIEXPORT jint JNICALL Java_com_reparent_ReparentUtil_startAndReparent     (JNIEnv *env, jclass classobj, jint parent, jstring command,                       jstring wndClass){ jboolean isCopy=FALSE; PROCESS_INFORMATION   pInfo;    STARTUPINFO                   sInfo;  int hParentWnd; jsize len = ( *env ).GetStringLength(command); const jchar *commandstr = (*env).GetStringChars(command,&isCopy); const jchar *wndClassStr = NULL; char commandcstr[200]; int size = 0; size = WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)commandstr,    len, commandcstr,(len*2+1), NULL, NULL ); (*env).ReleaseStringChars(command, commandstr); if(size==0){  return 0; } commandcstr[size] = 0; if(wndClass!=NULL){  wndClassStr = (*env).GetStringChars(wndClass,&isCopy);  if(wndClassStr!=NULL){   len = (*env).GetStringLength(wndClass);   size = WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)wndClassStr,      len, wndClassName,(len*2+1), NULL, NULL );   wndClassName[size] = 0;   (*env).ReleaseStringChars(wndClass, wndClassStr);  } }


    接着,我们使用 Windows 的 API:CreateProcess 函数来启动我们要集成的应用程序。

    sInfo.cb                     =   sizeof(STARTUPINFO);       sInfo.lpReserved             =   NULL;       sInfo.lpReserved2           =   NULL;       sInfo.cbReserved2           =   0;       sInfo.lpDesktop               =   NULL;       sInfo.lpTitle                   =   NULL;       sInfo.dwFlags                   =   0;       sInfo.dwX                           =   0;       sInfo.dwY                           =   0;       sInfo.dwFillAttribute   =   0;       sInfo.wShowWindow           =   SW_HIDE;       if(!CreateProcess(NULL,commandcstr,NULL,NULL, TRUE,0,NULL,NULL,&sInfo,&pInfo))   {               printf("ERROR:   Cannot   launch   child   process\n");      release();            return 0;    }


    CreateProcess 函数的定义是:

    BOOL CreateProcess (    LPCTSTR lpApplicationName,            LPTSTR lpCommandLine,            LPSECURITY_ATTRIBUTES lpProcessAttributes。    LPSECURITY_ATTRIBUTES lpThreadAttributes,            BOOL bInheritHandles,            DWORD dwCreationFlags,    LPVOID lpEnvironment,            LPCTSTR lpCurrentDirectory,            LPSTARTUPINFO lpStartupInfo,            LPPROCESS_INFORMATION lpProcessInformation );


    其中 lpApplicationName:指向一个 NULL 结尾的、用来指定可执行模块的字符串。lpCommandLine:指向一个 NULL 结尾的、用来指定要运行的命令行。lpProcessAttributes: 指向一个 SECURITY_ATTRIBUTES 结构体,这个结构体决定是否返回的句柄可以被子进程继承。lpThreadAttributes: 指向一个 SECURITY_ATTRIBUTES 结构体,这个结构体决定是否返回的句柄可以被子进程继承。bInheritHandles:指示新进程是否从调用进程处继承了句柄。 dwCreationFlags:指定附加的、用来控制优先类和进程的创建的标志。lpEnvironment:指向一个新进程的环境块。 lpCurrentDirectory:指向一个以 NULL 结尾的字符串,这个字符串用来指定子进程的工作路径。lpStartupInfo:指向一个用于决定新进程的主窗体如何显示的 STARTUPINFO 结构体。lpProcessInformation:指向一个用来接收新进程的识别信息的 PROCESS_INFORMATION 结构体。

    获取应用程序的主窗口句柄

    为了获取启动后的程序的主窗口句柄,在调用 CreateProcess() 之前,我们需要使用一个 Windows 的系统钩子来截获窗口创建的事件:

    hHook = SetWindowsHookEx(WH_SHELL, ShellProc,(HINSTANCE)hDllHandle,NULL);


    这里,我们使用的钩子类型是 WH_SHELL。这种钩子可以截获所有顶级窗口创建或者激活的事件。函数的第二个参数是事件处理函数。我们的处理函数叫 ShellProc。我们之后会介绍。

    启动应用程序之后,我们需要获取应用程序的主窗口之后才能继续运行。这里需要实现进程间的同步。在我们的主进程中,我们需要等待,当应用程序的主窗口创建之后,我们发一个消息,通知我们的主进程继续执行。

    我 们这里使用 Windows 的 Event 来实现同步。我们首先调用 CreateEvent 来创建一个事件,然后调用 WaitForSingleObject()等待事件的状态改变。在我们的 ShellProc 处理函数中,我们一旦获取应用程序主窗口句柄,我们会改变事件的状态以通知主进程继续执行。

    以下是创建事件的代码,我们创建了一个名为 Global\WaitWindowCreatedEvent 的事件:

     SECURITY_ATTRIBUTES secuAtt; secuAtt.bInheritHandle = TRUE; secuAtt.lpSecurityDescriptor = NULL; secuAtt.nLength = sizeof(SECURITY_ATTRIBUTES); hEvent = CreateEvent(&secuAtt,FALSE,FALSE,TEXT("Global\WaitWindowCreatedEvent"));


 

共4页  1 2 3 4


 
 
标签: 集成 , 本地 , Windows , Eclipse , 程序 , 应用 , IP 打印本文
 
 
  热点搜索
 
 
 



Valid XHTML 1.0 Transitional
Copyright ©2005 - 2008 Rdxx.Com,All Rights Reserved
收藏本页
收藏本站