1123 lines
34 KiB
C++
1123 lines
34 KiB
C++
|
// Copyright (c) 1996-2000 Microsoft Corporation
|
||
|
// ----------------------------------------------------------------------------
|
||
|
// Win64Helper.cpp
|
||
|
//
|
||
|
// Helper functions used by all the control wrappers
|
||
|
//
|
||
|
// ----------------------------------------------------------------------------
|
||
|
#include "Win64Helper.h"
|
||
|
#include "w95trace.h"
|
||
|
|
||
|
#include "RemoteProxy6432.h"
|
||
|
#include <atlbase.h> // CComPtr
|
||
|
|
||
|
|
||
|
// Used for Tab control code
|
||
|
// cbExtra for the tray is 8, so pick something even bigger, 16
|
||
|
#define CBEXTRA_TRAYTAB 16
|
||
|
|
||
|
|
||
|
|
||
|
// Stuff in this file:
|
||
|
//
|
||
|
// * Bitness utility functions
|
||
|
// - determine whether we are on a 32- or 64- bit system, determine
|
||
|
// what bitness a process is.
|
||
|
//
|
||
|
// * Cross-proc SendMessage utility class
|
||
|
// - manages allocting a struct in the remote process, copying to that
|
||
|
// struct, sending a message, and copying back out the result.
|
||
|
//
|
||
|
// * Remote type template class
|
||
|
// - template class used in the explicit 64/32 structure definitions
|
||
|
//
|
||
|
// * Explicit 64/32 structure definitions
|
||
|
// - Definitions of comctl and related structs (eg. LVITEM) in separate
|
||
|
// 64- and 32-bit versions (eg. LVITEM_64, LVITEM_32) that have the
|
||
|
// correct item sizes, layout and alignment for that bitness.
|
||
|
//
|
||
|
// * Cross-proc message handlers
|
||
|
// - one for each supported message/datatype. (eg. ListView_Get_Handler
|
||
|
// handles LVM_GETITEM which uses LVITEM.) These copy the 'in' fields
|
||
|
// from a local struct (eg. LVITEM) to a local copy of the appropriate
|
||
|
// 'remote' struct (eg. LVITEM_32 or LVITEM_64, depending on the bitness
|
||
|
// of the target proxy), use the cross-proc sendmessage helper to
|
||
|
// copy that to the remote proc, send the message, and copy back; and
|
||
|
// then copy the appropriate 'out' fields back to the original local
|
||
|
// struct.
|
||
|
//
|
||
|
// * Stub macro
|
||
|
// - this macro declares a function that does a plain sendmessage if we're
|
||
|
// in the same process as the target HWND - otherwise it uses a cross-proc
|
||
|
// handler (see above) to send the message cross-proc.
|
||
|
//
|
||
|
//
|
||
|
// * GetRemoteProxyFactory
|
||
|
// - Lives here because there's no other suitable place for it.
|
||
|
//
|
||
|
//
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Bitness utility functions
|
||
|
//
|
||
|
// Class CProcessorType is used to determine whether we are running on a
|
||
|
// 64- or 32-bit system (regardless of whether this is a 32- or 64-bit
|
||
|
// process - eg. we could be a 32-bit process on a 64-bit machine).
|
||
|
//
|
||
|
// Function SameBitness determines if a window belongs to a process with the
|
||
|
// same bitness as the current process.
|
||
|
//
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
// Taken from enum _PROCESSINFOCLASS in NT\PUBLIC\sdk\inc\ntpsapi.h ...
|
||
|
|
||
|
#define ProcessWow64Information 26
|
||
|
|
||
|
#define NT_ERROR(Status) ((ULONG)(Status) >> 30 == 3)
|
||
|
|
||
|
typedef enum ProcessorTypes {
|
||
|
ProcessorUndef,
|
||
|
ProcessorX86,
|
||
|
ProcessorIA64
|
||
|
} ProcessorTypes;
|
||
|
|
||
|
class CProcessorType {
|
||
|
private:
|
||
|
static ProcessorTypes m_ProcessorType;
|
||
|
static void Init()
|
||
|
{
|
||
|
if (m_ProcessorType != ProcessorUndef)
|
||
|
return;
|
||
|
#ifndef _WIN64
|
||
|
ULONG_PTR Wow64Info = NULL;
|
||
|
HANDLE hProcess;
|
||
|
|
||
|
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId());
|
||
|
long lStatus = MyNtQueryInformationProcess(hProcess, ProcessWow64Information, &Wow64Info, sizeof(Wow64Info), NULL);
|
||
|
CloseHandle(hProcess);
|
||
|
if (NT_ERROR(lStatus))
|
||
|
{
|
||
|
// Query failed. Must be on an NT4 or earlier NT machine. Definitely a 32-bit machine.
|
||
|
m_ProcessorType = ProcessorX86;
|
||
|
} else if (Wow64Info)
|
||
|
{
|
||
|
// We are running inside WOW64 on a 64-bit machine
|
||
|
m_ProcessorType = ProcessorIA64;
|
||
|
} else
|
||
|
{
|
||
|
// We are running on x86 Win2000 or later OS
|
||
|
m_ProcessorType = ProcessorX86;
|
||
|
}
|
||
|
DBPRINTF(TEXT("CProcessorType: !_WIN64 defined m_ProcessorType=%d\r\n"), m_ProcessorType);
|
||
|
#else
|
||
|
// _WIN64 is defined, so definitely running on a 64-bit processor
|
||
|
m_ProcessorType = ProcessorIA64;
|
||
|
DBPRINTF(TEXT("CProcessorType: _WIN64 defined m_ProcessorType=%d\r\n"), m_ProcessorType);
|
||
|
#endif
|
||
|
};
|
||
|
public:
|
||
|
CProcessorType() {};
|
||
|
~CProcessorType() {};
|
||
|
static BOOL ProcessorIsIA64() {
|
||
|
Init();
|
||
|
return m_ProcessorType == ProcessorIA64;
|
||
|
}
|
||
|
static BOOL ProcessorIsX86() {
|
||
|
Init();
|
||
|
return m_ProcessorType == ProcessorX86;
|
||
|
}
|
||
|
};
|
||
|
ProcessorTypes CProcessorType::m_ProcessorType = ProcessorUndef;
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
HRESULT SameBitness(HWND hwnd, BOOL *pfIsSameBitness)
|
||
|
{
|
||
|
*pfIsSameBitness = TRUE;
|
||
|
|
||
|
#ifndef ENABLE6432_INTEROP
|
||
|
return S_OK;
|
||
|
#endif
|
||
|
|
||
|
// If running on an X86 then we must be same bitness
|
||
|
if (CProcessorType::ProcessorIsX86())
|
||
|
return S_OK;
|
||
|
|
||
|
DWORD dwProcessId;
|
||
|
if ( !GetWindowThreadProcessId(hwnd, &dwProcessId) )
|
||
|
return E_FAIL;
|
||
|
|
||
|
BOOL fIs32Bit;
|
||
|
|
||
|
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwProcessId);
|
||
|
if ( NULL == hProcess )
|
||
|
{
|
||
|
// The desktop window is in a process that OpenProcess fails on
|
||
|
// with an ERROR_ACCESS_DENIED (5) so special case it an assume
|
||
|
// its the same as the platform
|
||
|
// TODO figure out what other thisngs could fall in this catagory
|
||
|
// and deal with them as exceptions
|
||
|
const HWND hwndDesktop = GetDesktopWindow();
|
||
|
if ( hwnd == hwndDesktop )
|
||
|
{
|
||
|
// at this point we are on a 64 bit platfrom and therefore
|
||
|
// can assume that the desktop is 64 bit as well
|
||
|
fIs32Bit = FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DWORD dwErr = GetLastError();
|
||
|
DBPRINTF( TEXT("OpenProcess returned null GetLastError()=%d\r\n"), dwErr );
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ULONG_PTR Wow64Info = NULL;
|
||
|
long rv = MyNtQueryInformationProcess(
|
||
|
hProcess
|
||
|
, ProcessWow64Information
|
||
|
, &Wow64Info
|
||
|
, sizeof(Wow64Info)
|
||
|
, NULL);
|
||
|
CloseHandle(hProcess);
|
||
|
|
||
|
if (NT_ERROR(rv))
|
||
|
{
|
||
|
Wow64Info = NULL; // fake that process is 64bit (OK because this code only executed for _WIN64)
|
||
|
}
|
||
|
|
||
|
fIs32Bit = (NULL != Wow64Info);
|
||
|
}
|
||
|
|
||
|
#ifdef _WIN64
|
||
|
*pfIsSameBitness = !fIs32Bit;
|
||
|
#else
|
||
|
*pfIsSameBitness = fIs32Bit;
|
||
|
#endif
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Cross-proc SendMessage utility class
|
||
|
//
|
||
|
// The cross-proc message handlers all follow a similar pattern.
|
||
|
//
|
||
|
// First, the handler works out how much extra storage it will need - eg.
|
||
|
// for returning a text string. It then calls Alloc() with the size of the
|
||
|
// base struct (eg. LVITEM), and the size of the extra data - if any (may be
|
||
|
// 0).
|
||
|
//
|
||
|
// Alloc() then allocaes space for both the base struct and the extra
|
||
|
// data, and returns TRUE if the allocation succeeded.
|
||
|
//
|
||
|
// GetExtraPtr() returns a pointer, relative to the remote process, to the
|
||
|
// extra space. If no extra space was requested, it returns NULL.
|
||
|
//
|
||
|
// ReadExtra() is used to read data in that extra space from the remote
|
||
|
// process to the local process. If no extra space was requested, it
|
||
|
// does nothing.
|
||
|
//
|
||
|
// WriteSendMsgRead() copies the struct to the remote process, sends the
|
||
|
// message using SendMessage, and then copies the struct back to the local
|
||
|
// process.
|
||
|
//
|
||
|
// WriteSendMsg() is the same as WriteSendMsgRead(), except it does not
|
||
|
// copy the result back. (This is used for 'put' messages that do not
|
||
|
// return information.)
|
||
|
//
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
class CXSendHelper
|
||
|
{
|
||
|
private:
|
||
|
void * m_pvAddress; // Ptr to remote shared mem
|
||
|
HANDLE m_hProcess; // Handle of remote process
|
||
|
UINT m_cbSize; // Size of base struct
|
||
|
UINT m_cbExtra; // Size of extra stuff - usually text - stored after the struct
|
||
|
|
||
|
public:
|
||
|
|
||
|
CXSendHelper() : m_pvAddress(0) {};
|
||
|
|
||
|
virtual ~CXSendHelper()
|
||
|
{
|
||
|
if (m_pvAddress)
|
||
|
{
|
||
|
::SharedFree(m_pvAddress, m_hProcess);
|
||
|
m_pvAddress = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BOOL Alloc( HWND hwnd, UINT cbSize, UINT cbExtra )
|
||
|
{
|
||
|
m_cbSize = cbSize;
|
||
|
m_cbExtra = cbExtra;
|
||
|
m_pvAddress = ::SharedAlloc( cbSize + cbExtra, hwnd, &m_hProcess );
|
||
|
return m_pvAddress != NULL;
|
||
|
}
|
||
|
|
||
|
void * GetExtraPtr()
|
||
|
{
|
||
|
// If no extra space was requested, then return NULL...
|
||
|
if( ! m_cbExtra )
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
// Return pointer to the 'extra' data that follows the struct
|
||
|
return (BYTE *)m_pvAddress + m_cbSize;
|
||
|
}
|
||
|
|
||
|
BOOL ReadExtra( LPVOID lpvDest, LPVOID lpvRemoteSrc, BOOL fIsString )
|
||
|
{
|
||
|
// Does nothing if no extra space was requested.
|
||
|
if( ! m_cbExtra )
|
||
|
return TRUE;
|
||
|
|
||
|
if( lpvRemoteSrc )
|
||
|
{
|
||
|
// This may point to the extra space we allocated, or the control may
|
||
|
// have changed the pointer to point to its own data instead of copying
|
||
|
// into the space we allocated.
|
||
|
if( ! SharedRead( lpvRemoteSrc, lpvDest, m_cbExtra, m_hProcess ) )
|
||
|
return FALSE;
|
||
|
|
||
|
if( fIsString )
|
||
|
{
|
||
|
// Paranoia - forcibly NUL-terminate, in case we get garbage...
|
||
|
LPTSTR pEnd = (LPTSTR)((BYTE *)lpvDest + m_cbExtra) - 1;
|
||
|
*pEnd = '\0';
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// The control changed the pointer to NULL - assume that this means there's
|
||
|
// nothing there.
|
||
|
if( fIsString )
|
||
|
{
|
||
|
// Use empty string
|
||
|
*(LPTSTR)lpvDest = '\0';
|
||
|
return TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
template < class T >
|
||
|
BOOL WriteSendMsgRead ( T * pStruct, HWND hwnd, UINT uMsg, WPARAM wParam, BOOL fCheckSend )
|
||
|
{
|
||
|
// Copy the struct to the remote process...
|
||
|
if( ! SharedWrite( pStruct, m_pvAddress, sizeof( T ), m_hProcess ) )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// Send the message...
|
||
|
// If SendMessage fails, we fail only if the fCheckSend flag is specified.
|
||
|
if( ( ! SendMessage( hwnd, uMsg, wParam, (LPARAM) m_pvAddress) ) && fCheckSend )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// Copy returned struct back to local process...
|
||
|
if( ! SharedRead( m_pvAddress, pStruct, sizeof( T ), m_hProcess ) )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
template < class T >
|
||
|
BOOL WriteSendMsg ( T * pStruct, HWND hwnd, UINT uMsg, WPARAM wParam, BOOL fCheckSend )
|
||
|
{
|
||
|
// Copy the struct remotely...
|
||
|
if( ! SharedWrite( pStruct, m_pvAddress, sizeof( T ), m_hProcess ) )
|
||
|
return FALSE;
|
||
|
|
||
|
// Send the message...
|
||
|
// If SendMessage fails, we fail only if the fCheckSend flag is specified.
|
||
|
if( ! SendMessage( hwnd, uMsg, wParam, (LPARAM) m_pvAddress) && fCheckSend )
|
||
|
return FALSE;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
//
|
||
|
// 'Remote Type' template class
|
||
|
//
|
||
|
// This is used to represent a type in a remote address space.
|
||
|
// While the local type may be a poiter, a handle, or some other 'native'
|
||
|
// type, when accessed remotely, an integer type is used to ensure correct
|
||
|
// size.
|
||
|
//
|
||
|
// Eg. a pointer in a 64-bit process is represented as a ULONG64; a ptr in a
|
||
|
// 32-bit process is represented as a ULONG32.
|
||
|
//
|
||
|
// Signedness matters for some types - pointers are zero-extended when going
|
||
|
// from 32-to-64, but handles are sign-extended.
|
||
|
//
|
||
|
// This class, which has assignment and conversion operators defined, takes
|
||
|
// care of the necessary casting to ensure correct conversion between the
|
||
|
// local type and the remote representation
|
||
|
//
|
||
|
// This is a template class, which takes the following parameters:
|
||
|
//
|
||
|
// REMOTE_INT - remote representation type - eg. ULONG64, LONG32, etc.
|
||
|
// LOCAL_INT_PTR - local integer type, eg. ULONG_PTR, LONG_PTR
|
||
|
// LOCAL_TYPE - local type - eg handle, void*, LPARAM, etc.
|
||
|
//
|
||
|
//
|
||
|
// A 64-bit pointer, for example, would have a REMOTE_INT of ULONG64 - 64bit
|
||
|
// size, unsigned for zero-extension; a LOCAL_INT_PTR of ULONG_PTR - same
|
||
|
// sign as REMOTE_INT - and a local type of void*.
|
||
|
//
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
template < typename REMOTE_INT, typename LOCAL_INT_PTR, typename LOCAL_TYPE >
|
||
|
class RemoteType
|
||
|
{
|
||
|
REMOTE_INT m_val;
|
||
|
|
||
|
public:
|
||
|
|
||
|
void operator = ( LOCAL_TYPE h )
|
||
|
{
|
||
|
// Convert from local type to remote integer type, via local integer type
|
||
|
m_val = (REMOTE_INT) (LOCAL_INT_PTR) h;
|
||
|
}
|
||
|
|
||
|
operator LOCAL_TYPE ( )
|
||
|
{
|
||
|
// Convert from remote integer to local type, via local integer type
|
||
|
return (LOCAL_TYPE) (LOCAL_INT_PTR) m_val;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
typedef RemoteType< ULONG32, ULONG_PTR, void * > Ptr32;
|
||
|
typedef RemoteType< ULONG64, ULONG_PTR, void * > Ptr64;
|
||
|
|
||
|
typedef RemoteType< LONG32, LONG_PTR, LPARAM > LParam32;
|
||
|
typedef RemoteType< LONG64, LONG_PTR, LPARAM > LParam64;
|
||
|
|
||
|
typedef RemoteType< LONG32, LONG_PTR, HWND > HWnd32;
|
||
|
typedef RemoteType< LONG64, LONG_PTR, HWND > HWnd64;
|
||
|
|
||
|
typedef RemoteType< LONG32, LONG_PTR, HBITMAP > HBitmap32;
|
||
|
typedef RemoteType< LONG64, LONG_PTR, HBITMAP > HBitmap64;
|
||
|
|
||
|
typedef RemoteType< LONG32, LONG_PTR, HINSTANCE > HInstance32;
|
||
|
typedef RemoteType< LONG64, LONG_PTR, HINSTANCE > HInstance64;
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Explicit 32-bit and 64-bit versions of the control structs
|
||
|
//
|
||
|
// These use explicit 'remote type' fields instead of handler or pointer,
|
||
|
// to ensure the correct size and sign extension when compiled as either
|
||
|
// 32-bit or 64-code. "for_alignment" fields are also added to the 64-bit
|
||
|
// versions where necessary to obtain correct alignment.
|
||
|
//
|
||
|
// These structs do not contain recently added fields (those that are ifdef'd
|
||
|
// out with #if (_WIN32_IE >= 0x0300) or later) - we go for a 'least common
|
||
|
// denominator' approach. The earlier, smalleer structs are accepted by both
|
||
|
// old and new comctl versions; but only the recent comctl versions accept
|
||
|
// the larger structs.
|
||
|
//
|
||
|
// (This only really matters where the struct has a cbSize field - otherwise
|
||
|
// a field isn't used unless it is referenced by a bit in the mask.)
|
||
|
//
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
struct LVITEM_32 {
|
||
|
UINT mask;
|
||
|
int iItem;
|
||
|
int iSubItem;
|
||
|
UINT state;
|
||
|
UINT stateMask;
|
||
|
Ptr32 pszText;
|
||
|
int cchTextMax;
|
||
|
int iImage;
|
||
|
LParam32 lParam;
|
||
|
int iIndent;
|
||
|
};
|
||
|
|
||
|
struct LVITEM_64 {
|
||
|
UINT mask;
|
||
|
int iItem;
|
||
|
int iSubItem;
|
||
|
UINT state;
|
||
|
UINT stateMask;
|
||
|
UINT for_alignment;
|
||
|
Ptr64 pszText;
|
||
|
int cchTextMax;
|
||
|
int iImage;
|
||
|
LParam64 lParam;
|
||
|
int iIndent;
|
||
|
};
|
||
|
|
||
|
|
||
|
// LVITEM_V6 structs are extensions of the old ones...
|
||
|
struct LVITEM_V6_32: public LVITEM_32
|
||
|
{
|
||
|
int iGroupId;
|
||
|
UINT cColumns;
|
||
|
Ptr32 puColumns;
|
||
|
};
|
||
|
|
||
|
struct LVITEM_V6_64: public LVITEM_64
|
||
|
{
|
||
|
int iGroupId;
|
||
|
UINT cColumns;
|
||
|
Ptr64 puColumns;
|
||
|
};
|
||
|
|
||
|
struct LVGROUP_V6_32
|
||
|
{
|
||
|
UINT cbSize;
|
||
|
UINT mask;
|
||
|
Ptr32 pszHeader;
|
||
|
int cchHeader;
|
||
|
|
||
|
Ptr32 pszFooter;
|
||
|
int cchFooter;
|
||
|
|
||
|
int iGroupId;
|
||
|
|
||
|
UINT stateMask;
|
||
|
UINT state;
|
||
|
UINT uAlign;
|
||
|
};
|
||
|
|
||
|
struct LVGROUP_V6_64
|
||
|
{
|
||
|
UINT cbSize;
|
||
|
UINT mask;
|
||
|
Ptr64 pszHeader;
|
||
|
int cchHeader;
|
||
|
|
||
|
Ptr64 pszFooter;
|
||
|
int cchFooter;
|
||
|
|
||
|
int iGroupId;
|
||
|
|
||
|
UINT stateMask;
|
||
|
UINT state;
|
||
|
UINT uAlign;
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
struct LVCOLUMN_32 {
|
||
|
UINT mask;
|
||
|
int fmt;
|
||
|
int cx;
|
||
|
Ptr32 pszText;
|
||
|
int cchTextMax;
|
||
|
int iSubItem;
|
||
|
};
|
||
|
|
||
|
struct LVCOLUMN_64 {
|
||
|
UINT mask;
|
||
|
int fmt;
|
||
|
int cx;
|
||
|
UINT for_alignment;
|
||
|
Ptr64 pszText;
|
||
|
int cchTextMax;
|
||
|
int iSubItem;
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
struct HDITEM_32 {
|
||
|
UINT mask;
|
||
|
int cxy;
|
||
|
Ptr32 pszText;
|
||
|
HBitmap32 hbm;
|
||
|
int cchTextMax;
|
||
|
int fmt;
|
||
|
LParam32 lParam;
|
||
|
int iImage;
|
||
|
int iOrder;
|
||
|
};
|
||
|
|
||
|
struct HDITEM_64 {
|
||
|
UINT mask;
|
||
|
int cxy;
|
||
|
Ptr64 pszText;
|
||
|
HBitmap64 hbm;
|
||
|
int cchTextMax;
|
||
|
int fmt;
|
||
|
LParam64 lParam;
|
||
|
int iImage;
|
||
|
int iOrder;
|
||
|
};
|
||
|
|
||
|
struct TCITEM_32 {
|
||
|
UINT mask;
|
||
|
DWORD dwState;
|
||
|
DWORD dwStateMask;
|
||
|
Ptr32 pszText;
|
||
|
int cchTextMax;
|
||
|
int iImage;
|
||
|
LParam32 lParam;
|
||
|
};
|
||
|
|
||
|
struct TCITEM_64 {
|
||
|
UINT mask;
|
||
|
DWORD dwState;
|
||
|
DWORD dwStateMask;
|
||
|
UINT for_alignment;
|
||
|
Ptr64 pszText;
|
||
|
int cchTextMax;
|
||
|
int iImage;
|
||
|
LParam64 lParam;
|
||
|
};
|
||
|
|
||
|
struct TOOLINFO_32 {
|
||
|
UINT cbSize;
|
||
|
UINT uFlags;
|
||
|
HWnd32 hwnd;
|
||
|
WPARAM uId;
|
||
|
RECT rect;
|
||
|
HInstance32 hinst;
|
||
|
Ptr32 lpszText;
|
||
|
};
|
||
|
|
||
|
struct TOOLINFO_64 {
|
||
|
UINT cbSize;
|
||
|
UINT uFlags;
|
||
|
HWnd64 hwnd;
|
||
|
WPARAM uId;
|
||
|
RECT rect;
|
||
|
HInstance64 hinst;
|
||
|
Ptr64 lpszText;
|
||
|
};
|
||
|
|
||
|
|
||
|
struct TTGETTITLE_32
|
||
|
{
|
||
|
DWORD dwSize;
|
||
|
UINT uTitleBitmap;
|
||
|
UINT cch;
|
||
|
Ptr32 pszTitle;
|
||
|
};
|
||
|
|
||
|
struct TTGETTITLE_64
|
||
|
{
|
||
|
DWORD dwSize;
|
||
|
UINT uTitleBitmap;
|
||
|
UINT cch;
|
||
|
UINT for_alignment;
|
||
|
Ptr64 pszTitle;
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Handlers for the common controls message handlers
|
||
|
//
|
||
|
// The basic structure of these is:
|
||
|
//
|
||
|
// 1. Determine if extra storage is needed for text.
|
||
|
// 2. Allocate storage
|
||
|
// 3. Fill a local struct that has the same bitness as the target
|
||
|
// 4. Copy that struct to the remote process, do the SendMessage, and copy
|
||
|
// the struct back
|
||
|
// 5. Copy fields from that struct back to the local one
|
||
|
// 6. Copy any extra data back (usually text) if necessary
|
||
|
//
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
template <class T>
|
||
|
HRESULT ListView_Get_Handler( T & lvDest, HWND hwnd, UINT uiMsg, WPARAM wParam, LVITEM * pItemSrc, BOOL fCheckSend, UINT )
|
||
|
{
|
||
|
// work out required size of target struct, and allocate...
|
||
|
DWORD dwTextSize = 0;
|
||
|
if(pItemSrc->mask & LVIF_TEXT)
|
||
|
dwTextSize = sizeof(TCHAR) * (pItemSrc->cchTextMax + 1);
|
||
|
|
||
|
CXSendHelper xsh;
|
||
|
if( ! xsh.Alloc( hwnd, sizeof(T), dwTextSize ) )
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
// Copy to remote struct...
|
||
|
lvDest.mask = pItemSrc->mask;
|
||
|
lvDest.iItem = pItemSrc->iItem;
|
||
|
lvDest.iSubItem = pItemSrc->iSubItem;
|
||
|
lvDest.pszText = xsh.GetExtraPtr();
|
||
|
lvDest.cchTextMax = pItemSrc->cchTextMax;
|
||
|
|
||
|
|
||
|
if( ! xsh.WriteSendMsgRead( & lvDest, hwnd, uiMsg, wParam, fCheckSend ) )
|
||
|
return E_FAIL;
|
||
|
|
||
|
// Copy back the struct out members...
|
||
|
pItemSrc->state = lvDest.state;
|
||
|
pItemSrc->stateMask = lvDest.stateMask;
|
||
|
pItemSrc->iImage = lvDest.iImage;
|
||
|
pItemSrc->lParam = lvDest.lParam;
|
||
|
pItemSrc->iIndent = lvDest.iIndent;
|
||
|
|
||
|
// Copy text back out separately...
|
||
|
if( ! xsh.ReadExtra( pItemSrc->pszText, lvDest.pszText, TRUE ) )
|
||
|
return E_FAIL;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
template <class T> // T is one of the LVITEM types
|
||
|
HRESULT ListView_Set_Handler( T & lvDest, HWND hwnd, UINT uiMsg, WPARAM wParam, LVITEM *pItemSrc, BOOL fCheckSend, UINT )
|
||
|
{
|
||
|
// work out required size of target struct, and allocate...
|
||
|
DWORD dwTextSize = 0;
|
||
|
if(pItemSrc->mask & LVIF_TEXT)
|
||
|
dwTextSize = sizeof(TCHAR) * (pItemSrc->cchTextMax + 1);
|
||
|
|
||
|
CXSendHelper xsh;
|
||
|
if( ! xsh.Alloc( hwnd, sizeof(T), dwTextSize ) )
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
// Copy to remote struct...
|
||
|
lvDest.mask = pItemSrc->mask;
|
||
|
lvDest.iItem = pItemSrc->iItem;
|
||
|
lvDest.iSubItem = pItemSrc->iSubItem;
|
||
|
lvDest.pszText = xsh.GetExtraPtr();
|
||
|
lvDest.cchTextMax = pItemSrc->cchTextMax;
|
||
|
lvDest.state = pItemSrc->state;
|
||
|
lvDest.stateMask = pItemSrc->stateMask;
|
||
|
lvDest.iImage = pItemSrc->iImage;
|
||
|
lvDest.lParam = pItemSrc->lParam;
|
||
|
lvDest.iIndent = pItemSrc->iIndent;
|
||
|
|
||
|
xsh.WriteSendMsg( & lvDest, hwnd, uiMsg, wParam, fCheckSend );
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
template <class T>
|
||
|
HRESULT ListView_GetCol_Handler( T & lvDest, HWND hwnd, UINT uiMsg, WPARAM wParam, LVCOLUMN * pItemSrc, BOOL fCheckSend, UINT )
|
||
|
{
|
||
|
// work out required size of target struct, and allocate...
|
||
|
DWORD dwTextSize = 0;
|
||
|
if(pItemSrc->mask & LVCF_TEXT)
|
||
|
dwTextSize = sizeof(TCHAR) * (pItemSrc->cchTextMax + 1);
|
||
|
|
||
|
CXSendHelper xsh;
|
||
|
if( ! xsh.Alloc( hwnd, sizeof(T), dwTextSize ) )
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
// Copy to remote struct...
|
||
|
lvDest.mask = pItemSrc->mask;
|
||
|
lvDest.iSubItem = pItemSrc->iSubItem;
|
||
|
lvDest.pszText = xsh.GetExtraPtr();
|
||
|
lvDest.cchTextMax = pItemSrc->cchTextMax;
|
||
|
|
||
|
if( ! xsh.WriteSendMsgRead( & lvDest, hwnd, uiMsg, wParam, fCheckSend ) )
|
||
|
return E_FAIL;
|
||
|
|
||
|
// Copy text back out separately...
|
||
|
if( ! xsh.ReadExtra( pItemSrc->pszText, lvDest.pszText, TRUE ) )
|
||
|
return E_FAIL;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
template <class T>
|
||
|
HRESULT ListView_V6_Get_Handler( T & lvDest, HWND hwnd, UINT uiMsg, WPARAM wParam, LVITEM_V6 * pItemSrc, BOOL fCheckSend, UINT )
|
||
|
{
|
||
|
// This version only gets column information, not text...
|
||
|
|
||
|
DWORD dwExtraSize = 0;
|
||
|
if(pItemSrc->mask & LVIF_COLUMNS)
|
||
|
dwExtraSize = sizeof(UINT) * (pItemSrc->cColumns);
|
||
|
|
||
|
CXSendHelper xsh;
|
||
|
if( ! xsh.Alloc( hwnd, sizeof(T), dwExtraSize ) )
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
// Copy to remote struct...
|
||
|
lvDest.mask = pItemSrc->mask;
|
||
|
lvDest.iItem = pItemSrc->iItem;
|
||
|
lvDest.iSubItem = pItemSrc->iSubItem;
|
||
|
lvDest.cColumns = pItemSrc->cColumns;
|
||
|
lvDest.puColumns = xsh.GetExtraPtr();
|
||
|
|
||
|
// LVM_GETITEM/LVIF_COLUMNS returns FALSE when puColumns is NULL, even though it
|
||
|
// does set cColumns to the size required. So we should only check that SendMessage
|
||
|
// returns TRUE when puColumns is non-NULL.
|
||
|
if( ! xsh.WriteSendMsgRead( & lvDest, hwnd, uiMsg, wParam, fCheckSend ) )
|
||
|
return E_FAIL;
|
||
|
|
||
|
// Copy back the struct out members...
|
||
|
pItemSrc->cColumns = lvDest.cColumns;
|
||
|
pItemSrc->iGroupId = lvDest.iGroupId;
|
||
|
|
||
|
// Copy columns back out separately...
|
||
|
// UINTs are the same on 64 vs 32, so don't need extra processing here.
|
||
|
if( ! xsh.ReadExtra( pItemSrc->puColumns, lvDest.puColumns, FALSE ) )
|
||
|
return E_FAIL;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
template <class T>
|
||
|
HRESULT ListView_V6_GetGroup_Handler( T & lvDest, HWND hwnd, UINT uiMsg, WPARAM wParam, LVGROUP_V6 * pItemSrc, BOOL fCheckSend, UINT )
|
||
|
{
|
||
|
DWORD dwTextSize = 0;
|
||
|
if( pItemSrc->mask & LVGF_HEADER )
|
||
|
dwTextSize = sizeof(TCHAR) * (pItemSrc->cchHeader + 1);
|
||
|
|
||
|
CXSendHelper xsh;
|
||
|
if( ! xsh.Alloc( hwnd, sizeof(T), dwTextSize ) )
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
// Copy to remote struct...
|
||
|
lvDest.cbSize = pItemSrc->cbSize;
|
||
|
lvDest.mask = pItemSrc->mask;
|
||
|
lvDest.pszHeader = xsh.GetExtraPtr();
|
||
|
lvDest.cchHeader = pItemSrc->cchHeader;
|
||
|
lvDest.iGroupId = pItemSrc->iGroupId;
|
||
|
|
||
|
if( ! xsh.WriteSendMsgRead( &lvDest, hwnd, uiMsg, wParam, fCheckSend ) )
|
||
|
return E_FAIL;
|
||
|
|
||
|
// Copy text back out separately...
|
||
|
if( ! xsh.ReadExtra( pItemSrc->pszHeader, lvDest.pszHeader, TRUE ) )
|
||
|
return E_FAIL;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
template <class T>
|
||
|
HRESULT HeaderCtrl_Get_Handler( T & hdDest, HWND hwnd, UINT uiMsg, WPARAM wParam, HDITEM *pItemSrc, BOOL fCheckSend, UINT )
|
||
|
{
|
||
|
// work out required size of target struct, and allocate...
|
||
|
DWORD dwTextSize = 0;
|
||
|
if(pItemSrc->mask & HDI_TEXT)
|
||
|
dwTextSize = sizeof(TCHAR) * (pItemSrc->cchTextMax + 1);
|
||
|
|
||
|
CXSendHelper xsh;
|
||
|
if( ! xsh.Alloc( hwnd, sizeof(T), dwTextSize ) )
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
// Copy to remote struct...
|
||
|
hdDest.mask = pItemSrc->mask;
|
||
|
hdDest.pszText = xsh.GetExtraPtr();
|
||
|
hdDest.cchTextMax = pItemSrc->cchTextMax;
|
||
|
|
||
|
if( ! xsh.WriteSendMsgRead( & hdDest, hwnd, uiMsg, wParam, fCheckSend ) )
|
||
|
return E_FAIL;
|
||
|
|
||
|
// Copy back the struct out members...
|
||
|
pItemSrc->cxy = hdDest.cxy;
|
||
|
pItemSrc->hbm = hdDest.hbm;
|
||
|
pItemSrc->fmt = hdDest.fmt;
|
||
|
pItemSrc->lParam = hdDest.lParam;
|
||
|
pItemSrc->iImage = hdDest.iImage;
|
||
|
pItemSrc->iOrder = hdDest.iOrder;
|
||
|
|
||
|
// Copy text back out separately...
|
||
|
if( ! xsh.ReadExtra( pItemSrc->pszText, hdDest.pszText, TRUE ) )
|
||
|
return E_FAIL;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
template <class T>
|
||
|
HRESULT TabCtrl_Get_Handler( T & tcDest, HWND hwnd, UINT uiMsg, WPARAM wParam, TCITEM *pItemSrc, BOOL fCheckSend, UINT )
|
||
|
{
|
||
|
// work out required size of target struct, and allocate...
|
||
|
DWORD dwTextSize = 0;
|
||
|
if(pItemSrc->mask & TCIF_TEXT)
|
||
|
dwTextSize = sizeof(TCHAR) * (pItemSrc->cchTextMax + 1);
|
||
|
|
||
|
CXSendHelper xsh;
|
||
|
if( ! xsh.Alloc( hwnd, sizeof(T) + CBEXTRA_TRAYTAB, dwTextSize ) )
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
// Copy to remote struct...
|
||
|
tcDest.mask = pItemSrc->mask;
|
||
|
tcDest.dwState = pItemSrc->dwState;
|
||
|
tcDest.dwStateMask = pItemSrc->dwStateMask;
|
||
|
tcDest.pszText = xsh.GetExtraPtr();
|
||
|
tcDest.cchTextMax = pItemSrc->cchTextMax;
|
||
|
tcDest.iImage = pItemSrc->iImage;
|
||
|
tcDest.lParam = pItemSrc->lParam;
|
||
|
|
||
|
if( ! xsh.WriteSendMsgRead( & tcDest, hwnd, uiMsg, wParam, fCheckSend ) )
|
||
|
return E_FAIL;
|
||
|
|
||
|
// Copy back the struct out members...
|
||
|
pItemSrc->dwState = tcDest.dwState;
|
||
|
pItemSrc->dwStateMask = tcDest.dwStateMask;
|
||
|
pItemSrc->iImage = tcDest.iImage;
|
||
|
pItemSrc->lParam = tcDest.lParam;
|
||
|
|
||
|
// Copy text back out separately...
|
||
|
if( ! xsh.ReadExtra( pItemSrc->pszText, tcDest.pszText, TRUE ) )
|
||
|
return E_FAIL;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
template <class T>
|
||
|
HRESULT ToolInfo_Get_Handler( T & tiDest, HWND hwnd, UINT uiMsg, WPARAM wParam, TOOLINFO *pItemSrc, BOOL fCheckSend, UINT cchTextMax )
|
||
|
{
|
||
|
CXSendHelper xsh;
|
||
|
if( ! xsh.Alloc( hwnd, sizeof(T), sizeof(TCHAR) * cchTextMax ) )
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
// Copy to remote struct...
|
||
|
tiDest.cbSize = sizeof( tiDest );
|
||
|
tiDest.uFlags = pItemSrc->uFlags;
|
||
|
tiDest.uId = pItemSrc->uId;
|
||
|
tiDest.hwnd = pItemSrc->hwnd;
|
||
|
tiDest.lpszText = xsh.GetExtraPtr();
|
||
|
|
||
|
// Don't fail if the message is TTM_GETTEXT and 0 is returned - that's OK for that message.
|
||
|
// (TTM_GETTEXT has no documented return value!)
|
||
|
if( ! xsh.WriteSendMsgRead( & tiDest, hwnd, uiMsg, wParam, fCheckSend ) )
|
||
|
return E_FAIL;
|
||
|
|
||
|
// Copy back the struct out members...
|
||
|
pItemSrc->uFlags = tiDest.uFlags;
|
||
|
pItemSrc->uId = tiDest.uId;
|
||
|
pItemSrc->rect = tiDest.rect;
|
||
|
|
||
|
// Copy text back out...
|
||
|
if( ! xsh.ReadExtra( pItemSrc->lpszText, tiDest.lpszText, TRUE ) )
|
||
|
return E_FAIL;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
template <class T>
|
||
|
HRESULT ToolInfo_GetTitle_Handler( T & tiDest, HWND hwnd, UINT uiMsg, WPARAM wParam, TTGETTITLE *pItemSrc, BOOL fCheckSend, UINT )
|
||
|
{
|
||
|
CXSendHelper xsh;
|
||
|
if( ! xsh.Alloc( hwnd, sizeof(T), sizeof(TCHAR) * pItemSrc->cch ) )
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
// Copy to remote struct...
|
||
|
tiDest.dwSize = sizeof( tiDest );
|
||
|
tiDest.cch = pItemSrc->cch;
|
||
|
tiDest.pszTitle = xsh.GetExtraPtr();
|
||
|
|
||
|
if( ! xsh.WriteSendMsgRead( & tiDest, hwnd, uiMsg, wParam, fCheckSend ) )
|
||
|
return E_FAIL;
|
||
|
|
||
|
// Copy back the struct out members...
|
||
|
pItemSrc->uTitleBitmap = tiDest.uTitleBitmap;
|
||
|
|
||
|
// Copy text back out...
|
||
|
if( ! xsh.ReadExtra( pItemSrc->pszTitle, tiDest.pszTitle, TRUE ) )
|
||
|
return E_FAIL;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Cross-proc sendmessage stub macro
|
||
|
//
|
||
|
// All cross-proc SendMessage code has the same basic structure - some tests
|
||
|
// to determine if a cross proc send message is needed in the first place -
|
||
|
// if not, we can do a regular local SendMessage instead.
|
||
|
// If we do need to do a remote SendMessage, we call either a 32-bit or 64-bit
|
||
|
// "handler" routine based on the bitness of the target proxy.
|
||
|
//
|
||
|
// Since this code is the same for all cases, a #define is used to avoid
|
||
|
// duplication of code.
|
||
|
//
|
||
|
//
|
||
|
// DEFINE_XSEND_STUB takes the following parameters:
|
||
|
//
|
||
|
// Name - the name of the function being defined
|
||
|
// Handler - the name of the cross-proc handler (see above)
|
||
|
// Type - base type used.
|
||
|
// CheckSendExpr - expression that indicates if the result of SendMessage
|
||
|
// should be checked. Most - but not all - messages return
|
||
|
// TRUE to indicate success.
|
||
|
//
|
||
|
//
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
// For a given type - eg. LVITEM - this macro sets LVITEM_THIS and
|
||
|
// LVITEM_REMOTE to be typedef'd to LVITEM_32 and LVITEM_64 as appropriate,
|
||
|
// depending on whether this is 32- or 64- bit code.
|
||
|
//
|
||
|
// This relies on the base struct (eg. LVITEM) having the same base name as the
|
||
|
// explicit 32- and 64- bit structs which are defined above.
|
||
|
|
||
|
#ifdef _WIN64
|
||
|
#define DEFINE_TYPE_6432( Type ) typedef Type ## _64 Type ## _THIS; typedef Type ## _32 Type ## _REMOTE;
|
||
|
#else
|
||
|
#define DEFINE_TYPE_6432( Type ) typedef Type ## _32 Type ## _THIS; typedef Type ## _64 Type ## _REMOTE;
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#define DEFINE_XSEND_STUB( Name, Handler, Type, CheckSendExpr ) /**/ \
|
||
|
HRESULT Name ( HWND hwnd, UINT uiMsg, WPARAM wParam, Type * pItem, UINT uiParam )\
|
||
|
{\
|
||
|
/* Optimize if in same process...*/\
|
||
|
DWORD dwProcessId;\
|
||
|
if( ! GetWindowThreadProcessId( hwnd, & dwProcessId ) )\
|
||
|
return E_FAIL;\
|
||
|
\
|
||
|
BOOL fCheckSend = CheckSendExpr;\
|
||
|
\
|
||
|
if( dwProcessId == GetCurrentProcessId() )\
|
||
|
{\
|
||
|
DBPRINTF( TEXT("Inprocess") );\
|
||
|
if( ! SendMessage( hwnd, uiMsg, wParam, (LPARAM) pItem ) && fCheckSend )\
|
||
|
{\
|
||
|
DBPRINTF( TEXT("SendMessag failed") );\
|
||
|
return E_FAIL;\
|
||
|
}\
|
||
|
\
|
||
|
return S_OK;\
|
||
|
}\
|
||
|
\
|
||
|
/* Otherwise pass the correct type off to the template function...*/\
|
||
|
BOOL fIsSameBitness;\
|
||
|
if( FAILED( SameBitness( hwnd, & fIsSameBitness ) ) )\
|
||
|
return E_FAIL;\
|
||
|
\
|
||
|
if( fIsSameBitness )\
|
||
|
{\
|
||
|
Type ## _THIS t;\
|
||
|
memset( & t, 0, sizeof( t ) );\
|
||
|
return Handler( t, hwnd, uiMsg, wParam, pItem, fCheckSend, uiParam );\
|
||
|
}\
|
||
|
else\
|
||
|
{\
|
||
|
Type ## _REMOTE t;\
|
||
|
memset( & t, 0, sizeof( t ) );\
|
||
|
return Handler( t, hwnd, uiMsg, wParam, pItem, fCheckSend, uiParam );\
|
||
|
}\
|
||
|
}
|
||
|
|
||
|
|
||
|
DEFINE_TYPE_6432( LVITEM )
|
||
|
DEFINE_TYPE_6432( LVITEM_V6 )
|
||
|
DEFINE_TYPE_6432( LVGROUP_V6 )
|
||
|
DEFINE_TYPE_6432( LVCOLUMN )
|
||
|
DEFINE_TYPE_6432( TCITEM )
|
||
|
DEFINE_TYPE_6432( HDITEM )
|
||
|
DEFINE_TYPE_6432( TOOLINFO )
|
||
|
DEFINE_TYPE_6432( TTGETTITLE )
|
||
|
|
||
|
DEFINE_XSEND_STUB( XSend_ListView_GetItem, ListView_Get_Handler, LVITEM, TRUE )
|
||
|
DEFINE_XSEND_STUB( XSend_ListView_SetItem, ListView_Set_Handler, LVITEM, FALSE )
|
||
|
DEFINE_XSEND_STUB( XSend_ListView_GetColumn, ListView_GetCol_Handler, LVCOLUMN, TRUE )
|
||
|
DEFINE_XSEND_STUB( XSend_ListView_V6_GetItem, ListView_V6_Get_Handler, LVITEM_V6, pItem->puColumns != NULL )
|
||
|
DEFINE_XSEND_STUB( XSend_ListView_V6_GetGroupInfo, ListView_V6_GetGroup_Handler, LVGROUP_V6, TRUE )
|
||
|
DEFINE_XSEND_STUB( XSend_TabCtrl_GetItem, TabCtrl_Get_Handler, TCITEM, TRUE )
|
||
|
DEFINE_XSEND_STUB( XSend_HeaderCtrl_GetItem, HeaderCtrl_Get_Handler, HDITEM, TRUE )
|
||
|
DEFINE_XSEND_STUB( XSend_ToolTip_GetItem, ToolInfo_Get_Handler, TOOLINFO, uiMsg != TTM_GETTEXT )
|
||
|
DEFINE_XSEND_STUB( XSend_ToolTip_GetTitle, ToolInfo_GetTitle_Handler, TTGETTITLE, TRUE )
|
||
|
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
//
|
||
|
// GetRemoteProxyFactory()
|
||
|
//
|
||
|
// Returns an AddRef'd proxy factory for the other bitness
|
||
|
//
|
||
|
|
||
|
CComPtr<IRemoteProxyFactory> g_pRemoteProxyFactory; // Only a single instance. CComPtr
|
||
|
// will release on dll unload.
|
||
|
|
||
|
HRESULT GetRemoteProxyFactory(IRemoteProxyFactory **pRPF)
|
||
|
{
|
||
|
if (IsBadWritePtr(pRPF, sizeof(IRemoteProxyFactory *)))
|
||
|
return E_POINTER;
|
||
|
|
||
|
*pRPF = NULL;
|
||
|
|
||
|
if (!g_pRemoteProxyFactory)
|
||
|
{
|
||
|
HRESULT hr = CoCreateInstance(
|
||
|
#ifdef _WIN64
|
||
|
CLSID_RemoteProxyFactory32
|
||
|
#else
|
||
|
CLSID_RemoteProxyFactory64
|
||
|
#endif
|
||
|
, NULL
|
||
|
, CLSCTX_LOCAL_SERVER
|
||
|
, IID_IRemoteProxyFactory
|
||
|
, reinterpret_cast<void **>(&g_pRemoteProxyFactory));
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
DBPRINTF(TEXT("GetRemoteProxyFactory: CoCreateInstance FAILED "));
|
||
|
#ifdef _WIN64
|
||
|
DBPRINTF(TEXT("for clsid 0x%x\r\n"), CLSID_RemoteProxyFactory32.Data1);
|
||
|
#else
|
||
|
DBPRINTF(TEXT("for clsid 0x%x\r\n"), CLSID_RemoteProxyFactory64.Data1);
|
||
|
#endif
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
if (!g_pRemoteProxyFactory)
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
DBPRINTF(TEXT("GetRemoteProxyFactory: CoCreateInstance SUCCEEDED\r\n"));
|
||
|
*pRPF = g_pRemoteProxyFactory;
|
||
|
(*pRPF)->AddRef();
|
||
|
|
||
|
return S_OK;
|
||
|
}
|