📄 dynamic vtable sink.cpp
字号:
// client.cpp
#define _WIN32_DCOM
#include <olectl.h>
#include <conio.h>
#include <iostream.h>
#include "Component\component.h"
// This sink can implement any interface at runtime
// In C++, struct == public class
struct CStink // class for the generic sink object
{
// The First item must be a pointer to the vtbl of the sink object
// Here we can see the binary standard that defines COM
void (__stdcall **pVtbl)(); // Declared as a pointer to one or more function pointers
// Next comes the object's data
long m_cRef; // reference counting variable
};
// Non-static methods in a class always have an implicit 'this' argument that points to the current object
// Since these methods are not part of a class we make beleive...
// Every method in the interface must pretend to have a 'this' argument as all callers will provide it
ULONG __stdcall CStink_AddRef(CStink* me)
{
// me is a stand-in for 'this', a reserved keyword in C++
// Everything must be explicitly accessed through the pointer to the object
// Now we can appreciate what C++ does automatically
return ++me->m_cRef;
}
ULONG __stdcall CStink_Release(CStink* me)
{
if(--me->m_cRef != 0)
return me->m_cRef;
delete me; // We can even use delete
return 0;
}
HRESULT __stdcall CStink_QueryInterface(CStink* me, REFIID riid, void** ppv)
{
if(riid == IID_IUnknown || riid == IID_IOutGoing)
*ppv = &me->pVtbl; // Here's a pointer to our interface
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
CStink_AddRef(me);
return S_OK;
}
// This method could be generated dynamically based on type information
HRESULT __stdcall GotMessage(CStink *me, int Message)
{
MessageBeep(MB_OK);
cout << "StinkGotMessage() is " << (char)Message << endl;
return S_OK;
}
void main()
{
cout << "Client: Calling CoInitialize()" << endl;
CoInitializeEx(NULL, COINIT_MULTITHREADED);
IUnknown* pUnknown;
cout << "Client: Calling CoCreateInstance() " << endl;
CoCreateInstance(CLSID_InsideCOM, NULL, CLSCTX_LOCAL_SERVER, IID_IUnknown, (void**)&pUnknown);
IConnectionPointContainer* pConnectionPointContainer;
HRESULT hr = pUnknown->QueryInterface(IID_IConnectionPointContainer, (void**)&pConnectionPointContainer);
if(FAILED(hr))
cout << "Not a connectable object, going to crash now" << endl;
IConnectionPoint* pConnectionPoint;
hr = pConnectionPointContainer->FindConnectionPoint(IID_IOutGoing, &pConnectionPoint);
cout << "FindConnectionPoint returns " << hr << " pConnectionPoint = " << pConnectionPoint << endl;
// Instantiate the object, sort of...
CStink* mySink = new CStink;
int num_methods = 4; // 3 for IUnknown + number of methods in outgoing interfaces
// Allocate memory for the vtbl and cast the returned void* to a pointer to a bunch of funcion pointers
void (__stdcall **IStink)() = (void (__stdcall **)())CoTaskMemAlloc(num_methods * sizeof(void*)); // 4 bytes per pointer
// Initialize the vtbl to point to our implementations
// These three always come first! (in this order)
*(IStink + 0) = (void (__stdcall *)())CStink_QueryInterface;
*(IStink + 1) = (void (__stdcall *)())CStink_AddRef;
*(IStink + 2) = (void (__stdcall *)())CStink_Release;
// Now add any additional methods to the vtbl based on the available type
// information for the outgoing interface
*(IStink + 3) = (void (__stdcall *)())GotMessage; // IOutGoing only has one additional method
// Give the sink a brain
mySink->pVtbl = IStink;
// Initialize the sink's reference counter
mySink->m_cRef = 0;
DWORD dwCookie;
hr = pConnectionPoint->Advise((IUnknown*)mySink, &dwCookie);
cout << "Client: IConnectionPoint::Advise returned " << hr << endl;
cout << "Press any key to exit" << endl;
_getch();
pConnectionPoint->Unadvise(dwCookie);
// Now free the vtbl, the has probably already deleted itself
CoTaskMemFree(IStink);
pConnectionPoint->Release();
pConnectionPointContainer->Release();
cout << "Client: Calling Release() for pUnknown" << endl;
hr = pUnknown->Release();
cout << "Client: Calling CoUninitialize()" << endl;
CoUninitialize();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -