- BORLAND/: Borland C++ 4.52 (chosen over 4.5 by byte-match: CODE/RP/CW32.LIB
is identical to 4.52's install lib). BCC32/TLINK32/TLIB/MAKE run natively on
Win11; CODE/BT/OPT.MAK is the shipped BTL4OPT.EXE's exact flag recipe
(extender = Borland PowerPack DPMI32, not Phar Lap TNT).
- restoration/source410/: the literal 1995-form reconstruction of the missing
BT game source (never mixed into CODE/). Round 1-3 state:
* 6 of 10 surviving original TUs COMPILE CLEAN under the period toolchain
(BTMSSN, BTCNSL, BTSCNRL, BTTEAM, BTL4MODE, BTL4ARND) - first builds
since 1996.
* BT_L4/BTL4APP.CPP pilot reconstruction: 12/12 functions, Fail() lands on
its binary-recorded line 400 exactly.
* BT/BTCNSL.HPP: console wire IDs recovered from the binary's ctors
(Killed=9, Damaged=10, ScoreUpdate=13, DeathWithoutHonor=15 [T1];
TeamScore=12 flagged [T4]).
* MUNGA/: 8 engine-header backfills back-dated from the BT412 WinTesla tree
(VDATA numbering decomp-verified; AUDREND's OpenAL-era virtual removed -
the period compiler is the drift detector).
* Tooling: backdate.py (WinTesla->1995 header transform), compile410.sh
(per-TU verification sweep under authentic OPT.MAK flags).
* README: corrected roadmap - MECH.HPP is the capstone grown with the mech
TU reconstructions; BTREG.CPP green = the header-family milestone.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1780 lines
46 KiB
C++
1780 lines
46 KiB
C++
//----------------------------------------------------------------------------
|
|
// ObjectWindows
|
|
// (C) Copyright 1994 by Borland International, All Rights Reserved
|
|
//
|
|
// Defines type TPasteSpecialDlg
|
|
//----------------------------------------------------------------------------
|
|
#define INC_OLE2
|
|
#include <owl/owlpch.h>
|
|
#include <owl/listbox.h>
|
|
#include <owl/radiobut.h>
|
|
#include <owl/edit.h>
|
|
#include <ocf/ocview.h>
|
|
#include <owl/oledlg.h>
|
|
#include <owl/except.h>
|
|
#include <bwcc.h> // for IDHELP
|
|
#include <dir.h>
|
|
|
|
//
|
|
// OWL OLE Dialog diagnostic group.
|
|
//
|
|
DIAG_DECLARE_GROUP(OwlOleDlg);
|
|
|
|
//
|
|
//
|
|
//
|
|
static bool
|
|
CompareTargetDevice(DVTARGETDEVICE FAR* ptdLeft,
|
|
DVTARGETDEVICE FAR* ptdRight)
|
|
{
|
|
if (ptdLeft == ptdRight)
|
|
return true;
|
|
else if (!ptdRight || !ptdLeft)
|
|
return false;
|
|
else if (ptdLeft->tdSize != ptdRight->tdSize)
|
|
return false;
|
|
else if (memcmp(ptdLeft, ptdRight, (int)ptdLeft->tdSize) != 0)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
//
|
|
// Returns 0 for exact match, 1 for no match, -1 for partial match (which is
|
|
// defined to mean the left is a subset of the right: fewer aspects,
|
|
// null target device, fewer medium).
|
|
//
|
|
static int
|
|
CompareFormatEtc(FORMATETC FAR* pFetcLeft, FORMATETC FAR* pFetcRight)
|
|
{
|
|
bool bExact = true;
|
|
|
|
if (pFetcLeft->cfFormat != pFetcRight->cfFormat)
|
|
return 1;
|
|
else if (!CompareTargetDevice (pFetcLeft->ptd, pFetcRight->ptd))
|
|
return 1;
|
|
if (pFetcLeft->dwAspect == pFetcRight->dwAspect)
|
|
//
|
|
// Same aspects implies equality
|
|
//
|
|
;
|
|
|
|
else if ((pFetcLeft->dwAspect & ~pFetcRight->dwAspect) != 0)
|
|
//
|
|
// Left not subset of aspects of right implies not equal
|
|
//
|
|
return 1;
|
|
else
|
|
//
|
|
// left subset of right
|
|
//
|
|
bExact = false;
|
|
|
|
if (pFetcLeft->tymed == pFetcRight->tymed)
|
|
// same medium flags; equal
|
|
;
|
|
else if ((pFetcLeft->tymed & ~pFetcRight->tymed) != 0)
|
|
//
|
|
// left not subset of medium flags of right; not equal
|
|
//
|
|
return 1;
|
|
else
|
|
//
|
|
// left subset of right
|
|
//
|
|
bExact = false;
|
|
|
|
return bExact ? 0 : -1;
|
|
}
|
|
|
|
DEFINE_RESPONSE_TABLE1(TPasteSpecialDlg, TOleDialog)
|
|
EV_WM_DRAWCLIPBOARD,
|
|
EV_WM_CHANGECBCHAIN,
|
|
EV_BN_CLICKED(IDC_CHANGEICON, ChangeIconClicked),
|
|
EV_BN_CLICKED(IDC_PASTE, PasteClicked),
|
|
EV_BN_CLICKED(IDC_PASTELINK, PasteLinkClicked),
|
|
EV_BN_CLICKED(IDC_DISPLAYASICON, DisplayAsIconClicked),
|
|
EV_LBN_SELCHANGE(IDC_DISPLAYLIST, DisplayListSelChange),
|
|
EV_LBN_DBLCLK(IDC_DISPLAYLIST, DisplayListDblClk),
|
|
END_RESPONSE_TABLE;
|
|
|
|
//
|
|
// Initialize all data members to 0 [or false]
|
|
//
|
|
TPasteSpecialDlg::TData::TData()
|
|
{
|
|
//
|
|
// This class is really just a PODS, so we'll take
|
|
// advantage of memset
|
|
//
|
|
memset(this, 0, sizeof(TData));
|
|
}
|
|
|
|
//
|
|
// Initialize all data members to 0 [or false]
|
|
//
|
|
TPasteSpecialDlg::TPasteListItemData::TPasteListItemData()
|
|
{
|
|
//
|
|
// This class is really just a PODS, so we'll take
|
|
// advantage of memset
|
|
//
|
|
memset(this, 0, sizeof(TPasteListItemData));
|
|
}
|
|
|
|
//
|
|
// Initialize all data members to 0 [or false]
|
|
//
|
|
TPasteSpecialDlg::TPasteEntry::TPasteEntry()
|
|
{
|
|
//
|
|
// This class is really just a PODS, so we'll take
|
|
// advantage of memset
|
|
//
|
|
memset(this, 0, sizeof(TPasteEntry));
|
|
}
|
|
|
|
//
|
|
// Initialize helper object used internally by TPasteSpecialDlg
|
|
//
|
|
TPasteSpecialDlg::THelper::THelper()
|
|
{
|
|
//
|
|
// This structure is a private PODS which allows
|
|
// us to take advantage of memset.
|
|
//
|
|
memset(this, 0, sizeof(THelper));
|
|
}
|
|
|
|
//
|
|
// Initialize TPasteSpecial Dialog:
|
|
// - Alias Dialog controls with C++ objects
|
|
// - Initialize internal variables
|
|
//
|
|
TPasteSpecialDlg::TPasteSpecialDlg(TWindow* parent,
|
|
TOcInitInfo &initInfo,
|
|
TData *data,
|
|
TResId templateId,
|
|
const char far *title,
|
|
TModule* module):
|
|
TOleDialog(parent,
|
|
templateId ? templateId : TResId(DLG_PASTESPECIAL),
|
|
title,
|
|
module),
|
|
InitInfo(initInfo), Helper(*new THelper)
|
|
{
|
|
//
|
|
// Wrap controls
|
|
//
|
|
ResultImage = new TResultImage(this, IDC_RESULTIMAGE);
|
|
IconImage = new TIconImage(this, IDC_ICONIMAGE);
|
|
DisplayAsIcon = new TCheckBox(this, IDC_DISPLAYASICON);
|
|
Paste = new TRadioButton(this, IDC_PASTE);
|
|
PasteLink = new TRadioButton(this, IDC_PASTELINK);
|
|
DisplayList = new TListBox(this, IDC_DISPLAYLIST);
|
|
PasteList = new TListBox(this, IDC_PASTELIST);
|
|
PasteLinkList = new TListBox(this, IDC_PASTELINKLIST);
|
|
ChangeIcon = new TButton(this, IDC_CHANGEICON);
|
|
ResultText = new TStatic(this, IDC_RESULTTEXT);
|
|
SourceText = new TStatic(this, IDC_SOURCE);
|
|
Help = new TButton(this, IDHELP);
|
|
|
|
//
|
|
// Store TData pointer (if specified)
|
|
//
|
|
Data = data;
|
|
|
|
//
|
|
// Init internal variables
|
|
//
|
|
DeleteData = false;
|
|
pOleUIEntries = 0;
|
|
pBOleEntries = 0;
|
|
pBOleLinkEntries = 0;
|
|
}
|
|
|
|
//
|
|
// Cleanup memory allocated for TPasteSpecialInfo pointers if
|
|
// user relied on default one.
|
|
//
|
|
TPasteSpecialDlg::~TPasteSpecialDlg()
|
|
{
|
|
delete &Helper;
|
|
|
|
//
|
|
// Delete Data pointer if we allocated it
|
|
//
|
|
if (DeleteData) {
|
|
delete Data;
|
|
|
|
if (pOleUIEntries)
|
|
delete []pOleUIEntries;
|
|
|
|
if (pBOleEntries)
|
|
delete []pBOleEntries;
|
|
|
|
if (pBOleLinkEntries)
|
|
delete []pBOleLinkEntries;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check if a TPasteSpecialInfo pointer was specified - Create one
|
|
// if necessary.
|
|
//
|
|
int
|
|
TPasteSpecialDlg::DoExecute()
|
|
{
|
|
if (!Data) {
|
|
if (!GetDefaultPasteSpecialData()) {
|
|
return IDCANCEL;
|
|
}
|
|
}
|
|
return TDialog::DoExecute();
|
|
}
|
|
|
|
//
|
|
// Validate flags, Initialize Helper structure,
|
|
// Fill Paste/PasteLink listboxes
|
|
//
|
|
bool
|
|
TPasteSpecialDlg::EvInitDialog(HWND hwndFocus)
|
|
{
|
|
//
|
|
// Call base to alias controls
|
|
//
|
|
TOleDialog::EvInitDialog(hwndFocus);
|
|
|
|
//
|
|
// Enable Wait cursor
|
|
//
|
|
HCURSOR oldCursor = HourGlassOn();
|
|
|
|
//
|
|
// Copy user info. and init helper class
|
|
//
|
|
Helper.Flags = Data->Flags;
|
|
Helper.PasteListCurSel = 0;
|
|
Helper.PasteLinkListCurSel = 0;
|
|
|
|
//
|
|
// Set control font
|
|
//
|
|
if (Font) {
|
|
ResultText->SetWindowFont(*Font, false);
|
|
SourceText->SetWindowFont(*Font, false);
|
|
}
|
|
|
|
//
|
|
// Hide help if requested
|
|
//
|
|
if (!(Helper.Flags & psShowHelp))
|
|
Activate(Help, false);
|
|
|
|
//
|
|
// Hide IconDisplay related controls if requested
|
|
//
|
|
if (Helper.Flags & psDisableDisplayAsIcon) {
|
|
Activate(DisplayAsIcon, false);
|
|
Activate(IconImage, false);
|
|
Activate(ChangeIcon, false);
|
|
}
|
|
|
|
//
|
|
// Clear 'CheckDisplayAsIcon' [out-flag only]
|
|
//
|
|
Helper.Flags &= ~psCheckDisplayAsIcon;
|
|
|
|
//
|
|
// Load 'Unknown Source' and 'Unknown Type' strings
|
|
//
|
|
GetModule()->LoadString(IDS_PSUNKNOWNTYPE,
|
|
Helper.UnknownType, MaxUnknownLen);
|
|
GetModule()->LoadString(IDS_PSUNKNOWNSRC,
|
|
Helper.UnknownSource, MaxUnknownLen);
|
|
Helper.AppName[0]= 0;
|
|
|
|
//
|
|
// Fill OBJECTDESCRIPTOR structure
|
|
//
|
|
STGMEDIUM medium;
|
|
CLIPFORMAT cfFormat;
|
|
Helper.ObjDesc = FillObjectDescriptorFromData(Data->lpSrcDataObj,
|
|
&medium, &cfFormat);
|
|
if (Helper.ObjDesc) {
|
|
LPOBJECTDESCRIPTOR lpOD = (LPOBJECTDESCRIPTOR)GlobalLock(Helper.ObjDesc);
|
|
|
|
//
|
|
// Retrieve FullUserTypeName, SourceOfCopy and CLSID
|
|
//
|
|
if (lpOD->dwFullUserTypeName)
|
|
Helper.FullUserTypeNameOD = (LPSTR)lpOD + (int)lpOD->dwFullUserTypeName;
|
|
else
|
|
Helper.FullUserTypeNameOD = Helper.UnknownType;
|
|
|
|
if (lpOD->dwSrcOfCopy) {
|
|
Helper.SourceOfDataOD = (LPSTR)lpOD + (int)lpOD->dwSrcOfCopy;
|
|
|
|
//
|
|
// If CF_FILENAME is offered, source of copy is a path name;
|
|
// Chop the name to fit the static control it will be displayed in
|
|
//
|
|
if (cfFormat == cfFileName)
|
|
Helper.SourceOfDataOD= ChopText(*SourceText, 0, Helper.SourceOfDataOD);
|
|
}
|
|
else {
|
|
Helper.SourceOfDataOD = Helper.UnknownSource;
|
|
}
|
|
|
|
Helper.ClsIdOD = lpOD->clsid;
|
|
Helper.SizeLOD = lpOD->sizel;
|
|
|
|
//
|
|
// Update helper class about DVASPECT_ICON & OLEMISC_ONLYICONIC flags
|
|
//
|
|
Helper.SrcAspectIconOD = (lpOD->dwDrawAspect & DVASPECT_ICON) ?
|
|
true : false;
|
|
Helper.SrcOnlyIconicOD = (lpOD->dwStatus & OLEMISC_ONLYICONIC) ?
|
|
true : false;
|
|
|
|
//
|
|
// Get App. Name of source from auxusertype3 in reg. database
|
|
//
|
|
if (!GetAuxUserType(Helper.ClsIdOD, 3, Helper.AppName, MaxKeyLen, 0)) {
|
|
//
|
|
// Default to "the application which created it" as the name
|
|
//
|
|
GetModule()->LoadString(IDS_PSUNKNOWNAPP, Helper.AppName, MaxKeyLen);
|
|
}
|
|
|
|
//
|
|
// Retrieve an icon from the object
|
|
//
|
|
if (Helper.SrcAspectIconOD) {
|
|
Helper.MetaPictOD = GetData(Data->lpSrcDataObj,
|
|
CF_METAFILEPICT, 0,
|
|
DVASPECT_ICON, &medium);
|
|
}
|
|
|
|
//
|
|
// If none, retrieve icon from CLSID
|
|
//
|
|
if (!Helper.MetaPictOD) {
|
|
Helper.MetaPictOD = GetIconFromClass(Helper.ClsIdOD, 0, TRUE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Does object offer CF_LINKSRCDESCRIPTOR
|
|
//
|
|
Helper.LinkSrcDesc = GetData(Data->lpSrcDataObj,
|
|
cfLinkSrcDescriptor, 0,
|
|
DVASPECT_CONTENT, &medium);
|
|
if (Helper.LinkSrcDesc) {
|
|
LPLINKSRCDESCRIPTOR lpLSD = (LPLINKSRCDESCRIPTOR)
|
|
GlobalLock(Helper.LinkSrcDesc);
|
|
|
|
//
|
|
// Get FullUserTypeName, SourceOfCopy and CLSID
|
|
//
|
|
if (lpLSD->dwFullUserTypeName)
|
|
Helper.FullUserTypeNameLSD = (LPSTR)lpLSD +
|
|
(int)lpLSD->dwFullUserTypeName;
|
|
else
|
|
Helper.FullUserTypeNameLSD = Helper.UnknownType;
|
|
|
|
if (lpLSD->dwSrcOfCopy)
|
|
Helper.SourceOfDataLSD = (LPSTR)lpLSD + (int)lpLSD->dwSrcOfCopy;
|
|
else
|
|
Helper.SourceOfDataLSD = Helper.UnknownSource;
|
|
|
|
//
|
|
// If no objectDescriptor, use linkSourceDescriptor source string
|
|
//
|
|
if (!Helper.ObjDesc)
|
|
Helper.SourceOfDataOD = Helper.SourceOfDataLSD;
|
|
|
|
Helper.ClsIdLSD = lpLSD->clsid;
|
|
Helper.SizeLLSD = lpLSD->sizel;
|
|
|
|
//
|
|
// Update helper class about DVASPECT_ICON & OLEMISC_ONLYICONIC
|
|
//
|
|
Helper.SrcAspectIconLSD = (lpLSD->dwDrawAspect & DVASPECT_ICON) ?
|
|
true : false;
|
|
Helper.SrcOnlyIconicLSD = (lpLSD->dwStatus & OLEMISC_ONLYICONIC) ?
|
|
true : false;
|
|
|
|
//
|
|
// Retrieve an icon from object
|
|
//
|
|
if (Helper.SrcAspectIconLSD) {
|
|
Helper.MetaPictLSD = GetData(Data->lpSrcDataObj,
|
|
CF_METAFILEPICT, 0,
|
|
DVASPECT_ICON, &medium);
|
|
//
|
|
// If object offers none, retrieve icon from CLSID
|
|
//
|
|
if (!Helper.MetaPictLSD) {
|
|
//
|
|
// Retrieve 1.5 times width of iconbox
|
|
//
|
|
TRect rect;
|
|
IconImage->GetClientRect(rect);
|
|
int width = rect.Width() *3/2;
|
|
|
|
//
|
|
// Chop label to fit width
|
|
//
|
|
char label[MaxLabelLen];
|
|
strcpyn(label, Helper.SourceOfDataLSD, sizeof(label));
|
|
label[sizeof(label)-1] = 0;
|
|
LPSTR lpszLabel = ChopText(*IconImage, width, label);
|
|
|
|
//
|
|
// Retrieve icon
|
|
//
|
|
Helper.MetaPictLSD = GetIconFromClass(Helper.ClsIdLSD,
|
|
lpszLabel, FALSE);
|
|
}
|
|
}
|
|
}
|
|
else if (Helper.ObjDesc) // Offers no LINKSRCDESCRIPTOR but
|
|
{ // Offers OBJECTDESCRIPTOR - Copy OD values!
|
|
Helper.FullUserTypeNameLSD = Helper.FullUserTypeNameOD;
|
|
Helper.SourceOfDataLSD = Helper.SourceOfDataOD;
|
|
Helper.ClsIdLSD = Helper.ClsIdOD;
|
|
Helper.SizeLLSD = Helper.SizeLOD;
|
|
Helper.SrcAspectIconLSD = Helper.SrcAspectIconOD;
|
|
Helper.SrcOnlyIconicLSD = Helper.SrcOnlyIconicOD;
|
|
|
|
//
|
|
// Grab copy of MetaPict
|
|
//
|
|
if (Helper.SrcAspectIconLSD) {
|
|
Helper.MetaPictLSD = GetData(Data->lpSrcDataObj,
|
|
CF_METAFILEPICT, 0,
|
|
DVASPECT_ICON, &medium);
|
|
}
|
|
|
|
//
|
|
// Retrieve icon from CLSID
|
|
//
|
|
if (!Helper.MetaPictLSD) {
|
|
//
|
|
// Retrieve 1.5 times width of iconbox
|
|
//
|
|
TRect rect;
|
|
IconImage->GetClientRect(rect);
|
|
int width = rect.Width() *3/2;
|
|
|
|
//
|
|
// Chop label to fit width
|
|
//
|
|
char label[MaxLabelLen];
|
|
strcpyn(label, Helper.SourceOfDataLSD, sizeof(label));
|
|
label[sizeof(label)-1] = 0;
|
|
LPSTR lpszLabel = ChopText(*IconImage, width, label);
|
|
|
|
//
|
|
// Retrieve Icon
|
|
//
|
|
Helper.MetaPictLSD = GetIconFromClass(Helper.ClsIdLSD,
|
|
lpszLabel, FALSE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// We have a non-OLE object
|
|
//
|
|
if (!Helper.ObjDesc && !Helper.LinkSrcDesc) {
|
|
Helper.FullUserTypeNameLSD =
|
|
Helper.FullUserTypeNameOD = Helper.UnknownType;
|
|
|
|
Helper.SourceOfDataLSD =
|
|
Helper.SourceOfDataOD = Helper.UnknownSource;
|
|
|
|
Helper.MetaPictLSD = Helper.MetaPictOD = 0;
|
|
}
|
|
|
|
//
|
|
// Update Flags: paste vs. pastelink
|
|
//
|
|
if (Helper.Flags & psSelectPasteLink)
|
|
Helper.Flags = (Helper.Flags & ~psSelectPaste) | psSelectPasteLink;
|
|
else
|
|
Helper.Flags = (Helper.Flags & ~psSelectPasteLink) | psSelectPaste;
|
|
|
|
//
|
|
// Mark which PasteEntry formats are available from source data object
|
|
//
|
|
MarkPasteEntryList(Data->lpSrcDataObj, Data->ArrayPasteEntries,
|
|
Data->cPasteEntries);
|
|
|
|
//
|
|
// Check if items are available for pasting
|
|
//
|
|
bool pasteAvailable = FillPasteList();
|
|
if (!pasteAvailable) {
|
|
Helper.Flags &= ~psSelectPaste;
|
|
Paste->EnableWindow(false);
|
|
}
|
|
|
|
//
|
|
// Check if items are available for paste-linking
|
|
//
|
|
bool pasteLinkAvailable = FillPasteLinkList();
|
|
if (!pasteLinkAvailable) {
|
|
Helper.Flags &= ~psSelectPasteLink;
|
|
PasteLink->EnableWindow(false);
|
|
}
|
|
|
|
//
|
|
// Validate flags base on paste availability
|
|
//
|
|
if (pasteAvailable && !pasteLinkAvailable)
|
|
Helper.Flags |= psSelectPaste;
|
|
|
|
if (pasteLinkAvailable && !pasteAvailable)
|
|
Helper.Flags |= psSelectPasteLink;
|
|
|
|
if (Helper.Flags & psSelectPaste) {
|
|
CheckRadioButton(IDC_PASTE, IDC_PASTELINK, IDC_PASTE);
|
|
|
|
//
|
|
// TogglePaste will set paste flag, so clear it first
|
|
//
|
|
Helper.Flags &= ~psSelectPaste;
|
|
TogglePasteType(psSelectPaste);
|
|
}
|
|
else if (Helper.Flags & psSelectPasteLink) {
|
|
CheckRadioButton(IDC_PASTE, IDC_PASTELINK, IDC_PASTELINK);
|
|
|
|
//
|
|
// TogglePaste will set pasteLink flag, so clear it first
|
|
//
|
|
Helper.Flags &= psSelectPasteLink;
|
|
TogglePasteType(psSelectPasteLink);
|
|
}
|
|
else {
|
|
EnableDisplayAsIcon();
|
|
SetPasteSpecialHelpResults();
|
|
}
|
|
|
|
//
|
|
// Set Focus to ListBox
|
|
//
|
|
DisplayList->SetFocus();
|
|
|
|
//
|
|
// Set property to handle clipboard change notifications
|
|
//
|
|
SetProp(NEXTCBVIEWER, HWND_BROADCAST);
|
|
SetProp(NEXTCBVIEWER, SetClipboardViewer(*this));
|
|
Helper.ClipboardChanged = false;
|
|
|
|
//
|
|
// Restore previous cursor
|
|
//
|
|
HourGlassOff(oldCursor);
|
|
|
|
return false;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
void
|
|
TPasteSpecialDlg::CleanupWindow()
|
|
{
|
|
//
|
|
// Free metafile of non-selected option
|
|
//
|
|
if (Helper.Link)
|
|
TOleMetaPict::Free(Helper.MetaPictOD);
|
|
else
|
|
TOleMetaPict::Free(Helper.MetaPictLSD);
|
|
|
|
//
|
|
// Free listbox entries
|
|
//
|
|
FreeListData(*PasteList);
|
|
FreeListData(*PasteLinkList);
|
|
|
|
//
|
|
// Free memory allocations
|
|
//
|
|
if (Helper.ObjDesc)
|
|
GlobalFree(Helper.ObjDesc);
|
|
|
|
if (Helper.LinkSrcDesc)
|
|
GlobalFree(Helper.LinkSrcDesc);
|
|
|
|
//
|
|
// Remove ourselves from Clipboard notification chain
|
|
//
|
|
HWND hwndNextViewer;
|
|
hwndNextViewer = (HWND)GetProp(NEXTCBVIEWER);
|
|
if (hwndNextViewer != HWND_BROADCAST) {
|
|
SetProp(NEXTCBVIEWER, HWND_BROADCAST);
|
|
ChangeClipboardChain(*this, hwndNextViewer);
|
|
}
|
|
RemoveProp(NEXTCBVIEWER);
|
|
}
|
|
|
|
//
|
|
// Handles User activating OK button by retrieving the current
|
|
// selection and updating the TPasteSpecialInfo and TOcInitInfo
|
|
// structures.
|
|
//
|
|
bool
|
|
TPasteSpecialDlg::OleDlgOk()
|
|
{
|
|
//
|
|
// Copy Helper information to Data structure
|
|
//
|
|
bool fDestAspectIcon = (Helper.Flags & psCheckDisplayAsIcon) ? true : false;
|
|
Data->Flags = Helper.Flags;
|
|
Data->SelectedIndex = Helper.SelectedIndex;
|
|
Data->fLink = Helper.Link;
|
|
if (Helper.Link) {
|
|
if (Helper.SrcAspectIconLSD == fDestAspectIcon)
|
|
Data->SizeL = Helper.SizeLLSD;
|
|
else
|
|
Data->SizeL.cx = Data->SizeL.cy = 0;
|
|
}
|
|
else {
|
|
if (Helper.SrcAspectIconOD == fDestAspectIcon)
|
|
Data->SizeL = Helper.SizeLOD;
|
|
else
|
|
Data->SizeL.cx = Data->SizeL.cy = 0;
|
|
}
|
|
|
|
//
|
|
// Grab selected metafile
|
|
//
|
|
Data->MetaPict = IconImage->GetMetaPict();
|
|
|
|
//
|
|
// Update TOcInitInfo data
|
|
//
|
|
if (Data->Flags & psCheckDisplayAsIcon)
|
|
InitInfo.HIcon = (HICON)Data->MetaPict;
|
|
|
|
LPDATAOBJECT pDataObj = Data->lpSrcDataObj;
|
|
int i = Data->SelectedIndex;
|
|
|
|
//
|
|
// Retrieve selected clipboard format - If we have the BOleFormat handy,
|
|
// go there since it's 'nearer' - otherwise use the Data data
|
|
//
|
|
CLIPFORMAT cf;
|
|
if (pBOleEntries)
|
|
cf = pBOleEntries[i].Id;
|
|
else
|
|
cf = Data->ArrayPasteEntries[i].fmtetc.cfFormat;
|
|
|
|
if (cf == cfEmbeddedObject) {
|
|
InitInfo.How = ihEmbed;
|
|
InitInfo.Where = iwDataObject;
|
|
InitInfo.Data = pDataObj;
|
|
}
|
|
else if (cf == cfEmbedSource) {
|
|
InitInfo.How = ihEmbed;
|
|
InitInfo.Where = iwDataObject;
|
|
InitInfo.Data = pDataObj;
|
|
InitInfo.Storage = 0;
|
|
}
|
|
else if (cf == cfLinkSource) {
|
|
InitInfo.How = ihLink;
|
|
InitInfo.Where = iwDataObject;
|
|
InitInfo.Data = pDataObj;
|
|
}
|
|
else {
|
|
STGMEDIUM medium;
|
|
InitInfo.How = Data->fLink ? ihLink : ihEmbed;
|
|
InitInfo.Where = iwHandle;
|
|
InitInfo.Handle.DataFormat = cf;
|
|
|
|
if (!Data->fLink)
|
|
InitInfo.Handle.Data = GetData(pDataObj, cf, 0,
|
|
DVASPECT_CONTENT, &medium);
|
|
//
|
|
// Release data object since we're only passing back a handle [not
|
|
// the data object]
|
|
//
|
|
pDataObj->Release();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//
|
|
// Allocate and Initialize a TPasteSpecialData structure [used if no
|
|
// TPasteSpecialData pointer was specified with constructing dialog]
|
|
//
|
|
bool
|
|
TPasteSpecialDlg::GetDefaultPasteSpecialData()
|
|
{
|
|
//
|
|
// Should be called only if user did not specify a TPasteSpecialInfo ptr.
|
|
//
|
|
PRECONDITION(Data == 0);
|
|
|
|
//
|
|
// Find container we'll be pasting in
|
|
//
|
|
IBContainer far* pCont = 0;
|
|
if (InitInfo.Container)
|
|
pCont = InitInfo.Container;
|
|
else {
|
|
TRACEX(OwlOleDlg, 1, "Container to paste in not found");
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Find data consumer from container
|
|
//
|
|
IBDataConsumer far* pConsumer = 0;
|
|
HRESULT hRes = pCont->QueryInterface(IID_IBDataConsumer,
|
|
&(LPVOID)pConsumer);
|
|
|
|
if (!SUCCEEDED(hRes)) {
|
|
TRACEX(OwlOleDlg, 1, "Container data consumer not found");
|
|
return false;
|
|
}
|
|
else {
|
|
pConsumer->Release();
|
|
}
|
|
|
|
//
|
|
// Check if clipboard is empty or (maybe) unavailable
|
|
//
|
|
LPDATAOBJECT pDataObj = 0;
|
|
if (OleGetClipboard(&pDataObj) != S_OK) {
|
|
TRACEX(OwlOleDlg, 1, "Clipboard's unavailable to paste from");
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Retrieve acceptable formats
|
|
//
|
|
uint nAcceptableFormats = 0;
|
|
nAcceptableFormats = pConsumer->CountFormats();
|
|
if (!nAcceptableFormats) {
|
|
TRACEX(OwlOleDlg, 1, "No acceptable formats from consumer");
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Allocate Dialog parameter information
|
|
//
|
|
pOleUIEntries = new TPasteEntry[nAcceptableFormats];
|
|
pBOleEntries = new TOcFormatInfo[nAcceptableFormats];
|
|
pBOleLinkEntries = new uint[nAcceptableFormats];
|
|
Data = new TData;
|
|
DeleteData = true;
|
|
|
|
//
|
|
// Iterate through formats to initialize structures and track
|
|
// linkable formats
|
|
//
|
|
uint nLinkableFormats = 0;
|
|
for (int i=0; i<nAcceptableFormats; i++) {
|
|
pConsumer->GetFormat(i, &pBOleEntries[i]);
|
|
|
|
InitFormatEtc(pOleUIEntries[i].fmtetc, pBOleEntries[i].Id,
|
|
pBOleEntries[i].Medium);
|
|
pOleUIEntries[i].lpstrFormatName = pBOleEntries[i].Name[0] ?
|
|
OleStr(pBOleEntries[i].Name) : OleText("%s");
|
|
pOleUIEntries[i].lpstrResultText =
|
|
pBOleEntries[i].ResultName[0] ?
|
|
OleStr(pBOleEntries[i].ResultName) : OleText("%s");
|
|
pOleUIEntries[i].dwFlags = pBOleEntries[i].IsLinkable ?
|
|
pfPaste : pfPasteOnly;
|
|
|
|
if (pBOleEntries[i].Id == cfEmbeddedObject ||
|
|
pBOleEntries[i].Id == cfLinkSource ||
|
|
pBOleEntries[i].Id == cfEmbedSource ) {
|
|
//
|
|
// PasteOnly and EnableIcon are mutually exclusive
|
|
//
|
|
if (pOleUIEntries[i].dwFlags == pfPaste)
|
|
pOleUIEntries[i].dwFlags |= pfEnableIcon;
|
|
}
|
|
|
|
if (pBOleEntries[i].IsLinkable) {
|
|
pBOleLinkEntries[nLinkableFormats] = pBOleEntries[i].Id;
|
|
|
|
DWORD flag;
|
|
switch(nLinkableFormats) {
|
|
case 0: flag = pfLinkType1; break;
|
|
case 1: flag = pfLinkType2; break;
|
|
case 2: flag = pfLinkType2; break;
|
|
case 3: flag = pfLinkType2; break;
|
|
case 4: flag = pfLinkType2; break;
|
|
case 5: flag = pfLinkType2; break;
|
|
case 6: flag = pfLinkType2; break;
|
|
case 7: flag = pfLinkType2; break;
|
|
}
|
|
pOleUIEntries[i].dwFlags |= flag;
|
|
nLinkableFormats++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Store all relevant PasteSpecial Initialization information
|
|
//
|
|
Data->ArrayPasteEntries = pOleUIEntries;
|
|
Data->cPasteEntries = nAcceptableFormats;
|
|
Data->lpSrcDataObj = pDataObj;
|
|
Data->ArrayLinkTypes = pBOleLinkEntries;
|
|
Data->cLinkTypes = nLinkableFormats;
|
|
Data->cClsIdExclude = 0;
|
|
|
|
return true;
|
|
}
|
|
|
|
//
|
|
// Mark each entry in the PasteEntryList if its format is available from
|
|
// the source IDataObject*. the dwScratchSpace field of each PasteEntry
|
|
// is set to TRUE if available, else FALSE.
|
|
//
|
|
void TPasteSpecialDlg::MarkPasteEntryList(LPDATAOBJECT lpSrcDataObj,
|
|
TPasteEntry far* lpPriorityList,
|
|
int cEntries)
|
|
{
|
|
LPENUMFORMATETC lpEnumFmtEtc = NULL;
|
|
FORMATETC rgfmtetc[MaxFormatEtc];
|
|
int i;
|
|
HRESULT hrErr;
|
|
long j, cFetched;
|
|
|
|
//
|
|
// Clear all marks
|
|
//
|
|
for (i = 0; i < cEntries; i++) {
|
|
lpPriorityList[i].dwScratchSpace = FALSE;
|
|
|
|
if (! lpPriorityList[i].fmtetc.cfFormat) {
|
|
//
|
|
// Caller wants this item always considered available
|
|
// (by specifying a NULL format)
|
|
//
|
|
lpPriorityList[i].dwScratchSpace = TRUE;
|
|
}
|
|
else if (lpPriorityList[i].fmtetc.cfFormat == cfEmbeddedObject
|
|
|| lpPriorityList[i].fmtetc.cfFormat == cfEmbedSource
|
|
|| lpPriorityList[i].fmtetc.cfFormat == cfFileName) {
|
|
|
|
//
|
|
// If there is an OLE object format, then handle it
|
|
// specially by calling OleQueryCreateFromData. the caller
|
|
// need only specify one object type format.
|
|
//
|
|
TRACEX(OwlOleDlg, 1, "OleQueryCreateFromData called");
|
|
hrErr = OleQueryCreateFromData(lpSrcDataObj);
|
|
|
|
if(NOERROR == hrErr) {
|
|
lpPriorityList[i].dwScratchSpace = TRUE;
|
|
}
|
|
}
|
|
else if (lpPriorityList[i].fmtetc.cfFormat == cfLinkSource) {
|
|
|
|
//
|
|
// If there is OLE 2.0 LinkSource format, then handle it
|
|
// specially by calling OleQueryLinkFromData.
|
|
//
|
|
TRACEX(OwlOleDlg, 1, "OleQueryLinkFromData called");
|
|
hrErr = OleQueryLinkFromData(lpSrcDataObj);
|
|
if(NOERROR == hrErr) {
|
|
lpPriorityList[i].dwScratchSpace = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
TRACEX(OwlOleDlg, 1, "IDataObject::EnumFormatEtc called" );
|
|
hrErr = lpSrcDataObj->EnumFormatEtc(DATADIR_GET,
|
|
(LPENUMFORMATETC FAR*)&lpEnumFmtEtc);
|
|
|
|
if (hrErr != NOERROR) {
|
|
TRACEX(OwlOleDlg, 1, "Unable to get format enumerator." );
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Enumerate the formats offered by the source
|
|
// Loop over all formats offered by the source
|
|
//
|
|
cFetched = 0;
|
|
memset(rgfmtetc, 0, sizeof(rgfmtetc[MaxFormatEtc]));
|
|
if (lpEnumFmtEtc->Next(MaxFormatEtc, rgfmtetc, (ULONG*)&cFetched) == NOERROR
|
|
|| (cFetched > 0 && cFetched <= MaxFormatEtc) ) {
|
|
|
|
for (j = 0; j < cFetched; j++) {
|
|
for (i = 0; i < cEntries; i++) {
|
|
if (! lpPriorityList[i].dwScratchSpace &&
|
|
CompareFormatEtc(&rgfmtetc[(int)j], &lpPriorityList[i].fmtetc)==0) {
|
|
lpPriorityList[i].dwScratchSpace = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Clean up
|
|
//
|
|
if (lpEnumFmtEtc)
|
|
lpEnumFmtEtc->Release();
|
|
}
|
|
|
|
//
|
|
// Toggles between Paste and PasteLink. NOTE: The Paste and PasteLink
|
|
// ListBoxes are always invisible. The third visible listbox [displayListBox]
|
|
// is filled with the contents of the Paste or PasteLink Listbox
|
|
//
|
|
bool
|
|
TPasteSpecialDlg::TogglePasteType(TPasteSpecialFlags flag)
|
|
{
|
|
PRECONDITION(flag == psSelectPaste ||
|
|
flag == psSelectPasteLink);
|
|
|
|
//
|
|
// Skip if option's already selected
|
|
//
|
|
if (Helper.Flags & flag)
|
|
return true;
|
|
|
|
//
|
|
// Update Flags
|
|
//
|
|
Helper.Flags= (Helper.Flags & ~(psSelectPaste | psSelectPasteLink)) | flag;
|
|
|
|
//
|
|
// Prevent icon display flashes
|
|
//
|
|
Activate(IconImage, false);
|
|
|
|
//
|
|
// Update Source and Icon displays and save index
|
|
//
|
|
TListBox *fromList = 0;
|
|
if (Helper.Flags & psSelectPaste) {
|
|
//
|
|
// Set source of object in clipboard
|
|
//
|
|
SourceText->SetText(Helper.SourceOfDataOD);
|
|
|
|
//
|
|
// Update Icon is one's available
|
|
//
|
|
if (Helper.MetaPictOD)
|
|
IconImage->SetMetaPict(Helper.MetaPictOD);
|
|
|
|
//
|
|
// Save current PasteLink index
|
|
//
|
|
Helper.PasteLinkListCurSel = DisplayList->GetSelIndex();
|
|
if (Helper.PasteLinkListCurSel == LB_ERR)
|
|
Helper.PasteLinkListCurSel = 0;
|
|
|
|
//
|
|
// Clear link flag
|
|
//
|
|
Helper.Link = false;
|
|
|
|
fromList = PasteList;
|
|
}
|
|
else { // PasteLink selected
|
|
//
|
|
// Update source of object in clipboard
|
|
//
|
|
SourceText->SetText(Helper.SourceOfDataLSD);
|
|
|
|
//
|
|
// Update Icon if one's available
|
|
//
|
|
if (Helper.MetaPictLSD)
|
|
IconImage->SetMetaPict(Helper.MetaPictLSD);
|
|
|
|
//
|
|
// Save current Paste index
|
|
//
|
|
Helper.PasteListCurSel = DisplayList->GetSelIndex();
|
|
if (Helper.PasteListCurSel == LB_ERR)
|
|
Helper.PasteListCurSel = 0;
|
|
|
|
//
|
|
// Set Link Flag
|
|
//
|
|
Helper.Link = true;
|
|
|
|
fromList = PasteLinkList;
|
|
}
|
|
|
|
//
|
|
// Refill display list
|
|
//
|
|
DisplayList->SetRedraw(false);
|
|
DisplayList->ClearList();
|
|
|
|
int itemCount = fromList->GetCount();
|
|
TPointer<char> buff = new char[GenericBufferLen];
|
|
for (int i=0; i<itemCount; i++) {
|
|
//
|
|
// Store strings
|
|
//
|
|
fromList->GetString(buff, i);
|
|
DisplayList->InsertString(buff, i);
|
|
|
|
//
|
|
// Store item data
|
|
//
|
|
DisplayList->SetItemData(i, fromList->GetItemData(i));
|
|
}
|
|
|
|
//
|
|
// Retore saved index
|
|
//
|
|
if (Helper.Flags & psSelectPaste)
|
|
DisplayList->SetSelIndex(Helper.PasteListCurSel);
|
|
else
|
|
DisplayList->SetSelIndex(Helper.PasteLinkListCurSel);
|
|
|
|
//
|
|
// Update Display Listbox
|
|
//
|
|
DisplayList->SetRedraw(true);
|
|
DisplayList->Invalidate();
|
|
DisplayList->UpdateWindow();
|
|
|
|
//
|
|
// Focus on Display Listbox
|
|
//
|
|
DisplayList->SetFocus();
|
|
|
|
//
|
|
// Allow updating of 'displayAsIcon', help result and bitmap
|
|
// according to the new selection
|
|
//
|
|
ChangeListSelection();
|
|
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Called when user changes the selection in the Listbox to enable/disable
|
|
// 'DisplayAsIcon' and update the result text and bitmap.
|
|
//
|
|
void
|
|
TPasteSpecialDlg::ChangeListSelection()
|
|
{
|
|
//
|
|
// Update result text&bitmap and enable/disable 'DisplayAsIcon'
|
|
//
|
|
EnableDisplayAsIcon();
|
|
SetPasteSpecialHelpResults();
|
|
|
|
//
|
|
// Retrieve selected index
|
|
//
|
|
int curSel = DisplayList->GetSelIndex();
|
|
if (curSel == LB_ERR)
|
|
return;
|
|
|
|
//
|
|
// Retrieve item data associated with index
|
|
//
|
|
TPasteListItemData FAR* itemData;
|
|
itemData = (TPasteListItemData FAR*)DisplayList->GetItemData(curSel);
|
|
|
|
if ((long)itemData == LB_ERR)
|
|
return;
|
|
|
|
//
|
|
// Save index
|
|
//
|
|
Helper.SelectedIndex = itemData->nPasteEntriesIndex;
|
|
}
|
|
|
|
//
|
|
// Enables/Disables 'DisplayAsIcon' based on the current source selection
|
|
// container's specification as outlined in table below:
|
|
//
|
|
//------------------------------------------------------------------------+
|
|
// Src. specifies | Src specifies | Contnr specifies| NET RESULTS |
|
|
// DVASPECT_ICON | OLEMISC_ONLYICONIC | pfEnableIcon | Check - Enable |
|
|
// ===============+====================+=================+================+
|
|
// N/A | N/A | N | N N |
|
|
// ---------------+--------------------+-----------------+----------------|
|
|
// N/A | Y | Y | Y N |
|
|
// ---------------+--------------------+-----------------+----------------|
|
|
// Y | N | Y | Y Y |
|
|
// ---------------+--------------------+-----------------+----------------|
|
|
// N | N | Y | N Y |
|
|
// ---------------+--------------------+-----------------+----------------|
|
|
//
|
|
void
|
|
TPasteSpecialDlg::EnableDisplayAsIcon()
|
|
{
|
|
bool srcOnlyIconic = (Helper.Link) ? Helper.SrcOnlyIconicLSD :
|
|
Helper.SrcOnlyIconicOD;
|
|
bool srcAspectIcon = (Helper.Link) ? Helper.SrcAspectIconLSD :
|
|
Helper.SrcAspectIconOD;
|
|
HGLOBAL metaPict = (Helper.Link) ? Helper.MetaPictLSD :
|
|
Helper.MetaPictOD;
|
|
bool cntrEnableIcon = false;;
|
|
int index = DisplayList->GetSelIndex();
|
|
|
|
//
|
|
// Get data of current selection
|
|
//
|
|
if (index != LB_ERR) {
|
|
TPasteListItemData FAR* itemData;
|
|
itemData = (TPasteListItemData FAR*)DisplayList->GetItemData(index);
|
|
if ((long)itemData != LB_ERR) {
|
|
cntrEnableIcon = itemData->fCntrEnableIcon;
|
|
}
|
|
else {
|
|
cntrEnableIcon = false;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If there's an icon available
|
|
//
|
|
if (metaPict) {
|
|
//
|
|
// Does container specify pfEnableIcon (OLEUIPASTE_ENABLEICON)?
|
|
//
|
|
if (!cntrEnableIcon) {
|
|
//
|
|
// Uncheck and disable 'DisplayAsIcon'
|
|
//
|
|
Helper.Flags &= ~psCheckDisplayAsIcon;
|
|
DisplayAsIcon->Uncheck();
|
|
DisplayAsIcon->EnableWindow(false);
|
|
|
|
//
|
|
// Hide the icon image and 'ChangeIcon'
|
|
//
|
|
Activate(ChangeIcon, false);
|
|
Activate(IconImage, false);
|
|
}
|
|
else if (srcOnlyIconic) { // Does SOURCE specify OLEMISC_ONLYICONIC
|
|
//
|
|
// Check and Disable 'DisplayAsIcon'
|
|
//
|
|
Helper.Flags |= psCheckDisplayAsIcon;
|
|
DisplayAsIcon->Check();
|
|
DisplayAsIcon->EnableWindow(false);
|
|
|
|
//
|
|
// Show iconImage and ChangeIcon button
|
|
//
|
|
Activate(ChangeIcon, true);
|
|
Activate(IconImage, true);
|
|
}
|
|
else if (srcAspectIcon) { // Does SOURCE specify DVASPECT_ICON
|
|
//
|
|
// Check and Enable 'DisplayAsIcon'
|
|
//
|
|
Helper.Flags |= psCheckDisplayAsIcon;
|
|
DisplayAsIcon->Check();
|
|
DisplayAsIcon->EnableWindow(true);
|
|
|
|
//
|
|
// Show iconImage and ChangeIcon button
|
|
//
|
|
Activate(ChangeIcon, true);
|
|
Activate(IconImage, true);
|
|
}
|
|
else {
|
|
//
|
|
// Uncheck and Enable DisplayAsIcon
|
|
//
|
|
Helper.Flags &= ~psCheckDisplayAsIcon;
|
|
DisplayAsIcon->Uncheck();
|
|
DisplayAsIcon->EnableWindow(true);
|
|
|
|
//
|
|
// Hide IconImage and ChangeIcon button
|
|
//
|
|
Activate(ChangeIcon, false);
|
|
Activate(IconImage, false);
|
|
}
|
|
}
|
|
else { // No Icon is available
|
|
//
|
|
// Uncheck and Disable displayAsIcon
|
|
//
|
|
Helper.Flags &= ~psCheckDisplayAsIcon;
|
|
DisplayAsIcon->Uncheck();
|
|
DisplayAsIcon->EnableWindow(false);
|
|
|
|
//
|
|
// Hide iconImage and ChangeIcon button
|
|
//
|
|
Activate(ChangeIcon, false);
|
|
Activate(IconImage, false);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Updates the flags; Hides/Shows the IconImage control and the
|
|
// ChangeIcon Button - Also updates the help result text and bitmap.
|
|
//
|
|
void
|
|
TPasteSpecialDlg::ToggleDisplayAsIcon()
|
|
{
|
|
bool checked = IsDlgButtonChecked(IDC_DISPLAYASICON) ? true : false;
|
|
|
|
//
|
|
// Update Flags
|
|
//
|
|
if (checked)
|
|
Helper.Flags |= psCheckDisplayAsIcon;
|
|
else
|
|
Helper.Flags &= ~psCheckDisplayAsIcon;
|
|
|
|
//
|
|
// Set result text and bitmap
|
|
//
|
|
SetPasteSpecialHelpResults();
|
|
|
|
//
|
|
// Show/hide Icon and ChgIcon button
|
|
//
|
|
Activate(IconImage, checked);
|
|
Activate(ChangeIcon, checked);
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
bool
|
|
TPasteSpecialDlg::HasPercentS(const char far* str)
|
|
{
|
|
if (!str)
|
|
return false;
|
|
|
|
//
|
|
// Copy passed string to local buffer
|
|
//
|
|
TPointer<char> buff = new char[GenericBufferLen];
|
|
strcpy(buff, str);
|
|
|
|
char* pBuff = buff;
|
|
while(*pBuff) {
|
|
if (*pBuff == '%') {
|
|
pBuff = AnsiNext(pBuff);
|
|
if (*pBuff == 's') {
|
|
return true;
|
|
}
|
|
else if (*pBuff == '%') {
|
|
pBuff = AnsiNext(pBuff);
|
|
}
|
|
}
|
|
else {
|
|
pBuff = AnsiNext(pBuff);
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
void
|
|
TPasteSpecialDlg::SetPasteSpecialHelpResults()
|
|
{
|
|
int selIndex = DisplayList->GetSelIndex();
|
|
if (selIndex == LB_ERR) {
|
|
TRACEX(OwlOleDlg, 1, "No item selected to display HelpResults");
|
|
return;
|
|
}
|
|
|
|
TPasteListItemData FAR *lpItemData;
|
|
lpItemData = (TPasteListItemData FAR*)DisplayList->GetItemData(selIndex);
|
|
if ((LRESULT)lpItemData == LB_ERR) {
|
|
TRACEX(OwlOleDlg, 1, "No PasteListItemData found at " << selIndex);
|
|
return;
|
|
}
|
|
|
|
int nPasteEntriesIndex = lpItemData->nPasteEntriesIndex;
|
|
bool fIsObject = HasPercentS(
|
|
Data->ArrayPasteEntries[nPasteEntriesIndex].lpstrFormatName
|
|
);
|
|
|
|
bool fDisplayAsIcon = (Helper.Flags & psCheckDisplayAsIcon) ? true : false;
|
|
LPSTR lpszFullUserTypeName = Helper.Link ? Helper.FullUserTypeNameLSD :
|
|
Helper.FullUserTypeNameOD;
|
|
LPSTR lpszInsert = lpszFullUserTypeName;
|
|
|
|
uint iString = 0;
|
|
uint iImage = 0;
|
|
|
|
if (Helper.Flags & psSelectPaste) {
|
|
if (fIsObject) {
|
|
iString = fDisplayAsIcon ? IDS_PSPASTEOBJECTASICON : IDS_PSPASTEOBJECT;
|
|
iImage = fDisplayAsIcon ? riEmbedIcon : riEmbed;
|
|
lpszInsert = Helper.AppName;
|
|
}
|
|
else {
|
|
iString = IDS_PSPASTEDATA;
|
|
iImage = riPaste;
|
|
}
|
|
}
|
|
else if (Helper.Flags & psSelectPasteLink) {
|
|
if (fIsObject) {
|
|
iString = fDisplayAsIcon ? IDS_PSPASTELINKOBJECTASICON :
|
|
IDS_PSPASTELINKOBJECT;
|
|
iImage = fDisplayAsIcon ? riLinkIcon : riLink;
|
|
}
|
|
else {
|
|
iString = IDS_PSPASTELINKDATA;
|
|
iImage = riLink;
|
|
}
|
|
}
|
|
else {
|
|
TRACEX(OwlOleDlg, 1, "Non-OLE object - Error!");
|
|
iString = IDS_PSNONOLE;
|
|
iImage = riPaste;
|
|
}
|
|
|
|
//
|
|
// Allocator buffers to build help text
|
|
//
|
|
TPointer<char> pstr1 = new char[GenericBufferLen];
|
|
TPointer<char> pstr2 = new char[GenericBufferLen];
|
|
TPointer<char> pstr3 = new char[GenericBufferLen];
|
|
TPointer<char> pstr4 = new char[GenericBufferLen];
|
|
|
|
//
|
|
// Build String from resource.
|
|
//
|
|
*((char*)pstr1) = 0; // Default to empty string
|
|
if (GetModule()->LoadString(iString, (LPSTR)(char*)pstr1, GenericBufferLen)) {
|
|
wsprintf((LPSTR)(char*)pstr3,
|
|
Data->ArrayPasteEntries[nPasteEntriesIndex].lpstrResultText,
|
|
lpszInsert);
|
|
|
|
wsprintf((LPSTR)(char*)pstr4, (LPSTR)(char*)pstr1, (LPSTR)(char*)pstr3);
|
|
strcpy(pstr1, pstr4);
|
|
}
|
|
|
|
//
|
|
// Update Display
|
|
//
|
|
ResultText->SetText(pstr1);
|
|
ResultImage->SetBitmapIndex(iImage);
|
|
}
|
|
|
|
//
|
|
// Adds the name of an object to the Paste or PasteLink listboxes.
|
|
//
|
|
bool
|
|
TPasteSpecialDlg::AddPasteListItem(TListBox &list, bool insertFirst,
|
|
int pasteEntryIndex,
|
|
const char far* fullUserTypeName)
|
|
{
|
|
TPointer<char> buff = new char[GenericBufferLen];
|
|
TPasteListItemData FAR* pItemData = new TPasteListItemData;
|
|
|
|
//
|
|
// Initialize PasteList Item Data
|
|
//
|
|
pItemData->nPasteEntriesIndex = pasteEntryIndex;
|
|
if (Data->ArrayPasteEntries[pasteEntryIndex].dwFlags & pfEnableIcon) {
|
|
pItemData->fCntrEnableIcon = TRUE;
|
|
}
|
|
else {
|
|
pItemData->fCntrEnableIcon = FALSE;
|
|
}
|
|
|
|
//
|
|
// Build the listbox entry string
|
|
//
|
|
wsprintf((LPSTR)(char*)buff,
|
|
Data->ArrayPasteEntries[pasteEntryIndex].lpstrFormatName,
|
|
(LPSTR)fullUserTypeName);
|
|
|
|
//
|
|
// Add data if it's not a duplicate
|
|
//
|
|
if (list.FindString(buff, 0) == LB_ERR) {
|
|
int index = insertFirst ? list.InsertString(buff, 0) : list.AddString(buff);
|
|
list.SetItemData(index, (LPARAM)pItemData);
|
|
}
|
|
else {
|
|
delete pItemData;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//
|
|
// Fill the (invisible) Paste listbox with the formats offered by the
|
|
// Clipboard object and asked form by the container
|
|
//
|
|
bool
|
|
TPasteSpecialDlg::FillPasteList()
|
|
{
|
|
int items = 0;
|
|
int defFormat = -1;
|
|
bool insertFirst = false;
|
|
bool tryObjFmt = false;
|
|
bool exclude = false;
|
|
|
|
//
|
|
// Loop through target's priority list of formats
|
|
//
|
|
for (int i=0; i<Data->cPasteEntries; i++) {
|
|
if (Data->ArrayPasteEntries[i].dwFlags != pfPasteOnly &&
|
|
!(Data->ArrayPasteEntries[i].dwFlags & pfPaste))
|
|
continue;
|
|
|
|
insertFirst = false;
|
|
|
|
if (Data->ArrayPasteEntries[i].fmtetc.cfFormat == cfFileName ||
|
|
Data->ArrayPasteEntries[i].fmtetc.cfFormat == cfEmbeddedObject ||
|
|
Data->ArrayPasteEntries[i].fmtetc.cfFormat == cfEmbedSource) {
|
|
if (!tryObjFmt) {
|
|
tryObjFmt = true; // Only use first object format
|
|
insertFirst = true; // OLE obj. format should always be first
|
|
|
|
//
|
|
// Check exclusion list
|
|
//
|
|
exclude = false;
|
|
for( int j=0; j < (int)Data->cClsIdExclude; j++) {
|
|
if (IsEqualCLSID(Helper.ClsIdOD, *(Data->lpClsIdExclude+j))) {
|
|
exclude = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Skip object if in exclusion list
|
|
//
|
|
if (exclude)
|
|
continue;
|
|
}
|
|
else {
|
|
//
|
|
// Already added an object format to list
|
|
//
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Ass to list if entry is marked true
|
|
//
|
|
if (Data->ArrayPasteEntries[i].dwScratchSpace) {
|
|
if (defFormat < 0) {
|
|
defFormat = insertFirst ? 0 : items;
|
|
}
|
|
else if (insertFirst) {
|
|
defFormat++;
|
|
}
|
|
if (AddPasteListItem(*PasteList, insertFirst, i,
|
|
Helper.FullUserTypeNameOD)) {
|
|
items++;
|
|
}
|
|
else {
|
|
FreeListData(*PasteList);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Initialize select to first matching format
|
|
//
|
|
if (defFormat >= 0)
|
|
Helper.PasteListCurSel = defFormat;
|
|
|
|
return (items > 0) ? true : false;
|
|
}
|
|
|
|
//
|
|
// Fill the (invisible) PasteLink listbox with the formats offered by the
|
|
// Clipboard object and asked form by the container
|
|
//
|
|
bool
|
|
TPasteSpecialDlg::FillPasteLinkList()
|
|
{
|
|
int items = 0;
|
|
int defFormat = -1;
|
|
bool tryObjFmt = false;
|
|
bool insertFirst = true;
|
|
LPDATAOBJECT lpSrcDataObj = Data->lpSrcDataObj;
|
|
|
|
FORMATETC fmtetc;
|
|
memset(&fmtetc, 0, sizeof(fmtetc));
|
|
|
|
//
|
|
// Array of flags indicating which link types are supported
|
|
//
|
|
bool arrayLinkTypesSupported[MaxLinkTypes];
|
|
bool linkTypeSupported = false;
|
|
|
|
for (int i=0; i<Data->cLinkTypes; i++) {
|
|
if (Data->ArrayLinkTypes[i] == cfLinkSource) {
|
|
TRACEX(OwlOleDlg, 1, "Calling OleQueryLinkFromData.");
|
|
if (OleQueryLinkFromData(lpSrcDataObj) == S_OK) {
|
|
arrayLinkTypesSupported[i] = true;
|
|
linkTypeSupported = true;
|
|
}
|
|
else {
|
|
arrayLinkTypesSupported[i] = false;
|
|
};
|
|
}
|
|
else {
|
|
fmtetc.cfFormat = Data->ArrayLinkTypes[i];
|
|
fmtetc.dwAspect = DVASPECT_CONTENT;
|
|
fmtetc.tymed = 0xFFFFFFFFL; // All tymed values
|
|
fmtetc.lindex = -1;
|
|
|
|
TRACEX(OwlOleDlg, 1, "IDataObject::QueryGetData called.");
|
|
if (lpSrcDataObj->QueryGetData(&fmtetc) == S_OK) {
|
|
arrayLinkTypesSupported[i] = true;
|
|
linkTypeSupported = true;
|
|
}
|
|
else {
|
|
arrayLinkTypesSupported[i] = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check if link types are offered by SourceDataObject
|
|
//
|
|
if (!linkTypeSupported) {
|
|
TRACEX(OwlOleDlg, 1, "No link types are offered by data source.");
|
|
items = 0;
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Iterate through acceptable formats
|
|
//
|
|
for(i=0; i<Data->cPasteEntries; i++) {
|
|
linkTypeSupported = false;
|
|
//
|
|
// Does container accept an link type offered by source object
|
|
//
|
|
if (Data->ArrayPasteEntries[i].dwFlags & pfLinkAnyType)
|
|
linkTypeSupported = true;
|
|
else {
|
|
//
|
|
// Checked if link types offered by source are acceptable
|
|
//
|
|
int j=0;
|
|
uint32 pasteFlag;
|
|
for (pasteFlag = pfLinkType1, j=0;
|
|
j < Data->cLinkTypes;
|
|
pasteFlag *=2, j++) {
|
|
if ((Data->ArrayPasteEntries[i].dwFlags & pasteFlag) &&
|
|
arrayLinkTypesSupported[i]) {
|
|
linkTypeSupported = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
insertFirst = false;
|
|
if ((Data->ArrayPasteEntries[i].fmtetc.cfFormat == cfFileName) ||
|
|
(Data->ArrayPasteEntries[i].fmtetc.cfFormat == cfLinkSource)) {
|
|
if (!tryObjFmt) {
|
|
tryObjFmt = true; // Only use first object format
|
|
insertFirst = true; // OLE object format should be first
|
|
}
|
|
else {
|
|
continue; // Already added object format to list
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add to list if entry's marked true
|
|
//
|
|
if (linkTypeSupported &&
|
|
Data->ArrayPasteEntries[i].dwScratchSpace) {
|
|
if (defFormat < 0) {
|
|
defFormat = insertFirst ? 0 : items;
|
|
}
|
|
else if (insertFirst) {
|
|
defFormat++;
|
|
}
|
|
|
|
if (AddPasteListItem(*PasteLinkList, insertFirst, i,
|
|
Helper.FullUserTypeNameLSD)) {
|
|
items++;
|
|
}
|
|
else {
|
|
FreeListData(*PasteLinkList);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Initialize selection to first matching format
|
|
//
|
|
if (defFormat >= 0)
|
|
Helper.PasteLinkListCurSel = defFormat;
|
|
|
|
items = PasteLinkList->GetCount();
|
|
return (items > 0) ? true : false;
|
|
}
|
|
|
|
//
|
|
// Frees PasteListItem data memory associated with each listbox entry.
|
|
//
|
|
void
|
|
TPasteSpecialDlg::FreeListData(TListBox &list)
|
|
{
|
|
TPasteListItemData FAR *lpItemData;
|
|
|
|
int items = list.GetCount();
|
|
for (int i=0; i<items; i++) {
|
|
lpItemData = (TPasteListItemData FAR*)(LPARAM)list.GetItemData(i);
|
|
if ((LPARAM)lpItemData != LB_ERR)
|
|
delete lpItemData;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Allows user to change current icon via the ChangeIcon Dialog
|
|
//
|
|
void
|
|
TPasteSpecialDlg::ChangeIconClicked()
|
|
{
|
|
TRY {
|
|
//
|
|
// Allocate and populate structure to hold parameters
|
|
//
|
|
TChangeIconDlg::TData &data = *new TChangeIconDlg::TData;
|
|
TPointer<TChangeIconDlg::TData> _cln1(&data);
|
|
data.MetaPict = IconImage->GetMetaPict();
|
|
data.Flags = ciSelectCurrent;
|
|
data.ClsId = Helper.Link ? Helper.ClsIdLSD : Helper.ClsIdOD;
|
|
|
|
if (Helper.Flags & ioShowHelp)
|
|
data.Flags |= ciShowHelp;
|
|
|
|
//
|
|
// Allocate dialog and execute
|
|
//
|
|
TChangeIconDlg &chgIconDlg = *new TChangeIconDlg(this, data);
|
|
TPointer<TChangeIconDlg> _cln2(&chgIconDlg);
|
|
if (chgIconDlg.Execute() == IDOK){
|
|
//
|
|
// Update display with new icon
|
|
//
|
|
IconImage->SetMetaPict(data.MetaPict);
|
|
|
|
//
|
|
// Save away new icon
|
|
//
|
|
if (Helper.Link)
|
|
Helper.MetaPictLSD = data.MetaPict;
|
|
else
|
|
Helper.MetaPictOD = data.MetaPict;
|
|
}
|
|
}
|
|
CATCH( (xmsg& msg){ GetModule()->Error(msg, 0); } )
|
|
}
|
|
|
|
//
|
|
// Switches to the PasteList
|
|
//
|
|
void
|
|
TPasteSpecialDlg::PasteClicked()
|
|
{
|
|
TogglePasteType(psSelectPaste);
|
|
}
|
|
|
|
//
|
|
// Switches to the PasteLink List
|
|
//
|
|
void
|
|
TPasteSpecialDlg::PasteLinkClicked()
|
|
{
|
|
TogglePasteType(psSelectPasteLink);
|
|
}
|
|
|
|
//
|
|
// Handles request to display Paste/Link as Icon
|
|
//
|
|
void
|
|
TPasteSpecialDlg::DisplayAsIconClicked()
|
|
{
|
|
ToggleDisplayAsIcon();
|
|
}
|
|
|
|
//
|
|
// Handles change in selection of items to paste/pasteLink
|
|
//
|
|
void
|
|
TPasteSpecialDlg::DisplayListSelChange()
|
|
{
|
|
ChangeListSelection();
|
|
}
|
|
|
|
//
|
|
// A double click on the Paste/PasteLink listbox is treated
|
|
// similar to hitting the OK button.
|
|
//
|
|
void
|
|
TPasteSpecialDlg::DisplayListDblClk()
|
|
{
|
|
SendNotification(IDOK, BN_CLICKED, GetDlgItem(IDOK));
|
|
}
|
|
|
|
//
|
|
// Handles notification that Clipboard content has changed.
|
|
// This basically means bad news since the data we're currently
|
|
// displaying to the user for Pasting/PasteLinking is now inaccurate.
|
|
//
|
|
void
|
|
TPasteSpecialDlg::EvDrawClipboard()
|
|
{
|
|
HWND hwndSaved = (HWND)GetProp(NEXTCBVIEWER);
|
|
if (hwndSaved == HWND_BROADCAST)
|
|
return;
|
|
|
|
//
|
|
// Take ourselves out of the loop
|
|
//
|
|
SetProp(NEXTCBVIEWER, HWND_BROADCAST);
|
|
::ChangeClipboardChain(*this, hwndSaved);
|
|
|
|
//
|
|
// Bring down the dialog
|
|
//
|
|
}
|
|
|
|
//
|
|
// Handle notification that a Window is being removed from
|
|
// Clipboard chain.
|
|
//
|
|
void
|
|
TPasteSpecialDlg::EvChangeCBChain(HWND hwndRemoved, HWND hwndNext)
|
|
{
|
|
//
|
|
// If the one after us is going, save the one following it.
|
|
//
|
|
HWND hwndSaved = (HWND)GetProp(NEXTCBVIEWER);
|
|
if (hwndRemoved == hwndSaved) {
|
|
SetProp(NEXTCBVIEWER, hwndNext);
|
|
//
|
|
// Otherwise pass the buck along
|
|
//
|
|
}
|
|
else if (hwndSaved && hwndSaved != HWND_BROADCAST) {
|
|
::SendMessage(hwndSaved, WM_CHANGECBCHAIN, (WPARAM)hwndRemoved,
|
|
(LPARAM)hwndNext);
|
|
}
|
|
}
|
|
|