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.
 
 
 
 
 
 

1405 lines
32 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1993.
//
// File: item2.cxx
//
// Contents:
//
// Classes:
//
// Functions:
//
// History: 6-07-94 kevinro Converted to NT and commented
//
//----------------------------------------------------------------------------
#include "ole2int.h"
#include <dde.h>
#include "ddeatoms.h"
#include "ddedebug.h"
#include "srvr.h"
#include "itemutil.h"
#include "trgt_dev.h"
#include <stddef.h>
#include <limits.h>
#ifndef WIN32
// #include <print.h>
#endif
ASSERTDATA
INTERNAL_(void) CDefClient::TerminateNonRenameClients
(
LPCLIENT lprenameClient
)
{
HANDLE hcliPrev = NULL;
PCLILIST pcli;
HANDLE *phandle;
HANDLE hcli;
HWND hwndClient;
LPCLIENT lpdocClient;
intrDebugOut((DEB_ITRACE,
"%x _IN CDefClient::TerminateNonRenameClients(lprenClient=%x)\n",
this,
lprenameClient));
// items also keep the parents window handle.
hwndClient = m_hwnd;
lpdocClient = (LPCLIENT)GetWindowLong (m_hwnd, 0);
hcli = m_hcliInfo;
while (hcli)
{
if ((pcli = (PCLILIST) LocalLock (hcli)) == NULL)
{
break;
}
phandle = (HANDLE *) (pcli->info);
while (phandle < (HANDLE *)(pcli + 1))
{
if (*phandle)
{
// This client is in the rename list. So, no termination
if(!FindClient (lprenameClient->m_hcliInfo, *phandle, FALSE))
{
#ifdef KEVINRO_I_CHANGED_THIS
//
// BUGBUG: (KevinRo) I don't understand why this didn't just call Terminate() instead.
// There may be the potential for problems on this PostMessageToClient, since it doesn't
// do the ModalLoop stuff. It is going to busy wait by doing Peeks
//
// I have changed this to call Terminate
//
PostMessageToClientWithReply ((HWND)*phandle,
WM_DDE_TERMINATE,
(UINT) hwndClient, NULL,
WM_DDE_TERMINATE);
#endif
//
// Terminate will send a WM_DDE_TERMINATE at the client
//
Terminate((HWND)*phandle,hwndClient);
// delete this client from all the items lists.
lpdocClient->DeleteFromItemsList ((HWND)*phandle);
}
}
phandle++;
phandle++;
}
hcliPrev = hcli;
hcli = pcli->hcliNext;
LocalUnlock (hcliPrev);
}
intrDebugOut((DEB_ITRACE,
"%x _OUT CDefClient::TerminateNonRenameClients\n",
this));
}
INTERNAL CDefClient::Terminate
(HWND hwndTo,
HWND hwndFrom)
{
intrDebugOut((DEB_ITRACE,
"%x _IN CDefClient::Terminate hwndTo=%x hwndFrom=%x\n",
this,
hwndTo,
hwndFrom));
DDECALLDATA DdeCD;
HRESULT hresult;
DdeCD.hwndSvr = hwndTo;
DdeCD.hwndCli = hwndFrom;
DdeCD.wMsg = WM_DDE_TERMINATE;
DdeCD.wParam = (WPARAM)hwndFrom,
DdeCD.lParam = 0;
//
// Setting the fCallData variable effects the way that the
// DocWndProc handles WM_DDE_TERMINATE. If it is set, then this
// object initiated the terminate, and will not reply to the
// TERMINATE. It will allow us to leave the CallRunModalLoop
//
m_fCallData = TRUE;
RPCOLEMESSAGE RpcOleMsg;
RpcOleMsg.Buffer = &DdeCD;
// Figure out the MsgQ input flags based on the callcat of the call.
DWORD dwMsgQInputFlag = gMsgQInputFlagTbl[CALLCAT_SYNCHRONOUS];
// Now construct a modal loop object for the call that is about to
// be made. It maintains the call state and exits when the call has
// been completed, cancelled, or rejected.
CCliModalLoop CML(0, dwMsgQInputFlag);
do
{
DWORD status = 0;
hresult = CML.SendReceive(&RpcOleMsg, &status, &m_pCallMgr);
} while (hresult == RPC_E_SERVERCALL_RETRYLATER);
m_fCallData = FALSE;
intrDebugOut((DEB_ITRACE,
"%x _OUT CDefClient::Terminate hresult = %x\n",
this,hresult));
return(hresult);
}
INTERNAL_(void) CDefClient::SendTerminateMsg ()
{
HANDLE hcliPrev = NULL;
PCLILIST pcli;
HANDLE *phandle;
HANDLE hcli;
HWND hwnd;
LPCLIENT lpdocClient;
static int staticcounter;
int counter = ++staticcounter;
intrDebugOut((DEB_ITRACE,
"%x _IN CDefClient::SendTerminateMsg\n",
this));
// items also keep the document's window handle
Assert (IsWindow (m_hwnd));
if (!IsWindow (m_hwnd))
{
goto exitRtn;
}
hwnd = m_hwnd;
lpdocClient = (LPCLIENT)GetWindowLong (m_hwnd, 0);
Assert (lpdocClient);
if (NULL==lpdocClient)
{
goto exitRtn;
}
Assert (lpdocClient==m_pdoc);
AssertIsDoc (lpdocClient);
// If "this" is a document (container) then iterate through
// and terminate all its client windows. If "this" is an item
// just terminate that item's client windows.
hcli = m_bContainer ? lpdocClient->m_hcli : m_hcliInfo;
while (hcli)
{
if ((pcli = (PCLILIST) LocalLock (hcli)) == NULL)
{
goto exitRtn;
}
phandle = (HANDLE *) (pcli->info);
while (phandle < (HANDLE *)(pcli + 1))
{
if ((HWND)*phandle)
{
intrDebugOut((DEB_ITRACE,
"%x ::SendTerminateMsg on hwnd=%x\n",
this,
(HWND)*phandle));
Terminate ((HWND)*phandle, hwnd);
Assert (lpdocClient->m_cClients > 0);
lpdocClient->m_cClients--;
HWND hwndClient = *(HWND *)phandle;
// This window is no longer a client.
// Remove window from document's master list
// and its item's list.
lpdocClient->DeleteFromItemsList (hwndClient);
}
//
// (KevinRo): Don't understand why the phandle is
// incremented twice. This is the same as the original
// code. Leaving it for now, since I don't have enough
// information.
//
phandle++;
phandle++;
}
hcliPrev = hcli;
hcli = pcli->hcliNext;
LocalUnlock (hcliPrev);
}
exitRtn:
intrDebugOut((DEB_ITRACE,
"%x _OUT CDefClient::SendTerminateMsg\n",
this));
}
// SendRenameMsg: enumerates the clients for the rename item
// and sends rename message for all the clients.
INTERNAL_(void) CDefClient::SendRenameMsgs
(
HANDLE hddeRename
)
{
ATOM aData = NULL;
HANDLE hdde = NULL;
PCLINFO pclinfo = NULL;
HWND hwndClient;
HANDLE hcliPrev = NULL;
PCLILIST pcli;
HANDLE *phandle;
HANDLE hcli;
HANDLE hcliInfo;
intrDebugOut((DEB_ITRACE,
"%x _IN CDefClient::SendRenameMsgs(hddeRename=%x)\n",
this,
hddeRename));
hcli = m_hcliInfo;
LPARAM lp;
while (hcli)
{
if ((pcli = (PCLILIST) LocalLock (hcli)) == NULL)
{
goto exitRtn;
}
phandle = (HANDLE *) (pcli->info);
while (phandle < (HANDLE *)(pcli + 1))
{
if (*phandle++)
{
hdde = NULL;
aData = NULL;
if (!(pclinfo = (PCLINFO) LocalLock (hcliInfo = *phandle++)))
{
goto exitRtn;
}
// Make the item atom with the options.
aData = DuplicateAtom (aStdDocName);
hdde = UtDupGlobal (hddeRename,GMEM_MOVEABLE);
hwndClient = pclinfo->hwnd;
LocalUnlock (hcliInfo);
// Post the message
lp = MAKE_DDE_LPARAM(WM_DDE_DATA,hdde,aData);
if (!PostMessageToClient (hwndClient,
WM_DDE_DATA,
(UINT) m_hwnd,
lp))
{
DDEFREE(WM_DDE_DATA,lp);
if (hdde)
GlobalFree (hdde);
if (aData)
GlobalDeleteAtom (aData);
}
}
else
{
phandle++;
}
}
hcliPrev = hcli;
hcli = pcli->hcliNext;
LocalUnlock (hcliPrev);
}
exitRtn:
intrDebugOut((DEB_ITRACE,
"%x _OUT CDefClient::SendRenameMsgs void return\n",
this));
}
INTERNAL_(BOOL) CDefClient::SendDataMsg
(
WORD msg // notification message
)
{
HANDLE hcliPrev = NULL;
PCLILIST pcli;
HANDLE *phandle;
HANDLE hcli;
BOOL bSaved = FALSE;
intrDebugOut((DEB_ITRACE,
"%x _IN CDefClient::SendDataMsg(msg=%x)\n",
this,
msg));
hcli = m_hcliInfo;
while (hcli)
{
if ((pcli = (PCLILIST) LocalLock (hcli)) == NULL)
{
break;
}
phandle = (HANDLE *) (pcli->info);
while (phandle < (HANDLE *)(pcli + 1)) {
if (*phandle++)
bSaved = SendDataMsg1 (*phandle++, msg);
else
phandle++;
}
hcliPrev = hcli;
hcli = pcli->hcliNext;
LocalUnlock (hcliPrev);
}
intrDebugOut((DEB_ITRACE,
"%x _OUT CDefClient::SendDataMsg() returns %x)\n",
this,bSaved));
return bSaved;
}
//SendDataMsg: Send data to the clients, if the data change options
//match the data advise options.
INTERNAL_(BOOL) CDefClient::SendDataMsg1
(
HANDLE hclinfo, // handle of the client info
WORD msg // notification message
)
{
intrDebugOut((DEB_ITRACE,
"%x _IN CDefClient::SendDataMsg1(hclinfo=%x,msg=%x)\n",
this,
hclinfo,
msg));
PCLINFO pclinfo = NULL;
HANDLE hdde = NULL;
ATOM aData = NULL;
HRESULT retval;
BOOL bSaved = FALSE;
ChkC (this);
if (m_lpdataObj == NULL) goto errRtn;
// LATER: Allow server to give us other tymed's beside HGLOBAL and do
// the conversion ourselves, e.g., IStorageToHGlobal()
FORMATETC formatetc;// = {0, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
STGMEDIUM medium;// = {TYMED_NULL, NULL, NULL};
formatetc.ptd = m_ptd;
formatetc.dwAspect = DVASPECT_CONTENT;
formatetc.lindex = DEF_LINDEX;
formatetc.tymed = TYMED_HGLOBAL;
medium.tymed = TYMED_NULL;
medium.hGlobal=0; // not really necessary
medium.pUnkForRelease = NULL;
if (!(pclinfo = (PCLINFO) LocalLock (hclinfo)))
{
goto errRtn;
}
// if the client dead, then no message
if (!IsWindowValid(pclinfo->hwnd))
{
goto errRtn;
}
//
// (KevinRo) UPDATE was not defined in the OLE 2.01 code base
//
#ifdef UPDATE
// OLE_SAVED is what 1.0 clients expect to get for embedded objects.
if (msg==OLE_CHANGED && m_fEmbed)
msg=OLE_SAVED;
#endif
if (pclinfo->options & (0x0001 << msg))
{
bSaved = TRUE;
SendDevInfo (pclinfo->hwnd);
// send message if the client needs data for every change or
// only for the selective ones he wants.
// now look for the data option.
if (pclinfo->bnative){
// prepare native data
if (pclinfo->bdata){
// Wants the data with DDE_DATA message
// Get native data from the server.
// GetData
formatetc.cfFormat = g_cfNative;
wSetTymed (&formatetc);
retval = GetData (&formatetc, &medium);
if (retval != NOERROR)
{
Assert(0);
goto errRtn;
}
Assert (medium.tymed==TYMED_HGLOBAL);
Assert (medium.hGlobal);
// Prepare the DDE data block.
// REVIEW: MakeDDEData frees medium.hGlobal manually, but should
// really call ReleaseStgMedium.
if(!MakeDDEData (medium.hGlobal, (int)g_cfNative, (LPHANDLE)&hdde, FALSE))
{
goto errRtn;
}
}
// Make the item atom with the options.
aData = MakeDataAtom (m_aItem, msg);
intrDebugOut((DEB_ITRACE,
"%x ::SendDataMsg1 send NativeData to hwnd=%x"
"format %x\n",
this,
pclinfo->hwnd,
pclinfo->format));
LPARAM lp = MAKE_DDE_LPARAM(WM_DDE_DATA,hdde,aData);
if (!PostMessageToClient(pclinfo->hwnd,
WM_DDE_DATA,
(UINT) m_hwnd,
lp))
{
DDEFREE(WM_DDE_DATA,lp);
//
// The two data items will be free'd on exit
//
goto errRtn;
}
hdde = NULL;
aData = NULL;
}
// Now post the data for the display format
if (pclinfo->format)
{
if (pclinfo->bdata)
{
intrDebugOut((DEB_ITRACE,
"%x ::SendDataMsg1 GetData on cf = %x\n",
pclinfo->format));
// Must reset because previous call to GetData set it.
medium.tymed = TYMED_NULL;
// GetData
formatetc.cfFormat = pclinfo->format;
wSetTymed (&formatetc);
Assert (IsValidInterface (m_lpdataObj));
retval = m_lpdataObj->GetData (&formatetc, &medium);
if (retval != NOERROR)
{
intrDebugOut((DEB_IERROR,
"m_lpdataObj->GetData returns %x\n",
retval));
goto errRtn;
}
if (pclinfo->format == CF_METAFILEPICT)
ChangeOwner (medium.hGlobal);
if(!MakeDDEData (medium.hGlobal, pclinfo->format, (LPHANDLE)&hdde, FALSE))
goto errRtn;
}
// atom is deleted. So, we need to duplicate for every post
aData = MakeDataAtom (m_aItem, msg);
// now post the message to the client;
intrDebugOut((DEB_ITRACE,
"%x ::SendDataMsg1 send PresentationData to hwnd=%x"
" cf=%x\n",
this,
pclinfo->hwnd,
pclinfo->format));
LPARAM lp = MAKE_DDE_LPARAM(WM_DDE_DATA,hdde,aData);
if (!PostMessageToClient(pclinfo->hwnd,
WM_DDE_DATA,
(UINT) m_hwnd,
lp))
{
DDEFREE(WM_DDE_DATA,lp);
goto errRtn;
}
hdde = NULL;
aData = NULL;
}
}
errRtn:
if (pclinfo)
LocalUnlock (hclinfo);
if (hdde)
GlobalFree (hdde);
if (aData)
GlobalDeleteAtom (aData);
intrDebugOut((DEB_ITRACE,
"%x _OUT CDefClient::SendDataMsg1() returns %x\n",
this,bSaved));
return bSaved;
}
// FixWriteBug
//
// `Write' gives a target device that is missing a NULL between
// the device name and the driver name. This function creates
// a fixed 1.0 target device.
//
// REVIEW: There is another Write bug we should work around.
// Write does not send the "extra bytes" that are supposed to follow
// the DEVMODE. It puts the Environment immediately after the DEVMODE.
// So the driver will read the Environment thinking it is the extra bytes.
// To fix this, FixWriteBug() should zero out the Environment bytes; the
// 2.0 target device does not use them anyway.
//
INTERNAL FixWriteBug
(HANDLE hTD,
LPHANDLE ph)
{
HRESULT hresult;
LPBYTE pChunk2;
LPBYTE pNewChunk2;
const LPCOLETARGETDEVICE ptd1 = (LPCOLETARGETDEVICE) GlobalLock (hTD);
RetZS (ptd1, E_OUTOFMEMORY);
HANDLE hNew = GlobalAlloc (GMEM_DDESHARE | GMEM_MOVEABLE,
GlobalSize (hTD) + 1);
RetZS (hNew, E_OUTOFMEMORY);
const LPBYTE pNew = (LPBYTE) GlobalLock (hNew);
RetZS (pNew, E_OUTOFMEMORY);
ULONG cbChunk1 = 7 * sizeof(UINT) + ptd1->otdDriverNameOffset;
ULONG cbChunk2 = GlobalSize (hTD) - cbChunk1;
ErrZS (!IsBadWritePtr (pNew, (UINT)cbChunk1), E_OUTOFMEMORY);
memcpy (pNew, ptd1, cbChunk1);
pNew[cbChunk1] = '\0'; // insert the missing NULL
pNewChunk2 = pNew + cbChunk1 + 1;
pChunk2 = (LPBYTE)ptd1 + cbChunk1;
ErrZS (!IsBadWritePtr (pNewChunk2, (UINT)cbChunk2), E_OUTOFMEMORY);
Assert (!IsBadReadPtr (pChunk2, (UINT)cbChunk2));
memcpy (pNewChunk2, pChunk2, cbChunk2);
// Fix up the offsets to accomodate the added NULL
#define macro(x) if (ptd1->otd##x##Offset > ptd1->otdDeviceNameOffset)\
((LPOLETARGETDEVICE)pNew)->otd##x##Offset++;
macro (DriverName)
macro (PortName)
macro (ExtDevmode)
macro (Environment)
#undef macro
GlobalUnlock (hNew);
GlobalUnlock (hTD);
*ph = hNew;
return NOERROR;
errRtn:
if (pNew)
GlobalUnlock (hNew);
if (ptd1)
GlobalUnlock (hTD);
return hresult;
}
// Convert10TargetDevice
//
INTERNAL Convert10TargetDevice
(HANDLE hTD, // 1.0 Target Device
DVTARGETDEVICE FAR* FAR* pptd2) // Out parm, corresponding 2.0 TD
{
intrDebugOut((DEB_ITRACE,
"0 _IN Convert10TargetDevice hTD=%x\n",hTD));
ULONG cbData1, cbData2;
if (NULL==hTD)
{
Assert(0);
return ReportResult(0, E_INVALIDARG, 0, 0);
}
if (*pptd2)
{
// delete old target device
PrivMemFree(*pptd2);
*pptd2 = NULL;
}
LPOLETARGETDEVICE ptd1 = (LPOLETARGETDEVICE) GlobalLock (hTD);
RetZS (ptd1, E_OUTOFMEMORY);
if ((ptd1->otdDeviceNameOffset < ptd1->otdDriverNameOffset)
&& (ptd1->otdDeviceNameOffset
+ strlen (LPSTR(((BYTE *)ptd1->otdData) +
ptd1->otdDeviceNameOffset)) + 1 > ptd1->otdDriverNameOffset))
{
// No NULL between device and driver name
HANDLE hNew;
GlobalUnlock (hTD);
RetErr (FixWriteBug (hTD, &hNew));
HRESULT hresult = Convert10TargetDevice (hNew, pptd2);
Verify (0==GlobalFree (hNew));
return hresult;
}
// Word Bug
DEVMODEA UNALIGNED *pdevmode = (DEVMODEA UNALIGNED *)
(((BYTE *)ptd1->otdData)+ ptd1->otdExtDevmodeOffset);
if ( HIBYTE(pdevmode->dmSpecVersion) < 3
|| HIBYTE(pdevmode->dmSpecVersion) > 6
|| pdevmode->dmDriverExtra > 0x1000)
{
if (0==ptd1->otdEnvironmentSize)
{
// Sometimes Word does not give an environment.
ptd1->otdExtDevmodeOffset = 0;
ptd1->otdExtDevmodeSize = 0;
}
else
{
// DevMode is garbage, use environment instead.
ptd1->otdExtDevmodeOffset = ptd1->otdEnvironmentOffset;
ptd1->otdExtDevmodeSize = ptd1->otdEnvironmentSize;
}
}
// These next assert does not HAVE to be true,
// but it's a sanity check.
Assert (ptd1->otdDeviceNameOffset
+ strlen (LPSTR(((BYTE *)ptd1->otdData) +
ptd1->otdDeviceNameOffset)) + 1
== ptd1->otdDriverNameOffset);
// Excel has zeroes for DevMode and Environment offsets and sizes
// Calculate size of Data block. Many 1.0 clients don't make their
// target device data block big enough for the DEVMODE.dmDriverExtra
// bytes (and they don't copy those bytes either). We can't reconstruct
// the bytes out of thin air, but we can at least make sure there's not
// a GP fault when the printer driver tries to access those bytes in
// a call to CreateDC. Any extra bytes are zeroed.
cbData2 = ptd1->otdExtDevmodeOffset + ptd1->otdExtDevmodeSize;
if (ptd1->otdExtDevmodeOffset != 0)
{
cbData2 += ((DEVMODEA UNALIGNED *)((LPBYTE)ptd1->otdData +
ptd1->otdExtDevmodeOffset))->dmDriverExtra;
}
cbData2 = max (cbData2,
ptd1->otdPortNameOffset + strlen (LPCSTR(
((BYTE *)ptd1->otdData) + ptd1->otdPortNameOffset)) + 1);
// Calculate size of OLE2 Target Device
//
// Its the size of the DVTARGETDEVICE header, plus the cbData2
// The definition of DVTARGETDEVICE currently uses an unsized array
// of bytes at the end, therefore we can not just do a sizeof().
//
ULONG cbTD2 = SIZEOF_DVTARGETDEVICE_HEADER + cbData2;
// Allocate OLE2 Target Device
*pptd2 = (DVTARGETDEVICE FAR*) PrivMemAlloc(cbTD2);
if (IsBadWritePtr (*pptd2, cbTD2)
|| IsBadWritePtr ((*pptd2)->tdData, cbData2))
{
AssertSz (0, "out of memory");
GlobalUnlock (hTD);
return ResultFromScode (E_OUTOFMEMORY);
}
_fmemset (*pptd2, '\0', cbTD2);
// OLE2 offsets are from the beginning of the DVTARGETDEVICE
const ULONG cbOffset = offsetof (DVTARGETDEVICE, tdData);
// Fill in new Target Device
(*pptd2)->tdSize = cbTD2;
#define Convert(a) \
((*pptd2)->td##a##Offset = (USHORT)(ptd1->otd##a##Offset + cbOffset))
Convert (DeviceName);
Convert (DriverName);
Convert (PortName);
if (ptd1->otdExtDevmodeOffset != 0)
Convert (ExtDevmode);
else // Excel uses 0
(*pptd2)->tdExtDevmodeOffset = 0;
// Calculate size of 1.0 data block in case the 1.0 target
// device is incorrectly not big enough.
cbData1 = (size_t) GlobalSize(hTD) - offsetof (OLETARGETDEVICE, otdData);
#undef Convert
_fmemcpy ((*pptd2)->tdData, ptd1->otdData, min(cbData1, cbData2));
GlobalUnlock (hTD);
//
// At this point, pptd2 holds an ANSI version of a DVTARGET device
//
// Now, we need to convert it to a UNICODE version. There are routines
// for doing this in the UTILS.H file.
//
DVTDINFO dvtdInfo;
DVTARGETDEVICE * pdvtd32 = NULL;
HRESULT hr;
hr = UtGetDvtd16Info(*pptd2, &dvtdInfo);
if (hr != NOERROR)
{
goto errRtn;
}
pdvtd32 = (DVTARGETDEVICE *) PrivMemAlloc(dvtdInfo.cbConvertSize);
if (pdvtd32 == NULL)
{
goto errRtn;
}
hr = UtConvertDvtd16toDvtd32(*pptd2, &dvtdInfo, pdvtd32);
if (hr != NOERROR)
{
PrivMemFree(pdvtd32);
pdvtd32=NULL;
}
errRtn:
PrivMemFree(*pptd2);
*pptd2 = pdvtd32;
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CDefClient::PokeStdItems
//
// Synopsis: Pokes the data for the standard items.
//
// Effects:
//
// For StdHostnames, StdDocDimensions and SetColorScheme the data is
// sent immediately and for the the StdTargetDeviceinfo the
// data is set in each client block and the data is sent just
// before the GetData call for rendering the right data.
//
// Arguments: [hwndClient] --
// [aItem] --
// [hdata] --
// [index] --
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: 6-07-94 kevinro Commented
//
// Notes:
//
//----------------------------------------------------------------------------
INTERNAL CDefClient::PokeStdItems(HWND hwndClient,
ATOM aItem,
HANDLE hdata,
int index)
{
DDEDATA FAR * lpdata = NULL;
HANDLE hnew = NULL;
LPHOSTNAMES lphostnames;
HRESULT retval = E_OUTOFMEMORY;
WORD format;
BOOL fRelease;
intrDebugOut((DEB_ITRACE,
"%p _IN CDefClient::PokeStdItems(hwndClient=%x,aItem=%x(%ws)hdata=%x,index=%x)\n",
this,
hwndClient,
aItem,
wAtomName(aItem),
hdata,
index));
if (m_fGotEditNoPokeNativeYet)
{
// We got StdEdit, but instead of getting Poke for native data,
// we got poke for some std items. So we want to generate InitNew()
// call for the object.
DoInitNew(); // the function clears the flag
}
if(!(hdata && (lpdata = (DDEDATA FAR *)GlobalLock (hdata))))
{
goto errRtn;
}
format = lpdata->cfFormat;
fRelease = lpdata->fRelease;
AssertSz (format == (int)g_cfBinary, "Format is not binary");
// we have extracted the data successfully.
m_lpoleObj = m_lpoleObj;
if (index == STDHOSTNAMES)
{
lphostnames = (LPHOSTNAMES)lpdata->Value;
//
// The client should have sent the HOSTNAMES in ANSI. This
// means we need to convert them to UNICODE before we can
// use them.
//
LPOLESTR lpstrClient = CreateUnicodeFromAnsi((LPSTR)(lphostnames->data) + lphostnames->clientNameOffset);
LPOLESTR lpstrDoc = CreateUnicodeFromAnsi((LPSTR)(lphostnames->data) + lphostnames->documentNameOffset);
intrDebugOut((DEB_ITRACE,
"%p ::PokeStdItems setting hostnames Client(%ws) Doc(%ws) \n",
this,
lpstrClient,
lpstrDoc));
retval = (HRESULT)m_lpoleObj->SetHostNames(lpstrClient,lpstrDoc);
if (retval==NOERROR)
{
m_fDidRealSetHostNames = TRUE;
}
PrivMemFree(lpstrClient);
PrivMemFree(lpstrDoc);
goto end;
}
if (index == STDDOCDIMENSIONS)
{
SIZEL size;
size.cy = ((LPRECT16)(lpdata->Value))->top;
size.cx = ((LPRECT16)(lpdata->Value))->left;
intrDebugOut((DEB_ITRACE,
"%p ::PokeStdItems STDDOCDIMENSIONS cy=%x cx=%x\n",
this,
size.cy,
size.cx));
retval = m_lpoleObj->SetExtent (DVASPECT_CONTENT, &size);
goto end;
}
if (index == STDCOLORSCHEME) {
intrDebugOut((DEB_ITRACE,
"%p ::PokeStdItems setting STDCOLORSCHEME\n",this));
retval = m_lpoleObj->SetColorScheme((LPLOGPALETTE)(lpdata->Value));
goto end;
}
// Target Device
if (index == STDTARGETDEVICE)
{
intrDebugOut((DEB_ITRACE,
"%p ::PokeStdItems setting STDTARGETDEVICE\n",this));
if (!(hnew = MakeItemData ((DDEPOKE FAR *)lpdata, hdata, format)))
goto errRtn;
retval = Convert10TargetDevice (hnew, &m_ptd);
goto end;
}
retval = E_UNEXPECTED;
intrAssert(!"::PokeStdItems - Unknown index\n");
//
// (KevinRo) Found the following line already commented out.
//
//(HRESULT)SetStdInfo (hwndClient, (LPOLESTR) (MAKELONG(STDTARGETDEVICE,0)),hnew);
end:
errRtn:
if (hnew)
// can only be global memory block
GlobalFree (hnew);
if (lpdata) {
GlobalUnlock (hdata);
if (retval == NOERROR && fRelease)
GlobalFree (hdata);
}
intrDebugOut((DEB_ITRACE,
"%p _OUT CDefClient::PokeStdItems() hresult = %x\n",
this,
retval));
return retval;
}
// SetStdInfo: Sets the targetdevice info. Creates a client
// for "StdTargetDevice". This item is created only within the
// lib and it is never visible in server app. When the change
// message comes from the server app, before we ask for
// the data, we send the targetdevice info if there is
// info for the client whom we are trying to send the data
// on advise.
INTERNAL_(HRESULT) CDefClient::SetStdInfo
(
HWND hwndClient,
LPOLESTR lpitemname,
HANDLE hdata
)
{
HANDLE hclinfo = NULL;
PCLINFO pclinfo = NULL;
LPCLIENT lpclient;
HRESULT retval = NOERROR;
intrDebugOut((DEB_ITRACE,
"%x _IN CDefClient::SetStdInfo(hwndClient=%x,ItemName=(%ws),hdata=%x)\n",
this,
hwndClient,
lpitemname,
hdata));
//
// first create/find the StdTargetDeviceItem.
//
if ((lpclient = SearchItem (lpitemname)) == NULL)
{
retval = (HRESULT)RegisterItem (lpitemname,(LPCLIENT FAR *)&lpclient, FALSE);
if (retval != NOERROR)
{
goto errRtn;
}
}
if(hclinfo = FindClient (lpclient->m_hcliInfo, hwndClient, FALSE))
{
if (pclinfo = (PCLINFO) LocalLock (hclinfo))
{
if (pclinfo->hdevInfo)
GlobalFree (pclinfo->hdevInfo);
pclinfo->bnewDevInfo = TRUE;
if (hdata)
pclinfo->hdevInfo = UtDupGlobal (hdata,GMEM_MOVEABLE);
else
pclinfo->hdevInfo = NULL;
pclinfo->hwnd = hwndClient;
LocalUnlock (hclinfo);
// We do not have to reset the client because we did not
// change the handle it self.
}
}
else
{
// Create the client structure to be attcahed to the object.
hclinfo = LocalAlloc (LMEM_MOVEABLE | LMEM_ZEROINIT, sizeof (CLINFO));
if (hclinfo == NULL || (pclinfo = (PCLINFO) LocalLock (hclinfo)) == NULL)
goto errRtn;
pclinfo->bnewDevInfo = TRUE;
if (hdata)
pclinfo->hdevInfo = UtDupGlobal (hdata,GMEM_MOVEABLE);
else
pclinfo->hdevInfo = NULL;
pclinfo->hwnd = hwndClient;
LocalUnlock (hclinfo);
// Now add this client to item client list
// !!! This error recovery is not correct.
if (!AddClient ((LPHANDLE)&lpclient->m_hcliInfo, hwndClient, hclinfo))
goto errRtn;
}
exitRtn:
intrDebugOut((DEB_ITRACE,
"%x _OUT CDefClient::SetStdInfo() hresult=%x\n",
this,retval));
return retval;
errRtn:
Assert(0);
if (pclinfo)
LocalUnlock (hclinfo);
if (hclinfo)
LocalFree (hclinfo);
retval = E_OUTOFMEMORY;
goto exitRtn;
}
// SendDevInfo: Sends targetdevice info to the the object.
// Caches the last targetdevice info sent to the object.
// If the targetdevice block is same as the one in the
// cache, then no targetdevice info is sent.
// (!!! There might be some problem here getting back
// the same global handle).
INTERNAL_(void) CDefClient::SendDevInfo
(
HWND hWndCli
)
{
HANDLE hclinfo = NULL;
PCLINFO pclinfo = NULL;
HANDLE hdata;
LPCLIENT lpdocClient;
intrDebugOut((DEB_ITRACE,
"%x _IN CDefClient::SendDevInfo(hwndCli=%x)\n",
this,
hWndCli));
#if 0
if (!m_bContainer)
lpdocClient = (LPCLIENT)GetWindowLong (m_hwnd, 0);
else
lpdocClient = this;
#endif
// find if any StdTargetDeviceInfo item is present at all
AssertIsDoc(m_pdoc);
lpdocClient = m_pdoc->SearchItem ((LPOLESTR) (MAKELONG(STDTARGETDEVICE, 0)));
if (lpdocClient == NULL)
{
goto exitRtn;
}
hclinfo = FindClient (lpdocClient->m_hcliInfo, hWndCli, FALSE);
// This client has not set any target device info. no need to send
// any stdtargetdevice info
if (hclinfo != NULL) {
if (!(pclinfo = (PCLINFO)LocalLock (hclinfo)))
goto end;
// if we cached it, do not send it again.
if ((!pclinfo->bnewDevInfo) && pclinfo->hdevInfo == m_hdevInfo)
goto end;
pclinfo->bnewDevInfo = FALSE;
if(!(hdata = UtDupGlobal (pclinfo->hdevInfo,GMEM_MOVEABLE)))
goto end;
} else {
// already screen
if (!m_hdevInfo)
goto end;
//for screen send NULL.
hdata = NULL;
}
if (pclinfo)
{
m_hdevInfo = pclinfo->hdevInfo;
}
else
{
m_hdevInfo = NULL;
}
// !!! error case who frees the data?'
end:
if (pclinfo)
LocalUnlock (hclinfo);
exitRtn:
intrDebugOut((DEB_ITRACE,
"%x _OUT CDefClient::SendDevInfo(hwndCli=%x)\n",
this,
hWndCli));
return;
}
// Constructor
CDefClient::CDefClient (LPUNKNOWN pUnkOuter): m_Unknown (this),
m_OleClientSite (this),
m_AdviseSink (this),
m_pCallMgr (this)
{
intrDebugOut((DEB_ITRACE,
"%x _IN CDefClient::CDefClient(pUnkOuter=%x)\n",
this,
pUnkOuter));
m_pUnkOuter = pUnkOuter ? pUnkOuter : &m_Unknown;
m_bContainer = TRUE;
m_lpoleObj = NULL;
m_lpdataObj = NULL;
m_bCreateInst = FALSE;
m_bTerminate = FALSE;
m_termNo = 0;
m_hcli = NULL;
m_lpNextItem = NULL;
m_cRef = 0;
m_hwnd = (HWND)0;
m_hdevInfo = NULL;
m_hcliInfo = NULL;
m_fDidRealSetHostNames= FALSE;
m_fDidSetClientSite = FALSE;
m_fGotDdeAdvise = FALSE;
m_fCreatedNotConnected = FALSE;
m_fInOnClose = FALSE;
m_fInOleSave = FALSE;
m_dwConnectionOleObj = 0L;
m_dwConnectionDataObj = 0L;
m_fGotStdCloseDoc = FALSE;
m_fEmbed = FALSE;
m_cClients = 0;
m_plkbytNative = NULL;
m_pstgNative = NULL;
m_fRunningInSDI = FALSE;
m_psrvrParent = NULL;
m_ptd = NULL;
m_pdoc = NULL;
m_chk = chkDefClient;
m_ExecuteAck.f = FALSE;
m_fGotEditNoPokeNativeYet = FALSE;
m_fLocked = FALSE;
m_fCallData = FALSE;
// CDefClient::Create does all the real work.
intrDebugOut((DEB_ITRACE,
"%x _OUT CDefClient::CDefClient(pUnkOuter=%x)\n",
this,
pUnkOuter));
}
CDefClient::~CDefClient (void)
{
// This should be more object-oriented.
// But right now, this BOOL tells us what kind of obj
// (doc or item) "this" is
intrDebugOut((DEB_ITRACE,
"%x _IN CDefClient::~CDefClient\n",
this));
Puts ("~CDefClient "); Puta(m_aItem); Putn();
BOOL fDoc = (m_pdoc==this);
Assert (m_chk==chkDefClient);
ReleaseObjPtrs ();
if (m_pdoc && !fDoc)
{
Assert (m_pdoc->m_chk==chkDefClient);
m_pdoc->m_pUnkOuter->Release();
}
if (fDoc)
{
// delete all the items(objects) for this doc
DeleteAllItems ();
if (m_fRunningInSDI && m_psrvrParent
&& m_psrvrParent->QueryRevokeClassFactory())
{
m_psrvrParent->Revoke();
}
}
if (ISATOM(m_aItem))
GlobalDeleteAtom (m_aItem);
if (m_plkbytNative)
{
m_plkbytNative->Release();
Assert (m_pstgNative);
// They always go together
}
if (m_pstgNative)
m_pstgNative->Release();
if (m_ptd)
PrivMemFree(m_ptd);
// Delete client advise info
DeleteAdviseInfo ();
if (fDoc && IsWindow(m_hwnd))
{
SSDestroyWindow (m_hwnd);
}
intrDebugOut((DEB_ITRACE,
"%x _OUT CDefClient::~CDefClient\n",
this));
}
//
// Unknown Implementation
//
STDMETHODIMP NC(CDefClient,CUnknownImpl)::QueryInterface
(REFIID iid,
LPVOID FAR* ppv)
{
intrDebugOut((DEB_ITRACE,"%p CDefClient::QueryInterface()\n",this));
if (iid == IID_IUnknown)
{
*ppv = (LPVOID) &m_pDefClient->m_Unknown;
AddRef();
return NOERROR;
}
else if (iid==IID_IAdviseSink)
*ppv = (LPVOID) &m_pDefClient->m_AdviseSink;
else if (iid==IID_IOleClientSite)
*ppv = (LPVOID) &m_pDefClient->m_OleClientSite;
else
{
*ppv = NULL;
return ReportResult(0, E_NOINTERFACE, 0, 0);
}
m_pDefClient->m_pUnkOuter->AddRef();
return NOERROR;
}
STDMETHODIMP_(ULONG) NC(CDefClient,CUnknownImpl)::AddRef()
{
intrDebugOut((DEB_ITRACE,
"%p CDefClient::AddRef() returns %x\n",
this,
m_pDefClient->m_cRef+1));
return ++m_pDefClient->m_cRef;
}
STDMETHODIMP_(ULONG) NC(CDefClient,CUnknownImpl)::Release()
{
AssertSz (m_pDefClient->m_cRef, "Release is being called on ref count of zero");
if (--m_pDefClient->m_cRef == 0)
{
delete m_pDefClient;
intrDebugOut((DEB_ITRACE,
"%p CDefClient::Release() returns 0\n",
this));
return 0;
}
intrDebugOut((DEB_ITRACE,
"%p CDefClient::Release() returns %x\n",
this,
m_pDefClient->m_cRef));
return m_pDefClient->m_cRef;
}