Skip to content

Instantly share code, notes, and snippets.

@sevaa
Created March 2, 2023 14:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sevaa/6c54b79be096fff6ea7beed37d7ab849 to your computer and use it in GitHub Desktop.
Save sevaa/6c54b79be096fff6ea7beed37d7ab849 to your computer and use it in GitHub Desktop.
COM double hop test
#include <windows.h>
static const GUID CLSID_B =
{ 0x51addb47, 0xd26a, 0x4f69, { 0xb9, 0x7b, 0x7e, 0x30, 0x62, 0x8d, 0xcf, 0x5b } };
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
CoInitializeEx(0, COINIT_APARTMENTTHREADED);
HRESULT hr;
IDispatch *pb, *pc;
if (FAILED(hr = CoCreateInstance(CLSID_B, 0, CLSCTX_ALL, IID_IDispatch, (void**)&pb)))
{
MessageBox(0, L"Cannot connect to B", 0, MB_OK);
return 0;
}
VARIANT v = { VT_EMPTY };
DISPPARAMS DispParams = { 0, 0, 0, 0 };
if (FAILED(hr = pb->Invoke(0, IID_NULL, 0, 0, &DispParams, &v, 0, 0)))
{
MessageBox(0, L"Cannot connect to C", 0, MB_OK);
return 0;
}
if (V_VT(&v) != VT_DISPATCH || !V_DISPATCH(&v))
{
MessageBox(0, L"Result from B not an object", 0, MB_OK);
return 0;
}
pc = V_DISPATCH(&v);
pc->AddRef();
VariantClear(&v);
while(MessageBox(0, L"Cancel to quit, OK to test", 0, MB_OKCANCEL) != IDCANCEL)
{
hr = pc->Invoke(0, IID_NULL, 0, 0, &DispParams, 0, 0, 0);
if(FAILED(hr))
MessageBox(0, L"Fail", 0, MB_OK);
}
CoUninitialize();
return 0;
}
#include <windows.h>
// {51ADDB47-D26A-4F69-B97B-7E30628DCF5B}
static const GUID CLSID_B =
{ 0x51addb47, 0xd26a, 0x4f69, { 0xb9, 0x7b, 0x7e, 0x30, 0x62, 0x8d, 0xcf, 0x5b } };
static const GUID CLSID_C =
{ 0x7d8df6fe, 0xbf5, 0x408a, { 0xba, 0x3, 0xf5, 0xae, 0x4b, 0xeb, 0x35, 0x2 } };
class CServer : IDispatch
{
STDMETHODIMP QueryInterface(REFIID riid, void** ppv)
{
if (InlineIsEqualGUID(riid, IID_IDispatch) || InlineIsEqualGUID(riid, IID_IUnknown))
{
*ppv = this;
return S_OK;
}
else
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) AddRef() { return 1; }
STDMETHODIMP_(ULONG) Release() { return 1; }
STDMETHODIMP GetTypeInfoCount(UINT* pctinfo) { return E_NOTIMPL; }
STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) { return E_NOTIMPL; }
STDMETHODIMP GetIDsOfNames(REFIID, LPOLESTR*, UINT, LCID, DISPID*) { return E_NOTIMPL; }
STDMETHODIMP Invoke(
_In_ DISPID dispIdMember,
_In_ REFIID riid,
_In_ LCID lcid,
_In_ WORD wFlags,
_In_ DISPPARAMS* pDispParams,
_Out_opt_ VARIANT* pVarResult,
_Out_opt_ EXCEPINFO* pExcepInfo,
_Out_opt_ UINT* puArgErr)
{
if (dispIdMember == 0)
{
if (!pVarResult)
return E_POINTER;
IDispatch* pd;
HRESULT hr;
if (SUCCEEDED(hr = CoCreateInstance(CLSID_C, 0, CLSCTX_ALL, IID_IDispatch, (void**)&pd)))
{
V_VT(pVarResult) = VT_DISPATCH;
V_DISPATCH(pVarResult) = pd;
return S_OK;
}
else
return hr;
}
else
return E_NOTIMPL;
}
} g_Server;
class CFactory :public IClassFactory
{
STDMETHODIMP QueryInterface(REFIID riid, void** ppv)
{
if (InlineIsEqualGUID(riid, IID_IClassFactory) || InlineIsEqualGUID(riid, IID_IUnknown))
{
*ppv = this;
return S_OK;
}
else
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) AddRef() { return 1; }
STDMETHODIMP_(ULONG) Release() { return 1; }
STDMETHODIMP CreateInstance(IUnknown* pOuter, REFIID riid, void** ppv)
{
if (pOuter)
return CLASS_E_NOAGGREGATION;
if (InlineIsEqualGUID(riid, IID_IDispatch) || InlineIsEqualGUID(riid, IID_IUnknown))
{
*ppv = &g_Server;
return S_OK;
}
return E_NOINTERFACE;
}
STDMETHODIMP LockServer(BOOL) { return S_OK; }
} g_Factory;
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
CoInitializeEx(0, COINIT_APARTMENTTHREADED);
DWORD dw;
CoRegisterClassObject(CLSID_B, &g_Factory, CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &dw);
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0))
DispatchMessage(&msg);
CoUninitialize();
return (int)msg.wParam;
}
#include <windows.h>
static const GUID CLSID_C =
{ 0x7d8df6fe, 0xbf5, 0x408a, { 0xba, 0x3, 0xf5, 0xae, 0x4b, 0xeb, 0x35, 0x2 } };
class CServer: IDispatch
{
STDMETHODIMP QueryInterface(REFIID riid, void** ppv)
{
if (InlineIsEqualGUID(riid, IID_IDispatch) || InlineIsEqualGUID(riid, IID_IUnknown))
{
*ppv = this;
return S_OK;
}
else
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) AddRef() { return 1; }
STDMETHODIMP_(ULONG) Release() { return 1; }
STDMETHODIMP GetTypeInfoCount(UINT* pctinfo) { return E_NOTIMPL; }
STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) { return E_NOTIMPL; }
STDMETHODIMP GetIDsOfNames(REFIID, LPOLESTR*, UINT, LCID, DISPID*) { return E_NOTIMPL; }
STDMETHODIMP Invoke(
_In_ DISPID dispIdMember,
_In_ REFIID riid,
_In_ LCID lcid,
_In_ WORD wFlags,
_In_ DISPPARAMS* pDispParams,
_Out_opt_ VARIANT* pVarResult,
_Out_opt_ EXCEPINFO* pExcepInfo,
_Out_opt_ UINT* puArgErr)
{
return S_OK;
}
} g_Server;
class CFactory :public IClassFactory
{
STDMETHODIMP QueryInterface(REFIID riid, void** ppv)
{
if (InlineIsEqualGUID(riid, IID_IClassFactory) || InlineIsEqualGUID(riid, IID_IUnknown))
{
*ppv = this;
return S_OK;
}
else
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) AddRef() { return 1; }
STDMETHODIMP_(ULONG) Release() { return 1; }
STDMETHODIMP CreateInstance(IUnknown* pOuter, REFIID riid, void** ppv)
{
if (pOuter)
return CLASS_E_NOAGGREGATION;
if (InlineIsEqualGUID(riid, IID_IDispatch) || InlineIsEqualGUID(riid, IID_IUnknown))
{
*ppv = &g_Server;
return S_OK;
}
return E_NOINTERFACE;
}
STDMETHODIMP LockServer(BOOL) { return S_OK; }
} g_Factory;
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
CoInitializeEx(0, COINIT_APARTMENTTHREADED);
DWORD dw;
CoRegisterClassObject(CLSID_C, &g_Factory, CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &dw);
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0))
DispatchMessage(&msg);
CoUninitialize();
return (int)msg.wParam;
}
@sevaa
Copy link
Author

sevaa commented Mar 2, 2023

This is a companion gist to this StackOverflow answer. Demonstrates the double hop marshaling in COM. Build each file as a separate project, using the Windows Desktop app template in Visual Studio.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment