PATRON.CPP
/* 
 * PATRON.CPP 
 * Patron Chapter 13 
 * 
 * WinMain which is all we need for the basic application. 
 * 
 * Copyright (c)1993-1996 Microsoft Corporation, All Rights Reserved 
 * 
 * Kraig Brockschmidt, Software Design Engineer 
 * Microsoft Systems Developer Relations 
 * 
 * Internet  :  kraigb@microsoft.com 
 * Compuserve:  >INTERNET:kraigb@microsoft.com 
 */ 
 
 
#define INITGUIDS 
#include "patron.h" 
 
extern "C" 
{ 
OLEDBGDATA_MAIN("PATRON") 
} 
 
//CHAPTER13MOD 
//Count number of objects and number of locks. 
ULONG       g_cObj=0; 
ULONG       g_cLock=0; 
 
//Make window handle global so other code can cause a shutdown 
HWND        g_hWnd=NULL; 
 
//Indicate if the user has control 
BOOL        g_fUser=TRUE; 
//End CHAPTER13MOD 
 
 
/* 
 * WinMain 
 * 
 * Purpose: 
 *  Main entry point of application.  Should register the app class 
 *  if a previous instance has not done so and do any other one-time 
 *  initializations. 
 */ 
 
int PASCAL WinMain (HINSTANCE hInst, HINSTANCE hPrev 
    , LPSTR pszCmdLine, int nCmdShow) 
    { 
    PCPatronFrame   pFR; 
    FRAMEINIT       fi; 
    WPARAM          wRet=0; 
 
   #ifndef WIN32 
    int             cMsg=96; 
 
    while (!SetMessageQueue(cMsg) && (cMsg-=8)); 
   #endif 
 
    //Attempt to allocate and initialize the application 
    pFR=new CPatronFrame(hInst, hPrev, pszCmdLine, nCmdShow); 
 
    if (NULL==pFR) 
        return -1; 
 
    fi.idsMin=IDS_FRAMEMIN; 
    fi.idsMax=IDS_FRAMEMAX; 
    fi.idsStatMin=IDS_STATMESSAGEMIN; 
    fi.idsStatMax=IDS_STATMESSAGEMAX; 
    fi.idStatMenuMin=ID_MENUFILE; 
    fi.idStatMenuMax=ID_MENUHELP; 
    fi.iPosWindowMenu=WINDOW_MENU; 
    fi.cMenus=CMENUS; 
 
    fi.x=CW_USEDEFAULT; 
    fi.y=CW_USEDEFAULT; 
    fi.cx=CW_USEDEFAULT; 
    fi.cy=CW_USEDEFAULT; 
 
    //If we can initialize pFR, start chugging messages 
    if (pFR->FInit(&fi)) 
        wRet=pFR->MessageLoop(); 
 
    delete pFR; 
    return wRet; 
    } 
 
 
 
//CHAPTER13MOD 
/* 
 * ObjectDestroyed 
 * 
 * Purpose: 
 *  Function for the Patron Document object to call when it gets 
 *  destroyed.  We destroy the main window if the proper conditions 
 *  are met for shutdown. 
 * 
 * Parameters: 
 *  None 
 * 
 * Return Value: 
 *  None 
 */ 
 
void PASCAL ObjectDestroyed(void) 
    { 
    g_cObj--; 
 
    //No more objects, no locks, no user control, shut the app down. 
    if (0==g_cObj && 0==g_cLock && IsWindow(g_hWnd) && !g_fUser) 
        PostMessage(g_hWnd, WM_CLOSE, 0, 0L); 
 
    return; 
    } 
 
//End CHAPTER13MOD 
 
 
 
 
/* 
 * CPatronFrame::CPatronFrame 
 * CPatronFrame::~CPatronFrame 
 * 
 * Constructor Parameters: 
 *  hInst           HINSTANCE from WinMain 
 *  hInstPrev       HINSTANCE from WinMain 
 *  pszCmdLine      LPSTR from WinMain 
 *  nCmdShow        int from WInMain 
 */ 
 
CPatronFrame::CPatronFrame(HINSTANCE hInst, HINSTANCE hInstPrev 
    , LPSTR pszCmdLine, int nCmdShow) 
    : CFrame(hInst, hInstPrev, pszCmdLine, nCmdShow) 
    { 
    //CHAPTER13MOD 
    char        szTemp[256];        //ParseCmdLine is ANSI 
 
    m_fInitialized=FALSE; 
    m_fOleStdInit=FALSE; 
    m_pIClassDataTran=NULL; 
 
    m_pDocCreated=NULL; 
    m_fEmbedding=FALSE; //-Embedding on command line? 
 
    ParseCmdLine(pszCmdLine, &m_fEmbedding, szTemp); 
    g_fUser=!m_fEmbedding; 
 
    m_dwRegCO=0; 
    m_pIClassFactory=NULL; 
    //End CHAPTER13MOD 
 
    return; 
    } 
 
 
CPatronFrame::~CPatronFrame(void) 
    { 
    //CHAPTER13MOD 
    //Opposite of CoRegisterClassObject, takes class factory ref to 1 
    if (0L!=m_dwRegCO) 
        CoRevokeClassObject(m_dwRegCO); 
 
    //This should be the last Release, which frees the class factory. 
    if (NULL!=m_pIClassFactory) 
        m_pIClassFactory->Release(); 
    //End CHAPTER13MOD 
 
    if (NULL!=m_pIClassDataTran) 
        { 
        m_pIClassDataTran->LockServer(FALSE); 
        m_pIClassDataTran->Release(); 
        } 
 
    OleFlushClipboard(); 
 
    if (m_fOleStdInit) 
        OleStdUninitialize(); 
 
    if (m_fInitialized) 
        OleUninitialize(); 
    return; 
    } 
 
 
 
 
/* 
 * CPatronFrame::FInit 
 * 
 * Purpose: 
 *  Call OleInitialize then calling down into the base class 
 *  initialization. 
 * 
 * Parameters: 
 *  pFI             PFRAMEINIT containing initialization 
 *                  parameters. 
 * 
 * Return Value: 
 *  BOOL            TRUE if initialization succeeded, 
 *                  FALSE otherwise. 
 */ 
 
BOOL CPatronFrame::FInit(PFRAMEINIT pFI) 
    { 
    DWORD       dwVer; 
    HRESULT     hr; 
 
    dwVer=OleBuildVersion(); 
 
    if (rmm!=HIWORD(dwVer)) 
        return FALSE; 
 
    if (FAILED(OleInitialize(NULL))) 
        return FALSE; 
 
    m_fInitialized=TRUE; 
 
    if (!OleStdInitialize(m_hInst)) 
        return FALSE; 
 
    m_fOleStdInit=TRUE; 
 
    //Lock the data transfer object factory as an optimization. 
    hr=CoGetClassObject(CLSID_DataTransferObject 
        , CLSCTX_INPROC_SERVER, NULL, IID_IClassFactory 
        , (PPVOID)&m_pIClassDataTran); 
 
    if (SUCCEEDED(hr)) 
        m_pIClassDataTran->LockServer(TRUE); 
 
    //CHAPTER13MOD 
    if (m_fEmbedding) 
        { 
        HRESULT     hr; 
 
        m_pIClassFactory=new CLinkClassFactory(this); 
 
        if (NULL==m_pIClassFactory) 
            return FALSE; 
 
        //Since we hold on to this, we should AddRef it. 
        m_pIClassFactory->AddRef(); 
 
        hr=CoRegisterClassObject(CLSID_PatronPages, m_pIClassFactory 
            , CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &m_dwRegCO); 
 
        if (FAILED(hr)) 
            return FALSE; 
        } 
    //End CHAPTER13MOD 
 
    return CFrame::FInit(pFI); 
    } 
 
 
 
 
 
/* 
 * CPatronFrame::CreateCClient 
 * 
 * Purpose: 
 *  Constructs a new client specific to the application. 
 * 
 * Parameters: 
 *  None 
 * 
 * Return Value: 
 *  PCClient        Pointer to the new client object. 
 */ 
 
PCClient CPatronFrame::CreateCClient(void) 
    { 
    return (PCClient)(new CPatronClient(m_hInst)); 
    } 
 
 
 
 
 
 
/* 
 * CPatronFrame::FRegisterAllClasses 
 * 
 * Purpose: 
 *  Registers all classes used in this application. 
 * 
 * Parameters: 
 *  None 
 * 
 * Return Value: 
 *  BOOL            TRUE if registration succeeded, FALSE otherwise. 
 */ 
 
BOOL CPatronFrame::FRegisterAllClasses(void) 
    { 
    WNDCLASS        wc; 
 
    //First let the standard frame do its thing 
    if (!CFrame::FRegisterAllClasses()) 
        return FALSE; 
 
    //We need double-clicks now and for object activation later. 
    wc.style         = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; 
    wc.hInstance     = m_hInst; 
    wc.cbClsExtra    = 0; 
    wc.lpfnWndProc   = PagesWndProc; 
    wc.cbWndExtra    = CBPAGESWNDEXTRA; 
    wc.hIcon         = NULL; 
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW); 
    wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE+1); 
    wc.lpszMenuName  = NULL; 
    wc.lpszClassName = SZCLASSPAGES; 
 
    if (!RegisterClass(&wc)) 
        return FALSE; 
 
    return TRUE; 
    } 
 
 
 
 
//CHAPTER13MOD 
/* 
 * CPatronFrame::FPreShowInit 
 * 
 * Purpose: 
 *  Called from FInit before intially showing the window.  We do 
 *  whatever else we want here, modifying m_nCmdShow as necessary 
 *  which affects ShowWindow in FInit. 
 * 
 * Parameters: 
 *  None 
 * 
 * Return Value: 
 *  BOOL            TRUE if this successful, FALSE otherwise. 
 */ 
 
BOOL CPatronFrame::FPreShowInit(void) 
    { 
    //Base class does nothing 
    CFrame::FPreShowInit(); 
 
    //Save the window handle for shutdown if necessary. 
    g_hWnd=m_hWnd; 
 
    //If we're -Embedding, don't show the window initially. 
    if (m_fEmbedding) 
        m_nCmdShow=SW_HIDE; 
 
    return TRUE; 
    } 
 
 
 
/* 
 * CPatronFrame::ParseCommandLine 
 * 
 * Purpose: 
 *  Allows the application to parse the command line and take action 
 *  after the window has possibly been shown.  For a compound 
 *  document server we need to just make sure that if -Embedding is 
 *  there that we take no file action.  FPreShowInit has already 
 *  handled the window visibility. 
 * 
 * Parameters: 
 *  None 
 * 
 * Return Value: 
 *  BOOL            TRUE if this successful, FALSE otherwise. 
 */ 
 
void CPatronFrame::ParseCommandLine(void) 
    { 
    //If -Embedding was there, prevent any attempt to load a file. 
    if (m_fEmbedding) 
        return; 
 
    CFrame::ParseCommandLine(); 
    return; 
    } 
//End CHAPTER13MOD 
 
 
 
 
 
/* 
 * CPatronFrame::OnCommand 
 * 
 * Purpose: 
 *  WM_COMMAND handler for the Patron frame window that processes extra 
 *  File menu items as well as the Page menu. 
 * 
 * Parameters: 
 *  hWnd            HWND of the frame window. 
 *  wParam          WPARAM of the message. 
 *  lParam          LPARAM of the message. 
 * 
 * Return Value: 
 *  LRESULT         Return value for the message. 
 */ 
 
LRESULT CPatronFrame::OnCommand(HWND hWnd, WPARAM wParam 
    , LPARAM lParam) 
    { 
    PCPatronDoc     pDoc; 
 
    COMMANDPARAMS(wID, wCode, hWndMsg); 
 
    /* 
     * Don't bother with anything during first initialization, 
     * skipping many GizmoBar notifications. 
     */ 
    if (m_fInit) 
        return 0L; 
 
    pDoc=(PCPatronDoc)m_pCL->ActiveDocument(); 
 
    if (NULL!=pDoc && (IDM_VERBMIN <= wID) && (IDM_VERBMAX >= wID)) 
        { 
        pDoc->ActivateObject(wID-IDM_VERBMIN); 
        return 0L; 
        } 
 
    switch (wID) 
        { 
        case IDM_FILEPRINT: 
            pDoc->Print(m_hWnd); 
            return 0L; 
 
        case IDM_FILEPRINTERSETUP: 
            pDoc->PrinterSetup(m_hWnd, FALSE); 
            return 0L; 
 
        case IDM_EDITPASTESPECIAL: 
            pDoc->FPasteSpecial(m_hWnd); 
            return 0L; 
 
        case IDM_EDITDELETEOBJECT: 
            pDoc->Delete(); 
            return 0L; 
 
        case IDM_EDITINSERTOBJECT: 
            pDoc->FInsertObject(m_hWnd); 
            return 0L; 
 
        case IDM_EDITLINKS: 
            pDoc->FEditLinks(m_hWnd); 
            return 0L; 
 
        case IDM_PAGENEWPAGE: 
            pDoc->NewPage(); 
            break; 
 
        case IDM_PAGEDELETEPAGE: 
            pDoc->DeletePage(); 
            break; 
 
        case IDM_PAGENEXTPAGE: 
            pDoc->NextPage(); 
            break; 
 
        case IDM_PAGEPREVIOUSPAGE: 
            pDoc->PreviousPage(); 
            break; 
 
        case IDM_PAGEFIRSTPAGE: 
            pDoc->FirstPage(); 
            break; 
 
        case IDM_PAGELASTPAGE: 
            pDoc->LastPage(); 
            break; 
 
        case IDM_PAGESHOWOBJECTS: 
            { 
            BOOL    fTemp; 
 
            //First get the current state, then toggle it. 
            fTemp=pDoc->FShowOrQueryObjectTypes(TRUE, FALSE); 
            pDoc->FShowOrQueryObjectTypes(FALSE, !fTemp); 
            } 
            break; 
 
        default: 
           return CFrame::OnCommand(hWnd, wParam, lParam); 
        } 
 
    return 0L; 
    } 
 
 
 
 
 
 
 
 
/* 
 * CPatronFrame::CreateGizmos 
 * 
 * Purpose: 
 *  Procedure to create all the necessary gizmobar buttons. 
 * 
 * Parameters: 
 *  None 
 * 
 * Return Value: 
 *  UINT            Number of gizmos added to the bar. 
 */ 
 
UINT CPatronFrame::CreateGizmos(void) 
    { 
    UINT            iLast; 
    UINT            uState=GIZMO_NORMAL; 
    UINT            utCmd =GIZMOTYPE_BUTTONCOMMAND; 
 
    //Insert the standard ones. 
    iLast=CFrame::CreateGizmos(); 
 
    //Remove Undo:  we don't use it. 
    m_pGB->Remove(IDM_EDITUNDO); 
 
    /* 
     * Insert Print File Import in the 5th position and account 
     * for it in iLast. 
     */ 
    m_pGB->Add(utCmd, 4, IDM_FILEPRINT, m_dxB, m_dyB 
        , NULL, NULL, 6, uState); 
 
    iLast++; 
 
    m_pGB->Add(GIZMOTYPE_SEPARATOR, iLast++, 0, 6, m_dyB 
        , NULL, NULL, 0, uState); 
 
    //Add New Page, and Delete Page 
    m_pGB->Add(utCmd, iLast++, IDM_PAGENEWPAGE, m_dxB, m_dyB 
        , NULL, m_hBmp, 2, uState); 
    m_pGB->Add(utCmd, iLast++, IDM_PAGEDELETEPAGE, m_dxB, m_dyB 
        , NULL, m_hBmp, 3, uState); 
 
    m_pGB->Add(GIZMOTYPE_SEPARATOR, iLast++, 0, 6, m_dyB 
        , NULL, NULL, 0, uState); 
 
    //First, Prev, Next, Last pages. 
    m_pGB->Add(utCmd, iLast++, IDM_PAGEFIRSTPAGE, m_dxB, m_dyB 
        , NULL, m_hBmp, 4, uState); 
    m_pGB->Add(utCmd, iLast++, IDM_PAGEPREVIOUSPAGE, m_dxB, m_dyB 
        , NULL, m_hBmp, 5, uState); 
    m_pGB->Add(utCmd, iLast++, IDM_PAGENEXTPAGE, m_dxB, m_dyB 
        , NULL, m_hBmp, 6, uState); 
    m_pGB->Add(utCmd, iLast++, IDM_PAGELASTPAGE, m_dxB, m_dyB 
        , NULL, m_hBmp, 7, uState); 
 
    return iLast; 
    } 
 
 
 
 
 
 
 
/* 
 * CPatronFrame::UpdateMenus 
 * 
 * Purpose: 
 *  Handles the WM_INITMENU message for the frame window.  Depending 
 *  on the existence of an active window, menu items are selectively 
 *  enabled and disabled. 
 * 
 * Parameters: 
 *  hMenu           HMENU of the menu to intialize 
 *  iMenu           UINT position of the menu. 
 * 
 * Return Value: 
 *  None 
 */ 
 
void CPatronFrame::UpdateMenus(HMENU hMenu, UINT iMenu) 
    { 
    PCPatronDoc     pDoc; 
    BOOL            fOK=FALSE; 
    BOOL            fCallDefault=TRUE; 
    UINT            uTemp; 
    UINT            uTempE; 
    UINT            uTempD; 
 
    pDoc=(PCPatronDoc)m_pCL->ActiveDocument(); 
 
    uTempE=MF_ENABLED | MF_BYCOMMAND; 
    uTempD=MF_DISABLED | MF_GRAYED | MF_BYCOMMAND; 
    uTemp=((NULL!=pDoc) ? uTempE : uTempD); 
 
    if (m_phMenu[0]==hMenu) 
        { 
        EnableMenuItem(hMenu, IDM_FILEPRINT, uTemp); 
 
        if (NULL!=pDoc) 
            fOK=pDoc->FQueryPrinterSetup(); 
 
        EnableMenuItem(hMenu, IDM_FILEPRINTERSETUP 
            , (fOK) ? uTempE : uTempD); 
        } 
 
    if (m_phMenu[1]==hMenu) 
        { 
        if (NULL!=pDoc) 
            fOK=pDoc->FQueryPaste(); 
 
        EnableMenuItem(hMenu, IDM_EDITPASTE 
            , (fOK) ? uTempE : uTempD); 
        EnableMenuItem(hMenu, IDM_EDITPASTESPECIAL 
            , (fOK) ? uTempE : uTempD); 
 
        //Cut, Copy, Delete depends on there being a selection. 
        if (NULL!=pDoc) 
            fOK=pDoc->FQueryObjectSelected(hMenu); 
        else 
            fOK=FALSE; 
 
        EnableMenuItem(hMenu, IDM_EDITCUT, (fOK) ? uTempE : uTempD); 
        EnableMenuItem(hMenu, IDM_EDITCOPY 
            , (fOK) ? uTempE : uTempD); 
        EnableMenuItem(hMenu, IDM_EDITDELETEOBJECT 
            , (fOK) ? uTempE : uTempD); 
 
        EnableMenuItem(hMenu, IDM_EDITINSERTOBJECT, uTemp); 
 
        if (NULL!=pDoc) 
            fOK=pDoc->FQueryEnableEditLinks(); 
        else 
            fOK=FALSE; 
 
        EnableMenuItem(hMenu, IDM_EDITLINKS 
            , (fOK) ? uTempE : uTempD); 
 
        //We did the whole menu... 
        fCallDefault=FALSE; 
        } 
 
    //Page menu 
    if (m_phMenu[2]==hMenu) 
        { 
        EnableMenuItem(hMenu, IDM_PAGENEWPAGE,      uTemp); 
        EnableMenuItem(hMenu, IDM_PAGEDELETEPAGE,   uTemp); 
        EnableMenuItem(hMenu, IDM_PAGENEXTPAGE,     uTemp); 
        EnableMenuItem(hMenu, IDM_PAGEPREVIOUSPAGE, uTemp); 
        EnableMenuItem(hMenu, IDM_PAGEFIRSTPAGE,    uTemp); 
        EnableMenuItem(hMenu, IDM_PAGELASTPAGE,     uTemp); 
 
        //Check the Show Objects command or not. 
        if (NULL!=pDoc) 
            fOK=pDoc->FShowOrQueryObjectTypes(TRUE, FALSE); 
        else 
            fOK=FALSE; 
 
        CheckMenuItem(hMenu, IDM_PAGESHOWOBJECTS, MF_BYCOMMAND 
            | ((fOK) ? MF_CHECKED : MF_UNCHECKED)); 
        EnableMenuItem(hMenu, IDM_PAGESHOWOBJECTS, uTemp); 
        } 
 
    if (fCallDefault) 
        CFrame::UpdateMenus(hMenu, iMenu); 
 
    return; 
    } 
 
 
 
 
 
 
/* 
 * CPatronFrame::UpdateGizmos 
 * 
 * Purpose: 
 *  Enables and disables gizmos depending on whether we have 
 *  a document or not. 
 * 
 * Parameters: 
 *  None 
 * 
 * Return Value: 
 *  None 
 */ 
 
void CPatronFrame::UpdateGizmos(void) 
    { 
    PCDocument  pDoc; 
    BOOL        fEnable; 
 
    //Let the default hack on its gizmos. 
    CFrame::UpdateGizmos(); 
 
    pDoc=m_pCL->ActiveDocument(); 
    fEnable=(NULL!=pDoc); 
 
    //No document, disable just about everything 
    m_pGB->Enable(IDM_FILEPRINT,        fEnable); 
    m_pGB->Enable(IDM_FILEPRINTERSETUP, fEnable); 
 
    m_pGB->Enable(IDM_PAGENEWPAGE,      fEnable); 
    m_pGB->Enable(IDM_PAGEDELETEPAGE,   fEnable); 
    m_pGB->Enable(IDM_PAGEFIRSTPAGE,    fEnable); 
    m_pGB->Enable(IDM_PAGEPREVIOUSPAGE, fEnable); 
    m_pGB->Enable(IDM_PAGENEXTPAGE,     fEnable); 
    m_pGB->Enable(IDM_PAGELASTPAGE,     fEnable); 
 
    return; 
    } 
 
 
 
/* 
 * CPatronFrame::FMessageHook 
 * 
 * Purpose: 
 *  Override of CFrame::FMessageHook so we can specifically trap 
 *  WM_MENUSELECT messages for the Object verb menu to provide some 
 *  meaningful information on the status strip. 
 * 
 * Parameters: 
 *  <WndProc Parameters> 
 *  pLRes           LRESULT * in which to store the return value 
 *                  for the message. 
 * 
 * Return Value: 
 *  BOOL            TRUE to prevent further processing, 
 *                  FALSE otherwise. 
 */ 
 
BOOL CPatronFrame::FMessageHook(HWND hWnd, UINT iMsg, WPARAM wParam 
    , LPARAM lParam, LRESULT *pLRes) 
    { 
    BOOL        fRet=FALSE; 
 
    *pLRes=0; 
 
    MENUSELECTPARAMS(wItem, wMenuFlags, hMenu); 
 
    //CHAPTER13MOD 
    /* 
     * When closing, make sure any document create from the 
     * class factory is saved since the object in it might 
     * have been changed.  We want to save without showing 
     * the user any message or asking if the user wants to save. 
     */ 
    if (WM_CLOSE==iMsg) 
        { 
        if (NULL!=m_pDocCreated) 
            { 
            if (m_pDocCreated->FDirtyGet()) 
                { 
                CHourglass  wait; 
                m_pDocCreated->USave(0, NULL); 
                } 
            } 
 
        return FALSE; 
        } 
    //End CHAPTER13MOD 
 
    //If this is the wrong message, nothing to do. 
    if (WM_MENUSELECT!=iMsg) 
        return FALSE; 
 
    //This happens when there's no menu selection. 
    if (-1==wMenuFlags) 
        return FALSE; 
 
    if (MF_POPUP & wMenuFlags) 
        { 
        /* 
         * If this is the cascade verb menu itself, display the same 
         * message.  m_phMenu[1] contains the current edit menu 
         * handle. 
         */ 
        fRet=((HMENU)wItem==GetSubMenu(m_phMenu[1],MENUPOS_OBJECT)); 
        } 
    else 
        { 
        /* 
         * If the ID is in the verb range, use 
         * IDS_ITEMMESSAGEEDITOBJECT message 
         */ 
        fRet=(IDM_VERBMIN <= wItem && IDM_VERBMAX >= wItem); 
        } 
 
    if (fRet) 
        m_pSS->MessageDisplay(IDM_EDITOBJECT); 
 
    return fRet; 
    }