1671 lines
41 KiB
C++
1671 lines
41 KiB
C++
|
/**********************************************************************/
|
||
|
/** Microsoft Windows/NT **/
|
||
|
/** Copyright(c) Microsoft Corporation, 1997 - 1999 -99 **/
|
||
|
/**********************************************************************/
|
||
|
|
||
|
/*
|
||
|
cprogdlg.cpp
|
||
|
The busy/progress dialog
|
||
|
|
||
|
FILE HISTORY:
|
||
|
|
||
|
*/
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
#include "winssnap.h"
|
||
|
#include "CProgdlg.h"
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
#define new DEBUG_NEW
|
||
|
#undef THIS_FILE
|
||
|
static char THIS_FILE[] = __FILE__;
|
||
|
#endif
|
||
|
|
||
|
TCHAR * gsz_EOL = _T("\r\n");
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// CProgress dialog
|
||
|
|
||
|
|
||
|
CProgress::CProgress(CWnd* pParent /*=NULL*/)
|
||
|
: CBaseDialog(CProgress::IDD, pParent)
|
||
|
{
|
||
|
//{{AFX_DATA_INIT(CProgress)
|
||
|
//}}AFX_DATA_INIT
|
||
|
}
|
||
|
|
||
|
|
||
|
void CProgress::DoDataExchange(CDataExchange* pDX)
|
||
|
{
|
||
|
CBaseDialog::DoDataExchange(pDX);
|
||
|
//{{AFX_DATA_MAP(CProgress)
|
||
|
DDX_Control(pDX, IDCANCEL, m_buttonCancel);
|
||
|
DDX_Control(pDX, IDC_EDIT_MESSAGE, m_editMessage);
|
||
|
//}}AFX_DATA_MAP
|
||
|
}
|
||
|
|
||
|
|
||
|
BEGIN_MESSAGE_MAP(CProgress, CBaseDialog)
|
||
|
//{{AFX_MSG_MAP(CProgress)
|
||
|
//}}AFX_MSG_MAP
|
||
|
END_MESSAGE_MAP()
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// CProgress message handlers
|
||
|
|
||
|
void CProgress::OnCancel()
|
||
|
{
|
||
|
// TODO: Add extra cleanup here
|
||
|
|
||
|
CBaseDialog::OnCancel();
|
||
|
}
|
||
|
|
||
|
BOOL CProgress::OnInitDialog()
|
||
|
{
|
||
|
CBaseDialog::OnInitDialog();
|
||
|
|
||
|
m_editMessage.SetLimitText(0xFFFFFFFF);
|
||
|
|
||
|
return TRUE; // return TRUE unless you set the focus to a control
|
||
|
// EXCEPTION: OCX Property Pages should return FALSE
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// CCheckNamesProgress dialog
|
||
|
|
||
|
BOOL CCheckNamesProgress::OnInitDialog()
|
||
|
{
|
||
|
CProgress::OnInitDialog();
|
||
|
|
||
|
m_Thread.m_pDlg = this;
|
||
|
|
||
|
CWaitCursor wc;
|
||
|
|
||
|
m_Thread.Start();
|
||
|
|
||
|
CString strText;
|
||
|
|
||
|
strText.LoadString(IDS_CANCEL);
|
||
|
m_buttonCancel.SetWindowText(strText);
|
||
|
|
||
|
strText.LoadString(IDS_CHECK_REG_TITLE);
|
||
|
SetWindowText(strText);
|
||
|
|
||
|
return TRUE; // return TRUE unless you set the focus to a control
|
||
|
// EXCEPTION: OCX Property Pages should return FALSE
|
||
|
}
|
||
|
|
||
|
void CCheckNamesProgress::BuildServerList()
|
||
|
{
|
||
|
CString strMessage;
|
||
|
|
||
|
strMessage.LoadString(IDS_BUILDING_SERVER_LIST);
|
||
|
strMessage += gsz_EOL;
|
||
|
|
||
|
AddStatusMessage(strMessage);
|
||
|
|
||
|
for (int i = 0; i < m_strServerArray.GetSize(); i++)
|
||
|
{
|
||
|
char szIP[MAX_PATH];
|
||
|
|
||
|
// NOTE: this should be ACP because it's winsock related
|
||
|
WideToMBCS(m_strServerArray[i], szIP);
|
||
|
|
||
|
// add this machine to the list
|
||
|
AddServerToList(inet_addr(szIP));
|
||
|
|
||
|
// check to see if we should add known partners
|
||
|
if (m_fVerifyWithPartners)
|
||
|
{
|
||
|
CWinsResults winsResults;
|
||
|
handle_t hBind;
|
||
|
WINSINTF_BIND_DATA_T BindData;
|
||
|
|
||
|
BindData.fTcpIp = TRUE;
|
||
|
BindData.pServerAdd = (LPSTR) (LPCTSTR) m_strServerArray[i];
|
||
|
|
||
|
hBind = ::WinsBind(&BindData);
|
||
|
if (!hBind)
|
||
|
{
|
||
|
// unable to bind to this server
|
||
|
AfxFormatString1(strMessage, IDS_UNABLE_TO_CONNECT, m_strServerArray[i]);
|
||
|
strMessage += gsz_EOL;
|
||
|
AddStatusMessage(strMessage);
|
||
|
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
DWORD err = winsResults.Update(hBind);
|
||
|
if (err)
|
||
|
{
|
||
|
strMessage.LoadString(IDS_GET_STATUS_FAILED);
|
||
|
strMessage += gsz_EOL;
|
||
|
AddStatusMessage(strMessage);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for (UINT j = 0; j < winsResults.NoOfOwners; j++)
|
||
|
{
|
||
|
// check to see if:
|
||
|
// 1. the address is not 0
|
||
|
// 2. the owner is not marked as deleted
|
||
|
// 3. the highest record count is not 0
|
||
|
|
||
|
if ( (winsResults.AddVersMaps[j].Add.IPAdd != 0) &&
|
||
|
(winsResults.AddVersMaps[j].VersNo.QuadPart != OWNER_DELETED) &&
|
||
|
(winsResults.AddVersMaps[j].VersNo.QuadPart != 0) )
|
||
|
{
|
||
|
AddServerToList(htonl(winsResults.AddVersMaps[j].Add.IPAdd));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
::WinsUnbind(&BindData, hBind);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// now display the list
|
||
|
strMessage.LoadString(IDS_SERVERS_TO_BE_QUERRIED);
|
||
|
strMessage += gsz_EOL;
|
||
|
AddStatusMessage(strMessage);
|
||
|
|
||
|
for (i = 0; i < m_winsServersArray.GetSize(); i++)
|
||
|
{
|
||
|
MakeIPAddress(ntohl(m_winsServersArray[i].Server.s_addr), strMessage);
|
||
|
strMessage += gsz_EOL;
|
||
|
|
||
|
AddStatusMessage(strMessage);
|
||
|
}
|
||
|
|
||
|
AddStatusMessage(gsz_EOL);
|
||
|
|
||
|
m_Thread.m_strNameArray.Copy(m_strNameArray);
|
||
|
m_Thread.m_winsServersArray.Copy(m_winsServersArray);
|
||
|
}
|
||
|
|
||
|
void CCheckNamesProgress::AddServerToList(u_long ip)
|
||
|
{
|
||
|
BOOL fFound = FALSE;
|
||
|
|
||
|
if (ip == 0)
|
||
|
return;
|
||
|
|
||
|
//
|
||
|
// Look to see if it is already in the list
|
||
|
//
|
||
|
for (int k = 0; k < m_winsServersArray.GetSize(); k++)
|
||
|
{
|
||
|
if (m_winsServersArray[k].Server.s_addr == ip)
|
||
|
{
|
||
|
fFound = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// if we didn't find it, add it.
|
||
|
if (!fFound)
|
||
|
{
|
||
|
WINSERVERS server = {0};
|
||
|
server.Server.s_addr = ip;
|
||
|
m_winsServersArray.Add(server);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CCheckNamesProgress::OnCancel()
|
||
|
{
|
||
|
if (m_Thread.IsRunning())
|
||
|
{
|
||
|
CWaitCursor wc;
|
||
|
|
||
|
CString strText;
|
||
|
strText.LoadString(IDS_CLEANING_UP);
|
||
|
strText += gsz_EOL;
|
||
|
AddStatusMessage(strText);
|
||
|
|
||
|
m_buttonCancel.EnableWindow(FALSE);
|
||
|
|
||
|
m_Thread.Abort(FALSE);
|
||
|
|
||
|
MSG msg;
|
||
|
while (PeekMessage(&msg,NULL,NULL,NULL,PM_REMOVE))
|
||
|
{
|
||
|
TranslateMessage(&msg);
|
||
|
DispatchMessage(&msg);
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
CProgress::OnCancel();
|
||
|
}
|
||
|
|
||
|
void CCheckNamesProgress::NotifyCompleted()
|
||
|
{
|
||
|
CString strText;
|
||
|
|
||
|
strText.LoadString(IDS_FINISHED);
|
||
|
strText += gsz_EOL;
|
||
|
AddStatusMessage(strText);
|
||
|
|
||
|
strText.LoadString(IDS_CLOSE);
|
||
|
m_buttonCancel.SetWindowText(strText);
|
||
|
m_buttonCancel.EnableWindow(TRUE);
|
||
|
}
|
||
|
|
||
|
/*---------------------------------------------------------------------------
|
||
|
CWinsThread
|
||
|
Background thread base class
|
||
|
Author: EricDav
|
||
|
---------------------------------------------------------------------------*/
|
||
|
CWinsThread::CWinsThread()
|
||
|
{
|
||
|
m_bAutoDelete = TRUE;
|
||
|
m_hEventHandle = NULL;
|
||
|
}
|
||
|
|
||
|
CWinsThread::~CWinsThread()
|
||
|
{
|
||
|
if (m_hEventHandle != NULL)
|
||
|
{
|
||
|
VERIFY(::CloseHandle(m_hEventHandle));
|
||
|
m_hEventHandle = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BOOL CWinsThread::Start()
|
||
|
{
|
||
|
ASSERT(m_hEventHandle == NULL); // cannot call start twice or reuse the same C++ object
|
||
|
|
||
|
m_hEventHandle = ::CreateEvent(NULL,TRUE /*bManualReset*/,FALSE /*signalled*/, NULL);
|
||
|
if (m_hEventHandle == NULL)
|
||
|
return FALSE;
|
||
|
|
||
|
return CreateThread();
|
||
|
}
|
||
|
|
||
|
void CWinsThread::Abort(BOOL fAutoDelete)
|
||
|
{
|
||
|
m_bAutoDelete = fAutoDelete;
|
||
|
|
||
|
SetEvent(m_hEventHandle);
|
||
|
}
|
||
|
|
||
|
void CWinsThread::AbortAndWait()
|
||
|
{
|
||
|
Abort(FALSE);
|
||
|
|
||
|
WaitForSingleObject(m_hThread, INFINITE);
|
||
|
}
|
||
|
|
||
|
BOOL CWinsThread::IsRunning()
|
||
|
{
|
||
|
if (WaitForSingleObject(m_hThread, 0) == WAIT_OBJECT_0)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BOOL CWinsThread::FCheckForAbort()
|
||
|
{
|
||
|
if (WaitForSingleObject(m_hEventHandle, 0) == WAIT_OBJECT_0)
|
||
|
{
|
||
|
Trace0("CWinsThread::FCheckForAbort - abort detected, exiting...\n");
|
||
|
return TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*---------------------------------------------------------------------------
|
||
|
CCheckNamesThread
|
||
|
Background thread for check registered names
|
||
|
Author: EricDav
|
||
|
---------------------------------------------------------------------------*/
|
||
|
int CCheckNamesThread::Run()
|
||
|
{
|
||
|
int i, nRetryCount, status;
|
||
|
BOOL fDone = FALSE;
|
||
|
int uNames, uServers;
|
||
|
u_short TransID = 0;
|
||
|
char szName[MAX_PATH];
|
||
|
WINSERVERS * pCurrentServer;
|
||
|
CString strStatus;
|
||
|
CString strTemp;
|
||
|
CString strTempName;
|
||
|
struct in_addr retaddr;
|
||
|
|
||
|
// build up the list of servers
|
||
|
m_pDlg->BuildServerList();
|
||
|
|
||
|
// initialize some comm stuff
|
||
|
InitNameCheckSocket();
|
||
|
|
||
|
// if the query is sent to the local server, TranIDs less than 0x7fff are dropped by NetBT
|
||
|
TransID = 0x8000;
|
||
|
|
||
|
// initialize all of the servers
|
||
|
for (i = 0; i < m_winsServersArray.GetSize(); i++)
|
||
|
{
|
||
|
m_winsServersArray[i].LastResponse = -1;
|
||
|
m_winsServersArray[i].fQueried = FALSE;
|
||
|
m_winsServersArray[i].Valid = 0;
|
||
|
m_winsServersArray[i].Failed = 0;
|
||
|
m_winsServersArray[i].Retries = 0;
|
||
|
m_winsServersArray[i].Completed = 0;
|
||
|
}
|
||
|
|
||
|
// initialize the verified address stuff
|
||
|
m_verifiedAddressArray.SetSize(m_strNameArray.GetSize());
|
||
|
for (i = 0; i < m_verifiedAddressArray.GetSize(); i++)
|
||
|
m_verifiedAddressArray[i] = 0;
|
||
|
|
||
|
for (uNames = 0; uNames < m_strNameArray.GetSize(); uNames++)
|
||
|
{
|
||
|
// convert unicode string to MBCS
|
||
|
memset(szName, 0, sizeof(szName));
|
||
|
CWinsName winsName = m_strNameArray[uNames];
|
||
|
|
||
|
// This should be OEM
|
||
|
WideToMBCS(winsName.strName, szName, WINS_NAME_CODE_PAGE);
|
||
|
|
||
|
// fill in the type (16th byte) and null terminate
|
||
|
szName[15] = (BYTE) winsName.dwType & 0x000000FF;
|
||
|
szName[16] = 0;
|
||
|
|
||
|
// pad the name with spaces to the 16th character
|
||
|
for (int nChar = 0; nChar < 16; nChar++)
|
||
|
{
|
||
|
if (szName[nChar] == 0)
|
||
|
szName[nChar] = ' ';
|
||
|
}
|
||
|
|
||
|
for (uServers = 0; uServers < m_winsServersArray.GetSize(); uServers++)
|
||
|
{
|
||
|
fDone = FALSE;
|
||
|
nRetryCount = 0;
|
||
|
TransID++;
|
||
|
|
||
|
pCurrentServer = &m_winsServersArray[uServers];
|
||
|
|
||
|
while (!fDone)
|
||
|
{
|
||
|
// build a status string
|
||
|
MakeIPAddress(ntohl(pCurrentServer->Server.S_un.S_addr), strTemp);
|
||
|
|
||
|
strTempName.Format(_T("%s[%02Xh]"), m_strNameArray[uNames].strName, m_strNameArray[uNames].dwType);
|
||
|
|
||
|
AfxFormatString2(strStatus,
|
||
|
IDS_SEND_NAME_QUERY,
|
||
|
strTemp,
|
||
|
strTempName);
|
||
|
|
||
|
// send the name query out on the wire
|
||
|
::SendNameQuery((unsigned char *)szName, pCurrentServer->Server.S_un.S_addr, TransID);
|
||
|
|
||
|
if (FCheckForAbort())
|
||
|
goto cleanup;
|
||
|
|
||
|
// check for a response
|
||
|
i = ::GetNameResponse(&retaddr.s_addr, TransID);
|
||
|
|
||
|
if (FCheckForAbort())
|
||
|
goto cleanup;
|
||
|
|
||
|
switch (i)
|
||
|
{
|
||
|
case WINSTEST_FOUND: // found
|
||
|
pCurrentServer->RetAddr.s_addr = retaddr.s_addr;
|
||
|
pCurrentServer->Valid = 1;
|
||
|
pCurrentServer->LastResponse = uNames;
|
||
|
|
||
|
if (retaddr.s_addr == m_verifiedAddressArray[uNames])
|
||
|
{
|
||
|
// this address has already been verified... don't
|
||
|
// do the checking again
|
||
|
strTemp.LoadString(IDS_OK);
|
||
|
strStatus += strTemp;
|
||
|
strStatus += gsz_EOL;
|
||
|
|
||
|
AddStatusMessage(strStatus);
|
||
|
fDone = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
status = VerifyRemote(inet_ntoa(pCurrentServer->RetAddr),
|
||
|
szName);
|
||
|
|
||
|
if (WINSTEST_VERIFIED == status)
|
||
|
{
|
||
|
strTemp.LoadString(IDS_OK);
|
||
|
strStatus += strTemp;
|
||
|
strStatus += gsz_EOL;
|
||
|
|
||
|
AddStatusMessage(strStatus);
|
||
|
|
||
|
m_verifiedAddressArray[uNames] = retaddr.s_addr;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
strTemp.LoadString(IDS_NOT_VERIFIED);
|
||
|
strStatus += strTemp;
|
||
|
strStatus += gsz_EOL;
|
||
|
|
||
|
AddStatusMessage(strStatus);
|
||
|
}
|
||
|
fDone = TRUE;
|
||
|
break;
|
||
|
|
||
|
case WINSTEST_NOT_FOUND: // responded -- name not found
|
||
|
pCurrentServer->RetAddr.s_addr = retaddr.s_addr;
|
||
|
pCurrentServer->Valid = 0;
|
||
|
pCurrentServer->LastResponse = uNames;
|
||
|
|
||
|
strTemp.LoadString(IDS_NAME_NOT_FOUND);
|
||
|
strStatus += strTemp;
|
||
|
strStatus += gsz_EOL;
|
||
|
|
||
|
AddStatusMessage(strStatus);
|
||
|
|
||
|
nRetryCount++;
|
||
|
if (nRetryCount > 2)
|
||
|
{
|
||
|
pCurrentServer->Failed = 1;
|
||
|
fDone = TRUE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WINSTEST_NO_RESPONSE: // no response
|
||
|
pCurrentServer->RetAddr.s_addr = retaddr.s_addr;
|
||
|
pCurrentServer->Valid = 0;
|
||
|
pCurrentServer->Retries++;
|
||
|
|
||
|
strTemp.LoadString(IDS_NO_RESPONSE);
|
||
|
strStatus += strTemp;
|
||
|
strStatus += gsz_EOL;
|
||
|
//strcat(lpResults, "; No response.\r\n");
|
||
|
|
||
|
AddStatusMessage(strStatus);
|
||
|
|
||
|
nRetryCount++;
|
||
|
if (nRetryCount > 2)
|
||
|
{
|
||
|
pCurrentServer->Failed = 1;
|
||
|
fDone = TRUE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
//unknown return
|
||
|
break;
|
||
|
|
||
|
} // switch GetNameResponse
|
||
|
|
||
|
} // while
|
||
|
|
||
|
} // for ServerInx
|
||
|
|
||
|
// Find a valid address for this name
|
||
|
for (uServers = 0; uServers < m_winsServersArray.GetSize(); uServers++)
|
||
|
{
|
||
|
pCurrentServer = &m_winsServersArray[uServers];
|
||
|
|
||
|
if (pCurrentServer->Valid)
|
||
|
{
|
||
|
DisplayInfo(uNames, pCurrentServer->RetAddr.s_addr);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} // name for loop
|
||
|
|
||
|
// mark all successful servers as completed
|
||
|
for (uServers = 0; uServers < m_winsServersArray.GetSize(); uServers++)
|
||
|
{
|
||
|
pCurrentServer = &m_winsServersArray[uServers];
|
||
|
if (!pCurrentServer->Failed)
|
||
|
{
|
||
|
pCurrentServer->Completed = 1;
|
||
|
}
|
||
|
} // for uServers
|
||
|
|
||
|
// dump the summary info
|
||
|
strStatus.LoadString(IDS_RESULTS);
|
||
|
strStatus = gsz_EOL + strStatus + gsz_EOL + gsz_EOL;
|
||
|
|
||
|
AddStatusMessage(strStatus);
|
||
|
|
||
|
for (i = 0; i < m_strSummaryArray.GetSize(); i++)
|
||
|
{
|
||
|
AddStatusMessage(m_strSummaryArray[i]);
|
||
|
}
|
||
|
|
||
|
// generate some end of run summary status
|
||
|
for (uServers = 0; uServers < m_winsServersArray.GetSize(); uServers++)
|
||
|
{
|
||
|
pCurrentServer = &m_winsServersArray[uServers];
|
||
|
if ((-1) == pCurrentServer->LastResponse)
|
||
|
{
|
||
|
MakeIPAddress(ntohl(pCurrentServer->Server.S_un.S_addr), strTemp);
|
||
|
AfxFormatString1(strStatus, IDS_SERVER_NEVER_RESPONDED, strTemp);
|
||
|
|
||
|
strStatus += gsz_EOL;
|
||
|
|
||
|
AddStatusMessage(strStatus);
|
||
|
}
|
||
|
else if (0 == pCurrentServer->Completed)
|
||
|
{
|
||
|
MakeIPAddress(ntohl(pCurrentServer->Server.S_un.S_addr), strTemp);
|
||
|
AfxFormatString1(strStatus, IDS_SERVER_NOT_COMPLETE, strTemp);
|
||
|
|
||
|
strStatus += gsz_EOL;
|
||
|
|
||
|
AddStatusMessage(strStatus);
|
||
|
}
|
||
|
} // for ServerInx
|
||
|
|
||
|
for (uNames = 0; uNames < m_strNameArray.GetSize(); uNames++)
|
||
|
{
|
||
|
if (0 == m_verifiedAddressArray[uNames])
|
||
|
{
|
||
|
strTempName.Format(_T("%s[%02Xh]"), m_strNameArray[uNames].strName, m_strNameArray[uNames].dwType);
|
||
|
AfxFormatString1(strStatus, IDS_NAME_NOT_VERIFIED, strTempName);
|
||
|
|
||
|
strStatus += gsz_EOL;
|
||
|
|
||
|
AddStatusMessage(strStatus);
|
||
|
}
|
||
|
} // for uNames
|
||
|
|
||
|
cleanup:
|
||
|
CloseNameCheckSocket();
|
||
|
|
||
|
m_pDlg->NotifyCompleted();
|
||
|
|
||
|
return 9;
|
||
|
}
|
||
|
|
||
|
void CCheckNamesThread::AddStatusMessage(LPCTSTR pszMessage)
|
||
|
{
|
||
|
m_pDlg->AddStatusMessage(pszMessage);
|
||
|
}
|
||
|
|
||
|
void CCheckNamesThread::DisplayInfo(int uNames, u_long ulValidAddr)
|
||
|
{
|
||
|
CString strTemp, strTempName, strStatus;
|
||
|
int uServers;
|
||
|
WINSERVERS * pCurrentServer;
|
||
|
struct in_addr tempaddr;
|
||
|
int i;
|
||
|
BOOL fMismatchFound = FALSE;
|
||
|
|
||
|
// now check and see which WINS servers didn't match
|
||
|
for (uServers = 0; uServers < m_winsServersArray.GetSize(); uServers++)
|
||
|
{
|
||
|
pCurrentServer = &m_winsServersArray[uServers];
|
||
|
if (pCurrentServer->Completed)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if ( (pCurrentServer->Valid) )
|
||
|
{
|
||
|
if ( (pCurrentServer->RetAddr.s_addr != ulValidAddr) ||
|
||
|
(m_verifiedAddressArray[uNames] != 0 &&
|
||
|
m_verifiedAddressArray[uNames] != ulValidAddr) )
|
||
|
{
|
||
|
// mismatch
|
||
|
strTempName.Format(_T("%s[%02Xh]"), m_strNameArray[uNames].strName, m_strNameArray[uNames].dwType);
|
||
|
AfxFormatString1(strStatus, IDS_INCONSISTENCY_FOUND, strTempName);
|
||
|
strStatus += gsz_EOL;
|
||
|
|
||
|
m_strSummaryArray.Add(strStatus);
|
||
|
|
||
|
if (m_verifiedAddressArray[uNames] != 0)
|
||
|
{
|
||
|
tempaddr.s_addr = m_verifiedAddressArray[uNames];
|
||
|
|
||
|
MakeIPAddress(ntohl(tempaddr.S_un.S_addr), strTemp);
|
||
|
AfxFormatString1(strStatus, IDS_VERIFIED_ADDRESS, strTemp);
|
||
|
strStatus += gsz_EOL;
|
||
|
|
||
|
m_strSummaryArray.Add(strStatus);
|
||
|
}
|
||
|
|
||
|
// display the inconsistent name resolutions
|
||
|
for (i = 0; i < m_winsServersArray.GetSize(); i++)
|
||
|
{
|
||
|
if (m_winsServersArray[i].Valid &&
|
||
|
m_verifiedAddressArray[uNames] != m_winsServersArray[i].RetAddr.S_un.S_addr)
|
||
|
{
|
||
|
MakeIPAddress(ntohl(m_winsServersArray[i].Server.S_un.S_addr), strTemp);
|
||
|
|
||
|
strTempName.Format(_T("%s[%02Xh]"), m_strNameArray[uNames].strName, m_strNameArray[uNames].dwType);
|
||
|
AfxFormatString2(strStatus,
|
||
|
IDS_NAME_QUERY_RESULT,
|
||
|
strTemp,
|
||
|
strTempName);
|
||
|
|
||
|
CString strTemp2;
|
||
|
|
||
|
MakeIPAddress(ntohl(m_winsServersArray[i].RetAddr.S_un.S_addr), strTemp2);
|
||
|
AfxFormatString1(strTemp, IDS_NAME_QUERY_RETURNED, strTemp2);
|
||
|
|
||
|
strStatus += strTemp;
|
||
|
strStatus += gsz_EOL;
|
||
|
|
||
|
m_strSummaryArray.Add(strStatus);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
m_strSummaryArray.Add(gsz_EOL);
|
||
|
fMismatchFound = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
} // end check for invalid addresses
|
||
|
|
||
|
if (!fMismatchFound)
|
||
|
{
|
||
|
// display the correct info
|
||
|
strTempName.Format(_T("%s[%02Xh]"), m_strNameArray[uNames].strName, m_strNameArray[uNames].dwType);
|
||
|
MakeIPAddress(ntohl(ulValidAddr), strTemp);
|
||
|
|
||
|
AfxFormatString2(strStatus, IDS_NAME_VERIFIED, strTempName, strTemp);
|
||
|
strStatus += gsz_EOL;
|
||
|
|
||
|
m_strSummaryArray.Add(strStatus);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*---------------------------------------------------------------------------
|
||
|
CCheckVersionProgress
|
||
|
Status dialog for check version consistency
|
||
|
Author: EricDav
|
||
|
---------------------------------------------------------------------------*/
|
||
|
BOOL CCheckVersionProgress::OnInitDialog()
|
||
|
{
|
||
|
CProgress::OnInitDialog();
|
||
|
|
||
|
CWaitCursor wc;
|
||
|
|
||
|
m_Thread.m_dwIpAddress = m_dwIpAddress;
|
||
|
m_Thread.m_pDlg = this;
|
||
|
m_Thread.m_hBinding = m_hBinding;
|
||
|
|
||
|
m_Thread.Start();
|
||
|
|
||
|
CString strText;
|
||
|
|
||
|
strText.LoadString(IDS_CANCEL);
|
||
|
m_buttonCancel.SetWindowText(strText);
|
||
|
|
||
|
strText.LoadString(IDS_CHECK_VERSION_TITLE);
|
||
|
SetWindowText(strText);
|
||
|
|
||
|
return TRUE; // return TRUE unless you set the focus to a control
|
||
|
// EXCEPTION: OCX Property Pages should return FALSE
|
||
|
}
|
||
|
|
||
|
void CCheckVersionProgress::OnCancel()
|
||
|
{
|
||
|
if (m_Thread.IsRunning())
|
||
|
{
|
||
|
CWaitCursor wc;
|
||
|
|
||
|
CString strText;
|
||
|
strText.LoadString(IDS_CLEANING_UP);
|
||
|
strText += gsz_EOL;
|
||
|
AddStatusMessage(strText);
|
||
|
|
||
|
m_buttonCancel.EnableWindow(FALSE);
|
||
|
|
||
|
m_Thread.Abort(FALSE);
|
||
|
|
||
|
MSG msg;
|
||
|
while (PeekMessage(&msg,NULL,NULL,NULL,PM_REMOVE))
|
||
|
{
|
||
|
TranslateMessage(&msg);
|
||
|
DispatchMessage(&msg);
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
CProgress::OnCancel();
|
||
|
}
|
||
|
|
||
|
void CCheckVersionProgress::NotifyCompleted()
|
||
|
{
|
||
|
CString strText;
|
||
|
|
||
|
strText.LoadString(IDS_FINISHED);
|
||
|
strText += gsz_EOL;
|
||
|
AddStatusMessage(strText);
|
||
|
|
||
|
strText.LoadString(IDS_CLOSE);
|
||
|
m_buttonCancel.SetWindowText(strText);
|
||
|
m_buttonCancel.EnableWindow(TRUE);
|
||
|
}
|
||
|
|
||
|
/*---------------------------------------------------------------------------
|
||
|
CCheckVersionThread
|
||
|
Background thread for check version consistency
|
||
|
Author: EricDav
|
||
|
---------------------------------------------------------------------------*/
|
||
|
void CCheckVersionThread::AddStatusMessage(LPCTSTR pszMessage)
|
||
|
{
|
||
|
m_pDlg->AddStatusMessage(pszMessage);
|
||
|
}
|
||
|
|
||
|
// this is where the work gets done
|
||
|
int CCheckVersionThread::Run()
|
||
|
{
|
||
|
HRESULT hr = hrOK;
|
||
|
CWinsResults winsResults, winsResultsCurrent;
|
||
|
CString strMessage;
|
||
|
CString strIP;
|
||
|
DWORD dwMasterNoOfOwners;
|
||
|
BOOL bProblem;
|
||
|
UINT i;
|
||
|
|
||
|
m_pLISOTable = new LARGE_INTEGER[100][MAX_WINS];
|
||
|
|
||
|
m_strLATable.RemoveAll();
|
||
|
m_strLATable.SetSize(MAX_WINS);
|
||
|
|
||
|
DWORD status = winsResults.Update(m_hBinding);
|
||
|
if (status != ERROR_SUCCESS)
|
||
|
{
|
||
|
strMessage.LoadString(IDS_ERROR_OCCURRED);
|
||
|
strMessage += gsz_EOL;
|
||
|
|
||
|
AddStatusMessage(strMessage);
|
||
|
|
||
|
LPTSTR pBuf = strMessage.GetBuffer(1024);
|
||
|
|
||
|
GetSystemMessage(status, pBuf, 1024);
|
||
|
strMessage.ReleaseBuffer();
|
||
|
strMessage += gsz_EOL;
|
||
|
|
||
|
AddStatusMessage(strMessage);
|
||
|
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
dwMasterNoOfOwners = winsResults.NoOfOwners;
|
||
|
|
||
|
memset(m_pLISOTable, 0, MAX_WINS);
|
||
|
|
||
|
status = InitLATable(winsResults.AddVersMaps.GetData(), 0, winsResults.NoOfOwners);
|
||
|
|
||
|
// Place entry in the SO Table in proper order
|
||
|
MakeIPAddress(m_dwIpAddress, strIP);
|
||
|
AddSOTableEntry(strIP, winsResults.AddVersMaps.GetData(), winsResults.NoOfOwners, dwMasterNoOfOwners);
|
||
|
|
||
|
// For each of the owners, get the owner-version map
|
||
|
for (i = 0; i < dwMasterNoOfOwners; i++)
|
||
|
{
|
||
|
if (m_strLATable[i] == strIP)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// Get the owner's table
|
||
|
WINSINTF_BIND_DATA_T wbdBindData;
|
||
|
handle_t hBinding = NULL;
|
||
|
|
||
|
wbdBindData.fTcpIp = 1;
|
||
|
wbdBindData.pPipeName = NULL;
|
||
|
|
||
|
wbdBindData.pServerAdd = (LPSTR) (LPCTSTR) m_strLATable[i];
|
||
|
|
||
|
// first bind to the machine
|
||
|
if ((hBinding = ::WinsBind(&wbdBindData)) == NULL)
|
||
|
{
|
||
|
CString strBuf;
|
||
|
LPTSTR pBuf = strBuf.GetBuffer(4096);
|
||
|
|
||
|
::GetSystemMessage(GetLastError(), pBuf, 4096);
|
||
|
strBuf.ReleaseBuffer();
|
||
|
|
||
|
Trace1("\n==> Machine %s is probably down\n\n", m_strLATable[i]);
|
||
|
|
||
|
AfxFormatString2(strMessage, IDS_MSG_STATUS_DOWN, m_strLATable[i], strBuf);
|
||
|
strMessage += gsz_EOL;
|
||
|
|
||
|
AddStatusMessage(strMessage);
|
||
|
|
||
|
RemoveFromSOTable(m_strLATable[i], winsResults.NoOfOwners);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// now get the info
|
||
|
status = winsResultsCurrent.Update(hBinding);
|
||
|
if (status != ERROR_SUCCESS)
|
||
|
{
|
||
|
CString strBuf;
|
||
|
LPTSTR pBuf = strBuf.GetBuffer(4096);
|
||
|
|
||
|
::GetSystemMessage(status, pBuf, 4096);
|
||
|
strBuf.ReleaseBuffer();
|
||
|
|
||
|
Trace1("\n==> Machine %s is probably down\n\n", m_strLATable[i]);
|
||
|
|
||
|
AfxFormatString2(strMessage, IDS_MSG_STATUS_DOWN, m_strLATable[i], strBuf);
|
||
|
strMessage += gsz_EOL;
|
||
|
|
||
|
AddStatusMessage(strMessage);
|
||
|
|
||
|
RemoveFromSOTable(m_strLATable[i], winsResults.NoOfOwners);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// ok, looks good
|
||
|
AfxFormatString1(strMessage, IDS_MSG_STATUS_UP, m_strLATable[i]);
|
||
|
strMessage += gsz_EOL;
|
||
|
AddStatusMessage(strMessage);
|
||
|
|
||
|
if (dwMasterNoOfOwners < winsResultsCurrent.NoOfOwners)
|
||
|
{
|
||
|
status = InitLATable(winsResultsCurrent.AddVersMaps.GetData(), dwMasterNoOfOwners, winsResultsCurrent.NoOfOwners);
|
||
|
if (status != winsResultsCurrent.NoOfOwners)
|
||
|
{
|
||
|
Trace0("New size does not match!!\n");
|
||
|
}
|
||
|
|
||
|
dwMasterNoOfOwners = status;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Place entry in the SO Table in proper order
|
||
|
//
|
||
|
AddSOTableEntry(m_strLATable[i], winsResultsCurrent.AddVersMaps.GetData(), winsResultsCurrent.NoOfOwners, dwMasterNoOfOwners);
|
||
|
}
|
||
|
|
||
|
::WinsUnbind(&wbdBindData, hBinding);
|
||
|
hBinding = NULL;
|
||
|
|
||
|
if (FCheckForAbort())
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
// Check if diagonal elements in the [SO] table are the highest in their cols.
|
||
|
bProblem = CheckSOTableConsistency(dwMasterNoOfOwners);
|
||
|
if (!bProblem)
|
||
|
{
|
||
|
strMessage.LoadString(IDS_VERSION_CHECK_SUCCESS);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
strMessage.LoadString(IDS_VERSION_CHECK_FAIL);
|
||
|
}
|
||
|
|
||
|
strMessage += gsz_EOL;
|
||
|
|
||
|
AddStatusMessage(strMessage);
|
||
|
|
||
|
cleanup:
|
||
|
if (m_pLISOTable)
|
||
|
{
|
||
|
delete[] m_pLISOTable;
|
||
|
m_pLISOTable = NULL;
|
||
|
}
|
||
|
|
||
|
m_pDlg->NotifyCompleted();
|
||
|
|
||
|
return 10;
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
CCheckVersionThread::InitLATable
|
||
|
(
|
||
|
PWINSINTF_ADD_VERS_MAP_T pAddVersMaps,
|
||
|
DWORD MasterOwners, // 0 first time
|
||
|
DWORD NoOfOwners
|
||
|
)
|
||
|
{
|
||
|
ULONG i, j;
|
||
|
|
||
|
if (MasterOwners == 0)
|
||
|
{
|
||
|
// first time - init the LA table
|
||
|
for (i = 0; i < NoOfOwners; i++, pAddVersMaps++)
|
||
|
{
|
||
|
DWORD dwIP = pAddVersMaps->Add.IPAdd;
|
||
|
CString strIP;
|
||
|
MakeIPAddress(dwIP, strIP);
|
||
|
m_strLATable.InsertAt(i, strIP);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// More came in this time - add them to the LA table after the others
|
||
|
for (i = 0; i < NoOfOwners; i++, pAddVersMaps++)
|
||
|
{
|
||
|
DWORD dwIP = pAddVersMaps->Add.IPAdd;
|
||
|
CString strIP;
|
||
|
MakeIPAddress(dwIP, strIP);
|
||
|
|
||
|
// If this entry is not in the LA table, insert
|
||
|
for (j = 0; j < MasterOwners; j++)
|
||
|
{
|
||
|
if (m_strLATable[j] == strIP)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (j == MasterOwners)
|
||
|
{
|
||
|
//
|
||
|
// Insert
|
||
|
//
|
||
|
Trace2("Inserting %s at %d\n", strIP, MasterOwners);
|
||
|
m_strLATable[MasterOwners] = strIP;
|
||
|
MasterOwners++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return MasterOwners;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
CCheckVersionThread::AddSOTableEntry
|
||
|
(
|
||
|
CString & strIP,
|
||
|
PWINSINTF_ADD_VERS_MAP_T pMasterMaps,
|
||
|
DWORD NoOfOwners,
|
||
|
DWORD MasterOwners
|
||
|
)
|
||
|
{
|
||
|
ULONG i;
|
||
|
LONG lRow;
|
||
|
|
||
|
int nResize = INIT_SIZE;
|
||
|
|
||
|
lRow = IPToIndex(strIP, MasterOwners);
|
||
|
|
||
|
// Fill the row
|
||
|
for ( i = 0; i < NoOfOwners; i++, pMasterMaps++)
|
||
|
{
|
||
|
LONG lCol;
|
||
|
|
||
|
DWORD dwIP = pMasterMaps->Add.IPAdd;
|
||
|
CString strColIP;
|
||
|
MakeIPAddress(dwIP, strColIP);
|
||
|
|
||
|
lCol = IPToIndex(strColIP, MasterOwners);
|
||
|
|
||
|
// Place only a non-deleted entry
|
||
|
if (!((pMasterMaps->VersNo.HighPart == MAXLONG) &&
|
||
|
(pMasterMaps->VersNo.LowPart == MAXLONG)))
|
||
|
{
|
||
|
|
||
|
if((int) i >= nResize)
|
||
|
{
|
||
|
// create a new array and copy the contents of m_pLISOTable
|
||
|
// to this array, this acts as a temp variable.
|
||
|
LARGE_INTEGER (*tempLISOTable)[MAX_WINS];
|
||
|
|
||
|
tempLISOTable = new LARGE_INTEGER[nResize][MAX_WINS];
|
||
|
|
||
|
// now copy the elements to the temp array
|
||
|
for(int xPos = 0; xPos < nResize; xPos++)
|
||
|
{
|
||
|
for (int yPos = 0; yPos < MAX_WINS; yPos++)
|
||
|
{
|
||
|
tempLISOTable [xPos][yPos] = m_pLISOTable[xPos][yPos];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// increase the amount to be allocated
|
||
|
nResize += INIT_SIZE;
|
||
|
|
||
|
// realloc the array
|
||
|
delete [] m_pLISOTable;
|
||
|
m_pLISOTable = new LARGE_INTEGER[nResize][MAX_WINS];
|
||
|
|
||
|
int nLimit = nResize-INIT_SIZE;
|
||
|
|
||
|
// copy back the elements from the temp array, remember nresize
|
||
|
// has been increased by INIT_SIZE
|
||
|
for(xPos = 0; xPos < nLimit; xPos++)
|
||
|
{
|
||
|
for(int yPos = 0; yPos < MAX_WINS; yPos++)
|
||
|
{
|
||
|
m_pLISOTable [xPos][yPos] = tempLISOTable[xPos][yPos];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// now delete the temp table
|
||
|
delete [] tempLISOTable;
|
||
|
}
|
||
|
// Also if the entry above us was 0, write 0 there so as to make the fail case stand out
|
||
|
if (lRow && m_pLISOTable[lRow-1][lCol].QuadPart == 0)
|
||
|
{
|
||
|
m_pLISOTable[lRow][lCol].QuadPart = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_pLISOTable[lRow][lCol] = pMasterMaps->VersNo;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LONG
|
||
|
CCheckVersionThread::IPToIndex
|
||
|
(
|
||
|
CString & strIP,
|
||
|
DWORD NoOfOwners
|
||
|
)
|
||
|
{
|
||
|
ULONG i;
|
||
|
|
||
|
// Get the Row #
|
||
|
for ( i = 0; i < NoOfOwners; i++)
|
||
|
{
|
||
|
if (m_strLATable[i] == strIP)
|
||
|
{
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
// The first NULL entry indicates end
|
||
|
if (m_strLATable[i] == _T(""))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Entry not found - add
|
||
|
m_strLATable[i] = strIP;
|
||
|
//LA_TableSize = i+1;
|
||
|
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
CCheckVersionThread::CheckSOTableConsistency
|
||
|
(
|
||
|
DWORD dwMasterOwners
|
||
|
)
|
||
|
{
|
||
|
//ULONG i;
|
||
|
//ULONG j;
|
||
|
BOOLEAN fProblem = FALSE;
|
||
|
CString strMessage;
|
||
|
|
||
|
for (DWORD i = 0; i < dwMasterOwners; i++)
|
||
|
{
|
||
|
// Is the diagonal element at i the largest in its column?
|
||
|
for (DWORD j = 0; j < dwMasterOwners; j++)
|
||
|
{
|
||
|
if (i == j)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// Compare only non-zero values
|
||
|
if (m_pLISOTable[i][i].QuadPart &&
|
||
|
m_pLISOTable[j][i].QuadPart &&
|
||
|
(m_pLISOTable[i][i].QuadPart < m_pLISOTable[j][i].QuadPart))
|
||
|
{
|
||
|
AfxFormatString2(strMessage, IDS_VERSION_INCONSISTENCY_FOUND, m_strLATable[j], m_strLATable[i]);
|
||
|
strMessage += gsz_EOL;
|
||
|
|
||
|
AddStatusMessage(strMessage);
|
||
|
|
||
|
fProblem = TRUE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return fProblem;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
CCheckVersionThread::RemoveFromSOTable
|
||
|
(
|
||
|
CString & strIP,
|
||
|
DWORD dwMasterOwners
|
||
|
)
|
||
|
{
|
||
|
ULONG i;
|
||
|
LONG Row;
|
||
|
|
||
|
Row = IPToIndex(strIP, dwMasterOwners);
|
||
|
|
||
|
// Mark the row and col as down (0's)
|
||
|
for (i = 0; i < dwMasterOwners; i++)
|
||
|
{
|
||
|
m_pLISOTable[Row][i].QuadPart = m_pLISOTable[i][Row].QuadPart = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*---------------------------------------------------------------------------
|
||
|
CDBCompactProgress
|
||
|
Status dialog for DBCompact
|
||
|
Author: EricDav
|
||
|
---------------------------------------------------------------------------*/
|
||
|
BOOL CDBCompactProgress::OnInitDialog()
|
||
|
{
|
||
|
CProgress::OnInitDialog();
|
||
|
|
||
|
CWaitCursor wc;
|
||
|
|
||
|
m_Thread.m_pDlg = this;
|
||
|
m_Thread.m_hBinding = m_hBinding;
|
||
|
m_Thread.m_dwIpAddress = m_dwIpAddress;
|
||
|
m_Thread.m_strServerName = m_strServerName;
|
||
|
m_Thread.m_pConfig = m_pConfig;
|
||
|
|
||
|
m_Thread.Start();
|
||
|
|
||
|
CString strText;
|
||
|
|
||
|
strText.LoadString(IDS_CANCEL);
|
||
|
m_buttonCancel.SetWindowText(strText);
|
||
|
|
||
|
strText.LoadString(IDS_COMPACT_DATABASE_TITLE);
|
||
|
SetWindowText(strText);
|
||
|
|
||
|
// user cannot cancel this operation as that would be really bad...
|
||
|
m_buttonCancel.EnableWindow(FALSE);
|
||
|
|
||
|
return TRUE; // return TRUE unless you set the focus to a control
|
||
|
// EXCEPTION: OCX Property Pages should return FALSE
|
||
|
}
|
||
|
|
||
|
void CDBCompactProgress::OnCancel()
|
||
|
{
|
||
|
if (m_Thread.IsRunning())
|
||
|
{
|
||
|
CWaitCursor wc;
|
||
|
|
||
|
CString strText;
|
||
|
strText.LoadString(IDS_CLEANING_UP);
|
||
|
strText += gsz_EOL;
|
||
|
AddStatusMessage(strText);
|
||
|
|
||
|
m_buttonCancel.EnableWindow(FALSE);
|
||
|
|
||
|
m_Thread.Abort(FALSE);
|
||
|
|
||
|
MSG msg;
|
||
|
while (PeekMessage(&msg,NULL,NULL,NULL,PM_REMOVE))
|
||
|
{
|
||
|
TranslateMessage(&msg);
|
||
|
DispatchMessage(&msg);
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
CProgress::OnCancel();
|
||
|
}
|
||
|
|
||
|
void CDBCompactProgress::NotifyCompleted()
|
||
|
{
|
||
|
CString strText;
|
||
|
|
||
|
strText.LoadString(IDS_FINISHED);
|
||
|
strText += gsz_EOL;
|
||
|
AddStatusMessage(strText);
|
||
|
|
||
|
strText.LoadString(IDS_CLOSE);
|
||
|
m_buttonCancel.SetWindowText(strText);
|
||
|
m_buttonCancel.EnableWindow(TRUE);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*---------------------------------------------------------------------------
|
||
|
CDBCompactThread
|
||
|
Background thread for DB Compact
|
||
|
Author: EricDav
|
||
|
---------------------------------------------------------------------------*/
|
||
|
|
||
|
// this is where the work gets done
|
||
|
int CDBCompactThread::Run()
|
||
|
{
|
||
|
DWORD err = ERROR_SUCCESS;
|
||
|
DWORD_PTR dwLength;
|
||
|
CString strStartingDirectory, strWinsDb, strWinsTempDb, strCommandLine;
|
||
|
CString strTemp, strMessage, strOutput;
|
||
|
LPSTR pszOutput;
|
||
|
|
||
|
// get the version of NT running on this machine
|
||
|
// we can do this because this command only runs locally.
|
||
|
OSVERSIONINFO os;
|
||
|
ZeroMemory(&os, sizeof(OSVERSIONINFO));
|
||
|
os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
||
|
|
||
|
BOOL bRet = GetVersionEx(&os);
|
||
|
|
||
|
if (!bRet)
|
||
|
{
|
||
|
strMessage.LoadString(IDS_ERROR_OCCURRED);
|
||
|
strMessage += gsz_EOL;
|
||
|
|
||
|
AddStatusMessage(strMessage);
|
||
|
|
||
|
LPTSTR pBuf = strMessage.GetBuffer(1024);
|
||
|
|
||
|
GetSystemMessage(GetLastError(), pBuf, 1024);
|
||
|
strMessage.ReleaseBuffer();
|
||
|
strMessage += gsz_EOL;
|
||
|
|
||
|
AddStatusMessage(strMessage);
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
// all of the log files go into system32\wins so that's our starting dir
|
||
|
if (!GetSystemDirectory(strStartingDirectory.GetBuffer(MAX_PATH), MAX_PATH))
|
||
|
{
|
||
|
strMessage.LoadString(IDS_ERROR_OCCURRED);
|
||
|
strMessage += gsz_EOL;
|
||
|
|
||
|
AddStatusMessage(strMessage);
|
||
|
|
||
|
LPTSTR pBuf = strMessage.GetBuffer(1024);
|
||
|
|
||
|
GetSystemMessage(GetLastError(), pBuf, 1024);
|
||
|
strMessage.ReleaseBuffer();
|
||
|
strMessage += gsz_EOL;
|
||
|
|
||
|
AddStatusMessage(strMessage);
|
||
|
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
strStartingDirectory.ReleaseBuffer();
|
||
|
strStartingDirectory += _T("\\wins");
|
||
|
|
||
|
// check to see if the database is in the correct location
|
||
|
if (m_pConfig->m_strDbName.IsEmpty())
|
||
|
{
|
||
|
strWinsDb = _T("wins.mdb");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// the user has changed it...
|
||
|
strWinsDb = m_pConfig->m_strDbName;
|
||
|
}
|
||
|
|
||
|
strWinsTempDb = _T("winstemp.mdb");
|
||
|
|
||
|
strCommandLine = _T("jetpack.exe ");
|
||
|
|
||
|
switch (os.dwMajorVersion)
|
||
|
{
|
||
|
case VERSION_NT_50:
|
||
|
strCommandLine += strWinsDb + _T(" ") + strWinsTempDb;
|
||
|
break;
|
||
|
|
||
|
case VERSION_NT_40:
|
||
|
strCommandLine += _T("-40db" ) + strWinsDb + _T(" ") + strWinsTempDb;
|
||
|
break;
|
||
|
|
||
|
case VERSION_NT_351:
|
||
|
strCommandLine += _T("-351db ") + strWinsDb + _T(" ") + strWinsTempDb;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
|
||
|
// disconnect from the server and stop the service
|
||
|
DisConnectFromWinsServer();
|
||
|
|
||
|
strTemp.LoadString(IDS_COMPACT_STATUS_STOPPING_WINS);
|
||
|
AddStatusMessage(strTemp);
|
||
|
|
||
|
ControlWINSService(m_strServerName, TRUE);
|
||
|
|
||
|
strTemp.LoadString(IDS_COMPACT_STATUS_COMPACTING);
|
||
|
AddStatusMessage(strTemp);
|
||
|
AddStatusMessage(strCommandLine);
|
||
|
AddStatusMessage(gsz_EOL);
|
||
|
|
||
|
dwLength = RunApp(strCommandLine, strStartingDirectory, &pszOutput);
|
||
|
|
||
|
// the output comes back in ANSI. Convert to unicode by using a CString
|
||
|
strOutput = pszOutput;
|
||
|
strOutput += gsz_EOL;
|
||
|
|
||
|
AddStatusMessage(strOutput);
|
||
|
|
||
|
strTemp.LoadString(IDS_COMPACT_STATUS_STARTING_WINS);
|
||
|
AddStatusMessage(strTemp);
|
||
|
|
||
|
//start the service again and connect to the server
|
||
|
err = ControlWINSService(m_strServerName, FALSE);
|
||
|
|
||
|
err = ConnectToWinsServer();
|
||
|
|
||
|
strTemp.LoadString(IDS_COMPACT_STATUS_COMPLETED);
|
||
|
AddStatusMessage(strTemp);
|
||
|
|
||
|
cleanup:
|
||
|
m_pDlg->NotifyCompleted();
|
||
|
|
||
|
return 11;
|
||
|
}
|
||
|
|
||
|
void CDBCompactThread::AddStatusMessage(LPCTSTR pszMessage)
|
||
|
{
|
||
|
m_pDlg->AddStatusMessage(pszMessage);
|
||
|
}
|
||
|
|
||
|
void CDBCompactThread::DisConnectFromWinsServer()
|
||
|
{
|
||
|
if (m_hBinding)
|
||
|
{
|
||
|
CString strIP;
|
||
|
WINSINTF_BIND_DATA_T wbdBindData;
|
||
|
|
||
|
MakeIPAddress(m_dwIpAddress, strIP);
|
||
|
|
||
|
wbdBindData.fTcpIp = 1;
|
||
|
wbdBindData.pPipeName = NULL;
|
||
|
wbdBindData.pServerAdd = (LPSTR) (LPCTSTR) strIP;
|
||
|
|
||
|
::WinsUnbind(&wbdBindData, m_hBinding);
|
||
|
|
||
|
m_hBinding = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DWORD CDBCompactThread::ConnectToWinsServer()
|
||
|
{
|
||
|
HRESULT hr = hrOK;
|
||
|
|
||
|
CString strServerName, strIP;
|
||
|
DWORD dwStatus = ERROR_SUCCESS;
|
||
|
WINSINTF_ADD_T waWinsAddress;
|
||
|
WINSINTF_BIND_DATA_T wbdBindData;
|
||
|
|
||
|
// build some information about the server
|
||
|
MakeIPAddress(m_dwIpAddress, strIP);
|
||
|
|
||
|
DisConnectFromWinsServer();
|
||
|
|
||
|
// now that the server name and ip are valid, call
|
||
|
// WINSBind function directly.
|
||
|
do
|
||
|
{
|
||
|
char szNetBIOSName[128] = {0};
|
||
|
|
||
|
// call WinsBind function with the IP address
|
||
|
wbdBindData.fTcpIp = 1;
|
||
|
wbdBindData.pPipeName = NULL;
|
||
|
wbdBindData.pServerAdd = (LPSTR) (LPCTSTR) strIP;
|
||
|
|
||
|
BEGIN_WAIT_CURSOR
|
||
|
|
||
|
if ((m_hBinding = ::WinsBind(&wbdBindData)) == NULL)
|
||
|
{
|
||
|
dwStatus = ::GetLastError();
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// do we need to do this? Is this just extra validation?
|
||
|
#ifdef WINS_CLIENT_APIS
|
||
|
dwStatus = ::WinsGetNameAndAdd(m_hBinding, &waWinsAddress, (LPBYTE) szNetBIOSName);
|
||
|
#else
|
||
|
dwStatus = ::WinsGetNameAndAdd(&waWinsAddress, (LPBYTE) szNetBIOSName);
|
||
|
#endif WINS_CLIENT_APIS
|
||
|
|
||
|
END_WAIT_CURSOR
|
||
|
|
||
|
} while (FALSE);
|
||
|
|
||
|
return dwStatus;
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* FUNCTION: RunApp
|
||
|
*
|
||
|
* PURPOSE: Starts a process to run the command line specified
|
||
|
*
|
||
|
* COMMENTS:
|
||
|
*
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
DWORD_PTR CDBCompactThread::RunApp(LPCTSTR input, LPCTSTR startingDirectory, LPSTR * output)
|
||
|
{
|
||
|
STARTUPINFO StartupInfo;
|
||
|
PROCESS_INFORMATION ProcessInfo;
|
||
|
SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES),
|
||
|
NULL, // NULL security descriptor
|
||
|
TRUE}; // Inherit handles (necessary!)
|
||
|
HANDLE hReadHandle, hWriteHandle, hErrorHandle;
|
||
|
LPSTR outputbuffer, lpOutput;
|
||
|
SIZE_T AvailableOutput;
|
||
|
BOOL TimeoutNotReached = TRUE;
|
||
|
DWORD BytesRead;
|
||
|
OVERLAPPED PipeOverlapInfo = {0,0,0,0,0};
|
||
|
CHAR szErrorMsg[1024];
|
||
|
|
||
|
// Create the heap if it doesn't already exist
|
||
|
if (m_hHeapHandle == 0)
|
||
|
{
|
||
|
if ((m_hHeapHandle = HeapCreate(0,
|
||
|
8192,
|
||
|
0)) == NULL) return 0;
|
||
|
}
|
||
|
|
||
|
// Create buffer to receive stdout output from our process
|
||
|
if ((outputbuffer = (LPSTR) HeapAlloc(m_hHeapHandle,
|
||
|
HEAP_ZERO_MEMORY,
|
||
|
4096)) == NULL) return 0;
|
||
|
*output = outputbuffer;
|
||
|
|
||
|
// Check input parameter
|
||
|
if (input == NULL)
|
||
|
{
|
||
|
strcpy(outputbuffer, "ERROR: No command line specified");
|
||
|
return strlen(outputbuffer);
|
||
|
}
|
||
|
|
||
|
// Zero init process startup struct
|
||
|
FillMemory(&StartupInfo, sizeof(StartupInfo), 0);
|
||
|
|
||
|
StartupInfo.cb = sizeof(StartupInfo);
|
||
|
StartupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; // Use the our stdio handles
|
||
|
|
||
|
// Create pipe that will xfer process' stdout to our buffer
|
||
|
if (!CreatePipe(&hReadHandle,
|
||
|
&hWriteHandle,
|
||
|
&sa,
|
||
|
0))
|
||
|
{
|
||
|
::GetSystemMessageA(GetLastError(), szErrorMsg, sizeof(szErrorMsg));
|
||
|
strcpy(outputbuffer, szErrorMsg);
|
||
|
return strlen(outputbuffer);
|
||
|
}
|
||
|
// Set process' stdout to our pipe
|
||
|
StartupInfo.hStdOutput = hWriteHandle;
|
||
|
|
||
|
// We are going to duplicate our pipe's write handle
|
||
|
// and pass it as stderr to create process. The idea
|
||
|
// is that some processes have been known to close
|
||
|
// stderr which would also close stdout if we passed
|
||
|
// the same handle. Therefore we make a copy of stdout's
|
||
|
// pipe handle.
|
||
|
if (!DuplicateHandle(GetCurrentProcess(),
|
||
|
hWriteHandle,
|
||
|
GetCurrentProcess(),
|
||
|
&hErrorHandle,
|
||
|
0,
|
||
|
TRUE,
|
||
|
DUPLICATE_SAME_ACCESS))
|
||
|
{
|
||
|
::GetSystemMessageA(GetLastError(), szErrorMsg, sizeof(szErrorMsg));
|
||
|
strcpy(outputbuffer, szErrorMsg);
|
||
|
return strlen(outputbuffer);
|
||
|
}
|
||
|
StartupInfo.hStdError = hErrorHandle;
|
||
|
|
||
|
// Initialize our OVERLAPPED structure for our I/O pipe reads
|
||
|
PipeOverlapInfo.hEvent = CreateEvent(NULL,
|
||
|
TRUE,
|
||
|
FALSE,
|
||
|
NULL);
|
||
|
if (PipeOverlapInfo.hEvent == NULL)
|
||
|
{
|
||
|
::GetSystemMessageA(GetLastError(), szErrorMsg, sizeof(szErrorMsg));
|
||
|
strcpy(outputbuffer, szErrorMsg);
|
||
|
return strlen(outputbuffer);
|
||
|
}
|
||
|
|
||
|
// Create the Process!
|
||
|
if (!CreateProcess(NULL, // name included in command line
|
||
|
(LPTSTR) input, // Command Line
|
||
|
NULL, // Default Process Sec. Attribs
|
||
|
NULL, // Default Thread Sec. Attribs
|
||
|
TRUE, // Inherit stdio handles
|
||
|
NORMAL_PRIORITY_CLASS, // Creation Flags
|
||
|
NULL, // Use this process' environment
|
||
|
startingDirectory, // Use the current directory
|
||
|
&StartupInfo,
|
||
|
&ProcessInfo))
|
||
|
{
|
||
|
::GetSystemMessageA(GetLastError(), szErrorMsg, sizeof(szErrorMsg));
|
||
|
strcpy(outputbuffer, szErrorMsg);
|
||
|
return strlen(outputbuffer);
|
||
|
}
|
||
|
|
||
|
// lpOutput is moving output pointer
|
||
|
lpOutput = outputbuffer;
|
||
|
AvailableOutput = HeapSize(m_hHeapHandle,
|
||
|
0,
|
||
|
outputbuffer);
|
||
|
// Close the write end of our pipe (both copies)
|
||
|
// so it will die when the child process terminates
|
||
|
CloseHandle(hWriteHandle);
|
||
|
CloseHandle(hErrorHandle);
|
||
|
|
||
|
while (TimeoutNotReached)
|
||
|
{
|
||
|
// Keep a read posted on the output pipe
|
||
|
if (ReadFile(hReadHandle,
|
||
|
lpOutput,
|
||
|
(DWORD) AvailableOutput,
|
||
|
&BytesRead,
|
||
|
&PipeOverlapInfo) == TRUE)
|
||
|
{
|
||
|
// Already received data...adjust buffer pointers
|
||
|
AvailableOutput-=BytesRead;
|
||
|
lpOutput += BytesRead;
|
||
|
|
||
|
if (AvailableOutput == 0)
|
||
|
{
|
||
|
// We used all our buffer, allocate more
|
||
|
LPSTR TempBufPtr = (LPSTR) HeapReAlloc(m_hHeapHandle,
|
||
|
HEAP_ZERO_MEMORY,
|
||
|
outputbuffer,
|
||
|
HeapSize(m_hHeapHandle,
|
||
|
0,
|
||
|
outputbuffer) + 4096);
|
||
|
|
||
|
if (TempBufPtr == NULL)
|
||
|
{
|
||
|
// Copy error message to end of buffer
|
||
|
::GetSystemMessageA(GetLastError(), szErrorMsg, sizeof(szErrorMsg));
|
||
|
strcpy(outputbuffer
|
||
|
+ HeapSize(m_hHeapHandle,0, outputbuffer)
|
||
|
- strlen(szErrorMsg) - 1,
|
||
|
szErrorMsg);
|
||
|
return strlen(outputbuffer);
|
||
|
}
|
||
|
|
||
|
// Fix pointers in case ouir buffer moved
|
||
|
outputbuffer = TempBufPtr;
|
||
|
lpOutput = outputbuffer + BytesRead;
|
||
|
AvailableOutput = HeapSize(m_hHeapHandle, 0, outputbuffer) - BytesRead;
|
||
|
*output = outputbuffer;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Switch on ReadFile result
|
||
|
switch (GetLastError())
|
||
|
{
|
||
|
case ERROR_IO_PENDING:
|
||
|
// No data yet, set event so we will be triggered
|
||
|
// when there is data
|
||
|
ResetEvent(PipeOverlapInfo.hEvent);
|
||
|
break;
|
||
|
|
||
|
case ERROR_MORE_DATA:
|
||
|
{
|
||
|
// Our buffer is too small...grow it
|
||
|
DWORD_PTR CurrentBufferOffset = lpOutput
|
||
|
- outputbuffer
|
||
|
+ BytesRead;
|
||
|
|
||
|
LPTSTR TempBufPtr = (LPTSTR) HeapReAlloc(m_hHeapHandle,
|
||
|
HEAP_ZERO_MEMORY,
|
||
|
outputbuffer,
|
||
|
4096);
|
||
|
|
||
|
if (TempBufPtr == NULL)
|
||
|
{
|
||
|
// Copy error message to end of buffer
|
||
|
::GetSystemMessageA(GetLastError(), szErrorMsg, sizeof(szErrorMsg));
|
||
|
strcpy(outputbuffer + HeapSize
|
||
|
(m_hHeapHandle,0, outputbuffer) -
|
||
|
strlen(szErrorMsg) - 1, szErrorMsg);
|
||
|
return strlen(outputbuffer);
|
||
|
}
|
||
|
|
||
|
// Set parameters to post a new ReadFile
|
||
|
lpOutput = outputbuffer + CurrentBufferOffset;
|
||
|
AvailableOutput = HeapSize(m_hHeapHandle, 0, outputbuffer)
|
||
|
- CurrentBufferOffset;
|
||
|
*output = outputbuffer;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case ERROR_BROKEN_PIPE:
|
||
|
// We are done..
|
||
|
|
||
|
//Make sure we are null terminated
|
||
|
*lpOutput = 0;
|
||
|
return (lpOutput - outputbuffer);
|
||
|
break;
|
||
|
|
||
|
case ERROR_INVALID_USER_BUFFER:
|
||
|
case ERROR_NOT_ENOUGH_MEMORY:
|
||
|
// Too many I/O requests pending...wait a little while
|
||
|
Sleep(2000);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
// Wierd error...return
|
||
|
::GetSystemMessageA(GetLastError(), szErrorMsg, sizeof(szErrorMsg));
|
||
|
strcpy(outputbuffer, szErrorMsg);
|
||
|
return strlen(outputbuffer);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Wait for data to read
|
||
|
if (WaitForSingleObject(PipeOverlapInfo.hEvent,
|
||
|
300000) == WAIT_TIMEOUT)
|
||
|
TimeoutNotReached = FALSE;
|
||
|
}
|
||
|
|
||
|
return strlen(outputbuffer);
|
||
|
}
|