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.

1521 lines
34 KiB

  1. // This is a multi-threaded app with two primary threads. One
  2. // sits in the message loop, waiting specifically for WM_PAINT
  3. // messages which are generated by the other thread, on which
  4. // the actual unit test runs.
  5. //
  6. // When the window thread receives an update message, it takes
  7. // a snapshot of the unit test state (protected by a mutex),
  8. // and redraws the screen accordingly.
  9. //
  10. // When the unit test thread wants a resource to be drawn in
  11. // the main window, it places the handle to that resource (for
  12. // example, an HMETAFILEPICT) in the ctest object associated
  13. // with the window thread, then fires a screen update. In
  14. // doing so, ownership of the resource is transfered from the
  15. // unit test thread to the window thread. By using this
  16. // mechanism, the window thread can draw the resource at its
  17. // leisure, while the unit test proceeds. The onus is on
  18. // the window thread to clean up any resources which have
  19. // been deposited in its care when it exists.
  20. //
  21. // If the window thread receives a WM_CLOSE message, it must
  22. // first check to see that the unit test thread has completed.
  23. // If not, it spins in a RETRY/CANCEL loop until the unit test
  24. // thread has completed, or until the user selects CANCEL, at
  25. // which point execution proceeds, ignoring the WM_CLOSE.
  26. //
  27. // "OVER-ENGINEERED, AND BUILT TO STAY THAT WAY" (tm)
  28. //
  29. #include "headers.hxx"
  30. #pragma hdrstop
  31. CCacheTestApp ctest; // Application instance
  32. TestInstance inst; // Test instance
  33. //
  34. // Prototype for the entry-point of the unit test thread
  35. //
  36. unsigned long __stdcall testmain(void *);
  37. //+---------------------------------------------------------------------------
  38. //
  39. // Function: WinMain
  40. //
  41. // Synopsis: windows entry point
  42. //
  43. // Arguments: [hInst] --
  44. // [hPrevInst] --
  45. // [lpszCmdLine] --
  46. // [nCmdShow] --
  47. //
  48. // Returns: int
  49. //
  50. // History: 05-Sep-94 davepl Created
  51. //
  52. // Notes:
  53. //
  54. //----------------------------------------------------------------------------
  55. int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpszCmdLine, int nCmdShow)
  56. {
  57. MSG message;
  58. //
  59. // Initialize the application
  60. //
  61. if (SUCCEEDED(ctest.Initialize(hInst, hPrevInst, lpszCmdLine)))
  62. {
  63. //
  64. // Show and update the window
  65. //
  66. ShowWindow(ctest.Window(), nCmdShow);
  67. UpdateWindow(ctest.Window());
  68. //
  69. // The main message loop
  70. //
  71. while (GetMessage(&message, NULL, NULL, NULL))
  72. {
  73. TranslateMessage(&message);
  74. DispatchMessage(&message);
  75. }
  76. }
  77. else
  78. {
  79. return(0);
  80. }
  81. return(message.wParam);
  82. }
  83. //+---------------------------------------------------------------------------
  84. //
  85. // Member: CCacheTestApp::CCacheTestApp
  86. //
  87. // Synopsis: Constructor
  88. //
  89. // Arguments: (none)
  90. //
  91. // Returns: nothing
  92. //
  93. // History: 05-Sep-94 Davepl Created
  94. //
  95. // Notes:
  96. //
  97. //----------------------------------------------------------------------------
  98. CCacheTestApp::CCacheTestApp ()
  99. {
  100. }
  101. //+---------------------------------------------------------------------------
  102. //
  103. // Member: CCacheTestApp::Initialize
  104. //
  105. // Synopsis: initializes the application
  106. //
  107. // Arguments: [hInst] -- current instance
  108. // [hPrevInst] -- previous instance
  109. // [lpszCmdLine] -- command line parameters
  110. //
  111. // Returns: HRESULT
  112. //
  113. // History: 05-Sep-94 Davepl Created
  114. //
  115. // Notes:
  116. //
  117. //----------------------------------------------------------------------------
  118. HRESULT CCacheTestApp::Initialize (HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpszCmdLine)
  119. {
  120. HRESULT hr = S_OK;
  121. //
  122. // Register the window class
  123. //
  124. if (hPrevInst == NULL)
  125. {
  126. WNDCLASS wndclass;
  127. wndclass.style = 0;
  128. wndclass.lpfnWndProc = CacheTestAppWndProc;
  129. wndclass.cbClsExtra = 0;
  130. wndclass.cbWndExtra = 0;
  131. wndclass.hInstance = hInst;
  132. wndclass.hIcon = LoadIcon(hInst, IDI_EXCLAMATION);
  133. wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  134. wndclass.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
  135. wndclass.lpszMenuName = NULL;
  136. wndclass.lpszClassName = CTESTAPPCLASS;
  137. if (RegisterClass(&wndclass) == 0)
  138. {
  139. hr = HRESULT_FROM_WIN32(GetLastError());
  140. }
  141. }
  142. //
  143. // Create the mutex
  144. //
  145. m_hMutex = CreateMutex(NULL, FALSE, NULL);
  146. if (NULL == m_hMutex)
  147. {
  148. hr = HRESULT_FROM_WIN32(GetLastError());
  149. }
  150. //
  151. // Create the window
  152. //
  153. if (SUCCEEDED(hr))
  154. {
  155. if ((m_hWnd = CreateWindowEx(0L,
  156. CTESTAPPCLASS,
  157. CTESTAPPTITLE,
  158. WS_OVERLAPPEDWINDOW,
  159. CW_USEDEFAULT,
  160. 0,
  161. CW_USEDEFAULT,
  162. 0,
  163. NULL,
  164. NULL,
  165. hInst,
  166. NULL)) == NULL)
  167. {
  168. hr = HRESULT_FROM_WIN32(GetLastError());
  169. }
  170. }
  171. return(hr);
  172. }
  173. //+---------------------------------------------------------------------------
  174. //
  175. // Member: CCacheTestApp::~CCacheTestApp
  176. //
  177. // Synopsis: Destructor
  178. //
  179. // Arguments: (none)
  180. //
  181. // Returns: nothing
  182. //
  183. // History: 05-Sep-94 Davepl Created
  184. //
  185. // Notes:
  186. //
  187. //----------------------------------------------------------------------------
  188. CCacheTestApp::~CCacheTestApp ()
  189. {
  190. }
  191. //+---------------------------------------------------------------------------
  192. //
  193. // Function: CacheTestAppWndProc
  194. //
  195. // Synopsis: window procedure
  196. //
  197. // Arguments: [hWnd] -- window
  198. // [message] -- message id
  199. // [wParam] -- parameter
  200. // [lParam] -- parameter
  201. //
  202. // Returns: LRESULT
  203. //
  204. // History: 05-Sep-94 Davepl Created
  205. //
  206. // Notes:
  207. //
  208. //----------------------------------------------------------------------------
  209. LRESULT FAR PASCAL CacheTestAppWndProc (HWND hWnd,
  210. UINT message,
  211. WPARAM wParam,
  212. LPARAM lParam)
  213. {
  214. //
  215. // Process the messages
  216. //
  217. switch (message)
  218. {
  219. case WM_CREATE:
  220. //
  221. // The unit test window is opening. Create another thread
  222. // on which the unit test itself runs, while this thread
  223. // continues to spin, waiting for redraws, close, and so
  224. // on...
  225. //
  226. ctest.m_hTest = CreateThread(NULL,
  227. 0,
  228. testmain,
  229. NULL,
  230. 0,
  231. &ctest.m_dwThreadID);
  232. if (NULL == ctest.m_hTest)
  233. {
  234. mprintf("Unable to begin unit test\n");
  235. PostQuitMessage(0);
  236. }
  237. break;
  238. case WM_PAINT:
  239. {
  240. PAINTSTRUCT ps;
  241. HDC hDC;
  242. //
  243. // Get the DC for painting
  244. //
  245. hDC = BeginPaint(hWnd, &ps);
  246. if (hDC)
  247. {
  248. //
  249. // Draw the metafile
  250. //
  251. inst.Draw(hDC);
  252. EndPaint(hWnd, &ps);
  253. }
  254. }
  255. break;
  256. case WM_SIZE:
  257. //
  258. // Invalidate the rectangle
  259. //
  260. InvalidateRect(hWnd, NULL, TRUE);
  261. return DefWindowProc(hWnd, message, wParam, lParam);
  262. break;
  263. case WM_CLOSE:
  264. {
  265. //
  266. // The user has tried to exit the main program. Before we
  267. // can shut down, we must wait until the child thread has
  268. // completed. We allow the user to keep retrying on the
  269. // thread, or to "cancel" and wait until later. We do not
  270. // provide the option of terminating the child thread while
  271. // it is still busy.
  272. //
  273. DWORD dwStatus = 0;
  274. if (FALSE == GetExitCodeThread(ctest.m_hTest, &dwStatus))
  275. {
  276. mprintf("Could not get thread information!");
  277. break;
  278. }
  279. else
  280. {
  281. INT response = IDRETRY;
  282. while (STILL_ACTIVE == dwStatus)
  283. {
  284. response = MessageBox(ctest.Window(),
  285. "The child thread has not yet completed.",
  286. "Cannot Shutdown",
  287. MB_RETRYCANCEL);
  288. if (IDCANCEL == response)
  289. {
  290. break;
  291. }
  292. }
  293. }
  294. //
  295. // Destroy the window if the child has gone away
  296. //
  297. if (STILL_ACTIVE != dwStatus)
  298. {
  299. DestroyWindow(hWnd);
  300. }
  301. break;
  302. }
  303. case WM_DESTROY:
  304. PostQuitMessage(0);
  305. break;
  306. default:
  307. return DefWindowProc(hWnd, message, wParam, lParam);
  308. }
  309. return NULL;
  310. }
  311. //+----------------------------------------------------------------------------
  312. //
  313. // Member:
  314. //
  315. // Synopsis:
  316. //
  317. // Arguments:
  318. //
  319. // Returns: HRESULT
  320. //
  321. // Notes:
  322. //
  323. // History: 23-Aug-94 Davepl Created
  324. //
  325. //-----------------------------------------------------------------------------
  326. unsigned long __stdcall testmain(void *)
  327. {
  328. HRESULT hr;
  329. hr = inst.CreateAndInit( OLESTR("mystg") );
  330. if (S_OK != hr)
  331. {
  332. mprintf("Cache Unit Test Failed [CreateAndInit] hr = %x\n", hr);
  333. goto exit;
  334. }
  335. hr = inst.EnumeratorTest();
  336. if (S_OK != hr)
  337. {
  338. mprintf("Cache Unit Test Failed [EnumeratorTest] hr = %x\n", hr);
  339. goto exit;
  340. }
  341. hr = inst.MultiCache(50);
  342. if (S_OK != hr)
  343. {
  344. mprintf("Cache Unit Test Failed [MultiCache] hr = %x\n", hr);
  345. goto exit;
  346. }
  347. hr = inst.CacheDataTest("TIGER.BMP", "TIGERNPH.WMF");
  348. if (S_OK != hr)
  349. {
  350. mprintf("Cache Unit Test Failed [CacheDataTest] hr = %x\n", hr);
  351. goto exit;
  352. }
  353. exit:
  354. PostMessage(ctest.Window(), WM_CLOSE, (WPARAM) hr, 0);
  355. return (ULONG) hr;
  356. }
  357. //+----------------------------------------------------------------------------
  358. //
  359. // Member: TestInstance::TestInstance
  360. //
  361. // Synopsis: Constructor
  362. //
  363. // Arguments:
  364. //
  365. // Returns:
  366. //
  367. // Notes:
  368. //
  369. // History: 23-Aug-94 Davepl Created
  370. //
  371. //-----------------------------------------------------------------------------
  372. TestInstance::TestInstance()
  373. {
  374. m_pStorage = NULL;
  375. m_pPersistStorage = NULL;
  376. m_pOleCache = NULL;
  377. m_pOleCache2 = NULL;
  378. m_pDataObject = NULL;
  379. m_pViewObject = NULL;
  380. m_State = TEST_STARTING;
  381. }
  382. TestInstance::~TestInstance()
  383. {
  384. //
  385. // Release our interface pointers
  386. //
  387. if (m_pDataObject)
  388. {
  389. m_pDataObject->Release();
  390. }
  391. if (m_pViewObject)
  392. {
  393. m_pViewObject->Release();
  394. }
  395. if (m_pPersistStorage)
  396. {
  397. m_pPersistStorage->Release();
  398. }
  399. if (m_pOleCache2)
  400. {
  401. m_pOleCache2->Release();
  402. }
  403. if (m_pOleCache)
  404. {
  405. m_pOleCache->Release();
  406. }
  407. if (m_pStorage)
  408. {
  409. m_pStorage->Release();
  410. }
  411. }
  412. //+----------------------------------------------------------------------------
  413. //
  414. // Member: TestInstance::CreateAndInit
  415. //
  416. // Synopsis: Creates a cache and sets up internal interface ptrs
  417. //
  418. // Arguments: (none)
  419. //
  420. // Returns: HRESULT
  421. //
  422. // Notes:
  423. //
  424. // History: 23-Aug-94 Davepl Created
  425. //
  426. //-----------------------------------------------------------------------------
  427. HRESULT TestInstance::CreateAndInit(LPOLESTR lpwszStgName)
  428. {
  429. HRESULT hr;
  430. TraceLog Log(this, "TestInstance::CreateAndInit", GS_CACHE, VB_MINIMAL);
  431. Log.OnEntry (" ( %p ) \n", lpwszStgName);
  432. Log.OnExit (" ( %X ) \n", &hr);
  433. //
  434. // Create the storage on which we will instantiate our cache
  435. //
  436. // BUGBUG use correct strcpy fn
  437. wcscpy(m_wszStorage, lpwszStgName);
  438. hr = StgCreateDocfile(lpwszStgName,
  439. STGM_DIRECT |
  440. STGM_READWRITE |
  441. STGM_SHARE_EXCLUSIVE |
  442. STGM_CREATE,
  443. 0,
  444. &m_pStorage);
  445. //
  446. // Create a Data Cache on our IStorage
  447. //
  448. if (S_OK == hr)
  449. {
  450. hr = CreateDataCache(NULL,
  451. CLSID_NULL,
  452. IID_IPersistStorage,
  453. (void **)&m_pPersistStorage);
  454. }
  455. if (S_OK == hr)
  456. {
  457. hr = m_pPersistStorage->InitNew(m_pStorage);
  458. }
  459. //
  460. // Get an IOleCache interface pointer to the cache
  461. //
  462. if (S_OK == hr)
  463. {
  464. hr = m_pPersistStorage->QueryInterface(IID_IOleCache,
  465. (void **) &m_pOleCache);
  466. }
  467. //
  468. // Get an IOleCache2 interface pointer to the cache
  469. //
  470. if (S_OK == hr)
  471. {
  472. hr = m_pPersistStorage->QueryInterface(IID_IOleCache2,
  473. (void **) &m_pOleCache2);
  474. }
  475. //
  476. // Get an IViewObject interface pointer to the cache
  477. //
  478. if (S_OK == hr)
  479. {
  480. hr = m_pPersistStorage->QueryInterface(IID_IViewObject,
  481. (void **) &m_pViewObject);
  482. }
  483. //
  484. // Get an IDataObject interface pointer to the cache
  485. //
  486. if (S_OK == hr)
  487. {
  488. hr = m_pPersistStorage->QueryInterface(IID_IDataObject,
  489. (void **) &m_pDataObject);
  490. }
  491. return hr;
  492. }
  493. //+----------------------------------------------------------------------------
  494. //
  495. // Member: TestInstance::SaveAndReload
  496. //
  497. // Synopsis: Saves the cache to its storage and reloads it
  498. // right back.
  499. //
  500. // Arguments: (none)
  501. //
  502. // Returns: HRESULT
  503. //
  504. // Notes: Once saved, the behavior of DiscardCache will
  505. // change, since each node present at the time of
  506. // save will have a stream from which it can demand
  507. // load its data.
  508. //
  509. // Since each interface pointer is released and
  510. // reaquired, the pointer values will (likely) change
  511. // during this call; hence, so _not_ cache the pointers
  512. // locally around this call.
  513. //
  514. // History: 23-Aug-94 Davepl Created
  515. //
  516. //-----------------------------------------------------------------------------
  517. HRESULT TestInstance::SaveAndReload()
  518. {
  519. HRESULT hr;
  520. TraceLog Log(NULL, "TestInstance::SaveAndReload", GS_CACHE, VB_MINIMAL);
  521. Log.OnEntry ();
  522. Log.OnExit (" ( %X )\n", &hr);
  523. SetCurrentState(SAVE_AND_RELOAD);
  524. hr = m_pPersistStorage->Save(m_pStorage, TRUE);
  525. if (S_OK == hr)
  526. {
  527. hr = m_pPersistStorage->SaveCompleted(NULL);
  528. }
  529. // Release our hold on the storage and the cache
  530. if (S_OK == hr)
  531. {
  532. m_pViewObject->Release();
  533. m_pViewObject = NULL;
  534. m_pDataObject->Release();
  535. m_pDataObject = NULL;
  536. m_pStorage->Release();
  537. m_pStorage = NULL;
  538. m_pPersistStorage->Release();
  539. m_pPersistStorage = NULL;
  540. m_pOleCache2->Release();
  541. m_pOleCache2 = NULL;
  542. m_pOleCache->Release();
  543. m_pOleCache = NULL;
  544. //
  545. // Reload the cache and QI to get our interfaces back
  546. //
  547. hr = StgOpenStorage(m_wszStorage,
  548. NULL,
  549. STGM_DIRECT |
  550. STGM_READWRITE |
  551. STGM_SHARE_EXCLUSIVE,
  552. NULL,
  553. 0,
  554. &m_pStorage);
  555. //
  556. // Create a Data Cache on our IStorage
  557. //
  558. if (S_OK == hr)
  559. {
  560. hr = CreateDataCache(NULL,
  561. CLSID_NULL,
  562. IID_IPersistStorage,
  563. (void **)&m_pPersistStorage);
  564. }
  565. if (S_OK == hr)
  566. {
  567. hr = m_pPersistStorage->Load(m_pStorage);
  568. }
  569. //
  570. // Get an IOleCache interface pointer to the cache
  571. //
  572. if (S_OK == hr)
  573. {
  574. hr = m_pPersistStorage->QueryInterface(IID_IOleCache,
  575. (void **) &m_pOleCache);
  576. }
  577. //
  578. // Get an IOleCache2 interface pointer to the cache
  579. //
  580. if (S_OK == hr)
  581. {
  582. hr = m_pPersistStorage->QueryInterface(IID_IOleCache2,
  583. (void **) &m_pOleCache2);
  584. }
  585. //
  586. // Get an IViewObject interface pointer to the cache
  587. //
  588. if (S_OK == hr)
  589. {
  590. hr = m_pPersistStorage->QueryInterface(IID_IViewObject,
  591. (void **) &m_pViewObject);
  592. }
  593. //
  594. // Get an IDataObject interface pointer to the cache
  595. //
  596. if (S_OK == hr)
  597. {
  598. hr = m_pPersistStorage->QueryInterface(IID_IDataObject,
  599. (void **) &m_pDataObject);
  600. }
  601. }
  602. return hr;
  603. }
  604. //+----------------------------------------------------------------------------
  605. //
  606. // Member: TestInstance::CacheDataTest
  607. //
  608. // Synopsis: Checks the cache for data integrity
  609. //
  610. // Arguments: lpszBMPFileName - Name of .BMP file to use for test
  611. // lpszWMFFileName - Name of .WMF file to use for test
  612. //
  613. // Returns: HRESULT
  614. //
  615. // Notes:
  616. //
  617. // History: 04-Sep-94 Davepl Created
  618. //
  619. //-----------------------------------------------------------------------------
  620. HRESULT TestInstance::CacheDataTest(char * lpszBMPFileName, char * lpszWMFFileName)
  621. {
  622. HRESULT hr = S_OK;
  623. TraceLog Log(NULL, "TestInstance::CacheDataTest", GS_CACHE, VB_MINIMAL);
  624. Log.OnEntry (" ( BMP=%s, WMF=%s )\n", lpszBMPFileName, lpszWMFFileName);
  625. Log.OnExit (" ( %X )\n", &hr);
  626. SetCurrentState(DATA_TEST);
  627. CBitmapFile bmpFile;
  628. HGLOBAL hDIB = NULL;
  629. //
  630. // Allocate an hglobal to hold our metafilepict structure
  631. //
  632. HGLOBAL hMFPICT = GlobalAlloc(GMEM_FIXED, sizeof(METAFILEPICT));
  633. if (NULL == hMFPICT)
  634. {
  635. hr = HRESULT_FROM_WIN32(GetLastError());
  636. }
  637. METAFILEPICT * pMFPICT = (METAFILEPICT *) hMFPICT;
  638. //
  639. // Load the bitmap from disk
  640. //
  641. if (S_OK == hr)
  642. {
  643. hr = bmpFile.LoadBitmapFile(lpszBMPFileName);
  644. }
  645. //
  646. // Create a DIB on an HGLOBAL from the bitmap
  647. //
  648. if (S_OK == hr)
  649. {
  650. hr = bmpFile.CreateDIBInHGlobal(&hDIB);
  651. }
  652. //
  653. // Add DIB and MF nodes to the cache
  654. //
  655. DWORD dwDIBCon;
  656. DWORD dwMFCon;
  657. if (S_OK == hr)
  658. {
  659. hr = AddDIBCacheNode(&dwDIBCon);
  660. }
  661. if (S_OK == hr)
  662. {
  663. hr = AddMFCacheNode(&dwMFCon);
  664. }
  665. //
  666. // Load the metafile from disk, then set up the
  667. // METAFILEPICT structure
  668. //
  669. if (S_OK == hr)
  670. {
  671. pMFPICT->hMF = GetMetaFileA(lpszWMFFileName);
  672. if (NULL == pMFPICT->hMF)
  673. {
  674. hr = HRESULT_FROM_WIN32(GetLastError());
  675. }
  676. else
  677. {
  678. //
  679. // We deem the metafile to have the same extents
  680. // as the the DIB. This is completely arbitrary,
  681. // but might aid in tracking down extents problems.
  682. // After all, we have to pick _some_ value, so it
  683. // might as well be a useful one...
  684. //
  685. pMFPICT->xExt = ConvWidthInPelsToLHM(NULL, bmpFile.GetDIBHeight());
  686. pMFPICT->yExt = ConvHeightInPelsToLHM(NULL, bmpFile.GetDIBWidth());
  687. pMFPICT->mm = MM_ANISOTROPIC;
  688. }
  689. }
  690. //
  691. // Place the nodes in the cache. We keep ownership of the handles,
  692. // which will force the cache to duplicate it. We can then compare
  693. // our original with whatever we later get back from the cache.
  694. //
  695. FORMATETC fetcDIB =
  696. {
  697. CF_DIB,
  698. NULL,
  699. DVASPECT_CONTENT,
  700. DEF_LINDEX,
  701. TYMED_HGLOBAL
  702. };
  703. STGMEDIUM stgmDIB;
  704. FORMATETC fetcMF =
  705. {
  706. CF_METAFILEPICT,
  707. NULL,
  708. DVASPECT_CONTENT,
  709. DEF_LINDEX,
  710. TYMED_MFPICT
  711. };
  712. STGMEDIUM stgmMF;
  713. if (S_OK == hr)
  714. {
  715. stgmDIB.tymed = TYMED_HGLOBAL;
  716. stgmDIB.hGlobal = hDIB;
  717. hr = m_pOleCache->SetData(&fetcDIB, &stgmDIB, FALSE);
  718. }
  719. if (S_OK == hr)
  720. {
  721. stgmMF.tymed = TYMED_MFPICT,
  722. stgmMF.hMetaFilePict = hMFPICT;
  723. hr = m_pOleCache->SetData(&fetcMF, &stgmMF, FALSE);
  724. }
  725. //
  726. // If we were able to place the data in the cache, check
  727. // to make sure whatever is in the cache matches our
  728. // original.
  729. //
  730. if (S_OK == hr)
  731. {
  732. hr = CompareDIB(hDIB);
  733. if (S_OK == hr)
  734. {
  735. hr = CompareMF(hMFPICT);
  736. }
  737. }
  738. //
  739. // Save and Reload the cache to test persistance
  740. //
  741. if (S_OK == hr)
  742. {
  743. hr = SaveAndReload();
  744. }
  745. if (S_OK == hr)
  746. {
  747. SetCurrentState(DATA_TEST);
  748. }
  749. //
  750. // Compare the data again
  751. //
  752. if (S_OK == hr)
  753. {
  754. hr = CompareDIB(hDIB);
  755. if (S_OK == hr)
  756. {
  757. hr = CompareMF(hMFPICT);
  758. }
  759. }
  760. //
  761. // Discard the cache.
  762. //
  763. if (S_OK == hr)
  764. {
  765. hr = m_pOleCache2->DiscardCache(DISCARDCACHE_NOSAVE);
  766. }
  767. //
  768. // Now compare again against the current presentations,
  769. // which would have to be demand-loaded after the discard.
  770. //
  771. if (S_OK == hr)
  772. {
  773. hr = CompareDIB(hDIB);
  774. if (S_OK == hr)
  775. {
  776. hr = CompareMF(hMFPICT);
  777. }
  778. }
  779. //
  780. // Try to draw the cache's best presentation (which should
  781. // be metafile at this point) into a metafile DC which we
  782. // will then hand off to the window thread for drawing.
  783. //
  784. if (S_OK == hr)
  785. {
  786. hr = DrawCacheToMetaFilePict(&ctest.m_hMFP, FALSE);
  787. if (S_OK == hr)
  788. {
  789. SetCurrentState(DRAW_METAFILE_NOW);
  790. }
  791. }
  792. //
  793. // Now draw the metafile tiled 4 times into the display
  794. // metafile, and hand it off...
  795. //
  796. if (S_OK == hr)
  797. {
  798. hr = DrawCacheToMetaFilePict(&ctest.m_hMFPTILED, TRUE);
  799. if (S_OK == hr)
  800. {
  801. SetCurrentState(DRAW_METAFILETILED_NOW);
  802. }
  803. }
  804. //
  805. // Uncache the metafile node, which will leave the DIB node
  806. // as the best (and only) node left for drawing
  807. //
  808. if (S_OK == hr)
  809. {
  810. hr = UncacheFormat(CF_METAFILEPICT);
  811. }
  812. //
  813. // Now draw the DIB into a metafile and hand that off
  814. // to the window thread for drawing
  815. //
  816. if (S_OK == hr)
  817. {
  818. hr = DrawCacheToMetaFilePict(&ctest.m_hMFPDIB, FALSE);
  819. if (S_OK == hr)
  820. {
  821. SetCurrentState(DRAW_DIB_NOW);
  822. }
  823. }
  824. //
  825. // Now draw the DIB again, this time tiled into the mf
  826. //
  827. if (S_OK == hr)
  828. {
  829. hr = DrawCacheToMetaFilePict(&ctest.m_hMFPDIBTILED, TRUE);
  830. if (S_OK == hr)
  831. {
  832. SetCurrentState(DRAW_DIBTILED_NOW);
  833. }
  834. }
  835. //
  836. // Cleanup our local DIB
  837. //
  838. if (hDIB)
  839. {
  840. GlobalFree(hDIB);
  841. }
  842. //
  843. // Cleaup our local metafile
  844. //
  845. if (pMFPICT)
  846. {
  847. if (pMFPICT->hMF)
  848. {
  849. if (FALSE == DeleteMetaFile(pMFPICT->hMF))
  850. {
  851. hr = HRESULT_FROM_WIN32(GetLastError());
  852. }
  853. }
  854. GlobalFree(hMFPICT);
  855. }
  856. return hr;
  857. }
  858. HRESULT TestInstance::CompareDIB(HGLOBAL hDIB)
  859. {
  860. return S_OK;
  861. }
  862. HRESULT TestInstance::CompareMF(HMETAFILEPICT hMFPICT)
  863. {
  864. return S_OK;
  865. }
  866. //+----------------------------------------------------------------------------
  867. //
  868. // Member: TestInstance::DrawCacheToMetaFilePict
  869. //
  870. // Synopsis: Draws the cache's current best presentation to
  871. // a metafile, contained in a metafilepict structure,
  872. // which is allocated off of the hGlobal pointer passed
  873. // in by the caller
  874. //
  875. // Arguments: [phGlobal] - The ptr to the hglobal to allocate on
  876. // [fTile] - If true, the pres is tiled into the mf
  877. //
  878. // Returns: HRESULT
  879. //
  880. // Notes:
  881. //
  882. // History: 06-Sep-94 Davepl Created
  883. //
  884. //-----------------------------------------------------------------------------
  885. HRESULT TestInstance::DrawCacheToMetaFilePict(HGLOBAL *phGlobal, BOOL fTile)
  886. {
  887. HRESULT hr = S_OK;
  888. TraceLog Log(NULL, "TestInstance::DrawCacheToMetaFilePict", GS_CACHE, VB_MINIMAL);
  889. Log.OnEntry (" ( %p, %d )\n", phGlobal, fTile);
  890. Log.OnExit (" ( %X )\n", &hr);
  891. //
  892. // Create a metafile, and have the cache draw its metafile
  893. // into _our_ metafile.
  894. //
  895. //
  896. // First, set up the METAFILEPICT structure.
  897. // Since ANISOTROPIC mode allows arbitrary scaling extents, we
  898. // pick 1000 as a nice arbitrary size.
  899. //
  900. //
  901. METAFILEPICT *pmfp = NULL;
  902. if (S_OK == hr)
  903. {
  904. *phGlobal = GlobalAlloc(GMEM_FIXED, sizeof(METAFILEPICT));
  905. if (NULL == *phGlobal)
  906. {
  907. hr = HRESULT_FROM_WIN32(GetLastError());
  908. }
  909. else
  910. {
  911. pmfp = (METAFILEPICT *) GlobalLock(*phGlobal);
  912. if (NULL == pmfp)
  913. {
  914. GlobalFree(*phGlobal);
  915. *phGlobal = NULL;
  916. hr = HRESULT_FROM_WIN32(GetLastError());
  917. }
  918. else
  919. {
  920. pmfp->xExt = 1000;
  921. pmfp->yExt = 1000;
  922. pmfp->mm = MM_ANISOTROPIC;
  923. }
  924. }
  925. }
  926. //
  927. // Now create the metafile within the METAFILEPICT structure,
  928. // and ask the cache to draw to it.
  929. //
  930. HDC mfdc;
  931. if (S_OK == hr)
  932. {
  933. mfdc = CreateMetaFile(NULL);
  934. if (NULL == mfdc)
  935. {
  936. hr = HRESULT_FROM_WIN32(GetLastError());
  937. GlobalUnlock(*phGlobal);
  938. GlobalFree(*phGlobal);
  939. *phGlobal = NULL;
  940. }
  941. }
  942. //
  943. // If we are not tiling the metafile, we draw it exactly once,
  944. // scaled to fit the entire output metafile
  945. //
  946. if (S_OK == hr && FALSE == fTile)
  947. {
  948. RECTL rcBounds = {0, 0, 1000, 1000};
  949. RECTL rcWBounds = {0, 0, 1000, 1000};
  950. SetMapMode(mfdc, MM_ANISOTROPIC);
  951. SetWindowExtEx(mfdc, 1000, 1000, NULL);
  952. SetWindowOrgEx(mfdc, 0, 0, NULL);
  953. hr = m_pViewObject->Draw(DVASPECT_CONTENT, // Aspect
  954. DEF_LINDEX, // LIndex
  955. NULL, // pvAspect
  956. NULL, // ptd
  957. NULL, // hicTargetDev
  958. mfdc, // hdc to draw to
  959. &rcBounds, // rectange to draw to
  960. &rcWBounds, // bounds of our mfdc
  961. NULL, // callback fn
  962. 0); // continue param
  963. }
  964. //
  965. // If we are tiling the metafile (which tests the ability of
  966. // the cache to offset and scale the presentation to a rect within
  967. // a larger metafile rect), we draw it once in each of the four
  968. // corners
  969. //
  970. if (S_OK == hr && TRUE == fTile)
  971. {
  972. RECTL rcBounds;
  973. RECTL rcWBounds = {0, 0, 1000, 1000};
  974. SetMapMode(mfdc, MM_ANISOTROPIC);
  975. SetWindowExtEx(mfdc, 1000, 1000, NULL);
  976. SetWindowOrgEx(mfdc, 0, 0, NULL);
  977. for (int a=0; a < 4 && S_OK == hr; a++)
  978. {
  979. switch(a)
  980. {
  981. case 0: // Upper left hand tile
  982. rcBounds.left = 0;
  983. rcBounds.top = 0;
  984. rcBounds.right = 500;
  985. rcBounds.bottom = 500;
  986. break;
  987. case 1: // Upper right hand tile
  988. rcBounds.left = 500;
  989. rcBounds.top = 0;
  990. rcBounds.right = 1000;
  991. rcBounds.bottom = 500;
  992. break;
  993. case 2: // Lower left hand tile
  994. rcBounds.left = 0;
  995. rcBounds.top = 500;
  996. rcBounds.right = 500;
  997. rcBounds.bottom = 1000;
  998. break;
  999. case 3: // Lower right hand tile
  1000. rcBounds.left = 500;
  1001. rcBounds.top = 500;
  1002. rcBounds.right = 1000;
  1003. rcBounds.bottom = 1000;
  1004. break;
  1005. }
  1006. hr = m_pViewObject->Draw(DVASPECT_CONTENT, // Aspect
  1007. DEF_LINDEX, // LIndex
  1008. NULL, // pvAspect
  1009. NULL, // ptd
  1010. NULL, // hicTargetDev
  1011. mfdc, // hdc to draw to
  1012. &rcBounds, // rectange to draw to
  1013. &rcWBounds, // bounds of our mfdc
  1014. NULL, // callback fn
  1015. 0); // continue param
  1016. }
  1017. }
  1018. //
  1019. // If the draw failed, clean up the metafile DC now
  1020. //
  1021. if (S_OK != hr)
  1022. {
  1023. GlobalUnlock(*phGlobal);
  1024. GlobalFree(*phGlobal);
  1025. HMETAFILE temp = CloseMetaFile(mfdc);
  1026. if (temp)
  1027. {
  1028. DeleteMetaFile(temp);
  1029. }
  1030. }
  1031. //
  1032. // Finish up the metafile and prepare to return it to the caller
  1033. //
  1034. if (S_OK == hr)
  1035. {
  1036. pmfp->hMF = CloseMetaFile(mfdc);
  1037. if (pmfp->hMF)
  1038. {
  1039. GlobalUnlock(*phGlobal);
  1040. }
  1041. else
  1042. {
  1043. hr = HRESULT_FROM_WIN32(GetLastError());
  1044. GlobalUnlock(*phGlobal);
  1045. GlobalFree(*phGlobal);
  1046. *phGlobal = NULL;
  1047. }
  1048. }
  1049. return hr;
  1050. }
  1051. //+----------------------------------------------------------------------------
  1052. //
  1053. // Member: TestInstance::GetCurrentState
  1054. //
  1055. // Synopsis: Returns the state of the unit test (for drawing)
  1056. //
  1057. // Arguments: (none)
  1058. //
  1059. // Returns: HRESULT
  1060. //
  1061. // Notes:
  1062. //
  1063. // History: 04-Sep-94 Davepl Created
  1064. //
  1065. //-----------------------------------------------------------------------------
  1066. TEST_STATE TestInstance::GetCurrentState()
  1067. {
  1068. //
  1069. // In order to avoid race conditions, we have a mutex around the
  1070. // current state of the unit test (required because this member
  1071. // function will be running on the window's thread, not the current
  1072. // test instance thread.)
  1073. //
  1074. DWORD dwResult = WaitForSingleObject(ctest.Mutex(), INFINITE);
  1075. if (WAIT_FAILED == dwResult)
  1076. {
  1077. return INVALID_STATE;
  1078. }
  1079. TEST_STATE tsSnapshot = m_State;
  1080. ReleaseMutex(ctest.Mutex());
  1081. return tsSnapshot;
  1082. }
  1083. //+----------------------------------------------------------------------------
  1084. //
  1085. // Member: TestInstance::SetCurrentState
  1086. //
  1087. // Synopsis: Sets the current (drawing) state of the unit test
  1088. //
  1089. // Arguments: [state] - the state to set
  1090. //
  1091. // Returns: HRESULT
  1092. //
  1093. // Notes:
  1094. //
  1095. // History: 04-Sep-94 Davepl Created
  1096. //
  1097. //-----------------------------------------------------------------------------
  1098. void TestInstance::SetCurrentState(TEST_STATE state)
  1099. {
  1100. //
  1101. // In order to avoid race conditions, we have a mutex around the
  1102. // current state of the unit test (required because this member
  1103. // function will be running on the window's thread, not the current
  1104. // test instance thread.)
  1105. //
  1106. DWORD dwResult = WaitForSingleObject(ctest.Mutex(), INFINITE);
  1107. if (WAIT_FAILED == dwResult)
  1108. {
  1109. return;
  1110. }
  1111. m_State = state;
  1112. ReleaseMutex(ctest.Mutex());
  1113. //
  1114. // Invalid the main window so it will redraw itself with the new
  1115. // state of the test.
  1116. //
  1117. InvalidateRgn(ctest.Window(), NULL, FALSE);
  1118. UpdateWindow(ctest.Window());
  1119. }
  1120. //+----------------------------------------------------------------------------
  1121. //
  1122. // Member: TestInstance::Draw
  1123. //
  1124. // Synopsis: Draws the current state of the unit test
  1125. //
  1126. // Arguments: [hdc] - The DC to draw to
  1127. //
  1128. // Returns: HRESULT
  1129. //
  1130. // Notes: The DC is supplied, but the main window is assumed
  1131. //
  1132. // History: 04-Sep-94 Davepl Created
  1133. //
  1134. //-----------------------------------------------------------------------------
  1135. static char szStarting[] = "Test is starting...";
  1136. static char szInvalid[] = "The state of the test has become invalid...";
  1137. static char szEnumerator[] = "Testing the cache enumerator...";
  1138. static char szSaveReload[] = "Saving and reloading the cache and its data...";
  1139. static char szDataTest[] = "Testing data integrity within the cache...";
  1140. static char szMulti[] = "Testing a large number of simultaneous cache nodes...";
  1141. static char szMetafile[] = "MF -> MF";
  1142. static char szMetafileTiled[] = "MF -> MF (Tiled)";
  1143. static char szDib[] = ""; // Dib contains its own title
  1144. void TestInstance::Draw(HDC hdc)
  1145. {
  1146. //
  1147. // Retrieve the current state of the unit test
  1148. //
  1149. TEST_STATE tsState = GetCurrentState();
  1150. //
  1151. // Clear the window
  1152. //
  1153. RECT rect;
  1154. if (TRUE == GetClientRect(ctest.Window(), &rect))
  1155. {
  1156. FillRect(hdc, &rect, (HBRUSH) GetStockObject(LTGRAY_BRUSH));
  1157. }
  1158. //
  1159. // Draw the current state
  1160. //
  1161. int iBackMode = SetBkMode(hdc, TRANSPARENT);
  1162. switch(tsState)
  1163. {
  1164. case TEST_STARTING:
  1165. TextOut(hdc, 10, 10, szStarting, strlen(szStarting));
  1166. break;
  1167. case TESTING_ENUMERATOR:
  1168. TextOut(hdc, 10, 10, szEnumerator, strlen(szEnumerator));
  1169. break;
  1170. case SAVE_AND_RELOAD:
  1171. TextOut(hdc, 10, 10, szSaveReload, strlen(szSaveReload));
  1172. break;
  1173. case DATA_TEST:
  1174. TextOut(hdc, 10, 10, szDataTest, strlen(szDataTest));
  1175. break;
  1176. case MULTI_CACHE:
  1177. TextOut(hdc, 10, 10, szMulti, strlen(szMulti));
  1178. break;
  1179. case DRAW_METAFILE_NOW:
  1180. case DRAW_METAFILETILED_NOW:
  1181. case DRAW_DIB_NOW:
  1182. case DRAW_DIBTILED_NOW:
  1183. {
  1184. // We know now that we have to draw a metafile, so
  1185. // determine which of the metafiles we should be drawing,
  1186. // and set a handle (so we can reuse the draw code) and
  1187. // the description text appropriately.
  1188. HGLOBAL hMFP;
  1189. char * szDesc;
  1190. if (DRAW_METAFILE_NOW == tsState)
  1191. {
  1192. hMFP = ctest.m_hMFP;
  1193. szDesc = szMetafile;
  1194. }
  1195. else if (DRAW_METAFILETILED_NOW == tsState)
  1196. {
  1197. hMFP = ctest.m_hMFPTILED;
  1198. szDesc = szMetafileTiled;
  1199. }
  1200. else if (DRAW_DIB_NOW == tsState)
  1201. {
  1202. hMFP = ctest.m_hMFPDIB;
  1203. szDesc = szDib;
  1204. }
  1205. else if (DRAW_DIBTILED_NOW == tsState)
  1206. {
  1207. hMFP = ctest.m_hMFPDIBTILED;
  1208. szDesc = szDib;
  1209. }
  1210. TextOut(hdc, 10, 10, szDesc, strlen(szDesc));
  1211. //
  1212. // Now actually draw the metafile to our main window
  1213. //
  1214. if (hMFP)
  1215. {
  1216. METAFILEPICT *pMFP = (METAFILEPICT *) GlobalLock(hMFP);
  1217. if (NULL == pMFP)
  1218. {
  1219. mprintf("Unable to lock metafile handle");
  1220. break;
  1221. }
  1222. int save = SaveDC(hdc);
  1223. SetMapMode(hdc, pMFP->mm);
  1224. SetWindowExtEx(hdc, pMFP->xExt, pMFP->yExt, NULL);
  1225. RECT client;
  1226. GetClientRect(ctest.Window(), &client);
  1227. SetViewportExtEx(hdc, client.right, client.bottom, NULL);
  1228. SetWindowOrgEx(hdc, 0, 0, NULL);
  1229. SetViewportOrgEx(hdc, client.left, client.top, NULL);
  1230. PlayMetaFile(hdc, pMFP->hMF);
  1231. RestoreDC(hdc, save);
  1232. }
  1233. break;
  1234. }
  1235. case INVALID_STATE:
  1236. default:
  1237. TextOut(hdc, 10, 10, szInvalid, strlen(szInvalid));
  1238. break;
  1239. }
  1240. SetBkMode(hdc, iBackMode);
  1241. }