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.
1665 lines
48 KiB
1665 lines
48 KiB
/**********************************************************************/
|
|
/** Microsoft Windows/NT **/
|
|
/** Copyright(c) Microsoft Corporation, 1997 - 1999 **/
|
|
/**********************************************************************/
|
|
|
|
/*
|
|
winsdb.cpp
|
|
Wins database enumerator
|
|
|
|
FILE HISTORY:
|
|
Oct 13 1997 EricDav Modified
|
|
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
#include "wins.h"
|
|
#include "search.h"
|
|
#include "winsdb.h"
|
|
#include "tfschar.h"
|
|
|
|
IMPLEMENT_ADDREF_RELEASE(CWinsDatabase);
|
|
|
|
IMPLEMENT_SIMPLE_QUERYINTERFACE(CWinsDatabase, IWinsDatabase)
|
|
|
|
DEBUG_DECLARE_INSTANCE_COUNTER(CWinsDatabase)
|
|
|
|
CWinsDatabase::CWinsDatabase()
|
|
: m_cRef(1), m_fFiltered(FALSE), m_fInitialized(FALSE), m_bShutdown(FALSE), m_hrLastError(hrOK)
|
|
{
|
|
DEBUG_INCREMENT_INSTANCE_COUNTER(CWinsDatabase);
|
|
|
|
SetCurrentState(WINSDB_NORMAL);
|
|
|
|
m_hBinding = NULL;
|
|
m_hThread = NULL;
|
|
m_hStart = NULL;
|
|
m_hAbort = NULL;
|
|
m_dwOwner = (DWORD)-1;
|
|
m_strPrefix = NULL;
|
|
m_dwRecsCount = 0;
|
|
m_bEnableCache = FALSE;
|
|
}
|
|
|
|
CWinsDatabase::~CWinsDatabase()
|
|
{
|
|
DEBUG_DECREMENT_INSTANCE_COUNTER(CWinsDatabase);
|
|
|
|
m_bShutdown = TRUE;
|
|
|
|
if (m_strPrefix != NULL)
|
|
delete m_strPrefix;
|
|
|
|
SetEvent(m_hAbort);
|
|
SetEvent(m_hStart);
|
|
|
|
if (WaitForSingleObject(m_hThread, 30000) != WAIT_OBJECT_0)
|
|
{
|
|
Trace0("WinsDatabase destructor thread never died!\n");
|
|
|
|
// TerminateThread
|
|
}
|
|
|
|
CloseHandle(m_hAbort);
|
|
CloseHandle(m_hStart);
|
|
CloseHandle(m_hThread);
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CWinsDatabase::Init
|
|
Implementation of IWinsDatabase::Init
|
|
Author: EricDav, v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CWinsDatabase::Init()
|
|
{
|
|
HRESULT hr = hrOK;
|
|
WINSDB_STATE uCurrentState;
|
|
|
|
m_dwRecsCount = 0;
|
|
|
|
COM_PROTECT_TRY
|
|
{
|
|
CORg (GetCurrentState(&uCurrentState));
|
|
if (uCurrentState != WINSDB_NORMAL)
|
|
{
|
|
Trace1("WinsDatabase::Init - called when database busy - state %d\n", uCurrentState);
|
|
return E_FAIL;
|
|
}
|
|
|
|
CORg (m_cMemMan.Initialize());
|
|
CORg (m_IndexMgr.Initialize());
|
|
|
|
m_hrLastError = hrOK;
|
|
|
|
CORg (SetCurrentState(WINSDB_LOADING));
|
|
|
|
COM_PROTECT_ERROR_LABEL;
|
|
}
|
|
COM_PROTECT_CATCH
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CWinsDatabase::Start
|
|
Implementation of IWinsDatabase::Start
|
|
Author: EricDav, v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CWinsDatabase::Start()
|
|
{
|
|
// signal the thread to start loading
|
|
SetEvent(m_hStart);
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CWinsDatabase::Initialize
|
|
Implementation of IWinsDatabase::Initialize
|
|
Author: EricDav, v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CWinsDatabase::Initialize(LPCOLESTR pszName, LPCOLESTR pszIP)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
DWORD dwError;
|
|
DWORD dwThreadId;
|
|
|
|
COM_PROTECT_TRY
|
|
{
|
|
m_strName = pszName;
|
|
m_strIp = pszIP;
|
|
|
|
CORg (m_cMemMan.Initialize());
|
|
CORg (m_IndexMgr.Initialize());
|
|
|
|
m_hStart = ::CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (m_hStart == NULL)
|
|
{
|
|
dwError = ::GetLastError();
|
|
Trace1("WinsDatabase::Initialize - CreateEvent Failed m_hStart %d\n", dwError);
|
|
|
|
return HRESULT_FROM_WIN32(dwError);
|
|
}
|
|
|
|
m_hAbort = ::CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (m_hAbort == NULL)
|
|
{
|
|
dwError = ::GetLastError();
|
|
Trace1("WinsDatabase::Initialize - CreateEvent Failed m_hAbort %d\n", dwError);
|
|
|
|
return HRESULT_FROM_WIN32(dwError);
|
|
}
|
|
|
|
m_hThread = ::CreateThread(NULL, 0, ThreadProc, this, 0, &dwThreadId);
|
|
if (m_hThread == NULL)
|
|
{
|
|
dwError = ::GetLastError();
|
|
Trace1("WinsDatabase::Init - CreateThread Failed %d\n", dwError);
|
|
|
|
return HRESULT_FROM_WIN32(dwError);
|
|
}
|
|
|
|
m_fInitialized = TRUE;
|
|
|
|
COM_PROTECT_ERROR_LABEL;
|
|
}
|
|
COM_PROTECT_CATCH
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CWinsDatabase::GetName
|
|
Implementation of IWinsDatabase::GetName
|
|
Author: EricDav, v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CWinsDatabase::GetName(LPOLESTR pszName, UINT cchMax)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
LPCTSTR pBuf;
|
|
|
|
COM_PROTECT_TRY
|
|
{
|
|
if (cchMax < (UINT) (m_strName.GetLength() / sizeof(TCHAR)))
|
|
return E_FAIL;
|
|
|
|
StrnCpy(pszName, (LPCTSTR) m_strName, cchMax);
|
|
}
|
|
COM_PROTECT_CATCH
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CWinsDatabase::GetIP
|
|
Implementation of IWinsDatabase::GetIP
|
|
Author: EricDav, v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CWinsDatabase::GetIP(LPOLESTR pszIP, UINT cchMax)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
LPCTSTR pBuf;
|
|
|
|
COM_PROTECT_TRY
|
|
{
|
|
if (cchMax < (UINT) (m_strIp.GetLength() / sizeof(TCHAR)))
|
|
return E_FAIL;
|
|
|
|
StrnCpy(pszIP, (LPCTSTR) m_strIp, cchMax);
|
|
|
|
}
|
|
COM_PROTECT_CATCH
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CWinsDatabase::Stop
|
|
Implementation of IWinsDatabase::Stop
|
|
Author: EricDav, v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CWinsDatabase::Stop()
|
|
{
|
|
HRESULT hr = hrOK;
|
|
WINSDB_STATE uState;
|
|
|
|
COM_PROTECT_TRY
|
|
{
|
|
CORg (GetCurrentState(&uState));
|
|
|
|
if (uState != WINSDB_LOADING)
|
|
return hr;
|
|
|
|
SetEvent(m_hAbort);
|
|
|
|
CORg (SetCurrentState(WINSDB_NORMAL));
|
|
|
|
COM_PROTECT_ERROR_LABEL;
|
|
}
|
|
COM_PROTECT_CATCH
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CWinsDatabase::Clear
|
|
Clears the wins DB of all records
|
|
Author: EricDav, v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CWinsDatabase::Clear()
|
|
{
|
|
HRESULT hr = hrOK;
|
|
WINSDB_STATE uState;
|
|
|
|
COM_PROTECT_TRY
|
|
{
|
|
CORg (GetCurrentState(&uState));
|
|
|
|
if (uState == WINSDB_SORTING ||
|
|
uState == WINSDB_FILTERING)
|
|
return E_FAIL;
|
|
|
|
if (uState == WINSDB_LOADING)
|
|
{
|
|
SetEvent(m_hAbort);
|
|
CORg (SetCurrentState(WINSDB_NORMAL));
|
|
}
|
|
|
|
CORg (m_cMemMan.Initialize());
|
|
CORg (m_IndexMgr.Initialize());
|
|
m_dwOwner = (DWORD)-1;
|
|
if (m_strPrefix != NULL)
|
|
delete m_strPrefix;
|
|
m_strPrefix = NULL;
|
|
|
|
COM_PROTECT_ERROR_LABEL;
|
|
}
|
|
COM_PROTECT_CATCH
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CWinsDatabase::GetLastError
|
|
Returns the last error for async calls
|
|
Author: EricDav, v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CWinsDatabase::GetLastError(HRESULT * pLastError)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
WINSDB_STATE uState;
|
|
|
|
COM_PROTECT_TRY
|
|
{
|
|
if (pLastError)
|
|
*pLastError = m_hrLastError;
|
|
|
|
}
|
|
COM_PROTECT_CATCH
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CWinsDatabase::Sort
|
|
Implementation of IWinsDatabase::Sort
|
|
Author: EricDav, v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CWinsDatabase::Sort(WINSDB_SORT_TYPE SortType, DWORD dwSortOptions)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
WINSDB_STATE uState;
|
|
|
|
COM_PROTECT_TRY
|
|
{
|
|
CORg (GetCurrentState(&uState));
|
|
|
|
if (uState != WINSDB_NORMAL)
|
|
return E_FAIL;
|
|
|
|
CORg (SetCurrentState(WINSDB_SORTING));
|
|
|
|
m_IndexMgr.Sort(SortType, dwSortOptions);
|
|
|
|
CORg (SetCurrentState(WINSDB_NORMAL));
|
|
|
|
COM_PROTECT_ERROR_LABEL;
|
|
}
|
|
COM_PROTECT_CATCH
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CWinsDatabase::GetHRow
|
|
Implementation of IWinsDatabase::GetHRow
|
|
returns the HRow in the current sorted index
|
|
Author: EricDav, v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CWinsDatabase::GetHRow(UINT uIndex,
|
|
LPHROW hRow)
|
|
{
|
|
Assert(uIndex >= 0);
|
|
|
|
HRESULT hr = hrOK;
|
|
WINSDB_STATE uState;
|
|
int nCurrentCount;
|
|
|
|
COM_PROTECT_TRY
|
|
{
|
|
CORg (GetCurrentCount(&nCurrentCount));
|
|
|
|
if (uIndex > (UINT) nCurrentCount)
|
|
return E_FAIL;
|
|
|
|
CORg (GetCurrentState(&uState));
|
|
if (uState == WINSDB_SORTING || uState == WINSDB_FILTERING)
|
|
return E_FAIL;
|
|
|
|
m_IndexMgr.GetHRow(uIndex, hRow);
|
|
|
|
COM_PROTECT_ERROR_LABEL;
|
|
}
|
|
COM_PROTECT_CATCH
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CWinsDatabase::GetRows
|
|
Implementation of IWinsDatabase::GetRows
|
|
Author: EricDav, v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT CWinsDatabase::GetRows( ULONG uNumberOfRows,
|
|
ULONG uStartPos,
|
|
HROW* pHRow,
|
|
int* nNumberOfRowsReturned)
|
|
{
|
|
int nCurrentCount;
|
|
WINSDB_STATE uState;
|
|
HRESULT hr = hrOK;
|
|
int nReturnedRows = 0;
|
|
int i;
|
|
HROW hrowCur;
|
|
|
|
Assert (uStartPos >= 0);
|
|
|
|
COM_PROTECT_TRY
|
|
{
|
|
CORg (GetCurrentState(&uState));
|
|
if (uState == WINSDB_SORTING || uState == WINSDB_FILTERING)
|
|
return E_FAIL;
|
|
|
|
CORg (GetCurrentCount(&nCurrentCount));
|
|
Assert ((int) uStartPos <= nCurrentCount);
|
|
if (uStartPos > (UINT) nCurrentCount)
|
|
return E_FAIL;
|
|
|
|
for (i = (int) uStartPos; i < (int) (uStartPos + uNumberOfRows); i++)
|
|
{
|
|
if( i > nCurrentCount )
|
|
{
|
|
break;
|
|
}
|
|
|
|
CORg (m_IndexMgr.GetHRow(i, &hrowCur));
|
|
|
|
// if the row is marked deleted, don't add it to the array
|
|
// REVIEW: directly accessing memory here.. we may want to change this
|
|
// to go through the memory manager
|
|
if ( ((LPWINSDBRECORD) hrowCur)->szRecordName[17] & WINSDB_INTERNAL_DELETED )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// fill in the data
|
|
pHRow[i-uStartPos] = hrowCur;
|
|
nReturnedRows++;
|
|
}
|
|
|
|
COM_PROTECT_ERROR_LABEL;
|
|
}
|
|
COM_PROTECT_CATCH
|
|
|
|
if (nNumberOfRowsReturned)
|
|
*nNumberOfRowsReturned = nReturnedRows;
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CWinsDatabase::GetData
|
|
Implementation of IWinsDatabase::GetData
|
|
returns the HRow in the current sorted index
|
|
Author: EricDav, v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT CWinsDatabase::GetData(HROW hRow,
|
|
LPWINSRECORD pRecordData)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
COM_PROTECT_TRY
|
|
{
|
|
CORg (m_cMemMan.GetData(hRow, pRecordData));
|
|
|
|
COM_PROTECT_ERROR_LABEL;
|
|
}
|
|
COM_PROTECT_CATCH
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CWinsDatabase::FindRow
|
|
Implementation of IWinsDatabase::FindRow
|
|
Author: EricDav, v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CWinsDatabase::FindRow(LPCOLESTR pszName,
|
|
HROW hrowStart,
|
|
HROW * phRow)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
WinsRecord ws;
|
|
int nIndex, nPos, nCurrentCount;
|
|
HROW hrowCur;
|
|
HROW hrowFound = NULL;
|
|
char szName[MAX_PATH];
|
|
|
|
CString strTemp(pszName);
|
|
|
|
// this should be OEM
|
|
WideToMBCS(strTemp, szName, WINS_NAME_CODE_PAGE);
|
|
|
|
COM_PROTECT_TRY
|
|
{
|
|
CORg (m_IndexMgr.GetIndex(hrowStart, &nIndex));
|
|
|
|
/////
|
|
CORg(GetHRow(nIndex, &hrowCur));
|
|
CORg (m_IndexMgr.GetIndex(hrowCur, &nIndex));
|
|
|
|
CORg (GetCurrentCount(&nCurrentCount));
|
|
|
|
if(nIndex != -1)
|
|
{
|
|
|
|
CORg(GetHRow(nIndex, &hrowCur));
|
|
|
|
for (nPos = nIndex + 1; nPos < nCurrentCount; nPos++)
|
|
{
|
|
CORg(GetHRow(nPos, &hrowCur));
|
|
|
|
CORg(GetData(hrowCur, &ws));
|
|
if(!_strnicmp(ws.szRecordName, szName, strlen(szName) ))
|
|
{
|
|
hrowFound = hrowCur;
|
|
hr = hrOK;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
COM_PROTECT_ERROR_LABEL;
|
|
}
|
|
COM_PROTECT_CATCH
|
|
|
|
if (phRow)
|
|
*phRow = hrowFound;
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CWinsDatabase::GetTotalCount
|
|
Implementation of IWinsDatabase::GetTotalCount
|
|
Author: EricDav, v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CWinsDatabase::GetTotalCount(int * nTotalCount)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
COM_PROTECT_TRY
|
|
{
|
|
*nTotalCount = m_IndexMgr.GetTotalCount();
|
|
}
|
|
COM_PROTECT_CATCH
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CWinsDatabase::GetCurrentCount
|
|
Implementation of IWinsDatabase::GetCurrentCount
|
|
returns the HRow in the current sorted index
|
|
Author: EricDav, v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CWinsDatabase::GetCurrentCount(int * nCurrentCount)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
|
|
COM_PROTECT_TRY
|
|
{
|
|
if (m_DBState == WINSDB_SORTING)
|
|
*nCurrentCount = 0;
|
|
else
|
|
*nCurrentCount = m_IndexMgr.GetCurrentCount();
|
|
}
|
|
COM_PROTECT_CATCH
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CWinsDatabase::GetCurrentScanned(int * nCurrentScanned)
|
|
Implementation of IWinsDatabase::GetCurrentScanned
|
|
returns the total number of records that were read from the server
|
|
Author: EricDav, v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CWinsDatabase::GetCurrentScanned(int * nCurrentCount)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
|
|
COM_PROTECT_TRY
|
|
{
|
|
*nCurrentCount = m_dwRecsCount;
|
|
}
|
|
COM_PROTECT_CATCH
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CWinsDatabase::AddRecord
|
|
Implementation of IWinsDatabase::AddRecord
|
|
Author: EricDav, v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CWinsDatabase::AddRecord(const LPWINSRECORD pRecordData)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
|
|
COM_PROTECT_TRY
|
|
{
|
|
// critical sections taken care by the memory manager
|
|
HROW hrow = NULL;
|
|
|
|
CORg (m_cMemMan.AddData(*pRecordData, &hrow));
|
|
CORg (m_IndexMgr.AddHRow(hrow));
|
|
|
|
COM_PROTECT_ERROR_LABEL;
|
|
}
|
|
COM_PROTECT_CATCH
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CWinsDatabase::DeleteRecord
|
|
Implementation of IWinsDatabase::DeleteRecord
|
|
Author: EricDav, v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CWinsDatabase::DeleteRecord(HROW hrowRecord)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
WINSDB_STATE uState;
|
|
|
|
COM_PROTECT_TRY
|
|
{
|
|
CORg (GetCurrentState(&uState));
|
|
|
|
if (uState != WINSDB_NORMAL)
|
|
return E_FAIL;
|
|
|
|
// make sure the hrow is a valid one
|
|
if (!m_cMemMan.IsValidHRow(hrowRecord))
|
|
return E_FAIL;
|
|
|
|
// Tell the memmgr to delete this record
|
|
CORg (m_cMemMan.Delete(hrowRecord));
|
|
|
|
// now tell the index manager to remove this hrow
|
|
CORg (m_IndexMgr.RemoveHRow(hrowRecord));
|
|
|
|
COM_PROTECT_ERROR_LABEL;
|
|
}
|
|
COM_PROTECT_CATCH
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CWinsDatabase::GetCurrentState
|
|
Implementation of IWinsDatabase::GetCurrentState
|
|
Author: EricDav, v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CWinsDatabase::GetCurrentState(WINSDB_STATE * pState)
|
|
{
|
|
CSingleLock cl(&m_csState);
|
|
cl.Lock();
|
|
|
|
*pState = m_DBState;
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CWinsDatabase::SetCurrentState
|
|
Helper function to set the current state, protected
|
|
Author: EricDav, v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CWinsDatabase::SetCurrentState(WINSDB_STATE winsdbState)
|
|
{
|
|
CSingleLock cl(&m_csState);
|
|
cl.Lock();
|
|
|
|
m_DBState = winsdbState;
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CWinsDatabase::FilterRecords
|
|
Implementation of IWinsDatabase::FilterRecords
|
|
Author: EricDav, v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CWinsDatabase::FilterRecords
|
|
(
|
|
WINSDB_FILTER_TYPE FilterType,
|
|
DWORD dwParam1,
|
|
DWORD dwParam2)
|
|
{
|
|
HRESULT hr = E_NOTIMPL;
|
|
WINSDB_STATE uState ;
|
|
|
|
COM_PROTECT_TRY
|
|
{
|
|
// fail if the state is other then WINSDB_NORMAL
|
|
CORg (GetCurrentState(&uState));
|
|
|
|
if (uState == WINSDB_SORTING || uState == WINSDB_FILTERING)
|
|
return E_FAIL;
|
|
|
|
// if in the loading state the readrecords function takes care
|
|
if(uState != WINSDB_LOADING)
|
|
CORg (SetCurrentState(WINSDB_FILTERING));
|
|
|
|
// do the filtering here, rebuild the filtered name Index
|
|
m_IndexMgr.Filter(FilterType, dwParam1, dwParam2);
|
|
|
|
if(uState != WINSDB_LOADING)
|
|
CORg (SetCurrentState(WINSDB_NORMAL));
|
|
|
|
COM_PROTECT_ERROR_LABEL;
|
|
}
|
|
COM_PROTECT_CATCH
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CWinsDatabase::AddFilter
|
|
Adds the filters specified to the list
|
|
Author: EricDav, v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CWinsDatabase::AddFilter(WINSDB_FILTER_TYPE FilterType, DWORD dwParam1, DWORD dwParam2, LPCOLESTR strParam3)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
|
|
COM_PROTECT_TRY
|
|
{
|
|
// for filter by type, dwParam1 is the type, dwParam2 is show/not show
|
|
m_IndexMgr.AddFilter(FilterType, dwParam1, dwParam2, strParam3);
|
|
}
|
|
COM_PROTECT_CATCH
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CWinsDatabase::ClearFilter
|
|
CLears all the filters
|
|
Author: EricDav, v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
|
|
HRESULT
|
|
CWinsDatabase::ClearFilter(WINSDB_FILTER_TYPE FilterType)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
|
|
COM_PROTECT_TRY
|
|
{
|
|
//CFilteredIndexName *pFilterName = (CFilteredIndexName *)m_IndexMgr.GetFilteredNameIndex();
|
|
//pFilterName->ClearFilter();
|
|
m_IndexMgr.ClearFilter(FilterType);
|
|
}
|
|
COM_PROTECT_CATCH
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CWinsDatabase::SetActiveView
|
|
Implementation of IWinsDatabase::SetActiveView
|
|
Author: EricDav, v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
|
|
HRESULT
|
|
CWinsDatabase::SetActiveView(WINSDB_VIEW_TYPE ViewType)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
|
|
COM_PROTECT_TRY
|
|
{
|
|
m_IndexMgr.SetActiveView(ViewType);
|
|
}
|
|
COM_PROTECT_CATCH
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CWinsDatabase::Execute()
|
|
The background thread calls into this to execute
|
|
Author: EricDav, v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CWinsDatabase::Execute()
|
|
{
|
|
DWORD dwStatus = 0;
|
|
|
|
// wait for the other thread to signal us to start doing something
|
|
|
|
while (::WaitForSingleObject(m_hStart, INFINITE) == WAIT_OBJECT_0)
|
|
{
|
|
if (m_bShutdown)
|
|
break;
|
|
|
|
Trace0("WinsDatabase::Execute - start event signaled\n");
|
|
|
|
WINSINTF_BIND_DATA_T wbdBindData;
|
|
handle_t hBinding = NULL;
|
|
|
|
do
|
|
{
|
|
// enumerate leases here
|
|
SetCurrentState(WINSDB_LOADING);
|
|
|
|
// now that the server name and ip are valid, call
|
|
// WINSBind function directly.
|
|
|
|
WINSINTF_ADD_T waWinsAddress;
|
|
|
|
DWORD dwStatus;
|
|
CString strNetBIOSName;
|
|
|
|
// call WinsBind function with the IP address
|
|
wbdBindData.fTcpIp = 1;
|
|
wbdBindData.pPipeName = NULL;
|
|
|
|
// convert wbdBindData.pServerAdd to wide char again as one of the internal
|
|
// functions expects a wide char string, this is done in WinsABind which is bypassed for
|
|
// unicode compatible apps
|
|
|
|
wbdBindData.pServerAdd = (LPSTR) (LPCTSTR) m_strIp;
|
|
|
|
if ((hBinding = ::WinsBind(&wbdBindData)) == NULL)
|
|
{
|
|
dwStatus = ::GetLastError();
|
|
Trace1("WinsDatabase::Execute - WinsBind failed %lx\n", dwStatus);
|
|
break;
|
|
}
|
|
|
|
#ifdef WINS_CLIENT_APIS
|
|
dwStatus = ::WinsGetNameAndAdd(
|
|
hBinding,
|
|
&waWinsAddress,
|
|
(BYTE *)strNetBIOSName.GetBuffer(128));
|
|
|
|
#else
|
|
dwStatus = ::WinsGetNameAndAdd(
|
|
&waWinsAddress,
|
|
(BYTE *)strNetBIOSName.GetBuffer(128));
|
|
|
|
#endif WINS_CLIENT_APIS
|
|
|
|
strNetBIOSName.ReleaseBuffer();
|
|
|
|
if (dwStatus == ERROR_SUCCESS)
|
|
{
|
|
if(m_dwOwner == (DWORD)-1)
|
|
dwStatus = ReadRecords(hBinding);
|
|
else
|
|
dwStatus = ReadRecordsByOwner(hBinding);
|
|
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
Trace1("WinsDatabase::Execute - WinsGetNameAndAdd failed %lx\n", dwStatus);
|
|
break;
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
SetCurrentState(WINSDB_NORMAL);
|
|
|
|
|
|
if(hBinding)
|
|
{
|
|
// call winsunbind here, the handle is invalid after this and that's fine
|
|
WinsUnbind(&wbdBindData, hBinding);
|
|
hBinding = NULL;
|
|
}
|
|
Trace0("WinsDatabase::Execute - all done, going to sleep now...\n");
|
|
|
|
} // while !Start
|
|
|
|
Trace0("WinsDatabase::Execute - exiting\n");
|
|
return dwStatus;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CWinsDatabase::ReadRecords
|
|
Reads records from the WINS server
|
|
Author: EricDav, v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CWinsDatabase::ReadRecords(handle_t hBinding)
|
|
{
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
DWORD err = ERROR_SUCCESS;
|
|
|
|
CWinsResults winsResults;
|
|
err = winsResults.Update(hBinding);
|
|
|
|
WINSINTF_RECS_T Recs;
|
|
Recs.pRow = NULL;
|
|
|
|
DWORD NoOfRecsDesired = 500;
|
|
DWORD TypeOfRecs = 4;
|
|
BOOL fReadAllRecords ;
|
|
|
|
PWINSINTF_RECORD_ACTION_T pRow;
|
|
enum {ST_SCAN_1B_NAME, ST_SCAN_NORM_NAME} State;
|
|
LPBYTE pLastName;
|
|
UINT nLastNameLen, nLastBuffLen;
|
|
|
|
pLastName = NULL;
|
|
nLastNameLen = 0;
|
|
nLastBuffLen = 0;
|
|
|
|
#ifdef DEBUG
|
|
CTime timeStart, timeFinish;
|
|
timeStart = CTime::GetCurrentTime();
|
|
#endif
|
|
|
|
m_dwRecsCount = 0;
|
|
|
|
// initialize the state machine. If we have a name prefix filter we
|
|
// start in ST_INIT_1B since we look first for the 1B names. These are
|
|
// particular in a sense their type byte - i.e. 0x1B - has been swapped
|
|
// with the first byte from the name. Consequently we need to do the same
|
|
// to allow WINS to look first for these names. Once we get over the 1B zone
|
|
// of our names, we restore the first byte and initiate another cycle for
|
|
// the rest of the name.
|
|
if (m_strPrefix != NULL)
|
|
{
|
|
nLastNameLen = nLastBuffLen = strlen(m_strPrefix) + 1;
|
|
pLastName = (LPBYTE) new CHAR[nLastBuffLen];
|
|
strcpy((LPSTR)pLastName, m_strPrefix);
|
|
pLastName[0] = 0x1B;
|
|
State = ST_SCAN_1B_NAME;
|
|
}
|
|
else
|
|
{
|
|
State = ST_SCAN_NORM_NAME;
|
|
}
|
|
|
|
do
|
|
{
|
|
|
|
#ifdef WINS_CLIENT_APIS
|
|
err = ::WinsGetDbRecsByName(
|
|
hBinding,
|
|
NULL,
|
|
WINSINTF_BEGINNING,
|
|
pLastName,
|
|
nLastNameLen,
|
|
NoOfRecsDesired,
|
|
TypeOfRecs,
|
|
&Recs);
|
|
|
|
#else
|
|
err = ::WinsGetDbRecsByName(
|
|
NULL,
|
|
WINSINTF_BEGINNING,
|
|
pFromName,
|
|
LastNameLen,
|
|
NoOfRecsDesired,
|
|
TypeOfRecs,
|
|
&Recs);
|
|
|
|
#endif WINS_CLIENT_APIS
|
|
|
|
|
|
// check to see if we need to abort
|
|
if (WaitForSingleObject(m_hAbort, 0) == WAIT_OBJECT_0)
|
|
{
|
|
Trace0("CWinsDatabase::ReadRecords - abort detected\n");
|
|
dwStatus = ERROR_OPERATION_ABORTED;
|
|
break;
|
|
}
|
|
|
|
if (err == ERROR_REC_NON_EXISTENT)
|
|
{
|
|
//
|
|
// Not a problem, there simply
|
|
// are no records in the database
|
|
//
|
|
Trace0("WinsDatabase::ReadRecords - no records in the Datbase\n");
|
|
fReadAllRecords = TRUE;
|
|
err = ERROR_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
if (err == ERROR_SUCCESS)
|
|
{
|
|
fReadAllRecords = Recs.NoOfRecs < NoOfRecsDesired;
|
|
if (fReadAllRecords)
|
|
Trace0("WinsDatabase::ReadRecords - Recs.NoOfRecs < NoOfRecsDesired, will exit\n");
|
|
|
|
TRY
|
|
{
|
|
DWORD i;
|
|
pRow = Recs.pRow;
|
|
|
|
for (i = 0; i < Recs.NoOfRecs; ++i, ++pRow)
|
|
{
|
|
PWINSINTF_RECORD_ACTION_T pRow1 = Recs.pRow;
|
|
WinsRecord wRecord;
|
|
HROW hrow = NULL;
|
|
|
|
WinsIntfToWinsRecord(pRow, wRecord);
|
|
if (pRow->OwnerId < (UINT) winsResults.AddVersMaps.GetSize())
|
|
{
|
|
wRecord.dwOwner = winsResults.AddVersMaps[pRow->OwnerId].Add.IPAdd;
|
|
}
|
|
else
|
|
{
|
|
// having a record owned by a server which is not in the version map
|
|
// we got just earlier from WINS is not something that usually happens.
|
|
// It might happen only if the new owner was added right in between.
|
|
// Unlikely since this is a very small window - but if this happens
|
|
// just skip the record. From our point of view this owner doesn't exist
|
|
// hence the record doesn't belong to the view. It will show up with the
|
|
// first refresh.
|
|
continue;
|
|
}
|
|
|
|
m_dwRecsCount++;
|
|
|
|
if (!m_bEnableCache && !m_IndexMgr.AcceptWinsRecord(&wRecord))
|
|
continue;
|
|
|
|
// add the data to our memory store and
|
|
// to the sorted index
|
|
m_cMemMan.AddData(wRecord, &hrow);
|
|
// if m_bEnableCache is 0 the the filter was checked
|
|
m_IndexMgr.AddHRow(hrow, TRUE, !m_bEnableCache);
|
|
|
|
//Trace1("%d records added to DB\n", m_dwRecsCount);
|
|
}
|
|
|
|
|
|
// if we reached the end of the DB there is no need to do
|
|
// anything from below. Is just pLastName that needs to be
|
|
// freed up - this is done outside the loop, before exiting
|
|
// the call.
|
|
if (!fReadAllRecords)
|
|
{
|
|
BOOL fRangeOver = FALSE;
|
|
|
|
// get to the last record that was retrieved.
|
|
--pRow;
|
|
|
|
// check if the last name retrieved from the server is still
|
|
// mathing the pattern prefix (if any) or the range has been
|
|
// passed over (fRangeOver)
|
|
|
|
if (m_strPrefix != NULL)
|
|
{
|
|
for (UINT i = 0; i < pRow->NameLen && m_strPrefix[i] != 0; i++)
|
|
{
|
|
if (m_strPrefix[i] != pRow->pName[i])
|
|
{
|
|
fRangeOver = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// here fRangeOver is either TRUE if the name doesn't match the pattern
|
|
// prefix or FALSE if the range is not passed yet. This latter thing means
|
|
// either the name is included in the prefix or the prefix isn't included in the name
|
|
// !!! We might want to invalidate the "name included in the prefix" case.
|
|
if (fRangeOver)
|
|
{
|
|
switch(State)
|
|
{
|
|
case ST_SCAN_1B_NAME:
|
|
// in this state pLastName is definitely not NULL and even more,
|
|
// it once copied m_strPrefix. Since pLastName can only grow, it is
|
|
// certain it is large enough to cotain m_strPrefix one more time.
|
|
strcpy((LPSTR)pLastName, m_strPrefix);
|
|
nLastNameLen = strlen((LPCSTR)pLastName);
|
|
State = ST_SCAN_NORM_NAME;
|
|
break;
|
|
case ST_SCAN_NORM_NAME:
|
|
// we were scanning normal names and we passed
|
|
// over the range of names we are looking for
|
|
// so just get out of the loop.
|
|
fReadAllRecords = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// enlarge the pLastName if needed
|
|
if (nLastBuffLen < pRow->NameLen+2)
|
|
{
|
|
if (pLastName != NULL)
|
|
delete pLastName;
|
|
nLastBuffLen = pRow->NameLen+2;
|
|
pLastName = (LPBYTE)new CHAR[nLastBuffLen];
|
|
}
|
|
// copy in pLastName the name of the last record
|
|
strcpy((LPSTR)pLastName, (LPCSTR)(pRow->pName));
|
|
|
|
if (pRow->NameLen >= 16 && pLastName[15] == 0x1B)
|
|
{
|
|
CHAR ch = pLastName[15];
|
|
pLastName[15] = pLastName[0];
|
|
pLastName[0] = ch;
|
|
}
|
|
|
|
strcat((LPSTR)pLastName, "\x01");
|
|
nLastNameLen = strlen((LPCSTR)pLastName);
|
|
}
|
|
}
|
|
}
|
|
CATCH_ALL(e)
|
|
{
|
|
err = ::GetLastError();
|
|
Trace1("WinsDatabase::ReadRecords - Exception! %d \n", err);
|
|
m_hrLastError = HRESULT_FROM_WIN32(err);
|
|
}
|
|
END_CATCH_ALL
|
|
}
|
|
else
|
|
{
|
|
Trace1("WinsDatabase::ReadRecords - GetRecsByName failed! %d \n", err);
|
|
m_hrLastError = HRESULT_FROM_WIN32(err);
|
|
break;
|
|
}
|
|
|
|
if (Recs.pRow != NULL)
|
|
{
|
|
::WinsFreeMem(Recs.pRow);
|
|
}
|
|
|
|
} while(!fReadAllRecords );
|
|
|
|
if (pLastName != NULL)
|
|
delete pLastName;
|
|
|
|
#ifdef DEBUG
|
|
timeFinish = CTime::GetCurrentTime();
|
|
CTimeSpan timeDelta = timeFinish - timeStart;
|
|
CString strTempTime = timeDelta.Format(_T("%H:%M:%S"));
|
|
Trace2("WINS DB - ReadRecords: %d records read, total time %s\n", m_dwRecsCount, strTempTime);
|
|
#endif
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
ThreadProc
|
|
-
|
|
Author: EricDav, v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
DWORD WINAPI
|
|
ThreadProc(LPVOID pParam)
|
|
{
|
|
DWORD dwReturn;
|
|
HRESULT hr = hrOK;
|
|
|
|
COM_PROTECT_TRY
|
|
{
|
|
CWinsDatabase *pWinsDB = (CWinsDatabase *) pParam;
|
|
|
|
Trace0("WinsDatabase Background Thread started.\n");
|
|
|
|
dwReturn = pWinsDB->Execute();
|
|
}
|
|
COM_PROTECT_CATCH
|
|
|
|
return dwReturn;
|
|
}
|
|
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
WinsIntfToWinsRecord
|
|
Converts a wins record from the server into the WinsRecord struct
|
|
Author: EricDav, v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
void
|
|
WinsIntfToWinsRecord(PWINSINTF_RECORD_ACTION_T pRecord, WinsRecord & wRecord)
|
|
{
|
|
ZeroMemory(&wRecord, sizeof(WinsRecord));
|
|
|
|
//::strcpy(wRecord.szRecordName, (LPCSTR)pRecord->pName);
|
|
::memcpy(wRecord.szRecordName, (LPCSTR)pRecord->pName, pRecord->NameLen);
|
|
|
|
wRecord.dwExpiration = (ULONG) pRecord->TimeStamp;
|
|
wRecord.liVersion = pRecord->VersNo;
|
|
wRecord.dwOwner = pRecord->OwnerId;
|
|
wRecord.dwNameLen = WINSINTF_NAME_LEN_M(pRecord->NameLen);
|
|
wRecord.dwType |= (BYTE) wRecord.szRecordName[15];
|
|
|
|
// translate the state and types to our own definitions
|
|
switch (pRecord->State_e)
|
|
{
|
|
case WINSINTF_E_TOMBSTONE:
|
|
wRecord.dwState |= WINSDB_REC_TOMBSTONE;
|
|
break;
|
|
|
|
case WINSINTF_E_DELETED:
|
|
//Trace0("WinsIntfToWinsRecord - deleted record.\n");
|
|
wRecord.dwState |= WINSDB_REC_DELETED;
|
|
break;
|
|
|
|
case WINSINTF_E_RELEASED:
|
|
//Trace0("WinsIntfToWinsRecord - released record.\n");
|
|
wRecord.dwState |= WINSDB_REC_RELEASED;
|
|
break;
|
|
|
|
default: // WINSINTF_E_ACTIVE:
|
|
wRecord.dwState |= WINSDB_REC_ACTIVE;
|
|
break;
|
|
}
|
|
|
|
switch (pRecord->TypOfRec_e)
|
|
{
|
|
case WINSINTF_E_NORM_GROUP:
|
|
wRecord.dwState |= WINSDB_REC_NORM_GROUP;
|
|
break;
|
|
|
|
case WINSINTF_E_SPEC_GROUP:
|
|
wRecord.dwState |= WINSDB_REC_SPEC_GROUP;
|
|
break;
|
|
|
|
case WINSINTF_E_MULTIHOMED:
|
|
wRecord.dwState |= WINSDB_REC_MULTIHOMED;
|
|
break;
|
|
|
|
default: // WINSINTF_E_UNIQUE:
|
|
wRecord.dwState |= WINSDB_REC_UNIQUE;
|
|
break;
|
|
}
|
|
|
|
// now do the type -- move the value into the high word
|
|
DWORD dwTemp = (pRecord->TypOfRec_e << 16);
|
|
wRecord.dwType |= dwTemp;
|
|
|
|
// now set the static flag
|
|
if (pRecord->fStatic)
|
|
wRecord.dwState |= WINSDB_REC_STATIC;
|
|
|
|
// store all of the IP addrs
|
|
wRecord.dwNoOfAddrs = pRecord->NoOfAdds;
|
|
if (pRecord->NoOfAdds > 1)
|
|
{
|
|
Assert(pRecord->NoOfAdds <= WINSDB_MAX_NO_IPADDRS);
|
|
|
|
//if (wRecord.dwNoOfAddrs > 4)
|
|
// Trace1("WinsIntfToWinsRecord - record with multiple (>4) IP addrs: %d\n", wRecord.dwNoOfAddrs);
|
|
|
|
wRecord.dwState |= WINSDB_REC_MULT_ADDRS;
|
|
|
|
for (UINT i = 0; i < pRecord->NoOfAdds; i++)
|
|
wRecord.dwIpAdd[i] = pRecord->pAdd[i].IPAdd;
|
|
}
|
|
else
|
|
{
|
|
if (pRecord->NoOfAdds == 0)
|
|
{
|
|
//Trace2("WinsIntfToWinsRecord - record with NoOfAdds == 0; IP: %lx State: %lx \n", pRecord->Add.IPAdd, wRecord.dwState);
|
|
}
|
|
|
|
if (pRecord->Add.IPAdd == 0)
|
|
{
|
|
Trace1("WinsIntfToWinsRecord - record with 0 IP Address! State: %lx \n", wRecord.dwState);
|
|
}
|
|
|
|
wRecord.dwIpAdd[0] = pRecord->Add.IPAdd;
|
|
}
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CreateWinsDatabase
|
|
-
|
|
Author: EricDav, v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CreateWinsDatabase(CString& strName, CString& strIP, IWinsDatabase **ppWinsDB)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetModuleState());
|
|
|
|
CWinsDatabase * pWinsDB = NULL;
|
|
HRESULT hr = hrOK;
|
|
|
|
SPIWinsDatabase spWinsDB;
|
|
|
|
COM_PROTECT_TRY
|
|
{
|
|
pWinsDB = new CWinsDatabase();
|
|
Assert(pWinsDB);
|
|
|
|
spWinsDB = pWinsDB;
|
|
CORg(pWinsDB->Initialize(strName, strIP));
|
|
|
|
*ppWinsDB = spWinsDB.Transfer();
|
|
|
|
COM_PROTECT_ERROR_LABEL;
|
|
}
|
|
COM_PROTECT_CATCH
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CWinsDatabase::SetApiInfo
|
|
Implementation of SetApiInfo of IWinsDatabase
|
|
Author: FlorinT
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CWinsDatabase::SetApiInfo(DWORD dwOwner, LPCOLESTR strPrefix, BOOL bCache)
|
|
{
|
|
// first cleanup the old prefix
|
|
if (m_strPrefix != NULL)
|
|
{
|
|
delete m_strPrefix;
|
|
m_strPrefix = NULL;
|
|
}
|
|
|
|
if (strPrefix != NULL)
|
|
{
|
|
UINT nPxLen = 0;
|
|
LPSTR pPrefix;
|
|
|
|
nPxLen = (_tcslen(strPrefix)+1)*sizeof(TCHAR);
|
|
m_strPrefix = new char[nPxLen];
|
|
if (m_strPrefix != NULL)
|
|
{
|
|
#ifdef _UNICODE
|
|
if (WideCharToMultiByte(CP_OEMCP,
|
|
0,
|
|
strPrefix,
|
|
-1,
|
|
m_strPrefix,
|
|
nPxLen,
|
|
NULL,
|
|
NULL) == 0)
|
|
{
|
|
delete m_strPrefix;
|
|
m_strPrefix = NULL;
|
|
}
|
|
#else
|
|
CharToOem(strPrefix, m_strPrefix);
|
|
#endif
|
|
m_strPrefix = _strupr(m_strPrefix);
|
|
|
|
for (pPrefix = m_strPrefix;
|
|
*pPrefix != '\0' && *pPrefix != '*' && *pPrefix != '?';
|
|
pPrefix++);
|
|
*pPrefix = '\0';
|
|
}
|
|
}
|
|
|
|
m_dwOwner = dwOwner;
|
|
|
|
m_bEnableCache = bCache;
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CWinsDatabase::GetCachingFlag
|
|
Implementation of GetCachingFlag of IWinsDatabase
|
|
Author: FlorinT
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CWinsDatabase::GetCachingFlag(LPBOOL pbCache)
|
|
{
|
|
*pbCache = m_bEnableCache;
|
|
return hrOK;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CWinsDatabase::ReloadSuggested
|
|
Implementation of ReloadSuggested of IWinsDatabase
|
|
Author: FlorinT
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CWinsDatabase::ReloadSuggested(DWORD dwOwner, LPCOLESTR strPrefix, LPBOOL pbReload)
|
|
{
|
|
// check whether we filtered on a particular owner.
|
|
if (m_dwOwner != 0xFFFFFFFF)
|
|
{
|
|
// we did filter on owner previously, suggest RELOAD if we now
|
|
// don't want to filter on any owner (dwOwner == 0xffffffff)
|
|
// or the owner we want to filter is different from the original one
|
|
*pbReload = (m_dwOwner != dwOwner);
|
|
}
|
|
else
|
|
{
|
|
// we didn't filter on any owner previously so we either loaded
|
|
// all the records (if no name prefix was specified) or loaded
|
|
// all the records matching the given prefix
|
|
if (m_strPrefix != NULL)
|
|
{
|
|
// we did have a previous prefix to match so we need to see
|
|
// if the new prefix is not by any chance more specific than
|
|
// the original one. In which case there is no need to reload
|
|
LPSTR pPrefix;
|
|
UINT nPxLen;
|
|
UINT i;
|
|
|
|
if (strPrefix == NULL)
|
|
{
|
|
// if now we're not filtering by name, since we did previously
|
|
// we definitely need to reload the database
|
|
*pbReload = TRUE;
|
|
return hrOK;
|
|
}
|
|
|
|
nPxLen = (_tcslen(strPrefix)+1)*sizeof(TCHAR);
|
|
pPrefix = new char[nPxLen];
|
|
if (pPrefix != NULL)
|
|
{
|
|
#ifdef _UNICODE
|
|
if (WideCharToMultiByte(CP_OEMCP,
|
|
0,
|
|
strPrefix,
|
|
-1,
|
|
pPrefix,
|
|
nPxLen,
|
|
NULL,
|
|
NULL) == 0)
|
|
{
|
|
delete pPrefix;
|
|
*pbReload = TRUE;
|
|
return hrOK;
|
|
}
|
|
#else
|
|
CharToOem(strPrefix, pPrefix);
|
|
#endif
|
|
pPrefix = _strupr(pPrefix);
|
|
|
|
for (i = 0;
|
|
pPrefix[i] != '\0' && pPrefix[i] != '*' && pPrefix[i] != '?';
|
|
i++);
|
|
pPrefix[i] = '\0';
|
|
|
|
// we don't suggest database reloading only if the current prefix
|
|
// is a prefix for the new one to be applied. This way, whatever
|
|
// was retrieved previously already contains the names having the
|
|
// new prefix.
|
|
*pbReload = (strncmp(m_strPrefix, pPrefix, strlen(m_strPrefix)) != 0);
|
|
|
|
delete pPrefix;
|
|
}
|
|
else
|
|
{
|
|
// couldn't allocate memory -> serious enough to ask a full reload
|
|
*pbReload = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// well, there was no prefix specified last time the db was loaded so
|
|
// we should have the whole database in hand. No need to reload.
|
|
*pbReload = FALSE;
|
|
}
|
|
}
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CWinsDatabase::ReadRecordsByOwner
|
|
Reads records from the WINS server for a particular owner
|
|
Author: EricDav, v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
#define MAX_DESIRED_RECORDS 400
|
|
#define LARGE_GAP_DETECT_COUNT 32
|
|
DWORD
|
|
CWinsDatabase::ReadRecordsByOwner(handle_t hBinding)
|
|
{
|
|
DWORD err;
|
|
CWinsResults winsResults;
|
|
WINSINTF_RECS_T Recs;
|
|
DWORD dwIP;
|
|
LARGE_INTEGER MinVersNo, MaxVersNo;
|
|
LARGE_INTEGER LowestVersNo;
|
|
DWORD dwDesired;
|
|
DWORD dwLargeGapCount;
|
|
WINSINTF_ADD_T OwnerAdd;
|
|
DWORD i;
|
|
|
|
err = winsResults.Update(hBinding);
|
|
if (err != ERROR_SUCCESS)
|
|
{
|
|
m_hrLastError = HRESULT_FROM_WIN32(err);
|
|
return err;
|
|
}
|
|
|
|
MinVersNo.QuadPart= 0;
|
|
for (i = 0; i < (int)winsResults.NoOfOwners; i++)
|
|
{
|
|
if (m_dwOwner == winsResults.AddVersMaps[i].Add.IPAdd)
|
|
{
|
|
MaxVersNo = winsResults.AddVersMaps[i].VersNo;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// if we couldn't find the owner (highly unlikely) get out
|
|
// with error INVALID_PARAMETER.
|
|
if (i == winsResults.NoOfOwners)
|
|
{
|
|
err = ERROR_INVALID_PARAMETER;
|
|
m_hrLastError = HRESULT_FROM_WIN32(err);
|
|
return err;
|
|
}
|
|
|
|
m_dwRecsCount = 0;
|
|
|
|
OwnerAdd.Type = 0;
|
|
OwnerAdd.Len = 4;
|
|
OwnerAdd.IPAdd = m_dwOwner;
|
|
|
|
// This is what the server does to retrieve the records:
|
|
// 1. sets an ascending index on owner & version number.
|
|
// 2. goes to the first record owned by the given owner,
|
|
// having a version number larger or equal to MinVersNo.
|
|
// 3. stop if the record's vers num is higher than the range specified
|
|
// 4. stop if more than 1000 recs have been already received
|
|
// 5. add the new record to the set to return and go to 3.
|
|
//
|
|
dwDesired = MAX_DESIRED_RECORDS;
|
|
dwLargeGapCount = LARGE_GAP_DETECT_COUNT;
|
|
LowestVersNo.QuadPart = 0;
|
|
if (MaxVersNo.QuadPart > dwDesired)
|
|
MinVersNo.QuadPart = MaxVersNo.QuadPart-dwDesired;
|
|
else
|
|
MinVersNo.QuadPart = 0;
|
|
Recs.pRow = NULL;
|
|
while(MaxVersNo.QuadPart >= MinVersNo.QuadPart)
|
|
{
|
|
// clear up the previous array - if any
|
|
if (Recs.pRow != NULL)
|
|
{
|
|
::WinsFreeMem(Recs.pRow);
|
|
Recs.pRow = NULL;
|
|
}
|
|
|
|
// go to WINS to get the data for the given Owner
|
|
#ifdef WINS_CLIENT_APIS
|
|
err = ::WinsGetDbRecs(hBinding, &OwnerAdd, MinVersNo,
|
|
MaxVersNo, &Recs);
|
|
#else
|
|
err = ::WinsGetDbRecs(&OwnerAdd, MinVersNo,
|
|
MaxVersNo, &Recs);
|
|
#endif WINS_CLIENT_APIS
|
|
|
|
// if abort was requested, break out with "ABORTED"
|
|
if (WaitForSingleObject(m_hAbort, 0) == WAIT_OBJECT_0)
|
|
{
|
|
err = ERROR_OPERATION_ABORTED;
|
|
break;
|
|
}
|
|
|
|
// if there is any kind of error break out
|
|
if (err != ERROR_SUCCESS)
|
|
{
|
|
if (err == ERROR_REC_NON_EXISTENT)
|
|
{
|
|
// I'm not sure this happens after all. The server side (WINS) has
|
|
// not code path returning such an error code.
|
|
err = ERROR_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
// if this happens, just get out with the error, and save the
|
|
// meaning of the error
|
|
m_hrLastError = HRESULT_FROM_WIN32(err);
|
|
}
|
|
break;
|
|
}
|
|
|
|
// if got less than 1/4 of the size of the range, expand the range
|
|
// to double of what it was + 1. (+1 is important to avoid the effect
|
|
// of dramatic drop down because of DWORD roll-over
|
|
if (Recs.NoOfRecs <= (dwDesired >> 2))
|
|
{
|
|
dwDesired <<= 1;
|
|
dwDesired |= 1;
|
|
}
|
|
// else if got more than 3/4 of the size of the range, split the range in 2
|
|
// but not less than MAX_DESIRED_RECORDS
|
|
else if (Recs.NoOfRecs >= (dwDesired - (dwDesired >> 2)))
|
|
{
|
|
dwDesired = max (MAX_DESIRED_RECORDS, dwDesired >> 1);
|
|
}
|
|
|
|
TRY
|
|
{
|
|
DWORD j;
|
|
PWINSINTF_RECORD_ACTION_T pRow;
|
|
|
|
for (j = 0, pRow = Recs.pRow; j < Recs.NoOfRecs; j++, ++pRow)
|
|
{
|
|
WinsRecord wRecord;
|
|
HROW hrow = NULL;
|
|
|
|
pRow->OwnerId = m_dwOwner;
|
|
WinsIntfToWinsRecord(pRow, wRecord);
|
|
|
|
m_dwRecsCount++;
|
|
|
|
if (!m_bEnableCache && !m_IndexMgr.AcceptWinsRecord(&wRecord))
|
|
continue;
|
|
|
|
// add the data to our memory store and
|
|
// to the sorted index
|
|
m_cMemMan.AddData(wRecord, &hrow);
|
|
m_IndexMgr.AddHRow(hrow, FALSE, !m_bEnableCache);
|
|
}
|
|
|
|
// now setup the new range to search..
|
|
//
|
|
// if this is not the gap boundary detection cycle, the next MaxVersNo
|
|
// needs to go right below the current MinVersNo. Otherwise, MaxVersNo
|
|
// needs to remain untouched!
|
|
if (dwLargeGapCount != 0)
|
|
MaxVersNo.QuadPart = MinVersNo.QuadPart - 1;
|
|
|
|
// if no records were found..
|
|
if (Recs.NoOfRecs == 0)
|
|
{
|
|
// ..and we were already in the gap boundary detection cycle..
|
|
if (dwLargeGapCount == 0)
|
|
// ..just break the loop - there are simply no more records
|
|
// for this owner in the database
|
|
break;
|
|
|
|
// ..otherwise just decrease the gap boundary detection counter.
|
|
// If it reaches 0, then next cycle we will attempt to see if
|
|
// there is any record closer to the lowest edge of the range by
|
|
// expanding for one time only the whole space.
|
|
dwLargeGapCount--;
|
|
}
|
|
else
|
|
{
|
|
// if we just exited the gap boundary detection cycle by finding some
|
|
// records, set the LowestVersNo to one more than the largest VersNo
|
|
// we found during this cycle.
|
|
if (dwLargeGapCount == 0)
|
|
{
|
|
pRow--;
|
|
LowestVersNo.QuadPart = pRow->VersNo.QuadPart+1;
|
|
}
|
|
|
|
// if there were any records found, just reset the gap boundary detection counter.
|
|
dwLargeGapCount = LARGE_GAP_DETECT_COUNT;
|
|
}
|
|
|
|
// if the dwLargeGapCount counter is zero, it means the next cycle is a gap boundary detection one
|
|
// which means the range should be set for the whole unexplored space.
|
|
if (dwLargeGapCount != 0 && MaxVersNo.QuadPart > LowestVersNo.QuadPart + dwDesired)
|
|
MinVersNo.QuadPart = MaxVersNo.QuadPart - dwDesired;
|
|
else
|
|
MinVersNo.QuadPart = LowestVersNo.QuadPart;
|
|
}
|
|
CATCH_ALL(e)
|
|
{
|
|
err = ::GetLastError();
|
|
m_hrLastError = HRESULT_FROM_WIN32(err);
|
|
}
|
|
END_CATCH_ALL
|
|
|
|
}
|
|
|
|
if (Recs.pRow != NULL)
|
|
::WinsFreeMem(Recs.pRow);
|
|
|
|
return err;
|
|
}
|