diff options
Diffstat (limited to 'private/ole32/ole232/util')
-rw-r--r-- | private/ole32/ole232/util/convert.cpp | 1209 | ||||
-rw-r--r-- | private/ole32/ole232/util/daytona/makefile | 10 | ||||
-rw-r--r-- | private/ole32/ole232/util/daytona/sources | 83 | ||||
-rw-r--r-- | private/ole32/ole232/util/depend.mk | 237 | ||||
-rw-r--r-- | private/ole32/ole232/util/dirs | 38 | ||||
-rw-r--r-- | private/ole32/ole232/util/filelist.mk | 54 | ||||
-rw-r--r-- | private/ole32/ole232/util/global.cpp | 821 | ||||
-rw-r--r-- | private/ole32/ole232/util/info.cpp | 65 | ||||
-rw-r--r-- | private/ole32/ole232/util/makefile | 26 | ||||
-rw-r--r-- | private/ole32/ole232/util/map_kv.cpp | 666 | ||||
-rw-r--r-- | private/ole32/ole232/util/ole2util.cpp | 1105 | ||||
-rw-r--r-- | private/ole32/ole232/util/plex.cpp | 53 | ||||
-rw-r--r-- | private/ole32/ole232/util/utils.cpp | 2726 | ||||
-rw-r--r-- | private/ole32/ole232/util/utstream.cpp | 986 |
14 files changed, 8079 insertions, 0 deletions
diff --git a/private/ole32/ole232/util/convert.cpp b/private/ole32/ole232/util/convert.cpp new file mode 100644 index 000000000..cb79c8279 --- /dev/null +++ b/private/ole32/ole232/util/convert.cpp @@ -0,0 +1,1209 @@ + +//+---------------------------------------------------------------------------- +// +// File: +// convert.cpp +// +// Contents: +// This module contains the code to read/write DIB, metafile, +// placeable metafiles, olepres stream, etc... This module also +// contains routines for converting from one format to other. +// +// Classes: +// +// Functions: +// +// History: +// 15-Feb-94 alexgo fixed a bug in loading placeable metafiles +// from a storage (incorrect size calculation). +// 25-Jan-94 alexgo first pass at converting to Cairo-style +// memory allocations. +// 01/11/93 - alexgo - added VDATEHEAP macros to every function +// 12/08/93 - ChrisWe - fixed wPrepareBitmapHeader not to use +// (LPOLESTR) cast +// 12/07/93 - ChrisWe - make default params to StSetSize explicit +// 12/02/93 - ChrisWe - more formatting; fixed UtHMFToMFStm, +// 32 bit version, which was doing questionable things +// with the hBits handle; got rid of the OLESTR +// uses in favor of (void *) or (BYTE *) as appropriate +// 11/29/93 - ChrisWe - move CONVERT_SOURCEISICON, returned +// by UtOlePresStmToContentsStm(), to utils.h +// 11/28/93 - ChrisWe - begin file inspection and cleanup +// 06/28/93 - SriniK - created +// +//----------------------------------------------------------------------------- + +#include <le2int.h> + +#pragma SEG(ole2) + +NAME_SEG(convert) +ASSERTDATA + +#ifndef _MAC +FARINTERNAL_(HMETAFILE) QD2GDI(HANDLE hBits); +#endif + +void UtGetHEMFFromContentsStm(LPSTREAM lpstm, HANDLE * phdata); + + +/************************ FILE FORMATS ********************************** + +Normal Metafile (memory or disk based): + + ------------ --------------- + | METAHEADER | Metafile bits | + ------------ --------------- + +Placeable Metafile: + + --------------------- ----------------- + | PLACEABLEMETAHEADER | Normal metafile | + --------------------- ----------------- + +Memory Based DIB: + + ------------------ --------------- ---------- + | BITMAPINFOHEADER | RGBQUAD array | DIB bits | + ------------------ --------------- ---------- + +DIB file format: + + ------------------ ------------------ + | BITMAPFILEHEADER | Memory based DIB | + ------------------ ------------------ + +Ole10NativeStream Format: + + -------- ---------------------- + | dwSize | Object's Native data | + -------- ---------------------- + +PBrush Native data format: + + ----------------- + | Dib File format | + ----------------- + +MSDraw Native data format: + + --------------------- ------------- ------------- ----------------- + | mapping mode (WORD) | xExt (WORD) | yExt (WORD) | Normal metafile | + --------------------- ------------- ------------- ----------------- + +*****************************************************************************/ + + +FARINTERNAL UtGetHGLOBALFromStm(LPSTREAM lpstream, DWORD dwSize, + HANDLE FAR* lphPres) +{ + VDATEHEAP(); + + HANDLE hBits = NULL; + void FAR *lpBits = NULL; + HRESULT error; + + // initialize this for error return cases + *lphPres = NULL; + + // allocate a new handle + if (!(hBits = GlobalAlloc(GMEM_MOVEABLE, dwSize)) + || !(lpBits = (BYTE *)GlobalLock(hBits))) + { + error = ResultFromScode(E_OUTOFMEMORY); + goto errRtn; + } + + // read the stream into the allocated memory + if (error = StRead(lpstream, lpBits, dwSize)) + goto errRtn; + + // if we got this far, return new handle + *lphPres = hBits; + +errRtn: + // unlock the handle, if it was successfully locked + if (lpBits) + GlobalUnlock(hBits); + + // free the handle if there was an error + if ((error != NOERROR) && hBits) + GlobalFree(hBits); + + return(error); +} + + +#ifndef _MAC + +FARINTERNAL UtGetHDIBFromDIBFileStm(LPSTREAM pstm, HANDLE FAR* lphdata) +{ + VDATEHEAP(); + + BITMAPFILEHEADER bfh; + DWORD dwSize; // the size of the data to read + HRESULT error; + + // read the bitmap file header + if (error = pstm->Read(&bfh, sizeof(BITMAPFILEHEADER), NULL)) + { + *lphdata = NULL; + return(error); + } + + // calculate the size of the DIB to read + dwSize = bfh.bfSize - sizeof(BITMAPFILEHEADER); + + // read the DIB + return(UtGetHGLOBALFromStm(pstm, dwSize, lphdata)); +} + + +FARINTERNAL_(HANDLE) UtGetHMFPICT(HMETAFILE hMF, BOOL fDeleteOnError, + DWORD xExt, DWORD yExt) +{ + VDATEHEAP(); + + HANDLE hmfp; // handle to the new METAFILEPICT + LPMETAFILEPICT lpmfp; // pointer to the new METAFILEPICT + + // if no METAFILE, nothing to do + if (hMF == NULL) + return(NULL); + + // allocate a new handle + if (!(hmfp = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT)))) + goto errRtn; + + // lock the handle + if (!(lpmfp = (LPMETAFILEPICT)GlobalLock(hmfp))) + goto errRtn; + + // make the METAFILEPICT + lpmfp->hMF = hMF; + lpmfp->xExt = (int)xExt; + lpmfp->yExt = (int)yExt; + lpmfp->mm = MM_ANISOTROPIC; + + GlobalUnlock(hmfp); + return(hmfp); + +errRtn: + if (hmfp) + GlobalFree(hmfp); + + if (fDeleteOnError) + DeleteMetaFile(hMF); + + return(NULL); +} + +#endif // _MAC + +//+------------------------------------------------------------------------- +// +// Function: UtGetHMFFromMFStm +// +// Synopsis: +// +// Effects: +// +// Arguments: [lpstream] -- stream containing metafile or PICT +// [dwSize] -- data size within stream +// [fConvert] -- FALSE for metafile, TRUE for PICT +// [lphPres] -- placeholder for output metafile +// +// Requires: lpstream positioned at start of data +// +// Returns: HRESULT +// +// Modifies: +// +// Algorithm: +// +// History: 29-Apr-94 AlexT Add comment block, enabled Mac conversion +// +// Notes: +// +//-------------------------------------------------------------------------- + +FARINTERNAL UtGetHMFFromMFStm(LPSTREAM lpstream, DWORD dwSize, + BOOL fConvert, HANDLE FAR* lphPres) +{ +#ifdef WIN32 + LEDebugOut((DEB_ITRACE, "%p _IN UtGetHMFFromMFStm (%p, %d, %d, %p)\n", + NULL, lpstream, dwSize, fConvert, lphPres)); + + VDATEHEAP(); + + BYTE *pbMFData = NULL; + HRESULT hrError; + + // initialize this in case of error return + *lphPres = NULL; + + // allocate a global handle for the data (since QD2GDI needs a + // handle) + + pbMFData = (BYTE *) GlobalAlloc(GMEM_FIXED, dwSize); + if (NULL == pbMFData) + { + hrError = ResultFromScode(E_OUTOFMEMORY); + goto errRtn; + } + + // read the stream into the bit storage + + ULONG cbRead; + hrError = lpstream->Read(pbMFData, dwSize, &cbRead); + if (FAILED(hrError)) + { + return(hrError); + } + // hrError = StRead(lpstream, pbMFData, dwSize); + + if (hrError != NOERROR) + { + goto errRtn; + } + + if (fConvert) + { + // It's a Mac PICT + *lphPres = QD2GDI((HGLOBAL) pbMFData); + } + else + { + // It's a Windows metafile + *lphPres = SetMetaFileBitsEx(dwSize, pbMFData); + } + + if (*lphPres == NULL) + hrError = ResultFromScode(E_OUTOFMEMORY); + +errRtn: + if (NULL != pbMFData) + { + GlobalFree(pbMFData); + } + + LEDebugOut((DEB_ITRACE, "%p OUT UtGetHMFFromMFStm ( %lx ) [ %p ]\n", + NULL, hrError, *lphPres)); + + return(hrError); +#else + HANDLE hBits; // handle to the new METAFILE + void FAR* lpBits = NULL; + HRESULT error; + + // initialize this in case of error return + *lphPres = NULL; + + // allocate a new handle, and lock the bits + if (!(hBits = GlobalAlloc(GMEM_MOVEABLE, dwSize)) + || !(lpBits = GlobalLock(hBits))) + { + error = ResultFromScode(E_OUTOFMEMORY); + goto errRtn; + } + + // read the stream into the bit storage + error = StRead(lpstream, lpBits, dwSize); + GlobalUnlock(hBits); + + if (error) + goto errRtn; + + if (!fConvert) + *lphPres = SetMetaFileBits(hBits); + else + { + if (*lphPres = QD2GDI(hBits)) + { + // Need to free this handle upon success + GlobalFree(hBits); + hBits = NULL; + } + + } + + if (!*lphPres) + error = ResultFromScode(E_OUTOFMEMORY); + +errRtn: + if (error && hBits) + GlobalFree(hBits); + return(error); +#endif // WIN32 +} + + +FARINTERNAL UtGetSizeAndExtentsFromPlaceableMFStm(LPSTREAM pstm, + DWORD FAR* pdwSize, LONG FAR* plWidth, LONG FAR* plHeight) +{ + VDATEHEAP(); + + HRESULT error; + LARGE_INTEGER large_int; // used to set the seek pointer + ULARGE_INTEGER ularge_int; // retrieves the new seek position + LONG xExt; // the x extent of the metafile + LONG yExt; // the y extent of the metafile + METAHEADER mfh; + PLACEABLEMETAHEADER plac_mfh; + + // read the placeable metafile header + if (error = pstm->Read(&plac_mfh, sizeof(plac_mfh), NULL)) + return(error); + + // check the magic number in the header + if (plac_mfh.key != PMF_KEY) + return ResultFromScode(E_FAIL); + + // remember the seek pointer + LISet32(large_int, 0); + if (error = pstm->Seek(large_int, STREAM_SEEK_CUR, &ularge_int)) + return(error); + + // read metafile header + if (error = pstm->Read(&mfh, sizeof(mfh), NULL)) + return(error); + + // seek back to the begining of metafile header + LISet32(large_int, ularge_int.LowPart); + if (error = pstm->Seek(large_int, STREAM_SEEK_SET, NULL)) + return(error); + + // calculate the extents of the metafile + xExt = (plac_mfh.bbox.right - plac_mfh.bbox.left);// metafile units + yExt = (plac_mfh.bbox.bottom - plac_mfh.bbox.top);// metafile units + + // REVIEW, why aren't there constants for this? + xExt = (xExt * 2540) / plac_mfh.inch; // HIMETRIC units + yExt = (yExt * 2540) / plac_mfh.inch; // HIMETRIC units + + if (pdwSize) + { +#ifdef WIN16 + //this code seems to work OK on Win16 + *pdwSize = 2 * (mfh.mtSize + mfh.mtHeaderSize); + // REVIEW NT: review METAHEADER +#else //WIN32 + //mt.Size is the size in words of the metafile. + //this fixes bug 6739 (static objects can't be copied + //or loaded from a file). + *pdwSize = sizeof(WORD) * mfh.mtSize; +#endif //WIN16 + } + + if (plWidth) + *plWidth = xExt; + + if (plHeight) + *plHeight = yExt; + + return NOERROR; +} + + +FARINTERNAL UtGetHMFPICTFromPlaceableMFStm(LPSTREAM pstm, HANDLE FAR* lphdata) +{ + VDATEHEAP(); + + HRESULT error; // error state so far + DWORD dwSize; // size of the METAFILE we have to read from the stream + LONG xExt; // x extent of the METAFILE we have to read from the stream + LONG yExt; // y extent of the METAFILE we have to read from the stream + HMETAFILE hMF; // handle to the METAFILE read from the stream + + if (lphdata == NULL) + return ResultFromScode(E_INVALIDARG); + + // initialize this in case of error return + *lphdata = NULL; + + // get the size of the METAFILE + if (error = UtGetSizeAndExtentsFromPlaceableMFStm(pstm, &dwSize, + &xExt, &yExt)) + return(error); + + // fetch the METAFILE + if (error = UtGetHMFFromMFStm(pstm, dwSize, FALSE /*fConvert*/, + (HANDLE FAR *)&hMF)) + return(error); + + // convert to a METAFILEPICT + if (!(*lphdata = UtGetHMFPICT(hMF, TRUE /*fDeleteOnError*/, xExt, + yExt))) + return ResultFromScode(E_OUTOFMEMORY); + + return NOERROR; +} + + + +/****************************************************************************/ +/***************** Write routines *********************/ +/****************************************************************************/ + +#ifndef _MAC + + +//+---------------------------------------------------------------------------- +// +// Function: +// wPrepareBitmapHeader, static +// +// Synopsis: +// Initializes the content of a BITMAPFILEHEADER +// +// Arguments: +// [lpbfh] -- pointer to the BITMAPFILEHEADER to initialize +// [dwSize] -- the size of the file; obtained by dividing +// the size of the file by 4 (see win32 documentation.) +// +// History: +// 12/08/93 - ChrisWe - made static +// +//----------------------------------------------------------------------------- +static INTERNAL_(void) wPrepareBitmapFileHeader(LPBITMAPFILEHEADER lpbfh, + DWORD dwSize) +{ + VDATEHEAP(); + + // NOTE THESE ARE NOT SUPPOSED TO BE UNICODE + // see win32s documentation + ((char *)(&lpbfh->bfType))[0] = 'B'; + ((char *)(&lpbfh->bfType))[1] = 'M'; + + lpbfh->bfSize = dwSize + sizeof(BITMAPFILEHEADER); + lpbfh->bfReserved1 = 0; + lpbfh->bfReserved2 = 0; + lpbfh->bfOffBits = 0; +} + + +FARINTERNAL UtHDIBToDIBFileStm(HANDLE hdata, DWORD dwSize, LPSTREAM pstm) +{ + VDATEHEAP(); + + HRESULT error; + BITMAPFILEHEADER bfh; + + wPrepareBitmapFileHeader(&bfh, dwSize); + + if (error = pstm->Write(&bfh, sizeof(bfh), NULL)) + return(error); + + return UtHGLOBALtoStm(hdata, dwSize, pstm); +} + + +FARINTERNAL UtDIBStmToDIBFileStm(LPSTREAM pstmDIB, DWORD dwSize, + LPSTREAM pstmDIBFile) +{ + VDATEHEAP(); + + HRESULT error; + BITMAPFILEHEADER bfh; + ULARGE_INTEGER ularge_int; // indicates how much to copy + + wPrepareBitmapFileHeader(&bfh, dwSize); + + if (error = pstmDIBFile->Write(&bfh, sizeof(bfh), NULL)) + return(error); + + ULISet32(ularge_int, dwSize); + if ((error = pstmDIB->CopyTo(pstmDIBFile, ularge_int, NULL, + NULL)) == NOERROR) + StSetSize(pstmDIBFile, 0, TRUE); + + return(error); +} + + +// REVIEW, move these to utils.h so that gen.cpp and mf.cpp can use them for +// the same purposes +// REVIEW, add some more comments; is HDIBFILEHDR a windows structure? +struct tagHDIBFILEHDR +{ + DWORD dwCompression; + DWORD dwWidth; + DWORD dwHeight; + DWORD dwSize; +}; +typedef struct tagHDIBFILEHDR HDIBFILEHDR; + +struct tagOLEPRESSTMHDR +{ + DWORD dwAspect; + DWORD dwLindex; + DWORD dwAdvf; +}; +typedef struct tagOLEPRESSTMHDR OLEPRESSTMHDR; + +FARINTERNAL UtHDIBFileToOlePresStm(HANDLE hdata, LPSTREAM pstm) +{ + VDATEHEAP(); + + HRESULT error; + HDIBFILEHDR hdfh; + LPBITMAPFILEHEADER lpbfh; + LPBITMAPINFOHEADER lpbmi; + + if (!(lpbfh = (LPBITMAPFILEHEADER)GlobalLock(hdata))) + return ResultFromScode(E_OUTOFMEMORY); + + lpbmi = (LPBITMAPINFOHEADER)(((BYTE *)lpbfh) + + sizeof(BITMAPFILEHEADER)); + + hdfh.dwCompression = 0; + // REVIEW, these casts are hosed + UtGetDibExtents(lpbmi, (LPLONG)&hdfh.dwWidth, (LPLONG)&hdfh.dwHeight); + + hdfh.dwSize = lpbfh->bfSize - sizeof(BITMAPFILEHEADER); + + // write compesssion, Width, Height, size + if (error = pstm->Write(&hdfh, sizeof(hdfh), 0)) + goto errRtn; + + // write the BITMAPINFOHEADER + // REVIEW, does this size include the data? + if ((error = pstm->Write(lpbmi, hdfh.dwSize, NULL)) == NOERROR) + StSetSize(pstm, 0, TRUE); + +errRtn: + GlobalUnlock(hdata); + return(error); +} + +#endif // _MAC + + + +FARINTERNAL UtHMFToMFStm(HANDLE FAR* lphMF, DWORD dwSize, LPSTREAM lpstream) +{ + VDATEHEAP(); + + HRESULT error; + + // if there's no handle, there's nothing to do + if (*lphMF == 0) + return ResultFromScode(OLE_E_BLANK); + +#ifdef _MAC + + AssertSz(GetHandleSize((Handle)*lphMF) == dwSize, + "pic hdl size not correct"); + HLock( (HANDLE)*lphMF ); + + error = StWrite(lpstream, * (*lphMF), dwSize); + + // Eric: We should be unlocking, right? + HUnlock((HANDLE)(*lphMF)); + + if (error != NOERROR) + AssertSz(0, "StWrite failure" ); + +#else + + HANDLE hBits = NULL; + void *lpBits; + +#ifdef WIN32 + + // allocate memory to hold the METAFILE bits + // Bug 18346 - OLE16 use to get the Handle size of the Metafile which was a METAHEADER bigger than the + // actual Metafile. Need to write out this much more worth of data so 16 bit dlls can read the Picture. + + dwSize += sizeof(METAHEADER); + + hBits = GlobalAlloc(GPTR, dwSize); + if (hBits == NULL) + return ResultFromScode(E_OUTOFMEMORY); + + if (!(lpBits = GlobalLock(hBits))) + goto errRtn; + + // REVIEW, shouldn't we check the returned size? + // REVIEW, what should we do about enhanced metafiles? If we + // convert and write those out (which have more features that 32 bit + // apps might use,) then you can't read the same document on a win16 + // machine.... + GetMetaFileBitsEx((HMETAFILE)*lphMF, dwSize, lpBits); + + // write the metafile bits out to the stream + error = StWrite(lpstream, lpBits, dwSize); + + GlobalUnlock(hBits); + +errRtn: + // free the metafile bits + GlobalFree(hBits); + +#else + if (!(hBits = GetMetaFileBits(*lphMF))) + { + error = ResultFromScode(E_OUTOFMEMORY); + goto errRtn; + } + + if (lpBits = GlobalLock(hBits)) + { + error = StWrite(lpstream, lpBits, dwSize); + GlobalUnlock(hBits); + } + else + error = ResultFromScode(E_OUTOFMEMORY); + + if (hBits) + *lphMF = SetMetaFileBits(hBits); +errRtn: + +#endif // WIN32 +#endif // _MAC + + // set the stream size + if (error == NOERROR) + StSetSize(lpstream, 0, TRUE); + + return(error); +} + + +//+---------------------------------------------------------------------------- +// +// Function: +// wPreparePlaceableMFHeader, static +// +// Synopsis: +// Initializes a PLACEABLEMETAHEADER. +// +// Arguments: +// [lpplac_mfh] -- pointer to the PLACEABLEMETAHEADER to initialize +// [lWidth] -- Width of the metafile +// REVIEW, in what units? +// REVIEW, why is this not unsigned? +// [lHeight] -- Height of the metafile +// REVIEW, in what units? +// REVIEW, why is this not unsigned? +// +// Notes: +// +// History: +// 12/08/93 - ChrisWe - made static +// +//----------------------------------------------------------------------------- +static INTERNAL_(void) wPreparePlaceableMFHeader( + PLACEABLEMETAHEADER FAR* lpplac_mfh, LONG lWidth, LONG lHeight) +{ + VDATEHEAP(); + + WORD FAR* lpw; // roves over the words included in the checksum + + lpplac_mfh->key = PMF_KEY; + lpplac_mfh->hmf = 0; + lpplac_mfh->inch = 576; // REVIEW, where's this magic number from? + lpplac_mfh->bbox.left = 0; + lpplac_mfh->bbox.top = 0; + lpplac_mfh->bbox.right = (int) ((lWidth * lpplac_mfh->inch) / 2540); + // REVIEW, more magic + lpplac_mfh->bbox.bottom = (int) ((lHeight * lpplac_mfh->inch) / 2540); + // REVIEW, more magic + lpplac_mfh->reserved = NULL; + + // Compute the checksum of the 10 words that precede the checksum field. + // It is calculated by XORing zero with those 10 words. + for(lpplac_mfh->checksum = 0, lpw = (WORD FAR*)lpplac_mfh; + lpw < (WORD FAR*)&lpplac_mfh->checksum; ++lpw) + lpplac_mfh->checksum ^= *lpw; +} + + +FARINTERNAL UtHMFToPlaceableMFStm(HANDLE FAR* lphMF, DWORD dwSize, + LONG lWidth, LONG lHeight, LPSTREAM pstm) +{ + VDATEHEAP(); + + PLACEABLEMETAHEADER plac_mfh; + HRESULT error; + + wPreparePlaceableMFHeader(&plac_mfh, lWidth, lHeight); + + // write the placeable header to the stream + if (error = pstm->Write(&plac_mfh, sizeof(plac_mfh), NULL)) + return(error); + + // write the rest of the METAFILE to the stream + return UtHMFToMFStm(lphMF, dwSize, pstm); +} + + +FARINTERNAL UtMFStmToPlaceableMFStm(LPSTREAM pstmMF, DWORD dwSize, + LONG lWidth, LONG lHeight, LPSTREAM pstmPMF) +{ + VDATEHEAP(); + + PLACEABLEMETAHEADER plac_mfh; + HRESULT error; + ULARGE_INTEGER ularge_int; // indicates how much data to copy + + wPreparePlaceableMFHeader(&plac_mfh, lWidth, lHeight); + + // write the placeable header to the stream + if (error = pstmPMF->Write(&plac_mfh, sizeof(plac_mfh), NULL)) + return(error); + + // copy the METAFILE data from one stream to the other + ULISet32(ularge_int, dwSize); + if ((error = pstmMF->CopyTo(pstmPMF, ularge_int, NULL, NULL)) == + NOERROR) + StSetSize(pstmPMF, 0, TRUE); + + return(error); +} + +//+------------------------------------------------------------------------- +// +// Function: UtWriteOlePresStmHeader, private +// +// Synopsis: Write the presentation stream header +// +// Effects: +// +// Arguments: [lpstream] -- destination stream +// [pforetc] -- FORMATETC for this presentation +// [dwAdvf] -- advise flags for the presentation +// +// Requires: +// +// Returns: HRESULT +// +// Modifies: +// +// Algorithm: +// +// History: 11-May-94 AlexT Added function header, translate to +// ANSI before saving ptd +// +// Notes: This function can fail in low memory for presentations with +// non-NULL ptds (since we allocate memory to do the conversion +// to the persistent format). NtIssue #2789 +// +//-------------------------------------------------------------------------- + +FARINTERNAL UtWriteOlePresStmHeader(LPSTREAM lpstream, LPFORMATETC pforetc, + DWORD dwAdvf) +{ + VDATEHEAP(); + + HRESULT error; + OLEPRESSTMHDR opsh; + + // write clip format + // REVIEW, change name of this function? + if (error = WriteClipformatStm(lpstream, pforetc->cfFormat)) + return(error); + + // write target device info + if (pforetc->ptd) + { + DVTDINFO dvtdInfo; + DVTARGETDEVICE *ptdA; + + error = UtGetDvtd32Info(pforetc->ptd, &dvtdInfo); + if (FAILED(error)) + { + return(error); + } + + ptdA = (DVTARGETDEVICE *) PrivMemAlloc(dvtdInfo.cbConvertSize); + if (NULL == ptdA) + { + return(E_OUTOFMEMORY); + } + + error = UtConvertDvtd32toDvtd16(pforetc->ptd, &dvtdInfo, ptdA); + + if (SUCCEEDED(error)) + { + error = StWrite(lpstream, ptdA, ptdA->tdSize); + } + + PrivMemFree(ptdA); + + if (FAILED(error)) + { + return(error); + } + } + else + { + // if ptd is null then write 4 as size. + // REVIEW, what is that the sizeof()? + DWORD dwNullPtdLength = 4; + + if (error = StWrite(lpstream, &dwNullPtdLength, sizeof(DWORD))) + return(error); + } + + opsh.dwAspect = pforetc->dwAspect; + opsh.dwLindex = pforetc->lindex; + opsh.dwAdvf = dwAdvf; + + // write DVASPECT, lindex, advise flags + return StWrite(lpstream, &opsh, sizeof(opsh)); +} + +//+------------------------------------------------------------------------- +// +// Function: UtReadOlePresStmHeader +// +// Synopsis: Reads in a presentation stream header +// +// Arguments: [pstm] -- source stream +// [pforetc] -- FORMATETC to be filled in +// [pdwAdvf] -- advise flags to be filled in +// [pfConvert] -- Mac conversion required, to be filled in +// +// Requires: +// +// Returns: HRESULT +// +// Modifies: +// +// Algorithm: +// +// History: 11-May-94 AlexT Added function header, translate ptd +// from ANSI when loading +// +// Notes: +// +//-------------------------------------------------------------------------- + +FARINTERNAL UtReadOlePresStmHeader(LPSTREAM pstm, LPFORMATETC pforetc, + DWORD FAR* pdwAdvf, BOOL FAR* pfConvert) +{ + VDATEHEAP(); + + HRESULT error; + DWORD dwRead; + OLEPRESSTMHDR opsh; + + // initialize this for error return cases + // Check for NULL ptr, as caller may not need this information + + if (pfConvert) + { + *pfConvert = FALSE; + } + + // there's no target device information yet + pforetc->ptd = NULL; + + // REVIEW, rename this function to indicate its origin? + error = ReadClipformatStm(pstm, &dwRead); + + if (error == NOERROR) + pforetc->cfFormat = (CLIPFORMAT)dwRead; + else + { +#ifndef _MAC + if (GetScode(error) == OLE_S_MAC_CLIPFORMAT) + { + // check whether the clipformat is "pict" + // REVIEW, what's this cuteness? + if (dwRead != *((DWORD *)"TCIP")) + return(error); + + if (pfConvert) + *pfConvert = TRUE; + else + return ResultFromScode(DV_E_CLIPFORMAT); + + pforetc->cfFormat = CF_METAFILEPICT; + } + else +#endif + return(error); + } + + // set the proper tymed + if (pforetc->cfFormat == CF_METAFILEPICT) + { + pforetc->tymed = TYMED_MFPICT; + } + else if (pforetc->cfFormat == CF_ENHMETAFILE) + { + pforetc->tymed = TYMED_ENHMF; + } + else if (pforetc->cfFormat == CF_BITMAP) + { + AssertSz(0, "We don't read/save CF_BITMAP anymore"); + return ResultFromScode(DV_E_CLIPFORMAT); + } + else if (pforetc->cfFormat == NULL) + { + pforetc->tymed = TYMED_NULL; + } + else + { + pforetc->tymed = TYMED_HGLOBAL; + } + + // Read targetdevice info. + if (error = StRead(pstm, &dwRead, sizeof(dwRead))) + return(error); + + // if the tdSize of ptd is non-null and is > 4, then go ahead read the + // remaining data of the target device info + if (dwRead > 4) + { + DVTARGETDEVICE *ptdA; + DVTDINFO dvtdInfo; + + ptdA = (DVTARGETDEVICE *) PrivMemAlloc(dwRead); + if (NULL == ptdA) + { + return ResultFromScode(E_OUTOFMEMORY); + } + + ptdA->tdSize = dwRead; + error = StRead(pstm, ((BYTE*)ptdA) + sizeof(dwRead), + dwRead - sizeof(dwRead)); + + if (SUCCEEDED(error)) + { + error = UtGetDvtd16Info(ptdA, &dvtdInfo); + if (SUCCEEDED(error)) + { + pforetc->ptd = (DVTARGETDEVICE *) PubMemAlloc(dvtdInfo.cbConvertSize); + if (NULL == pforetc->ptd) + { + error = E_OUTOFMEMORY; + } + else + { + error = UtConvertDvtd16toDvtd32(ptdA, &dvtdInfo, pforetc->ptd); + } + } + } + + PrivMemFree(ptdA); + + if (FAILED(error)) + { + goto errRtn; + } + } + else + pforetc->ptd = NULL; + + // Read DVASPECT, lindex, advise flags + if ((error = StRead(pstm, &opsh, sizeof(opsh))) != NOERROR) + goto errRtn; + + pforetc->dwAspect = opsh.dwAspect; + pforetc->lindex = opsh.dwLindex; + if (pdwAdvf) + *pdwAdvf = opsh.dwAdvf; + + return NOERROR; + +errRtn: + if (pforetc->ptd) + { + PubMemFree(pforetc->ptd); + pforetc->ptd = NULL; + } + + return(error); +} + + +FARINTERNAL UtOlePresStmToContentsStm(LPSTORAGE pstg, LPOLESTR lpszPresStm, + BOOL fDeletePresStm, UINT FAR* puiStatus) +{ + VDATEHEAP(); + + LPSTREAM pstmOlePres; + LPSTREAM pstmContents = NULL; + HRESULT error; + FORMATETC foretc; + HDIBFILEHDR hdfh; + + // there's no status yet + *puiStatus = 0; + + // POSTPPC: + // + // This function needs to be rewritten to correctly handle the case described in + // the comments below (rather than just skipping out of the function if the contents + // stream already exists). The best course of action will probably be to convert + // DIBs->Metafiles and Metafiles->DIBs in the needed cases. + + // The code inside the #ifdef below is used to determine if the contents + // stream has already been created (which is the case for an object that has + // been converted to a bitmap) because in the case of an object that has been + // converted to a static DIB and the object has a METAFILE presentation stream + // we already have a cachenode created as a DIB and we will read the contents + // stream after this call to get the DIB data. However, this function sees + // the metafile presentation, and converts it into the contents stream (which + // when then try to load as a DIB) and bad things happen (it doesn't work). If + // the stream already exists, then we bail out of this function. + if (pstg->CreateStream(OLE_CONTENTS_STREAM,(STGM_READWRITE | STGM_SHARE_EXCLUSIVE), NULL, + 0, &pstmContents) != NOERROR) + { + return NOERROR; + } + + // created stream, it must not have existed + pstmContents->Release(); + pstg->DestroyElement(OLE_CONTENTS_STREAM); + + if ((error = pstg->OpenStream(lpszPresStm, NULL, + (STGM_READ | STGM_SHARE_EXCLUSIVE), 0, &pstmOlePres)) != + NOERROR) + { + // we can't open the source stream + *puiStatus |= CONVERT_NOSOURCE; + + // check whether "CONTENTS" stream exits + if (pstg->OpenStream(OLE_CONTENTS_STREAM, NULL, + (STGM_READ | STGM_SHARE_EXCLUSIVE), 0, + &pstmContents) != NOERROR) + { + // we can't open the destination stream either + // REVIEW, since we can't open the source, who cares? + // REVIEW, is there a cheaper way to test existence + // other than opening? + *puiStatus |= CONVERT_NODESTINATION; + } + else + pstmContents->Release(); + + return(error); + } + + foretc.ptd = NULL; + if (error = UtReadOlePresStmHeader(pstmOlePres, &foretc, NULL, NULL)) + goto errRtn; + + if (error = pstmOlePres->Read(&hdfh, sizeof(hdfh), 0)) + goto errRtn; + + AssertSz(hdfh.dwCompression == 0, + "Non-zero compression not supported"); + + if (error = OpenOrCreateStream(pstg, OLE_CONTENTS_STREAM, + &pstmContents)) + { + *puiStatus |= CONVERT_NODESTINATION; + goto errRtn; + } + + if (foretc.dwAspect == DVASPECT_ICON) + { + *puiStatus |= CONVERT_SOURCEISICON; + fDeletePresStm = FALSE; + error = NOERROR; + goto errRtn; + } + + if (foretc.cfFormat == CF_DIB) + error = UtDIBStmToDIBFileStm(pstmOlePres, hdfh.dwSize, + pstmContents); + else if (foretc.cfFormat == CF_METAFILEPICT) + error = UtMFStmToPlaceableMFStm(pstmOlePres, + hdfh.dwSize, hdfh.dwWidth, hdfh.dwHeight, + pstmContents); + else + error = ResultFromScode(DV_E_CLIPFORMAT); + +errRtn: + if (pstmOlePres) + pstmOlePres->Release(); + + if (pstmContents) + pstmContents->Release(); + + if (foretc.ptd) + PubMemFree(foretc.ptd); + + if (error == NOERROR) + { + if (fDeletePresStm && lpszPresStm) + pstg->DestroyElement(lpszPresStm); + } + else + { + pstg->DestroyElement(OLE_CONTENTS_STREAM); + } + + return(error); +} + + +FARINTERNAL_(HANDLE) UtGetHPRESFromNative(LPSTORAGE pstg, CLIPFORMAT cfFormat, + BOOL fOle10Native) +{ + VDATEHEAP(); + + LPSTREAM pstm; + HGLOBAL hdata = NULL; + + if ((cfFormat != CF_METAFILEPICT) && + (cfFormat != CF_DIB) && + (cfFormat != CF_ENHMETAFILE)) + { + return(NULL); + } + + if (fOle10Native) + { + DWORD dwSize; + + if (pstg->OpenStream(OLE10_NATIVE_STREAM, NULL, + (STGM_READ | STGM_SHARE_EXCLUSIVE), 0, + &pstm) != NOERROR) + return(NULL); + + if (pstm->Read(&dwSize, sizeof(DWORD), NULL) == NOERROR) + { + // is it PBrush native data? + if (cfFormat == CF_DIB) + UtGetHDIBFromDIBFileStm(pstm, &hdata); + else + { + // MSDraw native data or PaintBrush + // + UtGetHMFPICTFromMSDrawNativeStm(pstm, dwSize, + &hdata); + } + } + } + else + { + if (pstg->OpenStream(OLE_CONTENTS_STREAM, NULL, + (STGM_READ | STGM_SHARE_EXCLUSIVE), 0, + &pstm) != NOERROR) + return(NULL); + + if (cfFormat == CF_DIB) + { + UtGetHDIBFromDIBFileStm(pstm, &hdata); + } + else if (cfFormat == CF_METAFILEPICT) + { + UtGetHMFPICTFromPlaceableMFStm(pstm, &hdata); + } + else + { + UtGetHEMFFromContentsStm(pstm, &hdata); + } + } + + pstm->Release(); + return(hdata); +} + + diff --git a/private/ole32/ole232/util/daytona/makefile b/private/ole32/ole232/util/daytona/makefile new file mode 100644 index 000000000..1d3728d41 --- /dev/null +++ b/private/ole32/ole232/util/daytona/makefile @@ -0,0 +1,10 @@ +############################################################################ +# +# Copyright (C) 1992, Microsoft Corporation. +# +# All rights reserved. +# +############################################################################ + +!include $(NTMAKEENV)\makefile.def + diff --git a/private/ole32/ole232/util/daytona/sources b/private/ole32/ole232/util/daytona/sources new file mode 100644 index 000000000..ecc4ad7c6 --- /dev/null +++ b/private/ole32/ole232/util/daytona/sources @@ -0,0 +1,83 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + +Author: + + David Plummer (davepl) 19-Mar-94 + + Modifed by via awk to include global project include file + and to wrap precompiled header line within a conditional + that can be set in this include file. + + Donna Liu (DonnaLi) 19-Dec-1993 + +!ENDIF + +MAJORCOMP = cairole +MINORCOMP = ole232 + +# +# This is the name of the target built from the source files specified +# below. The name should include neither the path nor the file extension. +# + +TARGETNAME= util + +# +# This specifies where the target is to be built. A private target of +# type LIBRARY or DYNLINK should go to obj, whereas a public target of +# type LIBRARY or DYNLINK should go to $(BASEDIR)\public\sdk\lib. +# + +TARGETPATH= obj + +# +# This specifies the type of the target, such as PROGRAM, DYNLINK, LIBRARY, +# etc. +# + +TARGETTYPE= LIBRARY + + +# +# The following includes a global include file defined at the +# base of the project for all components +# + +!include ..\..\..\daytona.inc + +INCLUDES= ..\..\..\common\daytona;..\..\..\ih;..\..\inc + +C_DEFINES= \ + $(C_DEFINES) \ + + +SOURCES= \ + ..\convert.cpp \ + ..\global.cpp \ + ..\info.cpp \ + ..\map_kv.cpp \ + ..\ole2util.cpp \ + ..\plex.cpp \ + ..\utils.cpp \ + ..\utstream.cpp + +UMTYPE= windows +UMAPPL= +UMTEST= +UMLIBS= + +!include ..\..\precomp2.inc diff --git a/private/ole32/ole232/util/depend.mk b/private/ole32/ole232/util/depend.mk new file mode 100644 index 000000000..6dc58d8fa --- /dev/null +++ b/private/ole32/ole232/util/depend.mk @@ -0,0 +1,237 @@ +# +# Built automatically +# + +# +# Source files +# + +$(OBJDIR)\convert.obj $(OBJDIR)\convert.lst: .\convert.cpp \ + $(CAIROLE)\common\cobjerr.h $(CAIROLE)\common\rpcferr.h \ + $(CAIROLE)\h\coguid.h $(CAIROLE)\h\compobj.h $(CAIROLE)\h\dvobj.h \ + $(CAIROLE)\h\initguid.h $(CAIROLE)\h\moniker.h $(CAIROLE)\h\ole2.h \ + $(CAIROLE)\h\ole2dbg.h $(CAIROLE)\h\oleguid.h $(CAIROLE)\h\scode.h \ + $(CAIROLE)\h\storage.h $(CAIROLE)\ih\debug.h $(CAIROLE)\ih\map_kv.h \ + $(CAIROLE)\ih\ole2sp.h $(CAIROLE)\ih\olecoll.h $(CAIROLE)\ih\olemem.h \ + $(CAIROLE)\ih\privguid.h $(CAIROLE)\ih\utils.h \ + $(CAIROLE)\ih\utstream.h $(CAIROLE)\ih\valid.h \ + $(CAIROLE)\ole232\inc\ole2int.h $(COMMON)\ih\dbgpoint.hxx \ + $(COMMON)\ih\debnot.h $(COMMON)\ih\winnot.h $(CRTINC)\ctype.h \ + $(CRTINC)\excpt.h $(CRTINC)\malloc.h $(CRTINC)\stdarg.h \ + $(CRTINC)\stddef.h $(CRTINC)\stdlib.h $(CRTINC)\string.h \ + $(CRTINC)\wchar.h $(OSINC)\cderr.h $(OSINC)\commdlg.h $(OSINC)\dde.h \ + $(OSINC)\ddeml.h $(OSINC)\dlgs.h $(OSINC)\drivinit.h \ + $(OSINC)\lzexpand.h $(OSINC)\mmsystem.h $(OSINC)\nb30.h \ + $(OSINC)\ole.h $(OSINC)\rpc.h $(OSINC)\rpcdce.h $(OSINC)\rpcdcep.h \ + $(OSINC)\rpcnsi.h $(OSINC)\rpcnterr.h $(OSINC)\shellapi.h \ + $(OSINC)\widewrap.h $(OSINC)\winbase.h $(OSINC)\wincon.h \ + $(OSINC)\windef.h $(OSINC)\windows.h $(OSINC)\winerror.h \ + $(OSINC)\wingdi.h $(OSINC)\winmm.h $(OSINC)\winnetwk.h \ + $(OSINC)\winnls.h $(OSINC)\winnt.h $(OSINC)\winperf.h \ + $(OSINC)\winreg.h $(OSINC)\winsock.h $(OSINC)\winspool.h \ + $(OSINC)\winsvc.h $(OSINC)\winuser.h $(OSINC)\winver.h + +$(OBJDIR)\global.obj $(OBJDIR)\global.lst: .\global.cpp \ + $(CAIROLE)\common\cobjerr.h $(CAIROLE)\common\rpcferr.h \ + $(CAIROLE)\h\coguid.h $(CAIROLE)\h\compobj.h $(CAIROLE)\h\dvobj.h \ + $(CAIROLE)\h\initguid.h $(CAIROLE)\h\moniker.h $(CAIROLE)\h\ole2.h \ + $(CAIROLE)\h\ole2dbg.h $(CAIROLE)\h\oleguid.h $(CAIROLE)\h\scode.h \ + $(CAIROLE)\h\storage.h $(CAIROLE)\ih\debug.h $(CAIROLE)\ih\map_kv.h \ + $(CAIROLE)\ih\ole2sp.h $(CAIROLE)\ih\olecoll.h $(CAIROLE)\ih\olemem.h \ + $(CAIROLE)\ih\privguid.h $(CAIROLE)\ih\utils.h \ + $(CAIROLE)\ih\utstream.h $(CAIROLE)\ih\valid.h \ + $(CAIROLE)\ole232\inc\ole2int.h $(COMMON)\ih\dbgpoint.hxx \ + $(COMMON)\ih\debnot.h $(COMMON)\ih\winnot.h $(CRTINC)\ctype.h \ + $(CRTINC)\excpt.h $(CRTINC)\malloc.h $(CRTINC)\stdarg.h \ + $(CRTINC)\stddef.h $(CRTINC)\stdlib.h $(CRTINC)\string.h \ + $(CRTINC)\wchar.h $(OSINC)\cderr.h $(OSINC)\commdlg.h $(OSINC)\dde.h \ + $(OSINC)\ddeml.h $(OSINC)\dlgs.h $(OSINC)\drivinit.h \ + $(OSINC)\lzexpand.h $(OSINC)\mmsystem.h $(OSINC)\nb30.h \ + $(OSINC)\ole.h $(OSINC)\rpc.h $(OSINC)\rpcdce.h $(OSINC)\rpcdcep.h \ + $(OSINC)\rpcnsi.h $(OSINC)\rpcnterr.h $(OSINC)\shellapi.h \ + $(OSINC)\widewrap.h $(OSINC)\winbase.h $(OSINC)\wincon.h \ + $(OSINC)\windef.h $(OSINC)\windows.h $(OSINC)\winerror.h \ + $(OSINC)\wingdi.h $(OSINC)\winmm.h $(OSINC)\winnetwk.h \ + $(OSINC)\winnls.h $(OSINC)\winnt.h $(OSINC)\winperf.h \ + $(OSINC)\winreg.h $(OSINC)\winsock.h $(OSINC)\winspool.h \ + $(OSINC)\winsvc.h $(OSINC)\winuser.h $(OSINC)\winver.h + +$(OBJDIR)\info.obj $(OBJDIR)\info.lst: .\info.cpp \ + $(CAIROLE)\common\cobjerr.h $(CAIROLE)\common\rpcferr.h \ + $(CAIROLE)\h\coguid.h $(CAIROLE)\h\compobj.h $(CAIROLE)\h\dvobj.h \ + $(CAIROLE)\h\initguid.h $(CAIROLE)\h\moniker.h $(CAIROLE)\h\ole2.h \ + $(CAIROLE)\h\ole2dbg.h $(CAIROLE)\h\oleguid.h $(CAIROLE)\h\scode.h \ + $(CAIROLE)\h\storage.h $(CAIROLE)\ih\debug.h $(CAIROLE)\ih\map_kv.h \ + $(CAIROLE)\ih\ole2sp.h $(CAIROLE)\ih\olecoll.h $(CAIROLE)\ih\olemem.h \ + $(CAIROLE)\ih\privguid.h $(CAIROLE)\ih\utils.h \ + $(CAIROLE)\ih\utstream.h $(CAIROLE)\ih\valid.h \ + $(CAIROLE)\ole232\inc\ole2int.h $(COMMON)\ih\dbgpoint.hxx \ + $(COMMON)\ih\debnot.h $(COMMON)\ih\winnot.h $(CRTINC)\ctype.h \ + $(CRTINC)\excpt.h $(CRTINC)\malloc.h $(CRTINC)\stdarg.h \ + $(CRTINC)\stddef.h $(CRTINC)\stdlib.h $(CRTINC)\string.h \ + $(CRTINC)\wchar.h $(OSINC)\cderr.h $(OSINC)\commdlg.h $(OSINC)\dde.h \ + $(OSINC)\ddeml.h $(OSINC)\dlgs.h $(OSINC)\drivinit.h \ + $(OSINC)\lzexpand.h $(OSINC)\mmsystem.h $(OSINC)\nb30.h \ + $(OSINC)\ole.h $(OSINC)\rpc.h $(OSINC)\rpcdce.h $(OSINC)\rpcdcep.h \ + $(OSINC)\rpcnsi.h $(OSINC)\rpcnterr.h $(OSINC)\shellapi.h \ + $(OSINC)\widewrap.h $(OSINC)\winbase.h $(OSINC)\wincon.h \ + $(OSINC)\windef.h $(OSINC)\windows.h $(OSINC)\winerror.h \ + $(OSINC)\wingdi.h $(OSINC)\winmm.h $(OSINC)\winnetwk.h \ + $(OSINC)\winnls.h $(OSINC)\winnt.h $(OSINC)\winperf.h \ + $(OSINC)\winreg.h $(OSINC)\winsock.h $(OSINC)\winspool.h \ + $(OSINC)\winsvc.h $(OSINC)\winuser.h $(OSINC)\winver.h + +$(OBJDIR)\map_kv.obj $(OBJDIR)\map_kv.lst: .\map_kv.cpp \ + $(CAIROLE)\ih\map_kv.h $(CAIROLE)\ih\plex.h \ + $(CAIROLE)\common\cobjerr.h $(CAIROLE)\common\rpcferr.h \ + $(CAIROLE)\h\coguid.h $(CAIROLE)\h\compobj.h $(CAIROLE)\h\dvobj.h \ + $(CAIROLE)\h\initguid.h $(CAIROLE)\h\moniker.h $(CAIROLE)\h\ole2.h \ + $(CAIROLE)\h\ole2dbg.h $(CAIROLE)\h\oleguid.h $(CAIROLE)\h\scode.h \ + $(CAIROLE)\h\storage.h $(CAIROLE)\ih\debug.h $(CAIROLE)\ih\map_kv.h \ + $(CAIROLE)\ih\ole2sp.h $(CAIROLE)\ih\olecoll.h $(CAIROLE)\ih\olemem.h \ + $(CAIROLE)\ih\privguid.h $(CAIROLE)\ih\utils.h \ + $(CAIROLE)\ih\utstream.h $(CAIROLE)\ih\valid.h \ + $(CAIROLE)\ole232\inc\ole2int.h $(COMMON)\ih\dbgpoint.hxx \ + $(COMMON)\ih\debnot.h $(COMMON)\ih\winnot.h $(CRTINC)\ctype.h \ + $(CRTINC)\excpt.h $(CRTINC)\malloc.h $(CRTINC)\stdarg.h \ + $(CRTINC)\stddef.h $(CRTINC)\stdlib.h $(CRTINC)\string.h \ + $(CRTINC)\wchar.h $(OSINC)\cderr.h $(OSINC)\commdlg.h $(OSINC)\dde.h \ + $(OSINC)\ddeml.h $(OSINC)\dlgs.h $(OSINC)\drivinit.h \ + $(OSINC)\lzexpand.h $(OSINC)\mmsystem.h $(OSINC)\nb30.h \ + $(OSINC)\ole.h $(OSINC)\rpc.h $(OSINC)\rpcdce.h $(OSINC)\rpcdcep.h \ + $(OSINC)\rpcnsi.h $(OSINC)\rpcnterr.h $(OSINC)\shellapi.h \ + $(OSINC)\widewrap.h $(OSINC)\winbase.h $(OSINC)\wincon.h \ + $(OSINC)\windef.h $(OSINC)\windows.h $(OSINC)\winerror.h \ + $(OSINC)\wingdi.h $(OSINC)\winmm.h $(OSINC)\winnetwk.h \ + $(OSINC)\winnls.h $(OSINC)\winnt.h $(OSINC)\winperf.h \ + $(OSINC)\winreg.h $(OSINC)\winsock.h $(OSINC)\winspool.h \ + $(OSINC)\winsvc.h $(OSINC)\winuser.h $(OSINC)\winver.h + +$(OBJDIR)\ole2util.obj $(OBJDIR)\ole2util.lst: .\ole2util.cpp \ + $(CAIROLE)\common\cobjerr.h $(CAIROLE)\common\rpcferr.h \ + $(CAIROLE)\h\coguid.h $(CAIROLE)\h\compobj.h $(CAIROLE)\h\dvobj.h \ + $(CAIROLE)\h\initguid.h $(CAIROLE)\h\moniker.h $(CAIROLE)\h\ole2.h \ + $(CAIROLE)\h\ole2dbg.h $(CAIROLE)\h\oleguid.h $(CAIROLE)\h\scode.h \ + $(CAIROLE)\h\storage.h $(CAIROLE)\ih\debug.h $(CAIROLE)\ih\map_kv.h \ + $(CAIROLE)\ih\ole2sp.h $(CAIROLE)\ih\olecoll.h $(CAIROLE)\ih\olemem.h \ + $(CAIROLE)\ih\privguid.h $(CAIROLE)\ih\utils.h \ + $(CAIROLE)\ih\utstream.h $(CAIROLE)\ih\valid.h \ + $(CAIROLE)\ole232\inc\ole2int.h $(COMMON)\ih\dbgpoint.hxx \ + $(COMMON)\ih\debnot.h $(COMMON)\ih\winnot.h $(CRTINC)\ctype.h \ + $(CRTINC)\excpt.h $(CRTINC)\malloc.h $(CRTINC)\stdarg.h \ + $(CRTINC)\stddef.h $(CRTINC)\stdlib.h $(CRTINC)\string.h \ + $(CRTINC)\wchar.h $(OSINC)\cderr.h $(OSINC)\commdlg.h $(OSINC)\dde.h \ + $(OSINC)\ddeml.h $(OSINC)\dlgs.h $(OSINC)\drivinit.h \ + $(OSINC)\lzexpand.h $(OSINC)\mmsystem.h $(OSINC)\nb30.h \ + $(OSINC)\ole.h $(OSINC)\rpc.h $(OSINC)\rpcdce.h $(OSINC)\rpcdcep.h \ + $(OSINC)\rpcnsi.h $(OSINC)\rpcnterr.h $(OSINC)\shellapi.h \ + $(OSINC)\widewrap.h $(OSINC)\winbase.h $(OSINC)\wincon.h \ + $(OSINC)\windef.h $(OSINC)\windows.h $(OSINC)\winerror.h \ + $(OSINC)\wingdi.h $(OSINC)\winmm.h $(OSINC)\winnetwk.h \ + $(OSINC)\winnls.h $(OSINC)\winnt.h $(OSINC)\winperf.h \ + $(OSINC)\winreg.h $(OSINC)\winsock.h $(OSINC)\winspool.h \ + $(OSINC)\winsvc.h $(OSINC)\winuser.h $(OSINC)\winver.h + +$(OBJDIR)\olenew.obj $(OBJDIR)\olenew.lst: .\olenew.cpp \ + $(CAIROLE)\common\cobjerr.h $(CAIROLE)\common\rpcferr.h \ + $(CAIROLE)\h\coguid.h $(CAIROLE)\h\compobj.h $(CAIROLE)\h\dvobj.h \ + $(CAIROLE)\h\initguid.h $(CAIROLE)\h\moniker.h $(CAIROLE)\h\ole2.h \ + $(CAIROLE)\h\ole2dbg.h $(CAIROLE)\h\oleguid.h $(CAIROLE)\h\scode.h \ + $(CAIROLE)\h\storage.h $(CAIROLE)\ih\debug.h $(CAIROLE)\ih\map_kv.h \ + $(CAIROLE)\ih\ole2sp.h $(CAIROLE)\ih\olecoll.h $(CAIROLE)\ih\olemem.h \ + $(CAIROLE)\ih\privguid.h $(CAIROLE)\ih\utils.h \ + $(CAIROLE)\ih\utstream.h $(CAIROLE)\ih\valid.h \ + $(CAIROLE)\ole232\inc\ole2int.h $(COMMON)\ih\dbgpoint.hxx \ + $(COMMON)\ih\debnot.h $(COMMON)\ih\winnot.h $(CRTINC)\ctype.h \ + $(CRTINC)\excpt.h $(CRTINC)\malloc.h $(CRTINC)\stdarg.h \ + $(CRTINC)\stddef.h $(CRTINC)\stdlib.h $(CRTINC)\string.h \ + $(CRTINC)\wchar.h $(OSINC)\cderr.h $(OSINC)\commdlg.h $(OSINC)\dde.h \ + $(OSINC)\ddeml.h $(OSINC)\dlgs.h $(OSINC)\drivinit.h \ + $(OSINC)\lzexpand.h $(OSINC)\mmsystem.h $(OSINC)\nb30.h \ + $(OSINC)\ole.h $(OSINC)\rpc.h $(OSINC)\rpcdce.h $(OSINC)\rpcdcep.h \ + $(OSINC)\rpcnsi.h $(OSINC)\rpcnterr.h $(OSINC)\shellapi.h \ + $(OSINC)\widewrap.h $(OSINC)\winbase.h $(OSINC)\wincon.h \ + $(OSINC)\windef.h $(OSINC)\windows.h $(OSINC)\winerror.h \ + $(OSINC)\wingdi.h $(OSINC)\winmm.h $(OSINC)\winnetwk.h \ + $(OSINC)\winnls.h $(OSINC)\winnt.h $(OSINC)\winperf.h \ + $(OSINC)\winreg.h $(OSINC)\winsock.h $(OSINC)\winspool.h \ + $(OSINC)\winsvc.h $(OSINC)\winuser.h $(OSINC)\winver.h + +$(OBJDIR)\plex.obj $(OBJDIR)\plex.lst: .\plex.cpp \ + $(CAIROLE)\common\cobjerr.h $(CAIROLE)\common\rpcferr.h \ + $(CAIROLE)\h\coguid.h $(CAIROLE)\h\compobj.h $(CAIROLE)\h\dvobj.h \ + $(CAIROLE)\h\initguid.h $(CAIROLE)\h\moniker.h $(CAIROLE)\h\ole2.h \ + $(CAIROLE)\h\ole2dbg.h $(CAIROLE)\h\oleguid.h $(CAIROLE)\h\scode.h \ + $(CAIROLE)\h\storage.h $(CAIROLE)\ih\debug.h $(CAIROLE)\ih\map_kv.h \ + $(CAIROLE)\ih\ole2sp.h $(CAIROLE)\ih\olecoll.h $(CAIROLE)\ih\olemem.h \ + $(CAIROLE)\ih\plex.h $(CAIROLE)\ih\privguid.h $(CAIROLE)\ih\utils.h \ + $(CAIROLE)\ih\utstream.h $(CAIROLE)\ih\valid.h \ + $(CAIROLE)\ole232\inc\ole2int.h $(COMMON)\ih\dbgpoint.hxx \ + $(COMMON)\ih\debnot.h $(COMMON)\ih\winnot.h $(CRTINC)\ctype.h \ + $(CRTINC)\excpt.h $(CRTINC)\malloc.h $(CRTINC)\stdarg.h \ + $(CRTINC)\stddef.h $(CRTINC)\stdlib.h $(CRTINC)\string.h \ + $(CRTINC)\wchar.h $(OSINC)\cderr.h $(OSINC)\commdlg.h $(OSINC)\dde.h \ + $(OSINC)\ddeml.h $(OSINC)\dlgs.h $(OSINC)\drivinit.h \ + $(OSINC)\lzexpand.h $(OSINC)\mmsystem.h $(OSINC)\nb30.h \ + $(OSINC)\ole.h $(OSINC)\rpc.h $(OSINC)\rpcdce.h $(OSINC)\rpcdcep.h \ + $(OSINC)\rpcnsi.h $(OSINC)\rpcnterr.h $(OSINC)\shellapi.h \ + $(OSINC)\widewrap.h $(OSINC)\winbase.h $(OSINC)\wincon.h \ + $(OSINC)\windef.h $(OSINC)\windows.h $(OSINC)\winerror.h \ + $(OSINC)\wingdi.h $(OSINC)\winmm.h $(OSINC)\winnetwk.h \ + $(OSINC)\winnls.h $(OSINC)\winnt.h $(OSINC)\winperf.h \ + $(OSINC)\winreg.h $(OSINC)\winsock.h $(OSINC)\winspool.h \ + $(OSINC)\winsvc.h $(OSINC)\winuser.h $(OSINC)\winver.h + +$(OBJDIR)\utils.obj $(OBJDIR)\utils.lst: .\utils.cpp \ + $(CAIROLE)\common\cobjerr.h $(CAIROLE)\common\rpcferr.h \ + $(CAIROLE)\h\coguid.h $(CAIROLE)\h\compobj.h $(CAIROLE)\h\dvobj.h \ + $(CAIROLE)\h\initguid.h $(CAIROLE)\h\moniker.h $(CAIROLE)\h\ole2.h \ + $(CAIROLE)\h\ole2dbg.h $(CAIROLE)\h\oleguid.h $(CAIROLE)\h\scode.h \ + $(CAIROLE)\h\storage.h $(CAIROLE)\ih\debug.h $(CAIROLE)\ih\map_kv.h \ + $(CAIROLE)\ih\ole2sp.h $(CAIROLE)\ih\olecoll.h $(CAIROLE)\ih\olemem.h \ + $(CAIROLE)\ih\privguid.h $(CAIROLE)\ih\utils.h \ + $(CAIROLE)\ih\utstream.h $(CAIROLE)\ih\valid.h \ + $(CAIROLE)\ole232\inc\ole2int.h $(COMMON)\ih\dbgpoint.hxx \ + $(COMMON)\ih\debnot.h $(COMMON)\ih\winnot.h $(CRTINC)\memory.h \ + $(CRTINC)\ctype.h $(CRTINC)\excpt.h $(CRTINC)\malloc.h \ + $(CRTINC)\stdarg.h $(CRTINC)\stddef.h $(CRTINC)\stdlib.h \ + $(CRTINC)\string.h $(CRTINC)\wchar.h $(OSINC)\cderr.h \ + $(OSINC)\commdlg.h $(OSINC)\dde.h $(OSINC)\ddeml.h $(OSINC)\dlgs.h \ + $(OSINC)\drivinit.h $(OSINC)\lzexpand.h $(OSINC)\mmsystem.h \ + $(OSINC)\nb30.h $(OSINC)\ole.h $(OSINC)\rpc.h $(OSINC)\rpcdce.h \ + $(OSINC)\rpcdcep.h $(OSINC)\rpcnsi.h $(OSINC)\rpcnterr.h \ + $(OSINC)\shellapi.h $(OSINC)\widewrap.h $(OSINC)\winbase.h \ + $(OSINC)\wincon.h $(OSINC)\windef.h $(OSINC)\windows.h \ + $(OSINC)\winerror.h $(OSINC)\wingdi.h $(OSINC)\winmm.h \ + $(OSINC)\winnetwk.h $(OSINC)\winnls.h $(OSINC)\winnt.h \ + $(OSINC)\winperf.h $(OSINC)\winreg.h $(OSINC)\winsock.h \ + $(OSINC)\winspool.h $(OSINC)\winsvc.h $(OSINC)\winuser.h \ + $(OSINC)\winver.h + +$(OBJDIR)\utstream.obj $(OBJDIR)\utstream.lst: .\utstream.cpp \ + $(CAIROLE)\ole232\inc\reterr.h $(CAIROLE)\common\cobjerr.h \ + $(CAIROLE)\common\rpcferr.h $(CAIROLE)\h\coguid.h \ + $(CAIROLE)\h\compobj.h $(CAIROLE)\h\dvobj.h $(CAIROLE)\h\initguid.h \ + $(CAIROLE)\h\moniker.h $(CAIROLE)\h\ole2.h $(CAIROLE)\h\ole2dbg.h \ + $(CAIROLE)\h\oleguid.h $(CAIROLE)\h\scode.h $(CAIROLE)\h\storage.h \ + $(CAIROLE)\ih\debug.h $(CAIROLE)\ih\map_kv.h $(CAIROLE)\ih\ole2sp.h \ + $(CAIROLE)\ih\olecoll.h $(CAIROLE)\ih\olemem.h \ + $(CAIROLE)\ih\privguid.h $(CAIROLE)\ih\utils.h \ + $(CAIROLE)\ih\utstream.h $(CAIROLE)\ih\valid.h \ + $(CAIROLE)\ole232\inc\ole2int.h $(COMMON)\ih\dbgpoint.hxx \ + $(COMMON)\ih\debnot.h $(COMMON)\ih\winnot.h $(CRTINC)\limits.h \ + $(CRTINC)\ctype.h $(CRTINC)\excpt.h $(CRTINC)\malloc.h \ + $(CRTINC)\stdarg.h $(CRTINC)\stddef.h $(CRTINC)\stdlib.h \ + $(CRTINC)\string.h $(CRTINC)\wchar.h $(OSINC)\cderr.h \ + $(OSINC)\commdlg.h $(OSINC)\dde.h $(OSINC)\ddeml.h $(OSINC)\dlgs.h \ + $(OSINC)\drivinit.h $(OSINC)\lzexpand.h $(OSINC)\mmsystem.h \ + $(OSINC)\nb30.h $(OSINC)\ole.h $(OSINC)\rpc.h $(OSINC)\rpcdce.h \ + $(OSINC)\rpcdcep.h $(OSINC)\rpcnsi.h $(OSINC)\rpcnterr.h \ + $(OSINC)\shellapi.h $(OSINC)\widewrap.h $(OSINC)\winbase.h \ + $(OSINC)\wincon.h $(OSINC)\windef.h $(OSINC)\windows.h \ + $(OSINC)\winerror.h $(OSINC)\wingdi.h $(OSINC)\winmm.h \ + $(OSINC)\winnetwk.h $(OSINC)\winnls.h $(OSINC)\winnt.h \ + $(OSINC)\winperf.h $(OSINC)\winreg.h $(OSINC)\winsock.h \ + $(OSINC)\winspool.h $(OSINC)\winsvc.h $(OSINC)\winuser.h \ + $(OSINC)\winver.h + diff --git a/private/ole32/ole232/util/dirs b/private/ole32/ole232/util/dirs new file mode 100644 index 000000000..1d0b9edbb --- /dev/null +++ b/private/ole32/ole232/util/dirs @@ -0,0 +1,38 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + dirs. + +Abstract: + + This file specifies the subdirectories of the current directory that + contain component makefiles. + + +Author: + + Donna Liu (DonnaLi) 19-Dec-1993 + +!ENDIF + +# +# This is a list of all subdirectories that build required components. +# Each subdirectory name should appear on a line by itself. The build +# follows the order in which the subdirectories are specified. +# + +DIRS= + +# +# This is a list of all subdirectories that build optional components. +# Each subdirectory name should appear on a line by itself. The build +# follows the order in which the subdirectories are specified. +# + +OPTIONAL_DIRS= \ + \ + \ + daytona diff --git a/private/ole32/ole232/util/filelist.mk b/private/ole32/ole232/util/filelist.mk new file mode 100644 index 000000000..53af21763 --- /dev/null +++ b/private/ole32/ole232/util/filelist.mk @@ -0,0 +1,54 @@ +############################################################################ +# +# Copyright (C) 1992, Microsoft Corporation. +# +# All rights reserved. +# +############################################################################ + + +# +# Name of target. Include an extension (.dll, .lib, .exe) +# If the target is part of the release, set RELEASE to 1. +# + +TARGET = util.lib + +RELEASE = + + +# +# Source files. Remember to prefix each name with .\ +# + +CPPFILES = \ + .\convert.cpp \ + .\global.cpp \ + .\info.cpp \ + .\map_kv.cpp \ + .\ole2util.cpp \ + .\olenew.cpp \ + .\plex.cpp \ + .\utils.cpp \ + .\utstream.cpp \ + +RCFILES = + + +# +# Libraries and other object files to link. +# + +DEFFILE = + +LIBS = + +OBJFILES = + +# +# Precompiled headers. +# + +PFILE = + +!include $(CAIROLE)\ole232\ole.mk diff --git a/private/ole32/ole232/util/global.cpp b/private/ole32/ole232/util/global.cpp new file mode 100644 index 000000000..25c95487f --- /dev/null +++ b/private/ole32/ole232/util/global.cpp @@ -0,0 +1,821 @@ +//+---------------------------------------------------------------------------- +// +// File: +// global.cpp +// +// Contents: +// Ut functions that deal with HGlobals for debugging; +// see le2int.h +// +// Classes: +// +// Functions: +// UtGlobalAlloc +// UtGlobalReAlloc +// UtGlobalLock +// UtGlobalUnlock +// UtGlobalFree +// UtGlobalFlush +// UtSetClipboardData +// +// History: +// 12/20/93 - ChrisWe - created +// 01/11/94 - alexgo - added VDATEHEAP macros to every function +// 02/25/94 AlexT Add some generic integrity checking +// 03/30/94 AlexT Add UtSetClipboardData +// +// Notes: +// +// These routines are designed to catch bugs that corrupt GlobalAlloc memory. +// We cannot guarantee that all global memory will be manipulated with these +// routines (e.g. OLE might allocate a handle and the client application +// might free it), so we can't require that these routines be used in pairs. +// +//----------------------------------------------------------------------------- + + +#include <le2int.h> + +#if DBG==1 && defined(WIN32) +#include <olesem.hxx> + +ASSERTDATA + +// undefine these, so we don't call ourselves recursively +// if this module is used, these are defined in le2int.h to replace +// the existing allocator with the functions here +#undef GlobalAlloc +#undef GlobalReAlloc +#undef GlobalLock +#undef GlobalUnlock +#undef GlobalFree +#undef SetClipboardData + +// Same ones as in memapi.cxx +#define OLEMEM_ALLOCBYTE 0xde +#define OLEMEM_FREEBYTE 0xed + +typedef struct s_GlobalAllocInfo +{ + HGLOBAL hGlobal; // A GlobalAlloc'd HGLOBAL + ULONG cbGlobalSize; // GlobalSize(hGlobal) + ULONG cbUser; // size requested by caller + ULONG ulIndex; // allocation index (1st, 2nd...) + struct s_GlobalAllocInfo *pNext; +} SGLOBALALLOCINFO, *PSGLOBALALLOCINFO; + +//+------------------------------------------------------------------------- +// +// Class: CGlobalTrack +// +// Purpose: GlobalAlloc memory tracking +// +// History: 25-Feb-94 AlexT Created +// +// Notes: +// +//-------------------------------------------------------------------------- + +class CGlobalTrack +{ + public: + + // + // We only have a constructor for debug builds, to ensure this object + // is statically allocated. Statically allocated objects are initialized + // to all zeroes, which is what we need. + // + + CGlobalTrack(); + + HGLOBAL cgtGlobalAlloc(UINT uiFlag, DWORD cbUser); + HGLOBAL cgtGlobalReAlloc(HGLOBAL hGlobal, DWORD cbUser, UINT uiFlag); + HGLOBAL cgtGlobalFree(HGLOBAL hGlobal); + LPVOID cgtGlobalLock(HGLOBAL hGlobal); + BOOL cgtGlobalUnlock(HGLOBAL hGlobal); + + void cgtVerifyAll(void); + void cgtFlushTracking(void); + BOOL cgtStopTracking(HGLOBAL hGlobal); + + private: + ULONG CalculateAllocSize(ULONG cbUser); + void InitializeRegion(HGLOBAL hGlobal, ULONG cbStart, ULONG cbEnd); + void Track(HGLOBAL hGlobal, ULONG cbUser); + void Retrack(HGLOBAL hOld, HGLOBAL hNew); + void VerifyHandle(HGLOBAL hGlobal); + + ULONG _ulIndex; + PSGLOBALALLOCINFO _pRoot; + static COleStaticMutexSem _mxsGlobalMemory; +}; + +COleStaticMutexSem CGlobalTrack::_mxsGlobalMemory; + +CGlobalTrack gGlobalTrack; + + + +//+------------------------------------------------------------------------- +// +// Member: CGlobalTrack::CGlobalTrack, public +// +// Synopsis: constructor +// +// History: 28-Feb-94 AlexT Created +// +//-------------------------------------------------------------------------- + +CGlobalTrack::CGlobalTrack() +{ + Win4Assert (g_fDllState == DLL_STATE_STATIC_CONSTRUCTING); + Win4Assert (_pRoot == NULL && _ulIndex == 0); +} + + + +//+------------------------------------------------------------------------- +// +// Member: CGlobalTrack::cgtGlobalAlloc, public +// +// Synopsis: Debugging version of GlobalAlloc +// +// Arguments: [uiFlag] -- allocation flags +// [cbUser] -- requested allocation size +// +// Requires: We must return a "real" GlobalAlloc'd pointer, because +// we may not necessarily be the ones to free it. +// +// Returns: HGLOBAL +// +// Algorithm: We allocate an extra amount to form a tail and initialize it +// to a known value. +// +// History: 25-Feb-94 AlexT Added this prologue +// +// Notes: +// +//-------------------------------------------------------------------------- + +HGLOBAL CGlobalTrack::cgtGlobalAlloc(UINT uiFlag, DWORD cbUser) +{ + VDATEHEAP(); + + ULONG cbAlloc; + HGLOBAL hGlobal; + + cbAlloc = CalculateAllocSize(cbUser); + hGlobal = GlobalAlloc(uiFlag, cbAlloc); + if (NULL == hGlobal) + { + LEDebugOut((DEB_WARN, "GlobalAlloc(%ld) failed - %lx\n", cbAlloc, + GetLastError())); + } + else + { + if (uiFlag & GMEM_ZEROINIT) + { + // Caller asked for zeroinit, so we only initialize the tail + InitializeRegion(hGlobal, cbUser, cbAlloc); + } + else + { + // Caller did not ask for zeroinit, so we initialize the whole + // region + InitializeRegion(hGlobal, 0, cbAlloc); + } + + Track(hGlobal, cbUser); + } + + return(hGlobal); +} + +//+------------------------------------------------------------------------- +// +// Member: CGlobalTrack::cgtGlobalReAlloc, public +// +// Synopsis: Debugging version of GlobalReAlloc +// +// Arguments: [hGlobal] -- handle to reallocate +// [cbUser] -- requested allocation size +// [uiFlag] -- allocation flags +// +// Returns: reallocated handle +// +// Algorithm: +// +// if (modify only) +// reallocate +// else +// reallocate with tail +// initialize tail +// +// update tracking information +// +// History: 25-Feb-94 AlexT Added this prologue +// +// Notes: +// +//-------------------------------------------------------------------------- + +HGLOBAL CGlobalTrack::cgtGlobalReAlloc(HGLOBAL hGlobal, DWORD cbUser, UINT uiFlag) +{ + VDATEHEAP(); + + HGLOBAL hNew; + ULONG cbAlloc; + + VerifyHandle(hGlobal); + + if (uiFlag & GMEM_MODIFY) + { + // We're not changing sizes, so there's no work for us to do + + LEDebugOut((DEB_WARN, "UtGlobalReAlloc modifying global handle\n")); + hNew = GlobalReAlloc(hGlobal, cbUser, uiFlag); + } + else + { + cbAlloc = CalculateAllocSize(cbUser); + hNew = GlobalReAlloc(hGlobal, cbAlloc, uiFlag); + if (NULL == hNew) + { + LEDebugOut((DEB_WARN, "GlobalReAlloc failed - %lx\n", + GetLastError())); + } + else + { + InitializeRegion(hNew, cbUser, cbAlloc); + } + } + + if (NULL != hNew) + { + if (uiFlag & GMEM_MODIFY) + { + // Retrack will only track hNew if we were tracking hGlobal + Retrack(hGlobal, hNew); + } + else + { + // We've allocated a new block, so we always want to track the + // new one + cgtStopTracking(hGlobal); + Track(hNew, cbUser); + } + } + + return(hNew); +} + +//+------------------------------------------------------------------------- +// +// Member: CGlobalTrack::cgtGlobalFree, public +// +// Synopsis: Debugging version of GlobalReAlloc +// +// Arguments: [hGlobal] -- global handle to free +// +// Returns: Same as GlobalFree +// +// Algorithm: +// +// History: 25-Feb-94 AlexT Created +// +// Notes: +// +//-------------------------------------------------------------------------- + +HGLOBAL CGlobalTrack::cgtGlobalFree(HGLOBAL hGlobal) +{ + VDATEHEAP(); + + HGLOBAL hReturn; + + VerifyHandle(hGlobal); + + hReturn = GlobalFree(hGlobal); + + if (NULL == hReturn) + { + cgtStopTracking(hGlobal); + } + else + { + LEDebugOut((DEB_WARN, "GlobalFree did not free %lx\n", hGlobal)); + } + + return(hReturn); +} + +//+------------------------------------------------------------------------- +// +// Member: CGlobalTrack::cgtGlobalLock, public +// +// Synopsis: Debugging version of GlobalLock +// +// Arguments: [hGlobal] -- global memory handle +// +// Returns: Same as GlobalLock +// +// History: 25-Feb-94 AlexT Created +// +// Notes: +// +//-------------------------------------------------------------------------- + +LPVOID CGlobalTrack::cgtGlobalLock(HGLOBAL hGlobal) +{ + VDATEHEAP(); + + VerifyHandle(hGlobal); + return(GlobalLock(hGlobal)); +} + +//+------------------------------------------------------------------------- +// +// Member: CGlobalTrack::cgtGlobalUnlock, public +// +// Synopsis: Debugging version of GlobalUnlock +// +// Arguments: [hGlobal] -- global memory handle +// +// Returns: Same as GlobalUnlock +// +// History: 25-Feb-94 AlexT Created +// +// Notes: +// +//-------------------------------------------------------------------------- + +BOOL CGlobalTrack::cgtGlobalUnlock(HGLOBAL hGlobal) +{ + VDATEHEAP(); + + VerifyHandle(hGlobal); + return(GlobalUnlock(hGlobal)); +} + +//+------------------------------------------------------------------------- +// +// Member: CGlobalTrack::cgtVerifyAll, public +// +// Synopsis: Verify all tracked handles +// +// History: 28-Feb-94 AlexT Created +// +// Notes: +// +//-------------------------------------------------------------------------- + +void CGlobalTrack::cgtVerifyAll(void) +{ + VerifyHandle(NULL); +} + +//+------------------------------------------------------------------------- +// +// Member: CGlobalTrack::cgtFlushTracking +// +// Synopsis: Stops all tracking +// +// Effects: Frees all internal memory +// +// History: 28-Feb-94 AlexT Created +// +// Notes: +// +//-------------------------------------------------------------------------- + +void CGlobalTrack::cgtFlushTracking(void) +{ + COleStaticLock lck(_mxsGlobalMemory); + BOOL bResult; + + while (NULL != _pRoot) + { + bResult = cgtStopTracking(_pRoot->hGlobal); + Assert(bResult && "CGT::cgtFlushTracking problem"); + } +} + +//+------------------------------------------------------------------------- +// +// Member: CGlobalTrack::CalculateAllocSize, private +// +// Synopsis: calculate total allocation size (inluding tail) +// +// Arguments: [cbUser] -- requested size +// +// Returns: total count of bytes to allocate +// +// Algorithm: calculate bytes needed to have at least one guard page at the +// end +// +// History: 28-Feb-94 AlexT Created +// +// Notes: By keeping this calculation in one location we make it +// easier to maintain. +// +//-------------------------------------------------------------------------- + +ULONG CGlobalTrack::CalculateAllocSize(ULONG cbUser) +{ + SYSTEM_INFO si; + ULONG cbAlloc; + +#ifdef _CHICAGO_ + // BUGBUG Chicago: GetSystemInfo not yet implemented + si.dwPageSize = 0x1000; +#else + GetSystemInfo(&si); +#endif + + // Calculate how many pages are need to cover cbUser + cbAlloc = ((cbUser + si.dwPageSize - 1) / si.dwPageSize) * si.dwPageSize; + + // Add an extra page so that the tail is at least one page long + cbAlloc += si.dwPageSize; + + return(cbAlloc); +} + +//+------------------------------------------------------------------------- +// +// Member: CGlobalTrack::InitializeRegion, private +// +// Synopsis: initialize region to bad value +// +// Effects: fills in memory region +// +// Arguments: [hGlobal] -- global memory handle +// [cbStart] -- count of bytes to skip +// [cbEnd] -- end offset (exclusive) +// +// Requires: cbEnd > cbStart +// +// Algorithm: fill in hGlobal from cbStart (inclusive) to cbEnd (exclusive) +// +// History: 28-Feb-94 AlexT Created +// +// Notes: +// +//-------------------------------------------------------------------------- + +void CGlobalTrack::InitializeRegion(HGLOBAL hGlobal, ULONG cbStart, ULONG cbEnd) +{ + BYTE *pbStart; + BYTE *pb; + + Assert(cbStart < cbEnd && "illogical parameters"); + Assert(cbEnd <= GlobalSize(hGlobal) && "global memory too small"); + + // GlobalLock on GMEM_FIXED memory is a nop, so this is a safe call + pbStart = (BYTE *) GlobalLock(hGlobal); + + if (NULL == pbStart) + { + // Shouldn't have failed - (we allocated > 0 bytes) + + LEDebugOut((DEB_WARN, "GlobalLock failed - %lx\n", GetLastError())); + return; + } + + // Initialize the tail portion of the memory + for (pb = pbStart + cbStart; pb < pbStart + cbEnd; pb++) + { + *pb = OLEMEM_ALLOCBYTE; + } + + GlobalUnlock(hGlobal); +} + +//+------------------------------------------------------------------------- +// +// Member: CGlobalTrack::Track, private +// +// Synopsis: +// +// Effects: +// +// Arguments: [hGlobal] -- global memory handle +// [cbUser] -- user allocation size +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Derivation: +// +// Algorithm: +// +// History: 28-Feb-94 AlexT Created +// +// Notes: +// +//-------------------------------------------------------------------------- + +void CGlobalTrack::Track(HGLOBAL hGlobal, ULONG cbUser) +{ + COleStaticLock lck(_mxsGlobalMemory); + PSGLOBALALLOCINFO pgi; + + if (cgtStopTracking(hGlobal)) + { + // If it's already in our list, it's possible that someone else + // freed the HGLOBAL without telling us - remove our stale one + LEDebugOut((DEB_WARN, "CGT::Track - %lx was already in list!\n", + hGlobal)); + } + + pgi = (PSGLOBALALLOCINFO) PrivMemAlloc(sizeof(SGLOBALALLOCINFO)); + if (NULL == pgi) + { + LEDebugOut((DEB_WARN, "CGT::Insert - PrivMemAlloc failed\n")); + + // Okay fine - we just won't track this one + + return; + } + + pgi->hGlobal = hGlobal; + pgi->cbGlobalSize = GlobalSize(hGlobal); + Assert((0 == cbUser || pgi->cbGlobalSize > 0) && "GlobalSize failed - bad handle?"); + pgi->cbUser = cbUser; + pgi->ulIndex = ++_ulIndex; + pgi->pNext = _pRoot; + _pRoot = pgi; +} + +//+------------------------------------------------------------------------- +// +// Member: CGlobalTrack::Retrack, private +// +// Synopsis: +// +// Effects: +// +// Arguments: [hOld] -- previous handle +// [hNew] -- new handle +// +// Modifies: +// +// Algorithm: +// +// History: 28-Feb-94 AlexT Created +// +// Notes: +// +//-------------------------------------------------------------------------- + +void CGlobalTrack::Retrack(HGLOBAL hOld, HGLOBAL hNew) +{ + COleStaticLock lck(_mxsGlobalMemory); + PSGLOBALALLOCINFO pgi; + + if (hOld != hNew && cgtStopTracking(hNew)) + { + // If hNew was already in the list, it's possible that someone else + // freed the HGLOBAL without telling us so we removed the stale one + LEDebugOut((DEB_WARN, "CGT::Retrack - %lx was already in list!\n", hNew)); + } + + for (pgi = _pRoot; NULL != pgi; pgi = pgi->pNext) + { + if (pgi->hGlobal == hOld) + { + pgi->hGlobal = hNew; + break; + } + } + + if (NULL == pgi) + { + // We didn't find hOld + LEDebugOut((DEB_WARN, "CGT::Retrack - hOld (%lx) not found\n", hOld)); + } +} + +//+------------------------------------------------------------------------- +// +// Member: CGlobalTrack::cgtStopTracking, public +// +// Synopsis: +// +// Effects: +// +// Arguments: [hGlobal] -- global handle +// +// Modifies: +// +// Algorithm: +// +// History: 28-Feb-94 AlexT Created +// +// Notes: +// +//-------------------------------------------------------------------------- + +BOOL CGlobalTrack::cgtStopTracking(HGLOBAL hGlobal) +{ + COleStaticLock lck(_mxsGlobalMemory); + PSGLOBALALLOCINFO *ppgi = &_pRoot; + PSGLOBALALLOCINFO pgi; + + while (*ppgi != NULL && (*ppgi)->hGlobal != hGlobal) + { + ppgi = &((*ppgi)->pNext); + } + + if (NULL == *ppgi) + { + return(FALSE); + } + + pgi = *ppgi; + Assert(pgi->hGlobal == hGlobal && "CGT::cgtStopTracking search problem"); + + *ppgi = pgi->pNext; + + PrivMemFree(pgi); + return(TRUE); +} + +//+------------------------------------------------------------------------- +// +// Member: CGlobalTrack::VerifyHandle, private +// +// Synopsis: Verify global handle +// +// Arguments: [hGlobal] -- global memory handle +// +// Signals: Asserts if bad +// +// Algorithm: +// +// History: 28-Feb-94 AlexT Created +// 22-Jun-94 AlexT Allow for handle to have been freed and +// reallocated under us +// +//-------------------------------------------------------------------------- + +void CGlobalTrack::VerifyHandle(HGLOBAL hGlobal) +{ + COleStaticLock lck(_mxsGlobalMemory); + PSGLOBALALLOCINFO pgi, pgiNext; + ULONG cbAlloc; + BYTE *pbStart; + BYTE *pb; + + // Note that we use a while loop (recording pgiNext up front) instead + // of a for loop because pgi will get removed from the list if we call + // cgtStopTracking on it + + pgi = _pRoot; + while (NULL != pgi) + { + pgiNext = pgi->pNext; + + if (NULL == hGlobal || pgi->hGlobal == hGlobal) + { + if (pgi->cbGlobalSize != GlobalSize(pgi->hGlobal)) + { + // pgi->hGlobal's size has changed since we started tracking + // it; it must have been freed or reallocated by someone + // else. Stop tracking it. + + // This call will remove pgi from the list (so we NULL it to + // make sure we don't try reusing it)! + + cgtStopTracking(pgi->hGlobal); + pgi = NULL; + } + else + { + cbAlloc = CalculateAllocSize(pgi->cbUser); + + pbStart = (BYTE *) GlobalLock(pgi->hGlobal); + + // it is legitimate to have a zero length (NULL memory) handle + if (NULL == pbStart) + { + LEDebugOut((DEB_WARN, "GlobalLock failed - %lx\n", + GetLastError())); + } + else + { + for (pb = pbStart + pgi->cbUser; + pb < pbStart + cbAlloc; + pb++) + { + if (*pb != OLEMEM_ALLOCBYTE) + break; + } + + if (pb < pbStart + cbAlloc) + { + // In general an application may have freed and reallocated + // any HGLOBAL, so we can only warn about corruption. + + LEDebugOut((DEB_WARN, "HGLOBAL #%ld may be corrupt\n", + pgi->ulIndex)); +#ifdef GLOBALDBG + // If GLOBALDBG is true, then all allocations should be + // coming through these routines. In this case we assert + // if we've found corruption. + Assert(0 && "CGlobalTrack::VerifyHandle - HGLOBAL corrupt"); +#endif + } + + GlobalUnlock(pgi->hGlobal); + } + } + } + + pgi = pgiNext; + } +} + +//+------------------------------------------------------------------------- +// +// Function: UtGlobalAlloc, ReAlloc, Free, Lock, Unlock +// +// Synopsis: Debug versions of Global memory routines +// +// Arguments: Same as Windows APIs +// +// History: 28-Feb-94 AlexT Created +// +// Notes: These entry points just call the worker routines +// +//-------------------------------------------------------------------------- + +extern "C" HGLOBAL WINAPI UtGlobalAlloc(UINT uiFlag, DWORD cbUser) +{ + return gGlobalTrack.cgtGlobalAlloc(uiFlag, cbUser); +} + +extern "C" HGLOBAL WINAPI UtGlobalReAlloc(HGLOBAL hGlobal, DWORD cbUser, UINT uiFlag) +{ + return gGlobalTrack.cgtGlobalReAlloc(hGlobal, cbUser, uiFlag); +} + +extern "C" LPVOID WINAPI UtGlobalLock(HGLOBAL hGlobal) +{ + return gGlobalTrack.cgtGlobalLock(hGlobal); +} + +extern "C" BOOL WINAPI UtGlobalUnlock(HGLOBAL hGlobal) +{ + return gGlobalTrack.cgtGlobalUnlock(hGlobal); +} + +extern "C" HGLOBAL WINAPI UtGlobalFree(HGLOBAL hGlobal) +{ + return gGlobalTrack.cgtGlobalFree(hGlobal); +} + +extern "C" void UtGlobalFlushTracking(void) +{ + gGlobalTrack.cgtFlushTracking(); +} + +//+------------------------------------------------------------------------- +// +// Function: UtSetClipboardData +// +// Synopsis: Calls Windows SetClipboardData and stops tracking the handle +// +// Arguments: [uFormat] -- clipboard format +// [hMem] -- data handle +// +// Returns: Same as SetClipboard +// +// Algorithm: If SetClipboardData succeeds, stop tracking the handle +// +// History: 30-Mar-94 AlexT Created +// +// Notes: +// +//-------------------------------------------------------------------------- + +extern "C" HANDLE WINAPI UtSetClipboardData(UINT uFormat, HANDLE hMem) +{ + HANDLE hRet; + + hRet = SetClipboardData(uFormat, hMem); + + if (NULL != hRet) + { + gGlobalTrack.cgtStopTracking(hMem); + } + + return(hRet); +} + +#endif // DBG==1 && defined(WIN32) diff --git a/private/ole32/ole232/util/info.cpp b/private/ole32/ole232/util/info.cpp new file mode 100644 index 000000000..5e2d7abd5 --- /dev/null +++ b/private/ole32/ole232/util/info.cpp @@ -0,0 +1,65 @@ + +//+------------------------------------------------------------------------- +// +// Microsoft Windows +// Copyright (C) Microsoft Corporation, 1992 - 1993. +// +// File: info.cpp +// +// Contents: RegisterWithCommnot and other hacks to build in +// the cairo environment +// +// Classes: +// +// Functions: +// +// History: dd-mmm-yy Author Comment +// 26-Oct-93 alexgo snagged and hacked from RickSa's stuff +// +// Notes: +// This stuff is OBSOLETE!! Remove it whenever BryanT +// removes the calls from the dll loaders... +// +//-------------------------------------------------------------------------- + + +#include <le2int.h> + +// BUGBUG: Temporary definitions of functions these probably can be removed +// as they are probably obsolete. + + +//+------------------------------------------------------------------- +// +// Function: RegisterWithCommnot +// +// Synopsis: Used by Cairo to work around DLL unloading problems +// +// Arguments: <none> +// +// History: 06-Oct-92 BryanT Created +// +//-------------------------------------------------------------------- +STDAPI_(void) RegisterWithCommnot( void ) +{ +} + +//+------------------------------------------------------------------- +// +// Function: DeRegisterWithCommnot +// +// Synopsis: Used by Cairo to work around DLL unloading problems +// +// Arguments: <none> +// +// History: 06-Oct-92 BryanT Created +// +// Notes: BUGBUG: Keep in touch with BryanT to see if this is +// obsolete. +// +//-------------------------------------------------------------------- + +STDAPI_(void) DeRegisterWithCommnot( void ) +{ +} + diff --git a/private/ole32/ole232/util/makefile b/private/ole32/ole232/util/makefile new file mode 100644 index 000000000..1725b5e9a --- /dev/null +++ b/private/ole32/ole232/util/makefile @@ -0,0 +1,26 @@ +############################################################################ +# +# Microsoft Windows +# Copyright (C) Microsoft Corporation, 1992 - 1992. +# All rights reserved. +# +############################################################################ + +!ifdef NTMAKEENV + +# We need to do the following so that build will stop reading from the +# pipe. + +all : + echo $(BUILDMSG) + +clean : all + +!else # NTMAKEENV + +default: all +!include filelist.mk +!include $(COMMON)\src\win40.mk +!include depend.mk + +!endif # NTMAKEENV diff --git a/private/ole32/ole232/util/map_kv.cpp b/private/ole32/ole232/util/map_kv.cpp new file mode 100644 index 000000000..7ba103fb0 --- /dev/null +++ b/private/ole32/ole232/util/map_kv.cpp @@ -0,0 +1,666 @@ +///////////////////////////////////////////////////////////////////////////// +// class CMapKeyToValue - a mapping from 'KEY's to 'VALUE's, passed in as +// pv/cb pairs. The keys can be variable length, although we optmizize the +// case when they are all the same. +// +///////////////////////////////////////////////////////////////////////////// + +#include <le2int.h> +#pragma SEG(map_kv) + +#include "map_kv.h" + +#include "plex.h" +ASSERTDATA + + +///////////////////////////////////////////////////////////////////////////// + + +#pragma SEG(CMapKeyToValue_ctor) +CMapKeyToValue::CMapKeyToValue(UINT cbValue, UINT cbKey, + int nBlockSize, LPFNHASHKEY lpfnHashKey, UINT nHashSize) +{ + VDATEHEAP(); + + Assert(nBlockSize > 0); + + m_cbValue = cbValue; + m_cbKey = cbKey; + m_cbKeyInAssoc = cbKey == 0 ? sizeof(CKeyWrap) : cbKey; + + m_pHashTable = NULL; + m_nHashTableSize = nHashSize; + m_lpfnHashKey = lpfnHashKey; + + m_nCount = 0; + m_pFreeList = NULL; + m_pBlocks = NULL; + m_nBlockSize = nBlockSize; +} + +#pragma SEG(CMapKeyToValue_dtor) +CMapKeyToValue::~CMapKeyToValue() +{ + VDATEHEAP(); + + ASSERT_VALID(this); + RemoveAll(); + Assert(m_nCount == 0); +} + +#define LOCKTHIS +#define UNLOCKTHIS + +#ifdef NEVER +void CMapKeyToValue::LockThis(void) +{ + VDATEHEAP(); + + LOCKTHIS; +} + +void CMapKeyToValue::UnlockThis(void) +{ + VDATEHEAP(); + + UNLOCKTHIS; +} + +#endif //NEVER + +#pragma SEG(MKVDefaultHashKey) +// simple, default hash function +// REVIEW: need to check the value in this for GUIDs and strings +STDAPI_(UINT) MKVDefaultHashKey(LPVOID pKey, UINT cbKey) +{ + VDATEHEAP(); + + UINT hash = 0; + BYTE FAR* lpb = (BYTE FAR*)pKey; + + while (cbKey-- != 0) + hash = 257 * hash + *lpb++; + + return hash; +} + + +#pragma SEG(CMapKeyToValue_InitHashTable) +BOOL CMapKeyToValue::InitHashTable() +{ + VDATEHEAP(); + + ASSERT_VALID(this); + Assert(m_nHashTableSize > 0); + + if (m_pHashTable != NULL) + return TRUE; + + Assert(m_nCount == 0); + + if ((m_pHashTable = (CAssoc FAR* FAR*)PrivMemAlloc(m_nHashTableSize * + sizeof(CAssoc FAR*))) == NULL) + return FALSE; + + _xmemset(m_pHashTable, 0, sizeof(CAssoc FAR*) * m_nHashTableSize); + + ASSERT_VALID(this); + + return TRUE; +} + + +#pragma SEG(CMapKeyToValue_RemoveAll) +void CMapKeyToValue::RemoveAll() +{ + VDATEHEAP(); + + LOCKTHIS; + + ASSERT_VALID(this); + + // free all key values and then hash table + if (m_pHashTable != NULL) + { + // destroy assocs + for (UINT nHash = 0; nHash < m_nHashTableSize; nHash++) + { + register CAssoc FAR* pAssoc; + for (pAssoc = m_pHashTable[nHash]; pAssoc != NULL; + pAssoc = pAssoc->pNext) + // assoc itself is freed by FreeDataChain below + FreeAssocKey(pAssoc); + } + + // free hash table + PrivMemFree(m_pHashTable); + m_pHashTable = NULL; + } + + m_nCount = 0; + m_pFreeList = NULL; + m_pBlocks->FreeDataChain(); + m_pBlocks = NULL; + + ASSERT_VALID(this); + UNLOCKTHIS; +} + +///////////////////////////////////////////////////////////////////////////// +// Assoc helpers +// CAssoc's are singly linked all the time + +#pragma SEG(CMapKeyToValue_NewAssoc) +CMapKeyToValue::CAssoc FAR* + CMapKeyToValue::NewAssoc(UINT hash, LPVOID pKey, UINT cbKey, LPVOID pValue) +{ + VDATEHEAP(); + + if (m_pFreeList == NULL) + { + // add another block + CPlex FAR* newBlock = CPlex::Create(m_pBlocks, m_nBlockSize, SizeAssoc()); + + if (newBlock == NULL) + return NULL; + + // chain them into free list + register BYTE FAR* pbAssoc = (BYTE FAR*) newBlock->data(); + // free in reverse order to make it easier to debug + pbAssoc += (m_nBlockSize - 1) * SizeAssoc(); + for (int i = m_nBlockSize-1; i >= 0; i--, pbAssoc -= SizeAssoc()) + { + ((CAssoc FAR*)pbAssoc)->pNext = m_pFreeList; + m_pFreeList = (CAssoc FAR*)pbAssoc; + } + } + Assert(m_pFreeList != NULL); // we must have something + + CMapKeyToValue::CAssoc FAR* pAssoc = m_pFreeList; + + // init all fields except pNext while still on free list + pAssoc->nHashValue = hash; + if (!SetAssocKey(pAssoc, pKey, cbKey)) + return NULL; + + SetAssocValue(pAssoc, pValue); + + // remove from free list after successfully initializing it (except pNext) + m_pFreeList = m_pFreeList->pNext; + m_nCount++; + Assert(m_nCount > 0); // make sure we don't overflow + + return pAssoc; +} + + +#pragma SEG(CMapKeyToValue_FreeAssoc) +// free individual assoc by freeing key and putting on free list +void CMapKeyToValue::FreeAssoc(CMapKeyToValue::CAssoc FAR* pAssoc) +{ + VDATEHEAP(); + + pAssoc->pNext = m_pFreeList; + m_pFreeList = pAssoc; + m_nCount--; + Assert(m_nCount >= 0); // make sure we don't underflow + + FreeAssocKey(pAssoc); +} + + +#pragma SEG(CMapKeyToValue_GetAssocAt) +// find association (or return NULL) +CMapKeyToValue::CAssoc FAR* +CMapKeyToValue::GetAssocAt(LPVOID pKey, UINT cbKey, UINT FAR& nHash) const +{ + VDATEHEAP(); + + if (m_lpfnHashKey) + nHash = (*m_lpfnHashKey)(pKey, cbKey) % m_nHashTableSize; + else + nHash = MKVDefaultHashKey(pKey, cbKey) % m_nHashTableSize; + + if (m_pHashTable == NULL) + return NULL; + + // see if it exists + register CAssoc FAR* pAssoc; + for (pAssoc = m_pHashTable[nHash]; pAssoc != NULL; pAssoc = pAssoc->pNext) + { + if (CompareAssocKey(pAssoc, pKey, cbKey)) + return pAssoc; + } + return NULL; +} + + +#pragma SEG(CMapKeyToValue_CompareAssocKey) +BOOL CMapKeyToValue::CompareAssocKey(CAssoc FAR* pAssoc, LPVOID pKey2, UINT cbKey2) const +{ + VDATEHEAP(); + + LPVOID pKey1; + UINT cbKey1; + + GetAssocKeyPtr(pAssoc, &pKey1, &cbKey1); + return cbKey1 == cbKey2 && _xmemcmp(pKey1, pKey2, cbKey1) == 0; +} + + +#pragma SEG(CMapKeyToValue_SetAssocKey) +BOOL CMapKeyToValue::SetAssocKey(CAssoc FAR* pAssoc, LPVOID pKey, UINT cbKey) const +{ + VDATEHEAP(); + + Assert(cbKey == m_cbKey || m_cbKey == 0); + + if (m_cbKey == 0) + { + Assert(m_cbKeyInAssoc == sizeof(CKeyWrap)); + + // alloc, set size and pointer + if ((pAssoc->key.pKey = PrivMemAlloc(cbKey)) == NULL) + return FALSE; + + pAssoc->key.cbKey = cbKey; + } + + LPVOID pKeyTo; + + GetAssocKeyPtr(pAssoc, &pKeyTo, &cbKey); + + _xmemcpy(pKeyTo, pKey, cbKey); + + return TRUE; +} + + +#pragma SEG(CMapKeyToValue_GetAssocKeyPtr) +// gets pointer to key and its length +void CMapKeyToValue::GetAssocKeyPtr(CAssoc FAR* pAssoc, LPVOID FAR* ppKey,UINT FAR* pcbKey) const +{ + VDATEHEAP(); + + if (m_cbKey == 0) + { + // variable length key; go indirect + *ppKey = pAssoc->key.pKey; + *pcbKey = pAssoc->key.cbKey; + } + else + { + // fixed length key; key in assoc + *ppKey = (LPVOID)&pAssoc->key; + *pcbKey = m_cbKey; + } +} + + +#pragma SEG(CMapKeyToValue_FreeAssocKey) +void CMapKeyToValue::FreeAssocKey(CAssoc FAR* pAssoc) const +{ + VDATEHEAP(); + + if (m_cbKey == 0) + PrivMemFree(pAssoc->key.pKey); +} + + +#pragma SEG(CMapKeyToValue_GetAssocValuePtr) +void CMapKeyToValue::GetAssocValuePtr(CAssoc FAR* pAssoc, LPVOID FAR* ppValue) const +{ + VDATEHEAP(); + + *ppValue = (char FAR*)&pAssoc->key + m_cbKeyInAssoc; +} + + +#pragma SEG(CMapKeyToValue_GetAssocValue) +void CMapKeyToValue::GetAssocValue(CAssoc FAR* pAssoc, LPVOID pValue) const +{ + VDATEHEAP(); + + LPVOID pValueFrom; + GetAssocValuePtr(pAssoc, &pValueFrom); + Assert(pValue != NULL); + _xmemcpy(pValue, pValueFrom, m_cbValue); +} + + +#pragma SEG(CMapKeyToValue_SetAssocValue) +void CMapKeyToValue::SetAssocValue(CAssoc FAR* pAssoc, LPVOID pValue) const +{ + VDATEHEAP(); + + LPVOID pValueTo; + GetAssocValuePtr(pAssoc, &pValueTo); + if (pValue == NULL) + _xmemset(pValueTo, 0, m_cbValue); + else + _xmemcpy(pValueTo, pValue, m_cbValue); +} + + +///////////////////////////////////////////////////////////////////////////// + +#pragma SEG(CMapKeyToValue_Lookup) +// lookup value given key; return FALSE if key not found; in that +// case, the value is set to all zeros +BOOL CMapKeyToValue::Lookup(LPVOID pKey, UINT cbKey, LPVOID pValue) const +{ + VDATEHEAP(); + + UINT nHash; + BOOL fFound; + + LOCKTHIS; + fFound = LookupHKey((HMAPKEY)GetAssocAt(pKey, cbKey, nHash), pValue); + UNLOCKTHIS; + return fFound; +} + + +#pragma SEG(CMapKeyToValue_LookupHKey) +// lookup value given key; return FALSE if NULL (or bad) key; in that +// case, the value is set to all zeros +BOOL CMapKeyToValue::LookupHKey(HMAPKEY hKey, LPVOID pValue) const +{ + VDATEHEAP(); + + BOOL fFound = FALSE; + + LOCKTHIS; + + // REVIEW: would like some way to verify that hKey is valid + register CAssoc FAR* pAssoc = (CAssoc FAR*)hKey; + if (pAssoc == NULL) + { + _xmemset(pValue, 0, m_cbValue); + goto Exit; // not in map + } + + ASSERT_VALID(this); + + GetAssocValue(pAssoc, pValue); + fFound = TRUE; +Exit: + UNLOCKTHIS; + return fFound; +} + + +#pragma SEG(CMapKeyToValue_LookupAdd) +// lookup and if not found add; returns FALSE only if OOM; if added, +// value added and pointer passed are set to zeros. +BOOL CMapKeyToValue::LookupAdd(LPVOID pKey, UINT cbKey, LPVOID pValue) const +{ + VDATEHEAP(); + + BOOL fFound; + + LOCKTHIS; + + fFound = Lookup(pKey, cbKey, pValue); + if (!fFound) // value set to zeros since lookup failed + fFound = ((CMapKeyToValue FAR*)this)->SetAt(pKey, cbKey, NULL); + + UNLOCKTHIS; + return fFound; +} + + +#pragma SEG(CMapKeyToValue_SetAt) +// the only place new assocs are created; return FALSE if OOM; +// never returns FALSE if keys already exists +BOOL CMapKeyToValue::SetAt(LPVOID pKey, UINT cbKey, LPVOID pValue) +{ + VDATEHEAP(); + + UINT nHash; + register CAssoc FAR* pAssoc; + BOOL fFound = FALSE; + + LOCKTHIS; + + ASSERT_VALID(this); + + if ((pAssoc = GetAssocAt(pKey, cbKey, nHash)) == NULL) + { + if (!InitHashTable()) + // out of memory + goto Exit; + + // it doesn't exist, add a new Association + if ((pAssoc = NewAssoc(nHash, pKey, cbKey, pValue)) == NULL) + goto Exit; + + // put into hash table + pAssoc->pNext = m_pHashTable[nHash]; + m_pHashTable[nHash] = pAssoc; + + ASSERT_VALID(this); + } + else + SetAssocValue(pAssoc, pValue); + + fFound = TRUE; +Exit: + UNLOCKTHIS; + return fFound; +} + + +#pragma SEG(CMapKeyToValue_SetAtHKey) +// set existing hkey to value; return FALSE if NULL or bad key +BOOL CMapKeyToValue::SetAtHKey(HMAPKEY hKey, LPVOID pValue) +{ + VDATEHEAP(); + + BOOL fDone = FALSE; + LOCKTHIS; + // REVIEW: would like some way to verify that hKey is valid + register CAssoc FAR* pAssoc = (CAssoc FAR*)hKey; + if (pAssoc == NULL) + goto Exit; // not in map + + ASSERT_VALID(this); + + SetAssocValue(pAssoc, pValue); + fDone = TRUE; +Exit: + UNLOCKTHIS; + return fDone; +} + + +#pragma SEG(CMapKeyToValue_RemoveKey) +// remove key - return TRUE if removed +BOOL CMapKeyToValue::RemoveKey(LPVOID pKey, UINT cbKey) +{ + VDATEHEAP(); + + BOOL fFound = FALSE; + UINT i; + + LOCKTHIS; + ASSERT_VALID(this); + + if (m_pHashTable == NULL) + goto Exit; // nothing in the table + + register CAssoc FAR* FAR* ppAssocPrev; + if (m_lpfnHashKey) + i = (*m_lpfnHashKey)(pKey, cbKey) % m_nHashTableSize; + else + i = MKVDefaultHashKey(pKey, cbKey) % m_nHashTableSize; + + ppAssocPrev = &m_pHashTable[i]; + + CAssoc FAR* pAssoc; + for (pAssoc = *ppAssocPrev; pAssoc != NULL; pAssoc = pAssoc->pNext) + { + if (CompareAssocKey(pAssoc, pKey, cbKey)) + { + // remove it + *ppAssocPrev = pAssoc->pNext; // remove from list + FreeAssoc(pAssoc); + ASSERT_VALID(this); + fFound = TRUE; + break; + } + ppAssocPrev = &pAssoc->pNext; + } +Exit: + UNLOCKTHIS; + return fFound; +} + + +#pragma SEG(CMapKeyToValue_RemoveHKey) +// remove key based on pAssoc (HMAPKEY) +BOOL CMapKeyToValue::RemoveHKey(HMAPKEY hKey) +{ + VDATEHEAP(); + + BOOL fFound = FALSE; + + // REVIEW: would like some way to verify that hKey is valid + CAssoc FAR* pAssoc = (CAssoc FAR*)hKey; + + LOCKTHIS; + ASSERT_VALID(this); + + if (m_pHashTable == NULL) + goto Exit; // nothing in the table + + if (pAssoc == NULL || pAssoc->nHashValue >= m_nHashTableSize) + goto Exit; // null hkey or bad hash value + + register CAssoc FAR* FAR* ppAssocPrev; + ppAssocPrev = &m_pHashTable[pAssoc->nHashValue]; + + while (*ppAssocPrev != NULL) + { + if (*ppAssocPrev == pAssoc) + { + // remove it + *ppAssocPrev = pAssoc->pNext; // remove from list + FreeAssoc(pAssoc); + ASSERT_VALID(this); + fFound = TRUE; + break; + } + ppAssocPrev = &(*ppAssocPrev)->pNext; + } + +Exit: + UNLOCKTHIS; + return fFound; +} + + +#pragma SEG(CMapKeyToValue_GetHKey) +HMAPKEY CMapKeyToValue::GetHKey(LPVOID pKey, UINT cbKey) const +{ + VDATEHEAP(); + + UINT nHash; + HMAPKEY hKey; + + LOCKTHIS; + ASSERT_VALID(this); + + hKey = (HMAPKEY)GetAssocAt(pKey, cbKey, nHash); + UNLOCKTHIS; + return hKey; +} + + +///////////////////////////////////////////////////////////////////////////// +// Iterating + +// for fixed length keys, copies key to pKey; pcbKey can be NULL; +// for variable length keys, copies pointer to key to pKey; sets pcbKey. + +#pragma SEG(CMapKeyToValue_GetNextAssoc) +void CMapKeyToValue::GetNextAssoc(POSITION FAR* pNextPosition, + LPVOID pKey, UINT FAR* pcbKey, LPVOID pValue) const +{ + VDATEHEAP(); + + ASSERT_VALID(this); + + Assert(m_pHashTable != NULL); // never call on empty map + + register CAssoc FAR* pAssocRet = (CAssoc FAR*)*pNextPosition; + Assert(pAssocRet != NULL); + + if (pAssocRet == (CAssoc FAR*) BEFORE_START_POSITION) + { + // find the first association + for (UINT nBucket = 0; nBucket < m_nHashTableSize; nBucket++) + if ((pAssocRet = m_pHashTable[nBucket]) != NULL) + break; + Assert(pAssocRet != NULL); // must find something + } + + // find next association + CAssoc FAR* pAssocNext; + if ((pAssocNext = pAssocRet->pNext) == NULL) + { + // go to next bucket + for (UINT nBucket = pAssocRet->nHashValue + 1; + nBucket < m_nHashTableSize; nBucket++) + if ((pAssocNext = m_pHashTable[nBucket]) != NULL) + break; + } + + // fill in return data + *pNextPosition = (POSITION) pAssocNext; + + // fill in key/pointer to key + LPVOID pKeyFrom; + UINT cbKey; + GetAssocKeyPtr(pAssocRet, &pKeyFrom, &cbKey); + if (m_cbKey == 0) + // variable length key; just return pointer to key itself + *(void FAR* FAR*)pKey = pKeyFrom; + else + _xmemcpy(pKey, pKeyFrom, cbKey); + + if (pcbKey != NULL) + *pcbKey = cbKey; + + // get value + GetAssocValue(pAssocRet, pValue); +} + +///////////////////////////////////////////////////////////////////////////// + +#pragma SEG(CMapKeyToValue_AssertValid) +void CMapKeyToValue::AssertValid() const +{ + VDATEHEAP(); + +#ifdef _DEBUG + Assert(m_cbKeyInAssoc == (m_cbKey == 0 ? sizeof(CKeyWrap) : m_cbKey)); + + Assert(m_nHashTableSize > 0); + Assert(m_nCount == 0 || m_pHashTable != NULL); + + if (m_pHashTable != NULL) + Assert(!IsBadReadPtr(m_pHashTable, m_nHashTableSize * sizeof(CAssoc FAR*))); + + if (m_lpfnHashKey) + Assert(!IsBadCodePtr((FARPROC)m_lpfnHashKey)); + + if (m_pFreeList != NULL) + Assert(!IsBadReadPtr(m_pFreeList, SizeAssoc())); + + if (m_pBlocks != NULL) + Assert(!IsBadReadPtr(m_pBlocks, SizeAssoc() * m_nBlockSize)); + +#endif //_DEBUG +} diff --git a/private/ole32/ole232/util/ole2util.cpp b/private/ole32/ole232/util/ole2util.cpp new file mode 100644 index 000000000..51e0ed81a --- /dev/null +++ b/private/ole32/ole232/util/ole2util.cpp @@ -0,0 +1,1105 @@ + +//+---------------------------------------------------------------------------- +// +// File: +// ole2util.cpp +// +// Contents: +// Ole internal utility routines +// +// Classes: +// +// Functions: +// +// History: +// 06/01/94 - AlexGo - UtQueryPictFormat now supports +// enhanced metafiles +// 03/18/94 - AlexGo - fixed UtGetPresStreamName (incorrect +// string processing) +// 01/11/94 - ChrisWe - don't reference unlocked handle in +// UtConvertBitmapToDib +// 01/11/94 - alexgo - added VDATEHEAP macro to every function +// 12/07/93 - ChrisWe - removed incorrect uses of (LPOLESTR); +// removed duplicate GetClassFromDataObj function, which +// is the same as UtGetClassID +// 11/30/93 - ChrisWe - continue file cleanup; don't open +// streams in UtRemoveExtraOlePresStreams() +// 11/28/93 - ChrisWe - file cleanup and inspection; +// reformatted many functions +// 11/22/93 - ChrisWe - replace overloaded ==, != with +// IsEqualIID and IsEqualCLSID +// 06/28/93 - SriniK - added UtGetDibExtents +// 11/16/92 - JasonFul - created; moved contents here from util.cpp +// +//----------------------------------------------------------------------------- + +#include <le2int.h> +#pragma SEG(ole2util) + +NAME_SEG(Ole2Utils) +ASSERTDATA + +#define WIDTHBYTES(i) ((i+31)/32*4) + +#define PALETTESIZE 256 /* Number of entries in the system palette */ + +// REVIEW, according to the spec, IDataObject::EnumFormatEtc() is only +// required to service one dwDirection DATADIR_ value at a time. This +// function has been asking it to do more than one at a time, and expecting +// return of FORMATETCs that match all the requested directions. Code +// seen in OleRegEnumFormatEtc() checks on creation, and fails if any +// value other than plain DATADIR_GET or plain DATADIR_SET is specified +// so this has clearly never worked for OLE1, or registration database lookups +// since the only caller of UtIsFormatSupported has always asked for both +// at the same time. +#pragma SEG(UtIsFormatSupported) +FARINTERNAL_(BOOL) UtIsFormatSupported(IDataObject FAR* lpDataObj, + DWORD dwDirection, CLIPFORMAT cfFormat) +{ + VDATEHEAP(); + + FORMATETC formatetc; // a place to fetch formats from the enumerator + IEnumFORMATETC FAR* penm; // enumerates the formats of [lpDataObj] + ULONG ulNumFetched; // a count of the number of formats fetched + HRESULT error; // the error state so far + + // try to get the enumerator from the data object + error = lpDataObj->EnumFormatEtc(dwDirection, &penm); + + if (error != NOERROR) + { + if (FAILED(error)) + return FALSE; + else + { + CLSID clsid; + + // Use reg db; this case is primarily for the OLE1 + // compatibility code since it may talk to a data + // object from a server in the same process as + // the server. + if (UtGetClassID(lpDataObj, &clsid) != TRUE) + return(FALSE); + + // synthesize an enumerator + // REVIEW, if the data object is synthesized for + // the OLE1 object, why doesn't that implementation + // go ahead and synthesize this? Why does it have + // to be done like this? What if it's on the clipboard + // and someone wants to use it? + if (OleRegEnumFormatEtc(clsid, dwDirection, &penm) + != NOERROR) + return FALSE; + Assert(penm); + } + } + + // check for the format we're looking for + while(NOERROR == (error = penm->Next(1, &formatetc, &ulNumFetched))) + { + if ((ulNumFetched == 1) && (formatetc.cfFormat == cfFormat)) + break; + } + + // release the enumerator + penm->Release(); + + // if error isn't S_FALSE, we fetched an item, and broke out of the + // while loop above --> the format was found. Return TRUE indicating + // that the format is supported + return(error == NOERROR ? TRUE : FALSE); +} + + +#pragma SEG(UtDupPalette) +FARINTERNAL_(HPALETTE) UtDupPalette(HPALETTE hpalette) +{ + VDATEHEAP(); + + WORD cEntries; // holds the number of entries in the palette + HANDLE hLogPal; // ia a handle to a new logical palette + LPLOGPALETTE pLogPal; // is a pointer to the new logical palette + HPALETTE hpaletteNew = NULL; // the new palette we will return + + if (0 == GetObject(hpalette, sizeof(cEntries), &cEntries)) + return(NULL); + + if (NULL == (hLogPal = GlobalAlloc(GMEM_MOVEABLE, + sizeof (LOGPALETTE) + + cEntries * sizeof (PALETTEENTRY)))) + return(NULL); + + if (NULL == (pLogPal = (LPLOGPALETTE)GlobalLock(hLogPal))) + goto errRtn; + + if (0 == GetPaletteEntries(hpalette, 0, cEntries, + pLogPal->palPalEntry)) + goto errRtn; + + pLogPal->palVersion = 0x300; + pLogPal->palNumEntries = cEntries; + + if (NULL == (hpaletteNew = CreatePalette(pLogPal))) + goto errRtn; + +errRtn: + if (pLogPal) + GlobalUnlock(hLogPal); + + if (hLogPal) + GlobalFree(hLogPal); + + AssertSz(hpaletteNew, "Warning: UtDupPalette Failed"); + return(hpaletteNew); +} + +//+------------------------------------------------------------------------- +// +// Function: UtFormatToTymed +// +// Synopsis: gets the right TYMED for the given rendering format +// +// Effects: +// +// Arguments: [cf] -- the clipboard format +// +// Requires: +// +// Returns: one of the TYMED enumeration +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: dd-mmm-yy Author Comment +// 07-Jul-94 alexgo added EMF's +// +// Notes: This should only be called for formats that we can +// render +// +//-------------------------------------------------------------------------- + +#pragma SEG(UtFormatToTymed) +FARINTERNAL_(DWORD) UtFormatToTymed(CLIPFORMAT cf) +{ + VDATEHEAP(); + + if( cf == CF_METAFILEPICT ) + { + return TYMED_MFPICT; + } + else if( cf == CF_BITMAP ) + { + return TYMED_GDI; + } + else if( cf == CF_DIB ) + { + return TYMED_HGLOBAL; + } + else if( cf == CF_ENHMETAFILE ) + { + return TYMED_ENHMF; + } + else if( cf == CF_PALETTE ) + { + LEWARN(1,"Trying to render CF_PALETTE"); + return TYMED_GDI; + } + + LEDebugOut((DEB_WARN, "WARNING: trying to render clipformat (%lx)\n", + cf)); + + return TYMED_HGLOBAL; +} + +//+------------------------------------------------------------------------- +// +// Function: UtQueryPictFormat +// +// Synopsis: finds our "preferred" drawing formatetc from the given +// data object +// +// Effects: +// +// Arguments: [lpSrcDataObj] -- the source data object +// [lpforetc] -- where to stuff the preferred format +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: dd-mmm-yy Author Comment +// 01-Jun-94 alexgo rewrite/now supports Enhanced Metafiles +// +// Notes: +// +//-------------------------------------------------------------------------- + +#pragma SEG(UtQueryPictFormat) +FARINTERNAL_(BOOL) UtQueryPictFormat(LPDATAOBJECT lpSrcDataObj, + LPFORMATETC lpforetc) +{ + FORMATETC foretctemp; // local copy of current values of format desc + VDATEHEAP(); + + LEDebugOut((DEB_ITRACE, "%p _IN UtQueryPictFormat ( %p , %p )\n", + NULL, lpSrcDataObj, lpforetc)); + + // copy format descriptor + foretctemp = *lpforetc; + + // set values and query for our preferred formats in order of + // preference + + + foretctemp.cfFormat = CF_METAFILEPICT; + foretctemp.tymed = TYMED_MFPICT; + if (lpSrcDataObj->QueryGetData(&foretctemp) == NOERROR) + { + goto QuerySuccess; + } + + foretctemp.cfFormat = CF_ENHMETAFILE; + foretctemp.tymed = TYMED_ENHMF; + if( lpSrcDataObj->QueryGetData(&foretctemp) == NOERROR ) + { + goto QuerySuccess; + } + foretctemp.cfFormat = CF_DIB; + foretctemp.tymed = TYMED_HGLOBAL; + if (lpSrcDataObj->QueryGetData(&foretctemp) == NOERROR) + { + goto QuerySuccess; + } + + foretctemp.cfFormat = CF_BITMAP; + foretctemp.tymed = TYMED_GDI; + if (lpSrcDataObj->QueryGetData(&foretctemp) == NOERROR) + { + goto QuerySuccess; + } + + LEDebugOut((DEB_ITRACE, "%p OUT UtQueryPictFormat ( %lu )\n", + NULL, FALSE)); + + return FALSE; + +QuerySuccess: + // data object supports this format; change passed in + // format to match + + lpforetc->cfFormat = foretctemp.cfFormat; + lpforetc->tymed = foretctemp.tymed; + + // return success + + LEDebugOut((DEB_ITRACE, "%p OUT UtQueryPictFormat ( %lu )\n", + NULL, TRUE)); + + return(TRUE); +} + + +#pragma SEG(UtConvertDibToBitmap) +FARINTERNAL_(HBITMAP) UtConvertDibToBitmap(HANDLE hDib) +{ + VDATEHEAP(); + + LPBITMAPINFOHEADER lpbmih; + HDC hdc; // the device context to create the bitmap for + size_t uBitsOffset; // the offset to where the image begins in the DIB + HBITMAP hBitmap; // the bitmap we'll return + + if (!(lpbmih = (LPBITMAPINFOHEADER)GlobalLock(hDib))) + return(NULL); + + if (!(hdc = GetDC(NULL))) // Get screen DC. + { + // REVIEW: we may have to use the target device of this + // cache node. + return(NULL); + } + + uBitsOffset = sizeof(BITMAPINFOHEADER) + + (lpbmih->biClrUsed ? lpbmih->biClrUsed : + UtPaletteSize(lpbmih)); + + hBitmap = CreateDIBitmap(hdc, lpbmih, CBM_INIT, + ((BYTE *)lpbmih)+uBitsOffset, + (LPBITMAPINFO) lpbmih, DIB_RGB_COLORS); + + // release the DC + ReleaseDC(NULL, hdc); + + return hBitmap; +} + +//+---------------------------------------------------------------------------- +// +// Function: +// UtConvertBitmapToDib, internal +// +// Synopsis: +// Creates a Device Independent Bitmap capturing the content of +// the argument bitmap. +// +// Arguments: +// [hBitmap] -- Handle to the bitmap to convert +// [hpal] -- color palette for the bitmap; may be null for +// default stock palette +// +// Returns: +// Handle to the DIB. May be null if any part of the conversion +// failed. +// +// Notes: +// +// History: +// 11/29/93 - ChrisWe - file inspection and cleanup +// 07/18/94 - DavePl - fixed for 16, 32, bpp bitmaps +// +//----------------------------------------------------------------------------- + +FARINTERNAL_(HANDLE) UtConvertBitmapToDib(HBITMAP hBitmap, HPALETTE hpal) +{ + VDATEHEAP(); + + HDC hScreenDC; + BITMAP bm; // bitmap for hBitmap + UINT uBits; // number of color bits for bitmap + size_t uBmiSize; // size of bitmap info for the DIB + size_t biSizeImage; // temp to hold value in the handle memory + HANDLE hBmi; // handle for the new DIB bitmap we'll create + LPBITMAPINFOHEADER lpBmi; // pointer to the actual data area for DIB + HANDLE hDib = NULL; // the DIB we'll return + BOOL fSuccess = FALSE; + DWORD dwCompression; + BOOL fDeletePalette = FALSE; + + if (NULL == hBitmap) + { + return(NULL); + } + + // if no palette provided, use the default + + if (NULL == hpal) + { + // This block fixes NTBUG #13029. The problem is that on a palette + // device (ie a 256 color video driver), we don't get passed the palette + // that is used by the DDB. So, we build the palette based on what + // is currently selected into the system palette. + + // POSTPPC: + // + // We should change the clipboard code that calls this to ask for + // CF_PALETTE from the IDataObject that the DDB was obtained from, that + // way we know we get the colors that the calling app really intended + HDC hDCGlobal = GetDC(NULL); + int iRasterCaps = GetDeviceCaps(hDCGlobal, RASTERCAPS); + + ReleaseDC(NULL, hDCGlobal); + + if ((iRasterCaps & RC_PALETTE)) + { + // Based the following code from the win sdk MYPAL example program. + // this creates a palette out of the currently active palette. + HANDLE hLogPal = GlobalAlloc (GHND, + (sizeof (LOGPALETTE) + + (sizeof (PALETTEENTRY) * (PALETTESIZE)))); + + // if we are OOM, return failure now, because we aren't going + // to make it through the allocations later on. + + if (!hLogPal) + return NULL; + + LPLOGPALETTE pLogPal = (LPLOGPALETTE)GlobalLock (hLogPal); + + // 0x300 is a magic number required by GDI + pLogPal->palVersion = 0x300; + pLogPal->palNumEntries = PALETTESIZE; + + // fill in intensities for all palette entry colors + for (int iLoop = 0; iLoop < PALETTESIZE; iLoop++) + { + *((WORD *) (&pLogPal->palPalEntry[iLoop].peRed)) = (WORD)iLoop; + pLogPal->palPalEntry[iLoop].peBlue = 0; + pLogPal->palPalEntry[iLoop].peFlags = PC_EXPLICIT; + } + + // create a logical color palette according the information + // in the LOGPALETTE structure. + hpal = CreatePalette ((LPLOGPALETTE) pLogPal) ; + + GlobalUnlock(hLogPal); + GlobalFree(hLogPal); + + if (!hpal) + return NULL; + + fDeletePalette = TRUE; + } + else + { + hpal = (HPALETTE)GetStockObject(DEFAULT_PALETTE); + } + } + + if (NULL == GetObject(hBitmap, sizeof(bm), (LPVOID)&bm)) + { + return(NULL); + } + + + uBits = bm.bmPlanes * bm.bmBitsPixel; + + // Based on the number of bits per pixel, set up the size + // of the color table, and the compression type as per the + // the following table: + // + // + // BPP Palette Size Compression + // ~~~ ~~~~~~~~~~~~ ~~~~~~~~~~~ + // 1,2,4,8 2^BPP * sizeof(RGBQUAD) None + // 16, 32 3 * sizeof(DWORD) masks BI_BITFIELDS + // 24 0 None + + + if (16 == bm.bmBitsPixel || 32 == bm.bmBitsPixel) + { + uBmiSize = sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD); + dwCompression = BI_BITFIELDS; + } + else if (24 == bm.bmBitsPixel) + { + uBmiSize = sizeof(BITMAPINFOHEADER); + dwCompression = BI_RGB; + } + else + { + Assert( bm.bmBitsPixel == 1 || + bm.bmBitsPixel == 2 || + bm.bmBitsPixel == 4 || + bm.bmBitsPixel == 8 ); + + + // VGA and EGA are planar devices on Chicago, so uBits needs + // to be used when determining the size of the bitmap info + + // the size of the color table. + uBmiSize = sizeof(BITMAPINFOHEADER) + + (1 << uBits) * sizeof(RGBQUAD); + dwCompression = BI_RGB; + } + + // Allocate enough memory to hold the BITMAPINFOHEADER + + hBmi = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, (DWORD)uBmiSize); + if (NULL == hBmi) + { + return NULL; + } + + lpBmi = (LPBITMAPINFOHEADER) GlobalLock(hBmi); + if (NULL == lpBmi) + { + GlobalFree(hBmi); + return NULL; + } + + // Set up any interesting non-zero fields + + lpBmi->biSize = (LONG)sizeof(BITMAPINFOHEADER); + lpBmi->biWidth = (LONG) bm.bmWidth; + lpBmi->biHeight = (LONG) bm.bmHeight; + lpBmi->biPlanes = 1; + lpBmi->biBitCount = uBits; + lpBmi->biCompression = dwCompression; + + // Grab the screen DC and set out palette into it + + hScreenDC = GetDC(NULL); + if (NULL == hScreenDC) + { + GlobalUnlock(hBmi); + goto errRtn; + } + + + // Call GetDIBits with a NULL lpBits parm, so that it will calculate + // the biSizeImage field for us + + GetDIBits(hScreenDC, // DC + hBitmap, // Bitmap handle + 0, // First scan line + bm.bmHeight, // Number of scan lines + NULL, // Buffer + (LPBITMAPINFO)lpBmi, // BITMAPINFO + DIB_RGB_COLORS); + + // If the driver did not fill in the biSizeImage field, make one up + + if (0 == lpBmi->biSizeImage) + { + LEDebugOut((DEB_WARN, "WARNING: biSizeImage was not computed for us\n")); + + lpBmi->biSizeImage = WIDTHBYTES((DWORD)bm.bmWidth * uBits) * bm.bmHeight; + } + + // Realloc the buffer to provide space for the bits. Use a new handle so + // that in the failure case we do not lose the exiting handle, which we + // would need to clean up properly. + + biSizeImage = lpBmi->biSizeImage; + GlobalUnlock(hBmi); + + hDib = GlobalReAlloc(hBmi, (uBmiSize + biSizeImage), GMEM_MOVEABLE); + if (NULL == hDib) + { + goto errRtn; + } + + // If the realloc succeeded, we can get rid of the old handle + + hBmi = NULL; + + // re-acquire the pointer to the handle + + lpBmi = (LPBITMAPINFOHEADER)GlobalLock(hDib); + if (NULL == lpBmi) + { + goto errRtn; + } + + hpal = SelectPalette(hScreenDC, hpal, FALSE); + RealizePalette(hScreenDC); + + // Call GetDIBits with a NON-NULL lpBits parm, and get the actual bits + + if (GetDIBits(hScreenDC, // DC + hBitmap, // HBITMAP + 0, // First scan line + (WORD)lpBmi->biHeight, // Count of scan lines + ((BYTE FAR *)lpBmi)+uBmiSize, // Bitmap bits + (LPBITMAPINFO)lpBmi, // BITMAPINFOHEADER + DIB_RGB_COLORS) // Palette style + ) + { + fSuccess = TRUE; + } + + GlobalUnlock(hDib); + +errRtn: + + if (hScreenDC) + { + // Select back the old palette into the screen DC + + SelectPalette(hScreenDC, hpal, FALSE); + ReleaseDC(NULL, hScreenDC); + } + + if (fDeletePalette) + { + DeleteObject(hpal); + } + + // If we failed, we need to free up the header and the DIB + // memory + + if (FALSE == fSuccess) + { + if (hBmi) + { + GlobalFree(hBmi); + } + + if (hDib) + { + GlobalFree(hDib); + hDib = NULL; + } + } + + return(hDib); +} + +//+---------------------------------------------------------------------------- +// +// Function: +// UtPaletteSize, internal +// +// Synopsis: +// Returns the size of a color table for a palette given the +// number of bits of color desired. +// +// Basically, the number of color table entries is: +// +// 1BPP +// 1<<1 = 2 +// +// 4BPP +// if pbmi->biClrUsed is not zero and is less than 16, then use pbmi->biClrUsed, +// otherwise use 1 << 4 = 16 +// +// 8BPP +// if pbmi->biClrUsed is not zero and is less than 256, then use pbmi->biClrUsed, +// otherwise use 1 << 8 = 256 +// +// 16BPP +// if pbmi->biCompression is BITFIELDS then there are three color entries, +// otherwise no color entries. +// +// 24BPP +// pbmi->biCompression must be BI_RGB, there is no color table. +// +// 32BPP +// if pbmi->biCompression is BITFIELDS then there are three color entries, +// otherwise no color entries. +// +// +// There is never a case with a color table larger than 256 colors. +// +// Arguments: +// [lpHeader] -- ptr to BITMAPINFOHEADER structure +// +// Returns: +// Size in bytes of color information +// +// Notes: +// +// History: +// 11/29/93 - ChrisWe - change bit count argument to unsigned, +// and return value to size_t +// +// 07/18/94 - DavePl - Fixed for 16, 24, 32bpp DIBs +// +//----------------------------------------------------------------------------- + + +FARINTERNAL_(size_t) UtPaletteSize(BITMAPINFOHEADER * pbmi) +{ +DWORD dwSize; +WORD biBitCount = pbmi->biBitCount; + + + VDATEHEAP(); + + // Compute size of color table information in a DIB. + + if (8 >= biBitCount) + { + if (pbmi->biClrUsed && (pbmi->biClrUsed < (DWORD) (1 << biBitCount)) ) + { + dwSize = pbmi->biClrUsed * sizeof(RGBQUAD); + } + else + { + Assert(0 == pbmi->biClrUsed); + + dwSize = (1 << biBitCount) * sizeof(RGBQUAD); + } + } + else if (BI_BITFIELDS == pbmi->biCompression) + { + Assert(24 != biBitCount); // BI_BITFIELDS should never be set for 24 bit. + dwSize = 3 * sizeof(RGBQUAD); + } + else + { + dwSize = 0; + } + + Assert( (dwSize < 65536) && "Palette size overflows WORD"); + + return dwSize; +} + +//+------------------------------------------------------------------------- +// +// Function: UtGetDibExtents +// +// Synopsis: Returns the size of the DIB in HIMETRIC units +// +// Effects: +// +// Arguments: [lpbmi] -- the BITMAPINFOHEADER for the DIB +// [plWidth] -- OUT param for width +// [plHeight] -- OUT param for height +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: dd-mmm-yy Author Comment +// 04-Aug-94 Davepl Corrected logic +// +// Notes: +// +//-------------------------------------------------------------------------- + +FARINTERNAL_(void) UtGetDibExtents(LPBITMAPINFOHEADER lpbmi, + LONG FAR* plWidth, LONG FAR* plHeight) +{ + VDATEHEAP(); + + #define HIMET_PER_METER 100000L // number of HIMETRIC units / meter + + if (!(lpbmi->biXPelsPerMeter && lpbmi->biYPelsPerMeter)) + { + HDC hdc; + hdc = GetDC(NULL); + lpbmi->biXPelsPerMeter = MulDiv(GetDeviceCaps(hdc, LOGPIXELSX), + 10000, 254); + lpbmi->biYPelsPerMeter = MulDiv(GetDeviceCaps(hdc, LOGPIXELSY), + 10000, 254); + + ReleaseDC(NULL, hdc); + } + + *plWidth = (lpbmi->biWidth * HIMET_PER_METER / lpbmi->biXPelsPerMeter); + *plHeight= (lpbmi->biHeight * HIMET_PER_METER / lpbmi->biYPelsPerMeter); + + // no longer need this + #undef HIMET_PER_METER + +} + + +#pragma SEG(UtGetClassID) +FARINTERNAL_(BOOL) UtGetClassID(LPUNKNOWN lpUnk, CLSID FAR* lpClsid) +{ + VDATEHEAP(); + + LPOLEOBJECT lpOleObj; // IOleObject pointer + LPPERSIST lpPersist; // IPersist pointer + + // try to ask it as an object + if (lpUnk->QueryInterface(IID_IOleObject, + (LPLPVOID)&lpOleObj) == NOERROR) + { + lpOleObj->GetUserClassID(lpClsid); + lpOleObj->Release(); + return(TRUE); + } + + // try to ask it as a persistent object + if (lpUnk->QueryInterface(IID_IPersist, + (LPLPVOID)&lpPersist) == NOERROR) + { + lpPersist->GetClassID(lpClsid); + lpPersist->Release(); + return(TRUE); + } + + *lpClsid = CLSID_NULL; + return(FALSE); +} + + +#pragma SEG(UtGetIconData) +FARINTERNAL UtGetIconData(LPDATAOBJECT lpSrcDataObj, REFCLSID rclsid, + LPFORMATETC lpforetc, LPSTGMEDIUM lpstgmed) +{ + VDATEHEAP(); + + CLSID clsid = rclsid; + + lpstgmed->tymed = TYMED_NULL; + lpstgmed->pUnkForRelease = NULL; + lpstgmed->hGlobal = NULL; + + if (lpSrcDataObj) + { + if (lpSrcDataObj->GetData(lpforetc, lpstgmed) == NOERROR) + return NOERROR; + + if (IsEqualCLSID(clsid, CLSID_NULL)) + UtGetClassID(lpSrcDataObj, &clsid); + } + + // get data from registration database + lpstgmed->hGlobal = OleGetIconOfClass(clsid, NULL, TRUE); + + if (lpstgmed->hGlobal == NULL) + return ResultFromScode(E_OUTOFMEMORY); + else + lpstgmed->tymed = TYMED_MFPICT; + + return NOERROR; +} + + + +// Performs operation like COPY, MOVE, REMOVE etc.. on src, dst storages. The +// caller can specifiy which streams to be operated upon through +// grfAllowedStreams parameter. + +STDAPI UtDoStreamOperation(LPSTORAGE pstgSrc, LPSTORAGE pstgDst, int iOpCode, + DWORD grfAllowedStmTypes) +{ + VDATEHEAP(); + + HRESULT error; // error status so far + IEnumSTATSTG FAR* penumStg; // used to enumerate the storage elements + ULONG celtFetched; // how many storage elements were fetched + STATSTG statstg; + + // get an enumerator over the source storage + if (error = pstgSrc->EnumElements(NULL, NULL, NULL, &penumStg)) + return error; + + // repeat for every storage + while(penumStg->Next(1, &statstg, &celtFetched) == NOERROR) + { + + // operate on streams that we're interested in + if (statstg.type == STGTY_STREAM) + { + DWORD stmType; + + // find the type of the stream + // REVIEW, we must have constants for these name + // prefixes!!! + switch (statstg.pwcsName[0]) + { + case '\1': + stmType = STREAMTYPE_CONTROL; + break; + + case '\2': + stmType = STREAMTYPE_CACHE; + break; + + case '\3': + stmType = STREAMTYPE_CONTAINER; + break; + + default: + stmType = (DWORD)STREAMTYPE_OTHER; + } + + + // check whether it should be operated upon + if (stmType & grfAllowedStmTypes) + { + switch(iOpCode) + { +#ifdef LATER + case OPCODE_COPY: + pstgDst->DestroyElement( + statstg.pwcsName); + error = pstgSrc->MoveElementTo( + statstg.pwcsName, + pstgDst, + statstg.pwcsName, + STGMOVE_COPY); + break; + + case OPCODE_MOVE: + pstgDst->DestroyElement( + statstg.pwcsName); + error = pstgSrc->MoveElementTo( + statstg.pwcsName, + pstgDst, + statstg.pwcsName, + STGMOVE_MOVE); + break; + + case OPCODE_EXCLUDEFROMCOPY: + AssertSz(FALSE, "Not yet implemented"); + break; + +#endif // LATER + case OPCODE_REMOVE: + error = pstgSrc->DestroyElement( + statstg.pwcsName); + break; + + default: + AssertSz(FALSE, "Invalid opcode"); + break; + } + } + } + + // if the enumerator allocated a new name string, get rid of it + if (statstg.pwcsName) + PubMemFree(statstg.pwcsName); + + // quit the enumeration loop if we've hit an error + if (error != NOERROR) + break; + } + + // release the enumerator + penumStg->Release(); + + // return the error state + return error; +} + + +FARINTERNAL_(void) UtGetPresStreamName(LPOLESTR lpszName, int iStreamNum) +{ + VDATEHEAP(); + int i; // counts down the digits of iStreamNum + + // count down the last three '0' characters of OLE_PRESENTATION_STREAM + // the -2 backs us up to the last character (remember the NULL + // terminator!) + for(lpszName += sizeof(OLE_PRESENTATION_STREAM)/sizeof(OLECHAR) - 2, + i = 3; i; --lpszName, --i) + { + *lpszName = OLESTR("0123456789")[iStreamNum % 10]; + if( iStreamNum > 0 ) + { + iStreamNum /= 10; + } + } +} + + +FARINTERNAL_(void) UtRemoveExtraOlePresStreams(LPSTORAGE pstg, int iStart) +{ + VDATEHEAP(); + + HRESULT hr; // error code from stream deletion + OLECHAR szName[sizeof(OLE_PRESENTATION_STREAM)/sizeof(OLECHAR)]; + // space for the stream names + + // if the stream number is invalid, do nothing + if ((iStart < 0) || (iStart >= OLE_MAX_PRES_STREAMS)) + return; + + // create presentation stream name + _xstrcpy(szName, OLE_PRESENTATION_STREAM); + UtGetPresStreamName(szName, iStart); + + // for each of these streams that exists, get rid of it + while((hr = pstg->DestroyElement(szName)) == NOERROR) + { + // if we've gotten to the end of the possible streams, quit + if (++iStart >= OLE_MAX_PRES_STREAMS) + break; + + // Get the next presentation stream name + UtGetPresStreamName(szName, iStart); + } + + // since the only reason these streams should be open, the first + // failure had better be that the file was not found, and not + // anything else (such as STG_E_ACCESSDENIED) + AssertSz(hr == STG_E_FILENOTFOUND, + "UtRemoveExtraOlePresStreams failure"); +} + +//+------------------------------------------------------------------------- +// +// Function: ConvertPixelsToHIMETRIC +// +// Synopsis: Converts a pixel dimension to HIMETRIC units +// +// Effects: +// +// Arguments: [hdcRef] -- the reference DC +// [ulPels] -- dimension in pixel measurement +// [pulHIMETRIC] -- OUT param of converted HIMETRIC result +// [tDimension] -- indicates XDIMENSION or YDIMENSION of input +// +// Returns: S_OK, E_FAIL +// +// Algorithm: screen_mm * input_pels HIMETRICS/ +// ---------------------- * / == HIMETRICS +// screen_pels /mm +// +// History: dd-mmm-yy Author Comment +// 04-Aug-94 Davepl Created +// +// Notes: We need to know whether the input size is in the X or +// Y dimension, since the aspect ratio could vary +// +//-------------------------------------------------------------------------- + +FARINTERNAL ConvertPixelsToHIMETRIC (HDC hdcRef, + ULONG lPels, + ULONG * pulHIMETRIC, + DIMENSION tDimension) +{ + VDATEHEAP(); + VDATEPTROUT(pulHIMETRIC, ULONG *); + + // Clear OUT parameter in case of error + + *pulHIMETRIC = 0; + + ULONG scrmm = 0; + ULONG scrpel = 0; + + const ULONG HIMETRIC_PER_MM = 100; + + // If we weren't given a reference DC, use the screen as a default + + BOOL fLocalDC = FALSE; + if (NULL == hdcRef) + { + hdcRef = GetDC(NULL); + if (hdcRef) + { + fLocalDC = TRUE; + } + } + + if (hdcRef) + { + Assert(tDimension == XDIMENSION || tDimension == YDIMENSION); + + // Get the count of pixels and millimeters for the screen + + if (tDimension == XDIMENSION) + { + scrmm = GetDeviceCaps(hdcRef, HORZSIZE); + scrpel = GetDeviceCaps(hdcRef, HORZRES); + } + else + { + scrmm = GetDeviceCaps(hdcRef, VERTSIZE); + scrpel = GetDeviceCaps(hdcRef, VERTRES); + } + + // If we had to create a temporary DC, it can be released now + + if (TRUE == fLocalDC) + { + ReleaseDC(NULL, hdcRef); + } + } + + // If we successfully obtained the DC's size and resolution, + // we can compute the HIMETRIC value. + + if (scrmm && scrpel) + { + *pulHIMETRIC = (scrmm * lPels * HIMETRIC_PER_MM) / scrpel; + + return S_OK; + } + + return E_FAIL; + +} diff --git a/private/ole32/ole232/util/plex.cpp b/private/ole32/ole232/util/plex.cpp new file mode 100644 index 000000000..bbdb33821 --- /dev/null +++ b/private/ole32/ole232/util/plex.cpp @@ -0,0 +1,53 @@ +// This is a part of the Microsoft Foundation Classes C++ library. +// Copyright (C) 1992 Microsoft Corporation +// All rights reserved. +// +// This source code is only intended as a supplement to the +// Microsoft Foundation Classes Reference and Microsoft +// QuickHelp documentation provided with the library. +// See these sources for detailed information regarding the +// Microsoft Foundation Classes product. + +#include <le2int.h> +#pragma SEG(plex) + +#include "plex.h" +ASSERTDATA + +// Collection support +#ifdef OLE_COLL_SEG +#pragma code_seg(OLE_COLL_SEG) +#endif + + +#pragma SEG(CPlex_Create) +CPlex FAR* CPlex::Create(CPlex FAR* FAR& pHead, UINT nMax, UINT cbElement) +{ + VDATEHEAP(); + + Assert(nMax > 0 && cbElement > 0); + CPlex FAR* p = (CPlex FAR*)PrivMemAlloc(sizeof(CPlex) + nMax * cbElement); + if (p == NULL) + return NULL; + + p->nMax = nMax; + p->nCur = 0; + p->pNext = pHead; + pHead = p; // change head (adds in reverse order for simplicity) + return p; +} + +#pragma SEG(CPlex_FreeDataChain) +void CPlex::FreeDataChain() // free this one and links +{ + VDATEHEAP(); + + CPlex FAR* pThis; + CPlex FAR* pNext; + + for (pThis = this; pThis != NULL; pThis = pNext) { + pNext = pThis->pNext; + pThis->pNext = NULL; // So compiler won't do nasty optimizations + PrivMemFree(pThis); + } +} diff --git a/private/ole32/ole232/util/utils.cpp b/private/ole32/ole232/util/utils.cpp new file mode 100644 index 000000000..46c7fe0ed --- /dev/null +++ b/private/ole32/ole232/util/utils.cpp @@ -0,0 +1,2726 @@ +//+---------------------------------------------------------------------------- +// +// File: +// utils.cpp +// +// Contents: +// general OLE internal utility routines +// +// Classes: +// +// Functions: +// +// History: +// 23-Jan-95 t-ScottH -added Dump method to CSafeRefCount and +// CThreadCheck class +// -added DumpCSafeRefCount API +// 28-Jul-94 alexgo added object stabilization classes +// 06-May-94 AlexT Add DVTARGET conversion routines +// 25-Jan-94 alexgo first pass at converting to Cairo-style +// memory allocations. +// 01/11/94 - alexgo - added VDATEHEAP macros to every function +// 12/15/93 - ChrisWe - UtDupString has to scale length by +// sizeof(OLECHAR) +// 12/08/93 - ChrisWe - added necessary casts to GlobalLock() calls +// resulting from removing bogus GlobalLock() macros in +// le2int.h +// 11/28/93 - ChrisWe - removed unreferenced define for MAX_STR, +// formatted UtDupGlobal, UtDupString +// 03/02/92 - SriniK - created +// +//----------------------------------------------------------------------------- + +#include <le2int.h> +#pragma SEG(utils) + +#include <memory.h> + +#ifdef _DEBUG +#include "dbgdump.h" +#endif // _DEBUG + +NAME_SEG(Utils) +ASSERTDATA + + +#pragma SEG(UtDupGlobal) +FARINTERNAL_(HANDLE) UtDupGlobal(HANDLE hsrc, UINT uiFlags) +{ + VDATEHEAP(); + + HANDLE hdst = NULL; // the newly create Handle DeSTination + DWORD dwSize; // the size of the global +#ifndef _MAC + void FAR *lpsrc; // a pointer to the source memory + void FAR *lpdst; // a pointer to the destination memory +#endif + + // if no source, nothing to duplicate + if (!hsrc) + return(NULL); + +#ifdef _MAC + if (!(hdst = NewHandle(dwSize = GetHandleSize(hsrc)))) + return(NULL); + BlockMove(*hsrc, *hdst, dwSize); + return(hdst); +#else + // if there's no content, do nothing + if (!(lpsrc = GlobalLock(hsrc))) + goto errRtn; + + // allocate a new global + hdst = GlobalAlloc(uiFlags, (dwSize = GlobalSize(hsrc))); + + // if the allocation failed, get out + if ((hdst == NULL) || ((lpdst = GlobalLock(hdst)) == NULL)) + goto errRtn; + + // copy the content + _xmemcpy(lpdst, lpsrc, dwSize); + + // unlock the handles + GlobalUnlock(hsrc); + GlobalUnlock(hdst); + return(hdst); + +errRtn: + // unlock the source handle + GlobalUnlock(hsrc); + + // if we allocated a destination handle, free it + if (hdst) + GlobalFree(hdst); + + return(NULL); +#endif // _MAC +} + + +#pragma SEG(UtDupString) + +// copies string using the TASK allocator; returns NULL on out of memory + +// often when calling UtDupString, the caller knows the string length. +// a good speed boost would be to call UtDupPtr instead + +// lpvIn must be non null +// note: we do an alloc even if dw == 0 +FARINTERNAL_(LPVOID) UtDupPtr(LPVOID lpvIn, DWORD dw) +{ + VDATEHEAP(); + LPVOID lpvOut; // the newly allocated ptr + + Assert(lpvIn); // internal fcn, lpvIn must be non-null + if ((lpvOut = PubMemAlloc(dw)) != NULL) { + memcpy(lpvOut, lpvIn, dw); + } + + return lpvOut; +} + +FARINTERNAL_(LPOLESTR) UtDupString(LPCOLESTR lpszIn) +{ + return (LPOLESTR) UtDupPtr( (LPVOID) lpszIn, + (_xstrlen(lpszIn)+1) * sizeof(OLECHAR) ); +} + + + +//+------------------------------------------------------------------------- +// +// Function: UtDupStringA +// +// Synopsis: Duplicates an ANSI string using the TASK allocator +// +// Effects: +// +// Arguments: [pszAnsi] -- the string to duplicate +// +// Requires: +// +// Returns: the newly allocated string duplicate or NULL +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: dd-mmm-yy Author Comment +// 04-Jun-94 alexgo author +// +// Notes: +// +//-------------------------------------------------------------------------- + +LPSTR UtDupStringA( LPCSTR pszAnsi ) +{ + return (LPSTR) UtDupPtr( (LPVOID) pszAnsi, + strlen(pszAnsi) + 1 ); +} + + + +#pragma SEG(UtCopyTargetDevice) +FARINTERNAL_(DVTARGETDEVICE FAR*) UtCopyTargetDevice(DVTARGETDEVICE FAR* ptd) +{ + // if nothing to copy, return + if (ptd == NULL) + return(NULL); + + return (DVTARGETDEVICE FAR*) UtDupPtr((LPVOID) ptd, ptd->tdSize); +} + + +#pragma SEG(UtCopyFormatEtc) +FARINTERNAL_(BOOL) UtCopyFormatEtc(FORMATETC FAR* pFetcIn, + FORMATETC FAR* pFetcCopy) +{ + VDATEHEAP(); + + // copy structures + *pFetcCopy = *pFetcIn; + + if (pFetcIn->ptd == NULL) { + // all done, return true because the copy succeeded + return TRUE; + } + + // create a copy of the td descriptor, which is allocated + pFetcCopy->ptd = UtCopyTargetDevice(pFetcIn->ptd); + + // return TRUE if we copied the data if we were supposed to + return(pFetcCopy->ptd != NULL); +} + + +#pragma SEG(UtCompareFormatEtc) +FARINTERNAL_(int) UtCompareFormatEtc(FORMATETC FAR* pFetcLeft, + FORMATETC FAR* pFetcRight) +{ + VDATEHEAP(); + + int iResult; // indicates whether the match is exact or partial + + // if the clipboard formats are different, there is no match + if (pFetcLeft->cfFormat != pFetcRight->cfFormat) + return(UTCMPFETC_NEQ); + + // if the target devices don't match, there is no match + if (!UtCompareTargetDevice(pFetcLeft->ptd, pFetcRight->ptd)) + return(UTCMPFETC_NEQ); + + // compare the aspects for the two formats + if (pFetcLeft->dwAspect == pFetcRight->dwAspect) + { + // the match is exact + iResult = UTCMPFETC_EQ; + } + else if ((pFetcLeft->dwAspect & ~pFetcRight->dwAspect) != 0) + { + // left not subset of aspects of right; not equal + return(UTCMPFETC_NEQ); + } + else + { + // left aspects are a subset of the right aspects + iResult = UTCMPFETC_PARTIAL; + } + + // if we get here, iResult is set to one of UPCMPFETC_EQ or _PARTIAL + + // compare the media for the two formats + if (pFetcLeft->tymed == pFetcRight->tymed) + { + // same medium flags; do not change value of iResult + ; + } + else if ((pFetcLeft->tymed & ~pFetcRight->tymed) != 0) + { + // left not subset of medium flags of right; not equal + return(UTCMPFETC_NEQ); + } + else + { + // left subset of right + iResult = UTCMPFETC_PARTIAL; + } + + return(iResult); +} + +//+------------------------------------------------------------------------- +// +// Function: UtCompareTargetDevice +// +// Synopsis: Compare two DVTARGETDEVICEs +// +// Arguments: [ptdLeft] -- comparand +// [ptdRight] -- comparee +// +// Returns: TRUE iff the two target devices are equivalent +// +// Algorithm: +// +// History: 09-May-94 AlexT Rewrote to do more than just a binary +// compare +// +// Notes: +// +//-------------------------------------------------------------------------- + +#define UT_DM_COMPARISON_FIELDS (DM_ORIENTATION | \ + DM_PAPERSIZE | \ + DM_PAPERLENGTH | \ + DM_PAPERWIDTH | \ + DM_SCALE | \ + DM_PRINTQUALITY | \ + DM_COLOR) + +#pragma SEG(UtCompareTargetDevice) +FARINTERNAL_(BOOL) UtCompareTargetDevice(DVTARGETDEVICE FAR* ptdLeft, + DVTARGETDEVICE FAR* ptdRight) +{ + LEDebugOut((DEB_ITRACE, "%p _IN UtCompareTargetDevice (%p, %p)\n", + NULL, ptdLeft, ptdRight)); + + VDATEHEAP(); + + BOOL bRet = FALSE; // More often than not we return FALSE + + // We use a do-while(FALSE) loop so that we can break out to common + // return code at the end (the joys of tracing) + do + { + // if the addresses of the two target device descriptors are the same, + // then they must be the same. Note this handles the two NULL case. + if (ptdLeft == ptdRight) + { + bRet = TRUE; + break; + } + + // if either td is NULL, can't compare them + if ((ptdRight == NULL) || (ptdLeft == NULL)) + { + AssertSz(bRet == FALSE, "bRet not set correctly"); + break; + } + + // we ignore device name (My Printer vs. Your Printer doesn't matter) + + // check driver name + if (ptdLeft->tdDriverNameOffset != 0) + { + if (ptdRight->tdDriverNameOffset == 0) + { + // Left driver exists, but no right driver + AssertSz(bRet == FALSE, "bRet not set correctly"); + break; + } + + // Both drivers exist + if (_xstrcmp((LPOLESTR)((BYTE*)ptdLeft + + ptdLeft->tdDriverNameOffset), + (LPOLESTR)((BYTE*)ptdRight + + ptdRight->tdDriverNameOffset)) != 0) + { + // Driver names don't match + AssertSz(bRet == FALSE, "bRet not set correctly"); + break; + } + } + else if (ptdRight->tdDriverNameOffset != 0) + { + // Left driver doesn't exist, but right driver does + AssertSz(bRet == FALSE, "bRet not set correctly"); + break; + } + + // we ignore port name + + if (0 == ptdLeft->tdExtDevmodeOffset) + { + if (0 == ptdRight->tdExtDevmodeOffset) + { + // Nothing left to compare + bRet = TRUE; + break; + } + else + { + // Only one Devmode + AssertSz(bRet == FALSE, "bRet not set correctly"); + break; + } + } + else if (0 == ptdRight->tdExtDevmodeOffset) + { + // Only one Devmode exists + AssertSz(bRet == FALSE, "bRet not set correctly"); + break; + } + + // Both TDs have Devmodes + DEVMODEW *pdmLeft, *pdmRight; + + pdmLeft = (DEVMODEW *)((BYTE*)ptdLeft + + ptdLeft->tdExtDevmodeOffset); + pdmRight = (DEVMODEW *)((BYTE*)ptdRight + + ptdRight->tdExtDevmodeOffset); + + // Check driver version + if (pdmLeft->dmDriverVersion != pdmRight->dmDriverVersion) + { + AssertSz(bRet == FALSE, "bRet not set correctly"); + break; + } + + // For a successful match, both device mode must specify the same + // values for each of the following: + // DM_ORIENTATION, DM_PAPERSIZE, DM_PAPERLENGTH. + // DM_PAPERWIDTH, DM_SCALE, DM_PRINTQUALITY, DM_COLOR + + if ((pdmLeft->dmFields & UT_DM_COMPARISON_FIELDS) ^ + (pdmRight->dmFields & UT_DM_COMPARISON_FIELDS)) + { + // Only one of pdmLeft and pdmRight specify at least one + // of the comparison fields + AssertSz(bRet == FALSE, "bRet not set correctly"); + break; + } + + if ((pdmLeft->dmFields & DM_ORIENTATION) && + pdmLeft->dmOrientation != pdmRight->dmOrientation) + { + AssertSz(bRet == FALSE, "bRet not set correctly"); + break; + } + + if ((pdmLeft->dmFields & DM_PAPERSIZE) && + pdmLeft->dmPaperSize != pdmRight->dmPaperSize) + { + AssertSz(bRet == FALSE, "bRet not set correctly"); + break; + } + + if ((pdmLeft->dmFields & DM_PAPERLENGTH) && + pdmLeft->dmPaperLength != pdmRight->dmPaperLength) + { + AssertSz(bRet == FALSE, "bRet not set correctly"); + break; + } + + if ((pdmLeft->dmFields & DM_PAPERWIDTH) && + pdmLeft->dmPaperWidth != pdmRight->dmPaperWidth) + { + AssertSz(bRet == FALSE, "bRet not set correctly"); + break; + } + + if ((pdmLeft->dmFields & DM_SCALE) && + pdmLeft->dmScale != pdmRight->dmScale) + { + AssertSz(bRet == FALSE, "bRet not set correctly"); + break; + } + + if ((pdmLeft->dmFields & DM_PRINTQUALITY) && + pdmLeft->dmPrintQuality != pdmRight->dmPrintQuality) + { + AssertSz(bRet == FALSE, "bRet not set correctly"); + break; + } + + if ((pdmLeft->dmFields & DM_COLOR) && + pdmLeft->dmColor != pdmRight->dmColor) + { + AssertSz(bRet == FALSE, "bRet not set correctly"); + break; + } + + bRet = TRUE; + } while (FALSE); + + LEDebugOut((DEB_ITRACE, "%p OUT UtCompareTargetDevice (%d)\n", + NULL, bRet)); + + return(bRet); +} + +#pragma SEG(UtCopyStatData) +FARINTERNAL_(BOOL) UtCopyStatData(STATDATA FAR* pSDIn, STATDATA FAR* pSDCopy) +{ + VDATEHEAP(); + + // copy structures + *pSDCopy = *pSDIn; + + // create copy of target device description (which is allocated) + pSDCopy->formatetc.ptd = UtCopyTargetDevice(pSDIn->formatetc.ptd); + + // if there is an advise sink, account for the copy/reference + if (pSDCopy->pAdvSink != NULL) + pSDCopy->pAdvSink->AddRef(); + + // return TRUE if the copy was done if it was required + return((pSDCopy->formatetc.ptd != NULL) == + (pSDIn->formatetc.ptd != NULL)); +} + +//+------------------------------------------------------------------------- +// +// Function: UtReleaseStatData +// +// Synopsis: nulls && releases members of the given stat data structure +// +// Effects: +// +// Arguments: pStatData +// +// Requires: +// +// Returns: void +// +// Signals: +// +// Modifies: +// +// Algorithm: We copy the data first and NULL out the stat data +// because the Release on the Advise sink could cause us +// to be re-entered. +// +// History: dd-mmm-yy Author Comment +// 20-Jul-94 alexgo made safe for OLE sytle re-entrancy +// +// Notes: +// +//-------------------------------------------------------------------------- + +FARINTERNAL_(void) UtReleaseStatData(STATDATA FAR* pStatData) +{ + STATDATA sd; + + VDATEHEAP(); + + sd = *pStatData; + + // zero out the original before doing any work + + _xmemset(pStatData, 0, sizeof(STATDATA)); + + // if there's a target device description, free it + if (sd.formatetc.ptd != NULL) + { + PubMemFree(sd.formatetc.ptd); + } + + if( sd.pAdvSink ) + { + sd.pAdvSink->Release(); + } +} + +//+------------------------------------------------------------------------- +// +// Function: UtCreateStorageOnHGlobal +// +// Synopsis: creates a storage on top of an HGlobal +// +// Effects: +// +// Arguments: [hGlobal] -- the memory on which to create the +// storage +// [fDeleteOnRelease] -- if TRUE, then delete the hglobal +// once the storage is released. +// [ppStg] -- where to put the storage interface +// [ppILockBytes] -- where to put the underlying ILockBytes, +// maybe NULL. The ILB must be released. + +// +// Requires: +// +// Returns: HRESULT +// +// Signals: +// +// Modifies: +// +// Algorithm: create an ILockBytes on HGLOBAL and then create the docfile +// on top of the ILockBytes +// +// History: dd-mmm-yy Author Comment +// 07-Apr-94 alexgo author +// +// Notes: +// +//-------------------------------------------------------------------------- + +HRESULT UtCreateStorageOnHGlobal( HGLOBAL hGlobal, BOOL fDeleteOnRelease, + IStorage **ppStg, ILockBytes **ppILockBytes ) +{ + HRESULT hresult; + ILockBytes * pLockBytes; + + VDATEHEAP(); + + LEDebugOut((DEB_ITRACE, "%p _IN UtCreateStorageOnHGlobal ( %lx , %p )" + "\n", NULL, hGlobal, ppStg)); + + hresult = CreateILockBytesOnHGlobal(hGlobal, fDeleteOnRelease, + &pLockBytes); + + if( hresult == NOERROR ) + { + hresult = StgCreateDocfileOnILockBytes( pLockBytes, + STGM_CREATE | STGM_SALL, 0, ppStg); + + // no matter what the result of StgCreate is, we want + // to release the LockBytes. If hresult == NOERROR, then + // the final release to the LockBytes will come when the + // created storage is released. + } + + if( ppILockBytes ) + { + *ppILockBytes = pLockBytes; + } + else if (pLockBytes) + { + // we release here so the final release of the storage + // will be the final release of the lockbytes + pLockBytes->Release(); + } + + + LEDebugOut((DEB_ITRACE, "%p OUT UtCreateStorageOnHGlobal ( %lx ) " + "[ %p ]\n", NULL, hresult, *ppStg)); + + return hresult; +} + +//+------------------------------------------------------------------------- +// +// Function: UtGetTempFileName +// +// Synopsis: retrieves a temporary filename (for use in GetData, TYMED_FILE +// and temporary docfiles) +// +// Effects: +// +// Arguments: [pszPrefix] -- prefix of the temp filename +// [pszTempName] -- buffer that will receive the temp path. +// must be MAX_PATH or greater. +// +// Requires: +// +// Returns: HRESULT; +// +// Signals: +// +// Modifies: +// +// Algorithm: tries to get a file in the temp directory, failing that, in +// the windows directory +// +// History: dd-mmm-yy Author Comment +// 07-Apr-94 alexgo author +// +// Notes: OPTIMIZATION: The storage code has a similar peice of code +// for generating temporary docfiles. We may want to use this +// routine there as well. +// +//-------------------------------------------------------------------------- + +HRESULT UtGetTempFileName( LPOLESTR pszPrefix, LPOLESTR pszTempName ) +{ + HRESULT hresult = NOERROR; + //OLECHAR szPath[MAX_PATH + 1]; + + VDATEHEAP(); + + LEDebugOut((DEB_ITRACE, "%p _IN UtGetTempFilename ( \"%ws\" , " + "\"%ws\")\n", NULL, pszPrefix, pszTempName)); + +//BUGBUG!! This doesn't compile on Chicago; fix it soon +#ifdef LATER + if( !GetTempPath(MAX_PATH, szPath) ) + { + LEDebugOut((DEB_WARN, "WARNING: GetTempPath failed!\n")); + if( !GetWindowsDirectory(szPath, MAX_PATH) ) + { + LEDebugOut((DEB_WARN, "WARNING: GetWindowsDirectory" + " failed!!\n")); + hresult = ResultFromScode(E_FAIL); + goto errRtn; + } + } + + if( !GetTempFileName( szPath, pszPrefix, 0, pszTempName ) ) + { + LEDebugOut((DEB_WARN, "WARNING: GetTempFileName failed!!\n")); + hresult = ResultFromScode(E_FAIL); + } +#endif //LATER + + // BUGBUG! This is just a hack for now + LEDebugOut((DEB_ERROR, "ERROR!: Filename support not complete!!\n")); + _xstrcpy(pszTempName, OLESTR("foo.bar")); + +//errRtn: + + LEDebugOut((DEB_ITRACE, "%p OUT UtGetTempFilename ( %lx ) " + "[ \"%ws\" ]\n", NULL, hresult, pszTempName)); + + return hresult; +} + + +//+---------------------------------------------------------------------------- +// +// Function: +// UtHGLOBALtoStm, internal +// +// Synopsis: +// Write the contents of an HGLOBAL to a stream +// +// Arguments: +// [hdata] -- handle to the data to write out +// [dwSize] -- size of the data to write out +// [pstm] -- stream to write the data out to; on exit, the +// stream is positioned after the written data +// +// Returns: +// HRESULT +// +// Notes: +// +// History: +// 04/10/94 - AlexGo - added call tracing, moved from convert.cpp +// to utils.cpp, misc improvements. +// 11/30/93 - ChrisWe - file inspection and cleanup +// +//----------------------------------------------------------------------------- + +HRESULT UtHGLOBALtoStm(HGLOBAL hGlobalSrc, DWORD dwSize, LPSTREAM pstm) +{ + HRESULT hresult = NOERROR; + void * lpdata; + ULONG cbWritten; + + VDATEHEAP(); + + LEDebugOut((DEB_ITRACE, "%p _IN UtHGLOBALtoStm ( %lx , %lu , %p )\n", + NULL, hGlobalSrc, dwSize, pstm)); + + lpdata = GlobalLock(hGlobalSrc); + + if (lpdata) + { + hresult = pstm->Write(lpdata, dwSize, &cbWritten); + + // if we didn't write enough data, then it's an error + // condition for us. + + if( hresult == NOERROR && cbWritten != dwSize ) + { + hresult = ResultFromScode(E_FAIL); + } + + if( hresult == NOERROR ) + { + // this call isn't strictly necessary, but may + // be useful for compacting the size of presentations + // stored on disk (when called by the presentation + // code) + hresult = StSetSize(pstm, 0, TRUE); + } + + GlobalUnlock(hGlobalSrc); + } + + + LEDebugOut((DEB_ITRACE, "%p OUT UtHGLOBALtoStm ( %lx )\n", NULL, + hresult)); + + return hresult; +} + +//+------------------------------------------------------------------------- +// +// Function: UtHGLOBALtoHGLOBAL, internal +// +// Synopsis: Copies the source HGLOBAL into the target HGLOBAL +// +// Effects: +// +// Arguments: [hGlobalSrc] -- the source HGLOBAL +// [dwSize] -- the number of bytes to copy +// [hGlobalTgt] -- the target HGLOBAL +// +// Requires: +// +// Returns: HRESULT +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: dd-mmm-yy Author Comment +// 10-Apr-94 alexgo author +// +// Notes: this function will fail if the target hglobal is not large +// enough +// +//-------------------------------------------------------------------------- + +HRESULT UtHGLOBALtoHGLOBAL( HGLOBAL hGlobalSrc, DWORD dwSize, + HGLOBAL hGlobalTgt) +{ + DWORD cbTarget; + void * pvSrc; + void * pvTgt; + HRESULT hresult = ResultFromScode(E_OUTOFMEMORY); + + VDATEHEAP(); + + LEDebugOut((DEB_ITRACE, "%p _IN UtHGLOBALtoHGLOBAL ( %lx , %lu , " + "%lx )\n", NULL, hGlobalSrc, dwSize, hGlobalTgt)); + + cbTarget = GlobalSize(hGlobalTgt); + + if( cbTarget == 0 || cbTarget < dwSize ) + { + hresult = ResultFromScode(E_FAIL); + goto errRtn; + } + + pvSrc = GlobalLock(hGlobalSrc); + + if( pvSrc ) + { + pvTgt = GlobalLock(hGlobalTgt); + + if( pvTgt ) + { + _xmemcpy( pvTgt, pvSrc, dwSize); + + GlobalUnlock(hGlobalTgt); + hresult = NOERROR; + } + + GlobalUnlock(hGlobalSrc); + } + +errRtn: + LEDebugOut((DEB_ITRACE, "%p OUT UtHGLOBALtoHGLOBAL ( %lx )\n", + NULL, hresult)); + + return hresult; +} + +//+------------------------------------------------------------------------- +// +// Function: UtHGLOBALtoStorage, internal +// +// Synopsis: Copies the source HGLOBAL into the target storage +// +// Effects: +// +// Arguments: [hGlobalSrc] -- the source HGLOBAL +// [pStgTgt] -- the target storage +// +// Requires: +// +// Returns: HRESULT +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: dd-mmm-yy Author Comment +// 10-Apr-94 alexgo author +// +// Notes: this function will fail if the source HGLOBAL did not +// originally have a storage layered on top of it. +// +//-------------------------------------------------------------------------- + +HRESULT UtHGLOBALtoStorage( HGLOBAL hGlobalSrc, IStorage *pStgTgt) +{ + HRESULT hresult; + ILockBytes * pLockBytes = NULL; + IStorage * pStgSrc; + ULONG cRefs; + + VDATEHEAP(); + + LEDebugOut((DEB_ITRACE, "%p _IN UtHGLOBALtoStroage ( %lx , %p )" + "\n", NULL, hGlobalSrc, pStgTgt)); + + hresult = CreateILockBytesOnHGlobal(hGlobalSrc, + FALSE /*fDeleteOnRelease*/, &pLockBytes); + + if( hresult != NOERROR ) + { + goto errRtn; + } + + // now we make sure that the hglobal really has a storage + // in it + + if( StgIsStorageILockBytes(pLockBytes) != NOERROR ) + { + hresult = ResultFromScode(E_FAIL); + goto errRtn; + } + + hresult = StgOpenStorageOnILockBytes( pLockBytes, NULL, + STGM_SALL, NULL, 0, &pStgSrc); + + if( hresult == NOERROR ) + { + hresult = pStgSrc->CopyTo( 0, NULL, NULL, pStgTgt); + + // no matter what the result, we want to free the + // source storage + + pStgSrc->Release(); + } + +errRtn: + + if( pLockBytes ) + { + cRefs = pLockBytes->Release(); + Assert(cRefs == 0); + } + + LEDebugOut((DEB_ITRACE, "%p OUT UtHGLOBALtoStorage ( %lx ) " + "[ %p ]\n", NULL, hresult)); + + return hresult; +} + +//+------------------------------------------------------------------------- +// +// Function: UtHGLOBALtoFile, internal +// +// Synopsis: Copies the source HGLOBAL into the target file +// +// Effects: +// +// Arguments: [hGlobalSrc] -- the source HGLOBAL +// [dwSize] -- the number of bytes to copy +// [pszFileName] -- the target file +// +// Requires: +// +// Returns: HRESULT +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: dd-mmm-yy Author Comment +// 10-Apr-94 alexgo author +// +// Notes: if the file already exists, we simply append to it +// +//-------------------------------------------------------------------------- + +HRESULT UtHGLOBALtoFile( HGLOBAL hGlobalSrc, DWORD dwSize, + LPCOLESTR pszFileName) +{ + HRESULT hresult; + HANDLE hFile; + void * pvSrc; + DWORD cbWritten; + + VDATEHEAP(); + + LEDebugOut((DEB_ITRACE, "%p _IN UtHGLOBALtoFile ( %lx , %lu , " + "\"%ws\" )\n", NULL, hGlobalSrc, dwSize, pszFileName)); + + + hresult = ResultFromScode(E_NOTIMPL); + (void)hFile; + (void)pvSrc; + (void)cbWritten; + + +// this doesn't compile for chicago, BUGBUG, fix soon +#ifdef LATER + pvSrc = GlobalLock(hGlobalSrc); + + if( !pvSrc ) + { + hresult = ResultFromScode(E_OUTOFMEMORY); + goto errRtn; + } + + // open the file for append, creating if it doesn't already exist. + + hFile = CreateFile( pszFileName, GENERIC_WRITE, 0, NULL, + OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); + + if( hFile ) + { + if( !WriteFile( hFile, pvSrc, dwSize, &cbWritten, NULL) ) + { + LEDebugOut((DEB_WARN, "WARNING: WriteFile failed!\n")); + hresult = HRESULT_FROM_WIN32(GetLastError()); + } + + if( cbWritten != dwSize && hresult == NOERROR ) + { + // still an error if we didn't write all the bytes + // we wanted + hresult = ResultFromScode(E_FAIL); + } + + if( !CloseHandle(hFile) ) + { + AssertSz(0, "CloseFile failed! Should not happen!"); + + // if there's no error yet, set the error + if( hresult == NOERROR ) + { + hresult = HRESULT_FROM_WIN32(GetLastError()); + } + } + } + else + { + LEDebugOut((DEB_WARN, "WARNING: CreateFile failed!!\n")); + hresult = HRESULT_FROM_WIN32(GetLastError()); + } + + GlobalUnlock(hGlobalSrc); + +errRtn: + +#endif // LATER + + + LEDebugOut((DEB_ITRACE, "%p OUT UtHGLOBALtoFile ( %lx )\n", NULL, + hresult)); + + return hresult; +} + +//+------------------------------------------------------------------------- +// +// Function: UtGetDvtd16Info +// +// Synopsis: Fills in pdvdtInfo +// +// Arguments: [pdvtd16] -- pointer to ANSI DVTARGETDEVICE +// [pdvtdInfo] -- pointer to DVDT_INFO block +// +// Requires: +// +// Returns: HRESULT +// +// Modifies: pdvtdInfo +// +// Algorithm: +// +// History: 06-May-94 AlexT Created from DrewB's original functions +// 10-Jul-94 AlexT Make sure DEVMODE ends up DWORD aligned +// +// Notes: Do we need to do any error checking on the strings? +// +//-------------------------------------------------------------------------- + +// We can't use sizeof(DV_TARGETDEVICE) because MIDL keeps flipping back +// and forth over whether to make the embedded array size 0 or size 1 + +#define UT_DVTARGETDEVICE_SIZE (sizeof(DWORD) + sizeof(WORD) * 4) + +// tdSize td...Offset's +#define DVTD_MINSIZE (sizeof(DWORD) + 4 * sizeof(WORD)) + +extern "C" HRESULT UtGetDvtd16Info(DVTARGETDEVICE const UNALIGNED *pdvtd16, + PDVTDINFO pdvtdInfo) +{ + LEDebugOut((DEB_ITRACE, "%p _IN UtGetDvtd16Info (%p, %p)\n", + NULL, pdvtd16, pdvtdInfo)); + + DEVMODEA UNALIGNED *pdm16; + + // Let's do some sanity checking on the incoming DVTARGETDEVICE + if (pdvtd16->tdSize < DVTD_MINSIZE) + { + LEDebugOut((DEB_WARN, "UtGetDvtd16Info - bad pdvtd16->tdSize\n")); + return(E_INVALIDARG); + } + + // We need at least a DVTARGETDEVICE + pdvtdInfo->cbConvertSize = UT_DVTARGETDEVICE_SIZE; + + // Compute required size for Drv, Device, Port names + if (pdvtd16->tdDriverNameOffset != 0) + { + if (pdvtd16->tdDriverNameOffset > pdvtd16->tdSize || + pdvtd16->tdDriverNameOffset < DVTD_MINSIZE) + { + // Offset can't be larger than size or fall within base + // structure + LEDebugOut((DEB_WARN, "UtGetDvtd16Info - bad pdvtd16->tdDriverNameOffset\n")); + return(E_INVALIDARG); + } + + pdvtdInfo->cchDrvName = strlen((char *)pdvtd16 + + pdvtd16->tdDriverNameOffset) + 1; + + pdvtdInfo->cbConvertSize += pdvtdInfo->cchDrvName * sizeof(WCHAR); + } + else + { + pdvtdInfo->cchDrvName = 0; + } + + if (pdvtd16->tdDeviceNameOffset != 0) + { + if (pdvtd16->tdDeviceNameOffset > pdvtd16->tdSize || + pdvtd16->tdDeviceNameOffset < DVTD_MINSIZE) + { + // Offset can't be larger than size or fall within base + // structure + LEDebugOut((DEB_WARN, "UtGetDvtd16Info - bad pdvtd16->tdDeviceNameOffset\n")); + return(E_INVALIDARG); + } + + pdvtdInfo->cchDevName = strlen((char *)pdvtd16 + + pdvtd16->tdDeviceNameOffset) + 1; + + pdvtdInfo->cbConvertSize += pdvtdInfo->cchDevName * sizeof(WCHAR); + } + else + { + pdvtdInfo->cchDevName = 0; + } + + if (pdvtd16->tdPortNameOffset != 0) + { + if (pdvtd16->tdPortNameOffset > pdvtd16->tdSize || + pdvtd16->tdPortNameOffset < DVTD_MINSIZE) + { + // Offset can't be larger than size or fall within base + // structure + LEDebugOut((DEB_WARN, "UtGetDvtd16Info - bad pdvtd16->tdPortNameOffset\n")); + return(E_INVALIDARG); + } + + + pdvtdInfo->cchPortName = strlen((char *)pdvtd16 + + pdvtd16->tdPortNameOffset) + 1; + + pdvtdInfo->cbConvertSize += pdvtdInfo->cchPortName * sizeof(WCHAR); + } + else + { + pdvtdInfo->cchPortName = 0; + } + + if (pdvtd16->tdExtDevmodeOffset != 0) + { + if (pdvtd16->tdExtDevmodeOffset > pdvtd16->tdSize || + pdvtd16->tdExtDevmodeOffset < DVTD_MINSIZE) + { + // Offset can't be larger than size or fall within base + // structure + LEDebugOut((DEB_WARN, "UtGetDvtd16Info - bad pdvtd16->tdExtDevmodeOffset\n")); + return(E_INVALIDARG); + } + + // The DEVMODEW structure needs to be DWORD aligned, so here we make + // sure cbConvertSize (which will be the beginning of DEVMODEW) is + // DWORD aligned + pdvtdInfo->cbConvertSize += (sizeof(DWORD) - 1); + pdvtdInfo->cbConvertSize &= ~(sizeof(DWORD) - 1); + + // Now compute the space needed for the DEVMODE + pdm16 = (DEVMODEA *)((BYTE *)pdvtd16 + pdvtd16->tdExtDevmodeOffset); + + // We start with a basic DEVMODEW + pdvtdInfo->cbConvertSize += sizeof(DEVMODEW); + + if (pdm16->dmSize > sizeof(DEVMODEA)) + { + // The input DEVMODEA is larger than a standard DEVMODEA, so + // add space for the extra amount + pdvtdInfo->cbConvertSize += pdm16->dmSize - sizeof(DEVMODEA); + } + + // Finally we account for the extra driver data + pdvtdInfo->cbConvertSize += pdm16->dmDriverExtra; + } + + LEDebugOut((DEB_ITRACE, "%p OUT UtGetDvtd16Info (%lx) [%ld]\n", + NULL, S_OK, pdvtdInfo->cbConvertSize)); + + return(S_OK); +} + +//+------------------------------------------------------------------------- +// +// Function: UtConvertDvtd16toDvtd32 +// +// Synopsis: Fills in a 32-bit DVTARGETDEVICE based on a 16-bit +// DVTARGETDEVICE +// +// Arguments: [pdvtd16] -- pointer to ANSI DVTARGETDEVICE +// [pdvtdInfo] -- pointer to DVDT_INFO block +// [pdvtd32] -- pointer to UNICODE DVTARGETDEVICE +// +// Requires: pdvtdInfo must have been filled in by a previous call to +// UtGetDvtd16Info +// +// pdvtd32 must be at least pdvtdInfo->cbConvertSize bytes long +// +// Returns: HRESULT +// +// Modifies: pdvtd32 +// +// Algorithm: +// +// History: 06-May-94 AlexT Created from DrewB's original functions +// 10-Jul-94 AlexT Make sure DEVMODEW is DWORD aligned +// +// Notes: Do we need to do any error checking on the strings? +// +//-------------------------------------------------------------------------- + +extern "C" HRESULT UtConvertDvtd16toDvtd32(DVTARGETDEVICE const UNALIGNED *pdvtd16, + DVTDINFO const *pdvtdInfo, + DVTARGETDEVICE *pdvtd32) +{ + LEDebugOut((DEB_ITRACE, "%p _IN UtConvertDvtd16toDvtd32 (%p, %p, %p)\n", + NULL, pdvtd16, pdvtdInfo, pdvtd32)); + +#if DBG==1 + { + // Verify the passed in pdvtdInfo is what we expect + DVTDINFO dbgDvtdInfo; + Assert(UtGetDvtd16Info(pdvtd16, &dbgDvtdInfo) == S_OK); + Assert(0 == memcmp(&dbgDvtdInfo, pdvtdInfo, sizeof(DVTDINFO))); + } +#endif + + HRESULT hr = S_OK; + USHORT cbOffset; + int cchWritten; + DEVMODEA UNALIGNED *pdm16; + DEVMODEW *pdm32; + UINT nCodePage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; + + memset(pdvtd32, 0, pdvtdInfo->cbConvertSize); + + cbOffset = UT_DVTARGETDEVICE_SIZE; + + if (pdvtdInfo->cchDrvName != 0) + { + pdvtd32->tdDriverNameOffset = cbOffset; + cchWritten = MultiByteToWideChar( + CP_ACP, 0, + (char *)pdvtd16+pdvtd16->tdDriverNameOffset, + pdvtdInfo->cchDrvName, + (LPOLESTR)((BYTE *)pdvtd32 + + pdvtd32->tdDriverNameOffset), + pdvtdInfo->cchDrvName); + if (0 == cchWritten) + { + hr = E_UNEXPECTED; + goto ErrRtn; + } + cbOffset += cchWritten * sizeof(WCHAR); + } + + if (pdvtdInfo->cchDevName != 0) + { + pdvtd32->tdDeviceNameOffset = cbOffset; + cchWritten = MultiByteToWideChar( + nCodePage, 0, + (char *)pdvtd16 + pdvtd16->tdDeviceNameOffset, + pdvtdInfo->cchDevName, + (LPOLESTR)((BYTE *)pdvtd32 + + pdvtd32->tdDeviceNameOffset), + pdvtdInfo->cchDevName); + + if (0 == cchWritten) + { + hr = E_UNEXPECTED; + goto ErrRtn; + } + cbOffset += cchWritten * sizeof(WCHAR); + } + + if (pdvtdInfo->cchPortName != 0) + { + pdvtd32->tdPortNameOffset = cbOffset; + cchWritten = MultiByteToWideChar( + nCodePage, 0, + (char *)pdvtd16 + pdvtd16->tdPortNameOffset, + pdvtdInfo->cchPortName, + (LPOLESTR)((BYTE *)pdvtd32 + + pdvtd32->tdPortNameOffset), + pdvtdInfo->cchPortName); + if (0 == cchWritten) + { + hr = E_UNEXPECTED; + goto ErrRtn; + } + + cbOffset += cchWritten * sizeof(WCHAR); + } + + if (pdvtd16->tdExtDevmodeOffset != 0) + { + // Make sure DEVMODEW will be DWORD aligned + cbOffset += (sizeof(DWORD) - 1); + cbOffset &= ~(sizeof(DWORD) - 1); + + pdvtd32->tdExtDevmodeOffset = cbOffset; + pdm32 = (DEVMODEW *)((BYTE *)pdvtd32+pdvtd32->tdExtDevmodeOffset); + + pdm16 = (DEVMODEA *)((BYTE *)pdvtd16+pdvtd16->tdExtDevmodeOffset); + + // The incoming DEVMODEA can have one of the following two forms: + // + // 1) 32 chars for dmDeviceName + // m bytes worth of fixed size data (where m <= 38) + // n bytes of dmDriverExtra data + // + // and dmSize will be 32+m + // + // 2) 32 chars for dmDeviceName + // 38 bytes worth of fixed size data + // 32 chars for dmFormName + // m additional bytes of fixed size data + // n bytes of dmDriverExtra data + // + // and dmSize will be 32 + 38 + 32 + m + // + // We have to be careful to translate the dmFormName string, if it + // exists + + // First, translate the dmDeviceName + if (MultiByteToWideChar(nCodePage, 0, (char *)pdm16->dmDeviceName, + CCHDEVICENAME, + pdm32->dmDeviceName, CCHDEVICENAME) == 0) + { + hr = E_UNEXPECTED; + goto ErrRtn; + } + + + // Now check to see if we have a dmFormName to translate + if (pdm16->dmSize <= FIELD_OFFSET(DEVMODEA, dmFormName)) + { + // No dmFormName, just copy the remaining m bytes + memcpy(&pdm32->dmSpecVersion, &pdm16->dmSpecVersion, + pdm16->dmSize - CCHDEVICENAME); + } + else + { + // There is a dmFormName; copy the bytes between the names first + memcpy(&pdm32->dmSpecVersion, &pdm16->dmSpecVersion, + FIELD_OFFSET(DEVMODEA, dmFormName) - + FIELD_OFFSET(DEVMODEA, dmSpecVersion)); + + // Now translate the dmFormName + if (MultiByteToWideChar(CP_ACP, 0, (char *)pdm16->dmFormName, + CCHFORMNAME, + pdm32->dmFormName, CCHFORMNAME) == 0) + { + hr = E_UNEXPECTED; + goto ErrRtn; + } + + // Now copy the remaining m bytes + + if (pdm16->dmSize > FIELD_OFFSET(DEVMODEA, dmLogPixels)) + { + memcpy(&pdm32->dmLogPixels, &pdm16->dmLogPixels, + pdm16->dmSize - FIELD_OFFSET(DEVMODEA, dmLogPixels)); + } + } + + pdm32->dmSize = sizeof(DEVMODEW); + if (pdm16->dmSize > sizeof(DEVMODEA)) + { + pdm32->dmSize += pdm16->dmSize - sizeof(DEVMODEA); + } + + // Copy the extra driver bytes + memcpy(((BYTE*)pdm32) + pdm32->dmSize, ((BYTE*)pdm16) + pdm16->dmSize, + pdm16->dmDriverExtra); + + cbOffset += pdm32->dmSize + pdm32->dmDriverExtra; + } + + // Finally, set pdvtd32's size + pdvtd32->tdSize = cbOffset; + + +ErrRtn: + LEDebugOut((DEB_ITRACE, "%p OUT UtConvertDvtd16toDvtd32 (%lx)\n", + NULL, hr)); + + return hr; +} + +//+------------------------------------------------------------------------- +// +// Function: UtGetDvtd32Info +// +// Synopsis: Fills in pdvdtInfo +// +// Arguments: [pdvtd32] -- pointer to ANSI DVTARGETDEVICE +// [pdvtdInfo] -- pointer to DVDT_INFO block +// +// Requires: +// +// Returns: HRESULT +// +// Modifies: pdvtdInfo +// +// Algorithm: +// +// History: 06-May-94 AlexT Created from DrewB's original functions +// +// Notes: Do we need to do any error checking on the strings? +// +//-------------------------------------------------------------------------- + +extern "C" HRESULT UtGetDvtd32Info(DVTARGETDEVICE const *pdvtd32, PDVTDINFO pdvtdInfo) +{ + LEDebugOut((DEB_ITRACE, "%p _IN UtGetDvtd32Info (%p, %p)\n", + NULL, pdvtd32, pdvtdInfo)); + + DEVMODEW *pdm32; + + // Let's do some sanity checking on the incoming DVTARGETDEVICE + if (pdvtd32->tdSize < DVTD_MINSIZE) + { + LEDebugOut((DEB_WARN, "UtGetDvtd32Info - bad pdvtd32->tdSize\n")); + return(E_INVALIDARG); + } + + pdvtdInfo->cbConvertSize = UT_DVTARGETDEVICE_SIZE; + + // Compute required size for Drv, Device, Port names + if (pdvtd32->tdDriverNameOffset != 0) + { + if (pdvtd32->tdDriverNameOffset > pdvtd32->tdSize || + pdvtd32->tdDriverNameOffset < DVTD_MINSIZE) + { + // Offset can't be larger than size or fall within base + // structure + LEDebugOut((DEB_WARN, "UtGetDvtd32Info - bad pdvtd32->tdDriverNameOffset\n")); + return(E_INVALIDARG); + } + + pdvtdInfo->cchDrvName = lstrlenW((WCHAR *)((BYTE *)pdvtd32 + + pdvtd32->tdDriverNameOffset)) + 1; + + pdvtdInfo->cbConvertSize += pdvtdInfo->cchDrvName * sizeof(WCHAR); + } + else + { + pdvtdInfo->cchDrvName = 0; + } + + if (pdvtd32->tdDeviceNameOffset != 0) + { + if (pdvtd32->tdDeviceNameOffset > pdvtd32->tdSize || + pdvtd32->tdDeviceNameOffset < DVTD_MINSIZE) + { + // Offset can't be larger than size or fall within base + // structure + LEDebugOut((DEB_WARN, "UtGetDvtd32Info - bad pdvtd32->tdDeviceNameOffset\n")); + return(E_INVALIDARG); + } + + pdvtdInfo->cchDevName = lstrlenW((WCHAR *)((BYTE *)pdvtd32 + + pdvtd32->tdDeviceNameOffset)) + 1; + + pdvtdInfo->cbConvertSize += pdvtdInfo->cchDevName * sizeof(WCHAR); + } + else + { + pdvtdInfo->cchDevName = 0; + } + + if (pdvtd32->tdPortNameOffset != 0) + { + if (pdvtd32->tdPortNameOffset > pdvtd32->tdSize || + pdvtd32->tdPortNameOffset < DVTD_MINSIZE) + { + // Offset can't be larger than size or fall within base + // structure + LEDebugOut((DEB_WARN, "UtGetDvtd32Info - bad pdvtd32->tdPortNameOffset\n")); + return(E_INVALIDARG); + } + + pdvtdInfo->cchPortName = lstrlenW((WCHAR *)((BYTE *)pdvtd32 + + pdvtd32->tdPortNameOffset)) + 1; + + pdvtdInfo->cbConvertSize += pdvtdInfo->cchPortName * sizeof(WCHAR); + } + else + { + pdvtdInfo->cchPortName = 0; + } + + // Now compute the space needed for the DEVMODE + if (pdvtd32->tdExtDevmodeOffset != 0) + { + if (pdvtd32->tdExtDevmodeOffset > pdvtd32->tdSize || + pdvtd32->tdExtDevmodeOffset < DVTD_MINSIZE) + { + // Offset can't be larger than size or fall within base + // structure + LEDebugOut((DEB_WARN, "UtGetDvtd32Info - bad pdvtd32->tdExtDevmodeOffset\n")); + return(E_INVALIDARG); + } + + // The DEVMODEA structure needs to be DWORD aligned, so here we make + // sure cbConvertSize (which will be the beginning of DEVMODEA) is + // DWORD aligned + pdvtdInfo->cbConvertSize += (sizeof(DWORD) - 1); + pdvtdInfo->cbConvertSize &= ~(sizeof(DWORD) - 1); + + pdm32 = (DEVMODEW *)((BYTE *)pdvtd32+pdvtd32->tdExtDevmodeOffset); + + // We start with a basic DEVMODEA + pdvtdInfo->cbConvertSize += sizeof(DEVMODEA); + + if (pdm32->dmSize > sizeof(DEVMODEW)) + { + // The input DEVMODEW is larger than a standard DEVMODEW, so + // add space for the extra amount + pdvtdInfo->cbConvertSize += pdm32->dmSize - sizeof(DEVMODEW); + } + + // Finally we account for the extra driver data + pdvtdInfo->cbConvertSize += pdm32->dmDriverExtra; + } + + LEDebugOut((DEB_ITRACE, "%p OUT UtGetDvtd32Info (%lx) [%ld]\n", + NULL, S_OK, pdvtdInfo->cbConvertSize)); + + return(S_OK); +} + +//+------------------------------------------------------------------------- +// +// Function: UtConvertDvtd32toDvtd16 +// +// Synopsis: Fills in a 32-bit DVTARGETDEVICE based on a 16-bit +// DVTARGETDEVICE +// +// Arguments: [pdvtd32] -- pointer to ANSI DVTARGETDEVICE +// [pdvtdInfo] -- pointer to DVDT_INFO block +// [pdvtd16] -- pointer to UNICODE DVTARGETDEVICE +// +// Requires: pdvtdInfo must have been filled in by a previous call to +// UtGetDvtd32Info +// +// pdvtd16 must be at least pdvtdInfo->cbSizeConvert bytes long +// +// Returns: HRESULT +// +// Modifies: pdvtd16 +// +// Algorithm: +// +// History: 06-May-94 AlexT Created from DrewB's original functions +// +// Notes: Do we need to do any error checking on the strings? +// +// On Chicago we'll have to provide helper code to do this +// translation +// +//-------------------------------------------------------------------------- + +extern "C" HRESULT UtConvertDvtd32toDvtd16(DVTARGETDEVICE const *pdvtd32, + DVTDINFO const *pdvtdInfo, + DVTARGETDEVICE UNALIGNED *pdvtd16) +{ + LEDebugOut((DEB_ITRACE, "%p _IN UtConvertDvtd32toDvtd16 (%p, %p, %p)\n", + NULL, pdvtd32, pdvtdInfo, pdvtd16)); + +#if DBG==1 + { + // Verify the passed in pdvtdInfo is what we expect + DVTDINFO dbgDvtdInfo; + Assert(UtGetDvtd32Info(pdvtd32, &dbgDvtdInfo) == S_OK); + Assert(0 == memcmp(&dbgDvtdInfo, pdvtdInfo, sizeof(DVTDINFO))); + } +#endif + + HRESULT hr = S_OK; + USHORT cbOffset; + int cbWritten; + DEVMODEA UNALIGNED *pdm16; + DEVMODEW *pdm32; + UINT nCodePage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; + + memset(pdvtd16, 0, pdvtdInfo->cbConvertSize); + + cbOffset = UT_DVTARGETDEVICE_SIZE; + + if (pdvtdInfo->cchDrvName != 0) + { + pdvtd16->tdDriverNameOffset = cbOffset; + cbWritten = WideCharToMultiByte(CP_ACP, 0, + (WCHAR *)((BYTE *)pdvtd32 + + pdvtd32->tdDriverNameOffset), + pdvtdInfo->cchDrvName, + (char *)pdvtd16 + pdvtd16->tdDriverNameOffset, + pdvtdInfo->cchDrvName * sizeof(WCHAR), + NULL, NULL); + + if (0 == cbWritten) + { + hr = E_UNEXPECTED; + goto ErrRtn; + } + cbOffset += cbWritten; + } + + if (pdvtdInfo->cchDevName != 0) + { + pdvtd16->tdDeviceNameOffset = cbOffset; + cbWritten = WideCharToMultiByte( + nCodePage, 0, + (WCHAR *)((BYTE *)pdvtd32 + + pdvtd32->tdDeviceNameOffset), + pdvtdInfo->cchDevName, + (char *)pdvtd16 + pdvtd16->tdDeviceNameOffset, + pdvtdInfo->cchDevName * sizeof(WCHAR), + NULL, NULL); + + if (0 == cbWritten) + { + hr = E_UNEXPECTED; + goto ErrRtn; + } + cbOffset += cbWritten; + } + + if (pdvtdInfo->cchPortName != 0) + { + pdvtd16->tdPortNameOffset = cbOffset; + cbWritten = WideCharToMultiByte(nCodePage, 0, + (WCHAR *)((BYTE *)pdvtd32 + + pdvtd32->tdPortNameOffset), + pdvtdInfo->cchPortName, + (char *)pdvtd16 + pdvtd16->tdPortNameOffset, + pdvtdInfo->cchPortName * sizeof(WCHAR), + NULL, NULL); + if (0 == cbWritten) + { + hr = E_UNEXPECTED; + goto ErrRtn; + } + cbOffset += cbWritten; + } + + if (pdvtd32->tdExtDevmodeOffset != 0) + { + // Make sure DEVMODEA will be DWORD aligned + cbOffset += (sizeof(DWORD) - 1); + cbOffset &= ~(sizeof(DWORD) - 1); + + pdvtd16->tdExtDevmodeOffset = cbOffset; + pdm16 = (DEVMODEA *)((BYTE *)pdvtd16+pdvtd16->tdExtDevmodeOffset); + + pdm32 = (DEVMODEW *)((BYTE *)pdvtd32+pdvtd32->tdExtDevmodeOffset); + + // The incoming DEVMODEW can have one of the following two forms: + // + // 1) 32 WCHARs for dmDeviceName + // m bytes worth of fixed size data (where m <= 38) + // n bytes of dmDriverExtra data + // + // and dmSize will be 64+m + // + // 2) 32 WCHARs for dmDeviceName + // 38 bytes worth of fixed size data + // 32 WCHARs for dmFormName + // m additional bytes of fixed size data + // n bytes of dmDriverExtra data + // + // and dmSize will be 64 + 38 + 64 + m + // + // We have to be careful to translate the dmFormName string, if it + // exists + + + // Need to attempt to copy the entire buffer since old UI lib does a memcmp to verify if ptd's are equal + + if (WideCharToMultiByte(nCodePage, 0, pdm32->dmDeviceName,CCHDEVICENAME, + (char *)pdm16->dmDeviceName, CCHDEVICENAME, + NULL, NULL) == 0) + { + + // in DBCS case we can run out of pdm16->dmDeviceName buffer space + // Current Implementation of WideCharToMultiByte copies in what fit before error + // but in case this behavior changes copy again up to NULL char if error out above + + if (WideCharToMultiByte(nCodePage, 0, pdm32->dmDeviceName,-1, + (char *)pdm16->dmDeviceName, CCHDEVICENAME, + NULL, NULL) == 0) + { + hr = E_UNEXPECTED; + goto ErrRtn; + } + } + + // Now check to see if we have a dmFormName to translate + if (pdm32->dmSize <= FIELD_OFFSET(DEVMODEW, dmFormName)) + { + // No dmFormName, just copy the remaining m bytes + memcpy(&pdm16->dmSpecVersion, &pdm32->dmSpecVersion, + pdm32->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion)); + } + else + { + // There is a dmFormName; copy the bytes between the names first + memcpy(&pdm16->dmSpecVersion, &pdm32->dmSpecVersion, + FIELD_OFFSET(DEVMODEW, dmFormName) - + FIELD_OFFSET(DEVMODEW, dmSpecVersion)); + + // Now translate the dmFormName + if (WideCharToMultiByte(CP_ACP, 0, + pdm32->dmFormName, CCHFORMNAME, + (char *) pdm16->dmFormName, CCHFORMNAME, + NULL, NULL) == 0) + { + + if (WideCharToMultiByte(CP_ACP, 0, + pdm32->dmFormName, -1, + (char *) pdm16->dmFormName, CCHFORMNAME, + NULL, NULL) == 0) + { + hr = E_UNEXPECTED; + goto ErrRtn; + } + } + + // Now copy the remaining m bytes + + if (pdm32->dmSize > FIELD_OFFSET(DEVMODEW, dmLogPixels)) + { + memcpy(&pdm16->dmLogPixels, &pdm32->dmLogPixels, + pdm32->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels)); + } + } + + pdm16->dmSize = sizeof(DEVMODEA); + if (pdm32->dmSize > sizeof(DEVMODEW)) + { + pdm16->dmSize += pdm32->dmSize - sizeof(DEVMODEW); + } + + // Copy the extra driver bytes + memcpy(((BYTE*)pdm16) + pdm16->dmSize, ((BYTE*)pdm32) + pdm32->dmSize, + pdm32->dmDriverExtra); + + cbOffset += pdm16->dmSize + pdm16->dmDriverExtra; + } + + // Finally, set pdvtd16's size + pdvtd16->tdSize = cbOffset; + +ErrRtn: + LEDebugOut((DEB_ITRACE, "%p OUT UtConvertDvtd32toDvtd16 (%lx)\n", + NULL, hr)); + + return hr; +} + +//+------------------------------------------------------------------------- +// +// Function: UtGetUNICODEData, PRIVATE INTERNAL +// +// Synopsis: Given a string length, and two pointers (one ANSI, one +// OLESTR), returns the UNICODE version of whichever string +// is valid. +// +// Effects: Memory is allocated on the caller's pointer for new OLESTR +// +// Arguments: [ulLength] -- length of string in CHARACTERS (not bytes) +// (including terminator) +// [szANSI] -- candidate ANSI string +// [szOLESTR] -- candidate OLESTR string +// [pstr] -- OLESTR OUT parameter +// +// Returns: NOERROR on success +// E_OUTOFMEMORY on allocation failure +// E_ANSITOUNICODE if ANSI cannot be converted to UNICODE +// +// Algorithm: If szOLESTR is available, a simple copy is performed +// If szOLESTR is not available, szANSI is converted to UNICODE +// and the result is copied. +// +// History: dd-mmm-yy Author Comment +// 08-Mar-94 davepl Created +// +// Notes: Only one of the two input strings (ANSI or UNICODE) should +// be set on entry. +// +//-------------------------------------------------------------------------- + +INTERNAL UtGetUNICODEData + ( ULONG ulLength, + LPSTR szANSI, + LPOLESTR szOLESTR, + LPOLESTR * pstr ) +{ + VDATEHEAP(); + + // This fn is only called when one of the input strings + // has valid data... assert the impossible. + + Win4Assert(pstr); // must have an out string + Win4Assert(ulLength); // must have a non-zero length + Win4Assert(szANSI || szOLESTR); // must have at least one source string + + // If neither the ANSI nor the OLESTR version has data, + // there is nothing to return. + +#if 0 +// This is no better than what was there!!! + *pstr = NULL; + if (szOLESTR) { + *pstr = (LPOLESTR) UtDupPtr(szOLESTR, ulLength * sizeof(OLECHAR)); + } + else if (szANSI) { + if (FALSE == MultiByteToWideChar(CP_ACP, // Code page ANSI + 0, // Flags (none) + szANSI, // Source ANSI str + ulLength, // length of string + *pstr, // Dest UNICODE buffer + ulLength * sizeof(OLECHAR) )) // size of UNICODE buffer + { + PubMemFree(*pstr); + *pstr = NULL; + return ResultFromScode(E_UNSPEC); + } + + } + + if (NULL == *pstr) + { + return ResultFromScode(E_OUTOFMEMORY); + } + +#else + + if (!(szANSI || szOLESTR)) + { + *pstr = NULL; + } + + // Allocate memory for the UNICODE return string + + *pstr = (LPOLESTR) PubMemAlloc(ulLength * sizeof(OLECHAR)); + if (NULL == *pstr) + { + return ResultFromScode(E_OUTOFMEMORY); + } + + // Trivial case: we already have UNICODE, just copy it + if (szOLESTR) + { + _xstrcpy(*pstr, szOLESTR); + return(NOERROR); + } + + // Otherwise, we have to convert the ANSI string to UNICODE + // and return that. + + else + { + if (FALSE == MultiByteToWideChar(CP_ACP, // Code page ANSI + 0, // Flags (none) + szANSI, // Source ANSI str + ulLength, // length of string + *pstr, // Dest UNICODE buffer + ulLength * sizeof(OLECHAR) )) // size of UNICODE buffer + { + PubMemFree(*pstr); + *pstr = NULL; + return ResultFromScode(E_UNSPEC); + } + } + return NOERROR; +#endif +} + +//+------------------------------------------------------------------------- +// +// Function: UtPutUNICODEData, PRIVATE INTERNAL +// +// Synopsis: Given an OLESTR and two possible buffer pointer, one ANSI +// and the other OLESTR, this fn tries to convert the string +// down to ANSI. If it succeeds, it allocates memory on the +// ANSI ptr for the result. If it fails, it allocates memory +// on the UNICODE ptr and copies the input string over. The +// length of the final result (ANSI or UNICODE) is returned +// in dwResultLen. +// +// Arguments: [ulLength] -- input length of OLESTR str +// NB!!!! this value must include the +// null terminator character. +// [str] -- the OLESTR to store +// [pszANSI] -- candidate ANSI str ptr +// [pszOLESTR] -- candidate OLESTR str ptr. May be NULL, +// in which case no copy is made of the +// original string if the ANSI conversion +// fails. +// [pdwResultLen] -- where to store the length of result. This +// length includes the terminating NULL. +// Length is in CHARACTERS. +// +// Returns: NOERROR on success +// E_OUTOFMEMORY on allocation failure +// E_FAIL can't convert ANSI string and no +// pszOLESTR is NULL +// +// History: dd-mmm-yy Author Comment +// 10-Jun-94 alexgo allow pszOLESTR to be NULL +// 08-Mar-94 davepl Created +// +//-------------------------------------------------------------------------- + +// this function is poorly coded. But, it looks like it only gets called when a 1.0 +// clip format is needed. That is not very often! + +INTERNAL UtPutUNICODEData + ( ULONG ulLength, + LPOLESTR str, + LPSTR * pszANSI, + LPOLESTR * pszOLESTR, + DWORD * pdwResultLen ) +{ + VDATEHEAP(); + + Win4Assert(pszANSI); + Win4Assert(str); + Win4Assert(pdwResultLen); + Win4Assert(ulLength); + + // Free any strings currently attached to these pointers; if we wind + // up setting one here, we can't leave the other valid. + + if (*pszANSI) + { + PubMemFree(*pszANSI); + *pszANSI = NULL; + } + if (pszOLESTR && *pszOLESTR) + { + PubMemFree(*pszOLESTR); + *pszOLESTR = NULL; + } + + // Create a working buffer for UNICODE->ANSI conversion + LPSTR szANSITEMP = (LPSTR) PubMemAlloc((ulLength+1) * 2); + if (NULL == szANSITEMP) + { + return ResultFromScode(E_OUTOFMEMORY); + } + + // Try to convert the UNICODE down to ANSI. If it succeeds, + // we just copy the result to the ANSI dest. If it fails, + // we copy the UNICODE version direct to the UNICODE dest. + + LPCSTR pDefault = "?"; + BOOL fUseDef = 0; + + if (FALSE == WideCharToMultiByte (CP_ACP, + 0, + str, + ulLength, + szANSITEMP, + (ulLength + 1) * 2, + pDefault, + &fUseDef) || fUseDef ) + { + // UNICODE->ANSI failed! + + // Won't be needing the ANSI buffer anymore... + PubMemFree(szANSITEMP); + + if( pszOLESTR ) + { + *pszANSI = NULL; + *pszOLESTR = (LPOLESTR) PubMemAlloc((ulLength + 1) * sizeof(OLECHAR)); + if (NULL == *pszOLESTR) + { + *pdwResultLen = 0; + return ResultFromScode(E_OUTOFMEMORY); + } + // Move the UNICODE source to UNICODE dest + _xstrcpy(*pszOLESTR, str); + *pdwResultLen = _xstrlen(str) + 1; + + // That's it... return success + return(NOERROR); + } + else + { + return ResultFromScode(E_FAIL); + } + } + + // This code path is taken when the conversion to ANSI was + // successful. We copy the ANSI result to the ANSI dest. + + if( pszOLESTR ) + { + *pszOLESTR = NULL; + } + + *pdwResultLen = strlen(szANSITEMP) + 1; + *pszANSI = (LPSTR) PubMemAlloc(*pdwResultLen); + if (NULL == *pszANSI) + { + *pdwResultLen = 0; + return ResultFromScode(E_OUTOFMEMORY); + } + strcpy(*pszANSI, szANSITEMP); + + PubMemFree(szANSITEMP); + + return(NOERROR); +} + +// +// Object Stabilization classes +// + +//+------------------------------------------------------------------------- +// +// Member: CSafeRefCount::CSafeRefCount +// +// Synopsis: constructor for the safe ref count class +// +// Effects: +// +// Arguments: none +// +// Requires: +// +// Returns: none +// +// Signals: +// +// Modifies: +// +// Derivation: +// +// Algorithm: +// +// History: dd-mmm-yy Author Comment +// 28-Jul-94 alexgo author +// +// Notes: +// +//-------------------------------------------------------------------------- + +CSafeRefCount::CSafeRefCount() +{ + RefDebugOut((DEB_TRACE, "%p _IN CSafeRefCount::CSafeRefCount ( )\n", + this)); + + m_cRefs = 0; + m_cNest = 0; + m_fInDelete = FALSE; + + RefDebugOut((DEB_TRACE, "%p OUT CSafeRefCount::CSafeRefcount ( )\n", + this)); +} + +//+------------------------------------------------------------------------- +// +// Member: CSafeRefCount::~CSafeRefCount (virtual) +// +// Synopsis: +// +// Effects: +// +// Arguments: +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Derivation: +// +// Algorithm: +// +// History: dd-mmm-yy Author Comment +// 28-Jul-94 alexgo author +// +// Notes: this fcn MUST be in retail build even though it does nothing +// it is needed to trigger derived class's virtual destructors +// +//-------------------------------------------------------------------------- + +//#ifdef _DEBUG +CSafeRefCount::~CSafeRefCount() +{ + Assert(m_cRefs == 0 && m_cNest == 0 && m_fInDelete == TRUE); +} +//#endif + +//+------------------------------------------------------------------------- +// +// Member: CSafeRefCount::SafeAddRef +// +// Synopsis: increments the reference count on the object +// +// Effects: +// +// Arguments: none +// +// Requires: +// +// Returns: ULONG -- the reference count after the increment +// +// Signals: +// +// Modifies: +// +// Derivation: +// +// Algorithm: increments the reference count. +// +// History: dd-mmm-yy Author Comment +// 28-Jul-94 alexgo author +// +// Notes: +// +//-------------------------------------------------------------------------- + +ULONG CSafeRefCount::SafeAddRef() +{ + RefDebugOut((DEB_TRACE, "%p _IN CSafeRefCount::SafeAddRef ( )\n", + this)); + + m_cRefs++; + + //AssertSz(m_fInDelete == FALSE, "AddRef called on deleted object!"); + + // this *could* be really bad. If we are deleting the object, + // it means that during the destructor, somebody made an outgoing + // call eventually ended up with another addref to ourselves + // (even though all pointers to us had been 'Released'). + // + // this is usually caused by code like the following: + // m_pFoo->Release(); + // m_pFoo = NULL; + // + // If the the Release may cause Foo to be deleted, which may cause + // the object to get re-entered during Foo's destructor. However, + // 'this' object has not yet set m_pFoo to NULL, so it may + // try to continue to use m_pFoo. + // + // However, the May '94 aggregation rules REQUIRE this behaviour + // In your destructor, you have to addref the outer unknown before + // releasing cached interface pointers on your aggregatee. We + // can't put an assert here because we do this all the time now. + // + // REVIEW32: we may want to try to figure out a way to distinguish + // 'safe' uses of AddRef-after-zero (like the aggregation case) + // as opposed to dangerous cases (noted above). + + RefDebugOut((DEB_TRACE, "%p OUT CSafeRefCount::SafeAddRef ( %lu )\n", + this, m_cRefs)); + + return m_cRefs; +} + +//+------------------------------------------------------------------------- +// +// Member: CSafeRefCount::SafeRelease +// +// Synopsis: decrements the reference count on the object +// +// Effects: May delete the object! +// +// Arguments: +// +// Requires: +// +// Returns: ULONG -- the reference count after decrement +// +// Signals: +// +// Modifies: +// +// Derivation: +// +// Algorithm: decrements the reference count. If the reference count +// is zero AND the nest count is zero AND we are not currently +// trying to delete our object, then it is safe to delete. +// +// History: dd-mmm-yy Author Comment +// 28-Jul-94 alexgo author +// +// Notes: +// +//-------------------------------------------------------------------------- + +ULONG CSafeRefCount::SafeRelease() +{ + ULONG cRefs; + + RefDebugOut((DEB_TRACE, "%p _IN CSafeRefCount::SafeRelease ( )\n", + this)); + + if( m_cRefs > 0 ) + { + cRefs = --m_cRefs; + + if( m_cRefs == 0 && m_cNest == 0 && m_fInDelete == FALSE ) + { + RefDebugOut((DEB_TRACE, + "DELETING CSafeRefCount %p\n", this)); + + m_fInDelete = TRUE; + delete this; + } + } + else + { + // somebody is releasing a non-addrefed pointer!! + AssertSz(0, "Release called on a non-addref'ed pointer!\n"); + + cRefs = 0; + } + + RefDebugOut((DEB_TRACE, "%p OUT CSafeRefCount::SafeRelease ( %lu )\n", + this, cRefs)); + + return cRefs; +} + +//+------------------------------------------------------------------------- +// +// Member: CSafeRefCount::IncrementNestCount +// +// Synopsis: increments the nesting count of the object +// +// Effects: +// +// Arguments: none +// +// Requires: +// +// Returns: ULONG; the nesting count after increment +// +// Signals: +// +// Modifies: +// +// Derivation: +// +// Algorithm: +// +// History: dd-mmm-yy Author Comment +// 28-Jul-94 alexgo author +// +// Notes: The nesting count is the count of how many times an +// an object has been re-entered. For example, suppose +// somebody calls pFoo->Bar1(), which makes some calls that +// eventually call pFoo->Bar2();. On entrace to Bar2, the +// nest count of the object should be 2 (since the invocation +// of Bar1 is still on the stack above us). +// +// It is important to keep track of the nest count so we do +// not accidentally delete ourselves during a nested invocation. +// If we did, then when the stack unwinds to the original +// top level call, it could try to access a non-existent member +// variable and crash. +// +//-------------------------------------------------------------------------- + +ULONG CSafeRefCount::IncrementNestCount() +{ + RefDebugOut((DEB_TRACE, "%p _IN CSafeRefCount::IncrementNestCount " + "( )\n", this)); + +#if DBG == 1 + if( m_fInDelete ) + { + RefDebugOut((DEB_IWARN, "WARNING: CSafeRefCount, object %p " + "re-entered during delete!\n", this)); + } +#endif + + m_cNest++; + + RefDebugOut((DEB_TRACE, "%p OUT CSafeRefCount::IncrementNestCount " + "( %lu )\n", this, m_cNest)); + + return m_cNest; +} + +//+------------------------------------------------------------------------- +// +// Member: CSafeRefCount::DecrementNestCount +// +// Synopsis: decrements the nesting count and deletes the object +// (if necessary) +// +// Effects: may delete 'this' object! +// +// Arguments: none +// +// Requires: +// +// Returns: ULONG, the nesting count after decrement +// +// Signals: +// +// Modifies: +// +// Derivation: +// +// Algorithm: decrements the nesting count. If the nesting count is zero +// AND the reference count is zero AND we are not currently +// trying to delete ourselves, then delete 'this' object +// +// History: dd-mmm-yy Author Comment +// 28-Jul-94 alexgo author +// +// Notes: +// +//-------------------------------------------------------------------------- + +ULONG CSafeRefCount::DecrementNestCount() +{ + ULONG cNest; + + RefDebugOut((DEB_TRACE, "%p _IN CSafeRefCount::DecrementNestCount " + "( )\n", this)); + + if( m_cNest > 0 ) + { + cNest = --m_cNest; + + if( m_cRefs == 0 && m_cNest == 0 && m_fInDelete == FALSE ) + { + RefDebugOut((DEB_TRACE, + "DELETING CSafeRefCount %p\n", this)); + + m_fInDelete = TRUE; + delete this; + } + } + else + { + // somebody forget to increment the nest count!! + AssertSz(0, "Unbalanced nest count!!"); + + cNest = 0; + } + + RefDebugOut((DEB_TRACE, "%p OUT CSafeRefCount::DecrementNestCount " + "( %lu )\n", this, cNest)); + + return cNest; +} + +//+------------------------------------------------------------------------- +// +// Member: CSafeRefCount::IsZombie +// +// Synopsis: determines whether or not the object is in a zombie state +// (i.e. all references gone, but we are still on the stack +// somewhere). +// +// Effects: +// +// Arguments: none +// +// Requires: +// +// Returns: TRUE if in a zombie state +// FALSE otherwise +// +// Signals: +// +// Modifies: +// +// Derivation: +// +// Algorithm: If we are in the middle of a delete, or if the ref count +// is zero and the nest count is greater than zero, then we +// are a zombie +// +// History: dd-mmm-yy Author Comment +// 28-Jul-94 alexgo author +// +// Notes: +// +//-------------------------------------------------------------------------- + +BOOL CSafeRefCount::IsZombie() +{ + BOOL fIsZombie; + + RefDebugOut((DEB_TRACE, "%p _IN CSafeRefCount::IsZombie ( )\n", + this)); + + if( (m_cRefs == 0 && m_cNest > 0) || m_fInDelete == TRUE ) + { + fIsZombie = TRUE; + } + else + { + fIsZombie = FALSE; + } + + RefDebugOut((DEB_TRACE, "%p OUT CSafeRefCount::IsZombie ( %d )\n", + this, fIsZombie)); + + return fIsZombie; +} + +//+------------------------------------------------------------------------- +// +// Member: CSafeRefCount::Dump, public (_DEBUG only) +// +// Synopsis: return a string containing the contents of the data members +// +// Effects: +// +// Arguments: [ppszDump] - an out pointer to a null terminated character array +// [ulFlag] - flag determining prefix of all newlines of the +// out character array (default is 0 - no prefix) +// [nIndentLevel] - will add a indent prefix after the other prefix +// for ALL newlines (including those with no prefix) +// +// Requires: +// +// Returns: HRESULT +// +// Signals: +// +// Modifies: [ppsz] - argument +// +// Derivation: +// +// Algorithm: +// +// History: dd-mmm-yy Author Comment +// 20-Jan-95 t-ScottH author +// +// Notes: +// +//-------------------------------------------------------------------------- +#ifdef _DEBUG + +HRESULT CSafeRefCount::Dump(char **ppszDump, ULONG ulFlag, int nIndentLevel) +{ + int i; + char *pszPrefix; + dbgstream dstrPrefix; + dbgstream dstrDump; + + // determine prefix of newlines + if ( ulFlag & DEB_VERBOSE ) + { + dstrPrefix << this << " _VB "; + } + + // determine indentation prefix for all newlines + for (i = 0; i < nIndentLevel; i++) + { + dstrPrefix << DUMPTAB; + } + + pszPrefix = dstrPrefix.str(); + + // put data members in stream + dstrDump << pszPrefix << "References = " << m_cRefs << endl; + dstrDump << pszPrefix << "Nesting level = " << m_cNest << endl; + dstrDump << pszPrefix << "InDelete = "; + if (m_fInDelete == TRUE) + { + dstrDump << "TRUE" << endl; + } + else + { + dstrDump << "FALSE" << endl; + } + + // clean up and provide pointer to character array + *ppszDump = dstrDump.str(); + + if (*ppszDump == NULL) + { + *ppszDump = UtDupStringA(szDumpErrorMessage); + } + + CoTaskMemFree(pszPrefix); + + return NOERROR; +} + +#endif //_DEBUG + +//+------------------------------------------------------------------------- +// +// Function: DumpCSafeRefCount, public (_DEBUG only) +// +// Synopsis: calls the CSafeRefCount::Dump method, takes care of errors and +// returns the zero terminated string +// +// Effects: +// +// Arguments: [pSRC] - pointer to CSafeRefCount +// [ulFlag] - flag determining prefix of all newlines of the +// out character array (default is 0 - no prefix) +// [nIndentLevel] - will add a indent prefix after the other prefix +// for ALL newlines (including those with no prefix) +// +// Requires: +// +// Returns: character array of structure dump or error (null terminated) +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: dd-mmm-yy Author Comment +// 20-Jan-95 t-ScottH author +// +// Notes: +// +//-------------------------------------------------------------------------- + +#ifdef _DEBUG + +char *DumpCSafeRefCount(CSafeRefCount *pSRC, ULONG ulFlag, int nIndentLevel) +{ + char *pszDump; + HRESULT hresult; + + if (pSRC == NULL) + { + return UtDupStringA(szDumpBadPtr); + } + + hresult = pSRC->Dump( &pszDump, ulFlag, nIndentLevel); + + if (hresult!=NOERROR) + { + CoTaskMemFree(pszDump); + + return DumpHRESULT(hresult); + } + + return pszDump; +} + +#endif // _DEBUG + +//+------------------------------------------------------------------------- +// +// Member: CThreadCheck::VerifyThreadId +// +// Synopsis: makes sure that the calling thread is the same as the thread +// the object was created on if the threading model is *not* +// free threading. +// +// Effects: +// +// Arguments: none +// +// Requires: +// +// Returns: TRUE/FALSE +// +// Signals: +// +// Modifies: +// +// Derivation: +// +// Algorithm: +// +// History: dd-mmm-yy Author Comment +// 21-Nov-94 alexgo author +// +// Notes: +// +//-------------------------------------------------------------------------- + +BOOL CThreadCheck::VerifyThreadId( void ) +{ + if( m_tid == GetCurrentThreadId() ) + { + return TRUE; + } + else + { + LEDebugOut((DEB_ERROR, "ERROR!: Called on thread %lx, should be" + " %lx \n", GetCurrentThreadId(), m_tid)); + return FALSE; + } +} + +//+------------------------------------------------------------------------- +// +// Member: CThreadCheck::Dump, public (_DEBUG only) +// +// Synopsis: return a string containing the contents of the data members +// +// Effects: +// +// Arguments: [ppszDump] - an out pointer to a null terminated character array +// [ulFlag] - flag determining prefix of all newlines of the +// out character array (default is 0 - no prefix) +// [nIndentLevel] - will add a indent prefix after the other prefix +// for ALL newlines (including those with no prefix) +// +// Requires: +// +// Returns: HRESULT +// +// Signals: +// +// Modifies: [ppszDump] - argument +// +// Derivation: +// +// Algorithm: use dbgstream to create a string containing information on the +// content of data structures +// +// History: dd-mmm-yy Author Comment +// 20-Jan-95 t-ScottH author +// +// Notes: +// +//-------------------------------------------------------------------------- +#ifdef _DEBUG + +HRESULT CThreadCheck::Dump(char **ppszDump, ULONG ulFlag, int nIndentLevel) +{ + int i; + char *pszPrefix; + dbgstream dstrPrefix; + dbgstream dstrDump; + + // determine prefix of newlines + if ( ulFlag & DEB_VERBOSE ) + { + dstrPrefix << this << " _VB "; + } + + // determine indentation prefix for all newlines + for (i = 0; i < nIndentLevel; i++) + { + dstrPrefix << DUMPTAB; + } + + pszPrefix = dstrPrefix.str(); + + // put data members in stream + dstrDump << pszPrefix << "Thread ID = " << m_tid << endl; + + // clean up and provide pointer to character array + *ppszDump = dstrDump.str(); + + if (*ppszDump == NULL) + { + *ppszDump = UtDupStringA(szDumpErrorMessage); + } + + CoTaskMemFree(pszPrefix); + + return NOERROR; +} + +#endif //_DEBUG + +//+------------------------------------------------------------------------- +// +// Function: DumpCThreadCheck, public (_DEBUG only) +// +// Synopsis: calls the CThreadCheck::Dump method, takes care of errors and +// returns the zero terminated string +// +// Effects: +// +// Arguments: [pTC] - pointer to CThreadCheck +// [ulFlag] - flag determining prefix of all newlines of the +// out character array (default is 0 - no prefix) +// [nIndentLevel] - will add a indent prefix after the other prefix +// for ALL newlines (including those with no prefix) +// +// Requires: +// +// Returns: character array of structure dump or error (null terminated) +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: dd-mmm-yy Author Comment +// 20-Jan-95 t-ScottH author +// +// Notes: +// +//-------------------------------------------------------------------------- + +#ifdef _DEBUG + +char *DumpCThreadCheck(CThreadCheck *pTC, ULONG ulFlag, int nIndentLevel) +{ + char *pszDump; + HRESULT hresult; + + if (pTC == NULL) + { + return UtDupStringA(szDumpBadPtr); + } + + hresult = pTC->Dump( &pszDump, ulFlag, nIndentLevel); + + if (hresult != NOERROR) + { + CoTaskMemFree(pszDump); + + return DumpHRESULT(hresult); + } + + return pszDump; +} + +#endif // _DEBUG diff --git a/private/ole32/ole232/util/utstream.cpp b/private/ole32/ole232/util/utstream.cpp new file mode 100644 index 000000000..155278c89 --- /dev/null +++ b/private/ole32/ole232/util/utstream.cpp @@ -0,0 +1,986 @@ + +//+---------------------------------------------------------------------------- +// +// File: +// utstream.cpp +// +// Contents: +// Ole stream utilities +// +// Classes: +// +// Functions: +// +// History: +// 10-May-94 KevinRo Added ansi versions of StringStream stuff +// 25-Jan-94 alexgo first pass at converting to Cairo-style +// memory allocations. +// 01/11/94 - alexgo - added VDATEHEAP macros to every function +// 12/07/93 - ChrisWe - file inspection and cleanup; fixed +// String reading and writing to cope with OLESTR, and +// with differing alignment requirements +// 06/23/93 - SriniK - moved ReadStringStream(), +// WriteStringStream(), and OpenOrCreateStream() here +// from api.cpp and ole2.cpp +// 03/14/92 - SriniK - created +// +//----------------------------------------------------------------------------- + +#include <le2int.h> +#pragma SEG(utstream) + +#include <reterr.h> +#include <limits.h> + +NAME_SEG(UtStream) +ASSERTDATA + +// this constant is used to size string buffers when we attempt to write out +// a string and its length in one write call +#define UTSTRINGBUF_SIZE 100 + +// REVIEW, I thought that OpenStream already had an option to do this. If +// so, this function shouldn't be used in our code. But we can't remove it +// because it is exported to the outside. +// this is exported to the outside +#pragma SEG(OpenOrCreateStream) +STDAPI OpenOrCreateStream(IStorage FAR * pstg, LPCOLESTR pwcsName, + IStream FAR* FAR* ppstm) +{ + VDATEHEAP(); + + HRESULT error; + + error = pstg->CreateStream(pwcsName, STGM_SALL | STGM_FAILIFTHERE, + 0, 0, ppstm); + if (GetScode(error) == STG_E_FILEALREADYEXISTS) + error = pstg->OpenStream(pwcsName, NULL, STGM_SALL, 0, ppstm); + + return(error); +} + +// returns S_OK when string read and allocated (even if zero length) +STDAPI ReadStringStream(CStmBufRead & StmRead, LPOLESTR FAR * ppsz) +{ + VDATEHEAP(); + + ULONG cb; // the length of the string in *bytes* (NOT CHARACTERS) + HRESULT hresult; + + // initialize the the string pointer for error returns + *ppsz = NULL; + + if ((hresult = StmRead.Read((void FAR *)&cb, sizeof(ULONG))) != NOERROR) + return hresult; + + // is string empty? + if (cb == 0) + return(NOERROR); + + // allocate memory to hold the string + if (!(*ppsz = (LPOLESTR)PubMemAlloc(cb))) + return(ReportResult(0, E_OUTOFMEMORY, 0, 0)); + + // read the string; this includes a trailing NULL + if ((hresult = StmRead.Read((void FAR *)(*ppsz), cb)) != NOERROR) + goto errRtn; + + return(NOERROR); + +errRtn: + // delete the string, and return without one + PubMemFree(*ppsz); + *ppsz = NULL; + return(hresult); +} + +//+--------------------------------------------------------------------------- +// +// Function: ReadStringStreamA +// +// Synopsis: Read a ANSI stream from the stream +// +// Effects: +// +// Arguments: [pstm] -- Stream to read from +// [ppsz] -- Output pointer +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: 5-12-94 kevinro Created +// 2-20-95 KentCe Converted to buffer stream reads. +// +// Notes: +// +//---------------------------------------------------------------------------- +STDAPI ReadStringStreamA(CStmBufRead & StmRead, LPSTR FAR * ppsz) +{ + VDATEHEAP(); + + ULONG cb; // the length of the string in *bytes* (NOT CHARACTERS) + HRESULT hresult; + + // initialize the the string pointer for error returns + *ppsz = NULL; + + if ((hresult = StmRead.Read((void FAR *)&cb, sizeof(ULONG))) != NOERROR) + return hresult; + + // is string empty? + if (cb == 0) + return(NOERROR); + + // allocate memory to hold the string + if (!(*ppsz = (LPSTR)PubMemAlloc(cb))) + return(ReportResult(0, E_OUTOFMEMORY, 0, 0)); + + // read the string; this includes a trailing NULL + if ((hresult = StmRead.Read((void FAR *)(*ppsz), cb)) != NOERROR) + goto errRtn; + + return(NOERROR); + +errRtn: + // delete the string, and return without one + PubMemFree(*ppsz); + *ppsz = NULL; + return(hresult); +} + + +// this is exported to the outside +STDAPI WriteStringStream(CStmBufWrite & StmWrite, LPCOLESTR psz) +{ + VDATEHEAP(); + + HRESULT error; + ULONG cb; // the count of bytes (NOT CHARACTERS) to write to the stream + + // if the string pointer is NULL, use zero length + if (!psz) + cb = 0; + else + { + // count is length of string, plus terminating null + cb = (1 + _xstrlen(psz))*sizeof(OLECHAR); + + // if possible, do a single write instead of two + + if (cb <= UTSTRINGBUF_SIZE) + { + BYTE bBuf[sizeof(ULONG)+ + UTSTRINGBUF_SIZE*sizeof(OLECHAR)]; + // buffer for count and string + + // we have to use _xmemcpy to copy the length into + // the buffer to avoid potential boundary faults, + // since bBuf might not be aligned strictly enough + // to do *((ULONG FAR *)bBuf) = cb; + _xmemcpy((void FAR *)bBuf, (const void FAR *)&cb, + sizeof(cb)); + _xmemcpy((void FAR *)(bBuf+sizeof(cb)), + (const void FAR *)psz, cb); + + // write contents of buffer all at once + return( StmWrite.Write((VOID FAR *)bBuf, + cb+sizeof(ULONG))); + } + } + + // if we got here, our buffer isn't large enough, so we do two writes + // first, write the length + if (error = StmWrite.Write((VOID FAR *)&cb, sizeof(ULONG))) + return error; + + // are we are done writing the string? + if (psz == NULL) + return NOERROR; + + // write the string + return(StmWrite.Write((VOID FAR *)psz, cb)); +} + + +//+--------------------------------------------------------------------------- +// +// Function: WriteStringStreamA +// +// Synopsis: Writes an ANSI string to a stream in a length prefixed format. +// +// Effects: +// +// Arguments: [pstm] -- Stream +// [psz] -- Ansi string to write +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: 5-12-94 kevinro Created +// 2-20-95 KentCe Converted to buffer stream writes. +// +// Notes: +// +//---------------------------------------------------------------------------- +FARINTERNAL_(HRESULT) WriteStringStreamA(CStmBufWrite & StmWrite, LPCSTR psz) +{ + VDATEHEAP(); + + HRESULT error; + ULONG cb; // the count of bytes (NOT CHARACTERS) to write to the stream + + // if the string pointer is NULL, use zero length + if (!psz) + cb = 0; + else + { + // count is length of string, plus terminating null + cb = (1 + strlen(psz)); + + // if possible, do a single write instead of two + + if (cb <= UTSTRINGBUF_SIZE) + { + BYTE bBuf[sizeof(ULONG)+ + UTSTRINGBUF_SIZE]; + // buffer for count and string + + // we have to use _xmemcpy to copy the length into + // the buffer to avoid potential boundary faults, + // since bBuf might not be aligned strictly enough + // to do *((ULONG FAR *)bBuf) = cb; + _xmemcpy((void FAR *)bBuf, (const void FAR *)&cb, + sizeof(cb)); + _xmemcpy((void FAR *)(bBuf+sizeof(cb)), + (const void FAR *)psz, cb); + + // write contents of buffer all at once + return(StmWrite.Write((VOID FAR *)bBuf, + cb+sizeof(ULONG))); + } + } + + // if we got here, our buffer isn't large enough, so we do two writes + // first, write the length + if (error = StmWrite.Write((VOID FAR *)&cb, sizeof(ULONG))) + return error; + + // are we are done writing the string? + if (psz == NULL) + return NOERROR; + + // write the string + return(StmWrite.Write((VOID FAR *)psz, cb)); +} + +//+------------------------------------------------------------------------- +// +// Function: StRead +// +// Synopsis: Stream read that only succeeds if all requested bytes read +// +// Arguments: [pStm] -- source stream +// [pvBuffer] -- destination buffer +// [ulcb] -- bytes to read +// +// Returns: S_OK if successful, else error code +// +// Algorithm: +// +// History: 18-May-94 AlexT Added header block, fixed S_FALSE case +// +// Notes: +// +//-------------------------------------------------------------------------- + +#pragma SEG(StRead) +FARINTERNAL_(HRESULT) StRead(IStream FAR * pStm, LPVOID pvBuffer, ULONG ulcb) +{ + VDATEHEAP(); + + HRESULT hr; + ULONG cbRead; + + hr = pStm->Read(pvBuffer, ulcb, &cbRead); + if (FAILED(hr)) + { + return(hr); + } + + if (ulcb == cbRead) + { + return(S_OK); + } + + // We got a success code but not enough bytes - turn it into an error + + return(STG_E_READFAULT); +} + + +// if fRelative is FALSE then dwSize is the size of the stream +// if it is TRUE then find the current seek position and add dwSize to that +// and then set it as the stream size. +FARINTERNAL StSetSize(LPSTREAM pstm, DWORD dwSize, BOOL fRelative) +{ + VDATEHEAP(); + + LARGE_INTEGER large_int; // indicates where to seek to + ULARGE_INTEGER ularge_int; // indicates absolute position + ULARGE_INTEGER ularge_integer; // the size we will set for the stream + HRESULT error; + + LISet32(large_int, 0); + ULISet32(ularge_integer, dwSize); + + if (fRelative) + { + if (error = pstm->Seek(large_int, STREAM_SEEK_CUR, &ularge_int)) + return(error); + + // REVIEW: is there a routine to do 64 bit addition ??? + ularge_integer.LowPart += ularge_int.LowPart; + } + + return(pstm->SetSize(ularge_integer)); +} + + +// REVIEW, is this actually used? +#pragma SEG(StSave10NativeData) +FARINTERNAL_(HRESULT) StSave10NativeData(IStorage FAR* pstgSave, + HANDLE hNative, BOOL fIsOle1Interop) +{ + VDATEHEAP(); + + DWORD dwSize; + HRESULT error; + + if (!hNative) + return ReportResult(0, E_UNSPEC, 0, 0); + + if (!(dwSize = GlobalSize (hNative))) + return ReportResult(0, E_OUTOFMEMORY, 0, 0); + +#ifdef OLE1INTEROP + if ( fIsOle1Interop ) + { + LPLOCKBYTES plkbyt; + LPSTORAGE pstgNative= NULL; + const DWORD grfStg = STGM_READWRITE | STGM_SHARE_EXCLUSIVE + | STGM_DIRECT ; + + if ((error = CreateILockBytesOnHGlobal (hNative, FALSE, &plkbyt))!=NOERROR) + goto errRtn; + + if ((error = StgOpenStorageOnILockBytes (plkbyt, (LPSTORAGE)NULL, grfStg, + (SNB)NULL, 0, &pstgNative)) != NOERROR){ + error = ReportResult(0, E_OUTOFMEMORY, 0, 0); + plkbyt->Release(); + goto errRtn; + } + + pstgNative->CopyTo (0, NULL, 0, pstgSave); + plkbyt->Release(); + pstgNative->Release(); + } + else +#endif + { + LPSTREAM lpstream = NULL; + + if (error = OpenOrCreateStream(pstgSave, OLE10_NATIVE_STREAM, &lpstream)) + goto errRtn; + + if (error = StWrite(lpstream, &dwSize, sizeof(DWORD))) { + lpstream->Release(); + goto errRtn; + } + + error = UtHGLOBALtoStm(hNative, dwSize, lpstream); + + lpstream->Release(); + } + +errRtn: + return error; +} + + + +#pragma SEG(StSave10ItemName) +FARINTERNAL StSave10ItemName + (IStorage FAR* pstg, + LPCSTR szItemNameAnsi) +{ + VDATEHEAP(); + + CStmBufWrite StmWrite; + HRESULT hresult; + + + if ((hresult = StmWrite.OpenOrCreateStream(pstg, OLE10_ITEMNAME_STREAM)) + != NOERROR) + { + return hresult; + } + + hresult = WriteStringStreamA(StmWrite, szItemNameAnsi); + if (FAILED(hresult)) + { + goto errRtn; + } + + hresult = StmWrite.Flush(); + +errRtn: + StmWrite.Release(); + + return hresult; +} + + +#pragma SEG(StRead10NativeData) +FARINTERNAL StRead10NativeData + (IStorage FAR* pstg, + HANDLE FAR* phNative) +{ + VDATEHEAP(); + + DWORD dwSize; + LPSTREAM pstream = NULL; + HRESULT hresult; + + *phNative = NULL; + + RetErr (pstg->OpenStream (OLE10_NATIVE_STREAM, NULL, STGM_SALL, 0, &pstream)); + ErrRtnH (StRead (pstream, &dwSize, sizeof (DWORD))); + + ErrRtnH (UtGetHGLOBALFromStm(pstream, dwSize, phNative)); + +errRtn: + if (pstream) + pstream->Release(); + return hresult; +} + + +//+--------------------------------------------------------------------------- +// +// Member: CStmBuf::CStmBuf, public +// +// Synopsis: Constructor. +// +// Arguments: None. +// +// Returns: None. +// +// History: 20-Feb-95 KentCe Created +// +// Notes: +// +//---------------------------------------------------------------------------- +CStmBuf::CStmBuf(void) +{ + m_pStm = NULL; +} + + +//+--------------------------------------------------------------------------- +// +// Member: CStmBuf::~CStmBuf, public +// +// Synopsis: Destructor. +// +// Arguments: None. +// +// Returns: None. +// +// History: 20-Feb-95 KentCe Created +// +// Notes: +// +//---------------------------------------------------------------------------- +CStmBuf::~CStmBuf(void) +{ + // + // Verify that the programmer released the stream interface. + // + Assert(m_pStm == NULL); +} + + +//+--------------------------------------------------------------------------- +// +// Member: CStmBufRead::Init, public +// +// Synopsis: Define the stream interface to read from. +// +// Arguments: [pstm] -- Pointer to stream to read. +// +// Returns: None. +// +// History: 20-Feb-95 KentCe Created +// +// Notes: Release method must be called. +// +//---------------------------------------------------------------------------- +void CStmBufRead::Init(IStream * pstm) +{ + Assert(m_pStm == NULL); + + m_pStm = pstm; + + m_pStm->AddRef(); + + Reset(); +} + + +//+--------------------------------------------------------------------------- +// +// Member: CStmBufRead::OpenStream, public +// +// Synopsis: Open a stream for reading. +// +// Arguments: [pstg] -- Pointer to storage that contains stream to open. +// [pwcsName] -- Name of stream to open. +// +// Returns: HRESULT. +// +// History: 20-Feb-95 KentCe Created +// +// Notes: Release method must be called. +// +//---------------------------------------------------------------------------- +HRESULT CStmBufRead::OpenStream(IStorage * pstg, const OLECHAR * pwcsName) +{ + VDATEHEAP(); + HRESULT hr; + + + Assert(m_pStm == NULL); + + hr = pstg->OpenStream(pwcsName, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, + &m_pStm); + + Reset(); + + return hr; +} + + +//+--------------------------------------------------------------------------- +// +// Member: CStmBufRead::Read, public +// +// Synopsis: Read data from the stream. +// +// Arguments: [pBuf] - Address to store read bytes in. +// [cBuf] - Maximum number of bytes to read. +// +// Returns: HRESULT. +// +// History: 20-Feb-95 KentCe Created +// +// Notes: +// +//---------------------------------------------------------------------------- +HRESULT CStmBufRead::Read(PVOID pBuf, ULONG cBuf) +{ + ULONG cnt; + HRESULT hr; + + + // + // While more bytes to read. + // + while (cBuf) + { + // + // If our buffer is empty, read more data. + // + if (m_cBuffer == 0) + { + hr = m_pStm->Read(m_aBuffer, sizeof(m_aBuffer), &m_cBuffer); + if (FAILED(hr)) + return hr; + + if (m_cBuffer == 0) + return STG_E_READFAULT; + + m_pBuffer = m_aBuffer; + } + + // + // Determine number of bytes to read. + // + cnt = min(m_cBuffer, cBuf); + + // + // Copy the input from the input buffer, update variables. + // + memcpy(pBuf, m_pBuffer, cnt); + pBuf = (PBYTE)pBuf + cnt; + cBuf -= cnt; + m_pBuffer += cnt; + m_cBuffer -= cnt; + } + + return S_OK; +} + + +//+--------------------------------------------------------------------------- +// +// Member: CStmBufRead::ReadLong, public +// +// Synopsis: Read a long value from the stream. +// +// Arguments: [plValue] - Address of long to fill. +// +// Returns: HRESULT. +// +// History: 20-Feb-95 KentCe Created +// +// Notes: +// +//---------------------------------------------------------------------------- +HRESULT CStmBufRead::ReadLong(LONG * plValue) +{ + return Read(plValue, sizeof(LONG)); +} + + +//+--------------------------------------------------------------------------- +// +// Member: CStmBufRead::Reset +// +// Synopsis: Reset buffer variables. +// +// Arguments: None. +// +// Returns: None. +// +// History: 20-Feb-95 KentCe Created +// +// Notes: +// +//---------------------------------------------------------------------------- +void CStmBufRead::Reset(void) +{ + m_pBuffer = m_aBuffer; + m_cBuffer = 0; +} + + +//+--------------------------------------------------------------------------- +// +// Member: CStmBufRead::Release, public +// +// Synopsis: Release read stream interface. +// +// Arguments: None. +// +// Returns: None. +// +// History: 20-Feb-95 KentCe Created +// +// Notes: +// +//---------------------------------------------------------------------------- +void CStmBufRead::Release() +{ + if (m_pStm) + { + m_pStm->Release(); + m_pStm = NULL; + } +} + + +//+--------------------------------------------------------------------------- +// +// Member: CStmBufWrite::Init, public +// +// Synopsis: Define the stream interface to write to. +// +// Arguments: [pstm] -- Pointer to stream to write. +// +// Returns: None. +// +// History: 20-Feb-95 KentCe Created +// +// Notes: Release method must be called. +// +//---------------------------------------------------------------------------- +void CStmBufWrite::Init(IStream * pstm) +{ + Assert(m_pStm == NULL); + + m_pStm = pstm; + + m_pStm->AddRef(); + + Reset(); +} + + +//+--------------------------------------------------------------------------- +// +// Member: CStmBufRead::OpenOrCreateStream, public +// +// Synopsis: Open/Create a stream for writing. +// +// Arguments: [pstg] -- Pointer to storage that contains stream to open. +// [pwcsName] -- Name of stream to open. +// +// Returns: HRESULT. +// +// History: 20-Feb-95 KentCe Created +// +// Notes: Release method must be called. +// +//---------------------------------------------------------------------------- +HRESULT CStmBufWrite::OpenOrCreateStream(IStorage * pstg, + const OLECHAR * pwcsName) +{ + VDATEHEAP(); + HRESULT hr; + + + hr = pstg->CreateStream(pwcsName, STGM_SALL | STGM_FAILIFTHERE, 0, 0, + &m_pStm); + + if (hr == STG_E_FILEALREADYEXISTS) + { + hr = pstg->OpenStream(pwcsName, NULL, STGM_SALL, 0, &m_pStm); + } + + Reset(); + + return hr; +} + + +//+--------------------------------------------------------------------------- +// +// Member: CStmBufRead::CreateStream, public +// +// Synopsis: Create a stream for writing. +// +// Arguments: [pstg] -- Pointer storage that contains stream to create. +// [pwcsName] -- Name of stream to create. +// +// Returns: HRESULT. +// +// History: 20-Feb-95 KentCe Created +// +// Notes: Release method must be called. +// +//---------------------------------------------------------------------------- +HRESULT CStmBufWrite::CreateStream(IStorage * pstg, const OLECHAR * pwcsName) +{ + VDATEHEAP(); + + HRESULT hr; + + + hr = pstg->CreateStream(pwcsName, STGM_CREATE | STGM_READWRITE | + STGM_SHARE_EXCLUSIVE, 0, 0, &m_pStm); + + Reset(); + + return hr; +} + + +//+--------------------------------------------------------------------------- +// +// Member: CStmBufWrite::Write, public +// +// Synopsis: Write data to the stream. +// +// Arguments: [pBuf] - Address to store write bytes to. +// [cBuf] - Maximum number of bytes to write. +// +// Returns: HRESULT. +// +// History: 20-Feb-95 KentCe Created +// +// Notes: +// +//---------------------------------------------------------------------------- +HRESULT CStmBufWrite::Write(void const * pBuf, ULONG cBuf) +{ + ULONG cnt; + HRESULT hr; + + + // + // Keep writing until the caller's buffer is empty. + // + while (cBuf) + { + // + // Compute the number of bytes to copy. + // + cnt = min(m_cBuffer, cBuf); + + // + // Copy to the internal write buffer and update variables. + // + memcpy(m_pBuffer, pBuf, cnt); + pBuf = (PBYTE)pBuf + cnt; + cBuf -= cnt; + m_pBuffer += cnt; + m_cBuffer -= cnt; + + // + // On full internal buffer, flush. + // + if (m_cBuffer == 0) + { + LEDebugOut((DEB_WARN, "WARNING: Multiple buffer flushes.\n")); + + hr = Flush(); + if (FAILED(hr)) + { + return hr; + } + } + } + + return S_OK; +} + + +//+--------------------------------------------------------------------------- +// +// Member: CStmBufWrite::WriteLong, public +// +// Synopsis: Write long value to the stream. +// +// Arguments: [lValue] - Long value to write. +// +// Returns: HRESULT. +// +// History: 20-Feb-95 KentCe Created +// +// Notes: +// +//---------------------------------------------------------------------------- +HRESULT CStmBufWrite::WriteLong(LONG lValue) +{ + return Write(&lValue, sizeof(LONG)); +} + + +//+--------------------------------------------------------------------------- +// +// Member: CStmBufWrite::Flush, public +// +// Synopsis: Flush write buffer to the system. +// +// Arguments: None. +// +// Returns: HRESULT. +// +// History: 20-Feb-95 KentCe Created +// +// Notes: Performs a write of the stream buffer to the system, does not +// force a flush to disk. +// +//---------------------------------------------------------------------------- +HRESULT CStmBufWrite::Flush(void) +{ + ULONG cnt; + HRESULT hr; + + + // + // This might be an overactive assert, but shouldn't happen. + // + Assert(m_cBuffer != sizeof(m_aBuffer)); + + hr = m_pStm->Write(m_aBuffer, sizeof(m_aBuffer) - m_cBuffer, &cnt); + if (FAILED(hr)) + { + return hr; + } + + if (cnt != sizeof(m_aBuffer) - m_cBuffer) + { + return STG_E_MEDIUMFULL; + } + + Reset(); + + return S_OK; +} + + +//+--------------------------------------------------------------------------- +// +// Member: CStmBufWrite::Reset, public +// +// Synopsis: Reset buffer variables. +// +// Arguments: None. +// +// Returns: None. +// +// History: 20-Feb-95 KentCe Created +// +// Notes: +// +//---------------------------------------------------------------------------- +void CStmBufWrite::Reset(void) +{ + m_pBuffer = m_aBuffer; + m_cBuffer = sizeof(m_aBuffer); +} + + +//+--------------------------------------------------------------------------- +// +// Member: CStmBufWrite::Release, public +// +// Synopsis: Release write stream interface. +// +// Arguments: None. +// +// Returns: None. +// +// History: 20-Feb-95 KentCe Created +// +// Notes: +// +//---------------------------------------------------------------------------- +void CStmBufWrite::Release() +{ + if (m_pStm) + { + // + // Verify that flush was called. + // + Assert(m_cBuffer == sizeof(m_aBuffer)); + + m_pStm->Release(); + m_pStm = NULL; + } +} |