Figure 1   DeleteMe.cpp

 Module name: DeleteMe.cpp
 Written by: Jeffrey Richter
 Description: Allows an EXEcutable file to delete itself
 ********************************************************************/
 
 #include <Windows.h>
 #include <stdlib.h>
 #include <tchar.h>
 
 /////////////////////////////////////////////////////////////////////
 
 int WINAPI WinMain(HINSTANCE h, HINSTANCE h2, LPSTR psz, int n) {
 
    // Is this the Original EXE or the clone EXE?
    // If the command-line 1  argument, this is the Original EXE
    // If the command-line >1 argument, this is the clone EXE
    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]);
       // Insert code here to remove the subdirectory too (if desired).
 
       // The system will delete the clone EXE automatically 
       // because it was opened with FILE_FLAG_DELETE_ON_CLOSE
    }
    return(0);
 }
 

Figure 2   Coptex

Optex.h


 /******************************************************************************
 Module name: Optex.h
 Written by:  Jeffrey Richter
 Purpose:     Defines the COptex (optimized mutex) synchronization object
 ******************************************************************************/
 #pragma once
 
 ///////////////////////////////////////////////////////////////////////////////
 
 class COptex {
 public:
    COptex(LPCSTR pszName,  DWORD dwSpinCount = 4000);
    COptex(LPCWSTR pszName, DWORD dwSpinCount = 4000);
    ~COptex();
    void SetSpinCount(DWORD dwSpinCount);
    void Enter();
    BOOL TryEnter();
    void Leave();
 
 private:
    typedef struct {
       DWORD m_dwSpinCount;
       long  m_lLockCount;
       DWORD m_dwThreadId;
       long  m_lRecurseCount;
    } SHAREDINFO, *PSHAREDINFO;
 
    BOOL        m_fUniprocessorHost;
    HANDLE      m_hevt;
    HANDLE      m_hfm;
    PSHAREDINFO m_pSharedInfo;
 
 private:
    BOOL CommonConstructor(PVOID pszName, BOOL fUnicode, DWORD dwSpinCount);
 };
 
 ///////////////////////////////////////////////////////////////////////////////
 
 inline COptex::COptex(LPCSTR pszName, DWORD dwSpinCount) {
    CommonConstructor((PVOID) pszName, FALSE, dwSpinCount);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
 inline COptex::COptex(LPCWSTR pszName, DWORD dwSpinCount) {
    CommonConstructor((PVOID) pszName, TRUE, dwSpinCount);
 }
Optex.cpp

 /******************************************************************************
 Module name: Optex.cpp
 Written by:  Jeffrey Richter
 Purpose:     Implements the COptex (optimized mutex) synchronization object
 ******************************************************************************/
 #include <windows.h>
 #include "Optex.h"
 
 ///////////////////////////////////////////////////////////////////////////////
 
 BOOL COptex::CommonConstructor(PVOID pszName, BOOL fUnicode, DWORD dwSpinCount) 
{
 
    m_hevt = m_hfm = NULL;
    m_pSharedInfo = NULL;
 
    SYSTEM_INFO sinf;
    GetSystemInfo(&sinf);
    m_fUniprocessorHost = (sinf.dwNumberOfProcessors == 1);
 
    char szNameA[100];
    if (fUnicode) {   // Convert Unicode name to ANSI
       wsprintfA(szNameA, "%S", pszName);
       pszName = (PVOID) szNameA;
    }
    char sz[100];
    wsprintfA(sz, "JMR_Optex_Event_%s", pszName);
    m_hevt = CreateEventA(NULL, FALSE, FALSE, sz);
    if (m_hevt != NULL) {
       wsprintfA(sz, "JMR_Optex_MMF_%s", pszName);
       m_hfm = CreateFileMappingA(NULL, NULL, PAGE_READWRITE, 0,
                                  sizeof(*m_pSharedInfo), sz);
       if (m_hfm != NULL) {
          m_pSharedInfo = (PSHAREDINFO) MapViewOfFile(m_hfm, FILE_MAP_WRITE, 
                                                     0, 0, 0);
 
          // Note: SHAREDINFO's m_lLockCount, m_dwThreadId, and m_lRecurseCount
          // members need to be initialized to 0. Fortunately, a new pagefile 
          // MMF sets all of its data to 0 when created. This saves us from 
          // some thread synchronization work.
 
          if (m_pSharedInfo != NULL) 
             SetSpinCount(dwSpinCount);
       }
    }
    return((m_hevt != NULL) && (m_hfm != NULL) && (m_pSharedInfo != NULL));
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
 COptex::~COptex() {
 #ifdef _DEBUG
    if (m_pSharedInfo->m_dwThreadId != 0) DebugBreak();
 #endif
    UnmapViewOfFile(m_pSharedInfo);
    CloseHandle(m_hfm);
    CloseHandle(m_hevt);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
 void COptex::SetSpinCount(DWORD dwSpinCount) {
    if (!m_fUniprocessorHost)
       InterlockedExchange((PLONG) &m_pSharedInfo->m_dwSpinCount, dwSpinCount);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
 void COptex::Enter() {
 
    // Spin, trying to get the Optex
    if (TryEnter()) return;
 
    DWORD dwThreadId = GetCurrentThreadId();  // The calling thread's ID
    if (InterlockedIncrement(&m_pSharedInfo->m_lLockCount) == 1) {
 
       // Optex is unowned, let this thread own it once
       InterlockedExchange((PLONG) &m_pSharedInfo->m_dwThreadId, dwThreadId);
       m_pSharedInfo->m_lRecurseCount = 1;
 
    } else {
 
       // Optex is owned by a thread
       if (m_pSharedInfo->m_dwThreadId == dwThreadId) {
 
          // Optex is owned by this thread, own it again
          m_pSharedInfo->m_lRecurseCount++;
 
       } else {
 
          // Optex is owned by another thread
          // Wait for the Owning thread to release the Optex
          WaitForSingleObject(m_hevt, INFINITE);
 
          // We got ownership of the Optex
          InterlockedExchange((PLONG) &m_pSharedInfo->m_dwThreadId, 
                               dwThreadId);         // We own it now
          m_pSharedInfo->m_lRecurseCount = 1;       // We own it once
       }
    }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
 BOOL COptex::TryEnter() {
 
    DWORD dwThreadId = GetCurrentThreadId();  // The calling thread's ID
 
    // If the lock count is zero, the Optex is unowned and
    // this thread can become the Owner of it now.
    BOOL fThisThreadOwnsthe Optex = FALSE;
    DWORD dwSpinCount = m_pSharedInfo->m_dwSpinCount;
    do {
       fThisThreadOwnsthe Optex = (0 == (DWORD) 
          InterlockedCompareExchange((PVOID*) &m_pSharedInfo->m_lLockCount, 
                                      (PVOID) 1, (PVOID) 0)); 
 
       if (fThisThreadOwnsthe Optex) {
 
          // We now own the Optex
          InterlockedExchange((PLONG) &m_pSharedInfo->m_dwThreadId, 
                               dwThreadId);         // We own it
          m_pSharedInfo->m_lRecurseCount = 1;       // We own it once
       } else {
         // Some thread owns the Optex
         if (m_pSharedInfo->m_dwThreadId == dwThreadId) {
            // We already own the Optex
            InterlockedIncrement(&m_pSharedInfo->m_lLockCount);
            m_pSharedInfo->m_lRecurseCount++;   // We own it again
            fThisThreadOwnsthe Optex = TRUE;     // Return that we own the Optex
         }
      }
   } while (!fThisThreadOwnsthe Optex && (dwSpinCount-- > 0));

   // Return whether or not this thread owns the Optex
   return(fThisThreadOwnsthe Optex);
}

///////////////////////////////////////////////////////////////////////////////

void COptex::Leave() {
#ifdef _DEBUG
   if (m_pSharedInfo->m_dwThreadId != GetCurrentThreadId()) 
      DebugBreak();
#endif

   if (--m_pSharedInfo->m_lRecurseCount > 0) {

      // We still own the Optex
      InterlockedDecrement(&m_pSharedInfo->m_lLockCount);

   } else {

      // We don't own the Optex
      InterlockedExchange((PLONG) &m_pSharedInfo->m_dwThreadId, 0);
      if (InterlockedDecrement(&m_pSharedInfo->m_lLockCount) > 0) {
      // Other threads are waiting, wake one of the M
         SetEvent(m_hevt);
      }
   }
}
TestOptex.cpp

/******************************************************************************
Module name: TestOptex.cpp
Written by:  Jeffrey Richter
Purpose:     A simple app that tests the COptex class 
NOTE:        Run multiple instances of this app to fully test the COptex
******************************************************************************/
#include <windows.h>
#include "Optex.h"

///////////////////////////////////////////////////////////////////////////////

#pragma data_seg("Shared")
int g_n= 0;
DWORD g_dw[1024] = { 0 };
#pragma data_seg()

#pragma comment(linker, "/section:Shared,rws")

///////////////////////////////////////////////////////////////////////////////

void main() {
   COptex optex("TestOptex");
   while (TRUE) {
      optex.Enter();
      if (g_n == 1024) { optex.Leave(); break; }
      g_dw[g_n++] = GetCurrentProcessId();
      optex.Leave();
   }
   GetLastError();
}