Why doesn't Outlook notify my addIn about cntact item events?

  • Thread starter Thread starter Ted Byers
  • Start date Start date
T

Ted Byers

NB: I am using VB, not VBA.

Here are two event handlers I created:

Private Sub objContactItem_PropertyChange(ByVal Name As String)
MsgBox (Name & " was changed.")
End Sub

Private Sub objContactItem_Write(Cancel As Boolean)
MsgBox (Name & " was changed.")
End Sub

And here is how objContactItem is declared:

Private WithEvents objContactItem As Outlook.ContactItem

And here is how it is initialized:

Set objContactItem = objOutlook.ContactItem

I assume I need to initialize objContactItem with a contact item in order to
be able to get the events, and not just declare it, and I need it to be set
to the value of the contact item that was changed.

I do not know if this is right, though, since ContactItem did not appear in
the dropdown list that appeared after I typed "objOutlook."

And can someone show me how to access the data members of objContactItem
(which I assume is populated with the edited contact item when the event is
passed to my COM object). I would assume that once I get the initialization
right, I should be able to access the data members directly.

What I don't see happening, at present, is the messagebox that is supposed
to be displayed in the event handlers, suggesting that my COM object is not
being notified of these events. Why?

Any help would be appreciated.

NB: I have been trying, in both VC++6 and VB6, but with great frustration
with inadequate documentation.

Thanks

Ted
 
You have to set objContactItem to the *particular* contact item that you
want to monitor for changes. (We don't have any way of knowing which item
you have in mind.) The objContactItem events will not fire until you do
that.
 
OK, so then I ought to be using whatever collection contains the contact
data. Right? What would be the container that has it? How do I declare
and initialize it? And how do I get the specific contact item that was
changed and led to the change event on the container? The container
containing the contact items does generate change events for the contact
items, doesn't it?

After all, I don't particularly care which contact item is changed. I need,
rather, to monitor them all, as well as the container for when NEW contact
items are added, and then I need to get the contact data that was either
added or edited.

Thanks,

Ted
 
You can monitor the Contacts folder for new and changed items with the
MAPIFolder.Items.ItemAdd and .ItemChange events. See
http://www.slipstick.com/dev/code/quarexe.htm for a simple example
monitoring the Inbox.

However, ItemChange will not tell you what specifically was changed. If you
explain your proposed application in more detail, someone may be able to
provide more advice.
--
Sue Mosher, Outlook MVP
Author of
Microsoft Outlook Programming - Jumpstart for
Administrators, Power Users, and Developers
 
Sue Mosher said:
You can monitor the Contacts folder for new and changed items with the
MAPIFolder.Items.ItemAdd and .ItemChange events. See
http://www.slipstick.com/dev/code/quarexe.htm for a simple example
monitoring the Inbox.

However, ItemChange will not tell you what specifically was changed. If you
explain your proposed application in more detail, someone may be able to
provide more advice.
--

In a nutshell, I need to keep the contact data in multiple instances of
Outlook (usually without the aide of exchange), and several other
applications in sync. The basic idea is that I will have two main
processes. 1) when a given application or instance thereof starts, it
compares all its contact data with that maintained by the others. 2) when
contact data is added, edited or removed using, e.g., one of the instances
of Outlook (I'm using Office 2000 for this), I want to be notified of the
relevant event and carry out the same operation with all of the other
applications or instances thereof. So, if Fred Flintstone is added to the
contact data using Outlook on my machine, the moment it is added, my addin
will be notified of the event and given the data, and it will, in turn pass
the data to a DCOM object running on one machine on the LAN, whether
workstation or server, and this latter object will maintain pointers to all
COM objects using it to synchronize contact data (and any given COM object
will only ever interact with two processes: the application it was designed
for and my DCOM gate keeper and distributor object). There is, of course,
more to my design than this, of course, since there is a need to ensure that
an event that is initiated on one machine using Outlook does not make it
back to try to carry out the corresponding edit on the same machine in the
same application, but the is enough to show where I am headed.

Whatever the nature of the edit, whether it is the addition of a new contact
item, or the editing of one or removal of one, I need to get the
corresponding event and in the event handler get the contact item data so I
can pass it to the gate keeper.

My preference would have been to do this in C++, but I am having as much
trouble getting my VC++6 project to be notified of events as I am getting my
VB project notified of events. But one thing is critical: all this must
happen transparently to the user and without user intervention as much as is
practicable. I am sure that eventually I will have to add logic to the
gatekeeper to detect edit collisions (as when two users edit the same object
in incompatible ways) and have a human gatekeeper to arbitrate the edits,
but that is a long distance down the road I'm travelling.

BTW: I added the following to my class module:

Private WithEvents colOlItems As Outlook.Items

and the following to my InitHandler:

Set colOlItems = objOutlook.GetNamespace("MAPI").Items

And then the following event handlers:

Private Sub colOlItems_ItemAdd(ByVal Item As Object)
MsgBox ("Something was changed.")
End Sub

Private Sub colOlItems_ItemChange(ByVal Item As Object)
MsgBox ("Something was changed.")
End Sub

Private Sub colOlItems_ItemRemove()
MsgBox ("Something was changed.")
End Sub

Still, none of these event handlers were executed regardless of what I did
to my contact data in Outlook. I must still be doing something wrong, but
the question is "WHAT?"

Thanks,

Ted
 
GetNamespace returns a Namespace object. It doesn't have an Items
collection. It does, however, have a GetDefaultFolder method.

Do you need to watch for changes in all contact folders?
--
Sue Mosher, Outlook MVP
Author of
Microsoft Outlook Programming - Jumpstart for
Administrators, Power Users, and Developers
 
Sue Mosher said:
GetNamespace returns a Namespace object. It doesn't have an Items
collection. It does, however, have a GetDefaultFolder method.

Do you need to watch for changes in all contact folders?
--
Yes, I need to watch for changes in all contact folders.

I do not need to worry about other objects in the Outlook Object Model,
though. Only names, address, phne numbers, etc.

Thanks,

Ted
 
Sue Mosher said:
GetNamespace returns a Namespace object. It doesn't have an Items
collection. It does, however, have a GetDefaultFolder method.
OK, I replaced Items by .GetDefaultFolder(olFolderContacts), so I now have:

Set colOlItems =
objOutlook.GetNamespace("MAPI").GetDefaultFolder(olFolderContacts)

But still no luck. :-(

Cheers

Ted
 
You declared colOlItems as an Items object? Then you can't set it to a
MAPIFolder object, which is what GetDefaultFolder returns. You must pay
attention to the details of what each method returns.
--
Sue Mosher, Outlook MVP
Author of
Microsoft Outlook Programming - Jumpstart for
Administrators, Power Users, and Developers
 
PMFJI here but to handle Items events for multiple Items collections
code would need to be used to create an Items wrapper collection,
where each instance of the Items wrapper class module would handle
ItemAdd and/or ItemChange for each Items collection. The Explorers
wrapper class and collection illustrated in the ItemsCB COM addin
sample on the Resources page at www.microeye.com can be used as a
model for and Items collection handler.
 
Ken Slovak - said:
PMFJI here but to handle Items events for multiple Items collections
code would need to be used to create an Items wrapper collection,
where each instance of the Items wrapper class module would handle
ItemAdd and/or ItemChange for each Items collection. The Explorers
wrapper class and collection illustrated in the ItemsCB COM addin
sample on the Resources page at www.microeye.com can be used as a
model for and Items collection handler.
I am developing an increasing dislike for VB. It allows assignment of one
kind of variable to a variable having what looks like an incompatible type
(unless I have misunderstood the documentation). And making things even
more annoying is that none of the examples I have seen in the Outlook
documentation show the declarations of the variables used in the examples.

FTR, I AM using the template for this from microeye, and I have studied the
ItemsCB example, but, unless I missed something, the latter does not declare
anything "withEvents".

Let me ask this in two parts.

1) since my COM object is not getting notified of change events, there must
be something wrong with the declarations I have used. I show both the
declarations of the relevant variables and the event handlers I am looking
for. Please tell me which of these is wrong and what the corrected
statement(s) would be.

Private WithEvents objOutlook As Outlook.Application
Private WithEvents objNS As Outlook.NameSpace
Private colFolder As MAPIFolder
Private WithEvents colOlItems As Outlook.Items

Private Sub colOlItems_ItemAdd(ByVal Item As Object)
MsgBox ("Something was changed.")
End Sub

Private Sub colOlItems_ItemChange(ByVal Item As Object)
MsgBox ("Something was changed.")
End Sub

Private Sub colOlItems_ItemRemove()
MsgBox ("Something was changed.")
End Sub

Did I omit any variable of any type required to catch events generated by
the user changing a contact item?

Here is how these things are initialized. Did I make an error here? If so,
what is it and what is the correction?

Set objOutlook = olApp 'Application Object
Set objNS = objOutlook.GetNamespace("MAPI") 'NameSpace Object
Set colFolder = objNS.GetDefaultFolder(olFolderContacts)
Set colOlItems = colFolder.Items

The objective, for the moment is just to be able to catch events generated
by the user editing contact data (such as a contact's phone number). As I
need to access the changed data, I assume, from the arugments to the event
handlers, Outlook is really passing a contactItem by value, and that
therefore I need to cast the argument to contactItem. If I were to do this
using C++, I would use std::static_cast<contactItem>(Item). What would the
VB equivalent be?

2) You talked about using multiple collections. How can I know whether or
not a given user has multiple collections of contact items, and can you show
me, in code, how best to be able to catch any edit event generated from any
of them? This strikes me as problematic since it creates the possibility
that the same item may be in two or more collections, and that copies in
different collections may get out of sync. Is there any good reason for
contact data to be anywhere other than in the default contacts folder?

Thanks for your time.

Cheers,

Ted
 
Look at the class Addin in ItemsCB, it most certainly does declare
object using WithEvents declarations. And the Items collection wrapper
I mentioned can be made up by modifying the Explorer collection
wrapper that already exists in ItemsCB.

When a variable is passed in VB it can be passed by value or by
reference. Passing it by reference is the equivalent in C of passing a
pointer to the object, passing it by value is the equivalent of
copying the original item and then passing the copy. That prevents the
original item from being changed in the called procedure.

If you are only instantiating your Items collection event handlers to
handle items in Contacts folders you can check for the item type using
Item.Class before you assign it to a ContactItem or you can just use
the item as an Object. It would have the contact item properties
available, you just wouldn't get the intellisense you would if you
were working with a ContactItem. Of course even with Object you should
check for Class since a contacts folder can hold DistributionListItems
in addition to contacts.

Your declarations seem to be correct as far as I can tell, do you get
the various events handlers in ItemsCB if you run that code in debug
mode?

If you end up using Items collection wrappers you would iterate the
users set of folders and check each one to see if it is a contacts
folder. Users might have many different contacts folders, such as
Personal and Business Contacts. You can't just assume that a user has
only the default contacts folders. Then for each folder you found you
would instantiate an instance of your class that handles Items. That
would be done in an AddItems procedure modeled on the AddExpl
procedure in ItemsCB. Within that class module you would have a
Private WithEvents colItems As Outlook.Items declaration. Assigning
the Items you want to colItems would make the event handlers available
and would also enable you to separate changes in one Items collection
from changes in another.
 
Ken Slovak - said:
Your declarations seem to be correct as far as I can tell, do you get
the various events handlers in ItemsCB if you run that code in debug
mode?
No. In fact, when the ItemsCB addin is added to Outlook, I expected to see
additional command buttons, but there is virtually nothing added to the
Outlook interface that I can see. Either I am doing something wrong when
trying it, or I'm looking in the wrong place for the command buttons added
by the addin, or there may be something wrong with Outlook (or my
installation/configuration of it). I am using Outlook from Office 2000.

Thanks,

Ted
 
ItemsCB should be creating a new toolbar in your Explorer that is
called "Items" and has various buttons on it. If it isn't then
something is wrong with your Outlook setup. ItemsCB was originally
written using Outlook 2000 so that's not the problem.

Have you stepped through the code and checked that all objects are
instantiated correctly and that you aren't getting any errors?
 
Back
Top