/* * PASTESPL.CPP * * Implements the OleUIPasteSpecial function which invokes the complete * Paste Special dialog. * * Copyright (c)1992 Microsoft Corporation, All Rights Reserved */ #include "precomp.h" #include "common.h" #include "utility.h" #include "resimage.h" #include "iconbox.h" #include OLEDBGDATA // Length of buffers to hold the strings 'Unknown Type', Unknown Source' // and 'the application which created it' // Extra long to allow room for localization. #define PS_UNKNOWNSTRLEN 200 #define PS_UNKNOWNNAMELEN 256 // Property label used to store clipboard viewer chain information #define NEXTCBVIEWER TEXT("NextCBViewer") // Internally used structure typedef struct tagPASTESPECIAL { // Keep this item first as the Standard* functions depend on it here. LPOLEUIPASTESPECIAL lpOPS; //Original structure passed. UINT nIDD; // IDD of dialog (used for help info) /* * What we store extra in this structure besides the original caller's * pointer are those fields that we need to modify during the life of * the dialog but that we don't want to change in the original structure * until the user presses OK. */ DWORD dwFlags; // Local copy of paste special flags int nPasteListCurSel; // Save the selection the user made last int nPasteLinkListCurSel; // in the paste and pastelink lists int nSelectedIndex; // Index in arrPasteEntries[] corresponding to user selection BOOL fLink; // Indicates if Paste or PasteLink was selected by user HGLOBAL hBuff; // Scratch Buffer for building up strings TCHAR szUnknownType[PS_UNKNOWNSTRLEN]; // Buffer for 'Unknown Type' string TCHAR szUnknownSource[PS_UNKNOWNSTRLEN]; // Buffer for 'Unknown Source' string TCHAR szAppName[OLEUI_CCHKEYMAX]; // Application name of Source. Used in the result text // when Paste is selected. Obtained using clsidOD. // Information obtained from OBJECTDESCRIPTOR. This information is accessed when the Paste // radio button is selected. CLSID clsidOD; // ClassID of source SIZEL sizelOD; // sizel transfered in // ObjectDescriptor TCHAR szFullUserTypeNameOD[PS_UNKNOWNNAMELEN]; // Full User Type Name TCHAR szSourceOfDataOD[PS_UNKNOWNNAMELEN]; // Source of Data BOOL fSrcAspectIconOD; // Does Source specify DVASPECT_ICON? BOOL fSrcOnlyIconicOD; // Does Source specify OLEMISC_ONLYICONIC? HGLOBAL hMetaPictOD; // Metafile containing icon and icon title HGLOBAL hObjDesc; // Handle to OBJECTDESCRIPTOR structure from which the // above information is obtained // Information obtained from LINKSRCDESCRIPTOR. This infomation is accessed when the PasteLink // radio button is selected. CLSID clsidLSD; // ClassID of source SIZEL sizelLSD; // sizel transfered in // LinkSrcDescriptor TCHAR szFullUserTypeNameLSD[PS_UNKNOWNNAMELEN];// Full User Type Name TCHAR szSourceOfDataLSD[PS_UNKNOWNNAMELEN]; // Source of Data BOOL fSrcAspectIconLSD; // Does Source specify DVASPECT_ICON? BOOL fSrcOnlyIconicLSD; // Does Source specify OLEMISC_ONLYICONIC? HGLOBAL hMetaPictLSD; // Metafile containing icon and icon title HGLOBAL hLinkSrcDesc; // Handle to LINKSRCDESCRIPTOR structure from which the // above information is obtained BOOL fClipboardChanged; // Has clipboard content changed // if so bring down dlg after // ChangeIcon dlg returns. } PASTESPECIAL, *PPASTESPECIAL, FAR *LPPASTESPECIAL; // Data corresponding to each list item. A pointer to this structure is attached to each // Paste\PasteLink list box item using LB_SETITEMDATA typedef struct tagPASTELISTITEMDATA { int nPasteEntriesIndex; // Index of arrPasteEntries[] corresponding to list item BOOL fCntrEnableIcon; // Does calling application (called container here) // specify OLEUIPASTE_ENABLEICON for this item? } PASTELISTITEMDATA, *PPASTELISTITEMDATA, FAR *LPPASTELISTITEMDATA; // Internal function prototypes // PASTESPL.CPP INT_PTR CALLBACK PasteSpecialDialogProc(HWND, UINT, WPARAM, LPARAM); BOOL FPasteSpecialInit(HWND hDlg, WPARAM, LPARAM); BOOL FTogglePasteType(HWND, LPPASTESPECIAL, DWORD); void ChangeListSelection(HWND, LPPASTESPECIAL, HWND); void EnableDisplayAsIcon(HWND, LPPASTESPECIAL); void ToggleDisplayAsIcon(HWND, LPPASTESPECIAL); void ChangeIcon(HWND, LPPASTESPECIAL); void SetPasteSpecialHelpResults(HWND, LPPASTESPECIAL); BOOL FAddPasteListItem(HWND, BOOL, int, LPPASTESPECIAL, LPTSTR, LPTSTR); BOOL FFillPasteList(HWND, LPPASTESPECIAL); BOOL FFillPasteLinkList(HWND, LPPASTESPECIAL); BOOL FHasPercentS(LPCTSTR, LPPASTESPECIAL); HGLOBAL AllocateScratchMem(LPPASTESPECIAL); void FreeListData(HWND); BOOL FPasteSpecialReInit(HWND hDlg, LPPASTESPECIAL lpPS); /* * OleUIPasteSpecial * * Purpose: * Invokes the standard OLE Paste Special dialog box which allows the user * to select the format of the clipboard object to be pasted or paste linked. * * Parameters: * lpPS LPOLEUIPasteSpecial pointing to the in-out structure * for this dialog. * * Return Value: * UINT One of the following codes or one of the standard error codes (OLEUI_ERR_*) * defined in OLEDLG.H, indicating success or error: * OLEUI_OK User selected OK * OLEUI_CANCEL User cancelled the dialog * OLEUI_IOERR_SRCDATAOBJECTINVALID lpSrcDataObject field of OLEUIPASTESPECIAL invalid * OLEUI_IOERR_ARRPASTEENTRIESINVALID arrPasteEntries field of OLEUIPASTESPECIAL invalid * OLEUI_IOERR_ARRLINKTYPESINVALID arrLinkTypes field of OLEUIPASTESPECIAL invalid * OLEUI_PSERR_CLIPBOARDCHANGED Clipboard contents changed while dialog was up */ STDAPI_(UINT) OleUIPasteSpecial(LPOLEUIPASTESPECIAL lpPS) { UINT uRet; HGLOBAL hMemDlg=NULL; uRet = UStandardValidation((LPOLEUISTANDARD)lpPS, sizeof(OLEUIPASTESPECIAL), &hMemDlg); if (uRet != OLEUI_SUCCESS) return uRet; // Validate PasteSpecial specific fields if (NULL != lpPS->lpSrcDataObj && IsBadReadPtr(lpPS->lpSrcDataObj, sizeof(IDataObject))) { uRet = OLEUI_IOERR_SRCDATAOBJECTINVALID; } if (NULL == lpPS->arrPasteEntries || IsBadReadPtr(lpPS->arrPasteEntries, lpPS->cPasteEntries * sizeof(OLEUIPASTEENTRY))) { uRet = OLEUI_IOERR_ARRPASTEENTRIESINVALID; } if (0 > lpPS->cLinkTypes || lpPS->cLinkTypes > PS_MAXLINKTYPES || IsBadReadPtr(lpPS->arrLinkTypes, lpPS->cLinkTypes * sizeof(UINT))) { uRet = OLEUI_IOERR_ARRLINKTYPESINVALID; } if (0 != lpPS->cClsidExclude && IsBadReadPtr(lpPS->lpClsidExclude, lpPS->cClsidExclude * sizeof(CLSID))) { uRet = OLEUI_IOERR_LPCLSIDEXCLUDEINVALID; } // If IDataObject passed is NULL, collect it from the clipboard if (NULL == lpPS->lpSrcDataObj) { if (OleGetClipboard(&lpPS->lpSrcDataObj) != NOERROR) uRet = OLEUI_PSERR_GETCLIPBOARDFAILED; if (NULL == lpPS->lpSrcDataObj) uRet = OLEUI_PSERR_GETCLIPBOARDFAILED; } if (uRet >= OLEUI_ERR_STANDARDMIN) { return uRet; } UINT nIDD = bWin4 ? IDD_PASTESPECIAL4 : IDD_PASTESPECIAL; //Now that we've validated everything, we can invoke the dialog. uRet = UStandardInvocation(PasteSpecialDialogProc, (LPOLEUISTANDARD)lpPS, hMemDlg, MAKEINTRESOURCE(nIDD)); return uRet; } /* * PasteSpecialDialogProc * * Purpose: * Implements the OLE Paste Special dialog as invoked through the * OleUIPasteSpecial function. * * Parameters: * Standard * * Return Value: * Standard */ INT_PTR CALLBACK PasteSpecialDialogProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam) { // Declare Win16/Win32 compatible WM_COMMAND parameters. COMMANDPARAMS(wID, wCode, hWndMsg); // This will fail under WM_INITDIALOG, where we allocate it. UINT fHook = FALSE; LPPASTESPECIAL lpPS = (LPPASTESPECIAL)LpvStandardEntry( hDlg, iMsg, wParam, lParam, &fHook); LPOLEUIPASTESPECIAL lpOPS = NULL; if (lpPS != NULL) lpOPS = lpPS->lpOPS; //If the hook processed the message, we're done. if (0!=fHook) return (INT_PTR)fHook; // Process help message from Change Icon if (iMsg == uMsgHelp) { // if lPS is NULL (in low memory situations, just ignore it. if (lpPS != NULL) { PostMessage(lpPS->lpOPS->hWndOwner, uMsgHelp, wParam, lParam); } return FALSE; } //Process the temination message if (iMsg == uMsgEndDialog) { EndDialog(hDlg, wParam); return TRUE; } switch (iMsg) { case WM_DESTROY: if (lpPS) { HWND hwndNextViewer; // Free the icon/icon-title metafile corresponding to Paste/PasteList option which is not selected if (lpPS->fLink) OleUIMetafilePictIconFree(lpPS->hMetaPictOD); else OleUIMetafilePictIconFree(lpPS->hMetaPictLSD); // Free data associated with each list box entry FreeListData(GetDlgItem(hDlg, IDC_PS_PASTELIST)); FreeListData(GetDlgItem(hDlg, IDC_PS_PASTELINKLIST)); //Free any specific allocations before calling StandardCleanup if (lpPS->hObjDesc) GlobalFree(lpPS->hObjDesc); if (lpPS->hLinkSrcDesc) GlobalFree(lpPS->hLinkSrcDesc); if (lpPS->hBuff) { GlobalFree(lpPS->hBuff); lpPS->hBuff = NULL; } // Change the clipboard notification chain hwndNextViewer = (HWND)GetProp(hDlg, NEXTCBVIEWER); if (hwndNextViewer != HWND_BROADCAST) { SetProp(hDlg, NEXTCBVIEWER, HWND_BROADCAST); ChangeClipboardChain(hDlg, hwndNextViewer); } RemoveProp(hDlg, NEXTCBVIEWER); StandardCleanup(lpPS, hDlg); } break; case WM_INITDIALOG: FPasteSpecialInit(hDlg, wParam, lParam); return FALSE; case WM_DRAWCLIPBOARD: { HWND hwndNextViewer = (HWND)GetProp(hDlg, NEXTCBVIEWER); HWND hDlg_ChgIcon; if (hwndNextViewer == HWND_BROADCAST) break; if (hwndNextViewer) { SendMessage(hwndNextViewer, iMsg, wParam, lParam); // Refresh next viewer in case it got modified // by the SendMessage() (likely if multiple // PasteSpecial dialogs are up simultaneously) hwndNextViewer = (HWND)GetProp(hDlg, NEXTCBVIEWER); } if (!(lpPS->dwFlags & PSF_STAYONCLIPBOARDCHANGE)) { SetProp(hDlg, NEXTCBVIEWER, HWND_BROADCAST); ChangeClipboardChain(hDlg, hwndNextViewer); /* OLE2NOTE: if the ChangeIcon dialog is currently up, then ** we need to defer bringing down PasteSpecial dialog ** until after ChangeIcon dialog returns. if the ** ChangeIcon dialog is NOT up, then we can bring down ** the PasteSpecial dialog immediately. */ if ((hDlg_ChgIcon=(HWND)GetProp(hDlg,PROP_HWND_CHGICONDLG))!=NULL) { // ChangeIcon dialog is UP lpPS->fClipboardChanged = TRUE; } else { // ChangeIcon dialog is NOT up // Free icon and icon title metafile SendDlgItemMessage( hDlg, IDC_PS_ICONDISPLAY, IBXM_IMAGEFREE, 0, 0L); SendMessage( hDlg, uMsgEndDialog, OLEUI_PSERR_CLIPBOARDCHANGED,0L); } } else { // skip refresh, ignoring clipboard change if PSF_NOREFRESHDATAOBJECT if (lpPS->dwFlags & PSF_NOREFRESHDATAOBJECT) break; // release current data object if (lpOPS->lpSrcDataObj != NULL) { lpOPS->lpSrcDataObj->Release(); lpOPS->lpSrcDataObj = NULL; } // obtain new one if (OleGetClipboard(&lpOPS->lpSrcDataObj) != NOERROR) { SendMessage(hDlg, uMsgEndDialog, OLEUI_PSERR_GETCLIPBOARDFAILED, 0); break; } // otherwise update the display to the new clipboard object FPasteSpecialReInit(hDlg, lpPS); } } break; case WM_CHANGECBCHAIN: { HWND hwndNextViewer = (HWND)GetProp(hDlg, NEXTCBVIEWER); if ((HWND)wParam == hwndNextViewer) SetProp(hDlg, NEXTCBVIEWER, (hwndNextViewer = (HWND)lParam)); else if (hwndNextViewer && hwndNextViewer != HWND_BROADCAST) SendMessage(hwndNextViewer, iMsg, wParam, lParam); } break; case WM_COMMAND: switch (wID) { case IDC_PS_PASTE: FTogglePasteType(hDlg, lpPS, PSF_SELECTPASTE); break; case IDC_PS_PASTELINK: FTogglePasteType(hDlg, lpPS, PSF_SELECTPASTELINK); break; case IDC_PS_DISPLAYLIST: switch (wCode) { case LBN_SELCHANGE: ChangeListSelection(hDlg, lpPS, hWndMsg); break; case LBN_DBLCLK: // Same as pressing OK if (IsWindowEnabled(GetDlgItem(hDlg, IDOK))) SendCommand(hDlg, IDOK, BN_CLICKED, hWndMsg); break; } break; case IDC_PS_DISPLAYASICON: ToggleDisplayAsIcon(hDlg, lpPS); break; case IDC_PS_CHANGEICON: ChangeIcon(hDlg, lpPS); if (lpPS->fClipboardChanged) { // Free icon and icon title metafile SendDlgItemMessage( hDlg, IDC_PS_ICONDISPLAY, IBXM_IMAGEFREE,0,0L); SendMessage(hDlg, uMsgEndDialog, OLEUI_PSERR_CLIPBOARDCHANGED, 0L); } break; case IDOK: { BOOL fDestAspectIcon = ((lpPS->dwFlags & PSF_CHECKDISPLAYASICON) ? TRUE : FALSE); // Return current flags lpOPS->dwFlags = lpPS->dwFlags; // Return index of arrPasteEntries[] corresponding to format selected by user lpOPS->nSelectedIndex = lpPS->nSelectedIndex; // Return if user selected Paste or PasteLink lpOPS->fLink = lpPS->fLink; /* if user selected same ASPECT as displayed in the ** source, then sizel passed in the ** ObjectDescriptor/LinkSrcDescriptor is ** applicable. otherwise, the sizel does not apply. */ if (lpPS->fLink) { if (lpPS->fSrcAspectIconLSD == fDestAspectIcon) lpOPS->sizel = lpPS->sizelLSD; else lpOPS->sizel.cx = lpOPS->sizel.cy = 0; } else { if (lpPS->fSrcAspectIconOD == fDestAspectIcon) lpOPS->sizel = lpPS->sizelOD; else lpOPS->sizel.cx = lpOPS->sizel.cy = 0; } // Return metafile with icon and icon title that the user selected lpOPS->hMetaPict = (HGLOBAL)SendDlgItemMessage(hDlg, IDC_PS_ICONDISPLAY, IBXM_IMAGEGET, 0, 0L); SendMessage(hDlg, uMsgEndDialog, OLEUI_OK, 0L); } break; case IDCANCEL: // Free icon and icon title metafile SendDlgItemMessage( hDlg, IDC_PS_ICONDISPLAY, IBXM_IMAGEFREE, 0, 0L); SendMessage(hDlg, uMsgEndDialog, OLEUI_CANCEL, 0L); break; case IDC_OLEUIHELP: PostMessage(lpPS->lpOPS->hWndOwner, uMsgHelp, (WPARAM)hDlg, MAKELPARAM(IDD_PASTESPECIAL, 0)); break; } break; } return FALSE; } BOOL FPasteSpecialReInit(HWND hDlg, LPPASTESPECIAL lpPS) { LPOLEUIPASTESPECIAL lpOPS = lpPS->lpOPS; // free the icon/icon-title metafiel if (lpPS->fLink) OleUIMetafilePictIconFree(lpPS->hMetaPictOD); else OleUIMetafilePictIconFree(lpPS->hMetaPictLSD); // Free data assocatiated with each list box entry FreeListData(GetDlgItem(hDlg, IDC_PS_PASTELIST)); FreeListData(GetDlgItem(hDlg, IDC_PS_PASTELINKLIST)); SendDlgItemMessage(hDlg, IDC_PS_DISPLAYLIST, LB_RESETCONTENT, 0, 0); // Initialize user selections in the Paste and PasteLink listboxes lpPS->nPasteListCurSel = 0; lpPS->nPasteLinkListCurSel = 0; // Free previous object descriptor/link descriptor data if (lpPS->hObjDesc != NULL) { GlobalFree(lpPS->hObjDesc); lpPS->hObjDesc = NULL; } if (lpPS->hLinkSrcDesc != NULL) { GlobalFree(lpPS->hLinkSrcDesc); lpPS->hLinkSrcDesc = NULL; } lpPS->szAppName[0] = '\0'; // GetData CF_OBJECTDESCRIPTOR. If the object on the clipboard in an // OLE1 object (offering CF_OWNERLINK) or has been copied to // clipboard by FileMaager (offering CF_FILENAME), an // OBJECTDESCRIPTOR will be created will be created from CF_OWNERLINK // or CF_FILENAME. See OBJECTDESCRIPTOR for more info. STGMEDIUM medium; CLIPFORMAT cfFormat; lpPS->hObjDesc = OleStdFillObjectDescriptorFromData( lpOPS->lpSrcDataObj, &medium, &cfFormat); if (lpPS->hObjDesc) { LPOBJECTDESCRIPTOR lpOD = (LPOBJECTDESCRIPTOR)GlobalLock(lpPS->hObjDesc); // Get FullUserTypeName, SourceOfCopy and CLSID if (lpOD->dwFullUserTypeName) #if defined(WIN32) && !defined(UNICODE) WTOA(lpPS->szFullUserTypeNameOD, (LPWSTR)((LPBYTE)lpOD+lpOD->dwFullUserTypeName), PS_UNKNOWNNAMELEN); #else lstrcpyn(lpPS->szFullUserTypeNameOD, (LPTSTR)((LPBYTE)lpOD+lpOD->dwFullUserTypeName), PS_UNKNOWNNAMELEN); #endif else lstrcpyn(lpPS->szFullUserTypeNameOD, lpPS->szUnknownType, PS_UNKNOWNNAMELEN); if (lpOD->dwSrcOfCopy) { #if defined(WIN32) && !defined(UNICODE) WTOA(lpPS->szSourceOfDataOD, (LPWSTR)((LPBYTE)lpOD+lpOD->dwSrcOfCopy), PS_UNKNOWNNAMELEN); #else lstrcpyn(lpPS->szSourceOfDataOD, (LPTSTR)((LPBYTE)lpOD+lpOD->dwSrcOfCopy), PS_UNKNOWNNAMELEN); #endif // If CF_FILENAME was offered, source of copy is a // path name. Fit the path to the static control that will display it. if (cfFormat == _g_cfFileName) { lstrcpyn(lpPS->szSourceOfDataOD, ChopText(GetDlgItem(hDlg, IDC_PS_SOURCETEXT), 0, lpPS->szSourceOfDataOD, 0), PS_UNKNOWNNAMELEN); } } else lstrcpyn(lpPS->szSourceOfDataOD, lpPS->szUnknownSource, PS_UNKNOWNNAMELEN); lpPS->clsidOD = lpOD->clsid; lpPS->sizelOD = lpOD->sizel; // Does source specify DVASPECT_ICON? if (lpOD->dwDrawAspect & DVASPECT_ICON) lpPS->fSrcAspectIconOD = TRUE; else lpPS->fSrcAspectIconOD = FALSE; // Does source specify OLEMISC_ONLYICONIC? if (lpOD->dwStatus & OLEMISC_ONLYICONIC) lpPS->fSrcOnlyIconicOD = TRUE; else lpPS->fSrcOnlyIconicOD = FALSE; // Get application name of source from auxusertype3 in the registration database LPOLESTR lpszAppName = NULL; if (OleRegGetUserType(lpPS->clsidOD, USERCLASSTYPE_APPNAME, &lpszAppName) == NOERROR) { #if defined(WIN32) && !defined(UNICODE) WTOA(lpPS->szAppName, lpszAppName, OLEUI_CCHKEYMAX); #else lstrcpyn(lpPS->szAppName, lpszAppName, OLEUI_CCHKEYMAX); #endif OleStdFree(lpszAppName); } else { if (0 == LoadString(_g_hOleStdResInst, IDS_PSUNKNOWNAPP, lpPS->szAppName, PS_UNKNOWNSTRLEN)) { PostMessage(hDlg, uMsgEndDialog, OLEUI_ERR_LOADSTRING, 0L); return FALSE; } } // Retrieve an icon from the object if (lpPS->fSrcAspectIconOD) { lpPS->hMetaPictOD = OleStdGetData( lpOPS->lpSrcDataObj, (CLIPFORMAT) CF_METAFILEPICT, NULL, DVASPECT_ICON, &medium ); } // If object does not offer icon, obtain it from the CLSID if (NULL == lpPS->hMetaPictOD) lpPS->hMetaPictOD = OleGetIconOfClass(lpPS->clsidOD, NULL, TRUE); } // Does object offer CF_LINKSRCDESCRIPTOR? lpPS->hLinkSrcDesc = OleStdGetData( lpOPS->lpSrcDataObj, (CLIPFORMAT) _g_cfLinkSrcDescriptor, NULL, DVASPECT_CONTENT, &medium); if (lpPS->hLinkSrcDesc) { // Get FullUserTypeName, SourceOfCopy and CLSID LPLINKSRCDESCRIPTOR lpLSD = (LPLINKSRCDESCRIPTOR)GlobalLock(lpPS->hLinkSrcDesc); if (lpLSD->dwFullUserTypeName) #if defined(WIN32) && !defined(UNICODE) WTOA(lpPS->szFullUserTypeNameLSD, (LPWSTR)((LPBYTE)lpLSD+lpLSD->dwFullUserTypeName), PS_UNKNOWNNAMELEN); #else lstrcpyn(lpPS->szFullUserTypeNameLSD, (LPTSTR)((LPBYTE)lpLSD+lpLSD->dwFullUserTypeName), PS_UNKNOWNNAMELEN); #endif else lstrcpyn(lpPS->szFullUserTypeNameLSD, lpPS->szUnknownType, PS_UNKNOWNNAMELEN); if (lpLSD->dwSrcOfCopy) #if defined(WIN32) && !defined(UNICODE) WTOA(lpPS->szSourceOfDataLSD, (LPWSTR)((LPBYTE)lpLSD+lpLSD->dwSrcOfCopy), PS_UNKNOWNNAMELEN); #else lstrcpyn(lpPS->szSourceOfDataLSD, (LPTSTR)((LPBYTE)lpLSD+lpLSD->dwSrcOfCopy), PS_UNKNOWNNAMELEN); #endif else lstrcpyn(lpPS->szSourceOfDataLSD, lpPS->szUnknownSource, PS_UNKNOWNNAMELEN); // if no ObjectDescriptor, then use LinkSourceDescriptor source string if (!lpPS->hObjDesc) lstrcpyn(lpPS->szSourceOfDataOD, lpPS->szSourceOfDataLSD, PS_UNKNOWNNAMELEN); lpPS->clsidLSD = lpLSD->clsid; lpPS->sizelLSD = lpLSD->sizel; // Does source specify DVASPECT_ICON? if (lpLSD->dwDrawAspect & DVASPECT_ICON) lpPS->fSrcAspectIconLSD = TRUE; else lpPS->fSrcAspectIconLSD = FALSE; // Does source specify OLEMISC_ONLYICONIC? if (lpLSD->dwStatus & OLEMISC_ONLYICONIC) lpPS->fSrcOnlyIconicLSD = TRUE; else lpPS->fSrcOnlyIconicLSD = FALSE; // Retrieve an icon from the object if (lpPS->fSrcAspectIconLSD) { lpPS->hMetaPictLSD = OleStdGetData( lpOPS->lpSrcDataObj, CF_METAFILEPICT, NULL, DVASPECT_ICON, &medium ); } // If object does not offer icon, obtain it from the CLSID if (NULL == lpPS->hMetaPictLSD) { HWND hIconWnd = GetDlgItem(hDlg, IDC_PS_ICONDISPLAY); RECT IconRect; GetClientRect(hIconWnd, &IconRect); LPTSTR lpszLabel = OleStdCopyString(lpPS->szSourceOfDataLSD); // width is 2 times width of iconbox because it can wrap int nWidth = (IconRect.right-IconRect.left) * 2; // limit text to the width or max characters LPTSTR lpszChopLabel = ChopText(hIconWnd, nWidth, lpszLabel, lstrlen(lpszLabel)); #if defined(WIN32) && !defined(UNICODE) OLECHAR wszChopLabel[MAX_PATH]; ATOW(wszChopLabel, lpszChopLabel, MAX_PATH); lpPS->hMetaPictLSD = OleGetIconOfClass(lpPS->clsidLSD, wszChopLabel, FALSE); #else lpPS->hMetaPictLSD = OleGetIconOfClass(lpPS->clsidLSD, lpszChopLabel, FALSE); #endif OleStdFree(lpszLabel); } } else if (lpPS->hObjDesc) // Does not offer CF_LINKSRCDESCRIPTOR but offers CF_OBJECTDESCRIPTOR { // Copy the values of OBJECTDESCRIPTOR lstrcpyn(lpPS->szFullUserTypeNameLSD, lpPS->szFullUserTypeNameOD, PS_UNKNOWNNAMELEN); lstrcpyn(lpPS->szSourceOfDataLSD, lpPS->szSourceOfDataOD, PS_UNKNOWNNAMELEN); lpPS->clsidLSD = lpPS->clsidOD; lpPS->sizelLSD = lpPS->sizelOD; lpPS->fSrcAspectIconLSD = lpPS->fSrcAspectIconOD; lpPS->fSrcOnlyIconicLSD = lpPS->fSrcOnlyIconicOD; // Don't copy the hMetaPict; instead get a separate copy if (lpPS->fSrcAspectIconLSD) { lpPS->hMetaPictLSD = OleStdGetData( lpOPS->lpSrcDataObj, CF_METAFILEPICT, NULL, DVASPECT_ICON, &medium ); } if (NULL == lpPS->hMetaPictLSD) { HWND hIconWnd = GetDlgItem(hDlg, IDC_PS_ICONDISPLAY); RECT IconRect; GetClientRect(hIconWnd, &IconRect); LPTSTR lpszLabel = OleStdCopyString(lpPS->szSourceOfDataLSD); // width is 2 times width of iconbox because it can wrap int nWidth = (IconRect.right-IconRect.left) * 2; // limit text to the width or max characters LPTSTR lpszChopLabel = ChopText(hIconWnd, nWidth, lpszLabel, lstrlen(lpszLabel)); #if defined(WIN32) && !defined(UNICODE) OLECHAR wszChopLabel[MAX_PATH]; ATOW(wszChopLabel, lpszChopLabel, MAX_PATH); lpPS->hMetaPictLSD = OleGetIconOfClass(lpPS->clsidLSD, wszChopLabel, FALSE); #else lpPS->hMetaPictLSD = OleGetIconOfClass(lpPS->clsidLSD, lpszChopLabel, FALSE); #endif OleStdFree(lpszLabel); } } // Not an OLE object if (lpPS->hObjDesc == NULL && lpPS->hLinkSrcDesc == NULL) { lstrcpyn(lpPS->szFullUserTypeNameLSD, lpPS->szUnknownType, PS_UNKNOWNNAMELEN); lstrcpyn(lpPS->szFullUserTypeNameOD, lpPS->szUnknownType, PS_UNKNOWNNAMELEN); lstrcpyn(lpPS->szSourceOfDataLSD, lpPS->szUnknownSource, PS_UNKNOWNNAMELEN); lstrcpyn(lpPS->szSourceOfDataOD, lpPS->szUnknownSource, PS_UNKNOWNNAMELEN); lpPS->hMetaPictLSD = lpPS->hMetaPictOD = NULL; } // Allocate scratch memory to construct item names in the paste and pastelink listboxes if (lpPS->hBuff != NULL) { GlobalFree(lpPS->hBuff); lpPS->hBuff = NULL; } lpPS->hBuff = AllocateScratchMem(lpPS); if (lpPS->hBuff == NULL) { PostMessage(hDlg, uMsgEndDialog, OLEUI_ERR_GLOBALMEMALLOC, 0L); return FALSE; } // Select the Paste Link Button if specified. Otherwise select // Paste Button by default if (lpPS->dwFlags & PSF_SELECTPASTELINK) lpPS->dwFlags = (lpPS->dwFlags & ~PSF_SELECTPASTE) | PSF_SELECTPASTELINK; else lpPS->dwFlags =(lpPS->dwFlags & ~PSF_SELECTPASTELINK) | PSF_SELECTPASTE; // Mark which PasteEntry formats are available from source data object OleStdMarkPasteEntryList( lpOPS->lpSrcDataObj, lpOPS->arrPasteEntries, lpOPS->cPasteEntries); // Check if items are available to be pasted BOOL fPasteAvailable = FFillPasteList(hDlg, lpPS); if (!fPasteAvailable) lpPS->dwFlags &= ~PSF_SELECTPASTE; StandardEnableDlgItem(hDlg, IDC_PS_PASTE, fPasteAvailable); // Check if items are available to be paste-linked BOOL fPasteLinkAvailable = FFillPasteLinkList(hDlg, lpPS); if (!fPasteLinkAvailable) lpPS->dwFlags &= ~PSF_SELECTPASTELINK; StandardEnableDlgItem(hDlg, IDC_PS_PASTELINK, fPasteLinkAvailable); // If one of Paste or PasteLink is disabled, select the other one // regardless of what the input flags say if (fPasteAvailable && !fPasteLinkAvailable) lpPS->dwFlags |= PSF_SELECTPASTE; if (fPasteLinkAvailable && !fPasteAvailable) lpPS->dwFlags |= PSF_SELECTPASTELINK; BOOL bEnabled = TRUE; if (lpPS->dwFlags & PSF_SELECTPASTE) { // FTogglePaste will set the PSF_SELECTPASTE flag, so clear it. lpPS->dwFlags &= ~PSF_SELECTPASTE; CheckRadioButton(hDlg, IDC_PS_PASTE, IDC_PS_PASTELINK, IDC_PS_PASTE); FTogglePasteType(hDlg, lpPS, PSF_SELECTPASTE); } else if (lpPS->dwFlags & PSF_SELECTPASTELINK) { // FTogglePaste will set the PSF_SELECTPASTELINK flag, so clear it. lpPS->dwFlags &= ~PSF_SELECTPASTELINK; CheckRadioButton(hDlg, IDC_PS_PASTE, IDC_PS_PASTELINK, IDC_PS_PASTELINK); FTogglePasteType(hDlg, lpPS, PSF_SELECTPASTELINK); } else // Items are not available to be be Pasted or Paste-Linked { // Enable or disable DisplayAsIcon and set the result text and image EnableDisplayAsIcon(hDlg, lpPS); SetPasteSpecialHelpResults(hDlg, lpPS); SetDlgItemText(hDlg, IDC_PS_SOURCETEXT, lpPS->szSourceOfDataOD); CheckRadioButton(hDlg, IDC_PS_PASTE, IDC_PS_PASTELINK, 0); bEnabled = FALSE; } StandardEnableDlgItem(hDlg, IDOK, bEnabled); return TRUE; } /* * FPasteSpecialInit * * Purpose: * WM_INITIDIALOG handler for the Paste Special dialog box. * * Parameters: * hDlg HWND of the dialog * wParam WPARAM of the message * lParam LPARAM of the message * * Return Value: * BOOL Value to return for WM_INITDIALOG. */ BOOL FPasteSpecialInit(HWND hDlg, WPARAM wParam, LPARAM lParam) { // Copy the structure at lParam into our instance memory. HFONT hFont; LPPASTESPECIAL lpPS = (LPPASTESPECIAL)LpvStandardInit(hDlg, sizeof(PASTESPECIAL), &hFont); // PvStandardInit sent a termination to us already. if (NULL == lpPS) return FALSE; LPOLEUIPASTESPECIAL lpOPS = (LPOLEUIPASTESPECIAL)lParam; // Copy other information from lpOPS that we might modify. lpPS->lpOPS = lpOPS; lpPS->nIDD = IDD_PASTESPECIAL; lpPS->dwFlags = lpOPS->dwFlags; // If we got a font, send it to the necessary controls. if (NULL!=hFont) { SendDlgItemMessage(hDlg, IDC_PS_SOURCETEXT, WM_SETFONT, (WPARAM)hFont, 0L); SendDlgItemMessage(hDlg, IDC_PS_RESULTTEXT, WM_SETFONT, (WPARAM)hFont, 0L); } // Hide the help button if required if (!(lpPS->lpOPS->dwFlags & PSF_SHOWHELP)) StandardShowDlgItem(hDlg, IDC_OLEUIHELP, SW_HIDE); // Show or hide the Change icon button if (lpPS->dwFlags & PSF_HIDECHANGEICON) DestroyWindow(GetDlgItem(hDlg, IDC_PS_CHANGEICON)); // Hide all DisplayAsIcon related controls if it should be disabled if (lpPS->dwFlags & PSF_DISABLEDISPLAYASICON) { StandardShowDlgItem(hDlg, IDC_PS_DISPLAYASICON, SW_HIDE); StandardShowDlgItem(hDlg, IDC_PS_CHANGEICON, SW_HIDE); StandardShowDlgItem(hDlg, IDC_PS_ICONDISPLAY, SW_HIDE); } // clear PSF_CHECKDISPLAYASICON -> it's an output parameter only lpPS->dwFlags &= ~ PSF_CHECKDISPLAYASICON; // Change the caption if required if (NULL != lpOPS->lpszCaption) SetWindowText(hDlg, lpOPS->lpszCaption); // Load 'Unknown Source' and 'Unknown Type' strings int n = LoadString(_g_hOleStdResInst, IDS_PSUNKNOWNTYPE, lpPS->szUnknownType, PS_UNKNOWNSTRLEN); if (n) n = LoadString(_g_hOleStdResInst, IDS_PSUNKNOWNSRC, lpPS->szUnknownSource, PS_UNKNOWNSTRLEN); if (!n) { PostMessage(hDlg, uMsgEndDialog, OLEUI_ERR_LOADSTRING, 0L); return FALSE; } if (!FPasteSpecialReInit(hDlg, lpPS)) return FALSE; // Give initial focus to the list box SetFocus(GetDlgItem(hDlg, IDC_PS_DISPLAYLIST)); // Set property to handle clipboard change notifications SetProp(hDlg, NEXTCBVIEWER, HWND_BROADCAST); SetProp(hDlg, NEXTCBVIEWER, SetClipboardViewer(hDlg)); lpPS->fClipboardChanged = FALSE; /* * PERFORM OTHER INITIALIZATION HERE. */ // Call the hook with lCustData in lParam UStandardHook(lpPS, hDlg, WM_INITDIALOG, wParam, lpOPS->lCustData); return TRUE; } /* * FTogglePasteType * * Purpose: * Toggles between Paste and Paste Link. The Paste list and PasteLink * list are always invisible. The Display List is filled from either * the Paste list or the PasteLink list depending on which Paste radio * button is selected. * * Parameters: * hDlg HWND of the dialog * lpPS Paste Special Dialog Structure * dwOption Paste or PasteSpecial option * * Return Value: * BOOL Returns TRUE if the option has already been selected. * Otherwise the option is selected and FALSE is returned */ BOOL FTogglePasteType(HWND hDlg, LPPASTESPECIAL lpPS, DWORD dwOption) { DWORD dwTemp; HWND hList, hListDisplay; LRESULT dwData; int i, nItems; LPTSTR lpsz; // Skip all this if the button is already selected if (lpPS->dwFlags & dwOption) return TRUE; dwTemp = PSF_SELECTPASTE | PSF_SELECTPASTELINK; lpPS->dwFlags = (lpPS->dwFlags & ~dwTemp) | dwOption; // Hide IconDisplay. This prevents flashing if the icon display is changed StandardShowDlgItem(hDlg, IDC_PS_ICONDISPLAY, SW_HIDE); hListDisplay = GetDlgItem(hDlg, IDC_PS_DISPLAYLIST); // If Paste was selected if (lpPS->dwFlags & PSF_SELECTPASTE) { // Set the Source of the object in the clipboard SetDlgItemText(hDlg, IDC_PS_SOURCETEXT, lpPS->szSourceOfDataOD); // If an icon is available if (lpPS->hMetaPictOD) // Set the icon display SendDlgItemMessage(hDlg, IDC_PS_ICONDISPLAY, IBXM_IMAGESET, 0, (LPARAM)lpPS->hMetaPictOD); hList = GetDlgItem(hDlg, IDC_PS_PASTELIST); // We are switching from PasteLink to Paste. Remember current selection // in PasteLink list so it can be restored. lpPS->nPasteLinkListCurSel = (int)SendMessage(hListDisplay, LB_GETCURSEL, 0, 0L); if (lpPS->nPasteLinkListCurSel == LB_ERR) lpPS->nPasteLinkListCurSel = 0; // Remember if user selected Paste or PasteLink lpPS->fLink = FALSE; } else // If PasteLink was selected { // Set the Source of the object in the clipboard SetDlgItemText(hDlg, IDC_PS_SOURCETEXT, lpPS->szSourceOfDataLSD); // If an icon is available if (lpPS->hMetaPictLSD) // Set the icon display SendDlgItemMessage(hDlg, IDC_PS_ICONDISPLAY, IBXM_IMAGESET, 0, (LPARAM)lpPS->hMetaPictLSD); hList = GetDlgItem(hDlg, IDC_PS_PASTELINKLIST); // We are switching from Paste to PasteLink. Remember current selection // in Paste list so it can be restored. lpPS->nPasteListCurSel = (int)SendMessage(hListDisplay, LB_GETCURSEL, 0, 0L); if (lpPS->nPasteListCurSel == LB_ERR) lpPS->nPasteListCurSel = 0; // Remember if user selected Paste or PasteLink lpPS->fLink = TRUE; } // Turn drawing off while the Display List is being filled SendMessage(hListDisplay, WM_SETREDRAW, (WPARAM)FALSE, 0L); // Move data to Display list box SendMessage(hListDisplay, LB_RESETCONTENT, 0, 0L); nItems = (int) SendMessage(hList, LB_GETCOUNT, 0, 0L); lpsz = (LPTSTR)GlobalLock(lpPS->hBuff); for (i = 0; i < nItems; i++) { SendMessage(hList, LB_GETTEXT, (WPARAM)i, (LPARAM)lpsz); dwData = SendMessage(hList, LB_GETITEMDATA, (WPARAM)i, 0L); SendMessage(hListDisplay, LB_INSERTSTRING, (WPARAM)i, (LPARAM)lpsz); SendMessage(hListDisplay, LB_SETITEMDATA, (WPARAM)i, dwData); } GlobalUnlock(lpPS->hBuff); // Restore the selection in the Display List from user's last selection if (lpPS->dwFlags & PSF_SELECTPASTE) SendMessage(hListDisplay, LB_SETCURSEL, lpPS->nPasteListCurSel, 0L); else SendMessage(hListDisplay, LB_SETCURSEL, lpPS->nPasteLinkListCurSel, 0L); // Paint Display List SendMessage(hListDisplay, WM_SETREDRAW, (WPARAM)TRUE, 0L); InvalidateRect(hListDisplay, NULL, TRUE); UpdateWindow(hListDisplay); // Auto give the focus to the Display List if (GetForegroundWindow() == hDlg) SetFocus(hListDisplay); // Enable/Disable DisplayAsIcon and set the help result text and bitmap corresponding to // the current selection ChangeListSelection(hDlg, lpPS, hListDisplay); return FALSE; } /* * ChangeListSelection * * Purpose: * When the user changes the selection in the list, DisplayAsIcon is enabled or disabled, * Result text and bitmap are updated and the index of the arrPasteEntries[] corresponding * to the current format selection is saved. * * Parameters: * hDlg HWND of the dialog * lpPS Paste Special Dialog Structure * hList HWND of the List * * Return Value: * No return value */ void ChangeListSelection(HWND hDlg, LPPASTESPECIAL lpPS, HWND hList) { LPPASTELISTITEMDATA lpItemData; int nCurSel; EnableDisplayAsIcon(hDlg, lpPS); SetPasteSpecialHelpResults(hDlg, lpPS); // Remember index of arrPasteEntries[] corresponding to the current selection nCurSel = (int)SendMessage(hList, LB_GETCURSEL, 0, 0L); if (nCurSel == LB_ERR) return; lpItemData = (LPPASTELISTITEMDATA) SendMessage(hList, LB_GETITEMDATA, (WPARAM)nCurSel, 0L); if ((LRESULT)lpItemData == LB_ERR) return; lpPS->nSelectedIndex = lpItemData->nPasteEntriesIndex; } /* * EnableDisplayAsIcon * * Purpose: * Enable or disable the DisplayAsIcon button depending on whether * the current selection can be displayed as an icon or not. The following table describes * the state of DisplayAsIcon. The calling application is termed CONTAINER, the source * of data on the clipboard is termed SOURCE. * Y = Yes; N = No; Blank = State does not matter; * ===================================================================== * SOURCE SOURCE CONTAINER DisplayAsIcon * specifies specifies specifies Initial State * DVASPECT_ICON OLEMISC_ONLYICONIC OLEUIPASTE_ENABLEICON * * N Unchecked&Disabled * Y Y Checked&Disabled * Y N Y Checked&Enabled * N N Y Unchecked&Enabled * ===================================================================== * * Parameters: * hDlg HWND of the dialog * lpPS Paste Special Dialog Structure * * Return Value: * No return value */ void EnableDisplayAsIcon(HWND hDlg, LPPASTESPECIAL lpPS) { int nIndex; BOOL fCntrEnableIcon; BOOL fSrcOnlyIconic = (lpPS->fLink) ? lpPS->fSrcOnlyIconicLSD : lpPS->fSrcOnlyIconicOD; BOOL fSrcAspectIcon = (lpPS->fLink) ? lpPS->fSrcAspectIconLSD : lpPS->fSrcAspectIconOD; HWND hList; LPPASTELISTITEMDATA lpItemData; HGLOBAL hMetaPict = (lpPS->fLink) ? lpPS->hMetaPictLSD : lpPS->hMetaPictOD; hList = GetDlgItem(hDlg, IDC_PS_DISPLAYLIST); // Get data corresponding to the current selection in the listbox nIndex = (int)SendMessage(hList, LB_GETCURSEL, 0, 0); if (nIndex != LB_ERR) { lpItemData = (LPPASTELISTITEMDATA) SendMessage(hList, LB_GETITEMDATA, (WPARAM)nIndex, 0L); if ((LRESULT)lpItemData != LB_ERR) fCntrEnableIcon = lpItemData->fCntrEnableIcon; else fCntrEnableIcon = FALSE; } else fCntrEnableIcon = FALSE; // If there is an icon available if (hMetaPict != NULL) { if (!fCntrEnableIcon) // Does CONTAINER specify OLEUIPASTE_ENABLEICON? { // Uncheck & Disable DisplayAsIcon lpPS->dwFlags &= ~PSF_CHECKDISPLAYASICON; CheckDlgButton(hDlg, IDC_PS_DISPLAYASICON, FALSE); StandardEnableDlgItem(hDlg, IDC_PS_DISPLAYASICON, FALSE); // Hide IconDisplay and ChangeIcon button StandardShowDlgItem(hDlg, IDC_PS_ICONDISPLAY, SW_HIDE); StandardShowDlgItem(hDlg, IDC_PS_CHANGEICON, SW_HIDE); } else if (fSrcOnlyIconic) // Does SOURCE specify OLEMISC_ONLYICONIC? { // Check & Disable DisplayAsIcon lpPS->dwFlags |= PSF_CHECKDISPLAYASICON; CheckDlgButton(hDlg, IDC_PS_DISPLAYASICON, TRUE); StandardEnableDlgItem(hDlg, IDC_PS_DISPLAYASICON, FALSE); // Show IconDisplay and ChangeIcon button StandardShowDlgItem(hDlg, IDC_PS_ICONDISPLAY, SW_SHOWNORMAL); StandardShowDlgItem(hDlg, IDC_PS_CHANGEICON, SW_SHOWNORMAL); } else if (fSrcAspectIcon) // Does SOURCE specify DVASPECT_ICON? { // Check & Enable DisplayAsIcon lpPS->dwFlags |= PSF_CHECKDISPLAYASICON; CheckDlgButton(hDlg, IDC_PS_DISPLAYASICON, TRUE); StandardEnableDlgItem(hDlg, IDC_PS_DISPLAYASICON, TRUE); // Show IconDisplay and ChangeIcon button StandardShowDlgItem(hDlg, IDC_PS_ICONDISPLAY, SW_SHOWNORMAL); StandardShowDlgItem(hDlg, IDC_PS_CHANGEICON, SW_SHOWNORMAL); } else { //Uncheck and Enable DisplayAsIcon lpPS->dwFlags &= ~PSF_CHECKDISPLAYASICON; CheckDlgButton(hDlg, IDC_PS_DISPLAYASICON, FALSE); StandardEnableDlgItem(hDlg, IDC_PS_DISPLAYASICON, TRUE); // Hide IconDisplay and ChangeIcon button StandardShowDlgItem(hDlg, IDC_PS_ICONDISPLAY, SW_HIDE); StandardShowDlgItem(hDlg, IDC_PS_CHANGEICON, SW_HIDE); } } else // No icon available { // Unchecked & Disabled lpPS->dwFlags &= ~PSF_CHECKDISPLAYASICON; CheckDlgButton(hDlg, IDC_PS_DISPLAYASICON, FALSE); StandardEnableDlgItem(hDlg, IDC_PS_DISPLAYASICON, FALSE); // Hide IconDisplay and ChangeIcon button StandardShowDlgItem(hDlg, IDC_PS_ICONDISPLAY, SW_HIDE); StandardShowDlgItem(hDlg, IDC_PS_CHANGEICON, SW_HIDE); } } /* * ToggleDisplayAsIcon * * Purpose: * Toggles the DisplayAsIcon button. Hides or shows the Icon Display and * the ChangeIcon button and changes the help result text and bitmap. * * Parameters: * hDlg HWND of the dialog * lpPS Paste Special Dialog Structure * * Return Value: * None * */ void ToggleDisplayAsIcon(HWND hDlg, LPPASTESPECIAL lpPS) { BOOL fCheck; int i; fCheck = IsDlgButtonChecked(hDlg, IDC_PS_DISPLAYASICON); if (fCheck) lpPS->dwFlags |= PSF_CHECKDISPLAYASICON; else lpPS->dwFlags &= ~PSF_CHECKDISPLAYASICON; // Set the help result text and bitmap SetPasteSpecialHelpResults(hDlg, lpPS); // Show or hide the Icon Display and ChangeIcon button depending // on the check state i = (fCheck) ? SW_SHOWNORMAL : SW_HIDE; StandardShowDlgItem(hDlg, IDC_PS_ICONDISPLAY, i); StandardShowDlgItem(hDlg, IDC_PS_CHANGEICON, i); } /* * ChangeIcon * * Purpose: * Brings up the ChangeIcon dialog which allows the user to change * the icon and label. * * Parameters: * hDlg HWND of the dialog * lpPS Paste Special Dialog Structure * * Return Value: * None * */ void ChangeIcon(HWND hDlg, LPPASTESPECIAL lpPS) { OLEUICHANGEICON ci; UINT uRet; CLSID clsid = (lpPS->fLink) ? lpPS->clsidLSD : lpPS->clsidOD; //Initialize the structure memset((LPOLEUICHANGEICON)&ci, 0, sizeof(ci)); ci.hMetaPict = (HGLOBAL)SendDlgItemMessage(hDlg, IDC_PS_ICONDISPLAY, IBXM_IMAGEGET, 0, 0L); ci.cbStruct = sizeof(ci); ci.hWndOwner = hDlg; ci.clsid = clsid; ci.dwFlags = CIF_SELECTCURRENT; // Only show help in the ChangeIcon dialog if we're showing it in this dialog. if (lpPS->dwFlags & PSF_SHOWHELP) ci.dwFlags |= CIF_SHOWHELP; // Let the hook in to customize Change Icon if desired. uRet = UStandardHook(lpPS, hDlg, uMsgChangeIcon, 0, (LPARAM)&ci); if (0 == uRet) uRet=(UINT)(OLEUI_OK==OleUIChangeIcon(&ci)); // Update the display if necessary. if (0!=uRet) { /* * OleUIChangeIcon will have already freed our * current hMetaPict that we passed in when OK is * pressed in that dialog. So we use 0L as lParam * here so the IconBox doesn't try to free the * metafilepict again. */ SendDlgItemMessage(hDlg, IDC_PS_ICONDISPLAY, IBXM_IMAGESET, 0, (LPARAM)ci.hMetaPict); // Remember the new icon chosen by the user. Note that Paste and PasteLink have separate // icons - changing one does not change the other. if (lpPS->fLink) lpPS->hMetaPictLSD = ci.hMetaPict; else lpPS->hMetaPictOD = ci.hMetaPict; } } /* *SetPasteSpecialHelpResults * * Purpose: * Sets the help result text and bitmap according to the current * list selection. The following state table indicates which ResultText * and ResultImage are selected. If %s in the lpstrFormatName is present, * it is assumed that an object is being pasted/paste-linked, otherwise it * is assumed that data is being pasted/paste-linked. * Y = Yes; N = No; Blank = State does not matter; * The numbers in the the ResultText and ResultImage columns refer to the table * entries that follow. * ===================================================================== * Paste/ lpstrFormatName in DisplayAsIcon Result Result * PasteLink arrPasteEntry[]contains %s checked Text Image * (Is Object == Y, Is Data == N) * Paste N 1 1 * Paste Y N 2 2 * Paste Y Y 3 3 * PasteLink N 4 4 * PasteLink Y N 5 4 * PasteLink Y Y 6 5 * ===================================================================== * Result Text: * * 1. "Inserts the contents of the Clipboard into your document as " * 2. "Inserts the contents of the Clipboard into your document so that you may * activate it using " * 3. "Inserts the contents of the Clipboard into your document so that you may * activate it using . It will be displayed as an icon." * 4. "Inserts the contents of the Clipboard into your document as . * Paste Link creates a link to the source file so that changes to the source file * will be reflected in your document." * 5. "Inserts a picture of the Clipboard contents into your document. Paste Link * creates a link to the source file so that changes to the source file will be * reflected in your document." * 6. "Inserts an icon into your document which represents the Clipboard contents. * Paste Link creates a link to the source file so that changes to the source file * will be reflected in your document." * ===================================================================== * Result Image: * * 1. Clipboard Image * 2. Paste image, non-iconic. * 3. Paste image, iconic. * 4. Paste Link image, non-iconic * 5. Paste Link image, iconic * ==================================================================== * * Parameters: * hDlg HWND of the dialog * lpPS Paste Special Dialog Structure * * Return Value: * No return value */ void SetPasteSpecialHelpResults(HWND hDlg, LPPASTESPECIAL lpPS) { LPTSTR psz1, psz2, psz3, psz4; UINT i, iString, iImage, cch; int nPasteEntriesIndex; BOOL fDisplayAsIcon; BOOL fIsObject; HWND hList; LPPASTELISTITEMDATA lpItemData; LPOLEUIPASTESPECIAL lpOPS = lpPS->lpOPS; LPTSTR szFullUserTypeName = (lpPS->fLink) ? lpPS->szFullUserTypeNameLSD : lpPS->szFullUserTypeNameOD; LPTSTR szInsert; hList = GetDlgItem(hDlg, IDC_PS_DISPLAYLIST); i=(UINT)SendMessage(hList, LB_GETCURSEL, 0, 0L); if (i != LB_ERR) { lpItemData = (LPPASTELISTITEMDATA)SendMessage(hList, LB_GETITEMDATA, i, 0L); if ((LRESULT)lpItemData == LB_ERR) return; nPasteEntriesIndex = lpItemData->nPasteEntriesIndex; // Check if there is a '%s' in the lpstrFormatName, then an object is being // pasted/pastelinked. Otherwise Data is being pasted-pastelinked. fIsObject = FHasPercentS(lpOPS->arrPasteEntries[nPasteEntriesIndex].lpstrFormatName, lpPS); } else return; // Is DisplayAsIcon checked? fDisplayAsIcon=(0L!=(lpPS->dwFlags & PSF_CHECKDISPLAYASICON)); szInsert = szFullUserTypeName; if (lpPS->dwFlags & PSF_SELECTPASTE) // If user selected Paste { if (fIsObject) { iString = fDisplayAsIcon ? IDS_PSPASTEOBJECTASICON : IDS_PSPASTEOBJECT; iImage = fDisplayAsIcon ? RESULTIMAGE_EMBEDICON : RESULTIMAGE_EMBED; szInsert = lpPS->szAppName; } else { iString = IDS_PSPASTEDATA; iImage = RESULTIMAGE_PASTE; } } else if (lpPS->dwFlags & PSF_SELECTPASTELINK) // User selected PasteLink { if (fIsObject) { iString = fDisplayAsIcon ? IDS_PSPASTELINKOBJECTASICON : IDS_PSPASTELINKOBJECT; iImage = fDisplayAsIcon ? RESULTIMAGE_LINKICON : RESULTIMAGE_LINK; } else { iString = IDS_PSPASTELINKDATA; iImage = RESULTIMAGE_LINK; } } else // Should never occur. { iString = IDS_PSNONOLE; iImage = RESULTIMAGE_PASTE; } // hBuff contains enough space for the 4 buffers required to build up the help // result text. cch = (UINT)(GlobalSize(lpPS->hBuff) / sizeof(TCHAR)) / 4; psz1 = (LPTSTR)GlobalLock(lpPS->hBuff); psz2 = psz1 + cch; psz3 = psz2 + cch; psz4 = psz3 + cch; // Default is an empty string. *psz1 = 0; if (0 != LoadString(_g_hOleStdResInst, iString, psz1, cch) && nPasteEntriesIndex != -1) { // Insert the FullUserTypeName of the source object into the partial result text // specified by the container. wsprintf(psz3, lpOPS->arrPasteEntries[nPasteEntriesIndex].lpstrResultText, (LPTSTR)szInsert); // Insert the above partial result text into the standard result text. wsprintf(psz4, psz1, (LPTSTR)psz3); psz1 = psz4; } // If LoadString failed, we simply clear out the results (*psz1 = 0 above) SetDlgItemText(hDlg, IDC_PS_RESULTTEXT, psz1); GlobalUnlock(lpPS->hBuff); // Change the result bitmap SendDlgItemMessage(hDlg, IDC_PS_RESULTIMAGE, RIM_IMAGESET, iImage, 0L); } /* * FAddPasteListItem * * Purpose: * Adds an item to the list box * * Parameters: * hList HWND List into which item is to be added * fInsertFirst BOOL Insert in the beginning of the list? * nPasteEntriesIndex int Index of Paste Entry array this list item corresponsds to * lpPS Paste Special Dialog Structure * lpszBuf LPSTR Scratch buffer to build up string for list entry * lpszFullUserTypeName LPSTR full user type name for object entry * * Return Value: * BOOL TRUE if sucessful. * FALSE if unsucessful. */ BOOL FAddPasteListItem( HWND hList, BOOL fInsertFirst, int nPasteEntriesIndex, LPPASTESPECIAL lpPS, LPTSTR lpszBuf, LPTSTR lpszFullUserTypeName) { LPOLEUIPASTESPECIAL lpOPS = lpPS->lpOPS; LPPASTELISTITEMDATA lpItemData; int nIndex; // Allocate memory for each list box item lpItemData = (LPPASTELISTITEMDATA)OleStdMalloc(sizeof(PASTELISTITEMDATA)); if (NULL == lpItemData) return FALSE; // Fill data associated with each list box item lpItemData->nPasteEntriesIndex = nPasteEntriesIndex; lpItemData->fCntrEnableIcon = ((lpOPS->arrPasteEntries[nPasteEntriesIndex].dwFlags & OLEUIPASTE_ENABLEICON) ? TRUE : FALSE); // Build list box entry string, insert the string and add the data the corresponds to it wsprintf( lpszBuf, lpOPS->arrPasteEntries[nPasteEntriesIndex].lpstrFormatName, lpszFullUserTypeName ); // only add to listbox if not a duplicate if (LB_ERR!=SendMessage(hList,LB_FINDSTRING, 0, (LPARAM)lpszBuf)) { // item is already in list; SKIP this one OleStdFree((LPVOID)lpItemData); return TRUE; // this is NOT an error } nIndex = (int)SendMessage( hList, (fInsertFirst ? LB_INSERTSTRING : LB_ADDSTRING), 0, (LPARAM)lpszBuf ); SendMessage( hList, LB_SETITEMDATA, nIndex, (LPARAM)(LPPASTELISTITEMDATA)lpItemData ); return TRUE; } /* * FFillPasteList * * Purpose: * Fills the invisible paste list with the formats offered by the clipboard object and * asked for by the container. * * Parameters: * hDlg HWND of the dialog * lpPS Paste Special Dialog Structure * * Return Value: * BOOL TRUE if sucessful and if formats could be found. * FALSE if unsucessful or if no formats could be found. */ BOOL FFillPasteList(HWND hDlg, LPPASTESPECIAL lpPS) { LPOLEUIPASTESPECIAL lpOPS = lpPS->lpOPS; HWND hList; int i, j; int nItems = 0; int nDefFormat = -1; BOOL fTryObjFmt = FALSE; BOOL fInsertFirst; BOOL fExclude; hList = GetDlgItem(hDlg, IDC_PS_PASTELIST); SendMessage(hList, LB_RESETCONTENT, 0, 0); // Loop over the target's priority list of formats for (i = 0; i < lpOPS->cPasteEntries; i++) { if (lpOPS->arrPasteEntries[i].dwFlags != OLEUIPASTE_PASTEONLY && !(lpOPS->arrPasteEntries[i].dwFlags & OLEUIPASTE_PASTE)) continue; fInsertFirst = FALSE; if (lpOPS->arrPasteEntries[i].fmtetc.cfFormat == _g_cfFileName || lpOPS->arrPasteEntries[i].fmtetc.cfFormat == _g_cfEmbeddedObject || lpOPS->arrPasteEntries[i].fmtetc.cfFormat == _g_cfEmbedSource) { if (! fTryObjFmt) { fTryObjFmt = TRUE; // only use 1st object format fInsertFirst = TRUE; // OLE obj format should always be 1st //Check if this CLSID is in the exclusion list. fExclude=FALSE; for (j=0; j < (int)lpOPS->cClsidExclude; j++) { if (IsEqualCLSID(lpPS->clsidOD, lpOPS->lpClsidExclude[j])) { fExclude=TRUE; break; } } if (fExclude) continue; // don't add the object entry to list } else { continue; // already added an object format to list } } // add to list if entry is marked TRUE if (lpOPS->arrPasteEntries[i].dwScratchSpace) { if (nDefFormat < 0) nDefFormat = (fInsertFirst ? 0 : nItems); else if (fInsertFirst) nDefFormat++; // adjust for obj fmt inserted 1st in list LPTSTR lpszBuf = (LPTSTR)GlobalLock(lpPS->hBuff); if (lpszBuf) { if (!FAddPasteListItem(hList, fInsertFirst, i, lpPS, lpszBuf, lpPS->szFullUserTypeNameOD)) { GlobalUnlock(lpPS->hBuff); goto error; } GlobalUnlock(lpPS->hBuff); } nItems++; } } // initialize selection to first format matched in list if (nDefFormat >= 0) lpPS->nPasteListCurSel = nDefFormat; // Clean up // If no items have been added to the list box (none of the formats // offered by the source matched those acceptable to the container), // return FALSE if (nItems > 0) return TRUE; else return FALSE; error: FreeListData(hList); return FALSE; } /* * FFillPasteLinkList * * Purpose: * Fills the invisible paste link list with the formats offered by the clipboard object and * asked for by the container. * * Parameters: * hDlg HWND of the dialog * lpPS Paste Special Dialog Structure * * Return Value: * BOOL TRUE if sucessful and if formats could be found. * FALSE if unsucessful or if no formats could be found. */ BOOL FFillPasteLinkList(HWND hDlg, LPPASTESPECIAL lpPS) { LPOLEUIPASTESPECIAL lpOPS = lpPS->lpOPS; LPDATAOBJECT lpSrcDataObj = lpOPS->lpSrcDataObj; LPENUMFORMATETC lpEnumFmtEtc = NULL; OLEUIPASTEFLAG pasteFlag; UINT arrLinkTypesSupported[PS_MAXLINKTYPES]; // Array of flags that // indicate which link types // are supported by source. FORMATETC fmtetc; int i, j; int nItems = 0; BOOL fLinkTypeSupported = FALSE; HWND hList; int nDefFormat = -1; BOOL fTryObjFmt = FALSE; BOOL fInsertFirst; HRESULT hrErr; // Remember which link type formats are offered by lpSrcDataObj. memset(&fmtetc, 0, sizeof(FORMATETC)); for (i = 0; i < lpOPS->cLinkTypes; i++) { if (lpOPS->arrLinkTypes[i] == _g_cfLinkSource) { OLEDBG_BEGIN2(TEXT("OleQueryLinkFromData called\r\n")) hrErr = OleQueryLinkFromData(lpSrcDataObj); OLEDBG_END2 if(NOERROR == hrErr) { arrLinkTypesSupported[i] = 1; fLinkTypeSupported = TRUE; } else arrLinkTypesSupported[i] = 0; } else { fmtetc.cfFormat = (CLIPFORMAT)lpOPS->arrLinkTypes[i]; fmtetc.dwAspect = DVASPECT_CONTENT; fmtetc.tymed = 0xFFFFFFFF; // All tymed values fmtetc.lindex = -1; OLEDBG_BEGIN2(TEXT("IDataObject::QueryGetData called\r\n")) hrErr = lpSrcDataObj->QueryGetData(&fmtetc); OLEDBG_END2 if(NOERROR == hrErr) { arrLinkTypesSupported[i] = 1; fLinkTypeSupported = TRUE; } else arrLinkTypesSupported[i] = 0; } } // No link types are offered by lpSrcDataObj if (! fLinkTypeSupported) { nItems = 0; goto cleanup; } hList = GetDlgItem(hDlg, IDC_PS_PASTELINKLIST); SendMessage(hList, LB_RESETCONTENT, 0, 0); // Enumerate the formats acceptable to container for (i = 0; i < lpOPS->cPasteEntries; i++) { fLinkTypeSupported = FALSE; // If container will accept any link type offered by source object if (lpOPS->arrPasteEntries[i].dwFlags & OLEUIPASTE_LINKANYTYPE) fLinkTypeSupported = TRUE; else { // Check if any of the link types offered by the source // object are acceptable to the container // This code depends on the LINKTYPE enum values being powers of 2 for (pasteFlag = OLEUIPASTE_LINKTYPE1, j = 0; j < lpOPS->cLinkTypes; (UINT&)pasteFlag *= 2, j++) { if ((lpOPS->arrPasteEntries[i].dwFlags & pasteFlag) && arrLinkTypesSupported[j]) { fLinkTypeSupported = TRUE; break; } } } fInsertFirst = FALSE; if (lpOPS->arrPasteEntries[i].fmtetc.cfFormat == _g_cfFileName || lpOPS->arrPasteEntries[i].fmtetc.cfFormat == _g_cfLinkSource) { if (! fTryObjFmt) { fTryObjFmt = TRUE; // only use 1st object format fInsertFirst = TRUE; // OLE obj format should always be 1st } else { continue; // already added an object format to list } } // add to list if entry is marked TRUE if (fLinkTypeSupported && lpOPS->arrPasteEntries[i].dwScratchSpace) { if (nDefFormat < 0) nDefFormat = (fInsertFirst ? 0 : nItems); else if (fInsertFirst) nDefFormat++; // adjust for obj fmt inserted 1st in list LPTSTR lpszBuf = (LPTSTR)GlobalLock(lpPS->hBuff); if (lpszBuf) { if (!FAddPasteListItem(hList, fInsertFirst, i, lpPS, lpszBuf, lpPS->szFullUserTypeNameLSD)) { GlobalUnlock(lpPS->hBuff); goto error; } GlobalUnlock(lpPS->hBuff); } nItems++; } } // end FOR nItems = (int)SendMessage(hList, LB_GETCOUNT, 0, 0L); // initialize selection to first format matched in list if (nDefFormat >= 0) lpPS->nPasteLinkListCurSel = nDefFormat; cleanup: // Clean up // If no items have been added to the list box (none of the formats // offered by the source matched those acceptable to the destination), // return FALSE if (nItems > 0) return TRUE; else return FALSE; error: FreeListData(hList); return FALSE; } /* * FreeListData * * Purpose: * Free the local memory associated with each list box item * * Parameters: * hList HWND of the list * * Return Value: * None */ void FreeListData(HWND hList) { int nItems, i; LPPASTELISTITEMDATA lpItemData; nItems = (int) SendMessage(hList, LB_GETCOUNT, 0, 0L); for (i = 0; i < nItems; i++) { lpItemData = (LPPASTELISTITEMDATA)SendMessage(hList, LB_GETITEMDATA, (WPARAM)i, 0L); if ((LRESULT)lpItemData != LB_ERR) OleStdFree((LPVOID)lpItemData); } } /* * FHasPercentS * * Purpose: * Determines if string contains %s. * * Parameters: * lpsz LPCSTR string in which occurence of '%s' is looked for * * Return Value: * BOOL TRUE if %s is found, else FALSE. */ BOOL FHasPercentS(LPCTSTR lpsz, LPPASTESPECIAL lpPS) { int n = 0; LPTSTR lpszTmp; if (!lpsz) return FALSE; // Copy input string to buffer. This allows caller to pass a // code-based string. Code segments may be swapped out in low memory situations // and so code-based strings need to be copied before string elements can be accessed. lpszTmp = (LPTSTR)GlobalLock(lpPS->hBuff); lstrcpy(lpszTmp, lpsz); while (*lpszTmp) { if (*lpszTmp == '%') { lpszTmp = CharNext(lpszTmp); if (*lpszTmp == 's') // if %s, return { GlobalUnlock(lpPS->hBuff); return TRUE; } else if (*lpszTmp == '%') // if %%, skip to next character lpszTmp = CharNext(lpszTmp); } else lpszTmp = CharNext(lpszTmp); } GlobalUnlock(lpPS->hBuff); return FALSE; } /* * AllocateScratchMem * * Purpose: * Allocates scratch memory for use by the PasteSpecial dialog. The memory is * is used as the buffer for building up strings using wsprintf. Strings are built up * using the buffer while inserting items into the Paste & PasteLink lists and while * setting the help result text. It must be big enough to handle the string that results after * replacing the %s in the lpstrFormatName and lpstrResultText in arrPasteEntries[] * by the FullUserTypeName. It must also be big enough to build the dialog's result text * after %s substitutions by the FullUserTypeName or the ApplicationName. * * Parameters: * lpPS Paste Special Dialog Structure * * Return Value: * HGLOBAL Handle to allocated global memory */ HGLOBAL AllocateScratchMem(LPPASTESPECIAL lpPS) { LPOLEUIPASTESPECIAL lpOPS = lpPS->lpOPS; int nLen, i; int nSubstitutedText = 0; int nAlloc = 0; // Get the maximum length of the FullUserTypeNames specified by OBJECTDESCRIPTOR // and the LINKSRCDESCRIPTOR and the Application Name. Any of these may be substituted // for %s in the result-text/list entries. if (lpPS->szFullUserTypeNameOD) nSubstitutedText = lstrlen(lpPS->szFullUserTypeNameOD); if (lpPS->szFullUserTypeNameLSD) nSubstitutedText = __max(nSubstitutedText, lstrlen(lpPS->szFullUserTypeNameLSD)); if (lpPS->szAppName) nSubstitutedText = __max(nSubstitutedText, lstrlen(lpPS->szAppName)); // Get the maximum length of lpstrFormatNames & lpstrResultText in arrPasteEntries nLen = 0; for (i = 0; i < lpOPS->cPasteEntries; i++) { nLen = max(nLen, lstrlen(lpOPS->arrPasteEntries[i].lpstrFormatName)); nLen = max(nLen, lstrlen(lpOPS->arrPasteEntries[i].lpstrResultText)); } // Get the maximum length of lpstrFormatNames and lpstrResultText after %s has // been substituted (At most one %s can appear in each string). // Add 1 to hold NULL terminator. nAlloc = (nLen+nSubstitutedText+1)*sizeof(TCHAR); // Allocate scratch memory to be used to build strings // nAlloc is big enough to hold any of the lpstrResultText or lpstrFormatName in arrPasteEntries[] // after %s substitution. // We also need space to build up the help result text. 512 is the maximum length of the // standard dialog help text before substitutions. 512+nAlloc is the maximum length // after %s substition. // SetPasteSpecialHelpResults() requires 4 such buffers to build up the result text return GlobalAlloc(GHND, (DWORD)4*(512 * sizeof(TCHAR) + nAlloc)); }