2727 lines
72 KiB
C++
2727 lines
72 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 = GlobalSize(hsrc)));
|
||
|
|
||
|
// if the allocation failed, get out
|
||
|
if ((hdst == NULL) || ((lpdst = GlobalLock(hdst)) == NULL))
|
||
|
goto errRtn;
|
||
|
|
||
|
// copy the content
|
||
|
_xmemcpy(lpdst, lpsrc, dwSize);
|
||
|
|
||
|
// unlock the handles
|
||
|
GlobalUnlock(hsrc);
|
||
|
GlobalUnlock(hdst);
|
||
|
return(hdst);
|
||
|
|
||
|
errRtn:
|
||
|
// unlock the source handle
|
||
|
GlobalUnlock(hsrc);
|
||
|
|
||
|
// if we allocated a destination handle, free it
|
||
|
if (hdst)
|
||
|
GlobalFree(hdst);
|
||
|
|
||
|
return(NULL);
|
||
|
#endif // _MAC
|
||
|
}
|
||
|
|
||
|
|
||
|
#pragma SEG(UtDupString)
|
||
|
|
||
|
// copies string using the TASK allocator; returns NULL on out of memory
|
||
|
|
||
|
// often when calling UtDupString, the caller knows the string length.
|
||
|
// a good speed boost would be to call UtDupPtr instead
|
||
|
|
||
|
// lpvIn must be non null
|
||
|
// note: we do an alloc even if dw == 0
|
||
|
FARINTERNAL_(LPVOID) UtDupPtr(LPVOID lpvIn, DWORD dw)
|
||
|
{
|
||
|
VDATEHEAP();
|
||
|
LPVOID lpvOut; // the newly allocated ptr
|
||
|
|
||
|
Assert(lpvIn); // internal fcn, lpvIn must be non-null
|
||
|
if ((lpvOut = PubMemAlloc(dw)) != NULL) {
|
||
|
memcpy(lpvOut, lpvIn, dw);
|
||
|
}
|
||
|
|
||
|
return lpvOut;
|
||
|
}
|
||
|
|
||
|
FARINTERNAL_(LPOLESTR) UtDupString(LPCOLESTR lpszIn)
|
||
|
{
|
||
|
return (LPOLESTR) UtDupPtr( (LPVOID) lpszIn,
|
||
|
(_xstrlen(lpszIn)+1) * sizeof(OLECHAR) );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: UtDupStringA
|
||
|
//
|
||
|
// Synopsis: Duplicates an ANSI string using the TASK allocator
|
||
|
//
|
||
|
// Effects:
|
||
|
//
|
||
|
// Arguments: [pszAnsi] -- the string to duplicate
|
||
|
//
|
||
|
// Requires:
|
||
|
//
|
||
|
// Returns: the newly allocated string duplicate or NULL
|
||
|
//
|
||
|
// Signals:
|
||
|
//
|
||
|
// Modifies:
|
||
|
//
|
||
|
// Algorithm:
|
||
|
//
|
||
|
// History: dd-mmm-yy Author Comment
|
||
|
// 04-Jun-94 alexgo author
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
LPSTR UtDupStringA( LPCSTR pszAnsi )
|
||
|
{
|
||
|
return (LPSTR) UtDupPtr( (LPVOID) pszAnsi,
|
||
|
strlen(pszAnsi) + 1 );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
#pragma SEG(UtCopyTargetDevice)
|
||
|
FARINTERNAL_(DVTARGETDEVICE FAR*) UtCopyTargetDevice(DVTARGETDEVICE FAR* ptd)
|
||
|
{
|
||
|
// if nothing to copy, return
|
||
|
if (ptd == NULL)
|
||
|
return(NULL);
|
||
|
|
||
|
return (DVTARGETDEVICE FAR*) UtDupPtr((LPVOID) ptd, ptd->tdSize);
|
||
|
}
|
||
|
|
||
|
|
||
|
#pragma SEG(UtCopyFormatEtc)
|
||
|
FARINTERNAL_(BOOL) UtCopyFormatEtc(FORMATETC FAR* pFetcIn,
|
||
|
FORMATETC FAR* pFetcCopy)
|
||
|
{
|
||
|
VDATEHEAP();
|
||
|
|
||
|
// copy structures
|
||
|
*pFetcCopy = *pFetcIn;
|
||
|
|
||
|
if (pFetcIn->ptd == NULL) {
|
||
|
// all done, return true because the copy succeeded
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
// create a copy of the td descriptor, which is allocated
|
||
|
pFetcCopy->ptd = UtCopyTargetDevice(pFetcIn->ptd);
|
||
|
|
||
|
// return TRUE if we copied the data if we were supposed to
|
||
|
return(pFetcCopy->ptd != NULL);
|
||
|
}
|
||
|
|
||
|
|
||
|
#pragma SEG(UtCompareFormatEtc)
|
||
|
FARINTERNAL_(int) UtCompareFormatEtc(FORMATETC FAR* pFetcLeft,
|
||
|
FORMATETC FAR* pFetcRight)
|
||
|
{
|
||
|
VDATEHEAP();
|
||
|
|
||
|
int iResult; // indicates whether the match is exact or partial
|
||
|
|
||
|
// if the clipboard formats are different, there is no match
|
||
|
if (pFetcLeft->cfFormat != pFetcRight->cfFormat)
|
||
|
return(UTCMPFETC_NEQ);
|
||
|
|
||
|
// if the target devices don't match, there is no match
|
||
|
if (!UtCompareTargetDevice(pFetcLeft->ptd, pFetcRight->ptd))
|
||
|
return(UTCMPFETC_NEQ);
|
||
|
|
||
|
// compare the aspects for the two formats
|
||
|
if (pFetcLeft->dwAspect == pFetcRight->dwAspect)
|
||
|
{
|
||
|
// the match is exact
|
||
|
iResult = UTCMPFETC_EQ;
|
||
|
}
|
||
|
else if ((pFetcLeft->dwAspect & ~pFetcRight->dwAspect) != 0)
|
||
|
{
|
||
|
// left not subset of aspects of right; not equal
|
||
|
return(UTCMPFETC_NEQ);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// left aspects are a subset of the right aspects
|
||
|
iResult = UTCMPFETC_PARTIAL;
|
||
|
}
|
||
|
|
||
|
// if we get here, iResult is set to one of UPCMPFETC_EQ or _PARTIAL
|
||
|
|
||
|
// compare the media for the two formats
|
||
|
if (pFetcLeft->tymed == pFetcRight->tymed)
|
||
|
{
|
||
|
// same medium flags; do not change value of iResult
|
||
|
;
|
||
|
}
|
||
|
else if ((pFetcLeft->tymed & ~pFetcRight->tymed) != 0)
|
||
|
{
|
||
|
// left not subset of medium flags of right; not equal
|
||
|
return(UTCMPFETC_NEQ);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// left subset of right
|
||
|
iResult = UTCMPFETC_PARTIAL;
|
||
|
}
|
||
|
|
||
|
return(iResult);
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: UtCompareTargetDevice
|
||
|
//
|
||
|
// Synopsis: Compare two DVTARGETDEVICEs
|
||
|
//
|
||
|
// Arguments: [ptdLeft] -- comparand
|
||
|
// [ptdRight] -- comparee
|
||
|
//
|
||
|
// Returns: TRUE iff the two target devices are equivalent
|
||
|
//
|
||
|
// Algorithm:
|
||
|
//
|
||
|
// History: 09-May-94 AlexT Rewrote to do more than just a binary
|
||
|
// compare
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
#define UT_DM_COMPARISON_FIELDS (DM_ORIENTATION | \
|
||
|
DM_PAPERSIZE | \
|
||
|
DM_PAPERLENGTH | \
|
||
|
DM_PAPERWIDTH | \
|
||
|
DM_SCALE | \
|
||
|
DM_PRINTQUALITY | \
|
||
|
DM_COLOR)
|
||
|
|
||
|
#pragma SEG(UtCompareTargetDevice)
|
||
|
FARINTERNAL_(BOOL) UtCompareTargetDevice(DVTARGETDEVICE FAR* ptdLeft,
|
||
|
DVTARGETDEVICE FAR* ptdRight)
|
||
|
{
|
||
|
LEDebugOut((DEB_ITRACE, "%p _IN UtCompareTargetDevice (%p, %p)\n",
|
||
|
NULL, ptdLeft, ptdRight));
|
||
|
|
||
|
VDATEHEAP();
|
||
|
|
||
|
BOOL bRet = FALSE; // More often than not we return FALSE
|
||
|
|
||
|
// We use a do-while(FALSE) loop so that we can break out to common
|
||
|
// return code at the end (the joys of tracing)
|
||
|
do
|
||
|
{
|
||
|
// if the addresses of the two target device descriptors are the same,
|
||
|
// then they must be the same. Note this handles the two NULL case.
|
||
|
if (ptdLeft == ptdRight)
|
||
|
{
|
||
|
bRet = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// if either td is NULL, can't compare them
|
||
|
if ((ptdRight == NULL) || (ptdLeft == NULL))
|
||
|
{
|
||
|
AssertSz(bRet == FALSE, "bRet not set correctly");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// we ignore device name (My Printer vs. Your Printer doesn't matter)
|
||
|
|
||
|
// check driver name
|
||
|
if (ptdLeft->tdDriverNameOffset != 0)
|
||
|
{
|
||
|
if (ptdRight->tdDriverNameOffset == 0)
|
||
|
{
|
||
|
// Left driver exists, but no right driver
|
||
|
AssertSz(bRet == FALSE, "bRet not set correctly");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Both drivers exist
|
||
|
if (_xstrcmp((LPOLESTR)((BYTE*)ptdLeft +
|
||
|
ptdLeft->tdDriverNameOffset),
|
||
|
(LPOLESTR)((BYTE*)ptdRight +
|
||
|
ptdRight->tdDriverNameOffset)) != 0)
|
||
|
{
|
||
|
// Driver names don't match
|
||
|
AssertSz(bRet == FALSE, "bRet not set correctly");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else if (ptdRight->tdDriverNameOffset != 0)
|
||
|
{
|
||
|
// Left driver doesn't exist, but right driver does
|
||
|
AssertSz(bRet == FALSE, "bRet not set correctly");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// we ignore port name
|
||
|
|
||
|
if (0 == ptdLeft->tdExtDevmodeOffset)
|
||
|
{
|
||
|
if (0 == ptdRight->tdExtDevmodeOffset)
|
||
|
{
|
||
|
// Nothing left to compare
|
||
|
bRet = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Only one Devmode
|
||
|
AssertSz(bRet == FALSE, "bRet not set correctly");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else if (0 == ptdRight->tdExtDevmodeOffset)
|
||
|
{
|
||
|
// Only one Devmode exists
|
||
|
AssertSz(bRet == FALSE, "bRet not set correctly");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Both TDs have Devmodes
|
||
|
DEVMODEW *pdmLeft, *pdmRight;
|
||
|
|
||
|
pdmLeft = (DEVMODEW *)((BYTE*)ptdLeft +
|
||
|
ptdLeft->tdExtDevmodeOffset);
|
||
|
pdmRight = (DEVMODEW *)((BYTE*)ptdRight +
|
||
|
ptdRight->tdExtDevmodeOffset);
|
||
|
|
||
|
// Check driver version
|
||
|
if (pdmLeft->dmDriverVersion != pdmRight->dmDriverVersion)
|
||
|
{
|
||
|
AssertSz(bRet == FALSE, "bRet not set correctly");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// For a successful match, both device mode must specify the same
|
||
|
// values for each of the following:
|
||
|
// DM_ORIENTATION, DM_PAPERSIZE, DM_PAPERLENGTH.
|
||
|
// DM_PAPERWIDTH, DM_SCALE, DM_PRINTQUALITY, DM_COLOR
|
||
|
|
||
|
if ((pdmLeft->dmFields & UT_DM_COMPARISON_FIELDS) ^
|
||
|
(pdmRight->dmFields & UT_DM_COMPARISON_FIELDS))
|
||
|
{
|
||
|
// Only one of pdmLeft and pdmRight specify at least one
|
||
|
// of the comparison fields
|
||
|
AssertSz(bRet == FALSE, "bRet not set correctly");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ((pdmLeft->dmFields & DM_ORIENTATION) &&
|
||
|
pdmLeft->dmOrientation != pdmRight->dmOrientation)
|
||
|
{
|
||
|
AssertSz(bRet == FALSE, "bRet not set correctly");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ((pdmLeft->dmFields & DM_PAPERSIZE) &&
|
||
|
pdmLeft->dmPaperSize != pdmRight->dmPaperSize)
|
||
|
{
|
||
|
AssertSz(bRet == FALSE, "bRet not set correctly");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ((pdmLeft->dmFields & DM_PAPERLENGTH) &&
|
||
|
pdmLeft->dmPaperLength != pdmRight->dmPaperLength)
|
||
|
{
|
||
|
AssertSz(bRet == FALSE, "bRet not set correctly");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ((pdmLeft->dmFields & DM_PAPERWIDTH) &&
|
||
|
pdmLeft->dmPaperWidth != pdmRight->dmPaperWidth)
|
||
|
{
|
||
|
AssertSz(bRet == FALSE, "bRet not set correctly");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ((pdmLeft->dmFields & DM_SCALE) &&
|
||
|
pdmLeft->dmScale != pdmRight->dmScale)
|
||
|
{
|
||
|
AssertSz(bRet == FALSE, "bRet not set correctly");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ((pdmLeft->dmFields & DM_PRINTQUALITY) &&
|
||
|
pdmLeft->dmPrintQuality != pdmRight->dmPrintQuality)
|
||
|
{
|
||
|
AssertSz(bRet == FALSE, "bRet not set correctly");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ((pdmLeft->dmFields & DM_COLOR) &&
|
||
|
pdmLeft->dmColor != pdmRight->dmColor)
|
||
|
{
|
||
|
AssertSz(bRet == FALSE, "bRet not set correctly");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
bRet = TRUE;
|
||
|
} while (FALSE);
|
||
|
|
||
|
LEDebugOut((DEB_ITRACE, "%p OUT UtCompareTargetDevice (%d)\n",
|
||
|
NULL, bRet));
|
||
|
|
||
|
return(bRet);
|
||
|
}
|
||
|
|
||
|
#pragma SEG(UtCopyStatData)
|
||
|
FARINTERNAL_(BOOL) UtCopyStatData(STATDATA FAR* pSDIn, STATDATA FAR* pSDCopy)
|
||
|
{
|
||
|
VDATEHEAP();
|
||
|
|
||
|
// copy structures
|
||
|
*pSDCopy = *pSDIn;
|
||
|
|
||
|
// create copy of target device description (which is allocated)
|
||
|
pSDCopy->formatetc.ptd = UtCopyTargetDevice(pSDIn->formatetc.ptd);
|
||
|
|
||
|
// if there is an advise sink, account for the copy/reference
|
||
|
if (pSDCopy->pAdvSink != NULL)
|
||
|
pSDCopy->pAdvSink->AddRef();
|
||
|
|
||
|
// return TRUE if the copy was done if it was required
|
||
|
return((pSDCopy->formatetc.ptd != NULL) ==
|
||
|
(pSDIn->formatetc.ptd != NULL));
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: UtReleaseStatData
|
||
|
//
|
||
|
// Synopsis: nulls && releases members of the given stat data structure
|
||
|
//
|
||
|
// Effects:
|
||
|
//
|
||
|
// Arguments: pStatData
|
||
|
//
|
||
|
// Requires:
|
||
|
//
|
||
|
// Returns: void
|
||
|
//
|
||
|
// Signals:
|
||
|
//
|
||
|
// Modifies:
|
||
|
//
|
||
|
// Algorithm: We copy the data first and NULL out the stat data
|
||
|
// because the Release on the Advise sink could cause us
|
||
|
// to be re-entered.
|
||
|
//
|
||
|
// History: dd-mmm-yy Author Comment
|
||
|
// 20-Jul-94 alexgo made safe for OLE sytle re-entrancy
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
FARINTERNAL_(void) UtReleaseStatData(STATDATA FAR* pStatData)
|
||
|
{
|
||
|
STATDATA sd;
|
||
|
|
||
|
VDATEHEAP();
|
||
|
|
||
|
sd = *pStatData;
|
||
|
|
||
|
// zero out the original before doing any work
|
||
|
|
||
|
_xmemset(pStatData, 0, sizeof(STATDATA));
|
||
|
|
||
|
// if there's a target device description, free it
|
||
|
if (sd.formatetc.ptd != NULL)
|
||
|
{
|
||
|
PubMemFree(sd.formatetc.ptd);
|
||
|
}
|
||
|
|
||
|
if( sd.pAdvSink )
|
||
|
{
|
||
|
sd.pAdvSink->Release();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: UtCreateStorageOnHGlobal
|
||
|
//
|
||
|
// Synopsis: creates a storage on top of an HGlobal
|
||
|
//
|
||
|
// Effects:
|
||
|
//
|
||
|
// Arguments: [hGlobal] -- the memory on which to create the
|
||
|
// storage
|
||
|
// [fDeleteOnRelease] -- if TRUE, then delete the hglobal
|
||
|
// once the storage is released.
|
||
|
// [ppStg] -- where to put the storage interface
|
||
|
// [ppILockBytes] -- where to put the underlying ILockBytes,
|
||
|
// maybe NULL. The ILB must be released.
|
||
|
|
||
|
//
|
||
|
// Requires:
|
||
|
//
|
||
|
// Returns: HRESULT
|
||
|
//
|
||
|
// Signals:
|
||
|
//
|
||
|
// Modifies:
|
||
|
//
|
||
|
// Algorithm: create an ILockBytes on HGLOBAL and then create the docfile
|
||
|
// on top of the ILockBytes
|
||
|
//
|
||
|
// History: dd-mmm-yy Author Comment
|
||
|
// 07-Apr-94 alexgo author
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT UtCreateStorageOnHGlobal( HGLOBAL hGlobal, BOOL fDeleteOnRelease,
|
||
|
IStorage **ppStg, ILockBytes **ppILockBytes )
|
||
|
{
|
||
|
HRESULT hresult;
|
||
|
ILockBytes * pLockBytes;
|
||
|
|
||
|
VDATEHEAP();
|
||
|
|
||
|
LEDebugOut((DEB_ITRACE, "%p _IN UtCreateStorageOnHGlobal ( %lx , %p )"
|
||
|
"\n", NULL, hGlobal, ppStg));
|
||
|
|
||
|
hresult = CreateILockBytesOnHGlobal(hGlobal, fDeleteOnRelease,
|
||
|
&pLockBytes);
|
||
|
|
||
|
if( hresult == NOERROR )
|
||
|
{
|
||
|
hresult = StgCreateDocfileOnILockBytes( pLockBytes,
|
||
|
STGM_CREATE | STGM_SALL, 0, ppStg);
|
||
|
|
||
|
// no matter what the result of StgCreate is, we want
|
||
|
// to release the LockBytes. If hresult == NOERROR, then
|
||
|
// the final release to the LockBytes will come when the
|
||
|
// created storage is released.
|
||
|
}
|
||
|
|
||
|
if( ppILockBytes )
|
||
|
{
|
||
|
*ppILockBytes = pLockBytes;
|
||
|
}
|
||
|
else if (pLockBytes)
|
||
|
{
|
||
|
// we release here so the final release of the storage
|
||
|
// will be the final release of the lockbytes
|
||
|
pLockBytes->Release();
|
||
|
}
|
||
|
|
||
|
|
||
|
LEDebugOut((DEB_ITRACE, "%p OUT UtCreateStorageOnHGlobal ( %lx ) "
|
||
|
"[ %p ]\n", NULL, hresult, *ppStg));
|
||
|
|
||
|
return hresult;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: UtGetTempFileName
|
||
|
//
|
||
|
// Synopsis: retrieves a temporary filename (for use in GetData, TYMED_FILE
|
||
|
// and temporary docfiles)
|
||
|
//
|
||
|
// Effects:
|
||
|
//
|
||
|
// Arguments: [pszPrefix] -- prefix of the temp filename
|
||
|
// [pszTempName] -- buffer that will receive the temp path.
|
||
|
// must be MAX_PATH or greater.
|
||
|
//
|
||
|
// Requires:
|
||
|
//
|
||
|
// Returns: HRESULT;
|
||
|
//
|
||
|
// Signals:
|
||
|
//
|
||
|
// Modifies:
|
||
|
//
|
||
|
// Algorithm: tries to get a file in the temp directory, failing that, in
|
||
|
// the windows directory
|
||
|
//
|
||
|
// History: dd-mmm-yy Author Comment
|
||
|
// 07-Apr-94 alexgo author
|
||
|
//
|
||
|
// Notes: OPTIMIZATION: The storage code has a similar peice of code
|
||
|
// for generating temporary docfiles. We may want to use this
|
||
|
// routine there as well.
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT UtGetTempFileName( LPOLESTR pszPrefix, LPOLESTR pszTempName )
|
||
|
{
|
||
|
HRESULT hresult = NOERROR;
|
||
|
//OLECHAR szPath[MAX_PATH + 1];
|
||
|
|
||
|
VDATEHEAP();
|
||
|
|
||
|
LEDebugOut((DEB_ITRACE, "%p _IN UtGetTempFilename ( \"%ws\" , "
|
||
|
"\"%ws\")\n", NULL, pszPrefix, pszTempName));
|
||
|
|
||
|
//BUGBUG!! This doesn't compile on Chicago; fix it soon
|
||
|
#ifdef LATER
|
||
|
if( !GetTempPath(MAX_PATH, szPath) )
|
||
|
{
|
||
|
LEDebugOut((DEB_WARN, "WARNING: GetTempPath failed!\n"));
|
||
|
if( !GetWindowsDirectory(szPath, MAX_PATH) )
|
||
|
{
|
||
|
LEDebugOut((DEB_WARN, "WARNING: GetWindowsDirectory"
|
||
|
" failed!!\n"));
|
||
|
hresult = ResultFromScode(E_FAIL);
|
||
|
goto errRtn;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( !GetTempFileName( szPath, pszPrefix, 0, pszTempName ) )
|
||
|
{
|
||
|
LEDebugOut((DEB_WARN, "WARNING: GetTempFileName failed!!\n"));
|
||
|
hresult = ResultFromScode(E_FAIL);
|
||
|
}
|
||
|
#endif //LATER
|
||
|
|
||
|
// BUGBUG! This is just a hack for now
|
||
|
LEDebugOut((DEB_ERROR, "ERROR!: Filename support not complete!!\n"));
|
||
|
_xstrcpy(pszTempName, OLESTR("foo.bar"));
|
||
|
|
||
|
//errRtn:
|
||
|
|
||
|
LEDebugOut((DEB_ITRACE, "%p OUT UtGetTempFilename ( %lx ) "
|
||
|
"[ \"%ws\" ]\n", NULL, hresult, pszTempName));
|
||
|
|
||
|
return hresult;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function:
|
||
|
// UtHGLOBALtoStm, internal
|
||
|
//
|
||
|
// Synopsis:
|
||
|
// Write the contents of an HGLOBAL to a stream
|
||
|
//
|
||
|
// Arguments:
|
||
|
// [hdata] -- handle to the data to write out
|
||
|
// [dwSize] -- size of the data to write out
|
||
|
// [pstm] -- stream to write the data out to; on exit, the
|
||
|
// stream is positioned after the written data
|
||
|
//
|
||
|
// Returns:
|
||
|
// HRESULT
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
// History:
|
||
|
// 04/10/94 - AlexGo - added call tracing, moved from convert.cpp
|
||
|
// to utils.cpp, misc improvements.
|
||
|
// 11/30/93 - ChrisWe - file inspection and cleanup
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT UtHGLOBALtoStm(HGLOBAL hGlobalSrc, DWORD dwSize, LPSTREAM pstm)
|
||
|
{
|
||
|
HRESULT hresult = NOERROR;
|
||
|
void * lpdata;
|
||
|
ULONG cbWritten;
|
||
|
|
||
|
VDATEHEAP();
|
||
|
|
||
|
LEDebugOut((DEB_ITRACE, "%p _IN UtHGLOBALtoStm ( %lx , %lu , %p )\n",
|
||
|
NULL, hGlobalSrc, dwSize, pstm));
|
||
|
|
||
|
lpdata = GlobalLock(hGlobalSrc);
|
||
|
|
||
|
if (lpdata)
|
||
|
{
|
||
|
hresult = pstm->Write(lpdata, dwSize, &cbWritten);
|
||
|
|
||
|
// if we didn't write enough data, then it's an error
|
||
|
// condition for us.
|
||
|
|
||
|
if( hresult == NOERROR && cbWritten != dwSize )
|
||
|
{
|
||
|
hresult = ResultFromScode(E_FAIL);
|
||
|
}
|
||
|
|
||
|
if( hresult == NOERROR )
|
||
|
{
|
||
|
// this call isn't strictly necessary, but may
|
||
|
// be useful for compacting the size of presentations
|
||
|
// stored on disk (when called by the presentation
|
||
|
// code)
|
||
|
hresult = StSetSize(pstm, 0, TRUE);
|
||
|
}
|
||
|
|
||
|
GlobalUnlock(hGlobalSrc);
|
||
|
}
|
||
|
|
||
|
|
||
|
LEDebugOut((DEB_ITRACE, "%p OUT UtHGLOBALtoStm ( %lx )\n", NULL,
|
||
|
hresult));
|
||
|
|
||
|
return hresult;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: UtHGLOBALtoHGLOBAL, internal
|
||
|
//
|
||
|
// Synopsis: Copies the source HGLOBAL into the target HGLOBAL
|
||
|
//
|
||
|
// Effects:
|
||
|
//
|
||
|
// Arguments: [hGlobalSrc] -- the source HGLOBAL
|
||
|
// [dwSize] -- the number of bytes to copy
|
||
|
// [hGlobalTgt] -- the target HGLOBAL
|
||
|
//
|
||
|
// Requires:
|
||
|
//
|
||
|
// Returns: HRESULT
|
||
|
//
|
||
|
// Signals:
|
||
|
//
|
||
|
// Modifies:
|
||
|
//
|
||
|
// Algorithm:
|
||
|
//
|
||
|
// History: dd-mmm-yy Author Comment
|
||
|
// 10-Apr-94 alexgo author
|
||
|
//
|
||
|
// Notes: this function will fail if the target hglobal is not large
|
||
|
// enough
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT UtHGLOBALtoHGLOBAL( HGLOBAL hGlobalSrc, DWORD dwSize,
|
||
|
HGLOBAL hGlobalTgt)
|
||
|
{
|
||
|
DWORD cbTarget;
|
||
|
void * pvSrc;
|
||
|
void * pvTgt;
|
||
|
HRESULT hresult = ResultFromScode(E_OUTOFMEMORY);
|
||
|
|
||
|
VDATEHEAP();
|
||
|
|
||
|
LEDebugOut((DEB_ITRACE, "%p _IN UtHGLOBALtoHGLOBAL ( %lx , %lu , "
|
||
|
"%lx )\n", NULL, hGlobalSrc, dwSize, hGlobalTgt));
|
||
|
|
||
|
cbTarget = GlobalSize(hGlobalTgt);
|
||
|
|
||
|
if( cbTarget == 0 || cbTarget < dwSize )
|
||
|
{
|
||
|
hresult = ResultFromScode(E_FAIL);
|
||
|
goto errRtn;
|
||
|
}
|
||
|
|
||
|
pvSrc = GlobalLock(hGlobalSrc);
|
||
|
|
||
|
if( pvSrc )
|
||
|
{
|
||
|
pvTgt = GlobalLock(hGlobalTgt);
|
||
|
|
||
|
if( pvTgt )
|
||
|
{
|
||
|
_xmemcpy( pvTgt, pvSrc, dwSize);
|
||
|
|
||
|
GlobalUnlock(hGlobalTgt);
|
||
|
hresult = NOERROR;
|
||
|
}
|
||
|
|
||
|
GlobalUnlock(hGlobalSrc);
|
||
|
}
|
||
|
|
||
|
errRtn:
|
||
|
LEDebugOut((DEB_ITRACE, "%p OUT UtHGLOBALtoHGLOBAL ( %lx )\n",
|
||
|
NULL, hresult));
|
||
|
|
||
|
return hresult;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: UtHGLOBALtoStorage, internal
|
||
|
//
|
||
|
// Synopsis: Copies the source HGLOBAL into the target storage
|
||
|
//
|
||
|
// Effects:
|
||
|
//
|
||
|
// Arguments: [hGlobalSrc] -- the source HGLOBAL
|
||
|
// [pStgTgt] -- the target storage
|
||
|
//
|
||
|
// Requires:
|
||
|
//
|
||
|
// Returns: HRESULT
|
||
|
//
|
||
|
// Signals:
|
||
|
//
|
||
|
// Modifies:
|
||
|
//
|
||
|
// Algorithm:
|
||
|
//
|
||
|
// History: dd-mmm-yy Author Comment
|
||
|
// 10-Apr-94 alexgo author
|
||
|
//
|
||
|
// Notes: this function will fail if the source HGLOBAL did not
|
||
|
// originally have a storage layered on top of it.
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT UtHGLOBALtoStorage( HGLOBAL hGlobalSrc, IStorage *pStgTgt)
|
||
|
{
|
||
|
HRESULT hresult;
|
||
|
ILockBytes * pLockBytes = NULL;
|
||
|
IStorage * pStgSrc;
|
||
|
ULONG cRefs;
|
||
|
|
||
|
VDATEHEAP();
|
||
|
|
||
|
LEDebugOut((DEB_ITRACE, "%p _IN UtHGLOBALtoStroage ( %lx , %p )"
|
||
|
"\n", NULL, hGlobalSrc, pStgTgt));
|
||
|
|
||
|
hresult = CreateILockBytesOnHGlobal(hGlobalSrc,
|
||
|
FALSE /*fDeleteOnRelease*/, &pLockBytes);
|
||
|
|
||
|
if( hresult != NOERROR )
|
||
|
{
|
||
|
goto errRtn;
|
||
|
}
|
||
|
|
||
|
// now we make sure that the hglobal really has a storage
|
||
|
// in it
|
||
|
|
||
|
if( StgIsStorageILockBytes(pLockBytes) != NOERROR )
|
||
|
{
|
||
|
hresult = ResultFromScode(E_FAIL);
|
||
|
goto errRtn;
|
||
|
}
|
||
|
|
||
|
hresult = StgOpenStorageOnILockBytes( pLockBytes, NULL,
|
||
|
STGM_SALL, NULL, 0, &pStgSrc);
|
||
|
|
||
|
if( hresult == NOERROR )
|
||
|
{
|
||
|
hresult = pStgSrc->CopyTo( 0, NULL, NULL, pStgTgt);
|
||
|
|
||
|
// no matter what the result, we want to free the
|
||
|
// source storage
|
||
|
|
||
|
pStgSrc->Release();
|
||
|
}
|
||
|
|
||
|
errRtn:
|
||
|
|
||
|
if( pLockBytes )
|
||
|
{
|
||
|
cRefs = pLockBytes->Release();
|
||
|
Assert(cRefs == 0);
|
||
|
}
|
||
|
|
||
|
LEDebugOut((DEB_ITRACE, "%p OUT UtHGLOBALtoStorage ( %lx ) "
|
||
|
"[ %p ]\n", NULL, hresult));
|
||
|
|
||
|
return hresult;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: UtHGLOBALtoFile, internal
|
||
|
//
|
||
|
// Synopsis: Copies the source HGLOBAL into the target file
|
||
|
//
|
||
|
// Effects:
|
||
|
//
|
||
|
// Arguments: [hGlobalSrc] -- the source HGLOBAL
|
||
|
// [dwSize] -- the number of bytes to copy
|
||
|
// [pszFileName] -- the target file
|
||
|
//
|
||
|
// Requires:
|
||
|
//
|
||
|
// Returns: HRESULT
|
||
|
//
|
||
|
// Signals:
|
||
|
//
|
||
|
// Modifies:
|
||
|
//
|
||
|
// Algorithm:
|
||
|
//
|
||
|
// History: dd-mmm-yy Author Comment
|
||
|
// 10-Apr-94 alexgo author
|
||
|
//
|
||
|
// Notes: if the file already exists, we simply append to it
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT UtHGLOBALtoFile( HGLOBAL hGlobalSrc, DWORD dwSize,
|
||
|
LPCOLESTR pszFileName)
|
||
|
{
|
||
|
HRESULT hresult;
|
||
|
HANDLE hFile;
|
||
|
void * pvSrc;
|
||
|
DWORD cbWritten;
|
||
|
|
||
|
VDATEHEAP();
|
||
|
|
||
|
LEDebugOut((DEB_ITRACE, "%p _IN UtHGLOBALtoFile ( %lx , %lu , "
|
||
|
"\"%ws\" )\n", NULL, hGlobalSrc, dwSize, pszFileName));
|
||
|
|
||
|
|
||
|
hresult = ResultFromScode(E_NOTIMPL);
|
||
|
(void)hFile;
|
||
|
(void)pvSrc;
|
||
|
(void)cbWritten;
|
||
|
|
||
|
|
||
|
// this doesn't compile for chicago, BUGBUG, fix soon
|
||
|
#ifdef LATER
|
||
|
pvSrc = GlobalLock(hGlobalSrc);
|
||
|
|
||
|
if( !pvSrc )
|
||
|
{
|
||
|
hresult = ResultFromScode(E_OUTOFMEMORY);
|
||
|
goto errRtn;
|
||
|
}
|
||
|
|
||
|
// open the file for append, creating if it doesn't already exist.
|
||
|
|
||
|
hFile = CreateFile( pszFileName, GENERIC_WRITE, 0, NULL,
|
||
|
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
|
||
|
|
||
|
if( hFile )
|
||
|
{
|
||
|
if( !WriteFile( hFile, pvSrc, dwSize, &cbWritten, NULL) )
|
||
|
{
|
||
|
LEDebugOut((DEB_WARN, "WARNING: WriteFile failed!\n"));
|
||
|
hresult = HRESULT_FROM_WIN32(GetLastError());
|
||
|
}
|
||
|
|
||
|
if( cbWritten != dwSize && hresult == NOERROR )
|
||
|
{
|
||
|
// still an error if we didn't write all the bytes
|
||
|
// we wanted
|
||
|
hresult = ResultFromScode(E_FAIL);
|
||
|
}
|
||
|
|
||
|
if( !CloseHandle(hFile) )
|
||
|
{
|
||
|
AssertSz(0, "CloseFile failed! Should not happen!");
|
||
|
|
||
|
// if there's no error yet, set the error
|
||
|
if( hresult == NOERROR )
|
||
|
{
|
||
|
hresult = HRESULT_FROM_WIN32(GetLastError());
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LEDebugOut((DEB_WARN, "WARNING: CreateFile failed!!\n"));
|
||
|
hresult = HRESULT_FROM_WIN32(GetLastError());
|
||
|
}
|
||
|
|
||
|
GlobalUnlock(hGlobalSrc);
|
||
|
|
||
|
errRtn:
|
||
|
|
||
|
#endif // LATER
|
||
|
|
||
|
|
||
|
LEDebugOut((DEB_ITRACE, "%p OUT UtHGLOBALtoFile ( %lx )\n", NULL,
|
||
|
hresult));
|
||
|
|
||
|
return hresult;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: UtGetDvtd16Info
|
||
|
//
|
||
|
// Synopsis: Fills in pdvdtInfo
|
||
|
//
|
||
|
// Arguments: [pdvtd16] -- pointer to ANSI DVTARGETDEVICE
|
||
|
// [pdvtdInfo] -- pointer to DVDT_INFO block
|
||
|
//
|
||
|
// Requires:
|
||
|
//
|
||
|
// Returns: HRESULT
|
||
|
//
|
||
|
// Modifies: pdvtdInfo
|
||
|
//
|
||
|
// Algorithm:
|
||
|
//
|
||
|
// History: 06-May-94 AlexT Created from DrewB's original functions
|
||
|
// 10-Jul-94 AlexT Make sure DEVMODE ends up DWORD aligned
|
||
|
//
|
||
|
// Notes: Do we need to do any error checking on the strings?
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
// We can't use sizeof(DV_TARGETDEVICE) because MIDL keeps flipping back
|
||
|
// and forth over whether to make the embedded array size 0 or size 1
|
||
|
|
||
|
#define UT_DVTARGETDEVICE_SIZE (sizeof(DWORD) + sizeof(WORD) * 4)
|
||
|
|
||
|
// tdSize td...Offset's
|
||
|
#define DVTD_MINSIZE (sizeof(DWORD) + 4 * sizeof(WORD))
|
||
|
|
||
|
extern "C" HRESULT UtGetDvtd16Info(DVTARGETDEVICE const UNALIGNED *pdvtd16,
|
||
|
PDVTDINFO pdvtdInfo)
|
||
|
{
|
||
|
LEDebugOut((DEB_ITRACE, "%p _IN UtGetDvtd16Info (%p, %p)\n",
|
||
|
NULL, pdvtd16, pdvtdInfo));
|
||
|
|
||
|
DEVMODEA UNALIGNED *pdm16;
|
||
|
|
||
|
// Let's do some sanity checking on the incoming DVTARGETDEVICE
|
||
|
if (pdvtd16->tdSize < DVTD_MINSIZE)
|
||
|
{
|
||
|
LEDebugOut((DEB_WARN, "UtGetDvtd16Info - bad pdvtd16->tdSize\n"));
|
||
|
return(E_INVALIDARG);
|
||
|
}
|
||
|
|
||
|
// We need at least a DVTARGETDEVICE
|
||
|
pdvtdInfo->cbConvertSize = UT_DVTARGETDEVICE_SIZE;
|
||
|
|
||
|
// Compute required size for Drv, Device, Port names
|
||
|
if (pdvtd16->tdDriverNameOffset != 0)
|
||
|
{
|
||
|
if (pdvtd16->tdDriverNameOffset > pdvtd16->tdSize ||
|
||
|
pdvtd16->tdDriverNameOffset < DVTD_MINSIZE)
|
||
|
{
|
||
|
// Offset can't be larger than size or fall within base
|
||
|
// structure
|
||
|
LEDebugOut((DEB_WARN, "UtGetDvtd16Info - bad pdvtd16->tdDriverNameOffset\n"));
|
||
|
return(E_INVALIDARG);
|
||
|
}
|
||
|
|
||
|
pdvtdInfo->cchDrvName = strlen((char *)pdvtd16 +
|
||
|
pdvtd16->tdDriverNameOffset) + 1;
|
||
|
|
||
|
pdvtdInfo->cbConvertSize += pdvtdInfo->cchDrvName * sizeof(WCHAR);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pdvtdInfo->cchDrvName = 0;
|
||
|
}
|
||
|
|
||
|
if (pdvtd16->tdDeviceNameOffset != 0)
|
||
|
{
|
||
|
if (pdvtd16->tdDeviceNameOffset > pdvtd16->tdSize ||
|
||
|
pdvtd16->tdDeviceNameOffset < DVTD_MINSIZE)
|
||
|
{
|
||
|
// Offset can't be larger than size or fall within base
|
||
|
// structure
|
||
|
LEDebugOut((DEB_WARN, "UtGetDvtd16Info - bad pdvtd16->tdDeviceNameOffset\n"));
|
||
|
return(E_INVALIDARG);
|
||
|
}
|
||
|
|
||
|
pdvtdInfo->cchDevName = strlen((char *)pdvtd16 +
|
||
|
pdvtd16->tdDeviceNameOffset) + 1;
|
||
|
|
||
|
pdvtdInfo->cbConvertSize += pdvtdInfo->cchDevName * sizeof(WCHAR);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pdvtdInfo->cchDevName = 0;
|
||
|
}
|
||
|
|
||
|
if (pdvtd16->tdPortNameOffset != 0)
|
||
|
{
|
||
|
if (pdvtd16->tdPortNameOffset > pdvtd16->tdSize ||
|
||
|
pdvtd16->tdPortNameOffset < DVTD_MINSIZE)
|
||
|
{
|
||
|
// Offset can't be larger than size or fall within base
|
||
|
// structure
|
||
|
LEDebugOut((DEB_WARN, "UtGetDvtd16Info - bad pdvtd16->tdPortNameOffset\n"));
|
||
|
return(E_INVALIDARG);
|
||
|
}
|
||
|
|
||
|
|
||
|
pdvtdInfo->cchPortName = strlen((char *)pdvtd16 +
|
||
|
pdvtd16->tdPortNameOffset) + 1;
|
||
|
|
||
|
pdvtdInfo->cbConvertSize += pdvtdInfo->cchPortName * sizeof(WCHAR);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pdvtdInfo->cchPortName = 0;
|
||
|
}
|
||
|
|
||
|
if (pdvtd16->tdExtDevmodeOffset != 0)
|
||
|
{
|
||
|
if (pdvtd16->tdExtDevmodeOffset > pdvtd16->tdSize ||
|
||
|
pdvtd16->tdExtDevmodeOffset < DVTD_MINSIZE)
|
||
|
{
|
||
|
// Offset can't be larger than size or fall within base
|
||
|
// structure
|
||
|
LEDebugOut((DEB_WARN, "UtGetDvtd16Info - bad pdvtd16->tdExtDevmodeOffset\n"));
|
||
|
return(E_INVALIDARG);
|
||
|
}
|
||
|
|
||
|
// The DEVMODEW structure needs to be DWORD aligned, so here we make
|
||
|
// sure cbConvertSize (which will be the beginning of DEVMODEW) is
|
||
|
// DWORD aligned
|
||
|
pdvtdInfo->cbConvertSize += (sizeof(DWORD) - 1);
|
||
|
pdvtdInfo->cbConvertSize &= ~(sizeof(DWORD) - 1);
|
||
|
|
||
|
// Now compute the space needed for the DEVMODE
|
||
|
pdm16 = (DEVMODEA *)((BYTE *)pdvtd16 + pdvtd16->tdExtDevmodeOffset);
|
||
|
|
||
|
// We start with a basic DEVMODEW
|
||
|
pdvtdInfo->cbConvertSize += sizeof(DEVMODEW);
|
||
|
|
||
|
if (pdm16->dmSize > sizeof(DEVMODEA))
|
||
|
{
|
||
|
// The input DEVMODEA is larger than a standard DEVMODEA, so
|
||
|
// add space for the extra amount
|
||
|
pdvtdInfo->cbConvertSize += pdm16->dmSize - sizeof(DEVMODEA);
|
||
|
}
|
||
|
|
||
|
// Finally we account for the extra driver data
|
||
|
pdvtdInfo->cbConvertSize += pdm16->dmDriverExtra;
|
||
|
}
|
||
|
|
||
|
LEDebugOut((DEB_ITRACE, "%p OUT UtGetDvtd16Info (%lx) [%ld]\n",
|
||
|
NULL, S_OK, pdvtdInfo->cbConvertSize));
|
||
|
|
||
|
return(S_OK);
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: UtConvertDvtd16toDvtd32
|
||
|
//
|
||
|
// Synopsis: Fills in a 32-bit DVTARGETDEVICE based on a 16-bit
|
||
|
// DVTARGETDEVICE
|
||
|
//
|
||
|
// Arguments: [pdvtd16] -- pointer to ANSI DVTARGETDEVICE
|
||
|
// [pdvtdInfo] -- pointer to DVDT_INFO block
|
||
|
// [pdvtd32] -- pointer to UNICODE DVTARGETDEVICE
|
||
|
//
|
||
|
// Requires: pdvtdInfo must have been filled in by a previous call to
|
||
|
// UtGetDvtd16Info
|
||
|
//
|
||
|
// pdvtd32 must be at least pdvtdInfo->cbConvertSize bytes long
|
||
|
//
|
||
|
// Returns: HRESULT
|
||
|
//
|
||
|
// Modifies: pdvtd32
|
||
|
//
|
||
|
// Algorithm:
|
||
|
//
|
||
|
// History: 06-May-94 AlexT Created from DrewB's original functions
|
||
|
// 10-Jul-94 AlexT Make sure DEVMODEW is DWORD aligned
|
||
|
//
|
||
|
// Notes: Do we need to do any error checking on the strings?
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
extern "C" HRESULT UtConvertDvtd16toDvtd32(DVTARGETDEVICE const UNALIGNED *pdvtd16,
|
||
|
DVTDINFO const *pdvtdInfo,
|
||
|
DVTARGETDEVICE *pdvtd32)
|
||
|
{
|
||
|
LEDebugOut((DEB_ITRACE, "%p _IN UtConvertDvtd16toDvtd32 (%p, %p, %p)\n",
|
||
|
NULL, pdvtd16, pdvtdInfo, pdvtd32));
|
||
|
|
||
|
#if DBG==1
|
||
|
{
|
||
|
// Verify the passed in pdvtdInfo is what we expect
|
||
|
DVTDINFO dbgDvtdInfo;
|
||
|
Assert(UtGetDvtd16Info(pdvtd16, &dbgDvtdInfo) == S_OK);
|
||
|
Assert(0 == memcmp(&dbgDvtdInfo, pdvtdInfo, sizeof(DVTDINFO)));
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
HRESULT hr = S_OK;
|
||
|
USHORT cbOffset;
|
||
|
int cchWritten;
|
||
|
DEVMODEA UNALIGNED *pdm16;
|
||
|
DEVMODEW *pdm32;
|
||
|
UINT nCodePage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
|
||
|
|
||
|
memset(pdvtd32, 0, pdvtdInfo->cbConvertSize);
|
||
|
|
||
|
cbOffset = UT_DVTARGETDEVICE_SIZE;
|
||
|
|
||
|
if (pdvtdInfo->cchDrvName != 0)
|
||
|
{
|
||
|
pdvtd32->tdDriverNameOffset = cbOffset;
|
||
|
cchWritten = MultiByteToWideChar(
|
||
|
CP_ACP, 0,
|
||
|
(char *)pdvtd16+pdvtd16->tdDriverNameOffset,
|
||
|
pdvtdInfo->cchDrvName,
|
||
|
(LPOLESTR)((BYTE *)pdvtd32 +
|
||
|
pdvtd32->tdDriverNameOffset),
|
||
|
pdvtdInfo->cchDrvName);
|
||
|
if (0 == cchWritten)
|
||
|
{
|
||
|
hr = E_UNEXPECTED;
|
||
|
goto ErrRtn;
|
||
|
}
|
||
|
cbOffset += cchWritten * sizeof(WCHAR);
|
||
|
}
|
||
|
|
||
|
if (pdvtdInfo->cchDevName != 0)
|
||
|
{
|
||
|
pdvtd32->tdDeviceNameOffset = cbOffset;
|
||
|
cchWritten = MultiByteToWideChar(
|
||
|
nCodePage, 0,
|
||
|
(char *)pdvtd16 + pdvtd16->tdDeviceNameOffset,
|
||
|
pdvtdInfo->cchDevName,
|
||
|
(LPOLESTR)((BYTE *)pdvtd32 +
|
||
|
pdvtd32->tdDeviceNameOffset),
|
||
|
pdvtdInfo->cchDevName);
|
||
|
|
||
|
if (0 == cchWritten)
|
||
|
{
|
||
|
hr = E_UNEXPECTED;
|
||
|
goto ErrRtn;
|
||
|
}
|
||
|
cbOffset += cchWritten * sizeof(WCHAR);
|
||
|
}
|
||
|
|
||
|
if (pdvtdInfo->cchPortName != 0)
|
||
|
{
|
||
|
pdvtd32->tdPortNameOffset = cbOffset;
|
||
|
cchWritten = MultiByteToWideChar(
|
||
|
nCodePage, 0,
|
||
|
(char *)pdvtd16 + pdvtd16->tdPortNameOffset,
|
||
|
pdvtdInfo->cchPortName,
|
||
|
(LPOLESTR)((BYTE *)pdvtd32 +
|
||
|
pdvtd32->tdPortNameOffset),
|
||
|
pdvtdInfo->cchPortName);
|
||
|
if (0 == cchWritten)
|
||
|
{
|
||
|
hr = E_UNEXPECTED;
|
||
|
goto ErrRtn;
|
||
|
}
|
||
|
|
||
|
cbOffset += cchWritten * sizeof(WCHAR);
|
||
|
}
|
||
|
|
||
|
if (pdvtd16->tdExtDevmodeOffset != 0)
|
||
|
{
|
||
|
// Make sure DEVMODEW will be DWORD aligned
|
||
|
cbOffset += (sizeof(DWORD) - 1);
|
||
|
cbOffset &= ~(sizeof(DWORD) - 1);
|
||
|
|
||
|
pdvtd32->tdExtDevmodeOffset = cbOffset;
|
||
|
pdm32 = (DEVMODEW *)((BYTE *)pdvtd32+pdvtd32->tdExtDevmodeOffset);
|
||
|
|
||
|
pdm16 = (DEVMODEA *)((BYTE *)pdvtd16+pdvtd16->tdExtDevmodeOffset);
|
||
|
|
||
|
// The incoming DEVMODEA can have one of the following two forms:
|
||
|
//
|
||
|
// 1) 32 chars for dmDeviceName
|
||
|
// m bytes worth of fixed size data (where m <= 38)
|
||
|
// n bytes of dmDriverExtra data
|
||
|
//
|
||
|
// and dmSize will be 32+m
|
||
|
//
|
||
|
// 2) 32 chars for dmDeviceName
|
||
|
// 38 bytes worth of fixed size data
|
||
|
// 32 chars for dmFormName
|
||
|
// m additional bytes of fixed size data
|
||
|
// n bytes of dmDriverExtra data
|
||
|
//
|
||
|
// and dmSize will be 32 + 38 + 32 + m
|
||
|
//
|
||
|
// We have to be careful to translate the dmFormName string, if it
|
||
|
// exists
|
||
|
|
||
|
// First, translate the dmDeviceName
|
||
|
if (MultiByteToWideChar(nCodePage, 0, (char *)pdm16->dmDeviceName,
|
||
|
CCHDEVICENAME,
|
||
|
pdm32->dmDeviceName, CCHDEVICENAME) == 0)
|
||
|
{
|
||
|
hr = E_UNEXPECTED;
|
||
|
goto ErrRtn;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Now check to see if we have a dmFormName to translate
|
||
|
if (pdm16->dmSize <= FIELD_OFFSET(DEVMODEA, dmFormName))
|
||
|
{
|
||
|
// No dmFormName, just copy the remaining m bytes
|
||
|
memcpy(&pdm32->dmSpecVersion, &pdm16->dmSpecVersion,
|
||
|
pdm16->dmSize - CCHDEVICENAME);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// There is a dmFormName; copy the bytes between the names first
|
||
|
memcpy(&pdm32->dmSpecVersion, &pdm16->dmSpecVersion,
|
||
|
FIELD_OFFSET(DEVMODEA, dmFormName) -
|
||
|
FIELD_OFFSET(DEVMODEA, dmSpecVersion));
|
||
|
|
||
|
// Now translate the dmFormName
|
||
|
if (MultiByteToWideChar(CP_ACP, 0, (char *)pdm16->dmFormName,
|
||
|
CCHFORMNAME,
|
||
|
pdm32->dmFormName, CCHFORMNAME) == 0)
|
||
|
{
|
||
|
hr = E_UNEXPECTED;
|
||
|
goto ErrRtn;
|
||
|
}
|
||
|
|
||
|
// Now copy the remaining m bytes
|
||
|
|
||
|
if (pdm16->dmSize > FIELD_OFFSET(DEVMODEA, dmLogPixels))
|
||
|
{
|
||
|
memcpy(&pdm32->dmLogPixels, &pdm16->dmLogPixels,
|
||
|
pdm16->dmSize - FIELD_OFFSET(DEVMODEA, dmLogPixels));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pdm32->dmSize = sizeof(DEVMODEW);
|
||
|
if (pdm16->dmSize > sizeof(DEVMODEA))
|
||
|
{
|
||
|
pdm32->dmSize += pdm16->dmSize - sizeof(DEVMODEA);
|
||
|
}
|
||
|
|
||
|
// Copy the extra driver bytes
|
||
|
memcpy(((BYTE*)pdm32) + pdm32->dmSize, ((BYTE*)pdm16) + pdm16->dmSize,
|
||
|
pdm16->dmDriverExtra);
|
||
|
|
||
|
cbOffset += pdm32->dmSize + pdm32->dmDriverExtra;
|
||
|
}
|
||
|
|
||
|
// Finally, set pdvtd32's size
|
||
|
pdvtd32->tdSize = cbOffset;
|
||
|
|
||
|
|
||
|
ErrRtn:
|
||
|
LEDebugOut((DEB_ITRACE, "%p OUT UtConvertDvtd16toDvtd32 (%lx)\n",
|
||
|
NULL, hr));
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: UtGetDvtd32Info
|
||
|
//
|
||
|
// Synopsis: Fills in pdvdtInfo
|
||
|
//
|
||
|
// Arguments: [pdvtd32] -- pointer to ANSI DVTARGETDEVICE
|
||
|
// [pdvtdInfo] -- pointer to DVDT_INFO block
|
||
|
//
|
||
|
// Requires:
|
||
|
//
|
||
|
// Returns: HRESULT
|
||
|
//
|
||
|
// Modifies: pdvtdInfo
|
||
|
//
|
||
|
// Algorithm:
|
||
|
//
|
||
|
// History: 06-May-94 AlexT Created from DrewB's original functions
|
||
|
//
|
||
|
// Notes: Do we need to do any error checking on the strings?
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
extern "C" HRESULT UtGetDvtd32Info(DVTARGETDEVICE const *pdvtd32, PDVTDINFO pdvtdInfo)
|
||
|
{
|
||
|
LEDebugOut((DEB_ITRACE, "%p _IN UtGetDvtd32Info (%p, %p)\n",
|
||
|
NULL, pdvtd32, pdvtdInfo));
|
||
|
|
||
|
DEVMODEW *pdm32;
|
||
|
|
||
|
// Let's do some sanity checking on the incoming DVTARGETDEVICE
|
||
|
if (pdvtd32->tdSize < DVTD_MINSIZE)
|
||
|
{
|
||
|
LEDebugOut((DEB_WARN, "UtGetDvtd32Info - bad pdvtd32->tdSize\n"));
|
||
|
return(E_INVALIDARG);
|
||
|
}
|
||
|
|
||
|
pdvtdInfo->cbConvertSize = UT_DVTARGETDEVICE_SIZE;
|
||
|
|
||
|
// Compute required size for Drv, Device, Port names
|
||
|
if (pdvtd32->tdDriverNameOffset != 0)
|
||
|
{
|
||
|
if (pdvtd32->tdDriverNameOffset > pdvtd32->tdSize ||
|
||
|
pdvtd32->tdDriverNameOffset < DVTD_MINSIZE)
|
||
|
{
|
||
|
// Offset can't be larger than size or fall within base
|
||
|
// structure
|
||
|
LEDebugOut((DEB_WARN, "UtGetDvtd32Info - bad pdvtd32->tdDriverNameOffset\n"));
|
||
|
return(E_INVALIDARG);
|
||
|
}
|
||
|
|
||
|
pdvtdInfo->cchDrvName = lstrlenW((WCHAR *)((BYTE *)pdvtd32 +
|
||
|
pdvtd32->tdDriverNameOffset)) + 1;
|
||
|
|
||
|
pdvtdInfo->cbConvertSize += pdvtdInfo->cchDrvName * sizeof(WCHAR);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pdvtdInfo->cchDrvName = 0;
|
||
|
}
|
||
|
|
||
|
if (pdvtd32->tdDeviceNameOffset != 0)
|
||
|
{
|
||
|
if (pdvtd32->tdDeviceNameOffset > pdvtd32->tdSize ||
|
||
|
pdvtd32->tdDeviceNameOffset < DVTD_MINSIZE)
|
||
|
{
|
||
|
// Offset can't be larger than size or fall within base
|
||
|
// structure
|
||
|
LEDebugOut((DEB_WARN, "UtGetDvtd32Info - bad pdvtd32->tdDeviceNameOffset\n"));
|
||
|
return(E_INVALIDARG);
|
||
|
}
|
||
|
|
||
|
pdvtdInfo->cchDevName = lstrlenW((WCHAR *)((BYTE *)pdvtd32 +
|
||
|
pdvtd32->tdDeviceNameOffset)) + 1;
|
||
|
|
||
|
pdvtdInfo->cbConvertSize += pdvtdInfo->cchDevName * sizeof(WCHAR);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pdvtdInfo->cchDevName = 0;
|
||
|
}
|
||
|
|
||
|
if (pdvtd32->tdPortNameOffset != 0)
|
||
|
{
|
||
|
if (pdvtd32->tdPortNameOffset > pdvtd32->tdSize ||
|
||
|
pdvtd32->tdPortNameOffset < DVTD_MINSIZE)
|
||
|
{
|
||
|
// Offset can't be larger than size or fall within base
|
||
|
// structure
|
||
|
LEDebugOut((DEB_WARN, "UtGetDvtd32Info - bad pdvtd32->tdPortNameOffset\n"));
|
||
|
return(E_INVALIDARG);
|
||
|
}
|
||
|
|
||
|
pdvtdInfo->cchPortName = lstrlenW((WCHAR *)((BYTE *)pdvtd32 +
|
||
|
pdvtd32->tdPortNameOffset)) + 1;
|
||
|
|
||
|
pdvtdInfo->cbConvertSize += pdvtdInfo->cchPortName * sizeof(WCHAR);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pdvtdInfo->cchPortName = 0;
|
||
|
}
|
||
|
|
||
|
// Now compute the space needed for the DEVMODE
|
||
|
if (pdvtd32->tdExtDevmodeOffset != 0)
|
||
|
{
|
||
|
if (pdvtd32->tdExtDevmodeOffset > pdvtd32->tdSize ||
|
||
|
pdvtd32->tdExtDevmodeOffset < DVTD_MINSIZE)
|
||
|
{
|
||
|
// Offset can't be larger than size or fall within base
|
||
|
// structure
|
||
|
LEDebugOut((DEB_WARN, "UtGetDvtd32Info - bad pdvtd32->tdExtDevmodeOffset\n"));
|
||
|
return(E_INVALIDARG);
|
||
|
}
|
||
|
|
||
|
// The DEVMODEA structure needs to be DWORD aligned, so here we make
|
||
|
// sure cbConvertSize (which will be the beginning of DEVMODEA) is
|
||
|
// DWORD aligned
|
||
|
pdvtdInfo->cbConvertSize += (sizeof(DWORD) - 1);
|
||
|
pdvtdInfo->cbConvertSize &= ~(sizeof(DWORD) - 1);
|
||
|
|
||
|
pdm32 = (DEVMODEW *)((BYTE *)pdvtd32+pdvtd32->tdExtDevmodeOffset);
|
||
|
|
||
|
// We start with a basic DEVMODEA
|
||
|
pdvtdInfo->cbConvertSize += sizeof(DEVMODEA);
|
||
|
|
||
|
if (pdm32->dmSize > sizeof(DEVMODEW))
|
||
|
{
|
||
|
// The input DEVMODEW is larger than a standard DEVMODEW, so
|
||
|
// add space for the extra amount
|
||
|
pdvtdInfo->cbConvertSize += pdm32->dmSize - sizeof(DEVMODEW);
|
||
|
}
|
||
|
|
||
|
// Finally we account for the extra driver data
|
||
|
pdvtdInfo->cbConvertSize += pdm32->dmDriverExtra;
|
||
|
}
|
||
|
|
||
|
LEDebugOut((DEB_ITRACE, "%p OUT UtGetDvtd32Info (%lx) [%ld]\n",
|
||
|
NULL, S_OK, pdvtdInfo->cbConvertSize));
|
||
|
|
||
|
return(S_OK);
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: UtConvertDvtd32toDvtd16
|
||
|
//
|
||
|
// Synopsis: Fills in a 32-bit DVTARGETDEVICE based on a 16-bit
|
||
|
// DVTARGETDEVICE
|
||
|
//
|
||
|
// Arguments: [pdvtd32] -- pointer to ANSI DVTARGETDEVICE
|
||
|
// [pdvtdInfo] -- pointer to DVDT_INFO block
|
||
|
// [pdvtd16] -- pointer to UNICODE DVTARGETDEVICE
|
||
|
//
|
||
|
// Requires: pdvtdInfo must have been filled in by a previous call to
|
||
|
// UtGetDvtd32Info
|
||
|
//
|
||
|
// pdvtd16 must be at least pdvtdInfo->cbSizeConvert bytes long
|
||
|
//
|
||
|
// Returns: HRESULT
|
||
|
//
|
||
|
// Modifies: pdvtd16
|
||
|
//
|
||
|
// Algorithm:
|
||
|
//
|
||
|
// History: 06-May-94 AlexT Created from DrewB's original functions
|
||
|
//
|
||
|
// Notes: Do we need to do any error checking on the strings?
|
||
|
//
|
||
|
// On Chicago we'll have to provide helper code to do this
|
||
|
// translation
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
extern "C" HRESULT UtConvertDvtd32toDvtd16(DVTARGETDEVICE const *pdvtd32,
|
||
|
DVTDINFO const *pdvtdInfo,
|
||
|
DVTARGETDEVICE UNALIGNED *pdvtd16)
|
||
|
{
|
||
|
LEDebugOut((DEB_ITRACE, "%p _IN UtConvertDvtd32toDvtd16 (%p, %p, %p)\n",
|
||
|
NULL, pdvtd32, pdvtdInfo, pdvtd16));
|
||
|
|
||
|
#if DBG==1
|
||
|
{
|
||
|
// Verify the passed in pdvtdInfo is what we expect
|
||
|
DVTDINFO dbgDvtdInfo;
|
||
|
Assert(UtGetDvtd32Info(pdvtd32, &dbgDvtdInfo) == S_OK);
|
||
|
Assert(0 == memcmp(&dbgDvtdInfo, pdvtdInfo, sizeof(DVTDINFO)));
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
HRESULT hr = S_OK;
|
||
|
USHORT cbOffset;
|
||
|
int cbWritten;
|
||
|
DEVMODEA UNALIGNED *pdm16;
|
||
|
DEVMODEW *pdm32;
|
||
|
UINT nCodePage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
|
||
|
|
||
|
memset(pdvtd16, 0, pdvtdInfo->cbConvertSize);
|
||
|
|
||
|
cbOffset = UT_DVTARGETDEVICE_SIZE;
|
||
|
|
||
|
if (pdvtdInfo->cchDrvName != 0)
|
||
|
{
|
||
|
pdvtd16->tdDriverNameOffset = cbOffset;
|
||
|
cbWritten = WideCharToMultiByte(CP_ACP, 0,
|
||
|
(WCHAR *)((BYTE *)pdvtd32 +
|
||
|
pdvtd32->tdDriverNameOffset),
|
||
|
pdvtdInfo->cchDrvName,
|
||
|
(char *)pdvtd16 + pdvtd16->tdDriverNameOffset,
|
||
|
pdvtdInfo->cchDrvName * sizeof(WCHAR),
|
||
|
NULL, NULL);
|
||
|
|
||
|
if (0 == cbWritten)
|
||
|
{
|
||
|
hr = E_UNEXPECTED;
|
||
|
goto ErrRtn;
|
||
|
}
|
||
|
cbOffset += cbWritten;
|
||
|
}
|
||
|
|
||
|
if (pdvtdInfo->cchDevName != 0)
|
||
|
{
|
||
|
pdvtd16->tdDeviceNameOffset = cbOffset;
|
||
|
cbWritten = WideCharToMultiByte(
|
||
|
nCodePage, 0,
|
||
|
(WCHAR *)((BYTE *)pdvtd32 +
|
||
|
pdvtd32->tdDeviceNameOffset),
|
||
|
pdvtdInfo->cchDevName,
|
||
|
(char *)pdvtd16 + pdvtd16->tdDeviceNameOffset,
|
||
|
pdvtdInfo->cchDevName * sizeof(WCHAR),
|
||
|
NULL, NULL);
|
||
|
|
||
|
if (0 == cbWritten)
|
||
|
{
|
||
|
hr = E_UNEXPECTED;
|
||
|
goto ErrRtn;
|
||
|
}
|
||
|
cbOffset += cbWritten;
|
||
|
}
|
||
|
|
||
|
if (pdvtdInfo->cchPortName != 0)
|
||
|
{
|
||
|
pdvtd16->tdPortNameOffset = cbOffset;
|
||
|
cbWritten = WideCharToMultiByte(nCodePage, 0,
|
||
|
(WCHAR *)((BYTE *)pdvtd32 +
|
||
|
pdvtd32->tdPortNameOffset),
|
||
|
pdvtdInfo->cchPortName,
|
||
|
(char *)pdvtd16 + pdvtd16->tdPortNameOffset,
|
||
|
pdvtdInfo->cchPortName * sizeof(WCHAR),
|
||
|
NULL, NULL);
|
||
|
if (0 == cbWritten)
|
||
|
{
|
||
|
hr = E_UNEXPECTED;
|
||
|
goto ErrRtn;
|
||
|
}
|
||
|
cbOffset += cbWritten;
|
||
|
}
|
||
|
|
||
|
if (pdvtd32->tdExtDevmodeOffset != 0)
|
||
|
{
|
||
|
// Make sure DEVMODEA will be DWORD aligned
|
||
|
cbOffset += (sizeof(DWORD) - 1);
|
||
|
cbOffset &= ~(sizeof(DWORD) - 1);
|
||
|
|
||
|
pdvtd16->tdExtDevmodeOffset = cbOffset;
|
||
|
pdm16 = (DEVMODEA *)((BYTE *)pdvtd16+pdvtd16->tdExtDevmodeOffset);
|
||
|
|
||
|
pdm32 = (DEVMODEW *)((BYTE *)pdvtd32+pdvtd32->tdExtDevmodeOffset);
|
||
|
|
||
|
// The incoming DEVMODEW can have one of the following two forms:
|
||
|
//
|
||
|
// 1) 32 WCHARs for dmDeviceName
|
||
|
// m bytes worth of fixed size data (where m <= 38)
|
||
|
// n bytes of dmDriverExtra data
|
||
|
//
|
||
|
// and dmSize will be 64+m
|
||
|
//
|
||
|
// 2) 32 WCHARs for dmDeviceName
|
||
|
// 38 bytes worth of fixed size data
|
||
|
// 32 WCHARs for dmFormName
|
||
|
// m additional bytes of fixed size data
|
||
|
// n bytes of dmDriverExtra data
|
||
|
//
|
||
|
// and dmSize will be 64 + 38 + 64 + m
|
||
|
//
|
||
|
// We have to be careful to translate the dmFormName string, if it
|
||
|
// exists
|
||
|
|
||
|
|
||
|
// Need to attempt to copy the entire buffer since old UI lib does a memcmp to verify if ptd's are equal
|
||
|
|
||
|
if (WideCharToMultiByte(nCodePage, 0, pdm32->dmDeviceName,CCHDEVICENAME,
|
||
|
(char *)pdm16->dmDeviceName, CCHDEVICENAME,
|
||
|
NULL, NULL) == 0)
|
||
|
{
|
||
|
|
||
|
// in DBCS case we can run out of pdm16->dmDeviceName buffer space
|
||
|
// Current Implementation of WideCharToMultiByte copies in what fit before error
|
||
|
// but in case this behavior changes copy again up to NULL char if error out above
|
||
|
|
||
|
if (WideCharToMultiByte(nCodePage, 0, pdm32->dmDeviceName,-1,
|
||
|
(char *)pdm16->dmDeviceName, CCHDEVICENAME,
|
||
|
NULL, NULL) == 0)
|
||
|
{
|
||
|
hr = E_UNEXPECTED;
|
||
|
goto ErrRtn;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Now check to see if we have a dmFormName to translate
|
||
|
if (pdm32->dmSize <= FIELD_OFFSET(DEVMODEW, dmFormName))
|
||
|
{
|
||
|
// No dmFormName, just copy the remaining m bytes
|
||
|
memcpy(&pdm16->dmSpecVersion, &pdm32->dmSpecVersion,
|
||
|
pdm32->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// There is a dmFormName; copy the bytes between the names first
|
||
|
memcpy(&pdm16->dmSpecVersion, &pdm32->dmSpecVersion,
|
||
|
FIELD_OFFSET(DEVMODEW, dmFormName) -
|
||
|
FIELD_OFFSET(DEVMODEW, dmSpecVersion));
|
||
|
|
||
|
// Now translate the dmFormName
|
||
|
if (WideCharToMultiByte(CP_ACP, 0,
|
||
|
pdm32->dmFormName, CCHFORMNAME,
|
||
|
(char *) pdm16->dmFormName, CCHFORMNAME,
|
||
|
NULL, NULL) == 0)
|
||
|
{
|
||
|
|
||
|
if (WideCharToMultiByte(CP_ACP, 0,
|
||
|
pdm32->dmFormName, -1,
|
||
|
(char *) pdm16->dmFormName, CCHFORMNAME,
|
||
|
NULL, NULL) == 0)
|
||
|
{
|
||
|
hr = E_UNEXPECTED;
|
||
|
goto ErrRtn;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Now copy the remaining m bytes
|
||
|
|
||
|
if (pdm32->dmSize > FIELD_OFFSET(DEVMODEW, dmLogPixels))
|
||
|
{
|
||
|
memcpy(&pdm16->dmLogPixels, &pdm32->dmLogPixels,
|
||
|
pdm32->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pdm16->dmSize = sizeof(DEVMODEA);
|
||
|
if (pdm32->dmSize > sizeof(DEVMODEW))
|
||
|
{
|
||
|
pdm16->dmSize += pdm32->dmSize - sizeof(DEVMODEW);
|
||
|
}
|
||
|
|
||
|
// Copy the extra driver bytes
|
||
|
memcpy(((BYTE*)pdm16) + pdm16->dmSize, ((BYTE*)pdm32) + pdm32->dmSize,
|
||
|
pdm32->dmDriverExtra);
|
||
|
|
||
|
cbOffset += pdm16->dmSize + pdm16->dmDriverExtra;
|
||
|
}
|
||
|
|
||
|
// Finally, set pdvtd16's size
|
||
|
pdvtd16->tdSize = cbOffset;
|
||
|
|
||
|
ErrRtn:
|
||
|
LEDebugOut((DEB_ITRACE, "%p OUT UtConvertDvtd32toDvtd16 (%lx)\n",
|
||
|
NULL, hr));
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: UtGetUNICODEData, PRIVATE INTERNAL
|
||
|
//
|
||
|
// Synopsis: Given a string length, and two pointers (one ANSI, one
|
||
|
// OLESTR), returns the UNICODE version of whichever string
|
||
|
// is valid.
|
||
|
//
|
||
|
// Effects: Memory is allocated on the caller's pointer for new OLESTR
|
||
|
//
|
||
|
// Arguments: [ulLength] -- length of string in CHARACTERS (not bytes)
|
||
|
// (including terminator)
|
||
|
// [szANSI] -- candidate ANSI string
|
||
|
// [szOLESTR] -- candidate OLESTR string
|
||
|
// [pstr] -- OLESTR OUT parameter
|
||
|
//
|
||
|
// Returns: NOERROR on success
|
||
|
// E_OUTOFMEMORY on allocation failure
|
||
|
// E_ANSITOUNICODE if ANSI cannot be converted to UNICODE
|
||
|
//
|
||
|
// Algorithm: If szOLESTR is available, a simple copy is performed
|
||
|
// If szOLESTR is not available, szANSI is converted to UNICODE
|
||
|
// and the result is copied.
|
||
|
//
|
||
|
// History: dd-mmm-yy Author Comment
|
||
|
// 08-Mar-94 davepl Created
|
||
|
//
|
||
|
// Notes: Only one of the two input strings (ANSI or UNICODE) should
|
||
|
// be set on entry.
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
INTERNAL UtGetUNICODEData
|
||
|
( ULONG ulLength,
|
||
|
LPSTR szANSI,
|
||
|
LPOLESTR szOLESTR,
|
||
|
LPOLESTR * pstr )
|
||
|
{
|
||
|
VDATEHEAP();
|
||
|
|
||
|
// This fn is only called when one of the input strings
|
||
|
// has valid data... assert the impossible.
|
||
|
|
||
|
Win4Assert(pstr); // must have an out string
|
||
|
Win4Assert(ulLength); // must have a non-zero length
|
||
|
Win4Assert(szANSI || szOLESTR); // must have at least one source string
|
||
|
|
||
|
// If neither the ANSI nor the OLESTR version has data,
|
||
|
// there is nothing to return.
|
||
|
|
||
|
#if 0
|
||
|
// This is no better than what was there!!!
|
||
|
*pstr = NULL;
|
||
|
if (szOLESTR) {
|
||
|
*pstr = (LPOLESTR) UtDupPtr(szOLESTR, ulLength * sizeof(OLECHAR));
|
||
|
}
|
||
|
else if (szANSI) {
|
||
|
if (FALSE == MultiByteToWideChar(CP_ACP, // Code page ANSI
|
||
|
0, // Flags (none)
|
||
|
szANSI, // Source ANSI str
|
||
|
ulLength, // length of string
|
||
|
*pstr, // Dest UNICODE buffer
|
||
|
ulLength * sizeof(OLECHAR) )) // size of UNICODE buffer
|
||
|
{
|
||
|
PubMemFree(*pstr);
|
||
|
*pstr = NULL;
|
||
|
return ResultFromScode(E_UNSPEC);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
if (NULL == *pstr)
|
||
|
{
|
||
|
return ResultFromScode(E_OUTOFMEMORY);
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
|
||
|
if (!(szANSI || szOLESTR))
|
||
|
{
|
||
|
*pstr = NULL;
|
||
|
}
|
||
|
|
||
|
// Allocate memory for the UNICODE return string
|
||
|
|
||
|
*pstr = (LPOLESTR) PubMemAlloc(ulLength * sizeof(OLECHAR));
|
||
|
if (NULL == *pstr)
|
||
|
{
|
||
|
return ResultFromScode(E_OUTOFMEMORY);
|
||
|
}
|
||
|
|
||
|
// Trivial case: we already have UNICODE, just copy it
|
||
|
if (szOLESTR)
|
||
|
{
|
||
|
_xstrcpy(*pstr, szOLESTR);
|
||
|
return(NOERROR);
|
||
|
}
|
||
|
|
||
|
// Otherwise, we have to convert the ANSI string to UNICODE
|
||
|
// and return that.
|
||
|
|
||
|
else
|
||
|
{
|
||
|
if (FALSE == MultiByteToWideChar(CP_ACP, // Code page ANSI
|
||
|
0, // Flags (none)
|
||
|
szANSI, // Source ANSI str
|
||
|
ulLength, // length of string
|
||
|
*pstr, // Dest UNICODE buffer
|
||
|
ulLength * sizeof(OLECHAR) )) // size of UNICODE buffer
|
||
|
{
|
||
|
PubMemFree(*pstr);
|
||
|
*pstr = NULL;
|
||
|
return ResultFromScode(E_UNSPEC);
|
||
|
}
|
||
|
}
|
||
|
return NOERROR;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: UtPutUNICODEData, PRIVATE INTERNAL
|
||
|
//
|
||
|
// Synopsis: Given an OLESTR and two possible buffer pointer, one ANSI
|
||
|
// and the other OLESTR, this fn tries to convert the string
|
||
|
// down to ANSI. If it succeeds, it allocates memory on the
|
||
|
// ANSI ptr for the result. If it fails, it allocates memory
|
||
|
// on the UNICODE ptr and copies the input string over. The
|
||
|
// length of the final result (ANSI or UNICODE) is returned
|
||
|
// in dwResultLen.
|
||
|
//
|
||
|
// Arguments: [ulLength] -- input length of OLESTR str
|
||
|
// NB!!!! this value must include the
|
||
|
// null terminator character.
|
||
|
// [str] -- the OLESTR to store
|
||
|
// [pszANSI] -- candidate ANSI str ptr
|
||
|
// [pszOLESTR] -- candidate OLESTR str ptr. May be NULL,
|
||
|
// in which case no copy is made of the
|
||
|
// original string if the ANSI conversion
|
||
|
// fails.
|
||
|
// [pdwResultLen] -- where to store the length of result. This
|
||
|
// length includes the terminating NULL.
|
||
|
// Length is in CHARACTERS.
|
||
|
//
|
||
|
// Returns: NOERROR on success
|
||
|
// E_OUTOFMEMORY on allocation failure
|
||
|
// E_FAIL can't convert ANSI string and no
|
||
|
// pszOLESTR is NULL
|
||
|
//
|
||
|
// History: dd-mmm-yy Author Comment
|
||
|
// 10-Jun-94 alexgo allow pszOLESTR to be NULL
|
||
|
// 08-Mar-94 davepl Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
// this function is poorly coded. But, it looks like it only gets called when a 1.0
|
||
|
// clip format is needed. That is not very often!
|
||
|
|
||
|
INTERNAL UtPutUNICODEData
|
||
|
( ULONG ulLength,
|
||
|
LPOLESTR str,
|
||
|
LPSTR * pszANSI,
|
||
|
LPOLESTR * pszOLESTR,
|
||
|
DWORD * pdwResultLen )
|
||
|
{
|
||
|
VDATEHEAP();
|
||
|
|
||
|
Win4Assert(pszANSI);
|
||
|
Win4Assert(str);
|
||
|
Win4Assert(pdwResultLen);
|
||
|
Win4Assert(ulLength);
|
||
|
|
||
|
// Free any strings currently attached to these pointers; if we wind
|
||
|
// up setting one here, we can't leave the other valid.
|
||
|
|
||
|
if (*pszANSI)
|
||
|
{
|
||
|
PubMemFree(*pszANSI);
|
||
|
*pszANSI = NULL;
|
||
|
}
|
||
|
if (pszOLESTR && *pszOLESTR)
|
||
|
{
|
||
|
PubMemFree(*pszOLESTR);
|
||
|
*pszOLESTR = NULL;
|
||
|
}
|
||
|
|
||
|
// Create a working buffer for UNICODE->ANSI conversion
|
||
|
LPSTR szANSITEMP = (LPSTR) PubMemAlloc((ulLength+1) * 2);
|
||
|
if (NULL == szANSITEMP)
|
||
|
{
|
||
|
return ResultFromScode(E_OUTOFMEMORY);
|
||
|
}
|
||
|
|
||
|
// Try to convert the UNICODE down to ANSI. If it succeeds,
|
||
|
// we just copy the result to the ANSI dest. If it fails,
|
||
|
// we copy the UNICODE version direct to the UNICODE dest.
|
||
|
|
||
|
LPCSTR pDefault = "?";
|
||
|
BOOL fUseDef = 0;
|
||
|
|
||
|
if (FALSE == WideCharToMultiByte (CP_ACP,
|
||
|
0,
|
||
|
str,
|
||
|
ulLength,
|
||
|
szANSITEMP,
|
||
|
(ulLength + 1) * 2,
|
||
|
pDefault,
|
||
|
&fUseDef) || fUseDef )
|
||
|
{
|
||
|
// UNICODE->ANSI failed!
|
||
|
|
||
|
// Won't be needing the ANSI buffer anymore...
|
||
|
PubMemFree(szANSITEMP);
|
||
|
|
||
|
if( pszOLESTR )
|
||
|
{
|
||
|
*pszANSI = NULL;
|
||
|
*pszOLESTR = (LPOLESTR) PubMemAlloc((ulLength + 1) * sizeof(OLECHAR));
|
||
|
if (NULL == *pszOLESTR)
|
||
|
{
|
||
|
*pdwResultLen = 0;
|
||
|
return ResultFromScode(E_OUTOFMEMORY);
|
||
|
}
|
||
|
// Move the UNICODE source to UNICODE dest
|
||
|
_xstrcpy(*pszOLESTR, str);
|
||
|
*pdwResultLen = _xstrlen(str) + 1;
|
||
|
|
||
|
// That's it... return success
|
||
|
return(NOERROR);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return ResultFromScode(E_FAIL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// This code path is taken when the conversion to ANSI was
|
||
|
// successful. We copy the ANSI result to the ANSI dest.
|
||
|
|
||
|
if( pszOLESTR )
|
||
|
{
|
||
|
*pszOLESTR = NULL;
|
||
|
}
|
||
|
|
||
|
*pdwResultLen = strlen(szANSITEMP) + 1;
|
||
|
*pszANSI = (LPSTR) PubMemAlloc(*pdwResultLen);
|
||
|
if (NULL == *pszANSI)
|
||
|
{
|
||
|
*pdwResultLen = 0;
|
||
|
return ResultFromScode(E_OUTOFMEMORY);
|
||
|
}
|
||
|
strcpy(*pszANSI, szANSITEMP);
|
||
|
|
||
|
PubMemFree(szANSITEMP);
|
||
|
|
||
|
return(NOERROR);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Object Stabilization classes
|
||
|
//
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CSafeRefCount::CSafeRefCount
|
||
|
//
|
||
|
// Synopsis: constructor for the safe ref count class
|
||
|
//
|
||
|
// Effects:
|
||
|
//
|
||
|
// Arguments: none
|
||
|
//
|
||
|
// Requires:
|
||
|
//
|
||
|
// Returns: none
|
||
|
//
|
||
|
// Signals:
|
||
|
//
|
||
|
// Modifies:
|
||
|
//
|
||
|
// Derivation:
|
||
|
//
|
||
|
// Algorithm:
|
||
|
//
|
||
|
// History: dd-mmm-yy Author Comment
|
||
|
// 28-Jul-94 alexgo author
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
CSafeRefCount::CSafeRefCount()
|
||
|
{
|
||
|
RefDebugOut((DEB_TRACE, "%p _IN CSafeRefCount::CSafeRefCount ( )\n",
|
||
|
this));
|
||
|
|
||
|
m_cRefs = 0;
|
||
|
m_cNest = 0;
|
||
|
m_fInDelete = FALSE;
|
||
|
|
||
|
RefDebugOut((DEB_TRACE, "%p OUT CSafeRefCount::CSafeRefcount ( )\n",
|
||
|
this));
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CSafeRefCount::~CSafeRefCount (virtual)
|
||
|
//
|
||
|
// Synopsis:
|
||
|
//
|
||
|
// Effects:
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// Requires:
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// Signals:
|
||
|
//
|
||
|
// Modifies:
|
||
|
//
|
||
|
// Derivation:
|
||
|
//
|
||
|
// Algorithm:
|
||
|
//
|
||
|
// History: dd-mmm-yy Author Comment
|
||
|
// 28-Jul-94 alexgo author
|
||
|
//
|
||
|
// Notes: this fcn MUST be in retail build even though it does nothing
|
||
|
// it is needed to trigger derived class's virtual destructors
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
//#ifdef _DEBUG
|
||
|
CSafeRefCount::~CSafeRefCount()
|
||
|
{
|
||
|
Assert(m_cRefs == 0 && m_cNest == 0 && m_fInDelete == TRUE);
|
||
|
}
|
||
|
//#endif
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CSafeRefCount::SafeAddRef
|
||
|
//
|
||
|
// Synopsis: increments the reference count on the object
|
||
|
//
|
||
|
// Effects:
|
||
|
//
|
||
|
// Arguments: none
|
||
|
//
|
||
|
// Requires:
|
||
|
//
|
||
|
// Returns: ULONG -- the reference count after the increment
|
||
|
//
|
||
|
// Signals:
|
||
|
//
|
||
|
// Modifies:
|
||
|
//
|
||
|
// Derivation:
|
||
|
//
|
||
|
// Algorithm: increments the reference count.
|
||
|
//
|
||
|
// History: dd-mmm-yy Author Comment
|
||
|
// 28-Jul-94 alexgo author
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
ULONG CSafeRefCount::SafeAddRef()
|
||
|
{
|
||
|
RefDebugOut((DEB_TRACE, "%p _IN CSafeRefCount::SafeAddRef ( )\n",
|
||
|
this));
|
||
|
|
||
|
m_cRefs++;
|
||
|
|
||
|
//AssertSz(m_fInDelete == FALSE, "AddRef called on deleted object!");
|
||
|
|
||
|
// this *could* be really bad. If we are deleting the object,
|
||
|
// it means that during the destructor, somebody made an outgoing
|
||
|
// call eventually ended up with another addref to ourselves
|
||
|
// (even though all pointers to us had been 'Released').
|
||
|
//
|
||
|
// this is usually caused by code like the following:
|
||
|
// m_pFoo->Release();
|
||
|
// m_pFoo = NULL;
|
||
|
//
|
||
|
// If the the Release may cause Foo to be deleted, which may cause
|
||
|
// the object to get re-entered during Foo's destructor. However,
|
||
|
// 'this' object has not yet set m_pFoo to NULL, so it may
|
||
|
// try to continue to use m_pFoo.
|
||
|
//
|
||
|
// However, the May '94 aggregation rules REQUIRE this behaviour
|
||
|
// In your destructor, you have to addref the outer unknown before
|
||
|
// releasing cached interface pointers on your aggregatee. We
|
||
|
// can't put an assert here because we do this all the time now.
|
||
|
//
|
||
|
// REVIEW32: we may want to try to figure out a way to distinguish
|
||
|
// 'safe' uses of AddRef-after-zero (like the aggregation case)
|
||
|
// as opposed to dangerous cases (noted above).
|
||
|
|
||
|
RefDebugOut((DEB_TRACE, "%p OUT CSafeRefCount::SafeAddRef ( %lu )\n",
|
||
|
this, m_cRefs));
|
||
|
|
||
|
return m_cRefs;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CSafeRefCount::SafeRelease
|
||
|
//
|
||
|
// Synopsis: decrements the reference count on the object
|
||
|
//
|
||
|
// Effects: May delete the object!
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// Requires:
|
||
|
//
|
||
|
// Returns: ULONG -- the reference count after decrement
|
||
|
//
|
||
|
// Signals:
|
||
|
//
|
||
|
// Modifies:
|
||
|
//
|
||
|
// Derivation:
|
||
|
//
|
||
|
// Algorithm: decrements the reference count. If the reference count
|
||
|
// is zero AND the nest count is zero AND we are not currently
|
||
|
// trying to delete our object, then it is safe to delete.
|
||
|
//
|
||
|
// History: dd-mmm-yy Author Comment
|
||
|
// 28-Jul-94 alexgo author
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
ULONG CSafeRefCount::SafeRelease()
|
||
|
{
|
||
|
ULONG cRefs;
|
||
|
|
||
|
RefDebugOut((DEB_TRACE, "%p _IN CSafeRefCount::SafeRelease ( )\n",
|
||
|
this));
|
||
|
|
||
|
if( m_cRefs > 0 )
|
||
|
{
|
||
|
cRefs = --m_cRefs;
|
||
|
|
||
|
if( m_cRefs == 0 && m_cNest == 0 && m_fInDelete == FALSE )
|
||
|
{
|
||
|
RefDebugOut((DEB_TRACE,
|
||
|
"DELETING CSafeRefCount %p\n", this));
|
||
|
|
||
|
m_fInDelete = TRUE;
|
||
|
delete this;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// somebody is releasing a non-addrefed pointer!!
|
||
|
AssertSz(0, "Release called on a non-addref'ed pointer!\n");
|
||
|
|
||
|
cRefs = 0;
|
||
|
}
|
||
|
|
||
|
RefDebugOut((DEB_TRACE, "%p OUT CSafeRefCount::SafeRelease ( %lu )\n",
|
||
|
this, cRefs));
|
||
|
|
||
|
return cRefs;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CSafeRefCount::IncrementNestCount
|
||
|
//
|
||
|
// Synopsis: increments the nesting count of the object
|
||
|
//
|
||
|
// Effects:
|
||
|
//
|
||
|
// Arguments: none
|
||
|
//
|
||
|
// Requires:
|
||
|
//
|
||
|
// Returns: ULONG; the nesting count after increment
|
||
|
//
|
||
|
// Signals:
|
||
|
//
|
||
|
// Modifies:
|
||
|
//
|
||
|
// Derivation:
|
||
|
//
|
||
|
// Algorithm:
|
||
|
//
|
||
|
// History: dd-mmm-yy Author Comment
|
||
|
// 28-Jul-94 alexgo author
|
||
|
//
|
||
|
// Notes: The nesting count is the count of how many times an
|
||
|
// an object has been re-entered. For example, suppose
|
||
|
// somebody calls pFoo->Bar1(), which makes some calls that
|
||
|
// eventually call pFoo->Bar2();. On entrace to Bar2, the
|
||
|
// nest count of the object should be 2 (since the invocation
|
||
|
// of Bar1 is still on the stack above us).
|
||
|
//
|
||
|
// It is important to keep track of the nest count so we do
|
||
|
// not accidentally delete ourselves during a nested invocation.
|
||
|
// If we did, then when the stack unwinds to the original
|
||
|
// top level call, it could try to access a non-existent member
|
||
|
// variable and crash.
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
ULONG CSafeRefCount::IncrementNestCount()
|
||
|
{
|
||
|
RefDebugOut((DEB_TRACE, "%p _IN CSafeRefCount::IncrementNestCount "
|
||
|
"( )\n", this));
|
||
|
|
||
|
#if DBG == 1
|
||
|
if( m_fInDelete )
|
||
|
{
|
||
|
RefDebugOut((DEB_IWARN, "WARNING: CSafeRefCount, object %p "
|
||
|
"re-entered during delete!\n", this));
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
m_cNest++;
|
||
|
|
||
|
RefDebugOut((DEB_TRACE, "%p OUT CSafeRefCount::IncrementNestCount "
|
||
|
"( %lu )\n", this, m_cNest));
|
||
|
|
||
|
return m_cNest;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CSafeRefCount::DecrementNestCount
|
||
|
//
|
||
|
// Synopsis: decrements the nesting count and deletes the object
|
||
|
// (if necessary)
|
||
|
//
|
||
|
// Effects: may delete 'this' object!
|
||
|
//
|
||
|
// Arguments: none
|
||
|
//
|
||
|
// Requires:
|
||
|
//
|
||
|
// Returns: ULONG, the nesting count after decrement
|
||
|
//
|
||
|
// Signals:
|
||
|
//
|
||
|
// Modifies:
|
||
|
//
|
||
|
// Derivation:
|
||
|
//
|
||
|
// Algorithm: decrements the nesting count. If the nesting count is zero
|
||
|
// AND the reference count is zero AND we are not currently
|
||
|
// trying to delete ourselves, then delete 'this' object
|
||
|
//
|
||
|
// History: dd-mmm-yy Author Comment
|
||
|
// 28-Jul-94 alexgo author
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
ULONG CSafeRefCount::DecrementNestCount()
|
||
|
{
|
||
|
ULONG cNest;
|
||
|
|
||
|
RefDebugOut((DEB_TRACE, "%p _IN CSafeRefCount::DecrementNestCount "
|
||
|
"( )\n", this));
|
||
|
|
||
|
if( m_cNest > 0 )
|
||
|
{
|
||
|
cNest = --m_cNest;
|
||
|
|
||
|
if( m_cRefs == 0 && m_cNest == 0 && m_fInDelete == FALSE )
|
||
|
{
|
||
|
RefDebugOut((DEB_TRACE,
|
||
|
"DELETING CSafeRefCount %p\n", this));
|
||
|
|
||
|
m_fInDelete = TRUE;
|
||
|
delete this;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// somebody forget to increment the nest count!!
|
||
|
AssertSz(0, "Unbalanced nest count!!");
|
||
|
|
||
|
cNest = 0;
|
||
|
}
|
||
|
|
||
|
RefDebugOut((DEB_TRACE, "%p OUT CSafeRefCount::DecrementNestCount "
|
||
|
"( %lu )\n", this, cNest));
|
||
|
|
||
|
return cNest;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CSafeRefCount::IsZombie
|
||
|
//
|
||
|
// Synopsis: determines whether or not the object is in a zombie state
|
||
|
// (i.e. all references gone, but we are still on the stack
|
||
|
// somewhere).
|
||
|
//
|
||
|
// Effects:
|
||
|
//
|
||
|
// Arguments: none
|
||
|
//
|
||
|
// Requires:
|
||
|
//
|
||
|
// Returns: TRUE if in a zombie state
|
||
|
// FALSE otherwise
|
||
|
//
|
||
|
// Signals:
|
||
|
//
|
||
|
// Modifies:
|
||
|
//
|
||
|
// Derivation:
|
||
|
//
|
||
|
// Algorithm: If we are in the middle of a delete, or if the ref count
|
||
|
// is zero and the nest count is greater than zero, then we
|
||
|
// are a zombie
|
||
|
//
|
||
|
// History: dd-mmm-yy Author Comment
|
||
|
// 28-Jul-94 alexgo author
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
BOOL CSafeRefCount::IsZombie()
|
||
|
{
|
||
|
BOOL fIsZombie;
|
||
|
|
||
|
RefDebugOut((DEB_TRACE, "%p _IN CSafeRefCount::IsZombie ( )\n",
|
||
|
this));
|
||
|
|
||
|
if( (m_cRefs == 0 && m_cNest > 0) || m_fInDelete == TRUE )
|
||
|
{
|
||
|
fIsZombie = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fIsZombie = FALSE;
|
||
|
}
|
||
|
|
||
|
RefDebugOut((DEB_TRACE, "%p OUT CSafeRefCount::IsZombie ( %d )\n",
|
||
|
this, fIsZombie));
|
||
|
|
||
|
return fIsZombie;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CSafeRefCount::Dump, public (_DEBUG only)
|
||
|
//
|
||
|
// Synopsis: return a string containing the contents of the data members
|
||
|
//
|
||
|
// Effects:
|
||
|
//
|
||
|
// Arguments: [ppszDump] - an out pointer to a null terminated character array
|
||
|
// [ulFlag] - flag determining prefix of all newlines of the
|
||
|
// out character array (default is 0 - no prefix)
|
||
|
// [nIndentLevel] - will add a indent prefix after the other prefix
|
||
|
// for ALL newlines (including those with no prefix)
|
||
|
//
|
||
|
// Requires:
|
||
|
//
|
||
|
// Returns: HRESULT
|
||
|
//
|
||
|
// Signals:
|
||
|
//
|
||
|
// Modifies: [ppsz] - argument
|
||
|
//
|
||
|
// Derivation:
|
||
|
//
|
||
|
// Algorithm:
|
||
|
//
|
||
|
// History: dd-mmm-yy Author Comment
|
||
|
// 20-Jan-95 t-ScottH author
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
#ifdef _DEBUG
|
||
|
|
||
|
HRESULT CSafeRefCount::Dump(char **ppszDump, ULONG ulFlag, int nIndentLevel)
|
||
|
{
|
||
|
int i;
|
||
|
char *pszPrefix;
|
||
|
dbgstream dstrPrefix;
|
||
|
dbgstream dstrDump;
|
||
|
|
||
|
// determine prefix of newlines
|
||
|
if ( ulFlag & DEB_VERBOSE )
|
||
|
{
|
||
|
dstrPrefix << this << " _VB ";
|
||
|
}
|
||
|
|
||
|
// determine indentation prefix for all newlines
|
||
|
for (i = 0; i < nIndentLevel; i++)
|
||
|
{
|
||
|
dstrPrefix << DUMPTAB;
|
||
|
}
|
||
|
|
||
|
pszPrefix = dstrPrefix.str();
|
||
|
|
||
|
// put data members in stream
|
||
|
dstrDump << pszPrefix << "References = " << m_cRefs << endl;
|
||
|
dstrDump << pszPrefix << "Nesting level = " << m_cNest << endl;
|
||
|
dstrDump << pszPrefix << "InDelete = ";
|
||
|
if (m_fInDelete == TRUE)
|
||
|
{
|
||
|
dstrDump << "TRUE" << endl;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dstrDump << "FALSE" << endl;
|
||
|
}
|
||
|
|
||
|
// clean up and provide pointer to character array
|
||
|
*ppszDump = dstrDump.str();
|
||
|
|
||
|
if (*ppszDump == NULL)
|
||
|
{
|
||
|
*ppszDump = UtDupStringA(szDumpErrorMessage);
|
||
|
}
|
||
|
|
||
|
CoTaskMemFree(pszPrefix);
|
||
|
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
#endif //_DEBUG
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DumpCSafeRefCount, public (_DEBUG only)
|
||
|
//
|
||
|
// Synopsis: calls the CSafeRefCount::Dump method, takes care of errors and
|
||
|
// returns the zero terminated string
|
||
|
//
|
||
|
// Effects:
|
||
|
//
|
||
|
// Arguments: [pSRC] - pointer to CSafeRefCount
|
||
|
// [ulFlag] - flag determining prefix of all newlines of the
|
||
|
// out character array (default is 0 - no prefix)
|
||
|
// [nIndentLevel] - will add a indent prefix after the other prefix
|
||
|
// for ALL newlines (including those with no prefix)
|
||
|
//
|
||
|
// Requires:
|
||
|
//
|
||
|
// Returns: character array of structure dump or error (null terminated)
|
||
|
//
|
||
|
// Signals:
|
||
|
//
|
||
|
// Modifies:
|
||
|
//
|
||
|
// Algorithm:
|
||
|
//
|
||
|
// History: dd-mmm-yy Author Comment
|
||
|
// 20-Jan-95 t-ScottH author
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
|
||
|
char *DumpCSafeRefCount(CSafeRefCount *pSRC, ULONG ulFlag, int nIndentLevel)
|
||
|
{
|
||
|
char *pszDump;
|
||
|
HRESULT hresult;
|
||
|
|
||
|
if (pSRC == NULL)
|
||
|
{
|
||
|
return UtDupStringA(szDumpBadPtr);
|
||
|
}
|
||
|
|
||
|
hresult = pSRC->Dump( &pszDump, ulFlag, nIndentLevel);
|
||
|
|
||
|
if (hresult!=NOERROR)
|
||
|
{
|
||
|
CoTaskMemFree(pszDump);
|
||
|
|
||
|
return DumpHRESULT(hresult);
|
||
|
}
|
||
|
|
||
|
return pszDump;
|
||
|
}
|
||
|
|
||
|
#endif // _DEBUG
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CThreadCheck::VerifyThreadId
|
||
|
//
|
||
|
// Synopsis: makes sure that the calling thread is the same as the thread
|
||
|
// the object was created on if the threading model is *not*
|
||
|
// free threading.
|
||
|
//
|
||
|
// Effects:
|
||
|
//
|
||
|
// Arguments: none
|
||
|
//
|
||
|
// Requires:
|
||
|
//
|
||
|
// Returns: TRUE/FALSE
|
||
|
//
|
||
|
// Signals:
|
||
|
//
|
||
|
// Modifies:
|
||
|
//
|
||
|
// Derivation:
|
||
|
//
|
||
|
// Algorithm:
|
||
|
//
|
||
|
// History: dd-mmm-yy Author Comment
|
||
|
// 21-Nov-94 alexgo author
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
BOOL CThreadCheck::VerifyThreadId( void )
|
||
|
{
|
||
|
if( m_tid == GetCurrentThreadId() )
|
||
|
{
|
||
|
return TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LEDebugOut((DEB_ERROR, "ERROR!: Called on thread %lx, should be"
|
||
|
" %lx \n", GetCurrentThreadId(), m_tid));
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CThreadCheck::Dump, public (_DEBUG only)
|
||
|
//
|
||
|
// Synopsis: return a string containing the contents of the data members
|
||
|
//
|
||
|
// Effects:
|
||
|
//
|
||
|
// Arguments: [ppszDump] - an out pointer to a null terminated character array
|
||
|
// [ulFlag] - flag determining prefix of all newlines of the
|
||
|
// out character array (default is 0 - no prefix)
|
||
|
// [nIndentLevel] - will add a indent prefix after the other prefix
|
||
|
// for ALL newlines (including those with no prefix)
|
||
|
//
|
||
|
// Requires:
|
||
|
//
|
||
|
// Returns: HRESULT
|
||
|
//
|
||
|
// Signals:
|
||
|
//
|
||
|
// Modifies: [ppszDump] - argument
|
||
|
//
|
||
|
// Derivation:
|
||
|
//
|
||
|
// Algorithm: use dbgstream to create a string containing information on the
|
||
|
// content of data structures
|
||
|
//
|
||
|
// History: dd-mmm-yy Author Comment
|
||
|
// 20-Jan-95 t-ScottH author
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
#ifdef _DEBUG
|
||
|
|
||
|
HRESULT CThreadCheck::Dump(char **ppszDump, ULONG ulFlag, int nIndentLevel)
|
||
|
{
|
||
|
int i;
|
||
|
char *pszPrefix;
|
||
|
dbgstream dstrPrefix;
|
||
|
dbgstream dstrDump;
|
||
|
|
||
|
// determine prefix of newlines
|
||
|
if ( ulFlag & DEB_VERBOSE )
|
||
|
{
|
||
|
dstrPrefix << this << " _VB ";
|
||
|
}
|
||
|
|
||
|
// determine indentation prefix for all newlines
|
||
|
for (i = 0; i < nIndentLevel; i++)
|
||
|
{
|
||
|
dstrPrefix << DUMPTAB;
|
||
|
}
|
||
|
|
||
|
pszPrefix = dstrPrefix.str();
|
||
|
|
||
|
// put data members in stream
|
||
|
dstrDump << pszPrefix << "Thread ID = " << m_tid << endl;
|
||
|
|
||
|
// clean up and provide pointer to character array
|
||
|
*ppszDump = dstrDump.str();
|
||
|
|
||
|
if (*ppszDump == NULL)
|
||
|
{
|
||
|
*ppszDump = UtDupStringA(szDumpErrorMessage);
|
||
|
}
|
||
|
|
||
|
CoTaskMemFree(pszPrefix);
|
||
|
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
#endif //_DEBUG
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DumpCThreadCheck, public (_DEBUG only)
|
||
|
//
|
||
|
// Synopsis: calls the CThreadCheck::Dump method, takes care of errors and
|
||
|
// returns the zero terminated string
|
||
|
//
|
||
|
// Effects:
|
||
|
//
|
||
|
// Arguments: [pTC] - pointer to CThreadCheck
|
||
|
// [ulFlag] - flag determining prefix of all newlines of the
|
||
|
// out character array (default is 0 - no prefix)
|
||
|
// [nIndentLevel] - will add a indent prefix after the other prefix
|
||
|
// for ALL newlines (including those with no prefix)
|
||
|
//
|
||
|
// Requires:
|
||
|
//
|
||
|
// Returns: character array of structure dump or error (null terminated)
|
||
|
//
|
||
|
// Signals:
|
||
|
//
|
||
|
// Modifies:
|
||
|
//
|
||
|
// Algorithm:
|
||
|
//
|
||
|
// History: dd-mmm-yy Author Comment
|
||
|
// 20-Jan-95 t-ScottH author
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
|
||
|
char *DumpCThreadCheck(CThreadCheck *pTC, ULONG ulFlag, int nIndentLevel)
|
||
|
{
|
||
|
char *pszDump;
|
||
|
HRESULT hresult;
|
||
|
|
||
|
if (pTC == NULL)
|
||
|
{
|
||
|
return UtDupStringA(szDumpBadPtr);
|
||
|
}
|
||
|
|
||
|
hresult = pTC->Dump( &pszDump, ulFlag, nIndentLevel);
|
||
|
|
||
|
if (hresult != NOERROR)
|
||
|
{
|
||
|
CoTaskMemFree(pszDump);
|
||
|
|
||
|
return DumpHRESULT(hresult);
|
||
|
}
|
||
|
|
||
|
return pszDump;
|
||
|
}
|
||
|
|
||
|
#endif // _DEBUG
|