Leaked source code of windows server 2003
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.

1041 lines
24 KiB

  1. /* server.c - This module contains the OLE server worker/public routines.
  2. *
  3. * Created by Microsoft Corporation.
  4. */
  5. #include "packager.h"
  6. #define CBLINKMAX 260
  7. /*
  8. * This server only supports one document per instance. The items are
  9. * just rectangles over the document, possibly overlapping.
  10. */
  11. static LHCLIENTDOC lhClipDoc = 0;
  12. static OLESERVERDOCVTBL vdocvtbl; // Document virtual table
  13. static OLEOBJECTVTBL vitemvtbl; // Item virtual table
  14. static OLESERVERVTBL vsrvrvtbl; // Server virtual table
  15. static LPSAMPITEM vlpitem[CITEMSMAX]; // Pointers to active OLE items
  16. static INT cItems = 0; // Number of active OLE items
  17. static CHAR szClip[] = "Clipboard";
  18. static VOID DeleteDoc(LPSAMPDOC lpdoc);
  19. static BOOL SendItemChangeMsg(LPSAMPITEM lpitem, UINT options);
  20. static INT FindItem(LPSAMPITEM lpitem);
  21. /************ Server initialization and termination routines **********/
  22. /* InitServer() - Initializes the OLE server
  23. */
  24. BOOL
  25. InitServer(
  26. VOID
  27. )
  28. {
  29. // Allocate the server block
  30. if (!(ghServer = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, sizeof(PBSRVR)))
  31. || !(glpsrvr = (LPSAMPSRVR)LocalLock(ghServer)))
  32. goto errRtn;
  33. // Initialize the server, document, and item virtual tables
  34. vsrvrvtbl.Open = SrvrOpen;
  35. vsrvrvtbl.Create = SrvrCreate;
  36. vsrvrvtbl.CreateFromTemplate = SrvrCreateFromTemplate;
  37. vsrvrvtbl.Edit = SrvrEdit;
  38. vsrvrvtbl.Exit = SrvrExit;
  39. vsrvrvtbl.Release = SrvrRelease;
  40. vsrvrvtbl.Execute = SrvrExecute;
  41. vdocvtbl.Save = DocSave;
  42. vdocvtbl.Close = DocClose;
  43. vdocvtbl.SetHostNames = DocSetHostNames;
  44. vdocvtbl.SetDocDimensions = DocSetDocDimensions;
  45. vdocvtbl.GetObject = DocGetObject;
  46. vdocvtbl.Release = DocRelease;
  47. vdocvtbl.SetColorScheme = DocSetColorScheme;
  48. vdocvtbl.Execute = DocExecute;
  49. vitemvtbl.QueryProtocol = ItemQueryProtocol;
  50. vitemvtbl.Release = ItemDelete;
  51. vitemvtbl.Show = ItemShow;
  52. vitemvtbl.DoVerb = ItemDoVerb;
  53. vitemvtbl.GetData = ItemGetData;
  54. vitemvtbl.SetData = ItemSetData;
  55. vitemvtbl.SetTargetDevice = ItemSetTargetDevice;
  56. vitemvtbl.SetBounds = ItemSetBounds;
  57. vitemvtbl.EnumFormats = ItemEnumFormats;
  58. vitemvtbl.SetColorScheme = ItemSetColorScheme;
  59. // Try to register the server
  60. glpsrvr->olesrvr.lpvtbl = &vsrvrvtbl;
  61. if (Error(OleRegisterServer(gszAppClassName, (LPOLESERVER)glpsrvr,
  62. (LONG_PTR * )&glpsrvr->lhsrvr, ghInst, OLE_SERVER_MULTI)))
  63. goto errRtn;
  64. // Initialize the client name
  65. lstrcpy(gszClientName, "");
  66. return TRUE;
  67. errRtn:
  68. ErrorMessage(E_FAILED_TO_REGISTER_SERVER);
  69. // If we failed, clean up
  70. if (glpsrvr)
  71. {
  72. LocalUnlock(ghServer);
  73. glpsrvr = NULL;
  74. }
  75. if (ghServer)
  76. LocalFree(ghServer);
  77. ghServer = NULL;
  78. return FALSE;
  79. }
  80. /* DeleteServer() - Revokes the OLE server.
  81. */
  82. VOID
  83. DeleteServer(
  84. LPSAMPSRVR lpsrvr
  85. )
  86. {
  87. if (gfServer)
  88. {
  89. gfServer = FALSE;
  90. OleRevokeServer(lpsrvr->lhsrvr);
  91. }
  92. }
  93. /* DestroyServer() - Deallocates the OLE server.
  94. */
  95. VOID
  96. DestroyServer(
  97. VOID
  98. )
  99. {
  100. if (ghServer)
  101. {
  102. // Release the server virtual table and info
  103. LocalUnlock(ghServer);
  104. LocalFree(ghServer);
  105. ghServer = NULL;
  106. // Destroy the window only when we're all through
  107. DestroyWindow(ghwndFrame);
  108. gfServer = FALSE;
  109. }
  110. }
  111. /********************* Document support functions ********************/
  112. /* InitDoc() - Initialize and register the document with the OLE library.
  113. */
  114. LPSAMPDOC
  115. InitDoc(
  116. LPSAMPSRVR lpsrvr,
  117. LHSERVERDOC lhdoc,
  118. LPSTR lptitle
  119. )
  120. {
  121. HANDLE hdoc = NULL;
  122. LPSAMPDOC lpdoc = NULL;
  123. if (!(hdoc = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, sizeof(PBDOC)))
  124. || !(lpdoc = (LPSAMPDOC)LocalLock(hdoc)))
  125. goto errRtn;
  126. lpdoc->hdoc = hdoc;
  127. lpdoc->aName = GlobalAddAtom(lptitle);
  128. lpdoc->oledoc.lpvtbl = &vdocvtbl;
  129. if (!lhdoc)
  130. {
  131. if (Error(OleRegisterServerDoc(lpsrvr->lhsrvr, lptitle,
  132. (LPOLESERVERDOC)lpdoc, (LHSERVERDOC * ) & lpdoc->lhdoc)))
  133. goto errRtn;
  134. }
  135. else
  136. {
  137. lpdoc->lhdoc = lhdoc;
  138. }
  139. gfDocExists = TRUE;
  140. gfDocCleared = FALSE;
  141. return lpdoc;
  142. errRtn:
  143. ErrorMessage(E_FAILED_TO_REGISTER_DOCUMENT);
  144. // Clean up
  145. if (lpdoc)
  146. LocalUnlock(hdoc);
  147. if (hdoc)
  148. LocalFree(hdoc);
  149. return NULL;
  150. }
  151. /* DeleteDoc() - Notify the OLE library that the document is to be deleted.
  152. */
  153. static VOID
  154. DeleteDoc(
  155. LPSAMPDOC lpdoc
  156. )
  157. {
  158. if (gfOleClosed)
  159. SendDocChangeMsg(lpdoc, OLE_CLOSED);
  160. OleRevokeServerDoc(lpdoc->lhdoc);
  161. }
  162. /* ChangeDocName() - Notify the OLE library that the document name is changing.
  163. */
  164. VOID
  165. ChangeDocName(
  166. LPSAMPDOC *lplpdoc,
  167. LPSTR lpname
  168. )
  169. {
  170. // If the document exists, delete and re-register.
  171. if (*lplpdoc)
  172. {
  173. GlobalDeleteAtom((*lplpdoc)->aName);
  174. (*lplpdoc)->aName = GlobalAddAtom(lpname);
  175. //
  176. // If the document contains items, just notify the children.
  177. // If we aren't embedded, always delete and re-register.
  178. //
  179. OleRenameServerDoc((*lplpdoc)->lhdoc, lpname);
  180. if (gfEmbedded && cItems)
  181. return;
  182. DeleteDoc(*lplpdoc);
  183. }
  184. *lplpdoc = InitDoc(glpsrvr, 0, lpname);
  185. }
  186. /* SendDocChangeMsg() - Notify the client that the document has changed.
  187. */
  188. BOOL
  189. SendDocChangeMsg(
  190. LPSAMPDOC lpdoc,
  191. UINT options
  192. )
  193. {
  194. BOOL fSuccess = FALSE;
  195. INT i;
  196. for (i = 0; i < cItems; i++)
  197. {
  198. if (SendItemChangeMsg(vlpitem[i], options))
  199. fSuccess = TRUE;
  200. }
  201. return fSuccess;
  202. }
  203. /* CreateNewDoc() - Called when a document is newly created.
  204. *
  205. * Returns: hDocument if document successfully created, NULL otherwise.
  206. * Note: This function is only called when the document is being
  207. * created through OLE actions.
  208. */
  209. LPSAMPDOC
  210. CreateNewDoc(
  211. LPSAMPSRVR lpsrvr,
  212. LHSERVERDOC lhdoc,
  213. LPSTR lpstr
  214. )
  215. {
  216. glpdoc = InitDoc(lpsrvr, lhdoc, lpstr);
  217. StringCchCopy(szUntitled, ARRAYSIZE(szUntitled), lpstr);
  218. SetTitle(TRUE);
  219. return glpdoc;
  220. }
  221. /* CreateDocFromFile() - Called when a document is to be created from a file.
  222. *
  223. * Returns: hDocument if document successfully created, NULL otherwise.
  224. * Note: This function is only called when the document is being
  225. * created through OLE actions. The file name is temporarily
  226. * set to load the file, then it is reset to "". This is so
  227. * that we won't save back to the template if we exit.
  228. */
  229. LPSAMPDOC
  230. CreateDocFromFile(
  231. LPSAMPSRVR lpsrvr,
  232. LHSERVERDOC lhdoc,
  233. LPSTR lpstr
  234. )
  235. {
  236. // Initialize document
  237. if (!(glpdoc = InitDoc(lpsrvr, lhdoc, lpstr)) || !(*lpstr))
  238. return NULL;
  239. lstrcpy(szUntitled, lpstr); // This could overrun, but I don't see how I can check the length of the lpstr coming in
  240. SetTitle(TRUE);
  241. return glpdoc;
  242. }
  243. /********************** Item support functions ************************/
  244. /* CopyObjects() - Copies selection to the clipboard.
  245. */
  246. BOOL
  247. CopyObjects(
  248. VOID
  249. )
  250. {
  251. HANDLE hdata;
  252. // If we can't open the clipboard, fail
  253. if (!OpenClipboard(ghwndFrame))
  254. return FALSE;
  255. Hourglass(TRUE);
  256. // Empty the clipboard
  257. EmptyClipboard();
  258. //
  259. // Copy the clipboard contents.
  260. //
  261. // Start with Native Data - which will just contain all the objects
  262. // which intersect with the selection rectangle.
  263. //
  264. if (hdata = GetNative(TRUE))
  265. {
  266. SetClipboardData(gcfNative, hdata);
  267. OleSavedClientDoc(lhClipDoc);
  268. }
  269. if (lhClipDoc)
  270. {
  271. OleRevokeClientDoc(lhClipDoc);
  272. lhClipDoc = 0;
  273. }
  274. if (hdata = GetLink())
  275. SetClipboardData(gcfOwnerLink, hdata);
  276. //
  277. // Metafile data: Re-invert the image before putting
  278. // it onto the clipboard.
  279. //
  280. if (hdata = GetMF())
  281. SetClipboardData(CF_METAFILEPICT, hdata);
  282. CloseClipboard();
  283. Hourglass(FALSE);
  284. return TRUE;
  285. }
  286. /* CreateNewItem() - Allocate a new item.
  287. *
  288. * Note: lpitem->rc will be filled out by the caller.
  289. */
  290. LPSAMPITEM
  291. CreateNewItem(
  292. LPSAMPDOC lpdoc
  293. )
  294. {
  295. HANDLE hitem = NULL;
  296. LPSAMPITEM lpitem = NULL;
  297. // Now create the item
  298. if (!(hitem = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof(ITEM)))
  299. || !(lpitem = (LPSAMPITEM)GlobalLock(hitem)))
  300. goto errRtn;
  301. lpitem->hitem = hitem;
  302. lpitem->oleobject.lpvtbl = &vitemvtbl;
  303. return lpitem;
  304. errRtn:
  305. if (lpitem)
  306. GlobalUnlock(hitem);
  307. if (hitem)
  308. GlobalFree(hitem);
  309. return NULL;
  310. }
  311. /* SendItemChangeMsg() - Notify the client that the item has changed.
  312. */
  313. static BOOL
  314. SendItemChangeMsg(
  315. LPSAMPITEM lpitem,
  316. UINT options
  317. )
  318. {
  319. if (lpitem->lpoleclient)
  320. {
  321. (*lpitem->lpoleclient->lpvtbl->CallBack)
  322. (lpitem->lpoleclient, options, (LPOLEOBJECT)lpitem);
  323. return TRUE;
  324. }
  325. return FALSE;
  326. }
  327. /******************** Data reading/writing functions *********************/
  328. /* GetNative(fClip) - Write the item native format to a memory block.
  329. *
  330. * This function will just write the objects which intersect
  331. * with the selection rectangle into a memory block. If we
  332. * are running as an embedded instance, return ALL items, even
  333. * those which are not in the selection area. Then we will
  334. * never lose objects that we move out of the selection area
  335. * when editing an embedded object.
  336. *
  337. * Args: fClip - TRUE means native data is for copying to clipboard
  338. *
  339. * Returns: A handle containing the native format, or NULL.
  340. */
  341. HANDLE
  342. GetNative(
  343. BOOL fClip
  344. )
  345. {
  346. BOOL fSuccess = FALSE;
  347. DWORD cBytes = 0L;
  348. HANDLE hdata = NULL;
  349. LPSTR lpdata = NULL;
  350. DWORD cEmbWrite;
  351. LPOLEOBJECT lpobjapp = NULL;
  352. LPOLEOBJECT lpobjcon = NULL;
  353. LPPICT lpcPict;
  354. LPPICT lpaPict;
  355. WORD w;
  356. // Compute the size of the appearance
  357. lpaPict = glpobj[APPEARANCE];
  358. lpcPict = glpobj[CONTENT];
  359. switch (gpty[APPEARANCE])
  360. {
  361. case ICON:
  362. cBytes += IconWriteToNative(glpobj[APPEARANCE], NULL);
  363. break;
  364. case PICTURE:
  365. if (fClip)
  366. {
  367. if (Error(OleRegisterClientDoc(
  368. gszAppClassName, szClip, 0L, &lhClipDoc)))
  369. goto Error;
  370. if (Error(OleClone(
  371. lpaPict->lpObject, glpclient, lhClipDoc,
  372. szAppearance, &lpobjapp)))
  373. goto Error;
  374. cBytes += PicWriteToNative(lpaPict, lpobjapp, NULL);
  375. }
  376. else
  377. {
  378. cBytes += PicWriteToNative(lpaPict, lpaPict->lpObject, NULL);
  379. }
  380. break;
  381. default:
  382. break;
  383. }
  384. // Compute the content size
  385. switch (gpty[CONTENT])
  386. {
  387. case CMDLINK:
  388. cBytes += CmlWriteToNative(glpobj[CONTENT], NULL);
  389. break;
  390. case PEMBED: /* EmbWrite returns -1L if the user cancels */
  391. cEmbWrite = EmbWriteToNative(glpobj[CONTENT], NULL);
  392. if (cEmbWrite == (DWORD) - 1L)
  393. return FALSE;
  394. cBytes += cEmbWrite;
  395. break;
  396. case PICTURE:
  397. if (fClip)
  398. {
  399. if (!lhClipDoc && (Error(OleRegisterClientDoc(
  400. gszAppClassName, szClip, 0L, &lhClipDoc))))
  401. goto Error;
  402. if (Error(OleClone(lpcPict->lpObject, glpclient,
  403. lhClipDoc, szContent, &lpobjcon)))
  404. goto Error;
  405. cBytes += PicWriteToNative(lpcPict, lpobjcon, NULL);
  406. }
  407. else
  408. {
  409. cBytes += PicWriteToNative(lpcPict, lpcPict->lpObject, NULL);
  410. }
  411. break;
  412. default:
  413. break;
  414. }
  415. if (cBytes == 0L) // then no data
  416. goto Error;
  417. cBytes += (DWORD)(2 * sizeof(WORD));
  418. // Allocate a memory block for the data
  419. if (!(hdata = GlobalAlloc(GMEM_ZEROINIT, cBytes)) ||
  420. !(lpdata = (LPSTR)GlobalLock(hdata)))
  421. goto Error;
  422. // Write out the appearance
  423. w = (WORD)gpty[APPEARANCE];
  424. MemWrite(&lpdata, (LPSTR)&w, sizeof(WORD));
  425. switch (gpty[APPEARANCE])
  426. {
  427. case ICON:
  428. IconWriteToNative(glpobj[APPEARANCE], &lpdata);
  429. break;
  430. case PICTURE:
  431. if (fClip)
  432. PicWriteToNative(lpaPict, lpobjapp, &lpdata);
  433. else
  434. PicWriteToNative(lpaPict, lpaPict->lpObject, &lpdata);
  435. break;
  436. default:
  437. break;
  438. }
  439. // Write out the content
  440. w = (WORD)gpty[CONTENT];
  441. MemWrite(&lpdata, (LPSTR)&w, sizeof(WORD));
  442. switch (gpty[CONTENT])
  443. {
  444. case CMDLINK:
  445. CmlWriteToNative(glpobj[CONTENT], &lpdata);
  446. break;
  447. case PEMBED:
  448. EmbWriteToNative(glpobj[CONTENT], &lpdata);
  449. break;
  450. case PICTURE:
  451. if (fClip)
  452. PicWriteToNative(lpcPict, lpobjcon, &lpdata);
  453. else
  454. PicWriteToNative(lpcPict, lpcPict->lpObject, &lpdata);
  455. break;
  456. default:
  457. break;
  458. }
  459. fSuccess = TRUE;
  460. Error:
  461. if (lpobjcon)
  462. OleRelease (lpobjcon);
  463. if (lpobjapp)
  464. OleRelease (lpobjapp);
  465. if (lpdata)
  466. GlobalUnlock(hdata);
  467. if (!fSuccess && hdata)
  468. {
  469. GlobalFree(hdata);
  470. hdata = NULL;
  471. }
  472. return hdata;
  473. }
  474. /* PutNative() - Read the item native data from a selector.
  475. *
  476. * Reads as many objects as it can, in upwards order (better error recovery).
  477. * Note: It may be worthwhile to scale the object(s) to the window here.
  478. *
  479. * Returns: TRUE iff successful.
  480. */
  481. BOOL
  482. PutNative(
  483. HANDLE hdata
  484. )
  485. {
  486. BOOL fSuccess = FALSE;
  487. LPSTR lpdata;
  488. WORD w;
  489. if (!(lpdata = (LPSTR)GlobalLock(hdata)))
  490. goto Error;
  491. // Delete any previous panes
  492. DeletePane(APPEARANCE, TRUE);
  493. DeletePane(CONTENT, TRUE);
  494. // Read in the appearance
  495. MemRead(&lpdata, (LPSTR)&w, sizeof(WORD));
  496. gpty[APPEARANCE] = w;
  497. switch (gpty[APPEARANCE])
  498. {
  499. case ICON:
  500. if (!(glpobj[APPEARANCE] = IconReadFromNative(&lpdata)))
  501. gpty[APPEARANCE] = NOTHING;
  502. break;
  503. case PICTURE:
  504. if (glpobj[APPEARANCE] =
  505. PicReadFromNative(&lpdata, gszCaption[APPEARANCE]))
  506. {
  507. SendMessage(ghwndPane[APPEARANCE], WM_FIXSCROLL, 0, 0L);
  508. break;
  509. }
  510. default:
  511. gpty[APPEARANCE] = NOTHING;
  512. break;
  513. }
  514. // Read the content
  515. MemRead(&lpdata, (LPSTR)&w, sizeof(WORD));
  516. gpty[CONTENT] = w;
  517. switch (gpty[CONTENT])
  518. {
  519. case CMDLINK:
  520. if (!(glpobj[CONTENT] = CmlReadFromNative(&lpdata)))
  521. gpty[CONTENT] = NOTHING;
  522. break;
  523. case PEMBED:
  524. if (!(glpobj[CONTENT] = (LPVOID)EmbReadFromNative(&lpdata)))
  525. gpty[CONTENT] = NOTHING;
  526. break;
  527. case PICTURE:
  528. if (glpobj[CONTENT] =
  529. (LPVOID)PicReadFromNative(&lpdata, gszCaption[CONTENT]))
  530. {
  531. SendMessage(ghwndPane[CONTENT], WM_FIXSCROLL, 0, 0L);
  532. EnableWindow(ghwndPict, TRUE);
  533. break;
  534. }
  535. default:
  536. gpty[CONTENT] = NOTHING;
  537. break;
  538. }
  539. fSuccess = TRUE;
  540. InvalidateRect(ghwndFrame, NULL, TRUE);
  541. Error:
  542. if (lpdata)
  543. GlobalUnlock(hdata);
  544. return fSuccess;
  545. }
  546. /* GetLink() - Retrieves ObjectLink/OwnerLink information.
  547. *
  548. * This function returns a string describing the selected area.
  549. */
  550. HANDLE
  551. GetLink(
  552. VOID
  553. )
  554. {
  555. CHAR pchlink[CBLINKMAX];
  556. INT cblink;
  557. HANDLE hlink;
  558. LPSTR lplink;
  559. // Link data - <App name>\0<Doc name>\0<Item name>\0\0
  560. StringCchCopy((LPSTR)pchlink, ARRAYSIZE(pchlink), gszAppClassName); // ok const
  561. cblink = lstrlen((LPSTR)pchlink) + 1;
  562. // Copy the file name
  563. StringCchCopy((LPSTR)(pchlink + cblink), ARRAYSIZE(pchlink) - cblink, szDummy); // szDummy size = 20
  564. cblink += lstrlen((LPSTR)(pchlink + cblink)) + 1;
  565. // Copy the item name
  566. StringCchCopy((LPSTR)(pchlink + cblink), ARRAYSIZE(pchlink) - cblink, szDummy);
  567. cblink += lstrlen((LPSTR)(pchlink + cblink)) + 1;
  568. pchlink[cblink++] = 0; /* throw in another NULL at the end */
  569. // Allocate a memory block for the data
  570. if (!(hlink = GlobalAlloc(GMEM_ZEROINIT, cblink)) ||
  571. !(lplink = (LPSTR)GlobalLock(hlink)))
  572. goto Error;
  573. // Copy the data, then return the memory block
  574. MemWrite(&lplink, (LPSTR)pchlink, cblink);
  575. GlobalUnlock(hlink);
  576. return hlink;
  577. Error:
  578. if (hlink)
  579. GlobalFree(hlink);
  580. return NULL;
  581. }
  582. /* GetMF() - Retrieve a metafile of the selected area.
  583. *
  584. * Note: Originally, tried to Blt directly from the Window DC. This
  585. * doesn't work very well because when the window is obscured,
  586. * the obscured portion shows up when the link is updated.
  587. */
  588. HANDLE
  589. GetMF(
  590. VOID
  591. )
  592. {
  593. BOOL fError = TRUE;
  594. HANDLE hdata = NULL;
  595. HDC hdcMF = NULL;
  596. HDC hdcWnd = NULL;
  597. HFONT hfont;
  598. HANDLE hmfpict;
  599. LPMETAFILEPICT lpmfpict;
  600. LPIC lpic;
  601. LPPICT lppict;
  602. RECT rcTemp;
  603. RECT rcText;
  604. INT cxImage;
  605. INT cyImage;
  606. hmfpict = GlobalAlloc(GMEM_ZEROINIT, sizeof(METAFILEPICT));
  607. if (!hmfpict)
  608. goto Error;
  609. lpmfpict = (LPMETAFILEPICT)GlobalLock(hmfpict);
  610. // If the picture has a metafile, use it!
  611. if (gpty[APPEARANCE] == PICTURE)
  612. {
  613. LPMETAFILEPICT lpmfpictOrg = NULL;
  614. if (Error(OleGetData(
  615. ((LPPICT)glpobj[APPEARANCE])->lpObject, CF_METAFILEPICT, &hdata))
  616. || !hdata
  617. || !(lpmfpictOrg = (LPMETAFILEPICT)GlobalLock(hdata)))
  618. goto NoPicture;
  619. // Copy the metafile
  620. lpmfpict->hMF = CopyMetaFile(lpmfpictOrg->hMF, NULL);
  621. GlobalUnlock(hdata);
  622. // If we failed, just draw it
  623. if (!lpmfpict->hMF)
  624. goto NoPicture;
  625. // Finish filling in the metafile header
  626. lpmfpict->mm = lpmfpictOrg->mm;
  627. lpmfpict->xExt = lpmfpictOrg->xExt;
  628. lpmfpict->yExt = lpmfpictOrg->yExt;
  629. GlobalUnlock(hmfpict);
  630. return hmfpict;
  631. }
  632. NoPicture:
  633. // Get the window DC, and make a DC compatible to it.
  634. if (!(hdcWnd = GetDC(NULL)))
  635. goto Error;
  636. switch (gpty[APPEARANCE])
  637. {
  638. case ICON:
  639. lpic = (LPIC)glpobj[APPEARANCE];
  640. // Set the icon text rectangle, and the icon font
  641. SetRect(&rcText, 0, 0, gcxArrange, gcyArrange);
  642. hfont = SelectObject(hdcWnd, ghfontTitle);
  643. // Figure out how large the text region will be
  644. // since this is going in a metafile we will not wrap
  645. // the icon text
  646. DrawText(hdcWnd, lpic->szIconText, -1, &rcText,
  647. DT_CALCRECT | DT_WORDBREAK | DT_NOPREFIX | DT_SINGLELINE);
  648. if (hfont)
  649. SelectObject(hdcWnd, hfont);
  650. // Compute the image size
  651. rcText.right++;
  652. cxImage = (rcText.right > gcxIcon) ? rcText.right : gcxIcon;
  653. cyImage = gcyIcon + rcText.bottom + 1;
  654. break;
  655. case PICTURE:
  656. lppict = (LPPICT)glpobj[APPEARANCE];
  657. cxImage = lppict->rc.right - lppict->rc.left + 1;
  658. cyImage = lppict->rc.bottom - lppict->rc.top + 1;
  659. break;
  660. default:
  661. cxImage = GetSystemMetrics(SM_CXICON);
  662. cyImage = GetSystemMetrics(SM_CYICON);
  663. break;
  664. }
  665. cxImage += cxImage / 4; // grow the image a bit
  666. cyImage += cyImage / 8;
  667. // Create the metafile
  668. if (!(hdcMF = CreateMetaFile(NULL)))
  669. goto Error;
  670. // Initialize the metafile
  671. SetWindowOrgEx(hdcMF, 0, 0, NULL);
  672. SetWindowExtEx(hdcMF, cxImage - 1, cyImage - 1, NULL);
  673. //
  674. // Fill in the background
  675. //
  676. // We displace back to (0, 0) because that's where the BITMAP resides.
  677. //
  678. SetRect(&rcTemp, 0, 0, cxImage, cyImage);
  679. switch (gpty[APPEARANCE])
  680. {
  681. case ICON:
  682. IconDraw(glpobj[APPEARANCE], hdcMF, &rcTemp, FALSE, cxImage, cyImage);
  683. break;
  684. case PICTURE:
  685. PicDraw(glpobj[APPEARANCE], hdcMF, &rcTemp, 0, 0, TRUE, FALSE);
  686. break;
  687. default:
  688. DrawIcon(hdcMF, 0, 0, LoadIcon(ghInst, MAKEINTRESOURCE(ID_APPLICATION)));
  689. break;
  690. }
  691. // Map to device independent coordinates
  692. rcTemp.right =
  693. MulDiv((rcTemp.right - rcTemp.left), HIMETRIC_PER_INCH, giXppli);
  694. rcTemp.bottom =
  695. MulDiv((rcTemp.bottom - rcTemp.top), HIMETRIC_PER_INCH, giYppli);
  696. // Finish filling in the metafile header
  697. lpmfpict->mm = MM_ANISOTROPIC;
  698. lpmfpict->xExt = rcTemp.right;
  699. lpmfpict->yExt = rcTemp.bottom;
  700. lpmfpict->hMF = CloseMetaFile(hdcMF);
  701. fError = FALSE;
  702. Error:
  703. if (hdcWnd)
  704. ReleaseDC(NULL, hdcWnd);
  705. // If we had an error, return NULL
  706. if (fError && hmfpict)
  707. {
  708. GlobalUnlock(hmfpict);
  709. GlobalFree(hmfpict);
  710. hmfpict = NULL;
  711. }
  712. return hmfpict;
  713. }
  714. /* InitEmbedded() - Perform operations specific to editing embedded objects.
  715. *
  716. * This routine changes the menu items as appropriate.
  717. */
  718. VOID
  719. InitEmbedded(
  720. BOOL fCreate
  721. )
  722. {
  723. HMENU hmenu;
  724. if (hmenu = GetMenu(ghwndFrame))
  725. EnableMenuItem(hmenu, IDM_UPDATE, fCreate ? MF_GRAYED : MF_ENABLED);
  726. gfEmbedded = TRUE;
  727. }
  728. /***************** Item circular queue/utility functions *****************/
  729. /* AddItem() - Add an item to the global item list.
  730. */
  731. LPSAMPITEM
  732. AddItem(
  733. LPSAMPITEM lpitem
  734. )
  735. {
  736. INT i;
  737. HANDLE hitem;
  738. i = FindItem((LPSAMPITEM)lpitem);
  739. if (i < cItems)
  740. {
  741. vlpitem[i]->ref++;
  742. // Free the duplicate item
  743. GlobalUnlock(hitem = lpitem->hitem);
  744. GlobalFree(hitem);
  745. }
  746. else
  747. {
  748. if (i < CITEMSMAX)
  749. {
  750. vlpitem[cItems] = (LPSAMPITEM)lpitem;
  751. vlpitem[cItems++]->ref = 1;
  752. }
  753. else
  754. {
  755. return NULL;
  756. }
  757. }
  758. return vlpitem[i];
  759. }
  760. /* DeleteItem() - Delete an item from the global item list.
  761. *
  762. * Returns: TRUE iff successful.
  763. */
  764. BOOL
  765. DeleteItem(
  766. LPSAMPITEM lpitem
  767. )
  768. {
  769. BOOL fFound;
  770. HANDLE hitem;
  771. INT i;
  772. i = FindItem(lpitem);
  773. if ((fFound = (i < cItems && vlpitem[i]->ref))
  774. && !(--vlpitem[i]->ref))
  775. {
  776. // Free the item
  777. GlobalUnlock(hitem = vlpitem[i]->hitem);
  778. GlobalFree(hitem);
  779. // Shift everything else down
  780. cItems--;
  781. for ( ; i < cItems; i++)
  782. vlpitem[i] = vlpitem[i + 1];
  783. }
  784. return fFound;
  785. }
  786. /* FindItem() - Locate an item in the global item list.
  787. */
  788. static INT
  789. FindItem(
  790. LPSAMPITEM lpitem
  791. )
  792. {
  793. BOOL fFound = FALSE;
  794. INT i;
  795. for (i = 0; i < cItems && !fFound;)
  796. {
  797. if (lpitem->aName == vlpitem[i]->aName)
  798. {
  799. fFound = TRUE;
  800. }
  801. else
  802. {
  803. i++;
  804. }
  805. }
  806. return i;
  807. }
  808. /* EndEmbedding() - Return to normal editing.
  809. *
  810. * This routine changes the menu items as appropriate.
  811. */
  812. VOID
  813. EndEmbedding(
  814. VOID
  815. )
  816. {
  817. HMENU hmenu;
  818. // Fix the "Untitled" string
  819. LoadString(ghInst, IDS_UNTITLED, szUntitled, CBMESSAGEMAX);
  820. if (hmenu = GetMenu(ghwndFrame))
  821. EnableMenuItem(hmenu, IDM_UPDATE, MF_GRAYED);
  822. gfEmbedded = FALSE;
  823. }