Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1335 lines
33 KiB

  1. /*
  2. OLE SERVER DEMO
  3. SrvrDemo.c
  4. This file contains the window handlers, and various initialization and
  5. utility functions.
  6. (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
  7. */
  8. #define SERVERONLY
  9. #include <windows.h>
  10. #include <ole.h>
  11. #include "srvrdemo.h"
  12. /* Global variable definitions */
  13. HWND hwndMain = 0;
  14. // Used in converting units from pixels to Himetric and vice-versa
  15. int giXppli = 0; // pixels per logical inch along width
  16. int giYppli = 0; // pixels per logical inch along height
  17. // Since this is a not an MDI app, there can be only one server and one doc.
  18. SRVR srvrMain;
  19. DOC docMain;
  20. CHAR szClient[cchFilenameMax];
  21. CHAR szClientDoc[cchFilenameMax];
  22. // Has the user made changes to the document?
  23. BOOL fDocChanged = FALSE;
  24. // Is this the first instance of this application currently running?
  25. BOOL fFirstInstance = TRUE;
  26. // This flag is used when OleRevokeServerDoc returns OLE_WAIT_FOR_RELEASE,
  27. // and we must wait until DocRelease is called.
  28. BOOL fWaitingForDocRelease = FALSE;
  29. // This flag is used when OleRevokeServer returns OLE_WAIT_FOR_RELEASE,
  30. // and we must wait until SrvrRelease is called.
  31. BOOL fWaitingForSrvrRelease = FALSE;
  32. // This flag is set to TRUE after an application has called OleBlockServer
  33. // and now wishes to unblock the queued messages. See WinMain.
  34. // Server Demo never sets fUnblock to TRUE because it never calls
  35. // OleBlockServer.
  36. BOOL fUnblock = FALSE;
  37. // Set this to FALSE if you want to guarantee that the server will not revoke
  38. // itself when SrvrRelease is called. This is used in the IDM_NEW case and
  39. // the IDM_OPEN case (in OpenDoc).
  40. BOOL fRevokeSrvrOnSrvrRelease = TRUE;
  41. // Version number, which is stored in the native data.
  42. VERSION version = 1;
  43. HBRUSH hbrColor[chbrMax];
  44. // Clipboard formats
  45. OLECLIPFORMAT cfObjectLink;
  46. OLECLIPFORMAT cfOwnerLink;
  47. OLECLIPFORMAT cfNative;
  48. // Method tables.
  49. OLESERVERDOCVTBL docvtbl;
  50. OLEOBJECTVTBL objvtbl;
  51. OLESERVERVTBL srvrvtbl;
  52. HANDLE hInst;
  53. HANDLE hAccelTable;
  54. HMENU hMainMenu = NULL;
  55. // Window dimensions saved in private profile.
  56. static struct
  57. {
  58. INT nX;
  59. INT nY;
  60. INT nWidth;
  61. INT nHeight;
  62. } dimsSaved, dimsCurrent;
  63. static enum
  64. {
  65. // Corresponds to the order of the menus in the .rc file.
  66. menuposFile,
  67. menuposEdit,
  68. menuposColor,
  69. menuposObject
  70. };
  71. // Static functions.
  72. static VOID DeleteInstance (VOID);
  73. static BOOL ExitApplication (BOOL);
  74. static VOID GetWord (LPSTR *plpszSrc, LPSTR lpszDst);
  75. static BOOL InitApplication( HANDLE hInstance);
  76. static BOOL InitInstance (HANDLE hInstance);
  77. static BOOL ProcessCmdLine (LPSTR,HWND);
  78. static VOID SaveDimensions (VOID);
  79. static VOID SkipBlanks (LPSTR *plpsz);
  80. static VOID UpdateObjMenus (VOID);
  81. static BOOL FailedUpdate(HWND);
  82. /* WinMain
  83. * -------
  84. *
  85. * Standard windows entry point
  86. *
  87. * CUSTOMIZATION: None
  88. *
  89. */
  90. int APIENTRY WinMain(
  91. HINSTANCE hInstance,
  92. HINSTANCE hPrevInstance,
  93. LPSTR lpCmdLine,
  94. INT nCmdShow
  95. ){
  96. MSG msg;
  97. if (!InitApplication(hInstance))
  98. return FALSE;
  99. msg.wParam = FALSE;
  100. if (!InitInstance(hInstance))
  101. goto errRtn;
  102. if (!InitServer (hwndMain, hInstance))
  103. goto errRtn;
  104. if (!ProcessCmdLine(lpCmdLine,hwndMain))
  105. {
  106. ExitApplication(FALSE);
  107. goto errRtn;
  108. }
  109. for (;;)
  110. {
  111. // Your application should set fUnblock to TRUE when it decides
  112. // to unblock.
  113. if (fUnblock)
  114. {
  115. BOOL fMoreMsgs = TRUE;
  116. while (fMoreMsgs)
  117. {
  118. if (srvrMain.lhsrvr == 0)
  119. OleUnblockServer (srvrMain.lhsrvr, &fMoreMsgs);
  120. }
  121. // We have taken care of all the messages in the OLE queue
  122. fUnblock = FALSE;
  123. }
  124. if (!GetMessage(&msg, NULL, 0, 0))
  125. break;
  126. if( !TranslateAccelerator(hwndMain, hAccelTable, &msg))
  127. {
  128. TranslateMessage(&msg);
  129. DispatchMessage(&msg);
  130. }
  131. }
  132. errRtn:
  133. DeleteInstance ();
  134. return (msg.wParam);
  135. }
  136. /* InitApplication
  137. * ---------------
  138. *
  139. * Initialize the application - register the window classes
  140. *
  141. * HANDLE hInstance
  142. *
  143. * RETURNS: TRUE if classes are properly registered.
  144. * FALSE otherwise
  145. *
  146. * CUSTOMIZATION: Re-implement
  147. *
  148. */
  149. static BOOL InitApplication( HANDLE hInstance )
  150. {
  151. WNDCLASS wc;
  152. wc.lpszClassName = "MainClass";
  153. wc.lpfnWndProc = (WNDPROC)MainWndProc;
  154. wc.style = 0;
  155. wc.cbClsExtra = 4;
  156. wc.cbWndExtra = 0;
  157. wc.hInstance = hInstance;
  158. wc.hIcon = LoadIcon(hInstance, "DocIcon");
  159. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  160. wc.hbrBackground = GetStockObject(WHITE_BRUSH);
  161. wc.lpszMenuName = "MainMenu";
  162. if (!RegisterClass(&wc))
  163. return FALSE;
  164. wc.lpszClassName = "ObjClass";
  165. wc.lpfnWndProc = (WNDPROC)ObjWndProc;
  166. wc.hIcon = NULL;
  167. wc.cbWndExtra = cbWindExtra;
  168. wc.lpszMenuName = NULL;
  169. wc.hCursor = LoadCursor(NULL, IDC_CROSS);
  170. if (!RegisterClass(&wc))
  171. return FALSE;
  172. return TRUE;
  173. }
  174. /* InitInstance
  175. * ------------
  176. *
  177. * Create brushes used by the program, the main window, and
  178. * do any other per-instance initialization.
  179. *
  180. * HANDLE hInstance
  181. *
  182. * RETURNS: TRUE if successful
  183. * FALSE otherwise.
  184. *
  185. * CUSTOMIZATION: Re-implement
  186. *
  187. */
  188. static BOOL InitInstance (HANDLE hInstance)
  189. {
  190. LONG rglColor [chbrMax] =
  191. {
  192. 0x000000ff, // Red
  193. 0x0000ff00, // Green
  194. 0x00ff0000, // Blue
  195. 0x00ffffff, // White
  196. 0x00808080, // Gray
  197. 0x00ffff00, // Cyan
  198. 0x00ff00ff, // Magenta
  199. 0x0000ffff // Yellow
  200. };
  201. INT iColor;
  202. HDC hDC ;
  203. hInst = hInstance;
  204. // Initialize the method tables.
  205. InitVTbls ();
  206. // Initialize the brushes used.
  207. for (iColor = 0; iColor < chbrMax; iColor++)
  208. hbrColor[iColor] = CreateSolidBrush (rglColor[iColor]);
  209. // Register clipboard formats.
  210. cfObjectLink= (OLECLIPFORMAT)RegisterClipboardFormat ("ObjectLink");
  211. cfOwnerLink = (OLECLIPFORMAT)RegisterClipboardFormat ("OwnerLink");
  212. cfNative = (OLECLIPFORMAT)RegisterClipboardFormat ("Native");
  213. hAccelTable = LoadAccelerators(hInst, "Accelerators");
  214. // hMainMenu = LoadMenu(hInst, "MainMenu");
  215. hwndMain = CreateWindow(
  216. "MainClass",
  217. szAppName,
  218. WS_OVERLAPPEDWINDOW,
  219. CW_USEDEFAULT, CW_USEDEFAULT,
  220. 3*OBJECT_WIDTH, 3*OBJECT_HEIGHT,
  221. NULL,
  222. NULL,
  223. hInstance,
  224. NULL
  225. );
  226. if (!hwndMain)
  227. return FALSE;
  228. szClient[0] = '\0';
  229. lstrcpy (szClientDoc, "Client Document");
  230. // Initialize global variables with LOGPIXELSX and LOGPIXELSY
  231. hDC = GetDC (NULL); // Get the hDC of the desktop window
  232. giXppli = GetDeviceCaps (hDC, LOGPIXELSX);
  233. giYppli = GetDeviceCaps (hDC, LOGPIXELSY);
  234. ReleaseDC (NULL, hDC);
  235. return TRUE;
  236. }
  237. /* DeleteInstance
  238. * --------------
  239. *
  240. * Deallocate the VTables, and the brushes created for this instance
  241. *
  242. *
  243. * CUSTOMIZATION: The call to FreeVTbls must remain.
  244. *
  245. */
  246. static VOID DeleteInstance (VOID)
  247. {
  248. INT i;
  249. for (i = 0; i < chbrMax; i++)
  250. DeleteObject (hbrColor[i]);
  251. }
  252. /* ExitApplication
  253. * ---------------
  254. *
  255. * Handles the WM_CLOSE and WM_COMMAND/IDM_EXIT messages.
  256. *
  257. * RETURNS: TRUE if application should really terminate
  258. * FALSE if not
  259. *
  260. *
  261. * CUSTOMIZATION: None
  262. *
  263. */
  264. static BOOL ExitApplication (BOOL fUpdateLater)
  265. {
  266. if (fUpdateLater)
  267. {
  268. // The non-standard OLE client did not accept the update
  269. // when we requested it, so we are sending the client
  270. // OLE_CLOSED now that we are closing the document.
  271. SendDocMsg (OLE_CLOSED);
  272. }
  273. if (StartRevokingServer() == OLE_WAIT_FOR_RELEASE)
  274. Wait (&fWaitingForSrvrRelease);
  275. /* SrvrRelease will not necessarily post a WM_QUIT message.
  276. If the document is not embedded, SrvrRelease by itself does
  277. not cause the application to terminate. But now we want it to.
  278. */
  279. if (docMain.doctype != doctypeEmbedded)
  280. PostQuitMessage(0);
  281. SaveDimensions();
  282. return TRUE;
  283. }
  284. /* MainWndProc
  285. * -----------
  286. *
  287. * Main window message handler.
  288. *
  289. *
  290. * CUSTOMIZATION: Remove the color menu and the object menu entirely.
  291. * Add handlers for your application's menu items and any
  292. * Windows messages your application needs to handle.
  293. * The handlers for the menu items that involve OLE
  294. * can be added to, but no logic should be removed.
  295. *
  296. *
  297. */
  298. LONG APIENTRY MainWndProc
  299. (HWND hwnd, UINT message, WPARAM wParam, LONG lParam )
  300. {
  301. LPOBJ lpobj;
  302. switch (message)
  303. {
  304. case WM_COMMAND:
  305. {
  306. WORD wID = LOWORD(wParam);
  307. if (fWaitingForDocRelease)
  308. {
  309. ErrorBox ("Waiting for a document to be revoked.\n\rPlease wait.");
  310. return 0;
  311. }
  312. switch (wID)
  313. {
  314. case IDM_EXIT:
  315. SendMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
  316. break;
  317. case IDM_ABOUT:
  318. DialogBox(hInst, "AboutBox", hwnd, (DLGPROC)About);
  319. break;
  320. case IDM_NEW:
  321. {
  322. BOOL fUpdateLater;
  323. OLESTATUS olestatus;
  324. if (SaveChangesOption (&fUpdateLater) == IDCANCEL)
  325. break;
  326. else if (fUpdateLater)
  327. SendDocMsg (OLE_CLOSED);
  328. // We want to revoke the doc but not the server, so if
  329. // SrvrRelease is called, do not revoke server.
  330. fRevokeSrvrOnSrvrRelease = FALSE;
  331. if ((olestatus = RevokeDoc()) > OLE_WAIT_FOR_RELEASE)
  332. {
  333. ErrorBox ("Serious Error: Cannot revoke document.");
  334. break;
  335. }
  336. else if (olestatus == OLE_WAIT_FOR_RELEASE)
  337. Wait (&fWaitingForDocRelease);
  338. fRevokeSrvrOnSrvrRelease = TRUE;
  339. if (!CreateNewDoc (0, "(Untitled)", doctypeNew))
  340. {
  341. ErrorBox ("Serious Error: Cannot create new document.");
  342. break;
  343. }
  344. // Your application need not create a default object.
  345. CreateNewObj (FALSE);
  346. EmbeddingModeOff();
  347. break;
  348. }
  349. case IDM_OPEN:
  350. OpenDoc();
  351. UpdateObjMenus();
  352. break;
  353. case IDM_SAVE:
  354. SaveDoc();
  355. break;
  356. case IDM_SAVEAS:
  357. if (!SaveDocAs ())
  358. break;
  359. if (docMain.doctype != doctypeEmbedded)
  360. EmbeddingModeOff();
  361. break;
  362. case IDM_UPDATE:
  363. switch (OleSavedServerDoc (docMain.lhdoc))
  364. {
  365. case OLE_ERROR_CANT_UPDATE_CLIENT:
  366. if (!FailedUpdate(hwnd))
  367. ExitApplication(TRUE);
  368. break;
  369. case OLE_OK:
  370. break;
  371. default:
  372. ErrorBox ("Serious Error: Cannot update.");
  373. }
  374. break;
  375. /* Color menu */
  376. case IDM_RED:
  377. case IDM_GREEN:
  378. case IDM_BLUE:
  379. case IDM_WHITE:
  380. case IDM_GRAY:
  381. case IDM_CYAN:
  382. case IDM_MAGENTA:
  383. case IDM_YELLOW:
  384. lpobj = SelectedObject();
  385. lpobj->native.idmColor = wID;
  386. // Recolor the object on the screen.
  387. InvalidateRect (lpobj->hwnd, (LPRECT)NULL, TRUE);
  388. UpdateWindow (lpobj->hwnd);
  389. fDocChanged = TRUE;
  390. if (docMain.doctype == doctypeFromFile)
  391. // If object is linked, update it in client now.
  392. SendObjMsg (lpobj, OLE_CHANGED);
  393. break;
  394. /* Edit menu */
  395. case IDM_COPY:
  396. CutOrCopyObj (TRUE);
  397. break;
  398. case IDM_CUT:
  399. CutOrCopyObj (FALSE);
  400. // Fall through.
  401. case IDM_DELETE:
  402. RevokeObj (SelectedObject());
  403. DestroyWindow (SelectedObjectWindow());
  404. UpdateObjMenus();
  405. break;
  406. /* Object menu */
  407. case IDM_NEXTOBJ:
  408. lpobj = SelectedObject();
  409. /* The 1 in the second parameter puts the current window
  410. at the bottom of the current window list. */
  411. SetWindowPos(lpobj->hwnd, (HANDLE)1, 0,0,0,0,
  412. SWP_NOMOVE | SWP_NOSIZE);
  413. break;
  414. case IDM_NEWOBJ:
  415. lpobj = CreateNewObj (TRUE);
  416. BringWindowToTop(lpobj->hwnd);
  417. break;
  418. default:
  419. ErrorBox ("Unknown Command.");
  420. break;
  421. }
  422. break;
  423. }
  424. case WM_NCCALCSIZE:
  425. if (!IsIconic(hwnd) && !IsZoomed(hwnd))
  426. {
  427. dimsCurrent.nX = ((LPRECT)lParam)->left;
  428. dimsCurrent.nWidth = ((LPRECT)lParam)->right - dimsCurrent.nX;
  429. dimsCurrent.nY = ((LPRECT)lParam)->top;
  430. dimsCurrent.nHeight = ((LPRECT)lParam)->bottom - dimsCurrent.nY;
  431. }
  432. return DefWindowProc(hwnd, message, wParam, lParam);
  433. break;
  434. case WM_QUERYENDSESSION:
  435. {
  436. BOOL fUpdateLater;
  437. if (SaveChangesOption(&fUpdateLater) == IDCANCEL)
  438. return FALSE;
  439. if (fUpdateLater)
  440. {
  441. // The non-standard OLE client did not accept the update
  442. // when we requested it, so we are sending the client
  443. // OLE_CLOSED now that we are closing the document.
  444. SendDocMsg (OLE_CLOSED);
  445. }
  446. return TRUE;
  447. }
  448. case WM_CLOSE:
  449. {
  450. BOOL fUpdateLater;
  451. if (SaveChangesOption(&fUpdateLater) != IDCANCEL)
  452. ExitApplication(fUpdateLater);
  453. break;
  454. }
  455. default:
  456. return DefWindowProc(hwnd, message, wParam, lParam);
  457. }
  458. return 0;
  459. }
  460. /* About
  461. * -----
  462. *
  463. * "About Box" dialog handler.
  464. *
  465. * CUSTOMIZATION: None
  466. *
  467. */
  468. BOOL APIENTRY About (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  469. {
  470. switch (message)
  471. {
  472. case WM_INITDIALOG:
  473. return TRUE;
  474. case WM_COMMAND:
  475. {
  476. WORD wID = LOWORD(wParam);
  477. if (wID == IDOK || wID == IDCANCEL)
  478. {
  479. EndDialog(hDlg, TRUE);
  480. return TRUE;
  481. }
  482. break;
  483. }
  484. }
  485. return FALSE;
  486. }
  487. /* ObjWndProc
  488. * ----------
  489. *
  490. * Message handler for the object windows.
  491. *
  492. *
  493. * CUSTOMIZATION: Server Demo specific
  494. *
  495. */
  496. LONG APIENTRY ObjWndProc
  497. (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  498. {
  499. static BOOL fCapture = FALSE;
  500. static struct {RECT rect; POINT pt;} drag;
  501. static RECT rectMain;
  502. switch (message)
  503. {
  504. case WM_CREATE:
  505. {
  506. LPOBJ lpobj;
  507. LPCREATESTRUCT lpcs;
  508. // The call to CreateWindow puts lpobj into lpCreateParams
  509. lpcs = (LPCREATESTRUCT) lParam;
  510. lpobj = (LPOBJ) lpcs->lpCreateParams;
  511. // Associate the window just created with the object.
  512. lpobj->hwnd = hwnd;
  513. /* Store pointer to object in the window structure. */
  514. SetWindowLong(hwnd, ibLpobj, (LONG) lpobj);
  515. UpdateObjMenus ();
  516. break;
  517. }
  518. case WM_SIZE:
  519. {
  520. RECT rect;
  521. if (fWaitingForDocRelease)
  522. {
  523. ErrorBox ("Waiting for a document to be revoked.\n\rPlease wait.");
  524. return 0;
  525. }
  526. // Get coordinates of object relative to main window's client area.
  527. GetWindowRect (hwnd, (LPRECT)&rect);
  528. ScreenToClient (hwndMain, (LPPOINT)&rect);
  529. ScreenToClient (hwndMain, (LPPOINT)&rect.right);
  530. SizeObj (hwnd, rect, TRUE);
  531. // Fall through.
  532. }
  533. case WM_PAINT:
  534. PaintObj (hwnd);
  535. break;
  536. case WM_LBUTTONDOWN:
  537. if (fWaitingForDocRelease)
  538. {
  539. ErrorBox ("Waiting for a document to be revoked.\n\rPlease wait.");
  540. return 0;
  541. }
  542. BringWindowToTop (hwnd);
  543. GetWindowRect (hwnd, (LPRECT) &drag.rect);
  544. ScreenToClient (hwndMain, (LPPOINT)&drag.rect.left);
  545. ScreenToClient (hwndMain, (LPPOINT)&drag.rect.right);
  546. drag.pt.x = LOWORD(lParam);
  547. drag.pt.y = HIWORD(lParam);
  548. // Convert drag.pt to the main window's client coordinates.
  549. ClientToScreen (hwnd, (LPPOINT)&drag.pt);
  550. ScreenToClient (hwndMain, (LPPOINT)&drag.pt);
  551. // Remember the coordinates of the main window so we do not drag
  552. // an object outside the main window.
  553. GetClientRect (hwndMain, (LPRECT) &rectMain);
  554. SetCapture (hwnd);
  555. fCapture = TRUE;
  556. break;
  557. case WM_MOUSEMOVE:
  558. {
  559. HDC hdc;
  560. POINT pt;
  561. if (!fCapture)
  562. break;
  563. fDocChanged = TRUE;
  564. pt.x = LOWORD(lParam);
  565. pt.y = HIWORD(lParam);
  566. // Convert pt to the main window's client coordinates.
  567. ClientToScreen (hwnd, (LPPOINT)&pt);
  568. ScreenToClient (hwndMain, (LPPOINT)&pt);
  569. if (!PtInRect (&rectMain, pt))
  570. break;
  571. hdc = GetDC(hwndMain);
  572. // Erase old drag rectangle
  573. InvertRect (hdc, (LPRECT)&drag.rect);
  574. // Update drag.rect
  575. OffsetRect (&drag.rect, pt.x - drag.pt.x, pt.y - drag.pt.y);
  576. // Update drag.pt
  577. drag.pt.x = pt.x;
  578. drag.pt.y = pt.y;
  579. // Show new drag rectangle
  580. InvertRect (hdc, (LPRECT)&drag.rect);
  581. ReleaseDC (hwndMain, hdc);
  582. break;
  583. }
  584. case WM_LBUTTONUP:
  585. {
  586. LPOBJ lpobj;
  587. if (!fCapture)
  588. return TRUE;
  589. fCapture = FALSE;
  590. ReleaseCapture ();
  591. MoveWindow (hwnd, drag.rect.left, drag.rect.top,
  592. drag.rect.right - drag.rect.left,
  593. drag.rect.bottom - drag.rect.top, TRUE);
  594. InvalidateRect (hwnd, (LPRECT)NULL, TRUE);
  595. lpobj = HwndToLpobj (hwnd);
  596. lpobj->native.nX = drag.rect.left;
  597. lpobj->native.nY = drag.rect.top;
  598. break;
  599. }
  600. case WM_DESTROY:
  601. DestroyObj (hwnd);
  602. return DefWindowProc(hwnd, message, wParam, lParam);
  603. default:
  604. return DefWindowProc(hwnd, message, wParam, lParam);
  605. }
  606. return 0;
  607. }
  608. /* DeviceToHiMetric
  609. * ----------------
  610. *
  611. * Converts a point from device units to HiMetric units.
  612. * This function is designed to be generic enough to be reused.
  613. *
  614. * HWND hwnd - The window whose display context is to be used
  615. * LPPOINT lppt - The point to be converted.
  616. *
  617. * CUSTOMIZATION: None
  618. *
  619. */
  620. void DeviceToHiMetric ( LPPOINT lppt)
  621. {
  622. lppt->x = MulDiv (lppt->x, HIMETRIC_PER_INCH, giXppli);
  623. lppt->y = MulDiv (lppt->y, HIMETRIC_PER_INCH, giYppli);
  624. }
  625. /* UpdateFileMenu
  626. * --------------
  627. *
  628. * Updates the "Update <Client doc>" and "Exit & Return to <Client doc>"
  629. * with the currently set client document name
  630. *
  631. * CUSTOMIZATION: Re-implement
  632. *
  633. */
  634. VOID UpdateFileMenu (INT iSaveUpdateId)
  635. {
  636. CHAR str[cchFilenameMax];
  637. HMENU hMenu = GetMenu(hwndMain);
  638. /* Change File menu so it contains "Update" instead of "Save". */
  639. lstrcpy (str, "&Update ");
  640. lstrcat (str, szClientDoc);
  641. ModifyMenu(hMenu, iSaveUpdateId, MF_BYCOMMAND|MF_STRING, IDM_UPDATE, str);
  642. /* Change File menu so it contains "Exit & Return to <client doc>" */
  643. /* instead of just "Exit" */
  644. lstrcpy (str, "E&xit && Return to ");
  645. lstrcat (str, szClientDoc);
  646. ModifyMenu(hMenu, IDM_EXIT, MF_BYCOMMAND|MF_STRING, IDM_EXIT, str);
  647. }
  648. /* EmbeddingModeOn
  649. * ---------------
  650. *
  651. * Do whatever is necessary for the application to start "embedding mode."
  652. *
  653. * CUSTOMIZATION: Re-implement
  654. *
  655. */
  656. VOID EmbeddingModeOn(VOID)
  657. {
  658. HMENU hMenu = GetMenu(hwndMain);
  659. UpdateFileMenu (IDM_SAVE);
  660. /* Change File menu so it contains "Save Copy As..." instead of */
  661. /* "Save As..." */
  662. ModifyMenu(hMenu, IDM_SAVEAS, MF_BYCOMMAND|MF_STRING, IDM_SAVEAS,
  663. "Save Copy As..");
  664. /* In embedded mode, the user can edit only the embedded object, not
  665. create new ones. */
  666. EnableMenuItem(hMenu, menuposObject, MF_BYPOSITION | MF_GRAYED);
  667. EnableMenuItem(hMenu, IDM_CUT, MF_BYCOMMAND | MF_GRAYED);
  668. EnableMenuItem(hMenu, IDM_DELETE, MF_BYCOMMAND | MF_GRAYED);
  669. DrawMenuBar (hwndMain);
  670. }
  671. /* EmbeddingModeOff
  672. * ----------------
  673. *
  674. * Do whatever is necessary for the application to end "embedding mode."
  675. *
  676. * CUSTOMIZATION: Re-implement
  677. *
  678. */
  679. VOID EmbeddingModeOff (VOID)
  680. {
  681. HMENU hMenu = GetMenu(hwndMain);
  682. /* Change File menu so it contains "Save" instead of "Update". */
  683. ModifyMenu(hMenu, IDM_UPDATE, MF_BYCOMMAND | MF_STRING, IDM_SAVE, "&Save");
  684. /* Change File menu so it contains "Exit & Return to <client doc>" */
  685. /* instead of just "Exit" */
  686. ModifyMenu(hMenu, IDM_EXIT, MF_BYCOMMAND | MF_STRING, IDM_EXIT, "E&xit");
  687. /* Change File menu so it contains "Save As..." instead of */
  688. /* "Save Copy As..." */
  689. ModifyMenu(hMenu, IDM_SAVEAS, MF_BYCOMMAND|MF_STRING, IDM_SAVEAS,
  690. "Save &As..");
  691. /* In non-embedded mode, the user can create new objects. */
  692. EnableMenuItem(hMenu, menuposObject, MF_BYPOSITION | MF_ENABLED);
  693. lstrcpy (szClientDoc, "Client Document");
  694. DrawMenuBar (hwndMain);
  695. }
  696. /* ErrorBox
  697. * --------
  698. *
  699. * char *szMessage - String to display inside message box.
  700. *
  701. * CUSTOMIZATION: Server Demo specific
  702. *
  703. */
  704. VOID ErrorBox (CHAR *szMessage)
  705. {
  706. MessageBox (hwndMain, szMessage, szAppName, MB_OK);
  707. }
  708. /* GetWord
  709. * -------
  710. *
  711. * LPSTR *plpszSrc - Pointer to a pointer to a source string
  712. * LPSTR lpszDst - Pointer to destination buffer
  713. *
  714. * Will copy one space-terminated or null-terminated word from the source
  715. * string to the destination buffer.
  716. * When done, *plpszSrc will point to the character after the word.
  717. *
  718. * CUSTOMIZATION: Server Demo specific
  719. *
  720. */
  721. static VOID GetWord (LPSTR *plpszSrc, LPSTR lpszDst)
  722. {
  723. INT i = 0;
  724. while (**plpszSrc && **plpszSrc != ' ')
  725. {
  726. lpszDst[i++] = *(*plpszSrc)++;
  727. }
  728. lpszDst[i] = '\0';
  729. }
  730. /* HiMetricToDevice
  731. * ----------------
  732. *
  733. * Converts a point from HiMetric units to device units.
  734. * This function is designed to be generic enough to be reused.
  735. *
  736. * HWND hwnd - The window whose display context is to be used
  737. * LPPOINT lppt - The point to be converted.
  738. *
  739. * CUSTOMIZATION: None
  740. *
  741. */
  742. void HiMetricToDevice ( LPPOINT lppt )
  743. {
  744. lppt->x = MulDiv (giXppli, lppt->x, HIMETRIC_PER_INCH);
  745. lppt->y = MulDiv (giYppli, lppt->y, HIMETRIC_PER_INCH);
  746. }
  747. /* HwndToLpobj
  748. * -----------
  749. *
  750. * Given an object's window, return a pointer to the object.
  751. * The GetWindowLong call extracts an LPOBJ from the extra data stored with
  752. * the window.
  753. *
  754. * HWND hwndObj - Handle to the object's window
  755. *
  756. * RETURNS: A pointer to the object
  757. *
  758. * CUSTOMIZATION: Server Demo specific
  759. *
  760. */
  761. LPOBJ HwndToLpobj (HWND hwndObj)
  762. {
  763. return (LPOBJ) GetWindowLong (hwndObj, ibLpobj);
  764. }
  765. /* CreateUntitledDoc
  766. * -----------------
  767. *
  768. * Create a fresh document with one object.
  769. *
  770. * RETURNS: TRUE if successful
  771. * FALSE otherwise
  772. *
  773. * CUSTOMIZATION: Re-implement
  774. *
  775. */
  776. static BOOL CreateUntitledDoc (INT nCmdShow)
  777. {
  778. if (!CreateNewDoc (0, "(Untitled)", doctypeNew))
  779. return FALSE;
  780. CreateNewObj (FALSE);
  781. ShowWindow(hwndMain, nCmdShow);
  782. UpdateWindow(hwndMain);
  783. return TRUE;
  784. }
  785. /* ProcessCmdLine
  786. * --------------
  787. *
  788. * Parses the Windows command line which was passed to WinMain.
  789. *
  790. * Case One: SrvrDemo.exe
  791. * fEmbedding = FALSE
  792. * Create an untitled document.
  793. *
  794. * Case two: SrvrDemo.exe filename
  795. * fEmbedding = FALSE
  796. * Create a new document from the file.
  797. *
  798. * Case three: SrvrDemo.exe -Embedding
  799. * fEmbedding = TRUE
  800. * Do not create or register a document.
  801. * Do not show window until client requests it.
  802. *
  803. * Case four: SrvrDemo.exe -Embedding filename
  804. * fEmbedding = TRUE
  805. * Load file.
  806. * Call OleRegisterServerDoc.
  807. * Do not show window until client requests it.
  808. *
  809. *
  810. * LPSTR lpszLine - The Windows command line
  811. * int nCmdShow - Parameter to WinMain
  812. * HWND hwndMain - The application's main window
  813. *
  814. * RETURNS: TRUE if the command line was processed correctly.
  815. * FALSE if a filename was specified which did not
  816. * contain a proper document.
  817. *
  818. * CUSTOMIZATION: None.
  819. *
  820. */
  821. static BOOL ProcessCmdLine (LPSTR lpszLine, HWND hwndMain)
  822. {
  823. CHAR szBuf[cchFilenameMax];
  824. BOOL fEmbedding = FALSE; // Is "-Embedding" on the command line?
  825. INT i=0;
  826. OFSTRUCT of;
  827. if (!*lpszLine) // No filename or options, so start a fresh document.
  828. {
  829. return CreateUntitledDoc(SW_SHOWNORMAL);
  830. }
  831. SkipBlanks (&lpszLine);
  832. // Check for "-Embedding" or "/Embedding" and set fEmbedding.
  833. if(*lpszLine == '-' || *lpszLine == '/')
  834. {
  835. lpszLine++;
  836. GetWord (&lpszLine, szBuf);
  837. fEmbedding = !lstrcmp(szBuf, szEmbeddingFlag);
  838. }
  839. SkipBlanks (&lpszLine);
  840. if (*lpszLine) // if there is a filename
  841. {
  842. // Put filename into szBuf.
  843. GetWord (&lpszLine, szBuf);
  844. if (-1 == OpenFile(szBuf, &of, OF_READ | OF_EXIST))
  845. {
  846. // File not found
  847. if (fEmbedding)
  848. return FALSE;
  849. else
  850. {
  851. CHAR sz[100];
  852. wsprintf (sz, "File %s not found.", (LPSTR) szBuf);
  853. ErrorBox (sz);
  854. return CreateUntitledDoc(SW_SHOWNORMAL);
  855. }
  856. }
  857. if (!CreateDocFromFile (szBuf, 0, doctypeFromFile))
  858. {
  859. // File not in proper format.
  860. if (fEmbedding)
  861. return FALSE;
  862. else
  863. {
  864. CHAR sz[100];
  865. wsprintf (sz, "File %s not in proper format.", (LPSTR) szBuf);
  866. ErrorBox (sz);
  867. return CreateUntitledDoc(SW_SHOWNORMAL);
  868. }
  869. }
  870. }
  871. if (fEmbedding)
  872. {
  873. /* Do not show window until told to do so by client. */
  874. ShowWindow(hwndMain, SW_HIDE);
  875. }
  876. else
  877. {
  878. ShowWindow(hwndMain, SW_SHOWNORMAL);
  879. UpdateWindow(hwndMain);
  880. }
  881. return TRUE;
  882. }
  883. /* SaveDimensions
  884. * --------------
  885. *
  886. * Save the dimensions of the main window in a private profile file.
  887. *
  888. * CUSTOMIZATION: This function may be removed. If you wish to support
  889. * intelligent window placement, then the only necessary
  890. * change is to change the string "SrvrDemo.Ini" to a filename
  891. * appropriate for your application.
  892. */
  893. static VOID SaveDimensions (VOID)
  894. {
  895. if ((dimsCurrent.nX != dimsSaved.nX) ||
  896. (dimsCurrent.nY != dimsSaved.nY) ||
  897. (dimsCurrent.nWidth != dimsSaved.nWidth) ||
  898. (dimsCurrent.nHeight != dimsSaved.nHeight) )
  899. {
  900. // Save current window dimensions to private profile.
  901. CHAR szBuf[7];
  902. wsprintf (szBuf, "%d", dimsCurrent.nX);
  903. WritePrivateProfileString
  904. (szAppName, "x", szBuf, "SrvrDemo.Ini");
  905. wsprintf (szBuf, "%d", dimsCurrent.nY);
  906. WritePrivateProfileString
  907. (szAppName, "y", szBuf, "SrvrDemo.Ini");
  908. wsprintf (szBuf, "%d", dimsCurrent.nWidth);
  909. WritePrivateProfileString
  910. (szAppName, "w", szBuf, "SrvrDemo.Ini");
  911. wsprintf (szBuf, "%d", dimsCurrent.nHeight);
  912. WritePrivateProfileString
  913. (szAppName, "h", szBuf, "SrvrDemo.Ini");
  914. }
  915. }
  916. /* SelectedObject
  917. * --------------
  918. *
  919. * Return a pointer to the currently selected object.
  920. *
  921. * CUSTOMIZATION: What a "selected object" is will vary from application
  922. * to application. You may find it useful to have a function
  923. * like this. In your application it may be necessary to
  924. * actually create an OBJ structure based on what data the
  925. * user has selected from the document (by highlighting some
  926. * text for example).
  927. *
  928. */
  929. LPOBJ SelectedObject (VOID)
  930. {
  931. return HwndToLpobj (SelectedObjectWindow());
  932. }
  933. /* SelectedObjectWindow
  934. * --------------------
  935. *
  936. * Return a handle to the window for the currently selected object.
  937. * The GetWindow calls returns a handle to the main window's first child,
  938. * which is the selected object's window.
  939. *
  940. * CUSTOMIZATION: Server Demo specific
  941. *
  942. */
  943. HWND SelectedObjectWindow (VOID)
  944. {
  945. return GetWindow (hwndMain, GW_CHILD);
  946. }
  947. /* SetHiMetricFields
  948. * -----------------
  949. *
  950. * Adjust the nHiMetricWidth and nHiMetricHeight fields of a NATIVE structure
  951. * so that they are equivalent to the nWidth and nHeight fields.
  952. * The negative sign in the last line is necessary because the positive
  953. * y direction is toward the top of the screen in MM_HIMETRIC mode.
  954. *
  955. * LPOBJ lpobj - Pointer to the object whose native data will be adjusted
  956. *
  957. * CUSTOMIZATION: Server Demo specific, although you may need a function like
  958. * this if you keep track of the size of an object, and an
  959. * object handler needs to know the object's size in
  960. * HiMetric units.
  961. *
  962. *
  963. */
  964. VOID SetHiMetricFields (LPOBJ lpobj)
  965. {
  966. POINT pt;
  967. pt.x = lpobj->native.nWidth;
  968. pt.y = lpobj->native.nHeight;
  969. DeviceToHiMetric ( &pt);
  970. lpobj->native.nHiMetricWidth = pt.x;
  971. lpobj->native.nHiMetricHeight = pt.y;
  972. }
  973. /* SkipBlanks
  974. * ----------
  975. *
  976. * LPSTR *plpsz - Pointer to a pointer to a character
  977. *
  978. * Increment *plpsz past any blanks in the character string.
  979. * This function is used in ProcessCmdLine.
  980. *
  981. */
  982. static VOID SkipBlanks (LPSTR *plpsz)
  983. {
  984. while (**plpsz && **plpsz == ' ')
  985. (*plpsz)++;
  986. }
  987. /* UpdateObjMenus
  988. * ---------------
  989. *
  990. * Grey or Ungrey menu items depending on the existence of at least one
  991. * object in the document.
  992. *
  993. * CUSTOMIZATION: Server Demo specific
  994. *
  995. */
  996. static VOID UpdateObjMenus (VOID)
  997. {
  998. static BOOL fObjMenusEnabled = TRUE;
  999. BOOL fOneObjExists; // Does at least one object exist?
  1000. WORD wEnable;
  1001. HMENU hMenu;
  1002. fOneObjExists = (SelectedObjectWindow() != NULL);
  1003. if (fOneObjExists == fObjMenusEnabled)
  1004. {
  1005. // Nothing has changed.
  1006. return;
  1007. }
  1008. wEnable = (WORD)(fOneObjExists ? MF_ENABLED : MF_GRAYED);
  1009. hMenu = GetMenu(hwndMain);
  1010. EnableMenuItem(hMenu, menuposColor, MF_BYPOSITION | wEnable);
  1011. hMenu = GetSubMenu(GetMenu(hwndMain), menuposFile);
  1012. EnableMenuItem(hMenu, IDM_SAVE, MF_BYCOMMAND | wEnable);
  1013. EnableMenuItem(hMenu, IDM_SAVEAS, MF_BYCOMMAND | wEnable);
  1014. hMenu = GetSubMenu(GetMenu(hwndMain), menuposEdit);
  1015. EnableMenuItem(hMenu, IDM_CUT, MF_BYCOMMAND | wEnable);
  1016. EnableMenuItem(hMenu, IDM_COPY, MF_BYCOMMAND | wEnable);
  1017. EnableMenuItem(hMenu, IDM_DELETE, MF_BYCOMMAND | wEnable);
  1018. hMenu = GetSubMenu(GetMenu(hwndMain), menuposObject);
  1019. EnableMenuItem(hMenu, IDM_NEXTOBJ, MF_BYCOMMAND | wEnable);
  1020. DrawMenuBar (hwndMain);
  1021. fObjMenusEnabled = fOneObjExists;
  1022. }
  1023. /* Wait
  1024. * ----
  1025. *
  1026. * Dispatch messages until the given flag is set to FALSE.
  1027. * One use of this function is to wait until a Release method is called
  1028. * after a function has returned OLE_WAIT_FOR_RELEASE.
  1029. *
  1030. * BOOL *pf - Pointer to the flag being waited on.
  1031. *
  1032. * CUSTOMIZATION: The use of OleUnblockServer is for illustration only.
  1033. * Since Server Demo does not call OleBlockServer, there
  1034. * will never be any messages in the OLE queue.
  1035. *
  1036. */
  1037. VOID Wait (BOOL *pf)
  1038. {
  1039. MSG msg;
  1040. BOOL fMoreMsgs = FALSE;
  1041. *pf = TRUE;
  1042. while (*pf==TRUE)
  1043. {
  1044. OleUnblockServer (srvrMain.lhsrvr, &fMoreMsgs);
  1045. if (!fMoreMsgs)
  1046. // if there are no more messages in the OLE queue, go to system queue
  1047. {
  1048. if (GetMessage (&msg, NULL, 0, 0))
  1049. {
  1050. TranslateMessage (&msg);
  1051. DispatchMessage (&msg);
  1052. }
  1053. }
  1054. }
  1055. }
  1056. static BOOL FailedUpdate(HWND hwnd)
  1057. {
  1058. return(DialogBox(hInst, "FailedUpdate", hwnd, (DLGPROC)fnFailedUpdate));
  1059. }
  1060. BOOL APIENTRY fnFailedUpdate (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  1061. {
  1062. switch (message)
  1063. {
  1064. case WM_COMMAND:
  1065. {
  1066. WORD wID = LOWORD(wParam);
  1067. switch (wID)
  1068. {
  1069. case IDCANCEL:
  1070. case IDD_CONTINUEEDIT:
  1071. EndDialog(hDlg, TRUE);
  1072. break;
  1073. case IDD_UPDATEEXIT:
  1074. EndDialog(hDlg, FALSE);
  1075. break;
  1076. default:
  1077. break;
  1078. }
  1079. break;
  1080. }
  1081. case WM_INITDIALOG:
  1082. {
  1083. CHAR szMsg[200];
  1084. szMsg[0] = '\0';
  1085. wsprintf(
  1086. szMsg,
  1087. "This %s document can only be updated when you exit %s.",
  1088. (LPSTR) szClient,
  1089. (LPSTR) szAppName
  1090. );
  1091. SetDlgItemText(hDlg, IDD_TEXT, szMsg);
  1092. return TRUE;
  1093. }
  1094. default:
  1095. break;
  1096. }
  1097. return FALSE;
  1098. }