Win32 Self-Deletion Function

SelfDelete() is a simple Win API function for creating a self-deleting executable. It works by invoking the command shell as a serialized process to delete the program file.

The Command Shell

The command shell program is defined by the environment variable "COMSPEC". This varies with the Windows OS: Win9x/ME use COMMAND.COM, while WinNT/2K/XP use CMD.EXE. The following string is passed to the command shell:

/c del Filename > nul

which translates to: "Run a single command to delete a file and redirect the output to nowhere." Filename is the full path and name of the file we want to delete. This name needs to be converted into its short 8.3 name to change any extended characters into OEM equivalents.

The command shell is started as an independent process by calling the ShellExecuteEx() function. Its process handle is defined by the SHELLEXECUTEINFO struct member "hProcess". NOTE: The "/c" switch is necessary for the command shell process to exit. Do not omit it from the parameters string.

Serializing Processes

Self-deletion presents us with a special problem: The main program must exit and close its opened file handle before the command shell deletes the file. To do this, we must serialize two independent, parallel processes—the current program process and the command shell process. This is done by manipulating CPU resource priorities to temporarily suppress the command shell process. As written, the code will allocate all CPU resources to the main program until it exits. This effectively blocks any command shell execution until the program has terminated.

CPU Allocation

Allocating the REALTIME_PRIORITY_CLASS and THREAD_PRIORITY_TIME_CRITICAL settings can interfere with driver functions and can cause Windows to "hang" if kept in a prolonged state. To avoid these problems, a self-deleting app must exit cleanly upon a boolean return of TRUE. Developers need to make sure all ancillary processes and threads have finished and all handles are closed before calling the function. SelfDelete() should only be called at a program's main exit:

  INT APIENTRY WinMain(...)
  {
    ...

    // on program exit
    // close all handles etc.
    if(!SelfDelete())
    {
      // add error messaging
    }
    return 0;    // WinMain exit
  }

It may be desirable to use a lower CPU allocation, such as:

  SetPriorityClass(GetCurrentProcess(),HIGH_PRIORITY_CLASS);
  SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_HIGHEST);

This allocation does not guarantee a complete cessation of the command shell process, but nevertheless works well.

Code Limitations

  • There is no error checking if the command shell cannot delete the file. Make sure the program file is not set with a "hidden," "system," or "read-only" attribute.
  • The explorer shell will always remove the program icon from view regardless of whether the command shell is able to actually delete the file. Pressing F5 will update the shell folder and correct any erroneous listings.
  • The command shell can only run a single command. Multiple commands such as to delete a file and remove its directory cannot be done without a script file.

Update

The code has been modified to work better on NT kernel computers with multiple processors. Windows allocates resources through a thread priority queue rather than by time-slicing CPU cycles. Two modifications have been made to the code:

  • The thread allocation to the program process has been increased prior to invoking the command shell process. This ensures the program process will always have priority in the resource queue. Threads created by the ShellExecuteEx function do not inherit the resource allocation of the calling process.
  • The NT kernel will transiently increase priority to whatever process is granted CPU resources. The SetProcessPriorityBoost function has been added to prevent this from happening to the command shell process.
////////////////////////////////////////////////////////

#include <windows.h>
#include <shlobj.h>

BOOL SelfDelete()
{
  SHELLEXECUTEINFO sei;

  TCHAR szModule [MAX_PATH],
        szComspec[MAX_PATH],
        szParams [MAX_PATH];

  // get file path names:
  if((GetModuleFileName(0,szModule,MAX_PATH)!=0) &&
     (GetShortPathName(szModule,szModule,MAX_PATH)!=0) &&
     (GetEnvironmentVariable("COMSPEC",szComspec,MAX_PATH)!=0))
  {
    // set command shell parameters
    lstrcpy(szParams,"/c del ");
    lstrcat(szParams, szModule);
    lstrcat(szParams, " > nul");

    // set struct members
    sei.cbSize       = sizeof(sei);
    sei.hwnd         = 0;
    sei.lpVerb       = "Open";
    sei.lpFile       = szComspec;
    sei.lpParameters = szParams;
    sei.lpDirectory  = 0;
    sei.nShow        = SW_HIDE;
    sei.fMask        = SEE_MASK_NOCLOSEPROCESS;

    // increase resource allocation to program
    SetPriorityClass(GetCurrentProcess(),
                     REALTIME_PRIORITY_CLASS);
    SetThreadPriority(GetCurrentThread(),
                      THREAD_PRIORITY_TIME_CRITICAL);

    // invoke command shell
    if(ShellExecuteEx(&sei))
    {
      // suppress command shell process until program exits
      SetPriorityClass(sei.hProcess,IDLE_PRIORITY_CLASS);
      SetProcessPriorityBoost(sei.hProcess,TRUE);

      // notify explorer shell of deletion
      SHChangeNotify(SHCNE_DELETE,SHCNF_PATH,szModule,0);
      return TRUE;
    }
    else // if error, normalize allocation
    {
      SetPriorityClass(GetCurrentProcess(),
                       NORMAL_PRIORITY_CLASS);
      SetThreadPriority(GetCurrentThread(),
                        THREAD_PRIORITY_NORMAL);
    }
  }
  return FALSE;
}

Downloads

Download source - 4 Kb


Comments

  • PERL solution

    Posted by Legacy on 09/16/2003 12:00am

    Originally posted by: David Ross

    I need this to happen from within a PERL program.

    Any ideas?

    Reply
  • When ShellExecute is finished

    Posted by Legacy on 08/10/2003 12:00am

    Originally posted by: Dave

    S****Execute
    
    How do we know when the program that we executed is finished

    Reply
  • Why so complicated solution?

    Posted by Legacy on 06/12/2003 12:00am

    Originally posted by: Jan

    If you spawn batch "deleteme.bat" file with:

    :repeat
    del yourfile.exe
    if exist yourfile.exe goto Repeat
    del deleteme.bat

    The last line will safely delete the batch file.

    Regards, Jan

    Reply
  • Good work

    Posted by Legacy on 06/11/2003 12:00am

    Originally posted by: Halid

    its good work.

    Reply
  • Ultimatly needed for some specific cases

    Posted by Legacy on 05/30/2003 12:00am

    Originally posted by: Ponn Periasamy

    Win32 Self-Deletion Function helps more.
    
    Ultimatly needed for some specific cases

    Reply
  • What happens on a dual processor machine?

    Posted by Legacy on 04/07/2003 12:00am

    Originally posted by: Vadim

    You cannot guarantee the first process will stop before the second one starts in this case.

    Reply
  • works greate

    Posted by Legacy on 03/31/2003 12:00am

    Originally posted by: gok

    in your cpp just add
    #include <shellapi.h>
    Thanks!

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • You probably have several goals for your patient portal of choice. Is "community" one of them? With a bevy of vendors offering portal solutions, it can be challenging for a hospital to know where to start. Fortunately, YourCareCommunity helps ease the decision-making process. Read this white paper to learn more. "3 Ways Clinicians can Leverage a Patient Portal to Craft a Healthcare Community" is a published document owned by www.medhost.com

  • The impact of a data loss event can be significant. Real-time data is essential to remaining competitive. Many companies can no longer afford to rely on a truck arriving each day to take backup tapes offsite. For most companies, a cloud backup and recovery solution will eliminate, or significantly reduce, IT resources related to the mundane task of backup and allow your resources to be redeployed to more strategic projects. The cloud - can now be comfortable for you – with 100% recovery from anywhere all …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds