Annotation of mstools/samples/ole/srvrdemo/doc.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.