diff options
Diffstat (limited to '')
-rw-r--r-- | private/ole32/com/remote/dde/server/ddeutils.cxx | 1015 |
1 files changed, 1015 insertions, 0 deletions
diff --git a/private/ole32/com/remote/dde/server/ddeutils.cxx b/private/ole32/com/remote/dde/server/ddeutils.cxx new file mode 100644 index 000000000..272a6a2f1 --- /dev/null +++ b/private/ole32/com/remote/dde/server/ddeutils.cxx @@ -0,0 +1,1015 @@ +/****************************** Module Header ******************************\ +* Module Name: ddeutils.c +* +* Purpose: Conatains all the utility routines +* +* Created: 1990 +* +* Copyright (c) 1990, 1991 Microsoft Corporation +* +* History: +* Raor, Srinik (../../1990) Designed and coded +* +\***************************************************************************/ +#include <windows.h> +#include "ole2int.h" +//#include "cmacs.h" +#include <dde.h> +#include "srvr.h" +#include "ddesrvr.h" +#include "ddedebug.h" +ASSERTDATA + + +#define WM_NCMOUSEFIRST WM_NCMOUSEMOVE +#define WM_NCMOUSELAST WM_NCMBUTTONDBLCLK + + + +#define KB_64 65536 + +extern ATOM aTrue; +extern ATOM aFalse; + +extern ATOM aStdCreateFromTemplate; +extern ATOM aStdCreate; +extern ATOM aStdOpen; +extern ATOM aStdEdit; +extern ATOM aStdShowItem; +extern ATOM aStdClose; +extern ATOM aStdExit; +extern ATOM aStdDoVerbItem; + + +//ScanBoolArg: scans the argument which is not included in +//the quotes. These args could be only TRUE or FALSE for +//the time being. !!!The scanning routines should be +//merged and it should be generalized. + +INTERNAL_(LPSTR) ScanBoolArg +( +LPSTR lpstr, +BOOL FAR *lpflag +) +{ + + + LPSTR lpbool; + ATOM aShow; + char ch; + + lpbool = lpstr; + + // !!! These routines does not take care of quoted quotes. + + while((ch = *lpstr) && (!(ch == ')' || ch == ','))) + lpstr++; + + if(ch == NULL) + return NULL; + + *lpstr++ = NULL; // terminate the arg by null + + // if terminated by paren, then check for end of command + // syntax. + + // Check for the end of the command string. + if (ch == ')') { + if (*lpstr++ != ']') + return NULL; + + if(*lpstr != NULL) + return NULL; //finally should be terminated by null. + + } + + aShow = GlobalFindAtomA (lpbool); + if (aShow == aTrue) + *lpflag = TRUE; + + else { + if (aShow ==aFalse) + *lpflag = FALSE; + else + return NULL;; + } + return lpstr; +} + + +//+--------------------------------------------------------------------------- +// +// Function: CreateUnicodeFromAnsi +// +// Synopsis: Creates a UNICODE string from an ANSI string +// +// Effects: Makes a new UNICODE string from the given ANSI string. +// The new UNICODE string is returned. Memory is allocated +// using PrivMemAlloc +// +// Arguments: [lpAnsi] -- Ansi version of string +// +// Requires: +// +// Returns: NULL if cannot create new string. +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: 6-07-94 kevinro Commented/cleaned +// +// Notes: +// +//---------------------------------------------------------------------------- +LPOLESTR CreateUnicodeFromAnsi( LPCSTR lpAnsi) +{ + WCHAR buf[MAX_PATH]; + ULONG ccbuf; + LPOLESTR lpWideStr; + + if ((ccbuf=MultiByteToWideChar(CP_ACP,0,lpAnsi,-1,buf,MAX_PATH)) + == FALSE) + { + intrAssert(!"Unable to convert characters"); + return NULL; + } + + lpWideStr = (LPOLESTR) PrivMemAlloc(ccbuf * sizeof(WCHAR)); + + if (lpWideStr != NULL) + { + memcpy(lpWideStr,buf,ccbuf*sizeof(WCHAR)); + } + return(lpWideStr); +} +//+--------------------------------------------------------------------------- +// +// Function: CreateAnsiFromUnicode +// +// Synopsis: Creates an Ansi string from a UNICODE string +// +// Effects: Makes a new ANSI string from the given UNICODE string. +// The new string is returned. Memory is allocated +// using PrivMemAlloc +// +// Arguments: [lpUnicode] -- Unicode version of string +// +// Requires: +// +// Returns: NULL if cannot create new string. +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: 6-07-94 kevinro Commented/cleaned +// +// Notes: +// +//---------------------------------------------------------------------------- +LPSTR CreateAnsiFromUnicode( LPCOLESTR lpUnicode) +{ + char buf[MAX_PATH]; + ULONG ccbuf; + LPSTR lpAnsiStr; + + ccbuf = WideCharToMultiByte(CP_ACP, + 0, + lpUnicode, + -1, + buf, + MAX_PATH, + NULL, + NULL); + + + if (ccbuf == FALSE) + { + intrAssert(!"Unable to convert characters"); + return NULL; + } + + lpAnsiStr = (LPSTR) PrivMemAlloc(ccbuf * sizeof(char)); + + if (lpAnsiStr != NULL) + { + memcpy(lpAnsiStr,buf,ccbuf); + } + return(lpAnsiStr); +} + +//ScannumArg: Checks for the syntax of num arg in Execute and if +//the arg is syntactically correct, returns the ptr to the +//beginning of the next arg and also, returns the number +//Does not take care of the last num arg in the list. + +INTERNAL_(LPSTR) ScanNumArg +( +LPSTR lpstr, +LPINT lpnum +) +{ + + WORD val = 0; + char ch; + + while((ch = *lpstr++) && (ch != ',')) { + if (ch < '0' || ch >'9') + return NULL; + val += val * 10 + (ch - '0'); + + } + + if(!ch) + return NULL; + + *lpnum = val; + return lpstr; +} + + + + +//ScanArg: Checks for the syntax of arg in Execute and if +//the arg is syntactically correct, returns the ptr to the +//beginning of the next arg or to the end of the excute string. + +INTERNAL_(LPSTR) ScanArg +( +LPSTR lpstr +) +{ + + + // !!! These routines does not take care of quoted quotes. + + // first char should be quote. + + if (*(lpstr-1) != '\"') + return NULL; + + while(*lpstr && *lpstr != '\"') + lpstr++; + + if(*lpstr == NULL) + return NULL; + + *lpstr++ = NULL; // terminate the arg by null + + if(!(*lpstr == ',' || *lpstr == ')')) + return NULL; + + + if(*lpstr++ == ','){ + + if(*lpstr == '\"') + return ++lpstr; + // If it is not quote, leave the ptr on the first char + return lpstr; + } + + // terminated by paren + // already skiped right paren + + // Check for the end of the command string. + if (*lpstr++ != ']') + return NULL; + + if(*lpstr != NULL) + return NULL; //finally should be terminated by null. + + return lpstr; +} + +// ScanCommand: scanns the command string for the syntax +// correctness. If syntactically correct, returns the ptr +// to the first arg or to the end of the string. + +INTERNAL_(WORD) ScanCommand +( +LPSTR lpstr, +WORD wType, +LPSTR FAR * lplpnextcmd, +ATOM FAR * lpAtom +) +{ + // !!! These routines does not take care of quoted quotes. + // and not taking care of blanks arround the operators + + // !!! We are not allowing blanks after operators. + // Should be allright! since this is arestricted syntax. + + char ch; + LPSTR lptemp = lpstr; + + + while(*lpstr && (!(*lpstr == '(' || *lpstr == ']'))) + lpstr++; + + if(*lpstr == NULL) + return NULL; + + ch = *lpstr; + *lpstr++ = NULL; // set the end of command + + *lpAtom = GlobalFindAtomA (lptemp); + + if (!IsOleCommand (*lpAtom, wType)) + return NON_OLE_COMMAND; + + if (ch == '(') { + ch = *lpstr++; + + if (ch == ')') { + if (*lpstr++ != ']') + return NULL; + } + else { + if (ch != '\"') + return NULL; + } + + *lplpnextcmd = lpstr; + return OLE_COMMAND; + } + + // terminated by ']' + + if (*(*lplpnextcmd = lpstr)) // if no nul termination, then it is error. + return NULL; + + return OLE_COMMAND; +} + + +//MakeDataAtom: Creates a data atom from the item string +//and the item data otions. + +INTERNAL_(ATOM) MakeDataAtom +( +ATOM aItem, +int options +) +{ + WCHAR buf[MAX_STR]; + + if (options == OLE_CHANGED) + return DuplicateAtom (aItem); + + if (!aItem) + buf[0] = NULL; + else + GlobalGetAtomName (aItem, buf, MAX_STR); + + if (options == OLE_CLOSED) + lstrcatW (buf, OLESTR("/Close")); + else { + if (options == OLE_SAVED) + lstrcatW (buf, OLESTR("/Save")); + else + AssertSz (0, "Bad option\n"); + } + + Puts ("MakeDataAtom "); Puts(buf); Putn(); + if (buf[0]) + return wGlobalAddAtom (buf); + else + return NULL; +} + +//DuplicateAtom: Duplicates an atom +INTERNAL_(ATOM) DuplicateAtom +( +ATOM atom +) +{ + WCHAR buf[MAX_STR]; + + if (!atom) + return NULL; + + GlobalGetAtomName (atom, buf, MAX_STR); + return wGlobalAddAtom (buf); +} + +// MakeGlobal: makes global out of strings. +// works only for << 64k + +INTERNAL_(HANDLE) MakeGlobal +( +LPSTR lpstr +) +{ + + int len = 0; + HANDLE hdata = NULL; + LPSTR lpdata = NULL; + + len = strlen (lpstr) + 1; + + hdata = GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE, len); + + if (hdata == NULL || (lpdata = (LPSTR) GlobalLock (hdata)) == NULL) + goto errRtn; + + + memcpy(lpdata, lpstr, (DWORD)len); + GlobalUnlock (hdata); + return hdata; + +errRtn: + Assert (0); + if (lpdata) + GlobalUnlock (hdata); + + + if (hdata) + GlobalFree (hdata); + + return NULL; + +} + + +INTERNAL_(BOOL) CLSIDFromAtom(ATOM aClass, LPCLSID lpclsid) +{ + WCHAR szProgID[MAX_STR]; + if (!ISATOM (aClass)) + return FALSE; + WORD cb=GlobalGetAtomName (aClass, szProgID, MAX_STR); + Assert (cb>0 && cb < (MAX_STR - 1)); + + return CLSIDFromProgID(szProgID, lpclsid) == S_OK; +} + +// CLSIDFromAtomWithTreatAs +// +// Input: *paClass +// Output: *pclsid == corresponding CLSID, taking into account TreatAs and +// AutoConvert +// *paClass == atom correpsonding to *pclsid +// +#pragma SEG(CLSIDFromAtomWithTreatAs) +INTERNAL CLSIDFromAtomWithTreatAs + (ATOM FAR* paClass, + LPCLSID pclsid, + CNVTYP FAR* pcnvtyp) +{ + HRESULT hr; + + + intrDebugOut((DEB_ITRACE, + "%p _IN CLSIDFromAtomWithTreatAs(paClass=%x," + "pclsid=%x,pcnvtyp=%x)\n",0, + paClass,pclsid,pcnvtyp)); + + LPOLESTR szProgID = NULL; + CLSID clsidNew; + + if (!CLSIDFromAtom (*paClass, pclsid)) + { + hr = S_FALSE; + goto exitRtn; + } + + DEBUG_GUIDSTR(clsidStr,pclsid); + + intrDebugOut((DEB_ITRACE,"Guid %ws",clsidStr)); + if (CoGetTreatAsClass (*pclsid, &clsidNew) == NOERROR) + { + DEBUG_GUIDSTR(newStr,pclsid); + + intrDebugOut((DEB_ITRACE," cnvtypTreatAs %ws\n",newStr)); + if (pcnvtyp) + *pcnvtyp = cnvtypTreatAs; + } + else if (OleGetAutoConvert (*pclsid, &clsidNew) == NOERROR) + { + DEBUG_GUIDSTR(newStr,pclsid); + intrDebugOut((DEB_ITRACE," cnvtypConvertTo %ws\n",newStr)); + if (pcnvtyp) + *pcnvtyp = cnvtypConvertTo; + } + else + { + intrDebugOut((DEB_ITRACE," no conversion\n")); + if (pcnvtyp) + *pcnvtyp = cnvtypNone; + clsidNew = *pclsid; // no translation + } + + hr = ProgIDFromCLSID(clsidNew, &szProgID); + if (FAILED(hr)) + { + intrDebugOut((DEB_ITRACE," ProgIDFromCLSID failed\n")); + goto exitRtn; + } + + intrDebugOut((DEB_ITRACE,"ProgIDFromCLSID returns %ws\n",szProgID)); + *paClass = GlobalAddAtom (szProgID); + *pclsid = clsidNew; + CoTaskMemFree(szProgID); + +exitRtn: + intrDebugOut((DEB_ITRACE, + "%p OUT CLSIDFromAtomWithTreatAs returns %x\n", + 0,hr)); + + return hr; +} + + +INTERNAL_(BOOL) PostMessageToClientWithReply +( +HWND hWnd, +UINT wMsg, +WPARAM wParam, // posting window +LPARAM lParam, +UINT wReplyMsg +) +{ + MSG msg; + + if (!IsWindowValid (hWnd)) + { + AssertSz(FALSE, "Client's window is missing"); + return FALSE; + } + + if (!IsWindowValid ((HWND)wParam)) + { + AssertSz (0, "Posting window is invalid"); + return FALSE; + } + + // Post message to client failed. Treat it as if we got the reply. + if (!PostMessageToClient (hWnd, wMsg, wParam, lParam)) + return FALSE; + + return NOERROR == wTimedGetMessage (&msg, (HWND)wParam, WM_DDE_TERMINATE, + WM_DDE_TERMINATE); +} + + + +INTERNAL_(BOOL) PostMessageToClient +( + HWND hWnd, + UINT wMsg, + WPARAM wParam, + LPARAM lParam +) +{ + UINT c=0; + + while (c < 10) + { + if (!IsWindowValid (hWnd)) { + Warn ("Client's window is missing"); + return FALSE; + } + Puts ("Posting"); Puth(wMsg); Puts("to"); Puth(hWnd); Putn(); + if (PostMessage (hWnd, wMsg, wParam, lParam)) + return TRUE; // success + else + { + Yield(); + c++; // try again + } + } + return FALSE; +} + + +INTERNAL_(BOOL) IsWindowValid + (HWND hwnd) +{ + HTASK htask; + + if (!IsWindow (hwnd)) + return FALSE; + + htask = GetWindowThreadProcessId(hwnd, NULL); + +#ifndef WIN32 + if (IsTask(htask)) +#endif + return TRUE; + + return FALSE; +} + + + +INTERNAL_(BOOL) UtilQueryProtocol +( +ATOM aClass, +LPOLESTR lpprotocol +) +{ + HKEY hKey; + WCHAR key[MAX_STR]; + WCHAR cclass[MAX_STR]; + + if (!aClass) + return FALSE; + + if (!GlobalGetAtomName (aClass, cclass, MAX_STR)) + return FALSE; + + lstrcpyW (key, cclass); + lstrcatW (key, OLESTR("\\protocol\\")); + lstrcatW (key, lpprotocol); + lstrcatW (key, OLESTR("\\server")); + if (RegOpenKey (HKEY_CLASSES_ROOT, key, &hKey) != ERROR_SUCCESS) + return FALSE; + RegCloseKey (hKey); + return TRUE; +} + + + +INTERNAL_(BOOL) IsOleCommand +( +ATOM aCmd, +WORD wType +) +{ + if (wType == WT_SRVR) { + if ((aCmd == aStdCreateFromTemplate) + || (aCmd == aStdCreate) + || (aCmd == aStdOpen) + || (aCmd == aStdEdit) + || (aCmd == aStdShowItem) + || (aCmd == aStdClose) + || (aCmd == aStdExit)) + return TRUE; + } + else { + if ((aCmd == aStdClose) + || (aCmd == aStdDoVerbItem) + || (aCmd == aStdShowItem)) + return TRUE; + } + + return FALSE; +} +INTERNAL wFileBind + (LPOLESTR szFile, + LPUNKNOWN FAR* ppUnk) +{ + HRESULT hresult = NOERROR; + LPBC pbc = NULL; + LPMONIKER pmk = NULL; + *ppUnk = NULL; + ErrRtnH (CreateBindCtx (0, &pbc)); + ErrRtnH (CreateFileMoniker (szFile, &pmk)); + ErrRtnH (pmk->BindToObject (pbc, NULL, IID_IUnknown, (LPLPVOID) ppUnk)); + errRtn: +// AssertOutPtrIface(hresult, *ppUnk); + if (pbc) + pbc->Release(); + if (pmk) + pmk->Release(); + return hresult; +} + +// SynchronousPostMessage +// +// Post a message and wait for the ack. +// (jasonful) +// +INTERNAL SynchronousPostMessage + (HWND hWndTo, // also who you expect the reply from + UINT wMsg, + WPARAM wParam, + LPARAM lParam) +{ +#ifdef _MAC +#else + + HRESULT hresult = NOERROR; + + static unsigned iCounter; + + + HWND hWndFrom = (HWND) wParam; + + + + RetZ (IsWindowValid(hWndFrom)); + RetZ (IsWindowValid(hWndTo)); + + Assert (wMsg != WM_DDE_INITIATE); // can't check for positive ack. + + RetZS (PostMessage (hWndTo, wMsg, wParam, lParam), RPC_E_SERVER_DIED); + + MSG msg; + RetErr (wTimedGetMessage (&msg, hWndFrom, WM_DDE_ACK, WM_DDE_ACK)); + Assert (msg.message == WM_DDE_ACK); + if (!( GET_WM_DDE_ACK_STATUS(msg.wParam,msg.lParam) & POSITIVE_ACK)) + hresult = ResultFromScode (RPC_E_DDE_NACK); + if (msg.hwnd != hWndFrom) + hresult = ResultFromScode (RPC_E_DDE_UNEXP_MSG); + + + + return hresult; +#endif _MAC +} + + +INTERNAL wFileIsRunning + (LPOLESTR szFile) +{ + LPMONIKER pmk = NULL; + LPBINDCTX pbc=NULL; + HRESULT hresult; + + RetErr (CreateBindCtx (0, &pbc)); + ErrRtnH (CreateFileMoniker (szFile, &pmk)); + hresult = pmk->IsRunning (pbc, NULL, NULL); + errRtn: + if (pbc) + pbc->Release(); + if (pmk) + pmk->Release(); + return hresult; +} + + + + +//+--------------------------------------------------------------------------- +// +// Function: IsFile +// +// Synopsis: Given a handle to an atom, determine if it is a file +// +// Effects: Attempts to get the files attributes. If there are no +// attributes, then the file doesn't exist. +// +// Arguments: [a] -- Atom for filename +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: 5-03-94 kevinro Commented/cleaned +// +// Notes: +// +//---------------------------------------------------------------------------- +INTERNAL_ (BOOL) IsFile + (ATOM a, BOOL FAR* pfUnsavedDoc) +{ + LPMONIKER pmk = NULL; + LPBC pbc = NULL; + LPRUNNINGOBJECTTABLE pROT=NULL; + + WCHAR szFile [MAX_STR]; + if (0==GlobalGetAtomName (a, szFile, MAX_STR)) + return FALSE; + + DWORD dwAttribs = GetFileAttributes(szFile); + + /* flags prevent sharing violation*/ + if (dwAttribs != 0xFFFFFFFF) + { + if (pfUnsavedDoc) + *pfUnsavedDoc = FALSE; + return TRUE; + } + // This will deal with unsaved documents in the ROT. + // We do NOT want to call pmk->IsRunning because if a 2.0 client called + // DdeIsRunning, we do not want call it here, because then we get stuck + // in an infinite loop. We only care about true 2.0 running objects. + + + // + // BUGBUG: KevinRo There is a function (GetPathFromRot) that could replace + // the following code sequence. + // + + BOOL f= NOERROR==CreateBindCtx (0, &pbc) && + NOERROR==CreateFileMoniker (szFile, &pmk) && + NOERROR==pbc->GetRunningObjectTable (&pROT) && + NOERROR==pROT->IsRunning (pmk) ; + if (pROT) + pROT->Release(); + if (pmk) + pmk->Release(); + if (pbc) + pbc->Release(); + if (pfUnsavedDoc) + *pfUnsavedDoc = TRUE; + return f; + + +} + +// wCompatibleClasses +// +// Determine if class "aClient" is Auto-Converted to class "aSrvr" or +// Treated-As class "aSrvr". +// (Does not check if aClient==aSrvr) +// +#pragma SEG(wCompatibleClasses) +INTERNAL wCompatibleClasses + (ATOM aClient, + ATOM aSrvr) +{ + CLSID clsidClient, clsidSrvr, clsidTo; + HRESULT hresult; + RetZS (CLSIDFromAtom (aClient, &clsidClient), S_FALSE); + RetZS (CLSIDFromAtom (aSrvr, &clsidSrvr ), S_FALSE); + if (NOERROR==OleGetAutoConvert (clsidClient, &clsidTo) + && clsidTo == clsidSrvr) + { + // aClient is Auto-Converted to aSrvr + return NOERROR; + } + hresult = CoGetTreatAsClass(clsidClient, &clsidTo); + if (hresult != NOERROR) + { + intrDebugOut((DEB_IERROR, + "wCompatibleClasses CoGetTreatAs returns %x\n", + hresult)); + return(hresult); + } + + if (clsidTo == clsidSrvr) + { + // aClient is Treated-As aSrvr + return NOERROR; + } + return ResultFromScode (S_FALSE); // not compatible +} + + + +// wCreateStgAroundNative +// +// Build an OLE2 storage around 1.0 native data by putting it in +// stream "\1Ole10Native" and creating valid CompObj and OLE streams. +// Return the IStorage and the ILockBytes it is built on. +// +INTERNAL wCreateStgAroundNative + (HANDLE hNative, + ATOM aClassOld, + ATOM aClassNew, + CNVTYP cnvtyp, + ATOM aItem, + LPSTORAGE FAR* ppstg, + LPLOCKBYTES FAR* pplkbyt) +{ + HRESULT hresult; + LPSTORAGE pstg = NULL; + LPLOCKBYTES plkbyt = NULL; + LPOLESTR szUserType = NULL; + WCHAR szClassOld [256]; + CLSID clsid; + ATOM aClass; + *ppstg = NULL; + + intrDebugOut((DEB_ITRACE, + "%p wCreateStgAroundNative(hNative=%x,aClassOld=%x" + ",aClassNew=%x cnvtyp=%x,aItem=%x)\n", + 0,hNative,aClassOld,aClassNew,cnvtyp,aItem)); + + // Create temporary docfile on our ILockBytes + ErrRtnH (CreateILockBytesOnHGlobal (NULL,/*fDeleteOnRelease*/TRUE,&plkbyt)); + + Assert (plkbyt); + + ErrRtnH (StgCreateDocfileOnILockBytes (plkbyt, grfCreateStg, 0, &pstg)); + + RetZ (pstg); + Assert (NOERROR==StgIsStorageILockBytes(plkbyt)); + + aClass = (cnvtyp == cnvtypConvertTo)?aClassNew:aClassOld; + + if (CLSIDFromAtom (aClass,(LPCLSID)&clsid) == FALSE) + { + hresult = REGDB_E_CLASSNOTREG; + goto errRtn; + } + + ErrRtnH (WriteClassStg (pstg, clsid)); + + // The UserType always corresponds to the clsid. + ErrRtnH (OleRegGetUserType (clsid, USERCLASSTYPE_FULL, &szUserType)); + + // The format is always the 1.0 format (classname/progid) + ErrZS (GlobalGetAtomName (aClassOld, szClassOld, 256), E_UNEXPECTED); + + ErrRtnH (WriteFmtUserTypeStg (pstg, RegisterClipboardFormat(szClassOld), + szUserType)); + + + if (cnvtyp == cnvtypConvertTo) + { + // SetConvertStg also writes a complete default Ole Stream + ErrRtnH (SetConvertStg (pstg, TRUE)); + } + else + { + ErrRtnH (WriteOleStg (pstg, NULL, (CLIPFORMAT)0, NULL)); + } + ErrRtnH (StSave10NativeData (pstg, hNative, FALSE)); + if (aItem) + { + ErrRtnH (StSave10ItemName (pstg, wAtomNameA (aItem))); + } + *ppstg = pstg; + *pplkbyt = plkbyt; + return NOERROR; + + errRtn: + if (pstg) + pstg->Release(); + if (plkbyt) + plkbyt->Release(); + CoTaskMemFree(szUserType); + return hresult; +} + + +#ifdef _DEBUG + + +INTERNAL_ (BOOL) IsAtom (ATOM a) +{ + WCHAR sz[256]= {0}; + if (a < 0xc000) + return FALSE; + WORD cb=GlobalGetAtomName (a, sz, 256); + Assert (lstrlenW(sz) == (int) cb); + return cb>0 && cb < MAX_STR; +} + + +#include <limits.h> +#undef GlobalFree + + + + +INTERNAL_(HANDLE) wGlobalFree (HANDLE h) +{ + LPVOID p; + Assert ((GlobalFlags(h) & GMEM_LOCKCOUNT)==0); + if (!(p=GlobalLock(h))) + { + Puts ("Cannot free handle"); + Puth (h); + Putn(); + AssertSz(0, "Invalid Handle\r\n"); + } + Assert (!IsBadReadPtr (p, (UINT) min (UINT_MAX, GlobalSize(h)))); + Assert (GlobalUnlock(h)==0); + Verify (!GlobalFree (h)); + Puts ("FREEING "); + Puth (h); + Putn (); + return NULL; // success +} + + + +#undef GlobalDeleteAtom + +INTERNAL_(ATOM) wGlobalDeleteAtom (ATOM a) +{ + WCHAR sz[256]; + Assert (0 != GlobalGetAtomName (a, sz, 256)); + Assert (0==GlobalDeleteAtom (a)); + return (ATOM)0; +} + +INTERNAL_(int) wCountChildren + (HWND h) +{ + int c = 0; + HWND hwndChild = GetWindow (h, GW_CHILD); + while (hwndChild) + { + c++; + hwndChild = GetWindow (hwndChild, GW_HWNDNEXT); + } + return c; +} + + +#endif // _DEBUG |