I can't seem to understand how i give my implementation of the IHttpSecurity::OnSecurityProblem to my IWebBrowser2 object.
I know that i need to implement a class something like this:
class CServiceProvider : public IServiceProvider
{
public:
CServiceProvider();
~CServiceProvider();
// IUnknown
ULONG STDMETHODCALLTYPE AddRef();
ULONG STDMETHODCALLTYPE Release();
STDMETHODIMP QueryInterface(REFIID iid, void ** ppvObject);
//QueryService
STDMETHODIMP QueryService(REFGUID guidService,REFIID riid,void **ppv);
private:
ULONG m_ulRefCnt;
};
And in the QueryService function when it requests the IID_IHttpSecurity i return my implementation of the IHttpSecurity interface.
But my problem is how i set the my service provider implementation on the IWebBrowser2 object and when?
My code is something like this:
IWebBrowser2 *_Browser;
IServiceProvider* pServiceProvider = NULL;
_Browser->QueryInterface(
IID_IServiceProvider,
(void**)&pServiceProvider);
IHttpSecurity* pi;
pServiceProvider->QueryService(IID_IHttpSecurity, &pi);
_Browser->Navigate(url.AllocSysString(),
&flags,
&target_frame_name,
&post_data,
&headers);
The question this works like i'm thinking if yes how i do this then, and if not can you explain how this works and can be setted?
PS: i only whant to implement the IID_IHttpSecurity interface, all other interfaces requested on the QueryService should do the default implementation provided by the system...
Thanks
I already figure out how this is done.
Using MFC we only need to implement CCustomOccManager that implements the COccManager in witch the implementation of CreateSite function returns an implementation of our COleControlSite (example CCustomControlSite). In this class you will need to override at least the QueryService function of IServiceProvider interface and in this implementation supply yours IHttpSecurity implementation (when required by the interface).
In the end the we register all this in the App InitInstance using the MFC function AfxEnableControlContainer.
Code:
// declare our custom control site to serve as the client site
class CCustomControlSite:public COleControlSite
{
public:
// constructor associates this site with the container
CCustomControlSite(COleControlContainer *pCnt):COleControlSite(pCnt){}
protected:
DECLARE_INTERFACE_MAP();
BEGIN_INTERFACE_PART(ServiceProvider, IServiceProvider)
// declare the interface method(s)
STDMETHOD(QueryService) (
/* [in] */ REFGUID guidService,
/* [in] */ REFIID riid,
/* [out] */ void __RPC_FAR *__RPC_FAR *ppvObject);
END_INTERFACE_PART(ServiceProvider)
};
// declare our control container manager
class CCustomOccManager :public COccManager
{
public:
CCustomOccManager(){}
// creates an instance of our custom control site and associates it with the container
COleControlSite* CreateSite(COleControlContainer* pCtrlCont)
{
CCustomControlSite *pSite = new CCustomControlSite(pCtrlCont);
return pSite;
}
};
In the App InitInstance simple call AfxEnableControlContainer on our implementation:
// Create a custom control container manager class so we can overide the client site
CCustomOccManager *pMgr = new CCustomOccManager;
// Set our control containment up but using our control container
// management class instead of MFC's default
AfxEnableControlContainer(pMgr);
If someone has the knowledge on how this is done without using MFC please let me know.
Thanks
Judging by the remarks in the documentation for IServiceProvider, it seems like your IOleClientSite object needs to implement IServiceProvider.
Related
I am trying to implement a custom Windows Media Foundation media sink for use in a UWP application that will use it via MediaCapture::PrepareLowLagRecordToCustomSinkAsync().
However, I am currently running into an issue where the ProcessSample() function of my IMFStreamSink is never called, even though I queue the event in my IMFMediaSink::OnClockStart().
I have followed the documentation here ( https://learn.microsoft.com/en-us/windows/win32/medfound/media-sinks ) and also taken a look at the "Simple Communication" sample.
Here is the output that I am getting, I have logged every function call and the HRESULT of every call that my sinks execute:
MyCaptureMediaSink::SetPresentationClock
OK: Clock->AddClockStateSink(this)
MyCaptureStreamSink::BeginGetEvent
OK: MediaEventQueue->BeginGetEvent(pCallback, punkState)
MyCaptureMediaSink::OnClockStart
MyCaptureStreamSink::QueueEvent
OK: MediaEventQueue->QueueEventParamVar(met, guidExtendedType, hrStatus, pvValue)
OK: Sink->QueueEvent(MEStreamSinkStarted, GUID_NULL, S_OK, nullptr)
MyCaptureStreamSink::QueueEvent
OK: MediaEventQueue->QueueEventParamVar(met, guidExtendedType, hrStatus, pvValue)
OK: Sink->QueueEvent(MEStreamSinkRequestSample, GUID_NULL, S_OK, nullptr)
What I think I should be seeing after the last line is a call to MyCaptureStreamSink::EndGetEvent() due to MEStreamSinkStarted being received, followed by another BeginGetEvent() and EndGetEvent() pair and a call ProcessSample() because the next event would be the MEStreamSinkRequestSample event.
Am I missing some functions that I still need to call in order to get a call to these functions by the MediaCapture system?
I have found the solution to my problem:
I re-implemented my stream sink without using winrt::implements, which seems to work as intended. What I assume (I'm still not 100% sure, though) is happening is that since IMFStreamSink derives from IMFMediaGenerator, the winrt::implemnets does not generate the QueryInterface properly for the base type. In my own implementation, I need to explicitly handle it.
This is the old class declaration, which doesn't work:
class MyStreamSink : public winrt::implements<MyStreamSink, IMFStreamSink>
{
// ...
};
and this is the class that works:
class MyStreamSink: public IMFStreamSink
{
virtual HRESULT QueryInterface(const IID& riid, void** ppvObject) override
{
if (riid == __uuidof(IMFMediaEventGenerator))
{
*ppvObject = static_cast<IMFMediaEventGenerator*>(this);
}
//...
}
}
An even better approach would be to override winrt::is_guid_of. By this approach you get one shared v-table and not two separate v-tables. For more information: How do I use C++/WinRT to implement a classic COM interface that derives from another classic COM interface
template<>
inline bool winrt::is_guid_of<IMFStreamSink>(guid const& id) noexcept
{
return winrt::is_guid_of<IMFStreamSink, IMFMediaEventGenerator>(id);
}
class MyStreamSink : public winrt::implements<MyStreamSink, IMFStreamSink>
{
//...
};
I have a question about virtual table.
The virtual table as i know is the function address arrays which can find
the function address when the polymorphism object call virtual function.
But In directx, some people mentioned about dx vtable that the table of d3d9.dll
's import function address arrays.
Why they call the import function address arrays to directx vtable?
It seems to not relevant with a vtable.
Did My knowledge was incorrect? May i know about vtable in detail?
Thanks!
When exporting COM objects from a DLL, there are usually two parts at work. First is the 'factory'. The factory can be a standard C-callable function exported from the DLL (which is the case with Direct3D), or a class registered with the system registry in which case you'd use CoCreateInstance to create the COM interface instance. An example of the first is creating a Direct3D device:
ID3D11Device* d3dDevice = nullptr;
hr = D3D11CreateDevice(
nullptr,
D3D_DRIVER_TYPE_HARDWARE,
0,
0,
nullptr,
0,
D3D11_SDK_VERSION,
&d3dDevice,
nullptr,
nullptr);
After this call, the d3dDevice interface points to an allocated COM interface object. The DLL that contains D3D11CreateDevice has to be implicitly linked to the calling program--or you can use LoadLibrary to do explicitly linking in which case you'd use a pointer to the function D3D11CreateDevice which amounts to much the same thing . This is derived from the 'import table' for the DLL.
An example of the second is what you do when using Windows Imaging Component (WIC):
IWICImagingFactory* factory = nullptr;
hr = CoCreateInstance(
CLSID_WICImagingFactory,
nullptr,
CLSCTX_INPROC_SERVER,
__uuidof(IWICImagingFactory),
&factory);
This has the COM system look up the class GUID in the registry, load up the referenced DLL, and then invoke the factory methods in there to create a COM interface object which it returns to you.
In both cases, the actual thing pointed to by the interface is of the form:
typedef struct IUnknownVtbl
{
BEGIN_INTERFACE
HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
IUnknown * This,
/* [in] */ REFIID riid,
/* [annotation][iid_is][out] */
_COM_Outptr_ void **ppvObject);
ULONG ( STDMETHODCALLTYPE *AddRef )(
IUnknown * This);
ULONG ( STDMETHODCALLTYPE *Release )(
IUnknown * This);
END_INTERFACE
} IUnknownVtbl;
which is contrived to exactly map to the Visual C++ implementation of virtual:
MIDL_INTERFACE("00000000-0000-0000-C000-000000000046")
IUnknown
{
public:
BEGIN_INTERFACE
virtual HRESULT STDMETHODCALLTYPE QueryInterface(
/* [in] */ REFIID riid,
/* [annotation][iid_is][out] */
_COM_Outptr_ void **ppvObject) = 0;
virtual ULONG STDMETHODCALLTYPE AddRef( void) = 0;
virtual ULONG STDMETHODCALLTYPE Release( void) = 0;
END_INTERFACE
};
COM doesn't really have a notion of inheritance, but again it's a convenience for ID3D11Device1 to use C++ public inheritance from ID3D1Device which only works because the language type has no data members declared. COM "inheritance" of interfaces is really just concatenation of the methods which you can see if you look at the C definitions in the headers:
#if defined(__cplusplus) && !defined(CINTERFACE)
MIDL_INTERFACE("cc86fabe-da55-401d-85e7-e3c9de2877e9")
ID3D11BlendState1 : public ID3D11BlendState
{
public:
virtual void STDMETHODCALLTYPE GetDesc1(
/* [annotation] */
_Out_ D3D11_BLEND_DESC1 *pDesc) = 0;
};
#else /* C style interface */
typedef struct ID3D11BlendState1Vtbl
{
BEGIN_INTERFACE
HRESULT ( STDMETHODCALLTYPE *QueryInterface )( /* ... */ );
ULONG ( STDMETHODCALLTYPE *AddRef )( ID3D11BlendState1 * This);
ULONG ( STDMETHODCALLTYPE *Release )( ID3D11BlendState1 * This);
void ( STDMETHODCALLTYPE *GetDevice )( /* ... */ );
HRESULT ( STDMETHODCALLTYPE *GetPrivateData )( /* ... */ );
HRESULT ( STDMETHODCALLTYPE *SetPrivateData )( /* ... */ );
HRESULT ( STDMETHODCALLTYPE *SetPrivateDataInterface )( /* ... */ );
void ( STDMETHODCALLTYPE *GetDesc )(
ID3D11BlendState1 * This,
/* [annotation] */
_Out_ D3D11_BLEND_DESC *pDesc);
void ( STDMETHODCALLTYPE *GetDesc1 )(
ID3D11BlendState1 * This,
/* [annotation] */
_Out_ D3D11_BLEND_DESC1 *pDesc);
END_INTERFACE
} ID3D11BlendState1Vtbl;
#endif
It's important to note this only works for the case of pure virtual (i.e. abstract) C++ classes with no data members and only virtual methods using public inheritance (i.e. interfaces). Constructors and destructors are ignored as COM life-time is managed through reference-counting via IUnknown.
The calling signatures of methods also take a pointer to the COM object as the first parameter which maps to the C++ calling convention for this.
COM interfaces are therefore designed to work like C++ virtual methods so you can use C++ syntax to call them, but they aren't necessarily C++ class objects at all.
From IUnknown there is a known standard way in COM to get a specific interface, which is QueryInterface. The Direct3D factory functions take care of this for you as well, and just return the base interface. In the case of Direct3D 11, that's a ID3D11Device.
If you want to get an interface to say 11.1, you then use QueryInterface on the ID3D11Device asking for a ID3D11Device1. It would fail on a DirectX 11.0 system, but works on a DirectX 11.1 or later system.
For a C++ programmer using Direct3D, the design purposely keeps the "COM" to a minimum (colloquially known as "COM lite"). Really just enough COM is used to make it easier to deal with interface changes over time and to provide a reasonable ABI. The Direct3D factory functions are simple C-callable exports from a known DLL, so you don't even have to muck about with the standard COM factories and in fact the API isn't designed to work if you try to use CoCreateInstance. You can technically use C via some macros that the standard MIDL compiler generates along with the C++ definitions, but it's a bit challenging to do and isn't particularly well tested these days.
Really all you need to know as a consumer of Direct3D COM is the basics of IUnknown reference counting and querying--which today is best done by using the Microsoft::WRL::ComPtr smart-pointer--and how to properly check HRESULT values--see ThrowIfFailed.
See The Component Object Model and Reference Counting (Direct3D 10)
In my project, I wrote a component which will be called in a service(COM server). There is another process will get this component's interface and register a callback interface through connection point. So the service could use the callback interface to do some feedback.
But I found that when I use the IConnectionPoint::Advise to register my callback interface cause a crash.
I implement the connection point manually. Here are part of my code:
class ATL_NO_VTABLE CUploadManager :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<CUploadManager, &CLSID_UploadManager>,
public IUploadManager,
public IConnectionPointContainer,
public IConnectionPoint
...
// IConnectionPointContainer Functions
STDMETHODIMP EnumConnectionPoints(IEnumConnectionPoints **ppEnum);
STDMETHODIMP FindConnectionPoint(REFIID riid, IConnectionPoint **ppCP);
// IConnectionPoint Functions
STDMETHODIMP GetConnectionInterface(IID *pIID);
STDMETHODIMP GetConnectionPointContainer(IConnectionPointContainer **ppCPC);
STDMETHODIMP Advise(IUnknown *pUnkSink, DWORD *pdwCookie);
STDMETHODIMP Unadvise(DWORD dwCookie);
STDMETHODIMP EnumConnections(IEnumConnections **ppEnum);
In the client, I have get the component interface already, then I get the connection point and try to call function Advise:
...
CComPtr<IConnectionPointContainer> pCPC;
hr = pUnknown->QueryInterface(IID_IConnectionPointContainer, (LPVOID *)&pCPC);
if (FAILED(hr))
{
return ;
}
CComPtr<IConnectionPoint> pConnectionPoint;
hr = pCPC->FindConnectionPoint(__uuidof(_IEvents), &pConnectionPoint);
if (SUCCEEDED(hr))
{
DWORD dwCookie = 0;
CDataCallback* pCallback = new CDataCallback();
IUnknown* pUnknown = NULL;
pCallback->QueryInterface(IID_IUnknown, (void**)&pUnknown);
hr = pConnectionPoint->Advise(pUnknown, &dwCookie);
...
All interface pointers could be got successfully, but when I call Advise, the crash occurs. The strange thing is the crash is not happened in the Advise implementation, it seems occurs in the RPC call process, the call stack is like this:
003d0070() <----crash here
combase.dll!76eea3ab()
[Frames below may be incorrect and/or missing, no symbols loaded for combase.dll]
combase.dll!76ee9d00()
rpcrt4.dll!7612a53d()
mfc90ud.dll!CDialog::OnCmdMsg
...
But if the first parameter of Advise is NULL, the function Advise could be executed.
Here is the Sink code implemented in client:
class CDataCallback : public _IEvents
{
public:
CDataCallback() {}
~CDataCallback() {}
HRESULT __stdcall QueryInterface(REFIID iid, LPVOID* ppInterface)
{
*ppInterface = this;
return S_OK;
}
ULONG STDMETHODCALLTYPE AddRef()
{
return 1;
}
ULONG STDMETHODCALLTYPE Release()
{
return 0;
}
HRESULT __stdcall TestFunc()
{
...
return S_OK;
}
};
The interface _IEvents is generated in the component which will be used as a callback in the connection point. I just use this class to test the connection point, so the implementation is very simple.
I have no idea about how this crash occurs.
Thanks for all your help!
The problem is likely to be in your CDataCallback class. It's QueryInterface implementation is unsafe and returns interface pointer incorrectly.
class CDataCallback : public _IEvents
HRESULT __stdcall QueryInterface(REFIID iid, LPVOID* ppInterface)
{
*ppInterface = this;
return S_OK;
}
You have to check iid and return E_NOINTERFACE in case requested interface is not _IEvents. Basically you can set a breakpoint there and see if you have a call there prior to crash and check the arguments.
Your sink might be queried for other interfaces (IMarhsal etc) and you have to properly indicate that you are not implementing them, instead of returning unmatching pointer, use of which leads to undefined behavior.
We have an existing network messaging server that implements a custom communications protocol that we are migrating to an in-process COM object. The server is implemented as a free threaded out-of-process COM server. The clients can register with the server (think publish-subscribe) to receive messages.
After migration we noticed several dead locks when calling GUI related functions, e.g. SetWindowPos, RedrawWindow, EnumWindows, etc. After doing some research I found that this was due to callbacks happening on a thread other than the main GUI thread (message pump). The callbacks are custom COM callbacks that derive from IUnknown, so we are not using connection points.
What's interesting is if a create a simple MFC dialog project, everything works. But in our main application it fails. Our main application (20+ years old and doing things now it was never designed for) is an MFC dialog project. In response to a message, the MFC dialog project loads a DLL that, in turn, creates an MFC dialog and registers with the COM server for messages. When the DLL dialog receives a message it calls one of the three example GUI related functions above, and blocks.
This use to work for an out-of-process COM server, so I know there is a way to get the callback to be within the context of the clients main GUI thread but have been unable find the 'magic' code to make it work. I did stumble upon SendMessageCallback but can't get the asynchronous callback function to be called.
The COM callbacks into the client are handled via a thread inside the in-process COM server. The thread is initialized with CoInitialize, which from my research means STA. I've tried changing this to CoInitializeEx and tested with MTA. I've also tried changing the COM server threading model to STA, MTA, Both, and Free. As you can see, I'm really starting to throw darts. here.
Any help would be appreciated.
I did order the Don Box books, Essential COM and Effective COM, but they will not arrive until later this week.
EDIT:
Our main application:
Inside of CApp derived class' InitInstance
AfxOleInit()
Inside of CDialog derived class' OnInitDialog
CoCreateInstance (Messaging COM Object)
Allocate callback pointer. The client callback is an interface that derives from IUnknown. Then a callback class derives from the client callback and implements the AddRef/Release interfaces. When the client creates the callback the client passes a pointer to itself so the callback can call the client.
MessageComObject->Register(callback pointer)
Inside MessageCOMObject:
MessageComObject adds the callback to the GIT and saves the cookie.
MessageComObject starts a thread to 'send' callbacks to the client.
Some point in time later the main application receives a 'message' via the callback pointer. The callback is initiated from within the MessageComObject.
Inside the MessageCOMObject:
MessageComObject gets the callback from the GIT using the cookie
MessageComObject calls a function on the callback interface
Inside the callback interface's derived class:
Calls the client callback function
Inside the CDialog derived class' callback handler:
Calls LoadLibrary on a DLL (what gets loaded is data driven)
Calls exported function from DLL.
Inside DLL's exported function:
Create CWnd object
CoCreateInstance (Messaging COM Object)
Allocate callback pointer (same as above)
MessageCOMObject->Register
Inside MessageCOMObject:
MessageComObject adds the callback to the GIT and saves the cookie.
MessageComObject starts a thread to 'send' callbacks to the client.
Some point in time later the DLL receives a message:
MessageComObject gets the callback from the GIT using the cookie, GIT returns 'Catastrophic Failure'
Code
Declaring the callback in the IDL file:
[
object,
uuid(...),
pointer_default(unique)
]
interface IMessageRouterCallback : IUnknown
{
...
};
[
object,
uuid(...),
pointer_default(unique)
]
interface IMessageRouter : IUnknown
{
...
};
[
uuid(....),
version(1.0),
]
library MessageRouterCOMLib
{
importlib("stdole2.tlb");
[
uuid(....)
]
coclass MessageRouter
{
[default] interface IMessageRouter;
};
};
The in-process COM DLL
class ATL_NO_VTABLE CMessageRouter :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<CMessageRouter, &CLSID_MessageRouter>,
public IMessageRouter
{
public:
DECLARE_GET_CONTROLLING_UNKNOWN()
BEGIN_COM_MAP(CMessageRouter)
COM_INTERFACE_ENTRY(IMessageRouter)
COM_INTERFACE_ENTRY_AGGREGATE(IID_IMarshal, m_pUnkMarshaler.p)
END_COM_MAP()
CComPtr<IUnknown> m_pUnkMarshaler;
DECLARE_PROTECT_FINAL_CONSTRUCT()
DWORD callbackRegistrationId;
HRESULT FinalConstruct()
{
//- TODO: Add error checking
IUnknown *unknown;
DllGetClassObject(IID_IMessageRouterCallback, IID_IUnknown, (void**)&unknown);
CoRegisterClassObject(IID_IMessageRouterCallback, unknown, CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &callbackRegistrationId);
CoRegisterPSClsid(IID_IMessageRouterCallback, IID_IMessageRouterCallback);
return CoCreateFreeThreadedMarshaler(GetControllingUnknown(),
}
void FinalRelease()
{
if (callbackRegistrationId)
CoRevokeClassObject(callbackRegistrationId);
callbackRegistrationId = 0;
if (m_pUnkMarshaler)
m_pUnkMarshaler.Release();
}
}
Where callback is registered:
boost::lock_guard<boost::mutex> guard(callbacksMutex);
//- callback is the raw interface pointer from the client
//- The class Callback contains a pointer to the raw client callback
//- and the global process ID. The raw pointer is AddRef/Release in
//- the Callback class' constructor and destructor.
ptr = Callback::Pointer(new Callback(callback));
DWORD callbackId = 0;
HRESULT result = globalInterfaceTable->RegisterInterfaceInGlobal(callback, IID_IMessageRouterCallback, &callbackId);
if (SUCCEEDED(result))
{
ptr->globalCallbackId = callbackId;
callbackMap[callback] = ptr;
//- NOTE: uses raw pointer as key into map. This key is only
//- ever used during un-register.
//- callbackMap is a std::map of Callback instances indexed by the raw pointer.
}
Callback thread:
CoInitialize(NULL);
while (processCallbackThreadRunning)
{
QueueMessage message = messageQueue.Pop();
if (!processCallbackThreadRunning)
break;
//- Make a copy because callbacks may be added/removed during
//- this call.
CallbackMap callbacks;
{
boost::lock_guard<boost::mutex> guard(callbacksMutex);
callbacks = callbackMap;
}
for (CallbackMap::iterator callback = callbacks.begin(); callback != callbacks.end(); ++callback)
{
try
{
IMessageRouterCallback *mrCallback = NULL;
HRESULT result = globalInterfaceTable->GetInterfaceFromGlobal(callback->second->globalCallbackId,IID_IMessageRouterCallback,(void **) &mrCallback);
if (SUCCEEDED(result))
{
result = mrCallback->MessageHandler((unsigned char*)message.messageBuffer->Data(), message.messageBuffer->Length(), message.metaData.id, message.metaData.fromId, CComBSTR(message.metaData.fromAddress.c_str()));
if (FAILED(result))
{
... log debug
}
}
else
{
... log debug
}
}
catch (...)
{
... log debug
}
}
MessagePool::Push(message.messageBuffer);
}
CoUninitialize();
Client's implementation of the callback:
template <class CALLBACKCLASS>
class CMessageRouterCallback :
public CComBase<IMessageRouterCallback>
{
CMessageRouterCallback( CALLBACKCLASS *pCallbackClass = NULL) :
m_pCallbackClass(pCallbackClass)
{
AddRef(); //- Require by CComBase. This makes it so that this
//- class does not get automatically deleted when
//- Message Router is done with the class.
}
STDMETHODIMP MessageHandler( UCHAR *szBuffer, int nSize, DWORD dwTransCode, DWORD dwSenderID, BSTR bstrFromIP )
{
if ( m_pCallbackClass != NULL )
{
m_pCallbackClass->MessageHandler( szBuffer, nSize, dwTransCode, dwSenderID, bstrFromIP );
}
return S_OK;
}
}
CComBase implements the IUnknown interface:
template < class BASE_INTERFACE, const IID* piid = &__uuidof(BASE_INTERFACE) >
class CComBase :
public BASE_INTERFACE
{
protected:
ULONG m_nRefCount;
public:
CComBase() : m_nRefCount(0) {}
STDMETHODIMP QueryInterface(REFIID riid, void** ppv)
{
if (riid == IID_IUnknown || riid == *piid )
*ppv=this;
else
return *ppv=0,E_NOINTERFACE;
AddRef();
return S_OK;
}
STDMETHODIMP_(ULONG) AddRef()
{
return ++m_nRefCount;
}
STDMETHODIMP_(ULONG) Release()
{
if (!--m_nRefCount)
{
delete this;
return 0;
}
return m_nRefCount;
}
virtual ~CComBase() {}
};
The client then uses it:
class Client
{
CMessageRouterCallback<Client> *callback;
Client(IMessageRouter *messageRouter)
{
callback = new CMessageRouterCallback<this>();
messageRouter->Register(..., callback);
}
void MessageHandler(...) { ... }
}
There's something wrong with how those callbacks are being registered. Possible causes may be:
A direct pointer to the callback manager's interface in the GUI thread, so you're providing direct pointers to STA objects to the callback manager too.
Your Callback instance in the code you added seems to be doing exactly this, it can't blindly call the raw pointer's Release when destroyed.
Your server objects are marshaled with CoCreateFreeThreadedMarshaler (not much different).
With the FTM, you must never use raw pointers, and you must always marshal interface pointers you intend to keep and unmarshal interface pointers you previously kept, preferrably using the GIT. And I mean always, if you intend to keep things safe.
I recommend you keep your server objects in MTA (ThreadingModel="Free") or NA (ThreadingModel="Neutral"), make sure you're accessing them somehow in the GUI thread through CoCreateInstance[Ex] or CoGetClassObject and IClassFactory::CreateInstance (or any other object activation API), and let the "magic" happen. This is as transparent as it can get without using the GIT or manually marshaling things between threads.
I've written a simple COM DLL inproc server with a single simple COM object. The COM object implements a connection point.
I know how to create an ATL client that derives from IDispEventImpl, and uses a sink map to simplify this process.
But, for the purposes of demonstration, I'd like to create a win32 console application that uses a class that calls my simple COM object, then acts as a connection point sink.
I've got no idea how to provide an implementation of IDispatch - can someone recommend documentation on this, as I can't find any (I've got ATL Internals, but this doesn't seem to cover what I need ).
Here's the class I've already got:
#pragma once
#include <iostream>
using namespace std;
// Because we're implementing a connection points sink (_IPogFarmEvents)
// in a non-ATL class, we must provide implementations for IUnknown and IDispatch.
class KidWithAPogFarm : public _IPogFarmEvents
{
private:
DWORD m_dwRefCount;
LONG m_lNumPogs;
public:
KidWithAPogFarm() :
m_dwRefCount (0),
m_lNumPogs (0)
{
}
~KidWithAPogFarm()
{
}
// -- IUnknown
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject)
{
if (iid == DIID__IPogFarmEvents)
{
m_dwRefCount++;
*ppvObject = (void *)this;
return S_OK;
}
if (iid == IID_IUnknown)
{
m_dwRefCount++;
*ppvObject = (void *)this;
return S_OK;
}
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE AddRef()
{
m_dwRefCount++;
return m_dwRefCount;
}
ULONG STDMETHODCALLTYPE Release()
{
ULONG l;
l = m_dwRefCount--;
if ( 0 == m_dwRefCount)
delete this;
return l;
}
// -- IDispatch
STDMETHODIMP GetTypeInfoCount(UINT *pctinfo)
{
return E_NOTIMPL;
}
STDMETHODIMP GetTypeInfo( UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo )
{
return E_NOTIMPL;
}
STDMETHODIMP GetIDsOfNames(const IID &riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId )
{
return E_NOTIMPL;
}
STDMETHODIMP Invoke(DISPID dispIdMember, const IID &riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr )
{
return E_NOT_IMPL;
}
// -- IAntFarmEvents
STDMETHODIMP OnFarmCreated(LONG lInitialPopulation)
{
m_lNumPogs = lInitialPopulation;
cout << "The kid has a pog farm with " << m_lNumPogs << " pogs " << endl;
return S_OK;
}
};
Since you already have ATL you can examine its sources and see how IDispatchImpl does all that stuff. IDispatch methods are implemented therehby reading data from the type library in the same module since it's the easiest and most reliable way when a type library is already present.
It's also worth noting that it's a rather hard topic for making a demonstration on it - you'll need to write a lot of code that doesn't really bring any insight. IMO you'll be much better off if you implement an events interface that doesn't inherit from IDispatch but rather inherits directly from IUnknown - this will demonstrate how events work without dragging too much of attention to IDispatch inner workings.
I think the easiest way of doing this is through CreateStdDispatch
You can use this IDispatch implementation.
It's not exactly what you're looking for, but FireBreath uses IDispatchEx and connection points to provide an ActiveX control that runs in IE. Because FireBreath is an abstraction to allow plugins to be written once and used in all major browsers, the IDispatch interface needed to be written by hand -- including connection points.
The code may be a little confusing, since there is a templated mixin class used to provide IDispatch and ConnectionPoints to two different COM object classes, but it may help.
Mixin class
ActiveX Control
Second COM control (not OLE)
You've already accepted an answer, but perhaps it will still help. Sorry I didn't see the question sooner.