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

  • Managing your company's financials is the backbone of your business and is vital to the long-term health and viability of your company. To continue applying the necessary financial rigor to support rapid growth, the accounting department needs the right tools to most efficiently do their job. Read this white paper to understand the 10 essentials of a complete financial management system and how the right solution can help you keep up with the rapidly changing business world.

  • Flash technology is becoming more prominent in the storage industry. Offering superior speed and reliability when compared to traditional hard disk drives – flash storage is a flexible and increasingly cost-effective technology that can be used to optimize enterprise storage environments. This ebook explores the many uses and benefits of flash storage technology in the enterprise. Check it out to discover and learn all you need to: Optimize storage performance Leverage server flash as storage cache …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds