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.

1445 lines
35 KiB

  1. /* packager.c - OLE object wrapping application
  2. *
  3. * Created by Microsoft Corporation.
  4. */
  5. #include "packager.h"
  6. #include <shellapi.h>
  7. #include "dialogs.h"
  8. #include <htmlhelp.h>
  9. #define MenuFlag(b) ((b) ? MF_ENABLED : MF_GRAYED)
  10. /* 4-Oct-93 #2695 v-katsuy */
  11. // win31#2174: 12/26/92 : fixing frame window initial position
  12. /* The width of the Packager Frame window is nearly equal to 640.
  13. This value must be changed, when the design will be changed.
  14. */
  15. #define JPFRAMEWIDTH 640
  16. // Pointer to function RegisterPenApp()
  17. VOID (CALLBACK *RegPen)(WORD, BOOL) = NULL;
  18. static BOOL gfDirty = FALSE; // TRUE if file needs to be written
  19. static CHAR szEmbedding[] = "-Embedding"; // Not NLS specific
  20. static CHAR szEmbedding2[] = "/Embedding"; // Not NLS specific
  21. static CHAR szFrameClass[] = "AppClass"; // Not NLS specific
  22. static CHAR szObjectMenu[CBSHORTSTRING]; // "&Object" menu string
  23. static CHAR szEdit[CBSHORTSTRING]; // "Edit" string
  24. static CHAR szHelpFile[] = "PACKAGER.CHM"; // packager.chm
  25. static BOOL InitApplication(VOID);
  26. static BOOL InitInstance(VOID);
  27. static VOID EndInstance(VOID);
  28. static VOID SaveAsNeeded(VOID);
  29. static BOOL WriteToFile(VOID);
  30. static BOOL ReadFromFile(LPSTR lpstrFile);
  31. static OLESTATUS ProcessCmdLine(LPSTR lpCmdLine, INT nCmdShow);
  32. static VOID WaitForAllObjects(VOID);
  33. static VOID UpdateMenu(HMENU hmenu);
  34. static VOID UpdateObjectMenuItem(HMENU hMenu);
  35. static VOID ExecuteVerb(INT iVerb);
  36. INT_PTR CALLBACK fnFailedUpdate(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
  37. static VOID SendOleClosed(VOID);
  38. static VOID CreateUntitled(VOID);
  39. static VOID MakePenAware(VOID);
  40. static VOID MakePenUnaware(VOID);
  41. static VOID MakeMenuString(CHAR *szCtrl, CHAR *szMenuStr, CHAR *szVerb,
  42. CHAR *szClass, CHAR *szObject);
  43. BOOL gbDBCS = FALSE; // TRUE if we're running in DBCS mode
  44. /* WinMain() - Main Windows routine
  45. */
  46. INT WINAPI
  47. WinMain(
  48. HINSTANCE hInstance,
  49. HINSTANCE hPrevInstance,
  50. LPSTR lpCmdLine,
  51. INT nCmdShow
  52. )
  53. {
  54. MSG msg;
  55. LCID lcid;
  56. //DebugBreak();
  57. // Store the application instance number
  58. ghInst = hInstance;
  59. // Check DBCSness
  60. lcid = GetThreadLocale();
  61. gbDBCS = ( (PRIMARYLANGID(LANGIDFROMLCID(lcid)) == LANG_JAPANESE) ||
  62. (PRIMARYLANGID(LANGIDFROMLCID(lcid)) == LANG_KOREAN) ||
  63. (PRIMARYLANGID(LANGIDFROMLCID(lcid)) == LANG_CHINESE)
  64. );
  65. // Initialize application global information (window classes)
  66. if (!hPrevInstance)
  67. {
  68. if (!InitApplication())
  69. return FALSE;
  70. }
  71. // Initialize instance-specific information
  72. if (!InitInstance() || !InitClient())
  73. goto errRtn;
  74. if (!(gfServer = InitServer()))
  75. goto errRtn;
  76. MakePenAware();
  77. if (ProcessCmdLine(lpCmdLine, nCmdShow) != OLE_OK)
  78. {
  79. DeleteServer(glpsrvr);
  80. goto errRtn;
  81. }
  82. // if blocking happened in SrvrOpen(), then wait for object to be created
  83. if (gfBlocked)
  84. WaitForObject(((LPPICT)(glpobj[CONTENT]))->lpObject);
  85. // Main message loop
  86. while (TRUE)
  87. {
  88. if (gfBlocked && glpsrvr)
  89. {
  90. BOOL bMore = TRUE;
  91. LHSERVER lhsrvr = glpsrvr->lhsrvr;
  92. gfBlocked = FALSE;
  93. while (bMore)
  94. {
  95. if (OleUnblockServer (lhsrvr, &bMore) != OLE_OK)
  96. break;
  97. if (gfBlocked)
  98. break;
  99. }
  100. }
  101. if (!GetMessage(&msg, NULL, 0, 0))
  102. break;
  103. if (!TranslateAccelerator(ghwndFrame, ghAccTable, &msg))
  104. {
  105. TranslateMessage(&msg);
  106. DispatchMessage(&msg);
  107. }
  108. //
  109. // to support activation of file based object though Ole mechanism
  110. // we create a linked object out of file and then activate it. But
  111. // we don't get any notification when server closes the document.
  112. // Using the following mechanism we find it out and then grab the
  113. // contents from file
  114. //
  115. if (gfEmbObjectOpen)
  116. {
  117. LPEMBED lpembed = (LPEMBED)(glpobj[CONTENT]);
  118. if (lpembed != NULL && OleQueryOpen(lpembed->lpLinkObj) != OLE_OK)
  119. {
  120. gfEmbObjectOpen = FALSE;
  121. EmbRead(lpembed);
  122. EmbDeleteLinkObject(lpembed);
  123. if (gfInvisible)
  124. PostMessage(ghwndFrame, WM_SYSCOMMAND, SC_CLOSE, 0L);
  125. }
  126. }
  127. }
  128. goto cleanup;
  129. errRtn:
  130. if (ghwndFrame)
  131. DestroyWindow(ghwndFrame);
  132. cleanup:
  133. EndClient();
  134. MakePenUnaware();
  135. EndInstance();
  136. return FALSE;
  137. }
  138. /* InitApplication() - Do application "global" initialization.
  139. *
  140. * This function registers the window classes used by the application.
  141. * Returns: TRUE iff successful.
  142. */
  143. static BOOL
  144. InitApplication(
  145. VOID
  146. )
  147. {
  148. WNDCLASS wc;
  149. wc.style = 0;
  150. wc.lpfnWndProc = FrameWndProc;
  151. wc.cbClsExtra = 0;
  152. wc.cbWndExtra = 0;
  153. wc.hInstance = ghInst;
  154. wc.hIcon = LoadIcon(ghInst, MAKEINTRESOURCE(ID_APPLICATION));
  155. wc.hCursor = LoadCursor(ghInst, MAKEINTRESOURCE(SPLIT));
  156. wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
  157. wc.lpszMenuName = MAKEINTRESOURCE(ID_APPLICATION);
  158. wc.lpszClassName = szFrameClass;
  159. if (!RegisterClass(&wc))
  160. return FALSE;
  161. return InitPaneClasses();
  162. }
  163. /* InitInstance() - Handles the instance-specific initialization.
  164. *
  165. * This function creates the main application window.
  166. * Returns: TRUE iff successful.
  167. */
  168. static BOOL
  169. InitInstance(
  170. VOID
  171. )
  172. {
  173. HDC hDC;
  174. ghAccTable = LoadAccelerators(ghInst, MAKEINTRESOURCE(ID_APPLICATION));
  175. ghbrBackground = GetSysColorBrush(COLOR_APPWORKSPACE);
  176. ghcurWait = LoadCursor(NULL, IDC_WAIT);
  177. // Load the string resources
  178. LoadString(ghInst, IDS_APPNAME, szAppName, CBMESSAGEMAX);
  179. LoadString(ghInst, IDS_UNTITLED, szUntitled, CBMESSAGEMAX);
  180. // Create the Main Window
  181. if (gbDBCS)
  182. {
  183. /* 4-Oct-93 #2695 v-katsuy */
  184. // win31#2174: 12/26/92 : fixing frame window initial position
  185. if (!(ghwndError = ghwndFrame =
  186. CreateWindow(szFrameClass, szAppName,
  187. WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU
  188. | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
  189. CW_USEDEFAULT, CW_USEDEFAULT,
  190. // Following values are calculated when the window size is changed.
  191. // Default posiotion of a window is desided here, so dumy values
  192. // must be set here.
  193. JPFRAMEWIDTH, JPFRAMEWIDTH * 7 / 18,
  194. NULL, NULL, ghInst, NULL)))
  195. return FALSE;
  196. }
  197. else
  198. {
  199. if (!(ghwndError = ghwndFrame =
  200. CreateWindow(szFrameClass, szAppName,
  201. WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU
  202. | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
  203. CW_USEDEFAULT, CW_USEDEFAULT,
  204. CW_USEDEFAULT, CW_USEDEFAULT,
  205. NULL, NULL, ghInst, NULL)))
  206. return FALSE;
  207. }
  208. // Initialize the registration database
  209. RegInit();
  210. // Set the correct caption string
  211. OfnInit();
  212. glpobj[CONTENT] = glpobj[APPEARANCE] = NULL;
  213. glpobjUndo[CONTENT] = glpobjUndo[APPEARANCE] = NULL;
  214. LoadString(ghInst, IDS_EDIT, szEdit, CBSHORTSTRING);
  215. LoadString(ghInst, IDS_OBJECT_MENU, szObjectMenu, CBSHORTSTRING);
  216. LoadString(ghInst, IDS_UNDO_MENU, szUndo, CBSHORTSTRING);
  217. LoadString(ghInst, IDS_GENERIC, szDummy, CBSHORTSTRING);
  218. LoadString(ghInst, IDS_CONTENT_OBJECT, szContent, CBMESSAGEMAX);
  219. LoadString(ghInst, IDS_APPEARANCE_OBJECT, szAppearance, CBMESSAGEMAX);
  220. // Initialize global variables with LOGPIXELSX and LOGPIXELSY
  221. if (hDC = GetDC (NULL))
  222. {
  223. giXppli = GetDeviceCaps(hDC, LOGPIXELSX);
  224. giYppli = GetDeviceCaps(hDC, LOGPIXELSY);
  225. ReleaseDC(NULL, hDC);
  226. }
  227. return InitPanes();
  228. }
  229. /* EndInstance() - Instance-specific termination code.
  230. */
  231. static VOID
  232. EndInstance(
  233. VOID
  234. )
  235. {
  236. EndPanes();
  237. }
  238. /* FrameWndProc() - Frame window procedure.
  239. *
  240. * This function is the message handler for the application frame window.
  241. */
  242. LRESULT CALLBACK
  243. FrameWndProc(
  244. HWND hwnd,
  245. UINT msg,
  246. WPARAM wParam,
  247. LPARAM lParam
  248. )
  249. {
  250. BOOL fSuccess = FALSE;
  251. if (SplitterFrame(hwnd, msg, wParam, lParam))
  252. return DefWindowProc(hwnd, msg, wParam, lParam);
  253. switch (msg)
  254. {
  255. case WM_READEMBEDDED:
  256. if (gpty[CONTENT] == PEMBED)
  257. {
  258. EmbRead(glpobj[CONTENT]);
  259. if (gfInvisible)
  260. PostMessage(ghwndFrame, WM_SYSCOMMAND, SC_CLOSE, 0L);
  261. }
  262. break;
  263. case WM_INITMENU:
  264. UpdateMenu((HMENU)wParam);
  265. break;
  266. case WM_COMMAND:
  267. switch (LOWORD(wParam))
  268. {
  269. case IDM_NEXTWINDOW:
  270. // Special trickery works because APP = 0 & CONTENT = 1
  271. Raise(GetTopWindow(hwnd) != ghwndPane[CONTENT]);
  272. break;
  273. case IDM_NEW:
  274. // Save the current file (if needed)
  275. SaveAsNeeded();
  276. // delete the current doc, and create untitled document
  277. CreateUntitled();
  278. break;
  279. case IDM_IMPORT:
  280. if (!OfnGetName(hwnd, IDM_IMPORT))
  281. break;
  282. Hourglass(TRUE);
  283. DeletePane(CONTENT, TRUE);
  284. if (ReadFromFile(gszFileName))
  285. {
  286. InvalidateRect(ghwndPane[CONTENT], NULL, TRUE);
  287. Dirty();
  288. if (!gpty[APPEARANCE])
  289. {
  290. if (glpobj[APPEARANCE] = IconCreateFromFile(gszFileName))
  291. {
  292. gpty[APPEARANCE] = ICON;
  293. InvalidateRect(ghwndPane[APPEARANCE], NULL, TRUE);
  294. }
  295. }
  296. }
  297. Hourglass(FALSE);
  298. break;
  299. case IDM_EXPORT:
  300. if (!OfnGetName(hwnd, IDM_EXPORT))
  301. return 0L; /* Operation cancelled */
  302. Hourglass(TRUE);
  303. if (!WriteToFile())
  304. ErrorMessage(E_FAILED_TO_SAVE_FILE);
  305. Hourglass(FALSE);
  306. break;
  307. case IDM_UPDATE:
  308. {
  309. OLESTATUS retval;
  310. if (Error(OleSavedClientDoc(glhcdoc)))
  311. ErrorMessage(W_FAILED_TO_NOTIFY);
  312. if ((retval = OleSavedServerDoc (glpdoc->lhdoc)) == OLE_OK)
  313. {
  314. gfDirty = FALSE;
  315. }
  316. else if (retval == OLE_ERROR_CANT_UPDATE_CLIENT)
  317. {
  318. //
  319. // The client doesn't take updates on Save. Let the
  320. // user explicitly update and exit, or continue with
  321. // the editing.
  322. //
  323. if (!MyDialogBox(DTFAILEDUPDATE, ghwndFrame, fnFailedUpdate))
  324. {
  325. // update the object and exit
  326. gfOleClosed = TRUE;
  327. DeregisterDoc();
  328. DeleteServer(glpsrvr);
  329. }
  330. }
  331. else
  332. {
  333. Error(retval);
  334. }
  335. break;
  336. }
  337. case IDM_EXIT:
  338. SendMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
  339. return 0L;
  340. break;
  341. case IDM_COMMAND:
  342. Raise(CONTENT);
  343. DeletePane(CONTENT, FALSE);
  344. if (gptyUndo[CONTENT] != CMDLINK)
  345. glpobj[CONTENT] = CmlCreate("", FALSE);
  346. else
  347. glpobj[CONTENT] = CmlClone(glpobjUndo[CONTENT]);
  348. if (glpobj[CONTENT])
  349. gpty[CONTENT] = CMDLINK;
  350. if (glpobj[CONTENT] && ChangeCmdLine(glpobj[CONTENT]))
  351. {
  352. InvalidateRect(ghwndPane[CONTENT], NULL, TRUE);
  353. Dirty();
  354. }
  355. else
  356. {
  357. CmlDelete(glpobj[CONTENT]);
  358. gpty[CONTENT] = NOTHING;
  359. glpobj[CONTENT] = NULL;
  360. SendMessage(ghwndPane[CONTENT], WM_COMMAND, IDM_UNDO, 0L);
  361. }
  362. break;
  363. case IDM_INSERTICON:
  364. PostMessage (ghwndBar[APPEARANCE], WM_COMMAND, IDM_INSERTICON, 0L);
  365. break;
  366. case IDM_DESC:
  367. case IDM_PICT:
  368. PostMessage(ghwndBar[CONTENT], WM_COMMAND, wParam, 0L);
  369. break;
  370. case IDM_LABEL:
  371. Raise(APPEARANCE);
  372. if (gpty[APPEARANCE] != ICON)
  373. break;
  374. ChangeLabel(glpobj[APPEARANCE]);
  375. InvalidateRect(ghwndPane[APPEARANCE], NULL, TRUE);
  376. Dirty();
  377. break;
  378. case IDM_COPYPACKAGE:
  379. if (!CopyObjects())
  380. ErrorMessage(E_CLIPBOARD_COPY_FAILED);
  381. break;
  382. case IDM_PASTE:
  383. // Check to see if we are pasting a packaged object
  384. if (IsClipboardFormatAvailable(gcfNative)
  385. && IsClipboardFormatAvailable(gcfOwnerLink))
  386. {
  387. HANDLE hData;
  388. HANDLE hData2;
  389. LPSTR lpData;
  390. OpenClipboard(ghwndFrame);
  391. hData = GetClipboardData(gcfOwnerLink);
  392. if (lpData = GlobalLock(hData))
  393. {
  394. // If it's the packager, get the native data
  395. if (!lstrcmpi(lpData, gszAppClassName)
  396. && (hData2 = GetClipboardData(gcfNative)))
  397. fSuccess = PutNative(hData2);
  398. // Unlock the clipboard Owner Link data
  399. GlobalUnlock(hData);
  400. }
  401. CloseClipboard();
  402. }
  403. // Did we successfully read the native data?
  404. if (fSuccess)
  405. break;
  406. // ... guess not (maybe not Package!)
  407. PostMessage(GetTopWindow(hwnd), msg, wParam, lParam);
  408. break;
  409. case IDM_OBJECT:
  410. ExecuteVerb(0); // Execute the ONLY verb
  411. break;
  412. case IDM_INDEX:
  413. HtmlHelp(ghwndFrame, szHelpFile, HH_DISPLAY_TOPIC, 0L);
  414. break;
  415. case IDM_ABOUT:
  416. ShellAbout(hwnd, szAppName, "",
  417. LoadIcon(ghInst, MAKEINTRESOURCE(ID_APPLICATION)));
  418. break;
  419. default:
  420. if ((LOWORD(wParam) >= IDM_VERBMIN)
  421. && (LOWORD(wParam) <= IDM_VERBMAX))
  422. {
  423. // An object verb has been selected
  424. // (Hmm. Did you know that an 'object verb' was a noun?)
  425. ExecuteVerb(LOWORD(wParam) - IDM_VERBMIN);
  426. }
  427. else
  428. {
  429. PostMessage(GetTopWindow(hwnd), msg, wParam, lParam);
  430. }
  431. break;
  432. }
  433. break;
  434. case WM_CLOSE:
  435. //
  436. // Update if necessary by notifying the server that we are closing
  437. // down, and revoke the server.
  438. //
  439. SaveAsNeeded();
  440. SendOleClosed();
  441. DeleteServer(glpsrvr);
  442. return 0L;
  443. case WM_DESTROY:
  444. PostQuitMessage(0);
  445. return 0L;
  446. default:
  447. return DefWindowProc(hwnd, msg, wParam, lParam);
  448. }
  449. return 0L;
  450. }
  451. /* SetTitle() - Sets the window caption to the current filename.
  452. *
  453. * If gszFileName is NULL, the caption will be set to "(Untitled)".
  454. * If DocSetHostNames() is called with a client app name, that name
  455. * will be prepended.
  456. *
  457. * For the Embedded case, the "Embedded #n" string is stored in
  458. * "Untitled", and is always displayed regardless of the file name.
  459. */
  460. VOID
  461. SetTitle(
  462. BOOL fRegistering
  463. )
  464. {
  465. CHAR szTitle[CBMESSAGEMAX + CBPATHMAX];
  466. if (!gfEmbedded)
  467. {
  468. StringCchPrintf(szTitle, ARRAYSIZE(szTitle), "%s%s%s - %s", gszClientName,
  469. (*gszClientName) ? " " : "",
  470. szAppName, szUntitled);
  471. }
  472. else
  473. {
  474. CHAR szEmbnameContent[CBSHORTSTRING];
  475. LoadString(ghInst, IDS_EMBNAME_CONTENT, szEmbnameContent, CBSHORTSTRING);
  476. if (gbDBCS)
  477. {
  478. //#3997: 2/19/93: changed Window title
  479. StringCchPrintf(szTitle, ARRAYSIZE(szTitle), "%s - %s %s", szAppName, szUntitled,
  480. szEmbnameContent);
  481. }
  482. else
  483. {
  484. StringCchPrintf(szTitle, ARRAYSIZE(szTitle), "%s - %s %s", szAppName, szEmbnameContent,
  485. szUntitled);
  486. }
  487. }
  488. // Perform the client document registration
  489. if (glhcdoc)
  490. {
  491. if (Error(OleRenameClientDoc(glhcdoc, szUntitled)))
  492. ErrorMessage(W_FAILED_TO_NOTIFY);
  493. if (!fRegistering)
  494. ChangeDocName(&glpdoc, szUntitled);
  495. }
  496. else
  497. {
  498. if (Error(OleRegisterClientDoc(gszAppClassName, szUntitled, 0L, &glhcdoc)))
  499. {
  500. ErrorMessage(W_FAILED_TO_NOTIFY);
  501. glhcdoc = 0;
  502. }
  503. // New file, so re-register it
  504. if (!fRegistering)
  505. glpdoc = InitDoc(glpsrvr, 0, szUntitled);
  506. }
  507. if (IsWindow(ghwndFrame))
  508. SetWindowText(ghwndFrame, szTitle);
  509. }
  510. /* InitFile() - Reinitializes the title bar, etc... when editing a New file.
  511. */
  512. VOID
  513. InitFile(
  514. VOID
  515. )
  516. {
  517. gfDirty = FALSE;
  518. // Deregister the edited document, and wipe out the objects.
  519. DeregisterDoc();
  520. // Reset the title bar, and register the OLE client document
  521. SetTitle(FALSE);
  522. }
  523. /* SaveAsNeeded() - Saves the file if it has been modified. It's assumed that
  524. * after this routine is called this document is going to be
  525. * closed. If that's not true, then this routine may have to
  526. * be rewritten.
  527. */
  528. static VOID
  529. SaveAsNeeded(
  530. VOID
  531. )
  532. {
  533. gfOleClosed = FALSE;
  534. if (gfDirty && gfEmbedded && (glpobj[APPEARANCE] || glpobj[CONTENT]))
  535. {
  536. CHAR sz[CBMESSAGEMAX];
  537. CHAR sz2[CBMESSAGEMAX + CBPATHMAX];
  538. if (gfInvisible)
  539. {
  540. SendDocChangeMsg(glpdoc, OLE_CLOSED);
  541. return;
  542. }
  543. LoadString(ghInst, gfEmbedded ? IDS_MAYBEUPDATE : IDS_MAYBESAVE, sz,
  544. CBMESSAGEMAX);
  545. StringCchPrintf(sz2, ARRAYSIZE(sz2), sz, (LPSTR)szUntitled);
  546. // Ask "Do you wish to save your changes?"
  547. if (MessageBoxAfterBlock(ghwndFrame, sz2, szAppName,
  548. MB_YESNO | MB_ICONQUESTION) == IDYES)
  549. {
  550. gfOleClosed = TRUE;
  551. return;
  552. }
  553. // If not saving changes, revert the document
  554. else if (OleRevertClientDoc(glhcdoc))
  555. {
  556. ErrorMessage(W_FAILED_TO_NOTIFY);
  557. }
  558. }
  559. }
  560. /* WriteToFile() - Writes the current document to a file.
  561. *
  562. * Returns: TRUE iff successful.
  563. */
  564. static BOOL
  565. WriteToFile(
  566. VOID
  567. )
  568. {
  569. BOOL fSuccess = FALSE;
  570. OFSTRUCT reopenbuf;
  571. INT fh;
  572. CHAR szDesc[CBSTRINGMAX];
  573. CHAR szMessage[CBSTRINGMAX + CBPATHMAX];
  574. if (OpenFile(gszFileName, &reopenbuf, OF_EXIST) != -1)
  575. {
  576. // File exists, query for overwrite!
  577. LoadString(ghInst, IDS_OVERWRITE, szDesc, CharCountOf(szDesc));
  578. StringCchPrintf(szMessage, ARRAYSIZE(szMessage), szDesc, gszFileName);
  579. if (MessageBoxAfterBlock(ghwndFrame, szMessage, szAppName,
  580. MB_YESNO | MB_ICONEXCLAMATION) == IDNO)
  581. return TRUE;
  582. }
  583. // Take care of this earlier?
  584. if ((fh = _lcreat((LPSTR)gszFileName, 0)) <= 0)
  585. {
  586. LoadString(ghInst, IDS_INVALID_FILENAME, szDesc, CharCountOf(szDesc));
  587. StringCchPrintf(szMessage, ARRAYSIZE(szMessage), szDesc, gszFileName);
  588. MessageBoxAfterBlock(ghwndFrame, szMessage, szAppName, MB_OK);
  589. return FALSE;
  590. }
  591. Hourglass(TRUE);
  592. // Go to the top of the file
  593. _llseek(fh, 0L, 0);
  594. EmbWriteToFile(glpobj[CONTENT], fh);
  595. fSuccess = TRUE;
  596. // Close the file, and return
  597. _lclose(fh);
  598. gfDirty = FALSE;
  599. Hourglass(FALSE);
  600. return fSuccess;
  601. }
  602. /* ReadFromFile() - Reads OLE objects from a file.
  603. *
  604. * Reads as many objects as it can, in upwards order (better error recovery).
  605. * Returns: TRUE iff successful.
  606. */
  607. static BOOL
  608. ReadFromFile(
  609. LPSTR lpstrFile
  610. )
  611. {
  612. BOOL fSuccess = FALSE;
  613. Hourglass(TRUE);
  614. // Read in each object and get them in the right order
  615. if (!(glpobj[CONTENT] = EmbCreate(lpstrFile)))
  616. {
  617. goto Error;
  618. }
  619. gpty[CONTENT] = PEMBED;
  620. fSuccess = TRUE;
  621. Error:
  622. gfDirty = FALSE;
  623. Hourglass(FALSE);
  624. return fSuccess;
  625. }
  626. /* ErrorMessage() - Pops up a message box containing a string table message.
  627. *
  628. * Pre: Assigns "ghwndError" to be its parent, so focus will return properly.
  629. */
  630. VOID
  631. ErrorMessage(
  632. UINT id
  633. )
  634. {
  635. CHAR sz[300];
  636. if (IsWindow(ghwndError))
  637. {
  638. LoadString(ghInst, id, sz, 300);
  639. MessageBoxAfterBlock(ghwndError, sz, szAppName,
  640. MB_OK | MB_ICONEXCLAMATION);
  641. }
  642. }
  643. /* ProcessMessage() - Spin in a message dispatch loop.
  644. */
  645. BOOL
  646. ProcessMessage(
  647. VOID
  648. )
  649. {
  650. BOOL fReturn;
  651. MSG msg;
  652. if (fReturn = GetMessage(&msg, NULL, 0, 0))
  653. {
  654. if (!TranslateAccelerator(ghwndFrame, ghAccTable, &msg))
  655. {
  656. TranslateMessage(&msg);
  657. DispatchMessage(&msg);
  658. }
  659. }
  660. return fReturn;
  661. }
  662. /* Contains() - Determines whether a string matches a pattern.
  663. * This could be more intelligent, but it is scarcely executed.
  664. *
  665. * Returns: Non-NULL iff lpPattern is a substring of lpString.
  666. */
  667. LPSTR
  668. Contains(
  669. LPSTR lpString,
  670. LPSTR lpPattern
  671. )
  672. {
  673. LPSTR lpSubstr;
  674. LPSTR lpPat;
  675. for (;;)
  676. {
  677. // Match the first character
  678. while (*lpString && *lpString != *lpPattern)
  679. lpString++;
  680. // We are at the end of the string, fail...
  681. if (!(*lpString))
  682. return NULL;
  683. // If we have a match, try to match the entire pattern string
  684. lpPat = lpPattern;
  685. lpSubstr = lpString;
  686. while (*lpPat && *lpSubstr && *lpPat == *lpSubstr)
  687. {
  688. lpPat++;
  689. lpSubstr++;
  690. }
  691. // We are at the end of the pattern, success! Wipe out the pattern
  692. if (!(*lpPat))
  693. return lpString;
  694. // We are at the end of the string, failure...
  695. if (!(*lpSubstr))
  696. return NULL;
  697. lpString++;
  698. }
  699. }
  700. /* ProcessCmdLine() - Processes the command line options.
  701. */
  702. static OLESTATUS
  703. ProcessCmdLine(
  704. LPSTR lpCmdLine,
  705. INT nCmdShow
  706. )
  707. {
  708. OLESTATUS retval = OLE_OK;
  709. // Does the command line contain "/Embedding"?
  710. if (gfEmbeddedFlag = gfInvisible =
  711. (Contains(lpCmdLine, szEmbedding) || Contains(lpCmdLine, szEmbedding2)))
  712. {
  713. // If we have a file name, register it NOW!
  714. lpCmdLine += lstrlen(szEmbedding);
  715. while (*lpCmdLine && *lpCmdLine == ' ')
  716. lpCmdLine++;
  717. if (*lpCmdLine)
  718. {
  719. retval = (glpsrvr->olesrvr.lpvtbl->Open)
  720. ((LPOLESERVER)glpsrvr, 0, lpCmdLine,
  721. (LPOLESERVERDOC *)&glpdoc);
  722. if (retval != OLE_OK)
  723. return retval;
  724. }
  725. gfDirty = FALSE;
  726. gnCmdShowSave = nCmdShow;
  727. }
  728. else
  729. {
  730. ShowWindow(ghwndFrame, nCmdShow);
  731. SendMessage(ghwndFrame, WM_COMMAND, IDM_NEW, 0L);
  732. }
  733. return retval;
  734. }
  735. /* Dirty() - This function is called each time the document is soiled.
  736. */
  737. VOID
  738. Dirty(
  739. VOID
  740. )
  741. {
  742. gfDirty = TRUE;
  743. SendDocChangeMsg(glpdoc, OLE_CHANGED);
  744. }
  745. /* WaitForAllObjects() - Wait for asynchronous operations to complete.
  746. *
  747. * We don't use ProcessMessage() because we want to terminate as quickly
  748. * as possible, and we don't want to allow any structured user input.
  749. */
  750. static VOID
  751. WaitForAllObjects(
  752. VOID
  753. )
  754. {
  755. MSG msgWait;
  756. if (gcOleWait)
  757. {
  758. while (gcOleWait)
  759. {
  760. if (GetMessage(&msgWait, NULL, 0, 0))
  761. DispatchMessage(&msgWait);
  762. }
  763. }
  764. }
  765. /* DeregisterDoc() - Deregisters the currently edited document.
  766. */
  767. VOID
  768. DeregisterDoc(
  769. VOID
  770. )
  771. {
  772. gfDocCleared = TRUE;
  773. SendOleClosed();
  774. // Destroy all the objects
  775. DeletePane(APPEARANCE, TRUE);
  776. DeletePane(CONTENT, TRUE);
  777. // Wait for the objects to be deleted
  778. WaitForAllObjects();
  779. if (glpdoc)
  780. {
  781. LHSERVERDOC lhdoc = glpdoc->lhdoc;
  782. glpdoc = NULL;
  783. OleRevokeServerDoc(lhdoc);
  784. }
  785. // Release the document
  786. if (glhcdoc)
  787. {
  788. if (Error(OleRevokeClientDoc(glhcdoc)))
  789. ErrorMessage(W_FAILED_TO_NOTIFY);
  790. glhcdoc = 0;
  791. }
  792. }
  793. static VOID
  794. UpdateMenu(
  795. HMENU hmenu
  796. )
  797. {
  798. INT iPane;
  799. INT mf;
  800. iPane = (GetTopWindow(ghwndFrame) == ghwndPane[CONTENT]);
  801. EnableMenuItem(hmenu, IDM_EXPORT, MenuFlag(gpty[CONTENT] == PEMBED));
  802. EnableMenuItem(hmenu, IDM_CLEAR, MenuFlag(gpty[iPane]));
  803. EnableMenuItem(hmenu, IDM_UNDO, MenuFlag(gptyUndo[iPane]));
  804. EnableMenuItem(hmenu, IDM_UPDATE, (gfEmbedded ? MF_ENABLED : MF_GRAYED));
  805. if (((iPane == APPEARANCE) && gpty[iPane]) || (gpty[iPane] == PICTURE))
  806. {
  807. EnableMenuItem(hmenu, IDM_CUT, MF_ENABLED);
  808. EnableMenuItem(hmenu, IDM_COPY, MF_ENABLED);
  809. }
  810. else
  811. {
  812. EnableMenuItem(hmenu, IDM_CUT, MF_GRAYED);
  813. EnableMenuItem(hmenu, IDM_COPY, MF_GRAYED);
  814. }
  815. if (gpty[iPane] == PICTURE)
  816. {
  817. LPPICT lppict = glpobj[iPane];
  818. DWORD ot;
  819. mf = MF_GRAYED;
  820. if (lppict->lpObject)
  821. {
  822. OleQueryType(lppict->lpObject, &ot);
  823. // Enable Links... only if we have a linked object
  824. mf = MenuFlag(ot == OT_LINK);
  825. }
  826. EnableMenuItem(hmenu, IDM_LINKS, mf);
  827. EnableMenuItem(hmenu, IDM_LABEL, MF_GRAYED);
  828. }
  829. else
  830. {
  831. EnableMenuItem(hmenu, IDM_LINKS, MF_GRAYED);
  832. EnableMenuItem(hmenu, IDM_LABEL, MenuFlag(gpty[APPEARANCE] == ICON));
  833. }
  834. UpdateObjectMenuItem(GetSubMenu(hmenu, POS_EDITMENU));
  835. mf = MenuFlag(OleQueryCreateFromClip(gszProtocol, olerender_draw, 0) ==
  836. OLE_OK
  837. || OleQueryCreateFromClip(gszSProtocol, olerender_draw, 0) == OLE_OK);
  838. EnableMenuItem(hmenu, IDM_PASTE, mf);
  839. if (iPane == CONTENT)
  840. {
  841. if (IsClipboardFormatAvailable(gcfFileName)) {
  842. EnableMenuItem(hmenu, IDM_PASTELINK, MF_ENABLED);
  843. }
  844. else
  845. {
  846. mf = MenuFlag(OleQueryLinkFromClip(gszProtocol, olerender_draw, 0)
  847. == OLE_OK);
  848. EnableMenuItem(hmenu, IDM_PASTELINK, mf);
  849. }
  850. }
  851. else
  852. {
  853. EnableMenuItem(hmenu, IDM_PASTELINK, MF_GRAYED);
  854. }
  855. mf = MenuFlag(gpty[CONTENT] && gpty[APPEARANCE]);
  856. EnableMenuItem(hmenu, IDM_COPYPACKAGE, mf);
  857. }
  858. /* UpdateObjectMenuItem - If there are items in the selection, add the
  859. * menu, with a possible popup depending on the
  860. * number of verbs.
  861. */
  862. static VOID
  863. UpdateObjectMenuItem(
  864. HMENU hMenu
  865. )
  866. {
  867. INT cVerbs = 0; /* how many verbs in list */
  868. HWND hwndItem = NULL;
  869. INT iPane;
  870. LONG objtype;
  871. LPPICT lpPict;
  872. CHAR szWordOrder2[10];
  873. CHAR szWordOrder3[10];
  874. if (!hMenu)
  875. return;
  876. DeleteMenu(hMenu, POS_OBJECT, MF_BYPOSITION);
  877. LoadString(ghInst, IDS_POPUPVERBS, szWordOrder2, sizeof(szWordOrder2));
  878. LoadString(ghInst, IDS_SINGLEVERB, szWordOrder3, sizeof(szWordOrder3));
  879. //
  880. // CASES:
  881. // object supports 0 verbs "<Object Class> Object"
  882. // object supports 1 verb == edit "<Object Class> Object"
  883. // object supports 1 verb != edit "<verb> <Object Class> Object"
  884. // object supports more than 1 verb "<Object Class> Object" => verbs
  885. //
  886. iPane = ((hwndItem = GetTopWindow(ghwndFrame)) == ghwndPane[CONTENT]);
  887. lpPict = glpobj[iPane];
  888. if (lpPict
  889. && OleQueryType(lpPict->lpObject, &objtype) == OLE_OK
  890. && hwndItem
  891. && gpty[iPane] == PICTURE
  892. && objtype != OT_STATIC)
  893. {
  894. HANDLE hData = NULL;
  895. LPSTR lpstrData;
  896. if (OleGetData(lpPict->lpObject, (OLECLIPFORMAT) (objtype == OT_LINK ?
  897. gcfLink : gcfOwnerLink), &hData) == OLE_OK)
  898. {
  899. // Both link formats are: "szClass0szDocument0szItem00"
  900. if (lpstrData = GlobalLock(hData))
  901. {
  902. DWORD dwSize = KEYNAMESIZE;
  903. CHAR szClass[KEYNAMESIZE], szBuffer[200];
  904. CHAR szVerb[KEYNAMESIZE];
  905. HANDLE hPopupNew = NULL;
  906. // get real language class of object in szClass for menu
  907. if (RegQueryValue(HKEY_CLASSES_ROOT, lpstrData,
  908. szClass, &dwSize))
  909. StringCchCopy(szClass, ARRAYSIZE(szClass), lpstrData); /* if above call failed */
  910. GlobalUnlock(hData);
  911. // append class key
  912. for (cVerbs = 0; ; ++cVerbs)
  913. {
  914. dwSize = KEYNAMESIZE;
  915. StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer),
  916. "%s\\protocol\\StdFileEditing\\verb\\%d",
  917. lpstrData, cVerbs);
  918. if (RegQueryValue(HKEY_CLASSES_ROOT, szBuffer,
  919. szVerb, &dwSize))
  920. break;
  921. if (hPopupNew == NULL)
  922. hPopupNew = CreatePopupMenu();
  923. InsertMenu(hPopupNew, (UINT)-1, MF_BYPOSITION,
  924. IDM_VERBMIN + cVerbs, szVerb);
  925. }
  926. if (cVerbs == 0)
  927. {
  928. MakeMenuString(szWordOrder3, szBuffer, szEdit,
  929. szClass, szObjectMenu);
  930. InsertMenu(hMenu, POS_OBJECT, MF_BYPOSITION,
  931. IDM_VERBMIN, szBuffer);
  932. }
  933. else if (cVerbs == 1)
  934. {
  935. MakeMenuString(szWordOrder3, szBuffer, szVerb,
  936. szClass, szObjectMenu);
  937. InsertMenu(hMenu, POS_OBJECT, MF_BYPOSITION,
  938. IDM_VERBMIN, szBuffer);
  939. DestroyMenu(hPopupNew);
  940. }
  941. else
  942. {
  943. // > 1 verbs
  944. MakeMenuString(szWordOrder2, szBuffer, NULL,
  945. szClass, szObjectMenu);
  946. InsertMenu(hMenu, POS_OBJECT, MF_BYPOSITION |
  947. MF_POPUP, (UINT_PTR)hPopupNew, szBuffer);
  948. }
  949. EnableMenuItem(hMenu, POS_OBJECT,
  950. MF_ENABLED | MF_BYPOSITION);
  951. return;
  952. }
  953. }
  954. }
  955. // error if got to here
  956. InsertMenu(hMenu, POS_OBJECT, MF_BYPOSITION, 0, szObjectMenu);
  957. EnableMenuItem(hMenu, POS_OBJECT, MF_GRAYED | MF_BYPOSITION);
  958. }
  959. /* ExecuteVerb() - Find the proper verb to execute for each selected item
  960. */
  961. static VOID
  962. ExecuteVerb(
  963. INT iVerb
  964. )
  965. {
  966. HWND hwndItem;
  967. INT iPane;
  968. RECT rc;
  969. iPane = ((hwndItem = GetTopWindow(ghwndFrame)) == ghwndPane[CONTENT]);
  970. GetClientRect(hwndItem, (LPRECT) & rc);
  971. // Execute the correct verb for this object
  972. if (Error(OleActivate(((LPPICT)(glpobj[iPane]))->lpObject, iVerb, TRUE,
  973. TRUE, hwndItem, &rc)))
  974. {
  975. if (OleQueryReleaseError(((LPPICT)(glpobj[iPane]))->lpObject) == OLE_ERROR_LAUNCH )
  976. ErrorMessage(E_FAILED_TO_LAUNCH_SERVER);
  977. }
  978. else
  979. {
  980. LONG ot;
  981. WaitForObject(((LPPICT)(glpobj[iPane]))->lpObject);
  982. if (!glpobj[iPane])
  983. return;
  984. OleQueryType(((LPPICT)(glpobj[iPane]))->lpObject, &ot);
  985. if (ot == OT_EMBEDDED)
  986. Error(OleSetHostNames(((LPPICT)(glpobj[iPane]))->lpObject,
  987. gszAppClassName,
  988. (iPane == CONTENT) ? szContent : szAppearance));
  989. }
  990. }
  991. VOID
  992. Raise(
  993. INT iPane
  994. )
  995. {
  996. if (GetTopWindow(ghwndFrame) != ghwndPane[iPane])
  997. SendMessage(ghwndPane[iPane], WM_LBUTTONDOWN, 0, 0L);
  998. }
  999. INT_PTR CALLBACK
  1000. fnFailedUpdate(
  1001. HWND hDlg,
  1002. UINT msg,
  1003. WPARAM wParam,
  1004. LPARAM lParam
  1005. )
  1006. {
  1007. switch (msg)
  1008. {
  1009. case WM_INITDIALOG:
  1010. {
  1011. CHAR szMsg[200];
  1012. CHAR szStr[100];
  1013. LoadString(ghInst, IDS_FAILEDUPDATE, szStr, sizeof(szStr));
  1014. StringCchPrintf((LPSTR)szMsg, ARRAYSIZE(szMsg), szStr, gszClientName, szAppName);
  1015. SetDlgItemText(hDlg, IDD_TEXT, szMsg);
  1016. return TRUE; // default Push button gets the focus
  1017. }
  1018. break;
  1019. case WM_COMMAND:
  1020. switch (LOWORD(wParam))
  1021. {
  1022. case IDCANCEL:
  1023. case IDD_CONTINUEEDIT:
  1024. EndDialog(hDlg, TRUE);
  1025. break;
  1026. case IDD_UPDATEEXIT:
  1027. EndDialog(hDlg, FALSE);
  1028. break;
  1029. default:
  1030. break;
  1031. }
  1032. break;
  1033. default:
  1034. break;
  1035. }
  1036. return FALSE;
  1037. }
  1038. static VOID
  1039. SendOleClosed(
  1040. VOID
  1041. )
  1042. {
  1043. // Do this first, so the data can be updated as needed
  1044. if (glpdoc)
  1045. {
  1046. if (gfOleClosed)
  1047. {
  1048. SendDocChangeMsg(glpdoc, OLE_CLOSED);
  1049. gfOleClosed = FALSE;
  1050. }
  1051. }
  1052. }
  1053. static VOID
  1054. CreateUntitled(
  1055. VOID
  1056. )
  1057. {
  1058. if (gfEmbedded) /* Unembed if embedded */
  1059. EndEmbedding();
  1060. if (gvlptempdoc = InitDoc(glpsrvr, 0, szUntitled))
  1061. {
  1062. InitFile(); /* Reset the file */
  1063. glpdoc = gvlptempdoc;
  1064. SetTitle(TRUE);
  1065. gvlptempdoc = NULL;
  1066. gfDocExists = TRUE;
  1067. gfDocCleared = FALSE;
  1068. }
  1069. else
  1070. {
  1071. ErrorMessage(E_FAILED_TO_REGISTER_DOCUMENT);
  1072. }
  1073. }
  1074. static VOID
  1075. MakePenAware(
  1076. VOID
  1077. )
  1078. {
  1079. HANDLE hPenWin = NULL;
  1080. if ((hPenWin = LongToHandle(GetSystemMetrics(SM_PENWINDOWS))) != NULL)
  1081. {
  1082. // We do this fancy GetProcAddress simply because we don't
  1083. // know if we're running Pen Windows.
  1084. if ((RegPen = (VOID (CALLBACK *)(WORD, BOOL))GetProcAddress(hPenWin, "RegisterPenApp")) != NULL)
  1085. (*RegPen)(1, TRUE);
  1086. }
  1087. }
  1088. static VOID
  1089. MakePenUnaware(
  1090. VOID
  1091. )
  1092. {
  1093. if (RegPen != NULL)
  1094. (*RegPen)(1, FALSE);
  1095. }
  1096. INT_PTR MessageBoxAfterBlock(
  1097. HWND hwndParent,
  1098. LPSTR lpText,
  1099. LPSTR lpCaption,
  1100. UINT fuStyle
  1101. )
  1102. {
  1103. if (glpsrvr && !gfBlocked && (OleBlockServer(glpsrvr->lhsrvr) == OLE_OK))
  1104. gfBlocked = TRUE;
  1105. return MessageBox((gfInvisible ? NULL : hwndParent), lpText, lpCaption,
  1106. fuStyle | MB_TOPMOST);
  1107. }
  1108. INT_PTR DialogBoxAfterBlock(
  1109. LPCSTR lpTemplate,
  1110. HWND hwndParent,
  1111. DLGPROC lpDialogFunc
  1112. )
  1113. {
  1114. if (glpsrvr && !gfBlocked && (OleBlockServer(glpsrvr->lhsrvr) == OLE_OK))
  1115. gfBlocked = TRUE;
  1116. return DialogBox(ghInst, lpTemplate, (gfInvisible ? NULL : hwndParent),
  1117. lpDialogFunc);
  1118. }
  1119. static VOID
  1120. MakeMenuString(
  1121. CHAR *szCtrl,
  1122. CHAR *szMenuStr,
  1123. CHAR *szVerb,
  1124. CHAR *szClass,
  1125. CHAR *szObject
  1126. )
  1127. {
  1128. register CHAR c;
  1129. CHAR *pStr;
  1130. while (c = *szCtrl++)
  1131. {
  1132. switch (c)
  1133. {
  1134. case 'c': // class
  1135. case 'C': // class
  1136. pStr = szClass;
  1137. break;
  1138. case 'v': // class
  1139. case 'V': // class
  1140. pStr = szVerb;
  1141. break;
  1142. case 'o': // object
  1143. case 'O': // object
  1144. pStr = szObject;
  1145. break;
  1146. default:
  1147. *szMenuStr++ = c;
  1148. *szMenuStr = '\0'; // just in case
  1149. continue;
  1150. }
  1151. if (pStr) // should always be true
  1152. {
  1153. StringCchCopy(szMenuStr, ARRAYSIZE(szMenuStr), pStr);
  1154. szMenuStr += lstrlen(pStr); // point to '\0'
  1155. }
  1156. }
  1157. }