FRAMER.CPP
/* 
 * FRAMER.CPP 
 * Document Objects Framer 
 * 
 * Sample to demonstrate in-place activation of a DocObject--also 
 * activates normal embeddings in separate windows. 
 * 
 * Copyright (c)1995-1997 Microsoft Corporation, All Rights Reserved 
 */ 
 
 
#define INITGUID 
#include "framer.h" 
 
 
/* 
 * 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) 
    { 
    PCFrame         pFR;     
    WPARAM          wRet; 
 
    //Attempt to allocate and initialize the application 
    pFR=new CFrame(hInst, hPrev, pszCmdLine, nCmdShow); 
 
    if (NULL==pFR) 
        return 0; 
     
    //If we can initialize pFR, start chugging messages 
    if (pFR->Init(CMENUS, CW_USEDEFAULT, CW_USEDEFAULT 
        , CW_USEDEFAULT, CW_USEDEFAULT)) 
        wRet=pFR->MessageLoop(); 
 
    delete pFR; 
    return wRet; 
    } 
 
 
 
/* 
 * CFrame::CFrame 
 * CFrame::~CFrame 
 * 
 * Constructor Parameters: 
 *  hInst           HINSTANCE from WinMain 
 *  hInstPrev       HINSTANCE from WinMain 
 *  pszCmdLine      LPSTR from WinMain 
 *  nCmdShow        int from WinMain 
 */ 
 
CFrame::CFrame(HINSTANCE hInst, HINSTANCE hInstPrev 
    , LPSTR pszCmdLine, int nCmdShow)     
    { 
    m_hInst=hInst; 
    m_hWnd=NULL; 
    m_hInstPrev=hInstPrev; 
    m_nCmdShow=nCmdShow; 
 
    m_phMenu=NULL; 
    m_hAccel=NULL; 
    m_hWndClient=NULL; 
 
    m_fInitialized=FALSE; 
    m_pIStorage=NULL; 
    m_dwIDCounter=0; 
 
    m_hMenuOrg=NULL; 
    m_hMenuTop=NULL; 
m_hMenuHelp=NULL; 
m_fInObjectHelp=FALSE; 
m_fUsingOurHelp=FALSE; 
     
    m_fHaveObject=FALSE; 
m_hWndObj=NULL; 
 
    m_pSite=NULL; 
    m_fOurMenuShowing=TRUE; 
    SetRect(&m_bwIP, 0, 0, 0, 0); 
    m_fInContextHelp=FALSE; 
    m_pIOleIPActiveObject=NULL; 
 
    return; 
    } 
 
 
 
CFrame::~CFrame(void) 
    { 
    if (NULL!=m_hWndClient) 
        DestroyWindow(m_hWndClient); 
 
    //Frees the temp file. 
    ReleaseInterface(m_pIStorage); 
     
    //m_pSite cleaned up in Close 
 
    //Accelerators freed automatically. 
 
//Destroy the special help menu 
if (NULL!=m_hMenuHelp) 
DestroyMenu(m_hMenuHelp); 
 
    //Free the menu handle array 
    if (NULL!=m_phMenu) 
        delete []((UINT *)m_phMenu); 
 
    if (m_fInitialized) 
        OleUninitialize(); 
 
    return; 
    } 
 
 
/* 
 * CFrame::Init 
 * 
 * Purpose: 
 *  Initializer for a CFrame object containing anything prone to 
 *  failure. 
 * 
 * Parameters: 
 *  cMenus          UINT number of menus on the frame 
 *  x, y, cx, cy    int location and size of frame window  
 * 
 * Return Value: 
 *  BOOL            TRUE if initialization succeeded, FALSE 
 *                  otherwise. If FALSE is returned, the caller must 
 *                  guarantee that the destructor is called promptly 
 *                  to insure cleanup. 
 */ 
 
BOOL CFrame::Init(UINT cMenus, int x, int y, int cx, int cy) 
    { 
    HMENU               hMenu; 
    UINT                uTemp; 
    RECT                rc; 
 
    //1.  Initialize OLE 
    if (SUCCEEDED(OleInitialize(NULL))) 
        m_fInitialized=TRUE; 
    else 
        return FALSE; 
 
 
    //2.  Register window classes 
    if (NULL==m_hInstPrev) 
        { 
        if (!RegisterAllClasses()) 
            return FALSE; 
        } 
 
 
    //3.  Create the main window and client-area window 
    m_hWnd=CreateWindow(SZCLASSFRAME, TEXT("DocObject Framer") 
        , WS_MINIMIZEBOX | WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN 
        , x, y, cx, cy, NULL, NULL, m_hInst, this); 
         
    if (NULL==m_hWnd) 
        return FALSE; 
 
    GetClientRect(m_hWnd, &rc); 
 
    m_hWndClient=CreateWindow(SZCLASSCLIENT, SZCLASSCLIENT 
        , WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | WS_CLIPSIBLINGS 
        , rc.left, rc.top, rc.right-rc.left 
        , rc.bottom-rc.top, m_hWnd, NULL, m_hInst, this); 
 
    if (NULL==m_hWndClient) 
        return FALSE; 
 
    //4. Allocate menu array for use with in-place menu merging. 
    m_phMenu=new HMENU[cMenus]; 
    hMenu=GetMenu(m_hWnd); 
    m_hMenuOrg=hMenu; 
 
    for (uTemp=0; uTemp < cMenus; uTemp++) 
        m_phMenu[uTemp]=GetSubMenu(hMenu, uTemp); 
 
//Also load the special help menu 
m_hMenuHelp=LoadMenu(m_hInst 
, MAKEINTRESOURCE(IDR_MENUHELP)); 
 
    //5.  Load accelerators 
    m_hAccel=LoadAccelerators(m_hInst 
        , MAKEINTRESOURCE(IDR_ACCELERATORS)); 
 
    if (NULL==m_hAccel) 
        return FALSE; 
 
 
    //6.  Make us all visible. 
    ShowWindow(m_hWnd, m_nCmdShow); 
    UpdateWindow(m_hWnd); 
 
 
    /* 
     * 7.  Create a temp file for all embedded files.  Note that in this 
     *     sample we don't save any changes to DocObjects because we  
 *     don't manage any storage directly. 
 */   
    if (FAILED(StgCreateDocfile(NULL, STGM_TRANSACTED | STGM_READWRITE 
        | STGM_SHARE_EXCLUSIVE | STGM_CREATE| STGM_DELETEONRELEASE 
        , 0, &m_pIStorage))) 
        return FALSE; 
 
    return TRUE; 
    } 
 
 
 
 
 
/* 
 * CFrame::RegisterAllClasses 
 * 
 * Purpose: 
 *  Registers all classes used in this application. 
 * 
 * Return Value: 
 *  BOOL            TRUE if registration succeeded, FALSE otherwise. 
 */ 
 
BOOL CFrame::RegisterAllClasses(void) 
    { 
    WNDCLASS        wc; 
 
    //Field that are the same for all windows. 
    wc.style         = CS_HREDRAW | CS_VREDRAW; 
    wc.hInstance     = m_hInst; 
    wc.cbClsExtra    = 0; 
 
    //Register the Frame window 
    wc.lpfnWndProc   = FrameWndProc; 
    wc.cbWndExtra    = CBFRAMEWNDEXTRA; 
    wc.hIcon         = LoadIcon(m_hInst, TEXT("Icon")); 
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW); 
    wc.hbrBackground = NULL; 
    wc.lpszMenuName  = MAKEINTRESOURCE(IDR_MENU); 
    wc.lpszClassName = SZCLASSFRAME; 
 
    if (!RegisterClass(&wc)) 
        return FALSE; 
 
 
    //Register the do-nothing Client window 
    wc.lpfnWndProc   = ClientWndProc; 
    wc.cbWndExtra    = CBCLIENTWNDEXTRA; 
    wc.hIcon         = NULL; 
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW); 
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); 
    wc.lpszMenuName  = NULL; 
    wc.lpszClassName = SZCLASSCLIENT; 
 
    if (!RegisterClass(&wc)) 
        return FALSE; 
 
    return TRUE; 
    } 
 
 
 
 
/* 
 * CFrame::OnCommand 
 * 
 * Purpose: 
 *  WM_COMMAND handler for the frame window so derivations can 
 *  process their messages and then pass the standard commands (like 
 *  file open and save) on to the base class. 
 * 
 * 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 CFrame::OnCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) 
    { 
    TCHAR           szFile[MAX_PATH]; 
    BOOL            fOK; 
    PCHourglass     pHour; 
    WORD            wID=LOWORD(wParam); 
 
    switch (wID) 
        { 
        case IDM_FILEOPEN: 
            /* 
             * This will be disabled if we already have an object. 
             * User must File/Close first to get back here.  
             * 
             * Otherwise open the File/Open dialog 
             */ 
            szFile[0]=0; 
            if (!OpenDialog(szFile, MAX_PATH)) 
                return 0L; 
                 
            pHour=new CHourglass;             
            fOK=CreateObject(szFile); 
            delete pHour; 
            return 0; 
 
 
        case IDM_FILECLOSE: 
            Close(); 
            break; 
 
 
        case IDM_FILEEXIT: 
            PostMessage(hWnd, WM_CLOSE, 0, 0L);             
            break; 
 
 
        case IDM_HELPABOUT: 
            DialogBox(m_hInst, MAKEINTRESOURCE(IDD_ABOUT) 
                , m_hWnd, (DLGPROC)AboutProc); 
            break; 
 
 
        case IDM_ENTERCONTEXTHELP: 
        case IDM_ESCAPECONTEXTHELP: 
            //Notify the object on entry and exit. 
            ContextSensitiveHelp(IDM_ENTERCONTEXTHELP==wID); 
            break; 
 
 
        default: 
           return DefWindowProc(hWnd, WM_COMMAND, wParam, lParam); 
                
        } 
 
    return 0L; 
    } 
 
 
 
 
 
/* 
 * CFrame::OpenDialog 
 * 
 * Purpose: 
 *  Invokes the COMMDLG.DLL GetOpenFileName dialog and retrieves 
 *  a filename for saving or opening. 
 * 
 * Parameters: 
 *  pszFile         LPTSTR buffer to receive the entered filename. 
 *  cchFile         UINT length of pszFile  
 * 
 * Return Value: 
 *  BOOL            TRUE if the function retrieved a filename, 
 *                  FALSE if the user pressed CANCEL. 
 */ 
 
BOOL CFrame::OpenDialog(LPTSTR pszFile, UINT cchFile) 
    { 
    OPENFILENAME        ofn; 
    static TCHAR        szFilter[80]=TEXT("All Files (*.*)\0*.*\0\0"); 
    BOOL                fRet; 
   #ifdef DEBUG 
    DWORD               dwErr; 
   #endif 
 
    if (NULL==pszFile) 
        return FALSE; 
 
    memset(&ofn, 0, sizeof(OPENFILENAME)); 
    ofn.lStructSize      =sizeof(OPENFILENAME); 
    ofn.hwndOwner        =m_hWnd; 
 
    ofn.lpstrFilter      =szFilter; 
    ofn.nFilterIndex     =1L; 
 
    ofn.lpstrTitle       =NULL; 
    ofn.lpstrFile        =pszFile; 
    ofn.nMaxFile         =cchFile; 
 
    ofn.lpstrDefExt      =TEXT("*"); 
    ofn.Flags            =OFN_HIDEREADONLY | OFN_FILEMUSTEXIST; 
 
    fRet=GetOpenFileName(&ofn); 
     
   #ifdef DEBUG 
    dwErr=CommDlgExtendedError(); 
   #endif 
    return fRet; 
    } 
 
 
 
/* 
 * CFrame::CreateObject 
 * 
 * Purpose: 
 *  Creates a site and has it create an object based on a filename. 
 * 
 * Parameters: 
 *  pszFile         LPTSTR pointing to the filename from which to 
 *                  create the object. 
 * 
 * Return Value: 
 *  BOOL            TRUE if successful, FALSE otherwise. 
 */ 
 
BOOL CFrame::CreateObject(LPTSTR pszFile) 
    {     
    m_pSite=new CSite(++m_dwIDCounter, m_hWndClient, this); 
 
    if (NULL==m_pSite) 
        return FALSE; 
 
    m_pSite->AddRef();  //So we can free with Release 
 
    /* 
     * Now tell the site to create an object in it using the filename 
     * and the storage we opened.  The site will create a sub-storage 
     * for the doc object's use. 
     */ 
    if (!m_pSite->Create(pszFile, m_pIStorage)) 
        return FALSE; 
 
    m_fHaveObject=TRUE; 
 
    //We created the thing, now activate it with "Show" 
    m_pSite->Activate(OLEIVERB_SHOW); 
 
//Force repaint to show "have object" message 
InvalidateRect(m_hWndClient, NULL, TRUE); 
UpdateWindow(m_hWndClient); 
    return TRUE;         
    } 
 
 
 
/* 
 * CFrame::Close 
 * 
 * Purpose: 
 *  Handles File/Close by freeing the object and resetting the 
 *  application state. 
 * 
 * Parameters: 
 *  None 
 * 
 * Return Value: 
 *  None 
 */ 
 
void CFrame::Close(void) 
    {     
RECTrc; 
 
    if (NULL!=m_pSite) 
        { 
CSite *pSite=m_pSite;        //Prevents reentry 
m_pSite=NULL; 
 
        pSite->Close(FALSE);         //Frees the object 
        pSite->Destroy(m_pIStorage); //Cleans up the storage 
        pSite->Release();            //Frees the site         
        } 
     
m_fHaveObject=FALSE; 
    SetRect(&m_bwIP, 0, 0, 0, 0); 
 
GetClientRect(m_hWnd, &rc); 
ResizeClientWindow(rc.left, rc.top, rc.right-rc.left 
, rc.bottom-rc.top); 
 
//Force repaint to remove "have object" message 
InvalidateRect(m_hWndClient, NULL, TRUE); 
UpdateWindow(m_hWndClient); 
     
    return;         
    } 
 
 
/* 
 * CFrame::ResizeClientWindow 
 * 
 * Purpose: 
 *Resizes the client-area window according to current toolbar sizes 
 *  and the frame window size. 
 * 
 * Parameters: 
 *x,y,cx,cyUINT origin and dimensions of the window 
 * 
 * Return Value: 
 *None 
 */ 
 
void CFrame::ResizeClientWindow(UINT x, UINT y, UINT cx, UINT cy) 
{ 
SetWindowPos(m_hWndClient, NULL, x, y, cx, cy     
        , SWP_NOZORDER | SWP_NOACTIVATE); 
 
    //Tell the site to tell the object. 
if (NULL!=m_pSite) 
    m_pSite->UpdateObjectRects(); 
 
return; 
} 
 
 
/* 
 * CFrame::MessageLoop 
 * 
 * Purpose: 
 *  Spins in a standard message loop (with accelerators) until 
 *  WM_QUIT is found after which it returns. 
 * 
 * Return Value: 
 *  WPARAM          Contents of msg.wParam from WM_QUIT. 
 */ 
 
WPARAM CFrame::MessageLoop(void) 
    { 
    MSG     msg; 
 
    while (GetMessage(&msg, NULL, 0,0 )) 
        { 
        //Always give the object first crack at translation. 
        if (NULL!=m_pIOleIPActiveObject) 
            { 
            HRESULT     hr; 
 
            hr=m_pIOleIPActiveObject->TranslateAccelerator(&msg); 
 
            //If the object translated the accelerator, we're done 
            if (NOERROR==hr) 
                continue; 
            } 
 
        if (!::TranslateAccelerator(m_hWnd, m_hAccel, &msg)) 
            { 
            TranslateMessage(&msg); 
            DispatchMessage(&msg); 
            } 
        } 
 
    return msg.wParam; 
    } 
 
 
 
/* 
 * FrameWndProc 
 * 
 * Purpose: 
 *  Frame window class procedure that allows a derivation of these 
 *  classes to hook and process any messages desired.  Otherwise this 
 *  handles standard commands as well as the status line and menus. 
 */ 
 
LRESULT APIENTRY FrameWndProc(HWND hWnd, UINT iMsg 
    , WPARAM wParam, LPARAM lParam) 
    { 
    PCFrame         pFR; 
    RECT            rc; 
    HMENU           hMenu; 
 
    pFR=(PCFrame)GetWindowLong(hWnd, FRAMEWL_STRUCTURE); 
 
    switch (iMsg) 
        { 
        case WM_NCCREATE: 
            pFR=(PCFrame)((LPCREATESTRUCT)lParam)->lpCreateParams; 
 
            SetWindowLong(hWnd, FRAMEWL_STRUCTURE, (LONG)pFR); 
            return DefWindowProc(hWnd, iMsg, wParam, lParam); 
 
        case WM_DESTROY: 
            PostQuitMessage(0); 
            break; 
 
        case WM_CLOSE:                         
            pFR->Close(); 
            DestroyWindow(hWnd); 
            break; 
 
        case WM_ERASEBKGND: 
            //Client area window always manages painting 
            return FALSE; 
 
        case WM_SIZE: 
            //Tell the in-place object about the new frame size 
            GetClientRect(hWnd, &rc); 
 
            if (NULL!=pFR->m_pIOleIPActiveObject) 
                pFR->m_pIOleIPActiveObject->ResizeBorder(&rc, pFR, TRUE); 
 
            /* 
             * Resize the client, which is done in all cases since this window 
 * is the parent of the DocObject, plus we need to tell the  
 * DocObject of the new size through IOleDocumentView::SetRect. 
 */ 
            rc.left  +=pFR->m_bwIP.left; 
            rc.right -=pFR->m_bwIP.right; 
            rc.top   +=pFR->m_bwIP.top; 
            rc.bottom-=pFR->m_bwIP.bottom;             
 
pFR->ResizeClientWindow(rc.left, rc.top, rc.right-rc.left 
, rc.bottom-rc.top); 
 
            break; 
 
 
        case WM_SETFOCUS: 
            if (NULL!=pFR->m_pIOleIPActiveObject) 
                { 
                HWND    hWndObj; 
 
                pFR->m_pIOleIPActiveObject->GetWindow(&hWndObj); 
                SetFocus(hWndObj); 
                } 
 
            return TRUE; 
 
 
case WM_INITMENU: 
pFR->m_fInObjectHelp=FALSE; 
break; 
 
 
case WM_MENUSELECT: 
{ 
 UINT fuFlags=(UINT)HIWORD(wParam); 
 UINT uItem=(UINT)LOWORD(wParam); 
 
if (MF_POPUP & fuFlags) 
{ 
/* 
 * If we're inside our m_hMenuHelp, and uItem is 
 * not zero (first item on the menu, which is ours), 
 * then we must be in an object-supplied menu. 
 * 
 * Therefore we set our flag and forward the message 
 * as well as others that occur later.  Otherwise we 
 * clear the flag so we get messages again. 
 */ 
if (NULL!=pFR->m_hMenuHelp 
&& (HMENU)lParam==pFR->m_hMenuHelp) 
{ 
pFR->m_fInObjectHelp=(0!=uItem); 
 
if (pFR->m_fInObjectHelp) 
SendMessage(pFR->m_hWndObj, iMsg, wParam, lParam); 
} 
} 
else 
{ 
//Forward the message on 
if (pFR->m_fInObjectHelp) 
{ 
SendMessage(pFR->m_hWndObj, iMsg, wParam, lParam); 
break; 
} 
} 
} 
break; 
 
case WM_INITMENUPOPUP: 
/* 
 * If we're in the object's Help menu, forward to 
 * the object received in IOleInPlaceFrame::SetActiveObject 
 */ 
if (pFR->m_fInObjectHelp && NULL!=pFR->m_hWndObj)  
SendMessage(pFR->m_hWndObj, iMsg, wParam, lParam); 
 
 
//Skip the system menu 
            if (TRUE==(BOOL)HIWORD(lParam)) 
                break; 
 
    /* 
             * If we have an object, enable Close, otherwise 
             * enable Open. 
             */ 
            hMenu=(HMENU)wParam; 
 
            if (hMenu==pFR->m_phMenu[0]) 
                { 
                UINT uTempE=MF_BYCOMMAND | MF_ENABLED; 
                UINT uTempD=MF_BYCOMMAND | MF_DISABLED | MF_GRAYED; 
 
                EnableMenuItem(hMenu, IDM_FILEOPEN 
                    , pFR->m_fHaveObject ? uTempD : uTempE); 
                EnableMenuItem(hMenu, IDM_FILECLOSE 
                    , pFR->m_fHaveObject ? uTempE : uTempD); 
                } 
             
            break; 
 
        case WM_COMMAND: 
if (pFR->m_fInObjectHelp) 
{ 
SendMessage(pFR->m_hWndObj, iMsg, wParam, lParam); 
break; 
} 
else 
            return pFR->OnCommand(hWnd, wParam, lParam); 
 
case WM_ACTIVATEAPP: 
if (NULL!=pFR->m_pIOleIPActiveObject) 
{ 
HRESULT hr; 
hr=pFR->m_pIOleIPActiveObject->OnFrameWindowActivate((BOOL)wParam); 
} 
break; 
 
        default: 
            return DefWindowProc(hWnd, iMsg, wParam, lParam); 
        } 
 
    return 0L; 
    } 
 
 
 
/* 
 * ClientWndProc 
 * 
 * Purpose: 
 *  Client window class procedure that's only used to paint a 
 *  message when we have a non-DocObject open.  Otherwise this 
 *  is completely hidden. 
 */ 
 
LRESULT APIENTRY ClientWndProc(HWND hWnd, UINT iMsg 
    , WPARAM wParam, LPARAM lParam) 
    { 
    PCFrame         pFR; 
PAINTSTRUCTps; 
 
    pFR=(PCFrame)GetWindowLong(hWnd, CLIENTWL_STRUCTURE); 
 
    switch (iMsg) 
        { 
        case WM_NCCREATE: 
            pFR=(PCFrame)((LPCREATESTRUCT)lParam)->lpCreateParams; 
 
            SetWindowLong(hWnd, CLIENTWL_STRUCTURE, (LONG)pFR); 
            return DefWindowProc(hWnd, iMsg, wParam, lParam); 
 
        case WM_PAINT: 
BeginPaint(hWnd, &ps); 
 
if (pFR->m_fHaveObject) 
{ 
static TCHAR szMsg[]={TEXT("A non-DocObject is open or loaded. Use File/Close to destroy it.")}; 
 
SetBkColor(ps.hdc, GetSysColor(COLOR_WINDOW)); 
TextOut(ps.hdc, 0, 0, szMsg, lstrlen(szMsg)); 
} 
 
EndPaint(hWnd, &ps); 
            break; 
 
        default: 
            return DefWindowProc(hWnd, iMsg, wParam, lParam); 
        } 
 
    return 0L; 
    } 
 
 
 
 
 
/* 
 * AboutProc 
 * 
 * Purpose: 
 *  Dialog procedure for the omnipresent About box. 
 * 
 * Parameters: 
 *  The standard. 
 * 
 * Return Value: 
 *  The value to be returned through the DialogBox call that 
 *  created the dialog. 
 * 
 */ 
 
BOOL APIENTRY AboutProc(HWND hDlg, UINT iMsg 
    , WPARAM wParam, LPARAM lParam) 
    { 
    switch (iMsg) 
        { 
        case WM_INITDIALOG: 
            return TRUE; 
 
        case WM_COMMAND: 
            switch (LOWORD(wParam)) 
                { 
                case IDOK: 
                    EndDialog(hDlg, TRUE); 
                } 
            break; 
        } 
    return FALSE; 
    } 
 
 
 
 
 
 
 
 
 
/* 
 * IUnknown implementation 
 */ 
 
 
/* 
 * CFrame::QueryInterface 
 * CFrame::AddRef 
 * CFrame::Release 
 */ 
 
STDMETHODIMP CFrame::QueryInterface(REFIID riid, void **ppv) 
    { 
    /* 
     * We only know IOleInPlaceFrame and its base interfaces as well 
     * as a bogus IOleCommandTarget to make PowerPoint happy. 
 */ 
    *ppv=NULL; 
 
    if (IID_IUnknown==riid || IID_IOleInPlaceUIWindow==riid 
        || IID_IOleWindow==riid || IID_IOleInPlaceFrame==riid) 
        *ppv=(IOleInPlaceFrame *)this; 
 
if (IID_IOleCommandTarget==riid) 
        *ppv=(IOleCommandTarget *)this; 
 
    if (NULL!=*ppv) 
        { 
        ((LPUNKNOWN)*ppv)->AddRef(); 
        return NOERROR; 
        } 
 
    return E_NOINTERFACE; 
    } 
 
 
STDMETHODIMP_(ULONG) CFrame::AddRef(void) 
    { 
    return ++m_cRef; 
    } 
 
STDMETHODIMP_(ULONG) CFrame::Release(void) 
    { 
    //Nothing special happening here--frame's life if user-controlled. 
    return --m_cRef; 
    } 
 
 
/* 
 * IOleInPlaceFrame implementation 
 */ 
 
 
/* 
 * CFrame::GetWindow 
 * 
 * Purpose: 
 *  Retrieves the handle of the window associated with the object 
 *  on which this interface is implemented. 
 * 
 * Parameters: 
 *  phWnd           HWND * in which to store the window handle. 
 * 
 * Return Value: 
 *  HRESULT         NOERROR if successful, E_FAIL if there is no 
 *                  window. 
 */ 
 
STDMETHODIMP CFrame::GetWindow(HWND *phWnd) 
    { 
    *phWnd=m_hWnd; 
    return NOERROR; 
    } 
 
 
 
 
/* 
 * CFrame::ContextSensitiveHelp 
 * 
 * Purpose: 
 *  Instructs the object on which this interface is implemented to 
 *  enter or leave a context-sensitive help mode. 
 * 
 * Parameters: 
 *  fEnterMode      BOOL TRUE to enter the mode, FALSE otherwise. 
 * 
 * Return Value: 
 *  HRESULT         NOERROR 
 */ 
 
STDMETHODIMP CFrame::ContextSensitiveHelp(BOOL fEnterMode) 
    { 
    /* 
     * Don't bother if there is no active object since we don't do 
     * context help on our own. 
     */ 
    if (NULL==m_pIOleIPActiveObject) 
        return NOERROR; 
 
    //If the state changes, notify the active object. 
    if (m_fInContextHelp!=fEnterMode) 
        { 
        m_fInContextHelp=fEnterMode; 
        m_pIOleIPActiveObject->ContextSensitiveHelp(fEnterMode); 
        } 
 
    return NOERROR; 
    } 
 
 
 
 
/* 
 * CFrame::GetBorder 
 * 
 * Purpose: 
 *  Returns the rectangle in which the container is willing to 
 *  negotiate about an object's adornments. 
 * 
 * Parameters: 
 *  prcBorder       LPRECT in which to store the rectangle. 
 * 
 * Return Value: 
 *  HRESULT         NOERROR if all is well, INPLACE_E_NOTOOLSPACE 
 *                  if there is no negotiable space. 
 */ 
 
STDMETHODIMP CFrame::GetBorder(LPRECT prcBorder) 
    { 
    if (NULL==prcBorder) 
        return E_INVALIDARG; 
 
    //We return all the client area space 
    GetClientRect(m_hWnd, prcBorder); 
    return NOERROR; 
    } 
 
 
 
 
/* 
 * CFrame::RequestBorderSpace 
 * 
 * Purpose: 
 *  Asks the container if it can surrender the amount of space 
 *  in pBW that the object would like for it's adornments.  The 
 *  container does nothing but validate the spaces on this call. 
 * 
 * Parameters: 
 *  pBW             LPCBORDERWIDTHS containing the requested space. 
 *                  The values are the amount of space requested 
 *                  from each side of the relevant window. 
 * 
 * Return Value: 
 *  HRESULT         NOERROR if we can give up space, 
 *                  INPLACE_E_NOTOOLSPACE otherwise. 
 */ 
 
STDMETHODIMP CFrame::RequestBorderSpace(LPCBORDERWIDTHS pBW) 
    { 
    //Framer has no border space restrictions 
    return NOERROR; 
    } 
 
 
 
 
/* 
 * CFrame::SetBorderSpace 
 * 
 * Purpose: 
 *  Called when the object now officially requests that the 
 *  container surrender border space it previously allowed 
 *  in RequestBorderSpace.  The container should resize windows 
 *  appropriately to surrender this space. 
 * 
 * Parameters: 
 *  pBW             LPCBORDERWIDTHS containing the amount of space 
 *                  from each side of the relevant window that the 
 *                  object is now reserving. 
 * 
 * Return Value: 
 *  HRESULT         NOERROR 
 */ 
 
STDMETHODIMP CFrame::SetBorderSpace(LPCBORDERWIDTHS pBW) 
    { 
    RECT            rc; 
 
    /* 
     * Since we have no tools, we can accept anything the object sends 
     * and must therefore adjust the client-area window accordingly. 
     */ 
 
    /* 
     * If pBW is NULL, the object is not interested in tools, so we 
     * don't have to do anything.  In either case we need to save 
     * the toolspace allocations in order to resize the client window 
     * correctly. 
     */ 
    if (NULL==pBW) 
        { 
        if (!m_fOurMenuShowing) 
            SetMenu(NULL, NULL, NULL); 
 
        SetRect(&m_bwIP, 0, 0, 0, 0); 
        GetClientRect( m_hWnd, &rc ); 
        } 
    else 
        { 
        GetClientRect(m_hWnd, &rc); 
        rc.left  +=pBW->left; 
        rc.right -=pBW->right; 
        rc.top   +=pBW->top; 
        rc.bottom-=pBW->bottom; 
 
        m_bwIP=*pBW; 
        } 
 
ResizeClientWindow(rc.left, rc.top, rc.right-rc.left 
, rc.bottom-rc.top); 
 
    return NOERROR; 
    } 
 
 
 
 
/* 
 * CFrame::SetActiveObject 
 * 
 * Purpose: 
 *  Provides the container with the object's IOleInPlaceActiveObject 
 *  pointer 
 * 
 * Parameters: 
 *  pIIPActiveObj   LPOLEINPLACEACTIVEOBJECT of interest. 
 *  pszObj          LPCOLESTR naming the object.  Not used. 
 * 
 * Return Value: 
 *  HRESULT         NOERROR 
 */ 
 
STDMETHODIMP CFrame::SetActiveObject 
    (LPOLEINPLACEACTIVEOBJECT pIIPActiveObj, LPCOLESTR pszObj) 
    { 
    if (NULL!=m_pIOleIPActiveObject) 
        m_pIOleIPActiveObject->Release(); 
 
    //NULLs m_pIOleIPActiveObject if pIIPActiveObj is NULL 
    m_pIOleIPActiveObject=pIIPActiveObj; 
 
    if (NULL!=m_pIOleIPActiveObject) 
        m_pIOleIPActiveObject->AddRef(); 
 
m_pIOleIPActiveObject->GetWindow(&m_hWndObj); 
    return NOERROR; 
    } 
 
 
 
 
/* 
 * CFrame::InsertMenus 
 * 
 * Purpose: 
 *  Instructs the container to place its in-place menu items where 
 *  necessary in the given menu and to fill in elements 0, 2, and 4 
 *  of the OLEMENUGROUPWIDTHS array to indicate how many top-level 
 *  items are in each group. 
 * 
 * Parameters: 
 *  hMenu           HMENU in which to add popups. 
 *  pMGW            LPOLEMENUGROUPWIDTHS in which to store the 
 *                  width of each container menu group. 
 * 
 * Return Value: 
 *  HRESULT         NOERROR 
 */ 
 
STDMETHODIMP CFrame::InsertMenus(HMENU hMenu 
    , LPOLEMENUGROUPWIDTHS pMGW) 
    {     
//Copy our File menu into the shared menu.     
    InsertMenu(hMenu, 0, MF_BYPOSITION | MF_POPUP, (UINT)m_phMenu[0] 
        , TEXT("&File")); 
 
    pMGW->width[0]=1; 
    pMGW->width[2]=0; 
    pMGW->width[4]=0; 
 
/* 
 * Add the special help menu which is the first item in 
 * the m_hMenuHelp popup that's sitting around. 
 */ 
InsertMenu(hMenu, 1, MF_BYPOSITION | MF_POPUP 
    , (UINT)m_hMenuHelp, TEXT("&Help")); 
 
//Tell the object we added our Help menu 
pMGW->width[5]=1;     
    return NOERROR; 
    } 
 
 
 
 
/* 
 * CFrame::SetMenu 
 * 
 * Purpose: 
 *  Instructs the container to replace whatever menu it's currently 
 *  using with the given menu and to call OleSetMenuDescritor so OLE 
 *  knows to whom to dispatch messages. 
 * 
 * Parameters: 
 *  hMenu           HMENU to show. 
 *  hOLEMenu        HOLEMENU to the menu descriptor. 
 *  hWndObj         HWND of the active object to which messages are 
 *                  dispatched. 
 * 
 * Return Value: 
 *  HRESULT         NOERROR 
 */ 
 
STDMETHODIMP CFrame::SetMenu(HMENU hMenu, HOLEMENU hOLEMenu 
    , HWND hWndObj) 
    { 
    HRESULT         hr; 
 
    /* 
     * Our responsibilities here are to put the menu on the frame 
     * window and call OleSetMenuDescriptor. 
     */ 
 
    if (NULL==hMenu) 
        { 
        //Prevent redundant calls, or debug warnings on startup. 
        if (NULL==m_hMenuTop) 
            return NOERROR; 
 
        hMenu=m_hMenuTop; 
        m_hMenuTop=NULL; 
        m_fOurMenuShowing=TRUE; 
        } 
    else 
        { 
        m_hMenuTop=m_hMenuOrg; 
        m_fOurMenuShowing=FALSE; 
 
/* 
 * Check if our Help menu has anything added to it.  If so, then 
 * remember to forward menu messages.  If not, remove the Help 
 * menu altogether (destroying it after removing our normal Help 
 * popup, as we also do in RemoveMenus. 
 */ 
if (CHELPITEMS!=GetMenuItemCount(m_hMenuHelp)) 
m_fUsingOurHelp=TRUE; 
else 
{ 
UINTi, cItems; 
 
cItems=GetMenuItemCount(hMenu); 
 
//Find m_hMenuHelp in the menu and remove it. 
for (i=0; i < cItems; i++) 
{ 
if (GetSubMenu(hMenu, i)==m_hMenuHelp) 
{ 
RemoveMenu(hMenu, i, MF_BYPOSITION); 
break; 
} 
} 
} 
        } 
 
    if (NULL!=hMenu) 
        ::SetMenu(m_hWnd, hMenu); 
 
    DrawMenuBar(m_hWnd); 
 
    hr=OleSetMenuDescriptor(hOLEMenu, m_hWnd, hWndObj, NULL, NULL); 
    return hr; 
    } 
 
 
 
 
/* 
 * CFrame::RemoveMenus 
 * 
 * Purpose: 
 *  Asks the container to remove any menus it put into hMenu in 
 *  InsertMenus. 
 * 
 * Parameters: 
 *  hMenu           HMENU from which to remove the container's 
 *                  items. 
 * 
 * Return Value: 
 *  HRESULT         NOERROR 
 */ 
 
STDMETHODIMP CFrame::RemoveMenus(HMENU hMenu) 
    { 
    int         cItems, i, j; 
    HMENU       hMenuT; 
 
/* 
     * To be defensive, loop through this menu removing anything 
     * we recognize (that is, anything in m_phMenu) just in case 
     * the server didn't clean it up right.  At least we can 
     * give ourselves the prophylactic benefit. 
     */ 
 
    if (NULL==hMenu) 
        return NOERROR; 
 
    cItems=GetMenuItemCount(hMenu); 
 
    /* 
     * Walk backwards down the menu.  For each popup, see if it 
     * matches any other popup we know about, and if so, remove 
     * it from the shared menu. 
     */ 
    for (i=cItems; i >=0; i--) 
        { 
        hMenuT=GetSubMenu(hMenu, i); 
 
        for (j=0; j <= CMENUS; j++) 
            { 
//Remove any owned popup, or our special help menu 
            if (hMenuT==m_phMenu[j] 
                || (hMenuT==m_hMenuHelp && m_hMenuHelp!=NULL)) 
                RemoveMenu(hMenu, i, MF_BYPOSITION); 
            } 
        } 
 
m_fUsingOurHelp=FALSE; 
 
    //The menu should now be empty. 
    return NOERROR; 
    } 
 
 
 
 
/* 
 * CFrame::SetStatusText 
 * 
 * Purpose: 
 *  Asks the container to place some text in a status line, if one 
 *  exists.  If the container does not have a status line it 
 *  should return E_FAIL here in which case the object could 
 *  display its own. 
 * 
 * Parameters: 
 *  pszText         LPCOLESTR to display. 
 * 
 * Return Value: 
 *  HRESULT         NOERROR if successful, S_TRUNCATED if not all 
 *                  of the text could be displayed, or E_FAIL if 
 *                  the container has no status line. 
 */ 
 
STDMETHODIMP CFrame::SetStatusText(LPCOLESTR pszText) 
    { 
    //We have no status line... 
    return E_NOTIMPL; 
    } 
 
 
 
/* 
 * CFrame::EnableModeless 
 * 
 * Purpose: 
 *  Instructs the container to show or hide any modeless popup 
 *  windows that it may be using. 
 * 
 * Parameters: 
 *  fEnable         BOOL indicating to enable/show the windows 
 *                  (TRUE) or to hide them (FALSE). 
 * 
 * Return Value: 
 *  HRESULT         NOERROR 
 */ 
 
STDMETHODIMP CFrame::EnableModeless(BOOL fEnable) 
    { 
    return NOERROR; 
    } 
 
 
 
 
/* 
 * CFrame::TranslateAccelerator 
 * 
 * Purpose: 
 *  When dealing with an in-place object from an EXE server, this 
 *  is called to give the container a chance to process accelerators 
 *  after the server has looked at the message. 
 * 
 * Parameters: 
 *  pMSG            LPMSG for the container to examine. 
 *  wID             WORD the identifier in the container's 
 *                  accelerator table (from IOleInPlaceSite 
 *                  ::GetWindowContext) for this message (OLE does 
 *                  some translation before calling). 
 * 
 * Return Value: 
 *  HRESULT         NOERROR if the keystroke was used, 
 *                  S_FALSE otherwise. 
 */ 
 
STDMETHODIMP CFrame::TranslateAccelerator(LPMSG pMSG, WORD wID) 
    { 
    /* 
     * wID already has anything translated from m_hAccel for us, 
     * so we can just check for the commands we want and process 
     * them instead of calling TranslateAccelerator which would be 
     * redundant and which also has a possibility of dispatching to 
     * the wrong window. 
     */ 
    if (IDM_ENTERCONTEXTHELP==wID || IDM_ESCAPECONTEXTHELP==wID) 
        { 
        //wID properly expands to 32-bits 
        OnCommand(m_hWnd, (WPARAM)wID, 0L); 
        return NOERROR; 
        } 
 
    return S_FALSE; 
    } 
 
 
/* 
 * IOleCommandTarget methods, provided to make PowerPoint happy 
 * with this frame. 
 */ 
 
STDMETHODIMP CFrame::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds 
    , OLECMD *prgCmds, OLECMDTEXT *pCmdText) 
{ 
return OLECMDERR_E_UNKNOWNGROUP; 
} 
         
STDMETHODIMP CFrame::Exec(const GUID *pguidCmdGroup, DWORD nCmdID 
    , DWORD nCmdexecopt, VARIANTARG *pvaIn, VARIANTARG *pvaOut) 
{ 
return OLECMDERR_E_UNKNOWNGROUP; 
}