虽然在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来完成了。

解决方案 »

  1.   

    有难度啊,你是用c启动了jvm,启动后想传递参数到jvm中是吧。
      

  2.   

    不对,是如果已经启动了jvm,在向jvm传参
      

  3.   

    我能想到的只能是开端口socket,有谁对jvm了解的,可提供下资料看看,有没有相应的接口。
      

  4.   

    恩差不多,要是能直接向jvm传参那更省事,但问题是没法直接得到jvm的引用,应为这个引用保存在原先启动的进程(就叫editor.exe好了)里。
    所以新的进程需要先和editor.exe通信,editor.exe得到参数后再调用jvm。
      

  5.   

    因为jvm是由editor.exe创建,对外部应该是不可见的,我觉得直接和jvm通信似乎不太能实现。
      

  6.   

    一定要新启动进程editor.exe吗取得原来进程的引用行不行,我明白你的需求了,不过不一定能帮上忙,但是我会持续关注。
      

  7.   

    是不现实,但是我觉得编辑器应该只有一个exe进程,你为什么会每次新建呢,你在说记事本吧。
      

  8.   

    新进程取句柄后可以通信把,我现在明白了在拥有jvm的进程中是可以随意调用jvm的,我看了些文章刚刚。
      

  9.   

    对阿,就像在用notepad++时,对于A.txt选择打开方式用notepad++打开;然后对于B.txt也是选择打开方式用notepad++打开,这时候notepad++会把B.txt打开在一个tab里。
    editor.exe就是要实现一样的功能。
    我尝试把notepad++的代码移植过来,但是没有成功(对C不熟啊...)。
      

  10.   

    感觉是这个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
      

  11.   

    呵呵,现在的问题是程序editor.exe是由用户打开的,并不是由某个更高层的程序控制的。
    所以需要进程间的通信,后来的editor.exe发现已经有editor.exe在运行后,把参数传给原来的进程,就退出了。
    由第一个editor.exe进程来接受参数,完成后续工作(调用jvm)。
      

  12.   

    恩,是的,我在c板块也发了同样的问题了,我也是c小白阿。谢谢呵呵。
    http://topic.csdn.net/u/20081016/21/dc39620f-4179-4296-a00c-fc7eb89ba4e8.html
      

  13.   

    c区帖子5楼说的是这个
    3。动态数据交换(DDE)通过维护全局分配内存使的应用程序间传递成为可能
       其方式是再一块全局内存中手工放置大量的数据,然后使用窗口消息传递内存    指针.这是16位WIN时代使用的方式,因为在WIN32下已经没有全局和局部内存    了,现在的内存只有一种就是虚存。  你可以根据关键字搜索下,c区高手估计一般都是提醒下,不会放代码。我理解你,隔行如隔山,语言也一样,尤其是c这种bt的语言。
    刚刚学习的。感觉还可以方法很全,虽然不懂实现,但是也当了解下。
    http://hi.baidu.com/charleswen/blog/item/8bdf9af3c062dec80b46e01a.html
      

  14.   

    好,今天正好也学习了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,,,
      

  15.   


    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,值得你仔细挖掘,研究。
      

  16.   

    今天发现(*env)->CallStaticVoidMethod(env, cls, mid, args);是不立即返回的,只有在jvm调用System.exit()的时候返回。
    这样看来和editor.exe通信似乎是不可能的了
    只有想办法得到JNIEnv的句柄了
      

  17.   

    恩,是的。
    我在CallStaticVoidMethod后加了打印语句。
    在窗口关闭后(jvm退出), 那个语句才打印出来。
    难怪我一开始在这后面再循环里getMessage都没反应。
      

  18.   

    现在还是用了比较土的办法,在后来打开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了。 
      

  19.   

    去结贴时才看到你的回复,不好意思啊
    其实办法一的难点就在于如何获得JNIEnv的地址,因为JNIEnv是在第一次启动时创建的。
    办法二的话接收消息就难了,因为main被CallStaticVoidMethod阻塞了。
      

  20.   

    给LZ推荐一个JNI的使用,有源码和大量注释,LZ一定要试下:
    http://download.csdn.net/detail/txzsp/2285294