Source code of Windows XP (NT5)
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.

1670 lines
41 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. HRESULT hr = hrOK;
  604. CWinsResults winsResults, winsResultsCurrent;
  605. CString strMessage;
  606. CString strIP;
  607. DWORD dwMasterNoOfOwners;
  608. BOOL bProblem;
  609. UINT i;
  610. m_pLISOTable = new LARGE_INTEGER[100][MAX_WINS];
  611. m_strLATable.RemoveAll();
  612. m_strLATable.SetSize(MAX_WINS);
  613. DWORD status = winsResults.Update(m_hBinding);
  614. if (status != ERROR_SUCCESS)
  615. {
  616. strMessage.LoadString(IDS_ERROR_OCCURRED);
  617. strMessage += gsz_EOL;
  618. AddStatusMessage(strMessage);
  619. LPTSTR pBuf = strMessage.GetBuffer(1024);
  620. GetSystemMessage(status, pBuf, 1024);
  621. strMessage.ReleaseBuffer();
  622. strMessage += gsz_EOL;
  623. AddStatusMessage(strMessage);
  624. goto cleanup;
  625. }
  626. dwMasterNoOfOwners = winsResults.NoOfOwners;
  627. memset(m_pLISOTable, 0, MAX_WINS);
  628. status = InitLATable(winsResults.AddVersMaps.GetData(), 0, winsResults.NoOfOwners);
  629. // Place entry in the SO Table in proper order
  630. MakeIPAddress(m_dwIpAddress, strIP);
  631. AddSOTableEntry(strIP, winsResults.AddVersMaps.GetData(), winsResults.NoOfOwners, dwMasterNoOfOwners);
  632. // For each of the owners, get the owner-version map
  633. for (i = 0; i < dwMasterNoOfOwners; i++)
  634. {
  635. if (m_strLATable[i] == strIP)
  636. {
  637. continue;
  638. }
  639. // Get the owner's table
  640. WINSINTF_BIND_DATA_T wbdBindData;
  641. handle_t hBinding = NULL;
  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], winsResults.NoOfOwners);
  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], winsResults.NoOfOwners);
  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. if (dwMasterNoOfOwners < winsResultsCurrent.NoOfOwners)
  680. {
  681. status = InitLATable(winsResultsCurrent.AddVersMaps.GetData(), dwMasterNoOfOwners, winsResultsCurrent.NoOfOwners);
  682. if (status != winsResultsCurrent.NoOfOwners)
  683. {
  684. Trace0("New size does not match!!\n");
  685. }
  686. dwMasterNoOfOwners = status;
  687. }
  688. //
  689. // Place entry in the SO Table in proper order
  690. //
  691. AddSOTableEntry(m_strLATable[i], winsResultsCurrent.AddVersMaps.GetData(), winsResultsCurrent.NoOfOwners, dwMasterNoOfOwners);
  692. }
  693. ::WinsUnbind(&wbdBindData, hBinding);
  694. hBinding = NULL;
  695. if (FCheckForAbort())
  696. goto cleanup;
  697. }
  698. // Check if diagonal elements in the [SO] table are the highest in their cols.
  699. bProblem = CheckSOTableConsistency(dwMasterNoOfOwners);
  700. if (!bProblem)
  701. {
  702. strMessage.LoadString(IDS_VERSION_CHECK_SUCCESS);
  703. }
  704. else
  705. {
  706. strMessage.LoadString(IDS_VERSION_CHECK_FAIL);
  707. }
  708. strMessage += gsz_EOL;
  709. AddStatusMessage(strMessage);
  710. cleanup:
  711. if (m_pLISOTable)
  712. {
  713. delete[] m_pLISOTable;
  714. m_pLISOTable = NULL;
  715. }
  716. m_pDlg->NotifyCompleted();
  717. return 10;
  718. }
  719. DWORD
  720. CCheckVersionThread::InitLATable
  721. (
  722. PWINSINTF_ADD_VERS_MAP_T pAddVersMaps,
  723. DWORD MasterOwners, // 0 first time
  724. DWORD NoOfOwners
  725. )
  726. {
  727. ULONG i, j;
  728. if (MasterOwners == 0)
  729. {
  730. // first time - init the LA table
  731. for (i = 0; i < NoOfOwners; i++, pAddVersMaps++)
  732. {
  733. DWORD dwIP = pAddVersMaps->Add.IPAdd;
  734. CString strIP;
  735. MakeIPAddress(dwIP, strIP);
  736. m_strLATable.InsertAt(i, strIP);
  737. }
  738. }
  739. else
  740. {
  741. // More came in this time - add them to the LA table after the others
  742. for (i = 0; i < NoOfOwners; i++, pAddVersMaps++)
  743. {
  744. DWORD dwIP = pAddVersMaps->Add.IPAdd;
  745. CString strIP;
  746. MakeIPAddress(dwIP, strIP);
  747. // If this entry is not in the LA table, insert
  748. for (j = 0; j < MasterOwners; j++)
  749. {
  750. if (m_strLATable[j] == strIP)
  751. {
  752. break;
  753. }
  754. }
  755. if (j == MasterOwners)
  756. {
  757. //
  758. // Insert
  759. //
  760. Trace2("Inserting %s at %d\n", strIP, MasterOwners);
  761. m_strLATable[MasterOwners] = strIP;
  762. MasterOwners++;
  763. }
  764. }
  765. }
  766. return MasterOwners;
  767. }
  768. void
  769. CCheckVersionThread::AddSOTableEntry
  770. (
  771. CString & strIP,
  772. PWINSINTF_ADD_VERS_MAP_T pMasterMaps,
  773. DWORD NoOfOwners,
  774. DWORD MasterOwners
  775. )
  776. {
  777. ULONG i;
  778. LONG lRow;
  779. int nResize = INIT_SIZE;
  780. lRow = IPToIndex(strIP, MasterOwners);
  781. // Fill the row
  782. for ( i = 0; i < NoOfOwners; i++, pMasterMaps++)
  783. {
  784. LONG lCol;
  785. DWORD dwIP = pMasterMaps->Add.IPAdd;
  786. CString strColIP;
  787. MakeIPAddress(dwIP, strColIP);
  788. lCol = IPToIndex(strColIP, MasterOwners);
  789. // Place only a non-deleted entry
  790. if (!((pMasterMaps->VersNo.HighPart == MAXLONG) &&
  791. (pMasterMaps->VersNo.LowPart == MAXLONG)))
  792. {
  793. if((int) i >= nResize)
  794. {
  795. // create a new array and copy the contents of m_pLISOTable
  796. // to this array, this acts as a temp variable.
  797. LARGE_INTEGER (*tempLISOTable)[MAX_WINS];
  798. tempLISOTable = new LARGE_INTEGER[nResize][MAX_WINS];
  799. // now copy the elements to the temp array
  800. for(int xPos = 0; xPos < nResize; xPos++)
  801. {
  802. for (int yPos = 0; yPos < MAX_WINS; yPos++)
  803. {
  804. tempLISOTable [xPos][yPos] = m_pLISOTable[xPos][yPos];
  805. }
  806. }
  807. // increase the amount to be allocated
  808. nResize += INIT_SIZE;
  809. // realloc the array
  810. delete [] m_pLISOTable;
  811. m_pLISOTable = new LARGE_INTEGER[nResize][MAX_WINS];
  812. int nLimit = nResize-INIT_SIZE;
  813. // copy back the elements from the temp array, remember nresize
  814. // has been increased by INIT_SIZE
  815. for(xPos = 0; xPos < nLimit; xPos++)
  816. {
  817. for(int yPos = 0; yPos < MAX_WINS; yPos++)
  818. {
  819. m_pLISOTable [xPos][yPos] = tempLISOTable[xPos][yPos];
  820. }
  821. }
  822. // now delete the temp table
  823. delete [] tempLISOTable;
  824. }
  825. // Also if the entry above us was 0, write 0 there so as to make the fail case stand out
  826. if (lRow && m_pLISOTable[lRow-1][lCol].QuadPart == 0)
  827. {
  828. m_pLISOTable[lRow][lCol].QuadPart = 0;
  829. }
  830. else
  831. {
  832. m_pLISOTable[lRow][lCol] = pMasterMaps->VersNo;
  833. }
  834. }
  835. }
  836. }
  837. LONG
  838. CCheckVersionThread::IPToIndex
  839. (
  840. CString & strIP,
  841. DWORD NoOfOwners
  842. )
  843. {
  844. ULONG i;
  845. // Get the Row #
  846. for ( i = 0; i < NoOfOwners; i++)
  847. {
  848. if (m_strLATable[i] == strIP)
  849. {
  850. return i;
  851. }
  852. // The first NULL entry indicates end
  853. if (m_strLATable[i] == _T(""))
  854. {
  855. break;
  856. }
  857. }
  858. // Entry not found - add
  859. m_strLATable[i] = strIP;
  860. //LA_TableSize = i+1;
  861. return i;
  862. }
  863. BOOL
  864. CCheckVersionThread::CheckSOTableConsistency
  865. (
  866. DWORD dwMasterOwners
  867. )
  868. {
  869. //ULONG i;
  870. //ULONG j;
  871. BOOLEAN fProblem = FALSE;
  872. CString strMessage;
  873. for (DWORD i = 0; i < dwMasterOwners; i++)
  874. {
  875. // Is the diagonal element at i the largest in its column?
  876. for (DWORD j = 0; j < dwMasterOwners; j++)
  877. {
  878. if (i == j)
  879. {
  880. continue;
  881. }
  882. // Compare only non-zero values
  883. if (m_pLISOTable[i][i].QuadPart &&
  884. m_pLISOTable[j][i].QuadPart &&
  885. (m_pLISOTable[i][i].QuadPart < m_pLISOTable[j][i].QuadPart))
  886. {
  887. AfxFormatString2(strMessage, IDS_VERSION_INCONSISTENCY_FOUND, m_strLATable[j], m_strLATable[i]);
  888. strMessage += gsz_EOL;
  889. AddStatusMessage(strMessage);
  890. fProblem = TRUE;
  891. }
  892. }
  893. }
  894. return fProblem;
  895. }
  896. void
  897. CCheckVersionThread::RemoveFromSOTable
  898. (
  899. CString & strIP,
  900. DWORD dwMasterOwners
  901. )
  902. {
  903. ULONG i;
  904. LONG Row;
  905. Row = IPToIndex(strIP, dwMasterOwners);
  906. // Mark the row and col as down (0's)
  907. for (i = 0; i < dwMasterOwners; i++)
  908. {
  909. m_pLISOTable[Row][i].QuadPart = m_pLISOTable[i][Row].QuadPart = 0;
  910. }
  911. }
  912. /*---------------------------------------------------------------------------
  913. CDBCompactProgress
  914. Status dialog for DBCompact
  915. Author: EricDav
  916. ---------------------------------------------------------------------------*/
  917. BOOL CDBCompactProgress::OnInitDialog()
  918. {
  919. CProgress::OnInitDialog();
  920. CWaitCursor wc;
  921. m_Thread.m_pDlg = this;
  922. m_Thread.m_hBinding = m_hBinding;
  923. m_Thread.m_dwIpAddress = m_dwIpAddress;
  924. m_Thread.m_strServerName = m_strServerName;
  925. m_Thread.m_pConfig = m_pConfig;
  926. m_Thread.Start();
  927. CString strText;
  928. strText.LoadString(IDS_CANCEL);
  929. m_buttonCancel.SetWindowText(strText);
  930. strText.LoadString(IDS_COMPACT_DATABASE_TITLE);
  931. SetWindowText(strText);
  932. // user cannot cancel this operation as that would be really bad...
  933. m_buttonCancel.EnableWindow(FALSE);
  934. return TRUE; // return TRUE unless you set the focus to a control
  935. // EXCEPTION: OCX Property Pages should return FALSE
  936. }
  937. void CDBCompactProgress::OnCancel()
  938. {
  939. if (m_Thread.IsRunning())
  940. {
  941. CWaitCursor wc;
  942. CString strText;
  943. strText.LoadString(IDS_CLEANING_UP);
  944. strText += gsz_EOL;
  945. AddStatusMessage(strText);
  946. m_buttonCancel.EnableWindow(FALSE);
  947. m_Thread.Abort(FALSE);
  948. MSG msg;
  949. while (PeekMessage(&msg,NULL,NULL,NULL,PM_REMOVE))
  950. {
  951. TranslateMessage(&msg);
  952. DispatchMessage(&msg);
  953. }
  954. return;
  955. }
  956. CProgress::OnCancel();
  957. }
  958. void CDBCompactProgress::NotifyCompleted()
  959. {
  960. CString strText;
  961. strText.LoadString(IDS_FINISHED);
  962. strText += gsz_EOL;
  963. AddStatusMessage(strText);
  964. strText.LoadString(IDS_CLOSE);
  965. m_buttonCancel.SetWindowText(strText);
  966. m_buttonCancel.EnableWindow(TRUE);
  967. }
  968. /*---------------------------------------------------------------------------
  969. CDBCompactThread
  970. Background thread for DB Compact
  971. Author: EricDav
  972. ---------------------------------------------------------------------------*/
  973. // this is where the work gets done
  974. int CDBCompactThread::Run()
  975. {
  976. DWORD err = ERROR_SUCCESS;
  977. DWORD_PTR dwLength;
  978. CString strStartingDirectory, strWinsDb, strWinsTempDb, strCommandLine;
  979. CString strTemp, strMessage, strOutput;
  980. LPSTR pszOutput;
  981. // get the version of NT running on this machine
  982. // we can do this because this command only runs locally.
  983. OSVERSIONINFO os;
  984. ZeroMemory(&os, sizeof(OSVERSIONINFO));
  985. os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  986. BOOL bRet = GetVersionEx(&os);
  987. if (!bRet)
  988. {
  989. strMessage.LoadString(IDS_ERROR_OCCURRED);
  990. strMessage += gsz_EOL;
  991. AddStatusMessage(strMessage);
  992. LPTSTR pBuf = strMessage.GetBuffer(1024);
  993. GetSystemMessage(GetLastError(), pBuf, 1024);
  994. strMessage.ReleaseBuffer();
  995. strMessage += gsz_EOL;
  996. AddStatusMessage(strMessage);
  997. goto cleanup;
  998. }
  999. // all of the log files go into system32\wins so that's our starting dir
  1000. if (!GetSystemDirectory(strStartingDirectory.GetBuffer(MAX_PATH), MAX_PATH))
  1001. {
  1002. strMessage.LoadString(IDS_ERROR_OCCURRED);
  1003. strMessage += gsz_EOL;
  1004. AddStatusMessage(strMessage);
  1005. LPTSTR pBuf = strMessage.GetBuffer(1024);
  1006. GetSystemMessage(GetLastError(), pBuf, 1024);
  1007. strMessage.ReleaseBuffer();
  1008. strMessage += gsz_EOL;
  1009. AddStatusMessage(strMessage);
  1010. goto cleanup;
  1011. }
  1012. strStartingDirectory.ReleaseBuffer();
  1013. strStartingDirectory += _T("\\wins");
  1014. // check to see if the database is in the correct location
  1015. if (m_pConfig->m_strDbName.IsEmpty())
  1016. {
  1017. strWinsDb = _T("wins.mdb");
  1018. }
  1019. else
  1020. {
  1021. // the user has changed it...
  1022. strWinsDb = m_pConfig->m_strDbName;
  1023. }
  1024. strWinsTempDb = _T("winstemp.mdb");
  1025. strCommandLine = _T("jetpack.exe ");
  1026. switch (os.dwMajorVersion)
  1027. {
  1028. case VERSION_NT_50:
  1029. strCommandLine += strWinsDb + _T(" ") + strWinsTempDb;
  1030. break;
  1031. case VERSION_NT_40:
  1032. strCommandLine += _T("-40db" ) + strWinsDb + _T(" ") + strWinsTempDb;
  1033. break;
  1034. case VERSION_NT_351:
  1035. strCommandLine += _T("-351db ") + strWinsDb + _T(" ") + strWinsTempDb;
  1036. default:
  1037. break;
  1038. }
  1039. // disconnect from the server and stop the service
  1040. DisConnectFromWinsServer();
  1041. strTemp.LoadString(IDS_COMPACT_STATUS_STOPPING_WINS);
  1042. AddStatusMessage(strTemp);
  1043. ControlWINSService(m_strServerName, TRUE);
  1044. strTemp.LoadString(IDS_COMPACT_STATUS_COMPACTING);
  1045. AddStatusMessage(strTemp);
  1046. AddStatusMessage(strCommandLine);
  1047. AddStatusMessage(gsz_EOL);
  1048. dwLength = RunApp(strCommandLine, strStartingDirectory, &pszOutput);
  1049. // the output comes back in ANSI. Convert to unicode by using a CString
  1050. strOutput = pszOutput;
  1051. strOutput += gsz_EOL;
  1052. AddStatusMessage(strOutput);
  1053. strTemp.LoadString(IDS_COMPACT_STATUS_STARTING_WINS);
  1054. AddStatusMessage(strTemp);
  1055. //start the service again and connect to the server
  1056. err = ControlWINSService(m_strServerName, FALSE);
  1057. err = ConnectToWinsServer();
  1058. strTemp.LoadString(IDS_COMPACT_STATUS_COMPLETED);
  1059. AddStatusMessage(strTemp);
  1060. cleanup:
  1061. m_pDlg->NotifyCompleted();
  1062. return 11;
  1063. }
  1064. void CDBCompactThread::AddStatusMessage(LPCTSTR pszMessage)
  1065. {
  1066. m_pDlg->AddStatusMessage(pszMessage);
  1067. }
  1068. void CDBCompactThread::DisConnectFromWinsServer()
  1069. {
  1070. if (m_hBinding)
  1071. {
  1072. CString strIP;
  1073. WINSINTF_BIND_DATA_T wbdBindData;
  1074. MakeIPAddress(m_dwIpAddress, strIP);
  1075. wbdBindData.fTcpIp = 1;
  1076. wbdBindData.pPipeName = NULL;
  1077. wbdBindData.pServerAdd = (LPSTR) (LPCTSTR) strIP;
  1078. ::WinsUnbind(&wbdBindData, m_hBinding);
  1079. m_hBinding = NULL;
  1080. }
  1081. }
  1082. DWORD CDBCompactThread::ConnectToWinsServer()
  1083. {
  1084. HRESULT hr = hrOK;
  1085. CString strServerName, strIP;
  1086. DWORD dwStatus = ERROR_SUCCESS;
  1087. WINSINTF_ADD_T waWinsAddress;
  1088. WINSINTF_BIND_DATA_T wbdBindData;
  1089. // build some information about the server
  1090. MakeIPAddress(m_dwIpAddress, strIP);
  1091. DisConnectFromWinsServer();
  1092. // now that the server name and ip are valid, call
  1093. // WINSBind function directly.
  1094. do
  1095. {
  1096. char szNetBIOSName[128] = {0};
  1097. // call WinsBind function with the IP address
  1098. wbdBindData.fTcpIp = 1;
  1099. wbdBindData.pPipeName = NULL;
  1100. wbdBindData.pServerAdd = (LPSTR) (LPCTSTR) strIP;
  1101. BEGIN_WAIT_CURSOR
  1102. if ((m_hBinding = ::WinsBind(&wbdBindData)) == NULL)
  1103. {
  1104. dwStatus = ::GetLastError();
  1105. break;
  1106. }
  1107. // do we need to do this? Is this just extra validation?
  1108. #ifdef WINS_CLIENT_APIS
  1109. dwStatus = ::WinsGetNameAndAdd(m_hBinding, &waWinsAddress, (LPBYTE) szNetBIOSName);
  1110. #else
  1111. dwStatus = ::WinsGetNameAndAdd(&waWinsAddress, (LPBYTE) szNetBIOSName);
  1112. #endif WINS_CLIENT_APIS
  1113. END_WAIT_CURSOR
  1114. } while (FALSE);
  1115. return dwStatus;
  1116. }
  1117. /****************************************************************************
  1118. *
  1119. * FUNCTION: RunApp
  1120. *
  1121. * PURPOSE: Starts a process to run the command line specified
  1122. *
  1123. * COMMENTS:
  1124. *
  1125. *
  1126. ****************************************************************************/
  1127. DWORD_PTR CDBCompactThread::RunApp(LPCTSTR input, LPCTSTR startingDirectory, LPSTR * output)
  1128. {
  1129. STARTUPINFO StartupInfo;
  1130. PROCESS_INFORMATION ProcessInfo;
  1131. SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES),
  1132. NULL, // NULL security descriptor
  1133. TRUE}; // Inherit handles (necessary!)
  1134. HANDLE hReadHandle, hWriteHandle, hErrorHandle;
  1135. LPSTR outputbuffer, lpOutput;
  1136. SIZE_T AvailableOutput;
  1137. BOOL TimeoutNotReached = TRUE;
  1138. DWORD BytesRead;
  1139. OVERLAPPED PipeOverlapInfo = {0,0,0,0,0};
  1140. CHAR szErrorMsg[1024];
  1141. // Create the heap if it doesn't already exist
  1142. if (m_hHeapHandle == 0)
  1143. {
  1144. if ((m_hHeapHandle = HeapCreate(0,
  1145. 8192,
  1146. 0)) == NULL) return 0;
  1147. }
  1148. // Create buffer to receive stdout output from our process
  1149. if ((outputbuffer = (LPSTR) HeapAlloc(m_hHeapHandle,
  1150. HEAP_ZERO_MEMORY,
  1151. 4096)) == NULL) return 0;
  1152. *output = outputbuffer;
  1153. // Check input parameter
  1154. if (input == NULL)
  1155. {
  1156. strcpy(outputbuffer, "ERROR: No command line specified");
  1157. return strlen(outputbuffer);
  1158. }
  1159. // Zero init process startup struct
  1160. FillMemory(&StartupInfo, sizeof(StartupInfo), 0);
  1161. StartupInfo.cb = sizeof(StartupInfo);
  1162. StartupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; // Use the our stdio handles
  1163. // Create pipe that will xfer process' stdout to our buffer
  1164. if (!CreatePipe(&hReadHandle,
  1165. &hWriteHandle,
  1166. &sa,
  1167. 0))
  1168. {
  1169. ::GetSystemMessageA(GetLastError(), szErrorMsg, sizeof(szErrorMsg));
  1170. strcpy(outputbuffer, szErrorMsg);
  1171. return strlen(outputbuffer);
  1172. }
  1173. // Set process' stdout to our pipe
  1174. StartupInfo.hStdOutput = hWriteHandle;
  1175. // We are going to duplicate our pipe's write handle
  1176. // and pass it as stderr to create process. The idea
  1177. // is that some processes have been known to close
  1178. // stderr which would also close stdout if we passed
  1179. // the same handle. Therefore we make a copy of stdout's
  1180. // pipe handle.
  1181. if (!DuplicateHandle(GetCurrentProcess(),
  1182. hWriteHandle,
  1183. GetCurrentProcess(),
  1184. &hErrorHandle,
  1185. 0,
  1186. TRUE,
  1187. DUPLICATE_SAME_ACCESS))
  1188. {
  1189. ::GetSystemMessageA(GetLastError(), szErrorMsg, sizeof(szErrorMsg));
  1190. strcpy(outputbuffer, szErrorMsg);
  1191. return strlen(outputbuffer);
  1192. }
  1193. StartupInfo.hStdError = hErrorHandle;
  1194. // Initialize our OVERLAPPED structure for our I/O pipe reads
  1195. PipeOverlapInfo.hEvent = CreateEvent(NULL,
  1196. TRUE,
  1197. FALSE,
  1198. NULL);
  1199. if (PipeOverlapInfo.hEvent == NULL)
  1200. {
  1201. ::GetSystemMessageA(GetLastError(), szErrorMsg, sizeof(szErrorMsg));
  1202. strcpy(outputbuffer, szErrorMsg);
  1203. return strlen(outputbuffer);
  1204. }
  1205. // Create the Process!
  1206. if (!CreateProcess(NULL, // name included in command line
  1207. (LPTSTR) input, // Command Line
  1208. NULL, // Default Process Sec. Attribs
  1209. NULL, // Default Thread Sec. Attribs
  1210. TRUE, // Inherit stdio handles
  1211. NORMAL_PRIORITY_CLASS, // Creation Flags
  1212. NULL, // Use this process' environment
  1213. startingDirectory, // Use the current directory
  1214. &StartupInfo,
  1215. &ProcessInfo))
  1216. {
  1217. ::GetSystemMessageA(GetLastError(), szErrorMsg, sizeof(szErrorMsg));
  1218. strcpy(outputbuffer, szErrorMsg);
  1219. return strlen(outputbuffer);
  1220. }
  1221. // lpOutput is moving output pointer
  1222. lpOutput = outputbuffer;
  1223. AvailableOutput = HeapSize(m_hHeapHandle,
  1224. 0,
  1225. outputbuffer);
  1226. // Close the write end of our pipe (both copies)
  1227. // so it will die when the child process terminates
  1228. CloseHandle(hWriteHandle);
  1229. CloseHandle(hErrorHandle);
  1230. while (TimeoutNotReached)
  1231. {
  1232. // Keep a read posted on the output pipe
  1233. if (ReadFile(hReadHandle,
  1234. lpOutput,
  1235. (DWORD) AvailableOutput,
  1236. &BytesRead,
  1237. &PipeOverlapInfo) == TRUE)
  1238. {
  1239. // Already received data...adjust buffer pointers
  1240. AvailableOutput-=BytesRead;
  1241. lpOutput += BytesRead;
  1242. if (AvailableOutput == 0)
  1243. {
  1244. // We used all our buffer, allocate more
  1245. LPSTR TempBufPtr = (LPSTR) HeapReAlloc(m_hHeapHandle,
  1246. HEAP_ZERO_MEMORY,
  1247. outputbuffer,
  1248. HeapSize(m_hHeapHandle,
  1249. 0,
  1250. outputbuffer) + 4096);
  1251. if (TempBufPtr == NULL)
  1252. {
  1253. // Copy error message to end of buffer
  1254. ::GetSystemMessageA(GetLastError(), szErrorMsg, sizeof(szErrorMsg));
  1255. strcpy(outputbuffer
  1256. + HeapSize(m_hHeapHandle,0, outputbuffer)
  1257. - strlen(szErrorMsg) - 1,
  1258. szErrorMsg);
  1259. return strlen(outputbuffer);
  1260. }
  1261. // Fix pointers in case ouir buffer moved
  1262. outputbuffer = TempBufPtr;
  1263. lpOutput = outputbuffer + BytesRead;
  1264. AvailableOutput = HeapSize(m_hHeapHandle, 0, outputbuffer) - BytesRead;
  1265. *output = outputbuffer;
  1266. }
  1267. }
  1268. else
  1269. {
  1270. // Switch on ReadFile result
  1271. switch (GetLastError())
  1272. {
  1273. case ERROR_IO_PENDING:
  1274. // No data yet, set event so we will be triggered
  1275. // when there is data
  1276. ResetEvent(PipeOverlapInfo.hEvent);
  1277. break;
  1278. case ERROR_MORE_DATA:
  1279. {
  1280. // Our buffer is too small...grow it
  1281. DWORD_PTR CurrentBufferOffset = lpOutput
  1282. - outputbuffer
  1283. + BytesRead;
  1284. LPTSTR TempBufPtr = (LPTSTR) HeapReAlloc(m_hHeapHandle,
  1285. HEAP_ZERO_MEMORY,
  1286. outputbuffer,
  1287. 4096);
  1288. if (TempBufPtr == NULL)
  1289. {
  1290. // Copy error message to end of buffer
  1291. ::GetSystemMessageA(GetLastError(), szErrorMsg, sizeof(szErrorMsg));
  1292. strcpy(outputbuffer + HeapSize
  1293. (m_hHeapHandle,0, outputbuffer) -
  1294. strlen(szErrorMsg) - 1, szErrorMsg);
  1295. return strlen(outputbuffer);
  1296. }
  1297. // Set parameters to post a new ReadFile
  1298. lpOutput = outputbuffer + CurrentBufferOffset;
  1299. AvailableOutput = HeapSize(m_hHeapHandle, 0, outputbuffer)
  1300. - CurrentBufferOffset;
  1301. *output = outputbuffer;
  1302. }
  1303. break;
  1304. case ERROR_BROKEN_PIPE:
  1305. // We are done..
  1306. //Make sure we are null terminated
  1307. *lpOutput = 0;
  1308. return (lpOutput - outputbuffer);
  1309. break;
  1310. case ERROR_INVALID_USER_BUFFER:
  1311. case ERROR_NOT_ENOUGH_MEMORY:
  1312. // Too many I/O requests pending...wait a little while
  1313. Sleep(2000);
  1314. break;
  1315. default:
  1316. // Wierd error...return
  1317. ::GetSystemMessageA(GetLastError(), szErrorMsg, sizeof(szErrorMsg));
  1318. strcpy(outputbuffer, szErrorMsg);
  1319. return strlen(outputbuffer);
  1320. }
  1321. }
  1322. // Wait for data to read
  1323. if (WaitForSingleObject(PipeOverlapInfo.hEvent,
  1324. 300000) == WAIT_TIMEOUT)
  1325. TimeoutNotReached = FALSE;
  1326. }
  1327. return strlen(outputbuffer);
  1328. }