想將Lua和腳本文件打包成一個(gè)exe文件,,以便發(fā)布,從網(wǎng)上查了N多資源,,終于搞定了^-^ 主要實(shí)現(xiàn)方案是通過將Lua解釋器和腳本文件以資源文件中RCDATA類型打包進(jìn)exe文件中,,在運(yùn)行文件時(shí)再 進(jìn)行釋放,然后在臨時(shí)目錄中執(zhí)行,。 大概步驟為: 1,、編寫相應(yīng)的rc文件,添加想打包的所有文件 2,、通過FindResource\SizeofResource\LoadResource\LockResource四個(gè)函數(shù)查找定位exe打包文件中對(duì) 應(yīng)的各個(gè)資源文件,,并創(chuàng)建至臨時(shí)目錄中 3、用CreateProcess\WaitForSingleObject\CloseHandle三個(gè)函數(shù)實(shí)現(xiàn)run and wait功能(好像 GetExitCodeProcess的方式也行) 4,、等程序執(zhí)行完畢,,刪除臨時(shí)文件 (5、LoadLibrary\GetProcAddress\CallWindowProc\FreeLibrary四個(gè)函數(shù)實(shí)現(xiàn)ActiveX dll的注冊(cè)) 該方案一個(gè)缺點(diǎn)是可能容易被殺軟認(rèn)為是病毒-_-|| 實(shí)現(xiàn)該功能的一個(gè)簡(jiǎn)單方案為使用專業(yè)軟件,,如PEBundle,。。,。 更新歷史: 2008-11-4: 改動(dòng)較多,目前可以釋放到"temp","current","system","windows"和指定目錄下了,,并 且解決了運(yùn)行腳本時(shí)工作目錄不一定為當(dāng)前exe文件所在目錄的問題。增加了部分目錄處理函數(shù)和字符串 處理函數(shù)。 2008-11-3: 看了一位大大的blog,,其使用pe文件的形式實(shí)現(xiàn)了動(dòng)態(tài)加載到內(nèi)存中執(zhí)行,,等有時(shí)間時(shí) 好好研究研究,http://blog.csdn.net/lisunlin0/ 2008-11-1: 添加ActiveX dll的注冊(cè)函數(shù)DllRegister的實(shí)現(xiàn),;將RunWait中的GetTempFilePath提取 出來,,以便通用;在一個(gè)字符串前添加一個(gè)空格寫為函數(shù),。 2008-10-31: 初次版本釋放,,主要為ResourceFile_Create,RunWait,,ResourceFile_Delete三個(gè)函 數(shù) 對(duì)應(yīng)的代碼如下: /*相應(yīng)的rc資源文件代碼 - data.rc*/ IDR_LUA RCDATA "lua.exe" IDR_SCRIPT RCDATA "script.lua" IDR_UNICODE RCDATA "Unicode.dll" /*相應(yīng)的C代碼 - OneEXE.c*/ #include <stdio.h> #include <windows.h> /*將給定的兩個(gè)字符串連接起來,,并返回為一個(gè)新的字符串*/ char* StringJoin(const char* first,const char* last) { char* result; int len = strlen(first)+strlen(last)+1; result = (char*)malloc(len*sizeof(char)); memset(result,0,len*sizeof(char)); strcpy(result,first); strcat(result,last); return result; } /*獲取字符串指定部分*/ char* StringSub(const char* string,int start,int number) { int len = strlen(string); char* temp; if(start>len) { printf("Start %d is too big than string length %d!\n",start,len); return NULL; } if(number>(len-start)) { printf("Number is too big!\n"); number = len - start + 1; } temp = (char*)malloc(sizeof(char)*(number+1)); memset(temp,0,(number+1)*sizeof(char)); int i = 0; int j = 0; while(i != number) temp[i++] = string[(start-1)+j++]; temp[number]='\0'; return temp; } /*用StringJoin函數(shù),在字符串末尾添加'\'*/ char* add_slash(char* string) { int len = strlen(string); /*查看最后一個(gè)字符是否為'\'*/ if(string[len-1] != '\\') return StringJoin(string,"\\"); else return string; } /*獲取臨時(shí)目錄*/ char* TempPath() { char *Buffer; DWORD dwRet; /*獲取臨時(shí)目錄*/ /*獲取臨時(shí)目錄字符串大小,,包含末尾的'\0'*/ dwRet = GetTempPath(0,NULL); if( dwRet == 0 ) { printf("GetCurrentDirectory failed (%d)\n", GetLastError()); return NULL; } /*根據(jù)獲取的空間,,分配內(nèi)存,并置零*/ Buffer = (char *)malloc(sizeof(char)*dwRet); memset(Buffer,0,dwRet*sizeof(char)); /*獲取臨時(shí)目錄*/ GetTempPath(dwRet,Buffer); return add_slash(Buffer); } /*獲取當(dāng)前工作目錄*/ char* CurrentPath() { char *Buffer; DWORD dwRet; /*獲取當(dāng)前目錄*/ /*獲取當(dāng)前目錄字符串大小,,包含末尾的'\0'*/ dwRet = GetCurrentDirectoryA (0,NULL); if( dwRet == 0 ) { printf("GetCurrentDirectory failed (%d)\n", GetLastError()); return NULL; } /*根據(jù)獲取的空間,,分配內(nèi)存,并置零*/ Buffer = (char *)malloc(sizeof(char)*dwRet); memset(Buffer,0,dwRet*sizeof(char)); /*獲取臨時(shí)目錄*/ GetCurrentDirectoryA (dwRet,Buffer); return add_slash(Buffer); } /*獲取系統(tǒng)System32目錄*/ char* SystemPath() { char *Buffer; DWORD dwRet; /*獲取System目錄*/ /*獲取System目錄字符串大小,,包含末尾的'\0'*/ dwRet = GetSystemDirectoryA (NULL,0); if( dwRet == 0 ) { printf("GetCurrentDirectory failed (%d)\n", GetLastError()); return NULL; } /*根據(jù)獲取的空間,,分配內(nèi)存,并置零*/ Buffer = (char *)malloc(sizeof(char)*dwRet); memset(Buffer,0,dwRet*sizeof(char)); /*獲取臨時(shí)目錄*/ GetSystemDirectoryA (Buffer,dwRet); return add_slash(Buffer); } /*獲取Windows目錄*/ char* WindowsPath() { char *Buffer; DWORD dwRet; /*獲取Windows目錄*/ /*獲取Windows目錄字符串大小,,包含末尾的'\0'*/ dwRet = GetWindowsDirectoryA (NULL,0); if( dwRet == 0 ) { printf("GetCurrentDirectory failed (%d)\n", GetLastError()); return NULL; } /*根據(jù)獲取的空間,,分配內(nèi)存,并置零*/ Buffer = (char *)malloc(sizeof(char)*dwRet); memset(Buffer,0,dwRet*sizeof(char)); /*獲取臨時(shí)目錄*/ GetWindowsDirectoryA (Buffer,dwRet); return add_slash(Buffer); } /*獲取當(dāng)前運(yùn)行程序的目錄*/ char* ExePath() { char *Buffer; /*設(shè)置初始緩存大小為32*/ DWORD size=32; DWORD dwRet=32; Buffer = (char*)malloc(sizeof(char)*dwRet); memset(Buffer,0,dwRet*sizeof(char)); /*獲取Windows目錄*/ /*獲取Windows目錄字符串大小,,包含末尾的'\0'*/ dwRet = GetModuleFileNameA(NULL,Buffer,dwRet); printf("%d %d\n",dwRet,size); if(dwRet == 0) return NULL; while (size == dwRet) { size *= 2; Buffer = (char*)realloc(Buffer,sizeof(char)*size); memset(Buffer,0,size*sizeof(char)); dwRet = GetModuleFileNameA(NULL,Buffer,size); printf("%d %d\n",dwRet,size); } return Buffer; } /*獲取一個(gè)指定文件的目錄*/ char* GetDir(const char* filepath) { char* pos = strrchr(filepath,'\\'); if(pos == NULL) return NULL; else return StringSub(filepath,1,pos + 1 - filepath); } /*設(shè)置文件路徑*/ char* SetFilePath(const char* name,const char* path) { char* filepath; if(strcmp(path,"temp")==0) filepath = StringJoin(TempPath(),name); else if (strcmp(tolower(path),"current")==0) /*該實(shí)現(xiàn)可能出現(xiàn)問題,似乎為父進(jìn)程工作目錄 filepath = StringJoin(CurrentPath(),name);*/ filepath = StringJoin(GetDir(ExePath()),name); else if (strcmp(tolower(path),"system")==0) filepath = StringJoin(SystemPath(),name); else if (strcmp(tolower(path),"windows")==0) filepath = StringJoin(WindowsPath(),name); else filepath = add_slash(StringJoin(path,name)); return filepath; } /*定位自己的資源文件,,并將其創(chuàng)建至系統(tǒng)臨時(shí)目錄*/ int ResourceFile_Create(const char* ID,const char* name,const char* path) { HRSRC hr; DWORD dwSize, dwWritten; HGLOBAL hg; LPSTR lp; HANDLE hFile; /*讀入資源文件,四步: 1.FindResource 2.SizeofResource 3.LoadResource 4.LockResource */ /*定位自定義資源,,由于是從本模塊定位資源,,所以將句柄簡(jiǎn)單地置為NULL即可, 第二個(gè)參數(shù)為定義ID字符串,,為函數(shù)的第一個(gè)參數(shù),,第三個(gè)為定義的類型,這里全部默認(rèn)定義為 RT_RCDATA*/ hr=FindResource(NULL,ID,RT_RCDATA); /*查找資源文件失敗的處理*/ if(hr==NULL) { MessageBox (NULL, TEXT ("hr error"),TEXT ("Error"), MB_OK); return -1; } /*獲取資源大小*/ dwSize=SizeofResource(NULL,hr); /*讀入資源文件*/ hg=LoadResource(NULL,hr); /*讀入資源失敗時(shí)的處理*/ if(hg==NULL) { MessageBox (NULL, TEXT ("hg error"),TEXT ("Error"), MB_OK); return -1; } /*鎖定資源*/ lp=(LPSTR)LockResource(hg); /*鎖定資源失敗的處理*/ if(lp==NULL) { MessageBox (NULL, TEXT ("lp error"),TEXT ("Error"), MB_OK); return -1; } /*獲取指定文件夾目錄路徑*/ char* filepath=SetFilePath(name,path); /*在指定目錄創(chuàng)建文件*/ hFile = CreateFile(filepath,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,0,NULL); /*創(chuàng)建文件失敗的處理*/ if(hFile == NULL) { MessageBox (NULL, TEXT ("Create file error!"),TEXT ("Error"), MB_OK); return -1; } /*將資源文件寫入指定目錄路徑*/ WriteFile(hFile,(LPCVOID)LockResource(hg),dwSize,&dwWritten,NULL); CloseHandle(hFile); return 0; } /*在一個(gè)字符串前加一個(gè)空格,,以便下邊的RunWait中CreateProcess第二個(gè)參數(shù)命令行使用*/ char* addblank(const char* string ) { char *string_blank; string_blank = (char*)malloc(strlen(string)+2); sprintf(string_blank," %s",string); return string_blank; } /*獲取一個(gè)文件的短路徑,,如果不存在該文件,則返回NULL*/ char* ShortPath(char* Path) { char *Buffer; DWORD dwRet; dwRet = GetShortPathNameA(Path,NULL,0); if(dwRet == 0) return NULL; Buffer = (char*)malloc(sizeof(char)*dwRet); memset(Buffer,0,dwRet*sizeof(char)); GetShortPathNameA(Path,Buffer,dwRet); return Buffer; } /*運(yùn)行文件及命令,,并等待其退出*/ int RunWait(const char* app,const char* cmdline) { /*初始化*/ STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory( &si, sizeof(si) ); si.cb = sizeof(si); ZeroMemory( &pi, sizeof(pi) ); /*開始執(zhí)行,,參數(shù)2在字符串前加了一個(gè)空格*/ /*函數(shù)倒數(shù)第三個(gè)函數(shù)設(shè)置為當(dāng)前exe文件的目錄,表示其工作目錄為exe文件目錄*/ if(!CreateProcess(ShortPath(app),addblank(ShortPath(cmdline)), NULL, NULL, FALSE, 0, NULL, GetDir(ExePath()), &si, &pi)) { char error_string[128]; sprintf(error_string,"Create Process failed (%d)",GetLastError()); MessageBox (NULL, TEXT (error_string),TEXT ("Error"), MB_OK); return -1; } /*等待結(jié)束*/ WaitForSingleObject( pi.hProcess, INFINITE ); /*結(jié)束句柄*/ CloseHandle( pi.hProcess ); CloseHandle( pi.hThread ); return 0; } /*注冊(cè)或者反注冊(cè)Dll文件*/ int DllRegister(const char* file,const char* func) { /*主要通過 1、LoadLibrary 2、GetProcAddress 3,、CallWindowProc 4,、FreeLibrary這4個(gè)函數(shù)進(jìn)行處理*/ HINSTANCE handle; typedef int (CALLBACK* LPFNDLLFUNC)(int,int); LPFNDLLFUNC lpfnDllFunc; /*讀入dll文件*/ handle = LoadLibrary(file); if( handle != NULL ) { /*通過GetProcAddress獲取函數(shù)func地址*/ lpfnDllFunc = (LPFNDLLFUNC)GetProcAddress(handle,func); if( lpfnDllFunc != NULL ) { /*調(diào)用函數(shù)*/ CallWindowProc((WNDPROC)lpfnDllFunc,(HWND)handle,0,0,0); } else { MessageBox (NULL, TEXT ("The function is invalid!"),TEXT ("Error"), MB_OK); return -1; } /*釋放資源*/ FreeLibrary(handle); } else { MessageBox (NULL, TEXT ("The dll is invalid!"),TEXT ("Error"), MB_OK); return -1; } return 0; } /*刪除釋放的資源文件*/ int ResourceFile_Delete(const char* name,const char* path) { BOOL check; /*設(shè)置文件路徑*/ char* filepath=SetFilePath(name,path);; /*刪除文件并驗(yàn)證是否成功*/ check = DeleteFile(filepath); char error_string[128]; sprintf(error_string,"Can't delete the file - %s",name); if(!check) { MessageBox (NULL, TEXT (error_string),TEXT ("Error"), MB_OK); return -1; } return 0; } /*主程序*/ int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { /*釋放臨時(shí)資源文件*/ ResourceFile_Create("IDR_LUA","lua.exe","temp"); ResourceFile_Create("IDR_SCRIPT","script.lua","temp"); ResourceFile_Create("IDR_Unicode","Unicode.dll","temp"); /*注冊(cè)dll,僅僅ActiveX dll需要注冊(cè),,假定Unicode.dll為ActiveX dll*/ DllRegister(SetFilePath("Unicode.dll","temp"),"DllRegisterServer"); /*運(yùn)行腳本*/ RunWait(SetFilePath("lua.exe","temp"),SetFilePath("script.lua","temp")); /*反注冊(cè)dll*/ DllRegister(SetFilePath("Unicode.dll","temp"),"DllUnregisterServer"); /*刪除臨時(shí)資源文件*/ ResourceFile_Delete("lua.exe","temp"); ResourceFile_Delete("script.lua","temp"); ResourceFile_Delete("Unicode.dll","temp"); return 0; } |
|