How to implement an outgoing interface on a sink object (C++) - c++

I have a predefined TLB file, with IS8SimulationEvents wrapper method implementations, for instance:
inline HRESULT IS8SimulationEvents::S8SimulationReset ( ) {
HRESULT _result = 0;
_com_dispatch_method(this, 0x1, DISPATCH_METHOD, VT_ERROR, (void*)&_result, NULL);
return _result;
}
Using Oleview, I can see the IConnectionPointContainer interface attached to the COM object.
Question:
How do I implement the outgoing interface on a sink object, for the client to receive event notification from the COM object
Without:
ATL
MFC

This article explain how to implement connections points sources/sinks in plain C http://www.codeproject.com/KB/COM/com_in_c5.aspx
Probably the whole series of articles "COM in plain C" by Jeff Glatt are more than recommended if you want to understand COM at the low level.
PD: Lambdasoft Comet is a framework that implement COM wrappers that doesn't make use of ATL/MFC, it is pretty dated but if you want something simple it worth to take a look https://bitbucket.org/sofusmortensen/comet/ or http://www.lambdasoft.dk/comet/.

Related

How can IUnkown Query another Interface

Problem Description
In the following function, we have an IUnkown object which is querying another interface.
hr = pI->QueryInterface(IID_IActiveIMMApp, (void**)&pIApp);
I don't understand how can pI query IActiveIMMMessagePumpOwner. How can we know that there is a handle from the Com Object to IActiveIMMMessagePumpOwner. How can the IID_IActiveIMMApp used in here tell us that yes there is a handle to the IActiveIMMMessagePumpOwner and we would like to get the a pointer to the pointer pointing to the interface?
If CLSID_CActiveIMM is the reason for knowing that the COM objects handles the interface. then why can't add as much interfaces Ids as we want in CoCreateInstance.
Source Code
global_ime_init(ATOM atom, HWND hWnd)
{
IUnknown *pI;
HRESULT hr;
if (pIApp != NULL || pIMsg != NULL)
return;
OleInitialize(NULL);
/*
* Get interface IUnknown
*/
hr = CoCreateInstance(CLSID_CActiveIMM, NULL, CLSCTX_SERVER,
IID_IUnknown, (void**)&pI);
if (FAILED(hr) || !pI)
return;
/*
* Get interface IActiveIMMApp
*/
hr = pI->QueryInterface(IID_IActiveIMMApp, (void**)&pIApp);
if (FAILED(hr))
pIApp = NULL;
/*
* Get interface IActiveIMMMessagePumpOwner
*/
hr = pI->QueryInterface(IID_IActiveIMMMessagePumpOwner, (void**)&pIMsg);
if (FAILED(hr))
pIMsg = NULL;
if (pIApp != NULL)
{
pIApp->Activate(TRUE);
pIApp->FilterClientWindows(&atom, 1);
}
if (pIMsg != NULL)
pIMsg->Start();
pI->Release();
s_hWnd = hWnd;
}
P.S. I started learning the COM Model 1 hour ago, so please bear with me.
When the IUnknown::QueryInterface is executed, you pass the execution to the actual object and so if it recognizes the arguments and it understands the IID_IActiveIMMApp you passed, it supplies you with the pointer you ask for.
This is described in every COM tutorial in the QueryInterface explanation, for example, here:
QueryInterface is the mechanism that allows clients to dynamically discover (at run time) whether or not an interface is supported by a COM component; at the same time, it is the mechanism that a client uses to get an interface pointer from a COM component. When an application wants to use some function of a COM component, it calls that object's QueryInterface, requesting a pointer to the interface that implements the desired function. If the COM component supports that interface, it will return the appropriate interface pointer and a success code. If the COM component doesn't support the requested interface, it will return an error value. The application will then examine the return code; if successful, it will use the interface pointer to access the desired method. If the QueryInterface failed, the application will take some other action, letting the user know that the desired method is not available.
The following example shows a call to QueryInterface on the PhoneBook component. We are asking this component, "Do you support the ILookup interface?" If the call returns successfully, we know that the COM component supports the ILookup interface and we have a pointer to use to call methods contained in the ILookup interface (either LookupByName or LookupByNumber). If not, we know that the PhoneBook COM component does not implement the ILookup interface.
LPLOOKUP *pLookup;
TCHAR szNumber[64];
HRESULT hRes;
// Call QueryInterface on the COM Component PhoneBook, asking for a pointer
// to the Ilookup interface identified by a unique interface ID.
hRes = pPhoneBook->QueryInterface( IID_ILOOKUP, &pLookup);
if( SUCCEEDED( hRes ) )
{
pLookup->LookupByName("Daffy Duck", &szNumber); // Use Ilookup interface pointer.
pLookup->Release(); // Finished using the IPhoneBook interface pointer.
}
else
{
// Failed to acquire Ilookup interface pointer.
}
[...]
A COM component implements IUnknown to control its lifespan and to provide access to the interfaces it supports. A COM component does not provide direct access to its data. GUIDs provide a unique identifier for each class and interface, thereby preventing naming conflicts. And finally, the COM Library is implemented as part of the operating system, and provides the "legwork" associated with finding and launching COM components.
By holding any COM interface you are controlling its life time just by having a pointer, and the COM object you talk to is essentially a "black box". You "see" a "view" of its functionality by having methods of this particular COM interface available for calling. With QueryInterface you request another "view" with a different set of methods associated with the interface identifier. If you are given this new pointer and it's recognized by the COM object you talk to, those new methods are also available for calling.

Implementing IServiceProvider in an MFC application

I need to implement the IServiceProvider interface in an open source MFC application; specifically my TTSApp application.
I am attempting to add support for the IAccessibleApplication interface, which is used by screen readers to obtain information about an application's name and version information.
It appears that Google Chrome implements the IServiceProvider interface via the AXPlatformNodeWin class, which is derived from the CComObjectRootEx class and other classes and interface. The problem is that an MFC application does not use the CComObjectRootEx class; it is used by ATL.
I have found the IServiceProviderImpl Class. Unfortunately, I cannot find any information on how it fits in the context of an application. Which class in my class hierarchy needs to be derived from the IServiceProviderImpl Class; my CWinApp derived class, my CDialogEx derived class, or some other class?
I learned a great deal while on my quest in search for an answer to this question. During the quest I fell down the rabbit hole (Alice's Adventures in Wonderland by Charles Lutwidge Dodgson, a.k.a. Lewis Carroll) only to find Cthulhu (The Call of Cthulhu by H. P. Lovecraft) waiting for me.
My initial research led me to the following macros defined in afxwin.h.
DECLARE_INTERFACE_MAP
BEGIN_INTERFACE_MAP
END_INTERFACE_MAP
BEGIN_INTERFACE_PART
END_INTERFACE_PART
The best documentation I could find for these macros is in the TN038: MFC/OLE IUnknown Implementation technical note. A good sample demonstrating the use of these macros and the implementation of the QueryService function is the TstCon sample.
Of course, this led to another question, what window do I need to do this for? To answer this question I looked at the source code of a certain screen reader to see how it uses the IAccessibleApplication interface.
The following function, though not the actual code used, demonstrates the technique (I cannot share the actual code since the screen reader is not open source).
std::wstring GetApplicationNameUsingTheIAccessibleApplicationInterface(
HWND hwnd, long idObject, long idChild)
{
CComPtr<IAccessible> acc;
CComVariant var;
auto hr = AccessibleObjectFromEvent(hwnd, idObject, idChild, &acc, &var);
if (hr != S_OK) return L"";
if (!acc) return L"";
CComQIPtr<IServiceProvider> serviceProvider = acc;
if (!serviceProvider) return L"";
CComQIPtr<IAccessibleApplication> application;
hr = serviceProvider->QueryService(
IID_IAccessible, __uuidof(IAccessibleApplication),
reinterpret_cast<void**>(&application));
if (FAILED(hr)) return L"";
if (!application) return L"";
CComBSTR appName;
hr = application->get_appName(&text);
if (FAILED(hr)) return L"";
return appName.m_str;
}
This function, or something like it, is called from our WinEventProc callback function in response to the EVENT_OBJECT_FOCUS event. This indicates that I need to do this for every window that can gain focus.
Armed with what I thought was the answer to my question, I dove in and implemented the IAccessibleApplication interface and added the necessary code to all of my focus-able windows. Much to my horror, my QueryService function was never called. When I debugged the screen reader to find out why, I discovered that the implicit QueryInterface implied by the following line of code failed.
CComQIPtr<IServiceProvider> serviceProvider = acc;
This led to a long and arduous quest to discover why the call to QueryInterface was failing.
I was working on a personal project at first so I could not call upon resources I have at my employer. Then, entirely by chance, I was assigned a task that required me to provide information on how to implement the IAccessible2 interface in a C++ application to a client who needed the information to help them make their applications more accessible. Hurrah, I was finally able to call upon coworkers for aid!
My coworker guided me down the correct path.
Create a customized version of the IAccessibleProxyImpl class and CAccessibleProxy class using source code obtained from atlacc.h.
Add a COM_INTERFACE_ENTRY for IAccessibleApplication in the COM_MAP (BEGIN_COM_MAP/END_COM_MAP) for my custom IAccessibleProxyImpl class.
Use the BEGIN_SERVICE_MAP, END_SERVICE_MAP, and SERVICE_ENTRY macros to provide an implementation of the IServiceProvider interface.
Provide an override for the CWnd::CreateAccessibleProxy function to cause my windows to use my custom accessible proxy and thus my implementation of the IAccessibleApplication interface.
Now the screen reader uses the application name I provide for the IAccessibleApplication interface for my application.
The application I did this for is open source. It is my TTSApp application. I have also made an example that demonstrates how to use a similar technique to support the IAccessible2 interface available here.
I am sharing this in the hopes that the information will prove to be helpful.

Upgrading COM call-back interface

We have a problem with COM Connection point callback interfaces
In our Sample.idl we have few call-back interfaces ISomeEvents
interface ISomeEvents : IUnknown
{
HRESULT Event1([in]int nData);
HRESULT Event2([in]int nData);
HRESULT Event3([in]int nData);
}
And in the CoClass we have the following statement
coclass MyComp
{
[default] interface IMyInterface;
interface IMyInterFace2;
[default, source] interface ISomeEvents;
};
Now whenever we add new interfaces as part of enhancement,this does not break the existing client, but if the enhancement has
Any modifications to call-back then we endup updating the interface ISomeEvents, which is breaking existing clients, we are forced to do this because I think we can
Have only one [defaut,source] Interface.
Can anyone tell me What is the workaround for this?
Regards
tom
If you are developing a COM object where the client(s) are live/in production, you really shouldn't change an existing interface, any interface. That has always been the fundamental rule of COM development: "interfaces are immutable"; exceptions are made during early development, of course.
(Here's a quote for example: "COM interfaces are immutable. You cannot define a new version of an old interface and give it the same identifier." (http://msdn.microsoft.com/en-us/library/windows/desktop/ms688484(v=vs.85).aspx). Look up "interfaces are immutable" on the web for plenty more)
In this case, you should create new interfaces ISomeEvents2, ISomeEvents3, so on as needed, and have those interfaces inherit from the previous version. Make the new interface your new default source.
interface ISomeEvents1 : ISomeEvents
{
/* new enhanced events here, for use by newly compiled clients */
}
Eventually, if you need more changes:
interface ISomeEvents2 : ISomeEvents1
{
/* Even newer enhanced events here, for even newer clients */
}
And so on.

Need help with events in COM in pure C++!

guys! Very important question:
Please, look at my project (300Kb). I can`t use MFC/ATL, pure C++ only.
I have COM library (niapi.dll), but no sources/headers available, dll only.
There is class for connecting to server (NiApi::SrvrSession), class has login event handler (NiApi::SrvrSession::OnLogin).
I used
#import "NiApi.dll"
to generate wrappers/information,
then
ISrvrSessionPtr session(L"NiApi.SrvrSession");
to create object, then trying
session->put_OnLogin();
to assign events, but there is no one put_On or such member.
niapi.tlh have _ISrvrSessionEvents struct inside, but it have no relations with SrvrSession.
I need to use events from NiApi::SrvrSession for handling connection status.
Please help or my boss kill me! (sorry for broken english, I read better than speak;)
COM events are handled via connection points. You need to write your own COM object that implements whichever event interface you are interested in. Then you need to connect it to the COM object that fires the events. First you QI the COM object for its IConnectionPointContainer, then find the corresponding connection point of the GUID of the event interface. The you call its Advise method to connect it to your event sink.
class CSrvrSessionEvents: public _ISrvrSessionEvents
{
public:
HRESULT OnLogin(long LoginResult)
{
// do something
return S_OK;
}
// implement rest of _ISrvrSessionEvents
};
ISrvrSession* pSrvrSession = ...; // get ISrvrSession from somewhere
_ISrvrSessionEvents* pSrvrSessionEvents = new CSrvrSessionEvents();
IConnectionPointContainer* pCPC = NULL;
pSrvrSession->QueryInterface(IID_IConnectionPointContainer, &pCPC);
IConnectionPoint* pCP = NULL;
pCPC->FindConnectionPoint(__uuidof(_ISrvrSessionEvents), &pCP);
DWORD dwCookie = 0;
pCP->Advise(pSrvrSessionEvents, &dwCookie);
pSrvrSession->Connect(); // I assume this fires some events
pCP->Unadvise(dwCookie);
What is really necessary, is to carefully read
codeproject_TEventHandler.
All explained here.
The put_ prefix is the default prefix for the raw interface (customizable via the raw_property_prefixes attribute). Since you are not using the raw interface, use session->OnLogin=... instead.
For event handling see ADO Events Model Example (VC++)

How to conditionally choose the C# class I invoke via COM in my C++ DLL?

After much help from all my StackOverFlow brethren, I managed to create a C++ DLL that calls my C# classes via COM and passes data back and forth to an external application. There was much celebration in the kingdom after that code started working.
Now I have a new problem. I'm expanding the DLL so that it can call different classes (all implementing the same interface). I need to decide what class to call depending on a char array passed to the DLL when it is loaded. The methods I call are exactly the same regardless of which class I use. What is the best way to switch between classes when calling the DLL?
// Initialize COM.
HRESULT hr = CoInitialize(NULL);
// I want to do something like this....but how?
if (strcmp(modelType, "Model1") == 0) {
IUnitModelPtr pIUnit(__uuidof(ClassOne));
}
if (strcmp(modelType, "Model2") == 0) {
IUnitModelPtr pIUnit(__uuidof(ClassTwo));
}
//call method 1
//call method 2
CoUninitialize();
//exit
This is probably a fairly simple question, but I really do not know any C++. Just getting COM going was a major challenge for me.
edit: Im sure there are some super elegant ways to achieve this (reflection?) but please limit your suggestions to stuff that can be implemented easily....efficiency is not important here and maintainability is not really an issue.
Do smth like this:
GUID classId = GUID_NULL;
if( strcmp( modelType, "Model1" ) == 0 ) {
classId = __uuidof( class1 );
} else if( strcmp( modelType, "Model2" ) == 0 ) {
classId = __uuidof( class2 );
} else if(... etc, continue for all possible model types
}
IUnitModelPtr unit;
unit.CreateInstance( classId );
// interface methods can be called here
Two options.
As each different interface implementation is a coclass, and your C++ code uses the right prog-id/classid to perform the create.
Alternately the exposed coclass is a factory with a method to return the actual implementation class.
Both need logic to map your modelType to implementation class. You can do this in the C++ code or in the .NET code. Without more information about the overall context (is the string --> coclass mapping logically part of the COM component or of the caller).
(In a pure C++ COM implementation you can create your own custom COM instance factory, but that's more advanced COM and not available for .NET COM interop.)