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.

1713 lines
59 KiB

  1. /*
  2. * PASTESPL.C
  3. *
  4. * Implements the OleUIPasteSpecial function which invokes the complete
  5. * Paste Special dialog.
  6. *
  7. * Copyright (c)1992 Microsoft Corporation, All Rights Reserved
  8. */
  9. #define STRICT 1
  10. #include "ole2ui.h"
  11. #include "pastespl.h"
  12. #include "common.h"
  13. #include "utility.h"
  14. #include "resimage.h"
  15. #include "iconbox.h"
  16. #include "geticon.h"
  17. #include "icon.h"
  18. #include "regdb.h"
  19. #include <stdlib.h>
  20. OLEDBGDATA
  21. /*
  22. * OleUIPasteSpecial
  23. *
  24. * Purpose:
  25. * Invokes the standard OLE Paste Special dialog box which allows the user
  26. * to select the format of the clipboard object to be pasted or paste linked.
  27. *
  28. * Parameters:
  29. * lpPS LPOLEUIPasteSpecial pointing to the in-out structure
  30. * for this dialog.
  31. *
  32. * Return Value:
  33. * UINT One of the following codes or one of the standard error codes (OLEUI_ERR_*)
  34. * defined in OLE2UI.H, indicating success or error:
  35. * OLEUI_OK User selected OK
  36. * OLEUI_CANCEL User cancelled the dialog
  37. * OLEUI_IOERR_SRCDATAOBJECTINVALID lpSrcDataObject field of OLEUIPASTESPECIAL invalid
  38. * OLEUI_IOERR_ARRPASTEENTRIESINVALID arrPasteEntries field of OLEUIPASTESPECIAL invalid
  39. * OLEUI_IOERR_ARRLINKTYPESINVALID arrLinkTypes field of OLEUIPASTESPECIAL invalid
  40. * OLEUI_PSERR_CLIPBOARDCHANGED Clipboard contents changed while dialog was up
  41. */
  42. STDAPI_(UINT) OleUIPasteSpecial(LPOLEUIPASTESPECIAL lpPS)
  43. {
  44. UINT uRet;
  45. HGLOBAL hMemDlg=NULL;
  46. uRet=UStandardValidation((LPOLEUISTANDARD)lpPS, sizeof(OLEUIPASTESPECIAL)
  47. , &hMemDlg);
  48. if (uRet != OLEUI_SUCCESS)
  49. return uRet;
  50. //Validate PasteSpecial specific fields
  51. if (NULL == lpPS->lpSrcDataObj || IsBadReadPtr(lpPS->lpSrcDataObj, sizeof(IDataObject)))
  52. uRet = OLEUI_IOERR_SRCDATAOBJECTINVALID;
  53. if (NULL == lpPS->arrPasteEntries || IsBadReadPtr(lpPS->arrPasteEntries, sizeof(OLEUIPASTEENTRY)))
  54. uRet = OLEUI_IOERR_ARRPASTEENTRIESINVALID;
  55. if (NULL != lpPS->arrLinkTypes && IsBadReadPtr(lpPS->arrLinkTypes, sizeof(UINT)))
  56. uRet = OLEUI_IOERR_ARRLINKTYPESINVALID;
  57. if (0!=lpPS->cClsidExclude)
  58. {
  59. if (NULL!=lpPS->lpClsidExclude && IsBadReadPtr(lpPS->lpClsidExclude
  60. , lpPS->cClsidExclude*sizeof(CLSID)))
  61. uRet=OLEUI_IOERR_LPCLSIDEXCLUDEINVALID;
  62. }
  63. if (uRet >= OLEUI_ERR_STANDARDMIN)
  64. {
  65. if (NULL != hMemDlg)
  66. FreeResource(hMemDlg);
  67. return uRet;
  68. }
  69. //Now that we've validated everything, we can invoke the dialog.
  70. uRet = UStandardInvocation(PasteSpecialDialogProc, (LPOLEUISTANDARD)lpPS
  71. , hMemDlg, MAKEINTRESOURCE(IDD_PASTESPECIAL));
  72. /*
  73. * IF YOU ARE CREATING ANYTHING BASED ON THE RESULTS, DO IT HERE.
  74. */
  75. return uRet;
  76. }
  77. /*
  78. * PasteSpecialDialogProc
  79. *
  80. * Purpose:
  81. * Implements the OLE Paste Special dialog as invoked through the
  82. * OleUIPasteSpecial function.
  83. *
  84. * Parameters:
  85. * Standard
  86. *
  87. * Return Value:
  88. * Standard
  89. */
  90. BOOL CALLBACK EXPORT PasteSpecialDialogProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
  91. {
  92. LPOLEUIPASTESPECIAL lpOPS;
  93. LPPASTESPECIAL lpPS;
  94. BOOL fHook=FALSE;
  95. HCURSOR hCursorOld;
  96. //Declare Win16/Win32 compatible WM_COMMAND parameters.
  97. COMMANDPARAMS(wID, wCode, hWndMsg);
  98. //This will fail under WM_INITDIALOG, where we allocate it.
  99. lpPS=(LPPASTESPECIAL)LpvStandardEntry(hDlg, iMsg, wParam, lParam, &fHook);
  100. //If the hook processed the message, we're done.
  101. if (0!=fHook)
  102. return fHook;
  103. // Process help message from Change Icon
  104. if (iMsg == uMsgHelp)
  105. {
  106. PostMessage(lpPS->lpOPS->hWndOwner, uMsgHelp, wParam, lParam);
  107. return FALSE;
  108. }
  109. //Process the temination message
  110. if (iMsg==uMsgEndDialog)
  111. {
  112. HWND hwndNextViewer;
  113. // Free the icon/icon-title metafile corresponding to Paste/PasteList option which is not selected
  114. if (lpPS->fLink)
  115. OleUIMetafilePictIconFree(lpPS->hMetaPictOD);
  116. else OleUIMetafilePictIconFree(lpPS->hMetaPictLSD);
  117. // Free data associated with each list box entry
  118. FreeListData(GetDlgItem(hDlg, ID_PS_PASTELIST));
  119. FreeListData(GetDlgItem(hDlg, ID_PS_PASTELINKLIST));
  120. //Free any specific allocations before calling StandardCleanup
  121. if (lpPS->hObjDesc) GlobalFree(lpPS->hObjDesc);
  122. if (lpPS->hLinkSrcDesc) GlobalFree(lpPS->hLinkSrcDesc);
  123. if (lpPS->hBuff) GlobalFree(lpPS->hBuff);
  124. // Change the clipboard notification chain
  125. hwndNextViewer = GetProp(hDlg, NEXTCBVIEWER);
  126. if (hwndNextViewer != HWND_BROADCAST)
  127. {
  128. SetProp(hDlg, NEXTCBVIEWER, HWND_BROADCAST);
  129. ChangeClipboardChain(hDlg, hwndNextViewer);
  130. }
  131. RemoveProp(hDlg, NEXTCBVIEWER);
  132. StandardCleanup(lpPS, hDlg);
  133. EndDialog(hDlg, wParam);
  134. return TRUE;
  135. }
  136. switch (iMsg)
  137. {
  138. case WM_INITDIALOG:
  139. hCursorOld = HourGlassOn();
  140. FPasteSpecialInit(hDlg, wParam, lParam);
  141. HourGlassOff(hCursorOld);
  142. return FALSE;
  143. case WM_DRAWCLIPBOARD:
  144. {
  145. HWND hwndNextViewer = GetProp(hDlg, NEXTCBVIEWER);
  146. HWND hDlg_ChgIcon;
  147. if (hwndNextViewer == HWND_BROADCAST)
  148. break;
  149. if (hwndNextViewer)
  150. {
  151. SendMessage(hwndNextViewer, iMsg, wParam, lParam);
  152. // Refresh next viewer in case it got modified
  153. // by the SendMessage() (likely if multiple
  154. // PasteSpecial dialogs are up simultaneously)
  155. hwndNextViewer = GetProp(hDlg, NEXTCBVIEWER);
  156. }
  157. SetProp(hDlg, NEXTCBVIEWER, HWND_BROADCAST);
  158. ChangeClipboardChain(hDlg, hwndNextViewer);
  159. /* OLE2NOTE: if the ChangeIcon dialog is currently up, then
  160. ** we need to defer bringing down PasteSpecial dialog
  161. ** until after ChangeIcon dialog returns. if the
  162. ** ChangeIcon dialog is NOT up, then we can bring down
  163. ** the PasteSpecial dialog immediately.
  164. */
  165. if ((hDlg_ChgIcon=(HWND)GetProp(hDlg,PROP_HWND_CHGICONDLG))!=NULL)
  166. {
  167. // ChangeIcon dialog is UP
  168. lpPS->fClipboardChanged = TRUE;
  169. } else {
  170. // ChangeIcon dialog is NOT up
  171. // Free icon and icon title metafile
  172. SendDlgItemMessage(
  173. hDlg, ID_PS_ICONDISPLAY, IBXM_IMAGEFREE, 0, 0L);
  174. SendMessage(
  175. hDlg, uMsgEndDialog, OLEUI_PSERR_CLIPBOARDCHANGED,0L);
  176. }
  177. break;
  178. }
  179. case WM_CHANGECBCHAIN:
  180. {
  181. HWND hwndNextViewer = GetProp(hDlg, NEXTCBVIEWER);
  182. if (wParam == (WORD)hwndNextViewer)
  183. SetProp(hDlg, NEXTCBVIEWER, (hwndNextViewer = (HWND)LOWORD(lParam)));
  184. else if (hwndNextViewer && hwndNextViewer != HWND_BROADCAST)
  185. SendMessage(hwndNextViewer, iMsg, wParam, lParam);
  186. break;
  187. }
  188. case WM_COMMAND:
  189. switch (wID)
  190. {
  191. case ID_PS_PASTE:
  192. FTogglePasteType(hDlg, lpPS, PSF_SELECTPASTE);
  193. break;
  194. case ID_PS_PASTELINK:
  195. FTogglePasteType(hDlg, lpPS, PSF_SELECTPASTELINK);
  196. break;
  197. case ID_PS_DISPLAYLIST:
  198. switch (wCode)
  199. {
  200. case LBN_SELCHANGE:
  201. ChangeListSelection(hDlg, lpPS, hWndMsg);
  202. break;
  203. case LBN_DBLCLK:
  204. // Same as pressing OK
  205. SendCommand(hDlg, IDOK, BN_CLICKED, hWndMsg);
  206. break;
  207. }
  208. break;
  209. case ID_PS_DISPLAYASICON:
  210. ToggleDisplayAsIcon(hDlg, lpPS);
  211. break;
  212. case ID_PS_CHANGEICON:
  213. ChangeIcon(hDlg, lpPS);
  214. if (lpPS->fClipboardChanged) {
  215. // Free icon and icon title metafile
  216. SendDlgItemMessage(
  217. hDlg, ID_PS_ICONDISPLAY, IBXM_IMAGEFREE,0,0L);
  218. SendMessage(
  219. hDlg, uMsgEndDialog,
  220. OLEUI_PSERR_CLIPBOARDCHANGED, 0L);
  221. }
  222. break;
  223. case IDOK:
  224. {
  225. BOOL fDestAspectIcon =
  226. ((lpPS->dwFlags & PSF_CHECKDISPLAYASICON) ?
  227. TRUE : FALSE);
  228. lpOPS = lpPS->lpOPS;
  229. // Return current flags
  230. lpOPS->dwFlags = lpPS->dwFlags;
  231. // Return index of arrPasteEntries[] corresponding to format selected by user
  232. lpOPS->nSelectedIndex = lpPS->nSelectedIndex;
  233. // Return if user selected Paste or PasteLink
  234. lpOPS->fLink = lpPS->fLink;
  235. /* if user selected same ASPECT as displayed in the
  236. ** source, then sizel passed in the
  237. ** ObjectDescriptor/LinkSrcDescriptor is
  238. ** applicable. otherwise, the sizel does not apply.
  239. */
  240. if (lpPS->fLink) {
  241. if (lpPS->fSrcAspectIconLSD == fDestAspectIcon)
  242. lpOPS->sizel = lpPS->sizelLSD;
  243. else
  244. lpOPS->sizel.cx = lpOPS->sizel.cy = 0;
  245. } else {
  246. if (lpPS->fSrcAspectIconOD == fDestAspectIcon)
  247. lpOPS->sizel = lpPS->sizelOD;
  248. else
  249. lpOPS->sizel.cx = lpOPS->sizel.cy = 0;
  250. }
  251. // Return metafile with icon and icon title that the user selected
  252. lpOPS->hMetaPict=(HGLOBAL)SendDlgItemMessage(hDlg, ID_PS_ICONDISPLAY,
  253. IBXM_IMAGEGET, 0, 0L);
  254. SendMessage(hDlg, uMsgEndDialog, OLEUI_OK, 0L);
  255. break;
  256. }
  257. case IDCANCEL:
  258. // Free icon and icon title metafile
  259. SendDlgItemMessage(
  260. hDlg, ID_PS_ICONDISPLAY, IBXM_IMAGEFREE, 0, 0L);
  261. SendMessage(hDlg, uMsgEndDialog, OLEUI_CANCEL, 0L);
  262. break;
  263. case ID_OLEUIHELP:
  264. PostMessage(lpPS->lpOPS->hWndOwner, uMsgHelp,
  265. (WPARAM)hDlg, MAKELPARAM(IDD_PASTESPECIAL, 0));
  266. break;
  267. }
  268. break;
  269. }
  270. return FALSE;
  271. }
  272. /*
  273. * FPasteSpecialInit
  274. *
  275. * Purpose:
  276. * WM_INITIDIALOG handler for the Paste Special dialog box.
  277. *
  278. * Parameters:
  279. * hDlg HWND of the dialog
  280. * wParam WPARAM of the message
  281. * lParam LPARAM of the message
  282. *
  283. * Return Value:
  284. * BOOL Value to return for WM_INITDIALOG.
  285. */
  286. BOOL FPasteSpecialInit(HWND hDlg, WPARAM wParam, LPARAM lParam)
  287. {
  288. LPPASTESPECIAL lpPS;
  289. LPOLEUIPASTESPECIAL lpOPS;
  290. HFONT hFont;
  291. BOOL fPasteAvailable, fPasteLinkAvailable;
  292. STGMEDIUM medium;
  293. LPOBJECTDESCRIPTOR lpOD;
  294. LPLINKSRCDESCRIPTOR lpLSD;
  295. int n;
  296. CLIPFORMAT cfFormat;
  297. // Copy the structure at lParam into our instance memory.
  298. lpPS = (LPPASTESPECIAL)LpvStandardInit(hDlg, sizeof(PASTESPECIAL), TRUE, &hFont);
  299. // PvStandardInit sent a termination to us already.
  300. if (NULL == lpPS)
  301. return FALSE;
  302. lpOPS=(LPOLEUIPASTESPECIAL)lParam;
  303. // Copy other information from lpOPS that we might modify.
  304. lpPS->lpOPS = lpOPS;
  305. lpPS->dwFlags = lpOPS->dwFlags;
  306. // Initialize user selections in the Paste and PasteLink listboxes
  307. lpPS->nPasteListCurSel = 0;
  308. lpPS->nPasteLinkListCurSel = 0;
  309. // If we got a font, send it to the necessary controls.
  310. if (NULL!=hFont)
  311. {
  312. SendDlgItemMessage(hDlg, ID_PS_SOURCETEXT, WM_SETFONT, (WPARAM)hFont, 0L);
  313. SendDlgItemMessage(hDlg, ID_PS_RESULTTEXT, WM_SETFONT, (WPARAM)hFont, 0L);
  314. }
  315. // Hide the help button if required
  316. if (!(lpPS->lpOPS->dwFlags & PSF_SHOWHELP))
  317. StandardShowDlgItem(hDlg, ID_OLEUIHELP, SW_HIDE);
  318. // Hide all DisplayAsIcon related controls if it should be disabled
  319. if ( lpPS->dwFlags & PSF_DISABLEDISPLAYASICON ) {
  320. StandardShowDlgItem(hDlg, ID_PS_DISPLAYASICON, SW_HIDE);
  321. StandardShowDlgItem(hDlg, ID_PS_CHANGEICON, SW_HIDE);
  322. StandardShowDlgItem(hDlg, ID_PS_ICONDISPLAY, SW_HIDE);
  323. }
  324. // PSF_CHECKDISPLAYASICON is an OUT flag. Clear it if has been set on the way in.
  325. lpPS->dwFlags = lpPS->dwFlags & ~PSF_CHECKDISPLAYASICON;
  326. // Change the caption if required
  327. if (NULL != lpOPS->lpszCaption)
  328. SetWindowText(hDlg, lpOPS->lpszCaption);
  329. // Load 'Unknown Source' and 'Unknown Type' strings
  330. n = LoadString(ghInst, IDS_PSUNKNOWNTYPE, lpPS->szUnknownType, PS_UNKNOWNSTRLEN);
  331. if (n)
  332. n = LoadString(ghInst, IDS_PSUNKNOWNSRC, lpPS->szUnknownSource, PS_UNKNOWNSTRLEN);
  333. if (!n)
  334. {
  335. PostMessage(hDlg, uMsgEndDialog, OLEUI_ERR_LOADSTRING, 0L);
  336. return FALSE;
  337. }
  338. lpPS->szAppName[0]=TEXT('\0');
  339. // GetData CF_OBJECTDESCRIPTOR. If the object on the clipboard in an OLE1 object (offering CF_OWNERLINK)
  340. // or has been copied to clipboard by FileMaager (offering CF_FILENAME), an OBJECTDESCRIPTOR will be
  341. // created will be created from CF_OWNERLINK or CF_FILENAME. See OBJECTDESCRIPTOR for more info.
  342. if (lpPS->hObjDesc = OleStdFillObjectDescriptorFromData(lpOPS->lpSrcDataObj, &medium, &cfFormat))
  343. {
  344. lpOD = GlobalLock(lpPS->hObjDesc);
  345. // Get FullUserTypeName, SourceOfCopy and CLSID
  346. if (lpOD->dwFullUserTypeName)
  347. lpPS->szFullUserTypeNameOD = (LPTSTR)lpOD+lpOD->dwFullUserTypeName;
  348. else lpPS->szFullUserTypeNameOD = lpPS->szUnknownType;
  349. if (lpOD->dwSrcOfCopy)
  350. {
  351. lpPS->szSourceOfDataOD = (LPTSTR)lpOD+lpOD->dwSrcOfCopy;
  352. // If CF_FILENAME was offered, source of copy is a path name. Fit the path to the
  353. // static control that will display it.
  354. if (cfFormat == cfFileName)
  355. lpPS->szSourceOfDataOD = ChopText(GetDlgItem(hDlg, ID_PS_SOURCETEXT), 0, lpPS->szSourceOfDataOD);
  356. }
  357. else lpPS->szSourceOfDataOD = lpPS->szUnknownSource;
  358. lpPS->clsidOD = lpOD->clsid;
  359. lpPS->sizelOD = lpOD->sizel;
  360. // Does source specify DVASPECT_ICON?
  361. if (lpOD->dwDrawAspect & DVASPECT_ICON)
  362. lpPS->fSrcAspectIconOD = TRUE;
  363. else lpPS->fSrcAspectIconOD = FALSE;
  364. // Does source specify OLEMISC_ONLYICONIC?
  365. if (lpOD->dwStatus & OLEMISC_ONLYICONIC)
  366. lpPS->fSrcOnlyIconicOD = TRUE;
  367. else lpPS->fSrcOnlyIconicOD = FALSE;
  368. // Get application name of source from auxusertype3 in the registration database
  369. if (0==OleStdGetAuxUserType(&lpPS->clsidOD, 3, lpPS->szAppName, OLEUI_CCHKEYMAX_SIZE, NULL))
  370. {
  371. // Use "the application which created it" as the name of the application
  372. if (0==LoadString(ghInst, IDS_PSUNKNOWNAPP, lpPS->szAppName, PS_UNKNOWNSTRLEN))
  373. {
  374. PostMessage(hDlg, uMsgEndDialog, OLEUI_ERR_LOADSTRING, 0L);
  375. return FALSE;
  376. }
  377. }
  378. // Retrieve an icon from the object
  379. if (lpPS->fSrcAspectIconOD)
  380. {
  381. lpPS->hMetaPictOD = OleStdGetData(
  382. lpOPS->lpSrcDataObj,
  383. (CLIPFORMAT) CF_METAFILEPICT,
  384. NULL,
  385. DVASPECT_ICON,
  386. &medium
  387. );
  388. }
  389. // If object does not offer icon, obtain it from the CLSID
  390. if (NULL == lpPS->hMetaPictOD)
  391. {
  392. #ifdef OLE201
  393. lpPS->hMetaPictOD = GetIconOfClass(
  394. ghInst,
  395. &lpPS->clsidOD,
  396. NULL,
  397. TRUE); // Use the short user type name (auxusertype3)
  398. #endif
  399. lpPS->hMetaPictOD = NULL;
  400. }
  401. }
  402. // Does object offer CF_LINKSRCDESCRIPTOR?
  403. if (lpPS->hLinkSrcDesc = OleStdGetData(
  404. lpOPS->lpSrcDataObj,
  405. (CLIPFORMAT) cfLinkSrcDescriptor,
  406. NULL,
  407. DVASPECT_CONTENT,
  408. &medium))
  409. {
  410. // Get FullUserTypeName, SourceOfCopy and CLSID
  411. lpLSD = GlobalLock(lpPS->hLinkSrcDesc);
  412. if (lpLSD->dwFullUserTypeName)
  413. lpPS->szFullUserTypeNameLSD = (LPTSTR)lpLSD+lpLSD->dwFullUserTypeName;
  414. else lpPS->szFullUserTypeNameLSD = lpPS->szUnknownType;
  415. if (lpLSD->dwSrcOfCopy)
  416. lpPS->szSourceOfDataLSD = (LPTSTR)lpLSD+lpLSD->dwSrcOfCopy;
  417. else lpPS->szSourceOfDataLSD = lpPS->szUnknownSource;
  418. // if no ObjectDescriptor, then use LinkSourceDescriptor source string
  419. if (!lpPS->hObjDesc)
  420. lpPS->szSourceOfDataOD = lpPS->szSourceOfDataLSD;
  421. lpPS->clsidLSD = lpLSD->clsid;
  422. lpPS->sizelLSD = lpLSD->sizel;
  423. // Does source specify DVASPECT_ICON?
  424. if (lpLSD->dwDrawAspect & DVASPECT_ICON)
  425. lpPS->fSrcAspectIconLSD = TRUE;
  426. else lpPS->fSrcAspectIconLSD = FALSE;
  427. // Does source specify OLEMISC_ONLYICONIC?
  428. if (lpLSD->dwStatus & OLEMISC_ONLYICONIC)
  429. lpPS->fSrcOnlyIconicLSD = TRUE;
  430. else lpPS->fSrcOnlyIconicLSD = FALSE;
  431. // Retrieve an icon from the object
  432. if (lpPS->fSrcAspectIconLSD)
  433. {
  434. lpPS->hMetaPictLSD = OleStdGetData(
  435. lpOPS->lpSrcDataObj,
  436. CF_METAFILEPICT,
  437. NULL,
  438. DVASPECT_ICON,
  439. &medium
  440. );
  441. }
  442. // If object does not offer icon, obtain it from the CLSID
  443. if (NULL == lpPS->hMetaPictLSD)
  444. {
  445. TCHAR szLabel[OLEUI_CCHLABELMAX];
  446. HWND hIconWnd;
  447. RECT IconRect;
  448. int nWidth;
  449. LPTSTR lpszLabel;
  450. hIconWnd = GetDlgItem(hDlg, ID_PS_ICONDISPLAY);
  451. GetClientRect(hIconWnd, &IconRect);
  452. nWidth = ((IconRect.right-IconRect.left) * 3) / 2; // width is 1.5 times width of iconbox
  453. LSTRCPYN(szLabel, lpPS->szSourceOfDataLSD, OLEUI_CCHLABELMAX);
  454. szLabel[OLEUI_CCHLABELMAX-1] = TEXT('\0');
  455. lpszLabel = ChopText(hIconWnd, nWidth, (LPTSTR)szLabel);
  456. #ifdef OLE201
  457. lpPS->hMetaPictLSD = GetIconOfClass(
  458. ghInst,
  459. &lpPS->clsidLSD,
  460. lpszLabel, /* use chopped source string as label */
  461. FALSE /* not applicable */
  462. );
  463. #endif
  464. lpPS->hMetaPictLSD = NULL;
  465. }
  466. }
  467. else if (lpPS->hObjDesc) // Does not offer CF_LINKSRCDESCRIPTOR but offers CF_OBJECTDESCRIPTOR
  468. {
  469. // Copy the values of OBJECTDESCRIPTOR
  470. lpPS->szFullUserTypeNameLSD = lpPS->szFullUserTypeNameOD;
  471. lpPS->szSourceOfDataLSD = lpPS->szSourceOfDataOD;
  472. lpPS->clsidLSD = lpPS->clsidOD;
  473. lpPS->sizelLSD = lpPS->sizelOD;
  474. lpPS->fSrcAspectIconLSD = lpPS->fSrcAspectIconOD;
  475. lpPS->fSrcOnlyIconicLSD = lpPS->fSrcOnlyIconicOD;
  476. // Don't copy the hMetaPict; instead get a separate copy
  477. if (lpPS->fSrcAspectIconLSD)
  478. {
  479. lpPS->hMetaPictLSD = OleStdGetData(
  480. lpOPS->lpSrcDataObj,
  481. CF_METAFILEPICT,
  482. NULL,
  483. DVASPECT_ICON,
  484. &medium
  485. );
  486. }
  487. if (NULL == lpPS->hMetaPictLSD)
  488. {
  489. TCHAR szLabel[OLEUI_CCHLABELMAX];
  490. HWND hIconWnd;
  491. RECT IconRect;
  492. int nWidth;
  493. LPTSTR lpszLabel;
  494. hIconWnd = GetDlgItem(hDlg, ID_PS_ICONDISPLAY);
  495. GetClientRect(hIconWnd, &IconRect);
  496. nWidth = ((IconRect.right-IconRect.left) * 3) / 2; // width is 1.5 times width of iconbox
  497. LSTRCPYN(szLabel, lpPS->szSourceOfDataLSD, OLEUI_CCHLABELMAX);
  498. szLabel[OLEUI_CCHLABELMAX-1] = TEXT('\0');
  499. lpszLabel = ChopText(hIconWnd, nWidth, (LPTSTR)szLabel);
  500. #ifdef OLE201
  501. lpPS->hMetaPictLSD = GetIconOfClass(
  502. ghInst,
  503. &lpPS->clsidLSD,
  504. lpszLabel, /* Use chopped source string as label */
  505. FALSE /* Not applicable */
  506. );
  507. #endif
  508. lpPS->hMetaPictLSD = NULL;
  509. }
  510. }
  511. // Not an OLE object
  512. if (lpPS->hObjDesc == NULL && lpPS->hLinkSrcDesc == NULL)
  513. {
  514. lpPS->szFullUserTypeNameLSD = lpPS->szFullUserTypeNameOD = lpPS->szUnknownType;
  515. lpPS->szSourceOfDataLSD = lpPS->szSourceOfDataOD = lpPS->szUnknownSource;
  516. lpPS->hMetaPictLSD = lpPS->hMetaPictOD = NULL;
  517. }
  518. // Allocate scratch memory to construct item names in the paste and pastelink listboxes
  519. lpPS->hBuff = AllocateScratchMem(lpPS);
  520. if (lpPS->hBuff == NULL)
  521. {
  522. PostMessage(hDlg, uMsgEndDialog, OLEUI_ERR_GLOBALMEMALLOC, 0L);
  523. return FALSE;
  524. }
  525. // Select the Paste Link Button if specified. Otherwise select
  526. // Paste Button by default
  527. if (lpPS->dwFlags & PSF_SELECTPASTELINK)
  528. lpPS->dwFlags = (lpPS->dwFlags & ~PSF_SELECTPASTE) | PSF_SELECTPASTELINK;
  529. else
  530. lpPS->dwFlags =(lpPS->dwFlags & ~PSF_SELECTPASTELINK) | PSF_SELECTPASTE;
  531. // Mark which PasteEntry formats are available from source data object
  532. OleStdMarkPasteEntryList(
  533. lpOPS->lpSrcDataObj,lpOPS->arrPasteEntries,lpOPS->cPasteEntries);
  534. // Check if items are available to be pasted
  535. fPasteAvailable = FFillPasteList(hDlg, lpPS);
  536. if (!fPasteAvailable)
  537. {
  538. lpPS->dwFlags &= ~PSF_SELECTPASTE;
  539. EnableWindow(GetDlgItem(hDlg, ID_PS_PASTE), FALSE);
  540. }
  541. // Check if items are available to be paste-linked
  542. fPasteLinkAvailable = FFillPasteLinkList(hDlg, lpPS);
  543. if (!fPasteLinkAvailable)
  544. {
  545. lpPS->dwFlags &= ~PSF_SELECTPASTELINK;
  546. EnableWindow(GetDlgItem(hDlg, ID_PS_PASTELINK), FALSE);
  547. }
  548. // If one of Paste or PasteLink is disabled, select the other one
  549. // regardless of what the input flags say
  550. if (fPasteAvailable && !fPasteLinkAvailable)
  551. lpPS->dwFlags |= PSF_SELECTPASTE;
  552. if (fPasteLinkAvailable && !fPasteAvailable)
  553. lpPS->dwFlags |= PSF_SELECTPASTELINK;
  554. if (lpPS->dwFlags & PSF_SELECTPASTE)
  555. {
  556. // FTogglePaste will set the PSF_SELECTPASTE flag, so clear it.
  557. lpPS->dwFlags &= ~PSF_SELECTPASTE;
  558. CheckRadioButton(hDlg, ID_PS_PASTE, ID_PS_PASTELINK, ID_PS_PASTE);
  559. FTogglePasteType(hDlg, lpPS, PSF_SELECTPASTE);
  560. }
  561. else if (lpPS->dwFlags & PSF_SELECTPASTELINK)
  562. {
  563. // FTogglePaste will set the PSF_SELECTPASTELINK flag, so clear it.
  564. lpPS->dwFlags &= ~PSF_SELECTPASTELINK;
  565. CheckRadioButton(hDlg, ID_PS_PASTE, ID_PS_PASTELINK, ID_PS_PASTELINK);
  566. FTogglePasteType(hDlg, lpPS, PSF_SELECTPASTELINK);
  567. }
  568. else // Items are not available to be be Pasted or Paste-Linked
  569. {
  570. // Enable or disable DisplayAsIcon and set the result text and image
  571. EnableDisplayAsIcon(hDlg, lpPS);
  572. SetPasteSpecialHelpResults(hDlg, lpPS);
  573. }
  574. // Give initial focus to the list box
  575. SetFocus(GetDlgItem(hDlg, ID_PS_DISPLAYLIST));
  576. // Set property to handle clipboard change notifications
  577. SetProp(hDlg, NEXTCBVIEWER, HWND_BROADCAST);
  578. SetProp(hDlg, NEXTCBVIEWER, SetClipboardViewer(hDlg));
  579. lpPS->fClipboardChanged = FALSE;
  580. /*
  581. * PERFORM OTHER INITIALIZATION HERE.
  582. */
  583. // Call the hook with lCustData in lParam
  584. UStandardHook(lpPS, hDlg, WM_INITDIALOG, wParam, lpOPS->lCustData);
  585. return TRUE;
  586. }
  587. /*
  588. * FTogglePasteType
  589. *
  590. * Purpose:
  591. * Toggles between Paste and Paste Link. The Paste list and PasteLink
  592. * list are always invisible. The Display List is filled from either
  593. * the Paste list or the PasteLink list depending on which Paste radio
  594. * button is selected.
  595. *
  596. * Parameters:
  597. * hDlg HWND of the dialog
  598. * lpPS Paste Special Dialog Structure
  599. * dwOption Paste or PasteSpecial option
  600. *
  601. * Return Value:
  602. * BOOL Returns TRUE if the option has already been selected.
  603. * Otherwise the option is selected and FALSE is returned
  604. */
  605. BOOL FTogglePasteType(HWND hDlg, LPPASTESPECIAL lpPS, DWORD dwOption)
  606. {
  607. DWORD dwTemp;
  608. HWND hList, hListDisplay;
  609. DWORD dwData;
  610. int i, nItems;
  611. LPTSTR lpsz;
  612. // Skip all this if the button is already selected
  613. if (lpPS->dwFlags & dwOption)
  614. return TRUE;
  615. dwTemp = PSF_SELECTPASTE | PSF_SELECTPASTELINK;
  616. lpPS->dwFlags = (lpPS->dwFlags & ~dwTemp) | dwOption;
  617. // Hide IconDisplay. This prevents flashing if the icon display is changed
  618. StandardShowDlgItem(hDlg, ID_PS_ICONDISPLAY, SW_HIDE);
  619. hListDisplay = GetDlgItem(hDlg, ID_PS_DISPLAYLIST);
  620. // If Paste was selected
  621. if (lpPS->dwFlags & PSF_SELECTPASTE)
  622. {
  623. // Set the Source of the object in the clipboard
  624. SetDlgItemText(hDlg, ID_PS_SOURCETEXT, lpPS->szSourceOfDataOD);
  625. // If an icon is available
  626. if (lpPS->hMetaPictOD)
  627. // Set the icon display
  628. SendDlgItemMessage(hDlg, ID_PS_ICONDISPLAY, IBXM_IMAGESET,
  629. (WPARAM)lpPS->hMetaPictOD, 0L);
  630. hList = GetDlgItem(hDlg, ID_PS_PASTELIST);
  631. // We are switching from PasteLink to Paste. Remember current selection
  632. // in PasteLink list so it can be restored.
  633. lpPS->nPasteLinkListCurSel = (int)SendMessage(hListDisplay, LB_GETCURSEL, 0, 0L);
  634. if (lpPS->nPasteLinkListCurSel == LB_ERR)
  635. lpPS->nPasteLinkListCurSel = 0;
  636. // Remember if user selected Paste or PasteLink
  637. lpPS->fLink = FALSE;
  638. }
  639. else // If PasteLink was selected
  640. {
  641. // Set the Source of the object in the clipboard
  642. SetDlgItemText(hDlg, ID_PS_SOURCETEXT, lpPS->szSourceOfDataLSD);
  643. // If an icon is available
  644. if (lpPS->hMetaPictLSD)
  645. // Set the icon display
  646. SendDlgItemMessage(hDlg, ID_PS_ICONDISPLAY, IBXM_IMAGESET,
  647. (WPARAM)lpPS->hMetaPictLSD, 0L);
  648. hList = GetDlgItem(hDlg, ID_PS_PASTELINKLIST);
  649. // We are switching from Paste to PasteLink. Remember current selection
  650. // in Paste list so it can be restored.
  651. lpPS->nPasteListCurSel = (int)SendMessage(hListDisplay, LB_GETCURSEL, 0, 0L);
  652. if (lpPS->nPasteListCurSel == LB_ERR)
  653. lpPS->nPasteListCurSel = 0;
  654. // Remember if user selected Paste or PasteLink
  655. lpPS->fLink = TRUE;
  656. }
  657. // Turn drawing off while the Display List is being filled
  658. SendMessage(hListDisplay, WM_SETREDRAW, (WPARAM)FALSE, 0L);
  659. // Move data to Display list box
  660. SendMessage(hListDisplay, LB_RESETCONTENT, 0, 0L);
  661. nItems = (int) SendMessage(hList, LB_GETCOUNT, 0, 0L);
  662. lpsz = (LPTSTR)GlobalLock(lpPS->hBuff);
  663. for (i = 0; i < nItems; i++)
  664. {
  665. SendMessage(hList, LB_GETTEXT, (WPARAM)i, (LPARAM)lpsz);
  666. dwData = SendMessage(hList, LB_GETITEMDATA, (WPARAM)i, 0L);
  667. SendMessage(hListDisplay, LB_INSERTSTRING, (WPARAM)i, (LPARAM)lpsz);
  668. SendMessage(hListDisplay, LB_SETITEMDATA, (WPARAM)i, dwData);
  669. }
  670. GlobalUnlock(lpPS->hBuff);
  671. // Restore the selection in the Display List from user's last selection
  672. if (lpPS->dwFlags & PSF_SELECTPASTE)
  673. SendMessage(hListDisplay, LB_SETCURSEL, lpPS->nPasteListCurSel, 0L);
  674. else
  675. SendMessage(hListDisplay, LB_SETCURSEL, lpPS->nPasteLinkListCurSel, 0L);
  676. // Paint Display List
  677. SendMessage(hListDisplay, WM_SETREDRAW, (WPARAM)TRUE, 0L);
  678. InvalidateRect(hListDisplay, NULL, TRUE);
  679. UpdateWindow(hListDisplay);
  680. // Auto give the focus to the Display List
  681. SetFocus(hListDisplay);
  682. // Enable/Disable DisplayAsIcon and set the help result text and bitmap corresponding to
  683. // the current selection
  684. ChangeListSelection(hDlg, lpPS, hListDisplay);
  685. return FALSE;
  686. }
  687. /*
  688. * ChangeListSelection
  689. *
  690. * Purpose:
  691. * When the user changes the selection in the list, DisplayAsIcon is enabled or disabled,
  692. * Result text and bitmap are updated and the index of the arrPasteEntries[] corresponding
  693. * to the current format selection is saved.
  694. *
  695. * Parameters:
  696. * hDlg HWND of the dialog
  697. * lpPS Paste Special Dialog Structure
  698. * hList HWND of the List
  699. *
  700. * Return Value:
  701. * No return value
  702. */
  703. void ChangeListSelection(HWND hDlg, LPPASTESPECIAL lpPS, HWND hList)
  704. {
  705. LPPASTELISTITEMDATA lpItemData;
  706. int nCurSel;
  707. EnableDisplayAsIcon(hDlg, lpPS);
  708. SetPasteSpecialHelpResults(hDlg, lpPS);
  709. // Remember index of arrPasteEntries[] corresponding to the current selection
  710. nCurSel = (int)SendMessage(hList, LB_GETCURSEL, 0, 0L);
  711. if (nCurSel == LB_ERR) return;
  712. lpItemData = (LPPASTELISTITEMDATA) SendMessage(hList, LB_GETITEMDATA,
  713. (WPARAM)nCurSel, 0L);
  714. if ((LRESULT)lpItemData == LB_ERR) return;
  715. lpPS->nSelectedIndex = lpItemData->nPasteEntriesIndex;
  716. }
  717. /*
  718. * EnableDisplayAsIcon
  719. *
  720. * Purpose:
  721. * Enable or disable the DisplayAsIcon button depending on whether
  722. * the current selection can be displayed as an icon or not. The following table describes
  723. * the state of DisplayAsIcon. The calling application is termed CONTAINER, the source
  724. * of data on the clipboard is termed SOURCE.
  725. * Y = Yes; N = No; Blank = State does not matter;
  726. * =====================================================================
  727. * SOURCE SOURCE CONTAINER DisplayAsIcon
  728. * specifies specifies specifies Initial State
  729. * DVASPECT_ICON OLEMISC_ONLYICONIC OLEUIPASTE_ENABLEICON
  730. *
  731. * N Unchecked&Disabled
  732. * Y Y Checked&Disabled
  733. * Y N Y Checked&Enabled
  734. * N N Y Unchecked&Enabled
  735. * =====================================================================
  736. *
  737. * Parameters:
  738. * hDlg HWND of the dialog
  739. * lpPS Paste Special Dialog Structure
  740. *
  741. * Return Value:
  742. * No return value
  743. */
  744. void EnableDisplayAsIcon(HWND hDlg, LPPASTESPECIAL lpPS)
  745. {
  746. int nIndex;
  747. BOOL fCntrEnableIcon;
  748. BOOL fSrcOnlyIconic = (lpPS->fLink) ? lpPS->fSrcOnlyIconicLSD : lpPS->fSrcOnlyIconicOD;
  749. BOOL fSrcAspectIcon = (lpPS->fLink) ? lpPS->fSrcAspectIconLSD : lpPS->fSrcAspectIconOD;
  750. HWND hList;
  751. LPPASTELISTITEMDATA lpItemData;
  752. HGLOBAL hMetaPict = (lpPS->fLink) ? lpPS->hMetaPictLSD : lpPS->hMetaPictOD;
  753. hList = GetDlgItem(hDlg, ID_PS_DISPLAYLIST);
  754. // Get data corresponding to the current selection in the listbox
  755. nIndex = (int)SendMessage(hList, LB_GETCURSEL, 0, 0);
  756. if (nIndex != LB_ERR)
  757. {
  758. lpItemData = (LPPASTELISTITEMDATA) SendMessage(hList, LB_GETITEMDATA, (WPARAM)nIndex, 0L);
  759. if ((LRESULT)lpItemData != LB_ERR)
  760. fCntrEnableIcon = lpItemData->fCntrEnableIcon;
  761. else fCntrEnableIcon = FALSE;
  762. }
  763. else fCntrEnableIcon = FALSE;
  764. // If there is an icon available
  765. if (hMetaPict != NULL)
  766. {
  767. if (!fCntrEnableIcon) // Does CONTAINER specify OLEUIPASTE_ENABLEICON?
  768. {
  769. // Uncheck & Disable DisplayAsIcon
  770. lpPS->dwFlags &= ~PSF_CHECKDISPLAYASICON;
  771. CheckDlgButton(hDlg, ID_PS_DISPLAYASICON, FALSE);
  772. EnableWindow(GetDlgItem(hDlg, ID_PS_DISPLAYASICON), FALSE);
  773. // Hide IconDisplay and ChangeIcon button
  774. StandardShowDlgItem(hDlg, ID_PS_ICONDISPLAY, SW_HIDE);
  775. StandardShowDlgItem(hDlg, ID_PS_CHANGEICON, SW_HIDE);
  776. }
  777. else if (fSrcOnlyIconic) // Does SOURCE specify OLEMISC_ONLYICONIC?
  778. {
  779. // Check & Disable DisplayAsIcon
  780. lpPS->dwFlags |= PSF_CHECKDISPLAYASICON;
  781. CheckDlgButton(hDlg, ID_PS_DISPLAYASICON, TRUE);
  782. EnableWindow(GetDlgItem(hDlg, ID_PS_DISPLAYASICON), FALSE);
  783. // Show IconDisplay and ChangeIcon button
  784. StandardShowDlgItem(hDlg, ID_PS_ICONDISPLAY, SW_SHOWNORMAL);
  785. StandardShowDlgItem(hDlg, ID_PS_CHANGEICON, SW_SHOWNORMAL);
  786. }
  787. else if (fSrcAspectIcon) // Does SOURCE specify DVASPECT_ICON?
  788. {
  789. // Check & Enable DisplayAsIcon
  790. lpPS->dwFlags |= PSF_CHECKDISPLAYASICON;
  791. CheckDlgButton(hDlg, ID_PS_DISPLAYASICON, TRUE);
  792. EnableWindow(GetDlgItem(hDlg, ID_PS_DISPLAYASICON), TRUE);
  793. // Show IconDisplay and ChangeIcon button
  794. StandardShowDlgItem(hDlg, ID_PS_ICONDISPLAY, SW_SHOWNORMAL);
  795. StandardShowDlgItem(hDlg, ID_PS_CHANGEICON, SW_SHOWNORMAL);
  796. }
  797. else
  798. {
  799. //Uncheck and Enable DisplayAsIcon
  800. lpPS->dwFlags &= ~PSF_CHECKDISPLAYASICON;
  801. CheckDlgButton(hDlg, ID_PS_DISPLAYASICON, FALSE);
  802. EnableWindow(GetDlgItem(hDlg, ID_PS_DISPLAYASICON), TRUE);
  803. // Hide IconDisplay and ChangeIcon button
  804. StandardShowDlgItem(hDlg, ID_PS_ICONDISPLAY, SW_HIDE);
  805. StandardShowDlgItem(hDlg, ID_PS_CHANGEICON, SW_HIDE);
  806. }
  807. }
  808. else // No icon available
  809. {
  810. // Unchecked & Disabled
  811. lpPS->dwFlags &= ~PSF_CHECKDISPLAYASICON;
  812. CheckDlgButton(hDlg, ID_PS_DISPLAYASICON, FALSE);
  813. EnableWindow(GetDlgItem(hDlg, ID_PS_DISPLAYASICON), FALSE);
  814. // Hide IconDisplay and ChangeIcon button
  815. StandardShowDlgItem(hDlg, ID_PS_ICONDISPLAY, SW_HIDE);
  816. StandardShowDlgItem(hDlg, ID_PS_CHANGEICON, SW_HIDE);
  817. }
  818. }
  819. /*
  820. * ToggleDisplayAsIcon
  821. *
  822. * Purpose:
  823. * Toggles the DisplayAsIcon button. Hides or shows the Icon Display and
  824. * the ChangeIcon button and changes the help result text and bitmap.
  825. *
  826. * Parameters:
  827. * hDlg HWND of the dialog
  828. * lpPS Paste Special Dialog Structure
  829. *
  830. * Return Value:
  831. * None
  832. *
  833. */
  834. void ToggleDisplayAsIcon(HWND hDlg, LPPASTESPECIAL lpPS)
  835. {
  836. BOOL fCheck;
  837. int i;
  838. fCheck = IsDlgButtonChecked(hDlg, ID_PS_DISPLAYASICON);
  839. if (fCheck)
  840. lpPS->dwFlags |= PSF_CHECKDISPLAYASICON;
  841. else lpPS->dwFlags &= ~PSF_CHECKDISPLAYASICON;
  842. // Set the help result text and bitmap
  843. SetPasteSpecialHelpResults(hDlg, lpPS);
  844. // Show or hide the Icon Display and ChangeIcon button depending
  845. // on the check state
  846. i = (fCheck) ? SW_SHOWNORMAL : SW_HIDE;
  847. StandardShowDlgItem(hDlg, ID_PS_ICONDISPLAY, i);
  848. StandardShowDlgItem(hDlg, ID_PS_CHANGEICON, i);
  849. }
  850. /*
  851. * ChangeIcon
  852. *
  853. * Purpose:
  854. * Brings up the ChangeIcon dialog which allows the user to change
  855. * the icon and label.
  856. *
  857. * Parameters:
  858. * hDlg HWND of the dialog
  859. * lpPS Paste Special Dialog Structure
  860. *
  861. * Return Value:
  862. * None
  863. *
  864. */
  865. void ChangeIcon(HWND hDlg, LPPASTESPECIAL lpPS)
  866. {
  867. OLEUICHANGEICON ci;
  868. UINT uRet;
  869. CLSID clsid = (lpPS->fLink) ? lpPS->clsidLSD : lpPS->clsidOD;
  870. //Initialize the structure
  871. _fmemset((LPOLEUICHANGEICON)&ci, 0, sizeof(ci));
  872. ci.hMetaPict = (HGLOBAL)SendDlgItemMessage(hDlg, ID_PS_ICONDISPLAY, IBXM_IMAGEGET, 0, 0L);
  873. ci.cbStruct = sizeof(ci);
  874. ci.hWndOwner = hDlg;
  875. ci.clsid = clsid;
  876. ci.dwFlags = CIF_SELECTCURRENT;
  877. // Only show help in the ChangeIcon dialog if we're showing it in this dialog.
  878. if (lpPS->dwFlags & PSF_SHOWHELP)
  879. ci.dwFlags |= CIF_SHOWHELP;
  880. // Let the hook in to customize Change Icon if desired.
  881. uRet = UStandardHook(lpPS, hDlg, uMsgChangeIcon, 0, (LONG)(LPSTR)&ci);
  882. if (0 == uRet)
  883. uRet=(UINT)(OLEUI_OK==OleUIChangeIcon(&ci));
  884. // Update the display if necessary.
  885. if (0!=uRet)
  886. {
  887. /*
  888. * OleUIChangeIcon will have already freed our
  889. * current hMetaPict that we passed in when OK is
  890. * pressed in that dialog. So we use 0L as lParam
  891. * here so the IconBox doesn't try to free the
  892. * metafilepict again.
  893. */
  894. SendDlgItemMessage(hDlg, ID_PS_ICONDISPLAY, IBXM_IMAGESET, (WPARAM)ci.hMetaPict, 0L);
  895. // Remember the new icon chosen by the user. Note that Paste and PasteLink have separate
  896. // icons - changing one does not change the other.
  897. if (lpPS->fLink)
  898. lpPS->hMetaPictLSD = ci.hMetaPict;
  899. else lpPS->hMetaPictOD = ci.hMetaPict;
  900. }
  901. }
  902. /*
  903. *SetPasteSpecialHelpResults
  904. *
  905. * Purpose:
  906. * Sets the help result text and bitmap according to the current
  907. * list selection. The following state table indicates which ResultText
  908. * and ResultImage are selected. If %s in the lpstrFormatName is present,
  909. * it is assumed that an object is being pasted/paste-linked, otherwise it
  910. * is assumed that data is being pasted/paste-linked.
  911. * Y = Yes; N = No; Blank = State does not matter;
  912. * The numbers in the the ResultText and ResultImage columns refer to the table
  913. * entries that follow.
  914. * =====================================================================
  915. * Paste/ lpstrFormatName in DisplayAsIcon Result Result
  916. * PasteLink arrPasteEntry[]contains %s checked Text Image
  917. * (Is Object == Y, Is Data == N)
  918. * Paste N 1 1
  919. * Paste Y N 2 2
  920. * Paste Y Y 3 3
  921. * PasteLink N 4 4
  922. * PasteLink Y N 5 4
  923. * PasteLink Y Y 6 5
  924. * =====================================================================
  925. * Result Text:
  926. *
  927. * 1. "Inserts the contents of the Clipboard into your document as <native type name,
  928. * and optionally an additional help sentence>"
  929. * 2. "Inserts the contents of the Clipboard into your document so that you may
  930. * activate it using <object app name>"
  931. * 3. "Inserts the contents of the Clipboard into your document so that you may
  932. * activate it using <object app name>. It will be displayed as an icon."
  933. * 4. "Inserts the contents of the Clipboard into your document as <native type name>.
  934. * Paste Link creates a link to the source file so that changes to the source file
  935. * will be reflected in your document."
  936. * 5. "Inserts a picture of the Clipboard contents into your document. Paste Link
  937. * creates a link to the source file so that changes to the source file will be
  938. * reflected in your document."
  939. * 6. "Inserts an icon into your document which represents the Clipboard contents.
  940. * Paste Link creates a link to the source file so that changes to the source file
  941. * will be reflected in your document."
  942. * =====================================================================
  943. * Result Image:
  944. *
  945. * 1. Clipboard Image
  946. * 2. Paste image, non-iconic.
  947. * 3. Paste image, iconic.
  948. * 4. Paste Link image, non-iconic
  949. * 5. Paste Link image, iconic
  950. * ====================================================================
  951. *
  952. * Parameters:
  953. * hDlg HWND of the dialog
  954. * lpPS Paste Special Dialog Structure
  955. *
  956. * Return Value:
  957. * No return value
  958. */
  959. void SetPasteSpecialHelpResults(HWND hDlg, LPPASTESPECIAL lpPS)
  960. {
  961. LPTSTR psz1, psz2, psz3, psz4;
  962. UINT i, iString, iImage, cch;
  963. int nPasteEntriesIndex;
  964. BOOL fDisplayAsIcon;
  965. BOOL fIsObject;
  966. HWND hList;
  967. LPPASTELISTITEMDATA lpItemData;
  968. LPOLEUIPASTESPECIAL lpOPS = lpPS->lpOPS;
  969. LPTSTR szFullUserTypeName = (lpPS->fLink) ?
  970. lpPS->szFullUserTypeNameLSD : lpPS->szFullUserTypeNameOD;
  971. LPTSTR szInsert;
  972. hList = GetDlgItem(hDlg, ID_PS_DISPLAYLIST);
  973. i=(UINT)SendMessage(hList, LB_GETCURSEL, 0, 0L);
  974. if (i != LB_ERR)
  975. {
  976. lpItemData = (LPPASTELISTITEMDATA)SendMessage(hList, LB_GETITEMDATA, i, 0L);
  977. if ((LRESULT)lpItemData == LB_ERR) return;
  978. nPasteEntriesIndex = lpItemData->nPasteEntriesIndex;
  979. // Check if there is a '%s' in the lpstrFormatName, then an object is being
  980. // pasted/pastelinked. Otherwise Data is being pasted-pastelinked.
  981. fIsObject = FHasPercentS(lpOPS->arrPasteEntries[nPasteEntriesIndex].lpstrFormatName,
  982. lpPS);
  983. }
  984. else return;
  985. // Is DisplayAsIcon checked?
  986. fDisplayAsIcon=(0L!=(lpPS->dwFlags & PSF_CHECKDISPLAYASICON));
  987. szInsert = szFullUserTypeName;
  988. if (lpPS->dwFlags & PSF_SELECTPASTE) // If user selected Paste
  989. {
  990. if (fIsObject)
  991. {
  992. iString = fDisplayAsIcon ? IDS_PSPASTEOBJECTASICON : IDS_PSPASTEOBJECT;
  993. iImage = fDisplayAsIcon ? RESULTIMAGE_EMBEDICON : RESULTIMAGE_EMBED;
  994. szInsert = lpPS->szAppName;
  995. }
  996. else
  997. {
  998. iString = IDS_PSPASTEDATA;
  999. iImage = RESULTIMAGE_PASTE;
  1000. }
  1001. }
  1002. else if (lpPS->dwFlags & PSF_SELECTPASTELINK) // User selected PasteLink
  1003. {
  1004. if (fIsObject)
  1005. {
  1006. iString = fDisplayAsIcon ? IDS_PSPASTELINKOBJECTASICON : IDS_PSPASTELINKOBJECT;
  1007. iImage = fDisplayAsIcon ? RESULTIMAGE_LINKICON : RESULTIMAGE_LINK;
  1008. }
  1009. else
  1010. {
  1011. iString = IDS_PSPASTELINKDATA;
  1012. iImage = RESULTIMAGE_LINK;
  1013. }
  1014. }
  1015. else // Should never occur.
  1016. {
  1017. iString = IDS_PSNONOLE;
  1018. iImage = RESULTIMAGE_PASTE;
  1019. }
  1020. // hBuff contains enough space for the 4 buffers required to build up the help
  1021. // result text.
  1022. cch = (UINT)GlobalSize(lpPS->hBuff)/4;
  1023. psz1=(LPTSTR)GlobalLock(lpPS->hBuff);
  1024. psz2=psz1+cch;
  1025. psz3=psz2+cch;
  1026. psz4=psz3+cch;
  1027. // Default is an empty string.
  1028. *psz1=0;
  1029. if (0!=LoadString(ghInst, iString, psz1, cch))
  1030. {
  1031. // Insert the FullUserTypeName of the source object into the partial result text
  1032. // specified by the container.
  1033. wsprintf(psz3, lpOPS->arrPasteEntries[nPasteEntriesIndex].lpstrResultText,
  1034. (LPTSTR)szInsert);
  1035. // Insert the above partial result text into the standard result text.
  1036. wsprintf(psz4, psz1, (LPTSTR)psz3);
  1037. psz1=psz4;
  1038. }
  1039. // If LoadString failed, we simply clear out the results (*psz1=0 above)
  1040. SetDlgItemText(hDlg, ID_PS_RESULTTEXT, psz1);
  1041. // Change the result bitmap
  1042. SendDlgItemMessage(hDlg, ID_PS_RESULTIMAGE, RIM_IMAGESET, iImage, 0L);
  1043. GlobalUnlock(lpPS->hBuff);
  1044. }
  1045. /*
  1046. * FAddPasteListItem
  1047. *
  1048. * Purpose:
  1049. * Adds an item to the list box
  1050. *
  1051. * Parameters:
  1052. * hList HWND List into which item is to be added
  1053. * fInsertFirst BOOL Insert in the beginning of the list?
  1054. * nPasteEntriesIndex int Index of Paste Entry array this list item corresponsds to
  1055. * lpPS Paste Special Dialog Structure
  1056. * pIMalloc LPMALLOC Memory Allocator
  1057. * lpszBuf LPSTR Scratch buffer to build up string for list entry
  1058. * lpszFullUserTypeName LPSTR full user type name for object entry
  1059. *
  1060. * Return Value:
  1061. * BOOL TRUE if sucessful.
  1062. * FALSE if unsucessful.
  1063. */
  1064. BOOL FAddPasteListItem(
  1065. HWND hList, BOOL fInsertFirst, int nPasteEntriesIndex,
  1066. LPPASTESPECIAL lpPS,
  1067. LPMALLOC pIMalloc, LPTSTR lpszBuf, LPTSTR lpszFullUserTypeName)
  1068. {
  1069. LPOLEUIPASTESPECIAL lpOPS = lpPS->lpOPS;
  1070. LPPASTELISTITEMDATA lpItemData;
  1071. int nIndex;
  1072. // Allocate memory for each list box item
  1073. lpItemData = (LPPASTELISTITEMDATA)pIMalloc->lpVtbl->Alloc(
  1074. pIMalloc, (DWORD)sizeof(PASTELISTITEMDATA));
  1075. if (NULL == lpItemData)
  1076. return FALSE;
  1077. // Fill data associated with each list box item
  1078. lpItemData->nPasteEntriesIndex = nPasteEntriesIndex;
  1079. lpItemData->fCntrEnableIcon = ((lpOPS->arrPasteEntries[nPasteEntriesIndex].dwFlags &
  1080. OLEUIPASTE_ENABLEICON) ? TRUE : FALSE);
  1081. // Build list box entry string, insert the string and add the data the corresponds to it
  1082. wsprintf(
  1083. (LPTSTR)lpszBuf,
  1084. lpOPS->arrPasteEntries[nPasteEntriesIndex].lpstrFormatName,
  1085. (LPTSTR)lpszFullUserTypeName
  1086. );
  1087. // only add to listbox if not a duplicate
  1088. if (LB_ERR!=SendMessage(hList,LB_FINDSTRING, 0, (LPARAM)(LPTSTR)lpszBuf)) {
  1089. // item is already in list; SKIP this one
  1090. pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)lpItemData);
  1091. return TRUE; // this is NOT an error
  1092. }
  1093. nIndex = (int)SendMessage(
  1094. hList,
  1095. (fInsertFirst ? LB_INSERTSTRING : LB_ADDSTRING),
  1096. 0,
  1097. (LPARAM)(LPTSTR)lpszBuf
  1098. );
  1099. SendMessage(
  1100. hList,
  1101. LB_SETITEMDATA,
  1102. nIndex,
  1103. (LPARAM)(LPPASTELISTITEMDATA)lpItemData
  1104. );
  1105. return TRUE;
  1106. }
  1107. /*
  1108. * FFillPasteList
  1109. *
  1110. * Purpose:
  1111. * Fills the invisible paste list with the formats offered by the clipboard object and
  1112. * asked for by the container.
  1113. *
  1114. * Parameters:
  1115. * hDlg HWND of the dialog
  1116. * lpPS Paste Special Dialog Structure
  1117. *
  1118. * Return Value:
  1119. * BOOL TRUE if sucessful and if formats could be found.
  1120. * FALSE if unsucessful or if no formats could be found.
  1121. */
  1122. BOOL FFillPasteList(HWND hDlg, LPPASTESPECIAL lpPS)
  1123. {
  1124. LPOLEUIPASTESPECIAL lpOPS = lpPS->lpOPS;
  1125. LPMALLOC pIMalloc = NULL;
  1126. LPTSTR lpszBuf = (LPTSTR)GlobalLock(lpPS->hBuff);
  1127. HWND hList;
  1128. int i, j;
  1129. int nItems = 0;
  1130. int nDefFormat = -1;
  1131. BOOL fTryObjFmt = FALSE;
  1132. BOOL fInsertFirst;
  1133. BOOL fExclude;
  1134. HRESULT hrErr;
  1135. hrErr = CoGetMalloc(MEMCTX_TASK, &pIMalloc);
  1136. if (hrErr != NOERROR)
  1137. goto error;
  1138. hList = GetDlgItem(hDlg, ID_PS_PASTELIST);
  1139. // Loop over the target's priority list of formats
  1140. for (i = 0; i < lpOPS->cPasteEntries; i++)
  1141. {
  1142. if (lpOPS->arrPasteEntries[i].dwFlags != OLEUIPASTE_PASTEONLY &&
  1143. !(lpOPS->arrPasteEntries[i].dwFlags & OLEUIPASTE_PASTE))
  1144. continue;
  1145. fInsertFirst = FALSE;
  1146. if (lpOPS->arrPasteEntries[i].fmtetc.cfFormat==cfFileName
  1147. || lpOPS->arrPasteEntries[i].fmtetc.cfFormat==cfEmbeddedObject
  1148. || lpOPS->arrPasteEntries[i].fmtetc.cfFormat==cfEmbedSource) {
  1149. if (! fTryObjFmt) {
  1150. fTryObjFmt = TRUE; // only use 1st object format
  1151. fInsertFirst = TRUE; // OLE obj format should always be 1st
  1152. //Check if this CLSID is in the exclusion list.
  1153. fExclude=FALSE;
  1154. for (j=0; j < (int)lpOPS->cClsidExclude; j++)
  1155. {
  1156. if (IsEqualCLSID(&lpPS->clsidOD,
  1157. (LPCLSID)(lpOPS->lpClsidExclude+j)))
  1158. {
  1159. fExclude=TRUE;
  1160. break;
  1161. }
  1162. }
  1163. if (fExclude)
  1164. continue; // don't add the object entry to list
  1165. } else {
  1166. continue; // already added an object format to list
  1167. }
  1168. }
  1169. // add to list if entry is marked TRUE
  1170. if (lpOPS->arrPasteEntries[i].dwScratchSpace) {
  1171. if (nDefFormat < 0)
  1172. nDefFormat = (fInsertFirst ? 0 : nItems);
  1173. else if (fInsertFirst)
  1174. nDefFormat++; // adjust for obj fmt inserted 1st in list
  1175. if (!FAddPasteListItem(hList, fInsertFirst, i, lpPS, pIMalloc,
  1176. lpszBuf, lpPS->szFullUserTypeNameOD))
  1177. goto error;
  1178. nItems++;
  1179. }
  1180. }
  1181. // initialize selection to first format matched in list
  1182. if (nDefFormat >= 0)
  1183. lpPS->nPasteListCurSel = nDefFormat;
  1184. // Clean up
  1185. if (pIMalloc)
  1186. pIMalloc->lpVtbl->Release(pIMalloc);
  1187. if (lpszBuf)
  1188. GlobalUnlock(lpPS->hBuff);
  1189. // If no items have been added to the list box (none of the formats
  1190. // offered by the source matched those acceptable to the container),
  1191. // return FALSE
  1192. if (nItems > 0)
  1193. return TRUE;
  1194. else
  1195. return FALSE;
  1196. error:
  1197. if (pIMalloc)
  1198. pIMalloc->lpVtbl->Release(pIMalloc);
  1199. if (lpszBuf)
  1200. GlobalUnlock(lpPS->hBuff);
  1201. FreeListData(hList);
  1202. return FALSE;
  1203. }
  1204. /*
  1205. * FFillPasteLinkList
  1206. *
  1207. * Purpose:
  1208. * Fills the invisible paste link list with the formats offered by the clipboard object and
  1209. * asked for by the container.
  1210. *
  1211. * Parameters:
  1212. * hDlg HWND of the dialog
  1213. * lpPS Paste Special Dialog Structure
  1214. *
  1215. * Return Value:
  1216. * BOOL TRUE if sucessful and if formats could be found.
  1217. * FALSE if unsucessful or if no formats could be found.
  1218. */
  1219. BOOL FFillPasteLinkList(HWND hDlg, LPPASTESPECIAL lpPS)
  1220. {
  1221. LPOLEUIPASTESPECIAL lpOPS = lpPS->lpOPS;
  1222. LPDATAOBJECT lpSrcDataObj = lpOPS->lpSrcDataObj;
  1223. LPENUMFORMATETC lpEnumFmtEtc = NULL;
  1224. LPMALLOC pIMalloc = NULL;
  1225. LPTSTR lpszBuf = (LPTSTR)GlobalLock(lpPS->hBuff);
  1226. OLEUIPASTEFLAG pasteFlag;
  1227. UINT arrLinkTypesSupported[PS_MAXLINKTYPES]; // Array of flags that
  1228. // indicate which link types
  1229. // are supported by source.
  1230. FORMATETC fmtetc;
  1231. int i, j;
  1232. int nItems = 0;
  1233. BOOL fLinkTypeSupported = FALSE;
  1234. HWND hList;
  1235. int nDefFormat = -1;
  1236. BOOL fTryObjFmt = FALSE;
  1237. BOOL fInsertFirst;
  1238. HRESULT hrErr;
  1239. hrErr = CoGetMalloc(MEMCTX_TASK, &pIMalloc);
  1240. if (hrErr != NOERROR)
  1241. goto error;
  1242. // Remember which link type formats are offered by lpSrcDataObj.
  1243. _fmemset(&fmtetc, 0, sizeof(FORMATETC));
  1244. for (i = 0; i < lpOPS->cLinkTypes; i++)
  1245. {
  1246. if (lpOPS->arrLinkTypes[i] = cfLinkSource) {
  1247. OLEDBG_BEGIN2(TEXT("OleQueryLinkFromData called\r\n"))
  1248. hrErr = OleQueryLinkFromData(lpSrcDataObj);
  1249. OLEDBG_END2
  1250. if(NOERROR == hrErr)
  1251. {
  1252. arrLinkTypesSupported[i] = 1;
  1253. fLinkTypeSupported = TRUE;
  1254. }
  1255. else arrLinkTypesSupported[i] = 0;
  1256. }
  1257. else {
  1258. fmtetc.cfFormat = lpOPS->arrLinkTypes[i];
  1259. fmtetc.dwAspect = DVASPECT_CONTENT;
  1260. fmtetc.tymed = 0xFFFFFFFF; // All tymed values
  1261. fmtetc.lindex = -1;
  1262. OLEDBG_BEGIN2(TEXT("IDataObject::QueryGetData called\r\n"))
  1263. hrErr = lpSrcDataObj->lpVtbl->QueryGetData(lpSrcDataObj,&fmtetc);
  1264. OLEDBG_END2
  1265. if(NOERROR == hrErr)
  1266. {
  1267. arrLinkTypesSupported[i] = 1;
  1268. fLinkTypeSupported = TRUE;
  1269. }
  1270. else arrLinkTypesSupported[i] = 0;
  1271. }
  1272. }
  1273. // No link types are offered by lpSrcDataObj
  1274. if (! fLinkTypeSupported) {
  1275. nItems = 0;
  1276. goto cleanup;
  1277. }
  1278. hList = GetDlgItem(hDlg, ID_PS_PASTELINKLIST);
  1279. // Enumerate the formats acceptable to container
  1280. for (i = 0; i < lpOPS->cPasteEntries; i++)
  1281. {
  1282. fLinkTypeSupported = FALSE;
  1283. // If container will accept any link type offered by source object
  1284. if (lpOPS->arrPasteEntries[i].dwFlags & OLEUIPASTE_LINKANYTYPE)
  1285. fLinkTypeSupported = TRUE;
  1286. else
  1287. {
  1288. // Check if any of the link types offered by the source
  1289. // object are acceptable to the container
  1290. // This code depends on the LINKTYPE enum values being powers of 2
  1291. for (pasteFlag = OLEUIPASTE_LINKTYPE1, j = 0;
  1292. j < lpOPS->cLinkTypes;
  1293. pasteFlag*=2, j++)
  1294. {
  1295. if ((lpOPS->arrPasteEntries[i].dwFlags & pasteFlag) &&
  1296. arrLinkTypesSupported[j])
  1297. {
  1298. fLinkTypeSupported = TRUE;
  1299. break;
  1300. }
  1301. }
  1302. }
  1303. fInsertFirst = FALSE;
  1304. if (lpOPS->arrPasteEntries[i].fmtetc.cfFormat==cfFileName
  1305. || lpOPS->arrPasteEntries[i].fmtetc.cfFormat==cfLinkSource) {
  1306. if (! fTryObjFmt) {
  1307. fTryObjFmt = TRUE; // only use 1st object format
  1308. fInsertFirst = TRUE; // OLE obj format should always be 1st
  1309. } else {
  1310. continue; // already added an object format to list
  1311. }
  1312. }
  1313. // add to list if entry is marked TRUE
  1314. if (fLinkTypeSupported && lpOPS->arrPasteEntries[i].dwScratchSpace) {
  1315. if (nDefFormat < 0)
  1316. nDefFormat = (fInsertFirst ? 0 : nItems);
  1317. else if (fInsertFirst)
  1318. nDefFormat++; // adjust for obj fmt inserted 1st in list
  1319. if (!FAddPasteListItem(hList, fInsertFirst, i, lpPS, pIMalloc,
  1320. lpszBuf, lpPS->szFullUserTypeNameLSD))
  1321. goto error;
  1322. nItems++;
  1323. }
  1324. } // end FOR
  1325. nItems = (int)SendMessage(hList, LB_GETCOUNT, 0, 0L);
  1326. // initialize selection to first format matched in list
  1327. if (nDefFormat >= 0)
  1328. lpPS->nPasteLinkListCurSel = nDefFormat;
  1329. cleanup:
  1330. // Clean up
  1331. if (pIMalloc)
  1332. pIMalloc->lpVtbl->Release(pIMalloc);
  1333. if (lpszBuf)
  1334. GlobalUnlock(lpPS->hBuff);
  1335. // If no items have been added to the list box (none of the formats
  1336. // offered by the source matched those acceptable to the destination),
  1337. // return FALSE
  1338. if (nItems > 0)
  1339. return TRUE;
  1340. else
  1341. return FALSE;
  1342. error:
  1343. if (pIMalloc)
  1344. pIMalloc->lpVtbl->Release(pIMalloc);
  1345. if (lpszBuf)
  1346. GlobalUnlock(lpPS->hBuff);
  1347. FreeListData(hList);
  1348. return FALSE;
  1349. }
  1350. /*
  1351. * FreeListData
  1352. *
  1353. * Purpose:
  1354. * Free the local memory associated with each list box item
  1355. *
  1356. * Parameters:
  1357. * hList HWND of the list
  1358. *
  1359. * Return Value:
  1360. * None
  1361. */
  1362. void FreeListData(HWND hList)
  1363. {
  1364. int nItems, i;
  1365. LPPASTELISTITEMDATA lpItemData;
  1366. LPMALLOC pIMalloc;
  1367. HRESULT hrErr;
  1368. hrErr = CoGetMalloc(MEMCTX_TASK, &pIMalloc);
  1369. if (hrErr != NOERROR)
  1370. return;
  1371. nItems = (int) SendMessage(hList, LB_GETCOUNT, 0, 0L);
  1372. for (i = 0; i < nItems; i++)
  1373. {
  1374. lpItemData = (LPPASTELISTITEMDATA)SendMessage(hList, LB_GETITEMDATA, (WPARAM)i, 0L);
  1375. if ((LRESULT)lpItemData != LB_ERR)
  1376. pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)lpItemData);
  1377. }
  1378. pIMalloc->lpVtbl->Release(pIMalloc);
  1379. }
  1380. /*
  1381. * FHasPercentS
  1382. *
  1383. * Purpose:
  1384. * Determines if string contains %s.
  1385. *
  1386. * Parameters:
  1387. * lpsz LPCSTR string in which occurence of '%s' is looked for
  1388. *
  1389. * Return Value:
  1390. * BOOL TRUE if %s is found, else FALSE.
  1391. */
  1392. BOOL FHasPercentS(LPCTSTR lpsz, LPPASTESPECIAL lpPS)
  1393. {
  1394. int n = 0;
  1395. LPTSTR lpszTmp;
  1396. if (!lpsz) return FALSE;
  1397. // Copy input string to buffer. This allows caller to pass a
  1398. // code-based string. Code segments may be swapped out in low memory situations
  1399. // and so code-based strings need to be copied before string elements can be accessed.
  1400. lpszTmp = (LPTSTR)GlobalLock(lpPS->hBuff);
  1401. lstrcpy(lpszTmp, lpsz);
  1402. while (*lpszTmp)
  1403. {
  1404. if (*lpszTmp == TEXT('%'))
  1405. {
  1406. #ifdef WIN32
  1407. // AnsiNext is obsolete in Win32
  1408. lpszTmp = CharNext(lpszTmp);
  1409. #else
  1410. lpszTmp = AnsiNext(lpszTmp);
  1411. #endif
  1412. if (*lpszTmp == TEXT('s')) // If %s, return
  1413. {
  1414. GlobalUnlock(lpPS->hBuff);
  1415. return TRUE;
  1416. }
  1417. else if (*lpszTmp == TEXT('%')) // if %%, skip to next character
  1418. #ifdef WIN32
  1419. // AnsiNext is obsolete in Win32
  1420. lpszTmp = CharNext(lpszTmp);
  1421. #else
  1422. lpszTmp = AnsiNext(lpszTmp);
  1423. #endif
  1424. }
  1425. else
  1426. #ifdef WIN32
  1427. lpszTmp = CharNext(lpszTmp);
  1428. #else
  1429. lpszTmp = AnsiNext(lpszTmp);
  1430. #endif
  1431. }
  1432. GlobalUnlock(lpPS->hBuff);
  1433. return FALSE;
  1434. }
  1435. /*
  1436. * AllocateScratchMem
  1437. *
  1438. * Purpose:
  1439. * Allocates scratch memory for use by the PasteSpecial dialog. The memory is
  1440. * is used as the buffer for building up strings using wsprintf. Strings are built up
  1441. * using the buffer while inserting items into the Paste & PasteLink lists and while
  1442. * setting the help result text. It must be big enough to handle the string that results after
  1443. * replacing the %s in the lpstrFormatName and lpstrResultText in arrPasteEntries[]
  1444. * by the FullUserTypeName. It must also be big enough to build the dialog's result text
  1445. * after %s substitutions by the FullUserTypeName or the ApplicationName.
  1446. *
  1447. * Parameters:
  1448. * lpPS Paste Special Dialog Structure
  1449. *
  1450. * Return Value:
  1451. * HGLOBAL Handle to allocated global memory
  1452. */
  1453. HGLOBAL AllocateScratchMem(LPPASTESPECIAL lpPS)
  1454. {
  1455. LPOLEUIPASTESPECIAL lpOPS = lpPS->lpOPS;
  1456. int nLen, i;
  1457. int nSubstitutedText = 0;
  1458. int nAlloc = 0;
  1459. // Get the maximum length of the FullUserTypeNames specified by OBJECTDESCRIPTOR
  1460. // and the LINKSRCDESCRIPTOR and the Application Name. Any of these may be substituted
  1461. // for %s in the result-text/list entries.
  1462. if (lpPS->szFullUserTypeNameOD)
  1463. nSubstitutedText = lstrlen(lpPS->szFullUserTypeNameOD);
  1464. if (lpPS->szFullUserTypeNameLSD)
  1465. nSubstitutedText = __max(nSubstitutedText, lstrlen(lpPS->szFullUserTypeNameLSD));
  1466. if (lpPS->szAppName)
  1467. nSubstitutedText = __max(nSubstitutedText, lstrlen(lpPS->szAppName));
  1468. // Get the maximum length of lpstrFormatNames & lpstrResultText in arrPasteEntries
  1469. nLen = 0;
  1470. for (i = 0; i < lpOPS->cPasteEntries; i++)
  1471. {
  1472. nLen = __max(nLen, lstrlen(lpOPS->arrPasteEntries[i].lpstrFormatName));
  1473. nLen = __max(nLen, lstrlen(lpOPS->arrPasteEntries[i].lpstrResultText));
  1474. }
  1475. // Get the maximum length of lpstrFormatNames and lpstrResultText after %s has
  1476. // been substituted (At most one %s can appear in each string).
  1477. // Add 1 to hold NULL terminator.
  1478. nAlloc = (nLen+nSubstitutedText+1)*sizeof(TCHAR);
  1479. // Allocate scratch memory to be used to build strings
  1480. // nAlloc is big enough to hold any of the lpstrResultText or lpstrFormatName in arrPasteEntries[]
  1481. // after %s substitution.
  1482. // We also need space to build up the help result text. 512 is the maximum length of the
  1483. // standard dialog help text before substitutions. 512+nAlloc is the maximum length
  1484. // after %s substition.
  1485. // SetPasteSpecialHelpResults() requires 4 such buffers to build up the result text
  1486. return GlobalAlloc(GHND, (DWORD)4*(512+nAlloc));
  1487. }