FRAMER.CPP
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:32k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /*
  2.  * FRAMER.CPP
  3.  * Document Objects Framer
  4.  *
  5.  * Sample to demonstrate in-place activation of a DocObject--also
  6.  * activates normal embeddings in separate windows.
  7.  *
  8.  * Copyright (c)1995-1997 Microsoft Corporation, All Rights Reserved
  9.  */
  10. #define INITGUID
  11. #include "framer.h"
  12. /*
  13.  * WinMain
  14.  *
  15.  * Purpose:
  16.  *  Main entry point of application.  Should register the app class
  17.  *  if a previous instance has not done so and do any other one-time
  18.  *  initializations.
  19.  */
  20. int PASCAL WinMain (HINSTANCE hInst, HINSTANCE hPrev
  21.     , LPSTR pszCmdLine, int nCmdShow)
  22.     {
  23.     PCFrame         pFR;    
  24.     WPARAM          wRet;
  25.     //Attempt to allocate and initialize the application
  26.     pFR=new CFrame(hInst, hPrev, pszCmdLine, nCmdShow);
  27.     if (NULL==pFR)
  28.         return 0;
  29.     
  30.     //If we can initialize pFR, start chugging messages
  31.     if (pFR->Init(CMENUS, CW_USEDEFAULT, CW_USEDEFAULT
  32.         , CW_USEDEFAULT, CW_USEDEFAULT))
  33.         wRet=pFR->MessageLoop();
  34.     delete pFR;
  35.     return wRet;
  36.     }
  37. /*
  38.  * CFrame::CFrame
  39.  * CFrame::~CFrame
  40.  *
  41.  * Constructor Parameters:
  42.  *  hInst           HINSTANCE from WinMain
  43.  *  hInstPrev       HINSTANCE from WinMain
  44.  *  pszCmdLine      LPSTR from WinMain
  45.  *  nCmdShow        int from WinMain
  46.  */
  47. CFrame::CFrame(HINSTANCE hInst, HINSTANCE hInstPrev
  48.     , LPSTR pszCmdLine, int nCmdShow)    
  49.     {
  50.     m_hInst=hInst;
  51.     m_hWnd=NULL;
  52.     m_hInstPrev=hInstPrev;
  53.     m_nCmdShow=nCmdShow;
  54.     m_phMenu=NULL;
  55.     m_hAccel=NULL;
  56.     m_hWndClient=NULL;
  57.     m_fInitialized=FALSE;
  58.     m_pIStorage=NULL;
  59.     m_dwIDCounter=0;
  60.     m_hMenuOrg=NULL;
  61.     m_hMenuTop=NULL;
  62. m_hMenuHelp=NULL;
  63. m_fInObjectHelp=FALSE;
  64. m_fUsingOurHelp=FALSE;
  65.     
  66.     m_fHaveObject=FALSE;
  67. m_hWndObj=NULL;
  68.     m_pSite=NULL;
  69.     m_fOurMenuShowing=TRUE;
  70.     SetRect(&m_bwIP, 0, 0, 0, 0);
  71.     m_fInContextHelp=FALSE;
  72.     m_pIOleIPActiveObject=NULL;
  73.     return;
  74.     }
  75. CFrame::~CFrame(void)
  76.     {
  77.     if (NULL!=m_hWndClient)
  78.         DestroyWindow(m_hWndClient);
  79.     //Frees the temp file.
  80.     ReleaseInterface(m_pIStorage);
  81.     
  82.     //m_pSite cleaned up in Close
  83.     //Accelerators freed automatically.
  84. //Destroy the special help menu
  85. if (NULL!=m_hMenuHelp)
  86. DestroyMenu(m_hMenuHelp);
  87.     //Free the menu handle array
  88.     if (NULL!=m_phMenu)
  89.         delete []((UINT *)m_phMenu);
  90.     if (m_fInitialized)
  91.         OleUninitialize();
  92.     return;
  93.     }
  94. /*
  95.  * CFrame::Init
  96.  *
  97.  * Purpose:
  98.  *  Initializer for a CFrame object containing anything prone to
  99.  *  failure.
  100.  *
  101.  * Parameters:
  102.  *  cMenus          UINT number of menus on the frame
  103.  *  x, y, cx, cy    int location and size of frame window 
  104.  *
  105.  * Return Value:
  106.  *  BOOL            TRUE if initialization succeeded, FALSE
  107.  *                  otherwise. If FALSE is returned, the caller must
  108.  *                  guarantee that the destructor is called promptly
  109.  *                  to insure cleanup.
  110.  */
  111. BOOL CFrame::Init(UINT cMenus, int x, int y, int cx, int cy)
  112.     {
  113.     HMENU               hMenu;
  114.     UINT                uTemp;
  115.     RECT                rc;
  116.     //1.  Initialize OLE
  117.     if (SUCCEEDED(OleInitialize(NULL)))
  118.         m_fInitialized=TRUE;
  119.     else
  120.         return FALSE;
  121.     //2.  Register window classes
  122.     if (NULL==m_hInstPrev)
  123.         {
  124.         if (!RegisterAllClasses())
  125.             return FALSE;
  126.         }
  127.     //3.  Create the main window and client-area window
  128.     m_hWnd=CreateWindow(SZCLASSFRAME, TEXT("DocObject Framer")
  129.         , WS_MINIMIZEBOX | WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN
  130.         , x, y, cx, cy, NULL, NULL, m_hInst, this);
  131.         
  132.     if (NULL==m_hWnd)
  133.         return FALSE;
  134.     GetClientRect(m_hWnd, &rc);
  135.     m_hWndClient=CreateWindow(SZCLASSCLIENT, SZCLASSCLIENT
  136.         , WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | WS_CLIPSIBLINGS
  137.         , rc.left, rc.top, rc.right-rc.left
  138.         , rc.bottom-rc.top, m_hWnd, NULL, m_hInst, this);
  139.     if (NULL==m_hWndClient)
  140.         return FALSE;
  141.     //4. Allocate menu array for use with in-place menu merging.
  142.     m_phMenu=new HMENU[cMenus];
  143.     hMenu=GetMenu(m_hWnd);
  144.     m_hMenuOrg=hMenu;
  145.     for (uTemp=0; uTemp < cMenus; uTemp++)
  146.         m_phMenu[uTemp]=GetSubMenu(hMenu, uTemp);
  147. //Also load the special help menu
  148. m_hMenuHelp=LoadMenu(m_hInst
  149. , MAKEINTRESOURCE(IDR_MENUHELP));
  150.     //5.  Load accelerators
  151.     m_hAccel=LoadAccelerators(m_hInst
  152.         , MAKEINTRESOURCE(IDR_ACCELERATORS));
  153.     if (NULL==m_hAccel)
  154.         return FALSE;
  155.     //6.  Make us all visible.
  156.     ShowWindow(m_hWnd, m_nCmdShow);
  157.     UpdateWindow(m_hWnd);
  158.     /*
  159.      * 7.  Create a temp file for all embedded files.  Note that in this
  160.      *     sample we don't save any changes to DocObjects because we 
  161.  *     don't manage any storage directly.
  162.  */   
  163.     if (FAILED(StgCreateDocfile(NULL, STGM_TRANSACTED | STGM_READWRITE
  164.         | STGM_SHARE_EXCLUSIVE | STGM_CREATE| STGM_DELETEONRELEASE
  165.         , 0, &m_pIStorage)))
  166.         return FALSE;
  167.     return TRUE;
  168.     }
  169. /*
  170.  * CFrame::RegisterAllClasses
  171.  *
  172.  * Purpose:
  173.  *  Registers all classes used in this application.
  174.  *
  175.  * Return Value:
  176.  *  BOOL            TRUE if registration succeeded, FALSE otherwise.
  177.  */
  178. BOOL CFrame::RegisterAllClasses(void)
  179.     {
  180.     WNDCLASS        wc;
  181.     //Field that are the same for all windows.
  182.     wc.style         = CS_HREDRAW | CS_VREDRAW;
  183.     wc.hInstance     = m_hInst;
  184.     wc.cbClsExtra    = 0;
  185.     //Register the Frame window
  186.     wc.lpfnWndProc   = FrameWndProc;
  187.     wc.cbWndExtra    = CBFRAMEWNDEXTRA;
  188.     wc.hIcon         = LoadIcon(m_hInst, TEXT("Icon"));
  189.     wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  190.     wc.hbrBackground = NULL;
  191.     wc.lpszMenuName  = MAKEINTRESOURCE(IDR_MENU);
  192.     wc.lpszClassName = SZCLASSFRAME;
  193.     if (!RegisterClass(&wc))
  194.         return FALSE;
  195.     //Register the do-nothing Client window
  196.     wc.lpfnWndProc   = ClientWndProc;
  197.     wc.cbWndExtra    = CBCLIENTWNDEXTRA;
  198.     wc.hIcon         = NULL;
  199.     wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  200.     wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  201.     wc.lpszMenuName  = NULL;
  202.     wc.lpszClassName = SZCLASSCLIENT;
  203.     if (!RegisterClass(&wc))
  204.         return FALSE;
  205.     return TRUE;
  206.     }
  207. /*
  208.  * CFrame::OnCommand
  209.  *
  210.  * Purpose:
  211.  *  WM_COMMAND handler for the frame window so derivations can
  212.  *  process their messages and then pass the standard commands (like
  213.  *  file open and save) on to the base class.
  214.  *
  215.  * Parameters:
  216.  *  hWnd            HWND of the frame window.
  217.  *  wParam          WPARAM of the message.
  218.  *  lParam          LPARAM of the message.
  219.  *
  220.  * Return Value:
  221.  *  LRESULT         Return value for the message.
  222.  */
  223. LRESULT CFrame::OnCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
  224.     {
  225.     TCHAR           szFile[MAX_PATH];
  226.     BOOL            fOK;
  227.     PCHourglass     pHour;
  228.     WORD            wID=LOWORD(wParam);
  229.     switch (wID)
  230.         {
  231.         case IDM_FILEOPEN:
  232.             /*
  233.              * This will be disabled if we already have an object.
  234.              * User must File/Close first to get back here. 
  235.              *
  236.              * Otherwise open the File/Open dialog
  237.              */
  238.             szFile[0]=0;
  239.             if (!OpenDialog(szFile, MAX_PATH))
  240.                 return 0L;
  241.                 
  242.             pHour=new CHourglass;            
  243.             fOK=CreateObject(szFile);
  244.             delete pHour;
  245.             return 0;
  246.         case IDM_FILECLOSE:
  247.             Close();
  248.             break;
  249.         case IDM_FILEEXIT:
  250.             PostMessage(hWnd, WM_CLOSE, 0, 0L);            
  251.             break;
  252.         case IDM_HELPABOUT:
  253.             DialogBox(m_hInst, MAKEINTRESOURCE(IDD_ABOUT)
  254.                 , m_hWnd, (DLGPROC)AboutProc);
  255.             break;
  256.         case IDM_ENTERCONTEXTHELP:
  257.         case IDM_ESCAPECONTEXTHELP:
  258.             //Notify the object on entry and exit.
  259.             ContextSensitiveHelp(IDM_ENTERCONTEXTHELP==wID);
  260.             break;
  261.         default:
  262.            return DefWindowProc(hWnd, WM_COMMAND, wParam, lParam);
  263.                
  264.         }
  265.     return 0L;
  266.     }
  267. /*
  268.  * CFrame::OpenDialog
  269.  *
  270.  * Purpose:
  271.  *  Invokes the COMMDLG.DLL GetOpenFileName dialog and retrieves
  272.  *  a filename for saving or opening.
  273.  *
  274.  * Parameters:
  275.  *  pszFile         LPTSTR buffer to receive the entered filename.
  276.  *  cchFile         UINT length of pszFile 
  277.  *
  278.  * Return Value:
  279.  *  BOOL            TRUE if the function retrieved a filename,
  280.  *                  FALSE if the user pressed CANCEL.
  281.  */
  282. BOOL CFrame::OpenDialog(LPTSTR pszFile, UINT cchFile)
  283.     {
  284.     OPENFILENAME        ofn;
  285.     static TCHAR        szFilter[80]=TEXT("All Files (*.*)*.*");
  286.     BOOL                fRet;
  287.    #ifdef DEBUG
  288.     DWORD               dwErr;
  289.    #endif
  290.     if (NULL==pszFile)
  291.         return FALSE;
  292.     memset(&ofn, 0, sizeof(OPENFILENAME));
  293.     ofn.lStructSize      =sizeof(OPENFILENAME);
  294.     ofn.hwndOwner        =m_hWnd;
  295.     ofn.lpstrFilter      =szFilter;
  296.     ofn.nFilterIndex     =1L;
  297.     ofn.lpstrTitle       =NULL;
  298.     ofn.lpstrFile        =pszFile;
  299.     ofn.nMaxFile         =cchFile;
  300.     ofn.lpstrDefExt      =TEXT("*");
  301.     ofn.Flags            =OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;
  302.     fRet=GetOpenFileName(&ofn);
  303.     
  304.    #ifdef DEBUG
  305.     dwErr=CommDlgExtendedError();
  306.    #endif
  307.     return fRet;
  308.     }
  309. /*
  310.  * CFrame::CreateObject
  311.  *
  312.  * Purpose:
  313.  *  Creates a site and has it create an object based on a filename.
  314.  *
  315.  * Parameters:
  316.  *  pszFile         LPTSTR pointing to the filename from which to
  317.  *                  create the object.
  318.  *
  319.  * Return Value:
  320.  *  BOOL            TRUE if successful, FALSE otherwise.
  321.  */
  322. BOOL CFrame::CreateObject(LPTSTR pszFile)
  323.     {    
  324.     m_pSite=new CSite(++m_dwIDCounter, m_hWndClient, this);
  325.     if (NULL==m_pSite)
  326.         return FALSE;
  327.     m_pSite->AddRef();  //So we can free with Release
  328.     /*
  329.      * Now tell the site to create an object in it using the filename
  330.      * and the storage we opened.  The site will create a sub-storage
  331.      * for the doc object's use.
  332.      */
  333.     if (!m_pSite->Create(pszFile, m_pIStorage))
  334.         return FALSE;
  335.     m_fHaveObject=TRUE;
  336.     //We created the thing, now activate it with "Show"
  337.     m_pSite->Activate(OLEIVERB_SHOW);
  338. //Force repaint to show "have object" message
  339. InvalidateRect(m_hWndClient, NULL, TRUE);
  340. UpdateWindow(m_hWndClient);
  341.     return TRUE;        
  342.     }
  343. /*
  344.  * CFrame::Close
  345.  *
  346.  * Purpose:
  347.  *  Handles File/Close by freeing the object and resetting the
  348.  *  application state.
  349.  *
  350.  * Parameters:
  351.  *  None
  352.  *
  353.  * Return Value:
  354.  *  None
  355.  */
  356. void CFrame::Close(void)
  357.     {    
  358. RECT rc;
  359.     if (NULL!=m_pSite)
  360.         {
  361. CSite *pSite=m_pSite;        //Prevents reentry
  362. m_pSite=NULL;
  363.         pSite->Close(FALSE);         //Frees the object
  364.         pSite->Destroy(m_pIStorage); //Cleans up the storage
  365.         pSite->Release();            //Frees the site        
  366.         }
  367.     
  368. m_fHaveObject=FALSE;
  369.     SetRect(&m_bwIP, 0, 0, 0, 0);
  370. GetClientRect(m_hWnd, &rc);
  371. ResizeClientWindow(rc.left, rc.top, rc.right-rc.left
  372. , rc.bottom-rc.top);
  373. //Force repaint to remove "have object" message
  374. InvalidateRect(m_hWndClient, NULL, TRUE);
  375. UpdateWindow(m_hWndClient);
  376.     
  377.     return;        
  378.     }
  379. /*
  380.  * CFrame::ResizeClientWindow
  381.  *
  382.  * Purpose:
  383.  * Resizes the client-area window according to current toolbar sizes
  384.  *  and the frame window size.
  385.  *
  386.  * Parameters:
  387.  * x,y,cx,cy UINT origin and dimensions of the window
  388.  *
  389.  * Return Value:
  390.  * None
  391.  */
  392. void CFrame::ResizeClientWindow(UINT x, UINT y, UINT cx, UINT cy)
  393. {
  394. SetWindowPos(m_hWndClient, NULL, x, y, cx, cy    
  395.         , SWP_NOZORDER | SWP_NOACTIVATE);
  396.     //Tell the site to tell the object.
  397. if (NULL!=m_pSite)
  398.      m_pSite->UpdateObjectRects();
  399. return;
  400. }
  401. /*
  402.  * CFrame::MessageLoop
  403.  *
  404.  * Purpose:
  405.  *  Spins in a standard message loop (with accelerators) until
  406.  *  WM_QUIT is found after which it returns.
  407.  *
  408.  * Return Value:
  409.  *  WPARAM          Contents of msg.wParam from WM_QUIT.
  410.  */
  411. WPARAM CFrame::MessageLoop(void)
  412.     {
  413.     MSG     msg;
  414.     while (GetMessage(&msg, NULL, 0,0 ))
  415.         {
  416.         //Always give the object first crack at translation.
  417.         if (NULL!=m_pIOleIPActiveObject)
  418.             {
  419.             HRESULT     hr;
  420.             hr=m_pIOleIPActiveObject->TranslateAccelerator(&msg);
  421.             //If the object translated the accelerator, we're done
  422.             if (NOERROR==hr)
  423.                 continue;
  424.             }
  425.         if (!::TranslateAccelerator(m_hWnd, m_hAccel, &msg))
  426.             {
  427.             TranslateMessage(&msg);
  428.             DispatchMessage(&msg);
  429.             }
  430.         }
  431.     return msg.wParam;
  432.     }
  433. /*
  434.  * FrameWndProc
  435.  *
  436.  * Purpose:
  437.  *  Frame window class procedure that allows a derivation of these
  438.  *  classes to hook and process any messages desired.  Otherwise this
  439.  *  handles standard commands as well as the status line and menus.
  440.  */
  441. LRESULT APIENTRY FrameWndProc(HWND hWnd, UINT iMsg
  442.     , WPARAM wParam, LPARAM lParam)
  443.     {
  444.     PCFrame         pFR;
  445.     RECT            rc;
  446.     HMENU           hMenu;
  447.     pFR=(PCFrame)GetWindowLong(hWnd, FRAMEWL_STRUCTURE);
  448.     switch (iMsg)
  449.         {
  450.         case WM_NCCREATE:
  451.             pFR=(PCFrame)((LPCREATESTRUCT)lParam)->lpCreateParams;
  452.             SetWindowLong(hWnd, FRAMEWL_STRUCTURE, (LONG)pFR);
  453.             return DefWindowProc(hWnd, iMsg, wParam, lParam);
  454.         case WM_DESTROY:
  455.             PostQuitMessage(0);
  456.             break;
  457.         case WM_CLOSE:                        
  458.             pFR->Close();
  459.             DestroyWindow(hWnd);
  460.             break;
  461.         case WM_ERASEBKGND:
  462.             //Client area window always manages painting
  463.             return FALSE;
  464.         case WM_SIZE:
  465.             //Tell the in-place object about the new frame size
  466.             GetClientRect(hWnd, &rc);
  467.             if (NULL!=pFR->m_pIOleIPActiveObject)
  468.                 pFR->m_pIOleIPActiveObject->ResizeBorder(&rc, pFR, TRUE);
  469.             /*
  470.              * Resize the client, which is done in all cases since this window
  471.  * is the parent of the DocObject, plus we need to tell the 
  472.  * DocObject of the new size through IOleDocumentView::SetRect.
  473.  */
  474.             rc.left  +=pFR->m_bwIP.left;
  475.             rc.right -=pFR->m_bwIP.right;
  476.             rc.top   +=pFR->m_bwIP.top;
  477.             rc.bottom-=pFR->m_bwIP.bottom;            
  478. pFR->ResizeClientWindow(rc.left, rc.top, rc.right-rc.left
  479. , rc.bottom-rc.top);
  480.             break;
  481.         case WM_SETFOCUS:
  482.             if (NULL!=pFR->m_pIOleIPActiveObject)
  483.                 {
  484.                 HWND    hWndObj;
  485.                 pFR->m_pIOleIPActiveObject->GetWindow(&hWndObj);
  486.                 SetFocus(hWndObj);
  487.                 }
  488.             return TRUE;
  489. case WM_INITMENU:
  490. pFR->m_fInObjectHelp=FALSE;
  491. break;
  492. case WM_MENUSELECT:
  493. {
  494.   UINT fuFlags=(UINT)HIWORD(wParam);
  495.   UINT uItem=(UINT)LOWORD(wParam);
  496. if (MF_POPUP & fuFlags)
  497. {
  498. /*
  499.  * If we're inside our m_hMenuHelp, and uItem is
  500.  * not zero (first item on the menu, which is ours),
  501.  * then we must be in an object-supplied menu.
  502.  *
  503.  * Therefore we set our flag and forward the message
  504.  * as well as others that occur later.  Otherwise we
  505.  * clear the flag so we get messages again.
  506.  */
  507. if (NULL!=pFR->m_hMenuHelp
  508. && (HMENU)lParam==pFR->m_hMenuHelp)
  509. {
  510. pFR->m_fInObjectHelp=(0!=uItem);
  511. if (pFR->m_fInObjectHelp)
  512. SendMessage(pFR->m_hWndObj, iMsg, wParam, lParam);
  513. }
  514. }
  515. else
  516. {
  517. //Forward the message on
  518. if (pFR->m_fInObjectHelp)
  519. {
  520. SendMessage(pFR->m_hWndObj, iMsg, wParam, lParam);
  521. break;
  522. }
  523. }
  524. }
  525. break;
  526. case WM_INITMENUPOPUP:
  527. /*
  528.  * If we're in the object's Help menu, forward to
  529.  * the object received in IOleInPlaceFrame::SetActiveObject
  530.  */
  531. if (pFR->m_fInObjectHelp && NULL!=pFR->m_hWndObj) 
  532. SendMessage(pFR->m_hWndObj, iMsg, wParam, lParam);
  533. //Skip the system menu
  534.             if (TRUE==(BOOL)HIWORD(lParam))
  535.                 break;
  536.     /*
  537.              * If we have an object, enable Close, otherwise
  538.              * enable Open.
  539.              */
  540.             hMenu=(HMENU)wParam;
  541.             if (hMenu==pFR->m_phMenu[0])
  542.                 {
  543.                 UINT uTempE=MF_BYCOMMAND | MF_ENABLED;
  544.                 UINT uTempD=MF_BYCOMMAND | MF_DISABLED | MF_GRAYED;
  545.                 EnableMenuItem(hMenu, IDM_FILEOPEN
  546.                     , pFR->m_fHaveObject ? uTempD : uTempE);
  547.                 EnableMenuItem(hMenu, IDM_FILECLOSE
  548.                     , pFR->m_fHaveObject ? uTempE : uTempD);
  549.                 }
  550.             
  551.             break;
  552.         case WM_COMMAND:
  553. if (pFR->m_fInObjectHelp)
  554. {
  555. SendMessage(pFR->m_hWndObj, iMsg, wParam, lParam);
  556. break;
  557. }
  558. else
  559.              return pFR->OnCommand(hWnd, wParam, lParam);
  560. case WM_ACTIVATEAPP:
  561. if (NULL!=pFR->m_pIOleIPActiveObject)
  562. {
  563. HRESULT hr;
  564. hr=pFR->m_pIOleIPActiveObject->OnFrameWindowActivate((BOOL)wParam);
  565. }
  566. break;
  567.         default:
  568.             return DefWindowProc(hWnd, iMsg, wParam, lParam);
  569.         }
  570.     return 0L;
  571.     }
  572. /*
  573.  * ClientWndProc
  574.  *
  575.  * Purpose:
  576.  *  Client window class procedure that's only used to paint a
  577.  *  message when we have a non-DocObject open.  Otherwise this
  578.  *  is completely hidden.
  579.  */
  580. LRESULT APIENTRY ClientWndProc(HWND hWnd, UINT iMsg
  581.     , WPARAM wParam, LPARAM lParam)
  582.     {
  583.     PCFrame         pFR;
  584. PAINTSTRUCT ps;
  585.     pFR=(PCFrame)GetWindowLong(hWnd, CLIENTWL_STRUCTURE);
  586.     switch (iMsg)
  587.         {
  588.         case WM_NCCREATE:
  589.             pFR=(PCFrame)((LPCREATESTRUCT)lParam)->lpCreateParams;
  590.             SetWindowLong(hWnd, CLIENTWL_STRUCTURE, (LONG)pFR);
  591.             return DefWindowProc(hWnd, iMsg, wParam, lParam);
  592.         case WM_PAINT:
  593. BeginPaint(hWnd, &ps);
  594. if (pFR->m_fHaveObject)
  595. {
  596. static TCHAR szMsg[]={TEXT("A non-DocObject is open or loaded. Use File/Close to destroy it.")};
  597. SetBkColor(ps.hdc, GetSysColor(COLOR_WINDOW));
  598. TextOut(ps.hdc, 0, 0, szMsg, lstrlen(szMsg));
  599. }
  600. EndPaint(hWnd, &ps);
  601.             break;
  602.         default:
  603.             return DefWindowProc(hWnd, iMsg, wParam, lParam);
  604.         }
  605.     return 0L;
  606.     }
  607. /*
  608.  * AboutProc
  609.  *
  610.  * Purpose:
  611.  *  Dialog procedure for the omnipresent About box.
  612.  *
  613.  * Parameters:
  614.  *  The standard.
  615.  *
  616.  * Return Value:
  617.  *  The value to be returned through the DialogBox call that
  618.  *  created the dialog.
  619.  *
  620.  */
  621. BOOL APIENTRY AboutProc(HWND hDlg, UINT iMsg
  622.     , WPARAM wParam, LPARAM lParam)
  623.     {
  624.     switch (iMsg)
  625.         {
  626.         case WM_INITDIALOG:
  627.             return TRUE;
  628.         case WM_COMMAND:
  629.             switch (LOWORD(wParam))
  630.                 {
  631.                 case IDOK:
  632.                     EndDialog(hDlg, TRUE);
  633.                 }
  634.             break;
  635.         }
  636.     return FALSE;
  637.     }
  638. /*
  639.  * IUnknown implementation
  640.  */
  641. /*
  642.  * CFrame::QueryInterface
  643.  * CFrame::AddRef
  644.  * CFrame::Release
  645.  */
  646. STDMETHODIMP CFrame::QueryInterface(REFIID riid, void **ppv)
  647.     {
  648.     /*
  649.      * We only know IOleInPlaceFrame and its base interfaces as well
  650.      * as a bogus IOleCommandTarget to make PowerPoint happy.
  651.  */
  652.     *ppv=NULL;
  653.     if (IID_IUnknown==riid || IID_IOleInPlaceUIWindow==riid
  654.         || IID_IOleWindow==riid || IID_IOleInPlaceFrame==riid)
  655.         *ppv=(IOleInPlaceFrame *)this;
  656. if (IID_IOleCommandTarget==riid)
  657.         *ppv=(IOleCommandTarget *)this;
  658.     if (NULL!=*ppv)
  659.         {
  660.         ((LPUNKNOWN)*ppv)->AddRef();
  661.         return NOERROR;
  662.         }
  663.     return E_NOINTERFACE;
  664.     }
  665. STDMETHODIMP_(ULONG) CFrame::AddRef(void)
  666.     {
  667.     return ++m_cRef;
  668.     }
  669. STDMETHODIMP_(ULONG) CFrame::Release(void)
  670.     {
  671.     //Nothing special happening here--frame's life if user-controlled.
  672.     return --m_cRef;
  673.     }
  674. /*
  675.  * IOleInPlaceFrame implementation
  676.  */
  677. /*
  678.  * CFrame::GetWindow
  679.  *
  680.  * Purpose:
  681.  *  Retrieves the handle of the window associated with the object
  682.  *  on which this interface is implemented.
  683.  *
  684.  * Parameters:
  685.  *  phWnd           HWND * in which to store the window handle.
  686.  *
  687.  * Return Value:
  688.  *  HRESULT         NOERROR if successful, E_FAIL if there is no
  689.  *                  window.
  690.  */
  691. STDMETHODIMP CFrame::GetWindow(HWND *phWnd)
  692.     {
  693.     *phWnd=m_hWnd;
  694.     return NOERROR;
  695.     }
  696. /*
  697.  * CFrame::ContextSensitiveHelp
  698.  *
  699.  * Purpose:
  700.  *  Instructs the object on which this interface is implemented to
  701.  *  enter or leave a context-sensitive help mode.
  702.  *
  703.  * Parameters:
  704.  *  fEnterMode      BOOL TRUE to enter the mode, FALSE otherwise.
  705.  *
  706.  * Return Value:
  707.  *  HRESULT         NOERROR
  708.  */
  709. STDMETHODIMP CFrame::ContextSensitiveHelp(BOOL fEnterMode)
  710.     {
  711.     /*
  712.      * Don't bother if there is no active object since we don't do
  713.      * context help on our own.
  714.      */
  715.     if (NULL==m_pIOleIPActiveObject)
  716.         return NOERROR;
  717.     //If the state changes, notify the active object.
  718.     if (m_fInContextHelp!=fEnterMode)
  719.         {
  720.         m_fInContextHelp=fEnterMode;
  721.         m_pIOleIPActiveObject->ContextSensitiveHelp(fEnterMode);
  722.         }
  723.     return NOERROR;
  724.     }
  725. /*
  726.  * CFrame::GetBorder
  727.  *
  728.  * Purpose:
  729.  *  Returns the rectangle in which the container is willing to
  730.  *  negotiate about an object's adornments.
  731.  *
  732.  * Parameters:
  733.  *  prcBorder       LPRECT in which to store the rectangle.
  734.  *
  735.  * Return Value:
  736.  *  HRESULT         NOERROR if all is well, INPLACE_E_NOTOOLSPACE
  737.  *                  if there is no negotiable space.
  738.  */
  739. STDMETHODIMP CFrame::GetBorder(LPRECT prcBorder)
  740.     {
  741.     if (NULL==prcBorder)
  742.         return E_INVALIDARG;
  743.     //We return all the client area space
  744.     GetClientRect(m_hWnd, prcBorder);
  745.     return NOERROR;
  746.     }
  747. /*
  748.  * CFrame::RequestBorderSpace
  749.  *
  750.  * Purpose:
  751.  *  Asks the container if it can surrender the amount of space
  752.  *  in pBW that the object would like for it's adornments.  The
  753.  *  container does nothing but validate the spaces on this call.
  754.  *
  755.  * Parameters:
  756.  *  pBW             LPCBORDERWIDTHS containing the requested space.
  757.  *                  The values are the amount of space requested
  758.  *                  from each side of the relevant window.
  759.  *
  760.  * Return Value:
  761.  *  HRESULT         NOERROR if we can give up space,
  762.  *                  INPLACE_E_NOTOOLSPACE otherwise.
  763.  */
  764. STDMETHODIMP CFrame::RequestBorderSpace(LPCBORDERWIDTHS pBW)
  765.     {
  766.     //Framer has no border space restrictions
  767.     return NOERROR;
  768.     }
  769. /*
  770.  * CFrame::SetBorderSpace
  771.  *
  772.  * Purpose:
  773.  *  Called when the object now officially requests that the
  774.  *  container surrender border space it previously allowed
  775.  *  in RequestBorderSpace.  The container should resize windows
  776.  *  appropriately to surrender this space.
  777.  *
  778.  * Parameters:
  779.  *  pBW             LPCBORDERWIDTHS containing the amount of space
  780.  *                  from each side of the relevant window that the
  781.  *                  object is now reserving.
  782.  *
  783.  * Return Value:
  784.  *  HRESULT         NOERROR
  785.  */
  786. STDMETHODIMP CFrame::SetBorderSpace(LPCBORDERWIDTHS pBW)
  787.     {
  788.     RECT            rc;
  789.     /*
  790.      * Since we have no tools, we can accept anything the object sends
  791.      * and must therefore adjust the client-area window accordingly.
  792.      */
  793.     /*
  794.      * If pBW is NULL, the object is not interested in tools, so we
  795.      * don't have to do anything.  In either case we need to save
  796.      * the toolspace allocations in order to resize the client window
  797.      * correctly.
  798.      */
  799.     if (NULL==pBW)
  800.         {
  801.         if (!m_fOurMenuShowing)
  802.             SetMenu(NULL, NULL, NULL);
  803.         SetRect(&m_bwIP, 0, 0, 0, 0);
  804.         GetClientRect( m_hWnd, &rc );
  805.         }
  806.     else
  807.         {
  808.         GetClientRect(m_hWnd, &rc);
  809.         rc.left  +=pBW->left;
  810.         rc.right -=pBW->right;
  811.         rc.top   +=pBW->top;
  812.         rc.bottom-=pBW->bottom;
  813.         m_bwIP=*pBW;
  814.         }
  815. ResizeClientWindow(rc.left, rc.top, rc.right-rc.left
  816. , rc.bottom-rc.top);
  817.     return NOERROR;
  818.     }
  819. /*
  820.  * CFrame::SetActiveObject
  821.  *
  822.  * Purpose:
  823.  *  Provides the container with the object's IOleInPlaceActiveObject
  824.  *  pointer
  825.  *
  826.  * Parameters:
  827.  *  pIIPActiveObj   LPOLEINPLACEACTIVEOBJECT of interest.
  828.  *  pszObj          LPCOLESTR naming the object.  Not used.
  829.  *
  830.  * Return Value:
  831.  *  HRESULT         NOERROR
  832.  */
  833. STDMETHODIMP CFrame::SetActiveObject
  834.     (LPOLEINPLACEACTIVEOBJECT pIIPActiveObj, LPCOLESTR pszObj)
  835.     {
  836.     if (NULL!=m_pIOleIPActiveObject)
  837.         m_pIOleIPActiveObject->Release();
  838.     //NULLs m_pIOleIPActiveObject if pIIPActiveObj is NULL
  839.     m_pIOleIPActiveObject=pIIPActiveObj;
  840.     if (NULL!=m_pIOleIPActiveObject)
  841.         m_pIOleIPActiveObject->AddRef();
  842. m_pIOleIPActiveObject->GetWindow(&m_hWndObj);
  843.     return NOERROR;
  844.     }
  845. /*
  846.  * CFrame::InsertMenus
  847.  *
  848.  * Purpose:
  849.  *  Instructs the container to place its in-place menu items where
  850.  *  necessary in the given menu and to fill in elements 0, 2, and 4
  851.  *  of the OLEMENUGROUPWIDTHS array to indicate how many top-level
  852.  *  items are in each group.
  853.  *
  854.  * Parameters:
  855.  *  hMenu           HMENU in which to add popups.
  856.  *  pMGW            LPOLEMENUGROUPWIDTHS in which to store the
  857.  *                  width of each container menu group.
  858.  *
  859.  * Return Value:
  860.  *  HRESULT         NOERROR
  861.  */
  862. STDMETHODIMP CFrame::InsertMenus(HMENU hMenu
  863.     , LPOLEMENUGROUPWIDTHS pMGW)
  864.     {    
  865. //Copy our File menu into the shared menu.    
  866.     InsertMenu(hMenu, 0, MF_BYPOSITION | MF_POPUP, (UINT)m_phMenu[0]
  867.         , TEXT("&File"));
  868.     pMGW->width[0]=1;
  869.     pMGW->width[2]=0;
  870.     pMGW->width[4]=0;
  871. /*
  872.  * Add the special help menu which is the first item in
  873.  * the m_hMenuHelp popup that's sitting around.
  874.  */
  875. InsertMenu(hMenu, 1, MF_BYPOSITION | MF_POPUP
  876.     , (UINT)m_hMenuHelp, TEXT("&Help"));
  877. //Tell the object we added our Help menu
  878. pMGW->width[5]=1;    
  879.     return NOERROR;
  880.     }
  881. /*
  882.  * CFrame::SetMenu
  883.  *
  884.  * Purpose:
  885.  *  Instructs the container to replace whatever menu it's currently
  886.  *  using with the given menu and to call OleSetMenuDescritor so OLE
  887.  *  knows to whom to dispatch messages.
  888.  *
  889.  * Parameters:
  890.  *  hMenu           HMENU to show.
  891.  *  hOLEMenu        HOLEMENU to the menu descriptor.
  892.  *  hWndObj         HWND of the active object to which messages are
  893.  *                  dispatched.
  894.  *
  895.  * Return Value:
  896.  *  HRESULT         NOERROR
  897.  */
  898. STDMETHODIMP CFrame::SetMenu(HMENU hMenu, HOLEMENU hOLEMenu
  899.     , HWND hWndObj)
  900.     {
  901.     HRESULT         hr;
  902.     /*
  903.      * Our responsibilities here are to put the menu on the frame
  904.      * window and call OleSetMenuDescriptor.
  905.      */
  906.     if (NULL==hMenu)
  907.         {
  908.         //Prevent redundant calls, or debug warnings on startup.
  909.         if (NULL==m_hMenuTop)
  910.             return NOERROR;
  911.         hMenu=m_hMenuTop;
  912.         m_hMenuTop=NULL;
  913.         m_fOurMenuShowing=TRUE;
  914.         }
  915.     else
  916.         {
  917.         m_hMenuTop=m_hMenuOrg;
  918.         m_fOurMenuShowing=FALSE;
  919. /*
  920.  * Check if our Help menu has anything added to it.  If so, then
  921.  * remember to forward menu messages.  If not, remove the Help
  922.  * menu altogether (destroying it after removing our normal Help
  923.  * popup, as we also do in RemoveMenus.
  924.  */
  925. if (CHELPITEMS!=GetMenuItemCount(m_hMenuHelp))
  926. m_fUsingOurHelp=TRUE;
  927. else
  928. {
  929. UINT i, cItems;
  930. cItems=GetMenuItemCount(hMenu);
  931. //Find m_hMenuHelp in the menu and remove it.
  932. for (i=0; i < cItems; i++)
  933. {
  934. if (GetSubMenu(hMenu, i)==m_hMenuHelp)
  935. {
  936. RemoveMenu(hMenu, i, MF_BYPOSITION);
  937. break;
  938. }
  939. }
  940. }
  941.         }
  942.     if (NULL!=hMenu)
  943.         ::SetMenu(m_hWnd, hMenu);
  944.     DrawMenuBar(m_hWnd);
  945.     hr=OleSetMenuDescriptor(hOLEMenu, m_hWnd, hWndObj, NULL, NULL);
  946.     return hr;
  947.     }
  948. /*
  949.  * CFrame::RemoveMenus
  950.  *
  951.  * Purpose:
  952.  *  Asks the container to remove any menus it put into hMenu in
  953.  *  InsertMenus.
  954.  *
  955.  * Parameters:
  956.  *  hMenu           HMENU from which to remove the container's
  957.  *                  items.
  958.  *
  959.  * Return Value:
  960.  *  HRESULT         NOERROR
  961.  */
  962. STDMETHODIMP CFrame::RemoveMenus(HMENU hMenu)
  963.     {
  964.     int         cItems, i, j;
  965.     HMENU       hMenuT;
  966. /*
  967.      * To be defensive, loop through this menu removing anything
  968.      * we recognize (that is, anything in m_phMenu) just in case
  969.      * the server didn't clean it up right.  At least we can
  970.      * give ourselves the prophylactic benefit.
  971.      */
  972.     if (NULL==hMenu)
  973.         return NOERROR;
  974.     cItems=GetMenuItemCount(hMenu);
  975.     /*
  976.      * Walk backwards down the menu.  For each popup, see if it
  977.      * matches any other popup we know about, and if so, remove
  978.      * it from the shared menu.
  979.      */
  980.     for (i=cItems; i >=0; i--)
  981.         {
  982.         hMenuT=GetSubMenu(hMenu, i);
  983.         for (j=0; j <= CMENUS; j++)
  984.             {
  985. //Remove any owned popup, or our special help menu
  986.             if (hMenuT==m_phMenu[j]
  987.                 || (hMenuT==m_hMenuHelp && m_hMenuHelp!=NULL))
  988.                 RemoveMenu(hMenu, i, MF_BYPOSITION);
  989.             }
  990.         }
  991. m_fUsingOurHelp=FALSE;
  992.     //The menu should now be empty.
  993.     return NOERROR;
  994.     }
  995. /*
  996.  * CFrame::SetStatusText
  997.  *
  998.  * Purpose:
  999.  *  Asks the container to place some text in a status line, if one
  1000.  *  exists.  If the container does not have a status line it
  1001.  *  should return E_FAIL here in which case the object could
  1002.  *  display its own.
  1003.  *
  1004.  * Parameters:
  1005.  *  pszText         LPCOLESTR to display.
  1006.  *
  1007.  * Return Value:
  1008.  *  HRESULT         NOERROR if successful, S_TRUNCATED if not all
  1009.  *                  of the text could be displayed, or E_FAIL if
  1010.  *                  the container has no status line.
  1011.  */
  1012. STDMETHODIMP CFrame::SetStatusText(LPCOLESTR pszText)
  1013.     {
  1014.     //We have no status line...
  1015.     return E_NOTIMPL;
  1016.     }
  1017. /*
  1018.  * CFrame::EnableModeless
  1019.  *
  1020.  * Purpose:
  1021.  *  Instructs the container to show or hide any modeless popup
  1022.  *  windows that it may be using.
  1023.  *
  1024.  * Parameters:
  1025.  *  fEnable         BOOL indicating to enable/show the windows
  1026.  *                  (TRUE) or to hide them (FALSE).
  1027.  *
  1028.  * Return Value:
  1029.  *  HRESULT         NOERROR
  1030.  */
  1031. STDMETHODIMP CFrame::EnableModeless(BOOL fEnable)
  1032.     {
  1033.     return NOERROR;
  1034.     }
  1035. /*
  1036.  * CFrame::TranslateAccelerator
  1037.  *
  1038.  * Purpose:
  1039.  *  When dealing with an in-place object from an EXE server, this
  1040.  *  is called to give the container a chance to process accelerators
  1041.  *  after the server has looked at the message.
  1042.  *
  1043.  * Parameters:
  1044.  *  pMSG            LPMSG for the container to examine.
  1045.  *  wID             WORD the identifier in the container's
  1046.  *                  accelerator table (from IOleInPlaceSite
  1047.  *                  ::GetWindowContext) for this message (OLE does
  1048.  *                  some translation before calling).
  1049.  *
  1050.  * Return Value:
  1051.  *  HRESULT         NOERROR if the keystroke was used,
  1052.  *                  S_FALSE otherwise.
  1053.  */
  1054. STDMETHODIMP CFrame::TranslateAccelerator(LPMSG pMSG, WORD wID)
  1055.     {
  1056.     /*
  1057.      * wID already has anything translated from m_hAccel for us,
  1058.      * so we can just check for the commands we want and process
  1059.      * them instead of calling TranslateAccelerator which would be
  1060.      * redundant and which also has a possibility of dispatching to
  1061.      * the wrong window.
  1062.      */
  1063.     if (IDM_ENTERCONTEXTHELP==wID || IDM_ESCAPECONTEXTHELP==wID)
  1064.         {
  1065.         //wID properly expands to 32-bits
  1066.         OnCommand(m_hWnd, (WPARAM)wID, 0L);
  1067.         return NOERROR;
  1068.         }
  1069.     return S_FALSE;
  1070.     }
  1071. /*
  1072.  * IOleCommandTarget methods, provided to make PowerPoint happy
  1073.  * with this frame.
  1074.  */
  1075. STDMETHODIMP CFrame::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds
  1076.     , OLECMD *prgCmds, OLECMDTEXT *pCmdText)
  1077. {
  1078. return OLECMDERR_E_UNKNOWNGROUP;
  1079. }
  1080.         
  1081. STDMETHODIMP CFrame::Exec(const GUID *pguidCmdGroup, DWORD nCmdID
  1082.     , DWORD nCmdexecopt, VARIANTARG *pvaIn, VARIANTARG *pvaOut)
  1083. {
  1084. return OLECMDERR_E_UNKNOWNGROUP;
  1085. }
  1086.