sinstance.cpp
上传用户:lds876
上传日期:2013-05-25
资源大小:567k
文件大小:11k
源码类别:

P2P编程

开发平台:

Visual C++

  1. /*
  2. Module : SINSTANCE.CPP
  3. Purpose: Defines the implementation for an MFC wrapper classe
  4.          to do instance checking
  5. Created: PJN / 29-07-1998
  6. History: PJN / 25-03-2000 Neville Franks made the following changes. Contact nevf@getsoft.com, www.getsoft.com
  7.                           1. Changed #pragma error to #pragma message. Former wouldn't compile under VC6
  8.                           2. Replaced above #pragma with #include
  9.                           3. Added TrackFirstInstanceRunning(), MakeMMFFilename()
  10.          PJN / 27-03-2000 1. Fixed a potential handle leak where the file handle m_hPrevInstance was not being
  11.                           closed under certain circumstances.
  12.                           Neville Franks made the following changes. Contact nevf@getsoft.com, www.getsoft.com
  13.                           2. Split PreviousInstanceRunning() up into separate functions so we
  14.                           can call it without needing the MainFrame window.
  15.                           3. Changed ActivatePreviousInstance() to return hWnd.
  16.          PJN / 15-05-2000 1. Serialized access to all of the CSingleInstance class to prevent race conditions
  17.                           which can occur when you app is programatically spawned.
  18.          PJN / 17-05-2000 1. Updated sample to show how the code can be used for dialog based apps.
  19.          PJN / 01-01-2001 1. Added a number of asserts to CInstanceChecker::ActivatePreviousInstance
  20.                           2. Now includes copyright message in the source code and documentation.
  21.          PJN / 15-01-2001 1. Now allows multiple calls to PreviousInstanceRunning without ASSERTing
  22.                           2. Removed some unnecessary VERIFY's from ActivatePreviousInstance
  23.                           3. Made the MMF filename used modifiable via a virtual function GetMMFFilename 
  24.                           4. Made the window to track modifiable via a virtual function GetWindowToTrack
  25.                           5. Made destructor virtual since the introduction of other virtual functions in the class
  26.                           6. Removed a number of unnecessary verifies
  27.                           7. Changed the meaning of the return value from TrackFirstInstanceRunning
  28.          PJN / 17-06-2001 1. Moved most of the code from CInstanceChecker::CInstanceChecker to 
  29.                           CInstanceChecker::ActivateChecker. This allows client code to turn on or off the instance
  30.                           checking code easily. Thanks to Anders Rundegren for this addition.
  31.          PJN / 31-08-2001 1. made the name of the mutex which the class uses to serialize access to itself a paramter
  32.                           to the constructor. That way multiple independent apps do not block each other while
  33.                           they are calling into the CSingleInstance class. Thanks to Eugene Shmelyov for spotting
  34.                           this problem.
  35.          PJN / 23-03-2002 1. Provided a QuitPreviousInstance method. Thanks to Jon Bennett for providing this.
  36.          PJN / 30-10-2002 1. The name of the internal memory mapped file is now based on the Mutex name rather than
  37.                           the application name. An example: a client was writing a webcam application and wanted it to 
  38.                           run with multiple configuration for multiple camera support. So the app can run multiple times 
  39.                           as long as a special configuration is given on the command line. But for that configuration 
  40.                           only one instance is allowed. Using the application name for the memory mapped file was tying 
  41.                           the single instance to the app rather than the unique mutex name. Thanks to Frank Fesevur for 
  42.                           this nice update.
  43.          PJN / 06-02-2003 1. Was missing a call to ReleaseLock in CInstanceChecker::ActivatePreviousInstance. Thanks to 
  44.                           Pierrick Ingels for reporting this problem.
  45. Copyright (c) 1996 - 2003 by PJ Naughter.  (Web: www.naughter.com, Email: pjna@naughter.com)
  46. All rights reserved.
  47. Copyright / Usage Details:
  48. You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise) 
  49. when your product is released in binary form. You are allowed to modify the source code in any way you want 
  50. except you cannot modify the copyright details at the top of each module. If you want to distribute source 
  51. code with your application, then you are only allowed to distribute versions released by the author. This is 
  52. to maintain a single distribution point for the source code. 
  53. */
  54. /////////////////////////////////  Includes  //////////////////////////////////
  55. #include "stdafx.h"
  56. #include "sinstance.h"
  57. /////////////////////////////// Defines / Macros //////////////////////////////
  58. #ifdef _DEBUG
  59. #undef THIS_FILE
  60. static char BASED_CODE THIS_FILE[] = __FILE__;
  61. #define new DEBUG_NEW
  62. #endif
  63. ///////////////////////////////// Implementation //////////////////////////////
  64. //struct which is put into shared memory
  65. struct CWindowInstance
  66. {
  67.   HWND hMainWnd;
  68. };
  69. //Class which be used as a static to ensure that we
  70. //only close the file mapping at the very last chance
  71. class _INSTANCE_DATA
  72. {
  73. public:
  74.   _INSTANCE_DATA();
  75.   ~_INSTANCE_DATA();
  76.   Close();
  77. protected:
  78.   HANDLE hInstanceData;
  79.   friend class CInstanceChecker;
  80. };
  81. _INSTANCE_DATA::_INSTANCE_DATA()
  82. {
  83.   hInstanceData = NULL;
  84. }
  85. _INSTANCE_DATA::~_INSTANCE_DATA()
  86. {
  87.   if (hInstanceData != NULL)
  88.   {
  89.     ::CloseHandle(hInstanceData);
  90.     hInstanceData = NULL;
  91.   }
  92. }
  93. _INSTANCE_DATA::Close()
  94. {
  95.   if (hInstanceData != NULL)
  96.   {
  97.     ::CloseHandle(hInstanceData);
  98.     hInstanceData = NULL;
  99.   }
  100. }
  101. static _INSTANCE_DATA instanceData;
  102. void AppReleaseInstance()
  103. {
  104. instanceData.Close();
  105. }
  106. CInstanceChecker::CInstanceChecker(const CString& sMutexName) : m_executeMutex(FALSE, sMutexName)
  107. {
  108.   //Hive away the unique name as we will also be using it for the name of the memory mapped file
  109.   m_sName = sMutexName;
  110.   // Only one object of type CInstanceChecker should be created
  111.   ASSERT(instanceData.hInstanceData == NULL);
  112.   m_pExecuteLock = NULL;
  113. }
  114. void CInstanceChecker::ActivateChecker()
  115. {
  116.   ASSERT(m_pExecuteLock == NULL);
  117.   //Ensure there is only ever one CInstanceChecker instance 
  118.   //active at any one time throughout the system
  119.   m_pExecuteLock = new CSingleLock(&m_executeMutex, TRUE);
  120. }
  121. CInstanceChecker::~CInstanceChecker()
  122. {
  123.   //Free up the instance lock
  124.   ReleaseLock();
  125. }
  126. void CInstanceChecker::ReleaseLock()
  127. {
  128.   if (m_pExecuteLock)
  129.   {
  130.     delete m_pExecuteLock;
  131.     m_pExecuteLock = NULL;
  132.   }  
  133. }
  134. // Track the first instance of our App.
  135. // return TRUE on success, else FALSE
  136. BOOL CInstanceChecker::TrackFirstInstanceRunning()
  137. {
  138.   //If a previous instance is running, just return prematurely
  139.   if (PreviousInstanceRunning())
  140.     return FALSE;
  141.   //If this is the first instance then copy in our info into the shared memory
  142.   //First create the MMF
  143.   int nMMFSize = sizeof(CWindowInstance);
  144.   instanceData.hInstanceData = ::CreateFileMapping((HANDLE)0xFFFFFFFF, NULL, PAGE_READWRITE, 0, nMMFSize, GetMMFFilename());
  145.   if (instanceData.hInstanceData == NULL)
  146.   {
  147.     TRACE(_T("Failed to create the MMF even though this is the first instance, you might want to consider overriding GetMMFFilename()n"));
  148.     return FALSE;
  149.   }
  150.   //Open the MMF
  151.   CWindowInstance* pInstanceData = (CWindowInstance*) ::MapViewOfFile(instanceData.hInstanceData, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, nMMFSize);
  152.   ASSERT(pInstanceData != NULL);   //Opening the MMF should work
  153.   // Lock the data prior to updating it
  154.   CSingleLock dataLock(&m_instanceDataMutex, TRUE);
  155.   pInstanceData->hMainWnd = GetWindowToTrack();
  156.   ::UnmapViewOfFile(pInstanceData);
  157.   //Since this will be the last function that will be called 
  158.   //when this is the first instance we can release the lock
  159.   ReleaseLock();
  160.   return TRUE;
  161. }
  162. // Returns TRUE if a previous instance of the App is running.
  163. BOOL CInstanceChecker::PreviousInstanceRunning()
  164. {
  165.   //Try to open the MMF first to see if we are the second instance
  166.   HANDLE hPrevInstance = ::OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, GetMMFFilename());
  167.   BOOL bPreviousInstance = (hPrevInstance != NULL);
  168.   if (hPrevInstance)
  169.     CloseHandle(hPrevInstance);
  170.   return bPreviousInstance;
  171. }
  172. CString CInstanceChecker::GetMMFFilename()
  173. {
  174.   CString sMMF(_T("CInstanceChecker_MMF_"));
  175.   sMMF += m_sName;
  176.   return sMMF;
  177. }
  178. HWND CInstanceChecker::GetWindowToTrack()
  179. {
  180.   //By default the window tracked will be the standard AfxGetMainWnd()
  181.   ASSERT(AfxGetMainWnd() != NULL); //Did you forget to set up the mainfrm in InitInstance ?
  182.   return AfxGetMainWnd()->GetSafeHwnd();
  183. }
  184. // Activate the Previous Instance of our Application.
  185. HWND CInstanceChecker::ActivatePreviousInstance()
  186. {
  187.   //Try to open the previous instances MMF
  188.   HANDLE hPrevInstance = ::OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, GetMMFFilename());
  189.   if (hPrevInstance)
  190.   {
  191.     // Open up the MMF
  192.     int nMMFSize = sizeof(CWindowInstance);
  193.     CWindowInstance* pInstanceData = (CWindowInstance*) ::MapViewOfFile(hPrevInstance, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, nMMFSize);
  194.     if (pInstanceData != NULL) //Opening the MMF should work
  195.     {
  196.       //Lock the data prior to reading from it
  197.       CSingleLock dataLock(&m_instanceDataMutex, TRUE);
  198.       //activate the old window
  199.       ASSERT(pInstanceData->hMainWnd); //Something gone wrong with the MMF
  200.       HWND hWindow = pInstanceData->hMainWnd;
  201.       if (hWindow)
  202.       {
  203.         CWnd wndPrev;
  204.         wndPrev.Attach(hWindow);
  205.         CWnd* pWndChild = wndPrev.GetLastActivePopup();
  206.         // Restore the focus to the previous instance and bring it to the foreground
  207.         if (wndPrev.IsIconic())
  208.           wndPrev.ShowWindow(SW_RESTORE);
  209.         pWndChild->SetForegroundWindow();
  210.         //Detach the CWnd we were using
  211.         wndPrev.Detach();
  212.       }
  213.       //Unmap the MMF we were using
  214.       ::UnmapViewOfFile(pInstanceData);
  215.       //Close the file handle now that we 
  216.       ::CloseHandle(hPrevInstance);
  217.       //When we have activate the previous instance, we can release the lock
  218.       ReleaseLock();
  219.       //return the Window handle of the previous instance
  220.       return hWindow;
  221.     }
  222.     //Close the file handle now that we 
  223.     ::CloseHandle(hPrevInstance);
  224.     //When we have activate the previous instance, we can release the lock
  225.     ReleaseLock();
  226.   }
  227.   return NULL;
  228. }
  229. void CInstanceChecker::QuitPreviousInstance(int nExitCode)
  230. {
  231.   //Try to open the previous instances MMF
  232.   HANDLE hPrevInstance = ::OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, GetMMFFilename());
  233. if (hPrevInstance)
  234. {
  235. // Open up the MMF
  236. int nMMFSize = sizeof(CWindowInstance);
  237. CWindowInstance* pInstanceData = (CWindowInstance*) ::MapViewOfFile(hPrevInstance, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, nMMFSize);
  238. if (pInstanceData != NULL) //Opening the MMF should work
  239. {
  240.   // Lock the data prior to reading from it
  241.   CSingleLock dataLock(&m_instanceDataMutex, TRUE);
  242.   //activate the old window
  243.   ASSERT(pInstanceData->hMainWnd); //Something gone wrong with the MMF
  244.   HWND hWindow = pInstanceData->hMainWnd;
  245.       //Ask it to exit
  246.   if (hWindow)
  247.   PostMessage(hWindow, WM_QUIT, nExitCode, 0);
  248.   }
  249.     //Close the file handle now that we 
  250.     ::CloseHandle(hPrevInstance);
  251.   }
  252. }