home *** CD-ROM | disk | FTP | other *** search
- /*
- OLE SERVER DEMO
- Doc.c
-
- This file contains document methods and various document-related support
- functions.
-
- (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
- */
-
- /*
- Important Note:
-
- No method should ever dispatch a DDE message or allow a DDE message to
- be dispatched.
- Therefore, no method should ever enter a message dispatch loop.
- Also, a method should not show a dialog or message box, because the
- processing of the dialog box messages will allow DDE messages to be
- dispatched.
- */
-
-
-
- #define SERVERONLY
- #include "Windows.h"
- #include "Ole.h"
- #include "SrvrDemo.h"
-
- /* AssociateClient
- * ---------------
- *
- * Add a client to the list of clients associated with an object.
- *
- * This function is necessary only because ServerDemo does not create object
- * structures as they are requested, but rather has a fixed set of objects.
- * When DocGetObject is called with a NULL object name, the entire
- * document is requested, but ServerDemo does not currently support making
- * the entire document an object, so DocGetObject returns one object.
- * That object now goes by two names: NULL and its real name. Therefore
- * we need to keep track of both lpoleclient's that were passed to
- * DocGetObject. Ideally, DocGetObject should always create a new OBJ
- * structure containing a pointer (or some reference) to the object's native
- * data and also containing one lpoleclient.
- *
- * LPOLECLIENT lpoleclient - the client to be associated with the object.
- * LPOBJ lpobj - the object
- *
- * RETURNS: TRUE if successful
- * FALSE if out of memory
- *
- * CUSTOMIZATION: Server Demo specific
- *
- */
- static BOOL AssociateClient (LPOLECLIENT lpoleclient, LPOBJ lpobj)
- {
- int i;
- for (i=0; i < clpoleclient; i++)
- {
- if (lpobj->lpoleclient[i]==lpoleclient)
- {
- return TRUE;
- }
- if (lpobj->lpoleclient[i]==NULL)
- {
- lpobj->lpoleclient[i]=lpoleclient;
- return TRUE;
- }
- }
- return FALSE;
- }
-
-
-
- /* CreateNewDoc
- * ------------
- *
- * If lhdoc == NULL then we must register the new document by calling
- * OleRegisterServerDoc, which will return a new handle which will be stored
- * in docMain.lhdoc.
- * Also if lhdoc==NULL then this document is being created at the request of
- * the user, not of the client library.
- *
- * LONG lhdoc - Document handle
- * LPSTR lpszDoc - Title of the new document
- * DOCTYPE doctype - What type of document is being created
- *
- * RETURNS: TRUE if successful, FALSE otherwise.
- *
- * CUSTOMIZATION: Re-implement
- *
- */
- BOOL CreateNewDoc (LONG lhdoc, LPSTR lpszDoc, DOCTYPE doctype)
- {
- int i;
-
- // Fill in the fields of the document structure.
- if (lhdoc == NULL)
- {
- if (OLE_OK != OleRegisterServerDoc
- (srvrMain.lhsrvr,
- lpszDoc,
- (LPOLESERVERDOC) &docMain,
- (LHSERVERDOC FAR *) &docMain.lhdoc))
- return FALSE;
- }
- else
- docMain.lhdoc = lhdoc;
-
- docMain.doctype = doctype;
- docMain.oledoc.lpvtbl= &docvtbl;
- // Reset all the flags because no object numbers have been used.
- for (i=1; i <= cfObjNums; i++)
- docMain.rgfObjNums[i] = FALSE;
-
- fDocChanged = FALSE;
-
- SetTitle (lpszDoc, doctype == doctypeEmbedded);
- return TRUE;
- }
-
-
-
- /* DestroyDoc
- * ----------
- *
- * Free all memory that had been allocated for a document.
- *
- *
- * CUSTOMIZATION: Re-implement. Your application will probably use some
- * other method for enumerating all the objects in a document.
- * ServerDemo enumerates the child windows, but if each object
- * does not have its own window, this will not work.
- *
- */
- void DestroyDoc (void)
- {
- HWND hwnd;
- HWND hwndNext;
-
- // Delete all object windows.
- hwnd = SelectedObjectWindow();
- while (hwnd)
- {
- hwndNext = GetWindow (hwnd, GW_HWNDNEXT);
- // Each object window frees its own memory upon receiving WM_DESTROY.
- DestroyWindow (hwnd);
- hwnd = hwndNext;
- }
-
- if (docMain.aName)
- {
- GlobalDeleteAtom (docMain.aName);
- docMain.aName = NULL;
- }
-
- if (docMain.hpal)
- DeleteObject (docMain.hpal);
- }
-
-
-
- /* DocClose DOCUMENT "Close" METHOD
- * --------
- *
- * The library calls this method to unconditionally close the document.
- *
- * LPOLESERVERDOC lpoledoc - The server document to close
- *
- * RETURNS: Return value from RevokeDoc.
- *
- * CUSTOMIZATION: None
- *
- */
- OLESTATUS FAR PASCAL __export DocClose (LPOLESERVERDOC lpoledoc)
- {
- return RevokeDoc();
- }
-
-
-
- /* DocExecute DOCUMENT "Execute" METHOD
- * ----------
- *
- * This application does not support the execution of DDE execution commands.
- *
- * LPOLESERVERDOC lpoledoc - The server document
- * HANDLE hCommands - DDE execute commands
- *
- * RETURNS: OLE_ERROR_COMMAND
- *
- * CUSTOMIZATION: Re-implement if your application supports the execution of
- * DDE commands.
- *
- */
- OLESTATUS FAR PASCAL __export DocExecute (LPOLESERVERDOC lpoledoc, HANDLE hCommands)
- {
- return OLE_ERROR_COMMAND;
- }
-
-
-
- /* DocGetObject DOCUMENT "GetObject" METHOD
- * ------------
- *
- * The library uses this method to get an object's structure for the
- * client. Memory needs to be allocated and initialized here for this.
- * A NULL string indicates that the client has an embedded object
- * which was started from Create, CreateFromTemplate, or Edit, but not Open.
- *
- * First see if the object name is NULL. If so, you would ordinarily
- * return the entire document, but Server Demo returns the selected object.
- * If the object name is not NULL, then go through the list of objects,
- * searching for one with that name. Return an error if there is not one.
- *
- * LPOLESERVERDOC lpoledoc - The server document
- * LPSTR lpszObjectName - The name of the object to get data for
- * LPOLEOBJECT FAR *lplpoleobject - The object's data is put here
- * LPOLECLIENT lpoleclient - The client structure
- *
- * RETURNS: OLE_OK
- * OLE_ERROR_NAME if object not found
- * OLE_ERROR_MEMORY if no more memory to store lpoleclient
- *
- * CUSTOMIZATION: Re-implement.
- * lpszObjectName == "" indicates that the whole document
- * should be the object returned.
- *
- */
- OLESTATUS FAR PASCAL __export DocGetObject
- (LPOLESERVERDOC lpoledoc, LPSTR lpszObjectName,
- LPOLEOBJECT FAR *lplpoleobject, LPOLECLIENT lpoleclient)
- {
- HWND hwnd;
- ATOM aName;
- LPOBJ lpobj;
-
- if (lpszObjectName == NULL || lpszObjectName[0] == '\0')
- {
- // Return a new object or the selected object.
- hwnd = SelectedObjectWindow();
- lpobj = hwnd ? HwndToLpobj (hwnd) : CreateNewObj (FALSE);
- *lplpoleobject = (LPOLEOBJECT) lpobj;
- // Associate client with object.
- if (!AssociateClient (lpoleclient, lpobj))
- return OLE_ERROR_MEMORY;
- return OLE_OK;
- }
-
- if (!(aName = GlobalFindAtom (lpszObjectName)))
- return OLE_ERROR_NAME;
-
- hwnd = SelectedObjectWindow();
-
- // Go through all the child windows and find the window whose name
- // matches the given object name.
-
- while (hwnd)
- {
- lpobj = HwndToLpobj (hwnd);
-
- if (aName == lpobj->aName)
- {
- // Return the object with the matching name.
- *lplpoleobject = (LPOLEOBJECT) lpobj;
- // Associate client with the object.
- if (!AssociateClient (lpoleclient, lpobj))
- return OLE_ERROR_MEMORY;
- return OLE_OK;
- }
- hwnd = GetWindow (hwnd, GW_HWNDNEXT);
- }
-
- if ((DOCTYPE)((DOCPTR)lpoledoc)->doctype == (DOCTYPE)doctypeEmbedded)
- {
- lpobj = CreateNewObj (FALSE);
- *lplpoleobject = (LPOLEOBJECT) lpobj;
-
- // Associate client with object.
- if (!AssociateClient (lpoleclient, lpobj))
- return OLE_ERROR_MEMORY;
- return OLE_OK;
- }
-
- // Object with name lpszObjName was not found.
- return OLE_ERROR_NAME;
- }
-
- /* DocRelease DOCUMENT "Release" METHOD
- * ----------
- *
- * The library uses this method to notify the server that a revoked
- * document has finally finished all conversations, and can be
- * destroyed.
- * It sets fWaitingForDocRelease to FALSE so a new document can be created
- * and the user can continue working.
- *
- * LPOLESERVERDOC lpoledoc - The server document
- *
- * RETURNS: OLE_OK
- *
- * CUSTOMIZATION: None
- *
- */
- OLESTATUS FAR PASCAL __export DocRelease (LPOLESERVERDOC lpoledoc)
- {
- fWaitingForDocRelease = FALSE;
- // Free all memory that has been allocated for the document.
- DestroyDoc();
-
- return OLE_OK;
- }
-
-
-
- /* DocSave DOCUMENT "Save" METHOD
- * -------
- *
- * Save document to a file.
- *
- * LPOLESERVERDOC lpoledoc - The document to save
- *
- * RETURNS: OLE_OK
- *
- * CUSTOMIZATION: None
- *
- */
- OLESTATUS FAR PASCAL __export DocSave (LPOLESERVERDOC lpoledoc)
- {
- if (docMain.doctype == doctypeFromFile)
- {
- // No "File Save As" dialog box will be brought up because the
- // file name is already known.
- return SaveDoc() ? OLE_OK : OLE_ERROR_GENERIC;
- }
- else
- return OLE_ERROR_GENERIC;
- }
-
-
-
- /* DocSetDocDimensions DOCUMENT "SetDocDimensions" METHOD
- * -------------------
- *
- * The library calls this method to tell the server the bounds on
- * the target device for rendering the document.
- * A call to this method is ignored for linked objects because the size of
- * a linked document depends only on the source file.
- *
- * LPOLESERVERDOC lpoledoc - The server document
- * LPRECT lprect - The target size in MM_HIMETRIC units
- *
- * RETURNS: OLE_OK
- *
- * CUSTOMIZATION: Re-implement
- * How an object is sized is application-specific. (Server Demo
- * uses MoveWindow.)
- *
- */
- OLESTATUS FAR PASCAL __export DocSetDocDimensions
- (LPOLESERVERDOC lpoledoc, LPRECT lprect)
- {
- if (docMain.doctype == doctypeEmbedded)
- {
- RECT rect = *lprect;
-
- // the units are in HIMETRIC
- rect.right = rect.right - rect.left;
- rect.bottom = rect.top - rect.bottom;
- HiMetricToDevice (hwndMain, (LPPOINT) &rect.right);
- MoveWindow (SelectedObjectWindow(), 0, 0,
- rect.right + 2 * GetSystemMetrics(SM_CXFRAME),
- rect.bottom + 2 * GetSystemMetrics(SM_CYFRAME),
- TRUE);
- /* If for some reason your application needs to notify the client that
- the data has changed because DocSetDocDimensions has been called,
- then notify the client here.
- SendDocMsg (OLE_CHANGED);
- */
- }
- return OLE_OK;
- }
-
-
-
- /* DocSetHostNames DOCUMENT "SetHostNames" METHOD
- * ---------------
- *
- * The library uses this method to set the name of the document
- * window.
- * All this function does is change the title bar text, although it could
- * do more if necesary.
- * This function is only called for embedded objects; linked objects
- * use their filenames for the title bar text.
- *
- * LPOLESERVERDOC lpoledoc - The server document
- * LPSTR lpszClient - The name of the client
- * LPSTR lpszDoc - The client's name for the document
- *
- * RETURNS: OLE_OK
- *
- * CUSTOMIZATION: None
- *
- */
- OLESTATUS FAR PASCAL __export DocSetHostNames
- (LPOLESERVERDOC lpoledoc, LPSTR lpszClient, LPSTR lpszDoc)
- {
- SetTitle (lpszDoc, TRUE);
- lstrcpy ((LPSTR) szClient, lpszClient);
- lstrcpy ((LPSTR) szClientDoc, Abbrev(lpszDoc));
- UpdateFileMenu (IDM_UPDATE);
- return OLE_OK;
- }
-
-
-
- /* DocSetColorScheme DOCUMENT "SetColorScheme" METHOD
- * -----------------
- *
- * The client calls this method to suggest a color scheme (palette) for
- * the server to use.
- * In Server Demo the document's palette is never actually used because each
- * object has its own palette. See ObjSetColorScheme.
- *
- * LPOLESERVERDOC lpoledoc - The server document
- * LPLOGPALETTE lppal - Suggested palette
- *
- * RETURNS: OLE_ERROR_PALETTE if CreatePalette fails,
- * OLE_OK otherwise
- *
- *
- * CUSTOMIZATION: If your application supports color schemes, then this
- * function is a good example of how to create and store
- * a palette.
- */
- OLESTATUS FAR PASCAL __export DocSetColorScheme
- (LPOLESERVERDOC lpoledoc, LPLOGPALETTE lppal)
- {
- HPALETTE hpal = CreatePalette (lppal);
-
- if (hpal==NULL)
- return OLE_ERROR_PALETTE;
-
- if (docMain.hpal)
- {
- // Delete old palette
- DeleteObject (docMain.hpal);
- }
- // Store handle to new palette
- docMain.hpal = hpal;
- return OLE_OK;
- }
-
-
-
- /* RevokeDoc
- * ---------
- *
- * Call OleRevokeServerDoc.
- * If the return value is OLE_WAIT_FOR_BUSY, then set fWaitingForDocRelease
- * and enter a message-dispatch loop until fWaitingForDocRelease is reset.
- * As long as fWaitingForDocRelease is set, the user interface will be
- * disabled so that the user will not be able to manipulate the document.
- * When the DocRelease method is called, it will reset fWaitingForDocRelease,
- * allowing RevokeDoc to free the document's memory and return.
- *
- * This is essentially a way to make an asynchronous operation synchronous.
- * We need to wait until the old document is revoked before we can delete
- * its data and create a new one.
- *
- * Note that we cannot call RevokeDoc from a method because it is illegal to
- * enter a message-dispatch loop within a method.
- *
- * RETURNS: The return value of OleRevokeServerDoc.
- *
- * CUSTOMIZATION: lhdoc may need to be passed in as a parameter if your
- * application does not have a global variable corresponding
- * to docMain.
- *
- */
- OLESTATUS RevokeDoc (void)
- {
- OLESTATUS olestatus;
-
- if ((olestatus = OleRevokeServerDoc(docMain.lhdoc)) > OLE_WAIT_FOR_RELEASE)
- DestroyDoc();
-
- docMain.lhdoc = NULL; // A NULL handle indicates that the document
- // has been revoked or is being revoked.
- return olestatus;
-
- }
-
-
-
- /* SaveChangesOption
- * -----------------
- *
- * Give the user the opportunity to save changes to the current document
- * before continuing.
- *
- * BOOL *pfUpdateLater - Will be set to TRUE if the client does not accept
- * the update and needs to be updated when the document
- * is closed. In that case, OLE_CLOSED will be sent.
- *
- * RETURNS: IDYES, IDNO, or IDCANCEL
- *
- * CUSTOMIZATION: None
- *
- */
- int SaveChangesOption (BOOL *pfUpdateLater)
- {
- int nReply;
- char szBuf[cchFilenameMax];
-
- *pfUpdateLater = FALSE;
-
- if (fDocChanged)
- {
- char szTmp[cchFilenameMax];
-
- if (docMain.aName)
- GlobalGetAtomName (docMain.aName, szTmp, cchFilenameMax);
- else
- szTmp[0] = NULL;
-
- if (docMain.doctype == doctypeEmbedded)
- wsprintf (szBuf, "The object has been changed.\n\nUpdate %s before closing the object?", Abbrev (szTmp));
- else
- lstrcpy (szBuf, (LPSTR) "Save changes?");
-
- nReply = MessageBox (hwndMain, szBuf, szAppName,
- MB_ICONEXCLAMATION | MB_YESNOCANCEL);
-
- switch (nReply)
- {
- case IDYES:
- if (docMain.doctype != doctypeEmbedded)
- SaveDoc();
- else
- switch (OleSavedServerDoc (docMain.lhdoc))
- {
- case OLE_ERROR_CANT_UPDATE_CLIENT:
- *pfUpdateLater = TRUE;
- break;
- case OLE_OK:
- break;
- default:
- ErrorBox ("Fatal Error: Cannot update.");
- }
- return IDYES;
- case IDNO:
- return IDNO;
- case IDCANCEL:
- return IDCANCEL;
- }
- }
- return TRUE;
- }
-
-
-
- /* SendDocMsg
- * ----------
- *
- * This function sends messages to all the objects in a document when
- * the document has changed.
- *
- * WORD wMessage - The message to send
- *
- * CUSTOMIZATION: The means of enumerating all the objects in a document
- * is application specific.
- */
- void SendDocMsg (WORD wMessage)
- {
- HWND hwnd;
-
- // Get handle to first object window.
- hwnd = SelectedObjectWindow();
-
- // Send message to all object windows.
- while (hwnd)
- {
- SendObjMsg (HwndToLpobj(hwnd), wMessage);
- hwnd = GetWindow (hwnd, GW_HWNDNEXT);
- }
- }
-