home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c480 / 17.ddi / SAMPLES / CLIDEMO / CLIDEMO.C_ / CLIDEMO.C
Encoding:
C/C++ Source or Header  |  1993-02-08  |  37.3 KB  |  1,033 lines

  1. /*
  2.  * clidemo.c - OLE client application sample code
  3.  *
  4.  * Created by Microsoft Corporation.
  5.  * (c) Copyright Microsoft Corp. 1990 - 1992  All Rights Reserved
  6.  *
  7.  */
  8.  
  9.  /***************************************************************************
  10.  * IMPORTANT - README:
  11.  * OLE client applications are windows programs which use the OLE client
  12.  * APIs.  Therefore it is imperative that you understand how these APIs
  13.  * operate. Most importantly it is essential that you keep in mind which
  14.  * procedure calls result in asynchronous states: a state where the operation
  15.  * is not truely complete after a return from the call.
  16.  *
  17.  * Many functions produce asynchronous states, for example, OleActivate,
  18.  * OleClose, OleCopyFromLink, OleCreate ... Reference your SDK manual for
  19.  * a complete list.
  20.  *
  21.  * So whenever you call any of these library functions keep in mind that
  22.  * the operation is not necessarily complete once a return is made.
  23.  * These operations require communications with a server application.  With
  24.  * OLE the inter-application communication is done through DDE.  In order
  25.  * for a DDE conversation to complete several DDE messages need to be
  26.  * sent and recieved by both the server and client OLE DLLs.  So, the
  27.  * asynchronous operations will not complete until the client application
  28.  * enters a message dipatch loop.  Therefore, it is necessary to enter
  29.  * a dispatch loop and wait for completion.  It is not necessary to block
  30.  * all other operation; however, it is very important to coordinate the
  31.  * user activity to prevent disastrous re-entry cases.
  32.  *
  33.  * In this application I have written a macro to prevent re-entry
  34.  * problems.  Namely: ANY_OBJECT_BUSY which prevents a user from initiating
  35.  * an action which will result in an asynchronous call if there is an object
  36.  * already in an asynchronous state.
  37.  *
  38.  * The following is brief summary of the three macros:
  39.  *
  40.  * ANY_OBJECT_BUSY: checks to see if any object in the document is busy.
  41.  *              This prevents a new document from being saved to file if there are
  42.  *              objects in asynchronous states.
  43.  *
  44.  * So, the problem is that we have to enter a message dispatch loop in order
  45.  * to let DDE messages get through so that asynchronous operations can finish.
  46.  * And while we are in the message dispatch loops (WaitForObject or WaitForAllObjects)
  47.  * we have to prevent the user from doing things that can't be done when an
  48.  * object(s) is busy.  Yes, it is confusing , but, the end result is a super
  49.  * cool application that can have linked and embbeded objects!
  50.  ***************************************************************************/
  51.  
  52. //--- INCLUDES ---
  53. //The order of the includes matters for compile efficiency ... /YX
  54.  
  55. #include <windows.h>                   //- WINDOWS
  56. #include <ole.h>                       //- OLE structs and defines
  57. #include "demorc.h"                    //- header for resource file
  58. #include "global.h"                    //- global app variables
  59.  
  60. #include <shellapi.h>                  //- Shell, drag and drop headers
  61. #include "register.h"
  62. #include "clidemo.h"                   //- app includes:
  63. #include "stream.h"
  64. #include "object.h"
  65. #include "dialog.h"
  66. #include "utility.h"
  67.  
  68. //--- VARIABLES ---
  69.  
  70. //-- Global
  71. BOOL              fRetry = FALSE;
  72. HWND              hwndFrame;           //- main window
  73. HANDLE            hAccTable;           //- accelerator table
  74. HANDLE          hInst;           //- Instance Handle
  75. char              szFrameClass[] = "CliDemo";//- main window class name
  76. char              szItemClass[]  = "ItemClass";//- item window class name
  77. char              szAppName[CBMESSAGEMAX];//- Application name
  78. int               iObjects = 0;        //- object count
  79. int               iObjectNumber = 0;   //- object number for object name
  80. char              szFileName[CBPATHMAX];
  81.                                        //- ClipBoard formats:
  82. OLECLIPFORMAT     vcfLink;             //- "ObjectLink"
  83. OLECLIPFORMAT     vcfNative;           //- "Native"
  84. OLECLIPFORMAT     vcfOwnerLink;        //- "OwnerLink"
  85.  
  86. extern int        giXppli;             //- pixels per logical inch along width
  87. extern int        giYppli;             //- pixels per logical inch along height
  88.  
  89. /***************************************************************************
  90.  * WinMain() - Main Windows routine
  91.  ***************************************************************************/
  92.  
  93. int PASCAL WinMain(                    //- ENTRY:
  94.    HANDLE         hInstance,           //- standard windows entry
  95.    HANDLE         hPrevInstance,
  96.    LPSTR          lpCmdLine,
  97.    int            nCmdShow
  98. ){
  99.     hInst = hInstance;
  100.  
  101.     if (!hPrevInstance)
  102.         if (!InitApplication(hInst))   //- register window classes
  103.             return FALSE;
  104.  
  105.  
  106.     if (!InitInstance(hInst))          //- create window instance
  107.         return FALSE;
  108.  
  109.     OfnInit(hInst);                    //- setup to use <commdlg.dll>
  110.  
  111.                                        //- register clipboard formats
  112.                                        //- used for OLE
  113.     vcfLink      = RegisterClipboardFormat("ObjectLink");
  114.     vcfNative    = RegisterClipboardFormat("Native");
  115.     vcfOwnerLink = RegisterClipboardFormat("OwnerLink");
  116.  
  117.  
  118.     ShowWindow(hwndFrame, nCmdShow);
  119.     UpdateWindow(hwndFrame);
  120.     ProcessCmdLine(lpCmdLine);
  121.  
  122.     while (ProcessMessage(hwndFrame, hAccTable)) ;
  123.  
  124.     return FALSE;
  125. }
  126.  
  127. /***************************************************************************
  128.  * InitApplication()
  129.  *
  130.  * registers the window classes used by the application.
  131.  *
  132.  * Returns BOOL:      - TRUE if successful.
  133.  ***************************************************************************/
  134.  
  135. static BOOL InitApplication(           //- ENTRY:
  136.    HANDLE         hInst                //- instance handle
  137. ){                                     //- LOCAL:
  138.    WNDCLASS       wc;                  //- temp wind-class structure
  139.  
  140.    wc.style          = NULL;
  141.    wc.lpfnWndProc    = FrameWndProc;
  142.    wc.cbClsExtra     = 0;
  143.    wc.cbWndExtra     = 0;
  144.    wc.hInstance      = hInst;
  145.    wc.hIcon          = LoadIcon(hInst, MAKEINTRESOURCE(ID_APPLICATION));
  146.    wc.hCursor        = LoadCursor(NULL, IDC_ARROW);
  147.    wc.hbrBackground  = COLOR_APPWORKSPACE + 1;
  148.    wc.lpszMenuName   = MAKEINTRESOURCE(ID_APPLICATION);
  149.    wc.lpszClassName  = szFrameClass;
  150.  
  151.    if (!RegisterClass(&wc))
  152.       return FALSE;
  153.                                        //- application item class
  154.    wc.style          = CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW;
  155.    wc.lpfnWndProc    = ItemWndProc;
  156.    wc.hIcon          = NULL;
  157.    wc.cbWndExtra     = sizeof(APPITEMPTR);
  158.    wc.lpszMenuName   = NULL;
  159.    wc.lpszClassName  = szItemClass;
  160.  
  161.    if (!RegisterClass(&wc))
  162.       return FALSE;
  163.  
  164.    return TRUE;
  165.  
  166. }
  167.  
  168. /***************************************************************************
  169.  * InitInstance()
  170.  *
  171.  * create the main application window.
  172.  *
  173.  * Returns BOOL:      - TRUE if successful else FALSE.
  174.  ***************************************************************************/
  175.  
  176. static BOOL InitInstance(              //- ENTRY:
  177.    HANDLE      hInst            //- instance handel
  178. ){
  179.    HDC  hDC;
  180.  
  181.    hAccTable = LoadAccelerators(hInst, MAKEINTRESOURCE(ID_APPLICATION));
  182.  
  183.    if (!(hwndFrame =
  184.       CreateWindow(
  185.          szFrameClass, "",
  186.          WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
  187.          CW_USEDEFAULT, CW_USEDEFAULT,
  188.          CW_USEDEFAULT, CW_USEDEFAULT,
  189.          NULL,
  190.          NULL,
  191.          hInst,
  192.          NULL
  193.       )))
  194.       return FALSE;                    //- ERROR return
  195.  
  196.    LoadString(hInst, IDS_APPNAME, szAppName, CBMESSAGEMAX);
  197.    DragAcceptFiles(hwndFrame, TRUE);   //- allow dragged and dropped files
  198.  
  199.    // Initialize global variables with LOGPIXELSX and LOGPIXELSY
  200.  
  201.    hDC    = GetDC (NULL);       // Get the hDC of the desktop window
  202.    giXppli = GetDeviceCaps (hDC, LOGPIXELSX);
  203.    giYppli = GetDeviceCaps (hDC, LOGPIXELSY);
  204.    ReleaseDC (NULL, hDC);
  205.  
  206.  
  207.    return TRUE;                        //- SUCCESS return
  208.  
  209. }
  210.  
  211. /***************************************************************************
  212.  *  ProcessCmdLine()
  213.  *
  214.  *  process command line getting any command arguments.
  215.  ***************************************************************************/
  216.  
  217. void ProcessCmdLine(                   //- ENTRY:
  218.    LPSTR          lpCmdLine            //- command line argument
  219. ){                                     //- LOCAL:
  220.    LPSTR          lpstrExt = lpCmdLine;//- pointer to file extension
  221.    OFSTRUCT       ofs;
  222.  
  223.    if (*lpCmdLine)
  224.    {                                   //- look for file extension
  225.       while (*lpstrExt && *lpstrExt != '.')
  226.          lpstrExt = AnsiNext(lpstrExt);
  227.  
  228.       lstrcpy(szFileName, lpCmdLine);
  229.       if (!(*lpstrExt))                //- append default extension
  230.       {
  231.          lstrcat(szFileName,".");
  232.          lstrcat(szFileName,szDefExtension);
  233.       }
  234.                                        //- get the files fully
  235.       OpenFile(szFileName, &ofs, OF_PARSE);//- qualified name
  236.       lstrcpy(szFileName, ofs.szPathName);
  237.    }
  238.    else
  239.       *szFileName = NULL;
  240.                                        //- pass filename to main winproc
  241.    SendMessage(hwndFrame,WM_INIT,NULL,(long)NULL);
  242.  
  243. }
  244.  
  245.  
  246. /***************************************************************************
  247.  *  FrameWndProc()
  248.  *
  249.  *  Message handler for the application frame window.
  250.  *
  251.  *  Returns long - Variable, depends on message.
  252.  ***************************************************************************/
  253.  
  254. long FAR PASCAL __export FrameWndProc( //- ENTRY:
  255.    HWND           hwnd,                //- standard wind-proc parameters
  256.    UINT       msg,
  257.    WPARAM      wParam,
  258.    LPARAM      lParam
  259. ){                                     //- LOCAL:
  260.                                        //- ^ Document file name
  261.    static LHCLIENTDOC   lhcDoc;        //- Document Handle
  262.    static LPOLECLIENT   lpClient;      //- pointer to client
  263.    static LPAPPSTREAM   lpStream;      //- pointer to stream vtbl
  264.    APPITEMPTR           pItem;         //- application item pointer
  265.  
  266.    switch (msg)
  267.    {
  268.       case WM_INIT:                    //- user defined message
  269.          if (!InitAsOleClient(hInst, hwnd, szFileName, &lhcDoc, &lpClient, &lpStream))
  270.             DestroyWindow(hwnd);
  271.          break;
  272.                                        //- the following three messages are
  273.                                        //- used to avoid problems with OLE
  274.                                        //- see the comment in object.h
  275.       case WM_DELETE:                  //- user defined message
  276.          pItem = (APPITEMPTR) wParam;  //- delete object
  277.          WaitForObject(pItem);
  278.          ObjDelete(pItem,DELETE);
  279.          if (lParam)
  280.             cOleWait--;
  281.          break;
  282.  
  283.       case WM_ERROR:                   //- user defined message
  284.          ErrorMessage(wParam);         //- display error message
  285.          break;
  286.  
  287.       case WM_RETRY:                   //- user defined message
  288.          RetryMessage((APPITEMPTR)wParam, RD_RETRY | RD_CANCEL);
  289.          break;
  290.  
  291.       case WM_INITMENU:
  292.          UpdateMenu((HMENU)wParam);
  293.          break;
  294.  
  295.       case WM_COMMAND:
  296.          pItem = GetTopItem();
  297.          switch (wParam)
  298.          {
  299.             case IDM_NEW:
  300.                ANY_OBJECT_BUSY;
  301.                NewFile(szFileName,&lhcDoc,lpStream);
  302.                break;
  303.  
  304.             case IDM_OPEN:
  305.                ANY_OBJECT_BUSY;
  306.                MyOpenFile(szFileName,&lhcDoc,lpClient,lpStream);
  307.                break;
  308.  
  309.             case IDM_SAVE:
  310.                ANY_OBJECT_BUSY;
  311.                SaveFile(szFileName,lhcDoc,lpStream);
  312.                break;
  313.  
  314.             case IDM_SAVEAS:
  315.                ANY_OBJECT_BUSY;
  316.                SaveasFile(szFileName,lhcDoc,lpStream);
  317.                break;
  318.  
  319.             case IDM_ABOUT:
  320.                AboutBox();
  321.                break;
  322.  
  323.             case IDM_INSERT:
  324.                ANY_OBJECT_BUSY;
  325.                ObjInsert(lhcDoc, lpClient);
  326.                break;
  327.  
  328.             case IDM_INSERTFILE:
  329.                ANY_OBJECT_BUSY;
  330.                ObjCreateFromTemplate(lhcDoc,lpClient);
  331.                break;
  332.  
  333.             case IDM_PASTE:
  334.             case IDM_PASTELINK:
  335.                ANY_OBJECT_BUSY;
  336.                ObjPaste(wParam == IDM_PASTE,lhcDoc,lpClient);
  337.                break;
  338.  
  339.             case IDM_LINKS:
  340.                ANY_OBJECT_BUSY;
  341.                pItem = GetTopItem();
  342.                LinkProperties();
  343.                break;
  344.  
  345.             case IDM_EXIT:
  346.                ANY_OBJECT_BUSY;
  347.                SendMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
  348.                break;
  349.  
  350.             case IDM_COPY:
  351.             case IDM_CUT:
  352.                ANY_OBJECT_BUSY;
  353.  
  354.                if (!ObjCopy(pItem))
  355.                {
  356.                   ErrorMessage((wParam == IDM_CUT) ?
  357.                      E_CLIPBOARD_CUT_FAILED : E_CLIPBOARD_COPY_FAILED);
  358.                   break;
  359.                }
  360.  
  361.                if (wParam == IDM_COPY)
  362.                   break;
  363.  
  364.             case IDM_CLEAR:            //- CUT falls through to clear
  365.                ANY_OBJECT_BUSY;
  366.                ClearItem(pItem);
  367.                break;
  368.  
  369.             case IDM_CLEARALL:
  370.                ANY_OBJECT_BUSY;
  371.                ClearAll(lhcDoc,DELETE);
  372.                Dirty(DOC_DIRTY);
  373.                break;
  374.  
  375.             default:
  376.                if( (wParam >= IDM_VERBMIN) && (wParam <= IDM_VERBMAX) )
  377.                {
  378.                   ANY_OBJECT_BUSY;
  379.                   ExecuteVerb(wParam - IDM_VERBMIN,pItem);
  380.                   break;
  381.                }
  382.                return DefWindowProc(hwnd, msg, wParam, lParam);
  383.          }
  384.          break;
  385.  
  386.       case WM_DROPFILES:
  387.          ANY_OBJECT_BUSY;
  388.          ObjCreateWrap(wParam, lhcDoc, lpClient);
  389.          break;
  390.  
  391.       case WM_CLOSE:
  392.          ANY_OBJECT_BUSY;
  393.          if (!SaveAsNeeded(szFileName, lhcDoc, lpStream))
  394.             break;
  395.          DeregDoc(lhcDoc);
  396.          DestroyWindow(hwnd);
  397.          break;
  398.  
  399.       case WM_DESTROY:
  400.          EndStream(lpStream);
  401.          EndClient(lpClient);
  402.          PostQuitMessage(0);
  403.          break;
  404.  
  405.       case WM_QUERYENDSESSION:         //- don't let windows terminate
  406.          return (QueryEndSession(szFileName,lhcDoc, lpStream));
  407.  
  408.       default:
  409.          return DefWindowProc(hwnd, msg, wParam, lParam);
  410.    }
  411.    return 0L;
  412.  
  413. }
  414.  
  415. /***************************************************************************
  416.  * InitAsOleClient()
  417.  *
  418.  * Initiates the creation of stream and client vtbls.  These vtbls are very
  419.  * important for the proper operation of this application.  The stream vtbl
  420.  * lets the OLE librarys know where the location of the stream I/O routines
  421.  * reside.  The stream routines are used by OleLoadFromStream and the like.
  422.  * The client vtbl is used to hold the pointer to the CallBack function.
  423.  * IMPORTANT: both the client and the stream structures have pointers to
  424.  * vtbls which have the pointers to the functions.  Therefore, it is
  425.  * necessary to allocate space for the vtbl and the client structure
  426.  * which has the pointer to the vtbl.
  427.  **************************************************************************/
  428.  
  429. static BOOL InitAsOleClient(           //- ENTRY:
  430.    HANDLE         hInstance,           //- applicaion instance handle
  431.    HWND           hwnd,                //- main window handle
  432.    PSTR           pFileName,           //- document file name
  433.    LHCLIENTDOC    *lhcDoc,             //- pointer to document Handle
  434.    LPOLECLIENT    *lpClient,           //- pointer to client pointer
  435.    LPAPPSTREAM    *lpStream            //- pointer to APPSTREAM pointer
  436. ){
  437.                                        //- initiate client vtbl creation
  438.    if (!(*lpClient = InitClient(hInstance)))
  439.    {
  440.       SendMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
  441.       return FALSE;                    //- ERROR return
  442.    }
  443.                                        //- initiate stream vtbl creation
  444.    if (!(*lpStream = InitStream(hInstance)))
  445.    {
  446.       SendMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
  447.       return FALSE;                    //- ERROR return
  448.    }
  449.  
  450.    if (*pFileName && RegDoc(pFileName,lhcDoc)
  451.        && LoadFile(pFileName,*lhcDoc,*lpClient,*lpStream))
  452.    {
  453.       SetTitle(pFileName);
  454.       return TRUE;                     //- SUCCESS return
  455.    }
  456.  
  457.    NewFile(pFileName, lhcDoc, *lpStream);
  458.    return TRUE;                        //- SUCCESS return
  459.  
  460. }                                      //- SUCCESS return
  461.  
  462. /****************************************************************************
  463.  *  InitClient()
  464.  *
  465.  *  Initialize the OLE client structure, create and fill the OLECLIENTVTBL
  466.  *  structure.
  467.  *
  468.  *  Returns LPOLECLIENT - if successful a pointer to a client structure
  469.  *                        , otherwise NULL.
  470.  ***************************************************************************/
  471.  
  472. static LPOLECLIENT InitClient(         //- ENTRY:
  473.    HANDLE hInstance                    //- application instance handle
  474. ){                                     //- LOCAL:
  475.    LPOLECLIENT lpClient=NULL;          //- pointer to client struct
  476.                                        //- Allocate vtbls
  477.    if (!(lpClient = (LPOLECLIENT)GlobalLock(
  478.          GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(OLECLIENT))
  479.       )))
  480.       goto Error;                      //- ERROR jump
  481.  
  482.    if (!(lpClient->lpvtbl = (LPOLECLIENTVTBL)GlobalLock(
  483.             GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(OLECLIENTVTBL))
  484.       )))
  485.       goto Error;                      //- ERROR jump
  486.                                        //- set the CALLBACK function
  487.                                        //- pointer
  488.    (FARPROC)lpClient->lpvtbl->CallBack    = MakeProcInstance((FARPROC)CallBack, hInst);
  489.  
  490.    return lpClient;                    //- SUCCESS return
  491.  
  492. Error:                                 //- ERROR Tag
  493.  
  494.    ErrorMessage(E_FAILED_TO_ALLOC);
  495.    EndClient(lpClient);                //- free any allocated space
  496.  
  497.    return NULL;                        //- ERROR return
  498.  
  499. }
  500.  
  501. /****************************************************************************
  502.  *  InitStream()
  503.  *
  504.  *  Create and fill the STREAMVTBL. Create a stream structure and initialize
  505.  *  pointer to stream vtbl.
  506.  *
  507.  *  Returns LPAPPSTREAM - if successful a pointer to a stream structure
  508.  *                        , otherwise NULL .
  509.  ***************************************************************************/
  510.  
  511. static LPAPPSTREAM InitStream(         //- ENTRY:
  512.    HANDLE hInstance                    //- handle to application instance
  513. ){                                     //- LOCAL:
  514.    LPAPPSTREAM lpStream = NULL;        //- pointer to stream structure
  515.  
  516.    if (!(lpStream = (LPAPPSTREAM)GlobalLock(
  517.          GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(APPSTREAM))
  518.       )))
  519.       goto Error;                      //- ERROR jump
  520.  
  521.    if (!(lpStream->olestream.lpstbl = (LPOLESTREAMVTBL)GlobalLock(
  522.          GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(OLESTREAMVTBL))
  523.       )))
  524.       goto Error;                      //- ERROR jump
  525.  
  526.                                        //- set stream func. pointers
  527.    (FARPROC)lpStream->olestream.lpstbl->Get =
  528.               MakeProcInstance((FARPROC)ReadStream, hInst);
  529.    (FARPROC)lpStream->olestream.lpstbl->Put =
  530.               MakeProcInstance((FARPROC)WriteStream, hInst);
  531.  
  532.    return lpStream;                    //- SUCCESS return
  533.  
  534. Error:                                 //- ERROR Tag
  535.  
  536.    ErrorMessage(E_FAILED_TO_ALLOC);
  537.    EndStream(lpStream);
  538.  
  539.    return NULL;                        //- ERROR return
  540.  
  541. }
  542.  
  543. /***************************************************************************
  544.  *  UpdateMenu()
  545.  *
  546.  *  Enabling or disable menuitems based upon program state.
  547.  ***************************************************************************/
  548.  
  549. static void UpdateMenu(                //- ENTRY:
  550.    HMENU       hMenu                   //- menu handle to updated
  551. ){                                     //- LOCAL:
  552.    int         mf;                     //- generic menu flag
  553.    APPITEMPTR  paItem;                 //- app item pointer
  554.    HMENU       hSub;
  555.                                        //- there must be at least on object
  556.                                        //- for the following to be enabled
  557.  
  558.    paItem = GetTopItem() ;
  559.  
  560.    mf = (paItem ? MF_ENABLED : MF_GRAYED);
  561.    EnableMenuItem(hMenu, IDM_CUT, mf); //- i.e. Cut,Copy,Clear,Clearall...
  562.    EnableMenuItem(hMenu, IDM_COPY, mf);
  563.    EnableMenuItem(hMenu, IDM_CLEAR, mf);
  564.    EnableMenuItem(hMenu, IDM_CLEARALL, mf);
  565.                                        //- enable links option only if there
  566.                                        //- is at least one linked object
  567.    EnableMenuItem(hMenu, IDM_LINKS, MF_GRAYED);
  568.    for (; paItem; paItem = GetNextItem(paItem))
  569.    {
  570.       if (paItem->otObject == OT_LINK)
  571.       {
  572.          EnableMenuItem(hMenu, IDM_LINKS, MF_ENABLED);
  573.          break;
  574.       }
  575.    }
  576.  
  577.    if (hSub = GetSubMenu(hMenu,POS_EDITMENU))
  578.       UpdateObjectMenuItem(hSub);
  579.  
  580.    if (OleQueryCreateFromClip(STDFILEEDITING, olerender_draw, 0) == OLE_OK)
  581.       EnableMenuItem(hMenu, IDM_PASTE, MF_ENABLED);
  582.    else if (OleQueryCreateFromClip(STATICP, olerender_draw, 0) == OLE_OK)
  583.       EnableMenuItem(hMenu, IDM_PASTE, MF_ENABLED);
  584.    else
  585.       EnableMenuItem(hMenu, IDM_PASTE, MF_GRAYED);
  586.  
  587.    if (OleQueryLinkFromClip(STDFILEEDITING, olerender_draw, 0) == OLE_OK)
  588.       EnableMenuItem(hMenu, IDM_PASTELINK, MF_ENABLED);
  589.    else
  590.       EnableMenuItem(hMenu, IDM_PASTELINK, MF_GRAYED);
  591.  
  592. }
  593.  
  594. /***************************************************************************
  595.  *  NewFile()
  596.  *
  597.  *  Save the present document and open a new blank one.
  598.  ***************************************************************************/
  599.  
  600. static void NewFile(                   //- ENTRY:
  601.    PSTR           pFileName,           //- open file name
  602.    LHCLIENTDOC    *lhcptrDoc,          //- pointer to client doc. handle
  603.    LPAPPSTREAM    lpStream             //- pointer to stream structure
  604. ){                                     //- LOCAL:
  605.    static char  szUntitled[CBMESSAGEMAX] = "";//- "(Untitled)" string
  606.    LHCLIENTDOC lhcDocNew;              //- handle for new doc.
  607.  
  608.    if (!(*szUntitled))
  609.       LoadString(hInst, IDS_UNTITLED, (LPSTR)szUntitled, CBMESSAGEMAX);
  610.  
  611.    if (SaveAsNeeded(pFileName, *lhcptrDoc, lpStream))
  612.    {                                   //- try to register new document
  613.       if (!RegDoc(szUntitled, &lhcDocNew))
  614.          return;                       //- before deregistring the old one
  615.       DeregDoc(*lhcptrDoc);
  616.       *lhcptrDoc = lhcDocNew;
  617.       Dirty(DOC_CLEAN);                //- new document is clean
  618.       lstrcpy(pFileName,szUntitled);
  619.       SetTitle(pFileName);
  620.       iObjectNumber = 0;
  621.    }
  622.  
  623. }
  624.  
  625. /***************************************************************************
  626.  *  MyOpenFile()
  627.  *
  628.  *  Open a file and load it.  Notice that the new file is loaded before
  629.  *  the old is removed.  This is done to assure a succesful file load
  630.  *  before removing an existing document.
  631.  ***************************************************************************/
  632.  
  633. static void MyOpenFile(                //- ENTRY:
  634.    PSTR           pFileName,           //- open file name
  635.    LHCLIENTDOC    *lhcptrDoc,          //- pointer to document handle
  636.    LPOLECLIENT    lpClient,            //- pointer to client structure
  637.    LPAPPSTREAM    lpStream             //- pointer to stream structure
  638. ){                                     //- LOCAL:
  639.    char           szNewFile[CBPATHMAX];//- new file name buffer
  640.    LHCLIENTDOC    lhcDocNew;           //- handle of new document
  641.    APPITEMPTR     pItem;               //- hold top item
  642.  
  643.    if (SaveAsNeeded(pFileName, *lhcptrDoc, lpStream))
  644.    {
  645.       *szNewFile = NULL;
  646.  
  647.       if (!OfnGetName(hwndFrame, szNewFile, IDM_OPEN))
  648.          return;                       //- ERROR return
  649.  
  650.       if (!RegDoc(szNewFile,&lhcDocNew))
  651.          return;                       //- ERROR return
  652.  
  653.       pItem = GetTopItem();
  654.       ShowDoc(*lhcptrDoc,0);           //- make old doc objects hidden.
  655.                                        //- try to load the new file before
  656.       if (!LoadFile(szNewFile, lhcDocNew, lpClient, lpStream))
  657.       {                                //- before removing the old.
  658.          DeregDoc(lhcDocNew);          //- restore old document if new
  659.          SetTopItem(pItem);            //- file did not load
  660.          ShowDoc(*lhcptrDoc,1);
  661.          return;                       //- ERROR return
  662.       }
  663.  
  664.       DeregDoc(*lhcptrDoc);            //- deregister old document
  665.       *lhcptrDoc = lhcDocNew;
  666.       lstrcpy(pFileName,szNewFile);
  667.       SetTitle(pFileName);             //- set new title
  668.       Dirty(DOC_CLEAN);
  669.    }
  670.  
  671. }                                      //- SUCCESS return
  672.  
  673. /***************************************************************************
  674.  *  SaveasFile()
  675.  *
  676.  * Prompt the user for a new file name.  Write the document to the new
  677.  * filename.
  678.  ***************************************************************************/
  679.  
  680. static void SaveasFile(                //- ENTRY:
  681.    PSTR           pFileName,           //- old filename
  682.    LHCLIENTDOC    lhcDoc,              //- document handle
  683.    LPAPPSTREAM    lpStream             //- pointer to stream structure
  684. ){
  685.    char           szNewFile[CBPATHMAX];//- new file name
  686.  
  687.    *szNewFile = NULL;                  //- prompt user for new file name
  688.    if (!OfnGetName(hwndFrame, szNewFile, IDM_SAVEAS))
  689.       return;                          //- ERROR return
  690.                                        //- rename document
  691.    if (!SaveFile(szNewFile, lhcDoc, lpStream))
  692.       return;
  693.  
  694.    if (Error(OleRenameClientDoc(lhcDoc, szNewFile)))
  695.    {
  696.       ErrorMessage(W_FAILED_TO_NOTIFY);
  697.       return;                          //- ERROR return
  698.    }
  699.  
  700.    lstrcpy(pFileName,szNewFile);
  701.    SetTitle(pFileName);
  702.  
  703. }                                      //- SUCCESS return
  704.  
  705. /***************************************************************************
  706.  *  SaveFile()
  707.  *
  708.  * Save a compound document file.  If the file is untitled, ask the user
  709.  * for a name and save the document to that file.
  710.  ***************************************************************************/
  711.  
  712. static BOOL SaveFile(                  //- ENTRY:
  713.    PSTR           pFileName,           //- file to save document to
  714.    LHCLIENTDOC    lhcDoc,              //- OLE document handle
  715.    LPAPPSTREAM    lpStream             //- pointer to app. stream struct
  716. ){                                     //- LOCAL:
  717.    char           szNewFile[CBPATHMAX];//- New file name strings
  718.    char           szOemFileName[2*CBPATHMAX];
  719.    static char    szUntitled[CBMESSAGEMAX] = "";
  720.    HANDLE         fh;                  //- file handle
  721.  
  722.    *szNewFile = NULL;
  723.    if (!(*szUntitled))
  724.       LoadString(hInst, IDS_UNTITLED, (LPSTR)szUntitled, CBMESSAGEMAX);
  725.  
  726.    if (!lstrcmp(szUntitled, pFileName))//- get filename for the untitled case
  727.    {
  728.       if (!OfnGetName(hwndFrame, szNewFile, IDM_SAVEAS))
  729.          return FALSE;                 //- CANCEL return
  730.       lstrcpy(pFileName,szNewFile);
  731.       SetTitle(pFileName);
  732.    }
  733.  
  734.    AnsiToOem(pFileName, szOemFileName);
  735.    if ((fh =_lcreat((LPSTR)szOemFileName, 0)) <= 0)
  736.    {
  737.       ErrorMessage(E_INVALID_FILENAME);
  738.       return FALSE;                    //- ERROR return
  739.    }
  740.  
  741.    lpStream->fh = fh;
  742.                                        //- save file on disk
  743.    if (!WriteToFile(lpStream))
  744.    {
  745.       _lclose(fh);
  746.       ErrorMessage(E_FAILED_TO_SAVE_FILE);
  747.       return FALSE;                    //- ERROR return
  748.    }
  749.    _lclose(fh);
  750.  
  751.    if (Error(OleSavedClientDoc(lhcDoc)))
  752.    {
  753.       ErrorMessage(W_FAILED_TO_NOTIFY);
  754.       return FALSE;                    //- ERROR return
  755.    }
  756.  
  757.    Dirty(DOC_CLEAN);
  758.    return TRUE;                        //- SUCCESS return
  759.  
  760. }
  761.  
  762. /***************************************************************************
  763.  *  LoadFile()
  764.  *
  765.  *  Load a document file from disk.
  766.  ***************************************************************************/
  767.  
  768. static BOOL LoadFile(                  //- ENTRY:
  769.    PSTR           pFileName,           //- file name
  770.    LHCLIENTDOC    lhcDoc,              //- document handle
  771.    LPOLECLIENT    lpClient,            //- pointer to client structure
  772.    LPAPPSTREAM    lpStream             //- pointer to stream structure
  773. ){                                     //- LOCAL:
  774.                                        //- OEM file name
  775.    char           szOemFileName[2*CBPATHMAX];
  776.    HANDLE         fh;                  //- file handle
  777.    int iObjectNumberHold;              //- hold object number
  778.  
  779.    AnsiToOem(pFileName, szOemFileName);
  780.    if ((fh = _lopen(szOemFileName, OF_READ | OF_SHARE_DENY_WRITE)) == -1)
  781.    {
  782.       ErrorMessage(E_FAILED_TO_READ_FILE);
  783.       return FALSE;                    //- ERROR return
  784.    }
  785.  
  786.    lpStream->fh = fh;
  787.  
  788.    iObjectNumberHold = iObjectNumber;  //- save object number so it can
  789.    iObjectNumber     = 0;              //- be restored if read from file
  790.                                        //- fails
  791.    if (!ReadFromFile(lpStream, lhcDoc, lpClient))
  792.    {
  793.       _lclose(fh);
  794.       ErrorMessage(E_FAILED_TO_READ_FILE);
  795.       iObjectNumber = iObjectNumberHold;
  796.       return FALSE;                    //- ERROR return
  797.    }
  798.    return TRUE;                        //- SUCCESS return
  799.  
  800. }
  801.  
  802. /***************************************************************************
  803.  *  RegDoc()
  804.  *
  805.  * Register the client document with the OLE library.
  806.  **************************************************************************/
  807.  
  808. static BOOL RegDoc(                    //- ENTRY:
  809.    PSTR           pFileName,           //- file name
  810.    LHCLIENTDOC    *lhcptrDoc           //- pointer to client document handle
  811. ){
  812.  
  813.    if (Error(OleRegisterClientDoc(szAppName, (LPSTR)pFileName, 0L, lhcptrDoc)))
  814.    {
  815.       ErrorMessage(W_FAILED_TO_NOTIFY);
  816.       return FALSE;                    //- ERROR return
  817.    }
  818.    return TRUE;                        //- SUCCESS return
  819.  
  820. }
  821.  
  822. /****************************************************************************
  823.  *  DeregDoc()
  824.  *
  825.  *  This function initiates the removal of all OLE objects from the
  826.  *  current document and deregisters the document with the OLE library.
  827.  ***************************************************************************/
  828.  
  829. static void DeregDoc(                  //- ENTRY:
  830.    LHCLIENTDOC    lhcDoc               //- client document handle
  831. ){
  832.  
  833.     if (lhcDoc)
  834.     {                                  //- release all OLE objects
  835.         ClearAll(lhcDoc,RELEASE);      //- and remove them from the screen
  836.         WaitForAllObjects();
  837.         if (Error(OleRevokeClientDoc(lhcDoc)))
  838.             ErrorMessage(W_FAILED_TO_NOTIFY);
  839.     }
  840.  
  841. }                                      //- SUCCESS return
  842.  
  843. /***************************************************************************
  844.  *  ClearAll()
  845.  *
  846.  * This function will destroy all of the item windows in the current
  847.  * document and delete all OLE objects.  The loop is basically an enum
  848.  * of all child windows.
  849.  **************************************************************************/
  850.  
  851. static void ClearAll(                  //- ENTRY:
  852.    LHCLIENTDOC    lhcDoc,              //- application document handle
  853.    BOOL           fDelete              //- Delete / Release
  854. ){                                     //- LOCAL:
  855.    APPITEMPTR     pItemNext;           //- working handles
  856.    APPITEMPTR     pItem;               //- pointer to application item
  857.  
  858.    pItem = GetTopItem();
  859.  
  860.    while (pItem)
  861.    {
  862.       pItemNext = GetNextItem(pItem);
  863.       if (pItem->lhcDoc == lhcDoc)
  864.          ObjDelete(pItem, fDelete);
  865.       pItem = pItemNext;
  866.    }
  867.  
  868. }
  869.                                     //- SUCCESS return
  870. /***************************************************************************
  871.  * ClearItem()
  872.  *
  873.  * This function will destroy an item window, and make the
  874.  * next window active.
  875.  **************************************************************************/
  876.  
  877. void  FAR ClearItem(                 //- ENTRY:
  878.    APPITEMPTR     pItem                //- application item pointer
  879. ){
  880.  
  881.    pItem->fVisible = FALSE;
  882.    SetTopItem(GetNextActiveItem());
  883.    ObjDelete(pItem, DELETE);
  884.    Dirty(DOC_DIRTY);
  885.  
  886. }
  887.  
  888. /****************************************************************************
  889.  *  SaveAsNeeded()
  890.  *
  891.  *  This function will have the file saved if and only
  892.  *  if the document has been modified. If the fDirty flag has
  893.  *  been set to TRUE, then the document needs to be saved.
  894.  *
  895.  *  Returns: BOOL -  TRUE if document doesn't need saving or if the
  896.  *                   document has been saved successfully.
  897.  ***************************************************************************/
  898.  
  899. static BOOL SaveAsNeeded(              //- ENTRY:
  900.    PSTR           pFileName,           //- file to save
  901.    LHCLIENTDOC    lhcDoc,              //- OLE doc handle
  902.    LPAPPSTREAM    lpStream             //- pointer to OLE stream vtbl ...
  903. ){                                     //- LOCAL:
  904.    char           sz[CBMESSAGEMAX];    //- work strings
  905.    char           sz2[CBMESSAGEMAX + CBPATHMAX];
  906.  
  907.    if (Dirty(DOC_QUERY))               //- if doc is clean don't bother
  908.    {
  909.  
  910.       LoadString(hInst, IDS_MAYBESAVE, sz, CBMESSAGEMAX);
  911.       wsprintf(sz2, sz, (LPSTR)pFileName );
  912.  
  913.       switch (MessageBox(hwndFrame, sz2, szAppName, MB_YESNOCANCEL | MB_ICONQUESTION))
  914.       {
  915.  
  916.          case IDCANCEL:
  917.             return FALSE;              //- CANCEL return
  918.  
  919.          case IDYES:
  920.             return (SaveFile(pFileName,lhcDoc,lpStream));
  921.  
  922.          default:
  923.             break;
  924.       }
  925.    }
  926.    return TRUE;                        //- SUCCESS return
  927.  
  928. }
  929.  
  930. /****************************************************************************
  931.  *  SetTitle()
  932.  *
  933.  *  Set the window caption to the current file name. If szFileName is
  934.  *  NULL, the caption will be set to "(Untitled)".
  935.  ***************************************************************************/
  936.  
  937. static void SetTitle(                  //- ENTRY:
  938.    PSTR           pFileName            //- file name
  939. ){                                     //- LOCAL
  940.                                        //- window title string
  941.    char           szTitle[CBMESSAGEMAX + CBPATHMAX];
  942.  
  943.    wsprintf(szTitle, "%s - %s", (LPSTR)szAppName, (LPSTR)pFileName);
  944.    SetWindowText(hwndFrame, szTitle);
  945.  
  946. }
  947.  
  948. /***************************************************************************
  949.  *  EndClient()
  950.  *
  951.  *  Perform cleanup prior to app termination. The OLECLIENT
  952.  *  memory blocks and procedure instance thunks freed.
  953.  **************************************************************************/
  954.  
  955. static void EndStream(                 //- ENTRY:
  956.    LPAPPSTREAM    lpStream             //- pointer to stream structure
  957. ){                                     //- LOCAL:
  958.    HANDLE         hGeneric;            //- temp handle
  959.  
  960.     if (lpStream)                      //- is there a STREAM struct?
  961.     {
  962.       if (lpStream->olestream.lpstbl)
  963.       {
  964.          FreeProcInstance((FARPROC)lpStream->olestream.lpstbl->Get);
  965.          FreeProcInstance((FARPROC)lpStream->olestream.lpstbl->Put);
  966.          hGeneric = (HANDLE)GlobalHandle(HIWORD(lpStream->olestream.lpstbl));
  967.          GlobalUnlock(hGeneric);
  968.          GlobalFree(hGeneric);
  969.       }
  970.       hGeneric = (HANDLE)GlobalHandle(HIWORD(lpStream));
  971.       GlobalUnlock(hGeneric);
  972.       GlobalFree(hGeneric);
  973.     }
  974.     if (lpfnTimerProc)
  975.         FreeProcInstance(lpfnTimerProc);
  976.  
  977. }                                      //- SUCCESS return
  978.  
  979. /***************************************************************************
  980.  *  EndClient()
  981.  *
  982.  *  Perform cleanup prior to app termination. The OLECLIENT
  983.  *  memory blocks and procedure instance thunks are freed.
  984.  **************************************************************************/
  985.  
  986. static void EndClient(                 //- ENTRY:
  987.    LPOLECLIENT    lpClient             //- pointer to client structure
  988. ){                                     //- LOCAL:
  989.    HANDLE         hGeneric;            //- temp handle
  990.  
  991.    if (lpClient)                       //- is there a client structure
  992.    {
  993.       if (lpClient->lpvtbl)
  994.       {
  995.          FreeProcInstance(lpClient->lpvtbl->CallBack);
  996.          hGeneric = (HANDLE)GlobalHandle(HIWORD(lpClient->lpvtbl));
  997.          GlobalUnlock(hGeneric);
  998.          GlobalFree(hGeneric);
  999.       }
  1000.       hGeneric = (HANDLE)GlobalHandle(HIWORD(lpClient));
  1001.       GlobalUnlock(hGeneric);
  1002.       GlobalFree(hGeneric);
  1003.    }
  1004.  
  1005. }                                      //- SUCCESS return
  1006.  
  1007. /****************************************************************************
  1008.  * QueryEndSession()
  1009.  ***************************************************************************/
  1010.  
  1011. static long QueryEndSession(           //- ENTRY:
  1012.    PSTR           pFileName,           //- document name
  1013.    LHCLIENTDOC    lhcDoc,              //- client document handle
  1014.    LPAPPSTREAM    lpStream             //- application stream pointer
  1015. ){                                     //- LOCAL:
  1016.    APPITEMPTR     pItem;               //- application item pointer
  1017.  
  1018.  
  1019.    for (pItem = GetTopItem(); pItem; pItem = GetNextItem(pItem))
  1020.       if (OleQueryOpen(pItem->lpObject) == OLE_OK)
  1021.       {
  1022.          MessageBox(hwndFrame,"Exit CliDemo before closing Windows",
  1023.                szAppName, MB_OK | MB_ICONSTOP);
  1024.          return 0L;
  1025.       }
  1026.  
  1027.    if (!SaveAsNeeded(pFileName, lhcDoc, lpStream))
  1028.       return 0L;
  1029.    DeregDoc(lhcDoc);
  1030.    return 1L;
  1031.  
  1032. }
  1033.