672 lines
44 KiB
C++
672 lines
44 KiB
C++
// ==========================================================================
|
||
// Class Implementation : COXInstanceManager
|
||
// ==========================================================================
|
||
|
||
// Source file : OXInstanceManager.cpp
|
||
|
||
// Version: 9.3
|
||
|
||
// This software along with its related components, documentation and files ("The Libraries")
|
||
// is ?1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
|
||
// governed by a software license agreement ("Agreement"). Copies of the Agreement are
|
||
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
|
||
// to obtain this file, or directly from our office. For a copy of the license governing
|
||
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.
|
||
|
||
// //////////////////////////////////////////////////////////////////////////
|
||
|
||
#include "stdafx.h"
|
||
#include "OXInstanceManager.h"
|
||
#include "UTB64bit.h"
|
||
|
||
#ifdef _DEBUG
|
||
#undef THIS_FILE
|
||
static char BASED_CODE THIS_FILE[] = __FILE__;
|
||
#endif
|
||
|
||
IMPLEMENT_DYNAMIC(COXInstanceManager, CObject)
|
||
|
||
#define new DEBUG_NEW
|
||
|
||
static const TCHAR szInstanceListMutexPrefix[] = _T("COXInstanceManager_InstanceList_Mutex_");
|
||
static const TCHAR szAdditionalDataMutexPrefix[] = _T("COXInstanceManager_Additional_Mutex_");
|
||
static const TCHAR szFileMapPrefix[] = _T("COXInstanceManager_FileMap_");
|
||
|
||
/////////////////////////////////////////////////////////////////////////////
|
||
// Definition of static members
|
||
const LPCTSTR COXInstanceManager::m_pszInstanceListMutexPrefix = szInstanceListMutexPrefix;
|
||
const LPCTSTR COXInstanceManager::m_pszAdditionalDataMutexPrefix = szAdditionalDataMutexPrefix;
|
||
const LPCTSTR COXInstanceManager::m_pszFileMapPrefix = szFileMapPrefix;
|
||
|
||
// Data members -------------------------------------------------------------
|
||
// protected:
|
||
// CString m_sApplicationName;
|
||
// --- A unique name identifying all the instances of an application
|
||
|
||
// DWORD m_nInstanceListSize;
|
||
// --- The complete size used for the CInstanceList object.
|
||
// This number is rounded to the allocation granularity
|
||
|
||
// DWORD m_nAdditionalDataSize;
|
||
// --- The complete size used for the additional data
|
||
// This number is rounded to the allocation granularity
|
||
|
||
// CMutex m_instanceListMutex;
|
||
// --- The mutexused to synchronize access to the list of instances
|
||
|
||
// CMutex m_additionalDataMutex;
|
||
// --- The mutex used to synchronize access to the additional data
|
||
|
||
// HANDLE m_hFileMap;
|
||
// --- The file mapping object
|
||
|
||
// LPVOID m_pInstanceListView;
|
||
// --- The view on the file mapping used to access the shared instance list
|
||
|
||
// LPVOID m_pAdditionalDataView;
|
||
// --- The view on the file mapping used to access the additional data
|
||
|
||
// private:
|
||
|
||
// Member functions ---------------------------------------------------------
|
||
// public:
|
||
|
||
// ... To make sure inly one object is created per instance
|
||
static BOOL bInstanceManagerCreated = FALSE;
|
||
|
||
COXInstanceManager::COXInstanceManager(LPCTSTR pszApplicationName, DWORD nMinAdditionalDataSize /* = 0 */)
|
||
:
|
||
m_sApplicationName(pszApplicationName),
|
||
m_nAdditionalDataSize(nMinAdditionalDataSize),
|
||
m_instanceListMutex(FALSE, m_pszInstanceListMutexPrefix + m_sApplicationName),
|
||
m_additionalDataMutex(FALSE, m_pszAdditionalDataMutexPrefix + m_sApplicationName),
|
||
m_hFileMap(NULL),
|
||
m_pInstanceListView(NULL),
|
||
m_pAdditionalDataView(NULL)
|
||
{
|
||
// ... You should supply a unique name for the application
|
||
ASSERT((pszApplicationName != NULL) && (*pszApplicationName != _T('\0')));
|
||
#ifdef _DEBUG
|
||
// ... Only one object of the COXInstanceManager class may be created per instance
|
||
ASSERT(bInstanceManagerCreated == FALSE);
|
||
bInstanceManagerCreated = TRUE;
|
||
#endif // _DEBUG
|
||
ASSERT_VALID(this);
|
||
|
||
// Compute the size of the instance list
|
||
m_nInstanceListSize = sizeof(CInstanceList);
|
||
|
||
// ... Round the size to a multiple of the page size
|
||
SYSTEM_INFO systemInfo;
|
||
::ZeroMemory(&systemInfo, sizeof(systemInfo));
|
||
::GetSystemInfo(&systemInfo);
|
||
|
||
if (m_nInstanceListSize % systemInfo.dwAllocationGranularity != 0)
|
||
m_nInstanceListSize = m_nInstanceListSize / systemInfo.dwAllocationGranularity +
|
||
systemInfo.dwAllocationGranularity;
|
||
else
|
||
m_nInstanceListSize = m_nInstanceListSize / systemInfo.dwAllocationGranularity;
|
||
|
||
if (m_nAdditionalDataSize % systemInfo.dwAllocationGranularity != 0)
|
||
m_nAdditionalDataSize = m_nAdditionalDataSize / systemInfo.dwAllocationGranularity +
|
||
systemInfo.dwAllocationGranularity;
|
||
else
|
||
m_nAdditionalDataSize = m_nAdditionalDataSize / systemInfo.dwAllocationGranularity;
|
||
|
||
// Create file map in memory
|
||
DWORD nTotalSize = m_nInstanceListSize + m_nAdditionalDataSize;
|
||
// ... Total size must also be a multiple of the page size
|
||
ASSERT(nTotalSize % systemInfo.dwAllocationGranularity == 0);
|
||
CString sFileMapName = m_pszFileMapPrefix + m_sApplicationName;
|
||
m_hFileMap = ::CreateFileMapping((HANDLE)(INT_PTR)0xFFFFFFFF, NULL,
|
||
PAGE_READWRITE | SEC_COMMIT, 0, nTotalSize, sFileMapName);
|
||
BOOL bAlreadyExists = (::GetLastError() == ERROR_ALREADY_EXISTS);
|
||
|
||
#ifdef _DEBUG
|
||
if (m_hFileMap == NULL)
|
||
TRACE1("COXInstanceManager::COXInstanceManager : No file map could be created (error %i)\n",
|
||
::GetLastError());
|
||
#endif // _DEBUG
|
||
|
||
if (!bAlreadyExists)
|
||
InitializeInstanceList();
|
||
|
||
// Add this instance to the list
|
||
AddInstanceToList(GetCurrentInstanceID());
|
||
}
|
||
|
||
BOOL COXInstanceManager::HasPreviousInstance()
|
||
{
|
||
return (1 < GetNumberOfInstances());
|
||
}
|
||
|
||
DWORD COXInstanceManager::GetNumberOfInstances()
|
||
{
|
||
// Get a pointer to the list of instances
|
||
if (!GetInstanceList())
|
||
return FALSE;
|
||
|
||
// ... Lock the list
|
||
CSingleLock listLock(&m_instanceListMutex, TRUE);
|
||
|
||
// Get the total number of instances in the list
|
||
CInstanceList* pInstanceList = (CInstanceList*)m_pInstanceListView;
|
||
ASSERT(pInstanceList->m_nCurrentNumInstances <= OX_MAX_NUM_INSTANCES_IN_LIST);
|
||
DWORD nCurrentNumInstances = pInstanceList->m_nCurrentNumInstances;
|
||
|
||
#ifdef _DEBUG
|
||
if (pInstanceList->m_nCurrentNumInstances == OX_MAX_NUM_INSTANCES_IN_LIST)
|
||
TRACE1("COXInstanceManager::GetNumberOfInstances : Max number reached (%i), extra may be ignored\n",
|
||
OX_MAX_NUM_INSTANCES_IN_LIST);
|
||
#endif
|
||
|
||
// Immediately unmap the view to protect against dangerous pointers
|
||
ReleaseInstanceList();
|
||
|
||
return nCurrentNumInstances;
|
||
}
|
||
|
||
DWORD COXInstanceManager::GetMaxAllowedInstances()
|
||
{
|
||
// Get a pointer to the list of instances
|
||
if (!GetInstanceList())
|
||
return 0;
|
||
|
||
// ... Lock the list
|
||
CSingleLock listLock(&m_instanceListMutex, TRUE);
|
||
|
||
// Get the total number of instances in the list
|
||
CInstanceList* pInstanceList = (CInstanceList*)m_pInstanceListView;
|
||
ASSERT(pInstanceList->m_nCurrentNumInstances <= OX_MAX_NUM_INSTANCES_IN_LIST);
|
||
DWORD nMaxAllowedInstances = pInstanceList->m_nMaxAllowedInstances;
|
||
|
||
// Immediately unmap the view to protect against dangerous pointers
|
||
ReleaseInstanceList();
|
||
|
||
return nMaxAllowedInstances;
|
||
}
|
||
|
||
BOOL COXInstanceManager::SetMaxAllowedInstances(DWORD nMaxAllowedInstances,
|
||
BOOL bCloseExtra /* = TRUE */)
|
||
{
|
||
// Get a pointer to the list of instances
|
||
if (!GetInstanceList())
|
||
return FALSE;
|
||
|
||
#ifdef _DEBUG
|
||
if (OX_MAX_NUM_INSTANCES_IN_LIST < nMaxAllowedInstances)
|
||
TRACE2("COXInstanceManager::SetMaxAllowedInstances : Trying to set max allowable number (%i)higher than process list size (%i), extra may be ignored\n",
|
||
nMaxAllowedInstances, OX_MAX_NUM_INSTANCES_IN_LIST);
|
||
#endif
|
||
|
||
// ... Lock the list
|
||
CSingleLock listLock(&m_instanceListMutex, TRUE);
|
||
|
||
// Get the total number of instances in the list
|
||
CInstanceList* pInstanceList = (CInstanceList*)m_pInstanceListView;
|
||
ASSERT(pInstanceList->m_nCurrentNumInstances <= OX_MAX_NUM_INSTANCES_IN_LIST);
|
||
pInstanceList->m_nMaxAllowedInstances = nMaxAllowedInstances;
|
||
|
||
// Get a copy off the data before we release the instancelist
|
||
CDWordArray instanceColl;
|
||
DWORD nCurrentNumInstances = pInstanceList->m_nCurrentNumInstances;
|
||
instanceColl.SetSize(pInstanceList->m_nCurrentNumInstances);
|
||
::CopyMemory(instanceColl.GetData(), pInstanceList->m_rgPID, pInstanceList->m_nCurrentNumInstances * sizeof(DWORD));
|
||
|
||
// Immediately unmap the view to protect against dangerous pointers
|
||
ReleaseInstanceList();
|
||
listLock.Unlock();
|
||
|
||
// If their are currently more instances running than allowed, we will close some
|
||
int nInstancesToKill = nCurrentNumInstances - nMaxAllowedInstances;
|
||
if (bCloseExtra && (0 < nInstancesToKill))
|
||
{
|
||
// ... Iterate the collection backwards (because we are deleting items)
|
||
DWORD nThisPID = GetCurrentInstanceID();
|
||
DWORD nInstanceID = 0;
|
||
int nInstanceIndex = PtrToInt(instanceColl.GetSize() - 1);
|
||
while ((0 <= nInstanceIndex) && (0 < nInstancesToKill))
|
||
{
|
||
nInstanceID = instanceColl.GetAt(nInstanceIndex);
|
||
// ... Kill the instance if it is not this instance
|
||
if ((nInstanceID != nThisPID) && (CloseInstance(nInstanceID)) )
|
||
nInstancesToKill--;
|
||
nInstanceIndex--;
|
||
}
|
||
|
||
if (0 < nInstancesToKill)
|
||
{
|
||
// ... We we still have not killed enough instances, try to kill this instance
|
||
if (CloseInstance(nThisPID))
|
||
nInstancesToKill--;
|
||
}
|
||
|
||
#ifdef _DEBUG
|
||
if (0 < nInstancesToKill)
|
||
TRACE0("COXInstanceManager::SetMaxAllowedInstances : Not enough instnaces could be closed\n");
|
||
#endif
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
BOOL COXInstanceManager::GetInstanceCollection(CDWordArray& instanceColl)
|
||
{
|
||
// Get a pointer to the list of instances
|
||
if (!GetInstanceList())
|
||
return FALSE;
|
||
|
||
// ... Lock the list
|
||
CSingleLock listLock(&m_instanceListMutex, TRUE);
|
||
|
||
// Get the total number of instances in the list
|
||
// ... First DWORD in list is the number of items, followed by the PIDs
|
||
CInstanceList* pInstanceList = (CInstanceList*)m_pInstanceListView;
|
||
ASSERT(pInstanceList->m_nCurrentNumInstances <= OX_MAX_NUM_INSTANCES_IN_LIST);
|
||
|
||
// Fill the result collection
|
||
instanceColl.SetSize(pInstanceList->m_nCurrentNumInstances);
|
||
::CopyMemory(instanceColl.GetData(), pInstanceList->m_rgPID, pInstanceList->m_nCurrentNumInstances * sizeof(DWORD));
|
||
|
||
// Immediately unmap the view to protect against dangerous pointers
|
||
ReleaseInstanceList();
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
BOOL COXInstanceManager::CheckMaxAllowedInstances(BOOL bActivatePrevious /* = TRUE */)
|
||
{
|
||
BOOL bMaxExceeded = FALSE;
|
||
|
||
// Get a pointer to the list of instances
|
||
if (!GetInstanceList())
|
||
return FALSE;
|
||
|
||
// ... Lock the list
|
||
CSingleLock listLock(&m_instanceListMutex, TRUE);
|
||
|
||
// Get the total number of instances in the list
|
||
CInstanceList* pInstanceList = (CInstanceList*)m_pInstanceListView;
|
||
ASSERT(pInstanceList->m_nCurrentNumInstances <= OX_MAX_NUM_INSTANCES_IN_LIST);
|
||
bMaxExceeded = (pInstanceList->m_nMaxAllowedInstances < pInstanceList->m_nCurrentNumInstances);
|
||
|
||
if (bMaxExceeded && bActivatePrevious)
|
||
{
|
||
// Activate a previous instance
|
||
DWORD nThisPID = GetCurrentInstanceID();
|
||
DWORD nPID = 0;
|
||
if (0 < pInstanceList->m_nCurrentNumInstances)
|
||
nPID = pInstanceList->m_rgPID[0];
|
||
if (nPID == nThisPID)
|
||
{
|
||
nPID = 0;
|
||
if (1 < pInstanceList->m_nCurrentNumInstances)
|
||
nPID = pInstanceList->m_rgPID[1];
|
||
ASSERT(nPID != nThisPID);
|
||
}
|
||
|
||
if (nPID != 0)
|
||
{
|
||
// Another instance was found : activate it
|
||
HWND hTopLevelWnd = GetMainWindow(nPID);
|
||
if (hTopLevelWnd != NULL)
|
||
{
|
||
::SetForegroundWindow(hTopLevelWnd);
|
||
if(CWnd::FromHandle(hTopLevelWnd)->GetStyle() & WS_MINIMIZE)
|
||
{
|
||
::ShowWindow(hTopLevelWnd,SW_RESTORE);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Immediately unmap the view to protect against dangerous pointers
|
||
ReleaseInstanceList();
|
||
|
||
return bMaxExceeded;
|
||
}
|
||
|
||
HWND COXInstanceManager::GetMainWindow(DWORD_PTR nPID)
|
||
{
|
||
// First find a top level window of the specified instance
|
||
CInstanceWindow instanceWindow;
|
||
instanceWindow.m_nPID = nPID;
|
||
instanceWindow.m_hMainWnd = NULL;
|
||
|
||
::EnumWindows(&EnumMainWindows, (LPARAM)&instanceWindow);
|
||
|
||
#ifdef _DEBUG
|
||
if (instanceWindow.m_hMainWnd == NULL)
|
||
TRACE1("COXInstanceManager::GetMainWindow : No main window found for instance %i\n", nPID);
|
||
#endif // _DEBUG
|
||
|
||
return instanceWindow.m_hMainWnd;
|
||
}
|
||
|
||
BOOL COXInstanceManager::CloseInstance(DWORD_PTR nPID)
|
||
{
|
||
// ... Assume failure
|
||
BOOL bSuccess = FALSE;
|
||
|
||
HWND hMainWnd = GetMainWindow(nPID);
|
||
if (hMainWnd != NULL)
|
||
{
|
||
// ... Only try to close enabled windows
|
||
// A window will be disabled e.g. when it owns an open modal dialog
|
||
// Closing the main window at this point may be dangerous
|
||
// For more info see MSDN :
|
||
// * Terminating Windows-Based Application from Another App (PSS ID Number: Q92528)
|
||
// * Dialog Box Default Message Instanceing : WM_CLOSE
|
||
if (::IsWindowEnabled(hMainWnd))
|
||
{
|
||
::PostMessage(hMainWnd, WM_CLOSE, 0, 0);
|
||
bSuccess = TRUE;
|
||
}
|
||
}
|
||
|
||
#ifdef _DEBUG
|
||
if (::IsWindow(hMainWnd) && !::IsWindowEnabled(hMainWnd))
|
||
TRACE1("COXInstanceManager::CloseInstance : Main window of instance %i is disabled, failing\n", nPID);
|
||
#endif // _DEBUG
|
||
|
||
return bSuccess;
|
||
}
|
||
|
||
DWORD COXInstanceManager::GetCurrentInstanceID()
|
||
{
|
||
return ::GetCurrentProcessId();
|
||
}
|
||
|
||
DWORD COXInstanceManager::GetAdditionalDataSize() const
|
||
{
|
||
return m_nAdditionalDataSize;
|
||
}
|
||
|
||
LPVOID COXInstanceManager::GetAdditionalData()
|
||
{
|
||
if (m_pAdditionalDataView != NULL)
|
||
return m_pAdditionalDataView;
|
||
|
||
if (m_hFileMap == NULL)
|
||
{
|
||
TRACE0("COXInstanceManager::GetAdditionalData : No file mapping could be created, returning NULL\n");
|
||
return NULL;
|
||
}
|
||
|
||
// Create new view of file mapping (additional data is located after the instance list)
|
||
m_pAdditionalDataView = ::MapViewOfFile(m_hFileMap, FILE_MAP_READ | FILE_MAP_WRITE,
|
||
0, m_nInstanceListSize, m_nAdditionalDataSize);
|
||
|
||
#ifdef _DEBUG
|
||
if (m_pAdditionalDataView != NULL)
|
||
ASSERT(AfxIsValidAddress(m_pAdditionalDataView, m_nAdditionalDataSize));
|
||
else
|
||
TRACE1("COXInstanceManager::GetAdditionalData : No view of file map could be created (error %i), returning NULL\n",
|
||
::GetLastError());
|
||
#endif // _DEBUG
|
||
|
||
return m_pAdditionalDataView;
|
||
}
|
||
|
||
void COXInstanceManager::ReleaseAdditionalData()
|
||
{
|
||
if (m_pAdditionalDataView != NULL)
|
||
{
|
||
VERIFY(::UnmapViewOfFile(m_pAdditionalDataView));
|
||
m_pAdditionalDataView = NULL;
|
||
}
|
||
}
|
||
|
||
CMutex& COXInstanceManager::GetAdditionalDataMutex()
|
||
{
|
||
return m_additionalDataMutex;
|
||
}
|
||
|
||
#ifdef _DEBUG
|
||
void COXInstanceManager::AssertValid() const
|
||
{
|
||
CObject::AssertValid();
|
||
}
|
||
|
||
void COXInstanceManager::Dump(CDumpContext& dc) const
|
||
{
|
||
CObject::Dump(dc);
|
||
}
|
||
#endif //_DEBUG
|
||
|
||
COXInstanceManager::~COXInstanceManager()
|
||
{
|
||
// Remove this instance from the list
|
||
RemoveInstanceFromList(GetCurrentInstanceID());
|
||
|
||
// ... View of instance list data should have been closed after use
|
||
ASSERT(m_pInstanceListView == NULL);
|
||
|
||
// Close view of additional data if not done yet
|
||
ReleaseAdditionalData();
|
||
|
||
// Close the file map
|
||
if (m_hFileMap != NULL)
|
||
{
|
||
VERIFY(::CloseHandle(m_hFileMap));
|
||
m_hFileMap = NULL;
|
||
}
|
||
|
||
bInstanceManagerCreated = FALSE;
|
||
}
|
||
|
||
// protected:
|
||
BOOL COXInstanceManager::GetInstanceList()
|
||
// --- In :
|
||
// --- Out :
|
||
// --- Returns : Whether it succeeded or not
|
||
// --- Effect : This functions gets a pointer to the instance list and stores it
|
||
// in the data member m_pInstanceListView
|
||
// The pointer is valid until the next call to ReleaseInstanceList()
|
||
{
|
||
// ... Should have been unmapped after its last use
|
||
ASSERT(m_pInstanceListView == NULL);
|
||
|
||
if (m_hFileMap == NULL)
|
||
{
|
||
TRACE0("COXInstanceManager::GetInstanceListData : No file mapping could be created, returning NULL\n");
|
||
return NULL;
|
||
}
|
||
|
||
// Create new view of file mapping (additional data is located after the instance list)
|
||
m_pInstanceListView = ::MapViewOfFile(m_hFileMap, FILE_MAP_READ | FILE_MAP_WRITE,
|
||
0, 0, m_nInstanceListSize);
|
||
|
||
#ifdef _DEBUG
|
||
if (m_pInstanceListView != NULL)
|
||
ASSERT(AfxIsValidAddress(m_pInstanceListView, m_nInstanceListSize));
|
||
else
|
||
TRACE1("COXInstanceManager::GetInstanceListData : No view of file map could be created (error %i), returning NULL\n",
|
||
::GetLastError());
|
||
#endif // _DEBUG
|
||
|
||
return (m_pInstanceListView != NULL);
|
||
}
|
||
|
||
void COXInstanceManager::ReleaseInstanceList()
|
||
// --- In :
|
||
// --- Out :
|
||
// --- Returns :
|
||
// --- Effect : Releases the pointer to the instance list
|
||
// The value of the data member m_pInstanceListView is no longer valid
|
||
{
|
||
if (m_pInstanceListView != NULL)
|
||
{
|
||
VERIFY(::UnmapViewOfFile(m_pInstanceListView));
|
||
m_pInstanceListView = NULL;
|
||
}
|
||
}
|
||
|
||
BOOL COXInstanceManager::InitializeInstanceList()
|
||
// --- In :
|
||
// --- Out :
|
||
// --- Returns : Whether it succeeded or not
|
||
// --- Effect : Initializes the shared data of the instance list
|
||
{
|
||
BOOL bSuccess = FALSE;
|
||
|
||
// Get a pointer to the list of instances
|
||
if (!GetInstanceList())
|
||
return FALSE;
|
||
|
||
// ... Lock the list
|
||
CSingleLock listLock(&m_instanceListMutex, TRUE);
|
||
|
||
// Initailze the instance list
|
||
CInstanceList* pInstanceList = (CInstanceList*)m_pInstanceListView;
|
||
// ... Default max allowed instances to 1
|
||
pInstanceList->m_nMaxAllowedInstances = 1;
|
||
pInstanceList->m_nCurrentNumInstances = 0;
|
||
::ZeroMemory(pInstanceList->m_rgPID, sizeof(pInstanceList->m_rgPID));
|
||
|
||
// Immediately unmap the view to protect against dangerous pointers
|
||
ReleaseInstanceList();
|
||
|
||
return bSuccess;
|
||
}
|
||
|
||
BOOL COXInstanceManager::AddInstanceToList(DWORD nPID)
|
||
// --- In : nPID : The instance (process) ID
|
||
// --- Out :
|
||
// --- Returns : Whether it succeeded or not
|
||
// --- Effect : Adds the specified instance ID to the list
|
||
{
|
||
// ... Assume failure
|
||
BOOL bSuccess = FALSE;
|
||
|
||
// Get a pointer to the list of instances
|
||
if (!GetInstanceList())
|
||
return FALSE;
|
||
|
||
// ... Lock the list
|
||
CSingleLock listLock(&m_instanceListMutex, TRUE);
|
||
|
||
// Add PID to the end of the list
|
||
CInstanceList* pInstanceList = (CInstanceList*)m_pInstanceListView;
|
||
ASSERT(pInstanceList->m_nCurrentNumInstances <= OX_MAX_NUM_INSTANCES_IN_LIST);
|
||
// ... Only add when there is space left
|
||
if (pInstanceList->m_nCurrentNumInstances < OX_MAX_NUM_INSTANCES_IN_LIST)
|
||
{
|
||
for(int nIndex=0; nIndex<(int)pInstanceList->m_nCurrentNumInstances; nIndex++)
|
||
{
|
||
::PostMessage(GetMainWindow(pInstanceList->m_rgPID[nIndex]),
|
||
WM_OX_INSTANCE_CREATED,(WPARAM)NULL,(LPARAM)nPID);
|
||
}
|
||
pInstanceList->m_rgPID[pInstanceList->m_nCurrentNumInstances] = nPID;
|
||
pInstanceList->m_nCurrentNumInstances++;
|
||
bSuccess = TRUE;
|
||
}
|
||
else
|
||
{
|
||
TRACE1("COXInstanceManager::AddInstanceToList : Max number of trackable instances (%i) reached, extra ignored\n",
|
||
OX_MAX_NUM_INSTANCES_IN_LIST);
|
||
}
|
||
ASSERT(pInstanceList->m_nCurrentNumInstances <= OX_MAX_NUM_INSTANCES_IN_LIST);
|
||
|
||
// Immediately unmap the view to protect against dangerous pointers
|
||
ReleaseInstanceList();
|
||
|
||
return bSuccess;
|
||
}
|
||
|
||
BOOL COXInstanceManager::RemoveInstanceFromList(DWORD nPID)
|
||
// --- In : nPID : The instance (process) ID
|
||
// --- Out :
|
||
// --- Returns : Whether it succeeded or not
|
||
// --- Effect : Removes the specified instance ID from the list
|
||
{
|
||
BOOL bSuccess = FALSE;
|
||
|
||
// Get a pointer to the list of instances
|
||
if (!GetInstanceList())
|
||
return FALSE;
|
||
|
||
// ... Lock the list
|
||
CSingleLock listLock(&m_instanceListMutex, TRUE);
|
||
|
||
// Search for the specified instance ID
|
||
CInstanceList* pInstanceList = (CInstanceList*)m_pInstanceListView;
|
||
ASSERT(pInstanceList->m_nCurrentNumInstances <= OX_MAX_NUM_INSTANCES_IN_LIST);
|
||
DWORD nInstanceIndex = 0;
|
||
while ((nInstanceIndex < pInstanceList->m_nCurrentNumInstances) &&
|
||
(pInstanceList->m_rgPID[nInstanceIndex] != nPID))
|
||
{
|
||
nInstanceIndex++;
|
||
}
|
||
|
||
if (nInstanceIndex < pInstanceList->m_nCurrentNumInstances)
|
||
{
|
||
DWORD dwRemovedPID=pInstanceList->m_rgPID[nInstanceIndex];
|
||
// Move all the following ID one position to the beginning and set
|
||
// the last one to zero
|
||
DWORD* pFoundInstance = &pInstanceList->m_rgPID[nInstanceIndex];
|
||
// ... Move 1 to the top
|
||
::MoveMemory(pFoundInstance, pFoundInstance+1,
|
||
(pInstanceList->m_nCurrentNumInstances-nInstanceIndex-1)*sizeof(DWORD));
|
||
// .. Add a new 0
|
||
pInstanceList->m_rgPID[pInstanceList->m_nCurrentNumInstances]=0;
|
||
ASSERT(1 <= pInstanceList->m_nCurrentNumInstances);
|
||
// ...Decrement the current number
|
||
pInstanceList->m_nCurrentNumInstances--;
|
||
bSuccess = TRUE;
|
||
|
||
for(int nIndex=0; nIndex<(int)pInstanceList->m_nCurrentNumInstances; nIndex++)
|
||
{
|
||
::PostMessage(GetMainWindow(pInstanceList->m_rgPID[nIndex]),
|
||
WM_OX_INSTANCE_DESTROYED,(WPARAM)NULL,(LPARAM)dwRemovedPID);
|
||
}
|
||
}
|
||
else
|
||
TRACE1("COXInstanceManager::RemoveInstanceFromList : Instances (%i) not found, ignored\n", nPID);
|
||
ASSERT(pInstanceList->m_nCurrentNumInstances <= OX_MAX_NUM_INSTANCES_IN_LIST);
|
||
|
||
// Immediately unmap the view to protect against dangerous pointers
|
||
ReleaseInstanceList();
|
||
|
||
return bSuccess;
|
||
}
|
||
|
||
BOOL CALLBACK COXInstanceManager::EnumMainWindows(HWND hWnd, LPARAM lParam)
|
||
// --- In : hWnd : A top-level window
|
||
// lParam : Additioanl data (pointer to a CInstanceWindow object)
|
||
// --- Out :
|
||
// --- Returns : Whether to continue iterating
|
||
// --- Effect : This function is called for every top-level window
|
||
{
|
||
#if defined (_WINDLL)
|
||
#if defined (_AFXDLL)
|
||
AFX_MANAGE_STATE(AfxGetAppModuleState());
|
||
#else
|
||
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
||
#endif
|
||
#endif
|
||
|
||
CInstanceWindow* pInstanceWindow = (CInstanceWindow*)lParam;
|
||
ASSERT(AfxIsValidAddress(pInstanceWindow, sizeof(CInstanceWindow)));
|
||
|
||
// We will search for a toplevel window of the specified instance
|
||
// Thiw window should be not-owned (to exclude dialogs)
|
||
DWORD nWindowPID = 0;
|
||
::GetWindowThreadProcessId(hWnd, &nWindowPID);
|
||
if ((nWindowPID==pInstanceWindow->m_nPID) &&
|
||
(::GetWindow(hWnd,GW_OWNER)==NULL) &&
|
||
(::GetWindowLongPtr(hWnd,GWL_EXSTYLE) & WS_EX_TOOLWINDOW)==0 &&
|
||
(::GetWindowLongPtr(hWnd,GWL_STYLE) & WS_VISIBLE)==WS_VISIBLE)
|
||
{
|
||
pInstanceWindow->m_hMainWnd = hWnd;
|
||
// ... Found, stop looking
|
||
return FALSE;
|
||
}
|
||
// ... Not found, keep on looking
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
// private:
|
||
|
||
// ==========================================================================
|