Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
Home
DiscussionsAccessExcelInfoPathOutlookPowerPointPublisherWord
DirectoryUser Groups
Related Topics
Outlook ExpressInternet ExplorerWindowsMS Server ProductsMore Topics ...

MS Office Forum / Outlook / Programming Add-Ins / April 2004

Tip: Looking for answers? Try searching our database.

Inspector Wrapper Help

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Kristy - 17 Mar 2004 23:37 GMT
Hi

I am creating a Com Add-in for Outlook 2000 and XP.  I have used the
ItemsCB example from Microeye as the basis for my project.

I have a query regarding my Inspector wrapper that I am hoping someone
will be able to help me with.

Basically I have 4 class modules ExplOutAddIn.cls, ExplWrap.cls,
InspOutAddIn & InspWrap, and 2 normal modules modOutlInsp and
modOutlExpl that do all the housekeeping for my project.

My issue is that when I send an email m_objInsp_close (the module
responsible for destroying the Inspector object) is not called and
therefore the sent item is not being removed from the Inspector
collection at that time like I'd expect.

Eventually when Outlook is closed m_objExpl_close is called and from
there I call gBaseClassExpl.UnInitHandlerExpl and
gBaseClassInsp.UnInitHandlerInsp to ensure that everything is released
from memory and Outlook closes properly but is this the correct way of
doing it?

I hope that all makes sense... In summary the sent items are
definitely part of the collection when created but they are not
removed from the collection until you exit outlook.  I would have
thought that they should be removed on send in the same way that a
closed item is? objMailtItem_close is called but not m_objInsp_close?
Is there a really obvious mistake in my code that I'm missing?

This is basically what happens...

1. Open Outlook, explorer added to collection

Private Sub colExpl_NewExplorer(ByVal Explorer As Outlook.Explorer)
   On Error Resume Next
   gblnNewExpl = True
   AddExpl Explorer
End Sub

2. Open new Mail Item, Inspector added to collection

Private Sub colInsp_NewInspector(ByVal Inspector As Outlook.Inspector)
 Dim objItem As Object
 Dim strID As String
 
   Set objInsp = Inspector  'declared WithEvents
   Set objItem = objInsp.CurrentItem
       Select Case objItem.Class
           Case olMail
              AddInsp Inspector
              Set objMailItem = objItem 'declared WithEvents
       Case Else
       End Select
   Set objItem = Nothing
   Set objInsp = Nothing
End Sub

3a. Close Item without sending, in this scenario first
objMailitem_close is called then  m_objInsp_close is called which
removes the object from the collection

Private Sub objMailItem_Close(Cancel As Boolean)
 On Error Resume Next
 If objOutlook.Explorers.Count = 0 And objOutlook.Inspectors.Count <=
1 Then
       UnInitHandlerInsp
 End If

Set objMailItem = Nothing
Set golApp = Nothing
End Sub

Private Sub m_objInsp_Close()
Dim objItem As Object
   On Error Resume Next
   modOutlInsp.KillInsp m_nID, Me
   'MsgBox m_objInsp.Caption & "was just Closed"
   Set m_objInsp = Nothing
   Set objItem = Nothing

End Sub

Public Sub KillInsp(anID As Integer, objInspWrap As InspWrap)
   Dim objInspWrap2 As InspWrap
   
On Error Resume Next
   Set objInspWrap2 = gcolInspWrap.item(CStr(anID))
   ' ensure removing the correct Inspector from the collection
   If Not objInspWrap2 Is objInspWrap Then
       Err.Raise 1, Description:="Unexpected Error in KillInsp"
       GoTo Cleanup
   End If

   gcolInspWrap.Remove CStr(anID)
   
Cleanup:

Set objInspWrap2 = Nothing
End Sub

3b.  Open Item is sent, under this scenario objMailItem_Send is
called, then you get a objMailItem_close event and that's it - no
m_objInsp_close.

Private Sub objMailItem_Send(Cancel As Boolean)
 
'Lots of stuff done here to sent item but it has no effect whether or
not m_objInsp is called so I've left it out.

Finish:
CustomField = ""
Set objItem = Nothing
Set MailItem = Nothing
Set golApp = Nothing
Set strFieldResult = Nothing
End Sub

4. Close Outlook, when you eventually exit outlook m_objExpl is called
and I am currently using this clean up explorer and inspector objects,
it works in that it releases outlook from memory but is it sloppy?

Private Sub m_objExpl_Close()

   'On Error Resume Next
   modOutlExpl.KillExpl m_nID, Me
   
   Set m_objExpl = Nothing
   
   If Outlook.Application.Explorers.Count <= 1 And
Outlook.Application.Inspectors.Count = 0 Then
       gBaseClassInsp.UnInitHandlerInsp
       gBaseClassExpl.UnInitHandlerExpl
       

   End If
End Sub

Public Sub KillExpl(anID As Integer, objExplWrap As ExplWrap)
   Dim objExplWrap2 As ExplWrap
   
   Set objExplWrap2 = gcolExplWrap.item(CStr(anID))

   If Not objExplWrap2 Is objExplWrap Then
       Err.Raise 1, Description:="Unexpected Error in KillExpl"
       Exit Sub
   End If
   
   gcolExplWrap.Remove CStr(anID)
End Sub



I hope that someone understands this and can advise.

Also, as you'll see from the code, I have kept all the Inspector and
Explorer modules completely separate to make it easier for me to
follow as I've worked through everything - should I merge them?  Is
this better practice for tidier projects or does it not matter?

Regards

Kristy
George Sugari - 18 Mar 2004 01:06 GMT
Hi Kristy,
Use MailItem_Close on the Inspector wrapper class

> My issue is that when I send an email m_objInsp_close (the module
> responsible for destroying the Inspector object) is not called and
> therefore the sent item is not being removed from the Inspector
> collection at that time like I'd expect.

and call

modOutlInsp.KillInsp m_nID, Me

to remove the Inspector from the collection. Outlook 2000 doesn't have
Inspector_Close.

> 3a. Close Item without sending, in this scenario first
> objMailitem_close is called then  m_objInsp_close is called which
[quoted text clipped - 10 lines]
> Set golApp = Nothing
> End Sub
Ken Slovak - [MVP - Outlook] - 18 Mar 2004 14:47 GMT
To add to what George said, make sure to declare a MailItem object at the
module level of your class (and other item types if you want to support
those):
   Private WithEvents m_objMail As Outlook.MailItem

Then in your init code for the class use a public property to set the mail
item or in the Inspector setting property also set the mail item from
Inspector.CurrentItem. That way you can handle m_objMail.Close and any other
events you want to handle like Send or Forward. That let's you handle cases
like you are seeing or when a user presses Next or Previous where you might
not get a NewInspector event in some versions of Outlook.

Signature

Ken Slovak
[MVP - Outlook]
http://www.slovaktech.com
Author: Absolute Beginner's Guide to Microsoft Office Outlook 2003
Reminder Manager, Extended Reminders, Attachment Options
http://www.slovaktech.com/products.htm

> Hi Kristy,
> Use MailItem_Close on the Inspector wrapper class
[quoted text clipped - 25 lines]
> > Set golApp = Nothing
> > End Sub
Kristy - 22 Mar 2004 01:12 GMT
Thanks George and Ken for replying.

Sorry but I am still having trouble understanding where to put things
to fix this problem.

If you have a minute could I be so bold as to ask...

George, would you possibly be able to give me some example code on how
you would set up the MailItem_Close event?  I really want an easy way
to check if my Item is still part of the collection and if it is to
remove it like happens in m_objInsp_close. I just can't seem to get it
to work (maybe it's my declarations)?

Ken, also if you have a minute could you please check my code, I
thought that I had it all set up as you suggest, and am now worried
that I've not got it right and I may get the next/previous issue with
Outlook 2000?

Sometimes I think I am not understanding all of this Inspector Wrapper
stuff as well as I thought... back to the books, the posts and the
sleepless nights!

I appreciate all of your help, Thanks

Kris

> To add to what George said, make sure to declare a MailItem object at the
> module level of your class (and other item types if you want to support
[quoted text clipped - 37 lines]
> > > Set golApp = Nothing
> > > End Sub
Ken Slovak - [MVP - Outlook] - 22 Mar 2004 15:29 GMT
I use code something like the following. This example only shows a MailItem
declared WithEvents, to handle other item types you'd add additional
declarations. In the code that adds the class to the wrapper collection you
would check for the type of the item in the new Inspector
(Inspector.CurrentItem) and add or not add the class based on that.

Private WithEvents m_objInsp As Outlook.Inspector
Private WithEvents m_objMail As Outlook.MailItem

Private m_lngID As Long

Private Sub Class_Initialize()
 On Error Resume Next

 Set m_objInsp = Nothing
 Set m_objMail = Nothing
End Sub

Private Sub Class_Terminate()
 On Error Resume Next

 Set m_objInsp = Nothing
 Set m_objMail = Nothing
End Sub

Public Property Let Inspector(objInspector As Outlook.Inspector)
 On Error Resume Next

 Set m_objInsp = objInspector
 Set m_objMail = objInspector.CurrentItem
End Property

Public Property Get Inspector() As Outlook.Inspector
 On Error Resume Next

 Set Inspector = m_objInsp
End Property

Public Property Let Key(lngID As Long)
 On Error Resume Next

 m_lngID = lngID
End Property

Public Property Get Key() As Long
 On Error Resume Next

 Key = m_lngID
End Property

'*********************************************************************
'Event Procedure: m_objInsp_Close()
'Destroy Inspector object in InspWrap
'*********************************************************************
Private Sub m_objInsp_Close()
 On Error Resume Next

 basOutlInsp.KillInsp m_lngID, Me
 Set m_objInsp = Nothing

 If Err <> 0 Then
   AddInErr Err, "clsInspWrap", "m_objInsp_Close"
 End If
End Sub

You can now add event handlers for any event available for a MailItem,
including the Close event.

Signature

Ken Slovak
[MVP - Outlook]
http://www.slovaktech.com
Author: Absolute Beginner's Guide to Microsoft Office Outlook 2003
Reminder Manager, Extended Reminders, Attachment Options
http://www.slovaktech.com/products.htm

> Thanks George and Ken for replying.
>
[quoted text clipped - 21 lines]
>
> Kris
Kristy - 23 Mar 2004 01:06 GMT
Thanks again Ken, I just have a few more questions if that's OK.

Firstly, instead of using...

Public Property Let Inspector(objInspl As Outlook.Inspector)
On Error Resume Next
   Set m_objInsp = objInspl
   Set m_objMail = objInspl.CurrentItem
End Property

as in your sample, I have been using...

Public Property Let MailItem(objMail As Outlook.MailItem)
On Error Resume Next
   Set m_objMail = objMail
End Property

Public Property Let Inspector(objInspl As Outlook.Inspector)
On Error Resume Next
   Set m_objInsp = objInspl
End Property

Where objMail is set to Inspector.CurrentItem in
colInsp_NewInspector(). Property Let MailItem(objMail As
Outlook.MailItem) is called from the Public Function AddInsp(Inspector
as Outlook.Inspector)  which checks the type of item being added
using...

Case olMail
   objInspWrap.MailItem = objItem
Case Else

To me it looks like it does the same job, but can you please confirm
that this is OK and will work in the same way?

Secondly, I've updated my m_objMail code to look like yours - thanks,
and added the following to capture the close event as that event seems
to fire on almost everything, most importantly for my problem, it
fires on send.

Private Sub m_objMail_Close(Cancel As Boolean)
On Error Resume Next

   modOutlInsp.KillInsp m_nID, Me
   Set m_objMail = Nothing
   
   If Err <> 0 Then
       AddInErr Err
   End If
End Sub

This takes care of having inspectors hanging around that have infact
been sent and therefore should've been removed.  Now though,
m_objInsp_Close() seems to be redundant as m_objMail_Close (which
always happens first) has already destroyed the inspector. The below
is never called...

Private Sub m_objInsp_Close()
On Error Resume Next
   modOutlInsp.KillInsp m_nID, Me
   Set m_objInsp = Nothing
   
   If Err <> 0 Then
       AddInErr Err
   End If
End Sub

Since you included m_objInsp_Close() in your sample code, I am
assuming that you still use it, whereas I seem to have replaced it?
Have I misunderstood?

Also by using m_objMail_Close() in this manner am I likely to remove
some items that I shouldn't be removing since this seems to fire for
everything, including Next, Previous etc.  I can't seem to think up
any scenarios where this might cause a problem but I'm sure there are
some given what I read so far with regards Next/Previous!

Finally, I use the following code in my InspOutAddInClass to capture
events, colInsp_NewInspector(ByVal Inspector As Outlook.Inspector)
sets objMailItem = objItem

Private Sub objMailItem_Open(Cancel As Boolean)
 On Error Resume Next
   Call CreateInspectorButtons(objMailItem)
End Sub

Private Sub objMailItem_Close(Cancel As Boolean)

 If objOutlook.Explorers.Count = 0 And objOutlook.Inspectors.Count <=
1 Then
       UnInitHandlerInsp
 End If

Set objMailItem = Nothing
Set golApp = Nothing
End Sub

Private Sub objMailItem_Send(Cancel As Boolean)
 On Error Resume Next

'does stuff...
End Sub

Private Sub objMailItem_Reply(ByVal Response As Object, Cancel As
Boolean)
 On Error Resume Next
'does stuff...  
End Sub
Private Sub objMailItem_ReplyAll(ByVal Response As Object, Cancel As
Boolean)
 On Error Resume Next
'does stuff...  
End Sub
Private Sub objMailItem_Forward(ByVal Response As Object, Cancel As
Boolean)
 On Error Resume Next
'does stuff...    
End Sub

Should I be using m_objMail_send, m_objMail_open, m_objMail_reply etc
instead of objMailItem?  I'm trying to figure out if this is more
advantageous and a better way of setting up my inspectors... what way
do you think is the best and why?

Sorry to ask so many questions, hopefully one day I'll be able to help
others too.

Kristy

> I use code something like the following. This example only shows a MailItem
> declared WithEvents, to handle other item types you'd add additional
[quoted text clipped - 89 lines]
> >
> > Kris
Ken Slovak - [MVP - Outlook] - 23 Mar 2004 16:12 GMT
The way you're using is just fine, setting the module level mail item object
in a separate procedure than the Inspector setting procedure. I usually use
your method as a matter of fact.

I leave the Inspector Close event handler in my code, it does fire under
certain circumstances.

What you could also look at is changing the code in your mail item close
event handler to destroy the Inspector:
   Set oInspector = m_objMail.GetInspector
   oInspector.Close
As the last lines in the event handler aside from setting any objects
declared in that procedure to Nothing.

If I understand your last question I'd handle all events for the mail item
in the wrapper class's event handlers rather than elsewhere. In that case
I'd use the module level m_objMail object.

Signature

Ken Slovak
[MVP - Outlook]
http://www.slovaktech.com
Author: Absolute Beginner's Guide to Microsoft Office Outlook 2003
Reminder Manager, Extended Reminders, Attachment Options
http://www.slovaktech.com/products.htm

> Thanks again Ken, I just have a few more questions if that's OK.
>
[quoted text clipped - 124 lines]
>
> Kristy
Kristy - 24 Mar 2004 23:58 GMT
Hi Ken

I feel much more confident after all you great advise, thanks :-)

The only thing that I am having problems with is the following
procedure since adding the new lines to destry the Inspector.

Basically if I use Next/Previous at all, when I come out of Outlook I
get a "Program Error: Outlook.exe has generated errors and will be
closed by windows.  You will need to restart...".  Since Next/Previous
does funny things with Inspectors I'd imagine it has something to do
with that, but shoudn't the On Error Resume Next statement take care
of that? Do I have it set up correctly?

If I remove the 2 lines that re oInspector.Close then I get no error
and Outlook closes as expected, however I can definitly see the
benefit of ensuring that the Inspector is also closed properly?   I am
compiling this on 2000.

Private Sub m_objMail_Close(Cancel As Boolean)
On Error Resume Next

modOutlInsp.KillInsp m_nID, Me
   
   If Err <> 0 Then
       AddInErr Err
   End If
   
   Set oInspector = m_objMail.GetInspector
   oInspector.Close

   Set m_objMail = Nothing
   Set oInspector = Nothing

End Sub

Cheers

Kristy

> The way you're using is just fine, setting the module level mail item object
> in a separate procedure than the Inspector setting procedure. I usually use
[quoted text clipped - 142 lines]
> >
> > Kristy
Ken Slovak - [MVP - Outlook] - 25 Mar 2004 16:52 GMT
You could add a test to see if Inspector Is Nothing or precede that with Not
to negate it before you close the Inspector. You can also add an Err.Clear
statement at the end of that Sub.

I've found odd circumstances where the Err object doesn't go out of local
scope when a Sub is ended and the calling procedure still has Err set to
something when the procedure resumes. I'm not sure of all the reasons why
that might be, I just sprinkle Err.Clear statements where needed and end my
UnInitHandler procedure with an Err.Clear also.

See if that helps.

Signature

Ken Slovak
[MVP - Outlook]
http://www.slovaktech.com
Author: Absolute Beginner's Guide to Microsoft Office Outlook 2003
Reminder Manager, Extended Reminders, Attachment Options
http://www.slovaktech.com/products.htm

> Hi Ken
>
[quoted text clipped - 35 lines]
>
> Kristy
Kristy - 30 Mar 2004 02:37 GMT
Hi Ken

Thanks for providing even more useful info, the err.clear in the
uninithandler is a great idea.

I changed my code to the below, but still have the same problem (ie,
Program Error: Outlook.exe has generated errors...) if I used
next/previous? If I leave the code out completley and the inspector
isn't closed properly (under some circumstances I guess this could
happen if m_objInsp isn't called) will this casue Outlook to stay in
memory?

Private Sub m_objMail_Close(Cancel As Boolean)
On Error Resume Next

modOutlInsp.KillInsp m_nID, Me
   
   If Err <> 0 Then
       AddInErr Err
   End If

   Set oInspector = m_objMail.GetInspector
   
   If Not oInspector Is Nothing Then
   oInspector.Close
   End If

   Set m_objMail = Nothing
   Set oInspector = Nothing

Err.Clear
End Sub

Cheers

Kristy

> You could add a test to see if Inspector Is Nothing or precede that with Not
> to negate it before you close the Inspector. You can also add an Err.Clear
[quoted text clipped - 47 lines]
> >
> > Kristy
Ken Slovak - [MVP - Outlook] - 30 Mar 2004 17:11 GMT
With Outlook coding both belts and suspenders are recommended <g>

In the UnInitHandler code I always have a section that unwraps and nulls any
of my wrapper collections. I always have a global Outlook.Application object
in my code and I check that to make sure that if UnInitHandler is called
more than once that errors aren't caused.

So, something like this in UnInitHandler:

If g_objOL Is Nothing Then
   Exit Sub
End If

 j = g_colInspectorWrap.Count
 For i = j To 1 Step -1
   g_colInspectorWrap.Remove i
 Next
 Set g_colInspectorWrap= Nothing

And so on for every wrapper collection I used. Then I end the UnInitHandler
code with Err.Clear.

Signature

Ken Slovak
[MVP - Outlook]
http://www.slovaktech.com
Author: Absolute Beginner's Guide to Microsoft Office Outlook 2003
Reminder Manager, Extended Reminders, Attachment Options
http://www.slovaktech.com/products.htm

> Hi Ken
>
[quoted text clipped - 32 lines]
>
> Kristy
Kristy - 02 Apr 2004 00:39 GMT
Thank you :-)

> With Outlook coding both belts and suspenders are recommended <g>
>
[quoted text clipped - 54 lines]
> >
> > Kristy
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.