//+---------------------------------------------------------------------------- // // 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 #pragma SEG(utils) #include #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