// Microsoft Corporation 1997 // This file contains methods for copying and releasing STGMEDIUMs and BINDINFOs // (which contains a STGMEDIUM). // Created: 8-15-97 t-gpease #include #undef URLMONOFFSETOF #define URLMONOFFSETOF(t,f) ((DWORD_PTR)(&((t*)0)->f)) // This function clears the BINDINFO structure. //- The "cbSize" will not be clear and will be the same as it // was pasted in. This is by design so that you can reuse the // BINDINFO (eg copy another BINDINFO into it). //- It does NOT release the memory that the BINDINFO oocupies // (this could be on the stack). //- It does properly release items that the BINDINFO might be // pointing to. STDAPI_(void) ReleaseBindInfo(BINDINFO * pbindinfo) { if ( !pbindinfo) return; DWORD cb = pbindinfo->cbSize; UrlMkAssert( cb && "CopyBindInfo(): cbSize of the BINDINFO is ZERO. We need the cbSize to be set before calling us."); if(!cb ) return; // we don't know which structure it is, so don't touch it. if (cb >= URLMONOFFSETOF(BINDINFO, dwReserved) && pbindinfo->pUnk) { pbindinfo->pUnk->Release(); } // Orginal BINDINFO no need to check size if (pbindinfo->szExtraInfo) { delete [] pbindinfo->szExtraInfo; } // Orginal BINDINFO no need to check size if (pbindinfo->szCustomVerb) { delete [] pbindinfo->szCustomVerb; } // Orginal BINDINFO no need to check size ReleaseStgMedium(&pbindinfo->stgmedData); // set this to zero so other function will not try to use the BINDINFO ZeroMemory(pbindinfo, cb); pbindinfo->cbSize = cb; // but keep this intact return; } // This function copies STGMEDIUM stuctures. //- Users need to allocate the memory that the STGMEDIUM Dest will be copied // into. //- If anything goes wrong, we return the proper HRESULT and STGMEDIUM.will // have been zero-ed. STDAPI CopyStgMedium(const STGMEDIUM * pcstgmedSrc, STGMEDIUM * pstgmedDest) { HRESULT hr = S_OK; if ( !pcstgmedSrc || !pstgmedDest ) return E_POINTER; ZeroMemory(pstgmedDest, sizeof(*pstgmedDest)); switch (pcstgmedSrc->tymed) { case TYMED_HGLOBAL: { void * pvDest; const void * pcvSrc; DWORD_PTR dwcbLen; HGLOBAL hGlobalDest; if (!pcstgmedSrc->hGlobal) break; // nothing to do hr = E_OUTOFMEMORY; pcvSrc = GlobalLock(pcstgmedSrc->hGlobal); if (!pcvSrc) goto Cleanup; dwcbLen = GlobalSize(pcstgmedSrc->hGlobal); // We can't do the following line: // hGlobalDest = GlobalAlloc((GMEM_MOVEABLE | GMEM_SHARE), dwcbLen); // because we hand out the bindinfo.stgmedData.hglobal to callers // that do NOT lock it and use the handle instead of the pointer. hGlobalDest = GlobalAlloc(GMEM_FIXED | GMEM_SHARE, dwcbLen); if (!hGlobalDest) { GlobalUnlock(pcstgmedSrc->hGlobal); goto Cleanup; } pvDest = GlobalLock(hGlobalDest); if (!pvDest) { GlobalFree(hGlobalDest); GlobalUnlock(pcstgmedSrc->hGlobal); goto Cleanup; } UrlMkAssert(dwcbLen>>32 == 0); memcpy(pvDest, pcvSrc, (unsigned long)dwcbLen); pstgmedDest->hGlobal = hGlobalDest; GlobalUnlock(hGlobalDest); GlobalUnlock(pcstgmedSrc->hGlobal); hr = S_OK; } break; case TYMED_FILE: { if (!pcstgmedSrc->lpszFileName) break; // nothing to do hr = E_OUTOFMEMORY; LPWSTR lpwstr = OLESTRDuplicate(pcstgmedSrc->lpszFileName); if (!lpwstr) goto Cleanup; pstgmedDest->lpszFileName = lpwstr; hr = S_OK; } break; case TYMED_ISTREAM: { pstgmedDest->pstm = pcstgmedSrc->pstm; if ( pstgmedDest->pstm ) pstgmedDest->pstm->AddRef(); } break; case TYMED_ISTORAGE: { pstgmedDest->pstg = pcstgmedSrc->pstg; if ( pstgmedDest->pstg ) pstgmedDest->pstg->AddRef(); } break; default: UrlMkAssert( !"CloneStgMedium has encountered a TYMED it doesn't know how to copy." ); // fall thru and copy it. case TYMED_NULL: // blindly copy case TYMED_GDI: // Just copy... memcpy(pstgmedDest, pcstgmedSrc, sizeof(*pstgmedDest)); break; } // Common things that can be copied if we get to this point. pstgmedDest->tymed = pcstgmedSrc->tymed; pstgmedDest->pUnkForRelease = pcstgmedSrc->pUnkForRelease; if (pstgmedDest->pUnkForRelease) (pstgmedDest->pUnkForRelease)->AddRef(); Cleanup: return hr; } // This function copies BINDINFO structures. // NOTE: IE4 added properties to the BINDINFO structure. This function // works with both versions. If the structure is extended in the // future, it will blindly copy the additional properties in the // structure. //- Users need to allocate the memory that the BINDINFO Dest will be copied // into. //- Users also need to set the "cbSize" of the BINDINFO Dest to // the sizeof(BINDINFO) before calling (see NOTE above). //- If there is a "cbSize" conflict between the Src and the Dest, we will: // 1) Src->cbSize = Dest->cbSize, normal copy. // 2) Src->cbSize > Dest->cbSize, copy as much info about the Src into // the Dest as will fit. // 3) Src->cbSize < Dest->cbSize, copy the Src into the Dest, Zero the // remaining unfilled portion of the Dest. //- We don't not copy the securityattribute. We clear this value of the // BINDINFO Dest. //- If anything goes wrong, we return the proper HRESULT and clear the // the BINDINFO structure using ReleaseBindInfo() (below). // NOTE: If "cbSize" of the Dest is ZERO, we don't do anything. STDAPI CopyBindInfo( const BINDINFO * pcbiSrc, BINDINFO *pbiDest ) { /****** 8-15-97 t-gpease Current structure at the time of writing... from URLMON.H typedef struct tagBINDINFO { ULONG cbSize; LPWSTR szExtraInfo; STGMEDIUM stgmedData; DWORD grfBindInfoF; DWORD dwBindVerb; LPWSTR szCustomVerb; DWORD cbstgmedData; // new part below this line // DWORD dwOptions; DWORD dwOptionsFlags; DWORD dwCodePage; SECURITY_ATTRIBUTES securityAttributes; IID iid; IUnknown __RPC_FAR *pUnk; DWORD dwReserved; } BINDINFO; Anything bigger than this we will blindly copy.the size of cbSize */ // NOTE: hr will an error until just before the Cleanup label. HRESULT hr = E_INVALIDARG; DWORD cbSrc; DWORD cbDst; if (!pcbiSrc || !pbiDest) return E_POINTER; cbSrc = pcbiSrc->cbSize; cbDst = pbiDest->cbSize; UrlMkAssert( cbSrc && "CopyBindInfo(): cbSize of the source is ZERO. You must set the cbSize."); UrlMkAssert( cbDst && "CopyBindInfo(): cbSize of the destination is ZERO. It needs to be set to the size of the BINDINFO before calling us."); if (!cbSrc || !cbDst) goto Abort; // nothing to do or can do. // Copy those bytes in common, zero the rest if any memcpy(pbiDest, pcbiSrc, min(cbSrc, cbDst)); pbiDest->cbSize = cbDst; // always keep this intact if (cbDst > cbSrc) { ZeroMemory((BYTE *)pbiDest + cbSrc, cbDst - cbSrc); } if (cbDst >= URLMONOFFSETOF(BINDINFO, dwReserved)) { ZeroMemory(&pbiDest->securityAttributes, sizeof(SECURITY_ATTRIBUTES)); } if (pcbiSrc->pUnk && cbDst >= URLMONOFFSETOF(BINDINFO, dwReserved)) { pbiDest->pUnk->AddRef(); } // NULL these anything fails we don't want to free the Sources resources. pbiDest->szExtraInfo = NULL; pbiDest->szCustomVerb = NULL; // Original BINDINFO no need to check size hr = CopyStgMedium( &pcbiSrc->stgmedData, &pbiDest->stgmedData ); if (hr) goto Cleanup; // Original BINDINFO no need to check size if (pcbiSrc->szExtraInfo) { LPWSTR lpwstr = OLESTRDuplicate(pcbiSrc->szExtraInfo); if (!lpwstr) { hr = E_OUTOFMEMORY; goto Cleanup; } pbiDest->szExtraInfo= lpwstr; } // Original BINDINFO no need to check size if (pcbiSrc->szCustomVerb) { LPWSTR lpwstr = OLESTRDuplicate(pcbiSrc->szCustomVerb); if (!lpwstr) { hr = E_OUTOFMEMORY; goto Cleanup; } pbiDest->szCustomVerb= lpwstr; } Cleanup: if (hr) { // This will set pbiDest members to zero so other function will not // try to use the new BINDINFO. ReleaseBindInfo( pbiDest ); } Abort: return(hr); }