|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.