|
|
// This is a multi-threaded app with two primary threads. One
// sits in the message loop, waiting specifically for WM_PAINT
// messages which are generated by the other thread, on which
// the actual unit test runs.
//
// When the window thread receives an update message, it takes
// a snapshot of the unit test state (protected by a mutex),
// and redraws the screen accordingly.
//
// When the unit test thread wants a resource to be drawn in
// the main window, it places the handle to that resource (for
// example, an HMETAFILEPICT) in the ctest object associated
// with the window thread, then fires a screen update. In
// doing so, ownership of the resource is transfered from the
// unit test thread to the window thread. By using this
// mechanism, the window thread can draw the resource at its
// leisure, while the unit test proceeds. The onus is on
// the window thread to clean up any resources which have
// been deposited in its care when it exists.
//
// If the window thread receives a WM_CLOSE message, it must
// first check to see that the unit test thread has completed.
// If not, it spins in a RETRY/CANCEL loop until the unit test
// thread has completed, or until the user selects CANCEL, at
// which point execution proceeds, ignoring the WM_CLOSE.
//
// "OVER-ENGINEERED, AND BUILT TO STAY THAT WAY" (tm)
//
#include "headers.hxx"
#pragma hdrstop
CCacheTestApp ctest; // Application instance
TestInstance inst; // Test instance
//
// Prototype for the entry-point of the unit test thread
//
unsigned long __stdcall testmain(void *);
//+---------------------------------------------------------------------------
//
// Function: WinMain
//
// Synopsis: windows entry point
//
// Arguments: [hInst] --
// [hPrevInst] --
// [lpszCmdLine] --
// [nCmdShow] --
//
// Returns: int
//
// History: 05-Sep-94 davepl Created
//
// Notes:
//
//----------------------------------------------------------------------------
int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpszCmdLine, int nCmdShow) { MSG message;
//
// Initialize the application
//
if (SUCCEEDED(ctest.Initialize(hInst, hPrevInst, lpszCmdLine))) { //
// Show and update the window
//
ShowWindow(ctest.Window(), nCmdShow); UpdateWindow(ctest.Window());
//
// The main message loop
//
while (GetMessage(&message, NULL, NULL, NULL)) { TranslateMessage(&message); DispatchMessage(&message); } } else { return(0); }
return(message.wParam); }
//+---------------------------------------------------------------------------
//
// Member: CCacheTestApp::CCacheTestApp
//
// Synopsis: Constructor
//
// Arguments: (none)
//
// Returns: nothing
//
// History: 05-Sep-94 Davepl Created
//
// Notes:
//
//----------------------------------------------------------------------------
CCacheTestApp::CCacheTestApp () {
}
//+---------------------------------------------------------------------------
//
// Member: CCacheTestApp::Initialize
//
// Synopsis: initializes the application
//
// Arguments: [hInst] -- current instance
// [hPrevInst] -- previous instance
// [lpszCmdLine] -- command line parameters
//
// Returns: HRESULT
//
// History: 05-Sep-94 Davepl Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CCacheTestApp::Initialize (HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpszCmdLine) { HRESULT hr = S_OK;
//
// Register the window class
//
if (hPrevInst == NULL) { WNDCLASS wndclass;
wndclass.style = 0; wndclass.lpfnWndProc = CacheTestAppWndProc;
wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0;
wndclass.hInstance = hInst; wndclass.hIcon = LoadIcon(hInst, IDI_EXCLAMATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = CTESTAPPCLASS;
if (RegisterClass(&wndclass) == 0) { hr = HRESULT_FROM_WIN32(GetLastError()); } }
//
// Create the mutex
//
m_hMutex = CreateMutex(NULL, FALSE, NULL); if (NULL == m_hMutex) { hr = HRESULT_FROM_WIN32(GetLastError()); }
//
// Create the window
//
if (SUCCEEDED(hr)) { if ((m_hWnd = CreateWindowEx(0L, CTESTAPPCLASS, CTESTAPPTITLE, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInst, NULL)) == NULL) { hr = HRESULT_FROM_WIN32(GetLastError()); } }
return(hr); }
//+---------------------------------------------------------------------------
//
// Member: CCacheTestApp::~CCacheTestApp
//
// Synopsis: Destructor
//
// Arguments: (none)
//
// Returns: nothing
//
// History: 05-Sep-94 Davepl Created
//
// Notes:
//
//----------------------------------------------------------------------------
CCacheTestApp::~CCacheTestApp () {
}
//+---------------------------------------------------------------------------
//
// Function: CacheTestAppWndProc
//
// Synopsis: window procedure
//
// Arguments: [hWnd] -- window
// [message] -- message id
// [wParam] -- parameter
// [lParam] -- parameter
//
// Returns: LRESULT
//
// History: 05-Sep-94 Davepl Created
//
// Notes:
//
//----------------------------------------------------------------------------
LRESULT FAR PASCAL CacheTestAppWndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { //
// Process the messages
//
switch (message) { case WM_CREATE:
//
// The unit test window is opening. Create another thread
// on which the unit test itself runs, while this thread
// continues to spin, waiting for redraws, close, and so
// on...
//
ctest.m_hTest = CreateThread(NULL, 0, testmain, NULL, 0, &ctest.m_dwThreadID);
if (NULL == ctest.m_hTest) { mprintf("Unable to begin unit test\n"); PostQuitMessage(0); }
break;
case WM_PAINT: { PAINTSTRUCT ps; HDC hDC;
//
// Get the DC for painting
//
hDC = BeginPaint(hWnd, &ps); if (hDC) { //
// Draw the metafile
//
inst.Draw(hDC);
EndPaint(hWnd, &ps); } } break;
case WM_SIZE:
//
// Invalidate the rectangle
//
InvalidateRect(hWnd, NULL, TRUE); return DefWindowProc(hWnd, message, wParam, lParam); break;
case WM_CLOSE:
{ //
// The user has tried to exit the main program. Before we
// can shut down, we must wait until the child thread has
// completed. We allow the user to keep retrying on the
// thread, or to "cancel" and wait until later. We do not
// provide the option of terminating the child thread while
// it is still busy.
//
DWORD dwStatus = 0;
if (FALSE == GetExitCodeThread(ctest.m_hTest, &dwStatus)) { mprintf("Could not get thread information!"); break; } else { INT response = IDRETRY;
while (STILL_ACTIVE == dwStatus) { response = MessageBox(ctest.Window(), "The child thread has not yet completed.", "Cannot Shutdown", MB_RETRYCANCEL);
if (IDCANCEL == response) { break; } } } //
// Destroy the window if the child has gone away
//
if (STILL_ACTIVE != dwStatus) { DestroyWindow(hWnd); }
break; }
case WM_DESTROY: PostQuitMessage(0); break;
default: return DefWindowProc(hWnd, message, wParam, lParam); }
return NULL; }
//+----------------------------------------------------------------------------
//
// Member:
//
// Synopsis:
//
// Arguments:
//
// Returns: HRESULT
//
// Notes:
//
// History: 23-Aug-94 Davepl Created
//
//-----------------------------------------------------------------------------
unsigned long __stdcall testmain(void *) { HRESULT hr;
hr = inst.CreateAndInit( OLESTR("mystg") );
if (S_OK != hr) { mprintf("Cache Unit Test Failed [CreateAndInit] hr = %x\n", hr); goto exit; }
hr = inst.EnumeratorTest(); if (S_OK != hr) { mprintf("Cache Unit Test Failed [EnumeratorTest] hr = %x\n", hr); goto exit; }
hr = inst.MultiCache(50); if (S_OK != hr) { mprintf("Cache Unit Test Failed [MultiCache] hr = %x\n", hr); goto exit; }
hr = inst.CacheDataTest("TIGER.BMP", "TIGERNPH.WMF"); if (S_OK != hr) { mprintf("Cache Unit Test Failed [CacheDataTest] hr = %x\n", hr); goto exit; }
exit:
PostMessage(ctest.Window(), WM_CLOSE, (WPARAM) hr, 0); return (ULONG) hr;
}
//+----------------------------------------------------------------------------
//
// Member: TestInstance::TestInstance
//
// Synopsis: Constructor
//
// Arguments:
//
// Returns:
//
// Notes:
//
// History: 23-Aug-94 Davepl Created
//
//-----------------------------------------------------------------------------
TestInstance::TestInstance() {
m_pStorage = NULL; m_pPersistStorage = NULL; m_pOleCache = NULL; m_pOleCache2 = NULL; m_pDataObject = NULL; m_pViewObject = NULL; m_State = TEST_STARTING; }
TestInstance::~TestInstance() { //
// Release our interface pointers
//
if (m_pDataObject) { m_pDataObject->Release(); }
if (m_pViewObject) { m_pViewObject->Release(); }
if (m_pPersistStorage) { m_pPersistStorage->Release(); }
if (m_pOleCache2) { m_pOleCache2->Release(); }
if (m_pOleCache) { m_pOleCache->Release(); }
if (m_pStorage) { m_pStorage->Release(); } }
//+----------------------------------------------------------------------------
//
// Member: TestInstance::CreateAndInit
//
// Synopsis: Creates a cache and sets up internal interface ptrs
//
// Arguments: (none)
//
// Returns: HRESULT
//
// Notes:
//
// History: 23-Aug-94 Davepl Created
//
//-----------------------------------------------------------------------------
HRESULT TestInstance::CreateAndInit(LPOLESTR lpwszStgName) { HRESULT hr;
TraceLog Log(this, "TestInstance::CreateAndInit", GS_CACHE, VB_MINIMAL); Log.OnEntry (" ( %p ) \n", lpwszStgName); Log.OnExit (" ( %X ) \n", &hr); //
// Create the storage on which we will instantiate our cache
//
// BUGBUG use correct strcpy fn
wcscpy(m_wszStorage, lpwszStgName);
hr = StgCreateDocfile(lpwszStgName, STGM_DIRECT | STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE, 0, &m_pStorage);
//
// Create a Data Cache on our IStorage
//
if (S_OK == hr) { hr = CreateDataCache(NULL, CLSID_NULL, IID_IPersistStorage, (void **)&m_pPersistStorage); }
if (S_OK == hr) { hr = m_pPersistStorage->InitNew(m_pStorage); }
//
// Get an IOleCache interface pointer to the cache
//
if (S_OK == hr) { hr = m_pPersistStorage->QueryInterface(IID_IOleCache, (void **) &m_pOleCache); }
//
// Get an IOleCache2 interface pointer to the cache
//
if (S_OK == hr) { hr = m_pPersistStorage->QueryInterface(IID_IOleCache2, (void **) &m_pOleCache2); }
//
// Get an IViewObject interface pointer to the cache
//
if (S_OK == hr) { hr = m_pPersistStorage->QueryInterface(IID_IViewObject, (void **) &m_pViewObject); }
//
// Get an IDataObject interface pointer to the cache
//
if (S_OK == hr) { hr = m_pPersistStorage->QueryInterface(IID_IDataObject, (void **) &m_pDataObject); }
return hr; }
//+----------------------------------------------------------------------------
//
// Member: TestInstance::SaveAndReload
//
// Synopsis: Saves the cache to its storage and reloads it
// right back.
//
// Arguments: (none)
//
// Returns: HRESULT
//
// Notes: Once saved, the behavior of DiscardCache will
// change, since each node present at the time of
// save will have a stream from which it can demand
// load its data.
//
// Since each interface pointer is released and
// reaquired, the pointer values will (likely) change
// during this call; hence, so _not_ cache the pointers
// locally around this call.
//
// History: 23-Aug-94 Davepl Created
//
//-----------------------------------------------------------------------------
HRESULT TestInstance::SaveAndReload() { HRESULT hr;
TraceLog Log(NULL, "TestInstance::SaveAndReload", GS_CACHE, VB_MINIMAL); Log.OnEntry (); Log.OnExit (" ( %X )\n", &hr);
SetCurrentState(SAVE_AND_RELOAD);
hr = m_pPersistStorage->Save(m_pStorage, TRUE);
if (S_OK == hr) { hr = m_pPersistStorage->SaveCompleted(NULL); }
// Release our hold on the storage and the cache
if (S_OK == hr) { m_pViewObject->Release(); m_pViewObject = NULL; m_pDataObject->Release(); m_pDataObject = NULL;
m_pStorage->Release(); m_pStorage = NULL;
m_pPersistStorage->Release(); m_pPersistStorage = NULL;
m_pOleCache2->Release(); m_pOleCache2 = NULL;
m_pOleCache->Release(); m_pOleCache = NULL;
//
// Reload the cache and QI to get our interfaces back
//
hr = StgOpenStorage(m_wszStorage, NULL, STGM_DIRECT | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &m_pStorage);
//
// Create a Data Cache on our IStorage
//
if (S_OK == hr) { hr = CreateDataCache(NULL, CLSID_NULL, IID_IPersistStorage, (void **)&m_pPersistStorage); } if (S_OK == hr) { hr = m_pPersistStorage->Load(m_pStorage); }
//
// Get an IOleCache interface pointer to the cache
//
if (S_OK == hr) { hr = m_pPersistStorage->QueryInterface(IID_IOleCache, (void **) &m_pOleCache); } //
// Get an IOleCache2 interface pointer to the cache
//
if (S_OK == hr) { hr = m_pPersistStorage->QueryInterface(IID_IOleCache2, (void **) &m_pOleCache2); }
//
// Get an IViewObject interface pointer to the cache
//
if (S_OK == hr) { hr = m_pPersistStorage->QueryInterface(IID_IViewObject, (void **) &m_pViewObject); }
//
// Get an IDataObject interface pointer to the cache
//
if (S_OK == hr) { hr = m_pPersistStorage->QueryInterface(IID_IDataObject, (void **) &m_pDataObject); } }
return hr; }
//+----------------------------------------------------------------------------
//
// Member: TestInstance::CacheDataTest
//
// Synopsis: Checks the cache for data integrity
//
// Arguments: lpszBMPFileName - Name of .BMP file to use for test
// lpszWMFFileName - Name of .WMF file to use for test
//
// Returns: HRESULT
//
// Notes:
//
// History: 04-Sep-94 Davepl Created
//
//-----------------------------------------------------------------------------
HRESULT TestInstance::CacheDataTest(char * lpszBMPFileName, char * lpszWMFFileName) { HRESULT hr = S_OK;
TraceLog Log(NULL, "TestInstance::CacheDataTest", GS_CACHE, VB_MINIMAL); Log.OnEntry (" ( BMP=%s, WMF=%s )\n", lpszBMPFileName, lpszWMFFileName); Log.OnExit (" ( %X )\n", &hr);
SetCurrentState(DATA_TEST);
CBitmapFile bmpFile; HGLOBAL hDIB = NULL; //
// Allocate an hglobal to hold our metafilepict structure
//
HGLOBAL hMFPICT = GlobalAlloc(GMEM_FIXED, sizeof(METAFILEPICT)); if (NULL == hMFPICT) { hr = HRESULT_FROM_WIN32(GetLastError()); } METAFILEPICT * pMFPICT = (METAFILEPICT *) hMFPICT;
//
// Load the bitmap from disk
//
if (S_OK == hr) { hr = bmpFile.LoadBitmapFile(lpszBMPFileName); }
//
// Create a DIB on an HGLOBAL from the bitmap
//
if (S_OK == hr) { hr = bmpFile.CreateDIBInHGlobal(&hDIB); }
//
// Add DIB and MF nodes to the cache
//
DWORD dwDIBCon; DWORD dwMFCon;
if (S_OK == hr) { hr = AddDIBCacheNode(&dwDIBCon); }
if (S_OK == hr) { hr = AddMFCacheNode(&dwMFCon); }
//
// Load the metafile from disk, then set up the
// METAFILEPICT structure
//
if (S_OK == hr) { pMFPICT->hMF = GetMetaFileA(lpszWMFFileName); if (NULL == pMFPICT->hMF) { hr = HRESULT_FROM_WIN32(GetLastError()); } else { //
// We deem the metafile to have the same extents
// as the the DIB. This is completely arbitrary,
// but might aid in tracking down extents problems.
// After all, we have to pick _some_ value, so it
// might as well be a useful one...
//
pMFPICT->xExt = ConvWidthInPelsToLHM(NULL, bmpFile.GetDIBHeight()); pMFPICT->yExt = ConvHeightInPelsToLHM(NULL, bmpFile.GetDIBWidth()); pMFPICT->mm = MM_ANISOTROPIC; } }
//
// Place the nodes in the cache. We keep ownership of the handles,
// which will force the cache to duplicate it. We can then compare
// our original with whatever we later get back from the cache.
//
FORMATETC fetcDIB = { CF_DIB, NULL, DVASPECT_CONTENT, DEF_LINDEX, TYMED_HGLOBAL };
STGMEDIUM stgmDIB;
FORMATETC fetcMF = { CF_METAFILEPICT, NULL, DVASPECT_CONTENT, DEF_LINDEX, TYMED_MFPICT };
STGMEDIUM stgmMF;
if (S_OK == hr) { stgmDIB.tymed = TYMED_HGLOBAL; stgmDIB.hGlobal = hDIB;
hr = m_pOleCache->SetData(&fetcDIB, &stgmDIB, FALSE); }
if (S_OK == hr) { stgmMF.tymed = TYMED_MFPICT, stgmMF.hMetaFilePict = hMFPICT;
hr = m_pOleCache->SetData(&fetcMF, &stgmMF, FALSE); }
//
// If we were able to place the data in the cache, check
// to make sure whatever is in the cache matches our
// original.
//
if (S_OK == hr) { hr = CompareDIB(hDIB); if (S_OK == hr) { hr = CompareMF(hMFPICT); } }
//
// Save and Reload the cache to test persistance
//
if (S_OK == hr) { hr = SaveAndReload(); }
if (S_OK == hr) { SetCurrentState(DATA_TEST); }
//
// Compare the data again
//
if (S_OK == hr) { hr = CompareDIB(hDIB); if (S_OK == hr) { hr = CompareMF(hMFPICT); } }
//
// Discard the cache.
//
if (S_OK == hr) { hr = m_pOleCache2->DiscardCache(DISCARDCACHE_NOSAVE); }
//
// Now compare again against the current presentations,
// which would have to be demand-loaded after the discard.
//
if (S_OK == hr) { hr = CompareDIB(hDIB); if (S_OK == hr) { hr = CompareMF(hMFPICT); } }
//
// Try to draw the cache's best presentation (which should
// be metafile at this point) into a metafile DC which we
// will then hand off to the window thread for drawing.
//
if (S_OK == hr) { hr = DrawCacheToMetaFilePict(&ctest.m_hMFP, FALSE); if (S_OK == hr) { SetCurrentState(DRAW_METAFILE_NOW); } }
//
// Now draw the metafile tiled 4 times into the display
// metafile, and hand it off...
//
if (S_OK == hr) { hr = DrawCacheToMetaFilePict(&ctest.m_hMFPTILED, TRUE); if (S_OK == hr) { SetCurrentState(DRAW_METAFILETILED_NOW); } }
//
// Uncache the metafile node, which will leave the DIB node
// as the best (and only) node left for drawing
//
if (S_OK == hr) { hr = UncacheFormat(CF_METAFILEPICT); }
//
// Now draw the DIB into a metafile and hand that off
// to the window thread for drawing
//
if (S_OK == hr) { hr = DrawCacheToMetaFilePict(&ctest.m_hMFPDIB, FALSE); if (S_OK == hr) { SetCurrentState(DRAW_DIB_NOW); } }
//
// Now draw the DIB again, this time tiled into the mf
//
if (S_OK == hr) { hr = DrawCacheToMetaFilePict(&ctest.m_hMFPDIBTILED, TRUE); if (S_OK == hr) { SetCurrentState(DRAW_DIBTILED_NOW); } }
//
// Cleanup our local DIB
//
if (hDIB) { GlobalFree(hDIB); }
//
// Cleaup our local metafile
//
if (pMFPICT) { if (pMFPICT->hMF) { if (FALSE == DeleteMetaFile(pMFPICT->hMF)) { hr = HRESULT_FROM_WIN32(GetLastError()); } }
GlobalFree(hMFPICT); }
return hr; }
HRESULT TestInstance::CompareDIB(HGLOBAL hDIB) { return S_OK; }
HRESULT TestInstance::CompareMF(HMETAFILEPICT hMFPICT) { return S_OK; }
//+----------------------------------------------------------------------------
//
// Member: TestInstance::DrawCacheToMetaFilePict
//
// Synopsis: Draws the cache's current best presentation to
// a metafile, contained in a metafilepict structure,
// which is allocated off of the hGlobal pointer passed
// in by the caller
//
// Arguments: [phGlobal] - The ptr to the hglobal to allocate on
// [fTile] - If true, the pres is tiled into the mf
//
// Returns: HRESULT
//
// Notes:
//
// History: 06-Sep-94 Davepl Created
//
//-----------------------------------------------------------------------------
HRESULT TestInstance::DrawCacheToMetaFilePict(HGLOBAL *phGlobal, BOOL fTile) { HRESULT hr = S_OK;
TraceLog Log(NULL, "TestInstance::DrawCacheToMetaFilePict", GS_CACHE, VB_MINIMAL); Log.OnEntry (" ( %p, %d )\n", phGlobal, fTile); Log.OnExit (" ( %X )\n", &hr);
//
// Create a metafile, and have the cache draw its metafile
// into _our_ metafile.
//
//
// First, set up the METAFILEPICT structure.
// Since ANISOTROPIC mode allows arbitrary scaling extents, we
// pick 1000 as a nice arbitrary size.
//
//
METAFILEPICT *pmfp = NULL; if (S_OK == hr) { *phGlobal = GlobalAlloc(GMEM_FIXED, sizeof(METAFILEPICT)); if (NULL == *phGlobal) { hr = HRESULT_FROM_WIN32(GetLastError()); } else { pmfp = (METAFILEPICT *) GlobalLock(*phGlobal); if (NULL == pmfp) { GlobalFree(*phGlobal); *phGlobal = NULL; hr = HRESULT_FROM_WIN32(GetLastError()); } else { pmfp->xExt = 1000; pmfp->yExt = 1000; pmfp->mm = MM_ANISOTROPIC; } } }
//
// Now create the metafile within the METAFILEPICT structure,
// and ask the cache to draw to it.
//
HDC mfdc; if (S_OK == hr) { mfdc = CreateMetaFile(NULL); if (NULL == mfdc) { hr = HRESULT_FROM_WIN32(GetLastError()); GlobalUnlock(*phGlobal); GlobalFree(*phGlobal); *phGlobal = NULL; } }
//
// If we are not tiling the metafile, we draw it exactly once,
// scaled to fit the entire output metafile
//
if (S_OK == hr && FALSE == fTile) { RECTL rcBounds = {0, 0, 1000, 1000}; RECTL rcWBounds = {0, 0, 1000, 1000};
SetMapMode(mfdc, MM_ANISOTROPIC); SetWindowExtEx(mfdc, 1000, 1000, NULL); SetWindowOrgEx(mfdc, 0, 0, NULL);
hr = m_pViewObject->Draw(DVASPECT_CONTENT, // Aspect
DEF_LINDEX, // LIndex
NULL, // pvAspect
NULL, // ptd
NULL, // hicTargetDev
mfdc, // hdc to draw to
&rcBounds, // rectange to draw to
&rcWBounds, // bounds of our mfdc
NULL, // callback fn
0); // continue param
}
//
// If we are tiling the metafile (which tests the ability of
// the cache to offset and scale the presentation to a rect within
// a larger metafile rect), we draw it once in each of the four
// corners
//
if (S_OK == hr && TRUE == fTile) { RECTL rcBounds; RECTL rcWBounds = {0, 0, 1000, 1000};
SetMapMode(mfdc, MM_ANISOTROPIC); SetWindowExtEx(mfdc, 1000, 1000, NULL); SetWindowOrgEx(mfdc, 0, 0, NULL);
for (int a=0; a < 4 && S_OK == hr; a++) { switch(a) { case 0: // Upper left hand tile
rcBounds.left = 0; rcBounds.top = 0; rcBounds.right = 500; rcBounds.bottom = 500; break;
case 1: // Upper right hand tile
rcBounds.left = 500; rcBounds.top = 0; rcBounds.right = 1000; rcBounds.bottom = 500; break;
case 2: // Lower left hand tile
rcBounds.left = 0; rcBounds.top = 500; rcBounds.right = 500; rcBounds.bottom = 1000; break;
case 3: // Lower right hand tile
rcBounds.left = 500; rcBounds.top = 500; rcBounds.right = 1000; rcBounds.bottom = 1000; break; } hr = m_pViewObject->Draw(DVASPECT_CONTENT, // Aspect
DEF_LINDEX, // LIndex
NULL, // pvAspect
NULL, // ptd
NULL, // hicTargetDev
mfdc, // hdc to draw to
&rcBounds, // rectange to draw to
&rcWBounds, // bounds of our mfdc
NULL, // callback fn
0); // continue param
} } //
// If the draw failed, clean up the metafile DC now
//
if (S_OK != hr) { GlobalUnlock(*phGlobal); GlobalFree(*phGlobal);
HMETAFILE temp = CloseMetaFile(mfdc); if (temp) { DeleteMetaFile(temp); } }
//
// Finish up the metafile and prepare to return it to the caller
//
if (S_OK == hr) { pmfp->hMF = CloseMetaFile(mfdc);
if (pmfp->hMF) { GlobalUnlock(*phGlobal); } else { hr = HRESULT_FROM_WIN32(GetLastError()); GlobalUnlock(*phGlobal); GlobalFree(*phGlobal); *phGlobal = NULL; } }
return hr; }
//+----------------------------------------------------------------------------
//
// Member: TestInstance::GetCurrentState
//
// Synopsis: Returns the state of the unit test (for drawing)
//
// Arguments: (none)
//
// Returns: HRESULT
//
// Notes:
//
// History: 04-Sep-94 Davepl Created
//
//-----------------------------------------------------------------------------
TEST_STATE TestInstance::GetCurrentState() { //
// In order to avoid race conditions, we have a mutex around the
// current state of the unit test (required because this member
// function will be running on the window's thread, not the current
// test instance thread.)
//
DWORD dwResult = WaitForSingleObject(ctest.Mutex(), INFINITE); if (WAIT_FAILED == dwResult) { return INVALID_STATE; }
TEST_STATE tsSnapshot = m_State;
ReleaseMutex(ctest.Mutex());
return tsSnapshot; }
//+----------------------------------------------------------------------------
//
// Member: TestInstance::SetCurrentState
//
// Synopsis: Sets the current (drawing) state of the unit test
//
// Arguments: [state] - the state to set
//
// Returns: HRESULT
//
// Notes:
//
// History: 04-Sep-94 Davepl Created
//
//-----------------------------------------------------------------------------
void TestInstance::SetCurrentState(TEST_STATE state) { //
// In order to avoid race conditions, we have a mutex around the
// current state of the unit test (required because this member
// function will be running on the window's thread, not the current
// test instance thread.)
//
DWORD dwResult = WaitForSingleObject(ctest.Mutex(), INFINITE); if (WAIT_FAILED == dwResult) { return; }
m_State = state;
ReleaseMutex(ctest.Mutex());
//
// Invalid the main window so it will redraw itself with the new
// state of the test.
//
InvalidateRgn(ctest.Window(), NULL, FALSE); UpdateWindow(ctest.Window()); }
//+----------------------------------------------------------------------------
//
// Member: TestInstance::Draw
//
// Synopsis: Draws the current state of the unit test
//
// Arguments: [hdc] - The DC to draw to
//
// Returns: HRESULT
//
// Notes: The DC is supplied, but the main window is assumed
//
// History: 04-Sep-94 Davepl Created
//
//-----------------------------------------------------------------------------
static char szStarting[] = "Test is starting..."; static char szInvalid[] = "The state of the test has become invalid..."; static char szEnumerator[] = "Testing the cache enumerator..."; static char szSaveReload[] = "Saving and reloading the cache and its data..."; static char szDataTest[] = "Testing data integrity within the cache..."; static char szMulti[] = "Testing a large number of simultaneous cache nodes..."; static char szMetafile[] = "MF -> MF"; static char szMetafileTiled[] = "MF -> MF (Tiled)"; static char szDib[] = ""; // Dib contains its own title
void TestInstance::Draw(HDC hdc) { //
// Retrieve the current state of the unit test
//
TEST_STATE tsState = GetCurrentState();
//
// Clear the window
//
RECT rect; if (TRUE == GetClientRect(ctest.Window(), &rect)) { FillRect(hdc, &rect, (HBRUSH) GetStockObject(LTGRAY_BRUSH)); }
//
// Draw the current state
//
int iBackMode = SetBkMode(hdc, TRANSPARENT);
switch(tsState) { case TEST_STARTING:
TextOut(hdc, 10, 10, szStarting, strlen(szStarting)); break;
case TESTING_ENUMERATOR: TextOut(hdc, 10, 10, szEnumerator, strlen(szEnumerator)); break;
case SAVE_AND_RELOAD:
TextOut(hdc, 10, 10, szSaveReload, strlen(szSaveReload)); break;
case DATA_TEST:
TextOut(hdc, 10, 10, szDataTest, strlen(szDataTest)); break;
case MULTI_CACHE:
TextOut(hdc, 10, 10, szMulti, strlen(szMulti)); break;
case DRAW_METAFILE_NOW: case DRAW_METAFILETILED_NOW: case DRAW_DIB_NOW: case DRAW_DIBTILED_NOW: { // We know now that we have to draw a metafile, so
// determine which of the metafiles we should be drawing,
// and set a handle (so we can reuse the draw code) and
// the description text appropriately.
HGLOBAL hMFP; char * szDesc; if (DRAW_METAFILE_NOW == tsState) { hMFP = ctest.m_hMFP; szDesc = szMetafile; } else if (DRAW_METAFILETILED_NOW == tsState) { hMFP = ctest.m_hMFPTILED; szDesc = szMetafileTiled; } else if (DRAW_DIB_NOW == tsState) { hMFP = ctest.m_hMFPDIB; szDesc = szDib; } else if (DRAW_DIBTILED_NOW == tsState) { hMFP = ctest.m_hMFPDIBTILED; szDesc = szDib; }
TextOut(hdc, 10, 10, szDesc, strlen(szDesc)); //
// Now actually draw the metafile to our main window
//
if (hMFP) { METAFILEPICT *pMFP = (METAFILEPICT *) GlobalLock(hMFP); if (NULL == pMFP) { mprintf("Unable to lock metafile handle"); break; }
int save = SaveDC(hdc);
SetMapMode(hdc, pMFP->mm); SetWindowExtEx(hdc, pMFP->xExt, pMFP->yExt, NULL); RECT client; GetClientRect(ctest.Window(), &client);
SetViewportExtEx(hdc, client.right, client.bottom, NULL); SetWindowOrgEx(hdc, 0, 0, NULL); SetViewportOrgEx(hdc, client.left, client.top, NULL); PlayMetaFile(hdc, pMFP->hMF); RestoreDC(hdc, save);
} break; }
case INVALID_STATE: default:
TextOut(hdc, 10, 10, szInvalid, strlen(szInvalid)); break;
}
SetBkMode(hdc, iBackMode);
}
|