可執行文件即 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命令。在程序最後結束處調用它,就可以簡單的實現程序的自刪除功能。
01.
include
< windows.h>
02.
#include
< shellapi.h>
03.
#include
< stdio.h>
04.
05.
int
DeleteMyExe()
06.
{
07.
TCHAR
tcsExename[MAX_PATH];
08.
TCHAR
tcsParam[MAX_PATH
* 2];
09.
TCHAR
tcsCmd[MAX_PATH];
10.
HANDLE
hProcess
= NULL;
11.
12.
//
get exe filename and command shell program
13.
if
(
0 == GetModuleFileName(NULL, tcsExename, MAX_PATH)
14.
||
0 == GetEnvironmentVariable(_T(
"COMSPEC"
),
tcsCmd, MAX_PATH))
15.
FAILRET;
16.
17.
//
get short filename for command shell program
18.
if
(
0 == GetShortPathName(tcsExename, tcsExename, MAX_PATH))
19.
FAILRET;
20.
21.
//
create a command process, set its priority, then start it.
22.
STARTUPINFO
si;
23.
PROCESS_INFORMATION
pi;
24.
25.
ZeroMemory(
&si,
sizeof
(si)
);
26.
si.cb
=
sizeof
(si);
27.
si.dwFlags
= STARTF_USESHOWWINDOW;
28.
si.wShowWindow
= SW_HIDE;
29.
ZeroMemory(
&pi,
sizeof
(pi)
);
30.
31.
_stprintf(tcsParam,
_T(
"%s
/c del %s"
),
tcsCmd, tcsExename);
32.
if
(!CreateProcess(NULL,
33.
tcsParam,
34.
NULL,
35.
NULL,
36.
FALSE,
37.
CREATE_SUSPENDED,
38.
NULL,
39.
NULL,
40.
&si,
41.
&pi))
42.
{
43.
return
GetLastError();
44.
}
45.
46.
//
heigthen priority of the current process
47.
SetPriorityClass(GetCurrentProcess(),
HIGH_PRIORITY_CLASS);
48.
49.
//
set file attribute to normal
50.
SetFileAttributes(tcsExename,
FILE_ATTRIBUTE_NORMAL);
51.
52.
//
depress priority of command process, then start it
53.
SetPriorityClass(pi.hProcess,
IDLE_PRIORITY_CLASS);
54.
ResumeThread(pi.hThread);
55.
return
0;
56.
}