mirror of
git://source.winehq.org/git/wine.git
synced 2024-11-05 18:01:34 +00:00
455 lines
16 KiB
C
455 lines
16 KiB
C
/*
|
|
* NDR Serialization Services
|
|
*
|
|
* Copyright (c) 2007 Robert Shearman for CodeWeavers
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
|
|
#include "windef.h"
|
|
#include "winbase.h"
|
|
#include "winerror.h"
|
|
#include "rpc.h"
|
|
#include "midles.h"
|
|
#include "ndrtypes.h"
|
|
|
|
#include "ndr_misc.h"
|
|
#include "ndr_stubless.h"
|
|
|
|
#include "wine/debug.h"
|
|
#include "wine/rpcfc.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(ole);
|
|
|
|
static inline void init_MIDL_ES_MESSAGE(MIDL_ES_MESSAGE *pEsMsg)
|
|
{
|
|
memset(pEsMsg, 0, sizeof(*pEsMsg));
|
|
/* even if we are unmarshalling, as we don't want pointers to be pointed
|
|
* to buffer memory */
|
|
pEsMsg->StubMsg.IsClient = TRUE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MesEncodeIncrementalHandleCreate [RPCRT4.@]
|
|
*/
|
|
RPC_STATUS WINAPI MesEncodeIncrementalHandleCreate(
|
|
void *UserState, MIDL_ES_ALLOC AllocFn, MIDL_ES_WRITE WriteFn,
|
|
handle_t *pHandle)
|
|
{
|
|
MIDL_ES_MESSAGE *pEsMsg;
|
|
|
|
TRACE("(%p, %p, %p, %p)\n", UserState, AllocFn, WriteFn, pHandle);
|
|
|
|
pEsMsg = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEsMsg));
|
|
if (!pEsMsg)
|
|
return ERROR_OUTOFMEMORY;
|
|
|
|
init_MIDL_ES_MESSAGE(pEsMsg);
|
|
|
|
pEsMsg->Operation = MES_ENCODE;
|
|
pEsMsg->UserState = UserState;
|
|
pEsMsg->HandleStyle = MES_INCREMENTAL_HANDLE;
|
|
pEsMsg->Alloc = AllocFn;
|
|
pEsMsg->Write = WriteFn;
|
|
|
|
*pHandle = (handle_t)pEsMsg;
|
|
|
|
return RPC_S_OK;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MesDecodeIncrementalHandleCreate [RPCRT4.@]
|
|
*/
|
|
RPC_STATUS WINAPI MesDecodeIncrementalHandleCreate(
|
|
void *UserState, MIDL_ES_READ ReadFn, handle_t *pHandle)
|
|
{
|
|
MIDL_ES_MESSAGE *pEsMsg;
|
|
|
|
TRACE("(%p, %p, %p)\n", UserState, ReadFn, pHandle);
|
|
|
|
pEsMsg = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEsMsg));
|
|
if (!pEsMsg)
|
|
return ERROR_OUTOFMEMORY;
|
|
|
|
init_MIDL_ES_MESSAGE(pEsMsg);
|
|
|
|
pEsMsg->Operation = MES_DECODE;
|
|
pEsMsg->UserState = UserState;
|
|
pEsMsg->HandleStyle = MES_INCREMENTAL_HANDLE;
|
|
pEsMsg->Read = ReadFn;
|
|
|
|
*pHandle = (handle_t)pEsMsg;
|
|
|
|
return RPC_S_OK;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MesIncrementalHandleReset [RPCRT4.@]
|
|
*/
|
|
RPC_STATUS WINAPI MesIncrementalHandleReset(
|
|
handle_t Handle, void *UserState, MIDL_ES_ALLOC AllocFn,
|
|
MIDL_ES_WRITE WriteFn, MIDL_ES_READ ReadFn, MIDL_ES_CODE Operation)
|
|
{
|
|
MIDL_ES_MESSAGE *pEsMsg = Handle;
|
|
|
|
TRACE("(%p, %p, %p, %p, %p, %d)\n", Handle, UserState, AllocFn,
|
|
WriteFn, ReadFn, Operation);
|
|
|
|
init_MIDL_ES_MESSAGE(pEsMsg);
|
|
|
|
pEsMsg->Operation = Operation;
|
|
pEsMsg->UserState = UserState;
|
|
pEsMsg->HandleStyle = MES_INCREMENTAL_HANDLE;
|
|
pEsMsg->Alloc = AllocFn;
|
|
pEsMsg->Write = WriteFn;
|
|
pEsMsg->Read = ReadFn;
|
|
|
|
return RPC_S_OK;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MesHandleFree [RPCRT4.@]
|
|
*/
|
|
RPC_STATUS WINAPI MesHandleFree(handle_t Handle)
|
|
{
|
|
TRACE("(%p)\n", Handle);
|
|
HeapFree(GetProcessHeap(), 0, Handle);
|
|
return RPC_S_OK;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MesEncodeFixedBufferHandleCreate [RPCRT4.@]
|
|
*/
|
|
RPC_STATUS RPC_ENTRY MesEncodeFixedBufferHandleCreate(
|
|
char *Buffer, ULONG BufferSize, ULONG *pEncodedSize, handle_t *pHandle)
|
|
{
|
|
MIDL_ES_MESSAGE *pEsMsg;
|
|
|
|
TRACE("(%p, %d, %p, %p)\n", Buffer, BufferSize, pEncodedSize, pHandle);
|
|
|
|
pEsMsg = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEsMsg));
|
|
if (!pEsMsg)
|
|
return ERROR_OUTOFMEMORY;
|
|
|
|
init_MIDL_ES_MESSAGE(pEsMsg);
|
|
|
|
pEsMsg->Operation = MES_ENCODE;
|
|
pEsMsg->HandleStyle = MES_FIXED_BUFFER_HANDLE;
|
|
pEsMsg->Buffer = (unsigned char *)Buffer;
|
|
pEsMsg->BufferSize = BufferSize;
|
|
pEsMsg->pEncodedSize = pEncodedSize;
|
|
|
|
*pHandle = (handle_t)pEsMsg;
|
|
|
|
return RPC_S_OK;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MesEncodeDynBufferHandleCreate [RPCRT4.@]
|
|
*/
|
|
RPC_STATUS RPC_ENTRY MesEncodeDynBufferHandleCreate(char **ppBuffer,
|
|
ULONG *pEncodedSize, handle_t *pHandle)
|
|
{
|
|
FIXME("%p %p %p stub\n", ppBuffer, pEncodedSize, pHandle);
|
|
return RPC_S_OK;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MesDecodeBufferHandleCreate [RPCRT4.@]
|
|
*/
|
|
RPC_STATUS RPC_ENTRY MesDecodeBufferHandleCreate(
|
|
char *Buffer, ULONG BufferSize, handle_t *pHandle)
|
|
{
|
|
MIDL_ES_MESSAGE *pEsMsg;
|
|
|
|
TRACE("(%p, %d, %p)\n", Buffer, BufferSize, pHandle);
|
|
|
|
pEsMsg = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEsMsg));
|
|
if (!pEsMsg)
|
|
return ERROR_OUTOFMEMORY;
|
|
|
|
init_MIDL_ES_MESSAGE(pEsMsg);
|
|
|
|
pEsMsg->Operation = MES_DECODE;
|
|
pEsMsg->HandleStyle = MES_FIXED_BUFFER_HANDLE;
|
|
pEsMsg->Buffer = (unsigned char *)Buffer;
|
|
pEsMsg->BufferSize = BufferSize;
|
|
|
|
*pHandle = (handle_t)pEsMsg;
|
|
|
|
return RPC_S_OK;
|
|
}
|
|
|
|
static void es_data_alloc(MIDL_ES_MESSAGE *pEsMsg, ULONG size)
|
|
{
|
|
if (pEsMsg->HandleStyle == MES_INCREMENTAL_HANDLE)
|
|
{
|
|
unsigned int tmpsize = size;
|
|
TRACE("%d with incremental handle\n", size);
|
|
pEsMsg->Alloc(pEsMsg->UserState, (char **)&pEsMsg->StubMsg.Buffer, &tmpsize);
|
|
if (tmpsize < size)
|
|
{
|
|
ERR("not enough bytes allocated - requested %d, got %d\n", size, tmpsize);
|
|
RpcRaiseException(ERROR_OUTOFMEMORY);
|
|
}
|
|
}
|
|
else if (pEsMsg->HandleStyle == MES_FIXED_BUFFER_HANDLE)
|
|
{
|
|
TRACE("%d with fixed buffer handle\n", size);
|
|
pEsMsg->StubMsg.Buffer = pEsMsg->Buffer;
|
|
}
|
|
pEsMsg->StubMsg.RpcMsg->Buffer = pEsMsg->StubMsg.BufferStart = pEsMsg->StubMsg.Buffer;
|
|
}
|
|
|
|
static void es_data_read(MIDL_ES_MESSAGE *pEsMsg, ULONG size)
|
|
{
|
|
if (pEsMsg->HandleStyle == MES_INCREMENTAL_HANDLE)
|
|
{
|
|
unsigned int tmpsize = size;
|
|
TRACE("%d from incremental handle\n", size);
|
|
pEsMsg->Read(pEsMsg->UserState, (char **)&pEsMsg->StubMsg.Buffer, &tmpsize);
|
|
if (tmpsize < size)
|
|
{
|
|
ERR("not enough bytes read - requested %d, got %d\n", size, tmpsize);
|
|
RpcRaiseException(ERROR_OUTOFMEMORY);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRACE("%d from fixed or dynamic buffer handle\n", size);
|
|
/* FIXME: validate BufferSize? */
|
|
pEsMsg->StubMsg.Buffer = pEsMsg->Buffer;
|
|
pEsMsg->Buffer += size;
|
|
pEsMsg->BufferSize -= size;
|
|
}
|
|
pEsMsg->StubMsg.BufferLength = size;
|
|
pEsMsg->StubMsg.RpcMsg->Buffer = pEsMsg->StubMsg.BufferStart = pEsMsg->StubMsg.Buffer;
|
|
pEsMsg->StubMsg.BufferEnd = pEsMsg->StubMsg.Buffer + size;
|
|
}
|
|
|
|
static void es_data_write(MIDL_ES_MESSAGE *pEsMsg, ULONG size)
|
|
{
|
|
if (pEsMsg->HandleStyle == MES_INCREMENTAL_HANDLE)
|
|
{
|
|
TRACE("%d to incremental handle\n", size);
|
|
pEsMsg->Write(pEsMsg->UserState, (char *)pEsMsg->StubMsg.BufferStart, size);
|
|
}
|
|
else
|
|
{
|
|
TRACE("%d to dynamic or fixed buffer handle\n", size);
|
|
*pEsMsg->pEncodedSize += size;
|
|
}
|
|
}
|
|
|
|
static inline ULONG mes_proc_header_buffer_size(void)
|
|
{
|
|
return 4 + 2*sizeof(RPC_SYNTAX_IDENTIFIER) + 12;
|
|
}
|
|
|
|
static void mes_proc_header_marshal(MIDL_ES_MESSAGE *pEsMsg)
|
|
{
|
|
const RPC_CLIENT_INTERFACE *client_interface = pEsMsg->StubMsg.StubDesc->RpcInterfaceInformation;
|
|
*(WORD *)pEsMsg->StubMsg.Buffer = 0x0101;
|
|
pEsMsg->StubMsg.Buffer += 2;
|
|
*(WORD *)pEsMsg->StubMsg.Buffer = 0xcccc;
|
|
pEsMsg->StubMsg.Buffer += 2;
|
|
memcpy(pEsMsg->StubMsg.Buffer, &client_interface->TransferSyntax, sizeof(RPC_SYNTAX_IDENTIFIER));
|
|
pEsMsg->StubMsg.Buffer += sizeof(RPC_SYNTAX_IDENTIFIER);
|
|
memcpy(pEsMsg->StubMsg.Buffer, &pEsMsg->InterfaceId, sizeof(RPC_SYNTAX_IDENTIFIER));
|
|
pEsMsg->StubMsg.Buffer += sizeof(RPC_SYNTAX_IDENTIFIER);
|
|
*(DWORD *)pEsMsg->StubMsg.Buffer = pEsMsg->ProcNumber;
|
|
pEsMsg->StubMsg.Buffer += 4;
|
|
*(DWORD *)pEsMsg->StubMsg.Buffer = 0x00000001;
|
|
pEsMsg->StubMsg.Buffer += 4;
|
|
*(DWORD *)pEsMsg->StubMsg.Buffer = pEsMsg->ByteCount;
|
|
pEsMsg->StubMsg.Buffer += 4;
|
|
}
|
|
|
|
static void mes_proc_header_unmarshal(MIDL_ES_MESSAGE *pEsMsg)
|
|
{
|
|
const RPC_CLIENT_INTERFACE *client_interface = pEsMsg->StubMsg.StubDesc->RpcInterfaceInformation;
|
|
|
|
es_data_read(pEsMsg, mes_proc_header_buffer_size());
|
|
|
|
if (*(WORD *)pEsMsg->StubMsg.Buffer != 0x0101)
|
|
{
|
|
FIXME("unknown value at Buffer[0] 0x%04x\n", *(WORD *)pEsMsg->StubMsg.Buffer);
|
|
RpcRaiseException(RPC_X_WRONG_ES_VERSION);
|
|
}
|
|
pEsMsg->StubMsg.Buffer += 2;
|
|
if (*(WORD *)pEsMsg->StubMsg.Buffer != 0xcccc)
|
|
FIXME("unknown value at Buffer[2] 0x%04x\n", *(WORD *)pEsMsg->StubMsg.Buffer);
|
|
pEsMsg->StubMsg.Buffer += 2;
|
|
if (memcmp(pEsMsg->StubMsg.Buffer, &client_interface->TransferSyntax, sizeof(RPC_SYNTAX_IDENTIFIER)))
|
|
{
|
|
const RPC_SYNTAX_IDENTIFIER *AlienTransferSyntax = (const RPC_SYNTAX_IDENTIFIER *)pEsMsg->StubMsg.Buffer;
|
|
ERR("bad transfer syntax %s {%d.%d}\n", debugstr_guid(&AlienTransferSyntax->SyntaxGUID),
|
|
AlienTransferSyntax->SyntaxVersion.MajorVersion,
|
|
AlienTransferSyntax->SyntaxVersion.MinorVersion);
|
|
RpcRaiseException(RPC_S_UNSUPPORTED_TRANS_SYN);
|
|
}
|
|
pEsMsg->StubMsg.Buffer += sizeof(RPC_SYNTAX_IDENTIFIER);
|
|
memcpy(&pEsMsg->InterfaceId, pEsMsg->StubMsg.Buffer, sizeof(RPC_SYNTAX_IDENTIFIER));
|
|
pEsMsg->StubMsg.Buffer += sizeof(RPC_SYNTAX_IDENTIFIER);
|
|
pEsMsg->ProcNumber = *(DWORD *)pEsMsg->StubMsg.Buffer;
|
|
pEsMsg->StubMsg.Buffer += 4;
|
|
if (*(DWORD *)pEsMsg->StubMsg.Buffer != 0x00000001)
|
|
FIXME("unknown value 0x%08x, expected 0x00000001\n", *(DWORD *)pEsMsg->StubMsg.Buffer);
|
|
pEsMsg->StubMsg.Buffer += 4;
|
|
pEsMsg->ByteCount = *(DWORD *)pEsMsg->StubMsg.Buffer;
|
|
pEsMsg->StubMsg.Buffer += 4;
|
|
if (pEsMsg->ByteCount + mes_proc_header_buffer_size() < pEsMsg->ByteCount)
|
|
RpcRaiseException(RPC_S_INVALID_BOUND);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* NdrMesProcEncodeDecode [RPCRT4.@]
|
|
*/
|
|
void WINAPIV NdrMesProcEncodeDecode(handle_t Handle, const MIDL_STUB_DESC * pStubDesc, PFORMAT_STRING pFormat, ...)
|
|
{
|
|
/* pointer to start of stack where arguments start */
|
|
RPC_MESSAGE rpcMsg;
|
|
MIDL_ES_MESSAGE *pEsMsg = Handle;
|
|
/* size of stack */
|
|
unsigned short stack_size;
|
|
/* header for procedure string */
|
|
const NDR_PROC_HEADER *pProcHeader = (const NDR_PROC_HEADER *)&pFormat[0];
|
|
const RPC_CLIENT_INTERFACE *client_interface;
|
|
__ms_va_list args;
|
|
unsigned int number_of_params;
|
|
ULONG_PTR arg_buffer[256];
|
|
|
|
TRACE("Handle %p, pStubDesc %p, pFormat %p, ...\n", Handle, pStubDesc, pFormat);
|
|
|
|
/* Later NDR language versions probably won't be backwards compatible */
|
|
if (pStubDesc->Version > 0x50002)
|
|
{
|
|
FIXME("Incompatible stub description version: 0x%x\n", pStubDesc->Version);
|
|
RpcRaiseException(RPC_X_WRONG_STUB_VERSION);
|
|
}
|
|
|
|
client_interface = pStubDesc->RpcInterfaceInformation;
|
|
pEsMsg->InterfaceId = client_interface->InterfaceId;
|
|
|
|
if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS)
|
|
{
|
|
const NDR_PROC_HEADER_RPC *header_rpc = (const NDR_PROC_HEADER_RPC *)&pFormat[0];
|
|
stack_size = header_rpc->stack_size;
|
|
pEsMsg->ProcNumber = header_rpc->proc_num;
|
|
pFormat += sizeof(NDR_PROC_HEADER_RPC);
|
|
}
|
|
else
|
|
{
|
|
stack_size = pProcHeader->stack_size;
|
|
pEsMsg->ProcNumber = pProcHeader->proc_num;
|
|
pFormat += sizeof(NDR_PROC_HEADER);
|
|
}
|
|
|
|
if (pProcHeader->handle_type == RPC_FC_BIND_EXPLICIT)
|
|
{
|
|
switch (*pFormat) /* handle_type */
|
|
{
|
|
case RPC_FC_BIND_PRIMITIVE: /* explicit primitive */
|
|
pFormat += sizeof(NDR_EHD_PRIMITIVE);
|
|
break;
|
|
case RPC_FC_BIND_GENERIC: /* explicit generic */
|
|
pFormat += sizeof(NDR_EHD_GENERIC);
|
|
break;
|
|
case RPC_FC_BIND_CONTEXT: /* explicit context */
|
|
pFormat += sizeof(NDR_EHD_CONTEXT);
|
|
break;
|
|
default:
|
|
ERR("bad explicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
|
|
RpcRaiseException(RPC_X_BAD_STUB_DATA);
|
|
}
|
|
}
|
|
|
|
TRACE("stack size: 0x%x\n", stack_size);
|
|
TRACE("proc num: %d\n", pEsMsg->ProcNumber);
|
|
|
|
memset(&rpcMsg, 0, sizeof(rpcMsg));
|
|
pEsMsg->StubMsg.RpcMsg = &rpcMsg;
|
|
pEsMsg->StubMsg.StubDesc = pStubDesc;
|
|
pEsMsg->StubMsg.pfnAllocate = pStubDesc->pfnAllocate;
|
|
pEsMsg->StubMsg.pfnFree = pStubDesc->pfnFree;
|
|
|
|
/* create the full pointer translation tables, if requested */
|
|
if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR)
|
|
pEsMsg->StubMsg.FullPtrXlatTables = NdrFullPointerXlatInit(0,XLAT_CLIENT);
|
|
|
|
TRACE("Oi_flags = 0x%02x\n", pProcHeader->Oi_flags);
|
|
TRACE("stubdesc version = 0x%x\n", pStubDesc->Version);
|
|
TRACE("MIDL stub version = 0x%x\n", pStubDesc->MIDLVersion);
|
|
|
|
/* needed for conformance of top-level objects */
|
|
__ms_va_start( args, pFormat );
|
|
pEsMsg->StubMsg.StackTop = va_arg( args, unsigned char * );
|
|
__ms_va_end( args );
|
|
|
|
pFormat = convert_old_args( &pEsMsg->StubMsg, pFormat, stack_size, FALSE,
|
|
arg_buffer, sizeof(arg_buffer), &number_of_params );
|
|
|
|
switch (pEsMsg->Operation)
|
|
{
|
|
case MES_ENCODE:
|
|
pEsMsg->StubMsg.BufferLength = mes_proc_header_buffer_size();
|
|
|
|
client_do_args( &pEsMsg->StubMsg, pFormat, STUBLESS_CALCSIZE, NULL, number_of_params, NULL );
|
|
|
|
pEsMsg->ByteCount = pEsMsg->StubMsg.BufferLength - mes_proc_header_buffer_size();
|
|
es_data_alloc(pEsMsg, pEsMsg->StubMsg.BufferLength);
|
|
|
|
mes_proc_header_marshal(pEsMsg);
|
|
|
|
client_do_args( &pEsMsg->StubMsg, pFormat, STUBLESS_MARSHAL, NULL, number_of_params, NULL );
|
|
|
|
es_data_write(pEsMsg, pEsMsg->ByteCount);
|
|
break;
|
|
case MES_DECODE:
|
|
mes_proc_header_unmarshal(pEsMsg);
|
|
|
|
es_data_read(pEsMsg, pEsMsg->ByteCount);
|
|
|
|
client_do_args( &pEsMsg->StubMsg, pFormat, STUBLESS_UNMARSHAL, NULL, number_of_params, NULL );
|
|
break;
|
|
default:
|
|
RpcRaiseException(RPC_S_INTERNAL_ERROR);
|
|
return;
|
|
}
|
|
/* free the full pointer translation tables */
|
|
if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR)
|
|
NdrFullPointerXlatFree(pEsMsg->StubMsg.FullPtrXlatTables);
|
|
}
|
|
|
|
void RPC_ENTRY NdrMesTypeDecode2(handle_t Handle, const MIDL_TYPE_PICKLING_INFO *pPicklingInfo,
|
|
const MIDL_STUB_DESC *pStubDesc, PFORMAT_STRING pFormatString, void *pObject)
|
|
{
|
|
FIXME("(%p, %p, %p, %p, %p)\n", Handle, pPicklingInfo, pStubDesc, pFormatString, pObject);
|
|
}
|
|
|
|
void RPC_ENTRY NdrMesTypeEncode2(handle_t Handle, const MIDL_TYPE_PICKLING_INFO *pPicklingInfo,
|
|
const MIDL_STUB_DESC *pStubDesc, PFORMAT_STRING pFormatString, const void *pObject)
|
|
{
|
|
FIXME("(%p, %p, %p, %p, %p)\n", Handle, pPicklingInfo, pStubDesc, pFormatString, pObject);
|
|
}
|
|
|
|
void RPC_ENTRY NdrMesTypeFree2(handle_t Handle, const MIDL_TYPE_PICKLING_INFO *pPicklingInfo,
|
|
const MIDL_STUB_DESC *pStubDesc, PFORMAT_STRING pFormatString, void *pObject)
|
|
{
|
|
FIXME("(%p, %p, %p, %p, %p)\n", Handle, pPicklingInfo, pStubDesc, pFormatString, pObject);
|
|
}
|