使用jni时的进程通信问题

xstom19 2008-10-16 09:33:09
虽然在C板块也提了同样的问题,不过为了能让更多人看到,也希望java板块也有对c很熟的人能帮忙看一下。
我在写一个编辑器,图形部分是用java写的,但是是通过exe来启动的,就像eclispe一样。
我希望在已经启动一个进程的情况下,再打开文件不新开进程,而是把参数(文件名)传给原来的进程,在原来的进程里打开文件。
其实就像notepad++一样拉,新打开文件是作为tab的。
但是我对c很不熟,请问这个该如何实现呢?
这是我的代码
#include<jni.h>
#include<windows.h>
#include<string.h>
#include<stdio.h>
#define MAXDIR 256
#define TRUE 1
#define FALSE 0

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hprevInst, LPSTR lpCmd, int nShow) {
typedef int boolean;
JNIEnv *env;
JavaVM *jvm;
jint res;
jclass cls;
jmethodID mid;
jstring jstr;
jclass stringClass;
jobjectArray args;

boolean first_open = TRUE;

char dir[MAXDIR] = "";


char szDrive[_MAX_DRIVE];
char szFolder[_MAX_DIR];
char szFileName[_MAX_FNAME];
char szExt[_MAX_EXT];

SetLastError(NO_ERROR);
CreateMutex(NULL, FALSE, "RuleEditorInstance");
if (GetLastError() == ERROR_ALREADY_EXISTS)
first_open = FALSE;


#ifdef JNI_VERSION_1_6
if (first_open) {
JavaVMInitArgs vm_args;
JavaVMOption options[2];

char jvm_class_path[1024] = "-Djava.class.path=";
char lib_path[256] = "-Djava.library.path=\"";


GetModuleFileName(NULL,dir,MAXDIR);
_splitpath(dir, szDrive, szFolder, szFileName, szExt);
strcpy(dir, szDrive);
strcat(dir, szFolder);

strcat(jvm_class_path, dir);
strcat(jvm_class_path, "bin;");
strcat(jvm_class_path, dir);
strcat(jvm_class_path, "lib\\org.eclipse.swt.win32.win32.x86_3.4.0.v3448f.jar;");
options[0].optionString = jvm_class_path;

strcat(lib_path, dir);
strcat(lib_path, "lib\"");
options[1].optionString = lib_path;

vm_args.version = 0x00010002;
vm_args.options = options;
vm_args.nOptions = 2;
vm_args.ignoreUnrecognized = JNI_TRUE;
/* Create the Java VM */
res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);

if (res < 0) {
fprintf(stderr, "Can't create Java VM\n");
exit(1);
}
cls = (*env)->FindClass(env, "ch/ruleedit/RuleEditor");
if (cls == NULL) {
goto destroy;
}

mid = (*env)->GetStaticMethodID(env, cls, "main",
"([Ljava/lang/String;)V");
if (mid == NULL) {
goto destroy;
}
//解析lpCmd,赋值给jstr
jstr = (*env)->NewStringUTF(env, "");
if (jstr == NULL) {
goto destroy;
}
stringClass = (*env)->FindClass(env, "java/lang/String");
args = (*env)->NewObjectArray(env, 1, stringClass, jstr);
if (args == NULL) {
goto destroy;
}
(*env)->CallStaticVoidMethod(env, cls, mid, args);
} else {
//解析lpCmd(是个文件名)
//怎么发送消息给已经在运行的进程?
//进程怎么接收到消息?
//进程在收到消息得到文件名后,就可以调用(*env)->CallStaticVoidMethod();了
}

#else
fprintf(stderr, "JNI Version Not Supported...\n");
exit(1);
#endif /* JNI_VERSION_1_2 */
destroy:
if ((*env)->ExceptionOccurred(env)) {
(*env)->ExceptionDescribe(env);
}
(*jvm)->DestroyJavaVM(jvm);
return 0;
}


我用CreateMutex已经能判断是不是新进程了,问题主要是在那个else里面。
主要就是怎么取到文件名参数,之后的事情就是java来完成了。
...全文
413 26 打赏 收藏 转发到动态 举报
写回复
用AI写文章
26 条回复
切换为时间正序
请发表友善的回复…
发表回复
txzsp 2011-11-11
  • 打赏
  • 举报
回复
给LZ推荐一个JNI的使用,有源码和大量注释,LZ一定要试下:
http://download.csdn.net/detail/txzsp/2285294
xstom19 2008-10-20
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 relidgon 的回复:]
思路一:
对于第二次调用,本人觉得不必再找原来的main函数,而是需要你在java的类RuleEditor内自己
再提供一个二次调用的函数,如 AddNodeFile(String sFileName)函数了。
思路二:
就按你的线程的消息处理呗
[/Quote]
去结贴时才看到你的回复,不好意思啊。。。
其实办法一的难点就在于如何获得JNIEnv的地址,因为JNIEnv是在第一次启动时创建的。
办法二的话接收消息就难了,因为main被CallStaticVoidMethod阻塞了。
xstom19 2008-10-20
  • 打赏
  • 举报
回复
现在还是用了比较土的办法,在后来打开editor.exe时,就把参数写到文件里,在java里起个线程去读参数。
不过我有看到现在有java dde的实现www.nevaobject.com,也许有人能用得上。

另外还找到了WinRun4jhttp://winrun4j.sourceforge.net/,完全满足我的需求:
Uses an INI file for specifying classpath, main class, vm args, program args.
Custom executable name that appears in task manager.
Additional JVM args for more flexible memory use.
Built-in icon replacer for custom icon.
Pre-JVM splash screen with auto-hide.
DDE implementation for file assocations.
Windows NT Service wrapper.
Windows EventLog API
Console version
JNI library for INI access, splash screen, logger, registry, shell.
Support for 64-bit JVM.
过两天直接就用这个了,都用不着自己写C了。
xstom19 2008-10-17
  • 打赏
  • 举报
回复
c板块的人说用DDE,正在看
xstom19 2008-10-17
  • 打赏
  • 举报
回复
恩,是的。
我在CallStaticVoidMethod后加了打印语句。
在窗口关闭后(jvm退出), 那个语句才打印出来。
难怪我一开始在这后面再循环里getMessage都没反应。
sunyujia 2008-10-17
  • 打赏
  • 举报
回复
[Quote=引用 20 楼 xstom19 的回复:]
今天发现
C/C++ code(*env)->CallStaticVoidMethod(env, cls, mid, args);



是不立即返回的,只有在jvm调用System.exit()的时候返回。
这样看来和editor.exe通信似乎是不可能的了。。。
只有想办法得到JNIEnv的句柄了
[/Quote]
进程会阻塞在哪里是吗?
xstom19 2008-10-17
  • 打赏
  • 举报
回复
今天发现
(*env)->CallStaticVoidMethod(env, cls, mid, args);

是不立即返回的,只有在jvm调用System.exit()的时候返回。
这样看来和editor.exe通信似乎是不可能的了。。。
只有想办法得到JNIEnv的句柄了
红男爵 2008-10-17
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 sunyujia 的回复:]
引用 15 楼 xstom19 的回复:
恩,是的,我在c板块也发了同样的问题了,我也是c小白阿。谢谢呵呵。
http://topic.csdn.net/u/20081016/21/dc39620f-4179-4296-a00c-fc7eb89ba4e8.html

c区帖子5楼说的是这个
3。动态数据交换(DDE)通过维护全局分配内存使的应用程序间传递成为可能
其方式是再一块全局内存中手工放置大量的数据,然后使用窗口消息传递内存 指针.这是16位WIN时代使用的方式,因为在WIN32下已经没有…
[/Quote]

http://hi.baidu.com/charleswen/blog/item/8bdf9af3c062dec80b46e01a.html
这11种进程通讯不错,收藏一下。

To:lz
再次,给lz新的方案,针对于第二种进程通讯处理。
Using Memory Mapped Files and JNI to communicate between Java and C++ programs
(http://www.codeproject.com/KB/java/sharedmem_jni.aspx)

不错的sample,值得你仔细挖掘,研究。
红男爵 2008-10-17
  • 打赏
  • 举报
回复
好,今天正好也学习了C调用jvm了。这两天看了下 java 中JNI调用C++ dll,过两天还要研究JNI调用C#的dll呢。

正好碰到dll调试,sunyunjia兄给了链接过来。一起学些下了。

思路一:
对于第二次调用,本人觉得不必再找原来的main函数,而是需要你在java的类RuleEditor内自己
再提供一个二次调用的函数,如 AddNodeFile(String sFileName)函数了。

实现时,就在else里,找到对应函数对象,然后传递过文件参数即可。

cls_ RuleEditor = (*env)->FindClass(env, "ch/ruleedit/RuleEditor");
jmethodID construct=env->GetMethodID( cls_ RuleEditor, "","()V");/* 获得构造方法 */
jobject obj_ NewObject =env->NewObject( cls_ RuleEditor, construct, "");/* 创建java对象 */
/* 获得RuleEditor的AddNodeFile方法 */
jmethodID cls_addfile=(*env)->GetMethodID(Cls_ RuleEditor,"AddNodeFile","( Ljava/lang/String;)Z");

/* 调用AddNodeFile方法 */
jstring sFileName;
(*env)->CallObjectMethod(obj_ NewObject, cls_addfile, sFileName);



思路二:
就按你的线程的消息处理呗


// 得到进程
hProc = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,FALSE, aiPID[i]);
// 得到进程模块
lpfEnumProcessModules(hProc,&hMod,sizeof(hMod), &iCbneeded)
// 得到进程名字
lpfGetModuleBaseName(hProc, hMod, szName, MAX_PATH);


然后是给进程发消息,那个RuleEditor类还得处理对应的消息才行。
类似

unsigned long stat = WaitForSingleObject(hNotify, 5000);
// If it got signalled
if (stat == WAIT_OBJECT_0)
{

}


希望对你有所帮助。关注ing,,,
xstom19 2008-10-16
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 sunyujia 的回复:]
http://hi.baidu.com/charleswen/blog/item/8bdf9af3c062dec80b46e01a.html
[/Quote]
呵呵,这个网址不错,慢慢去试了,顺便学点C。
还好我还得把这个做成插件,那倒是没有这个问题了。
sunyujia 2008-10-16
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 xstom19 的回复:]
恩,是的,我在c板块也发了同样的问题了,我也是c小白阿。谢谢呵呵。
http://topic.csdn.net/u/20081016/21/dc39620f-4179-4296-a00c-fc7eb89ba4e8.html
[/Quote]
c区帖子5楼说的是这个
3。动态数据交换(DDE)通过维护全局分配内存使的应用程序间传递成为可能
其方式是再一块全局内存中手工放置大量的数据,然后使用窗口消息传递内存 指针.这是16位WIN时代使用的方式,因为在WIN32下已经没有全局和局部内存 了,现在的内存只有一种就是虚存。

你可以根据关键字搜索下,c区高手估计一般都是提醒下,不会放代码。我理解你,隔行如隔山,语言也一样,尤其是c这种bt的语言。
刚刚学习的。感觉还可以方法很全,虽然不懂实现,但是也当了解下。
http://hi.baidu.com/charleswen/blog/item/8bdf9af3c062dec80b46e01a.html
xstom19 2008-10-16
  • 打赏
  • 举报
回复
恩,是的,我在c板块也发了同样的问题了,我也是c小白阿。谢谢呵呵。
http://topic.csdn.net/u/20081016/21/dc39620f-4179-4296-a00c-fc7eb89ba4e8.html
xstom19 2008-10-16
  • 打赏
  • 举报
回复
呵呵,现在的问题是程序editor.exe是由用户打开的,并不是由某个更高层的程序控制的。
所以需要进程间的通信,后来的editor.exe发现已经有editor.exe在运行后,把参数传给原来的进程,就退出了。
由第一个editor.exe进程来接受参数,完成后续工作(调用jvm)。
sunyujia 2008-10-16
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 xstom19 的回复:]
引用 8 楼 sunyujia 的回复:
一定要新启动进程editor.exe吗
对阿,就像在用notepad++时,对于A.txt选择打开方式用notepad++打开;然后对于B.txt也是选择打开方式用notepad++打开,这时候notepad++会把B.txt打开在一个tab里。
editor.exe就是要实现一样的功能。
我尝试把notepad++的代码移植过来,但是没有成功(对C不熟啊...)。
[/Quote]
我感觉你要做的事就两步
1取句柄,原进程。
2传参数给进程。
sunyujia 2008-10-16
  • 打赏
  • 举报
回复
感觉是这个c++问题,其实和jni没多少关系了相信c区的高手可以帮你搞定,我是c++小白,估计帮不到你了,不过感谢你,今天学会靠c++控制jvm了。此贴做收藏。

另附自己刚才百度的东西。以备有时间在看。
http://blog.chinaunix.net/u/8818/showart.php?id=411261
http://tech.163.com/06/0119/12/27R2H8K800091LRC.html
xstom19 2008-10-16
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 sunyujia 的回复:]
一定要新启动进程editor.exe吗[/Quote]
对阿,就像在用notepad++时,对于A.txt选择打开方式用notepad++打开;然后对于B.txt也是选择打开方式用notepad++打开,这时候notepad++会把B.txt打开在一个tab里。
editor.exe就是要实现一样的功能。
我尝试把notepad++的代码移植过来,但是没有成功(对C不熟啊...)。
sunyujia 2008-10-16
  • 打赏
  • 举报
回复
新进程取句柄后可以通信把,我现在明白了在拥有jvm的进程中是可以随意调用jvm的,我看了些文章刚刚。
sunyujia 2008-10-16
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 xstom19 的回复:]
因为jvm是由editor.exe创建,对外部应该是不可见的,我觉得直接和jvm通信似乎不太能实现。
[/Quote]
是不现实,但是我觉得编辑器应该只有一个exe进程,你为什么会每次新建呢,你在说记事本吧。
sunyujia 2008-10-16
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 xstom19 的回复:]
引用 4 楼 sunyujia 的回复:
不对,是如果已经启动了jvm,在向jvm传参

恩差不多,要是能直接向jvm传参那更省事,但问题是没法直接得到jvm的引用,应为这个引用保存在原先启动的进程(就叫editor.exe好了)里。
所以新的进程需要先和editor.exe通信,editor.exe得到参数后再调用jvm。
[/Quote]
一定要新启动进程editor.exe吗取得原来进程的引用行不行,我明白你的需求了,不过不一定能帮上忙,但是我会持续关注。
xstom19 2008-10-16
  • 打赏
  • 举报
回复
因为jvm是由editor.exe创建,对外部应该是不可见的,我觉得直接和jvm通信似乎不太能实现。
加载更多回复(6)

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧