NT4/private/ole32/olethunk/olethk32/thoputil.cxx

4548 lines
114 KiB
C++
Raw Normal View History

2001-01-01 00:00:00 +01:00
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1994.
//
// File: thoputil.cxx
//
// Contents: Utility routines for thunking
//
// History: 01-Mar-94 DrewB Created
//
//----------------------------------------------------------------------------
#include "headers.cxx"
#pragma hdrstop
#include <stdio.h>
#include <limits.h>
#include <vdmdbg.h>
#include <valid.h>
//
// Chicago doesn't support the NT ExpLdr API, use the new Chicago
// WOWGetDescriptor that copies the LDT info to a provided buffer.
//
#if defined(_CHICAGO_)
extern "C" WOWGetDescriptor(VPVOID, VDMLDT_ENTRY *);
#else
extern "C" DECLSPEC_IMPORT VDMLDT_ENTRY *ExpLdt;
#endif
#include "struct16.hxx"
#define CF_INVALID ((CLIPFORMAT)0)
#define OBJDESC_CF(cf) \
((cf) == g_cfObjectDescriptor || (cf) == g_cfLinkSourceDescriptor)
// Alias manager for THOP_ALIAS32
CAliases gAliases32;
//+---------------------------------------------------------------------------
//
// Function: IidToIidIdx, public
//
// Synopsis: Looks up an interface index by IID
// If it's not found, it returns the IID pointer
//
// Arguments: [riid] - IID
//
// Returns: Index or IID
//
// History: 23-Feb-94 DrewB Created
//
//----------------------------------------------------------------------------
IIDIDX IidToIidIdx(REFIID riid)
{
int idx;
for (idx = 0; idx < THI_COUNT; idx++)
{
if (IsEqualIID(riid, *aittIidToThi[idx].piid))
{
return INDEX_IIDIDX(aittIidToThi[idx].iThi);
}
}
return IID_IIDIDX(&riid);
}
//+---------------------------------------------------------------------------
//
// Function: TaskMalloc32, public
//
// Synopsis: Task allocation for 32-bits
//
// History: 01-Mar-94 DrewB Created
//
// Notes: Temporary until CoTaskMemAlloc is hooked up
//
//----------------------------------------------------------------------------
#ifndef COTASK_DEFINED
LPVOID TaskMalloc32(DWORD cb)
{
IMalloc *pm;
LPVOID pv;
if (FAILED(GetScode(CoGetMalloc(MEMCTX_TASK, &pm))))
{
return NULL;
}
else
{
pv = pm->Alloc(cb);
pm->Release();
}
return pv;
}
//+---------------------------------------------------------------------------
//
// Function: TaskFree32, public
//
// Synopsis: Task free for 32-bits
//
// History: 01-Mar-94 DrewB Created
//
// Notes: Temporary until CoTaskMemAlloc is hooked up
//
//----------------------------------------------------------------------------
void TaskFree32(LPVOID pv)
{
IMalloc *pm;
if (FAILED(GetScode(CoGetMalloc(MEMCTX_TASK, &pm))))
{
thkAssert(!"CoGetMalloc failed");
}
else
{
pm->Free(pv);
pm->Release();
}
}
#endif
//+---------------------------------------------------------------------------
//
// Function: TaskMalloc16, public
//
// Synopsis: Allocates 16-bit task memory
//
// Arguments: [uiSize] - Amount of memory to allocate
//
// Returns: VPVOID for memory allocated
//
// History: 01-Mar-94 DrewB Created
//
//----------------------------------------------------------------------------
DWORD TaskMalloc16( UINT uiSize )
{
return CallbackTo16(gdata16Data.fnTaskAlloc, uiSize);
}
//+---------------------------------------------------------------------------
//
// Function: TaskFree16, public
//
// Synopsis: Frees 16-bit task memory
//
// Arguments: [vpvoid] - VPVOID of allocated memory
//
// History: 01-Mar-94 DrewB Created
//
//----------------------------------------------------------------------------
void TaskFree16( DWORD vpvoid )
{
CallbackTo16(gdata16Data.fnTaskFree, vpvoid);
}
// List of 16/32 HRESULT mappings for mapping functions
struct SHrMapping
{
HRESULT hr16;
HRESULT hr32;
};
// Since we're including 32-bit headers in this code we can use
// the defines for the 32-bit values but we must specify the
// 16-bit values explicitly
static SHrMapping hmMappings[] =
{
0x80000001, E_NOTIMPL,
0x80000002, E_OUTOFMEMORY,
0x80000003, E_INVALIDARG,
0x80000004, E_NOINTERFACE,
0x80000005, E_POINTER,
0x80000006, E_HANDLE,
0x80000007, E_ABORT,
0x80000008, E_FAIL,
0x80000009, E_ACCESSDENIED
};
#define NMAPPINGS (sizeof(hmMappings)/sizeof(hmMappings[0]))
#define HR16_ERROR 0x80000000
#define HR16_MAP_FIRST 1
#define HR16_MAP_LAST 9
//+---------------------------------------------------------------------------
//
// Function: TransformHRESULT_1632, public
//
// Synopsis: Translates a 16-bit hresult into a 32-bit hresult
//
// Arguments: [hresult] - 16-bit hresult to transform
//
// History: 15-Mar-94 BobDay Created
//
//----------------------------------------------------------------------------
STDAPI_(DWORD) TransformHRESULT_1632( DWORD hresult )
{
ULONG ulIndex;
// We only map error codes
if (hresult & HR16_ERROR)
{
// The 16-bit HRESULTs to be mapped are known quantities
// whose values are sequential, so we can map directly from
// the value to an array index
ulIndex = hresult & ~HR16_ERROR;
if (ulIndex >= HR16_MAP_FIRST && ulIndex <= HR16_MAP_LAST)
{
// Known value, index array to find 32-bit HRESULT
return hmMappings[ulIndex-HR16_MAP_FIRST].hr32;
}
}
// No mapping found, so return the original
return hresult;
}
//+---------------------------------------------------------------------------
//
// Function: TransformHRESULT_3216, public
//
// Synopsis: Translates a 32-bit hresult into a 16-bit hresult
//
// Arguments: [hresult] - 32-bit hresult to transform
//
// History: 15-Mar-94 BobDay Created
//
//----------------------------------------------------------------------------
STDAPI_(DWORD) TransformHRESULT_3216( DWORD hresult )
{
int i;
SHrMapping *phm;
// We don't know the true values of 32-bit HRESULTs since we're
// using the defines and they may change, so we have to look up
// the hard way
phm = hmMappings;
for (i = 0; i < NMAPPINGS; i++)
{
if (phm->hr32 == (HRESULT)hresult)
{
return phm->hr16;
}
phm++;
}
// No mapping found, so return the original
return hresult;
}
//+---------------------------------------------------------------------------
//
// Function: RecordStackState, public debug
//
// Synopsis: Records the current state of the stack
//
// Arguments: [psr] - Storage space for information
//
// Modifies: [psr]
//
// History: 28-Apr-94 DrewB Created
//
//----------------------------------------------------------------------------
#if DBG == 1
void RecordStackState16(SStackRecord *psr)
{
CStackAllocator *psa;
psa = TlsThkGetStack16();
psa->RecordState(psr);
}
void RecordStackState32(SStackRecord *psr)
{
CStackAllocator *psa;
psa = TlsThkGetStack32();
psa->RecordState(psr);
}
#endif
//+---------------------------------------------------------------------------
//
// Function: CheckStackState, public debug
//
// Synopsis: Checks recorded information about the stack against its
// current state
//
// Arguments: [psr] - Recorded information
//
// History: 28-Apr-94 DrewB Created
//
//----------------------------------------------------------------------------
#if DBG == 1
void CheckStackState16(SStackRecord *psr)
{
CStackAllocator *psa;
psa = TlsThkGetStack16();
psa->CheckState(psr);
}
void CheckStackState32(SStackRecord *psr)
{
CStackAllocator *psa;
psa = TlsThkGetStack32();
psa->CheckState(psr);
}
#endif
//+---------------------------------------------------------------------------
//
// Function: Convert_VPSTR_to_LPOLESTR
//
// Synopsis: Converts 16-bit VPSTR to 32-bit LPOLESTR pointer
//
// Arguments: [vpstr] - VPSTR
// [lpOleStr] - OLESTR
// [uiSizeInPlace] - Amount of data available in [lpOleStr]
// for in-place conversion (in characters, not bytes)
// including nul
//
// Returns: Pointer to LPOLESTR with data
//
// History: 24-Feb-94 BobDay Created
//
//----------------------------------------------------------------------------
LPOLESTR Convert_VPSTR_to_LPOLESTR(
THUNKINFO *pti,
VPSTR vpstr,
LPOLESTR lpOleStr,
UINT uiSizeInPlace
)
{
LPSTR lpstr;
UINT uiSize;
LPOLESTR lpOleStrResult;
UINT cChars;
// We shouldn't be calling here for null strings
thkAssert( vpstr != NULL );
lpstr = GetStringPtr16(pti, vpstr, CCHMAXSTRING, &uiSize);
if ( lpstr == NULL )
{
//
// GetStringPtr will have filled in the pti->scResult
//
return( NULL );
}
// The string has to have at least one character in it
// because it must be null-terminated to be valid
thkAssert(uiSize > 0);
lpOleStrResult = lpOleStr;
if ( uiSize > uiSizeInPlace )
{
lpOleStrResult = (LPOLESTR)TaskMalloc32(uiSize*sizeof(OLECHAR));
if (lpOleStrResult == NULL)
{
pti->scResult = E_OUTOFMEMORY;
return NULL;
}
}
cChars = MultiByteToWideChar( AreFileApisANSI() ? CP_ACP : CP_OEMCP,
0,
lpstr,
uiSize,
lpOleStrResult,
uiSize );
WOWRELVDMPTR(vpstr);
if ( cChars == 0 )
{
if (lpOleStrResult != lpOleStr)
{
TaskFree32(lpOleStrResult);
}
pti->scResult = E_UNEXPECTED;
return( NULL );
}
else
{
return( lpOleStrResult );
}
}
//+---------------------------------------------------------------------------
//
// Function: Convert_LPOLESTR_to_VPSTR
//
// Synopsis: Converts 32-bit LPOLESTR to 16-bit VPSTR pointer
//
// Arguments: [lpOleStr] - OLESTR
// [vpstr] - VPSTR
// [uiSize32] - Length of OLESTR in characters (not bytes)
// including nul
// [uiSize16] - Byte length of buffer referred to by VPSTR
//
// Returns: Appropriate status code
//
// History: 24-Feb-94 BobDay Created
//
// Notes: Always converts in place
//
//----------------------------------------------------------------------------
SCODE Convert_LPOLESTR_to_VPSTR(
LPCOLESTR lpOleStr,
VPSTR vpstr,
UINT uiSize32,
UINT uiSize16
)
{
LPSTR lpstr;
UINT cChars;
SCODE sc;
sc = S_OK;
lpstr = (LPSTR)WOWFIXVDMPTR(vpstr, uiSize16);
cChars = WideCharToMultiByte( AreFileApisANSI() ? CP_ACP : CP_OEMCP,
0,
lpOleStr,
uiSize32,
lpstr,
uiSize16,
NULL,
NULL );
if ( cChars == 0 && uiSize32 != 0 )
{
sc = E_UNEXPECTED;
}
WOWRELVDMPTR(vpstr);
return sc;
}
#ifdef _CHICAGO_
//+---------------------------------------------------------------------------
//
// Function: Convert_LPSTR_to_VPSTR
//
// Synopsis: Converts 32-bit LPSTR to 16-bit VPSTR pointer
//
// Arguments: [lpOleStr] - LPSTR
// [vpstr] - VPSTR
// [uiSize32] - Length of LPSTR in bytes including nul
// [uiSize16] - Byte length of buffer referred to by VPSTR
//
// Returns: Appropriate status code
//
// History: 10-21-95 KevinRo Created
//
// Notes:
//
//----------------------------------------------------------------------------
SCODE Convert_LPSTR_to_VPSTR(
LPCSTR lpOleStr,
VPSTR vpstr,
UINT uiSize32,
UINT uiSize16
)
{
LPSTR lpstr;
lpstr = (LPSTR)WOWFIXVDMPTR(vpstr, uiSize16);
memcpy(lpstr,lpOleStr,uiSize32);
WOWRELVDMPTR(vpstr);
return S_OK;
}
#endif // _CHICAGO_
// Selector bit constants
#define SEL_TI 0x0004
#define SEL_RPL 0x0003
#define SEL_INDEX 0xfff8
#define IS_LDT_SELECTOR(sel) (((sel) & SEL_TI) == SEL_TI)
// LDT bit constants
#define LTYPE_APP 0x0010
#define LTYPE_CODE 0x0008
#define LTYPE_CREAD 0x0002
#define LTYPE_DDOWN 0x0004
#define LTYPE_DWRITE 0x0002
// Pointer access types, or'able
// Defined to be the same as thop in/out so that no translation
// is necessary for checks on thop memory access
#define PACC_READ THOP_IN
#define PACC_WRITE THOP_OUT
#define PACC_CODE 1 // Special for CODE PTRs
// Information about a VDM pointer
typedef struct _VPTRDESC
{
BYTE *pbFlat;
DWORD dwLengthLeft;
} VPTRDESC;
// VDM memory is always zero-based on Win95
#ifndef _CHICAGO_
DWORD dwBaseVDMMemory = 0xFFFFFFFF;
#else
#define dwBaseVDMMemory 0
#endif
// Extended success returns from GetPtr16Description
#define S_GDTENTRY MAKE_SCODE(SEVERITY_SUCCESS, FACILITY_NULL, 1)
#define S_SYSLDTENTRY MAKE_SCODE(SEVERITY_SUCCESS, FACILITY_NULL, 2)
//+---------------------------------------------------------------------------
//
// Function: GetPtr16Description, public
//
// Synopsis: Validates access for a VDM pointer and returns
// information about it
// Also forces not-present segments into memory by
// touching them
//
// Arguments: [vp] - VDM pointer
// [grfAccess] - Desired access
// [dwSize] - Desired size of access, must be >= 1
// [pvpd] - VPTRDESC out
//
// Returns: Appropriate status code
//
// Modifies: [pvpd]
//
// History: 26-Apr-94 DrewB Created
//
// Notes: Returns fixed memory
//
//----------------------------------------------------------------------------
SCODE GetPtr16Description(VPVOID vp,
WORD grfAccess,
DWORD dwSize,
VPTRDESC *pvpd)
{
VDMLDT_ENTRY *vle;
#if defined(_CHICAGO_)
VDMLDT_ENTRY LdtEntry;
#endif
WORD wSel;
WORD wOff;
DWORD dwLength;
thkAssert(vp != 0);
thkAssert(dwSize > 0);
thkAssert(grfAccess != 0);
wSel = (WORD)(vp >> 16);
wOff = (WORD)(vp & 0xffff);
pvpd->dwLengthLeft = 0xffff-wOff+1; // Default length remaining
if (!IS_LDT_SELECTOR(wSel))
{
// According to the WOW developers, the only GDT selector
// is for the BIOS data area so we should never see one
thkDebugOut((DEB_ERROR, "GDT selector: 0x%04X\n", wSel));
// Handle it just in case
pvpd->pbFlat = (BYTE *)WOWFIXVDMPTR(vp, dwSize);
return S_GDTENTRY;
}
#if defined(_CHICAGO_)
vle = &LdtEntry;
if (!WOWGetDescriptor(vp, vle))
{
return E_INVALIDARG;
}
#else
vle = (VDMLDT_ENTRY *)((BYTE *)(ExpLdt)+(wSel & SEL_INDEX));
#endif
if ((vle->HighWord.Bits.Type & LTYPE_APP) == 0)
{
// According to the WOW developers, they don't use
// system segments so we should never see one
thkDebugOut((DEB_ERROR, "System descriptor: 0x%04X\n", wSel));
// Handle it just in case
pvpd->pbFlat = (BYTE *)WOWFIXVDMPTR(vp, dwSize);
return S_SYSLDTENTRY;
}
// Do as much up-front validation as possible
// Since the segment may not be present, we are restricted to
// only checking the access permissions
if (vle->HighWord.Bits.Type & LTYPE_CODE)
{
// Validate access for code segments
// Code segments are never writable
if (((grfAccess & PACC_READ) &&
(vle->HighWord.Bits.Type & LTYPE_CREAD) == 0) ||
(grfAccess & PACC_WRITE))
{
return E_INVALIDARG;
}
}
else
{
// Validate access for data segments
// Data segments are always readable never executable
if (((grfAccess & PACC_WRITE) &&
(vle->HighWord.Bits.Type & LTYPE_DWRITE) == 0) ||
(grfAccess & PACC_CODE))
{
return E_INVALIDARG;
}
}
// Bring in segment if it's not present
if (!vle->HighWord.Bits.Pres)
{
// We've validated access permissions and segments must
// always be at least one byte long so it's safe to
// touch the first byte to bring it in
// On Win95, this will call GlobalFix on the pointer
// to ensure that it stays in memory
WOWCallback16(gdata16Data.fnTouchPointer16, vp);
#if defined(_CHICAGO_)
// Since we only copy the descriptor, recopy it now.
WOWGetDescriptor(vp, vle);
#endif
thkAssert(vle->HighWord.Bits.Pres);
}
#ifdef _CHICAGO_
else
{
// Lock the LDT entry (as best as we can) by fixing it
// This prevents global blocks from being relocated during
// heap compaction
WOWGetVDMPointerFix(vp, dwSize, TRUE);
}
#endif
dwLength = ((DWORD)vle->LimitLow |
((DWORD)vle->HighWord.Bits.LimitHi << 16))+1;
if (vle->HighWord.Bits.Granularity)
{
// 4K granularity
dwLength <<= 12;
}
if ((vle->HighWord.Bits.Type & LTYPE_CODE) ||
(vle->HighWord.Bits.Type & LTYPE_DDOWN) == 0)
{
// Validate length for code and normal data segments
if (wOff+dwSize > dwLength)
{
WOWRELVDMPTR(vp);
return E_INVALIDARG;
}
pvpd->dwLengthLeft = dwLength-wOff;
}
else
{
// Expand-down segment
if (wOff < dwLength)
{
WOWRELVDMPTR(vp);
return E_INVALIDARG;
}
// Check for wraparound
if (vle->HighWord.Bits.Granularity)
{
// BUGBUG - Compiler - This should be +1, but
// the compiler generates a warning about an overflow
// in constant arithmetic
pvpd->dwLengthLeft = 0xffffffff-wOff;
}
if (dwSize > pvpd->dwLengthLeft)
{
WOWRELVDMPTR(vp);
return E_INVALIDARG;
}
}
// VDM memory is always zero-based on Win95
#ifndef _CHICAGO_
if ( dwBaseVDMMemory == 0xFFFFFFFF )
{
dwBaseVDMMemory = (DWORD)WOWGetVDMPointer(0, 0, FALSE);
}
#endif
// Translate the pointer even on Win95 because forcing the segment
// present may have changed its address
pvpd->pbFlat = (BYTE *)(dwBaseVDMMemory +
wOff +
( (DWORD)vle->BaseLow |
( (DWORD)vle->HighWord.Bytes.BaseMid << 16) |
( (DWORD)vle->HighWord.Bytes.BaseHi << 24) ) );
#if DBG == 1
if (pvpd->pbFlat != WOWGetVDMPointer(vp, dwSize, TRUE))
{
thkDebugOut((DEB_ERROR, "GetPtr16Description: "
"%p computed, %p system\n",
pvpd->pbFlat, WOWGetVDMPointer(vp, dwSize, TRUE)));
}
#endif
return S_OK;
}
//+---------------------------------------------------------------------------
//
// Function: GetReadPtr16
//
// Synopsis: Validates a 16-bit pointer for reading and converts it into
// a flat 32 pointer.
//
// Arguments: [pti] - THUNKINFO * for updating error code
// [vp] - 16-bit pointer to validate/convert
// [dwSize] - Length to validate
//
// Returns: Appropriate status code
//
// History: 22-Mar-94 BobDay Created
//
//----------------------------------------------------------------------------
VOID *
GetReadPtr16(
THUNKINFO *pti,
VPVOID vp,
DWORD dwSize )
{
VPTRDESC vpd;
SCODE sc;
sc = GetPtr16Description(vp, PACC_READ, dwSize, &vpd);
if (FAILED(sc))
{
pti->scResult = sc;
return NULL;
}
else
{
return vpd.pbFlat;
}
}
//+---------------------------------------------------------------------------
//
// Function: GetWritePtr16
//
// Synopsis: Validates a 16-bit pointer for writing and converts it into
// a flat 32 pointer.
//
// Arguments: [pti] - THUNKINFO * for updating error code
// [vp] - 16-bit pointer to validate/convert
// [dwSize] - Length to validate
//
// Returns: Appropriate status code
//
// History: 22-Mar-94 BobDay Created
//
//----------------------------------------------------------------------------
VOID *
GetWritePtr16(
THUNKINFO *pti,
VPVOID vp,
DWORD dwSize )
{
VPTRDESC vpd;
SCODE sc;
sc = GetPtr16Description(vp, PACC_WRITE, dwSize, &vpd);
if (FAILED(sc))
{
pti->scResult = sc;
return NULL;
}
else
{
return vpd.pbFlat;
}
}
//+---------------------------------------------------------------------------
//
// Function: GetCodePtr16
//
// Synopsis: Validates a 16-bit pointer for execution and converts it
// into a flat 32 pointer.
//
// Arguments: [pti] - THUNKINFO * for updating error code
// [vp] - 16-bit pointer to validate/convert
// [dwSize] - Length to validate
//
// Returns: Appropriate status code
//
// History: 22-Jul-94 BobDay Created
//
//----------------------------------------------------------------------------
VOID *
GetCodePtr16(
THUNKINFO *pti,
VPVOID vp,
DWORD dwSize )
{
VPTRDESC vpd;
SCODE sc;
sc = GetPtr16Description(vp, PACC_CODE, dwSize, &vpd);
if (FAILED(sc))
{
pti->scResult = sc;
return NULL;
}
else
{
return vpd.pbFlat;
}
}
//+---------------------------------------------------------------------------
//
// Function: GetReadWritePtr16
//
// Synopsis: Validates a 16-bit pointer for reading and writing and
// converts it into a flat 32 pointer.
//
// Arguments: [pti] - THUNKINFO * for updating error code
// [vp] - 16-bit pointer to validate/convert
// [dwSize] - Length to validate
//
// Returns: Appropriate status code
//
// History: 22-Mar-94 BobDay Created
//
//----------------------------------------------------------------------------
VOID *
GetReadWritePtr16(
THUNKINFO *pti,
VPVOID vp,
DWORD dwSize )
{
VPTRDESC vpd;
SCODE sc;
sc = GetPtr16Description(vp, PACC_READ | PACC_WRITE, dwSize, &vpd);
if (FAILED(sc))
{
pti->scResult = sc;
return NULL;
}
else
{
return vpd.pbFlat;
}
}
//+---------------------------------------------------------------------------
//
// Function: GetStringPtr16
//
// Synopsis: Validates a 16-bit pointer to a string for reading and
// converts it (the pointer) into a flat 32 pointer. It also
// returns the length, since it has to compute it anyway.
//
// Arguments: [pti] - THUNKINFO * for updating error code
// [vp] - 16-bit pointer to validate/convert
// [cchMax] - Maximum legal length
// [lpSize] - Place to return length
//
// Returns: Appropriate status code
//
// History: 22-Mar-94 BobDay Created
//
//----------------------------------------------------------------------------
CHAR *
GetStringPtr16(
THUNKINFO *pti,
VPSTR vp,
UINT cchMax,
PUINT lpSize )
{
VPTRDESC vpd;
SCODE sc;
// Check the first byte to ensure read access to the segment
sc = GetPtr16Description(vp, PACC_READ, 1, &vpd);
if (FAILED(sc))
{
pti->scResult = sc;
return NULL;
}
else
{
UINT cchLen;
BYTE *pb;
BOOL fMbLead;
pb = vpd.pbFlat;
if (pb == NULL)
{
goto Exit;
}
// Restrict zero-termination search to cchMax characters
// or valid remaining memory
// Since we specified one in GetPtr16Description, dwLengthLeft
// is one off here
cchMax = min(cchMax, vpd.dwLengthLeft+1);
cchLen = 0;
fMbLead = FALSE;
while (cchMax > 0)
{
cchLen++;
if (*pb == 0 && !fMbLead)
{
break;
}
else
{
fMbLead = (BOOL)g_abLeadTable[*pb++];
cchMax--;
}
}
if (cchMax > 0)
{
*lpSize = cchLen;
return (LPSTR)vpd.pbFlat;
}
Exit:
{
pti->scResult = E_INVALIDARG;
WOWRELVDMPTR(vp);
return NULL;
}
}
}
//+---------------------------------------------------------------------------
//
// Function: ValidatePtr16, public
//
// Synopsis: Calls an appropriate validation routine for 16-bit
// memory based on in/out status
//
// Arguments: [pti] - Thunk info, can be NULL for no validation
// [vp16] - 16-bit pointer
// [dwSize] - Size
// [thopInOut] - In/out type
//
// Returns: Pointer or NULL
//
// Modifies: [pti]->scResult for errors
//
// History: 24-Apr-94 DrewB Created
//
// Notes: 0 - No validation
// THOP_IN - Read validation
// THOP_OUT - Write validation
// THOP_INOUT - Read/write validation
//
//----------------------------------------------------------------------------
VOID *
ValidatePtr16(THUNKINFO *pti,
VPVOID vp16,
DWORD dwSize,
THOP thopInOut)
{
VPTRDESC vpd;
SCODE sc;
thopInOut &= THOP_INOUT;
if (thopInOut != 0)
{
sc = GetPtr16Description(vp16, thopInOut, dwSize, &vpd);
if (FAILED(sc))
{
pti->scResult = sc;
return NULL;
}
else
{
return vpd.pbFlat;
}
}
else
{
return WOWFIXVDMPTR(vp16, dwSize);
}
}
//+---------------------------------------------------------------------------
//
// Function: IsValidInterface16, public
//
// Synopsis: Validates that a provided 16-bit interface is really valid
// (uses the same validation technique as 16-bit OLE 2.01)
//
// Arguments: [pti] - Thunk info, can be NULL for no validation
// [vp16] - 16-bit pointer
//
// Returns: BOOL - true for valid, false for invalid
//
// Modifies: [pti]->scResult for errors
//
// History: 22-Jul-92 BobDay Created
//
//----------------------------------------------------------------------------
BOOL IsValidInterface16( THUNKINFO *pti, VPVOID vp )
{
VPVOID UNALIGNED *pvpv;
VPVOID vpvtbl;
VPVOID vpfn;
LPVOID lpfn;
//
// Make sure we can read the vtbl pointer from the object.
//
pvpv = (VPVOID FAR *)GetReadPtr16(pti, vp, sizeof(VPVOID));
if ( pvpv == NULL )
{
thkDebugOut((DEB_WARN, "IsValidInterface16: "
"Interface ptr invalid %p\n", vp));
return FALSE;
}
vpvtbl = *pvpv; // Read the vtbl ptr
WOWRELVDMPTR(vp);
// Make sure we can read the first entry from the vtbl (QI)
pvpv = (VPVOID FAR *)GetReadPtr16(pti, vpvtbl, sizeof(VPVOID));
if ( pvpv == NULL )
{
thkDebugOut((DEB_WARN, "Vtbl ptr invalid %p:%p\n", vp, vpvtbl));
return FALSE;
}
vpfn = *pvpv; // Get the QI Function
WOWRELVDMPTR(vpvtbl);
if ( vpfn == 0 )
{
thkDebugOut((DEB_WARN, "QI function NULL %p:%p\n", vp, vpvtbl));
pti->scResult = E_INVALIDARG;
return FALSE;
}
// Why it has to be 9 bytes long, I have no idea.
// This check was taken from valid.cpp in
// \src\ole2\dll\src\debug the 16-bit ole2.01
// sources...
lpfn = (LPVOID)GetCodePtr16(pti, vpfn, 9);
WOWRELVDMPTR(vpfn);
if ( lpfn == NULL )
{
thkDebugOut((DEB_WARN, "QI function ptr invalid %p:%p:%p\n",
vp,vpvtbl,vpfn));
return FALSE;
}
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Function: GuidString, debug public
//
// Synopsis: Converts a guid to a string
//
// Arguments: [pguid] - GUID
//
// Returns: Pointer to string
//
// History: 08-Mar-94 DrewB Created
//
// Notes: Uses a static buffer
//
//----------------------------------------------------------------------------
#if DBG == 1
#pragma pack(1)
struct SplitGuid
{
DWORD dw1;
WORD w1;
WORD w2;
BYTE b[8];
};
#pragma pack()
char *GuidString(GUID const *pguid)
{
static char ach[39];
SplitGuid *psg = (SplitGuid *)pguid;
wsprintfA(ach, "{%08lX-%04hX-%04hX-%02X%02X-%02X%02X%02X%02X%02X%02X}",
psg->dw1, psg->w1, psg->w2, psg->b[0], psg->b[1], psg->b[2],
psg->b[3], psg->b[4], psg->b[5], psg->b[6], psg->b[7]);
return ach;
}
#endif
#if DBG == 1
char *apszThopNames[] =
{
"THOP_END",
"THOP_SHORTLONG",
"THOP_WORDDWORD",
"THOP_COPY",
"THOP_LPSTR",
"THOP_LPLPSTR",
"THOP_BUFFER",
"THOP_HUSER",
"THOP_HGDI",
"THOP_SIZE",
"THOP_RECT",
"THOP_MSG",
"THOP_HRESULT",
"THOP_STATSTG",
"THOP_DVTARGETDEVICE",
"THOP_STGMEDIUM",
"THOP_FORMATETC",
"THOP_HACCEL",
"THOP_OIFI",
"THOP_BINDOPTS",
"THOP_LOGPALETTE",
"THOP_SNB",
"THOP_CRGIID",
"THOP_OLESTREAM",
"THOP_HTASK",
"THOP_INTERFACEINFO",
"THOP_IFACE",
"THOP_IFACEOWNER",
"THOP_IFACENOADDREF",
"THOP_IFACECLEAN",
"THOP_IFACEGEN",
"THOP_IFACEGENOWNER",
"THOP_ROUTINEINDEX",
"THOP_RETURNTYPE",
"THOP_NULL",
"THOP_ERROR",
"THOP_ENUM",
"THOP_CALLBACK",
"THOP_RPCOLEMESSAGE",
"THOP_ALIAS32",
"THOP_CLSCONTEXT",
"THOP_FILENAME",
"THOP_SIZEDSTRING"
};
#endif
//+---------------------------------------------------------------------------
//
// Function: ThopName, debug public
//
// Synopsis: Returns the string name of a thop
//
// Arguments: [thop] - Thop
//
// Returns: Pointer to string
//
// History: 11-Mar-94 DrewB Created
//
// Notes: Uses a static buffer
//
//----------------------------------------------------------------------------
#if DBG == 1
char *ThopName(THOP thop)
{
static char achString[80];
char *psz;
thkAssert((thop & THOP_OPMASK) < THOP_LASTOP);
thkAssert(THOP_LASTOP ==
(sizeof(apszThopNames)/sizeof(apszThopNames[0])));
strcpy(achString, apszThopNames[thop & THOP_OPMASK]);
psz = achString+strlen(achString);
if (thop & THOP_IN)
{
strcpy(psz, " | THOP_IN");
psz += strlen(psz);
}
if (thop & THOP_OUT)
{
strcpy(psz, " | THOP_OUT");
}
return achString;
}
#endif
#if DBG == 1
char *apszEnumThopNames[] =
{
"STRING",
"UNKNOWN",
"STATSTG",
"FORMATETC",
"STATDATA",
"MONIKER",
"OLEVERB"
};
#endif
//+---------------------------------------------------------------------------
//
// Function: EnumThopName, debug public
//
// Synopsis: Returns the string name of an enum thop
//
// Arguments: [thopEnum] - Thop
//
// Returns: Pointer to string
//
// History: 11-Mar-94 DrewB Created
//
//----------------------------------------------------------------------------
#if DBG == 1
char *EnumThopName(THOP thopEnum)
{
thkAssert(thopEnum <
(sizeof(apszEnumThopNames)/sizeof(apszEnumThopNames[0])));
return apszEnumThopNames[thopEnum];
}
#endif
#if DBG == 1
// Maintain current thunking invocation nesting level
int _iThunkNestingLevel = 1;
#endif
//+---------------------------------------------------------------------------
//
// Function: NestingSpaces, debug public
//
// Synopsis: Spaces for each nesting level
//
// History: 22-Mar-94 DrewB Created
//
//----------------------------------------------------------------------------
#if DBG == 1
#define NESTING_SPACES 32
#define SPACES_PER_LEVEL 2
static char achSpaces[NESTING_SPACES+1] = " ";
void NestingSpaces(char *psz)
{
int iSpaces, i;
iSpaces = _iThunkNestingLevel*SPACES_PER_LEVEL;
while (iSpaces > 0)
{
i = min(iSpaces, NESTING_SPACES);
memcpy(psz, achSpaces, i);
psz += i;
*psz = 0;
iSpaces -= i;
}
}
#endif
//+---------------------------------------------------------------------------
//
// Function: NestingLevelString, debug public
//
// Synopsis: Provides a string describing the nesting level
//
// History: 22-Mar-94 DrewB Created
//
// Notes: Uses a static buffer
//
//----------------------------------------------------------------------------
#if DBG == 1
char *NestingLevelString(void)
{
static char ach[256];
char *psz;
if ((thkInfoLevel & DEB_NESTING) == 0)
{
return "";
}
wsprintfA(ach, "%2d:", _iThunkNestingLevel);
psz = ach+strlen(ach);
if (sizeof(ach)/SPACES_PER_LEVEL <= _iThunkNestingLevel)
{
strcpy(psz, "...");
}
else
{
NestingSpaces(psz);
}
return ach;
}
#endif
//+---------------------------------------------------------------------------
//
// Function: IidOrInterfaceString, debug public
//
// Synopsis: Returns the interface name for known interfaces or
// the IID string itself
//
// Arguments: [piid] - IID
//
// Returns: char *
//
// History: 18-Jun-94 DrewB Created
//
//----------------------------------------------------------------------------
#if DBG == 1
char *IidOrInterfaceString(IID const *piid)
{
return IidIdxString(IidToIidIdx(*piid));
}
#endif
//+---------------------------------------------------------------------------
//
// Function: IidIdxString, debug public
//
// Synopsis: Returns the interface name for known interfaces or
// the IID string itself
//
// Arguments: [iidx] - IID or index
//
// Returns: char *
//
// History: 07-Jul-94 DrewB Created
//
//----------------------------------------------------------------------------
#if DBG == 1
char *IidIdxString(IIDIDX iidx)
{
if (IIDIDX_IS_IID(iidx))
{
return GuidString(IIDIDX_IID(iidx));
}
else if (IIDIDX_INDEX(iidx) == THI_COUNT)
{
// Special case here because of IMalloc's unusual unthunked-
// but-indexed existence
return "IMalloc";
}
else
{
return inInterfaceNames[IIDIDX_INDEX(iidx)].pszInterface;
}
}
#endif
//+---------------------------------------------------------------------------
//
// Function: Handler routines, public
//
// Synopsis: Generic conversion routines for the generic thop handler
//
// Arguments: [pbFrom] - Data to convert from
// [pbTo] - Buffer to convert into
// [cbFrom] - Size of source data
// [cbTo] - Size of destination data
//
// History: 05-Apr-94 DrewB Created
//
//----------------------------------------------------------------------------
//+---------------------------------------------------------------------------
//
// Function: FhCopyMemory, public
//
// Synopsis: Handler routine for memory copies
//
// History: 05-Apr-94 DrewB Created
//
//----------------------------------------------------------------------------
void FhCopyMemory(BYTE *pbFrom, BYTE *pbTo, UINT cbFrom, UINT cbTo)
{
thkAssert(cbFrom == cbTo);
memcpy(pbTo, pbFrom, cbFrom);
#if DBG == 1
if (cbFrom == sizeof(DWORD))
{
thkDebugOut((DEB_ARGS, "Arg DWORD: 0x%08lX\n",
*(DWORD UNALIGNED *)pbFrom));
}
else if (cbFrom == sizeof(LARGE_INTEGER))
{
thkDebugOut((DEB_ARGS, "Arg 8 byte: 0x%08lX:%08lX\n",
*(DWORD UNALIGNED *)(pbFrom+1*sizeof(DWORD)),
*(DWORD UNALIGNED *)(pbFrom+0*sizeof(DWORD))));
}
else if (cbFrom == sizeof(GUID))
{
thkDebugOut((DEB_ARGS, "Arg 16 byte: 0x%08lX:%08lX:%08lX:%08lX\n",
*(DWORD UNALIGNED *)(pbFrom+3*sizeof(DWORD)),
*(DWORD UNALIGNED *)(pbFrom+2*sizeof(DWORD)),
*(DWORD UNALIGNED *)(pbFrom+1*sizeof(DWORD)),
*(DWORD UNALIGNED *)(pbFrom+0*sizeof(DWORD))));
}
else
{
thkDebugOut((DEB_ARGS, "Arg %d byte copy\n", cbFrom));
}
#endif
}
//+---------------------------------------------------------------------------
//
// Function: FhShortToLong, FhLongToShort, public
//
// Synopsis: Signed int conversion
//
// History: 05-Apr-94 DrewB Created
//
//----------------------------------------------------------------------------
void FhShortToLong(BYTE *pbFrom, BYTE *pbTo, UINT cbFrom, UINT cbTo)
{
thkAssert(cbFrom == sizeof(SHORT));
thkAssert(cbTo == sizeof(LONG));
*(LONG UNALIGNED *)pbTo = (LONG)*(SHORT UNALIGNED *)pbFrom;
thkDebugOut((DEB_ARGS, "ShToLo %d -> %d\n",
*(SHORT UNALIGNED *)pbFrom, *(LONG UNALIGNED *)pbTo));
}
void FhLongToShort(BYTE *pbFrom, BYTE *pbTo, UINT cbFrom, UINT cbTo)
{
thkAssert(cbFrom == sizeof(LONG));
thkAssert(cbTo == sizeof(SHORT));
// Not used in situations where clamping is meaningful
*(SHORT UNALIGNED *)pbTo = (SHORT)*(LONG UNALIGNED *)pbFrom;
thkDebugOut((DEB_ARGS, "LoToSh %d -> %d\n",
*(LONG UNALIGNED *)pbFrom, *(SHORT UNALIGNED *)pbTo));
}
//+---------------------------------------------------------------------------
//
// Function: FhWordToDword, FhDwordToWord, public
//
// Synopsis: Handler routine for memory copies
//
// History: 05-Apr-94 DrewB Created
//
//----------------------------------------------------------------------------
void FhWordToDword(BYTE *pbFrom, BYTE *pbTo, UINT cbFrom, UINT cbTo)
{
thkAssert(cbFrom == sizeof(WORD));
thkAssert(cbTo == sizeof(DWORD));
*(DWORD UNALIGNED *)pbTo = (DWORD)*(WORD UNALIGNED *)pbFrom;
thkDebugOut((DEB_ARGS, "WoToDw 0x%04lX -> 0x%08lX\n",
*(WORD UNALIGNED *)pbFrom, *(DWORD UNALIGNED *)pbTo));
}
void FhDwordToWord(BYTE *pbFrom, BYTE *pbTo, UINT cbFrom, UINT cbTo)
{
thkAssert(cbFrom == sizeof(DWORD));
thkAssert(cbTo == sizeof(WORD));
// Not used in situations where clamping is meaningful
*(WORD UNALIGNED *)pbTo = (WORD)*(DWORD UNALIGNED *)pbFrom;
thkDebugOut((DEB_ARGS, "DwToWo 0x%08lX -> 0x%04lX\n",
*(DWORD UNALIGNED *)pbFrom, *(WORD UNALIGNED *)pbTo));
}
//+---------------------------------------------------------------------------
//
// Function: Handle routines, public
//
// Synopsis: Handler routine for Windows handles
//
// History: 05-Apr-94 DrewB Created
//
//----------------------------------------------------------------------------
void FhGdiHandle1632(BYTE *pbFrom, BYTE *pbTo, UINT cbFrom, UINT cbTo)
{
thkAssert(cbFrom == sizeof(HAND16));
thkAssert(cbTo == sizeof(HANDLE));
*(HBITMAP *)pbTo = HBITMAP_32(*(HBITMAP16 UNALIGNED *)pbFrom);
thkDebugOut((DEB_ARGS, "1632 HGdi: 0x%04lX -> 0x%p\n",
*(HAND16 UNALIGNED *)pbFrom, *(HANDLE *)pbTo));
}
void FhGdiHandle3216(BYTE *pbFrom, BYTE *pbTo, UINT cbFrom, UINT cbTo)
{
thkAssert(cbFrom == sizeof(HANDLE));
thkAssert(cbTo == sizeof(HAND16));
*(HAND16 UNALIGNED *)pbTo = HBITMAP_16(*(HANDLE *)pbFrom);
thkDebugOut((DEB_ARGS, "3216 HGdi: 0x%p -> 0x%04lX\n",
*(HANDLE *)pbFrom, *(HAND16 UNALIGNED *)pbTo));
}
void FhUserHandle1632(BYTE *pbFrom, BYTE *pbTo, UINT cbFrom, UINT cbTo)
{
thkAssert(cbFrom == sizeof(HAND16));
thkAssert(cbTo == sizeof(HANDLE));
// Even though the constant is WOW_TYPE_FULLHWND, it
// works for any user handle
*(HANDLE *)pbTo = WOWHandle32(*(HAND16 UNALIGNED *)pbFrom,
WOW_TYPE_FULLHWND);
thkDebugOut((DEB_ARGS, "1632 HUser: 0x%04lX -> 0x%p\n",
*(HAND16 UNALIGNED *)pbFrom, *(HANDLE *)pbTo));
}
void FhUserHandle3216(BYTE *pbFrom, BYTE *pbTo, UINT cbFrom, UINT cbTo)
{
thkAssert(cbFrom == sizeof(HANDLE));
thkAssert(cbTo == sizeof(HAND16));
*(HAND16 UNALIGNED *)pbTo = HWND_16(*(HANDLE *)pbFrom);
thkDebugOut((DEB_ARGS, "3216 HUser: 0x%p -> 0x%04lX\n",
*(HANDLE *)pbFrom, *(HAND16 UNALIGNED *)pbTo));
}
void FhHaccel1632(BYTE *pbFrom, BYTE *pbTo, UINT cbFrom, UINT cbTo)
{
thkAssert(cbFrom == sizeof(HAND16));
thkAssert(cbTo == sizeof(HANDLE));
*(HANDLE *)pbTo = HACCEL_32(*(HAND16 UNALIGNED *)pbFrom);
thkDebugOut((DEB_ARGS, "1632 HACCEL: 0x%04lX -> 0x%p\n",
*(HAND16 UNALIGNED *)pbFrom, *(HANDLE *)pbTo));
}
void FhHaccel3216(BYTE *pbFrom, BYTE *pbTo, UINT cbFrom, UINT cbTo)
{
thkAssert(cbFrom == sizeof(HANDLE));
thkAssert(cbTo == sizeof(HAND16));
*(HAND16 UNALIGNED *)pbTo = HACCEL_16(*(HANDLE *)pbFrom);
thkDebugOut((DEB_ARGS, "3216 HACCEL: 0x%p -> 0x%04lX\n",
*(HANDLE *)pbFrom, *(HAND16 UNALIGNED *)pbTo));
}
void FhHtask1632(BYTE *pbFrom, BYTE *pbTo, UINT cbFrom, UINT cbTo)
{
HAND16 h16;
DWORD h32;
thkAssert(cbFrom == sizeof(HAND16));
thkAssert(cbTo == sizeof(HANDLE));
h16 = *(HAND16 UNALIGNED *)pbFrom;
if ( h16 == 0 )
{
h32 = 0;
}
else
{
h32 = HTASK_32(h16);
}
*(DWORD *)pbTo = h32;
thkDebugOut((DEB_ARGS, "1632 HTASK: 0x%04lX -> 0x%p\n", h16, h32));
}
void FhHtask3216(BYTE *pbFrom, BYTE *pbTo, UINT cbFrom, UINT cbTo)
{
HAND16 h16;
HANDLE h32;
thkAssert(cbFrom == sizeof(HANDLE));
thkAssert(cbTo == sizeof(HAND16));
h32 = *(HANDLE *)pbFrom;
if ( h32 == NULL )
{
h16 = 0;
}
else
{
h16 = HTASK_16(h32);
}
*(HAND16 UNALIGNED *)pbTo = h16;
thkDebugOut((DEB_ARGS, "3216 HTASK: 0x%p -> 0x%04lX\n",h32, h16));
}
//+---------------------------------------------------------------------------
//
// Function: HRESULT routines, public
//
// Synopsis: Handler routine for HRESULTs
//
// History: 05-Apr-94 DrewB Created
//
//----------------------------------------------------------------------------
void FhHresult1632(BYTE *pbFrom, BYTE *pbTo, UINT cbFrom, UINT cbTo)
{
thkAssert(cbFrom == sizeof(HRESULT));
thkAssert(cbTo == sizeof(HRESULT));
*(HRESULT *)pbTo = TransformHRESULT_1632(*(HRESULT UNALIGNED *)pbFrom);
thkDebugOut((DEB_ARGS, "1632 HRESULT: 0x%08lX -> 0x%08lX\n",
*(HRESULT UNALIGNED *)pbFrom, *(HRESULT *)pbTo));
}
void FhHresult3216(BYTE *pbFrom, BYTE *pbTo, UINT cbFrom, UINT cbTo)
{
thkAssert(cbFrom == sizeof(HRESULT));
thkAssert(cbTo == sizeof(HRESULT));
*(HRESULT UNALIGNED *)pbTo = TransformHRESULT_3216(*(HRESULT *)pbFrom);
thkDebugOut((DEB_ARGS, "3216 HRESULT: 0x%08lX -> 0x%08lX\n",
*(HRESULT *)pbFrom, *(HRESULT UNALIGNED *)pbTo));
}
//+---------------------------------------------------------------------------
//
// Function: NULL routines, public
//
// Synopsis: Handler routine for NULL
//
// History: 05-Apr-94 DrewB Created
//
//----------------------------------------------------------------------------
void FhNull(BYTE *pbFrom, BYTE *pbTo, UINT cbFrom, UINT cbTo)
{
thkAssert(cbFrom == sizeof(void *));
thkAssert(cbTo == sizeof(void *));
thkDebugOut((DEB_WARN, "FhNull: %p NULL value not NULL\n", pbFrom));
*(void UNALIGNED **)pbTo = NULL;
thkDebugOut((DEB_ARGS, "Arg NULL\n"));
}
//+---------------------------------------------------------------------------
//
// Function: Rect routines, public
//
// Synopsis: Handler routines for RECT
//
// History: 05-Apr-94 DrewB Created
//
//----------------------------------------------------------------------------
void FhRect1632(BYTE *pbFrom, BYTE *pbTo, UINT cbFrom, UINT cbTo)
{
RECT *pr32;
RECT16 UNALIGNED * pr16;
thkAssert(cbFrom == sizeof(RECT16));
thkAssert(cbTo == sizeof(RECT));
pr16 = (RECT16 UNALIGNED *)pbFrom;
pr32 = (RECT *)pbTo;
pr32->left = (LONG)pr16->left; // Sign extend
pr32->top = (LONG)pr16->top; // Sign extend
pr32->right = (LONG)pr16->right; // Sign extend
pr32->bottom = (LONG)pr16->bottom; // Sign extend
thkDebugOut((DEB_ARGS, "1632 RECT: {%d, %d, %d, %d}\n",
pr32->left, pr32->top, pr32->right, pr32->bottom));
}
void FhRect3216(BYTE *pbFrom, BYTE *pbTo, UINT cbFrom, UINT cbTo)
{
RECT *pr32;
RECT16 UNALIGNED *pr16;
thkAssert(cbFrom == sizeof(RECT));
thkAssert(cbTo == sizeof(RECT16));
pr32 = (RECT *)pbFrom;
pr16 = (RECT16 UNALIGNED *)pbTo;
pr16->left = ClampLongToShort(pr32->left);
pr16->top = ClampLongToShort(pr32->top);
pr16->right = ClampLongToShort(pr32->right);
pr16->bottom = ClampLongToShort(pr32->bottom);
thkDebugOut((DEB_ARGS, "3216 RECT: {%d, %d, %d, %d}\n",
pr32->left, pr32->top, pr32->right, pr32->bottom));
}
//+---------------------------------------------------------------------------
//
// Function: Size routines, public
//
// Synopsis: Handler routines for SIZE
//
// History: 05-Apr-94 DrewB Created
//
//----------------------------------------------------------------------------
void FhSize1632(BYTE *pbFrom, BYTE *pbTo, UINT cbFrom, UINT cbTo)
{
SIZE16 UNALIGNED *psize16;
SIZE *psize32;
thkAssert(cbFrom == sizeof(SIZE16));
thkAssert(cbTo == sizeof(SIZE));
psize16 = (SIZE16 UNALIGNED *)pbFrom;
psize32 = (SIZE *)pbTo;
psize32->cx = (LONG)psize16->cx;
psize32->cy = (LONG)psize16->cy;
thkDebugOut((DEB_ARGS, "1632 SIZE: {%d, %d}\n",
psize32->cx, psize32->cy));
}
void FhSize3216(BYTE *pbFrom, BYTE *pbTo, UINT cbFrom, UINT cbTo)
{
SIZE16 UNALIGNED *psize16;
SIZE *psize32;
thkAssert(cbFrom == sizeof(SIZE));
thkAssert(cbTo == sizeof(SIZE16));
psize32 = (SIZE *)pbFrom;
psize16 = (SIZE16 UNALIGNED *)pbTo;
psize16->cx = ClampLongToShort(psize32->cx);
psize16->cy = ClampLongToShort(psize32->cy);
thkDebugOut((DEB_ARGS, "3216 SIZE: {%d, %d}\n",
psize32->cx, psize32->cy));
}
//+---------------------------------------------------------------------------
//
// Function: Message routines, public
//
// Synopsis: Handler routines for MSG
//
// History: 05-Apr-94 DrewB Created
//
//----------------------------------------------------------------------------
void FhMsg1632(BYTE *pbFrom, BYTE *pbTo, UINT cbFrom, UINT cbTo)
{
MSG16 UNALIGNED *pmsg16;
MSG *pmsg32;
thkAssert(cbFrom == sizeof(MSG16));
thkAssert(cbTo == sizeof(MSG));
pmsg16 = (MSG16 UNALIGNED *)pbFrom;
pmsg32 = (MSG *)pbTo;
pmsg32->hwnd = HWND_32(pmsg16->hwnd);
pmsg32->message = (UINT)pmsg16->message;
pmsg32->wParam = (WPARAM)pmsg16->wParam; // Should we sign extend?
pmsg32->lParam = (LPARAM)pmsg16->lParam;
pmsg32->time = pmsg16->time;
pmsg32->pt.x = (LONG)(SHORT)LOWORD(pmsg16->pt); // Sign extend
pmsg32->pt.y = (LONG)(SHORT)HIWORD(pmsg16->pt); // Sign extend
thkDebugOut((DEB_ARGS, "1632 MSG: {0x%p, %d, 0x%08lX, 0x%08lX, "
"0x%08lX, {%d, %d}}\n",
pmsg32->hwnd, pmsg32->message, pmsg32->wParam,
pmsg32->lParam, pmsg32->time, pmsg32->pt.x,
pmsg32->pt.y));
}
void FhMsg3216(BYTE *pbFrom, BYTE *pbTo, UINT cbFrom, UINT cbTo)
{
MSG16 UNALIGNED *pmsg16;
MSG *pmsg32;
thkAssert(cbFrom == sizeof(MSG));
thkAssert(cbTo == sizeof(MSG16));
pmsg32 = (MSG *)pbFrom;
pmsg16 = (MSG16 UNALIGNED *)pbTo;
pmsg16->hwnd = HWND_16(pmsg32->hwnd);
pmsg16->message = (WORD)pmsg32->message;
pmsg16->wParam = (WORD)pmsg32->wParam; // Sign truncate
pmsg16->lParam = (LONG)pmsg32->lParam;
pmsg16->time = pmsg32->time;
pmsg16->pt = MAKELONG(ClampLongToShort(pmsg32->pt.x),
ClampLongToShort(pmsg32->pt.y));
thkDebugOut((DEB_ARGS, "3216 MSG: {0x%p, %d, 0x%08lX, 0x%08lX, "
"0x%08lX, {%d, %d}}\n",
pmsg32->hwnd, pmsg32->message, pmsg32->wParam,
pmsg32->lParam, pmsg32->time, pmsg32->pt.x,
pmsg32->pt.y));
}
//+---------------------------------------------------------------------------
//
// Function: ALLOCROUTINE, public
//
// Synopsis: A routine which allocates memory
//
// Arguments: [cb] - Amount to allocate
//
// Returns: Pointer to memory
//
// History: 19-Apr-94 DrewB Created
//
//----------------------------------------------------------------------------
//+---------------------------------------------------------------------------
//
// Function: FREEROUTINE, public
//
// Synopsis: A routine which frees memory
//
// Arguments: [pv] - Memory to free
// [cb] - Size of memory to free
//
// History: 19-Apr-94 DrewB Created
//
//----------------------------------------------------------------------------
void *ArTask16(UINT cb)
{
return (void *)TaskMalloc16(cb);
}
void FrTask16(void *pv, UINT cb)
{
TaskFree16((VPVOID)pv);
}
void *ArTask32(UINT cb)
{
return TaskMalloc32(cb);
}
void FrTask32(void *pv, UINT cb)
{
TaskFree32(pv);
}
void *ArStack16(UINT cb)
{
return (void *)STACKALLOC16(cb);
}
void FrStack16(void *pv, UINT cb)
{
STACKFREE16((VPVOID)pv, cb);
}
void *ArStack32(UINT cb)
{
// Can't use STACKALLOC32 on NT since it may be _alloca which wouldn't
// live beyond this routine
#ifdef _CHICAGO_
return STACKALLOC32(cb);
#else
return (void *)LocalAlloc(LMEM_FIXED, cb);
#endif
}
void FrStack32(void *pv, UINT cb)
{
#ifdef _CHICAGO_
STACKFREE32(pv, cb);
#else
LocalFree(pv);
#endif
}
//+---------------------------------------------------------------------------
//
// Function: ConvertDvtd1632, private
//
// Synopsis: Converts a DVTARGETDEVICE from 16 to 32-bits
//
// Arguments: [pti] - Thunking state information
// [vpdvtd16] - Source
// [pfnAlloc] - ALLOCROUTINE
// [pfnFree] - FREEROUTINE
// [ppdvtd32] - Destination
// [pcbSize] - Size return
//
// Returns: Appropriate status code
//
// Modifies: [ppdvtd32]
// [pcbSize]
//
// History: 18-Apr-94 DrewB Created
//
// Notes: [pfnAlloc/Free] must deal with 32-bit memory
//
//----------------------------------------------------------------------------
SCODE ConvertDvtd1632(THUNKINFO *pti,
VPVOID vpdvtd16,
ALLOCROUTINE pfnAlloc,
FREEROUTINE pfnFree,
DVTARGETDEVICE **ppdvtd32,
UINT *pcbSize)
{
DVTARGETDEVICE UNALIGNED *pdvtd16;
DVTARGETDEVICE *pdvtd32;
DVTDINFO dvtdi;
pdvtd16 = (DVTARGETDEVICE UNALIGNED *)GetReadPtr16(pti, vpdvtd16,
sizeof(DVTARGETDEVICE));
if (pdvtd16 == NULL)
{
return pti->scResult;
}
pdvtd16 = (DVTARGETDEVICE UNALIGNED *)GetReadPtr16(pti, vpdvtd16,
pdvtd16->tdSize);
WOWRELVDMPTR(vpdvtd16);
if (pdvtd16 == NULL)
{
return pti->scResult;
}
pti->scResult = UtGetDvtd16Info( pdvtd16, &dvtdi );
if ( FAILED(pti->scResult) )
{
WOWRELVDMPTR(vpdvtd16);
return pti->scResult;
}
pdvtd32 = (DVTARGETDEVICE *)pfnAlloc(dvtdi.cbConvertSize);
if (pdvtd32 == NULL)
{
WOWRELVDMPTR(vpdvtd16);
return E_OUTOFMEMORY;
}
pti->scResult = UtConvertDvtd16toDvtd32( pdvtd16, &dvtdi, pdvtd32 );
WOWRELVDMPTR(vpdvtd16);
if ( FAILED(pti->scResult) )
{
pfnFree(pdvtd32, dvtdi.cbConvertSize);
return pti->scResult;
}
*ppdvtd32 = pdvtd32;
*pcbSize = dvtdi.cbConvertSize;
return S_OK;
}
//+---------------------------------------------------------------------------
//
// Function: ConvertDvtd3216, private
//
// Synopsis: Converts a DVTARGETDEVICE from 32 to 16-bits
//
// Arguments: [pti] - Thunking state information
// [pdvtd32] - Source
// [pfnAlloc] - Allocator
// [pfnFree] - Freer
// [ppvdvtd16] - Destination
// [pcbSize] - Size return
//
// Returns: Appropriate status code
//
// Modifies: [ppvdvtd16]
// [pcbSize]
//
// History: 18-Apr-94 DrewB Created
//
// Notes: [pfnAlloc/Free] must deal with 16-bit memory
//
//----------------------------------------------------------------------------
SCODE ConvertDvtd3216(THUNKINFO *pti,
DVTARGETDEVICE *pdvtd32,
ALLOCROUTINE pfnAlloc,
FREEROUTINE pfnFree,
VPVOID *ppvdvtd16,
UINT *pcbSize)
{
DVTARGETDEVICE UNALIGNED *pdvtd16;
VPVOID vpdvtd16;
DVTDINFO dvtdi;
if (IsBadReadPtr(pdvtd32, sizeof(DVTARGETDEVICE)) ||
IsBadReadPtr(pdvtd32, pdvtd32->tdSize))
{
return E_INVALIDARG;
}
pti->scResult = UtGetDvtd32Info( pdvtd32, &dvtdi );
if ( FAILED(pti->scResult) )
{
return pti->scResult;
}
vpdvtd16 = (VPVOID)pfnAlloc(dvtdi.cbConvertSize);
if (vpdvtd16 == 0)
{
return E_OUTOFMEMORY;
}
pdvtd16 = (DVTARGETDEVICE UNALIGNED *)WOWFIXVDMPTR(vpdvtd16,
dvtdi.cbConvertSize);
pti->scResult = UtConvertDvtd32toDvtd16( pdvtd32, &dvtdi, pdvtd16 );
WOWRELVDMPTR(vpdvtd16);
if ( FAILED(pti->scResult) )
{
pfnFree((void *)vpdvtd16, dvtdi.cbConvertSize);
return pti->scResult;
}
*ppvdvtd16 = vpdvtd16;
*pcbSize = dvtdi.cbConvertSize;
return S_OK;
}
#if !defined(_CHICAGO_)
SCODE ConvertHDrop1632(HMEM16 hg16, HGLOBAL* phg32)
{
SCODE sc = S_OK;
*phg32 = CopyDropFilesFrom16(hg16);
if (!*phg32)
sc = E_INVALIDARG;
return sc;
}
SCODE ConvertHDrop3216(HGLOBAL hg32, HMEM16* phg16)
{
SCODE sc = S_OK;
*phg16 = CopyDropFilesFrom32(hg32);
if (!*phg16)
sc = E_INVALIDARG;
return sc;
}
#endif
//+---------------------------------------------------------------------------
//
// Function: ConvertHGlobal1632, public
//
// Synopsis: Creates a 32-bit HGLOBAL for a 16-bit HGLOBAL
//
// Arguments: [pti] - Thunk info, can be NULL for no validation
// [hg16] - 16-bit HGLOBAL
// [thopInOut] - Validation type
// [phg32] - 32-bit HGLOBAL in/out
// [pdwSize] - Size in/out
//
// Returns: Appropriate status code
//
// Modifies: [phg32]
// [pdwSize]
//
// History: 24-Apr-94 DrewB Created
//
// Notes: If [phg32] is non-NULL on entry, [pdwSize] must be set
// appropriately also
//
//----------------------------------------------------------------------------
SCODE ConvertHGlobal1632(THUNKINFO *pti,
HMEM16 hg16,
THOP thopInOut,
HGLOBAL *phg32,
DWORD *pdwSize)
{
SCODE sc;
VPVOID vpdata16;
LPVOID lpdata16;
LPVOID lpdata32;
HGLOBAL hg32;
DWORD dwSize;
BOOL fOwn;
sc = S_OK;
vpdata16 = WOWGlobalLockSize16( hg16, &dwSize );
if ( vpdata16 == 0 )
{
sc = E_INVALIDARG;
}
else
{
if (*phg32 != 0 && *pdwSize == dwSize)
{
hg32 = *phg32;
fOwn = FALSE;
}
else
{
hg32 = GlobalAlloc( GMEM_MOVEABLE, dwSize );
fOwn = TRUE;
}
if ( hg32 == 0 )
{
sc = E_OUTOFMEMORY;
}
else
{
lpdata32 = GlobalLock( hg32 );
lpdata16 = (LPVOID)ValidatePtr16(pti, vpdata16, dwSize, thopInOut);
if ( lpdata16 != NULL )
{
memcpy( lpdata32, lpdata16, dwSize );
WOWRELVDMPTR(vpdata16);
}
else
{
sc = pti->scResult;
}
GlobalUnlock(hg32);
if (FAILED(sc) && fOwn)
{
GlobalFree(hg32);
}
}
WOWGlobalUnlock16( hg16 );
}
if (SUCCEEDED(sc))
{
if (*phg32 != 0 && hg32 != *phg32)
{
GlobalFree(*phg32);
}
*phg32 = hg32;
*pdwSize = dwSize;
thkDebugOut((DEB_ARGS, "1632 HGLOBAL: 0x%04X -> 0x%p, %u\n",
hg16, hg32, dwSize));
}
return sc;
}
//+---------------------------------------------------------------------------
//
// Function: ConvertHGlobal3216, public
//
// Synopsis: Creates a 16-bit HGLOBAL for a 32-bit HGLOBAL
//
// Arguments: [pti] - Thunk info, can be NULL for no validation
// [hg32] - 32-bit HGLOBAL
// [thopInOut] - Validation type
// [phg16] - 16-bit HGLOBAL in/out
// [pdwSize] - Size in/out
//
// Returns: Appropriate status code
//
// Modifies: [phg16]
// [pdwSize]
//
// History: 24-Apr-94 DrewB Created
//
// Notes: If [phg16] is non-NULL on entry, [pdwSize] must be set
// appropriately also
//
//----------------------------------------------------------------------------
SCODE ConvertHGlobal3216(THUNKINFO *pti,
HGLOBAL hg32,
THOP thopInOut,
HMEM16 *phg16,
DWORD *pdwSize)
{
SCODE sc;
VPVOID vpdata16;
LPVOID lpdata16;
LPVOID lpdata32;
HMEM16 hg16;
DWORD dwSize;
BOOL fOwn;
sc = S_OK;
dwSize = GlobalSize(hg32);
if (dwSize == 0)
{
sc = E_INVALIDARG;
}
else
{
lpdata32 = GlobalLock(hg32);
if (*phg16 != 0 && *pdwSize == dwSize)
{
hg16 = *phg16;
vpdata16 = WOWGlobalLock16(hg16);
fOwn = FALSE;
}
else
{
vpdata16 = WOWGlobalAllocLock16(GMEM_MOVEABLE | GMEM_DDESHARE,
dwSize, &hg16);
fOwn = TRUE;
}
if (vpdata16 == 0)
{
sc = E_OUTOFMEMORY;
}
else
{
lpdata16 = (LPVOID)WOWFIXVDMPTR( vpdata16, dwSize );
if ( lpdata16 == NULL )
{
sc = E_UNEXPECTED;
}
else
{
memcpy( lpdata16, lpdata32, dwSize );
WOWRELVDMPTR(vpdata16);
}
WOWGlobalUnlock16( hg16 );
if (FAILED(sc) && fOwn)
{
WOWGlobalFree16(hg16);
}
}
GlobalUnlock(hg32);
}
if (SUCCEEDED(sc))
{
if (*phg16 != 0 && hg16 != *phg16)
{
WOWGlobalFree16(*phg16);
}
*phg16 = hg16;
*pdwSize = dwSize;
thkDebugOut((DEB_ARGS, "3216 HGLOBAL: 0x%p -> 0x%04X, %u\n",
hg32, hg16, dwSize));
}
return sc;
}
//+---------------------------------------------------------------------------
//
// Function: ConvertMfPict1632, public
//
// Synopsis: Converts a 16-bit METAFILEPICT to 32-bit
//
// Arguments: [pti] - Thunk info
// [hg16] - 16-bit HGLOBAL containing METAFILEPICT
// [phg32] - 32-bit HGLOBAL return
//
// Returns: Appropriate status code
//
// Modifies: [phg32]
//
// History: 24-Apr-94 DrewB Created
//
//----------------------------------------------------------------------------
SCODE ConvertMfPict1632(THUNKINFO *pti,
HMEM16 hg16,
HGLOBAL *phg32)
{
SCODE sc;
VPVOID vpmfp16;
METAFILEPICT16 UNALIGNED *pmfp16;
METAFILEPICT *pmfp32;
HGLOBAL hg32;
DWORD dwSize;
#if DBG == 1
BOOL fSaveToFile = FALSE;
#endif
thkDebugOut((DEB_ITRACE, "In ConvertMfPict1632(%p, 0x%04X, %p)\n",
pti, hg16, phg32));
*phg32 = 0;
sc = S_OK;
vpmfp16 = WOWGlobalLockSize16( hg16, &dwSize );
if ( vpmfp16 == 0 || dwSize < sizeof(METAFILEPICT16))
{
sc = E_INVALIDARG;
}
else
{
hg32 = GlobalAlloc( GMEM_MOVEABLE, sizeof(METAFILEPICT) );
if ( hg32 == 0 )
{
sc = E_OUTOFMEMORY;
}
else
{
pmfp32 = (METAFILEPICT *)GlobalLock( hg32 );
pmfp16 = (METAFILEPICT16 UNALIGNED *)GetReadPtr16(pti, vpmfp16,
dwSize);
if ( pmfp16 != NULL )
{
pmfp32->mm = (LONG)pmfp16->mm;
pmfp32->xExt = (LONG)pmfp16->xExt;
pmfp32->yExt = (LONG)pmfp16->yExt;
pmfp32->hMF = HMETAFILE_32(pmfp16->hMF);
thkDebugOut((DEB_ARGS, "1632 METAFILEPICT: "
"{%d, %d, %d, 0x%p} -> {%d, %d, %d, 0x%4x}\n",
pmfp16->mm, pmfp16->xExt, pmfp16->yExt, pmfp16->hMF,
pmfp32->mm, pmfp32->xExt, pmfp32->yExt, pmfp32->hMF));
WOWRELVDMPTR(vpmfp16);
#if DBG == 1
if (fSaveToFile)
{
HMETAFILE hmf;
hmf = CopyMetaFile(pmfp32->hMF, __TEXT("thkmf.wmf"));
if (hmf != NULL)
{
DeleteMetaFile(hmf);
}
}
#endif
}
else
{
sc = pti->scResult;
}
GlobalUnlock(hg32);
if (FAILED(sc))
{
GlobalFree(hg32);
}
}
WOWGlobalUnlock16( hg16 );
}
if (SUCCEEDED(sc))
{
*phg32 = hg32;
}
thkDebugOut((DEB_ITRACE, "Out ConvertMfPict1632 => 0x%08lX, 0x%p\n",
sc, *phg32));
return sc;
}
//+---------------------------------------------------------------------------
//
// Function: ConvertMfPict3216, public
//
// Synopsis: Converts a 32-bit METAFILEPICT to 16-bit
//
// Arguments: [pti] - Thunk info
// [hg32] - 32-bit HGLOBAL containing METAFILEPICT
// [phg16] - 16-bit HGLOBAL return
//
// Returns: Appropriate status code
//
// Modifies: [phg16]
//
// History: 24-Apr-94 DrewB Created
//
//----------------------------------------------------------------------------
SCODE ConvertMfPict3216(THUNKINFO *pti,
HGLOBAL hg32,
HMEM16 *phg16)
{
SCODE sc;
VPVOID vpmfp16;
METAFILEPICT16 UNALIGNED *pmfp16;
METAFILEPICT *pmfp32;
DWORD dwSize;
HMEM16 hg16;
#if DBG == 1
BOOL fSaveToFile = FALSE;
#endif
thkDebugOut((DEB_ITRACE, "In ConvertMfPict3216(%p, 0x%p, %p)\n",
pti, hg32, phg16));
*phg16 = 0;
sc = S_OK;
dwSize = GlobalSize(hg32);
pmfp32 = (METAFILEPICT *)GlobalLock(hg32);
if (dwSize == 0 || dwSize < sizeof(METAFILEPICT) || pmfp32 == NULL)
{
sc = E_INVALIDARG;
}
else
{
vpmfp16 = WOWGlobalAllocLock16(GMEM_MOVEABLE | GMEM_DDESHARE,
sizeof(METAFILEPICT16), &hg16);
if (vpmfp16 == 0)
{
sc = E_OUTOFMEMORY;
}
else
{
pmfp16 = FIXVDMPTR(vpmfp16, METAFILEPICT16);
if ( pmfp16 != NULL )
{
pmfp16->mm = (SHORT)pmfp32->mm;
pmfp16->xExt = ClampLongToShort(pmfp32->xExt);
pmfp16->yExt = ClampLongToShort(pmfp32->yExt);
pmfp16->hMF = HMETAFILE_16(pmfp32->hMF);
thkDebugOut((DEB_ARGS, "3216 METAFILEPICT: "
"{%d, %d, %d, 0x%p} -> {%d, %d, %d, 0x%4x}\n",
pmfp32->mm, pmfp32->xExt, pmfp32->yExt, pmfp32->hMF,
pmfp16->mm, pmfp16->xExt, pmfp16->yExt, pmfp16->hMF));
RELVDMPTR(vpmfp16);
#if DBG == 1
if (fSaveToFile)
{
HMETAFILE hmf;
hmf = CopyMetaFile(pmfp32->hMF, __TEXT("thkmf.wmf"));
if (hmf != NULL)
{
DeleteMetaFile(hmf);
}
}
#endif
}
else
{
sc = E_UNEXPECTED;
}
WOWGlobalUnlock16(hg16);
if (FAILED(sc))
{
WOWGlobalFree16(hg16);
}
}
GlobalUnlock(hg32);
}
if (SUCCEEDED(sc))
{
*phg16 = hg16;
}
thkDebugOut((DEB_ITRACE, "Out ConvertMfPict3216 => 0x%08lX, 0x%04X\n",
sc, *phg16));
return sc;
}
//+---------------------------------------------------------------------------
//
// Function: ConvertObjDesc1632, public
//
// Synopsis: Converts an OBJECTDESCRIPTOR structure
//
// Arguments: [pti] - THUNKINFO
// [hg16] - HGLOBAL containing structure
// [phg32] - Output HGLOBAL
//
// Returns: Appropriate status code
//
// Modifies: [phg32]
//
// History: 04-May-94 DrewB Created
//
//----------------------------------------------------------------------------
SCODE ConvertObjDesc1632(THUNKINFO *pti,
HMEM16 hg16,
HGLOBAL *phg32)
{
SCODE sc;
VPVOID vp16;
HGLOBAL hg32;
DWORD dwSize;
OBJECTDESCRIPTOR UNALIGNED *pod16;
OBJECTDESCRIPTOR *pod32;
char *pszFutn, *pszSoc;
UINT cchFutn, cchSoc;
UINT cbOffset;
sc = S_OK;
vp16 = WOWGlobalLock16(hg16);
if ( vp16 == 0 )
{
return E_INVALIDARG;
}
pszFutn = NULL;
pszSoc = NULL;
pod16 = (OBJECTDESCRIPTOR UNALIGNED *)
GetReadPtr16(pti, vp16, sizeof(OBJECTDESCRIPTOR));
if (pod16 == NULL)
{
sc = pti->scResult;
goto EH_Unlock;
}
dwSize = sizeof(OBJECTDESCRIPTOR);
if (pod16->dwFullUserTypeName > 0)
{
pszFutn = (char *)GetStringPtr16(pti, vp16+pod16->dwFullUserTypeName,
CCHMAXSTRING, &cchFutn);
if (pszFutn == NULL)
{
sc = pti->scResult;
goto EH_Unlock;
}
dwSize += cchFutn*sizeof(WCHAR);
}
if (pod16->dwSrcOfCopy > 0)
{
pszSoc = (char *)GetStringPtr16(pti, vp16+pod16->dwSrcOfCopy,
CCHMAXSTRING, &cchSoc);
if (pszSoc == NULL)
{
sc = pti->scResult;
goto EH_Unlock;
}
dwSize += cchSoc*sizeof(WCHAR);
}
hg32 = GlobalAlloc(GMEM_MOVEABLE, dwSize);
if ( hg32 == 0 )
{
sc = E_OUTOFMEMORY;
goto EH_Unlock;
}
pod32 = (OBJECTDESCRIPTOR *)GlobalLock(hg32);
memcpy(pod32, pod16, sizeof(OBJECTDESCRIPTOR));
pod32->cbSize = dwSize;
cbOffset = sizeof(OBJECTDESCRIPTOR);
if (pod16->dwFullUserTypeName > 0)
{
if (MultiByteToWideChar(AreFileApisANSI() ? CP_ACP : CP_OEMCP,
0, pszFutn, cchFutn,
(WCHAR *)((BYTE *)pod32+cbOffset),
cchFutn) == 0)
{
sc = E_UNEXPECTED;
goto EH_Free;
}
pod32->dwFullUserTypeName = cbOffset;
cbOffset += cchFutn*sizeof(WCHAR);
}
if (pod16->dwSrcOfCopy > 0)
{
if (MultiByteToWideChar(AreFileApisANSI() ? CP_ACP : CP_OEMCP,
0, pszSoc, cchSoc,
(WCHAR *)((BYTE *)pod32+cbOffset),
cchSoc) == 0)
{
sc = E_UNEXPECTED;
goto EH_Free;
}
pod32->dwSrcOfCopy = cbOffset;
cbOffset += cchFutn*sizeof(WCHAR);
}
#if DBG == 1
WCHAR *pwcsFutn, *pwcsSoc;
if (pod32->dwFullUserTypeName > 0)
{
pwcsFutn = (WCHAR *)((BYTE *)pod32+pod32->dwFullUserTypeName);
}
else
{
pwcsFutn = NULL;
}
if (pod32->dwSrcOfCopy > 0)
{
pwcsSoc = (WCHAR *)((BYTE *)pod32+pod32->dwSrcOfCopy);
}
else
{
pwcsSoc = NULL;
}
thkDebugOut((DEB_ARGS, "1632 OBJECTDESCRIPTOR: "
"{%d, ..., \"%ws\" (%s), \"%ws\" (%s)} %p -> %p\n",
pod32->cbSize, pwcsFutn, pszFutn, pwcsSoc, pszSoc,
vp16, pod32));
#endif
GlobalUnlock(hg32);
*phg32 = hg32;
EH_Unlock:
if (pszFutn != NULL)
{
WOWRELVDMPTR(vp16+pod16->dwFullUserTypeName);
}
if (pszSoc != NULL)
{
WOWRELVDMPTR(vp16+pod16->dwSrcOfCopy);
}
if (pod16 != NULL)
{
WOWRELVDMPTR(vp16);
}
WOWGlobalUnlock16(hg16);
return sc;
EH_Free:
GlobalUnlock(hg32);
GlobalFree(hg32);
goto EH_Unlock;
}
//+---------------------------------------------------------------------------
//
// Function: ConvertObjDesc3216, public
//
// Synopsis: Converts an OBJECTDESCRIPTOR structure
//
// Arguments: [pti] - THUNKINFO
// [hg32] - HGLOBAL containing structure
// [phg16] - Output HGLOBAL
//
// Returns: Appropriate status code
//
// Modifies: [phg16]
//
// History: 04-May-94 DrewB Created
//
//----------------------------------------------------------------------------
SCODE ConvertObjDesc3216(THUNKINFO *pti,
HGLOBAL hg32,
HMEM16 *phg16)
{
SCODE sc;
VPVOID vp16;
HMEM16 hg16;
DWORD dwSize;
OBJECTDESCRIPTOR UNALIGNED *pod16;
OBJECTDESCRIPTOR *pod32;
WCHAR *pwcsFutn, *pwcsSoc;
UINT cchFutn, cchSoc;
UINT cbOffset;
sc = S_OK;
pod32 = (OBJECTDESCRIPTOR *)GlobalLock(hg32);
if ( pod32 == 0 )
{
return E_INVALIDARG;
}
if (IsBadReadPtr(pod32, sizeof(OBJECTDESCRIPTOR)))
{
sc = E_INVALIDARG;
goto EH_Unlock;
}
dwSize = sizeof(OBJECTDESCRIPTOR);
pwcsFutn = NULL;
if (pod32->dwFullUserTypeName > 0)
{
pwcsFutn = (WCHAR *)((BYTE *)pod32+pod32->dwFullUserTypeName);
if (IsBadStringPtrW(pwcsFutn, CCHMAXSTRING))
{
sc = E_INVALIDARG;
goto EH_Unlock;
}
cchFutn = lstrlenW(pwcsFutn)+1;
dwSize += cchFutn*2;
}
pwcsSoc = NULL;
if (pod32->dwSrcOfCopy > 0)
{
pwcsSoc = (WCHAR *)((BYTE *)pod32+pod32->dwSrcOfCopy);
if (IsBadStringPtrW(pwcsSoc, CCHMAXSTRING))
{
sc = E_INVALIDARG;
goto EH_Unlock;
}
cchSoc = lstrlenW(pwcsSoc)+1;
dwSize += cchSoc*2;
}
vp16 = WOWGlobalAllocLock16(GMEM_MOVEABLE, dwSize, &hg16);
if ( vp16 == 0 )
{
sc = E_OUTOFMEMORY;
goto EH_Unlock;
}
pod16 = FIXVDMPTR(vp16, OBJECTDESCRIPTOR);
memcpy(pod16, pod32, sizeof(OBJECTDESCRIPTOR));
pod16->cbSize = dwSize;
cbOffset = sizeof(OBJECTDESCRIPTOR);
if (pod32->dwFullUserTypeName > 0)
{
if (WideCharToMultiByte(AreFileApisANSI() ? CP_ACP : CP_OEMCP,
0, pwcsFutn, cchFutn,
(char *)pod16+cbOffset, 2 * cchFutn,
NULL, NULL) == 0)
{
sc = E_UNEXPECTED;
goto EH_Free;
}
pod16->dwFullUserTypeName = cbOffset;
cbOffset += cchFutn*2;
}
if (pod32->dwSrcOfCopy > 0)
{
if (WideCharToMultiByte(AreFileApisANSI() ? CP_ACP : CP_OEMCP,
0, pwcsSoc, cchSoc,
(char *)pod16+cbOffset, 2 * cchSoc,
NULL, NULL) == 0)
{
sc = E_UNEXPECTED;
goto EH_Free;
}
pod16->dwSrcOfCopy = cbOffset;
cbOffset += cchFutn*2;
}
#if DBG == 1
char *pszFutn, *pszSoc;
if (pod16->dwFullUserTypeName > 0)
{
pszFutn = (char *)((BYTE *)pod16+pod16->dwFullUserTypeName);
}
else
{
pszFutn = NULL;
}
if (pod16->dwSrcOfCopy > 0)
{
pszSoc = (char *)((BYTE *)pod16+pod16->dwSrcOfCopy);
}
else
{
pszSoc = NULL;
}
thkDebugOut((DEB_ARGS, "3216 OBJECTDESCRIPTOR: "
"{%d, ..., \"%s\" (%ws), \"%s\" (%ws)} %p -> %p\n",
pod16->cbSize, pszFutn, pwcsFutn, pszSoc, pwcsSoc,
pod32, vp16));
#endif
RELVDMPTR(vp16);
WOWGlobalUnlock16(hg16);
*phg16 = hg16;
EH_Unlock:
GlobalUnlock(hg32);
return sc;
EH_Free:
WOWGlobalUnlockFree16(vp16);
goto EH_Unlock;
}
//+---------------------------------------------------------------------------
//
// Class: CSm32ReleaseHandler (srh)
//
// Purpose: Provides punkForRelease for 16->32 STGMEDIUM conversion
//
// Interface: IUnknown
//
// History: 24-Apr-94 DrewB Created
//
//----------------------------------------------------------------------------
class CSm32ReleaseHandler : public IUnknown
{
public:
CSm32ReleaseHandler(void)
{
_punkForRelease = NULL;
}
~CSm32ReleaseHandler(void)
{
// Clean up proxy if it hasn't already been released
if (_punkForRelease)
{
_pThkMgr->FreeProxy3216((VPVOID)_sm16.pUnkForRelease);
}
}
void Init(CThkMgr *pThkMgr,
STGMEDIUM UNALIGNED *psm16,
STGMEDIUM *psm32,
IUnknown *punkForRelease,
CLIPFORMAT cfFormat)
{
// Unfortunately, the MIPS compiler is not smart enough
// to do the right thing if we just declare psm16 as UNALIGNED -- it
// doesn't recognize that each member of the structure is also
// unaligned when it does the structure copy. So...to make
// sure we don't generate an alignment fault, we just copy each
// member of the structure directly.
_sm16.tymed = psm16->tymed;
_sm16.hGlobal = psm16->hGlobal;
_sm16.pUnkForRelease = psm16->pUnkForRelease;
_sm32 = *psm32;
_punkForRelease = punkForRelease;
_cReferences = 1;
_cfFormat = cfFormat;
_pThkMgr = pThkMgr;
}
STDMETHOD(QueryInterface)(REFIID riid, void **ppv)
{
if ( IsEqualIID(riid,IID_IUnknown) )
{
*ppv = this;
AddRef();
return NOERROR;
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
}
STDMETHOD_(ULONG, AddRef)(void)
{
return InterlockedIncrement(&_cReferences);
}
STDMETHOD_(ULONG, Release)(void);
private:
STGMEDIUM _sm16;
STGMEDIUM _sm32;
IUnknown *_punkForRelease;
CLIPFORMAT _cfFormat;
CThkMgr *_pThkMgr;
public:
LONG _cReferences;
};
//+---------------------------------------------------------------------------
//
// Member: CSm32ReleaseHandler::Release, public
//
// Synopsis: Frees resources for the 32-bit copy and then
// passes the ReleaseStgMedium on to 16-bits
//
// Returns: Ref count
//
// History: 24-Apr-94 DrewB Created
//
//----------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CSm32ReleaseHandler::Release(void)
{
STGMEDIUM UNALIGNED *psm16;
STGMEDIUM *psm32;
LONG lRet;
SCODE sc;
DWORD dwSize;
lRet = InterlockedDecrement(&_cReferences);
if (lRet != 0)
{
return lRet;
}
psm16 = &_sm16;
psm32 = &_sm32;
switch(psm32->tymed)
{
case TYMED_HGLOBAL:
// BUGBUG - Assumption that OBJECTDESCRIPTOR does not need copyback
if (!OBJDESC_CF(_cfFormat))
{
// BUGBUG - Do we ever need to do this?
// Is it valid to rely on the contents of the HGLOBAL
// at release time?
// BUGBUG - Is this the right time to copy back?
Assert(NULL != psm32->hGlobal);
WOWGlobalLockSize16((HMEM16)psm16->hGlobal, &dwSize);
WOWGlobalUnlock16((HMEM16)psm16->hGlobal);
sc = ConvertHGlobal3216(NULL, psm32->hGlobal, 0,
(HMEM16 *)&psm16->hGlobal, &dwSize);
// BUGBUG - What happens on errors?
thkAssert(SUCCEEDED(sc));
}
GlobalFree(psm32->hGlobal);
psm32->hGlobal = NULL;
break;
case TYMED_MFPICT:
// Chicago uses the same GDI handles for both 32bit and 16bit worlds.
// Don't delete the handle after a copy since Chicago doesn't actually
// copy the handle.
#if !defined(_CHICAGO_)
METAFILEPICT *pmfp32;
pmfp32 = (METAFILEPICT *)GlobalLock(psm32->hGlobal);
DeleteMetaFile(pmfp32->hMF);
GlobalUnlock(psm32->hGlobal);
#endif
GlobalFree(psm32->hGlobal);
break;
case TYMED_FILE:
// 32-bit handled by ReleaseStgMedium
// Clean up 16-bit ourselves
#ifdef SM_FREE_16BIT_FILENAME
// BUGBUG - 16-bit OLE did not free the filename, so we can't
// either. This may lead to memory leaks, but there's not
// really anything we can do about it
TaskFree16((VPVOID)psm16->lpszFileName);
#endif
break;
case TYMED_ISTREAM:
case TYMED_ISTORAGE:
// Handled by ReleaseStgMedium and thunked to 16-bits if necessary
break;
case TYMED_GDI:
case TYMED_NULL:
// Nothing to release
break;
default:
thkAssert(!"Unknown tymed in CSm32ReleaseHandler::Release");
break;
}
// Call 16-bit Release through proxy
((IUnknown *)_punkForRelease)->Release();
_punkForRelease = NULL;
// Clean up this
delete this;
return 0;
}
//+---------------------------------------------------------------------------
//
// Member: CSm16ReleaseHandler::Init, public
//
// Synopsis: Initialize class
//
// Arguments: [psm32] - 32-bit STGMEDIUM
// [psm16] - 16-bit STGMEDIUM
// [vpvUnkForRelease] - Object for punkForRelease
// [cfFormat] - Clipboard format associated with STGMEDIUM
//
// History: 24-Apr-94 DrewB Created
//
//----------------------------------------------------------------------------
void CSm16ReleaseHandler::Init(IUnknown *pThkMgr,
STGMEDIUM *psm32,
STGMEDIUM UNALIGNED *psm16,
VPVOID vpvUnkForRelease,
CLIPFORMAT cfFormat)
{
_avpfnVtbl = gdata16Data.avpfnSm16ReleaseHandlerVtbl;
_sm32 = *psm32;
// Unfortunately, the MIPS compiler is not smart enough
// to do the right thing if we just (ony) declare psm16 as UNALIGNED,
// it doesn't recognize that each member of the structure is also
// unaligned when it does the structure copy. So...to make
// sure we don't generate an alignment fault, we just copy each
// member of the structure directly.
_sm16.tymed = psm16->tymed;
_sm16.hGlobal = psm16->hGlobal;
_sm16.pUnkForRelease = psm16->pUnkForRelease;
_vpvUnkForRelease = vpvUnkForRelease;
_cReferences = 1;
_cfFormat = cfFormat;
_pUnkThkMgr = pThkMgr;
}
//+---------------------------------------------------------------------------
//
// Member: CSm16ReleaseHandler::Uninit, public
//
// Synopsis: Uninitialize class
//
// History: 25-Apr-94 DrewB Created
//
// Notes: For cleanup without use only; do not call after
// the release handler has actually executed Release
//
//----------------------------------------------------------------------------
void CSm16ReleaseHandler::Uninit(void)
{
((CThkMgr *)_pUnkThkMgr)->FreeProxy1632(_sm32.pUnkForRelease);
}
//+---------------------------------------------------------------------------
//
// Function: CSm16ReleaseHandler_Release32, public
//
// Synopsis: Handles 32-bit portion of cleaning up STGMEDIUMs for
// punkForRelease
//
// Arguments: [psrh] - this
// [dw1]
// [dw2]
//
// Returns: punkForRelease->Release()
//
// History: 24-Apr-94 DrewB Created
//
//----------------------------------------------------------------------------
STDAPI_(DWORD) CSm16ReleaseHandler_Release32(CSm16ReleaseHandler *psrh,
DWORD dw1,
DWORD dw2)
{
STGMEDIUM UNALIGNED *psm16;
STGMEDIUM *psm32;
DWORD dwSize;
SCODE sc;
psm16 = &psrh->_sm16;
psm32 = &psrh->_sm32;
switch(psm32->tymed)
{
case TYMED_FILE:
// 16-bit code cleaned up the 16-bit name,
// now clean up the 32-bit name
TaskFree32(psm32->lpszFileName);
break;
case TYMED_HGLOBAL:
// BUGBUG - Assumption that OBJECTDESCRIPTOR does not need copyback
if (!OBJDESC_CF(psrh->_cfFormat))
{
// BUGBUG - Do we ever need to do this?
// Copy data back and free global memory
dwSize = GlobalSize(psm32->hGlobal);
sc = ConvertHGlobal1632(NULL, (HMEM16)psm16->hGlobal, 0,
&psm32->hGlobal, &dwSize);
// BUGBUG - What happens on errors?
thkAssert(SUCCEEDED(sc));
}
WOWGlobalFree16((HMEM16)psm16->hGlobal);
break;
case TYMED_MFPICT:
// Untouched in this case
break;
case TYMED_ISTREAM:
case TYMED_ISTORAGE:
// Handled by ReleaseStgMedium and thunked to 32-bits if necessary
break;
case TYMED_GDI:
case TYMED_NULL:
// Nothing to release
break;
default:
thkAssert(!"Unknown tymed in ReleaseStgMedium32");
break;
}
return 0;
}
//+---------------------------------------------------------------------------
//
// Function: ConvertStgMed1632, public
//
// Synopsis: Converts a 16-bit STGMEDIUM to 32-bits
//
// Arguments: [pti] - Thunk info
// [vpsm16] - VDM pointer to 16-bit STGMEDIUM
// [psm32] - 32-bit STGMEDIUM to fill in
// [pfe] - FORMATETC paired with STGMEDIUM or NULL
// [pdwSize] - Size return
//
// Returns: Appropriate status code
//
// Modifies: [pdwSize]
//
// History: 24-Apr-94 DrewB Created
//
// Notes: [pdwSize] is only set for TYMED_HGLOBAL
//
//----------------------------------------------------------------------------
SCODE ConvertStgMed1632(THUNKINFO *pti,
VPVOID vpsm16,
STGMEDIUM *psm32,
FORMATETC *pfe,
BOOL fPassingOwnershipIn,
DWORD *pdwSize)
{
SCODE sc;
STGMEDIUM UNALIGNED *psm16;
CSm32ReleaseHandler *psrh;
IUnknown *punkForRelease;
VPVOID vpvUnk;
HMEM16 hmem16;
HGDIOBJ hGDI = NULL;
THKSTATE thkstateSaved;
psm16 = (STGMEDIUM UNALIGNED *)
GetReadPtr16(pti, vpsm16, sizeof(STGMEDIUM));
if (psm16 == NULL)
{
return pti->scResult;
}
sc = S_OK;
psm32->tymed = psm16->tymed;
vpvUnk = (VPVOID)psm16->pUnkForRelease;
WOWRELVDMPTR(vpsm16);
if (vpvUnk != 0)
{
// If the storageMedium includes a pUnk and we are passing
// ownership via an [in] parameter. Then we need to build
// a proxy with a "real" (rather than "local") reference.
// Here we trick "FindProxy3216" into believing it
// is building an [out] parameter
thkstateSaved = pti->pThkMgr->GetThkState();
if(fPassingOwnershipIn)
{
pti->pThkMgr->SetThkState(THKSTATE_INVOKETHKOUT32);
}
punkForRelease = pti->pThkMgr->FindProxy3216(NULL,
vpvUnk,
INDEX_IIDIDX(THI_IUnknown),
NULL);
pti->pThkMgr->SetThkState(thkstateSaved);
if (punkForRelease == NULL)
{
return E_OUTOFMEMORY;
}
psrh = new CSm32ReleaseHandler;
if (psrh == NULL)
{
pti->pThkMgr->FreeProxy3216(vpvUnk);
return E_OUTOFMEMORY;
}
}
else
{
psrh = NULL;
}
psm32->pUnkForRelease = psrh;
psm16 = FIXVDMPTR(vpsm16, STGMEDIUM);
// Word 6 insists on treating BITMAPs as HGLOBALS, which is bogus.
// If this is the case, just patch the tymed to the correct value
if (pfe != NULL)
{
if( (pfe->cfFormat == CF_BITMAP || pfe->cfFormat == CF_PALETTE ) &&
psm16->tymed == TYMED_HGLOBAL )
{
DWORD dw = TlsThkGetAppCompatFlags();
// if we are in Word 6, then hack the tymed so we thunk the
// bitmaps as GDI objects
if( (dw & OACF_USEGDI ) )
{
DWORD dwType;
hGDI = HBITMAP_32((HBITMAP16)psm16->hBitmap);
// make sure HGDI is either a bitmap or palette
dwType = GetObjectType(hGDI);
if( (pfe->cfFormat == CF_BITMAP && dwType == OBJ_BITMAP) ||
(pfe->cfFormat == CF_PALETTE && dwType == OBJ_PAL) )
{
psm16->tymed = TYMED_GDI;
}
else
{
thkDebugOut((DEB_WARN,
"WARNING! invalid bitmap or palette!\n"));
hGDI = NULL;
}
}
else
{
thkDebugOut((DEB_WARN, "WARNING! App trying to transfer a "
"bitmap or palette on an HGLOBAL\n"));
}
}
}
switch( psm16->tymed )
{
case TYMED_HGLOBAL:
hmem16 = (HMEM16)psm16->hGlobal;
RELVDMPTR(vpsm16);
if (pfe && OBJDESC_CF(pfe->cfFormat))
{
sc = ConvertObjDesc1632(pti, hmem16, &psm32->hGlobal);
}
#if !defined(_CHICAGO_)
else if (pfe && pfe->cfFormat == CF_HDROP)
{
// fix for mapi forms
// thunk CF_HDROP passed as HGLOBAL format
sc = ConvertHDrop1632(hmem16, &psm32->hGlobal);
}
#endif
else
{
psm32->hGlobal = 0;
sc = ConvertHGlobal1632(pti, hmem16, THOP_INOUT,
&psm32->hGlobal, pdwSize);
}
break;
case TYMED_MFPICT:
hmem16 = (HMEM16)psm16->hGlobal;
RELVDMPTR(vpsm16);
sc = ConvertMfPict1632(pti, hmem16, &psm32->hGlobal);
break;
case TYMED_FILE:
psm32->lpszFileName =
Convert_VPSTR_to_LPOLESTR( pti,
(VPVOID)psm16->lpszFileName,
NULL, 0 );
if (psm32->lpszFileName == NULL)
{
sc = pti->scResult;
}
else
{
#if DBG == 1
thkDebugOut((DEB_ARGS, "1632 TYMED_FILE: '%ws' (%s)\n",
psm32->lpszFileName,
WOWFIXVDMPTR((VPVOID)psm16->lpszFileName, 0)));
WOWRELVDMPTR((VPVOID)psm16->lpszFileName);
#endif
}
RELVDMPTR(vpsm16);
break;
case TYMED_ISTREAM:
vpvUnk = (VPVOID)psm16->pstm;
RELVDMPTR(vpsm16);
psm32->pstm =
(LPSTREAM)pti->pThkMgr->FindProxy3216(NULL, vpvUnk,
INDEX_IIDIDX(THI_IStream),
NULL);
if (psm32->pstm == NULL)
{
sc = E_OUTOFMEMORY;
}
else
{
thkDebugOut((DEB_ARGS, "1632 TYMED_ISTREAM: %p -> %p\n",
vpvUnk, psm32->pstm));
}
break;
case TYMED_ISTORAGE:
vpvUnk = (VPVOID)psm16->pstm;
RELVDMPTR(vpsm16);
psm32->pstg =
(LPSTORAGE)pti->pThkMgr->FindProxy3216(NULL, vpvUnk,
INDEX_IIDIDX(THI_IStorage),
NULL);
if (psm32->pstg == NULL)
{
sc = E_OUTOFMEMORY;
}
else
{
thkDebugOut((DEB_ARGS, "1632 TYMED_ISTORAGE: %p -> %p\n",
vpvUnk, psm32->pstg));
}
break;
case TYMED_GDI:
// if we're in Word6, then we may have already converted the bitmap
// or palette handle
if( hGDI == NULL )
{
psm32->hBitmap = HBITMAP_32((HBITMAP16)psm16->hBitmap);
}
else
{
psm32->hBitmap = (HBITMAP)hGDI;
}
thkDebugOut((DEB_ARGS, "1632 TYMED_GDI: 0x%04X -> 0x%p\n",
psm16->hBitmap, psm32->hBitmap));
RELVDMPTR(vpsm16);
break;
case TYMED_NULL:
RELVDMPTR(vpsm16);
break;
default:
RELVDMPTR(vpsm16);
sc = E_INVALIDARG;
break;
}
if (FAILED(sc))
{
delete psrh;
}
else
{
if (psrh)
{
CLIPFORMAT cf;
if (pfe)
{
cf = pfe->cfFormat;
}
else
{
cf = CF_INVALID;
}
psrh->Init(pti->pThkMgr, FIXVDMPTR(vpsm16, STGMEDIUM), psm32,
punkForRelease, cf);
RELVDMPTR(vpsm16);
}
#if DBG == 1
if (pfe)
{
thkDebugOut((DEB_ARGS, "1632 STGMEDIUM FORMATETC %p {%d}\n",
pfe, pfe->cfFormat));
}
thkDebugOut((DEB_ARGS, "1632 STGMEDIUM: %p {%d, %p, ...} -> "
"%p {%d, %p, ...}\n", vpsm16, psm16->tymed,
psm16->pUnkForRelease, psm32, psm32->tymed,
psm32->pUnkForRelease));
#endif
}
return sc;
}
//+---------------------------------------------------------------------------
//
// Function: CleanStgMed32, public
//
// Synopsis: Cleans up a 32-bit STGMEDIUM
//
// Arguments: [pti] - Thunk info
// [psm32] - STGMEDIUM to clean
// [vpsm16] - Source STGMEDIUM if thunk
// [dwSize] - Source size if thunk
// [fIsThunk] - STGMEDIUM was generated by thunking
// [pfe] - FORMATETC or NULL
//
// Returns: Appropriate status code
//
// History: 24-Apr-94 DrewB Created
//
//----------------------------------------------------------------------------
SCODE CleanStgMed32(THUNKINFO *pti,
STGMEDIUM *psm32,
VPVOID vpsm16,
DWORD dwSize,
BOOL fIsThunk,
FORMATETC *pfe)
{
SCODE sc;
STGMEDIUM UNALIGNED *psm16;
HMEM16 hmem16;
VPVOID vpvUnk;
BOOL bNoRefs=TRUE;
thkDebugOut((DEB_ITRACE, "In CleanStgMed32(%p, %p, %p, %u, %d, %p)\n",
pti, psm32, vpsm16, dwSize, fIsThunk, pfe));
sc = S_OK;
if (fIsThunk && (NULL!=psm32->pUnkForRelease) )
{
CSm32ReleaseHandler* psm32rh = (CSm32ReleaseHandler*)psm32->pUnkForRelease;
// When the StgMed is a Thunk and we have a pUnkForRelease:
//
// Only the remote end is expected to call the last Release() of
// the ReleaseHandler. We normally have the last reference here
// so just "delete" the ReleaseHandler and release everything.
//
// But... in the Async OnDataChange() if the remote call hasn't
// completed yet the system will be holding a reference so we need to
// release our reference but not free any non-reference counted objects
// below. Sm32ReleaseHandler->Release() will be called when the
// remote side call completes and Release() is called on the
// pUnkForRelease. And that will clean up.
if(1 == psm32rh->_cReferences)
{
delete psm32rh;
bNoRefs = TRUE;
}
else
{
psm32rh->Release();
bNoRefs = FALSE;
}
psm32->pUnkForRelease = NULL;
}
switch( psm32->tymed )
{
case TYMED_HGLOBAL:
if (bNoRefs)
{
if (fIsThunk &&
(pfe == NULL || !OBJDESC_CF(pfe->cfFormat)))
{
psm16 = FIXVDMPTR(vpsm16, STGMEDIUM);
hmem16 = (HMEM16)psm16->hGlobal;
RELVDMPTR(vpsm16);
Assert(NULL != psm32->hGlobal);
sc = ConvertHGlobal3216(pti, psm32->hGlobal, 0,
&hmem16, &dwSize);
psm16 = FIXVDMPTR(vpsm16, STGMEDIUM);
psm16->hGlobal = (HGLOBAL)hmem16;
RELVDMPTR(vpsm16);
}
GlobalFree( psm32->hGlobal );
psm32->hGlobal = NULL;
}
break;
case TYMED_MFPICT:
if (bNoRefs)
{
// Chicago uses the same GDI handles for both 32bit and 16bit worlds.
// Don't delete the handle after a copy since Chicago doesn't actually
// copy the handle.
#if !defined(_CHICAGO_)
// Can't modify an MFPICT
METAFILEPICT *pmfp32;
pmfp32 = (METAFILEPICT *)GlobalLock(psm32->hGlobal);
DeleteMetaFile(pmfp32->hMF);
GlobalUnlock(psm32->hGlobal);
#endif
GlobalFree(psm32->hGlobal);
}
break;
case TYMED_FILE:
if (bNoRefs)
{
Convert_VPSTR_to_LPOLESTR_free( NULL, psm32->lpszFileName );
}
break;
case TYMED_ISTREAM:
if (fIsThunk)
{
psm16 = FIXVDMPTR(vpsm16, STGMEDIUM);
vpvUnk = (VPVOID)psm16->pstm;
RELVDMPTR(vpsm16);
pti->pThkMgr->FreeProxy3216(vpvUnk);
}
break;
case TYMED_ISTORAGE:
if (fIsThunk)
{
psm16 = FIXVDMPTR(vpsm16, STGMEDIUM);
vpvUnk = (VPVOID)psm16->pstg;
RELVDMPTR(vpsm16);
pti->pThkMgr->FreeProxy3216(vpvUnk);
}
break;
case TYMED_GDI:
//
// No unthunking needed
//
break;
case TYMED_NULL:
break;
default:
// Ignore, this case is handled on input
thkAssert(!"STGMEDIUM with invalid tymed");
break;
}
thkDebugOut((DEB_ITRACE, "Out CleanStgMed32 => 0x%08lX\n", sc));
return sc;
}
//+---------------------------------------------------------------------------
//
// Function: ConvertStgMed3216, public
//
// Synopsis: Converts a 32-bit STGMEDIUM to 16-bits
//
// Arguments: [pti] - Thunk info
// [psm32] - 32-bit STGMEDIUM
// [vpsm16] - VDM pointer to 16-bit STGMEDIUM
// [pfe] - FORMATETC paired with STGMEDIUM or NULL
// [pdwSize] - Size return
//
// Returns: Appropriate status code
//
// Modifies: [pdwSize]
//
// History: 24-Apr-94 DrewB Created
//
// Notes: [pdwSize] is only set for TYMED_HGLOBAL
//
//----------------------------------------------------------------------------
SCODE ConvertStgMed3216(THUNKINFO *pti,
STGMEDIUM *psm32,
VPVOID vpsm16,
FORMATETC *pfe,
BOOL fPassingOwnershipIn,
DWORD *pdwSize)
{
SCODE sc;
STGMEDIUM UNALIGNED *psm16;
VPVOID vpsrh;
VPSTR vpstr;
UINT uiSize;
VPVOID vpvUnkForRelease;
VPVOID vpvUnk;
HMEM16 hmem16;
THKSTATE thkstateSaved;
sc = S_OK;
if (psm32->pUnkForRelease != NULL)
{
// If the storageMedium includes a pUnk and we are passing
// ownership via an [in] parameter. Then we need to build
// a proxy with a "real" (rather than "local") reference.
// Here we trick "FindProxy1632" into believing it
// is building an [out] parameter
thkstateSaved = pti->pThkMgr->GetThkState();
if(fPassingOwnershipIn)
pti->pThkMgr->SetThkState(THKSTATE_INVOKETHKOUT16);
vpvUnkForRelease = pti->pThkMgr->FindProxy1632(NULL,
psm32->pUnkForRelease,
INDEX_IIDIDX(THI_IUnknown),
NULL);
pti->pThkMgr->SetThkState(thkstateSaved);
if (vpvUnkForRelease == 0)
{
return E_OUTOFMEMORY;
}
vpsrh = WOWGlobalAllocLock16(GMEM_MOVEABLE,
sizeof(CSm16ReleaseHandler),
NULL);
if (vpsrh == 0)
{
pti->pThkMgr->FreeProxy1632(psm32->pUnkForRelease);
return E_OUTOFMEMORY;
}
}
else
{
vpsrh = 0;
}
psm16 = FIXVDMPTR(vpsm16, STGMEDIUM);
psm16->tymed = psm32->tymed;
psm16->pUnkForRelease = (IUnknown *)vpsrh;
RELVDMPTR(vpsm16);
switch( psm32->tymed )
{
case TYMED_HGLOBAL:
if (pfe && OBJDESC_CF(pfe->cfFormat))
{
sc = ConvertObjDesc3216(pti, psm32->hGlobal, &hmem16);
}
#if !defined(_CHICAGO_)
else if (pfe && pfe->cfFormat == CF_HDROP)
{
// fix for mapi forms
sc = ConvertHDrop3216(psm32->hGlobal, &hmem16);
}
#endif
else
{
hmem16 = 0;
sc = ConvertHGlobal3216(pti, psm32->hGlobal, THOP_INOUT,
&hmem16, pdwSize);
}
psm16 = FIXVDMPTR(vpsm16, STGMEDIUM);
psm16->hGlobal = (HGLOBAL)hmem16;
RELVDMPTR(vpsm16);
break;
case TYMED_MFPICT:
sc = ConvertMfPict3216(pti, psm32->hGlobal, &hmem16);
psm16 = FIXVDMPTR(vpsm16, STGMEDIUM);
psm16->hGlobal = (HGLOBAL)hmem16;
RELVDMPTR(vpsm16);
break;
case TYMED_FILE:
uiSize = lstrlenW(psm32->lpszFileName) + 1;
vpstr = TaskMalloc16( uiSize*2 );
if ( vpstr == NULL )
{
sc = E_OUTOFMEMORY;
}
else
{
sc = Convert_LPOLESTR_to_VPSTR( psm32->lpszFileName,
vpstr, uiSize, uiSize*2 );
if (FAILED(sc))
{
TaskFree16(vpstr);
}
else
{
psm16 = FIXVDMPTR(vpsm16, STGMEDIUM);
psm16->lpszFileName = (LPOLESTR)vpstr;
RELVDMPTR(vpsm16);
#if DBG == 1
thkDebugOut((DEB_ARGS, "3216 TYMED_FILE: '%s' (%ws)\n",
WOWFIXVDMPTR(vpstr, 0),
psm32->lpszFileName));
WOWRELVDMPTR(vpstr);
#endif
}
}
break;
case TYMED_ISTREAM:
vpvUnk = pti->pThkMgr->FindProxy1632(NULL, psm32->pstm,
INDEX_IIDIDX(THI_IStream),
NULL);
if (vpvUnk == 0)
{
sc = E_OUTOFMEMORY;
}
else
{
thkDebugOut((DEB_ARGS, "3216 TYMED_ISTREAM: %p -> %p\n",
psm32->pstm, vpvUnk));
psm16 = FIXVDMPTR(vpsm16, STGMEDIUM);
psm16->pstm = (IStream *)vpvUnk;
RELVDMPTR(vpsm16);
}
break;
case TYMED_ISTORAGE:
vpvUnk = pti->pThkMgr->FindProxy1632(NULL, psm32->pstg,
INDEX_IIDIDX(THI_IStorage),
NULL);
if (vpvUnk == 0)
{
sc = E_OUTOFMEMORY;
}
else
{
thkDebugOut((DEB_ARGS, "3216 TYMED_ISTORAGE: %p -> %p\n",
psm32->pstg, vpvUnk));
psm16 = FIXVDMPTR(vpsm16, STGMEDIUM);
psm16->pstg = (IStorage *)vpvUnk;
RELVDMPTR(vpsm16);
}
break;
case TYMED_GDI:
psm16 = FIXVDMPTR(vpsm16, STGMEDIUM);
psm16->hBitmap = (HBITMAP)HBITMAP_16(psm32->hBitmap);
thkDebugOut((DEB_ARGS, "3216 TYMED_GDI: 0x%p -> 0x%04X\n",
psm32->hBitmap, psm16->hBitmap));
RELVDMPTR(vpsm16);
break;
case TYMED_NULL:
break;
default:
sc = E_INVALIDARG;
break;
}
if (FAILED(sc))
{
if (vpsrh != 0)
{
pti->pThkMgr->FreeProxy1632(psm32->pUnkForRelease);
WOWGlobalUnlockFree16(vpsrh);
}
}
else
{
if (vpsrh != 0)
{
CSm16ReleaseHandler UNALIGNED *psrh;
CLIPFORMAT cf;
if (pfe)
{
cf = pfe->cfFormat;
}
else
{
cf = CF_INVALID;
}
psrh = FIXVDMPTR(vpsrh, CSm16ReleaseHandler);
psrh->Init(pti->pThkMgr, psm32, FIXVDMPTR(vpsm16, STGMEDIUM),
vpvUnkForRelease, cf);
RELVDMPTR(vpsrh);
RELVDMPTR(vpsm16);
}
#if DBG == 1
if (pfe)
{
thkDebugOut((DEB_ARGS, "3216 STGMEDIUM FORMATETC %p {%d}\n",
pfe, pfe->cfFormat));
}
thkDebugOut((DEB_ARGS, "3216 STGMEDIUM: %p {%d, %p, ...} -> "
"%p {%d, %p, ...}\n", psm32, psm32->tymed,
psm32->pUnkForRelease, vpsm16, psm16->tymed,
psm16->pUnkForRelease));
#endif
}
return sc;
}
//+---------------------------------------------------------------------------
//
// Function: CleanStgMed16, public
//
// Synopsis: Frees up resources in a 16-bit STGMEDIUM
//
// Arguments: [pti] - Thunk info
// [vpsm16] - STGMEDIUM to clean
// [psm32] - Source STGMEDIUM if thunk
// [dwSize] - Source size for thunked HGLOBAL
// [fIsThunk] - If the STGMEDIUM is a result of thunking
// [pfe] - FORMATETC or NULL
//
// Returns: Appropriate status code
//
// History: 24-Apr-94 DrewB Created
//
//----------------------------------------------------------------------------
SCODE CleanStgMed16(THUNKINFO *pti,
VPVOID vpsm16,
STGMEDIUM *psm32,
DWORD dwSize,
BOOL fIsThunk,
FORMATETC *pfe)
{
SCODE sc;
STGMEDIUM UNALIGNED *psm16;
VPVOID vpvUnk;
HMEM16 hmem16;
thkDebugOut((DEB_ITRACE, "In CleanStgMed16(%p, %p, %p, %u, %d, %p)\n",
pti, vpsm16, psm32, dwSize, fIsThunk, pfe));
sc = S_OK;
psm16 = FIXVDMPTR(vpsm16, STGMEDIUM);
vpvUnk = (VPVOID)psm16->pUnkForRelease;
RELVDMPTR(vpsm16);
if (fIsThunk && vpvUnk != 0)
{
CSm16ReleaseHandler UNALIGNED *psrh;
psrh = FIXVDMPTR(vpvUnk, CSm16ReleaseHandler);
psrh->Uninit();
RELVDMPTR(vpvUnk);
WOWGlobalUnlockFree16(vpvUnk);
}
psm16 = FIXVDMPTR(vpsm16, STGMEDIUM);
switch( psm16->tymed )
{
case TYMED_HGLOBAL:
hmem16 = (HMEM16)psm16->hGlobal;
RELVDMPTR(vpsm16);
if (fIsThunk &&
(pfe == NULL || !OBJDESC_CF(pfe->cfFormat)))
{
sc = ConvertHGlobal1632(pti, hmem16, 0,
&psm32->hGlobal, &dwSize);
}
WOWGlobalFree16( hmem16 );
break;
case TYMED_MFPICT:
hmem16 = (HMEM16)psm16->hGlobal;
RELVDMPTR(vpsm16);
// Can't modify an MFPICT
// Chicago uses the same GDI handles for both 32bit and 16bit worlds.
// Don't delete the handle after a copy since Chicago doesn't actually
// copy the handle.
#if !defined(_CHICAGO_)
VPVOID vpvmfp16;
METAFILEPICT16 *pmfp16;
HMEM16 hmf16;
vpvmfp16 = WOWGlobalLock16(hmem16);
pmfp16 = FIXVDMPTR(vpvmfp16, METAFILEPICT16);
hmf16 = pmfp16->hMF;
RELVDMPTR(vpvmfp16);
// Relies on the fact that a 16-bit metafile is an HGLOBAL
WOWGlobalFree16(hmf16);
WOWGlobalUnlockFree16(vpvmfp16);
#else
WOWGlobalFree16(hmem16);
#endif
break;
case TYMED_FILE:
vpvUnk = (VPVOID)psm16->lpszFileName;
RELVDMPTR(vpsm16);
TaskFree16(vpvUnk);
break;
case TYMED_ISTREAM:
RELVDMPTR(vpsm16);
if (fIsThunk)
{
pti->pThkMgr->FreeProxy1632(psm32->pstm);
}
break;
case TYMED_ISTORAGE:
RELVDMPTR(vpsm16);
if (fIsThunk)
{
pti->pThkMgr->FreeProxy1632(psm32->pstg);
}
break;
case TYMED_GDI:
RELVDMPTR(vpsm16);
//
// No unthunking needed
//
break;
case TYMED_NULL:
RELVDMPTR(vpsm16);
break;
default:
// Ignore, this case is handled on input
thkAssert(!"CleanStgMed16 with invalid tymed");
break;
}
thkDebugOut((DEB_ITRACE, "Out CleanStgMed16 => 0x%08lX\n", sc));
return sc;
}
//+---------------------------------------------------------------------------
//
// Function: ConvertFetc1632, public
//
// Synopsis: Converts a FORMATETC
//
// Arguments: [pti] - Thunk info
// [vpfe16] - FORMATETC
// [pfe32] - FORMATETC
// [fFree] - Free resources as converting
//
// Returns: Appropriate status code
//
// Modifies: [pfe32]
//
// History: 14-May-94 DrewB Created
//
//----------------------------------------------------------------------------
SCODE ConvertFetc1632(THUNKINFO *pti,
VPVOID vpfe16,
FORMATETC *pfe32,
BOOL fFree)
{
FORMATETC16 UNALIGNED *pfe16;
VPVOID vpdv16;
DVTARGETDEVICE *pdv32;
UINT cbSize;
SCODE sc;
pfe16 = FIXVDMPTR(vpfe16, FORMATETC16);
vpdv16 = (VPVOID)pfe16->ptd;
RELVDMPTR(vpfe16);
if ( vpdv16 == 0 )
{
pdv32 = NULL;
}
else
{
sc = ConvertDvtd1632(pti, vpdv16, ArTask32, FrTask32,
&pdv32, &cbSize);
if (fFree)
{
TaskFree16(vpdv16);
}
if (FAILED(sc))
{
return sc;
}
}
pfe16 = FIXVDMPTR(vpfe16, FORMATETC16);
pfe32->cfFormat = pfe16->cfFormat;
pfe32->ptd = pdv32;
pfe32->dwAspect = pfe16->dwAspect;
pfe32->lindex = pfe16->lindex;
pfe32->tymed = pfe16->tymed;
thkDebugOut((DEB_ARGS, "1632 FORMATETC: "
"%p -> %p {%d, %p (%p), %u, %u, 0x%X}\n",
vpfe16, pfe32,
pfe32->cfFormat,
pfe32->ptd, vpdv16,
pfe32->dwAspect,
pfe32->lindex,
pfe32->tymed));
RELVDMPTR(vpfe16);
return S_OK;
}
//+---------------------------------------------------------------------------
//
// Function: ConvertFetc3216, public
//
// Synopsis: Converts a FORMATETC
//
// Arguments: [pti] - Thunk info
// [pfe32] - FORMATETC
// [vpfe16] - FORMATETC
// [fFree] - Free resources as converting
//
// Returns: Appropriate status code
//
// Modifies: [vpfe16]
//
// History: 14-May-94 DrewB Created
//
//----------------------------------------------------------------------------
SCODE ConvertFetc3216(THUNKINFO *pti,
FORMATETC *pfe32,
VPVOID vpfe16,
BOOL fFree)
{
FORMATETC16 UNALIGNED *pfe16;
DVTARGETDEVICE *pdv32;
SCODE sc;
VPVOID vpdv16;
UINT cbSize;
pdv32 = pfe32->ptd;
if (pdv32 != NULL)
{
sc = ConvertDvtd3216(pti, pdv32, ArTask16, FrTask16,
&vpdv16, &cbSize);
if (fFree)
{
TaskFree32(pdv32);
}
if (FAILED(sc))
{
return sc;
}
}
else
{
vpdv16 = 0;
}
pfe16 = FIXVDMPTR(vpfe16, FORMATETC16);
pfe16->cfFormat = pfe32->cfFormat;
pfe16->ptd = vpdv16;
pfe16->dwAspect = pfe32->dwAspect;
pfe16->lindex = pfe32->lindex;
pfe16->tymed = pfe32->tymed;
thkDebugOut((DEB_ARGS, "3216 FORMATETC: "
"%p -> %p {%d, %p (%p), %u, %u, 0x%X}\n",
pfe32, vpfe16,
pfe16->cfFormat,
vpdv16, pdv32,
pfe16->dwAspect,
pfe16->lindex,
pfe16->tymed));
RELVDMPTR(vpfe16);
return S_OK;
}
//+---------------------------------------------------------------------------
//
// Function: DebugValidateProxy1632, debug public
//
// Synopsis: Validates a 16->32 proxy pointer and its memory
//
// Arguments: [vpvProxy] - Proxy
//
// History: 07-Jul-94 DrewB Created
//
//----------------------------------------------------------------------------
#if DBG == 1
void DebugValidateProxy1632(VPVOID vpvProxy)
{
THUNK1632OBJ UNALIGNED *pto;
THUNKINFO ti;
thkAssert(vpvProxy != 0 && "Invalid proxy pointer");
pto = (THUNK1632OBJ UNALIGNED *)
GetReadWritePtr16(&ti, vpvProxy, sizeof(THUNK1632OBJ));
thkAssert(pto != NULL && "Invalid proxy pointer");
thkAssert(pto->dwSignature == PSIG1632 && "Dead or invalid proxy!");
thkAssert(pto->cRefLocal >= 0 && "Invalid proxy refcount");
thkAssert(pto->cRefLocal >= pto->cRef && "Invalid proxy refcount");
if (!IsValidInterface(pto->punkThis32))
{
thkDebugOut((DEB_ERROR, "1632 %p: Invalid proxied object %p\n",
vpvProxy, pto->punkThis32));
}
WOWRELVDMPTR(vpvProxy);
}
#endif
//+---------------------------------------------------------------------------
//
// Function: DebugValidateProxy3216, debug public
//
// Synopsis: Validates a 32->16 proxy pointer and its memory
//
// Arguments: [pto] - Proxy
//
// History: 07-Jul-94 DrewB Created
//
//----------------------------------------------------------------------------
#if DBG == 1
void DebugValidateProxy3216(THUNK3216OBJ *pto)
{
THUNKINFO ti;
thkAssert(pto != 0 && "Invalid proxy pointer");
thkAssert(!IsBadReadPtr(pto, sizeof(THUNK3216OBJ)) &&
!IsBadWritePtr(pto, sizeof(THUNK3216OBJ)) &&
"Invalid proxy pointer");
thkAssert(pto->dwSignature == PSIG3216 && "Dead or invalid proxy!");
thkAssert(pto->cRefLocal >= 0 && "Invalid proxy refcount");
thkAssert(pto->cRefLocal >= pto->cRef && "Invalid proxy refcount");
if (!IsValidInterface16(&ti, pto->vpvThis16))
{
thkDebugOut((DEB_ERROR, "3216 %p: Invalid proxied object %p\n",
pto, pto->vpvThis16));
}
}
#endif
//+---------------------------------------------------------------------------
//
// Function: ClampLongToShort, public
//
// Synopsis: Restricts a long value to a short value by clamping
//
// Arguments: [l] - Long
//
// Returns: Short
//
// History: 16-Aug-94 DrewB Created
//
//----------------------------------------------------------------------------
SHORT ClampLongToShort(LONG l)
{
SHORT s;
if (l < SHRT_MIN)
{
s = SHRT_MIN;
thkDebugOut((DEB_WARN, "ClampLongToShort: %ld -> %d\n", l, s));
}
else if (l > SHRT_MAX)
{
s = SHRT_MAX;
thkDebugOut((DEB_WARN, "ClampLongToShort: %ld -> %d\n", l, s));
}
else
{
s = (SHORT)l;
}
return s;
}
//+---------------------------------------------------------------------------
//
// Function: ClampULongToUShort, public
//
// Synopsis: Restricts an unsigned long value to an unsigned short value
// by clamping
//
// Arguments: [ul] - Long
//
// Returns: UShort
//
// History: 16-Aug-94 DrewB Created
//
//----------------------------------------------------------------------------
USHORT ClampULongToUShort(ULONG ul)
{
USHORT us;
if (ul > USHRT_MAX)
{
us = USHRT_MAX;
thkDebugOut((DEB_WARN, "ClampULongToUShort: %ld -> %d\n", ul, us));
}
else
{
us = (USHORT)ul;
}
return us;
}
//+---------------------------------------------------------------------------
//
// Function: ConvertObjDescriptor
//
// Synopsis: Exported API called by WOW to convert ObjectDescriptors to
// the indicated format.
//
//
// Arguments: [hMem] -- Handle to the ObjectDescriptor to convert.
// [flag] -- Flag indicating which direction the convertion
// should take place. Valid values are:
// CFOLE_UNICODE_TO_ANSI.
// CFOLE_ANSI_TO_UNICODE.
//
// Returns: HGLOBAL to the converted ObjectDescriptor,
// or NULL on failure.
//
// History: 8-16-94 terryru Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDAPI_(HGLOBAL) ConvertObjDescriptor( HANDLE hMem, UINT flag )
{
const UINT CFOLE_UNICODE_TO_ANSI = 0;
const UINT CFOLE_ANSI_TO_UNICODE = 1;
THUNKINFO ti;
HGLOBAL hMem32;
HMEM16 hMem16;
switch ( flag )
{
case CFOLE_UNICODE_TO_ANSI:
if( FAILED( ConvertObjDesc3216( &ti, (HGLOBAL) hMem, &hMem16 )))
{
return (HGLOBAL) NULL;
}
else
{
return (HGLOBAL) hMem16;
}
break;
case CFOLE_ANSI_TO_UNICODE:
if( FAILED( ConvertObjDesc1632( &ti, (HMEM16) hMem, &hMem32 )))
{
return (HGLOBAL) NULL;
}
else
{
return (HGLOBAL) hMem32;
}
break;
default:
thkAssert(!"ConvertObjDescriptor, Invalid flag");
break;
}
return (HGLOBAL) NULL;
}
#if defined(_CHICAGO_)
//
// BUGBUGCHICAGO
//
// A hack so everyone can build Chicago OLE until I write the thunking
// library later this week.
//
#define ERR ((char*) -1)
#if DBG==1
int UnicodeToAnsi(LPSTR sz, LPCWSTR pwsz, LONG cb)
{
int ret;
ret = WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, pwsz, -1, sz, cb, NULL, NULL);
thkAssert(ret != 0 && "Lost characters in thk Unicode->Ansi conversion");
if (ret == 0)
{
DebugBreak();
}
return ret;
}
#else
#define UnicodeToAnsi(sz,pwsz,cb) WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, pwsz, -1, sz, cb, NULL, NULL)
#endif
#if DBG==1
int AnsiToUnicode(LPWSTR pwsz, LPCSTR sz, LONG cb)
{
int ret;
ret = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, sz, -1, pwsz, cb);
thkAssert(ret != 0 && "Lost characters in thk Ansi->Unicode conversion");
if (ret == 0)
{
DebugBreak();
}
return ret;
}
#else
#define AnsiToUnicode(pwsz,sz,cb) MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, sz, -1, pwsz, cb)
#endif
extern "C"
DWORD
WINAPI
GetShortPathNameX(
LPCWSTR lpszFullPath,
LPWSTR lpszShortPath,
DWORD cchBuffer
)
{
#ifdef DEBUG_OUTPUT
OutputDebugString("GetShortPathName\n");
#endif
CHAR szFullPath[MAX_PATH];
CHAR szShortBuffer[MAX_PATH];
DWORD ret;
UnicodeToAnsi(szFullPath, lpszFullPath, sizeof(szFullPath));
if (lpszShortPath == NULL)
{
ret = GetShortPathNameA(szFullPath, NULL, cchBuffer);
}
else
{
ret = GetShortPathNameA(szFullPath, szShortBuffer,
sizeof(szShortBuffer));
thkAssert(ret != cchBuffer &&
"GetShortPathName - Output buffer too short");
//
// Don't convert the buffer if the
// call to GetShortPathNameA() failed.
//
if(0 != ret)
{
//
// Only convert the actual data, not the whole buffer.
//
if (cchBuffer > ret + 1)
cchBuffer = ret + 1;
AnsiToUnicode(lpszShortPath, szShortBuffer, cchBuffer);
}
}
return ret;
}
#endif // _CHICAGO_