summaryrefslogtreecommitdiffstats
path: root/private/ole32/ole232/util
diff options
context:
space:
mode:
Diffstat (limited to 'private/ole32/ole232/util')
-rw-r--r--private/ole32/ole232/util/convert.cpp1209
-rw-r--r--private/ole32/ole232/util/daytona/makefile10
-rw-r--r--private/ole32/ole232/util/daytona/sources83
-rw-r--r--private/ole32/ole232/util/depend.mk237
-rw-r--r--private/ole32/ole232/util/dirs38
-rw-r--r--private/ole32/ole232/util/filelist.mk54
-rw-r--r--private/ole32/ole232/util/global.cpp821
-rw-r--r--private/ole32/ole232/util/info.cpp65
-rw-r--r--private/ole32/ole232/util/makefile26
-rw-r--r--private/ole32/ole232/util/map_kv.cpp666
-rw-r--r--private/ole32/ole232/util/ole2util.cpp1105
-rw-r--r--private/ole32/ole232/util/plex.cpp53
-rw-r--r--private/ole32/ole232/util/utils.cpp2726
-rw-r--r--private/ole32/ole232/util/utstream.cpp986
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;
+ }
+}