Outlook Add-in. How to manage Items Events - c++

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}};

Related

A descendant of TStyledPresentationProxy has not been registered for class

I have a custom grid control that inherits from TGrid called TFmGrid. This control was working fine in Rad Studio 10 Seattle Update One. I recently upgraded to 10.1 Berlin and started noticing this error message showing up on my TFmGrid controls both when I run the application and in the designer:
A descendant of TStyledPresentationProxy has not been registered for class TFmGrid. Maybe it is necessary to add the FMX.Grid.Style module to the uses section
The image below shows how the error message shows up on my grid controls:
I started by doing as the message suggests, and adding #include <FMX.Grid.Style.hpp> to the header file of my TFmGrid control, however this seems to have done nothing.
So as far as trying to register a decendant of TStyledPresentationProxy I am not exactly sure where to start. I found this documentation about a method which:
Attempts to register the presentation proxy class with the specified name or the specified combination of control class and control type.
So I assume I need to use this method or at least something similar, but I don't understand how I am supposed to go about calling this method.
But then that brings up the question of WHERE do I call this code?
My custom control has a method in its namespace called Register() which I believe was autogenerated by the IDE when the control was created:
namespace Fmgridu
{
void __fastcall PACKAGE Register()
{
TComponentClass classes[1] = {__classid(TFmGrid)};
RegisterComponents(L"Kalos FM Controls", classes, 0);
}
}
Do I need to call something in there to register a decendant of TStyledPresentationProxy? What is the proper way to go about this?
Just override virtual method DefinePresentationName in you TfmGrid and return name of presentation name for grid:
function TfmGrid.DefinePresentationName: string;
begin
Result := 'Grid-' + GetPresentationSuffix;
end;
Fm registers presentation by string name and uses class name for it, so if you create new component (based on existed) you automatically change classname, so system cannot find presentation for you. There are two solution:
Said that you will use presentation from TGrid (DefinePresentationName)
Register existed presentation for you class (look at the initialization section of FMX.Grid.Style.pas)
P.S. Year ago i wrote article about it in common eNew approach of development of FireMonkey control “Control – Model – Presentation”. Part 1 I hope it will help you
It's simple :
Just put "StyleBook" component to your form
I had the same issue with a test component I was developing.
Complementing Yaroslav Brovin's speech, I solved the problem by adding the class register in the initialization and finalization clauses at the end of the unit, like this:
initialization
TPresentationProxyFactory.Current.Register(<COMPONENT CLASSNAME HERE>, TControlType.Styled, TStyledPresentationProxy<TStyledGrid>);
finalization
TPresentationProxyFactory.Current.Unregister(<COMPONENT CLASSNAME HERE>, TControlType.Styled, TStyledPresentationProxy<TStyledGrid>);
In my case looks like this:
initialization
TPresentationProxyFactory.Current.Register(TSGrid, TControlType.Styled, TStyledPresentationProxy<TStyledGrid>);
finalization
TPresentationProxyFactory.Current.Unregister(TSGrid, TControlType.Styled, TStyledPresentationProxy<TStyledGrid>);
PS: Don't forget to declare the FMX.Presentation.Factory,
FMX.Presentation.Style and FMX.Grid.Style units in the uses clause

Dynamically create the structure and variables of a class based on user input in c++

I'm new to the site (and to c++) so please forgive me if this is a basic question - I've googled and looked through this site without success so far, so any help anyone can provide would be hugely appreciated.
I'd like to add some functionality to an app, that allows a user to fully define the structure and contents of an object. For example, user would be presented with a configuration screen that allows them to list each property of the object - given my limited knowledge I've assumed this might be achieved by using a class:
Class Name: CustomClassName
Class Property 1: property1Name property1DataType property1DefaultValue
...
Class Property n: propertynName propertynDataType propertynDefaultValue
The user would then be able to hit a button to save their custom configuration, and the program could then reference that configuration as a Class:
class CustomClassName
{
property1DataType property1Name = property1DefaultValue;
...
propertynDataType propertynName = propertynDefaultValue;
}
I'm not even sure this is possible using Classes, so if there's another mechanism that facilitates this I'm open to suggestions!
You can't create classes in runtime, but since dynamic typing is in essence a subset of static typing, you can fake it.
Start with the Property type1:
using Property = variant<int, float, string>;
A simple "dynamic" class could look like this:
class DynamicClass {
std::map<std::string, Property> properties;
public:
Property const& operator[](std::string const&) const
Property operator[](std::string const&);
};
Use:
DynamicClass d;
d["myInt"] = 5;
1 Example implementation. Internals of variant should be tailored for your specific purpose. If you need an open variant, where you don't know all of the possible types beforehand, this gets more complicated, calling for something like any.

Spawning new async request from an asio handler

I'm trying to get my feet wet with ASIO and thought a good first project would be a simple web crawler: download an html page, find the links in it, download all the links.
I have tried modifying the ASIO http client example to use enable_shared_from_this instead of a raw pointer so that I can spawn new async task from within the handler of the previous task without having to worry about the resources getting deleted in the middle of my work.
The problems start when I tried to subclass my client to handle different pages in different ways. The compiler complains that the type of the shared_ptr doesn't match the type of this.
Does anybody know how this is solved? I haven't been able to figure it out by myself.
This is unrelated to Asio.
If you inherited a base class from enable_shared_from_this, but need it in the derived one, use boost::static_pointer_cast:
struct base : enable_shared_from_this<base>
{
};
struct derived : base
{
shared_ptr<derived> shared_from_derived()
{
return static_pointer_cast<derived>(shared_from_this());
}
};

Firebreath how to know if my method is called without debugging

I am using Objective-C++ in my firebreath project. The problem is that I am using Xcode 4 and I can not find the way to debug my project. So I have thought about if my method is been called from the web page.
Here is my source code:
In my OpenOnDesktopPluginAPI.h class:
class OpenOnDesktopPluginAPI : public FB::JSAPIAuto
{
public:
OpenOnDesktopPluginAPI(const OpenOnDesktopPluginPtr& plugin, const FB::BrowserHostPtr& host);
virtual ~OpenOnDesktopPluginAPI();
OpenOnDesktopPluginPtr getPlugin();
...
//This is my method
void runNotification();
...
};
In my OpenOnDesktopPluginAPI.mm class:
OpenOnDesktopPluginAPI::OpenOnDesktopPluginAPI(const OpenOnDesktopPluginPtr& plugin, const FB::BrowserHostPtr& host) : m_plugin(plugin), m_host(host)
{
...
//Register my method
registerMethod("runNotification", make_method(this, &OpenOnDesktopPluginAPI::runNotification));
...
}
//DistributedNotification class is my objective-c class with the implementation for post a distributed notification.
void OpenOnDesktopPluginAPI::runNotification()
{
DistributedNotification * notificationClass = [[DistributedNotification alloc] init];
[notificationClass postNotification];
[notificationClass release];
}
In my FBControl.html:
...
function myFunction()
{
plugin().runNotification();
}
...
My new method
...
I put my DistributedNotification.mm class in the
Build Phases -> "Compile Sources"
for my plugin target.
But I don´t know if my runNotification method is called, because when (In my web page) I click on My new method link, nothing happens.
I'll repeat what I said on the forum when you ask; perhaps you haven't seen that answer yet:
First of all, you can debug with Xcode4, at least on some browsers; the trick is figuring out which process to connect to.
Secondly, you can always use NSLog to log things to the console. Thirdly, you could use log4cplus (see http://www.firebreath.org/display/documentation/Logging).
Finally, you haven't specified what browser you're testing on, nor have you indicated what happens. It looks reasonable, but aparently doesn't work? What doesn't work? What does it do?
It's nearly impossible to give you any useful advice without detailed information about what you are encountering.

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++)