/* OLE SERVER DEMO Server.c This file contains server methods and various server-related support functions. (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved */ #define SERVERONLY #include #include #include "srvrdemo.h" CLASS_STRINGS ClassStrings = { "ServerDemo", "*.sd", "Server Demo", "srvrdemo.exe" }; /* 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. */ BOOL RegServer(){ LONG fRet; HKEY hKey; CHAR szKeyName[300]; //Get better value BOOL retVal = FALSE; lstrcpy(szKeyName, ClassStrings.pClassName); lstrcat(szKeyName, "\\protocol\\StdFileEditing\\verb"); //Check if Class is installed, following should hold correct if class is installed. if ((fRet = RegOpenKey(HKEY_CLASSES_ROOT, szKeyName, &hKey)) == ERROR_SUCCESS) return FALSE; RegCloseKey(hKey); if ((fRet = RegSetValue(HKEY_CLASSES_ROOT, (LPSTR)(ClassStrings.pFileSpec+1), REG_SZ, ClassStrings.pClassName, 7)) != ERROR_SUCCESS) return FALSE; if((fRet = RegSetValue(HKEY_CLASSES_ROOT, ClassStrings.pClassName, REG_SZ, ClassStrings.pHumanReadable, 7)) != ERROR_SUCCESS) return FALSE; lstrcat(szKeyName, "\\0"); if((fRet = RegSetValue(HKEY_CLASSES_ROOT, (LPSTR)szKeyName, REG_SZ, "PLAY", 4)) != ERROR_SUCCESS) return FALSE; szKeyName[lstrlen(szKeyName) - 1] = '1'; if((fRet = RegSetValue(HKEY_CLASSES_ROOT, (LPSTR)szKeyName, REG_SZ, "EDIT", 4)) != ERROR_SUCCESS) return FALSE; lstrcpy(szKeyName, ClassStrings.pClassName); lstrcat(szKeyName, "\\protocol\\StdFileEditing\\Server"); if((fRet = RegSetValue(HKEY_CLASSES_ROOT, (LPSTR)szKeyName, REG_SZ, ClassStrings.pExeName, 11)) != ERROR_SUCCESS) return FALSE; lstrcpy(szKeyName, ClassStrings.pClassName); lstrcat(szKeyName, "\\protocol\\StdExecute\\Server"); if((fRet = RegSetValue(HKEY_CLASSES_ROOT, (LPSTR)szKeyName, REG_SZ, ClassStrings.pExeName, 11)) != ERROR_SUCCESS) return FALSE; return TRUE; } /* Abbrev * ------ * * Return a pointer to the filename part of a fully-qualified pathname. * * LPSTR lpsz - Fully qualified pathname * * CUSTOMIZATION: May be useful, but not necessary. * */ LPSTR Abbrev (LPSTR lpsz) { LPSTR lpszTemp; lpszTemp = lpsz + lstrlen(lpsz) - 1; while (lpszTemp > lpsz && lpszTemp[-1] != '\\') lpszTemp--; return lpszTemp; } /* InitServer * ---------- * * Initialize the server by allocating memory for it, and calling * the OleRegisterServer method. Requires that the server method table * has been properly initialized. * * HWND hwnd - Handle to the main window * LPSTR lpszLine - The Windows command line * * RETURNS: TRUE if the memory could be allocated, and the server * was properly registered. * FALSE otherwise * * CUSTOMIZATION: Your application might not use a global variable * for srvrMain. * */ BOOL InitServer (HWND hwnd, HANDLE hInst) { RegServer(); srvrMain.olesrvr.lpvtbl = &srvrvtbl; if (OLE_OK != OleRegisterServer (szClassName, (LPOLESERVER) &srvrMain, &srvrMain.lhsrvr, hInst, OLE_SERVER_MULTI)) return FALSE; else return TRUE; } /* InitVTbls * --------- * * Create procedure instances for all the OLE methods. * * * CUSTOMIZATION: Your application might not use global variables for srvrvtbl, * docvtbl, and objvtbl. */ VOID InitVTbls (VOID) { typedef LPVOID ( APIENTRY *LPVOIDPROC) (LPOLEOBJECT, LPSTR); // Server method table srvrvtbl.Create = SrvrCreate; srvrvtbl.CreateFromTemplate = SrvrCreateFromTemplate; srvrvtbl.Edit = SrvrEdit; srvrvtbl.Execute = SrvrExecute; srvrvtbl.Exit = SrvrExit; srvrvtbl.Open = SrvrOpen; srvrvtbl.Release = SrvrRelease; // Document method table docvtbl.Close = DocClose; docvtbl.GetObject = DocGetObject; docvtbl.Execute = DocExecute; docvtbl.Release = DocRelease; docvtbl.Save = DocSave; docvtbl.SetColorScheme = DocSetColorScheme; docvtbl.SetDocDimensions = DocSetDocDimensions; docvtbl.SetHostNames = DocSetHostNames; // Object method table objvtbl.DoVerb = ObjDoVerb; objvtbl.EnumFormats = ObjEnumFormats; objvtbl.GetData = ObjGetData; objvtbl.QueryProtocol = ObjQueryProtocol; objvtbl.Release = ObjRelease; objvtbl.SetBounds = ObjSetBounds; objvtbl.SetColorScheme = ObjSetColorScheme; objvtbl.SetData = ObjSetData; objvtbl.SetTargetDevice = ObjSetTargetDevice; objvtbl.Show = ObjShow; } /* SetTitle * -------- * * Sets the main window's title bar. The format of the title bar is as follows * * If embedded * - in * * Example: "Server Demo - SrvrDemo Shape in OLECLI.DOC" * where OLECLI.DOC is a Winword document * * otherwise * - * * Example: "Server Demo - OLESVR.SD" * where OLESVR.SD is a Server demo document * * LPSTR lpszDoc - document name * BOOL fEmbedded - If TRUE embedded document, else normal document * * RETURNS: OLE_OK * * * CUSTOMIZATION: Your application may store the document's name somewhere * other than docMain.aName. Other than that, you may * find this a useful utility function as is. * */ VOID SetTitle (LPSTR lpszDoc, BOOL fEmbedded) { CHAR szBuf[cchFilenameMax]; if (lpszDoc && lpszDoc[0]) { // Change document name. if (docMain.aName) GlobalDeleteAtom (docMain.aName); docMain.aName = GlobalAddAtom (lpszDoc); } if (fEmbedded) { // if (lpszDoc && lpszDoc[0]) { wsprintf (szBuf, "%s - SrvrDemo Shape in %s", (LPSTR) szAppName, Abbrev (lpszDoc)); } else { // Use name from docMain CHAR szDoc [cchFilenameMax]; GlobalGetAtomName (docMain.aName, szDoc, cchFilenameMax); wsprintf (szBuf, "%s - SrvrDemo Shape in %s", (LPSTR) szAppName, Abbrev (szDoc)); } SetWindowText (hwndMain, (LPSTR)szBuf); } else if (lpszDoc && lpszDoc[0]) { wsprintf (szBuf, "%s - %s", (LPSTR) szAppName, Abbrev(lpszDoc)); SetWindowText (hwndMain, szBuf); } } /* SrvrCreate SERVER "Create" METHOD * ---------- * * Create a document, allocate and initialize the OLESERVERDOC structure, * and associate the library's handle with it. * In this demo server, we also create an object for the user to edit. * * LPOLESERVER lpolesrvr - The server structure registered by * the application * LHSERVERDOC lhdoc - The library's handle * OLE_LPCSTR lpszClassName - The class of document to create * OLE_LPCSTR lpszDoc - The name of the document * LPOLESERVERDOC FAR *lplpoledoc - Indicates the server doc structure to be * created * * RETURNS: OLE_OK if the named document was created. * OLE_ERROR_NEW if the document could not be created. * * CUSTOMIZATION: Your application might not call CreateNewObj. * */ OLESTATUS APIENTRY SrvrCreate (LPOLESERVER lpolesrvr, LHSERVERDOC lhdoc, OLE_LPCSTR lpszClassName, OLE_LPCSTR lpszDoc, LPOLESERVERDOC FAR *lplpoledoc) { if (!CreateNewDoc (lhdoc, (LPSTR) lpszDoc, doctypeEmbedded)) return OLE_ERROR_NEW; // Although the document has not actually been changed, the client has not // received any data from the server yet, so the client will need to be // updated. Therefore, CreateNewObj sets fDocChanged to TRUE. CreateNewObj (TRUE); *lplpoledoc = (LPOLESERVERDOC) &docMain; EmbeddingModeOn(); return OLE_OK; } /* SrvrCreateFromTemplate SERVER "CreateFromTemplate" METHOD * ---------------------- * * Create a document, allocate and initialize the OLESERVERDOC structure, * initializing the document with the contents named in the template name, * and associate the library's handle with the document structure. * * LPOLESERVER lpolesrvr - The server structure registered by * the application * LHSERVERDOC lhdoc - The library's handle * OLE_LPCSTR lpszClassName - The class of document to create * OLE_LPCSTR lpszDoc - The name of the document * OLE_LPCSTR lpszTemplate - The name of the template * LPOLESERVERDOC FAR *lplpoledoc - Indicates the server doc structure * to be created * * RETURNS: OLE_OK if the named document was created. * OLE_ERROR_TEMPLATE if the document could not be created. * * CUSTOMIZATION: None * */ OLESTATUS APIENTRY SrvrCreateFromTemplate (LPOLESERVER lpolesrvr, LHSERVERDOC lhdoc, OLE_LPCSTR lpszClassName, OLE_LPCSTR lpszDoc, OLE_LPCSTR lpszTemplate, LPOLESERVERDOC FAR *lplpoledoc) { if (!CreateDocFromFile((LPSTR) lpszTemplate, (LHSERVERDOC) lhdoc, doctypeEmbedded)) return OLE_ERROR_TEMPLATE; *lplpoledoc = (LPOLESERVERDOC) &docMain; // Although the document has not actually been changed, the client has not // received any data from the server yet, so the client will need to be // updated. fDocChanged = TRUE; EmbeddingModeOn(); return OLE_OK; } /* SrvrEdit SERVER "Edit" METHOD * -------- * * A request by the libraries to create a document, allocate and * initialize the OLESERVERDOC structure, and associate the * library's handle with the document structure. * We create an object which will be modified by the SetData method * before the user has a chance to touch it. * * LPOLESERVER lpolesrvr - The server structure registered by * the application * LHSERVERDOC lhdoc - The library's handle * OLE_LPCSTR lpszClassName - The class of document to create * OLE_LPCSTR lpszDoc - The name of the document * LPOLESERVERDOC FAR *lplpoledoc - Indicates the server doc structure to be * created * * RETURNS: OLE_OK if the named document was created. * OLE_ERROR_EDIT if the document could not be created. * * CUSTOMIZATION: None * */ OLESTATUS APIENTRY SrvrEdit (LPOLESERVER lpolesrvr, LHSERVERDOC lhdoc, OLE_LPCSTR lpszClassName, OLE_LPCSTR lpszDoc, LPOLESERVERDOC FAR *lplpoledoc) { if (!CreateNewDoc ((LONG)lhdoc, (LPSTR)lpszDoc, doctypeEmbedded)) return OLE_ERROR_EDIT; // The client is creating an embedded object for the server to edit, // so initially the client and server are in sync. fDocChanged = FALSE; *lplpoledoc = (LPOLESERVERDOC) &docMain; EmbeddingModeOn(); return OLE_OK; } /* SrvrExecute SERVER "Execute" METHOD * -------- * * This application does not support the execution of DDE execution commands. * * LPOLESERVER lpolesrvr - The server structure registered by * the application * HANDLE hCommands - DDE execute commands * * RETURNS: OLE_ERROR_COMMAND * * CUSTOMIZATION: Re-implement if your application supports the execution of * DDE commands. * */ OLESTATUS APIENTRY SrvrExecute (LPOLESERVER lpolesrvr, HANDLE hCommands) { return OLE_ERROR_COMMAND; } /* SrvrExit SERVER "Exit" METHOD * -------- * * This method is called the library to instruct the server to exit. * * LPOLESERVER lpolesrvr - The server structure registered by * the application * * RETURNS: OLE_OK * * CUSTOMIZATION: None * */ OLESTATUS APIENTRY SrvrExit (LPOLESERVER lpolesrvr) { if (srvrMain.lhsrvr) // If we haven't already tried to revoke the server. { StartRevokingServer(); } return OLE_OK; } /* SrvrOpen SERVER "Open" METHOD * -------- * * Open the named document, allocate and initialize the OLESERVERDOC * structure, and associate the library's handle with it. * * LPOLESERVER lpolesrvr - The server structure registered by * the application * LHSERVERDOC lhdoc - The library's handle * OLE_LPCSTR lpszDoc - The name of the document * LPOLESERVERDOC FAR *lplpoledoc - Indicates server doc structure to be * created * * RETURNS: OLE_OK if the named document was opened. * OLE_ERROR_OPEN if document could not be opened correctly. * * CUSTOMIZATION: None * */ OLESTATUS APIENTRY SrvrOpen (LPOLESERVER lpolesrvr, LHSERVERDOC lhdoc, OLE_LPCSTR lpszDoc, LPOLESERVERDOC FAR *lplpoledoc) { if (!CreateDocFromFile ((LPSTR)lpszDoc, (LHSERVERDOC)lhdoc, doctypeFromFile)) return OLE_ERROR_OPEN; *lplpoledoc = (LPOLESERVERDOC) &docMain; return OLE_OK; } /* SrvrRelease SERVER "Release" METHOD * ----------- * * This library calls the SrvrRelease method when it is safe to quit the * application. Note that the server application is not required to quit. * * srvrMain.lhsrvr != NULL indicates that SrvrRelease has been called * because the client is no longer connected, not because the server called * OleRevokeServer. * Therefore, only start the revoking process if the document is of type * doctypeEmbedded or if the server was opened for an invisible update. * * srvrmain.lhsrvr == NULL indicates that OleRevokeServer has already * been called (by the server application), and srvrMain is bad. * It is safe to quit now because SrvrRelease has just been called. * * Note that this method may be called twice: when OleRevokeServer is * called in StartRevokingServer, SrvrRelease is called again. * Therefore we need to be reentrant. * * LPOLESERVER lpolesrvr - The server structure to release * * RETURNS: OLE_OK * * CUSTOMIZATION: None * */ OLESTATUS APIENTRY SrvrRelease (LPOLESERVER lpolesrvr) { if (srvrMain.lhsrvr) { if (fRevokeSrvrOnSrvrRelease && (docMain.doctype == doctypeEmbedded || !IsWindowVisible (hwndMain))) StartRevokingServer(); } else { fWaitingForSrvrRelease = FALSE; // Here you should free any memory that had been allocated for the server. PostQuitMessage (0); } return OLE_OK; } /* StartRevokingServer * ------------------- * * Hide the window, and start to revoke the server. * Revoking the server will let the library close any registered documents. * OleRevokeServer may return OLE_WAIT_FOR_RELEASE. * Calling StartRevokingServer starts a chain of events that will eventually * lead to the application being terminated. * * RETURNS: The return value from OleRevokeServer * * CUSTOMIZATION: None * */ OLESTATUS StartRevokingServer (VOID) { OLESTATUS olestatus; if (srvrMain.lhsrvr) { LHSERVER lhserver; // Hide the window so user can do nothing while we are waiting. ShowWindow (hwndMain, SW_HIDE); lhserver = srvrMain.lhsrvr; // Set lhsrvr to NULL to indicate that srvrMain is a bad and that // if SrvrRelease is called, then it is ok to quit the application. srvrMain.lhsrvr = 0; olestatus = OleRevokeServer (lhserver); } else // The programmer should ensure that this never happens. ErrorBox ("Fatal Error: StartRevokingServer called on NULL server."); return olestatus; }