diff options
Diffstat (limited to '')
-rw-r--r-- | private/ole32/com/remote/dde/server/item2.cxx | 1400 |
1 files changed, 1400 insertions, 0 deletions
diff --git a/private/ole32/com/remote/dde/server/item2.cxx b/private/ole32/com/remote/dde/server/item2.cxx new file mode 100644 index 000000000..20def4815 --- /dev/null +++ b/private/ole32/com/remote/dde/server/item2.cxx @@ -0,0 +1,1400 @@ +//+--------------------------------------------------------------------------- +// +// 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> +#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)); + + CALLDATA CD; + IID iid = CLSID_NULL; + DDECALLDATA DdeCD; + HRESULT hresult; + + DdeCD.hwndSvr = hwndTo; + DdeCD.hwndCli = hwndFrom; + DdeCD.wMsg = WM_DDE_TERMINATE; + DdeCD.wParam = (WPARAM)hwndFrom, + DdeCD.lParam = 0; + DdeCD.fInitialSend = FALSE; + + CD.id = CALLDATAID_UNUSED; + CD.lid = iid; + CD.TIDCallee = 0; + CD.pRpcMsg = (LPVOID) &DdeCD; + CD.CallCat = CALLCAT_SYNCHRONOUS; + CD.Event = 0; + + // + // Setting the pCallData 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_pCallData = &CD; + + hresult = m_pCallControl->CallRunModalLoop(&CD); + + m_pCallData = NULL; + + 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) +{ + 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_pCallData = NULL; + m_pCallControl = NULL; + // 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); + } + if (m_pCallControl) + { + ReleaseDdeCallControlInterface(); + } + 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; +} |