Leaked source code of windows server 2003
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.

1582 lines
42 KiB

  1. /**********************************************************************/
  2. /** Microsoft Windows/NT **/
  3. /** Copyright(c) Microsoft Corporation, 1997 - 1999 -99 **/
  4. /**********************************************************************/
  5. /*
  6. cprogdlg.cpp
  7. The busy/progress dialog
  8. FILE HISTORY:
  9. */
  10. #include "stdafx.h"
  11. #include "winssnap.h"
  12. #include "CProgdlg.h"
  13. #ifdef _DEBUG
  14. #define new DEBUG_NEW
  15. #undef THIS_FILE
  16. static char THIS_FILE[] = __FILE__;
  17. #endif
  18. TCHAR * gsz_EOL = _T("\r\n");
  19. /////////////////////////////////////////////////////////////////////////////
  20. // CProgress dialog
  21. CProgress::CProgress(CWnd* pParent /*=NULL*/)
  22. : CBaseDialog(CProgress::IDD, pParent)
  23. {
  24. //{{AFX_DATA_INIT(CProgress)
  25. //}}AFX_DATA_INIT
  26. }
  27. void CProgress::DoDataExchange(CDataExchange* pDX)
  28. {
  29. CBaseDialog::DoDataExchange(pDX);
  30. //{{AFX_DATA_MAP(CProgress)
  31. DDX_Control(pDX, IDCANCEL, m_buttonCancel);
  32. DDX_Control(pDX, IDC_EDIT_MESSAGE, m_editMessage);
  33. //}}AFX_DATA_MAP
  34. }
  35. BEGIN_MESSAGE_MAP(CProgress, CBaseDialog)
  36. //{{AFX_MSG_MAP(CProgress)
  37. //}}AFX_MSG_MAP
  38. END_MESSAGE_MAP()
  39. /////////////////////////////////////////////////////////////////////////////
  40. // CProgress message handlers
  41. void CProgress::OnCancel()
  42. {
  43. // TODO: Add extra cleanup here
  44. CBaseDialog::OnCancel();
  45. }
  46. BOOL CProgress::OnInitDialog()
  47. {
  48. CBaseDialog::OnInitDialog();
  49. m_editMessage.SetLimitText(0xFFFFFFFF);
  50. return TRUE; // return TRUE unless you set the focus to a control
  51. // EXCEPTION: OCX Property Pages should return FALSE
  52. }
  53. /////////////////////////////////////////////////////////////////////////////
  54. // CCheckNamesProgress dialog
  55. BOOL CCheckNamesProgress::OnInitDialog()
  56. {
  57. CProgress::OnInitDialog();
  58. m_Thread.m_pDlg = this;
  59. CWaitCursor wc;
  60. m_Thread.Start();
  61. CString strText;
  62. strText.LoadString(IDS_CANCEL);
  63. m_buttonCancel.SetWindowText(strText);
  64. strText.LoadString(IDS_CHECK_REG_TITLE);
  65. SetWindowText(strText);
  66. return TRUE; // return TRUE unless you set the focus to a control
  67. // EXCEPTION: OCX Property Pages should return FALSE
  68. }
  69. void CCheckNamesProgress::BuildServerList()
  70. {
  71. CString strMessage;
  72. strMessage.LoadString(IDS_BUILDING_SERVER_LIST);
  73. strMessage += gsz_EOL;
  74. AddStatusMessage(strMessage);
  75. for (int i = 0; i < m_strServerArray.GetSize(); i++)
  76. {
  77. char szIP[MAX_PATH];
  78. // NOTE: this should be ACP because it's winsock related
  79. WideToMBCS(m_strServerArray[i], szIP);
  80. // add this machine to the list
  81. AddServerToList(inet_addr(szIP));
  82. // check to see if we should add known partners
  83. if (m_fVerifyWithPartners)
  84. {
  85. CWinsResults winsResults;
  86. handle_t hBind;
  87. WINSINTF_BIND_DATA_T BindData;
  88. BindData.fTcpIp = TRUE;
  89. BindData.pServerAdd = (LPSTR) (LPCTSTR) m_strServerArray[i];
  90. hBind = ::WinsBind(&BindData);
  91. if (!hBind)
  92. {
  93. // unable to bind to this server
  94. AfxFormatString1(strMessage, IDS_UNABLE_TO_CONNECT, m_strServerArray[i]);
  95. strMessage += gsz_EOL;
  96. AddStatusMessage(strMessage);
  97. continue;
  98. }
  99. DWORD err = winsResults.Update(hBind);
  100. if (err)
  101. {
  102. strMessage.LoadString(IDS_GET_STATUS_FAILED);
  103. strMessage += gsz_EOL;
  104. AddStatusMessage(strMessage);
  105. }
  106. else
  107. {
  108. for (UINT j = 0; j < winsResults.NoOfOwners; j++)
  109. {
  110. // check to see if:
  111. // 1. the address is not 0
  112. // 2. the owner is not marked as deleted
  113. // 3. the highest record count is not 0
  114. if ( (winsResults.AddVersMaps[j].Add.IPAdd != 0) &&
  115. (winsResults.AddVersMaps[j].VersNo.QuadPart != OWNER_DELETED) &&
  116. (winsResults.AddVersMaps[j].VersNo.QuadPart != 0) )
  117. {
  118. AddServerToList(htonl(winsResults.AddVersMaps[j].Add.IPAdd));
  119. }
  120. }
  121. }
  122. ::WinsUnbind(&BindData, hBind);
  123. }
  124. }
  125. // now display the list
  126. strMessage.LoadString(IDS_SERVERS_TO_BE_QUERRIED);
  127. strMessage += gsz_EOL;
  128. AddStatusMessage(strMessage);
  129. for (i = 0; i < m_winsServersArray.GetSize(); i++)
  130. {
  131. MakeIPAddress(ntohl(m_winsServersArray[i].Server.s_addr), strMessage);
  132. strMessage += gsz_EOL;
  133. AddStatusMessage(strMessage);
  134. }
  135. AddStatusMessage(gsz_EOL);
  136. m_Thread.m_strNameArray.Copy(m_strNameArray);
  137. m_Thread.m_winsServersArray.Copy(m_winsServersArray);
  138. }
  139. void CCheckNamesProgress::AddServerToList(u_long ip)
  140. {
  141. BOOL fFound = FALSE;
  142. if (ip == 0)
  143. return;
  144. //
  145. // Look to see if it is already in the list
  146. //
  147. for (int k = 0; k < m_winsServersArray.GetSize(); k++)
  148. {
  149. if (m_winsServersArray[k].Server.s_addr == ip)
  150. {
  151. fFound = TRUE;
  152. break;
  153. }
  154. }
  155. // if we didn't find it, add it.
  156. if (!fFound)
  157. {
  158. WINSERVERS server = {0};
  159. server.Server.s_addr = ip;
  160. m_winsServersArray.Add(server);
  161. }
  162. }
  163. void CCheckNamesProgress::OnCancel()
  164. {
  165. if (m_Thread.IsRunning())
  166. {
  167. CWaitCursor wc;
  168. CString strText;
  169. strText.LoadString(IDS_CLEANING_UP);
  170. strText += gsz_EOL;
  171. AddStatusMessage(strText);
  172. m_buttonCancel.EnableWindow(FALSE);
  173. m_Thread.Abort(FALSE);
  174. MSG msg;
  175. while (PeekMessage(&msg,NULL,NULL,NULL,PM_REMOVE))
  176. {
  177. TranslateMessage(&msg);
  178. DispatchMessage(&msg);
  179. }
  180. return;
  181. }
  182. CProgress::OnCancel();
  183. }
  184. void CCheckNamesProgress::NotifyCompleted()
  185. {
  186. CString strText;
  187. strText.LoadString(IDS_FINISHED);
  188. strText += gsz_EOL;
  189. AddStatusMessage(strText);
  190. strText.LoadString(IDS_CLOSE);
  191. m_buttonCancel.SetWindowText(strText);
  192. m_buttonCancel.EnableWindow(TRUE);
  193. }
  194. /*---------------------------------------------------------------------------
  195. CWinsThread
  196. Background thread base class
  197. Author: EricDav
  198. ---------------------------------------------------------------------------*/
  199. CWinsThread::CWinsThread()
  200. {
  201. m_bAutoDelete = TRUE;
  202. m_hEventHandle = NULL;
  203. }
  204. CWinsThread::~CWinsThread()
  205. {
  206. if (m_hEventHandle != NULL)
  207. {
  208. VERIFY(::CloseHandle(m_hEventHandle));
  209. m_hEventHandle = NULL;
  210. }
  211. }
  212. BOOL CWinsThread::Start()
  213. {
  214. ASSERT(m_hEventHandle == NULL); // cannot call start twice or reuse the same C++ object
  215. m_hEventHandle = ::CreateEvent(NULL,TRUE /*bManualReset*/,FALSE /*signalled*/, NULL);
  216. if (m_hEventHandle == NULL)
  217. return FALSE;
  218. return CreateThread();
  219. }
  220. void CWinsThread::Abort(BOOL fAutoDelete)
  221. {
  222. m_bAutoDelete = fAutoDelete;
  223. SetEvent(m_hEventHandle);
  224. }
  225. void CWinsThread::AbortAndWait()
  226. {
  227. Abort(FALSE);
  228. WaitForSingleObject(m_hThread, INFINITE);
  229. }
  230. BOOL CWinsThread::IsRunning()
  231. {
  232. if (WaitForSingleObject(m_hThread, 0) == WAIT_OBJECT_0)
  233. {
  234. return FALSE;
  235. }
  236. else
  237. {
  238. return TRUE;
  239. }
  240. }
  241. BOOL CWinsThread::FCheckForAbort()
  242. {
  243. if (WaitForSingleObject(m_hEventHandle, 0) == WAIT_OBJECT_0)
  244. {
  245. Trace0("CWinsThread::FCheckForAbort - abort detected, exiting...\n");
  246. return TRUE;
  247. }
  248. else
  249. {
  250. return FALSE;
  251. }
  252. }
  253. /*---------------------------------------------------------------------------
  254. CCheckNamesThread
  255. Background thread for check registered names
  256. Author: EricDav
  257. ---------------------------------------------------------------------------*/
  258. int CCheckNamesThread::Run()
  259. {
  260. int i, nRetryCount, status;
  261. BOOL fDone = FALSE;
  262. int uNames, uServers;
  263. u_short TransID = 0;
  264. char szName[MAX_PATH];
  265. WINSERVERS * pCurrentServer;
  266. CString strStatus;
  267. CString strTemp;
  268. CString strTempName;
  269. struct in_addr retaddr;
  270. // build up the list of servers
  271. m_pDlg->BuildServerList();
  272. // initialize some comm stuff
  273. InitNameCheckSocket();
  274. // if the query is sent to the local server, TranIDs less than 0x7fff are dropped by NetBT
  275. TransID = 0x8000;
  276. // initialize all of the servers
  277. for (i = 0; i < m_winsServersArray.GetSize(); i++)
  278. {
  279. m_winsServersArray[i].LastResponse = -1;
  280. m_winsServersArray[i].fQueried = FALSE;
  281. m_winsServersArray[i].Valid = 0;
  282. m_winsServersArray[i].Failed = 0;
  283. m_winsServersArray[i].Retries = 0;
  284. m_winsServersArray[i].Completed = 0;
  285. }
  286. // initialize the verified address stuff
  287. m_verifiedAddressArray.SetSize(m_strNameArray.GetSize());
  288. for (i = 0; i < m_verifiedAddressArray.GetSize(); i++)
  289. m_verifiedAddressArray[i] = 0;
  290. for (uNames = 0; uNames < m_strNameArray.GetSize(); uNames++)
  291. {
  292. // convert unicode string to MBCS
  293. memset(szName, 0, sizeof(szName));
  294. CWinsName winsName = m_strNameArray[uNames];
  295. // This should be OEM
  296. WideToMBCS(winsName.strName, szName, WINS_NAME_CODE_PAGE);
  297. // fill in the type (16th byte) and null terminate
  298. szName[15] = (BYTE) winsName.dwType & 0x000000FF;
  299. szName[16] = 0;
  300. // pad the name with spaces to the 16th character
  301. for (int nChar = 0; nChar < 16; nChar++)
  302. {
  303. if (szName[nChar] == 0)
  304. szName[nChar] = ' ';
  305. }
  306. for (uServers = 0; uServers < m_winsServersArray.GetSize(); uServers++)
  307. {
  308. fDone = FALSE;
  309. nRetryCount = 0;
  310. TransID++;
  311. pCurrentServer = &m_winsServersArray[uServers];
  312. while (!fDone)
  313. {
  314. // build a status string
  315. MakeIPAddress(ntohl(pCurrentServer->Server.S_un.S_addr), strTemp);
  316. strTempName.Format(_T("%s[%02Xh]"), m_strNameArray[uNames].strName, m_strNameArray[uNames].dwType);
  317. AfxFormatString2(strStatus,
  318. IDS_SEND_NAME_QUERY,
  319. strTemp,
  320. strTempName);
  321. // send the name query out on the wire
  322. ::SendNameQuery((unsigned char *)szName, pCurrentServer->Server.S_un.S_addr, TransID);
  323. if (FCheckForAbort())
  324. goto cleanup;
  325. // check for a response
  326. i = ::GetNameResponse(&retaddr.s_addr, TransID);
  327. if (FCheckForAbort())
  328. goto cleanup;
  329. switch (i)
  330. {
  331. case WINSTEST_FOUND: // found
  332. pCurrentServer->RetAddr.s_addr = retaddr.s_addr;
  333. pCurrentServer->Valid = 1;
  334. pCurrentServer->LastResponse = uNames;
  335. if (retaddr.s_addr == m_verifiedAddressArray[uNames])
  336. {
  337. // this address has already been verified... don't
  338. // do the checking again
  339. strTemp.LoadString(IDS_OK);
  340. strStatus += strTemp;
  341. strStatus += gsz_EOL;
  342. AddStatusMessage(strStatus);
  343. fDone = TRUE;
  344. break;
  345. }
  346. status = VerifyRemote(inet_ntoa(pCurrentServer->RetAddr),
  347. szName);
  348. if (WINSTEST_VERIFIED == status)
  349. {
  350. strTemp.LoadString(IDS_OK);
  351. strStatus += strTemp;
  352. strStatus += gsz_EOL;
  353. AddStatusMessage(strStatus);
  354. m_verifiedAddressArray[uNames] = retaddr.s_addr;
  355. }
  356. else
  357. {
  358. strTemp.LoadString(IDS_NOT_VERIFIED);
  359. strStatus += strTemp;
  360. strStatus += gsz_EOL;
  361. AddStatusMessage(strStatus);
  362. }
  363. fDone = TRUE;
  364. break;
  365. case WINSTEST_NOT_FOUND: // responded -- name not found
  366. pCurrentServer->RetAddr.s_addr = retaddr.s_addr;
  367. pCurrentServer->Valid = 0;
  368. pCurrentServer->LastResponse = uNames;
  369. strTemp.LoadString(IDS_NAME_NOT_FOUND);
  370. strStatus += strTemp;
  371. strStatus += gsz_EOL;
  372. AddStatusMessage(strStatus);
  373. nRetryCount++;
  374. if (nRetryCount > 2)
  375. {
  376. pCurrentServer->Failed = 1;
  377. fDone = TRUE;
  378. }
  379. break;
  380. case WINSTEST_NO_RESPONSE: // no response
  381. pCurrentServer->RetAddr.s_addr = retaddr.s_addr;
  382. pCurrentServer->Valid = 0;
  383. pCurrentServer->Retries++;
  384. strTemp.LoadString(IDS_NO_RESPONSE);
  385. strStatus += strTemp;
  386. strStatus += gsz_EOL;
  387. //strcat(lpResults, "; No response.\r\n");
  388. AddStatusMessage(strStatus);
  389. nRetryCount++;
  390. if (nRetryCount > 2)
  391. {
  392. pCurrentServer->Failed = 1;
  393. fDone = TRUE;
  394. }
  395. break;
  396. default:
  397. //unknown return
  398. break;
  399. } // switch GetNameResponse
  400. } // while
  401. } // for ServerInx
  402. // Find a valid address for this name
  403. for (uServers = 0; uServers < m_winsServersArray.GetSize(); uServers++)
  404. {
  405. pCurrentServer = &m_winsServersArray[uServers];
  406. if (pCurrentServer->Valid)
  407. {
  408. DisplayInfo(uNames, pCurrentServer->RetAddr.s_addr);
  409. break;
  410. }
  411. }
  412. } // name for loop
  413. // mark all successful servers as completed
  414. for (uServers = 0; uServers < m_winsServersArray.GetSize(); uServers++)
  415. {
  416. pCurrentServer = &m_winsServersArray[uServers];
  417. if (!pCurrentServer->Failed)
  418. {
  419. pCurrentServer->Completed = 1;
  420. }
  421. } // for uServers
  422. // dump the summary info
  423. strStatus.LoadString(IDS_RESULTS);
  424. strStatus = gsz_EOL + strStatus + gsz_EOL + gsz_EOL;
  425. AddStatusMessage(strStatus);
  426. for (i = 0; i < m_strSummaryArray.GetSize(); i++)
  427. {
  428. AddStatusMessage(m_strSummaryArray[i]);
  429. }
  430. // generate some end of run summary status
  431. for (uServers = 0; uServers < m_winsServersArray.GetSize(); uServers++)
  432. {
  433. pCurrentServer = &m_winsServersArray[uServers];
  434. if ((-1) == pCurrentServer->LastResponse)
  435. {
  436. MakeIPAddress(ntohl(pCurrentServer->Server.S_un.S_addr), strTemp);
  437. AfxFormatString1(strStatus, IDS_SERVER_NEVER_RESPONDED, strTemp);
  438. strStatus += gsz_EOL;
  439. AddStatusMessage(strStatus);
  440. }
  441. else if (0 == pCurrentServer->Completed)
  442. {
  443. MakeIPAddress(ntohl(pCurrentServer->Server.S_un.S_addr), strTemp);
  444. AfxFormatString1(strStatus, IDS_SERVER_NOT_COMPLETE, strTemp);
  445. strStatus += gsz_EOL;
  446. AddStatusMessage(strStatus);
  447. }
  448. } // for ServerInx
  449. for (uNames = 0; uNames < m_strNameArray.GetSize(); uNames++)
  450. {
  451. if (0 == m_verifiedAddressArray[uNames])
  452. {
  453. strTempName.Format(_T("%s[%02Xh]"), m_strNameArray[uNames].strName, m_strNameArray[uNames].dwType);
  454. AfxFormatString1(strStatus, IDS_NAME_NOT_VERIFIED, strTempName);
  455. strStatus += gsz_EOL;
  456. AddStatusMessage(strStatus);
  457. }
  458. } // for uNames
  459. cleanup:
  460. CloseNameCheckSocket();
  461. m_pDlg->NotifyCompleted();
  462. return 9;
  463. }
  464. void CCheckNamesThread::AddStatusMessage(LPCTSTR pszMessage)
  465. {
  466. m_pDlg->AddStatusMessage(pszMessage);
  467. }
  468. void CCheckNamesThread::DisplayInfo(int uNames, u_long ulValidAddr)
  469. {
  470. CString strTemp, strTempName, strStatus;
  471. int uServers;
  472. WINSERVERS * pCurrentServer;
  473. struct in_addr tempaddr;
  474. int i;
  475. BOOL fMismatchFound = FALSE;
  476. // now check and see which WINS servers didn't match
  477. for (uServers = 0; uServers < m_winsServersArray.GetSize(); uServers++)
  478. {
  479. pCurrentServer = &m_winsServersArray[uServers];
  480. if (pCurrentServer->Completed)
  481. {
  482. continue;
  483. }
  484. if ( (pCurrentServer->Valid) )
  485. {
  486. if ( (pCurrentServer->RetAddr.s_addr != ulValidAddr) ||
  487. (m_verifiedAddressArray[uNames] != 0 &&
  488. m_verifiedAddressArray[uNames] != ulValidAddr) )
  489. {
  490. // mismatch
  491. strTempName.Format(_T("%s[%02Xh]"), m_strNameArray[uNames].strName, m_strNameArray[uNames].dwType);
  492. AfxFormatString1(strStatus, IDS_INCONSISTENCY_FOUND, strTempName);
  493. strStatus += gsz_EOL;
  494. m_strSummaryArray.Add(strStatus);
  495. if (m_verifiedAddressArray[uNames] != 0)
  496. {
  497. tempaddr.s_addr = m_verifiedAddressArray[uNames];
  498. MakeIPAddress(ntohl(tempaddr.S_un.S_addr), strTemp);
  499. AfxFormatString1(strStatus, IDS_VERIFIED_ADDRESS, strTemp);
  500. strStatus += gsz_EOL;
  501. m_strSummaryArray.Add(strStatus);
  502. }
  503. // display the inconsistent name resolutions
  504. for (i = 0; i < m_winsServersArray.GetSize(); i++)
  505. {
  506. if (m_winsServersArray[i].Valid &&
  507. m_verifiedAddressArray[uNames] != m_winsServersArray[i].RetAddr.S_un.S_addr)
  508. {
  509. MakeIPAddress(ntohl(m_winsServersArray[i].Server.S_un.S_addr), strTemp);
  510. strTempName.Format(_T("%s[%02Xh]"), m_strNameArray[uNames].strName, m_strNameArray[uNames].dwType);
  511. AfxFormatString2(strStatus,
  512. IDS_NAME_QUERY_RESULT,
  513. strTemp,
  514. strTempName);
  515. CString strTemp2;
  516. MakeIPAddress(ntohl(m_winsServersArray[i].RetAddr.S_un.S_addr), strTemp2);
  517. AfxFormatString1(strTemp, IDS_NAME_QUERY_RETURNED, strTemp2);
  518. strStatus += strTemp;
  519. strStatus += gsz_EOL;
  520. m_strSummaryArray.Add(strStatus);
  521. }
  522. }
  523. m_strSummaryArray.Add(gsz_EOL);
  524. fMismatchFound = TRUE;
  525. break;
  526. }
  527. }
  528. } // end check for invalid addresses
  529. if (!fMismatchFound)
  530. {
  531. // display the correct info
  532. strTempName.Format(_T("%s[%02Xh]"), m_strNameArray[uNames].strName, m_strNameArray[uNames].dwType);
  533. MakeIPAddress(ntohl(ulValidAddr), strTemp);
  534. AfxFormatString2(strStatus, IDS_NAME_VERIFIED, strTempName, strTemp);
  535. strStatus += gsz_EOL;
  536. m_strSummaryArray.Add(strStatus);
  537. }
  538. }
  539. /*---------------------------------------------------------------------------
  540. CCheckVersionProgress
  541. Status dialog for check version consistency
  542. Author: EricDav
  543. ---------------------------------------------------------------------------*/
  544. BOOL CCheckVersionProgress::OnInitDialog()
  545. {
  546. CProgress::OnInitDialog();
  547. CWaitCursor wc;
  548. m_Thread.m_dwIpAddress = m_dwIpAddress;
  549. m_Thread.m_pDlg = this;
  550. m_Thread.m_hBinding = m_hBinding;
  551. m_Thread.Start();
  552. CString strText;
  553. strText.LoadString(IDS_CANCEL);
  554. m_buttonCancel.SetWindowText(strText);
  555. strText.LoadString(IDS_CHECK_VERSION_TITLE);
  556. SetWindowText(strText);
  557. return TRUE; // return TRUE unless you set the focus to a control
  558. // EXCEPTION: OCX Property Pages should return FALSE
  559. }
  560. void CCheckVersionProgress::OnCancel()
  561. {
  562. if (m_Thread.IsRunning())
  563. {
  564. CWaitCursor wc;
  565. CString strText;
  566. strText.LoadString(IDS_CLEANING_UP);
  567. strText += gsz_EOL;
  568. AddStatusMessage(strText);
  569. m_buttonCancel.EnableWindow(FALSE);
  570. m_Thread.Abort(FALSE);
  571. MSG msg;
  572. while (PeekMessage(&msg,NULL,NULL,NULL,PM_REMOVE))
  573. {
  574. TranslateMessage(&msg);
  575. DispatchMessage(&msg);
  576. }
  577. return;
  578. }
  579. CProgress::OnCancel();
  580. }
  581. void CCheckVersionProgress::NotifyCompleted()
  582. {
  583. CString strText;
  584. strText.LoadString(IDS_FINISHED);
  585. strText += gsz_EOL;
  586. AddStatusMessage(strText);
  587. strText.LoadString(IDS_CLOSE);
  588. m_buttonCancel.SetWindowText(strText);
  589. m_buttonCancel.EnableWindow(TRUE);
  590. }
  591. /*---------------------------------------------------------------------------
  592. CCheckVersionThread
  593. Background thread for check version consistency
  594. Author: EricDav
  595. ---------------------------------------------------------------------------*/
  596. void CCheckVersionThread::AddStatusMessage(LPCTSTR pszMessage)
  597. {
  598. m_pDlg->AddStatusMessage(pszMessage);
  599. }
  600. // this is where the work gets done
  601. int CCheckVersionThread::Run()
  602. {
  603. CWinsResults winsResults;
  604. CString strMessage;
  605. CString strIP;
  606. BOOL bProblem;
  607. m_strLATable.RemoveAll();
  608. m_strLATable.SetSize(MAX_WINS); // table grows dynamically nevertheless
  609. m_uLATableDim = 0;
  610. DWORD status = winsResults.Update(m_hBinding);
  611. if (status != ERROR_SUCCESS)
  612. {
  613. strMessage.LoadString(IDS_ERROR_OCCURRED);
  614. strMessage += gsz_EOL;
  615. AddStatusMessage(strMessage);
  616. LPTSTR pBuf = strMessage.GetBuffer(1024);
  617. GetSystemMessage(status, pBuf, 1024);
  618. strMessage.ReleaseBuffer();
  619. strMessage += gsz_EOL;
  620. AddStatusMessage(strMessage);
  621. goto cleanup;
  622. }
  623. // add all the mappings for the target WINS to the Look Ahead table
  624. InitLATable(
  625. winsResults.AddVersMaps.GetData(),
  626. winsResults.NoOfOwners);
  627. // Place entry in the SO Table in proper order
  628. MakeIPAddress(m_dwIpAddress, strIP);
  629. AddSOTableEntry(
  630. strIP,
  631. winsResults.AddVersMaps.GetData(),
  632. winsResults.NoOfOwners);
  633. // For each of the owners, get the owner-version map
  634. for (UINT i = 0; i < m_uLATableDim; i++)
  635. {
  636. WINSINTF_BIND_DATA_T wbdBindData;
  637. handle_t hBinding = NULL;
  638. CWinsResults winsResultsCurrent;
  639. // skip this one since we already did it!
  640. if (m_strLATable[i] == strIP)
  641. continue;
  642. wbdBindData.fTcpIp = 1;
  643. wbdBindData.pPipeName = NULL;
  644. wbdBindData.pServerAdd = (LPSTR) (LPCTSTR) m_strLATable[i];
  645. // first bind to the machine
  646. if ((hBinding = ::WinsBind(&wbdBindData)) == NULL)
  647. {
  648. CString strBuf;
  649. LPTSTR pBuf = strBuf.GetBuffer(4096);
  650. ::GetSystemMessage(GetLastError(), pBuf, 4096);
  651. strBuf.ReleaseBuffer();
  652. Trace1("\n==> Machine %s is probably down\n\n", m_strLATable[i]);
  653. AfxFormatString2(strMessage, IDS_MSG_STATUS_DOWN, m_strLATable[i], strBuf);
  654. strMessage += gsz_EOL;
  655. AddStatusMessage(strMessage);
  656. RemoveFromSOTable(m_strLATable[i]);
  657. continue;
  658. }
  659. // now get the info
  660. status = winsResultsCurrent.Update(hBinding);
  661. if (status != ERROR_SUCCESS)
  662. {
  663. CString strBuf;
  664. LPTSTR pBuf = strBuf.GetBuffer(4096);
  665. ::GetSystemMessage(status, pBuf, 4096);
  666. strBuf.ReleaseBuffer();
  667. Trace1("\n==> Machine %s is probably down\n\n", m_strLATable[i]);
  668. AfxFormatString2(strMessage, IDS_MSG_STATUS_DOWN, m_strLATable[i], strBuf);
  669. strMessage += gsz_EOL;
  670. AddStatusMessage(strMessage);
  671. RemoveFromSOTable(m_strLATable[i]);
  672. }
  673. else
  674. {
  675. // ok, looks good
  676. AfxFormatString1(strMessage, IDS_MSG_STATUS_UP, m_strLATable[i]);
  677. strMessage += gsz_EOL;
  678. AddStatusMessage(strMessage);
  679. // add this mappings to the Look Ahead table
  680. InitLATable(
  681. winsResultsCurrent.AddVersMaps.GetData(),
  682. winsResultsCurrent.NoOfOwners);
  683. // Update the SO Table
  684. AddSOTableEntry(
  685. m_strLATable[i],
  686. winsResultsCurrent.AddVersMaps.GetData(),
  687. winsResultsCurrent.NoOfOwners);
  688. }
  689. ::WinsUnbind(&wbdBindData, hBinding);
  690. hBinding = NULL;
  691. if (FCheckForAbort())
  692. goto cleanup;
  693. }
  694. // Check if diagonal elements in the [SO] table are the highest in their cols.
  695. bProblem = CheckSOTableConsistency();
  696. strMessage.LoadString(bProblem ? IDS_VERSION_CHECK_FAIL : IDS_VERSION_CHECK_SUCCESS);
  697. strMessage += gsz_EOL;
  698. AddStatusMessage(strMessage);
  699. cleanup:
  700. if (m_pLISOTable)
  701. {
  702. delete [] m_pLISOTable;
  703. m_pLISOTable = NULL;
  704. m_uLISOTableDim = 0;
  705. }
  706. m_pDlg->NotifyCompleted();
  707. return 10;
  708. }
  709. DWORD
  710. CCheckVersionThread::InitLATable(
  711. PWINSINTF_ADD_VERS_MAP_T pAddVersMaps,
  712. DWORD NoOfOwners)
  713. {
  714. UINT n;
  715. // it is assumed pAddVersMaps doesn't contain duplicates within itself hence
  716. // we only check for duplicates with whatever is in the array at the moment
  717. // of the call and not with whatever we're adding there
  718. n = m_uLATableDim;
  719. for (UINT i = 0; i < NoOfOwners; i++, pAddVersMaps++)
  720. {
  721. UINT j;
  722. CString strIP;
  723. MakeIPAddress(pAddVersMaps->Add.IPAdd, strIP);
  724. for (j = 0; j < n; j++)
  725. {
  726. if (m_strLATable[j] == strIP)
  727. break;
  728. }
  729. if (j == n)
  730. {
  731. m_strLATable.InsertAt(m_uLATableDim,strIP);
  732. m_uLATableDim++;
  733. }
  734. }
  735. return ERROR_SUCCESS;
  736. }
  737. DWORD
  738. CCheckVersionThread::AddSOTableEntry (
  739. CString & strIP,
  740. PWINSINTF_ADD_VERS_MAP_T pAddVersMaps,
  741. DWORD NoOfOwners)
  742. {
  743. UINT uRow = IPToIndex(strIP);
  744. // it is assumed here that m_strLATable is already updated
  745. // such that it includes already all the mappings from pAddVersMaps
  746. // and the address strIP provided as argument!
  747. // enlarge m_ppLISOTable if needed
  748. if (m_uLISOTableDim < m_uLATableDim)
  749. {
  750. ULARGE_INTEGER *pLISOTable = NULL;
  751. UINT uLISOTableDim = m_uLATableDim;
  752. pLISOTable = new ULARGE_INTEGER[uLISOTableDim * uLISOTableDim];
  753. if (pLISOTable == NULL)
  754. return ERROR_NOT_ENOUGH_MEMORY;
  755. // transfer whatever we had in the original table (if anything)
  756. // and zero out the new empty space. Transfer & Zero is done line by line!
  757. for (UINT i = 0; i < m_uLISOTableDim; i++)
  758. {
  759. memcpy(
  760. (LPBYTE)(pLISOTable + i * uLISOTableDim),
  761. (LPBYTE)(m_pLISOTable + i * m_uLISOTableDim),
  762. m_uLISOTableDim * sizeof(ULARGE_INTEGER));
  763. ZeroMemory(
  764. (LPBYTE)(pLISOTable + i * uLISOTableDim + m_uLISOTableDim),
  765. (uLISOTableDim - m_uLISOTableDim) * sizeof(ULARGE_INTEGER));
  766. }
  767. if (m_pLISOTable != NULL)
  768. delete [] m_pLISOTable;
  769. m_pLISOTable = pLISOTable;
  770. m_uLISOTableDim = uLISOTableDim;
  771. }
  772. for (UINT i=0; i < NoOfOwners; i++, pAddVersMaps++)
  773. {
  774. CString strOwnerIP;
  775. UINT uCol;
  776. MakeIPAddress(pAddVersMaps->Add.IPAdd, strOwnerIP);
  777. uCol = IPToIndex(strOwnerIP);
  778. // lCol should definitely be less than m_uLISOTableDim since
  779. // the address is assumed already in m_dwLATable and m_pLISOTable is
  780. // large enough for the dimension of that table
  781. if (pAddVersMaps->VersNo.HighPart != MAXLONG ||
  782. pAddVersMaps->VersNo.LowPart != MAXLONG)
  783. {
  784. SOCell(uRow, uCol).QuadPart = (ULONGLONG)pAddVersMaps->VersNo.QuadPart;
  785. }
  786. }
  787. return ERROR_SUCCESS;
  788. }
  789. LONG
  790. CCheckVersionThread::IPToIndex(
  791. CString & strIP)
  792. {
  793. // it is assumed the strIP does exist in the m_strLATable when
  794. // the index is looked for!
  795. for (UINT i = 0; i < m_uLATableDim; i++)
  796. {
  797. if (m_strLATable[i] == strIP)
  798. return i;
  799. }
  800. return m_uLATableDim;
  801. }
  802. BOOL
  803. CCheckVersionThread::CheckSOTableConsistency()
  804. {
  805. BOOLEAN fProblem = FALSE;
  806. for (UINT i = 0; i < m_uLISOTableDim; i++)
  807. {
  808. for (UINT j = 0; j < m_uLISOTableDim; j++)
  809. {
  810. // if the diagonal element is less than any other element on its column,
  811. // it means some other WINS pretends to have a better image about this WINS that itself!
  812. // This is an inconsistency!
  813. if (SOCell(i,i).QuadPart < SOCell(j,i).QuadPart)
  814. {
  815. CString strMessage;
  816. AfxFormatString2(strMessage, IDS_VERSION_INCONSISTENCY_FOUND, m_strLATable[j], m_strLATable[i]);
  817. strMessage += gsz_EOL;
  818. AddStatusMessage(strMessage);
  819. fProblem = TRUE;
  820. }
  821. }
  822. }
  823. return fProblem;
  824. }
  825. void
  826. CCheckVersionThread::RemoveFromSOTable(
  827. CString & strIP)
  828. {
  829. UINT uCol, uRow;
  830. // make the diagonal element corresponding to this WINS the
  831. // highest value possible (since WINS is not reachable, we'll
  832. // assume it is consistent!)
  833. uCol = uRow = IPToIndex(strIP);
  834. SOCell(uRow, uCol).HighPart = MAXLONG;
  835. SOCell(uRow, uCol).LowPart = MAXLONG;
  836. }
  837. ULARGE_INTEGER&
  838. CCheckVersionThread::SOCell(UINT i, UINT j)
  839. {
  840. return m_pLISOTable[i*m_uLISOTableDim + j];
  841. }
  842. /*---------------------------------------------------------------------------
  843. CDBCompactProgress
  844. Status dialog for DBCompact
  845. Author: EricDav
  846. ---------------------------------------------------------------------------*/
  847. BOOL CDBCompactProgress::OnInitDialog()
  848. {
  849. CProgress::OnInitDialog();
  850. CWaitCursor wc;
  851. m_Thread.m_pDlg = this;
  852. m_Thread.m_hBinding = m_hBinding;
  853. m_Thread.m_dwIpAddress = m_dwIpAddress;
  854. m_Thread.m_strServerName = m_strServerName;
  855. m_Thread.m_pConfig = m_pConfig;
  856. m_Thread.Start();
  857. CString strText;
  858. strText.LoadString(IDS_CANCEL);
  859. m_buttonCancel.SetWindowText(strText);
  860. strText.LoadString(IDS_COMPACT_DATABASE_TITLE);
  861. SetWindowText(strText);
  862. // user cannot cancel this operation as that would be really bad...
  863. m_buttonCancel.EnableWindow(FALSE);
  864. return TRUE; // return TRUE unless you set the focus to a control
  865. // EXCEPTION: OCX Property Pages should return FALSE
  866. }
  867. void CDBCompactProgress::OnCancel()
  868. {
  869. if (m_Thread.IsRunning())
  870. {
  871. CWaitCursor wc;
  872. CString strText;
  873. strText.LoadString(IDS_CLEANING_UP);
  874. strText += gsz_EOL;
  875. AddStatusMessage(strText);
  876. m_buttonCancel.EnableWindow(FALSE);
  877. m_Thread.Abort(FALSE);
  878. MSG msg;
  879. while (PeekMessage(&msg,NULL,NULL,NULL,PM_REMOVE))
  880. {
  881. TranslateMessage(&msg);
  882. DispatchMessage(&msg);
  883. }
  884. return;
  885. }
  886. CProgress::OnCancel();
  887. }
  888. void CDBCompactProgress::NotifyCompleted()
  889. {
  890. CString strText;
  891. strText.LoadString(IDS_FINISHED);
  892. strText += gsz_EOL;
  893. AddStatusMessage(strText);
  894. strText.LoadString(IDS_CLOSE);
  895. m_buttonCancel.SetWindowText(strText);
  896. m_buttonCancel.EnableWindow(TRUE);
  897. }
  898. /*---------------------------------------------------------------------------
  899. CDBCompactThread
  900. Background thread for DB Compact
  901. Author: EricDav
  902. ---------------------------------------------------------------------------*/
  903. // this is where the work gets done
  904. int CDBCompactThread::Run()
  905. {
  906. DWORD err = ERROR_SUCCESS;
  907. DWORD_PTR dwLength;
  908. CString strStartingDirectory, strWinsDb, strWinsTempDb, strCommandLine;
  909. CString strTemp, strMessage, strOutput;
  910. LPSTR pszOutput;
  911. // get the version of NT running on this machine
  912. // we can do this because this command only runs locally.
  913. OSVERSIONINFO os;
  914. ZeroMemory(&os, sizeof(OSVERSIONINFO));
  915. os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  916. BOOL bRet = GetVersionEx(&os);
  917. if (!bRet)
  918. {
  919. strMessage.LoadString(IDS_ERROR_OCCURRED);
  920. strMessage += gsz_EOL;
  921. AddStatusMessage(strMessage);
  922. LPTSTR pBuf = strMessage.GetBuffer(1024);
  923. GetSystemMessage(GetLastError(), pBuf, 1024);
  924. strMessage.ReleaseBuffer();
  925. strMessage += gsz_EOL;
  926. AddStatusMessage(strMessage);
  927. goto cleanup;
  928. }
  929. // all of the log files go into system32\wins so that's our starting dir
  930. if (!GetSystemDirectory(strStartingDirectory.GetBuffer(MAX_PATH), MAX_PATH))
  931. {
  932. strMessage.LoadString(IDS_ERROR_OCCURRED);
  933. strMessage += gsz_EOL;
  934. AddStatusMessage(strMessage);
  935. LPTSTR pBuf = strMessage.GetBuffer(1024);
  936. GetSystemMessage(GetLastError(), pBuf, 1024);
  937. strMessage.ReleaseBuffer();
  938. strMessage += gsz_EOL;
  939. AddStatusMessage(strMessage);
  940. goto cleanup;
  941. }
  942. strStartingDirectory.ReleaseBuffer();
  943. strStartingDirectory += _T("\\wins");
  944. // check to see if the database is in the correct location
  945. if (m_pConfig->m_strDbName.IsEmpty())
  946. {
  947. strWinsDb = _T("wins.mdb");
  948. }
  949. else
  950. {
  951. // the user has changed it...
  952. strWinsDb = m_pConfig->m_strDbName;
  953. }
  954. strWinsTempDb = _T("winstemp.mdb");
  955. strCommandLine = _T("jetpack.exe ");
  956. switch (os.dwMajorVersion)
  957. {
  958. case VERSION_NT_50:
  959. strCommandLine += strWinsDb + _T(" ") + strWinsTempDb;
  960. break;
  961. case VERSION_NT_40:
  962. strCommandLine += _T("-40db" ) + strWinsDb + _T(" ") + strWinsTempDb;
  963. break;
  964. case VERSION_NT_351:
  965. strCommandLine += _T("-351db ") + strWinsDb + _T(" ") + strWinsTempDb;
  966. default:
  967. break;
  968. }
  969. // disconnect from the server and stop the service
  970. DisConnectFromWinsServer();
  971. strTemp.LoadString(IDS_COMPACT_STATUS_STOPPING_WINS);
  972. AddStatusMessage(strTemp);
  973. ControlWINSService(m_strServerName, TRUE);
  974. strTemp.LoadString(IDS_COMPACT_STATUS_COMPACTING);
  975. AddStatusMessage(strTemp);
  976. AddStatusMessage(strCommandLine);
  977. AddStatusMessage(gsz_EOL);
  978. dwLength = RunApp(strCommandLine, strStartingDirectory, &pszOutput);
  979. // the output comes back in ANSI. Convert to unicode by using a CString
  980. strOutput = pszOutput;
  981. strOutput += gsz_EOL;
  982. AddStatusMessage(strOutput);
  983. strTemp.LoadString(IDS_COMPACT_STATUS_STARTING_WINS);
  984. AddStatusMessage(strTemp);
  985. //start the service again and connect to the server
  986. err = ControlWINSService(m_strServerName, FALSE);
  987. err = ConnectToWinsServer();
  988. strTemp.LoadString(IDS_COMPACT_STATUS_COMPLETED);
  989. AddStatusMessage(strTemp);
  990. cleanup:
  991. m_pDlg->NotifyCompleted();
  992. return 11;
  993. }
  994. void CDBCompactThread::AddStatusMessage(LPCTSTR pszMessage)
  995. {
  996. m_pDlg->AddStatusMessage(pszMessage);
  997. }
  998. void CDBCompactThread::DisConnectFromWinsServer()
  999. {
  1000. if (m_hBinding)
  1001. {
  1002. CString strIP;
  1003. WINSINTF_BIND_DATA_T wbdBindData;
  1004. MakeIPAddress(m_dwIpAddress, strIP);
  1005. wbdBindData.fTcpIp = 1;
  1006. wbdBindData.pPipeName = NULL;
  1007. wbdBindData.pServerAdd = (LPSTR) (LPCTSTR) strIP;
  1008. ::WinsUnbind(&wbdBindData, m_hBinding);
  1009. m_hBinding = NULL;
  1010. }
  1011. }
  1012. DWORD CDBCompactThread::ConnectToWinsServer()
  1013. {
  1014. HRESULT hr = hrOK;
  1015. CString strServerName, strIP;
  1016. DWORD dwStatus = ERROR_SUCCESS;
  1017. WINSINTF_ADD_T waWinsAddress;
  1018. WINSINTF_BIND_DATA_T wbdBindData;
  1019. // build some information about the server
  1020. MakeIPAddress(m_dwIpAddress, strIP);
  1021. DisConnectFromWinsServer();
  1022. // now that the server name and ip are valid, call
  1023. // WINSBind function directly.
  1024. do
  1025. {
  1026. char szNetBIOSName[128] = {0};
  1027. // call WinsBind function with the IP address
  1028. wbdBindData.fTcpIp = 1;
  1029. wbdBindData.pPipeName = NULL;
  1030. wbdBindData.pServerAdd = (LPSTR) (LPCTSTR) strIP;
  1031. BEGIN_WAIT_CURSOR
  1032. if ((m_hBinding = ::WinsBind(&wbdBindData)) == NULL)
  1033. {
  1034. dwStatus = ::GetLastError();
  1035. break;
  1036. }
  1037. // do we need to do this? Is this just extra validation?
  1038. #ifdef WINS_CLIENT_APIS
  1039. dwStatus = ::WinsGetNameAndAdd(m_hBinding, &waWinsAddress, (LPBYTE) szNetBIOSName);
  1040. #else
  1041. dwStatus = ::WinsGetNameAndAdd(&waWinsAddress, (LPBYTE) szNetBIOSName);
  1042. #endif WINS_CLIENT_APIS
  1043. END_WAIT_CURSOR
  1044. } while (FALSE);
  1045. return dwStatus;
  1046. }
  1047. /****************************************************************************
  1048. *
  1049. * FUNCTION: RunApp
  1050. *
  1051. * PURPOSE: Starts a process to run the command line specified
  1052. *
  1053. * COMMENTS:
  1054. *
  1055. *
  1056. ****************************************************************************/
  1057. DWORD_PTR CDBCompactThread::RunApp(LPCTSTR input, LPCTSTR startingDirectory, LPSTR * output)
  1058. {
  1059. STARTUPINFO StartupInfo;
  1060. PROCESS_INFORMATION ProcessInfo;
  1061. SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES),
  1062. NULL, // NULL security descriptor
  1063. TRUE}; // Inherit handles (necessary!)
  1064. HANDLE hReadHandle, hWriteHandle, hErrorHandle;
  1065. LPSTR outputbuffer, lpOutput;
  1066. SIZE_T AvailableOutput;
  1067. BOOL TimeoutNotReached = TRUE;
  1068. DWORD BytesRead;
  1069. OVERLAPPED PipeOverlapInfo = {0,0,0,0,0};
  1070. CHAR szErrorMsg[1024];
  1071. // Create the heap if it doesn't already exist
  1072. if (m_hHeapHandle == 0)
  1073. {
  1074. if ((m_hHeapHandle = HeapCreate(0,
  1075. 8192,
  1076. 0)) == NULL) return 0;
  1077. }
  1078. // Create buffer to receive stdout output from our process
  1079. if ((outputbuffer = (LPSTR) HeapAlloc(m_hHeapHandle,
  1080. HEAP_ZERO_MEMORY,
  1081. 4096)) == NULL) return 0;
  1082. *output = outputbuffer;
  1083. // Check input parameter
  1084. if (input == NULL)
  1085. {
  1086. strcpy(outputbuffer, "ERROR: No command line specified");
  1087. return strlen(outputbuffer);
  1088. }
  1089. // Zero init process startup struct
  1090. FillMemory(&StartupInfo, sizeof(StartupInfo), 0);
  1091. StartupInfo.cb = sizeof(StartupInfo);
  1092. StartupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; // Use the our stdio handles
  1093. // Create pipe that will xfer process' stdout to our buffer
  1094. if (!CreatePipe(&hReadHandle,
  1095. &hWriteHandle,
  1096. &sa,
  1097. 0))
  1098. {
  1099. ::GetSystemMessageA(GetLastError(), szErrorMsg, sizeof(szErrorMsg));
  1100. strcpy(outputbuffer, szErrorMsg);
  1101. return strlen(outputbuffer);
  1102. }
  1103. // Set process' stdout to our pipe
  1104. StartupInfo.hStdOutput = hWriteHandle;
  1105. // We are going to duplicate our pipe's write handle
  1106. // and pass it as stderr to create process. The idea
  1107. // is that some processes have been known to close
  1108. // stderr which would also close stdout if we passed
  1109. // the same handle. Therefore we make a copy of stdout's
  1110. // pipe handle.
  1111. if (!DuplicateHandle(GetCurrentProcess(),
  1112. hWriteHandle,
  1113. GetCurrentProcess(),
  1114. &hErrorHandle,
  1115. 0,
  1116. TRUE,
  1117. DUPLICATE_SAME_ACCESS))
  1118. {
  1119. ::GetSystemMessageA(GetLastError(), szErrorMsg, sizeof(szErrorMsg));
  1120. strcpy(outputbuffer, szErrorMsg);
  1121. return strlen(outputbuffer);
  1122. }
  1123. StartupInfo.hStdError = hErrorHandle;
  1124. // Initialize our OVERLAPPED structure for our I/O pipe reads
  1125. PipeOverlapInfo.hEvent = CreateEvent(NULL,
  1126. TRUE,
  1127. FALSE,
  1128. NULL);
  1129. if (PipeOverlapInfo.hEvent == NULL)
  1130. {
  1131. ::GetSystemMessageA(GetLastError(), szErrorMsg, sizeof(szErrorMsg));
  1132. strcpy(outputbuffer, szErrorMsg);
  1133. return strlen(outputbuffer);
  1134. }
  1135. // Create the Process!
  1136. if (!CreateProcess(NULL, // name included in command line
  1137. (LPTSTR) input, // Command Line
  1138. NULL, // Default Process Sec. Attribs
  1139. NULL, // Default Thread Sec. Attribs
  1140. TRUE, // Inherit stdio handles
  1141. NORMAL_PRIORITY_CLASS, // Creation Flags
  1142. NULL, // Use this process' environment
  1143. startingDirectory, // Use the current directory
  1144. &StartupInfo,
  1145. &ProcessInfo))
  1146. {
  1147. ::GetSystemMessageA(GetLastError(), szErrorMsg, sizeof(szErrorMsg));
  1148. strcpy(outputbuffer, szErrorMsg);
  1149. return strlen(outputbuffer);
  1150. }
  1151. // lpOutput is moving output pointer
  1152. lpOutput = outputbuffer;
  1153. AvailableOutput = HeapSize(m_hHeapHandle,
  1154. 0,
  1155. outputbuffer);
  1156. // Close the write end of our pipe (both copies)
  1157. // so it will die when the child process terminates
  1158. CloseHandle(hWriteHandle);
  1159. CloseHandle(hErrorHandle);
  1160. while (TimeoutNotReached)
  1161. {
  1162. // Keep a read posted on the output pipe
  1163. if (ReadFile(hReadHandle,
  1164. lpOutput,
  1165. (DWORD) AvailableOutput,
  1166. &BytesRead,
  1167. &PipeOverlapInfo) == TRUE)
  1168. {
  1169. // Already received data...adjust buffer pointers
  1170. AvailableOutput-=BytesRead;
  1171. lpOutput += BytesRead;
  1172. if (AvailableOutput == 0)
  1173. {
  1174. // We used all our buffer, allocate more
  1175. LPSTR TempBufPtr = (LPSTR) HeapReAlloc(m_hHeapHandle,
  1176. HEAP_ZERO_MEMORY,
  1177. outputbuffer,
  1178. HeapSize(m_hHeapHandle,
  1179. 0,
  1180. outputbuffer) + 4096);
  1181. if (TempBufPtr == NULL)
  1182. {
  1183. // Copy error message to end of buffer
  1184. ::GetSystemMessageA(GetLastError(), szErrorMsg, sizeof(szErrorMsg));
  1185. strcpy(outputbuffer
  1186. + HeapSize(m_hHeapHandle,0, outputbuffer)
  1187. - strlen(szErrorMsg) - 1,
  1188. szErrorMsg);
  1189. return strlen(outputbuffer);
  1190. }
  1191. // Fix pointers in case ouir buffer moved
  1192. outputbuffer = TempBufPtr;
  1193. lpOutput = outputbuffer + BytesRead;
  1194. AvailableOutput = HeapSize(m_hHeapHandle, 0, outputbuffer) - BytesRead;
  1195. *output = outputbuffer;
  1196. }
  1197. }
  1198. else
  1199. {
  1200. // Switch on ReadFile result
  1201. switch (GetLastError())
  1202. {
  1203. case ERROR_IO_PENDING:
  1204. // No data yet, set event so we will be triggered
  1205. // when there is data
  1206. ResetEvent(PipeOverlapInfo.hEvent);
  1207. break;
  1208. case ERROR_MORE_DATA:
  1209. {
  1210. // Our buffer is too small...grow it
  1211. DWORD_PTR CurrentBufferOffset = lpOutput
  1212. - outputbuffer
  1213. + BytesRead;
  1214. LPTSTR TempBufPtr = (LPTSTR) HeapReAlloc(m_hHeapHandle,
  1215. HEAP_ZERO_MEMORY,
  1216. outputbuffer,
  1217. 4096);
  1218. if (TempBufPtr == NULL)
  1219. {
  1220. // Copy error message to end of buffer
  1221. ::GetSystemMessageA(GetLastError(), szErrorMsg, sizeof(szErrorMsg));
  1222. strcpy(outputbuffer + HeapSize
  1223. (m_hHeapHandle,0, outputbuffer) -
  1224. strlen(szErrorMsg) - 1, szErrorMsg);
  1225. return strlen(outputbuffer);
  1226. }
  1227. // Set parameters to post a new ReadFile
  1228. lpOutput = outputbuffer + CurrentBufferOffset;
  1229. AvailableOutput = HeapSize(m_hHeapHandle, 0, outputbuffer)
  1230. - CurrentBufferOffset;
  1231. *output = outputbuffer;
  1232. }
  1233. break;
  1234. case ERROR_BROKEN_PIPE:
  1235. // We are done..
  1236. //Make sure we are null terminated
  1237. *lpOutput = 0;
  1238. return (lpOutput - outputbuffer);
  1239. break;
  1240. case ERROR_INVALID_USER_BUFFER:
  1241. case ERROR_NOT_ENOUGH_MEMORY:
  1242. // Too many I/O requests pending...wait a little while
  1243. Sleep(2000);
  1244. break;
  1245. default:
  1246. // Wierd error...return
  1247. ::GetSystemMessageA(GetLastError(), szErrorMsg, sizeof(szErrorMsg));
  1248. strcpy(outputbuffer, szErrorMsg);
  1249. return strlen(outputbuffer);
  1250. }
  1251. }
  1252. // Wait for data to read
  1253. if (WaitForSingleObject(PipeOverlapInfo.hEvent,
  1254. 300000) == WAIT_TIMEOUT)
  1255. TimeoutNotReached = FALSE;
  1256. }
  1257. return strlen(outputbuffer);
  1258. }