Created
March 2, 2023 14:38
-
-
Save sevaa/6c54b79be096fff6ea7beed37d7ab849 to your computer and use it in GitHub Desktop.
COM double hop test
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.