home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c480 / 18.ddi / SAMPLES / SRVRDEMO / DOC.C_ / DOC.C
Encoding:
C/C++ Source or Header  |  1993-02-08  |  16.6 KB  |  587 lines

  1. /*
  2.   OLE SERVER DEMO
  3.   Doc.c
  4.  
  5.   This file contains document methods and various document-related support
  6.   functions.
  7.  
  8.   (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
  9. */
  10.  
  11. /*
  12.    Important Note:
  13.  
  14.    No method should ever dispatch a DDE message or allow a DDE message to
  15.    be dispatched.
  16.    Therefore, no method should ever enter a message dispatch loop.
  17.    Also, a method should not show a dialog or message box, because the
  18.    processing of the dialog box messages will allow DDE messages to be
  19.    dispatched.
  20. */
  21.  
  22.  
  23.  
  24. #define SERVERONLY
  25. #include "Windows.h"
  26. #include "Ole.h"
  27. #include "SrvrDemo.h"
  28.  
  29. /* AssociateClient
  30.  * ---------------
  31.  *
  32.  * Add a client to the list of clients associated with an object.
  33.  *
  34.  * This function is necessary only because ServerDemo does not create object
  35.  * structures as they are requested, but rather has a fixed set of objects.
  36.  * When DocGetObject is called with a NULL object name, the entire
  37.  * document is requested, but ServerDemo does not currently support making
  38.  * the entire document an object, so DocGetObject returns one object.
  39.  * That object now goes by two names: NULL and its real name.  Therefore
  40.  * we need to keep track of both lpoleclient's that were passed to
  41.  * DocGetObject.  Ideally, DocGetObject should always create a new OBJ
  42.  * structure containing a pointer (or some reference) to the object's native
  43.  * data and also containing one lpoleclient.
  44.  *
  45.  * LPOLECLIENT lpoleclient - the client to be associated with the object.
  46.  * LPOBJ lpobj             - the object
  47.  *
  48.  * RETURNS: TRUE if successful
  49.  *          FALSE if out of memory
  50.  *
  51.  * CUSTOMIZATION: Server Demo specific
  52.  *
  53.  */
  54. static BOOL AssociateClient (LPOLECLIENT lpoleclient, LPOBJ lpobj)
  55. {
  56.    int i;
  57.    for (i=0; i < clpoleclient; i++)
  58.    {
  59.       if (lpobj->lpoleclient[i]==lpoleclient)
  60.       {
  61.          return TRUE;
  62.       }
  63.       if (lpobj->lpoleclient[i]==NULL)
  64.       {
  65.          lpobj->lpoleclient[i]=lpoleclient;
  66.          return TRUE;
  67.       }
  68.    }
  69.    return FALSE;
  70. }
  71.  
  72.  
  73.  
  74. /* CreateNewDoc
  75.  * ------------
  76.  *
  77.  * If lhdoc == NULL then we must register the new document by calling
  78.  * OleRegisterServerDoc, which will return a new handle which will be stored
  79.  * in docMain.lhdoc.
  80.  * Also if lhdoc==NULL then this document is being created at the request of
  81.  * the user, not of the client library.
  82.  *
  83.  * LONG lhdoc      - Document handle
  84.  * LPSTR lpszDoc   - Title of the new document
  85.  * DOCTYPE doctype - What type of document is being created
  86.  *
  87.  * RETURNS: TRUE if successful, FALSE otherwise.
  88.  *
  89.  * CUSTOMIZATION: Re-implement
  90.  *
  91.  */
  92. BOOL CreateNewDoc (LONG lhdoc, LPSTR lpszDoc, DOCTYPE doctype)
  93. {
  94.    int i;
  95.  
  96.    // Fill in the fields of the document structure.
  97.    if (lhdoc == NULL)
  98.    {
  99.       if (OLE_OK != OleRegisterServerDoc
  100.                      (srvrMain.lhsrvr,
  101.                       lpszDoc,
  102.                       (LPOLESERVERDOC) &docMain,
  103.                       (LHSERVERDOC FAR *) &docMain.lhdoc))
  104.          return FALSE;
  105.    }
  106.    else
  107.       docMain.lhdoc = lhdoc;
  108.  
  109.    docMain.doctype      = doctype;
  110.    docMain.oledoc.lpvtbl= &docvtbl;
  111.    // Reset all the flags because no object numbers have been used.
  112.    for (i=1; i <= cfObjNums; i++)
  113.       docMain.rgfObjNums[i] = FALSE;
  114.  
  115.    fDocChanged = FALSE;
  116.  
  117.    SetTitle (lpszDoc, doctype == doctypeEmbedded);
  118.    return TRUE;
  119. }
  120.  
  121.  
  122.  
  123. /* DestroyDoc
  124.  * ----------
  125.  *
  126.  * Free all memory that had been allocated for a document.
  127.  *
  128.  *
  129.  * CUSTOMIZATION: Re-implement.  Your application will probably use some
  130.  *                other method for enumerating all the objects in a document.
  131.  *                ServerDemo enumerates the child windows, but if each object
  132.  *                does not have its own window, this will not work.
  133.  *
  134.  */
  135. void DestroyDoc (void)
  136. {
  137.    HWND hwnd;
  138.    HWND hwndNext;
  139.  
  140.    // Delete all object windows.
  141.    hwnd = SelectedObjectWindow();
  142.    while (hwnd)
  143.    {
  144.       hwndNext = GetWindow (hwnd, GW_HWNDNEXT);
  145.       // Each object window frees its own memory upon receiving WM_DESTROY.
  146.       DestroyWindow (hwnd);
  147.       hwnd = hwndNext;
  148.    }
  149.  
  150.    if (docMain.aName)
  151.    {
  152.       GlobalDeleteAtom (docMain.aName);
  153.       docMain.aName = NULL;
  154.    }
  155.  
  156.    if (docMain.hpal)
  157.       DeleteObject (docMain.hpal);
  158. }
  159.  
  160.  
  161.  
  162. /* DocClose                DOCUMENT "Close" METHOD
  163.  * --------
  164.  *
  165.  * The library calls this method to unconditionally close the document.
  166.  *
  167.  * LPOLESERVERDOC lpoledoc - The server document to close
  168.  *
  169.  * RETURNS: Return value from RevokeDoc.
  170.  *
  171.  * CUSTOMIZATION: None
  172.  *
  173.  */
  174. OLESTATUS FAR PASCAL __export DocClose (LPOLESERVERDOC lpoledoc)
  175. {
  176.    return RevokeDoc();
  177. }
  178.  
  179.  
  180.  
  181. /* DocExecute                DOCUMENT "Execute" METHOD
  182.  * ----------
  183.  *
  184.  * This application does not support the execution of DDE execution commands.
  185.  *
  186.  * LPOLESERVERDOC lpoledoc - The server document
  187.  * HANDLE hCommands        - DDE execute commands
  188.  *
  189.  * RETURNS: OLE_ERROR_COMMAND
  190.  *
  191.  * CUSTOMIZATION: Re-implement if your application supports the execution of
  192.  *                DDE commands.
  193.  *
  194.  */
  195. OLESTATUS FAR PASCAL __export DocExecute (LPOLESERVERDOC lpoledoc, HANDLE hCommands)
  196. {
  197.    return OLE_ERROR_COMMAND;
  198. }
  199.  
  200.  
  201.  
  202. /* DocGetObject                DOCUMENT "GetObject" METHOD
  203.  * ------------
  204.  *
  205.  * The library uses this method to get an object's structure for the
  206.  * client.  Memory needs to be allocated and initialized here for this.
  207.  * A NULL string indicates that the client has an embedded object
  208.  * which was started from Create, CreateFromTemplate, or Edit, but not Open.
  209.  *
  210.  * First see if the object name is NULL.  If so, you would ordinarily
  211.  * return the entire document, but Server Demo returns the selected object.
  212.  * If the object name is not NULL, then go through the list of objects,
  213.  * searching for one with that name.  Return an error if there is not one.
  214.  *
  215.  * LPOLESERVERDOC lpoledoc        - The server document
  216.  * LPSTR lpszObjectName           - The name of the object to get data for
  217.  * LPOLEOBJECT FAR *lplpoleobject - The object's data is put here
  218.  * LPOLECLIENT lpoleclient        - The client structure
  219.  *
  220.  * RETURNS:        OLE_OK
  221.  *                 OLE_ERROR_NAME if object not found
  222.  *                 OLE_ERROR_MEMORY if no more memory to store lpoleclient
  223.  *
  224.  * CUSTOMIZATION: Re-implement.
  225.  *                lpszObjectName == "" indicates that the whole document
  226.  *                should be the object returned.
  227.  *
  228.  */
  229. OLESTATUS FAR PASCAL __export DocGetObject
  230.    (LPOLESERVERDOC lpoledoc, LPSTR lpszObjectName,
  231.     LPOLEOBJECT FAR *lplpoleobject, LPOLECLIENT lpoleclient)
  232. {
  233.     HWND  hwnd;
  234.     ATOM  aName;
  235.     LPOBJ lpobj;
  236.  
  237.     if (lpszObjectName == NULL || lpszObjectName[0] == '\0')
  238.     {
  239.         // Return a new object or the selected object.
  240.         hwnd = SelectedObjectWindow();
  241.         lpobj = hwnd ? HwndToLpobj (hwnd) : CreateNewObj (FALSE);
  242.         *lplpoleobject = (LPOLEOBJECT) lpobj;
  243.         // Associate client with object.
  244.         if (!AssociateClient (lpoleclient, lpobj))
  245.             return OLE_ERROR_MEMORY;
  246.         return OLE_OK;
  247.     }
  248.  
  249.     if (!(aName = GlobalFindAtom (lpszObjectName)))
  250.         return OLE_ERROR_NAME;
  251.  
  252.     hwnd = SelectedObjectWindow();
  253.  
  254.     // Go through all the child windows and find the window whose name
  255.     // matches the given object name.
  256.  
  257.     while (hwnd)
  258.     {
  259.          lpobj = HwndToLpobj (hwnd);
  260.  
  261.          if (aName == lpobj->aName)
  262.          {
  263.             // Return the object with the matching name.
  264.             *lplpoleobject = (LPOLEOBJECT) lpobj;
  265.             // Associate client with the object.
  266.             if (!AssociateClient (lpoleclient, lpobj))
  267.                return OLE_ERROR_MEMORY;
  268.             return OLE_OK;
  269.          }
  270.          hwnd = GetWindow (hwnd, GW_HWNDNEXT);
  271.     }
  272.  
  273.  if ((DOCTYPE)((DOCPTR)lpoledoc)->doctype ==  (DOCTYPE)doctypeEmbedded)
  274.    {
  275.       lpobj = CreateNewObj (FALSE);
  276.       *lplpoleobject = (LPOLEOBJECT) lpobj;
  277.  
  278.       // Associate client with object.
  279.       if (!AssociateClient (lpoleclient, lpobj))
  280.          return OLE_ERROR_MEMORY;
  281.       return OLE_OK;
  282.     }
  283.  
  284.     // Object with name lpszObjName was not found.
  285.     return OLE_ERROR_NAME;
  286. }
  287.  
  288. /* DocRelease                DOCUMENT "Release" METHOD
  289.  * ----------
  290.  *
  291.  * The library uses this method to notify the server that a revoked
  292.  * document has finally finished all conversations, and can be
  293.  * destroyed.
  294.  * It sets fWaitingForDocRelease to FALSE so a new document can be created
  295.  * and the user can continue working.
  296.  *
  297.  * LPOLESERVERDOC lpoledoc      - The server document
  298.  *
  299.  * RETURNS: OLE_OK
  300.  *
  301.  * CUSTOMIZATION: None
  302.  *
  303.  */
  304. OLESTATUS FAR PASCAL __export DocRelease (LPOLESERVERDOC lpoledoc)
  305. {
  306.    fWaitingForDocRelease = FALSE;
  307.    // Free all memory that has been allocated for the document.
  308.    DestroyDoc();
  309.  
  310.    return OLE_OK;
  311. }
  312.  
  313.  
  314.  
  315. /* DocSave                DOCUMENT "Save" METHOD
  316.  * -------
  317.  *
  318.  * Save document to a file.
  319.  *
  320.  * LPOLESERVERDOC lpoledoc - The document to save
  321.  *
  322.  * RETURNS: OLE_OK
  323.  *
  324.  * CUSTOMIZATION: None
  325.  *
  326.  */
  327. OLESTATUS FAR PASCAL __export DocSave (LPOLESERVERDOC lpoledoc)
  328. {
  329.     if (docMain.doctype == doctypeFromFile)
  330.     {
  331.          // No "File Save As" dialog box will be brought up because the
  332.          // file name is already known.
  333.          return SaveDoc() ? OLE_OK : OLE_ERROR_GENERIC;
  334.     }
  335.     else
  336.       return OLE_ERROR_GENERIC;
  337. }
  338.  
  339.  
  340.  
  341. /* DocSetDocDimensions        DOCUMENT "SetDocDimensions" METHOD
  342.  * -------------------
  343.  *
  344.  * The library calls this method to tell the server the bounds on
  345.  * the target device for rendering the document.
  346.  * A call to this method is ignored for linked objects because the size of
  347.  * a linked document depends only on the source file.
  348.  *
  349.  * LPOLESERVERDOC lpoledoc - The server document
  350.  * LPRECT         lprect   - The target size in MM_HIMETRIC units
  351.  *
  352.  * RETURNS: OLE_OK
  353.  *
  354.  * CUSTOMIZATION: Re-implement
  355.  *                How an object is sized is application-specific. (Server Demo
  356.  *                uses MoveWindow.)
  357.  *
  358.  */
  359. OLESTATUS FAR PASCAL __export DocSetDocDimensions
  360.    (LPOLESERVERDOC lpoledoc, LPRECT lprect)
  361. {
  362.    if (docMain.doctype == doctypeEmbedded)
  363.    {
  364.       RECT rect = *lprect;
  365.  
  366.       // the units are in HIMETRIC
  367.       rect.right   = rect.right - rect.left;
  368.       rect.bottom  = rect.top - rect.bottom;
  369.       HiMetricToDevice (hwndMain, (LPPOINT) &rect.right);
  370.       MoveWindow (SelectedObjectWindow(), 0, 0,
  371.                   rect.right + 2 * GetSystemMetrics(SM_CXFRAME),
  372.                   rect.bottom + 2 * GetSystemMetrics(SM_CYFRAME),
  373.                   TRUE);
  374.       /* If for some reason your application needs to notify the client that
  375.          the data has changed because DocSetDocDimensions has been called,
  376.          then notify the client here.
  377.          SendDocMsg (OLE_CHANGED);
  378.       */
  379.    }
  380.    return OLE_OK;
  381. }
  382.  
  383.  
  384.  
  385. /* DocSetHostNames        DOCUMENT "SetHostNames" METHOD
  386.  * ---------------
  387.  *
  388.  * The library uses this method to set the name of the document
  389.  * window.
  390.  * All this function does is change the title bar text, although it could
  391.  * do more if necesary.
  392.  * This function is only called for embedded objects; linked objects
  393.  * use their filenames for the title bar text.
  394.  *
  395.  * LPOLESERVERDOC lpoledoc    - The server document
  396.  * LPSTR lpszClient           - The name of the client
  397.  * LPSTR lpszDoc              - The client's name for the document
  398.  *
  399.  * RETURNS:        OLE_OK
  400.  *
  401.  * CUSTOMIZATION: None
  402.  *
  403.  */
  404. OLESTATUS FAR PASCAL __export DocSetHostNames
  405.    (LPOLESERVERDOC lpoledoc, LPSTR lpszClient, LPSTR lpszDoc)
  406. {
  407.    SetTitle (lpszDoc, TRUE);
  408.    lstrcpy ((LPSTR) szClient, lpszClient);
  409.    lstrcpy ((LPSTR) szClientDoc, Abbrev(lpszDoc));
  410.    UpdateFileMenu (IDM_UPDATE);
  411.    return OLE_OK;
  412. }
  413.  
  414.  
  415.  
  416. /* DocSetColorScheme                DOCUMENT "SetColorScheme" METHOD
  417.  * -----------------
  418.  *
  419.  * The client calls this method to suggest a color scheme (palette) for
  420.  * the server to use.
  421.  * In Server Demo the document's palette is never actually used because each
  422.  * object has its own palette.  See ObjSetColorScheme.
  423.  *
  424.  * LPOLESERVERDOC lpoledoc - The server document
  425.  * LPLOGPALETTE   lppal    - Suggested palette
  426.  *
  427.  * RETURNS: OLE_ERROR_PALETTE if CreatePalette fails,
  428.  *          OLE_OK otherwise
  429.  *
  430.  *
  431.  * CUSTOMIZATION: If your application supports color schemes, then this
  432.  *                function is a good example of how to create and store
  433.  *                a palette.
  434.  */
  435. OLESTATUS FAR PASCAL __export DocSetColorScheme
  436.    (LPOLESERVERDOC lpoledoc, LPLOGPALETTE lppal)
  437. {
  438.    HPALETTE hpal = CreatePalette (lppal);
  439.  
  440.    if (hpal==NULL)
  441.       return OLE_ERROR_PALETTE;
  442.  
  443.    if (docMain.hpal)
  444.    {
  445.       // Delete old palette
  446.       DeleteObject (docMain.hpal);
  447.    }
  448.    // Store handle to new palette
  449.    docMain.hpal = hpal;
  450.    return OLE_OK;
  451. }
  452.  
  453.  
  454.  
  455. /* RevokeDoc
  456.  * ---------
  457.  *
  458.  * Call OleRevokeServerDoc.
  459.  * If the return value is OLE_WAIT_FOR_BUSY, then set fWaitingForDocRelease
  460.  * and enter a message-dispatch loop until fWaitingForDocRelease is reset.
  461.  * As long as fWaitingForDocRelease is set, the user interface will be
  462.  * disabled so that the user will not be able to manipulate the document.
  463.  * When the DocRelease method is called, it will reset fWaitingForDocRelease,
  464.  * allowing RevokeDoc to free the document's memory and return.
  465.  *
  466.  * This is essentially a way to make an asynchronous operation synchronous.
  467.  * We need to wait until the old document is revoked before we can delete
  468.  * its data and create a new one.
  469.  *
  470.  * Note that we cannot call RevokeDoc from a method because it is illegal to
  471.  * enter a message-dispatch loop within a method.
  472.  *
  473.  * RETURNS: The return value of OleRevokeServerDoc.
  474.  *
  475.  * CUSTOMIZATION: lhdoc may need to be passed in as a parameter if your
  476.  *                application does not have a global variable corresponding
  477.  *                to docMain.
  478.  *
  479.  */
  480. OLESTATUS RevokeDoc (void)
  481. {
  482.    OLESTATUS olestatus;
  483.  
  484.    if ((olestatus = OleRevokeServerDoc(docMain.lhdoc)) > OLE_WAIT_FOR_RELEASE)
  485.       DestroyDoc();
  486.  
  487.    docMain.lhdoc = NULL; // A NULL handle indicates that the document
  488.                          // has been revoked or is being revoked.
  489.    return olestatus;
  490.  
  491. }
  492.  
  493.  
  494.  
  495. /* SaveChangesOption
  496.  * -----------------
  497.  *
  498.  * Give the user the opportunity to save changes to the current document
  499.  * before continuing.
  500.  *
  501.  * BOOL *pfUpdateLater - Will be set to TRUE if the client does not accept
  502.  *                       the update and needs to be updated when the document
  503.  *                       is closed.  In that case, OLE_CLOSED will be sent.
  504.  *
  505.  * RETURNS: IDYES, IDNO, or IDCANCEL
  506.  *
  507.  * CUSTOMIZATION: None
  508.  *
  509.  */
  510. int SaveChangesOption (BOOL *pfUpdateLater)
  511. {
  512.    int  nReply;
  513.    char szBuf[cchFilenameMax];
  514.  
  515.    *pfUpdateLater = FALSE;
  516.  
  517.    if (fDocChanged)
  518.    {
  519.        char szTmp[cchFilenameMax];
  520.  
  521.        if (docMain.aName)
  522.            GlobalGetAtomName (docMain.aName, szTmp, cchFilenameMax);
  523.        else
  524.            szTmp[0] = NULL;
  525.  
  526.        if (docMain.doctype == doctypeEmbedded)
  527.            wsprintf (szBuf, "The object has been changed.\n\nUpdate %s before closing the object?", Abbrev (szTmp));
  528.        else
  529.            lstrcpy (szBuf, (LPSTR) "Save changes?");
  530.  
  531.        nReply = MessageBox (hwndMain, szBuf, szAppName,
  532.                       MB_ICONEXCLAMATION | MB_YESNOCANCEL);
  533.  
  534.        switch (nReply)
  535.        {
  536.           case IDYES:
  537.               if (docMain.doctype != doctypeEmbedded)
  538.                   SaveDoc();
  539.               else
  540.                   switch (OleSavedServerDoc (docMain.lhdoc))
  541.                   {
  542.                       case OLE_ERROR_CANT_UPDATE_CLIENT:
  543.                           *pfUpdateLater = TRUE;
  544.                           break;
  545.                       case OLE_OK:
  546.                           break;
  547.                       default:
  548.                           ErrorBox ("Fatal Error: Cannot update.");
  549.                   }
  550.               return IDYES;
  551.           case IDNO:
  552.               return IDNO;
  553.          case IDCANCEL:
  554.               return IDCANCEL;
  555.        }
  556.    }
  557.    return TRUE;
  558. }
  559.  
  560.  
  561.  
  562. /* SendDocMsg
  563.  * ----------
  564.  *
  565.  * This function sends messages to all the objects in a document when
  566.  * the document has changed.
  567.  *
  568.  * WORD wMessage - The message to send
  569.  *
  570.  * CUSTOMIZATION: The means of enumerating all the objects in a document
  571.  *                is application specific.
  572.  */
  573. void SendDocMsg (WORD wMessage)
  574. {
  575.     HWND    hwnd;
  576.  
  577.     // Get handle to first object window.
  578.     hwnd = SelectedObjectWindow();
  579.  
  580.     // Send message to all object windows.
  581.     while (hwnd)
  582.     {
  583.         SendObjMsg (HwndToLpobj(hwnd), wMessage);
  584.         hwnd = GetWindow (hwnd, GW_HWNDNEXT);
  585.     }
  586. }
  587.