1446 lines
42 KiB
C
1446 lines
42 KiB
C
/*
|
|
* Unit test suite for cstubs
|
|
*
|
|
* Copyright 2006 Huw Davies
|
|
*
|
|
* 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>
|
|
|
|
#define COBJMACROS
|
|
|
|
#include <windef.h>
|
|
#include <winbase.h>
|
|
#include <winnt.h>
|
|
#include <winerror.h>
|
|
|
|
#include "initguid.h"
|
|
#include <ole2.h>
|
|
#include "rpc.h"
|
|
#include "rpcdce.h"
|
|
#include "rpcproxy.h"
|
|
|
|
#include "wine/heap.h"
|
|
#include "wine/test.h"
|
|
|
|
#include "cstub.h"
|
|
|
|
static CStdPSFactoryBuffer PSFactoryBuffer;
|
|
|
|
static ULONG WINAPI test_CStdStubBuffer_Release(IRpcStubBuffer *This)
|
|
{
|
|
return NdrCStdStubBuffer_Release(This, (IPSFactoryBuffer *)&PSFactoryBuffer);
|
|
}
|
|
|
|
static ULONG WINAPI test_CStdStubBuffer2_Release(IRpcStubBuffer *This)
|
|
{
|
|
return NdrCStdStubBuffer2_Release(This, (IPSFactoryBuffer *)&PSFactoryBuffer);
|
|
}
|
|
|
|
static GUID IID_if1 = {0x12345678, 1234, 5678, {12,34,56,78,90,0xab,0xcd,0xef}};
|
|
static GUID IID_if2 = {0x12345679, 1234, 5678, {12,34,56,78,90,0xab,0xcd,0xef}};
|
|
static GUID IID_if3 = {0x1234567a, 1234, 5678, {12,34,56,78,90,0xab,0xcd,0xef}};
|
|
static GUID IID_if4 = {0x1234567b, 1234, 5678, {12,34,56,78,90,0xab,0xcd,0xef}};
|
|
static CLSID CLSID_psfact = {0x1234567c, 1234, 5678, {12,34,56,78,90,0xab,0xcd,0xef}};
|
|
|
|
static int my_alloc_called;
|
|
static int my_free_called;
|
|
|
|
static void * CALLBACK my_alloc(SIZE_T size)
|
|
{
|
|
my_alloc_called++;
|
|
return NdrOleAllocate(size);
|
|
}
|
|
|
|
static void CALLBACK my_free(void *ptr)
|
|
{
|
|
my_free_called++;
|
|
NdrOleFree(ptr);
|
|
}
|
|
|
|
typedef struct _MIDL_PROC_FORMAT_STRING
|
|
{
|
|
short Pad;
|
|
unsigned char Format[ 2 ];
|
|
} MIDL_PROC_FORMAT_STRING;
|
|
|
|
typedef struct _MIDL_TYPE_FORMAT_STRING
|
|
{
|
|
short Pad;
|
|
unsigned char Format[ 2 ];
|
|
} MIDL_TYPE_FORMAT_STRING;
|
|
|
|
|
|
static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString =
|
|
{
|
|
0,
|
|
{
|
|
0, 0
|
|
}
|
|
};
|
|
|
|
static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString =
|
|
{
|
|
0,
|
|
{
|
|
0, 0
|
|
}
|
|
};
|
|
|
|
static const MIDL_STUB_DESC Object_StubDesc =
|
|
{
|
|
NULL,
|
|
my_alloc,
|
|
my_free,
|
|
{ 0 },
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
__MIDL_TypeFormatString.Format,
|
|
1, /* -error bounds_check flag */
|
|
0x20000, /* Ndr library version */
|
|
0,
|
|
0x50100a4, /* MIDL Version 5.1.164 */
|
|
0,
|
|
NULL,
|
|
0, /* notify & notify_flag routine table */
|
|
1, /* Flags */
|
|
0, /* Reserved3 */
|
|
0, /* Reserved4 */
|
|
0 /* Reserved5 */
|
|
};
|
|
|
|
static HRESULT WINAPI if1_fn1_Proxy(void *This)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
static void __RPC_STUB if1_fn1_Stub(
|
|
IRpcStubBuffer *This,
|
|
IRpcChannelBuffer *_pRpcChannelBuffer,
|
|
PRPC_MESSAGE _pRpcMessage,
|
|
DWORD *_pdwStubPhase)
|
|
{
|
|
trace("fn1 stub\n");
|
|
}
|
|
|
|
static HRESULT WINAPI if1_fn2_Proxy(void *This)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
static void __RPC_STUB if1_fn2_Stub(
|
|
IRpcStubBuffer *This,
|
|
IRpcChannelBuffer *_pRpcChannelBuffer,
|
|
PRPC_MESSAGE _pRpcMessage,
|
|
DWORD *_pdwStubPhase)
|
|
{
|
|
trace("fn2 stub\n");
|
|
}
|
|
|
|
static CINTERFACE_PROXY_VTABLE(5) if1_proxy_vtbl =
|
|
{
|
|
{ &IID_if1 },
|
|
{ IUnknown_QueryInterface_Proxy,
|
|
IUnknown_AddRef_Proxy,
|
|
IUnknown_Release_Proxy ,
|
|
if1_fn1_Proxy,
|
|
if1_fn2_Proxy
|
|
}
|
|
};
|
|
|
|
|
|
static const unsigned short if1_FormatStringOffsetTable[] =
|
|
{
|
|
0,
|
|
0
|
|
};
|
|
|
|
static const MIDL_SERVER_INFO if1_server_info =
|
|
{
|
|
&Object_StubDesc,
|
|
0,
|
|
__MIDL_ProcFormatString.Format,
|
|
&if1_FormatStringOffsetTable[-3],
|
|
0,
|
|
0,
|
|
0,
|
|
0};
|
|
|
|
|
|
static const PRPC_STUB_FUNCTION if1_table[] =
|
|
{
|
|
if1_fn1_Stub,
|
|
if1_fn2_Stub
|
|
};
|
|
|
|
static CInterfaceStubVtbl if1_stub_vtbl =
|
|
{
|
|
{
|
|
&IID_if1,
|
|
&if1_server_info,
|
|
5,
|
|
&if1_table[-3]
|
|
},
|
|
{
|
|
CStdStubBuffer_QueryInterface,
|
|
CStdStubBuffer_AddRef,
|
|
test_CStdStubBuffer_Release,
|
|
CStdStubBuffer_Connect,
|
|
CStdStubBuffer_Disconnect,
|
|
CStdStubBuffer_Invoke,
|
|
CStdStubBuffer_IsIIDSupported,
|
|
CStdStubBuffer_CountRefs,
|
|
CStdStubBuffer_DebugServerQueryInterface,
|
|
CStdStubBuffer_DebugServerRelease
|
|
}
|
|
};
|
|
|
|
static CINTERFACE_PROXY_VTABLE(13) if2_proxy_vtbl =
|
|
{
|
|
{ &IID_if2 },
|
|
{ IUnknown_QueryInterface_Proxy,
|
|
IUnknown_AddRef_Proxy,
|
|
IUnknown_Release_Proxy ,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0
|
|
}
|
|
};
|
|
|
|
static const unsigned short if2_FormatStringOffsetTable[] =
|
|
{
|
|
(unsigned short) -1,
|
|
(unsigned short) -1,
|
|
(unsigned short) -1,
|
|
(unsigned short) -1,
|
|
(unsigned short) -1,
|
|
(unsigned short) -1,
|
|
(unsigned short) -1,
|
|
(unsigned short) -1,
|
|
(unsigned short) -1,
|
|
(unsigned short) -1,
|
|
0
|
|
};
|
|
|
|
static const MIDL_SERVER_INFO if2_server_info =
|
|
{
|
|
&Object_StubDesc,
|
|
0,
|
|
__MIDL_ProcFormatString.Format,
|
|
&if2_FormatStringOffsetTable[-3],
|
|
0,
|
|
0,
|
|
0,
|
|
0};
|
|
|
|
|
|
static const PRPC_STUB_FUNCTION if2_table[] =
|
|
{
|
|
STUB_FORWARDING_FUNCTION,
|
|
STUB_FORWARDING_FUNCTION,
|
|
STUB_FORWARDING_FUNCTION,
|
|
STUB_FORWARDING_FUNCTION,
|
|
STUB_FORWARDING_FUNCTION,
|
|
STUB_FORWARDING_FUNCTION,
|
|
STUB_FORWARDING_FUNCTION,
|
|
STUB_FORWARDING_FUNCTION,
|
|
STUB_FORWARDING_FUNCTION,
|
|
STUB_FORWARDING_FUNCTION
|
|
};
|
|
|
|
static CInterfaceStubVtbl if2_stub_vtbl =
|
|
{
|
|
{
|
|
&IID_if2,
|
|
&if2_server_info,
|
|
13,
|
|
&if2_table[-3]
|
|
},
|
|
{ 0, 0, test_CStdStubBuffer2_Release, 0, 0, 0, 0, 0, 0, 0 }
|
|
};
|
|
|
|
static CINTERFACE_PROXY_VTABLE(5) if3_proxy_vtbl =
|
|
{
|
|
{ &IID_if3 },
|
|
{ IUnknown_QueryInterface_Proxy,
|
|
IUnknown_AddRef_Proxy,
|
|
IUnknown_Release_Proxy ,
|
|
if1_fn1_Proxy,
|
|
0
|
|
}
|
|
};
|
|
|
|
|
|
static const unsigned short if3_FormatStringOffsetTable[] =
|
|
{
|
|
0,
|
|
0
|
|
};
|
|
|
|
static const MIDL_SERVER_INFO if3_server_info =
|
|
{
|
|
&Object_StubDesc,
|
|
0,
|
|
__MIDL_ProcFormatString.Format,
|
|
&if3_FormatStringOffsetTable[-3],
|
|
0,
|
|
0,
|
|
0,
|
|
0};
|
|
|
|
static CInterfaceStubVtbl if3_stub_vtbl =
|
|
{
|
|
{
|
|
&IID_if3,
|
|
&if3_server_info,
|
|
5,
|
|
&if1_table[-3]
|
|
},
|
|
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
|
|
};
|
|
|
|
static CINTERFACE_PROXY_VTABLE(7) if4_proxy_vtbl =
|
|
{
|
|
{ &IID_if4 },
|
|
{ IUnknown_QueryInterface_Proxy,
|
|
IUnknown_AddRef_Proxy,
|
|
IUnknown_Release_Proxy ,
|
|
0,
|
|
0,
|
|
0,
|
|
0
|
|
}
|
|
};
|
|
|
|
static const unsigned short if4_FormatStringOffsetTable[] =
|
|
{
|
|
(unsigned short) -1,
|
|
(unsigned short) -1,
|
|
(unsigned short) -1,
|
|
(unsigned short) -1,
|
|
0
|
|
};
|
|
|
|
static const MIDL_SERVER_INFO if4_server_info =
|
|
{
|
|
&Object_StubDesc,
|
|
0,
|
|
__MIDL_ProcFormatString.Format,
|
|
&if4_FormatStringOffsetTable[-3],
|
|
0,
|
|
0,
|
|
0,
|
|
0};
|
|
|
|
static CInterfaceStubVtbl if4_stub_vtbl =
|
|
{
|
|
{
|
|
&IID_if4,
|
|
&if4_server_info,
|
|
7,
|
|
&if2_table[-3]
|
|
},
|
|
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
|
|
};
|
|
|
|
static const CInterfaceProxyVtbl *cstub_ProxyVtblList[] =
|
|
{
|
|
(const CInterfaceProxyVtbl *) &if1_proxy_vtbl,
|
|
(const CInterfaceProxyVtbl *) &if2_proxy_vtbl,
|
|
(const CInterfaceProxyVtbl *) &if3_proxy_vtbl,
|
|
(const CInterfaceProxyVtbl *) &if4_proxy_vtbl,
|
|
NULL
|
|
};
|
|
|
|
static const CInterfaceStubVtbl *cstub_StubVtblList[] =
|
|
{
|
|
&if1_stub_vtbl,
|
|
&if2_stub_vtbl,
|
|
&if3_stub_vtbl,
|
|
&if4_stub_vtbl,
|
|
NULL
|
|
};
|
|
|
|
static PCInterfaceName const if_name_list[] =
|
|
{
|
|
"if1",
|
|
"if2",
|
|
"if3",
|
|
"if4",
|
|
NULL
|
|
};
|
|
|
|
static const IID *base_iid_list[] =
|
|
{
|
|
NULL,
|
|
&IID_ITypeLib,
|
|
NULL,
|
|
&IID_IDispatch,
|
|
NULL
|
|
};
|
|
|
|
#define cstub_CHECK_IID(n) IID_GENERIC_CHECK_IID( cstub, pIID, n)
|
|
|
|
static int __stdcall iid_lookup( const IID * pIID, int * pIndex )
|
|
{
|
|
IID_BS_LOOKUP_SETUP
|
|
|
|
IID_BS_LOOKUP_INITIAL_TEST( cstub, 4, 4 )
|
|
IID_BS_LOOKUP_NEXT_TEST( cstub, 2 )
|
|
IID_BS_LOOKUP_NEXT_TEST( cstub, 1 )
|
|
IID_BS_LOOKUP_RETURN_RESULT( cstub, 4, *pIndex )
|
|
|
|
}
|
|
|
|
|
|
static BOOL check_address(void *actual, void *expected)
|
|
{
|
|
static void *ole32_start = NULL;
|
|
static void *ole32_end = NULL;
|
|
static void *combase_start = NULL;
|
|
static void *combase_end = NULL;
|
|
|
|
if (actual == expected)
|
|
return TRUE;
|
|
|
|
/* On Win7, actual can be located inside ole32.dll */
|
|
if (ole32_start == NULL || ole32_end == NULL)
|
|
{
|
|
PIMAGE_NT_HEADERS nt_headers;
|
|
ole32_start = (void *) GetModuleHandleA("ole32.dll");
|
|
if (ole32_start == NULL)
|
|
return FALSE;
|
|
nt_headers = (PIMAGE_NT_HEADERS)((char *) ole32_start + ((PIMAGE_DOS_HEADER) ole32_start)->e_lfanew);
|
|
ole32_end = (void *)((char *) ole32_start + nt_headers->OptionalHeader.SizeOfImage);
|
|
}
|
|
|
|
if (ole32_start <= actual && actual < ole32_end)
|
|
return TRUE;
|
|
|
|
/* On Win8, actual can be located inside combase.dll */
|
|
if (combase_start == NULL || combase_end == NULL)
|
|
{
|
|
PIMAGE_NT_HEADERS nt_headers;
|
|
combase_start = (void *) GetModuleHandleA("combase.dll");
|
|
if (combase_start == NULL)
|
|
return FALSE;
|
|
nt_headers = (PIMAGE_NT_HEADERS)((char *) combase_start + ((PIMAGE_DOS_HEADER) combase_start)->e_lfanew);
|
|
combase_end = (void *)((char *) combase_start + nt_headers->OptionalHeader.SizeOfImage);
|
|
}
|
|
|
|
return (combase_start <= actual && actual < combase_end);
|
|
}
|
|
|
|
static const ExtendedProxyFileInfo my_proxy_file_info =
|
|
{
|
|
(const PCInterfaceProxyVtblList *) &cstub_ProxyVtblList,
|
|
(const PCInterfaceStubVtblList *) &cstub_StubVtblList,
|
|
(const PCInterfaceName *) &if_name_list,
|
|
(const IID **) &base_iid_list,
|
|
&iid_lookup,
|
|
4,
|
|
1,
|
|
NULL,
|
|
0,
|
|
0,
|
|
0
|
|
};
|
|
|
|
static const ProxyFileInfo *proxy_file_list[] = {
|
|
&my_proxy_file_info,
|
|
NULL
|
|
};
|
|
|
|
|
|
static IPSFactoryBuffer *test_NdrDllGetClassObject(void)
|
|
{
|
|
HMODULE rpcrt4 = GetModuleHandleA("rpcrt4.dll");
|
|
IPSFactoryBuffer *ppsf = NULL;
|
|
const PCInterfaceProxyVtblList* proxy_vtbl;
|
|
const PCInterfaceStubVtblList* stub_vtbl;
|
|
const CLSID CLSID_Unknown = {0x45678, 0x1234, 0x6666, {0xff, 0x67, 0x45, 0x98, 0x76, 0x12, 0x34, 0x56}};
|
|
static const GUID * const interfaces[] = { &IID_if1, &IID_if2, &IID_if3, &IID_if4 };
|
|
UINT i;
|
|
HRESULT r;
|
|
HMODULE hmod = GetModuleHandleA("rpcrt4.dll");
|
|
void *CStd_QueryInterface = GetProcAddress(hmod, "CStdStubBuffer_QueryInterface");
|
|
void *CStd_AddRef = GetProcAddress(hmod, "CStdStubBuffer_AddRef");
|
|
void *CStd_Release = GetProcAddress(hmod, "NdrCStdStubBuffer_Release");
|
|
void *CStd_Connect = GetProcAddress(hmod, "CStdStubBuffer_Connect");
|
|
void *CStd_Disconnect = GetProcAddress(hmod, "CStdStubBuffer_Disconnect");
|
|
void *CStd_Invoke = GetProcAddress(hmod, "CStdStubBuffer_Invoke");
|
|
void *CStd_IsIIDSupported = GetProcAddress(hmod, "CStdStubBuffer_IsIIDSupported");
|
|
void *CStd_CountRefs = GetProcAddress(hmod, "CStdStubBuffer_CountRefs");
|
|
void *CStd_DebugServerQueryInterface = GetProcAddress(hmod, "CStdStubBuffer_DebugServerQueryInterface");
|
|
void *CStd_DebugServerRelease = GetProcAddress(hmod, "CStdStubBuffer_DebugServerRelease");
|
|
|
|
r = NdrDllGetClassObject(&CLSID_Unknown, &IID_IPSFactoryBuffer, (void**)&ppsf, proxy_file_list,
|
|
&CLSID_psfact, &PSFactoryBuffer);
|
|
ok(r == CLASS_E_CLASSNOTAVAILABLE, "NdrDllGetClassObject with unknown clsid should have returned CLASS_E_CLASSNOTAVAILABLE instead of 0x%x\n", r);
|
|
ok(ppsf == NULL, "NdrDllGetClassObject should have set ppsf to NULL on failure\n");
|
|
|
|
r = NdrDllGetClassObject(&CLSID_psfact, &IID_IPSFactoryBuffer, (void**)&ppsf, proxy_file_list,
|
|
&CLSID_psfact, &PSFactoryBuffer);
|
|
|
|
ok(r == S_OK, "ret %08x\n", r);
|
|
ok(ppsf != NULL, "ppsf == NULL\n");
|
|
|
|
proxy_vtbl = PSFactoryBuffer.pProxyFileList[0]->pProxyVtblList;
|
|
stub_vtbl = PSFactoryBuffer.pProxyFileList[0]->pStubVtblList;
|
|
ok(PSFactoryBuffer.pProxyFileList == proxy_file_list, "pfl not the same\n");
|
|
ok(proxy_vtbl == (PCInterfaceProxyVtblList *) &cstub_ProxyVtblList, "proxy vtbllist not the same\n");
|
|
ok(stub_vtbl == (PCInterfaceStubVtblList *) &cstub_StubVtblList, "stub vtbllist not the same\n");
|
|
|
|
/* if1 is non-delegating, if2 is delegating, if3 is non-delegating
|
|
but I've zero'ed the vtbl entries, similarly if4 is delegating
|
|
with zero'ed vtbl entries */
|
|
|
|
#define VTBL_TEST_NOT_CHANGE_TO(name, i) \
|
|
ok(stub_vtbl[i]->Vtbl.name != CStd_##name, #name "vtbl %d updated %p %p\n", \
|
|
i, stub_vtbl[i]->Vtbl.name, CStd_##name )
|
|
#define VTBL_TEST_CHANGE_TO(name, i) \
|
|
ok(check_address(stub_vtbl[i]->Vtbl.name, CStd_##name), #name "vtbl %d not updated %p %p\n", \
|
|
i, stub_vtbl[i]->Vtbl.name, CStd_##name )
|
|
#define VTBL_TEST_ZERO(name, i) \
|
|
ok(stub_vtbl[i]->Vtbl.name == NULL, #name "vtbl %d not null %p\n", \
|
|
i, stub_vtbl[i]->Vtbl.name )
|
|
|
|
VTBL_TEST_NOT_CHANGE_TO(QueryInterface, 0);
|
|
VTBL_TEST_NOT_CHANGE_TO(AddRef, 0);
|
|
VTBL_TEST_NOT_CHANGE_TO(Release, 0);
|
|
VTBL_TEST_NOT_CHANGE_TO(Connect, 0);
|
|
VTBL_TEST_NOT_CHANGE_TO(Disconnect, 0);
|
|
VTBL_TEST_NOT_CHANGE_TO(Invoke, 0);
|
|
VTBL_TEST_NOT_CHANGE_TO(IsIIDSupported, 0);
|
|
VTBL_TEST_NOT_CHANGE_TO(CountRefs, 0);
|
|
VTBL_TEST_NOT_CHANGE_TO(DebugServerQueryInterface, 0);
|
|
VTBL_TEST_NOT_CHANGE_TO(DebugServerRelease, 0);
|
|
|
|
VTBL_TEST_CHANGE_TO(QueryInterface, 1);
|
|
VTBL_TEST_CHANGE_TO(AddRef, 1);
|
|
VTBL_TEST_NOT_CHANGE_TO(Release, 1);
|
|
VTBL_TEST_NOT_CHANGE_TO(Connect, 1);
|
|
VTBL_TEST_NOT_CHANGE_TO(Disconnect, 1);
|
|
VTBL_TEST_CHANGE_TO(Invoke, 1);
|
|
VTBL_TEST_CHANGE_TO(IsIIDSupported, 1);
|
|
VTBL_TEST_NOT_CHANGE_TO(CountRefs, 1);
|
|
VTBL_TEST_CHANGE_TO(DebugServerQueryInterface, 1);
|
|
VTBL_TEST_CHANGE_TO(DebugServerRelease, 1);
|
|
|
|
VTBL_TEST_CHANGE_TO(QueryInterface, 2);
|
|
VTBL_TEST_CHANGE_TO(AddRef, 2);
|
|
VTBL_TEST_ZERO(Release, 2);
|
|
VTBL_TEST_CHANGE_TO(Connect, 2);
|
|
VTBL_TEST_CHANGE_TO(Disconnect, 2);
|
|
VTBL_TEST_CHANGE_TO(Invoke, 2);
|
|
VTBL_TEST_CHANGE_TO(IsIIDSupported, 2);
|
|
VTBL_TEST_CHANGE_TO(CountRefs, 2);
|
|
VTBL_TEST_CHANGE_TO(DebugServerQueryInterface, 2);
|
|
VTBL_TEST_CHANGE_TO(DebugServerRelease, 2);
|
|
|
|
VTBL_TEST_CHANGE_TO(QueryInterface, 3);
|
|
VTBL_TEST_CHANGE_TO(AddRef, 3);
|
|
VTBL_TEST_ZERO(Release, 3);
|
|
VTBL_TEST_NOT_CHANGE_TO(Connect, 3);
|
|
VTBL_TEST_NOT_CHANGE_TO(Disconnect, 3);
|
|
VTBL_TEST_CHANGE_TO(Invoke, 3);
|
|
VTBL_TEST_CHANGE_TO(IsIIDSupported, 3);
|
|
VTBL_TEST_NOT_CHANGE_TO(CountRefs, 3);
|
|
VTBL_TEST_CHANGE_TO(DebugServerQueryInterface, 3);
|
|
VTBL_TEST_CHANGE_TO(DebugServerRelease, 3);
|
|
|
|
#define VTBL_PROXY_TEST(i,num,ptr) \
|
|
ok( check_address(proxy_vtbl[i]->Vtbl[num], (ptr)), "wrong proxy %u func %u %p/%p\n", \
|
|
(i), (num), proxy_vtbl[i]->Vtbl[num], (ptr) )
|
|
#define VTBL_PROXY_TEST_NOT_ZERO(i,num) \
|
|
ok( proxy_vtbl[i]->Vtbl[num] != NULL, "wrong proxy %u func %u is NULL\n", (i), (num))
|
|
|
|
VTBL_PROXY_TEST(0, 0, IUnknown_QueryInterface_Proxy);
|
|
VTBL_PROXY_TEST(0, 1, IUnknown_AddRef_Proxy);
|
|
VTBL_PROXY_TEST(0, 2, IUnknown_Release_Proxy);
|
|
VTBL_PROXY_TEST(0, 3, if1_fn1_Proxy);
|
|
VTBL_PROXY_TEST(0, 4, if1_fn2_Proxy);
|
|
|
|
VTBL_PROXY_TEST(1, 0, GetProcAddress(rpcrt4,"IUnknown_QueryInterface_Proxy"));
|
|
VTBL_PROXY_TEST(1, 1, GetProcAddress(rpcrt4,"IUnknown_AddRef_Proxy"));
|
|
VTBL_PROXY_TEST(1, 2, GetProcAddress(rpcrt4,"IUnknown_Release_Proxy"));
|
|
VTBL_PROXY_TEST_NOT_ZERO(1, 3);
|
|
VTBL_PROXY_TEST_NOT_ZERO(1, 4);
|
|
VTBL_PROXY_TEST_NOT_ZERO(1, 5);
|
|
VTBL_PROXY_TEST_NOT_ZERO(1, 6);
|
|
VTBL_PROXY_TEST_NOT_ZERO(1, 7);
|
|
VTBL_PROXY_TEST_NOT_ZERO(1, 8);
|
|
VTBL_PROXY_TEST_NOT_ZERO(1, 9);
|
|
VTBL_PROXY_TEST_NOT_ZERO(1, 10);
|
|
VTBL_PROXY_TEST_NOT_ZERO(1, 11);
|
|
VTBL_PROXY_TEST_NOT_ZERO(1, 12);
|
|
|
|
VTBL_PROXY_TEST(2, 0, IUnknown_QueryInterface_Proxy);
|
|
VTBL_PROXY_TEST(2, 1, IUnknown_AddRef_Proxy);
|
|
VTBL_PROXY_TEST(2, 2, IUnknown_Release_Proxy);
|
|
VTBL_PROXY_TEST(2, 3, if1_fn1_Proxy);
|
|
todo_wine VTBL_PROXY_TEST_NOT_ZERO(2, 4);
|
|
|
|
VTBL_PROXY_TEST(3, 0, GetProcAddress(rpcrt4,"IUnknown_QueryInterface_Proxy"));
|
|
VTBL_PROXY_TEST(3, 1, GetProcAddress(rpcrt4,"IUnknown_AddRef_Proxy"));
|
|
VTBL_PROXY_TEST(3, 2, GetProcAddress(rpcrt4,"IUnknown_Release_Proxy"));
|
|
VTBL_PROXY_TEST_NOT_ZERO(3, 3);
|
|
VTBL_PROXY_TEST_NOT_ZERO(3, 4);
|
|
VTBL_PROXY_TEST_NOT_ZERO(3, 5);
|
|
VTBL_PROXY_TEST_NOT_ZERO(3, 6);
|
|
|
|
#undef VTBL_TEST_NOT_CHANGE_TO
|
|
#undef VTBL_TEST_CHANGE_TO
|
|
#undef VTBL_TEST_ZERO
|
|
#undef VTBL_PROXY_TEST
|
|
#undef VTBL_PROXY_TEST_NOT_ZERO
|
|
|
|
for (i = 0; i < ARRAY_SIZE(interfaces); i++)
|
|
ok( proxy_vtbl[i]->header.piid == interfaces[i],
|
|
"wrong proxy %u iid %p/%p\n", i, proxy_vtbl[i]->header.piid, interfaces[i] );
|
|
|
|
ok(PSFactoryBuffer.RefCount == 1, "ref count %d\n", PSFactoryBuffer.RefCount);
|
|
IPSFactoryBuffer_Release(ppsf);
|
|
|
|
/* One can also search by IID */
|
|
r = NdrDllGetClassObject(&IID_if3, &IID_IPSFactoryBuffer, (void**)&ppsf, proxy_file_list,
|
|
&CLSID_psfact, &PSFactoryBuffer);
|
|
ok(r == S_OK, "ret %08x\n", r);
|
|
ok(ppsf != NULL, "ppsf == NULL\n");
|
|
IPSFactoryBuffer_Release(ppsf);
|
|
|
|
r = NdrDllGetClassObject(&IID_if3, &IID_IPSFactoryBuffer, (void**)&ppsf, proxy_file_list,
|
|
NULL, &PSFactoryBuffer);
|
|
ok(r == S_OK, "ret %08x\n", r);
|
|
ok(ppsf != NULL, "ppsf == NULL\n");
|
|
IPSFactoryBuffer_Release(ppsf);
|
|
|
|
/* but only if the PS factory implements it */
|
|
r = NdrDllGetClassObject(&IID_IDispatch, &IID_IPSFactoryBuffer, (void**)&ppsf, proxy_file_list,
|
|
&CLSID_psfact, &PSFactoryBuffer);
|
|
ok(r == CLASS_E_CLASSNOTAVAILABLE, "ret %08x\n", r);
|
|
|
|
/* Create it again to return */
|
|
r = NdrDllGetClassObject(&CLSID_psfact, &IID_IPSFactoryBuffer, (void**)&ppsf, proxy_file_list,
|
|
&CLSID_psfact, &PSFactoryBuffer);
|
|
ok(r == S_OK, "ret %08x\n", r);
|
|
ok(ppsf != NULL, "ppsf == NULL\n");
|
|
|
|
/* Because this PS factory is not loaded as a dll in the normal way, Windows 8 / 10
|
|
get confused and will crash when one of the proxies for the delegated ifaces is created.
|
|
Registering the ifaces fixes this (in fact calling CoRegisterPSClsid() with any IID / CLSID is enough). */
|
|
|
|
r = CoRegisterPSClsid(&IID_if1, &CLSID_psfact);
|
|
ok(r == S_OK, "ret %08x\n", r);
|
|
r = CoRegisterPSClsid(&IID_if2, &CLSID_psfact);
|
|
ok(r == S_OK, "ret %08x\n", r);
|
|
r = CoRegisterPSClsid(&IID_if3, &CLSID_psfact);
|
|
ok(r == S_OK, "ret %08x\n", r);
|
|
r = CoRegisterPSClsid(&IID_if4, &CLSID_psfact);
|
|
ok(r == S_OK, "ret %08x\n", r);
|
|
|
|
return ppsf;
|
|
}
|
|
|
|
static int base_buffer_invoke_called;
|
|
static HRESULT WINAPI base_buffer_Invoke(IRpcStubBuffer *This, RPCOLEMESSAGE *msg, IRpcChannelBuffer *channel)
|
|
{
|
|
base_buffer_invoke_called++;
|
|
ok(msg == (RPCOLEMESSAGE*)0xcafebabe, "msg ptr changed\n");
|
|
ok(channel == (IRpcChannelBuffer*)0xdeadbeef, "channel ptr changed\n");
|
|
return S_OK; /* returning any failure here results in an exception */
|
|
}
|
|
|
|
static IRpcStubBufferVtbl base_buffer_vtbl = {
|
|
(void*)0xcafebab0,
|
|
(void*)0xcafebab1,
|
|
(void*)0xcafebab2,
|
|
(void*)0xcafebab3,
|
|
(void*)0xcafebab4,
|
|
base_buffer_Invoke,
|
|
(void*)0xcafebab6,
|
|
(void*)0xcafebab7,
|
|
(void*)0xcafebab8,
|
|
(void*)0xcafebab9
|
|
};
|
|
|
|
static void test_NdrStubForwardingFunction(void)
|
|
{
|
|
void *This[5];
|
|
void *real_this;
|
|
IRpcChannelBuffer *channel = (IRpcChannelBuffer*)0xdeadbeef;
|
|
RPC_MESSAGE *msg = (RPC_MESSAGE*)0xcafebabe;
|
|
DWORD *phase = (DWORD*)0x12345678;
|
|
IRpcStubBufferVtbl *base_buffer_vtbl_ptr = &base_buffer_vtbl;
|
|
IRpcStubBuffer *base_stub_buffer = (IRpcStubBuffer*)&base_buffer_vtbl_ptr;
|
|
|
|
memset(This, 0xcc, sizeof(This));
|
|
This[0] = base_stub_buffer;
|
|
real_this = &This[1];
|
|
|
|
NdrStubForwardingFunction( real_this, channel, msg, phase );
|
|
ok(base_buffer_invoke_called == 1, "base_buffer_invoke called %d times\n", base_buffer_invoke_called);
|
|
|
|
}
|
|
|
|
static IRpcStubBuffer *create_stub(IPSFactoryBuffer *ppsf, REFIID iid, IUnknown *obj, HRESULT expected_result)
|
|
{
|
|
IRpcStubBuffer *pstub = NULL;
|
|
HRESULT r;
|
|
|
|
r = IPSFactoryBuffer_CreateStub(ppsf, iid, obj, &pstub);
|
|
ok(r == expected_result, "CreateStub returned %08x expected %08x\n", r, expected_result);
|
|
return pstub;
|
|
}
|
|
|
|
static HRESULT WINAPI create_stub_test_QI(IUnknown *This, REFIID iid, void **ppv)
|
|
{
|
|
ok(IsEqualIID(iid, &IID_if1), "incorrect iid\n");
|
|
*ppv = (void*)0xdeadbeef;
|
|
return S_OK;
|
|
}
|
|
|
|
static IUnknownVtbl create_stub_test_vtbl =
|
|
{
|
|
create_stub_test_QI,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
static HRESULT WINAPI create_stub_test_fail_QI(IUnknown *This, REFIID iid, void **ppv)
|
|
{
|
|
ok(IsEqualIID(iid, &IID_if1), "incorrect iid\n");
|
|
*ppv = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static IUnknownVtbl create_stub_test_fail_vtbl =
|
|
{
|
|
create_stub_test_fail_QI,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
struct dummy_unknown
|
|
{
|
|
IUnknown IUnknown_iface;
|
|
LONG ref;
|
|
};
|
|
|
|
static inline struct dummy_unknown *impl_from_IUnknown(IUnknown *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct dummy_unknown, IUnknown_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI dummy_QueryInterface(IUnknown *This, REFIID iid, void **ppv)
|
|
{
|
|
*ppv = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static ULONG WINAPI dummy_AddRef(LPUNKNOWN iface)
|
|
{
|
|
struct dummy_unknown *this = impl_from_IUnknown(iface);
|
|
return InterlockedIncrement( &this->ref );
|
|
}
|
|
|
|
static ULONG WINAPI dummy_Release(LPUNKNOWN iface)
|
|
{
|
|
struct dummy_unknown *this = impl_from_IUnknown(iface);
|
|
return InterlockedDecrement( &this->ref );
|
|
}
|
|
|
|
static IUnknownVtbl dummy_unknown_vtbl =
|
|
{
|
|
dummy_QueryInterface,
|
|
dummy_AddRef,
|
|
dummy_Release
|
|
};
|
|
static struct dummy_unknown dummy_unknown = { { &dummy_unknown_vtbl }, 0 };
|
|
|
|
static void create_proxy_test( IPSFactoryBuffer *ppsf, REFIID iid, const void *expected_vtbl )
|
|
{
|
|
IRpcProxyBuffer *proxy = NULL;
|
|
IUnknown *iface = NULL;
|
|
HRESULT r;
|
|
ULONG count;
|
|
|
|
r = IPSFactoryBuffer_CreateProxy(ppsf, NULL, iid, &proxy, (void **)&iface);
|
|
ok( r == S_OK, "IPSFactoryBuffer_CreateProxy failed %x\n", r );
|
|
ok( *(void **)iface == expected_vtbl, "wrong iface pointer %p/%p\n", *(void **)iface, expected_vtbl );
|
|
count = IUnknown_Release( iface );
|
|
ok( count == 1, "wrong refcount %u\n", count );
|
|
count = IRpcProxyBuffer_Release( proxy );
|
|
ok( count == 0, "wrong refcount %u\n", count );
|
|
|
|
dummy_unknown.ref = 4;
|
|
r = IPSFactoryBuffer_CreateProxy(ppsf, &dummy_unknown.IUnknown_iface, iid, &proxy,
|
|
(void **)&iface);
|
|
ok( r == S_OK, "IPSFactoryBuffer_CreateProxy failed %x\n", r );
|
|
ok( dummy_unknown.ref == 5, "wrong refcount %u\n", dummy_unknown.ref );
|
|
ok( *(void **)iface == expected_vtbl, "wrong iface pointer %p/%p\n", *(void **)iface, expected_vtbl );
|
|
count = IUnknown_Release( iface );
|
|
ok( count == 4, "wrong refcount %u\n", count );
|
|
ok( dummy_unknown.ref == 4, "wrong refcount %u\n", dummy_unknown.ref );
|
|
count = IRpcProxyBuffer_Release( proxy );
|
|
ok( count == 0, "wrong refcount %u\n", count );
|
|
ok( dummy_unknown.ref == 4, "wrong refcount %u\n", dummy_unknown.ref );
|
|
}
|
|
|
|
static void test_CreateProxy( IPSFactoryBuffer *ppsf )
|
|
{
|
|
create_proxy_test( ppsf, &IID_if1, if1_proxy_vtbl.Vtbl );
|
|
create_proxy_test( ppsf, &IID_if2, if2_proxy_vtbl.Vtbl );
|
|
create_proxy_test( ppsf, &IID_if3, if3_proxy_vtbl.Vtbl );
|
|
create_proxy_test( ppsf, &IID_if4, if4_proxy_vtbl.Vtbl );
|
|
}
|
|
|
|
static void test_CreateStub(IPSFactoryBuffer *ppsf)
|
|
{
|
|
IUnknownVtbl *vtbl = &create_stub_test_vtbl;
|
|
IUnknown *obj = (IUnknown*)&vtbl;
|
|
IRpcStubBuffer *pstub = create_stub(ppsf, &IID_if1, obj, S_OK);
|
|
CStdStubBuffer *cstd_stub = (CStdStubBuffer*)pstub;
|
|
const CInterfaceStubHeader *header = &CONTAINING_RECORD(cstd_stub->lpVtbl, const CInterfaceStubVtbl, Vtbl)->header;
|
|
|
|
ok(IsEqualIID(header->piid, &IID_if1), "header iid differs\n");
|
|
ok(cstd_stub->RefCount == 1, "ref count %d\n", cstd_stub->RefCount);
|
|
/* 0xdeadbeef returned from create_stub_test_QI */
|
|
ok(cstd_stub->pvServerObject == (void*)0xdeadbeef, "pvServerObject %p\n", cstd_stub->pvServerObject);
|
|
ok(cstd_stub->pPSFactory != NULL, "pPSFactory was NULL\n");
|
|
cstd_stub->pvServerObject = NULL;
|
|
IRpcStubBuffer_Release(pstub);
|
|
|
|
vtbl = &create_stub_test_fail_vtbl;
|
|
pstub = create_stub(ppsf, &IID_if1, obj, E_NOINTERFACE);
|
|
ok(pstub == S_OK, "create_stub failed: %u\n", GetLastError());
|
|
|
|
}
|
|
|
|
static HRESULT WINAPI connect_test_orig_QI(IUnknown *This, REFIID iid, void **ppv)
|
|
{
|
|
ok(IsEqualIID(iid, &IID_if1) ||
|
|
IsEqualIID(iid, &IID_if2), "incorrect iid\n");
|
|
*ppv = (void*)This;
|
|
return S_OK;
|
|
}
|
|
|
|
static int connect_test_orig_release_called;
|
|
static ULONG WINAPI connect_test_orig_release(IUnknown *This)
|
|
{
|
|
connect_test_orig_release_called++;
|
|
return 0;
|
|
}
|
|
|
|
static IUnknownVtbl connect_test_orig_vtbl =
|
|
{
|
|
connect_test_orig_QI,
|
|
NULL,
|
|
connect_test_orig_release
|
|
};
|
|
|
|
static HRESULT WINAPI connect_test_new_QI(IUnknown *This, REFIID iid, void **ppv)
|
|
{
|
|
ok(IsEqualIID(iid, &IID_if1) ||
|
|
IsEqualIID(iid, &IID_if2), "incorrect iid\n");
|
|
*ppv = (void*)0xcafebabe;
|
|
return S_OK;
|
|
}
|
|
|
|
static IUnknownVtbl connect_test_new_vtbl =
|
|
{
|
|
connect_test_new_QI,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
static HRESULT WINAPI connect_test_new_fail_QI(IUnknown *This, REFIID iid, void **ppv)
|
|
{
|
|
ok(IsEqualIID(iid, &IID_if1), "incorrect iid\n");
|
|
*ppv = (void*)0xdeadbeef;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static IUnknownVtbl connect_test_new_fail_vtbl =
|
|
{
|
|
connect_test_new_fail_QI,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
static int connect_test_base_Connect_called;
|
|
static HRESULT WINAPI connect_test_base_Connect(IRpcStubBuffer *pstub, IUnknown *obj)
|
|
{
|
|
connect_test_base_Connect_called++;
|
|
ok(*(void**)obj == (void*)0xbeefcafe, "unexpected obj %p\n", obj);
|
|
return S_OK;
|
|
}
|
|
|
|
static IRpcStubBufferVtbl connect_test_base_stub_buffer_vtbl =
|
|
{
|
|
(void*)0xcafebab0,
|
|
(void*)0xcafebab1,
|
|
(void*)0xcafebab2,
|
|
connect_test_base_Connect,
|
|
(void*)0xcafebab4,
|
|
(void*)0xcafebab5,
|
|
(void*)0xcafebab6,
|
|
(void*)0xcafebab7,
|
|
(void*)0xcafebab8,
|
|
(void*)0xcafebab9
|
|
};
|
|
|
|
static void test_Connect(IPSFactoryBuffer *ppsf)
|
|
{
|
|
IUnknownVtbl *orig_vtbl = &connect_test_orig_vtbl;
|
|
IUnknownVtbl *new_vtbl = &connect_test_new_vtbl;
|
|
IUnknownVtbl *new_fail_vtbl = &connect_test_new_fail_vtbl;
|
|
IUnknown *obj = (IUnknown*)&orig_vtbl;
|
|
IRpcStubBuffer *pstub = create_stub(ppsf, &IID_if1, obj, S_OK);
|
|
CStdStubBuffer *cstd_stub = (CStdStubBuffer*)pstub;
|
|
IRpcStubBufferVtbl *base_stub_buf_vtbl = &connect_test_base_stub_buffer_vtbl;
|
|
HRESULT r;
|
|
|
|
obj = (IUnknown*)&new_vtbl;
|
|
r = IRpcStubBuffer_Connect(pstub, obj);
|
|
ok(r == S_OK, "r %08x\n", r);
|
|
ok(connect_test_orig_release_called == 1, "release called %d\n", connect_test_orig_release_called);
|
|
ok(cstd_stub->pvServerObject == (void*)0xcafebabe, "pvServerObject %p\n", cstd_stub->pvServerObject);
|
|
|
|
cstd_stub->pvServerObject = (IUnknown*)&orig_vtbl;
|
|
obj = (IUnknown*)&new_fail_vtbl;
|
|
r = IRpcStubBuffer_Connect(pstub, obj);
|
|
ok(r == E_NOINTERFACE, "r %08x\n", r);
|
|
ok(cstd_stub->pvServerObject == (void*)0xdeadbeef, "pvServerObject %p\n", cstd_stub->pvServerObject);
|
|
ok(connect_test_orig_release_called == 2, "release called %d\n", connect_test_orig_release_called);
|
|
|
|
/* Now use a delegated stub.
|
|
|
|
We know from the NdrStubForwardFunction test that
|
|
(void**)pstub-1 is the base interface stub buffer. This shows
|
|
that (void**)pstub-2 contains the address of a vtable that gets
|
|
passed to the base interface's Connect method. Note that
|
|
(void**)pstub-2 itself gets passed to Connect and not
|
|
*((void**)pstub-2), so it should contain the vtable ptr and not
|
|
an interface ptr. */
|
|
|
|
obj = (IUnknown*)&orig_vtbl;
|
|
pstub = create_stub(ppsf, &IID_if2, obj, S_OK);
|
|
*((void**)pstub-1) = &base_stub_buf_vtbl;
|
|
*((void**)pstub-2) = (void*)0xbeefcafe;
|
|
|
|
obj = (IUnknown*)&new_vtbl;
|
|
r = IRpcStubBuffer_Connect(pstub, obj);
|
|
ok(r == S_OK, "r %08x\n", r);
|
|
ok(connect_test_base_Connect_called == 1, "connect_test_bsae_Connect called %d times\n",
|
|
connect_test_base_Connect_called);
|
|
ok(connect_test_orig_release_called == 3, "release called %d\n", connect_test_orig_release_called);
|
|
cstd_stub = (CStdStubBuffer*)pstub;
|
|
ok(cstd_stub->pvServerObject == (void*)0xcafebabe, "pvServerObject %p\n", cstd_stub->pvServerObject);
|
|
}
|
|
|
|
static void test_Disconnect(IPSFactoryBuffer *ppsf)
|
|
{
|
|
IUnknownVtbl *orig_vtbl = &connect_test_orig_vtbl;
|
|
IUnknown *obj = (IUnknown*)&orig_vtbl;
|
|
IRpcStubBuffer *pstub = create_stub(ppsf, &IID_if1, obj, S_OK);
|
|
CStdStubBuffer *cstd_stub = (CStdStubBuffer*)pstub;
|
|
|
|
connect_test_orig_release_called = 0;
|
|
IRpcStubBuffer_Disconnect(pstub);
|
|
ok(connect_test_orig_release_called == 1, "release called %d\n", connect_test_orig_release_called);
|
|
ok(cstd_stub->pvServerObject == NULL, "pvServerObject %p\n", cstd_stub->pvServerObject);
|
|
IRpcStubBuffer_Release(pstub);
|
|
}
|
|
|
|
|
|
static int release_test_psfacbuf_release_called;
|
|
static ULONG WINAPI release_test_pretend_psfacbuf_release(IUnknown *pUnk)
|
|
{
|
|
release_test_psfacbuf_release_called++;
|
|
return 1;
|
|
}
|
|
|
|
static IUnknownVtbl release_test_pretend_psfacbuf_vtbl =
|
|
{
|
|
NULL,
|
|
NULL,
|
|
release_test_pretend_psfacbuf_release
|
|
};
|
|
|
|
static void test_Release(IPSFactoryBuffer *ppsf)
|
|
{
|
|
LONG facbuf_refs;
|
|
IUnknownVtbl *orig_vtbl = &connect_test_orig_vtbl;
|
|
IUnknown *obj = (IUnknown*)&orig_vtbl;
|
|
IUnknownVtbl *pretend_psfacbuf_vtbl = &release_test_pretend_psfacbuf_vtbl;
|
|
IUnknown *pretend_psfacbuf = (IUnknown *)&pretend_psfacbuf_vtbl;
|
|
IRpcStubBuffer *pstub = create_stub(ppsf, &IID_if1, obj, S_OK);
|
|
CStdStubBuffer *cstd_stub = (CStdStubBuffer*)pstub;
|
|
|
|
facbuf_refs = PSFactoryBuffer.RefCount;
|
|
|
|
/* This shows that NdrCStdStubBuffer_Release doesn't call Disconnect */
|
|
ok(cstd_stub->RefCount == 1, "ref count %d\n", cstd_stub->RefCount);
|
|
connect_test_orig_release_called = 0;
|
|
IRpcStubBuffer_Release(pstub);
|
|
todo_wine {
|
|
ok(connect_test_orig_release_called == 0, "release called %d\n", connect_test_orig_release_called);
|
|
}
|
|
ok(PSFactoryBuffer.RefCount == facbuf_refs - 1, "factory buffer refs %d orig %d\n", PSFactoryBuffer.RefCount, facbuf_refs);
|
|
|
|
/* This shows that NdrCStdStubBuffer_Release calls Release on its 2nd arg, rather than on This->pPSFactory
|
|
(which are usually the same and indeed it's odd that _Release requires this 2nd arg). */
|
|
pstub = create_stub(ppsf, &IID_if1, obj, S_OK);
|
|
ok(PSFactoryBuffer.RefCount == facbuf_refs, "factory buffer refs %d orig %d\n", PSFactoryBuffer.RefCount, facbuf_refs);
|
|
NdrCStdStubBuffer_Release(pstub, (IPSFactoryBuffer*)pretend_psfacbuf);
|
|
ok(release_test_psfacbuf_release_called == 1, "pretend_psfacbuf_release called %d\n", release_test_psfacbuf_release_called);
|
|
ok(PSFactoryBuffer.RefCount == facbuf_refs, "factory buffer refs %d orig %d\n", PSFactoryBuffer.RefCount, facbuf_refs);
|
|
}
|
|
|
|
static HRESULT WINAPI delegating_invoke_test_QI(ITypeLib *pUnk, REFIID iid, void** ppv)
|
|
{
|
|
|
|
*ppv = pUnk;
|
|
return S_OK;
|
|
}
|
|
|
|
static ULONG WINAPI delegating_invoke_test_addref(ITypeLib *pUnk)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
static ULONG WINAPI delegating_invoke_test_release(ITypeLib *pUnk)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
static UINT WINAPI delegating_invoke_test_get_type_info_count(ITypeLib *pUnk)
|
|
{
|
|
return 0xabcdef;
|
|
}
|
|
|
|
static ITypeLibVtbl delegating_invoke_test_obj_vtbl =
|
|
{
|
|
delegating_invoke_test_QI,
|
|
delegating_invoke_test_addref,
|
|
delegating_invoke_test_release,
|
|
delegating_invoke_test_get_type_info_count,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
static HRESULT WINAPI delegating_invoke_chan_query_interface(IRpcChannelBuffer *pchan,
|
|
REFIID iid,
|
|
void **ppv)
|
|
{
|
|
ok(0, "call to QueryInterface not expected\n");
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static ULONG WINAPI delegating_invoke_chan_add_ref(IRpcChannelBuffer *pchan)
|
|
{
|
|
return 2;
|
|
}
|
|
|
|
static ULONG WINAPI delegating_invoke_chan_release(IRpcChannelBuffer *pchan)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
static HRESULT WINAPI delegating_invoke_chan_get_buffer(IRpcChannelBuffer *pchan,
|
|
RPCOLEMESSAGE *msg,
|
|
REFIID iid)
|
|
{
|
|
msg->Buffer = HeapAlloc(GetProcessHeap(), 0, msg->cbBuffer);
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI delegating_invoke_chan_send_receive(IRpcChannelBuffer *pchan,
|
|
RPCOLEMESSAGE *pMessage,
|
|
ULONG *pStatus)
|
|
{
|
|
ok(0, "call to SendReceive not expected\n");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI delegating_invoke_chan_free_buffer(IRpcChannelBuffer *pchan,
|
|
RPCOLEMESSAGE *pMessage)
|
|
{
|
|
ok(0, "call to FreeBuffer not expected\n");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI delegating_invoke_chan_get_dest_ctx(IRpcChannelBuffer *pchan,
|
|
DWORD *pdwDestContext,
|
|
void **ppvDestContext)
|
|
{
|
|
*pdwDestContext = MSHCTX_LOCAL;
|
|
*ppvDestContext = NULL;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI delegating_invoke_chan_is_connected(IRpcChannelBuffer *pchan)
|
|
{
|
|
ok(0, "call to IsConnected not expected\n");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static IRpcChannelBufferVtbl delegating_invoke_test_rpc_chan_vtbl =
|
|
{
|
|
delegating_invoke_chan_query_interface,
|
|
delegating_invoke_chan_add_ref,
|
|
delegating_invoke_chan_release,
|
|
delegating_invoke_chan_get_buffer,
|
|
delegating_invoke_chan_send_receive,
|
|
delegating_invoke_chan_free_buffer,
|
|
delegating_invoke_chan_get_dest_ctx,
|
|
delegating_invoke_chan_is_connected
|
|
};
|
|
|
|
static void test_delegating_Invoke(IPSFactoryBuffer *ppsf)
|
|
{
|
|
ITypeLibVtbl *obj_vtbl = &delegating_invoke_test_obj_vtbl;
|
|
IUnknown *obj = (IUnknown*)&obj_vtbl;
|
|
IRpcStubBuffer *pstub = create_stub(ppsf, &IID_if2, obj, S_OK);
|
|
IRpcChannelBufferVtbl *pchan_vtbl = &delegating_invoke_test_rpc_chan_vtbl;
|
|
IRpcChannelBuffer *pchan = (IRpcChannelBuffer *)&pchan_vtbl;
|
|
HRESULT r = E_FAIL;
|
|
RPCOLEMESSAGE msg;
|
|
|
|
memset(&msg, 0, sizeof(msg));
|
|
msg.dataRepresentation = NDR_LOCAL_DATA_REPRESENTATION;
|
|
msg.iMethod = 3;
|
|
r = IRpcStubBuffer_Invoke(pstub, &msg, pchan);
|
|
ok(r == S_OK, "ret %08x\n", r);
|
|
if(r == S_OK)
|
|
{
|
|
ok(*(DWORD*)msg.Buffer == 0xabcdef, "buf[0] %08x\n", *(DWORD*)msg.Buffer);
|
|
ok(*((DWORD*)msg.Buffer + 1) == S_OK, "buf[1] %08x\n", *((DWORD*)msg.Buffer + 1));
|
|
}
|
|
/* free the buffer allocated by delegating_invoke_chan_get_buffer */
|
|
HeapFree(GetProcessHeap(), 0, msg.Buffer);
|
|
IRpcStubBuffer_Release(pstub);
|
|
}
|
|
static const CInterfaceProxyVtbl *cstub_ProxyVtblList2[] =
|
|
{
|
|
NULL
|
|
};
|
|
|
|
static const CInterfaceStubVtbl *cstub_StubVtblList2[] =
|
|
{
|
|
NULL
|
|
};
|
|
|
|
static PCInterfaceName const if_name_list2[] =
|
|
{
|
|
NULL
|
|
};
|
|
|
|
static const IID *base_iid_list2[] =
|
|
{
|
|
NULL,
|
|
};
|
|
|
|
static const ExtendedProxyFileInfo my_proxy_file_info2 =
|
|
{
|
|
(const PCInterfaceProxyVtblList *) &cstub_ProxyVtblList2,
|
|
(const PCInterfaceStubVtblList *) &cstub_StubVtblList2,
|
|
(const PCInterfaceName *) &if_name_list2,
|
|
(const IID **) &base_iid_list2,
|
|
&iid_lookup,
|
|
0,
|
|
1,
|
|
NULL,
|
|
0,
|
|
0,
|
|
0
|
|
};
|
|
|
|
static const ProxyFileInfo *proxy_file_list2[] = {
|
|
&my_proxy_file_info2,
|
|
NULL
|
|
};
|
|
|
|
static void test_NdrDllRegisterProxy( void )
|
|
{
|
|
HRESULT res;
|
|
const ExtendedProxyFileInfo *pf;
|
|
HMODULE hmod = GetModuleHandleA(NULL);
|
|
|
|
|
|
res = NdrDllRegisterProxy(NULL, NULL, NULL);
|
|
ok(res == E_HANDLE, "Incorrect return code %x\n",res);
|
|
pf = NULL;
|
|
res = NdrDllRegisterProxy(hmod, &pf, NULL);
|
|
ok(res == E_NOINTERFACE, "Incorrect return code %x\n",res);
|
|
res = NdrDllRegisterProxy(hmod, proxy_file_list2, NULL);
|
|
ok(res == E_NOINTERFACE, "Incorrect return code %x\n",res);
|
|
/* This fails on Vista and Windows 7 due to permissions */
|
|
res = NdrDllRegisterProxy(hmod, proxy_file_list, NULL);
|
|
ok(res == S_OK || res == E_ACCESSDENIED, "NdrDllRegisterProxy failed %x\n",res);
|
|
if (res == S_OK)
|
|
{
|
|
res = NdrDllUnregisterProxy(hmod,proxy_file_list, NULL);
|
|
ok(res == S_OK, "NdrDllUnregisterProxy failed %x\n",res);
|
|
}
|
|
}
|
|
|
|
static HANDLE create_process(const char *arg)
|
|
{
|
|
PROCESS_INFORMATION pi;
|
|
STARTUPINFOA si = {0};
|
|
char cmdline[200];
|
|
char **argv;
|
|
BOOL ret;
|
|
|
|
si.cb = sizeof(si);
|
|
winetest_get_mainargs(&argv);
|
|
sprintf(cmdline, "\"%s\" %s %s", argv[0], argv[1], arg);
|
|
ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
|
|
ok(ret, "CreateProcess failed: %u\n", GetLastError());
|
|
CloseHandle(pi.hThread);
|
|
return pi.hProcess;
|
|
}
|
|
|
|
DEFINE_GUID(CLSID_test1,0xdeadf00d,0x0001,0x44c7,0x85,0x0f,0x2a,0x0f,0x46,0x5c,0x0c,0x6c);
|
|
|
|
static HRESULT WINAPI test1_QueryInterface(ITest1 *iface, REFIID iid, void **out)
|
|
{
|
|
if (winetest_debug > 1) trace("%s\n", wine_dbgstr_guid(iid));
|
|
if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_ITest1))
|
|
{
|
|
*out = iface;
|
|
return S_OK;
|
|
}
|
|
*out = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static ULONG WINAPI test1_AddRef(ITest1 *iface)
|
|
{
|
|
return 2;
|
|
}
|
|
|
|
static ULONG WINAPI test1_Release(ITest1 *iface)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
static HRESULT WINAPI test1_GetClassID(ITest1 *iface, CLSID *clsid)
|
|
{
|
|
*clsid = CLSID_test1;
|
|
return S_OK;
|
|
}
|
|
|
|
static int WINAPI test1_square(ITest1 *iface, int x)
|
|
{
|
|
return x * x;
|
|
}
|
|
|
|
static const ITest1Vtbl test1_vtbl =
|
|
{
|
|
test1_QueryInterface,
|
|
test1_AddRef,
|
|
test1_Release,
|
|
test1_GetClassID,
|
|
test1_square,
|
|
};
|
|
|
|
static HRESULT WINAPI test_cf_QueryInterface(IClassFactory *iface, REFIID iid, void **out)
|
|
{
|
|
if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IClassFactory))
|
|
{
|
|
*out = iface;
|
|
return S_OK;
|
|
}
|
|
*out = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static ULONG WINAPI test_cf_AddRef(IClassFactory *iface)
|
|
{
|
|
return 2;
|
|
}
|
|
|
|
static ULONG WINAPI test_cf_Release(IClassFactory *iface)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
static HRESULT WINAPI test_cf_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID iid, void **out)
|
|
{
|
|
ITest1 *obj = heap_alloc(sizeof(*obj));
|
|
|
|
obj->lpVtbl = &test1_vtbl;
|
|
|
|
return ITest1_QueryInterface(obj, iid, out);
|
|
}
|
|
|
|
static HRESULT WINAPI test_cf_LockServer(IClassFactory *iface, BOOL lock)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
static const IClassFactoryVtbl test_cf_vtbl =
|
|
{
|
|
test_cf_QueryInterface,
|
|
test_cf_AddRef,
|
|
test_cf_Release,
|
|
test_cf_CreateInstance,
|
|
test_cf_LockServer,
|
|
};
|
|
|
|
static IClassFactory test_cf = { &test_cf_vtbl };
|
|
|
|
extern CStdPSFactoryBuffer gPFactory;
|
|
extern const ProxyFileInfo * aProxyFileList;
|
|
|
|
static void local_server_proc(void)
|
|
{
|
|
DWORD obj_cookie, ps_cookie, index;
|
|
HANDLE stop_event, ready_event;
|
|
IPSFactoryBuffer *ps;
|
|
HRESULT hr;
|
|
|
|
stop_event = OpenEventA(EVENT_ALL_ACCESS, FALSE, "wine_cstub_test_server_stop");
|
|
ready_event = OpenEventA(EVENT_ALL_ACCESS, FALSE, "wine_cstub_test_server_ready");
|
|
|
|
CoInitialize(NULL);
|
|
|
|
hr = CoRegisterClassObject(&CLSID_test1, (IUnknown *)&test_cf,
|
|
CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &obj_cookie);
|
|
ok(hr == S_OK, "got %#x\n", hr);
|
|
|
|
hr = NdrDllGetClassObject(&CLSID_test_ps, &IID_IPSFactoryBuffer, (void **)&ps,
|
|
&aProxyFileList, &CLSID_test_ps, &gPFactory);
|
|
ok(hr == S_OK, "got %#x\n", hr);
|
|
|
|
hr = CoRegisterClassObject(&CLSID_test_ps, (IUnknown *)ps,
|
|
CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &ps_cookie);
|
|
ok(hr == S_OK, "got %#x\n", hr);
|
|
|
|
hr = CoRegisterPSClsid(&IID_ITest1, &CLSID_test_ps);
|
|
ok(hr == S_OK, "got %#x\n", hr);
|
|
|
|
SetEvent(ready_event);
|
|
|
|
hr = CoWaitForMultipleHandles(0, 1000, 1, &stop_event, &index);
|
|
ok(hr == S_OK, "got %#x\n", hr);
|
|
ok(!index, "got %u\n", index);
|
|
|
|
hr = CoRevokeClassObject(ps_cookie);
|
|
ok(hr == S_OK, "got %#x\n", hr);
|
|
|
|
hr = CoRevokeClassObject(obj_cookie);
|
|
ok(hr == S_OK, "got %#x\n", hr);
|
|
|
|
CoUninitialize();
|
|
ExitProcess(0);
|
|
}
|
|
|
|
static void test_delegated_methods(void)
|
|
{
|
|
HANDLE process, stop_event, ready_event;
|
|
IPSFactoryBuffer *ps;
|
|
ITest1 *test_obj;
|
|
DWORD ps_cookie;
|
|
CLSID clsid;
|
|
HRESULT hr;
|
|
int ret;
|
|
|
|
stop_event = CreateEventA(NULL, TRUE, FALSE, "wine_cstub_test_server_stop");
|
|
ready_event = CreateEventA(NULL, TRUE, FALSE, "wine_cstub_test_server_ready");
|
|
|
|
process = create_process("server");
|
|
ok(!WaitForSingleObject(ready_event, 5000), "wait failed\n");
|
|
|
|
hr = NdrDllGetClassObject(&CLSID_test_ps, &IID_IPSFactoryBuffer, (void **)&ps,
|
|
&aProxyFileList, &CLSID_test_ps, &gPFactory);
|
|
ok(hr == S_OK, "got %#x\n", hr);
|
|
|
|
hr = CoRegisterClassObject(&CLSID_test_ps, (IUnknown *)ps,
|
|
CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &ps_cookie);
|
|
ok(hr == S_OK, "got %#x\n", hr);
|
|
|
|
hr = CoRegisterPSClsid(&IID_ITest1, &CLSID_test_ps);
|
|
ok(hr == S_OK, "got %#x\n", hr);
|
|
|
|
hr = CoCreateInstance(&CLSID_test1, NULL, CLSCTX_LOCAL_SERVER, &IID_ITest1, (void **)&test_obj);
|
|
ok(hr == S_OK, "got %#x\n", hr);
|
|
|
|
ret = ITest1_square(test_obj, 3);
|
|
ok(ret == 9, "got %d\n", ret);
|
|
|
|
hr = ITest1_GetClassID(test_obj, &clsid);
|
|
ok(hr == S_OK, "got %#x\n", hr);
|
|
ok(IsEqualGUID(&clsid, &CLSID_test1), "got %s\n", wine_dbgstr_guid(&clsid));
|
|
|
|
ITest1_Release(test_obj);
|
|
|
|
SetEvent(stop_event);
|
|
ok(!WaitForSingleObject(process, 1000), "wait failed\n");
|
|
|
|
hr = CoRevokeClassObject(ps_cookie);
|
|
ok(hr == S_OK, "got %#x\n", hr);
|
|
}
|
|
|
|
START_TEST( cstub )
|
|
{
|
|
IPSFactoryBuffer *ppsf;
|
|
int argc;
|
|
char **argv;
|
|
|
|
argc = winetest_get_mainargs( &argv );
|
|
if (argc > 2 && !strcmp(argv[2], "server"))
|
|
{
|
|
local_server_proc();
|
|
return;
|
|
}
|
|
|
|
OleInitialize(NULL);
|
|
|
|
ppsf = test_NdrDllGetClassObject();
|
|
test_NdrStubForwardingFunction();
|
|
test_CreateProxy(ppsf);
|
|
test_CreateStub(ppsf);
|
|
test_Connect(ppsf);
|
|
test_Disconnect(ppsf);
|
|
test_Release(ppsf);
|
|
test_delegating_Invoke(ppsf);
|
|
test_NdrDllRegisterProxy();
|
|
test_delegated_methods();
|
|
|
|
OleUninitialize();
|
|
}
|