| Current Path : /var/www/html/prashantkr/TurboC/TCWIN45/SOURCE/OWL/ |
| Current File : /var/www/html/prashantkr/TurboC/TCWIN45/SOURCE/OWL/PASTESPC.CPP |
//----------------------------------------------------------------------------
// 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);
}
}