You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1436 lines
36 KiB
1436 lines
36 KiB
//+----------------------------------------------------------------------------
|
|
//
|
|
// File: CONTABLE.CPP
|
|
//
|
|
// Module: CMCONTBL.LIB
|
|
//
|
|
// Synopsis: Implements the CM connection table (CConnectionTable). The connection
|
|
// table is a list of active conenctions stored in a (memory only) memory
|
|
// mapped file, and shared by the various CM components in order to
|
|
// manage CM connections.
|
|
//
|
|
// Copyright (c) 1998-1999 Microsoft Corporation
|
|
//
|
|
// Author: nickball Created 02/02/98
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
|
|
#include <windows.h>
|
|
|
|
#include "contable.h"
|
|
#include "cmdebug.h"
|
|
#include "cmutil.h"
|
|
#include "uapi.h"
|
|
#include "setacl.h"
|
|
|
|
#if 0
|
|
#include "DumpSecInfo.cpp"
|
|
#endif
|
|
|
|
#define CONN_TABLE_NAME TEXT("CmConnectionTable")
|
|
#define CONN_TABLE_OPEN TEXT("CmConnectionOpen")
|
|
|
|
#define CONN_TABLE_NAME_WIN2K_ABOVE TEXT("Global\\CmConnectionTable")
|
|
#define CONN_TABLE_OPEN_WIN2K_ABOVE TEXT("Global\\CmConnectionOpen")
|
|
|
|
static const int MAX_LOCK_WAIT = 1000; // wait timeout in milliseconds
|
|
|
|
//
|
|
// Constructor and destructor
|
|
//
|
|
CConnectionTable::CConnectionTable()
|
|
{
|
|
CMTRACE(TEXT("CConnectionTable::CConnectionTable()"));
|
|
|
|
//
|
|
// Initialize our data members
|
|
//
|
|
|
|
m_hMap = NULL;
|
|
m_pConnTable = NULL;
|
|
m_fLocked = FALSE;
|
|
m_hEvent = NULL;
|
|
}
|
|
|
|
CConnectionTable::~CConnectionTable()
|
|
{
|
|
CMTRACE(TEXT("CConnectionTable::~CConnectionTable()"));
|
|
|
|
//
|
|
// Data should have been cleaned up in Close, etc. Double-Check
|
|
//
|
|
|
|
MYDBGASSERT(NULL == m_pConnTable);
|
|
MYDBGASSERT(NULL == m_hMap);
|
|
MYDBGASSERT(FALSE == m_fLocked);
|
|
MYDBGASSERT(NULL == m_hEvent);
|
|
|
|
//
|
|
// Release handles and pointers
|
|
//
|
|
|
|
if (m_pConnTable)
|
|
{
|
|
MYVERIFY(NULL != UnmapViewOfFile(m_pConnTable));
|
|
m_pConnTable = NULL;
|
|
}
|
|
|
|
if (m_hMap)
|
|
{
|
|
MYVERIFY(NULL != CloseHandle(m_hMap));
|
|
m_hMap = NULL;
|
|
}
|
|
|
|
if (m_hEvent)
|
|
{
|
|
MYVERIFY(NULL != CloseHandle(m_hEvent));
|
|
m_hEvent = NULL;
|
|
}
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CConnectionTable::LockTable
|
|
//
|
|
// Synopsis: Sets the internal lock on the table. Should be called internally
|
|
// prior to any table access.
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: HRESULT - Failure code or S_OK
|
|
//
|
|
// History: nickball Created 2/2/98
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
HRESULT CConnectionTable::LockTable()
|
|
{
|
|
MYDBGASSERT(m_pConnTable);
|
|
MYDBGASSERT(m_hMap);
|
|
MYDBGASSERT(m_hEvent);
|
|
CMTRACE(TEXT("CConnectionTable::LockTable()"));
|
|
|
|
HRESULT hrRet = S_OK;
|
|
|
|
//
|
|
// Validate our current state
|
|
//
|
|
|
|
if (NULL == m_hEvent)
|
|
{
|
|
MYDBGASSERT(FALSE);
|
|
return E_ACCESSDENIED;
|
|
}
|
|
|
|
//
|
|
// Wait for the open event to be signaled
|
|
//
|
|
|
|
DWORD dwWait = WaitForSingleObject(m_hEvent, MAX_LOCK_WAIT);
|
|
|
|
//
|
|
// If our records indicate that we are already locked at this point
|
|
// then something is wrong within the class implementation
|
|
//
|
|
|
|
MYDBGASSERT(FALSE == m_fLocked); // no double locks please
|
|
|
|
if (TRUE == m_fLocked)
|
|
{
|
|
SetEvent(m_hEvent); // cleat the signal that we just set by clearing the wait
|
|
return E_ACCESSDENIED;
|
|
}
|
|
|
|
//
|
|
// Check the
|
|
//
|
|
|
|
if (WAIT_FAILED == dwWait)
|
|
{
|
|
MYDBGASSERT(FALSE);
|
|
hrRet = GetLastError();
|
|
return HRESULT_FROM_WIN32(hrRet);
|
|
}
|
|
|
|
//
|
|
// If not signaled, bail
|
|
//
|
|
|
|
MYDBGASSERT(WAIT_OBJECT_0 == dwWait);
|
|
|
|
if (WAIT_OBJECT_0 != dwWait)
|
|
{
|
|
if (WAIT_TIMEOUT == dwWait)
|
|
{
|
|
hrRet = HRESULT_FROM_WIN32(ERROR_TIMEOUT);
|
|
}
|
|
else
|
|
{
|
|
hrRet = E_ACCESSDENIED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The event is signaled automatically by virtue of the
|
|
// fact that we cleared the wait on the event. Its locked.
|
|
//
|
|
|
|
m_fLocked = TRUE;
|
|
}
|
|
|
|
return hrRet;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CConnectionTable::UnlockTable
|
|
//
|
|
// Synopsis: Clears the internal lock on the table. Should be cleared
|
|
// following any access to the table.
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: HRESULT - Failure code or S_OK
|
|
//
|
|
// History: nickball Created 2/2/98
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
HRESULT CConnectionTable::UnlockTable()
|
|
{
|
|
MYDBGASSERT(m_pConnTable);
|
|
MYDBGASSERT(m_hMap);
|
|
MYDBGASSERT(m_hEvent);
|
|
MYDBGASSERT(TRUE == m_fLocked);
|
|
CMTRACE(TEXT("CConnectionTable::UnlockTable()"));
|
|
|
|
HRESULT hrRet = S_OK;
|
|
|
|
//
|
|
// Validate our current state
|
|
//
|
|
|
|
if (FALSE == m_fLocked || NULL == m_hEvent)
|
|
{
|
|
return E_ACCESSDENIED;
|
|
}
|
|
|
|
//
|
|
// Signal the open event, allowing access
|
|
//
|
|
|
|
if (SetEvent(m_hEvent))
|
|
{
|
|
m_fLocked = FALSE;
|
|
}
|
|
else
|
|
{
|
|
MYDBGASSERT(FALSE);
|
|
|
|
hrRet = GetLastError();
|
|
hrRet = HRESULT_FROM_WIN32(hrRet);
|
|
}
|
|
|
|
return hrRet;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CConnectionTable::FindEntry - pszEntry
|
|
//
|
|
// Synopsis: Determines the ID (index) of an entry in the table. Table should
|
|
// be locked before making this call.
|
|
//
|
|
// Arguments: LPCTSTR pszEntry - Ptr to the name of the entry we are seeking.
|
|
// LPINT piID - Ptr to buffer for ID (index) of connection
|
|
//
|
|
// Returns: HRESULT - Failure code, or S_OK if piID filled.
|
|
//
|
|
// History: nickball Created 2/2/98
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
HRESULT CConnectionTable::FindEntry(LPCTSTR pszEntry, LPINT piID)
|
|
{
|
|
MYDBGASSERT(m_pConnTable);
|
|
MYDBGASSERT(m_hMap);
|
|
MYDBGASSERT(pszEntry);
|
|
MYDBGASSERT(piID);
|
|
MYDBGASSERT(TRUE == m_fLocked);
|
|
CMTRACE1(TEXT("CConnectionTable::FindEntry(%s)"), pszEntry);
|
|
|
|
if (FALSE == m_fLocked || NULL == m_pConnTable)
|
|
{
|
|
return E_ACCESSDENIED;
|
|
}
|
|
|
|
if (NULL == pszEntry || NULL == piID)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
if (0 == pszEntry[0])
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Look for the entry
|
|
//
|
|
|
|
for (int i = 0; i < MAX_CM_CONNECTIONS; i++)
|
|
{
|
|
//
|
|
// Name compare for a match
|
|
//
|
|
|
|
if (0 == lstrcmpU(pszEntry, m_pConnTable->Connections[i].szEntry))
|
|
{
|
|
MYDBGASSERT(m_pConnTable->Connections[i].dwUsage);
|
|
MYDBGASSERT(m_pConnTable->Connections[i].CmState);
|
|
|
|
*piID = i;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
}
|
|
|
|
return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CConnectionTable::FindEntry - hRasConn
|
|
//
|
|
// Synopsis: Determines the ID (index) of an entry in the table. Table should
|
|
// be locked before making this call.
|
|
//
|
|
// Arguments: HRASCONN hRasConn - Tunnel or dial handle of the entry we are seeking.
|
|
// LPINT piID - Ptr to buffer for ID (index) of connection
|
|
//
|
|
// Returns: HRESULT - Failure code, or S_OK if piID filled.
|
|
//
|
|
// History: nickball Created 2/2/98
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
HRESULT CConnectionTable::FindEntry(HRASCONN hRasConn, LPINT piID)
|
|
{
|
|
MYDBGASSERT(m_pConnTable);
|
|
MYDBGASSERT(m_hMap);
|
|
MYDBGASSERT(hRasConn);
|
|
MYDBGASSERT(piID);
|
|
MYDBGASSERT(TRUE == m_fLocked);
|
|
CMTRACE1(TEXT("CConnectionTable::FindEntry(%u)"), (DWORD_PTR) hRasConn);
|
|
|
|
if (FALSE == m_fLocked || NULL == m_pConnTable)
|
|
{
|
|
return E_ACCESSDENIED;
|
|
}
|
|
|
|
if (NULL == piID)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
if (NULL == hRasConn)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Look for the entry
|
|
//
|
|
|
|
for (int i = 0; i < MAX_CM_CONNECTIONS; i++)
|
|
{
|
|
//
|
|
// Compare for either handle for a match
|
|
//
|
|
|
|
if (hRasConn == m_pConnTable->Connections[i].hDial ||
|
|
hRasConn == m_pConnTable->Connections[i].hTunnel)
|
|
{
|
|
MYDBGASSERT(m_pConnTable->Connections[i].dwUsage);
|
|
MYDBGASSERT(m_pConnTable->Connections[i].CmState);
|
|
|
|
*piID = i;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
}
|
|
|
|
return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CConnectionTable::FindUnused
|
|
//
|
|
// Synopsis: Determines the ID (index) of the first unused entry in the table.
|
|
// Table should be locked before making this call.
|
|
//
|
|
// Arguments: LPINT piID - Ptr to buffer for ID (index) of connection
|
|
//
|
|
// Returns: HRESULT - Failure code, or S_OK if piID filled.
|
|
//
|
|
// History: nickball Created 2/2/98
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
HRESULT CConnectionTable::FindUnused(LPINT piID)
|
|
{
|
|
MYDBGASSERT(m_pConnTable);
|
|
MYDBGASSERT(m_hMap);
|
|
MYDBGASSERT(piID);
|
|
MYDBGASSERT(TRUE == m_fLocked);
|
|
CMTRACE(TEXT("CConnectionTable::FindUnused()"));
|
|
|
|
if (FALSE == m_fLocked || NULL == m_pConnTable)
|
|
{
|
|
return E_ACCESSDENIED;
|
|
}
|
|
|
|
if (NULL == piID)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Look for an unused slot
|
|
//
|
|
|
|
for (int i = 0; i < MAX_CM_CONNECTIONS; i++)
|
|
{
|
|
if (0 == m_pConnTable->Connections[i].dwUsage)
|
|
{
|
|
MYDBGASSERT(CM_DISCONNECTED == m_pConnTable->Connections[i].CmState);
|
|
|
|
*piID = i;
|
|
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: Create
|
|
//
|
|
// Synopsis: Creates a new table. This function will fail if the table already exists.
|
|
// The table should be released by calling Close.
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: HRESULT - Failure code or S_OK
|
|
//
|
|
// History: nickball Created 2/2/98
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
HRESULT CConnectionTable::Create()
|
|
{
|
|
MYDBGASSERT(NULL == m_hMap);
|
|
MYDBGASSERT(NULL == m_pConnTable);
|
|
MYDBGASSERT(FALSE == m_fLocked);
|
|
CMTRACE(TEXT("CConnectionTable::Create()"));
|
|
|
|
if (m_hMap || m_pConnTable)
|
|
{
|
|
return E_ACCESSDENIED;
|
|
}
|
|
|
|
SECURITY_ATTRIBUTES sa;
|
|
PACL pAcl = NULL;
|
|
|
|
// Initialize a default Security attributes, giving world permissions,
|
|
// this is basically prevent Semaphores and other named objects from
|
|
// being created because of default acls given by winlogon when perfmon
|
|
// is being used remotely.
|
|
sa.bInheritHandle = FALSE;
|
|
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
sa.lpSecurityDescriptor = CmMalloc(sizeof(SECURITY_DESCRIPTOR));
|
|
|
|
if ( !sa.lpSecurityDescriptor )
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if ( !InitializeSecurityDescriptor(sa.lpSecurityDescriptor,SECURITY_DESCRIPTOR_REVISION) )
|
|
{
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
if (OS_NT)
|
|
{
|
|
if (FALSE == SetAclPerms(&pAcl))
|
|
{
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
}
|
|
|
|
if (FALSE == SetSecurityDescriptorDacl(sa.lpSecurityDescriptor, TRUE, pAcl, FALSE))
|
|
{
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
//
|
|
// Now use this 'sa' for the mapped file as well as the event (below)
|
|
//
|
|
if (OS_NT5)
|
|
{
|
|
m_hMap = CreateFileMappingU(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE,
|
|
0, sizeof(CM_CONNECTION_TABLE), CONN_TABLE_NAME_WIN2K_ABOVE);
|
|
if (m_hMap)
|
|
{
|
|
CMTRACE1(TEXT("CreateFileMapping - create succeeded %s"), CONN_TABLE_NAME_WIN2K_ABOVE);
|
|
}
|
|
else
|
|
{
|
|
CMTRACE1(TEXT("CreateFileMapping - create failed %s"), CONN_TABLE_NAME_WIN2K_ABOVE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_hMap = CreateFileMappingU(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE,
|
|
0, sizeof(CM_CONNECTION_TABLE), CONN_TABLE_NAME);
|
|
if (m_hMap)
|
|
{
|
|
CMTRACE1(TEXT("CreateFileMapping - create succeeded %s"), CONN_TABLE_NAME);
|
|
}
|
|
else
|
|
{
|
|
CMTRACE1(TEXT("CreateFileMapping - create failed %s"), CONN_TABLE_NAME);
|
|
}
|
|
}
|
|
|
|
DWORD dwRet = ERROR_SUCCESS;
|
|
|
|
if (NULL == m_hMap)
|
|
{
|
|
dwRet = GetLastError();
|
|
if (dwRet == ERROR_ALREADY_EXISTS)
|
|
{
|
|
if (m_hMap)
|
|
{
|
|
MYVERIFY(NULL != CloseHandle(m_hMap));
|
|
m_hMap = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CMTRACE1(TEXT("CreateFileMapping failed with error %d"), dwRet);
|
|
MYDBGASSERT(FALSE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#if 0 // DBG
|
|
DumpAclInfo(m_hMap);
|
|
#endif
|
|
//
|
|
// File mapping created successfully, map a view of it
|
|
//
|
|
|
|
m_pConnTable = (LPCM_CONNECTION_TABLE) MapViewOfFile(m_hMap,
|
|
FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
|
|
if (NULL == m_pConnTable)
|
|
{
|
|
dwRet = GetLastError();
|
|
MYVERIFY(NULL != CloseHandle(m_hMap));
|
|
m_hMap = NULL;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Success, make sure mapping is empty becuase we are paranoid
|
|
//
|
|
|
|
ZeroMemory(m_pConnTable, sizeof(CM_CONNECTION_TABLE));
|
|
|
|
//
|
|
// Create the named event to be used for locking the file
|
|
// Note: We use auto-reset.
|
|
//
|
|
|
|
if (OS_NT5)
|
|
{
|
|
m_hEvent = CreateEventU(&sa, FALSE, TRUE, CONN_TABLE_OPEN_WIN2K_ABOVE);
|
|
if (m_hEvent)
|
|
{
|
|
CMTRACE1(TEXT("CreateEventU - succeeded - %s"), CONN_TABLE_OPEN_WIN2K_ABOVE);
|
|
}
|
|
else
|
|
{
|
|
CMTRACE1(TEXT("CreateEventU - failed - %s"), CONN_TABLE_OPEN_WIN2K_ABOVE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_hEvent = CreateEventU(&sa, FALSE, TRUE, CONN_TABLE_OPEN);
|
|
if (m_hEvent)
|
|
{
|
|
CMTRACE1(TEXT("CreateEventU - succeeded - %s"), CONN_TABLE_OPEN);
|
|
}
|
|
else
|
|
{
|
|
CMTRACE1(TEXT("CreateEventU - failed - %s"), CONN_TABLE_OPEN);
|
|
}
|
|
}
|
|
|
|
if (NULL == m_hEvent)
|
|
{
|
|
MYDBGASSERT(FALSE);
|
|
dwRet = GetLastError();
|
|
m_hEvent = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
CmFree(sa.lpSecurityDescriptor);
|
|
|
|
if (pAcl)
|
|
{
|
|
LocalFree(pAcl);
|
|
}
|
|
|
|
return HRESULT_FROM_WIN32(dwRet);
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CConnectionTable::Open
|
|
//
|
|
// Synopsis: Opens an existing table. This function will fail if no table exists.
|
|
// The table should be released by calling Close.
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: HRESULT - Failure code on S_OK
|
|
//
|
|
// History: nickball Created 2/2/98
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
HRESULT CConnectionTable::Open()
|
|
{
|
|
MYDBGASSERT(NULL == m_hMap);
|
|
MYDBGASSERT(NULL == m_pConnTable);
|
|
MYDBGASSERT(FALSE == m_fLocked);
|
|
CMTRACE(TEXT("CConnectionTable::Open()"));
|
|
|
|
if (m_hMap || m_pConnTable)
|
|
{
|
|
CMTRACE(TEXT("CConnectionTable::Open() - E_ACCESSDENIED"));
|
|
return E_ACCESSDENIED;
|
|
}
|
|
|
|
LRESULT lRet = ERROR_SUCCESS;
|
|
|
|
//
|
|
// Open the file mapping
|
|
//
|
|
|
|
if (OS_NT5)
|
|
{
|
|
m_hMap = OpenFileMappingU(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, CONN_TABLE_NAME_WIN2K_ABOVE);
|
|
}
|
|
else
|
|
{
|
|
m_hMap = OpenFileMappingU(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, CONN_TABLE_NAME);
|
|
}
|
|
|
|
if (NULL == m_hMap)
|
|
{
|
|
lRet = GetLastError();
|
|
CMTRACE1(TEXT("CConnectionTable::Open() - OpenFileMappingU fails. GLE = 0x%x"), lRet);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// File mapping opened successfully, map a view of it.
|
|
//
|
|
|
|
m_pConnTable = (LPCM_CONNECTION_TABLE) MapViewOfFile(m_hMap,
|
|
FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
|
|
MYDBGASSERT(m_pConnTable);
|
|
|
|
if (NULL == m_pConnTable)
|
|
{
|
|
MYVERIFY(NULL != CloseHandle(m_hMap));
|
|
m_hMap = NULL;
|
|
lRet = GetLastError();
|
|
CMTRACE1(TEXT("CConnectionTable::Open() - MapViewOfFile fails. GLE = 0x%x"), lRet);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Open the named event used for locking the file
|
|
//
|
|
|
|
if (OS_NT5)
|
|
{
|
|
m_hEvent = OpenEventU(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE,
|
|
NULL, CONN_TABLE_OPEN_WIN2K_ABOVE);
|
|
}
|
|
else
|
|
{
|
|
m_hEvent = OpenEventU(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE,
|
|
NULL, CONN_TABLE_OPEN);
|
|
}
|
|
|
|
|
|
if (NULL == m_hEvent)
|
|
{
|
|
MYDBGASSERT(FALSE);
|
|
lRet = GetLastError();
|
|
CMTRACE1(TEXT("CConnectionTable::Open() - OpenEventU fails. GLE = 0x%x"), lRet);
|
|
}
|
|
}
|
|
}
|
|
|
|
return HRESULT_FROM_WIN32(lRet);
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CConnectionTable::Close
|
|
//
|
|
// Synopsis: Closes an opened table. This function will fail if the table is
|
|
// not open.
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: HRESULT - Failure code or S_OK
|
|
//
|
|
// History: nickball Created 2/2/98
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
HRESULT CConnectionTable::Close()
|
|
{
|
|
MYDBGASSERT(m_pConnTable);
|
|
MYDBGASSERT(m_hMap);
|
|
MYDBGASSERT(FALSE == m_fLocked);
|
|
CMTRACE(TEXT("CConnectionTable::Close()"));
|
|
|
|
if (m_pConnTable)
|
|
{
|
|
MYVERIFY(NULL != UnmapViewOfFile(m_pConnTable));
|
|
m_pConnTable = NULL;
|
|
}
|
|
|
|
if (m_hMap)
|
|
{
|
|
MYVERIFY(NULL != CloseHandle(m_hMap));
|
|
m_hMap = NULL;
|
|
}
|
|
|
|
if (m_hEvent)
|
|
{
|
|
MYVERIFY(NULL != CloseHandle(m_hEvent));
|
|
m_hEvent = NULL;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CConnectionTable::AddEntry
|
|
//
|
|
// Synopsis: Creates a new entry in the table with the specified name. Adding
|
|
// an entry implies that the connection is being attempted, so the
|
|
// connection state is set to CM_CONNECTING. If an entry for the
|
|
// connection already exists, the usage count is incremented.
|
|
//
|
|
// Arguments: LPCTSTR pszEntry - The name of connection for which we're creating an entry.
|
|
// BOOL fAllUser - The All User attribute of the profile
|
|
//
|
|
// Returns: HRESULT - Failure code or S_OK
|
|
//
|
|
// History: nickball Created 2/2/98
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
HRESULT CConnectionTable::AddEntry(LPCTSTR pszEntry, BOOL fAllUser)
|
|
{
|
|
MYDBGASSERT(m_pConnTable);
|
|
MYDBGASSERT(m_hMap);
|
|
MYDBGASSERT(pszEntry);
|
|
CMTRACE1(TEXT("CConnectionTable::AddEntry(%s)"), pszEntry);
|
|
|
|
if (NULL == pszEntry)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
if (0 == pszEntry[0])
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (NULL == m_pConnTable)
|
|
{
|
|
return E_ACCESSDENIED;
|
|
}
|
|
|
|
HRESULT hrRet = LockTable();
|
|
|
|
if (FAILED(hrRet))
|
|
{
|
|
return hrRet;
|
|
}
|
|
|
|
//
|
|
// See if we already have an entry by this name
|
|
//
|
|
|
|
int iID = -1;
|
|
hrRet = FindEntry(pszEntry, &iID);
|
|
|
|
if (SUCCEEDED(hrRet))
|
|
{
|
|
//
|
|
// We do, bump the usage count.
|
|
//
|
|
|
|
MYDBGASSERT(iID >= 0 && iID < MAX_CM_CONNECTIONS);
|
|
|
|
//
|
|
// Don't bump ref count when reconnecting the same connection.
|
|
//
|
|
if (m_pConnTable->Connections[iID].CmState != CM_RECONNECTPROMPT)
|
|
{
|
|
m_pConnTable->Connections[iID].dwUsage += 1;
|
|
}
|
|
|
|
//
|
|
// Unless this entry is already connected, make sure
|
|
// its now in the connecting state. This allows us
|
|
// to preserve the usage count across prompt reconnect
|
|
// events.
|
|
//
|
|
|
|
if (m_pConnTable->Connections[iID].CmState != CM_CONNECTED)
|
|
{
|
|
m_pConnTable->Connections[iID].CmState = CM_CONNECTING;
|
|
}
|
|
|
|
MYDBGASSERT(m_pConnTable->Connections[iID].dwUsage < 1000); // Sanity check
|
|
}
|
|
else
|
|
{
|
|
if (HRESULT_CODE(hrRet) == ERROR_NOT_FOUND)
|
|
{
|
|
//
|
|
// Its a new entry, find the first unused slot
|
|
//
|
|
|
|
hrRet = FindUnused(&iID);
|
|
|
|
MYDBGASSERT(SUCCEEDED(hrRet));
|
|
|
|
if (SUCCEEDED(hrRet))
|
|
{
|
|
MYDBGASSERT(iID >= 0 && iID < MAX_CM_CONNECTIONS);
|
|
|
|
ZeroMemory(&m_pConnTable->Connections[iID], sizeof(CM_CONNECTION));
|
|
|
|
//
|
|
// Set usage count, state and name
|
|
//
|
|
|
|
m_pConnTable->Connections[iID].dwUsage = 1;
|
|
m_pConnTable->Connections[iID].CmState = CM_CONNECTING;
|
|
|
|
lstrcpyU(m_pConnTable->Connections[iID].szEntry, pszEntry);
|
|
|
|
m_pConnTable->Connections[iID].fAllUser = fAllUser;
|
|
}
|
|
}
|
|
}
|
|
|
|
MYVERIFY(SUCCEEDED(UnlockTable()));
|
|
|
|
return hrRet;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CConnectionTable::RemoveEntry
|
|
//
|
|
// Synopsis: Decrements the usage count for the specified connection. If the
|
|
// usage count falls to 0 the entire entry is cleared.
|
|
//
|
|
// Arguments: LPCTSTR pszEntry - The name of the entry to be removed
|
|
//
|
|
// Returns: HRESULT - Failure code or S_OK
|
|
//
|
|
// Note: If the entry does not exists the request fails.
|
|
//
|
|
// History: nickball Created 2/2/98
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
HRESULT CConnectionTable::RemoveEntry(LPCTSTR pszEntry)
|
|
{
|
|
MYDBGASSERT(m_pConnTable);
|
|
MYDBGASSERT(m_hMap);
|
|
MYDBGASSERT(pszEntry);
|
|
CMTRACE1(TEXT("CConnectionTable::RemoveEntry(%s)"), pszEntry);
|
|
|
|
if (NULL == pszEntry)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
if (0 == pszEntry[0])
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (NULL == m_pConnTable)
|
|
{
|
|
return E_ACCESSDENIED;
|
|
}
|
|
|
|
//
|
|
// Lock the table and locate the entry
|
|
//
|
|
|
|
HRESULT hrRet = LockTable();
|
|
|
|
if (FAILED(hrRet))
|
|
{
|
|
return hrRet;
|
|
}
|
|
|
|
int iID = -1;
|
|
hrRet = FindEntry(pszEntry, &iID);
|
|
|
|
if (SUCCEEDED(hrRet))
|
|
{
|
|
MYDBGASSERT(iID >= 0 && iID < MAX_CM_CONNECTIONS);
|
|
|
|
if (m_pConnTable->Connections[iID].dwUsage == 1)
|
|
{
|
|
ZeroMemory(&m_pConnTable->Connections[iID], sizeof(CM_CONNECTION));
|
|
}
|
|
else
|
|
{
|
|
m_pConnTable->Connections[iID].dwUsage -= 1;
|
|
MYDBGASSERT(m_pConnTable->Connections[iID].dwUsage != 0xFFFFFFFF);
|
|
}
|
|
}
|
|
|
|
MYVERIFY(SUCCEEDED(UnlockTable()));
|
|
|
|
return hrRet;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CConnectionTable::GetMonitorWnd
|
|
//
|
|
// Synopsis: Simple accessor to retrieve the hwnd of the CM Connection
|
|
// Monitor from the table.
|
|
//
|
|
// Arguments: phWnd - Ptr to buffer to receive hWnd
|
|
//
|
|
// Returns: Failure code or S_OK
|
|
//
|
|
// History: nickball Created 2/2/98
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
HRESULT CConnectionTable::GetMonitorWnd(HWND *phWnd)
|
|
{
|
|
MYDBGASSERT(m_pConnTable);
|
|
MYDBGASSERT(m_hMap);
|
|
CMTRACE(TEXT("CConnectionTable::GetMonitorWnd()"));
|
|
|
|
if (NULL == m_pConnTable)
|
|
{
|
|
return E_ACCESSDENIED;
|
|
}
|
|
|
|
if (NULL == phWnd)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Lock the table and retrieve the HWND
|
|
//
|
|
|
|
HRESULT hrRet = LockTable();
|
|
|
|
if (FAILED(hrRet))
|
|
{
|
|
return hrRet;
|
|
}
|
|
|
|
*phWnd = m_pConnTable->hwndCmMon;
|
|
|
|
MYVERIFY(SUCCEEDED(UnlockTable()));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CConnectionTable::SetMonitorWnd
|
|
//
|
|
// Synopsis: Simple assignment method for setting the CMMON HWND in the table
|
|
// .
|
|
// Arguments: HWND hwndMonitor - The HWND of CMMON
|
|
//
|
|
// Returns: HRESULT - Failure code or S_OK
|
|
//
|
|
// Note: hwndMonitor CAN be NULL. It is possible CMMON is unloaded, but
|
|
// the table statys in memory
|
|
// History: nickball Created 2/2/98
|
|
// fengsun 2/20/98 change to allow NULL phwndMonitor
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
HRESULT CConnectionTable::SetMonitorWnd(HWND hwndMonitor)
|
|
{
|
|
MYDBGASSERT(m_pConnTable);
|
|
MYDBGASSERT(m_hMap);
|
|
CMTRACE(TEXT("CConnectionTable::SetMonitorWnd()"));
|
|
|
|
if (NULL == m_pConnTable)
|
|
{
|
|
return E_ACCESSDENIED;
|
|
}
|
|
|
|
//
|
|
// Lock the table and set the HWND
|
|
//
|
|
|
|
HRESULT hrRet = LockTable();
|
|
|
|
if (FAILED(hrRet))
|
|
{
|
|
return hrRet;
|
|
}
|
|
|
|
m_pConnTable->hwndCmMon = hwndMonitor;
|
|
|
|
MYVERIFY(SUCCEEDED(UnlockTable()));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CConnectionTable::GetEntry - pszEntry
|
|
//
|
|
// Synopsis: Retrieves a copy the data for the specified connection based on
|
|
// the entry name provided.
|
|
//
|
|
// Arguments: LPCTSTR pszEntry - The name of the connection
|
|
// LPCM_CONNECTION pConnection - Ptr to a CM_CONNECTION sturct to be filled
|
|
//
|
|
// Returns: HRESULT - Failure Code or S_OK.
|
|
//
|
|
// Note: A NULL ptr may be passed for pConnection, if the existence of the
|
|
// entry is the only information required.
|
|
//
|
|
// History: nickball Created 2/2/98
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
HRESULT CConnectionTable::GetEntry(LPCTSTR pszEntry,
|
|
LPCM_CONNECTION pConnection)
|
|
{
|
|
MYDBGASSERT(m_pConnTable);
|
|
MYDBGASSERT(m_hMap);
|
|
MYDBGASSERT(pszEntry);
|
|
CMTRACE1(TEXT("CConnectionTable::GetEntry(%s)"), pszEntry);
|
|
|
|
if (NULL == m_pConnTable)
|
|
{
|
|
return E_ACCESSDENIED;
|
|
}
|
|
|
|
if (NULL == pszEntry)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
if (0 == pszEntry[0])
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Lock the table and retrieve the entry
|
|
//
|
|
|
|
HRESULT hrRet = LockTable();
|
|
|
|
if (FAILED(hrRet))
|
|
{
|
|
return hrRet;
|
|
}
|
|
|
|
int iID = -1;
|
|
hrRet = FindEntry(pszEntry, &iID);
|
|
|
|
if (SUCCEEDED(hrRet))
|
|
{
|
|
MYDBGASSERT(iID >= 0 && iID < MAX_CM_CONNECTIONS);
|
|
|
|
//
|
|
// If a buffer was given fill it.
|
|
//
|
|
|
|
if (pConnection)
|
|
{
|
|
memcpy(pConnection, &m_pConnTable->Connections[iID], sizeof(CM_CONNECTION));
|
|
}
|
|
}
|
|
|
|
MYVERIFY(SUCCEEDED(UnlockTable()));
|
|
|
|
return hrRet;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CConnectionTable::GetEntry - hRasConn
|
|
//
|
|
// Synopsis: Retrieves a copy the data for the specified connection based on the
|
|
// Ras handle provided
|
|
//
|
|
// Arguments: HRASCONN hRasConn - Either the tunnel or dial handle of the connection
|
|
// LPCM_CONNECTION pConnection - Ptr to a CM_CONNECTION sturct to be filled
|
|
//
|
|
// Returns: HRESULT - Failure Code or S_OK.
|
|
//
|
|
// Note: A NULL ptr may be passed for pConnection, if the existence of the
|
|
// entry is the only information required.
|
|
//
|
|
// History: nickball Created 2/2/98
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
HRESULT CConnectionTable::GetEntry(HRASCONN hRasConn,
|
|
LPCM_CONNECTION pConnection)
|
|
{
|
|
MYDBGASSERT(m_pConnTable);
|
|
MYDBGASSERT(m_hMap);
|
|
MYDBGASSERT(hRasConn);
|
|
CMTRACE1(TEXT("CConnectionTable::GetEntry(%u)"), (DWORD_PTR) hRasConn);
|
|
|
|
if (NULL == m_pConnTable)
|
|
{
|
|
return E_ACCESSDENIED;
|
|
}
|
|
|
|
if (NULL == hRasConn)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Lock the table and retrieve the entry
|
|
//
|
|
|
|
HRESULT hrRet = LockTable();
|
|
|
|
if (FAILED(hrRet))
|
|
{
|
|
return hrRet;
|
|
}
|
|
|
|
int iID = -1;
|
|
hrRet = FindEntry(hRasConn, &iID);
|
|
|
|
if (SUCCEEDED(hrRet))
|
|
{
|
|
MYDBGASSERT(iID >= 0 && iID < MAX_CM_CONNECTIONS);
|
|
|
|
//
|
|
// If a buffer was given fill it.
|
|
//
|
|
|
|
if (pConnection)
|
|
{
|
|
memcpy(pConnection, &m_pConnTable->Connections[iID], sizeof(CM_CONNECTION));
|
|
}
|
|
}
|
|
|
|
MYVERIFY(SUCCEEDED(UnlockTable()));
|
|
|
|
return hrRet;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CConnectionTable::SetConnected
|
|
//
|
|
// Synopsis: Sets the connection to CM_CONNECTED indicating that a connection
|
|
// has been established. The caller must provide either the hDial or
|
|
// the hTunnel parameter or both in order for the function to succeed.
|
|
//
|
|
// Arguments: LPCTSTR pszEntry - The name of the connection.
|
|
// HRASCONN hDial - A Dial-up connection handle.
|
|
// HRASCONN hTunnel - A tunnel connection handle.
|
|
//
|
|
// Returns: HRESULT - Failure code or S_OK.
|
|
//
|
|
// History: nickball Created 2/2/98
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
HRESULT CConnectionTable::SetConnected(LPCTSTR pszEntry,
|
|
HRASCONN hDial,
|
|
HRASCONN hTunnel)
|
|
{
|
|
MYDBGASSERT(m_pConnTable);
|
|
MYDBGASSERT(m_hMap);
|
|
MYDBGASSERT(pszEntry);
|
|
CMTRACE1(TEXT("CConnectionTable::SetConnected(%s)"), pszEntry);
|
|
|
|
if (NULL == m_pConnTable)
|
|
{
|
|
return E_ACCESSDENIED;
|
|
}
|
|
|
|
if (NULL == pszEntry)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
if (0 == pszEntry[0] || (NULL == hDial && NULL == hTunnel))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Lock the table and retrieve the entry
|
|
//
|
|
|
|
HRESULT hrRet = LockTable();
|
|
|
|
if (FAILED(hrRet))
|
|
{
|
|
return hrRet;
|
|
}
|
|
|
|
int iID = -1;
|
|
hrRet = FindEntry(pszEntry, &iID);
|
|
|
|
MYDBGASSERT(SUCCEEDED(hrRet));
|
|
|
|
if (SUCCEEDED(hrRet))
|
|
{
|
|
//
|
|
// Found, set the state and Ras handles
|
|
//
|
|
|
|
MYDBGASSERT(iID >= 0 && iID < MAX_CM_CONNECTIONS);
|
|
MYDBGASSERT(m_pConnTable->Connections[iID].CmState != CM_CONNECTED);
|
|
|
|
m_pConnTable->Connections[iID].CmState = CM_CONNECTED;
|
|
m_pConnTable->Connections[iID].hDial = hDial;
|
|
m_pConnTable->Connections[iID].hTunnel = hTunnel;
|
|
}
|
|
|
|
MYVERIFY(SUCCEEDED(UnlockTable()));
|
|
|
|
return hrRet;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CConnectionTable::SetDisconnecting
|
|
//
|
|
// Synopsis: Set the state of the connection to CM_DISCONNECTING
|
|
//
|
|
// Arguments: LPCTSTR pszEntry - The name of the connection to be set.
|
|
//
|
|
// Returns: HRESULT - Failure code or S_OK
|
|
//
|
|
// History: nickball Created 2/2/98
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
HRESULT CConnectionTable::SetDisconnecting(LPCTSTR pszEntry)
|
|
{
|
|
MYDBGASSERT(m_pConnTable);
|
|
MYDBGASSERT(m_hMap);
|
|
MYDBGASSERT(pszEntry);
|
|
CMTRACE1(TEXT("CConnectionTable::Disconnecting(%s)"), pszEntry);
|
|
|
|
if (NULL == m_pConnTable)
|
|
{
|
|
return E_ACCESSDENIED;
|
|
}
|
|
|
|
if (NULL == pszEntry)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
if (0 == pszEntry[0])
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Lock the table and retrieve the entry
|
|
//
|
|
|
|
HRESULT hrRet = LockTable();
|
|
|
|
if (FAILED(hrRet))
|
|
{
|
|
return hrRet;
|
|
}
|
|
|
|
int iID = -1;
|
|
hrRet = FindEntry(pszEntry, &iID);
|
|
|
|
//MYDBGASSERT(SUCCEEDED(hrRet));
|
|
|
|
if (SUCCEEDED(hrRet))
|
|
{
|
|
//
|
|
// Found, set the state
|
|
//
|
|
|
|
MYDBGASSERT(iID >= 0 && iID < MAX_CM_CONNECTIONS);
|
|
m_pConnTable->Connections[iID].CmState = CM_DISCONNECTING;
|
|
}
|
|
|
|
MYVERIFY(SUCCEEDED(UnlockTable()));
|
|
|
|
return hrRet;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: SetPrompting
|
|
//
|
|
// Synopsis: Set the state of the connection to CM_RECONNECTPROMPT
|
|
//
|
|
// Arguments: LPCTSTR pszEntry - The name of the connection to be set.
|
|
//
|
|
// Returns: HRESULT - Failure code or S_OK
|
|
//
|
|
// History: nickball Created 2/2/98
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
HRESULT CConnectionTable::SetPrompting(LPCTSTR pszEntry)
|
|
{
|
|
MYDBGASSERT(m_pConnTable);
|
|
MYDBGASSERT(m_hMap);
|
|
MYDBGASSERT(pszEntry);
|
|
CMTRACE1(TEXT("CConnectionTable::SetPrompting(%s)"), pszEntry);
|
|
|
|
if (NULL == m_pConnTable)
|
|
{
|
|
return E_ACCESSDENIED;
|
|
}
|
|
|
|
if (NULL == pszEntry)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
if (0 == pszEntry[0])
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Lock the table and retrieve the entry
|
|
//
|
|
|
|
HRESULT hrRet = LockTable();
|
|
|
|
if (FAILED(hrRet))
|
|
{
|
|
return hrRet;
|
|
}
|
|
|
|
int iID = -1;
|
|
hrRet = FindEntry(pszEntry, &iID);
|
|
|
|
//MYDBGASSERT(SUCCEEDED(hrRet));
|
|
|
|
if (SUCCEEDED(hrRet))
|
|
{
|
|
//
|
|
// Found, set the state
|
|
//
|
|
|
|
MYDBGASSERT(iID >= 0 && iID < MAX_CM_CONNECTIONS);
|
|
m_pConnTable->Connections[iID].CmState = CM_RECONNECTPROMPT;
|
|
}
|
|
|
|
MYVERIFY(SUCCEEDED(UnlockTable()));
|
|
|
|
return hrRet;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CConnectionTable::ClearEntry
|
|
//
|
|
// Synopsis: Clears the specified entry regardless of the usage count.
|
|
//
|
|
// Arguments: LPCTSTR pszEntry - The name of the entry to be cleared.
|
|
//
|
|
// Returns: HRESULT - Failure code or S_OK
|
|
//
|
|
// History: nickball Created 2/2/98
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
HRESULT CConnectionTable::ClearEntry(LPCTSTR pszEntry)
|
|
{
|
|
MYDBGASSERT(m_pConnTable);
|
|
MYDBGASSERT(m_hMap);
|
|
MYDBGASSERT(pszEntry);
|
|
CMTRACE1(TEXT("CConnectionTable::ClearEntry(%s)"), pszEntry);
|
|
|
|
if (NULL == m_pConnTable)
|
|
{
|
|
return E_ACCESSDENIED;
|
|
}
|
|
|
|
if (NULL == pszEntry)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
if (0 == pszEntry[0])
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Lock the table and retrieve the entry
|
|
//
|
|
|
|
HRESULT hrRet = LockTable();
|
|
|
|
if (FAILED(hrRet))
|
|
{
|
|
return hrRet;
|
|
}
|
|
|
|
int iID = -1;
|
|
hrRet = FindEntry(pszEntry, &iID);
|
|
|
|
if (SUCCEEDED(hrRet))
|
|
{
|
|
//
|
|
// Found, clear it
|
|
//
|
|
|
|
MYDBGASSERT(iID >= 0 && iID < MAX_CM_CONNECTIONS);
|
|
ZeroMemory(&m_pConnTable->Connections[iID], sizeof(CM_CONNECTION));
|
|
}
|
|
|
|
MYVERIFY(SUCCEEDED(UnlockTable()));
|
|
|
|
return hrRet;
|
|
}
|
|
|