windows-nt/Source/XPSP1/NT/com/ole32/ole232/util/utils.cpp
2020-09-26 16:20:57 +08:00

2300 lines
64 KiB
C++

//+----------------------------------------------------------------------------
//
// 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,
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));
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);
}
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 = 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 += (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 += (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 += (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 += (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 += (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 += (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 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);
}
//+-------------------------------------------------------------------------
//
// 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