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.

847 lines
19 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. WiaStress.cpp
  5. Abstract:
  6. Author:
  7. Hakki T. Bostanci (hakkib) 06-Apr-2000
  8. Revision History:
  9. --*/
  10. #include "stdafx.h"
  11. #include "WiaStress.h"
  12. //////////////////////////////////////////////////////////////////////////
  13. //
  14. //
  15. //
  16. #define DEFAULT_WIASTRESS_TIMEOUT (1i64 * 3 * 60 * 1000 * 1000 * 10)
  17. //////////////////////////////////////////////////////////////////////////
  18. //
  19. // bugbug: hardcoded globals
  20. //
  21. TCHAR g_szGetResultsPipeName[] = _T("\\\\hakkib\\pipe\\WIAStress_GetResults");
  22. TCHAR g_szSetResultsPipeName[] = _T("\\\\hakkib\\pipe\\WIAStress_SetResults");
  23. TCHAR g_szCollectLogsDirName[] = _T("\\\\hakkib\\WIAStressLogs");
  24. CBvtLog::COwners g_Owners =
  25. {
  26. /*PCTSTR pTestName = */ _T("WiaStress"),
  27. /*PCTSTR pContactName = */ _T("hakkib"),
  28. /*PCTSTR pMgrName = */ _T("hakkib"),
  29. /*PCTSTR pDevPrimeName = */ _T("hakkib"),
  30. /*PCTSTR pDevAltName = */ _T("hakkib"),
  31. /*PCTSTR pTestPrimeName = */ _T("hakkib"),
  32. /*PCTSTR pTestAltName = */ _T("hakkib")
  33. };
  34. //////////////////////////////////////////////////////////////////////////
  35. //
  36. // Usage string
  37. //
  38. TCHAR g_szUsage[] =
  39. _T("Optional command line arguments:\n")
  40. _T("\n")
  41. _T("/s\t\tRun in stress test mode\n")
  42. _T("/bvt\t\tRun in BVT mode\n")
  43. _T("/threads <#>\tNumber of threads (default = 1)\n")
  44. _T("/wait <#>\t\tMilliseconds to wait between tests (default = 0)\n")
  45. _T("/case <#>\tRun only specified test case\n")
  46. _T("/good\t\tRun only good parameter tests\n")
  47. _T("/repeat\t\tRepeat the tests in a loop\n")
  48. _T("/noui\t\tDo no display the UI, output to console only\n")
  49. _T("/frames\t\tSave stack frame on memory allocations\n")
  50. _T("/alloc <#>\tMemory allocation scheme\n")
  51. _T("\t\t(0=no guard, 1=guard tail, 2=guard head)\n")
  52. _T("/ntlog <file>\tLog using ntlog.dll\n")
  53. _T("/lorlog <file>\tLog using lorlog32.dll\n")
  54. _T("/bvtlog <file>\tLog in Windows 2000 BVT format\n")
  55. _T("");
  56. //////////////////////////////////////////////////////////////////////////
  57. //
  58. //
  59. //
  60. BOOL WINAPI ControlHandler(DWORD dwCtrlType)
  61. {
  62. g_LogWindow.Close();
  63. return TRUE;
  64. }
  65. //////////////////////////////////////////////////////////////////////////
  66. //
  67. //
  68. //
  69. int
  70. RunWiaStress()
  71. {
  72. // parse the command line arguments (if any)
  73. BOOL bStressMode = FALSE;
  74. BOOL bBVTMode = FALSE;
  75. BOOL bRunBadParamTests = TRUE;
  76. BOOL bRepeatTest = FALSE;
  77. int nThreads = 1;
  78. int nSleepAmount = 0;
  79. int nRunSingle = 0;
  80. int nGuardFlags = CGuardAllocator::GUARD_TAIL;
  81. BOOL bDisplayUI = TRUE;
  82. PCTSTR pLogFileName = 0;
  83. INT argc;
  84. CGlobalMem<PTSTR> argv = CommandLineToArgv(GetCommandLine(), &argc);
  85. for (int i = 1; i < argc; ++i)
  86. {
  87. if (_tcsicmp(argv[i], _T("/s")) == 0)
  88. {
  89. bStressMode = TRUE;
  90. bRepeatTest = TRUE;
  91. }
  92. else if (_tcsicmp(argv[i], _T("/bvt")) == 0)
  93. {
  94. bBVTMode = TRUE;
  95. bRunBadParamTests = FALSE;
  96. }
  97. else if (_tcsicmp(argv[i], _T("/threads")) == 0)
  98. {
  99. nThreads = Min(_ttoi(argv[++i]), (MAXIMUM_WAIT_OBJECTS - 1) / 2);
  100. }
  101. else if (_tcsicmp(argv[i], _T("/wait")) == 0)
  102. {
  103. nSleepAmount = _ttoi(argv[++i]);
  104. }
  105. else if (_tcsicmp(argv[i], _T("/case")) == 0)
  106. {
  107. nRunSingle = _ttoi(argv[++i]);
  108. }
  109. else if (_tcsicmp(argv[i], _T("/good")) == 0)
  110. {
  111. bRunBadParamTests = FALSE;
  112. }
  113. else if (_tcsicmp(argv[i], _T("/repeat")) == 0)
  114. {
  115. bRepeatTest = TRUE;
  116. }
  117. else if (_tcsicmp(argv[i], _T("/noui")) == 0)
  118. {
  119. bDisplayUI = FALSE;
  120. }
  121. else if (_tcsicmp(argv[i], _T("/frames")) == 0)
  122. {
  123. nGuardFlags |= CGuardAllocator::SAVE_STACK_FRAMES;
  124. }
  125. else if (_tcsicmp(argv[i], _T("/alloc")) == 0)
  126. {
  127. nGuardFlags &= ~CGuardAllocator::GUARD_FLAGS;
  128. nGuardFlags |= _ttoi(argv[++i]);
  129. }
  130. else if (_tcsicmp(argv[i], _T("/ntlog")) == 0)
  131. {
  132. pLogFileName = argv[++i];
  133. g_pLog = (CLog *) new CNtLog(pLogFileName, TLS_LOGALL);
  134. }
  135. else if (_tcsicmp(argv[i], _T("/lorlog")) == 0)
  136. {
  137. USES_CONVERSION;
  138. pLogFileName = argv[++i];
  139. g_pLog = (CLog *) new CLorLog(T2A(pLogFileName), ".", LOG_NEW, 0, 0);
  140. }
  141. else if (_tcsicmp(argv[i], _T("/bvtlog")) == 0)
  142. {
  143. pLogFileName = argv[++i];
  144. g_pLog = (CLog *) new CBvtLog(&g_Owners, pLogFileName);
  145. }
  146. else
  147. {
  148. return MessageBox(0, g_szUsage, _T("WiaStress"), MB_ICONINFORMATION | MB_OK);
  149. }
  150. }
  151. // initialize memory allocation scheme
  152. g_GuardAllocator.SetGuardType(nGuardFlags);
  153. // set up the output window / logging system
  154. g_LogWindow.ReadSavedData(g_szGetResultsPipeName);
  155. if (bDisplayUI)
  156. {
  157. g_LogWindow.Create(
  158. _T("WIA Stress"),
  159. GetConsoleHwnd(),
  160. LoadIcon(0, IDI_APPLICATION),
  161. 3000
  162. );
  163. g_pLog->SetLogWindow(&g_LogWindow);
  164. }
  165. else
  166. {
  167. g_LogWindow.Close(false);
  168. SetConsoleCtrlHandler(ControlHandler, TRUE);
  169. }
  170. // set up the who-run-when logging
  171. if (bStressMode && pLogFileName)
  172. {
  173. static CLogCollector RunInBackground(pLogFileName, g_szCollectLogsDirName);
  174. }
  175. // launch the threads
  176. CCppMem<CWiaStressThread> Threads(nThreads);
  177. CMultipleWait Handles(1 + nThreads + nThreads);
  178. Handles[0] = g_LogWindow.GetWaitHandle();
  179. for (int nThread = 0; nThread < nThreads; ++nThread)
  180. {
  181. Threads[nThread] = CWiaStressThread(
  182. bStressMode,
  183. bBVTMode,
  184. bRunBadParamTests,
  185. bRepeatTest,
  186. nSleepAmount,
  187. nRunSingle,
  188. nThread
  189. );
  190. Handles[1 + nThread] = Threads[nThread].m_ThreadObject;
  191. Handles[1 + nThreads + nThread] = Threads[nThread].m_TimeoutTimer;
  192. }
  193. // wait until all threads have terminated and the user has closed the window
  194. Event NotSignalled(TRUE, FALSE);
  195. int nRunningThreads = nThreads;
  196. while (nRunningThreads > 0 || bDisplayUI == TRUE)
  197. {
  198. DWORD dwWaitResult = Handles.WaitFor(FALSE);
  199. if (dwWaitResult == WAIT_OBJECT_0)
  200. {
  201. // user has closed the window or pressed ctrl+c
  202. Handles[dwWaitResult - WAIT_OBJECT_0] = NotSignalled;
  203. bDisplayUI = FALSE;
  204. }
  205. else if (dwWaitResult < 1 + nThreads + WAIT_OBJECT_0)
  206. {
  207. // one of the test threads has exited
  208. Handles[dwWaitResult - WAIT_OBJECT_0] = NotSignalled;
  209. nRunningThreads -= 1;
  210. }
  211. else if (dwWaitResult < 1 + 2 * nThreads + WAIT_OBJECT_0)
  212. {
  213. // one of the test threads has timed out
  214. int nHungThread = dwWaitResult - WAIT_OBJECT_0 - nThreads - 1;
  215. //***bugbug:TerminateThread(Threads[nHungThread].m_ThreadObject, 0);
  216. g_pLog->Log(
  217. TLS_ABORT | TLS_DEBUG | TLS_VARIATION,
  218. 0,
  219. nHungThread,
  220. _T("Thread was not responding, terminated")
  221. );
  222. // forget about this thread
  223. Handles[1 + nHungThread] = NotSignalled;
  224. nRunningThreads -= 1;
  225. }
  226. }
  227. // write the modified comments (if any) to the central database
  228. g_LogWindow.WriteModifiedData(g_szSetResultsPipeName);
  229. return 0;
  230. }
  231. //////////////////////////////////////////////////////////////////////////
  232. //
  233. //
  234. //
  235. CWiaStressThread::CWiaStressThread(
  236. BOOL bStressMode,
  237. BOOL bBVTMode,
  238. BOOL bRunBadParamTests,
  239. BOOL bRepeatTest,
  240. DWORD nSleepAmount,
  241. int nRunSingle,
  242. LONG nThread
  243. ) :
  244. m_bStressMode(bStressMode),
  245. m_bBVTMode(bBVTMode),
  246. m_bRunBadParamTests(bRunBadParamTests),
  247. m_bRepeatTest(bRepeatTest),
  248. m_nSleepAmount(nSleepAmount),
  249. m_nRunSingle(nRunSingle),
  250. m_nThread(nThread),
  251. m_pszContext(0),
  252. m_TimeoutTimer(FALSE),
  253. m_ThreadObject(ThreadProc, this)
  254. {
  255. }
  256. //////////////////////////////////////////////////////////////////////////
  257. //
  258. //
  259. //
  260. unsigned WINAPI CWiaStressThread::ThreadProc(PVOID pVoid)
  261. {
  262. CWiaStressThread *that = (CWiaStressThread *) pVoid;
  263. // init
  264. g_pLog->InitThread();
  265. that->LOG_INFO(_T("Starting thread"));
  266. srand(GetTickCount());
  267. HRESULT hr = CoInitializeEx(0, COINIT_APARTMENTTHREADED);
  268. if (hr != S_OK)
  269. {
  270. return FALSE;
  271. }
  272. // run
  273. do
  274. {
  275. try
  276. {
  277. CHECK_HR(that->m_pWiaDevMgr.CoCreateInstance(CLSID_WiaDevMgr));
  278. that->RunAllTests();
  279. }
  280. catch (const CError &Error)
  281. {
  282. if (Error.Num() == WIA_ERROR_BUSY)
  283. {
  284. that->LOG_INFO(_T("Device busy, test aborted"));
  285. }
  286. else
  287. {
  288. Error.Print(CLogHelper<TLS_SEV1 | TLS_DEBUG | TLS_VARIATION>());
  289. }
  290. that->m_pszContext = 0;
  291. }
  292. that->m_pWiaDevMgr.Release();
  293. }
  294. while (
  295. that->m_bRepeatTest &&
  296. g_LogWindow.WaitForSingleObject(that->m_nSleepAmount) == WAIT_TIMEOUT
  297. );
  298. // uninit
  299. CoUninitialize();
  300. that->LOG_INFO(_T("Exiting thread"));
  301. g_pLog->DoneThread();
  302. return TRUE;
  303. }
  304. //////////////////////////////////////////////////////////////////////////
  305. //
  306. //
  307. //
  308. void CWiaStressThread::RunAllTests()
  309. {
  310. CheckWiaDeviceAvailibility();
  311. INIT_STRESS(18);
  312. //
  313. // TestIWiaDevMgr
  314. //
  315. IF_SELECTED RunTest(TestEnumDeviceInfo);
  316. IF_SELECTED RunTest(TestCreateDevice);
  317. IF_SELECTED RunTest(TestSelectDeviceDlg);
  318. //IF_SELECTED RunTest(TestRegisterEventCallbackInterface);
  319. //
  320. // TestIWiaDataTransfer
  321. //
  322. IF_SELECTED RunTestForEachDevice(TestGetData, TRUE);
  323. IF_SELECTED RunTestForEachDevice(TestQueryData, TRUE);
  324. IF_SELECTED RunTestForEachDevice(TestEnumWIA_FORMAT_INFO, TRUE);
  325. //
  326. // TestIWiaItem
  327. //
  328. IF_SELECTED RunTestForEachDevice(TestGetItemType, TRUE);
  329. IF_SELECTED RunTestForEachDevice(TestEnumChildItems, TRUE);
  330. IF_SELECTED RunTestForEachDevice(TestCreateChildItem, TRUE);
  331. IF_SELECTED RunTestForEachDevice(TestEnumRegisterEventInfo, FALSE);
  332. IF_SELECTED RunTestForEachDevice(TestFindItemByName, TRUE);
  333. IF_SELECTED RunTestForEachDevice(TestDeviceDlg, FALSE);
  334. IF_SELECTED RunTestForEachDevice(TestGetRootItem, TRUE);
  335. IF_SELECTED RunTestForEachDevice(TestEnumDeviceCapabilities, FALSE);
  336. //
  337. // TestIWiaPropertyStorage
  338. //
  339. IF_SELECTED RunTestForEachDevice(TestPropStorage, TRUE);
  340. IF_SELECTED RunTestForEachDevice(TestPropGetCount, TRUE);
  341. IF_SELECTED RunTestForEachDevice(TestReadPropertyNames, TRUE);
  342. IF_SELECTED RunTestForEachDevice(TestEnumSTATPROPSTG, TRUE);
  343. }
  344. //////////////////////////////////////////////////////////////////////////
  345. //
  346. //
  347. //
  348. BOOL CWiaStressThread::CheckWiaDeviceAvailibility()
  349. {
  350. CComPtr<IEnumWIA_DEV_INFO> pEnumWIA_DEV_INFO;
  351. CHECK_HR(m_pWiaDevMgr->EnumDeviceInfo(0, &pEnumWIA_DEV_INFO));
  352. ULONG nDevices = -1;
  353. CHECK_HR(pEnumWIA_DEV_INFO->GetCount(&nDevices));
  354. if (nDevices == 0)
  355. {
  356. if (
  357. m_bStressMode ||
  358. MessageBox(
  359. 0,
  360. _T("No WIA devices available.\n")
  361. _T("Do you want to install a test device?"),
  362. 0,
  363. MB_ICONQUESTION | MB_YESNO
  364. ) == IDYES
  365. )
  366. {
  367. LOG_INFO(_T("No WIA devices available, installing test device"));
  368. CModuleFileName strPathName(0);
  369. PTSTR pszExeName = FindFileNamePortion(strPathName);
  370. _tcscpy(pszExeName, _T("scanner\\testscan.inf"));
  371. CHECK_HR(InstallTestDevice(m_pWiaDevMgr, strPathName, 0));
  372. }
  373. else
  374. {
  375. g_pLog->Log(
  376. TLS_BLOCK | TLS_VARIATION,
  377. 0,
  378. 0,
  379. _T("No WIA devices available, test results will not be meaningful")
  380. );
  381. }
  382. }
  383. return TRUE;
  384. }
  385. //////////////////////////////////////////////////////////////////////////
  386. //
  387. //
  388. //
  389. void CWiaStressThread::RunTest(PFNWIACALLBACK Callback)
  390. {
  391. if (g_LogWindow.IsClosed())
  392. {
  393. return;
  394. }
  395. g_pLog->StartBlock(_T("TEST CASE"));
  396. g_pLog->StartVariation();
  397. if (m_bStressMode)
  398. {
  399. m_TimeoutTimer.Set(-DEFAULT_WIASTRESS_TIMEOUT);
  400. }
  401. try
  402. {
  403. (this->*Callback)();
  404. }
  405. catch (const CError &Error)
  406. {
  407. if (Error.Num() == WIA_ERROR_BUSY)
  408. {
  409. LOG_INFO(_T("Device busy, test aborted"));
  410. }
  411. else
  412. {
  413. Error.Print(CLogHelper<TLS_SEV1 | TLS_DEBUG | TLS_VARIATION>());
  414. }
  415. m_pszContext = 0;
  416. }
  417. g_pLog->Log(
  418. TLS_NOCONSOLE | TLS_VARIATION | g_pLog->EndVariation(),
  419. m_pszContext,
  420. m_nThread,
  421. _T("Test complete")
  422. );
  423. g_pLog->EndBlock(_T("TEST CASE"));
  424. m_TimeoutTimer.Cancel();
  425. }
  426. //////////////////////////////////////////////////////////////////////////
  427. //
  428. //
  429. //
  430. void
  431. CWiaStressThread::RunTestForEachDevice(
  432. PFNWIAITEMCALLBACK Callback,
  433. BOOL bEnumChildItems
  434. )
  435. {
  436. if (g_LogWindow.IsClosed())
  437. {
  438. return;
  439. }
  440. g_pLog->StartBlock(_T("TEST CASE"));
  441. g_pLog->StartVariation();
  442. try
  443. {
  444. // enumerate all devices
  445. CComPtr<IEnumWIA_DEV_INFO> pEnumWIA_DEV_INFO;
  446. CHECK_HR(m_pWiaDevMgr->EnumDeviceInfo(StiDeviceTypeDefault, &pEnumWIA_DEV_INFO));
  447. ULONG nDevices;
  448. CHECK_HR(pEnumWIA_DEV_INFO->GetCount(&nDevices));
  449. // for the stress tests, use a random device. Otherwise, try all devices
  450. ULONG __nSelected = m_bStressMode && nDevices ? rand() % nDevices : 0;
  451. ULONG __nFrom = m_bStressMode ? __nSelected : 0;
  452. ULONG __nTo = m_bStressMode ? Min(__nSelected + 1, nDevices) : nDevices;
  453. for (ULONG i = __nFrom; i < __nTo; ++i)
  454. {
  455. // get the next device
  456. CComPtr<CMyWiaPropertyStorage> pProp;
  457. CHECK_HR(pEnumWIA_DEV_INFO->Next(1, (IWiaPropertyStorage **) &pProp, 0));
  458. // read the device id
  459. CPropVariant varDeviceID;
  460. CHECK_HR(pProp->ReadSingle(WIA_DIP_DEV_ID, &varDeviceID, VT_BSTR));
  461. // create the wiaitem
  462. CComPtr<IWiaItem> pWiaRootItem;
  463. CHECK_HR(m_pWiaDevMgr->CreateDevice(varDeviceID.bstrVal, &pWiaRootItem));
  464. // invoke the callback function
  465. CParentsList ParentsList;
  466. CWiaItemData ItemData(pWiaRootItem, ParentsList);
  467. RunTest(&ItemData, Callback);
  468. // continue enumeration with child items
  469. if (bEnumChildItems)
  470. {
  471. RunTestForEachChildItem(pWiaRootItem, Callback, ParentsList);
  472. }
  473. }
  474. }
  475. catch (const CError &Error)
  476. {
  477. if (Error.Num() == WIA_ERROR_BUSY)
  478. {
  479. LOG_INFO(_T("Device busy, test aborted"));
  480. }
  481. else
  482. {
  483. Error.Print(CLogHelper<TLS_SEV1 | TLS_DEBUG | TLS_VARIATION>());
  484. }
  485. }
  486. g_pLog->Log(
  487. TLS_NOCONSOLE | TLS_VARIATION | g_pLog->EndVariation(),
  488. m_pszContext,
  489. m_nThread,
  490. _T("Test complete")
  491. );
  492. g_pLog->EndBlock(_T("TEST CASE"));
  493. }
  494. //////////////////////////////////////////////////////////////////////////
  495. //
  496. //
  497. //
  498. void
  499. CWiaStressThread::RunTestForEachChildItem(
  500. IWiaItem *pWiaItem,
  501. PFNWIAITEMCALLBACK Callback,
  502. CParentsList ParentsList
  503. )
  504. {
  505. ParentsList.push_back(pWiaItem);
  506. // enumerate all child items
  507. CComPtr<IEnumWiaItem> pEnumWiaItem;
  508. CHECK_HR(pWiaItem->EnumChildItems(&pEnumWiaItem));
  509. ULONG nChildItems;
  510. CHECK_HR(pEnumWiaItem->GetCount(&nChildItems));
  511. FOR_SELECTED(i, nChildItems)
  512. {
  513. // get next item
  514. CComPtr<IWiaItem> pWiaItem;
  515. CHECK_HR(pEnumWiaItem->Next(1, &pWiaItem, 0));
  516. // invoke the callback function
  517. CWiaItemData ItemData(pWiaItem, ParentsList);
  518. RunTest(&ItemData, Callback);
  519. // continue enumeration if this is a folder
  520. if (ItemData.lItemType & WiaItemTypeFolder)
  521. {
  522. RunTestForEachChildItem(pWiaItem, Callback, ParentsList);
  523. }
  524. }
  525. }
  526. //////////////////////////////////////////////////////////////////////////
  527. //
  528. //
  529. //
  530. void
  531. CWiaStressThread::RunTest(
  532. CWiaItemData *pItemData,
  533. PFNWIAITEMCALLBACK Callback
  534. )
  535. {
  536. if (m_bStressMode)
  537. {
  538. m_TimeoutTimer.Set(-DEFAULT_WIASTRESS_TIMEOUT);
  539. }
  540. try
  541. {
  542. (this->*Callback)(pItemData);
  543. }
  544. catch (const CError &Error)
  545. {
  546. if (Error.Num() == WIA_ERROR_BUSY)
  547. {
  548. LOG_INFO(_T("Device busy, test aborted"));
  549. }
  550. else
  551. {
  552. Error.Print(CLogHelper<TLS_SEV1 | TLS_DEBUG | TLS_VARIATION>());
  553. }
  554. m_pszContext = 0;
  555. }
  556. m_TimeoutTimer.Cancel();
  557. }
  558. //////////////////////////////////////////////////////////////////////////
  559. //
  560. //
  561. //
  562. CWiaStressThread::CWiaItemData::CWiaItemData(
  563. IWiaItem *_pWiaItem,
  564. const CParentsList &_ParentsList
  565. ) :
  566. pWiaItem(_pWiaItem),
  567. ParentsList(_ParentsList)
  568. {
  569. // get item type
  570. CHECK_HR(pWiaItem->GetItemType(&lItemType));
  571. // get the full item name
  572. CPropVariant varFullItemName;
  573. CHECK_HR(ReadWiaItemProperty(
  574. pWiaItem,
  575. WIA_IPA_FULL_ITEM_NAME,
  576. &varFullItemName,
  577. VT_BSTR
  578. ));
  579. bstrFullName = varFullItemName.bstrVal;
  580. }
  581. //////////////////////////////////////////////////////////////////////////
  582. //
  583. //
  584. //
  585. int
  586. RunProgram()
  587. {
  588. try
  589. {
  590. return RunWiaStress();
  591. }
  592. catch (const CError &Error)
  593. {
  594. return Error.Print(CLogHelper<TLS_SEV1 | TLS_DEBUG | TLS_VARIATION>());
  595. }
  596. }
  597. //////////////////////////////////////////////////////////////////////////
  598. //
  599. //
  600. //
  601. VOID
  602. DumpStack(LPEXCEPTION_POINTERS pExceptionPointers)
  603. {
  604. HANDLE hProcess = GetCurrentProcess();
  605. SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES);
  606. SymInitialize(hProcess, 0, TRUE);
  607. const int nBufferSize = 4096;
  608. CHAR Buffer[nBufferSize];
  609. CStackFrame StackFrame(pExceptionPointers->ContextRecord);
  610. for (int i = 0; i < 30 && StackFrame.Walk(); ++i)
  611. {
  612. StackFrame.Dump(hProcess, Buffer, nBufferSize);
  613. OutputDebugStringA(Buffer);
  614. }
  615. SymCleanup(hProcess);
  616. }
  617. //////////////////////////////////////////////////////////////////////////
  618. //
  619. //
  620. //
  621. int
  622. RunProgramSEH()
  623. {
  624. __try
  625. {
  626. RunProgram();
  627. }
  628. __except(DumpStack(GetExceptionInformation()), EXCEPTION_CONTINUE_SEARCH)
  629. {
  630. }
  631. return 0;
  632. }
  633. //////////////////////////////////////////////////////////////////////////
  634. //
  635. //
  636. //
  637. extern "C"
  638. int
  639. WINAPI
  640. _tWinMain(
  641. HINSTANCE /*hInstance*/,
  642. HINSTANCE /*hPrevInstance*/,
  643. PSTR /*pCmdLine*/,
  644. int /*nCmdShow*/
  645. )
  646. {
  647. return RunProgram();
  648. }
  649. //////////////////////////////////////////////////////////////////////////
  650. //
  651. //
  652. //
  653. extern "C" int __cdecl _tmain()
  654. {
  655. return RunProgram();
  656. }