|
|
//+----------------------------------------------------------------------------
//
// 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 = (ULONG) 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, (ULONG) 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]; DWORD dwRet = 0; VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN UtGetTempFilename ( \"%ws\" , " "\"%ws\")\n", NULL, pszPrefix, pszTempName));
if( (dwRet = GetTempPath(MAX_PATH, szPath)) == 0) { UINT uiRet = 0; LEDebugOut((DEB_WARN, "WARNING: GetTempPath failed!\n")); if( (uiRet=GetWindowsDirectory(szPath, MAX_PATH)) == 0 ) { LEDebugOut((DEB_WARN, "WARNING: GetWindowsDirectory" " failed!!\n")); hresult = ResultFromScode(E_FAIL); goto errRtn; } else if (uiRet > MAX_PATH) { LEDebugOut((DEB_WARN, "WARNING: WindowsDir longer than MAX_PATH!\n")); hresult = HRESULT_FROM_WIN32(ERROR_MORE_DATA); goto errRtn; } } else if (dwRet > MAX_PATH) { LEDebugOut((DEB_WARN, "WARNING: TempDir longer than MAX_PATH!\n")); hresult = HRESULT_FROM_WIN32(ERROR_MORE_DATA); goto errRtn; }
if( !GetTempFileName( szPath, pszPrefix, 0, pszTempName ) ) { LEDebugOut((DEB_WARN, "WARNING: GetTempFileName failed!!\n")); hresult = ResultFromScode(E_FAIL); }
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 = (ULONG) 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 [, but we don't need this anyway]
#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 != INVALID_HANDLE_VALUE ) { 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 = (UINT) 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 = (UINT) 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 = (UINT) 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 = cbOffset + (USHORT)(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 = cbOffset + (USHORT)(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 = cbOffset + (USHORT)(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 = cbOffset + (USHORT) 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 = cbOffset + (USHORT) 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 = cbOffset + (USHORT) 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 (!(szANSI || szOLESTR)) { *pstr = NULL; }
// Allocate memory for the UNICODE return string
*pstr = (LPOLESTR) PubMemAlloc((ulLength+1) * 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 )) // size of UNICODE buffer
{ PubMemFree(*pstr); *pstr = NULL; return ResultFromScode(E_UNSPEC); } } return NOERROR; }
//+-------------------------------------------------------------------------
//
// 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 = (DWORD) strlen(szANSITEMP) + 1; *pszANSI = (LPSTR) PubMemAlloc(*pdwResultLen); if (NULL == *pszANSI) { *pdwResultLen = 0; return ResultFromScode(E_OUTOFMEMORY); } strcpy(*pszANSI, szANSITEMP);
PubMemFree(szANSITEMP);
return(NOERROR); }
//+-------------------------------------------------------------------------
//
// Method: CSafeRefCount::SafeRefCount()
//
// Purpose: CSafeRefCount implements reference counting rules for objects.
// It keeps track of reference count and zombie state.
// It helps object manage their liveness properly.
//
// History: dd-mmm-yy Author Comment
// 16-Jan-97 Gopalk Rewritten to handle aggregation
//
//--------------------------------------------------------------------------
ULONG CSafeRefCount::SafeRelease() { ULONG cRefs;
// Decrement ref count
cRefs = InterlockedDecrement((LONG *) &m_cRefs); // Check if this is the last release
if(cRefs == 0) { // As this function is reentrant on the current
// thread, gaurd against double destruction
if(!m_fInDelete) { // There are no race conditions here
// Mark object as in destructor
m_fInDelete = TRUE; // Here is the need for the destructor to be virtual
delete this; } }
return cRefs; }
//+-------------------------------------------------------------------------
//
// Method: CRefExportCount::SafeRelease
//
// Purpose: CRefExportCount implements reference counting rules for server
// objects that export their nested objects on behalf of their
// clients like DEFHANDLER abd CACHE. It keeps track of
// reference count, export count, zombie state, etc.
// It helps object manage their shutdown logic properly.
//
// History: dd-mmm-yy Author Comment
// 16-Jan-97 Gopalk Creation
//
//--------------------------------------------------------------------------
ULONG CRefExportCount::SafeRelease() { ULONG cRefs;
// Decrement ref count
cRefs = InterlockedDecrement((LONG *) &m_cRefs); // Check if ref count has become zero
if(cRefs == 0) { // As this function is reentrant on the current
// thread, gaurd against double destruction
if(!m_IsZombie) { // There are no race conditions here
// Mark object as a zombie
m_IsZombie = TRUE; // Call cleanup function while destruction is not allowed
CleanupFn();
// Allow destruction
InterlockedExchange((LONG *) &m_Status, KILL);
// Check for any exported objects
if(m_cExportCount == 0) { // Gaurd against double destruction
if(InterlockedExchange((LONG *) &m_Status, DEAD) == KILL) { // Here is the need for the destructor to be virtual
delete this; } } } }
return cRefs; }
//+-------------------------------------------------------------------------
//
// Method: CRefExportCount::DecrementExportCount
//
// Purpose: CRefExportCount implements reference counting rules for server
// objects that export their nested objects on behalf of their
// clients like DEFHANDLER abd CACHE. It keeps track of
// reference count, export count, zombie state, etc.
// It helps object manage their shutdown logic properly.
//
// History: dd-mmm-yy Author Comment
// 16-Jan-97 Gopalk Creation
//
//--------------------------------------------------------------------------
ULONG CRefExportCount::DecrementExportCount() { ULONG cExportCount;
// Decrement export count
cExportCount = InterlockedDecrement((LONG *) &m_cExportCount); // Check if the export count has become zero
if(cExportCount == 0) { // Check if destruction is allowed
if(m_Status == KILL) { // Gaurd against double destruction
if(InterlockedExchange((LONG *) &m_Status, DEAD) == KILL) { // Here is the need for the destructor to be virtual
delete this; } } }
return cExportCount; }
//+-------------------------------------------------------------------------
//
// 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
|