/* OLE SERVER DEMO SrvrDemo.c This file contains the window handlers, and various initialization and utility functions. (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved */ #define SERVERONLY #include #include #include "srvrdemo.h" /* Global variable definitions */ HWND hwndMain = 0; // Used in converting units from pixels to Himetric and vice-versa int giXppli = 0; // pixels per logical inch along width int giYppli = 0; // pixels per logical inch along height // Since this is a not an MDI app, there can be only one server and one doc. SRVR srvrMain; DOC docMain; CHAR szClient[cchFilenameMax]; CHAR szClientDoc[cchFilenameMax]; // Has the user made changes to the document? BOOL fDocChanged = FALSE; // Is this the first instance of this application currently running? BOOL fFirstInstance = TRUE; // This flag is used when OleRevokeServerDoc returns OLE_WAIT_FOR_RELEASE, // and we must wait until DocRelease is called. BOOL fWaitingForDocRelease = FALSE; // This flag is used when OleRevokeServer returns OLE_WAIT_FOR_RELEASE, // and we must wait until SrvrRelease is called. BOOL fWaitingForSrvrRelease = FALSE; // This flag is set to TRUE after an application has called OleBlockServer // and now wishes to unblock the queued messages. See WinMain. // Server Demo never sets fUnblock to TRUE because it never calls // OleBlockServer. BOOL fUnblock = FALSE; // Set this to FALSE if you want to guarantee that the server will not revoke // itself when SrvrRelease is called. This is used in the IDM_NEW case and // the IDM_OPEN case (in OpenDoc). BOOL fRevokeSrvrOnSrvrRelease = TRUE; // Version number, which is stored in the native data. VERSION version = 1; HBRUSH hbrColor[chbrMax]; // Clipboard formats OLECLIPFORMAT cfObjectLink; OLECLIPFORMAT cfOwnerLink; OLECLIPFORMAT cfNative; // Method tables. OLESERVERDOCVTBL docvtbl; OLEOBJECTVTBL objvtbl; OLESERVERVTBL srvrvtbl; HANDLE hInst; HANDLE hAccelTable; HMENU hMainMenu = NULL; // Window dimensions saved in private profile. static struct { INT nX; INT nY; INT nWidth; INT nHeight; } dimsSaved, dimsCurrent; static enum { // Corresponds to the order of the menus in the .rc file. menuposFile, menuposEdit, menuposColor, menuposObject }; // Static functions. static VOID DeleteInstance (VOID); static BOOL ExitApplication (BOOL); static VOID GetWord (LPSTR *plpszSrc, LPSTR lpszDst); static BOOL InitApplication( HANDLE hInstance); static BOOL InitInstance (HANDLE hInstance); static BOOL ProcessCmdLine (LPSTR,HWND); static VOID SaveDimensions (VOID); static VOID SkipBlanks (LPSTR *plpsz); static VOID UpdateObjMenus (VOID); static BOOL FailedUpdate(HWND); /* WinMain * ------- * * Standard windows entry point * * CUSTOMIZATION: None * */ int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow ){ MSG msg; if (!InitApplication(hInstance)) return FALSE; msg.wParam = FALSE; if (!InitInstance(hInstance)) goto errRtn; if (!InitServer (hwndMain, hInstance)) goto errRtn; if (!ProcessCmdLine(lpCmdLine,hwndMain)) { ExitApplication(FALSE); goto errRtn; } for (;;) { // Your application should set fUnblock to TRUE when it decides // to unblock. if (fUnblock) { BOOL fMoreMsgs = TRUE; while (fMoreMsgs) { if (srvrMain.lhsrvr == 0) OleUnblockServer (srvrMain.lhsrvr, &fMoreMsgs); } // We have taken care of all the messages in the OLE queue fUnblock = FALSE; } if (!GetMessage(&msg, NULL, 0, 0)) break; if( !TranslateAccelerator(hwndMain, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } errRtn: DeleteInstance (); return (msg.wParam); } /* InitApplication * --------------- * * Initialize the application - register the window classes * * HANDLE hInstance * * RETURNS: TRUE if classes are properly registered. * FALSE otherwise * * CUSTOMIZATION: Re-implement * */ static BOOL InitApplication( HANDLE hInstance ) { WNDCLASS wc; wc.lpszClassName = "MainClass"; wc.lpfnWndProc = MainWndProc; wc.style = 0; wc.cbClsExtra = 4; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(hInstance, "DocIcon"); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = GetStockObject(WHITE_BRUSH); wc.lpszMenuName = "MainMenu"; if (!RegisterClass(&wc)) return FALSE; wc.lpszClassName = "ObjClass"; wc.lpfnWndProc = ObjWndProc; wc.hIcon = NULL; wc.cbWndExtra = cbWindExtra; wc.lpszMenuName = NULL; wc.hCursor = LoadCursor(NULL, IDC_CROSS); if (!RegisterClass(&wc)) return FALSE; return TRUE; } /* InitInstance * ------------ * * Create brushes used by the program, the main window, and * do any other per-instance initialization. * * HANDLE hInstance * * RETURNS: TRUE if successful * FALSE otherwise. * * CUSTOMIZATION: Re-implement * */ static BOOL InitInstance (HANDLE hInstance) { LONG rglColor [chbrMax] = { 0x000000ff, // Red 0x0000ff00, // Green 0x00ff0000, // Blue 0x00ffffff, // White 0x00808080, // Gray 0x00ffff00, // Cyan 0x00ff00ff, // Magenta 0x0000ffff // Yellow }; INT iColor; HDC hDC ; hInst = hInstance; // Initialize the method tables. InitVTbls (); // Initialize the brushes used. for (iColor = 0; iColor < chbrMax; iColor++) hbrColor[iColor] = CreateSolidBrush (rglColor[iColor]); // Register clipboard formats. cfObjectLink= RegisterClipboardFormat ("ObjectLink"); cfOwnerLink = RegisterClipboardFormat ("OwnerLink"); cfNative = RegisterClipboardFormat ("Native"); hAccelTable = LoadAccelerators(hInst, "Accelerators"); // hMainMenu = LoadMenu(hInst, "MainMenu"); hwndMain = CreateWindow( "MainClass", szAppName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 3*OBJECT_WIDTH, 3*OBJECT_HEIGHT, NULL, NULL, hInstance, NULL ); if (!hwndMain) return FALSE; szClient[0] = '\0'; lstrcpy (szClientDoc, "Client Document"); // Initialize global variables with LOGPIXELSX and LOGPIXELSY hDC = GetDC (NULL); // Get the hDC of the desktop window giXppli = GetDeviceCaps (hDC, LOGPIXELSX); giYppli = GetDeviceCaps (hDC, LOGPIXELSY); ReleaseDC (NULL, hDC); return TRUE; } /* DeleteInstance * -------------- * * Deallocate the VTables, and the brushes created for this instance * * * CUSTOMIZATION: The call to FreeVTbls must remain. * */ static VOID DeleteInstance (VOID) { INT i; for (i = 0; i < chbrMax; i++) DeleteObject (hbrColor[i]); } /* ExitApplication * --------------- * * Handles the WM_CLOSE and WM_COMMAND/IDM_EXIT messages. * * RETURNS: TRUE if application should really terminate * FALSE if not * * * CUSTOMIZATION: None * */ static BOOL ExitApplication (BOOL fUpdateLater) { if (fUpdateLater) { // The non-standard OLE client did not accept the update // when we requested it, so we are sending the client // OLE_CLOSED now that we are closing the document. SendDocMsg (OLE_CLOSED); } if (StartRevokingServer() == OLE_WAIT_FOR_RELEASE) Wait (&fWaitingForSrvrRelease); /* SrvrRelease will not necessarily post a WM_QUIT message. If the document is not embedded, SrvrRelease by itself does not cause the application to terminate. But now we want it to. */ if (docMain.doctype != doctypeEmbedded) PostQuitMessage(0); SaveDimensions(); return TRUE; } /* MainWndProc * ----------- * * Main window message handler. * * * CUSTOMIZATION: Remove the color menu and the object menu entirely. * Add handlers for your application's menu items and any * Windows messages your application needs to handle. * The handlers for the menu items that involve OLE * can be added to, but no logic should be removed. * * */ LONG APIENTRY MainWndProc (HWND hwnd, UINT message, WPARAM wParam, LONG lParam ) { LPOBJ lpobj; switch (message) { case WM_COMMAND: { WORD wID = LOWORD(wParam); if (fWaitingForDocRelease) { ErrorBox ("Waiting for a document to be revoked.\n\rPlease wait."); return 0; } switch (wID) { case IDM_EXIT: SendMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L); break; case IDM_ABOUT: DialogBox(hInst, "AboutBox", hwnd, About); break; case IDM_NEW: { BOOL fUpdateLater; OLESTATUS olestatus; if (SaveChangesOption (&fUpdateLater) == IDCANCEL) break; else if (fUpdateLater) SendDocMsg (OLE_CLOSED); // We want to revoke the doc but not the server, so if // SrvrRelease is called, do not revoke server. fRevokeSrvrOnSrvrRelease = FALSE; if ((olestatus = RevokeDoc()) > OLE_WAIT_FOR_RELEASE) { ErrorBox ("Serious Error: Cannot revoke document."); break; } else if (olestatus == OLE_WAIT_FOR_RELEASE) Wait (&fWaitingForDocRelease); fRevokeSrvrOnSrvrRelease = TRUE; if (!CreateNewDoc (0, "(Untitled)", doctypeNew)) { ErrorBox ("Serious Error: Cannot create new document."); break; } // Your application need not create a default object. CreateNewObj (FALSE); EmbeddingModeOff(); break; } case IDM_OPEN: OpenDoc(); UpdateObjMenus(); break; case IDM_SAVE: SaveDoc(); break; case IDM_SAVEAS: if (!SaveDocAs ()) break; if (docMain.doctype != doctypeEmbedded) EmbeddingModeOff(); break; case IDM_UPDATE: switch (OleSavedServerDoc (docMain.lhdoc)) { case OLE_ERROR_CANT_UPDATE_CLIENT: if (!FailedUpdate(hwnd)) ExitApplication(TRUE); break; case OLE_OK: break; default: ErrorBox ("Serious Error: Cannot update."); } break; /* Color menu */ case IDM_RED: case IDM_GREEN: case IDM_BLUE: case IDM_WHITE: case IDM_GRAY: case IDM_CYAN: case IDM_MAGENTA: case IDM_YELLOW: lpobj = SelectedObject(); lpobj->native.idmColor = wID; // Recolor the object on the screen. InvalidateRect (lpobj->hwnd, (LPRECT)NULL, TRUE); UpdateWindow (lpobj->hwnd); fDocChanged = TRUE; if (docMain.doctype == doctypeFromFile) // If object is linked, update it in client now. SendObjMsg (lpobj, OLE_CHANGED); break; /* Edit menu */ case IDM_COPY: CutOrCopyObj (TRUE); break; case IDM_CUT: CutOrCopyObj (FALSE); // Fall through. case IDM_DELETE: RevokeObj (SelectedObject()); DestroyWindow (SelectedObjectWindow()); UpdateObjMenus(); break; /* Object menu */ case IDM_NEXTOBJ: lpobj = SelectedObject(); /* The 1 in the second parameter puts the current window at the bottom of the current window list. */ SetWindowPos(lpobj->hwnd, (HANDLE)1, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE); break; case IDM_NEWOBJ: lpobj = CreateNewObj (TRUE); BringWindowToTop(lpobj->hwnd); break; default: ErrorBox ("Unknown Command."); break; } break; } case WM_NCCALCSIZE: if (!IsIconic(hwnd) && !IsZoomed(hwnd)) { dimsCurrent.nX = ((LPRECT)lParam)->left; dimsCurrent.nWidth = ((LPRECT)lParam)->right - dimsCurrent.nX; dimsCurrent.nY = ((LPRECT)lParam)->top; dimsCurrent.nHeight = ((LPRECT)lParam)->bottom - dimsCurrent.nY; } return DefWindowProc(hwnd, message, wParam, lParam); break; case WM_QUERYENDSESSION: { BOOL fUpdateLater; if (SaveChangesOption(&fUpdateLater) == IDCANCEL) return FALSE; if (fUpdateLater) { // The non-standard OLE client did not accept the update // when we requested it, so we are sending the client // OLE_CLOSED now that we are closing the document. SendDocMsg (OLE_CLOSED); } return TRUE; } case WM_CLOSE: { BOOL fUpdateLater; if (SaveChangesOption(&fUpdateLater) != IDCANCEL) ExitApplication(fUpdateLater); break; } default: return DefWindowProc(hwnd, message, wParam, lParam); } return 0; } /* About * ----- * * "About Box" dialog handler. * * CUSTOMIZATION: None * */ INT_PTR CALLBACK About (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_INITDIALOG: return TRUE; case WM_COMMAND: { WORD wID = LOWORD(wParam); if (wID == IDOK || wID == IDCANCEL) { EndDialog(hDlg, TRUE); return TRUE; } break; } } return FALSE; } /* ObjWndProc * ---------- * * Message handler for the object windows. * * * CUSTOMIZATION: Server Demo specific * */ LONG APIENTRY ObjWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static BOOL fCapture = FALSE; static struct {RECT rect; POINT pt;} drag; static RECT rectMain; switch (message) { case WM_CREATE: { LPOBJ lpobj; LPCREATESTRUCT lpcs; // The call to CreateWindow puts lpobj into lpCreateParams lpcs = (LPCREATESTRUCT) lParam; lpobj = (LPOBJ) lpcs->lpCreateParams; // Associate the window just created with the object. lpobj->hwnd = hwnd; /* Store pointer to object in the window structure. */ SetWindowLong(hwnd, ibLpobj, (LONG) lpobj); UpdateObjMenus (); break; } case WM_SIZE: { RECT rect; if (fWaitingForDocRelease) { ErrorBox ("Waiting for a document to be revoked.\n\rPlease wait."); return 0; } // Get coordinates of object relative to main window's client area. GetWindowRect (hwnd, (LPRECT)&rect); ScreenToClient (hwndMain, (LPPOINT)&rect); ScreenToClient (hwndMain, (LPPOINT)&rect.right); SizeObj (hwnd, rect, TRUE); // Fall through. } case WM_PAINT: PaintObj (hwnd); break; case WM_LBUTTONDOWN: if (fWaitingForDocRelease) { ErrorBox ("Waiting for a document to be revoked.\n\rPlease wait."); return 0; } BringWindowToTop (hwnd); GetWindowRect (hwnd, (LPRECT) &drag.rect); ScreenToClient (hwndMain, (LPPOINT)&drag.rect.left); ScreenToClient (hwndMain, (LPPOINT)&drag.rect.right); drag.pt.x = LOWORD(lParam); drag.pt.y = HIWORD(lParam); // Convert drag.pt to the main window's client coordinates. ClientToScreen (hwnd, (LPPOINT)&drag.pt); ScreenToClient (hwndMain, (LPPOINT)&drag.pt); // Remember the coordinates of the main window so we do not drag // an object outside the main window. GetClientRect (hwndMain, (LPRECT) &rectMain); SetCapture (hwnd); fCapture = TRUE; break; case WM_MOUSEMOVE: { HDC hdc; POINT pt; if (!fCapture) break; fDocChanged = TRUE; pt.x = LOWORD(lParam); pt.y = HIWORD(lParam); // Convert pt to the main window's client coordinates. ClientToScreen (hwnd, (LPPOINT)&pt); ScreenToClient (hwndMain, (LPPOINT)&pt); if (!PtInRect (&rectMain, pt)) break; hdc = GetDC(hwndMain); // Erase old drag rectangle InvertRect (hdc, (LPRECT)&drag.rect); // Update drag.rect OffsetRect (&drag.rect, pt.x - drag.pt.x, pt.y - drag.pt.y); // Update drag.pt drag.pt.x = pt.x; drag.pt.y = pt.y; // Show new drag rectangle InvertRect (hdc, (LPRECT)&drag.rect); ReleaseDC (hwndMain, hdc); break; } case WM_LBUTTONUP: { LPOBJ lpobj; if (!fCapture) return TRUE; fCapture = FALSE; ReleaseCapture (); MoveWindow (hwnd, drag.rect.left, drag.rect.top, drag.rect.right - drag.rect.left, drag.rect.bottom - drag.rect.top, TRUE); InvalidateRect (hwnd, (LPRECT)NULL, TRUE); lpobj = HwndToLpobj (hwnd); lpobj->native.nX = drag.rect.left; lpobj->native.nY = drag.rect.top; break; } case WM_DESTROY: DestroyObj (hwnd); return DefWindowProc(hwnd, message, wParam, lParam); default: return DefWindowProc(hwnd, message, wParam, lParam); } return 0; } /* DeviceToHiMetric * ---------------- * * Converts a point from device units to HiMetric units. * This function is designed to be generic enough to be reused. * * HWND hwnd - The window whose display context is to be used * LPPOINT lppt - The point to be converted. * * CUSTOMIZATION: None * */ void DeviceToHiMetric ( LPPOINT lppt) { lppt->x = MulDiv (lppt->x, HIMETRIC_PER_INCH, giXppli); lppt->y = MulDiv (lppt->y, HIMETRIC_PER_INCH, giYppli); } /* UpdateFileMenu * -------------- * * Updates the "Update " and "Exit & Return to " * with the currently set client document name * * CUSTOMIZATION: Re-implement * */ VOID UpdateFileMenu (INT iSaveUpdateId) { CHAR str[cchFilenameMax]; HMENU hMenu = GetMenu(hwndMain); /* Change File menu so it contains "Update" instead of "Save". */ lstrcpy (str, "&Update "); lstrcat (str, szClientDoc); ModifyMenu(hMenu, iSaveUpdateId, MF_BYCOMMAND|MF_STRING, IDM_UPDATE, str); /* Change File menu so it contains "Exit & Return to " */ /* instead of just "Exit" */ lstrcpy (str, "E&xit && Return to "); lstrcat (str, szClientDoc); ModifyMenu(hMenu, IDM_EXIT, MF_BYCOMMAND|MF_STRING, IDM_EXIT, str); } /* EmbeddingModeOn * --------------- * * Do whatever is necessary for the application to start "embedding mode." * * CUSTOMIZATION: Re-implement * */ VOID EmbeddingModeOn(VOID) { HMENU hMenu = GetMenu(hwndMain); UpdateFileMenu (IDM_SAVE); /* Change File menu so it contains "Save Copy As..." instead of */ /* "Save As..." */ ModifyMenu(hMenu, IDM_SAVEAS, MF_BYCOMMAND|MF_STRING, IDM_SAVEAS, "Save Copy As.."); /* In embedded mode, the user can edit only the embedded object, not create new ones. */ EnableMenuItem(hMenu, menuposObject, MF_BYPOSITION | MF_GRAYED); EnableMenuItem(hMenu, IDM_CUT, MF_BYCOMMAND | MF_GRAYED); EnableMenuItem(hMenu, IDM_DELETE, MF_BYCOMMAND | MF_GRAYED); DrawMenuBar (hwndMain); } /* EmbeddingModeOff * ---------------- * * Do whatever is necessary for the application to end "embedding mode." * * CUSTOMIZATION: Re-implement * */ VOID EmbeddingModeOff (VOID) { HMENU hMenu = GetMenu(hwndMain); /* Change File menu so it contains "Save" instead of "Update". */ ModifyMenu(hMenu, IDM_UPDATE, MF_BYCOMMAND | MF_STRING, IDM_SAVE, "&Save"); /* Change File menu so it contains "Exit & Return to " */ /* instead of just "Exit" */ ModifyMenu(hMenu, IDM_EXIT, MF_BYCOMMAND | MF_STRING, IDM_EXIT, "E&xit"); /* Change File menu so it contains "Save As..." instead of */ /* "Save Copy As..." */ ModifyMenu(hMenu, IDM_SAVEAS, MF_BYCOMMAND|MF_STRING, IDM_SAVEAS, "Save &As.."); /* In non-embedded mode, the user can create new objects. */ EnableMenuItem(hMenu, menuposObject, MF_BYPOSITION | MF_ENABLED); lstrcpy (szClientDoc, "Client Document"); DrawMenuBar (hwndMain); } /* ErrorBox * -------- * * char *szMessage - String to display inside message box. * * CUSTOMIZATION: Server Demo specific * */ VOID ErrorBox (CHAR *szMessage) { MessageBox (hwndMain, szMessage, szAppName, MB_OK); } /* GetWord * ------- * * LPSTR *plpszSrc - Pointer to a pointer to a source string * LPSTR lpszDst - Pointer to destination buffer * * Will copy one space-terminated or null-terminated word from the source * string to the destination buffer. * When done, *plpszSrc will point to the character after the word. * * CUSTOMIZATION: Server Demo specific * */ static VOID GetWord (LPSTR *plpszSrc, LPSTR lpszDst) { INT i = 0; while (**plpszSrc && **plpszSrc != ' ') { lpszDst[i++] = *(*plpszSrc)++; } lpszDst[i] = '\0'; } /* HiMetricToDevice * ---------------- * * Converts a point from HiMetric units to device units. * This function is designed to be generic enough to be reused. * * HWND hwnd - The window whose display context is to be used * LPPOINT lppt - The point to be converted. * * CUSTOMIZATION: None * */ void HiMetricToDevice ( LPPOINT lppt ) { lppt->x = MulDiv (giXppli, lppt->x, HIMETRIC_PER_INCH); lppt->y = MulDiv (giYppli, lppt->y, HIMETRIC_PER_INCH); } /* HwndToLpobj * ----------- * * Given an object's window, return a pointer to the object. * The GetWindowLong call extracts an LPOBJ from the extra data stored with * the window. * * HWND hwndObj - Handle to the object's window * * RETURNS: A pointer to the object * * CUSTOMIZATION: Server Demo specific * */ LPOBJ HwndToLpobj (HWND hwndObj) { return (LPOBJ) GetWindowLong (hwndObj, ibLpobj); } /* CreateUntitledDoc * ----------------- * * Create a fresh document with one object. * * RETURNS: TRUE if successful * FALSE otherwise * * CUSTOMIZATION: Re-implement * */ static BOOL CreateUntitledDoc (INT nCmdShow) { if (!CreateNewDoc (0, "(Untitled)", doctypeNew)) return FALSE; CreateNewObj (FALSE); ShowWindow(hwndMain, nCmdShow); UpdateWindow(hwndMain); return TRUE; } /* ProcessCmdLine * -------------- * * Parses the Windows command line which was passed to WinMain. * * Case One: SrvrDemo.exe * fEmbedding = FALSE * Create an untitled document. * * Case two: SrvrDemo.exe filename * fEmbedding = FALSE * Create a new document from the file. * * Case three: SrvrDemo.exe -Embedding * fEmbedding = TRUE * Do not create or register a document. * Do not show window until client requests it. * * Case four: SrvrDemo.exe -Embedding filename * fEmbedding = TRUE * Load file. * Call OleRegisterServerDoc. * Do not show window until client requests it. * * * LPSTR lpszLine - The Windows command line * int nCmdShow - Parameter to WinMain * HWND hwndMain - The application's main window * * RETURNS: TRUE if the command line was processed correctly. * FALSE if a filename was specified which did not * contain a proper document. * * CUSTOMIZATION: None. * */ static BOOL ProcessCmdLine (LPSTR lpszLine, HWND hwndMain) { CHAR szBuf[cchFilenameMax]; BOOL fEmbedding = FALSE; // Is "-Embedding" on the command line? INT i=0; OFSTRUCT of; if (!*lpszLine) // No filename or options, so start a fresh document. { return CreateUntitledDoc(SW_SHOWNORMAL); } SkipBlanks (&lpszLine); // Check for "-Embedding" or "/Embedding" and set fEmbedding. if(*lpszLine == '-' || *lpszLine == '/') { lpszLine++; GetWord (&lpszLine, szBuf); fEmbedding = !lstrcmp(szBuf, szEmbeddingFlag); } SkipBlanks (&lpszLine); if (*lpszLine) // if there is a filename { // Put filename into szBuf. GetWord (&lpszLine, szBuf); if (-1 == OpenFile(szBuf, &of, OF_READ | OF_EXIST)) { // File not found if (fEmbedding) return FALSE; else { CHAR sz[100]; wsprintf (sz, "File %s not found.", (LPSTR) szBuf); ErrorBox (sz); return CreateUntitledDoc(SW_SHOWNORMAL); } } if (!CreateDocFromFile (szBuf, 0, doctypeFromFile)) { // File not in proper format. if (fEmbedding) return FALSE; else { CHAR sz[100]; wsprintf (sz, "File %s not in proper format.", (LPSTR) szBuf); ErrorBox (sz); return CreateUntitledDoc(SW_SHOWNORMAL); } } } if (fEmbedding) { /* Do not show window until told to do so by client. */ ShowWindow(hwndMain, SW_HIDE); } else { ShowWindow(hwndMain, SW_SHOWNORMAL); UpdateWindow(hwndMain); } return TRUE; } /* SaveDimensions * -------------- * * Save the dimensions of the main window in a private profile file. * * CUSTOMIZATION: This function may be removed. If you wish to support * intelligent window placement, then the only necessary * change is to change the string "SrvrDemo.Ini" to a filename * appropriate for your application. */ static VOID SaveDimensions (VOID) { if ((dimsCurrent.nX != dimsSaved.nX) || (dimsCurrent.nY != dimsSaved.nY) || (dimsCurrent.nWidth != dimsSaved.nWidth) || (dimsCurrent.nHeight != dimsSaved.nHeight) ) { // Save current window dimensions to private profile. CHAR szBuf[7]; wsprintf (szBuf, "%d", dimsCurrent.nX); WritePrivateProfileString (szAppName, "x", szBuf, "SrvrDemo.Ini"); wsprintf (szBuf, "%d", dimsCurrent.nY); WritePrivateProfileString (szAppName, "y", szBuf, "SrvrDemo.Ini"); wsprintf (szBuf, "%d", dimsCurrent.nWidth); WritePrivateProfileString (szAppName, "w", szBuf, "SrvrDemo.Ini"); wsprintf (szBuf, "%d", dimsCurrent.nHeight); WritePrivateProfileString (szAppName, "h", szBuf, "SrvrDemo.Ini"); } } /* SelectedObject * -------------- * * Return a pointer to the currently selected object. * * CUSTOMIZATION: What a "selected object" is will vary from application * to application. You may find it useful to have a function * like this. In your application it may be necessary to * actually create an OBJ structure based on what data the * user has selected from the document (by highlighting some * text for example). * */ LPOBJ SelectedObject (VOID) { return HwndToLpobj (SelectedObjectWindow()); } /* SelectedObjectWindow * -------------------- * * Return a handle to the window for the currently selected object. * The GetWindow calls returns a handle to the main window's first child, * which is the selected object's window. * * CUSTOMIZATION: Server Demo specific * */ HWND SelectedObjectWindow (VOID) { return GetWindow (hwndMain, GW_CHILD); } /* SetHiMetricFields * ----------------- * * Adjust the nHiMetricWidth and nHiMetricHeight fields of a NATIVE structure * so that they are equivalent to the nWidth and nHeight fields. * The negative sign in the last line is necessary because the positive * y direction is toward the top of the screen in MM_HIMETRIC mode. * * LPOBJ lpobj - Pointer to the object whose native data will be adjusted * * CUSTOMIZATION: Server Demo specific, although you may need a function like * this if you keep track of the size of an object, and an * object handler needs to know the object's size in * HiMetric units. * * */ VOID SetHiMetricFields (LPOBJ lpobj) { POINT pt; pt.x = lpobj->native.nWidth; pt.y = lpobj->native.nHeight; DeviceToHiMetric ( &pt); lpobj->native.nHiMetricWidth = pt.x; lpobj->native.nHiMetricHeight = pt.y; } /* SkipBlanks * ---------- * * LPSTR *plpsz - Pointer to a pointer to a character * * Increment *plpsz past any blanks in the character string. * This function is used in ProcessCmdLine. * */ static VOID SkipBlanks (LPSTR *plpsz) { while (**plpsz && **plpsz == ' ') (*plpsz)++; } /* UpdateObjMenus * --------------- * * Grey or Ungrey menu items depending on the existence of at least one * object in the document. * * CUSTOMIZATION: Server Demo specific * */ static VOID UpdateObjMenus (VOID) { static BOOL fObjMenusEnabled = TRUE; BOOL fOneObjExists; // Does at least one object exist? WORD wEnable; HMENU hMenu; fOneObjExists = (SelectedObjectWindow() != NULL); if (fOneObjExists == fObjMenusEnabled) { // Nothing has changed. return; } wEnable = (WORD)(fOneObjExists ? MF_ENABLED : MF_GRAYED); hMenu = GetMenu(hwndMain); EnableMenuItem(hMenu, menuposColor, MF_BYPOSITION | wEnable); hMenu = GetSubMenu(GetMenu(hwndMain), menuposFile); EnableMenuItem(hMenu, IDM_SAVE, MF_BYCOMMAND | wEnable); EnableMenuItem(hMenu, IDM_SAVEAS, MF_BYCOMMAND | wEnable); hMenu = GetSubMenu(GetMenu(hwndMain), menuposEdit); EnableMenuItem(hMenu, IDM_CUT, MF_BYCOMMAND | wEnable); EnableMenuItem(hMenu, IDM_COPY, MF_BYCOMMAND | wEnable); EnableMenuItem(hMenu, IDM_DELETE, MF_BYCOMMAND | wEnable); hMenu = GetSubMenu(GetMenu(hwndMain), menuposObject); EnableMenuItem(hMenu, IDM_NEXTOBJ, MF_BYCOMMAND | wEnable); DrawMenuBar (hwndMain); fObjMenusEnabled = fOneObjExists; } /* Wait * ---- * * Dispatch messages until the given flag is set to FALSE. * One use of this function is to wait until a Release method is called * after a function has returned OLE_WAIT_FOR_RELEASE. * * BOOL *pf - Pointer to the flag being waited on. * * CUSTOMIZATION: The use of OleUnblockServer is for illustration only. * Since Server Demo does not call OleBlockServer, there * will never be any messages in the OLE queue. * */ VOID Wait (BOOL *pf) { MSG msg; BOOL fMoreMsgs = FALSE; *pf = TRUE; while (*pf==TRUE) { OleUnblockServer (srvrMain.lhsrvr, &fMoreMsgs); if (!fMoreMsgs) // if there are no more messages in the OLE queue, go to system queue { if (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg); DispatchMessage (&msg); } } } } static BOOL FailedUpdate(HWND hwnd) { return(DialogBox(hInst, "FailedUpdate", hwnd, fnFailedUpdate)); } INT_PTR CALLBACK fnFailedUpdate (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_COMMAND: { WORD wID = LOWORD(wParam); switch (wID) { case IDCANCEL: case IDD_CONTINUEEDIT: EndDialog(hDlg, TRUE); break; case IDD_UPDATEEXIT: EndDialog(hDlg, FALSE); break; default: break; } break; } case WM_INITDIALOG: { CHAR szMsg[200]; szMsg[0] = '\0'; wsprintf( szMsg, "This %s document can only be updated when you exit %s.", (LPSTR) szClient, (LPSTR) szAppName ); SetDlgItemText(hDlg, IDD_TEXT, szMsg); return TRUE; } default: break; } return FALSE; }