I need to create a Folder Wrapper Class... HELP!!!

  • Thread starter Thread starter Kristy
  • Start date Start date
K

Kristy

Hi

I have created a com addin for Outlook 2000 and higher, and usually
run it with Exchange server.

My application currently performs certain functions on tagged items
that go into the sent items folder. However, since you can choose not
to save items to the sent items folder and can use the rules wizard to
save them elsewhere, I would like to be able to set up an ItemAdd
event for all folders. I don't want to do this manually as folders
are created and deleted so often I could never keep up, and often
there will be hundreds of folders to monitor, personal and public. If
I could set up a Folder Wrapper to handle events ie ItemsAdd etc on
any accessed folder it would be fab!

I have tried setting up a Folder Wrapper like the Explorer warapper in
the Itemscb example. I have already set up an Inspector wrapper based
on that but it took me such a long time to get that right and already
I am struggling with this that I am hoping that someone may take pity
on me and have some sample code of a Folder Wrapper for me to look
at???

If no code sample is available then here is handful of issues so far
that maybe you can help with. Basically I am having trouble knowing
how to declare things properly. This is what I have so far... I am
initalising gBaseclassFldr in the on_Connection event as follows:

gBaseClassFldr.InitHandlerFldr Application, AddInInst.ProgId

I have set up two class modules FldrOutAddin and FldrWrap and a module
modOutlFldr (as per ItemsCB). Now I need to instantiate a folder
collection declared withevents so that I can trap the events for the
folder.

In the FldrOutAddin class module I am using

Private WithEvents colFldr As Outlook.Items

but have no idea if this is correct and how do I then add folders to
the collection, do I use Outlook.MapiFolder eg:

Private Sub colFldr_NewFolder(ByVal Folder As Outlook.MapiFolder)
On Error Resume Next
gblnNewFldr = True
AddFldr Folder
End Sub

In the FldrWrap class I am declaring

Private gBaseClassFldr As New FldrOutAddin
Private WithEvents m_objFldr As Outlook.Items


Again is this correct and then how do I use this? I can't declare them
as MapiFolder so I think I'm just missing the point or really confused
:-(

Public Property Let Folder(objFolder As Outlook.Items)
Set m_objFldr = objFldr
End Property

Public Property Get Folder() As Outlook.Items
Set Folder = m_objFldr
End Property

I hope that someone can offer some insight.

Cheers

Kristy
 
Very close, you almost have it :)

I use an Items wrapper in cases like that, not a folder wrapper. I get each
folder I'm interested in and then pass it to an AddToItems procedure. That
instantiates a new class wrapper and sets a public Property for the
MAPIFolder. The Items collection is declared WithEvents in the class and is
set in the Folder Property Let code. Then I can handle events like ItemAdd
or ItemChange.

Here's a skeleton of code you can use:

'in basOutlItems code module, it also has a kill method to remove classes
from
'the wrapper collection.

Dim m_intID As Integer

Public Function AddToItems(oFolder As Outlook.MAPIFolder) As String
Dim objItemsWrap As New clsItemsWrap
Dim strID As String

On Error Resume Next

objItemsWrap.Folder = oFolder

objItemsWrap.Key = m_intID
strID = CStr(m_intID)
g_colItemsWrap.Add objItemsWrap, strID

AddToItems = strID

m_intID = m_intID + 1

Set objItemsWrap = Nothing
End Function

'in clsItemsWrap class module.

Private WithEvents m_colItems As Outlook.Items
Private m_objFolder As Outlook.MAPIFolder
Private m_strFolderName As String
Private m_intID As Integer

Private Sub Class_Initialize()
On Error Resume Next

Set m_colItems = Nothing
Set m_objFolder = Nothing
End Sub

Private Sub Class_Terminate()
On Error Resume Next

Set m_colItems = Nothing
Set m_objFolder = Nothing
End Sub

Friend Property Let Folder(objFolder As Outlook.MAPIFolder)
On Error Resume Next

Set m_objFolder = objFolder
m_strFolderName = objFolder.Name
Set m_colItems = objFolder.Items
End Property

At that point the class module can handle any of the Items collection
events, although ItemRemove is pretty useless.
 
Hi Ken

Thanks for all of that :-)

I must be having a real blonde day though becasue I still can't get it
to work! I can't get any of the events to fire so I must still have
it set up incorrectly. I really cant seem to see the tree for the
forest!

Some more questions if you please...

Obviously my initialisation code isn't working so basically how should
I set it up? Do I need to initialise gBaseClassItems in the
On_Connection event or should I do something in the Outlook_Startup
event? What would the difference be? What would be better and why?

ie, should I use the below in the Connect.dsr

Private gBaseClassItems As New clsItemsOutAddin

Private Sub IDTExtensibility2_OnConnection(ByVal Application As
Object, _
ByVal ConnectMode As AddInDesignerObjects.ext_ConnectMode, _
ByVal AddInInst As Object, custom() As Variant)

gBaseClassItems.InitHandlerItems Application, AddInInst.ProgId

End Sub

Then what would I put in the inithandler... AddToItems oFolder maybe?

Or maybe mre straightforward like this in the Outlook_Startup event...
(would this even work, do I need to get the MapiFolder?)

Private Sub objOutlook_Startup()

Set m_objFolder = Outlook.ActiveExplorer.CurrentFolder

End Sub

Thanks Ken, as you can see I'm a bit confused!

Kristy
 
Where you instantiate your items collection is up to you. I usually declare
the collection as Public in a Globals code module As New Collection. I then
call the code that adds folders and their Items collection to the wrapper
collection whenever I want. If I'm only handling certain folders I do it on
demand. If I'm setting up initially to handle a set of folders I do that in
the InitHandler code.

If you say wanted to add the folder for any new Explorer I'd call the adder
code in NewExplorer.

The initialization of the actual class that's put in the wrapper collection
happens in the adder code:

Public Function AddToItems(oFolder As Outlook.MAPIFolder) As String
Dim objItemsWrap As New clsItemsWrap

A little clearer?
 
Hi

Thanks again, you're advice is great and I've learnt a lot but
obviously still have some way to go... Everything makes sense and I
can see how it is all going to work, but I can't figure out how to
instantiate my Items collection. Or if I'm maybe going about it the
wrong way. It makes perfect sense to me with the Explorer and
Inspector since I call an Inithandler for both from the on_connection
event to set up everything I need, eg

Friend Sub InitHandlerExpl(olapp As Outlook.Application, strProgId As
String)
On Error Resume Next

Set objOutlook = olapp 'Declared WithEvents
gstrProgId = strProgId

If colExpl.Count >= 1 Then
Set colExpl = objOutlook.Explorers 'declared with events
AddExpl objOutlook.ActiveExplorer
FMMOutlookItemsExpl objOutlook.ActiveExplorer.CurrentFolder
End If

End Sub

I can then use the colExpl_NewExplorer event to add a new explorer to
the collection, eg

Private Sub colExpl_NewExplorer(ByVal Explorer As Outlook.Explorer)
On Error Resume Next

AddExpl Explorer

End Sub

So because I need to handle all accessed folders (not just certain
folders) then I want to set it up in a similar manner, but I can't get
this to work, I want to do something like this...

Friend Sub InitHandlerItems(olapp As Outlook.Application, strProgId As
String)
On Error Resume Next
Set objOutlook = olapp 'Declared WithEvents

gstrProgId = strProgId

'This is where I get stuck because I want to use something like
objOutlook.Explorers that will put all folders under one umbrella.

Set colItems = ??????

Everything to do with folders seems to need a specific folder so I
can't use something like... Set colItems = oFolder.Items because
oFolder has to be a specified folder.

My plan was then to use like...


Private Sub colItems_FolderChange(ByVal Folder As Outlook.MAPIFolder)
On Error Resume Next

AddToItems Folder
End Sub

Once this is done I can then use m_colItems_ItemAdd(ByVal Item As
Object) to check all added items and do whatever I have to when
certain criteria is met.

Am I on the right track?

Thanks for your patience

Kris
 
The way I would do it would be to add the ActiveExplorer on startup to the
Explorers wrapper collection and in the code that adds the Explorer (same
code as called by NewExplorer) instantiate the Items collection of the
Explorer.CurrentFolder by calling the code to add the Items wrapper.

Then I would handle (in the Explorer wrapper class) the BeforeFolderSwitch
event. That event fires just before the Explorer switches to the new folder
it's going to show. In that event handler I'd call the code to add that new
folder's Items collection to the Items wrapper.

Depending on how you wanted to handle things you could just leave all the
Items collections instantiated for the duration of the Outlook session, or
you could remove those Items wrapper classes as needed.
 
Thanks Ken

I have set it all up as you suggested and it looks good, however
(sorry, I'm still quite new to all of this!)... if I drag an item to a
folder that hasn't been opened, or programmatically send an item to a
different folder then the beforefolderswith doesn't fire and therefore
I can't use m_colItems_ItemAdd to do it's thing where necessary! Is
there another event that I could use to make sure that the folder
(even if not specifically opened) still becomes part of the collection
(maybe Explorer_SelectionChange would do it?).

Or would it be easier to use Explorer_NewExplorer to iterate through
all folders and add each folder in turn. I would then leave all the
items collection instantiated for the duration of the Outlook Session,
and could therefore ensure that m_colItems_ItemAdd, (or any other
m_colItems event) would fire every time and item was added ... Not
quite sure how I'd add new folders that were created during the
session though (m_colItems_FolderAdd maybe... is this a good event?).
Anyway is this a better idea or is it overkill since most the folders
would probably never be accessed during a session? Would it bring
Outlook to its knees if there are hundreds of folders, and loads of
people using them (the public ones anyway)?

Cheers

Kristy
 
You don't have to set up your Items collections based on Explorers. That was
one example. If you want to handle the events for every Items collection in
a mail store (InfoStore) then you can do that too at any point in your code.

For example, you could iterate the folders in the mail store on startup and
add every folder and its Items collection to your wrapper collection or you
could designate a subset of them to add. I do that with my Reminder Manager
COM addin. When the user has designated certain folders to fire reminders I
get the StoreID and EntryID of each of the folders and store them in the
registry. On startup of the addin I retrieve that information from the
registry and add each folder to my Items wrapper collection. Then as the
user changes things I add and remove Items collections as dictated by their
changes.

You could get the Inbox.Parent folder, which is TopOfInformationStore
(Outlook Today) and then get its Folders collection. Iterating each folder
and subfolder and checking each of those Folders collections for other
subfolders would allow you to add every folder in the store to your wrapper
collection.

Code that like is easiest to do using a recursive procedure. Call the
procedure for each MAPIFolder in a Folders collection and let it call itself
if any MAPIFolders are in the next Folders collection. Once done everything
is added to your wrapper collection.

To handle folders added during an Outlook session you could handle the
Folders.FolderAdd event. Of course you'd have to set up a collection for
that and handle FolderAdd in the class in the collection for every
collection of Folders in Outlook. Messy. I usually prefer using a
configuration dialog with a treeview control that lists all the Outlook
folders and let the user check which ones to monitor.

Certainly the greater the amount of processing that you are doing will hit
the Exchange server with additional load. How much is too much depends on
lots of factors such as number of Exchange logins and users, network
bandwidth and how Outlook is connected to the server. Worst case is a VPN
connection over a relatively narrow pipe. That can cause Outlook to appear
to hang at intervals as the processing is done and data is being downloaded
and synched with the server. That you have to determine empirically based on
your own situation.
 
Thank you Ken for your patience and your great ideas.

I have set it all up, now I have hours of testing to do... Joy! If I
find that I have perfomance issues then I may look at utilising the
regestry to create a folder list... I think that is a cool idea!

K
 
Back
Top