可執行文件即 EXE 文件在運行過程中,由系統管理其打開的句柄。此時對該 文件的一些操作是被系統禁止的,比如刪除操作。然而在某些場合,可能須要程 序有自我刪除的功能,也就是程序運行結束後刪除自身。基於這個想法,可以有 一種很簡單的方法來實現這個基本功能。
本方法基於兩點來實現刪除功能。一是利用 windows 的 command program 的 刪除文件操作;再者就是啟動新的進程來執行這個刪除操作。下面就仔細說明。
Windows 中的 command program 是一個系統的 shell program. 在 windows95/98/Me 中,其文件名為 command.com ,而在 NT/2000/XP 中則是 cmd.exe 。我們可以通過環境變量 COMSPEC 得到其全路徑名。
假定目前我們所使用的是 XP ,在命令行中輸入 :
cmd.exe /?
即得到 command shell 的使用方法;其中 /c 的含義是:執行字符串指定的 命令然後終斷,這正是我們所須要的。這樣利用 command shell 刪除一個文件的 命令如下:
cmd.exe /c del mypro.exe
這裡要注意一點,文件名應該是短文件名(文件名不得超過 8 個字符 , 後綴 不超過 3 個字符)。如果實際文件是長文件句,那麼程序中我們可以用 GetShortPathName 這個 API 函數來轉換。
接下來我們要做是如何在一新的進程中成功的執行這一指令。起來一個新進程 的命令主要有 ShellExecute 和 CreateProcess 。
先使用 ShellExecute 為例。在程序的結束處使用如下語句:
ShellExecute(NULL, "open","cmd.exe", "/c del mypro.exe ", NULL, SW_HIDE);
編譯後運行文件發現執行成功,文件運行完後被刪除。但是後面做多次實驗後 ,發現有時文件執行完後並不會被刪除。通過分析,認為在刪除操作執行時,可 執行文件還未關閉。也就是說只有在執行文件的進程關閉後,執行刪除操作的進 程才能完成操作。這樣就有了一個問題,系統負責進程和線程的調度執行,我們 無法人為規定進程或線程以某種秩序執行。
對此我的解決辦法是,建立執行刪除操作的進程時設定其為掛起狀態,從而為 其的設定一個低優先級別,同時提高執行文件的進程級別,然後才正式起動新進 程。這樣基本可以保證兩個進程的先後執行。這樣新的解決方法就是用 CreateProcess以CREATE_SUSPEND標志來建立新進程,然後用SetPriorityClass來 設定相應的優先級,主進程的優先級是HIGH_PRIORITY_CLASS,而執行刪除操作的 進程的優先級是IDLE_PRIORITY_CLASS。經過數百次的測試,刪除操作都是成功的 。
下面是一個封裝了刪除操作的函數,函數內起動一個進程執行command shell的 del命令。在程序最後結束處調用它,就可以簡單的實現程序的自刪除功能。 #include <windows.h>
#include <shellapi.h>
#include <stdio.h>
int DeleteMyExe()
{
TCHAR tcsExename[MAX_PATH];
TCHAR tcsParam[MAX_PATH * 2];
TCHAR tcsCmd[MAX_PATH];
HANDLE hProcess = NULL;
// get exe filename and command shell program
if( 0 == GetModuleFileName(NULL, tcsExename, MAX_PATH)
|| 0 == GetEnvironmentVariable(_T("COMSPEC"), tcsCmd, MAX_PATH))
FAILRET;
// get short filename for command shell program
if( 0 == GetShortPathName(tcsExename, tcsExename, MAX_PATH))
FAILRET;
// create a command process, set its priority, then start it.
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
ZeroMemory( &pi, sizeof(pi) );
_stprintf(tcsParam, _T("%s /c del %s"), tcsCmd, tcsExename);
if(!CreateProcess(NULL,
tcsParam,
NULL,
NULL,
FALSE,
CREATE_SUSPENDED,
NULL,
NULL,
&si,
&pi))
{
return GetLastError();
}
// heigthen priority of the current process
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
// set file attribute to normal
SetFileAttributes(tcsExename, FILE_ATTRIBUTE_NORMAL);
// depress priority of command process, then start it
SetPriorityClass(pi.hProcess, IDLE_PRIORITY_CLASS);
ResumeThread(pi.hThread);
return 0;
}
(全文完)