在C++程式碼中建立Java虛擬機器。

lin_zyang發表於2007-10-08

好多人都在問如何將java程式碼打包成exe檔案,其實,下面這段程式碼稍微修改一下就可以做一個類似Java2Exe的功能。

順便看了一下JBuilder編譯生成的exe檔案(星期天半天的時間花在研究這個上面了),是將jar檔案追加到exe檔案末尾,然後將exe檔案當作jar檔案來使用,因此,除錯了半天也沒發現它寫臨時檔案。方法還是挺巧妙的。其實,替換掉JBuilder生成的exe檔案末尾的jar檔案就可以生成你自己的打包exe檔案。 

下面程式碼是csdn blog 上fita的,原文在:http://blog.csdn.net/fita/archive/2005/03/23/327838.aspx ,不過有編譯錯誤(估計是fita故意的),我只是調了調。

另一個問題是,如果是Java GUI程式,須在啟動Java程式後,開始一個訊息迴圈,否則Java程式視窗會一閃而過。

 

#include <windows.h>
#include 
<jni.h>
//#pragma comment( linker, "/subsystem:"console" /entry:"mainCRTStartup"" ) 
#pragma comment( linker, "/subsystem:"windows" /entry:"WinMainCRTStartup"" ) 

typedef jint (JNICALL 
*JNICREATEPROC)(JavaVM **void **void *);
bool setStream(JNIEnv *env, const char* pszFileName, const char* pszMethod);
//啟動java虛擬機器方法

//bool main(int argc,char *argv[])
int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow)
{
    
//jvm動態庫的路徑
    const char szJvmPath[] = "d:/jdk1.5.0_07/jre/bin/server/jvm.dll";
    
    
//java 虛擬機器的啟動引數,每個引數寫一項,不能合在一起寫
    int nOptionCount = 2;
    JavaVMOption options[
2];
    options[
1].optionString = "-Xmx256M";
    
    
//設定classpath
    options[0].optionString = "-Djava.class.path=./startup.jar;./DirectMail.exe";
    
    JavaVMInitArgs vm_args;
    vm_args.version 
= JNI_VERSION_1_4;
    vm_args.options 
= options;
    vm_args.nOptions 
= nOptionCount;
    vm_args.ignoreUnrecognized 
= JNI_TRUE;
    
    
//啟動類,注意分割符是/,例如啟動類test.JTest應該寫成 test/JTest
    const char szStartClass[] = "com/qzsoft/directmail/MainFrame";
    
    
//啟動方法,通常是main函式,你也可以設定成其他函式
    const char szStartMethod[] = "main";
    
    
//重導向檔案
    const char szStdoutFileName[] = "stdout.txt";
    
const char szStderrFileName[] = "stderr.txt";
    
    
//java程式的命令列引數
    int nParamCount = 2;
    
const char *szParams[2= {"arg1","arg2"};
    
    
//載入JVM。
    HINSTANCE jvmDll = LoadLibrary(szJvmPath);
    
if (jvmDll == NULL)
    
{
        printf(
"載入JVM動態庫錯誤。%l", ::GetLastError());
        
return false;
    }

    
    
//查詢JNI_CreateJavaVM過程。
    JNICREATEPROC jvmCreateProc = (JNICREATEPROC)GetProcAddress(jvmDll, "JNI_CreateJavaVM");
    
if (jvmCreateProc == NULL)
    
{
        FreeLibrary(jvmDll);
        printf(
"查詢JNI_CreateJavaVM過程錯誤。%l", ::GetLastError());
        
return false;
    }

    
    
//建立JVM。
    JNIEnv *env;
    JavaVM 
*jvm;
    jint r 
= (jvmCreateProc)(&jvm, (void **)&env, &vm_args);
    
if (r < 0 || jvm == NULL || env == NULL)
    
{
        FreeLibrary(jvmDll);
        printf( 
"建立JVM發生錯誤。");
        
return false;
    }

    
    
//重導向stdout, stderr到輸出檔案
    if (!setStream(env, szStdoutFileName, "setOut"))
    
{
        printf(
"設定stdout輸出檔案失敗");
        
return false;
    }

    
    
if (!setStream(env, szStderrFileName, "setErr"))
    
{
        printf(
"設定stderr輸出檔案失敗");
        
return false;
    }

    
    
//載入啟動類。
    jclass serviceClass = env->FindClass(szStartClass);
    
if (env->ExceptionCheck() == JNI_TRUE || serviceClass == NULL)
    
{
        env
->ExceptionDescribe();
        env
->ExceptionClear();
        FreeLibrary(jvmDll);
        printf(
"載入啟動類失敗。");
        
return false;
    }

    
    
//啟動方法
    jmethodID mid = env->GetStaticMethodID(serviceClass, szStartMethod , "([Ljava/lang/String;)V");
    
if (env->ExceptionCheck() == JNI_TRUE || mid == NULL)
    
{
        env
->ExceptionDescribe();
        env
->ExceptionClear();
        FreeLibrary(jvmDll);
        printf(
"查詢啟動方法失敗。");
        
return false;
    }

    
    
    
    
//查詢String類。
    jclass stringClass = env->FindClass("java/lang/String");
    
if (env->ExceptionCheck() == JNI_TRUE || stringClass == NULL)
    
{
        env
->ExceptionDescribe();
        env
->ExceptionClear();
        FreeLibrary(jvmDll);
        
        printf(
"查詢String類失敗。");
        
return false;
    }

    
    
    
    jstring jstr;
    jobjectArray args 
= 0;
    
    args 
= env->NewObjectArray(2, stringClass, 0);
    
for (int i=0; i<nParamCount; i++)
    
{
        jstr 
= env->NewStringUTF(szParams[i]);
        
if (jstr == 0{
            printf(
"分配String失敗 ");
            
if (env->ExceptionOccurred()) {
                env
->ExceptionDescribe();
                env
->ExceptionClear();
            }

            
            
return false;
        }

        
        env
->SetObjectArrayElement(args, i, jstr);
        
if (env->ExceptionCheck() == JNI_TRUE)
        
{
            printf(
"設定引數失敗 ");
            
if (env->ExceptionOccurred()) {
                env
->ExceptionDescribe();
                env
->ExceptionClear();
            }

            
return false;
        }

    }

    
    
    
    
//呼叫啟動類的啟動方法啟動Java程式
    
//env->CallStaticVoidMethod(serviceClass, mid, parameterArray);
    env->CallStaticVoidMethod(serviceClass, mid, args);
    
    
if (env->ExceptionCheck() == JNI_TRUE)
    
{
        env
->ExceptionDescribe();
        env
->ExceptionClear();
        FreeLibrary(jvmDll);
        
return false;
    }

    
    MSG  msg ;
    
while (GetMessage (&msg, NULL, 00))
    
{
        TranslateMessage (
&msg) ;
        DispatchMessage (
&msg) ;
    }

    
return true;
    
}


//設定輸出流的方法

bool setStream(JNIEnv *env, const char* pszFileName, const char* pszMethod)
{
    
int pBufferSize = 1024;
    
char* pBuffer = new char[pBufferSize];
    
    
//建立字串物件。
    jstring pathString = env->NewStringUTF(pszFileName);
    
if (env->ExceptionCheck() == JNI_TRUE || pathString == NULL)
    
{
        env
->ExceptionDescribe();
        env
->ExceptionClear();
        printf(
"建立字串失敗。");
        
return false;
    }

    
    
//查詢FileOutputStream類。
    jclass fileOutputStreamClass = env->FindClass("java/io/FileOutputStream");
    
if (env->ExceptionCheck() == JNI_TRUE || fileOutputStreamClass == NULL)
    
{
        env
->ExceptionDescribe();
        env
->ExceptionClear();
        printf(
"查詢FileOutputStream類失敗。");
        
return false;
    }

    
    
//查詢FileOutputStream類構造方法。
    jmethodID fileOutputStreamConstructor = env->GetMethodID(fileOutputStreamClass, "<init>""(Ljava/lang/String;)V");
    
if (env->ExceptionCheck() == JNI_TRUE || fileOutputStreamConstructor == NULL)
    
{
        env
->ExceptionDescribe();
        env
->ExceptionClear();
        printf(
"查詢FileOutputStream類構造方法失敗。");
        
return false;
    }

    
    
//建立FileOutputStream類的物件。
    jobject fileOutputStream = env->NewObject(fileOutputStreamClass, fileOutputStreamConstructor, pathString);
    
if (env->ExceptionCheck() == JNI_TRUE || fileOutputStream == NULL)
    
{
        env
->ExceptionDescribe();
        env
->ExceptionClear();
        printf(
"建立FileOutputStream類的物件失敗。");
        
return false;
    }

    
    
//查詢PrintStream類。
    jclass printStreamClass = env->FindClass("java/io/PrintStream");
    
if (env->ExceptionCheck() == JNI_TRUE || printStreamClass == NULL)
    
{
        env
->ExceptionDescribe();
        env
->ExceptionClear();
        
        printf(
"查詢PrintStream類失敗。");
        
return false;
    }

    
    
//查詢PrintStream類構造方法。
    jmethodID printStreamConstructor = env->GetMethodID(printStreamClass, "<init>""(Ljava/io/OutputStream;)V");
    
if (env->ExceptionCheck() == JNI_TRUE || printStreamConstructor == NULL)
    
{
        env
->ExceptionDescribe();
        env
->ExceptionClear();
        printf(
"查詢PrintStream類構造方法失敗。");
        
return false;
    }

    
    
//建立PrintStream類的物件。
    jobject printStream = env->NewObject(printStreamClass, printStreamConstructor, fileOutputStream);
    
if (env->ExceptionCheck() == JNI_TRUE || printStream == NULL)
    
{
        env
->ExceptionDescribe();
        env
->ExceptionClear();
        printf(
"建立PrintStream類的物件失敗。");
        
return false;
    }

    
    
//查詢System類。
    jclass systemClass = env->FindClass("java/lang/System");
    
if (env->ExceptionCheck() == JNI_TRUE || systemClass == NULL)
    
{
        env
->ExceptionDescribe();
        env
->ExceptionClear();
        printf( 
"查詢System類失敗。");
        
return false;
    }

    
    
//查詢System類設定方法。
    jmethodID setStreamMethod = env->GetStaticMethodID(systemClass, pszMethod, "(Ljava/io/PrintStream;)V");
    
if (env->ExceptionCheck() == JNI_TRUE || setStreamMethod == NULL)
    
{
        env
->ExceptionDescribe();
        env
->ExceptionClear();
        printf(
"查詢System類設定方法失敗。");
        
return false;
    }

    
    
//設定System類的流。
    env->CallStaticVoidMethod(systemClass, setStreamMethod, printStream);
    
if (env->ExceptionCheck() == JNI_TRUE)
    
{
        env
->ExceptionDescribe();
        env
->ExceptionClear();
        printf(
"設定System類的流失敗。");
        
return false;
    }

    
    
return true;
}

 

相關文章