1332 lines
31 KiB
C++
1332 lines
31 KiB
C++
/*++
|
|
|
|
copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ddeworkr.cpp
|
|
|
|
Abstract:
|
|
|
|
This module contains the code for the worker routines
|
|
|
|
Author:
|
|
|
|
Srini Koppolu (srinik) 22-June-1992
|
|
Jason Fuller (jasonful) 24-July-1992
|
|
|
|
Revision History:
|
|
Kevin Ross (KevinRo) 10-May-1994
|
|
Mostly added comments, and attempted to clean
|
|
it up.
|
|
|
|
--*/
|
|
#include "ddeproxy.h"
|
|
|
|
ASSERTDATA
|
|
|
|
/*
|
|
* WORKER ROUTINES
|
|
*
|
|
*/
|
|
|
|
|
|
INTERNAL_(BOOL) wPostMessageToServer(LPDDE_CHANNEL pChannel,
|
|
WORD wMsg,
|
|
LONG lParam,
|
|
BOOL fFreeOnError)
|
|
{
|
|
int c=0;
|
|
intrDebugOut((DEB_ITRACE,
|
|
"wPostMessageToServer(pChannel=%x,wMsg=%x,lParam=%x,fFreeOnError=%x\n",
|
|
pChannel,
|
|
wMsg,
|
|
lParam,
|
|
fFreeOnError));
|
|
if (NULL==pChannel)
|
|
{
|
|
AssertSz (0, "Channel missing");
|
|
return FALSE;
|
|
}
|
|
pChannel->wMsg = wMsg;
|
|
pChannel->lParam = lParam;
|
|
pChannel->hres = NOERROR;
|
|
|
|
while (TRUE && c<10 )
|
|
{
|
|
if (!IsWindow (pChannel->hwndSvr))
|
|
{
|
|
intrDebugOut((DEB_IWARN,
|
|
"wPostMessageToServer: invalid window %x\n",
|
|
pChannel->hwndSvr));
|
|
goto errRet;
|
|
}
|
|
if (wTerminateIsComing (pChannel)
|
|
&& wMsg != WM_DDE_ACK
|
|
&& wMsg != WM_DDE_TERMINATE)
|
|
{
|
|
intrDebugOut((DEB_IWARN,"Server sent terminate, cannot post\n"));
|
|
goto errRet;
|
|
}
|
|
if (!PostMessage (pChannel->hwndSvr, wMsg, (WPARAM) pChannel->hwndCli, lParam))
|
|
{
|
|
intrDebugOut((DEB_IWARN,
|
|
"wPostMessageToServer: PostMessageFailed, yielding\n"));
|
|
Yield ();
|
|
c++;
|
|
}
|
|
else
|
|
return TRUE;
|
|
}
|
|
AssertSz (0, "PostMessage failed");
|
|
|
|
errRet:
|
|
intrDebugOut((DEB_IWARN,"wPostMessageToServer returns FALSE\n"));
|
|
if (fFreeOnError)
|
|
{
|
|
DDEFREE(wMsg,lParam);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// call Ole1ClassFromCLSID then global add atom; returns NULL if error.
|
|
INTERNAL_(ATOM) wAtomFromCLSID(REFCLSID rclsid)
|
|
{
|
|
WCHAR szClass[MAX_STR];
|
|
ATOM aCls;
|
|
|
|
if (Ole1ClassFromCLSID2(rclsid, szClass, sizeof(szClass)) == 0)
|
|
return NULL;
|
|
aCls = wGlobalAddAtom(szClass);
|
|
intrAssert(wIsValidAtom(aCls));
|
|
return aCls;
|
|
}
|
|
|
|
INTERNAL_(ATOM) wGlobalAddAtom(LPCOLESTR sz)
|
|
{
|
|
if (sz==NULL || sz[0] == '\0')
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
ATOM a = GlobalAddAtom(sz);
|
|
intrAssert(wIsValidAtom(a));
|
|
return a;
|
|
}
|
|
|
|
INTERNAL_(ATOM) wGlobalAddAtomA(LPCSTR sz)
|
|
{
|
|
if (sz==NULL || sz[0] == '\0')
|
|
return NULL;
|
|
ATOM a = GlobalAddAtomA(sz);
|
|
intrAssert(wIsValidAtom(a));
|
|
return a;
|
|
}
|
|
|
|
|
|
INTERNAL_(ATOM) wGetExeNameAtom (REFCLSID rclsid)
|
|
{
|
|
LONG cb = MAX_STR;
|
|
WCHAR key[MAX_STR];
|
|
ATOM a;
|
|
|
|
if (Ole1ClassFromCLSID2(rclsid, key, sizeof(key)) == 0)
|
|
return NULL;
|
|
|
|
lstrcatW (key, OLESTR("\\protocol\\StdFileEditing\\server"));
|
|
|
|
if (RegQueryValue (HKEY_CLASSES_ROOT, key, key, &cb))
|
|
{
|
|
Puts ("ERROR: wGetExeNameAtom failed\n");
|
|
return NULL;
|
|
}
|
|
a = wGlobalAddAtom (key);
|
|
intrAssert(wIsValidAtom(a));
|
|
return a;
|
|
}
|
|
|
|
INTERNAL_(void) wFreeData (HANDLE hData, CLIPFORMAT cfFormat,
|
|
BOOL fFreeNonGdiHandle)
|
|
{
|
|
intrDebugOut((DEB_ITRACE,
|
|
"wFreeData(hData=%x,cfFormat=%x,FreeNonGDIHandle=%x\n",
|
|
hData,
|
|
(USHORT)cfFormat,
|
|
fFreeNonGdiHandle));
|
|
|
|
AssertSz (hData != NULL, "Trying to free NULL handle");
|
|
AssertSz (hData != (HANDLE) 0xcccccccc, "Trying to free handle from a deleted object");
|
|
|
|
switch (cfFormat) {
|
|
case CF_METAFILEPICT:
|
|
LPMETAFILEPICT lpMfp;
|
|
|
|
if (lpMfp = (LPMETAFILEPICT) GlobalLock (hData))
|
|
{
|
|
intrDebugOut((DEB_ITRACE,
|
|
"wFreeData freeing metafile %x\n",
|
|
lpMfp->hMF));
|
|
|
|
OleDdeDeleteMetaFile(lpMfp->hMF);
|
|
GlobalUnlock (hData);
|
|
}
|
|
GlobalFree (hData);
|
|
break;
|
|
|
|
case CF_BITMAP:
|
|
case CF_PALETTE:
|
|
Verify(DeleteObject (hData));
|
|
break;
|
|
|
|
case CF_DIB:
|
|
GlobalFree (hData);
|
|
break;
|
|
|
|
default:
|
|
if (fFreeNonGdiHandle)
|
|
GlobalFree (hData);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
INTERNAL_(BOOL) wInitiate (LPDDE_CHANNEL pChannel, ATOM aLow, ATOM aHigh)
|
|
{
|
|
intrDebugOut((DEB_ITRACE,"wInitiate(pChannel=%x,aLow=%x,aHigh=%x)\n",
|
|
pChannel, aLow, aHigh));
|
|
|
|
intrAssert(wIsValidAtom(aLow));
|
|
if (aLow == (ATOM)0)
|
|
{
|
|
intrDebugOut((DEB_IERROR,"wInitiate Failed, aLow == 0\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
pChannel->iAwaitAck = AA_INITIATE;
|
|
|
|
SSSendMessage ((HWND)-1, WM_DDE_INITIATE, (WPARAM) pChannel->hwndCli,
|
|
MAKE_DDE_LPARAM (WM_DDE_INITIATE, aLow, aHigh));
|
|
|
|
pChannel->iAwaitAck = NULL;
|
|
|
|
intrDebugOut((DEB_ITRACE,
|
|
"wInitiate pChannel->hwndSrvr = %x\n",
|
|
pChannel->hwndSvr));
|
|
|
|
return (pChannel->hwndSvr != NULL);
|
|
}
|
|
|
|
|
|
|
|
INTERNAL_(HRESULT) wScanItemOptions (ATOM aItem, int FAR* lpoptions)
|
|
{
|
|
ATOM aModifier;
|
|
LPOLESTR lpbuf;
|
|
WCHAR buf[MAX_STR];
|
|
|
|
*lpoptions = ON_CHANGE; // default
|
|
|
|
if (!aItem) {
|
|
// NULL item with no modifier means ON_CHANGE for NULL item
|
|
return NOERROR;
|
|
}
|
|
|
|
intrAssert(wIsValidAtom(aItem));
|
|
GlobalGetAtomName (aItem, buf, MAX_STR);
|
|
lpbuf = buf;
|
|
|
|
while ( *lpbuf && *lpbuf != '/')
|
|
IncLpch (lpbuf);
|
|
|
|
// no modifier same as /change
|
|
|
|
if (*lpbuf == NULL)
|
|
return NOERROR;
|
|
|
|
*lpbuf++ = NULL; // seperate out the item string
|
|
// We are using this in the caller.
|
|
|
|
if (!(aModifier = GlobalFindAtom (lpbuf)))
|
|
{
|
|
Puts ("ERROR: wScanItemOptions found non-atom modifier\n");
|
|
return ReportResult(0, RPC_E_DDE_SYNTAX_ITEM, 0, 0);
|
|
}
|
|
|
|
intrAssert(wIsValidAtom(aModifier));
|
|
|
|
if (aModifier == aChange)
|
|
return NOERROR;
|
|
|
|
// Is it a save?
|
|
if (aModifier == aSave){
|
|
*lpoptions = ON_SAVE;
|
|
return NOERROR;
|
|
}
|
|
// Is it a Close?
|
|
if (aModifier == aClose){
|
|
*lpoptions = ON_CLOSE;
|
|
return NOERROR;
|
|
}
|
|
|
|
// unknown modifier
|
|
Puts ("ERROR: wScanItemOptions found bad modifier\n");
|
|
return ReportResult(0, RPC_E_DDE_SYNTAX_ITEM, 0, 0);
|
|
}
|
|
|
|
|
|
INTERNAL_(BOOL) wClearWaitState (LPDDE_CHANNEL pChannel)
|
|
{
|
|
Assert (pChannel);
|
|
// kill if any timer active.
|
|
if (pChannel->wTimer) {
|
|
KillTimer (pChannel->hwndCli, 1);
|
|
pChannel->wTimer = 0;
|
|
|
|
if (pChannel->hDdePoke) {
|
|
GlobalFree (pChannel->hDdePoke);
|
|
pChannel->hDdePoke = NULL;
|
|
}
|
|
|
|
if (pChannel->hopt) {
|
|
GlobalFree (pChannel->hopt);
|
|
pChannel->hopt = NULL;
|
|
}
|
|
|
|
//
|
|
// If the channel is waiting on an Ack, and there is an
|
|
// lParam, then we may need to cleanup the data.
|
|
|
|
if (pChannel->iAwaitAck && (pChannel->lParam)) {
|
|
if (pChannel->iAwaitAck == AA_EXECUTE)
|
|
{
|
|
//
|
|
// KevinRo: Found the following comment in the code.
|
|
// ; // BUGBUG32 - get hData from GET_WM_DDE_EXECUTE_HADATA ??
|
|
// It appears, by looking at what the 16-bit code does,
|
|
// that the goal is to free the handle that was passed as
|
|
// part of the EXECUTE message. Judging by what the 16-bit
|
|
// code did, I have determined that this is correct.
|
|
//
|
|
// The macro used below wanted two parameters. The first was
|
|
// the WPARAM, the second the LPARAM. We don't have the WPARAM.
|
|
// However, it isn't actually used by the macro, so I have
|
|
// cheated and provided 0 as a default
|
|
//
|
|
GlobalFree(GET_WM_DDE_EXECUTE_HDATA(0,pChannel->lParam));
|
|
|
|
#ifdef KEVINRO_HERE_IS_THE_16_BIT_CODE
|
|
GlobalFree (HIWORD (pChannel->lParam));
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// All of the other DDE messages pass an Atom in the high word.
|
|
// Therefore, we should delete the atom.
|
|
//
|
|
//
|
|
ATOM aTmp;
|
|
|
|
aTmp = MGetDDElParamHi(pChannel->wMsg,pChannel->lParam);
|
|
|
|
intrAssert(wIsValidAtom(aTmp));
|
|
if (aTmp)
|
|
{
|
|
GlobalDeleteAtom (aTmp);
|
|
}
|
|
}
|
|
DDEFREE(pChannel->wMsg,pChannel->lParam);
|
|
|
|
// we want to wipe out the lParam
|
|
pChannel->lParam = 0x0;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
// wNewHandle (LPSTR, DWORD)
|
|
//
|
|
// Copy cb bytes from lpstr into a new memory block and return a handle to it.
|
|
// If lpstr is an ASCIIZ string, cb must include 1 for the null terminator.
|
|
//
|
|
|
|
INTERNAL_(HANDLE) wNewHandle (LPSTR lpstr, DWORD cb)
|
|
{
|
|
|
|
HANDLE hdata = NULL;
|
|
LPSTR lpdata = NULL;
|
|
|
|
hdata = GlobalAlloc (GMEM_DDESHARE | GMEM_MOVEABLE, cb);
|
|
if (hdata == NULL || (lpdata = (LPSTR) GlobalLock (hdata)) == NULL)
|
|
goto errRtn;
|
|
|
|
memcpy (lpdata, lpstr, cb);
|
|
GlobalUnlock (hdata);
|
|
return hdata;
|
|
|
|
errRtn:
|
|
Puts ("ERROR: wNewHandle\n");
|
|
Assert (0);
|
|
if (lpdata)
|
|
GlobalUnlock (hdata);
|
|
|
|
if (hdata)
|
|
GlobalFree (hdata);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
// wDupData
|
|
//
|
|
// Copy data from handle h into a new handle which is returned as *ph.
|
|
//
|
|
|
|
INTERNAL wDupData (LPHANDLE ph, HANDLE h, CLIPFORMAT cf)
|
|
{
|
|
Assert (ph);
|
|
RetZ (wIsValidHandle(h, cf));
|
|
*ph = OleDuplicateData (h, cf, GMEM_DDESHARE | GMEM_MOVEABLE);
|
|
RetZ (wIsValidHandle (*ph, cf));
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
// wTransferHandle
|
|
//
|
|
//
|
|
INTERNAL wTransferHandle
|
|
(LPHANDLE phDst,
|
|
LPHANDLE phSrc,
|
|
CLIPFORMAT cf)
|
|
{
|
|
RetErr (wDupData (phDst, *phSrc, cf));
|
|
wFreeData (*phSrc, cf, TRUE);
|
|
*phSrc = (HANDLE)0;
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
// wHandleCopy
|
|
//
|
|
// copy data from hSrc to hDst.
|
|
// Both handles must already have memory allocated to them.
|
|
//
|
|
|
|
INTERNAL wHandleCopy (HANDLE hDst, HANDLE hSrc)
|
|
{
|
|
LPSTR lpDst, lpSrc;
|
|
DWORD dwSrc;
|
|
|
|
if (NULL==hDst || NULL==hSrc)
|
|
return ResultFromScode (E_INVALIDARG);
|
|
if (GlobalSize(hDst) < (dwSrc=GlobalSize(hSrc)))
|
|
{
|
|
HANDLE hDstNew = GlobalReAlloc (hDst, dwSrc, GMEM_DDESHARE | GMEM_MOVEABLE);
|
|
if (hDstNew != hDst)
|
|
return ResultFromScode (E_OUTOFMEMORY);
|
|
}
|
|
if (!(lpDst = (LPSTR) GlobalLock(hDst)))
|
|
{
|
|
intrAssert(!"ERROR: wHandleCopy hDst");
|
|
return ReportResult(0, E_OUTOFMEMORY, 0, 0);
|
|
}
|
|
if (!(lpSrc = (LPSTR) GlobalLock(hSrc)))
|
|
{
|
|
GlobalUnlock(hDst);
|
|
intrAssert (!"ERROR: wHandleCopy hSrc");
|
|
return ReportResult(0, E_OUTOFMEMORY, 0, 0);
|
|
}
|
|
memcpy (lpDst, lpSrc, dwSrc);
|
|
GlobalUnlock(hDst);
|
|
GlobalUnlock(hSrc);
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
// ExtendAtom: Create a new atom, which is the old one plus extension
|
|
|
|
INTERNAL_(ATOM) wExtendAtom (ATOM aItem, int iAdvOn)
|
|
{
|
|
WCHAR buffer[MAX_STR+1];
|
|
LPOLESTR lpext;
|
|
|
|
buffer[0] = 0;
|
|
// aItem==NULL for embedded objects.
|
|
// If so, there is no item name before the slash.
|
|
if (aItem)
|
|
GlobalGetAtomName (aItem, buffer, MAX_STR);
|
|
|
|
switch (iAdvOn) {
|
|
case ON_CHANGE:
|
|
lpext = OLESTR("");
|
|
break;
|
|
|
|
case ON_SAVE:
|
|
lpext = OLESTR("/Save");
|
|
break;
|
|
|
|
case ON_CLOSE:
|
|
lpext = OLESTR("/Close");
|
|
break;
|
|
|
|
default:
|
|
AssertSz (FALSE, "Unknown Advise option");
|
|
break;
|
|
|
|
}
|
|
|
|
lstrcatW (buffer, lpext);
|
|
if (buffer[0])
|
|
return wGlobalAddAtom (buffer);
|
|
else
|
|
return NULL;
|
|
// not an error. For embedded object on-change, aItem==NULL
|
|
}
|
|
|
|
|
|
|
|
|
|
INTERNAL_(ATOM) wDupAtom (ATOM a)
|
|
{
|
|
WCHAR sz[MAX_STR];
|
|
|
|
if (!a)
|
|
return NULL;
|
|
|
|
Assert (wIsValidAtom (a));
|
|
GlobalGetAtomName (a, sz, MAX_STR);
|
|
return wGlobalAddAtom (sz);
|
|
}
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: wAtomLen
|
|
//
|
|
// Synopsis: Return the length, in characters, of the atom name.
|
|
// The length includes the NULL. This function returns the
|
|
// length of the UNICODE version of the atom.
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [atom] --
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 5-12-94 kevinro Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
INTERNAL_(int) wAtomLen (ATOM atom)
|
|
{
|
|
WCHAR buf[MAX_STR];
|
|
|
|
if (!atom)
|
|
return NULL;
|
|
|
|
return (GlobalGetAtomName (atom, buf, MAX_STR));
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: wAtomLenA
|
|
//
|
|
// Synopsis: Return the length, in characters, of the atom name.
|
|
// The length includes the NULL This function returns the
|
|
// length of the ANSI version of the atom,
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [atom] --
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 5-12-94 kevinro Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
INTERNAL_(int) wAtomLenA (ATOM atom)
|
|
{
|
|
char buf[MAX_STR];
|
|
|
|
if (!atom)
|
|
return NULL;
|
|
|
|
return (GlobalGetAtomNameA (atom, (LPSTR)buf, MAX_STR));
|
|
}
|
|
|
|
|
|
|
|
// NOTE: returns address of static buffer. Use return value immediately.
|
|
//
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: wAtomName
|
|
//
|
|
// Synopsis: Returns a STATIC BUFFER that holds the string name of the
|
|
// atom.
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [atom] --
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 5-12-94 kevinro Commented
|
|
//
|
|
// Notes:
|
|
//
|
|
// WARNING: This uses a static buffer, so don't depend on the pointer for
|
|
// very long.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
INTERNAL_(LPOLESTR) wAtomName (ATOM atom)
|
|
{
|
|
static WCHAR buf[MAX_STR];
|
|
|
|
if (!atom)
|
|
return NULL;
|
|
|
|
if (0==GlobalGetAtomName (atom, buf, MAX_STR))
|
|
return NULL;
|
|
|
|
return buf;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: wAtomName
|
|
//
|
|
// Synopsis: Returns a STATIC BUFFER that holds the string name of the
|
|
// atom.
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [atom] --
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 5-12-94 kevinro Commented
|
|
//
|
|
// Notes:
|
|
//
|
|
// WARNING: This uses a static buffer, so don't depend on the pointer for
|
|
// very long.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
INTERNAL_(LPSTR) wAtomNameA (ATOM atom)
|
|
{
|
|
static char buf[MAX_STR];
|
|
|
|
if (!atom)
|
|
return NULL;
|
|
|
|
if (0==GlobalGetAtomNameA (atom, (LPSTR)buf, MAX_STR))
|
|
return NULL;
|
|
|
|
return buf;
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: wHandleFromDdeData
|
|
//
|
|
// Synopsis: Return a handle from the DDEDATA passed in.
|
|
//
|
|
// Effects: This function will return the correct data from the
|
|
// DDEDATA that is referenced by the handle passed in.
|
|
//
|
|
// DDEDATA is a small structure that is used in DDE to
|
|
// specify the data type of the buffer, its release
|
|
// semantics, and the actual data.
|
|
//
|
|
// In the case of a known format, the handle to the
|
|
// data is extracted from the DDEDATA structure, and
|
|
// the hDdeData is released.
|
|
//
|
|
// If its a Native format, the data is either moved
|
|
// within the memory block allocated, or is copied to
|
|
// another block, depending on the fRelease flag in
|
|
// the hDdeData.
|
|
//
|
|
// Arguments: [hDdeData] -- Handle to DDEDATA
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: A handle to the data. hDdeData will be invalidated
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 5-13-94 kevinro Commented
|
|
//
|
|
// Notes:
|
|
//
|
|
// hDdeData is invalid after calling this function
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
INTERNAL_(HANDLE) wHandleFromDdeData
|
|
(HANDLE hDdeData)
|
|
{
|
|
intrDebugOut((DEB_ITRACE,"wHandleFromDdeData(%x)\n",hDdeData));
|
|
BOOL fRelease;
|
|
HGLOBAL h = NULL; // return value
|
|
|
|
DDEDATA FAR* lpDdeData = (DDEDATA FAR *) GlobalLock (hDdeData);
|
|
|
|
//
|
|
// If the handle is invalid, then the lpDdeData will be NULL
|
|
//
|
|
if (!lpDdeData)
|
|
{
|
|
intrDebugOut((DEB_ITRACE,
|
|
"\twHandleFromDdeData(%x) invalid handle\n",
|
|
hDdeData));
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// The header section of a DDEDATA consists of 2 shorts.
|
|
// That makes it 4 bytes. Due to the new packing values,
|
|
// it turns out that doing a sizeof(DDEDATA) won't work,
|
|
// because the size gets rounded up to a multple of 2
|
|
//
|
|
// We will just hard code the 4 here, since it cannot change
|
|
// for all time anyway.
|
|
//
|
|
#define cbHeader 4
|
|
Assert (cbHeader==4);
|
|
|
|
//
|
|
// If the cfFormat is BITMAP or METAFILEPICT, then the
|
|
// handle will be retrieved from the first DWORD of the
|
|
// buffer
|
|
//
|
|
if (lpDdeData->cfFormat == CF_BITMAP ||
|
|
lpDdeData->cfFormat == CF_METAFILEPICT)
|
|
{
|
|
//
|
|
// The alignment here should be fine, since the Value
|
|
// field is DWORD aligned. So, we trust this cast
|
|
//
|
|
h = *(LPHANDLE)lpDdeData->Value;
|
|
Assert (GlobalFlags(h) != GMEM_INVALID_HANDLE);
|
|
fRelease = lpDdeData->fRelease;
|
|
GlobalUnlock (hDdeData);
|
|
if (fRelease)
|
|
{
|
|
GlobalFree (hDdeData);
|
|
}
|
|
|
|
return h;
|
|
}
|
|
else if (lpDdeData->cfFormat == CF_DIB)
|
|
{
|
|
//
|
|
// The alignment here should be fine, since the Value
|
|
// field is DWORD aligned.
|
|
//
|
|
// This changes the memory from fixed to moveable.
|
|
//
|
|
h = GlobalReAlloc (*(LPHANDLE)lpDdeData->Value, 0L,
|
|
GMEM_MODIFY|GMEM_MOVEABLE);
|
|
Assert (GlobalFlags(h) != GMEM_INVALID_HANDLE);
|
|
fRelease = lpDdeData->fRelease;
|
|
GlobalUnlock (hDdeData);
|
|
if (fRelease)
|
|
GlobalFree (hDdeData);
|
|
return h;
|
|
}
|
|
|
|
|
|
// Native and other data case
|
|
// dwSize = size of Value array, ie, size of the data itself
|
|
const DWORD dwSize = GlobalSize (hDdeData) - cbHeader;
|
|
|
|
if (lpDdeData->fRelease)
|
|
{
|
|
// Move the Value data up over the DDE_DATA header flags.
|
|
memcpy ((LPSTR)lpDdeData, ((LPSTR)lpDdeData)+cbHeader, dwSize);
|
|
GlobalUnlock (hDdeData);
|
|
h = GlobalReAlloc (hDdeData, dwSize, GMEM_MOVEABLE);
|
|
Assert (GlobalFlags(h) != GMEM_INVALID_HANDLE);
|
|
return h;
|
|
}
|
|
else
|
|
{
|
|
// Duplicate the data because the server will free the original.
|
|
h = wNewHandle (((LPSTR)lpDdeData)+cbHeader, dwSize);
|
|
Assert (GlobalFlags(h) != GMEM_INVALID_HANDLE);
|
|
GlobalUnlock (hDdeData);
|
|
return h;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CDdeObject::CanCallBack
|
|
//
|
|
// Synopsis: This routine apparently was supposed to determine if a
|
|
// call back could be made. However, the PeekMessage stuff
|
|
// was commented out.
|
|
//
|
|
// So, it returns TRUE if 0 or 1, FALSE but increments lpCount
|
|
// if 2, returns true but decrements lpCount if > 3. Why?
|
|
// Dunno. Need to ask JasonFul
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [lpCount] --
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 5-16-94 kevinro Commented, confused, and disgusted
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
INTERNAL_(BOOL) CDdeObject::CanCallBack (LPINT lpCount)
|
|
{
|
|
switch (*lpCount) {
|
|
case 0:
|
|
case 1:
|
|
return TRUE;
|
|
|
|
case 2:
|
|
{
|
|
// MSG msg;
|
|
if (0)
|
|
//!PeekMessage (&msg, m_pDocChannel->hwndCli,0,0, PM_NOREMOVE) ||
|
|
// msg.message != WM_DDE_DATA)
|
|
{
|
|
Puts ("Server only sent one format (hopefully presentation)\n");
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
++(*lpCount);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
case 3:
|
|
--(*lpCount);
|
|
return TRUE;
|
|
|
|
default:
|
|
AssertSz (FALSE, "012345" + *lpCount);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
INTERNAL_(BOOL) wIsOldServer (ATOM aClass)
|
|
{
|
|
LONG cb = MAX_STR;
|
|
WCHAR key[MAX_STR];
|
|
int len;
|
|
|
|
if (aClass==(ATOM)0)
|
|
return FALSE;
|
|
|
|
if (!GlobalGetAtomName (aClass, key, sizeof(key)))
|
|
return TRUE;
|
|
|
|
lstrcatW (key, OLESTR("\\protocol\\StdFileEditing\\verb\\"));
|
|
len = lstrlenW (key);
|
|
key [len++] = (char) ('0');
|
|
key [len++] = 0;
|
|
|
|
if (RegQueryValue (HKEY_CLASSES_ROOT, key, key, &cb))
|
|
return TRUE; // no verbs registered
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
|
|
INTERNAL_(void) wFreePokeData
|
|
(LPDDE_CHANNEL pChannel,
|
|
BOOL fMSDrawBug)
|
|
{
|
|
DDEPOKE FAR * lpdde;
|
|
|
|
if (!pChannel )
|
|
return;
|
|
|
|
if (!pChannel->hDdePoke)
|
|
return;
|
|
|
|
if (lpdde = (DDEPOKE FAR *) GlobalLock (pChannel->hDdePoke)) {
|
|
|
|
// The old version of MSDraw expects the _contents_ of METAFILEPICT
|
|
// structure, rather than the handle to it, to be part of DDEPOKE.
|
|
|
|
if (fMSDrawBug && lpdde->cfFormat==CF_METAFILEPICT) {
|
|
intrDebugOut((DEB_ITRACE,
|
|
"wFreePokeData is accomodating MSDraw bug\n"));
|
|
//
|
|
// This meta file was created in 32-bits, and was not passed
|
|
// into us by DDE. Therefore, this metafile should not need to
|
|
// call WOW to be free'd.
|
|
//
|
|
DeleteMetaFile (((LPMETAFILEPICT) ((LPVOID) &lpdde->Value))->hMF);
|
|
}
|
|
// If there is a normal metafile handle in the Value field,
|
|
// it will be freed (if necessary) by the ReleaseStgMedium()
|
|
// in DO::SetData
|
|
GlobalUnlock (pChannel->hDdePoke);
|
|
}
|
|
GlobalFree (pChannel->hDdePoke);
|
|
pChannel->hDdePoke = NULL;
|
|
}
|
|
|
|
|
|
|
|
|
|
INTERNAL_(HANDLE) wPreparePokeBlock
|
|
(HANDLE hData, CLIPFORMAT cfFormat, ATOM aClass, BOOL bOldSvr)
|
|
{
|
|
HANDLE hDdePoke;
|
|
LPSTR lpBuf;
|
|
|
|
if (!hData)
|
|
return NULL;
|
|
|
|
// The old version of MSDraw expects the contents of METAFILEPICT
|
|
// structure to be part of DDEPOKE, rather than the handle to it.
|
|
if ((cfFormat==CF_METAFILEPICT && !(aClass==aMSDraw && bOldSvr))
|
|
|| (cfFormat == CF_DIB)
|
|
|| (cfFormat == CF_BITMAP)) {
|
|
|
|
Verify (lpBuf = wAllocDdePokeBlock (4, cfFormat, &hDdePoke));
|
|
*((HANDLE FAR*)lpBuf) = hData;
|
|
|
|
}
|
|
else {
|
|
// Handle the non-metafile case and the MS-Draw bug
|
|
DWORD dwSize = GlobalSize (hData);
|
|
|
|
if ((aClass == aMSDraw) && bOldSvr)
|
|
{
|
|
intrDebugOut((DEB_ITRACE,
|
|
"wPreparePokeBlock is accomodating MSDraw bug\n"));
|
|
}
|
|
|
|
if (lpBuf = wAllocDdePokeBlock (dwSize, cfFormat, &hDdePoke)) {
|
|
memcpy (lpBuf, GlobalLock(hData), dwSize);
|
|
GlobalUnlock (hData);
|
|
}
|
|
}
|
|
GlobalUnlock (hDdePoke);
|
|
return hDdePoke;
|
|
}
|
|
|
|
|
|
// wAllocDdePokeBlock
|
|
// The caller must unlock *phDdePoke when it is done using the return value
|
|
// of this function but before a DDe message is sent using *phDdePoke.
|
|
//
|
|
|
|
INTERNAL_(LPSTR) wAllocDdePokeBlock
|
|
(DWORD dwSize, CLIPFORMAT cfFormat, LPHANDLE phDdePoke)
|
|
{
|
|
HANDLE hdde = NULL;
|
|
DDEPOKE FAR * lpdde = NULL;
|
|
|
|
if (!(hdde = GlobalAlloc (GMEM_DDESHARE | GMEM_ZEROINIT,
|
|
(dwSize + sizeof(DDEPOKE) - sizeof(BYTE) ))))
|
|
return NULL;
|
|
|
|
if (!(lpdde = (DDEPOKE FAR*)GlobalLock (hdde))) {
|
|
GlobalFree (hdde);
|
|
return NULL;
|
|
}
|
|
// hdde will be UnLock'ed in wPreparePokeBlock and Free'd in wFreePokeData
|
|
lpdde->fRelease = FALSE;
|
|
lpdde->cfFormat = cfFormat;
|
|
*phDdePoke = hdde;
|
|
return (LPSTR) &(lpdde->Value);
|
|
}
|
|
|
|
|
|
#ifdef OLD
|
|
INTERNAL_(ULONG) wPixelsToHiMetric
|
|
(ULONG cPixels,
|
|
ULONG cPixelsPerInch)
|
|
{
|
|
return cPixels * HIMETRIC_PER_INCH / cPixelsPerInch;
|
|
}
|
|
#endif
|
|
|
|
// Can ask for icon based on either CLSID or filename
|
|
//
|
|
|
|
INTERNAL GetDefaultIcon (REFCLSID clsidIn, LPCOLESTR szFile, HANDLE FAR* phmfp)
|
|
{
|
|
if (!(*phmfp = OleGetIconOfClass(clsidIn, NULL, TRUE)))
|
|
return ResultFromScode(E_OUTOFMEMORY);
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
#ifdef OLD
|
|
VDATEPTROUT (phmfp, HICON);
|
|
VDATEPTRIN (szFile, char);
|
|
WCHAR szExe[MAX_STR];
|
|
HICON hicon;
|
|
HDC hdc;
|
|
METAFILEPICT FAR* pmfp=NULL;
|
|
HRESULT hresult;
|
|
static int cxIcon = 0;
|
|
static int cyIcon = 0;
|
|
static int cxIconHiMetric = 0;
|
|
static int cyIconHiMetric = 0;
|
|
|
|
*phmfp = NULL;
|
|
CLSID clsid;
|
|
if (clsidIn != CLSID_NULL)
|
|
{
|
|
clsid = clsidIn;
|
|
}
|
|
else
|
|
{
|
|
RetErr (GetClassFile (szFile, &clsid));
|
|
}
|
|
ATOM aExe = wGetExeNameAtom (clsid);
|
|
if (0==GlobalGetAtomName (aExe, szExe, MAX_STR))
|
|
{
|
|
Assert (0);
|
|
return ReportResult(0, E_UNEXPECTED, 0, 0);
|
|
}
|
|
hicon = ExtractIcon (hmodOLE2, szExe, 0/*first icon*/);
|
|
if (((HICON) 1)==hicon || NULL==hicon)
|
|
{
|
|
// ExtractIcon failed, so we can't support DVASPECT_ICON
|
|
return ResultFromScode (DV_E_DVASPECT);
|
|
}
|
|
*phmfp = GlobalAlloc (GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(METAFILEPICT));
|
|
ErrZS (*phmfp, E_OUTOFMEMORY);
|
|
pmfp = (METAFILEPICT FAR*) GlobalLock (*phmfp);
|
|
ErrZS (pmfp, E_OUTOFMEMORY);
|
|
if (0==cxIcon)
|
|
{
|
|
// In units of pixels
|
|
Verify (cxIcon = GetSystemMetrics (SM_CXICON));
|
|
Verify (cyIcon = GetSystemMetrics (SM_CYICON));
|
|
// In units of .01 millimeter
|
|
cxIconHiMetric = (int)(long)wPixelsToHiMetric (cxIcon, giPpliX) ;
|
|
cyIconHiMetric = (int)(long)wPixelsToHiMetric (cyIcon, giPpliY) ;
|
|
}
|
|
pmfp->mm = MM_ANISOTROPIC;
|
|
pmfp->xExt = cxIconHiMetric;
|
|
pmfp->yExt = cyIconHiMetric;
|
|
hdc = CreateMetaFile (NULL);
|
|
SetWindowOrg (hdc, 0, 0);
|
|
SetWindowExt (hdc, cxIcon, cyIcon);
|
|
DrawIcon (hdc, 0, 0, hicon);
|
|
pmfp->hMF = CloseMetaFile (hdc);
|
|
ErrZ (pmfp->hMF);
|
|
Assert (wIsValidHandle (pmfp->hMF, NULL));
|
|
GlobalUnlock (*phmfp);
|
|
Assert (wIsValidHandle (*phmfp, CF_METAFILEPICT));
|
|
return NOERROR;
|
|
|
|
errRtn:
|
|
if (pmfp)
|
|
GlobalUnlock (*phmfp);
|
|
if (*phmfp)
|
|
GlobalFree (*phmfp);
|
|
return hresult;
|
|
}
|
|
#endif
|
|
|
|
#define DWTIMEOUT 1000L
|
|
|
|
INTERNAL wTimedGetMessage
|
|
(LPMSG pmsg,
|
|
HWND hwnd,
|
|
WORD wFirst,
|
|
WORD wLast)
|
|
{
|
|
DWORD dwStartTickCount = GetTickCount();
|
|
while (!SSPeekMessage (pmsg, hwnd, wFirst, wLast, PM_REMOVE))
|
|
{
|
|
if (GetTickCount() - dwStartTickCount > DWTIMEOUT)
|
|
{
|
|
if (!IsWindow (hwnd))
|
|
return ResultFromScode (RPC_E_CONNECTION_LOST);
|
|
else
|
|
return ResultFromScode (RPC_E_SERVER_DIED);
|
|
}
|
|
}
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
INTERNAL wNormalize
|
|
(LPFORMATETC pformatetcIn,
|
|
LPFORMATETC pformatetcOut)
|
|
{
|
|
if (pformatetcIn->cfFormat == 0
|
|
&& pformatetcIn->ptd == NULL // Is WildCard
|
|
&& pformatetcIn->dwAspect == -1L
|
|
&& pformatetcIn->lindex == -1L
|
|
&& pformatetcIn->tymed == -1L)
|
|
{
|
|
pformatetcOut->cfFormat = CF_METAFILEPICT;
|
|
pformatetcOut->ptd = NULL;
|
|
pformatetcOut->dwAspect = DVASPECT_CONTENT;
|
|
pformatetcOut->lindex = DEF_LINDEX;
|
|
pformatetcOut->tymed = TYMED_MFPICT;
|
|
}
|
|
else
|
|
{
|
|
memcpy (pformatetcOut, pformatetcIn, sizeof(FORMATETC));
|
|
}
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
|
|
INTERNAL wVerifyFormatEtc
|
|
(LPFORMATETC pformatetc)
|
|
{
|
|
intrDebugOut((DEB_ITRACE,
|
|
"wVerifyFormatEtc(pformatetc=%x)\n",
|
|
pformatetc));
|
|
|
|
VDATEPTRIN (pformatetc, FORMATETC);
|
|
if (!HasValidLINDEX(pformatetc))
|
|
{
|
|
intrDebugOut((DEB_IERROR, "\t!HasValidLINDEX(pformatetc)\n"));
|
|
return(DV_E_LINDEX);
|
|
}
|
|
|
|
if (0==(pformatetc->tymed & (TYMED_HGLOBAL | TYMED_MFPICT | TYMED_GDI)))
|
|
{
|
|
intrDebugOut((DEB_IERROR,
|
|
"\t0==(pformatetc->tymed & (TYMED_HGLOBAL | TYMED_MFPICT | TYMED_GDI))\n"));
|
|
return ResultFromScode (DV_E_TYMED);
|
|
}
|
|
if (0==(UtFormatToTymed (pformatetc->cfFormat) & pformatetc->tymed))
|
|
{
|
|
intrDebugOut((DEB_IERROR,
|
|
"\t0==(UtFormatToTymed (pformatetc->cfFormat) & pformatetc->tymed)\n"));
|
|
return ResultFromScode (DV_E_TYMED);
|
|
}
|
|
if (0==(pformatetc->dwAspect & (DVASPECT_CONTENT | DVASPECT_ICON)))
|
|
{
|
|
intrDebugOut((DEB_IERROR,
|
|
"\t0==(pformatetc->dwAspect & (DVASPECT_CONTENT | DVASPECT_ICON))\n"));
|
|
|
|
return ResultFromScode (DV_E_DVASPECT);
|
|
}
|
|
if (pformatetc->dwAspect & DVASPECT_ICON)
|
|
{
|
|
if (CF_METAFILEPICT != pformatetc->cfFormat)
|
|
{
|
|
intrDebugOut((DEB_IERROR,
|
|
"\tCF_METAFILEPICT != pformatetc->cfFormat\n"));
|
|
return ResultFromScode (DV_E_CLIPFORMAT);
|
|
}
|
|
|
|
if (0==(pformatetc->tymed & TYMED_MFPICT))
|
|
{
|
|
intrDebugOut((DEB_IERROR,
|
|
"\t0==(pformatetc->tymed & TYMED_MFPICT)\n"));
|
|
return ResultFromScode (DV_E_TYMED);
|
|
}
|
|
}
|
|
if (pformatetc->ptd)
|
|
{
|
|
if (IsBadReadPtr (pformatetc->ptd, sizeof (DWORD))
|
|
|| IsBadReadPtr (pformatetc->ptd, (size_t)pformatetc->ptd->tdSize))
|
|
{
|
|
intrDebugOut((DEB_IERROR,"\tDV_E_DVTARGETDEVICE\n"));
|
|
|
|
return ResultFromScode (DV_E_DVTARGETDEVICE);
|
|
}
|
|
}
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
|
|
INTERNAL wClassesMatch
|
|
(REFCLSID clsidIn,
|
|
LPOLESTR szFile)
|
|
{
|
|
CLSID clsid;
|
|
if (NOERROR==GetClassFile (szFile, &clsid))
|
|
{
|
|
return clsid==clsidIn ? NOERROR : ResultFromScode (S_FALSE);
|
|
}
|
|
else
|
|
{
|
|
// If we can't determine the class of the file (because it's
|
|
// not a real file) then OK. Bug 3937.
|
|
return NOERROR;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#ifdef KEVINRO_DUPLICATECODE
|
|
|
|
This routine also appears in ole1.lib in the OLE232\OLE1 directory
|
|
|
|
INTERNAL wWriteFmtUserType
|
|
(LPSTORAGE pstg,
|
|
REFCLSID clsid)
|
|
{
|
|
HRESULT hresult = NOERROR;
|
|
LPOLESTR szProgID = NULL;
|
|
LPOLESTR szUserType = NULL;
|
|
|
|
ErrRtnH (ProgIDFromCLSID (clsid, &szProgID));
|
|
ErrRtnH (OleRegGetUserType (clsid, USERCLASSTYPE_FULL, &szUserType));
|
|
ErrRtnH (WriteFmtUserTypeStg (pstg, RegisterClipboardFormat (szProgID),
|
|
szUserType));
|
|
errRtn:
|
|
delete szProgID;
|
|
delete szUserType;
|
|
return hresult;
|
|
}
|
|
#endif
|
|
|
|
#if DBG == 1
|
|
|
|
INTERNAL_(BOOL) wIsValidHandle
|
|
(HANDLE h,
|
|
CLIPFORMAT cf) // cf==NULL means normal memory
|
|
{
|
|
LPVOID p;
|
|
if (CF_BITMAP == cf)
|
|
{
|
|
BITMAP bm;
|
|
return (0 != GetObject (h, sizeof(BITMAP), (LPVOID) &bm));
|
|
}
|
|
if (CF_PALETTE == cf)
|
|
{
|
|
WORD w;
|
|
return (0 != GetObject (h, sizeof(w), (LPVOID) &w));
|
|
}
|
|
if (!(p=GlobalLock(h)))
|
|
{
|
|
Puts ("Invalid handle");
|
|
Puth (h);
|
|
Putn();
|
|
return FALSE;
|
|
}
|
|
if (IsBadReadPtr (p, (WPARAM) min (UINT_MAX, GlobalSize(h))))
|
|
{
|
|
GlobalUnlock (h);
|
|
return FALSE;
|
|
}
|
|
GlobalUnlock (h);
|
|
return TRUE;
|
|
}
|
|
INTERNAL_(BOOL) wIsValidAtom (ATOM a)
|
|
{
|
|
WCHAR sz[MAX_STR];
|
|
if (a==0)
|
|
return TRUE;
|
|
if (a < 0xC000)
|
|
return FALSE;
|
|
if (0==GlobalGetAtomName (a, sz, MAX_STR))
|
|
return FALSE;
|
|
if ('\0'==sz[0])
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
// A "gentle" assert used in reterr.h
|
|
//
|
|
|
|
|
|
INTERNAL_(void) wWarn
|
|
(LPSTR sz,
|
|
LPSTR szFile,
|
|
int iLine)
|
|
{
|
|
intrDebugOut((DEB_WARN,
|
|
"Warning: %s:%u %s\n",
|
|
szFile,iLine,sz));
|
|
}
|
|
|
|
#endif // DBG
|
|
|
|
|