|
-
Nov 26th, 2002, 11:33 AM
#1
Thread Starter
Addicted Member
Outlook 2000 Com Addin
I'm working on an Addin for Outlook 2000 in VB.NET.
I've found several articles on MSDN that are supposed to be helpful but I've been having no end of problem with it. I actually had to end up making the functionality the client wanted into a seperate app just to get it in on time. However I don't like being beaten by a computer program so I'm trying again.
All I need the thing to do right now... is work correctly as a shell with Outlook 2000 (version 9.0.0.2711)....I'll add in the functionality of it later. I seem to be having a type conflict which doesn't make sense but it causing errors when I start up outlook. I assume it has something to do with how COM behaves with the new .Net framework.
I've tried using the Microsoft.Office.Outlook.Interop.Dll (which is actually for Office XP). I've tried using the Interop.Dll that is compiled by VB.NET. I've tried changing the references to Office and Outlook themselves (from COM to .NET versions in the reference section). But each time a new error crops up from the same location in the addin. Below is the relevant section of the code. I've even tried declaring the variables differently but thus far I've had no luck and since my startup event is erroring out, I can't get any of the code I need to work functional.
Public Sub OnConnection(ByVal application As Object, ByVal connectMode As Extensibility.ext_ConnectMode, ByVal addInInst As Object, ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnConnection
Dim oApp As Outlook.Application
oApp = CType(application, Outlook.Application)
mobjAddInGuts.InitHandler(oApp, MyProgID)
Catch ex As System.Exception
MsgBox("On Connection Exception: " & vbCrLf & ex.Message & vbCrLf & "----" & vbCrLf & "Stack Trace: " & vbCrLf & ex.StackTrace & vbCrLf & "----" & vbCrLf & "Source: " & ex.Source)
End Try
End Sub
And in another class....
Friend Sub InitHandler(ByVal oApp As Outlook.Application, ByVal strProgID As String)
Try
mobjOutlook = CType(oApp, Outlook.Application)
Catch ex As System.Exception
MsgBox("On Connection Exception: " & vbCrLf & ex.Message & vbCrLf & "----" & vbCrLf & "Stack Trace: " & vbCrLf & ex.StackTrace & vbCrLf & "----" & vbCrLf & "Source: " & ex.Source)
End Try
end Sub
There is actually other code in these sections, but nothng related to these objects. What appears to be happening is that the Outlook instance that is spawning the Addin is being passed (as the application object variable) as an Object to the OnConnection sub....The OnConnection sub is casting it as an Outlook.Application...
THen it's supposed to pass it to the InitHandler method of the mobjAddinGuts class along with the ProgID (not sure why it needs that...doesn't appear to be doing anything with it).
It's erroring out, depending on what I try at the line where oApp is cast equal to application as an Outlook.Application. Which causes another problem once we get to the INithandler.
Anyone know what's going on?
Eiredrake
-
Dec 9th, 2002, 04:03 PM
#2
Thread Starter
Addicted Member
Fu fun fun
Alrighty. I've actually gotten the Outlook 2000 plugin working for XP in VB.NET.
It wasn't easy. It was rather reminescent of mining for gold in a swamp but finding enough hematite to sell to keep you from starving to death. I've gone through SO much crap trying to get this to work that I am seriously discouraged for using .NET at all. Were it not for the object oriented abilities that it gives (and the fact that my employer wants me to use it) I'd be kicking it to the curb and going with good ol' VB 6.
One of the biggest problems I've run in to, was the lack of information on the net for .NET. Yes, I found stuff. But usually not anything useful. You do a search for almost anything having to do with 6.0, you can find it. That is the reason why I am posting what I've found. We need to expand the online resources available to us as developers. Because I don't believe anyone should have to go data mining to find out why M$'s stuff isnt working the way they say it will. Fortunately... I'm a stubborn bastich and I refuse to be beaten by a computer.
In any case... the Interop.Outlook.dll that is compiled by .NET makes some incorrect assumptions about how the outlook objects should be interacting with .NET. It makes some of the ones you need PRIVATE... so that you can't actually access them. This causes some odd errors including an Invalid Cast Error when you try to cast objects... such as grabbing the Inbox and creating an email in it. The next link explains what had to be done to get around that... and it's a pain in the butt.
Invalid Casting of Objects
http://support.microsoft.com/default...;en-us;Q309336
This issue also creates a problem where the compiler cannot tell the difference between the QUIT event of an object and the QUIT method of that object. To combat this, the interop creates what I assume is some sort of shell class object that you can access. Of course none of this is noted in the original MS code I found. I had to look for it. I can't find the right bookmark to post it, but if you declare everything except your main Outlook.Application object as Outlook.<object>Class you'll get an extra event that allows you to close the objects. Without that event handler you'll never get outlook out of memory without terminating it's process.
To top it off, Outlook never seems to actually release memory until it terminates. Try it yourself. Use the Task Manager (CTRL-ALT-DEL) and activate outlook. Watch the memory usage and click on a few emails. It goes up pretty quickly and never actually goes away until you close the program. In order to make it do so, you have to create event handlers for every object that raises events, which means all your objects must be of modular scope or better. Local scope doesn't allow event handlers
. Most importantly are the Inspector and Explorer objects. Unfortunately to do this, you must declare them as OUtlook.ExplorerClass objects because of the Interop.dll's problems above. In theory... if the use left it open long enough Outlook would gobble up every last bit of memory as the user opened email, contacts and other inspector based objects and closed. The objects don't actually get removed from memory when you close them.
Outlook won't terminate from memory
http://support.microsoft.com/default...b;EN-US;208332
Microeye's Help & Base code
http://www.microeye.com/resources/template.htm
Once the user closes the outlook instance that spawns your addin, you will need to dispose of each object from memory using Marshal.ReleaseComObject(object) method. Unfortunately, you have to pause after each disposal or outlook will either lock up or alternatively Crash and display the nice 'Would you like to report this problem to Microsoft' prompt. I caused the thread to Sleep for 800 miliseconds and it seems to work just fine. 500 ms also worked well but anything less than that seemed to crash outlook. This should only be done during the Explorer.ExplorerEvents_Event_Close event that you will need to create a handler for and only when the Inspector's count is 0. Not doing so will be begin throwing page fault errors at you.
Now then we have the threading/timer issue. Apparently com interop with .NET is such that if you declare COM or COM+ objects on a thread different from the one they are declared on you end up with some invalid or partially valid reference.
What I mean is if you follow your code and step through it and get to the point where you reference it in the other thread, then look at the object's members in the Watch window you'll see most if not all of them say 'Error: Cannot retrieve value'.
I found this out because I used a timer to control when the code in my add in was executed and got what I just said in the last paragraph. When I created a loop in the main thread (The OnConnection or OnStartupComplete subs) the objects worked just fine and displayed all of their methods and properties. Unfortunately because I was in a loop the User never actually got to interact with outlook. At first I used the loop in the OnConnection sub, but that didn't work because Outlook's UI hasn't kicked in yet.
I tried using a seperate thread instead of a loop in the main sub and got the same result as with a timer. Because apparently a timer is a seperate thread, so it doesn't interfere with the main execution of a program. Makes sense really, otherwise while a timer was running you would never be able to do anything.
What I finally had to do... was move the loop to the OnStartupComplete sub, which is after Outlook's UI has taken over. The loop is a standard DO...LOOP using a boolean to control whether or not the loop goes all the way through it's current interation or immediately jumps out of the sub. I also had to put in a second boolean to make sure that the previous iteration of the loop had fully fnished it's loop. Just in case it was still working when the loop came back around.
I started getting some odd errors until I put that in. Something about an object (which turned out to the the mailitem object) being seperated from it's RVC. Never did find out what it meant, but it seemed to happen when the program tried to instantiate a new mail object using the same subroutine and modular object before the last iteration was finished.
I use a rather elaborate conditional statement to get the work done.. Including a date variable with a second added to the 'current time' of the executing loop iteration. I also librally use Windows.Forms.Application.DoEvents() to allow the Outlook UI to actually respond to the user while I'm doing my thing.
The boolean controlling the loop is triggered to halt the loop when the last Explorer closes... this allows Outlook to move on to the BeginShutdown sub and then to the OnDisconnect event.
All in all I don't believe this project was at all worth what effort I had to put into it in order to get the damned thing to finally function. It works reasonably well as long as the user isn't receiving more than 5 email a second. You begin noticing a difference in outlook if that threshhold is reached.
I'd post the base code here in the hopes that someone can be saved the same aggravation I went through. Minus the proprietary stuff that I wrote for my company of course. Anyone using it should keep in mind that the setup routine is essential, you cannot install the .dll manually inside outlook.
Happy coding all,
Eiredrake
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|