Need help with events in COM in pure C++! - 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++)

Related

C++ mapi outlook call to ResolveMessageClass fails randomly?

I am working on my outlook plugin using C++ MAPI.
On one particular button click I want to open New Mail window for which I am following below approach. But to my surprise, IMAPIFormMgr::ResolveMessageClass() function fails. That too randomly. At times it works fine and at other times it fails. Couldn't figure out what could be the cause for the same.
Any pointer, idea?
My code flow is something like below
Note: It's not full code, just little bit of overview.
I have printed all the variables and poiters in my log fine and non of them is NULL or garbage or like.
Still it fails at ResolveMessageClass() function only. That too strangely it fails randomly. many a time it works like champ and suddenly it shows some error in ResolveMessageClass()
Code
CComPtr<IMessage> mapiMessage;
hRes = spOutboxFolder->CreateMessage(&IID_IMessage, 0, &mapiMessage);
CComPtr<IMAPIFormInfo> pFormInfo;
std::wstring szMessageClass(L"IPM.Note");
hRes = pFormMgr->ResolveMessageClass(
wstringTostring(szMessageClass).c_str(), // Message class is ALWAYS ANSI --> Never Unicode
0,
spOutboxFolder.get(),
&pFormInfo);
CComPtr<IPersistMessage> pPersistMessage;
hRes = pFormMgr->CreateForm(NULL, 0L, pFormInfo, IID_IPersistMessage, (LPVOID*)&pPersistMessage);
ULONG_PTR ul = 0;
hRes = spSession->PrepareForm(NULL, mapiMessage, &ul);
hRes = spSession->ShowForm(
NULL, //(ULONG)parent->GetSafeHwnd(),
msgStore,
spInboxFolder.get(),
NULL,
ul,
NULL,
MAPI_POST_MESSAGE,
pPropsMsg[MSG_STATUS].Value.l,
pPropsMsg[MSG_FLAGS].Value.l,
pPropsMsg[MSG_ACCESS].Value.l,
pPropsMsg[MSG_CLASS].Value.lpszA);
Thanks in advance
If your code is in an Outlook addin, why not use OOM to create and display message? In this particular case, using MAPI does not buy you anything.
Use the Outlook object model instead of Extended MAPI. Creating a COM add-in involves two major steps:
Implement the IDTExtensibility2 interface in a class module of a dynamic link library (DLL).
Register the COM add-in.
The key to understanding COM add-in development is the IDTExensibility2 interface. This interface is used by all Office applications to communicate with a COM add-in. This ensures a common initialization mechanism and an ability to pass in the application's object model so that the COM add-in can communicate with the Office application. Listing 23-1 shows the IDTExtensibility2 interface.
public interface IDTExtensibility2
{
void OnAddInsUpdate(ref System.Array custom);
void OnBeginShutdown(ref System.Array custom);
void OnConnection(object Application,
Extensibility.ext_ConnectMode ConnectMode,
object AddInInst, ref System.Array custom);
void OnDisconnection(Extensibility.ext_DisconnectMode RemoveMode,
ref System.Array custom);
void OnStartupComplete(ref System.Array custom);
}
As you can see the OnConnection method gets an instance of the host application instance. So, that is where you could start from developing your add-in.
Read more about the OOM in the Outlook object model overview section of MSDN.

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.

Outlook Add-in. How to manage Items Events

I'm doing an add-in for Outlook 2007 in C++.
I need to capture the events like create, change or delete from the Outlook Items (Contact, Appointment, Tasks and Notes) but the only information/examples I've found are for Visual Basic so I don't know how to connect the event handler.
Here is some information related: http://msdn.microsoft.com/en-us/library/bb208390(v=office.12).aspx
Any help is welcome :) Thanks
Update
Sorry for taking this long to update, I've been out of town. I have some doubts/problems that you may know how to help.
In my case, I'm taking this project that was started so I'm a bit confused about all this. I have the class OutlookAddin that derives from IDTExtensibility2. I also have this other class, called AutoSync, were I'd like to do all the methods when the event fires and so. An object of this class is initialized in OutlookAddin.cpp OnStartupComplete.
According to your post MyClass should extends from IDispEventSimpleImpl<1 /*N*/, MyClass, &__uuidof(Outlook::ItemsEvents)> but which one of them? OutlookAddin or AutoSync ?
Where I should put this code also?
CComPtr<Outlook::MAPIFolder> folder;
// get the folder you're interested in
CComPtr<Outlook::_Items> items;
hr = folder->get_Items(&items);
hr = MyItemEvents::DispEventAdvise(items, &__uuidof(Outlook::ItemsEvents));
typedef IDispEventSimpleImpl<1 /*N*/, MyClass,
&__uuidof(Outlook::ItemsEvents)> MyItemEvents;
I've read the links you posted but still having these doubts...
Update 2
This is more complicated to understand than I though in a first instance.
So I have like this:
OutlookAddin.h
class OutlookAddin :
public IDTExtensibility2,
public IDispEventSimpleImpl<1, OutlookAddin, &__uuidof(Outlook::ItemEvents)>
...
BEGIN_SINK_MAP(OutlookAddin)
SINK_ENTRY_INFO(1, __uuidof(Outlook::ItemEvents), 0xf002, OutlookAddin::OnItemChange, &OnSimpleEventInfo)
END_SINK_MAP()
...
void __stdcall OnItemChange();
'OnSimpleEventInfo' is defined like:
extern _ATL_FUNC_INFO OnSimpleEventInfo;
_ATL_FUNC_INFO OnSimpleEventInfo = {CC_STDCALL,VT_EMPTY,0};
then in OutlookAddin.cpp, OnConnection method:
CComPtr<Outlook::MAPIFolder> folder;
CComPtr<Outlook::_Items> items;
OutlookWorker::GetInstance()->GetNameSpacePtr()->GetDefaultFolder(olFolderContacts, &folder);
folder->get_Items(&items);
DispEventAdvise(items, &__uuidof(Outlook::ItemsEvents));
being 'OutlookWorker::GetInstance()->GetNameSpacePtr()' the _NameSpacePtr where all the environment is kept.
The expected behaviour here is to fire the function 'OnItemChange' from OutlookAddin class when an ContactItem is created/edited/deleted but that's not happening... I changed a little bit the structure to everything is in the main class OutlookAddin. Then on the function 'OnItemChange' I'll start the object of 'AutoSync' that I told you before.
Anyway I'm following the articles you gave me, really useful, thank you. Do you still have any other suggestion for me?
Thanks your patience.
Its been a while, but you should get these item events by advising for Folder.Items:
CComPtr<Outlook::MAPIFolder> folder;
// get the folder you're interested in
CComPtr<Outlook::_Items> items;
hr = folder->get_Items(&items);
hr = MyItemEvents::DispEventAdvise(items, &__uuidof(Outlook::ItemsEvents));
Where your class MyClass derives from:
IDispEventSimpleImpl<1 /*N*/, MyClass, &__uuidof(Outlook::ItemsEvents)>
And MyItemEvents is:
typedef IDispEventSimpleImpl<1 /*N*/, MyClass,
&__uuidof(Outlook::ItemsEvents)> MyItemEvents;
N identifies your sink here. Then there is the joy of the remaining macros to setup and the handler functions to implement - i refer you to this and this article for examples and to the dispinterface ItemsEvents that you can look up in oleview.exe.
Regarding update 1:
If you want to receive the events in AutoSync, implement the interface there - you are not required to sink the events to any specific instance. However, you know your design best :)
I'd just personally keep as much logic out of the central addin class as possible.
The registration code would go into some method of the class implementing the events then and called whenever it should start to receive events, while the typedef would be e.g. well placed in the class' declaration.
Regarding update 2:
From a quick glance it looks mostly right, but OnItemChange() takes one parameter - an IDispatch:
_ATL_FUNC_INFO AtlCallDispatch = {CC_STDCALL, VT_EMPTY, 1, {VT_DISPATCH}};

How to implement an outgoing interface on a sink object (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/.