DATAOBJ.CPP
/* 
 * DATAOBJ.CPP 
 * Data Object Chapter 19 
 * 
 * Implementation of CDataObject and CImpIDataObject that work 
 * in either an EXE or DLL. 
 * 
 * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved 
 * 
 * Kraig Brockschmidt, Microsoft 
 * Internet  :  kraigb@microsoft.com 
 * Compuserve:  >INTERNET:kraigb@microsoft.com 
 */ 
 
 
#include "dataobj.h" 
 
extern HINSTANCE   g_hInst; 
 
DWORD              g_dwID=0; 
 
//Names of data sizes 
static TCHAR * rgszSize[3]={TEXT("Small"), TEXT("Medium") 
    , TEXT("Large")}; 
 
 
 
/* 
 * CDataObject::CDataObject 
 * CDataObject::~CDataObject 
 * 
 * Parameters (Constructor): 
 *  pUnkOuter       LPUNKNOWN of controlling unknown, if it exists. 
 *  pfnDestroy      PFNDESTROYED to call when object is destroyed. 
 *  iSize           UINT specifying the size of the data set to use. 
 */ 
 
CDataObject::CDataObject(LPUNKNOWN pUnkOuter 
    , PFNDESTROYED pfnDestroy, UINT iSize) 
    { 
    UINT        i; 
 
    m_cRef=0; 
    m_pUnkOuter=pUnkOuter; 
    m_pfnDestroy=pfnDestroy; 
    m_iSize=iSize; 
 
    m_hWndAdvise=NULL; 
    m_dwAdvFlags=ADVF_NODATA; 
 
    //NULL any contained interfaces initially. 
    m_pImpIDataObject=NULL; 
    m_pIDataAdviseHolder=NULL; 
 
    //Initilize the FORMATETCs arrays we use for EnumFormatEtc 
    m_cfeGet=CFORMATETCGET; 
 
    SETDefFormatEtc(m_rgfeGet[0], CF_METAFILEPICT, TYMED_MFPICT); 
    SETDefFormatEtc(m_rgfeGet[1], CF_BITMAP, TYMED_GDI); 
    SETDefFormatEtc(m_rgfeGet[2], CF_TEXT, TYMED_HGLOBAL); 
 
    for (i=0; i < DOSIZE_CSIZES; i++) 
        m_rghBmp[i]=NULL; 
 
    return; 
    } 
 
 
CDataObject::~CDataObject(void) 
    { 
    UINT        i; 
 
    for (i=0; i < DOSIZE_CSIZES; i++) 
        { 
        if (NULL!=m_rghBmp[i]) 
            DeleteObject(m_rghBmp[i]); 
        } 
 
    ReleaseInterface(m_pIDataAdviseHolder); 
    DeleteInterfaceImp(m_pImpIDataObject); 
 
    if (NULL!=m_hWndAdvise) 
        DestroyWindow(m_hWndAdvise); 
 
    return; 
    } 
 
 
 
/* 
 * CDataObject::Init 
 * 
 * Purpose: 
 *  Performs any intiailization of a CDataObject that's prone to 
 *  failure that we also use internally before exposing the 
 *  object outside. 
 * 
 * Parameters: 
 *  None 
 * 
 * Return Value: 
 *  BOOL            TRUE if the function is successful, 
 *                  FALSE otherwise. 
 */ 
 
BOOL CDataObject::Init(void) 
    { 
    LPUNKNOWN       pIUnknown=this; 
    UINT            i; 
    TCHAR           szTemp[80]; 
    UINT            cy; 
 
    if (NULL!=m_pUnkOuter) 
        pIUnknown=m_pUnkOuter; 
 
    //Allocate contained interfaces. 
    m_pImpIDataObject=new CImpIDataObject(this, pIUnknown); 
 
    if (NULL==m_pImpIDataObject) 
        return FALSE; 
 
    for (i=0; i < DOSIZE_CSIZES; i++) 
        { 
        m_rghBmp[i]=LoadBitmap(g_hInst, MAKEINTRESOURCE(i+IDB_MIN)); 
 
        if (NULL==m_rghBmp[i]) 
            return FALSE; 
        } 
 
 
    /* 
     * Register the Advise window class first time through 
     * (g_dwID==0) 
     */ 
 
    if (0L==g_dwID) 
        { 
        WNDCLASS    wc; 
 
        wc.style          = CS_HREDRAW | CS_VREDRAW; 
        wc.lpfnWndProc    = AdvisorWndProc; 
        wc.cbClsExtra     = 0; 
        wc.cbWndExtra     = sizeof(PCDataObject); 
        wc.hInstance      = g_hInst; 
        wc.hIcon          = LoadIcon(g_hInst 
            , MAKEINTRESOURCE(IDR_ADVISORICON)); 
        wc.hCursor        = NULL; 
        wc.hbrBackground  = (HBRUSH)(COLOR_WINDOW + 1); 
        wc.lpszMenuName   = MAKEINTRESOURCE(IDR_MENU); 
        wc.lpszClassName  = TEXT("Advisor"); 
 
        if (!RegisterClass(&wc)) 
            return FALSE; 
        } 
 
    /* 
     * Create an advise window with a unique caption: 
     * "<size> <module> Advisor #xx" where <size> is Small, 
     * Medium, or Large, <module> is EXE or DLL, and xx is 
     * counted globally every time a CDataObject is created. 
     */ 
 
    g_dwID++; 
   #ifdef EXEDATAOBJECT 
    wsprintf(szTemp, TEXT("%s EXE Advisor #%lu") 
        , (LPTSTR)rgszSize[m_iSize], g_dwID); 
   #else 
    wsprintf(szTemp, TEXT("%s DLL Advisor #%lu") 
        , (LPTSTR)rgszSize[m_iSize], g_dwID); 
   #endif 
 
    cy=(GetSystemMetrics(SM_CYBORDER)*2)+GetSystemMetrics(SM_CYMENU) 
        + GetSystemMetrics(SM_CYCAPTION); 
 
    m_hWndAdvise=CreateWindow(TEXT("Advisor"), szTemp 
        , WS_OVERLAPPED | WS_CAPTION | WS_MINIMIZEBOX | WS_BORDER 
        | WS_VISIBLE, 400, 35+(g_dwID*(cy+30)), 200, cy 
        , HWND_DESKTOP, NULL, g_hInst, this); 
 
    if (NULL==m_hWndAdvise) 
        return FALSE; 
 
    return TRUE; 
    } 
 
 
 
 
 
/* 
 * CDataObject::QueryInterface 
 * CDataObject::AddRef 
 * CDataObject::Release 
 * 
 * Purpose: 
 *  IUnknown members for CDataObject object. 
 */ 
 
STDMETHODIMP CDataObject::QueryInterface(REFIID riid, PPVOID ppv) 
    { 
    *ppv=NULL; 
 
    if (IID_IUnknown==riid) 
        *ppv=this; 
 
    if (IID_IDataObject==riid) 
        *ppv=m_pImpIDataObject; 
 
    if (NULL!=*ppv) 
        { 
        ((LPUNKNOWN)*ppv)->AddRef(); 
        return NOERROR; 
        } 
 
    return ResultFromScode(E_NOINTERFACE); 
    } 
 
 
STDMETHODIMP_(ULONG) CDataObject::AddRef(void) 
    { 
    return ++m_cRef; 
    } 
 
 
STDMETHODIMP_(ULONG) CDataObject::Release(void) 
    { 
    if (0!=--m_cRef) 
        return m_cRef; 
 
    if (NULL!=m_pfnDestroy) 
        (*m_pfnDestroy)(); 
 
    delete this; 
    return 0; 
    } 
 
 
 
 
 
/* 
 * AdvisorWndProc 
 * 
 * Purpose: 
 *  Standard window class procedure. 
 */ 
 
LRESULT APIENTRY AdvisorWndProc(HWND hWnd, UINT iMsg 
    , WPARAM wParam, LPARAM lParam) 
    { 
    PCDataObject    pDO; 
    DWORD           i; 
    DWORD           iAdvise; 
    DWORD           dwTime; 
    DWORD           dwAvg; 
    TCHAR           szTime[128]; 
    TCHAR           szTitle[80]; 
    HCURSOR         hCur, hCurT; 
 
    pDO=(PCDataObject)GetWindowLong(hWnd, 0); 
 
    switch (iMsg) 
        { 
        case WM_NCCREATE: 
            pDO=(PCDataObject)(((LPCREATESTRUCT)lParam) 
                ->lpCreateParams); 
            SetWindowLong(hWnd, 0, (LONG)pDO); 
            return (DefWindowProc(hWnd, iMsg, wParam, lParam)); 
 
        case WM_CLOSE: 
            //Forbid task manager from closing us. 
            return 0L; 
 
        case WM_COMMAND: 
            if (NULL==pDO->m_pIDataAdviseHolder) 
                break; 
 
            //Send IAdviseSink::OnDataChange many times. 
            i=(DWORD)(LOWORD(wParam)-IDM_ADVISEITERATIONSMIN+1); 
            iAdvise=(i*i)*16; 
 
            hCur=LoadCursor(NULL, MAKEINTRESOURCE(IDC_WAIT)); 
            hCurT=SetCursor(hCur); 
            ShowCursor(TRUE); 
 
            dwTime=GetTickCount(); 
 
            i=0; 
            while (TRUE) 
                { 
               #ifdef EXEDATAOBJECT 
               #ifndef WIN32 
                MSG     msg; 
 
                if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 
                    { 
                    TranslateMessage(&msg); 
                    DispatchMessage(&msg); 
                    } 
                else 
               #endif 
               #endif 
                    { 
                    pDO->m_pIDataAdviseHolder->SendOnDataChange 
                        (pDO->m_pImpIDataObject, 0, ADVF_NODATA); 
 
                    if (++i >= iAdvise) 
                        break; 
                    } 
                } 
 
            dwTime=GetTickCount()-dwTime; 
            dwAvg=dwTime/iAdvise; 
 
            SetCursor(hCurT); 
            ShowCursor(FALSE); 
 
            wsprintf(szTime 
                , TEXT("Total=%lu ms\n\rAverage=%lu ms") 
                , dwTime, dwAvg); 
 
            GetWindowText(hWnd, szTitle, sizeof(szTitle)); 
            MessageBox(hWnd, szTime, szTitle, MB_OK); 
            break; 
 
        default: 
            return (DefWindowProc(hWnd, iMsg, wParam, lParam)); 
        } 
 
    return 0L; 
    }