Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1210 lines
28 KiB

/****************************** Module Header ******************************\
* Module Name: Item.c Object(item) main module
*
* Purpose: Includes All the object releated routiens.
*
* Created: Oct 1990.
*
* Copyright (c) 1990, 1991 Microsoft Corporation
*
* History:
* Raor (../10/1990) Designed, coded
*
*
\***************************************************************************/
#include "ole2int.h"
//#include "cmacs.h"
#include <dde.h>
#include "ddeatoms.h"
#include "ddedebug.h"
#include "srvr.h"
#include "itemutil.h"
ASSERTDATA
// !!!change child enumeration.
// !!!No consistency in errors (Sometimes Bools and sometimes HRESULT).
//SearchItem: Searches for a given item in a document tree.
//If found, returns the corresponding client ptr.
INTERNAL_(LPCLIENT) CDefClient::SearchItem
(
LPOLESTR lpitemname
)
{
ATOM aItem;
LPCLIENT lpclient;
ChkC(this);
Assert (m_pdoc==this);
Assert (m_bContainer);
Puts ("DefClient::SearchItem\r\n");
// If the item passed is an atom, get its name.
if (!HIWORD(lpitemname))
aItem = (ATOM) (LOWORD((DWORD)lpitemname));
else if (!lpitemname[0])
aItem = NULL;
else
aItem = GlobalFindAtom (lpitemname);
// walk thru the items list and mtach for the itemname.
lpclient = this;
while (lpclient) {
ChkC(lpclient);
if (lpclient->m_aItem == aItem)
return lpclient;
// The NULL item is the client that is a container (the whole doc).
// REVIEW: jasonful
if (lpclient->m_bContainer && aItem==NULL)
return lpclient;
lpclient = lpclient->m_lpNextItem;
}
Puts ("SearchItem failed\r\n");
return NULL;
}
// FindItem: Given the itemname and the doc obj ptr,
// searches for the the item (object) in the document tree.
// Items are lonked to the doc obj.
INTERNAL_(HRESULT) CDefClient::FindItem
(
LPOLESTR lpitemname,
LPCLIENT FAR * lplpclient
)
{
LPCLIENT lpclient;
WCHAR buf[MAX_STR];
Puts ("DefClient::FindItem "); Puts (lpitemname); Putn();
ChkC(this);
if (lpclient = SearchItem (lpitemname)) {
// we found the item window
ChkC(lpclient);
*lplpclient = lpclient;
return NOERROR;
}
if (!HIWORD(lpitemname)){
if (LOWORD(lpitemname))
GlobalGetAtomName ((ATOM)LOWORD((DWORD)lpitemname),
buf, MAX_STR);
else
buf[0] = NULL;
lpitemname = buf;
}
// Item (object)window is not created yet. Let us create one.
return RegisterItem (lpitemname, lplpclient, TRUE);
}
//RegisterItem: Given the document handle and the item string
//creates item with the given name in the doc obj list..
INTERNAL CDefClient::RegisterItem
(LPOLESTR lpitemname,
LPCLIENT FAR * lplpclient,
BOOL bSrvr)
{
LPCLIENT pitemNew = NULL;
HRESULT hresult = ReportResult(0, E_UNEXPECTED, 0, 0);
LPOLEOBJECT lpoleObj = NULL;
LPOLEITEMCONTAINER lpcontainer;
intrDebugOut((DEB_ITRACE,
"%x _IN CDefClient::RegisterItem(%ws)\n",
this,WIDECHECK(lpitemname)));
ChkC(this);
AssertIsDoc(this);
*lplpclient = NULL;
ErrZS (pitemNew = new CDefClient(NULL), E_OUTOFMEMORY);
pitemNew->m_bTerminate = FALSE;
pitemNew->m_bContainer = FALSE; // not a container, i.e.,document
// Set containing document
pitemNew->m_pdoc = this;
m_pUnkOuter->AddRef(); // item keeps its document alive
// Corresponding Release is in CDefClient::~CDefClient
if (!HIWORD(lpitemname)) {
AssertSz (!bSrvr, "invalid lpitemname in RegisterItem\r\n");
pitemNew->m_aItem = LOWORD((DWORD)lpitemname);
}
else if (!lpitemname[0])
pitemNew->m_aItem = NULL;
else
pitemNew->m_aItem = wGlobalAddAtom (lpitemname);
lpoleObj = m_lpoleObj;
// Call the server if the item is not one of the standard items.
if (bSrvr) {
// Call the server app for container interface
hresult = lpoleObj->QueryInterface (IID_IOleItemContainer, (LPVOID FAR *)&lpcontainer);
if (hresult != NOERROR)
{
intrDebugOut((DEB_IERROR,
"%x ::RegisterItem(%ws) No IOleContainer intr\n",
this,WIDECHECK(lpitemname)));
goto errRtn;
}
hresult = lpcontainer->GetObject(lpitemname, BINDSPEED_INDEFINITE, 0,
IID_IOleObject, (LPLPVOID)&pitemNew->m_lpoleObj);
if (hresult != NOERROR)
{
intrDebugOut((DEB_ERROR,
"IOleItemContainer::GetObject(%ws,...) failed (hr=%x)\n",
lpitemname,
hresult));
}
lpcontainer->Release ();
if (hresult != NOERROR)
goto errRtn;
hresult = pitemNew->m_lpoleObj->QueryInterface (IID_IDataObject, (LPLPVOID)
&pitemNew->m_lpdataObj);
if (hresult != NOERROR)
{
intrDebugOut((DEB_ERROR,
"::QueryInterface(IID_IDataObject) failed (hr=%x)\n",
hresult));
pitemNew->m_lpoleObj->Release();
goto errRtn;
}
// This is for Packager, in particular. If client does not advise
// on any data, we still need to do an OLE advise so we can get
// OnClose notifications.
pitemNew->DoOle20Advise (OLE_CLOSED, (CLIPFORMAT)0);
}
// This keeps the CDefClient alive until _we_ are done with it
// The corresponding Release is in CDefClient::Revoke
pitemNew->m_pUnkOuter->AddRef();
pitemNew->m_lpNextItem = m_lpNextItem;
pitemNew->m_hwnd = m_hwnd; // set the window handle to
// same as the doc level window
m_lpNextItem = pitemNew;
*lplpclient = pitemNew;
hresult = NOERROR;
goto exitRtn;
errRtn:
if (pitemNew) {
delete pitemNew;
}
exitRtn:
intrDebugOut((DEB_ITRACE,
"%x CDefClient::RegisterItem(%ws) hresult=%x\n",
this,WIDECHECK(lpitemname),hresult));
return(hresult);
}
// Return NOERROR if "this" document has no items which have connections
// (client windows).
//
INTERNAL CDefClient::NoItemConnections (void)
{
PCLINFO pclinfo = NULL;
HANDLE hcliPrev = NULL;
HANDLE hcli;
PCLILIST pcli;
HANDLE *phandle;
ChkCR (this);
AssertIsDoc (this);
LPCLIENT pitem;
for (pitem = m_lpNextItem;
pitem;
pitem = pitem->m_lpNextItem)
{
ChkCR (pitem);
if (pitem->m_aItem == aStdDocName)
continue;
hcli = pitem->m_hcliInfo;
while (hcli)
{
if ((pcli = (PCLILIST) LocalLock (hcli)) == NULL)
return ResultFromScode (S_FALSE);
phandle = (HANDLE *) (pcli->info);
while (phandle < (HANDLE *)(pcli + 1))
{
if (*phandle)
{
LocalUnlock (hcli);
return ResultFromScode (S_FALSE);
}
else
{
phandle++;
phandle++;
}
}
hcliPrev = hcli;
hcli = pcli->hcliNext;
LocalUnlock (hcliPrev);
}
}
return NOERROR;
}
INTERNAL_(void) CDefClient::DeleteAdviseInfo (void)
{
PCLINFO pclinfo = NULL;
HANDLE hcliPrev = NULL;
PCLILIST pcli;
HANDLE *phandle;
HANDLE hcli;
HANDLE hcliInfo;
Puts ("DefClient::DeleteAdviseInfo\r\n");
ChkC(this);
hcli = m_hcliInfo;
while (hcli) {
if ((pcli = (PCLILIST) LocalLock (hcli)) == NULL)
return;
phandle = (HANDLE *) (pcli->info);
while (phandle < (HANDLE *)(pcli + 1)) {
if (*phandle) {
*phandle++ = 0;
// delete the printer dev info block
if(pclinfo = (PCLINFO)LocalLock ((hcliInfo = *phandle++))){
if(pclinfo->hdevInfo)
GlobalFree (pclinfo->hdevInfo);
LocalUnlock (hcliInfo);
// no free if lock failed
LocalFree (hcliInfo);
}
} else {
phandle++;
phandle++;
}
}
hcliPrev = hcli;
hcli = pcli->hcliNext;
LocalUnlock (hcliPrev);
LocalFree (hcliPrev); // free the block;
}
m_hcliInfo = NULL;
}
//DeleteFromItemsList: Deletes a client from the object lists of
//all the objects of a given document. Thie client possibly
//is terminating the conversation with our doc window.
//
INTERNAL_(void) CDefClient::DeleteFromItemsList
(HWND hwndClient)
{
HANDLE hclinfo;
PCLINFO pclinfo;
LPCLIENT lpclient;
LPCLIENT FAR* ppitemLast = NULL;
BOOL fRevokedDoc = FALSE;
static int staticcounter;
int counter = ++staticcounter;
Puts ("DefClient::DeleteFromItemsList "); Puti(counter); Putn();
AssertIsDoc(this);
lpclient = this;
ppitemLast = &m_lpNextItem;
while (lpclient)
{
ChkC(lpclient);
BOOL fDoc = (lpclient==this);
if (fDoc)
{
AssertIsDoc (lpclient);
// Remove window from doc's master list
HWND hwnd = (HWND) FindClient (lpclient->m_hcli, hwndClient, /*fDelete*/TRUE);
Assert (hwnd==hwndClient);
}
hclinfo = FindClient (lpclient->m_hcliInfo, hwndClient, /*fDelete*/TRUE);
LPCLIENT pitemNext = lpclient->m_lpNextItem;
// We must make sure no other client is connected (linked)
// to this item before deleting.
if (!fDoc && AreNoClients (lpclient->m_hcliInfo))
{
Assert (ppitemLast);
if (ppitemLast && !fDoc)
{
// Remove from linked list
*ppitemLast = lpclient->m_lpNextItem;
}
fRevokedDoc |= fDoc;
lpclient->Revoke ();
}
else
{
ppitemLast = &(lpclient->m_lpNextItem);
}
if (hclinfo)
{
if(pclinfo = (PCLINFO)LocalLock (hclinfo))
{
if(pclinfo->hdevInfo)
GlobalFree (pclinfo->hdevInfo);
LocalUnlock (hclinfo);
}
LocalFree (hclinfo);
}
lpclient = pitemNext;
}
// Handle invisible update
if (!fRevokedDoc && !m_fEmbed //&& !m_fGotDdeAdvise
&& NOERROR ==NoItemConnections()
&& AreNoClients (m_hcliInfo)
&& AreNoClients (m_hcli) )
{
ChkC (this);
Assert (m_lpoleObj);
Assert (m_lpdataObj);
ReleaseObjPtrs();
}
Puts ("DefClient::DeleteFromItemsList Done "); Puti(counter); Putn();
}
INTERNAL_(void) CDefClient::RemoveItemFromItemList
(void)
{
// Make sure it's an item
Assert (m_pdoc != this && !m_bContainer);
LPCLIENT lpclient = m_pdoc;
ChkC (lpclient);
LPCLIENT FAR* ppitemLast = &(m_pdoc->m_lpNextItem);
while (lpclient)
{
ChkC(lpclient);
if (lpclient==this)
{
// Remove from linked list
*ppitemLast = lpclient->m_lpNextItem;
break;
}
ppitemLast = &(lpclient->m_lpNextItem);
lpclient = lpclient->m_lpNextItem;
}
Revoke();
}
INTERNAL_(void) CDefClient::ReleaseAllItems ()
{
LPCLIENT lpclient;
Puts ("DefClient::ReleaseAllItems\r\n");
AssertIsDoc(this);
// leave the doc level object.
lpclient = m_lpNextItem;
while (lpclient)
{
ChkC(this);
LPCLIENT pitemNext = lpclient->m_lpNextItem;
lpclient->Revoke();
lpclient = pitemNext;
}
// After revoking all the items, we can't keep any refernces to them.
m_lpNextItem = NULL;
}
INTERNAL_(void) CDefClient::DeleteAllItems ()
{
LPCLIENT lpclient;
Puts ("DefClient::DeleteAllItems\r\n");
AssertIsDoc(this);
// leave the doc level object.
lpclient = m_lpNextItem;
while (lpclient)
{
ChkC(lpclient);
if (ISATOM(lpclient->m_aItem))
GlobalDeleteAtom (lpclient->m_aItem);
// Delete client advise info
lpclient->DeleteAdviseInfo ();
lpclient = lpclient->m_lpNextItem;
}
}
// PokeData: Prepares and gives the data to the server app thru
// the SetData object method.
INTERNAL CDefClient::PokeData(HWND hwndClient,ATOM aItem,HANDLE hPoke)
{
HRESULT hresult = ReportResult(0, E_UNEXPECTED, 0, 0);
DDEPOKE FAR * lpPoke = NULL;
int format;
BOOL fRelease = FALSE;
LPPERSISTSTORAGE pPersistStg=NULL;
FORMATETC formatetc;
STGMEDIUM medium;
// Due to a C7 bug, do not use a structure initialization for STGMEDIUM
medium.tymed = TYMED_HGLOBAL;
medium.hGlobal = NULL; // invalid
medium.pUnkForRelease= NULL;
intrDebugOut((DEB_ITRACE,
"%p CDefClient::PokeData(hwndClient=%x,aItem=%x,hPoke=%x)\n",
this,hwndClient,aItem,hPoke));
ChkC(this);
AssertIsDoc (this);
// Until now, m_aItem had been the client-generated (ugly) document name.
// Now it becomes the actual item name, which will almost always be NULL.
// Only in the TreatAs/ConvertTo case will it be non-NULL.
m_aItem = aItem;
formatetc.cfFormat = 0; /* invalid */
formatetc.ptd = m_ptd;
formatetc.lindex = DEF_LINDEX;
formatetc.dwAspect = DVASPECT_CONTENT;
formatetc.tymed = TYMED_HGLOBAL;
ErrZS (hPoke && (lpPoke = (DDEPOKE FAR *) GlobalLock (hPoke)),
E_OUTOFMEMORY);
format = formatetc.cfFormat = (UINT)(unsigned short)lpPoke->cfFormat;
Assert (format);
fRelease = lpPoke->fRelease;
// We found the item. Now prepare the data to be given to the object
// MakeItemData returns a newly allocated handle.
if (!(medium.hGlobal = MakeItemData (lpPoke, hPoke, format)))
goto errRtn;
// Change type acording to format (not that default has been set above)
if (format == CF_METAFILEPICT)
formatetc.tymed = medium.tymed = TYMED_MFPICT;
else
if (format == CF_BITMAP)
formatetc.tymed = medium.tymed = TYMED_GDI;
// Now send the data to the object
if (formatetc.cfFormat==g_cfNative)
{
m_fGotEditNoPokeNativeYet = FALSE;
// Cannot do SetData. Must do PersisStg::Load on an IStorage
// made from the native data, i.e., medium.hGlobal.
Assert (m_plkbytNative==NULL);
ErrRtnH (CreateILockBytesOnHGlobal (medium.hGlobal,
/*fDeleteOnRelease*/TRUE,
&m_plkbytNative));
Assert (m_pstgNative==NULL);
if (NOERROR==StgIsStorageILockBytes(m_plkbytNative))
{
// This is a flattened 2.0 storage
ErrRtnH (StgOpenStorageOnILockBytes (m_plkbytNative,
(LPSTORAGE)NULL,
STGM_READWRITE| STGM_SHARE_EXCLUSIVE| STGM_DIRECT,
(SNB)NULL,
0,
&m_pstgNative));
}
else
{
// It is a raw 1.0 Native handle.
// This is the TreatAs/ ConvertTo case.
LPLOCKBYTES plkbyt = NULL;
Assert (m_psrvrParent->m_aOriginalClass);
ErrRtnH (wCreateStgAroundNative (medium.hGlobal,
m_psrvrParent->m_aOriginalClass,
m_psrvrParent->m_aClass,
m_psrvrParent->m_cnvtyp,
m_aItem,
&m_pstgNative,
&plkbyt));
Assert (m_plkbytNative);
if (m_plkbytNative)
{
// This should free the original native hGlobal also.
m_plkbytNative->Release();
medium.hGlobal = NULL;
}
m_plkbytNative = plkbyt;
}
RetZ (m_pstgNative);
Assert (m_lpoleObj);
ErrRtnH (m_lpoleObj->QueryInterface (IID_IPersistStorage,
(LPLPVOID) &pPersistStg));
hresult = pPersistStg->Load (m_pstgNative);
pPersistStg->Release();
pPersistStg=NULL;
ErrRtnH (hresult);
// Now that we have initialized the object, we can call SetClientSite
ErrRtnH (SetClientSite() );
// This is for Packager, in particular. If client does not advise
// on any data, we still need to do an OLE advise so we can get
// OnClose notifications.
ErrRtnH (DoOle20Advise (OLE_CLOSED, (CLIPFORMAT)0));
}
else
{
if (m_fGotEditNoPokeNativeYet)
{
// We got StdEdit, but instead of getting Poke for native data,
// we got poke for someother format. So we want to generate
// InitNew() call for the object.
ErrRtnH (DoInitNew()); // the function clears the flag
}
// Not native format, do SetData
// Callee frees medium, i.e., the hglobal returned by MakeItemData
Assert (m_lpdataObj);
hresult = m_lpdataObj->SetData (&formatetc, &medium, TRUE);
#ifdef _DEBUG
if (hresult != NOERROR)
{
Puts ("****WARNING: SetData failed. cfFormat==");
WCHAR sz[100];
GetClipboardFormatName (formatetc.cfFormat, sz, 100);
Puts (sz);
Putn();
}
#endif
// We free the data if server deos not return NOERROR.
// Otherwise server must've deleted it.
if (hresult == NOERROR)
medium.hGlobal = NULL;
}
errRtn:
GlobalUnlock (hPoke);
if (fRelease && hPoke)
GlobalFree (hPoke);
// Do NOT free medium.hGlobal, because it becomes the hGlobal on which
// m_plkbytNative (and therefore m_pstgNative) is based.
// It will be freed when m_plkbytNative is Release().
// if (medium.hGlobal)
// ReleaseStgMedium(&medium);
if (pPersistStg)
pPersistStg->Release();
return hresult;
}
INTERNAL_(HRESULT) CDefClient::UnAdviseData
(HWND hwndClient,
ATOM aItem)
{
WCHAR buf[MAX_STR];
int options;
LPCLIENT lpclient;
HRESULT hresult = ReportResult(0, E_UNEXPECTED, 0, 0);
HANDLE hclinfo = NULL;
PCLINFO pclinfo = NULL;
Puts ("DefClient::UnadviseData\r\n");
ChkC(this);
if (aItem == NULL)
{
buf[0] = NULL;
}
else
{
GlobalGetAtomName (aItem, buf, MAX_STR);
}
// Scan for the advise options like "Close", "Save" etc
// at the end of the item.
ErrRtnH (ScanItemOptions (buf, (int far *)&options));
// Now get the corresponding object.
ErrRtnH (FindItem (buf, (LPCLIENT FAR *)&lpclient));
// Find the client structure to be attached to the object.
if ((hclinfo = FindClient (lpclient->m_hcliInfo, hwndClient, FALSE)) == NULL ||
(pclinfo = (PCLINFO) LocalLock (hclinfo)) == NULL )
{
hresult = ReportResult(0, E_OUTOFMEMORY, 0, 0);
goto errRtn;
}
pclinfo->options &= (~(0x0001 << options));
errRtn:
if (pclinfo)
LocalUnlock (hclinfo);
return hresult;
}
// AdviseStdItems: This routine takes care of the DDEADVISE for a
//particular object in given document. Creates a client strutcure
//and attaches to the property list of the object window.
INTERNAL_(HRESULT) CDefClient::AdviseStdItems
(
HWND hwndClient,
ATOM aItem,
HANDLE hopt,
BOOL FAR * lpfack
)
{
DDEADVISE FAR *lpopt;
HRESULT hresult = ReportResult(0, E_UNEXPECTED, 0, 0);
intrDebugOut((DEB_ITRACE,
"%x _IN CDefClient::AdviseStdItems(hwndClient=%x,aItem=%x(%ws),hopt=%x)\n",
this,
hwndClient,
aItem,
wAtomName(aItem),
hopt));
ChkC(this);
ErrZS (lpopt = (DDEADVISE FAR *) GlobalLock (hopt), E_OUTOFMEMORY);
AssertSz (aItem == aStdDocName, "AdviseStdItem is not Documentname");
*lpfack = lpopt->fAckReq;
hresult = (HRESULT)SetStdInfo (hwndClient, OLESTR("StdDocumentName"), NULL);
if (lpopt)
GlobalUnlock (hopt);
errRtn:
if (hresult == NOERROR)
{
// Rules say to free handle if ACK will be positive
GlobalFree (hopt);
}
Assert (hresult==NOERROR);
intrDebugOut((DEB_ITRACE,
"%x _OUT CDefClient::AdviseStdItems hresult=%x\n",
this,
hresult));
return hresult;
}
//AdviseData: This routine takes care of the DDE_ADVISE for a
//particular object in given document. Creates a client strutcure
//and attaches to the property list of the object window.
INTERNAL CDefClient::AdviseData
(
HWND hwndClient,
ATOM aItem,
HANDLE hopt,
BOOL FAR * lpfack
)
{
DDEADVISE FAR *lpopt = NULL;
int format = NULL;
WCHAR buf[MAX_STR];
OLE_NOTIFICATION options;
LPCLIENT lpclient;
HRESULT hresult = ReportResult(0, E_UNEXPECTED, 0, 0);
HANDLE hclinfo = NULL;
PCLINFO pclinfo = NULL;
BOOL fAllocatedClInfo = FALSE;
intrDebugOut((DEB_ITRACE,
"%x _IN CDefClient::AdviseData(hwndClient=%x,aItem=%x(%ws),hopt=%x)\n",
this,
hwndClient,
aItem,
wAtomName(aItem),
hopt));
ChkC(this);
if (m_fGotEditNoPokeNativeYet) {
// We got StdEdit, but instead of getting Poke for native data,
// we got advise. So we want to generate InitNew() call for
// the object.
DoInitNew(); // the function clears the flag
}
m_fGotDdeAdvise = TRUE;
ErrZS (lpopt = (DDEADVISE FAR *) GlobalLock (hopt), E_OUTOFMEMORY);
if (!aItem)
buf[0] = NULL;
else
GlobalGetAtomName (aItem, buf, MAX_STR);
// Scan for the advise options like "Close", "Save" etc
// at the end of the item.
// ack flag should be set before the error return. Otherwise the
// the atom is getting deleted.
*lpfack = lpopt->fAckReq;
ErrRtnH (ScanItemOptions (buf, (int far *)&options));
// Now get the corresponding item.
ErrRtnH (FindItem (buf, (LPCLIENT FAR *)&lpclient));
if (!IsFormatAvailable ((CLIPFORMAT)(unsigned short)lpopt->cfFormat)){
hresult = ReportResult(0, DV_E_CLIPFORMAT, 0, 0); // this format is not supported;
goto errRtn;
}
lpclient->DoOle20Advise (options, (CLIPFORMAT)(unsigned short)lpopt->cfFormat);
// Create the client structure to be attcahed to the object.
if (!(hclinfo = FindClient (lpclient->m_hcliInfo, hwndClient, FALSE)))
{
hclinfo = LocalAlloc (LMEM_MOVEABLE | LMEM_ZEROINIT, sizeof (CLINFO));
fAllocatedClInfo = TRUE;
}
if (hclinfo == NULL || (pclinfo = (PCLINFO) LocalLock (hclinfo)) == NULL){
hresult = ReportResult(0, E_OUTOFMEMORY, 0, 0);
goto errRtn;
}
// Remember the client window (Needed for sending DATA later on
// when the data change message comes from the server)
pclinfo->hwnd = hwndClient;
if ((CLIPFORMAT)(unsigned short)lpopt->cfFormat == g_cfNative)
pclinfo->bnative = TRUE;
else
pclinfo->format = (CLIPFORMAT)(unsigned short)lpopt->cfFormat;
// Remeber the data transfer options
pclinfo->options |= (1 << options) ;
pclinfo->bdata = !lpopt->fDeferUpd;
LocalUnlock (hclinfo);
pclinfo = NULL;
// if the entry exists already, delete it.
FindClient (lpclient->m_hcliInfo, hwndClient, /*fDelete*/TRUE);
// Now add this client to item client list
// !!! This error recovery is not correct.
if(!AddClient ((LPHANDLE)&lpclient->m_hcliInfo, hwndClient, hclinfo))
goto errRtn;
errRtn:
if (lpopt)
GlobalUnlock (hopt);
if (pclinfo)
LocalUnlock (hclinfo);
if (hresult==NOERROR)
{
// hresult==NOERROR iff we will send a postive ACK, so we must
// free the hOptions handle.
GlobalFree (hopt);
}
else
{
intrDebugOut((DEB_IERROR,
"%x ::AdviseData() failing.\n",this));
// We free hclinfo because it was not stored in the item's
// client list via the AddClient just before the errRtn label.
if (hclinfo && fAllocatedClInfo)
LocalFree (hclinfo);
}
intrDebugOut((DEB_ITRACE,
"%x _OUT CDefClient::AdviseData() returns hresult = %x\n",
this, hresult));
return hresult;
}
INTERNAL_(BOOL) CDefClient::IsFormatAvailable
(CLIPFORMAT cfFormat)
{
intrDebugOut((DEB_ITRACE,
"%x _IN CDefClient::IsFormatAvailable(cfFormat=%x)\n",
this, cfFormat));
ChkC(this);
BOOL f = ((cfFormat==g_cfNative) || UtIsFormatSupported (m_lpdataObj, DATADIR_GET, cfFormat));
intrDebugOut((DEB_ITRACE,
"%x _OUT CDefClient::IsFormatAvailable(cfFormat=%x) returning %x\n",
this, cfFormat,f));
return f;
}
//RequestData: Sends data in response to a DDE Request message.
// for agiven doc and an object.
INTERNAL_(HRESULT) CDefClient::RequestData
(
HWND hwndClient,
ATOM aItem,
USHORT cfFormat,
LPHANDLE lphdde
)
{
HRESULT hresult = NOERROR;
LPCLIENT lpclient;
FORMATETC formatetc;
STGMEDIUM medium;
// Due to a C7 bug, do not use a structure initialization for STGMEDIUM
medium.tymed = TYMED_NULL;
medium.hGlobal = 0;
medium.pUnkForRelease= NULL;
intrDebugOut((DEB_ITRACE,
"%x _IN CDefClient::RequestData(hwndClient=%x,aItem=%x(%ws),cfFormat=%x,lphdde=%x)\n",
this,
hwndClient,
aItem,
wAtomName(aItem),
cfFormat,
lphdde));
ChkC(this);
// If edit environment Send data if we can
if (aItem == aEditItems)
{
hresult = RequestDataStd (aItem, lphdde);
goto exitRtn;
}
hresult = FindItem ((LPOLESTR) MAKEINTATOM(aItem),(LPCLIENT FAR *)&lpclient);
if (hresult != NOERROR)
{
goto errRtn;
}
ChkC (lpclient);
formatetc.cfFormat = cfFormat;
formatetc.ptd = lpclient->m_ptd;
formatetc.lindex = DEF_LINDEX;
formatetc.dwAspect = DVASPECT_CONTENT;
formatetc.tymed = TYMED_HGLOBAL;
hresult = ReportResult(0, DV_E_FORMATETC, 0, 0);
if (!lpclient->IsFormatAvailable (formatetc.cfFormat))
{
goto errRtn;
}
// Now ask the item for the given format data
SendDevInfo (hwndClient);
wSetTymed (&formatetc);
hresult = lpclient->GetData (&formatetc, &medium);
if (hresult != NOERROR)
{
intrDebugOut((DEB_IERROR,
"GetData returns hresult=%x\n",
hresult));
goto errRtn;
}
if (medium.tymed & ~(TYMED_HGLOBAL | TYMED_MFPICT | TYMED_GDI))
{
AssertSz (0, "Got a storage medium of type other than hGlobal");
goto errRtn;
}
if (cfFormat == CF_METAFILEPICT)
{
ChangeOwner (medium.hGlobal);
}
// Duplicate the DDE data
// medium.hGlobal is freed by MakeDdeData or by the client once the
// DDE_DATA is posted with *lphdde.
if (MakeDDEData (medium.hGlobal, cfFormat, lphdde, TRUE)){
// !!! Why do we have to duplicate the atom
DuplicateAtom (aItem);
hresult = NOERROR;
}
else
hresult = E_OUTOFMEMORY;
errRtn:
exitRtn:
intrDebugOut((DEB_ITRACE,
"%x _OUT CDefClient::RequestData() returning %x\n",
this, hresult));
return hresult;
}
// REVIEW: needs review. Item callvback has to be split
// ItemCallback: Calback routine for the server to inform the
// data changes. When the change message is received, DDE data
// message is sent to each of the clients depending on the
// options.
INTERNAL_(HRESULT) CDefClient::ItemCallBack
(
int msg, // notification message
LPOLESTR szNewName // for OLE_RENAMED notification
)
{
intrDebugOut((DEB_ITRACE,
"%x _IN CDefClient::ItemCallBack(msg=%x,szNewName=%x)\n",
this,
szNewName));
HRESULT hresult = NOERROR;
BOOL bSaved;
LPCLIENT lpclientRename;
LPCLIENT lpclient;
ChkC(this);
if (msg == OLE_RENAMED) {
Assert (szNewName);
intrDebugOut((DEB_ITRACE,
"%x ::ItemCallBack(szNewName=(%ws))\n",
WIDECHECK(szNewName)));
if (!m_bContainer)
{
lpclient = (LPCLIENT)GetWindowLong (m_hwnd, 0);
Assert (lpclient==m_pdoc);
}
else
lpclient = this;
Assert (lpclient->m_chk==chkDefClient);
// Replace the internally-stored name
if (lpclient->m_aItem)
{
GlobalDeleteAtom (lpclient->m_aItem);
lpclient->m_aItem = wGlobalAddAtom (szNewName);
}
// find if any StdDocName item is present at all
if (lpclientRename =
lpclient->SearchItem ((LPOLESTR) MAKEINTATOM(aStdDocName)))
{
HANDLE hDdeData=NULL;
//
// We have a new name in UNICODE. Need to create a new
// name in ANSI.
//
LPSTR lpName = CreateAnsiFromUnicode(szNewName);
HANDLE hNewName = wNewHandle (lpName, strlen(lpName) + 1);
PrivMemFree(lpName);
// hNewName is freed by MakeDDEData
if (!MakeDDEData (hNewName, (int)g_cfBinary, &hDdeData, FALSE))
{
hresult = ReportResult(0, E_OUTOFMEMORY, 0, 0);
goto errrtn;
}
Assert (hDdeData);
lpclientRename->SendRenameMsgs (hDdeData);
GlobalFree (hDdeData);
// Post termination for each of the doc clients that did not
// advise on rename
lpclient->TerminateNonRenameClients (lpclientRename);
}
Assert (FALSE == lpclient->m_fEmbed);
// REVIEW: what is this?
//lpclient->m_fEmbed = FALSE;
hresult = NOERROR;
errrtn:
Assert (hresult == NOERROR);
goto exitRtn;
} else {
// Enumerate all the clients and send DDE_DATA if necessary.
bSaved = SendDataMsg (msg);
// REVIEW: Hack from 1.0 for old pre-OLE-library apps
if ((msg == OLE_SAVED) && m_fEmbed && !bSaved)
return ReportResult(0, RPC_E_DDE_CANT_UPDATE, 0, 0);
hresult = NOERROR;
}
exitRtn:
intrDebugOut((DEB_ITRACE,
"%x _OUT CDefClient::ItemCallBack() returning hresult=%x\n",
this,hresult));
return(hresult);
}
// This func should definitely be replaced by use of MFC map. (IsEmpty)
INTERNAL_(BOOL) AreNoClients (HANDLE hcli)
{
HANDLE hcliPrev = NULL;
PCLILIST pcli;
HANDLE *phandle;
while (hcli) {
if ((pcli = (PCLILIST) LocalLock (hcli)) == NULL)
{
Puth (hcli);
Putn();
Assert(0);
return TRUE;
}
phandle = (HANDLE *) pcli->info;
while (phandle < (HANDLE *)(pcli + 1))
{
if (*phandle)
{
LocalUnlock (hcli);
return FALSE;
}
phandle++;
phandle++;
}
hcliPrev = hcli;
hcli = pcli->hcliNext;
LocalUnlock (hcliPrev);
}
return TRUE;
}
#ifdef _DEBUG
// For use in CodeView
// NOTE: Returns a static string
INTERNAL_(LPOLESTR) a2s (ATOM a)
{
static WCHAR sz[256];
GlobalGetAtomName (a, sz, 256);
return sz;
}
#endif