最近 需要实现程序自删除功能,在网上看到一段代码 如下:#include "stdafx.h"
#include <Windows.h>
#include <stdlib.h>
#include <tchar.h>
int main(int argc, char* argv[])
{
if (argc == 1)
{
// Original EXE: Spawn clone EXE to delete this EXE
// Copy this EXEcutable image into the user's temp directory
TCHAR szPathOrig[_MAX_PATH], szPathClone[_MAX_PATH];
GetModuleFileName(NULL, szPathOrig, _MAX_PATH);
GetTempPath(_MAX_PATH, szPathClone);
GetTempFileName(szPathClone, __TEXT("Del"), 0, szPathClone); 
CopyFile(szPathOrig, szPathClone, FALSE);
//***注意了***: 
// Open the clone EXE using FILE_FLAG_DELETE_ON_CLOSE
HANDLE hfile = CreateFile(szPathClone, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, NULL);
// Spawn the clone EXE passing it our EXE's process handle
// and the full path name to the Original EXE file.
TCHAR szCmdLine[512];
HANDLE hProcessOrig = OpenProcess(SYNCHRONIZE, TRUE, GetCurrentProcessId());
wsprintf(szCmdLine, __TEXT("%s %d \"%s\""), szPathClone, hProcessOrig, szPathOrig);
STARTUPINFO si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
PROCESS_INFORMATION pi;
CreateProcess(NULL, szCmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
CloseHandle(hProcessOrig);
CloseHandle(hfile);
// This original process can now terminate.
}
else 
{
// Clone EXE: When original EXE terminates, delete it
HANDLE hProcessOrig = (HANDLE) _ttoi(__targv[1]);
WaitForSingleObject(hProcessOrig, INFINITE);
CloseHandle(hProcessOrig);
DeleteFile(__targv[2]);
}
return(0);
}结果是 主程序删除了 temp文件夹下的那个临时文件 没有删除,哪位大神看看是个什么因为,谢谢了VCEXE

解决方案 »

  1.   

    自删除貌似都需要双进程,或者自带bat文件,看看老帖http://bbs.csdn.net/topics/390354206
      

  2.   

    那个临时文件正在运行啊,FILE_FLAG_DELETE_ON_CLOSE也是删不掉的
      

  3.   

     The DELETE_ON_CLOSE methodThe CreateFile API call accepts several flags which affect how a file is created or opened. One of these flags, FILE_FLAG_DELETE_ON_CLOSE, specifies that the file will be deleted when the last handle to it is closed. The basis to this technique will be to run an executable with this flag set, so that when it exits, it is deleted automatically.The first step is to create an empty file with the DELETE_ON_CLOSE flag specified. The exact binary content of the current executable file is then copied into this new file, in effect duplicating the executable on disk. A new process is then created (using the new executable file). This has the effect that the duplicate file's handle count is incremented. Also, when the new process was created, the full path of the current process was passed through the command-line argument.Next, the current executable (which wants to delete itself) closes the file handle used to create the new process, and then exits. Now, the duplicate's file-handle count is decremented, but because CreateProcess incremented its handle count when it started, the file is not deleted.At this point, the duplicate executable has started running. The PID specified on the command-line is used to open a handle to the original process. The duplicate waits for the original process to terminate, using WaitForSingleObject. When this call returns, the duplicate can call DeleteFile on the filename also specified through its command-line argument. The original executable (the one that wanted to delete itself) has been successfully deleted. This just leaves the duplicate copy, which exits normally. The duplicate's file-handle count drops to zero, the DELETE_ON_CLOSE flag comes into effect, and the duplicate file is deleted also.It sounds a bit complicated, but it's not too difficult. Here's the steps one more time:
    [ Current process ]
    1. Create a new file with FILE_FLAG_DELETE_ON_CLOSE.
    2. Copy the current executable's content into the new file.
    3. Create a new process with the duplicate executable:
    4. Pass the current executable's full path and PID in the call to CreateFile.
    5. Sleep for a short time to give the new process time to start.
    6. Close the new file.
    7. Exit current process.
     
    [ Duplicate process ]
    8.  Wait for the process specified on command-line to die.
    9.  Delete file specified on command-line.
    10. Exit duplicate process.There are just a couple of technicalities to mention. First, when the "new" process is spawned, the "old" process must sleep for a short period, enough to let the Windows loader open the file and create the process (thus incrementing it's file count).Second, the new process must wait until the old process terminates, which releases its file count.Third, when the duplicate executable is created, it must also have the FILE_SHARE_DELETE flag specified, otherwise CreateProcess will fail, because it won't be able to open the file whilst we have it open with the DELETE_ON_CLOSE flag set.Obviously this method will require careful coding, because the program must be written in such a way so that it can perform these dual tasks. The "new" executable must know that it's job is to delete the file specified on the command line, for instance.It's a little messy, but it does work very well. In fact, the uninstall program that I wrote, which is included with the software you can download from this site, uses this very method. I've included an example program which demonstrates this technique.An alternative method is to write a very small stand-alone executable, which it's sole task is to delete the file-name specified on it's command-line. This executable could then be imbedded as a "payload" to the executable which wants to delete itself. This payload would be created and executed in the same way as described above.
      

  4.   

    http://www.catch22.net/tuts/self-deleting-executables
    我下载了他的例子来试过了,他那个FILE_FLAG_DELETE_ON_CLOSE的例子也是删不掉临时文件的
    http://www.catch22.net/sites/default/files/selfdel.zip
    #include <windows.h>
    #include <tchar.h>#pragma comment (linker, "/NODEFAULTLIB")#ifndef _DEBUG
    #pragma comment(linker,"/merge:.rdata=.data")
    #pragma comment(linker,"/merge:.text=.data")
    #pragma comment(linker,"/FILEALIGN:0x200")
    #endif // _DEBUG
    TCHAR szAppName[]  = _T("delthis");
    TCHAR szUsage[]    = _T("Usage:\r\n\r\nselfdel  [options]\r\n\r\nOptions:\r\n-u  (Uninstall)\r\n-pid Pid\r\n-exe Path");
    TCHAR szError1[]   = _T("Failed to open process [%u]");
    TCHAR szDeleting[] = _T("Deleting:\r\n\r\n%s");int _tatoi(TCHAR *num)
    {
    int   n = 0;
    TCHAR *nptr = num;

    while(*nptr && IsCharAlphaNumeric(*nptr) && !IsCharAlpha(*nptr))
    n = 10 * n + (*nptr++ - '0'); return n;
    }void MyZeroMem(void *mem, DWORD bytes)
    {
    BYTE *bptr = (BYTE *)mem; while(bytes--)
    *bptr++ = 0;
    }//
    // Delete THIS executable by spawning a copy off
    //
    void CommitSuicide(void)
    {
    HANDLE hTemp;
    char szPath[MAX_PATH];
    char szTemp[MAX_PATH];
    char szBig [MAX_PATH*2 + 100]; STARTUPINFO si;
    PROCESS_INFORMATION pi;

    UINT ret; //
    // Open a temporary file
    //
    GetTempPath(MAX_PATH, szTemp);
    lstrcat(szTemp, "selfdel.exe"); //
    // Get the current executable path
    //
    GetModuleFileName(0, szPath, MAX_PATH);

    //
    // Copy ourselves into the temporary file
    //
    CopyFile(szPath, szTemp, FALSE); //
    // Open the temporary file, with DELETE_ON_CLOSE access.
    // When we finally exit, the temporary file will get deleted
    //
    hTemp = CreateFile(szTemp, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_DELETE, 0,
    OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, 0); //
    // Create a process using the temporary executable. This will cause
    // the file's handle count to increase, so we can close it,
    // without it deleting itself
    //
    MyZeroMem(&si, sizeof(STARTUPINFO));
    MyZeroMem(&pi, sizeof(PROCESS_INFORMATION)); si.cb = sizeof(STARTUPINFO); wsprintf(szBig, "\"%s\" -pid %u -exe \"%s\"", 
    szTemp, 
    GetCurrentProcessId(),
    szPath);
    ret = CreateProcess(0, szBig, 0, 0, FALSE, NORMAL_PRIORITY_CLASS, 0, 0, &si, &pi); //Close our handle to the new process. Because the process is
    //memory-mapped, there will still be a handle held by the O/S, so
    //it won't get deleted. Give the other process a chance to run..
    Sleep(100);
    CloseHandle(hTemp);
    }//
    // Wait for the specified Process to terminate,
    // then delete the exe's path
    //
    void DeleteExe(DWORD dwPid, TCHAR *szPath)
    {
    HANDLE hProcess;
    TCHAR  szErr[MAX_PATH+32]; //
    // Open the process
    //
    hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, dwPid); if(hProcess == 0)
    {
    wsprintf(szErr, szError1, dwPid);
    MessageBox(0, szErr, szAppName, MB_OK|MB_ICONINFORMATION);
    return;
    } //
    // Wait for process to die
    //
    WaitForSingleObject(hProcess, INFINITE);
    CloseHandle(hProcess); //
    // Delete the process
    //
    DeleteFile(szPath);
    }TCHAR * GetNextArg(TCHAR *szPtr, TCHAR *szOut)
    {
    TCHAR *pOut = szOut;
    TCHAR ch = *szPtr++; if(ch == '\0')
    return 0; //Skip white-space
    while(ch == ' ' || ch == '\t')
    {
    ch = *szPtr++;
    } //Process quoted strings
    if(ch == '\"')
    {
    ch = *szPtr++;

    while(ch && ch != '\"')
    {
    *szOut++ = ch;
    ch = *szPtr++; } *szOut = '\0';
    return szPtr;
    } //Return the next argument
    while(ch && ch != ' ' && ch != '\t')
    {
    *szOut++ = ch;
    ch = *szPtr++;
    } *szOut = '\0';
    return szPtr;
    }
    int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmdLine, int nShowCmd)
    {
    DWORD dwProcessId;
    TCHAR  *ptr;
    TCHAR   buf[MAX_PATH]; ptr = lpCmdLine; //
    // Get options..
    //
    ptr = GetNextArg(ptr, buf); if(lstrcmpi(buf, "-u") == 0)
    {
    CommitSuicide();
    ExitProcess(0);
    return 0;
    }

    if(lstrcmpi(buf, "-pid") == 0)
    {
    //Pid specified - now get the PID
    ptr = GetNextArg(ptr, buf); dwProcessId = _tatoi(buf); //get the next option
    ptr = GetNextArg(ptr, buf); if(lstrcmpi(buf, "-exe") == 0)
    {
    //exe-path specified - get the path
    ptr = GetNextArg(ptr, buf);
    DeleteExe(dwProcessId, buf);
    return 0;
    }
    else
    {
    return 1;
    }
    }
    else
    {
    //return failure
    return 1;
    } return 0;
    }//
    // Usage:
    //   selfdel.exe [-u | -pid<PID> -exe<path>]
    //
    int  WINAPI WinMainCRTStartup()
    {
    UINT  ret;
    TCHAR *pszCmdLine;
    TCHAR temp[MAX_PATH]; HINSTANCE hInst = GetModuleHandle(0);
    pszCmdLine = GetCommandLine(); pszCmdLine = GetNextArg(pszCmdLine, temp);

    ret = WinMain(hInst, 0, pszCmdLine, SW_SHOWNORMAL);

    if(ret != 0)
    {
    MessageBox(0, szUsage, szAppName, MB_OK|MB_ICONINFORMATION);
    } ExitProcess(ret);
    return 0;
    }