//+--------------------------------------------------------------------------- // // 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 #include #include #include // // 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_