[Repost] Introduction to Outlook 2003 Programming Using C #

zhaozj2021-02-12  129

Introduction to Outlook 2003 programming using C #

Release Date: 7/5/2004 | Update Date: 7/5/2004

Andrew W. Troelsen

Intertech Training

Click here to download the code example of this article.

Summary: This article describes the Microsoft Outlook 2003 object model, and explores how to generate Outlook recognition applications and Outlook add-on applications using C # programming languages. (35 page print pages)

Note This article assumes that you are already familiar with the C # programming language and .NET platform. Outlook 2003 development knowledge is not required or expected.

Applicable to:

Microsoft Visual Studio .NET 2003

Microsoft Visual C # .NET 2003

Microsoft Outlook 2003

Outlook 2003 as an object model

Microsoft has a long history in terms of applying the application's functionality to external programs. For example, if the project requires spelling inspection, you can take advantage of the object model exposed from Microsoft_ Word. In the same way, if the application being generated needs to provide the functionality provided by Microsoft_ Outlook_ 2003, the associated object model can be utilized. Simply put, Outlook 2003 object model allows you to interact with the following:

• Email item. • Outlook contact database. • Outlook calendar. • Outlook Comments and tasks. • Outlook itself 's UI (Explorer, Inspector, Command Bar, etc.).

This is obviously a subset of the features, but I am sure you have a probilization: you can access the Outlook 2003's functionality by associated object models.

Back to top

Outlook Main Interoperability Set (PIA)

So far, Outlook's functionality is made public by a COM-based process server (msoutl.olb). .NET developers want to interact with these COM types, so you need to do this through interoperability. Microsoft Corporation has provided an "formal" interoperable assembly (ie, the main interoperability assembly) included with Outlook 2003.

The assembly has been naming and resides in the global program cache under the name Microsoft.Office.Interop.Outlook.dll. To reference this assembly from Microsoft_ Visual Studio_ .NET 2003, access the "COM" tab from the "Add Reference" dialog, and select "Microsoft Outlook 11.0 Object Library" (Figure 1).

Figure 1. Quote Outlook PIA

Note If you use the previous version of Outlook PIA (or multiple versions) to generate custom applications, you must read http://go.microsoft.com/fwlink/?Linkid=30833, this article discusses some possible version conflicts .

Introduction to Interoperability

The ultimate goal of any interoperability assembly is to provide a .NET type similar to the appearance and experience similar to the original COM type. Interoperability (combined with the agent generated by the running library, the term name of the agent is "Running can call", ie RCW) to process various information about the seal processing data type. For example, if the interface method is defined as accepting a COM-based BSTR parameter, the .NET developer can freely deliver the CLR-based System.String. For each COM class, the interoperable assembly contains specific types of "-class" suffixes, as well as managed equivalents with the same name. For example, the following COM IDL definition:

coclass MyComObject {// Assume this interface defines three methods named // One (), Two (), Three () [default] interface IMyComObject;. // Assume this interface defines two methods named // Four (), Five () Interface isomenterface;}

The result is two .NET class types named myComobject and MyComobjectClass. MyComobject Type Only the member of the [Default] interface. When you want to access other interfaces, you need to perform explicit conversion (this will trigger the call to IUNKNOWN :: queryinterface ():

// Create a new MyComObject MyComObject c = new MyComObject ();. C.One (); // To call Four () or Five (), we need to obtain the // ISomeOtherInterface explicity ISomeOtherInterface itfOther = (ISomeOtherInterface) c. itfother.five ();

On the other hand, if you use the MyComObjectClass type, you can use a single object reference to access each member in each interface:

// Create a new mycomobjectclass. MycomobjectClass C = new mycomobjectclass (); c.one (); c.five ();

In fact, the type with -class suffix is ​​the combination of all interface methods of the original COM type. Assume that Outlook 2003 CoClass is initially intended to support only a single [Default] COM interface, you can usually ignore the type of -class as a suffix, and use the same .NET agent as the name.

Note If you want to discuss COM to .NET conversion process, visit http://blogs.msdn.com/eric_carter/archive/2004/05/06/127698.aspx will be helpful.

About the interaction of the hosted language with the COM type, the last point is related to the role of the CLR garbage collector. The .NET memory management model is inherently uncertain because we do not know when the developer will know when the object will be destroyed, and only know that it will eventually be destroyed. On the other hand, the COM memory model is inherently very troublesome, because we are forced to use a variety of iUnknown :: addRef () and iunknown :: release () call to manually adjust the internal reference count of the COM type object ( Although Visual Basic_ 6.0 tries to hide this).

When programming for the type of interoperability, it will be garbage collection as any CLR reference type. Once the agent has been collected by garbage, RCW will forward all IUNKNOWN:: Release () calls to the associated COM object and destroy the agent at this time. With this technology, it is conceivable that as long as the agent is active in memory, the associated COM object is also active in memory. If you want to make sure the COM type is destroyed in a more timely and more prophetically, you can use the System.Runtime.InterOpServices.Marshal type. This class defines a static method called ReleaseComObject (). Just pass the object reference, the associated COM type will be destroyed on the spot:

using System.Runtime.InteropServices; class MyClass {public void SomeMethod () {MyComObjectClass c = new MyComObjectClass ();. ... // Explicitly destroy COM type after use Marshal.ReleaseComObject (c);}}

Although the destruction of the COM type can sound very attractive, you must know that other CLR objects in Appdomain are now unable to use the basic COM type. With this (dangerous) possibility, the sample code herein will avoid using Marshal.ReleaseComObject ().

This problem has been resolved in the release of the upcoming .NET platform (Microsoft_ Visual Studio.net_ 2005, whidbey). For further details, see http://blogs.msdn.com/yvesdolc/archive/2004/04/17/115379.aspx.

Back to top

Outlook 2003 Object Model

Once the Outlook PIA is referenced, the next task is to investigate a number of types in the Microsoft.Office.Interop.Outlook namespace (Figure 2).

Figure 2. Microsoft.Office.Interop.outlook Namespace

Regardless of the size of the type, good news is that the object model itself is organized very well, and uses common design patterns. Therefore, once you know how to traverse your contact list, it will be simple to traverse the inbox item.

Other good news is that the entire object model has a complete introduction in the help file (VBAOL11.chm), which is located under: / Program Files / Microsoft Office / Office11 / 1033 by default (Figure 3).

Figure 3. Outlook 2003 documentation

Now, bad news (depending on your point of view) is the help system uses VBScript code examples and member prototypes. Assume that this article does not attempt to introduce each type in the Outlook 2003 object model, please refer to the help system to get complete information. Below, let us study some core types.

Application type

The first type to know is appropriately referred to as "Application", which is the root of all other objects in the hierarchy. Once this type of object is obtained, all aspects of Outlook itself can be programmed. Table 1 lists some members you need (but not all) members.

Table 1. Select member of the Application type

APPLICATION Type Members Basin ActiveExplorer () ActiveInSpector () These methods retrieve the Explorer / Inspector type from the current Outlook instance. This article then describes the resource manager / inspector model. CreateItem () allows new Outlook items to be created by programming. GetNameSpace () provides access to data storage. Up to Outlook 2003, MAPI is the only namespace that can be used, which is used to access the Outlook folder group (inbox, annotation, etc.). Quit () Terminates the current Outlook session. Comaddins This property allows you to find an add-in collection in the current Outlook instance at runtime. Explorers Inspectors These properties allow for a strong type of Explorers / Inspectors collection. The exact way to get Application type will be slightly different depending on the type of software developed. If you want to generate a custom application of Outlook 2003, all things to do are created using the C # new keyword:

// Create An Outlook Application Object. Application OutlookApp = New Application ();

On the other hand, when generating an Outlook 2003 external program (this article will later introduce), the Application instance will be passed by the method named onConnection ():

public void OnConnection (object application, Extensibility.ext_ConnectMode connectMode, object addInInst, ref System.Array custom) {// Assume 'applicationObject' is a member variable of // type Microsoft.Office.Interop.Outlook.Application. applicationObject = (Microsoft . In. Interop.outlook.Application) Application;

In addition to various properties and methods, the Application type also defines many events triggered in various environments (Startup, Quit, ItemSend, NewMailex). Consider the following code snippet:

public class MyApp {public static void Main () {// Create an Outlook Application object Application outLookApp = new Application ();. // Rig up the NewMailEx event outLookApp.NewMailEx = new ApplicationEvents_11_NewMailExEventHandler (outLookApp_NewMailEx);. ...} Private static void Outlookapp_newmailex (String EntryidCollection) {// do something interesting when a new e-mail arrives.}

Again, after a given interoperability, the process of processing COM-based events appears to be the same as the process of processing CLR events. Don't pay attention to the details, just pay attention to the NewMailex event work with a specific delegate (ApplicationEvents_11_NewMailexEventHandler), this delegate can call any way to accept system.string as its unique parameter, and does not return any content. Outlook "Item" class type

Once an Application type is available, you can create a new Outlook "item". Enumerate by Microsoft.Office.Interop.Outlook.OLITEMTYPE enumeration:

Public enum = 2; olcontactItem = 2; OLDISTRIBUTIONLISTITEM = 7; OljournalizationM = 4; OlmailItem = 0; OLNOTEITEM = 5; OLPOSTITEM = 6; OLTASKITEM = 3;}

Suppose you want to create a new Outlook Task item by programming. To do this, specify OliteMType.oltaskItem as an application.createItem () parameter:

. Public static void Main () {// Create an Outlook Application object Application outLookApp = new Application ();. // Create a new TaskItem TaskItem newTask = (TaskItem) outLookApp.CreateItem (OlItemType.olTaskItem); // Configure the task . at hand and save it newTask.Body = "Do not forget to send DOM the links ..."; newTask.DueDate = DateTime.Now; newTask.Importance = OlImportance.olImportanceHigh; newTask.Subject = "Get DOM to stop Bugging me. "; newtask.save ();

Note that the return value of CreateItem () is a general OLITEMTYPE; thus need to be explicitly converted to the correct type (here is TaskItem). At this time, you only need to use the type of common interface to configure the item. Once executed, you will be able to find tasks in the Outlook Task Inspector (Figure 4).

Figure 4. Mission-generated task

Although the name of the OLITEMTYPE enumeration is simple, Table 2 details the relationship between the returning type generated by the OliteMType enumeration and application.createItem ().

Table 2. OliteMType Enum / Outlook class type relationship

OliteMType enumeration value The type of basic meaning OLAPPOINTITEM AppointItem represents a single date. OlcontactItem ContactItem represents a single contact. OldiStributionListItem DistributionListIStItem represents a list of distribution groups. Oljournalitem Journalitem represents a single diary. OlmailItem MailItem represents a single email item. OlnoteItem NoteItem represents a single annotation. OlpostItem PostItem represents an announcement in the public folder that others may browse. OltaskItem TaskItem represents a single task. Get existing Outlook items

In addition to creating new items, the Outlook 2003 model also allows (and possibly modified) existing items. Regardless of which Outlook item is interested, the basic process is:

• Get the Namespace type from Application.getNameSpace (). • Get the mapiFolder type from Namespace.getDefaultFolder (). • Use the MapiFolder.Items indexer enumerator enumeration.

When specifying the parameter of the string "MAPI" as getNameSpace (), a NameSpace type will be received, which indicates the specific Outlook data store abstract level (currently, "MAPI" is the only valid namespace). The MapiFolder type can represent any folder in the mail store for a given user (deleted items, inbox, journal, etc.). The full range of folder options is represented by OldefaultFolders enumeration:

public enum OlDefaultFolders {olFolderCalendar = 9; olFolderConflicts = 19; olFolderContacts = 10; olFolderDeletedItems = 3; olFolderDrafts = 16; olFolderInbox = 6; olFolderJournal = 11; olFolderJunk = 23; olFolderLocalFailures = 21; olFolderNotes = 12; olFolderOutbox = 4; olFolderSentMail = 5; OlfolderServerFailures = 22; Olfoldersyncissues = 20; Olfoldertasks = 13; OlpublicFoldersallPublicFolders = 18;}

To request a specific folder, specify the values ​​in the OldefaultFolders enumeration as the parameters of Namespace.getDefaultFolder (). Consider the following code, these codes enumerate the current user's task collection:

static void Main (string [] args) {// Create an Outlook Application object Application outLookApp = new Application ();.. // Print all tasks NameSpace outlookNS = outLookApp.GetNamespace ( "MAPI"); MAPIFolder theTasks = outlookNS.GetDefaultFolder (Oldefault Folders.olfoldertasks); Foreach (TaskItem Task In Thetasks.Items) {Console.Writeline ("-> Time Created: {0}", Task.CreationTime); console.writeline ("-> body: {0}", Task.body);}}}}} inspectors and explorers

The Outlook object model not only allows you to access various items, but also define the type used to operate the user interface. The Explorer type represents a window for displaying the folder content. On the other hand, INSPECTORS indicates a single item that can be viewed after opening. The Application class maintains a collection of all Explorers and Inspectors to get these types by using the appropriate named Explorers / Inspectors property:

Application App = New Application (); Explorers theexplorers = app.explorers; Foreach (Explorer E In The Expercture) {// Do Something with Each Explorer ...}

The getActiveExplorer () and getActiveInSpector () methods of the Application class can be used to get the current active UI element:

Application App = New Application (); Explorer ActiveExp = App.ActiveExplorer (); Console.WriteLine ("Explorer Caption: {0}", ActiveExp.caption;

Explorers and Inspectors are useful when you generate custom Outlook add-in, because they allow you to attach UI widgets to existing Commandbars collection. This article will further introduce this situation later.

Back to top

Generate Outlook Identification Applications

To focus on Outlook object models (rather than generating a typical user interface), the first example will utilize a simple command line user interface. If you want to do it, create a new C # console application and name Opine. UNIX users may know, "PINE" is a very popular name of the command line email utility. Opine will imitate the function subset of Pine. Specifically, Opine will respond to the following command:

DIB: Show inbox item? SNM: Send new mail item? CN: Create new comment? DN: Show existing comments? Q: Exit Opine

By responding to the NewMailex event, Opine also notifies the user when the new message arrives.

Note Opine will use the ApplicationClass type (rather than application) to solve a name conflict introduced when the SYSTEM.WINDOWS.FORMS.DLL program set is then referenced. You can also use the C # alias as shown below to resolve the name conflict: use OutlookApp = Microsoft.Office.Interop.outlook.Application;

But in this case, the use -class type will not harm the OPINE example.

Handling "DIB" command

Assuming that Outlook 2003 PIA has been referenced, the next step is to create an OPINEHELPER, define a set of static methods that perform batch processing. First, we have a method called DisplayInBox (), which accepts the ApplicationClass type as its unique parameter. DisplayInbox () implementation will get the current MAPI namespace to retrieve each MailItem in the inbox folder. Here, we will use the various properties of the MailItem type, print the received time, sender name, and topic to the console:

public static void DisplayInbox (ApplicationClass o) {// Get items in my inbox NameSpace outlookNS = o.GetNamespace ( "MAPI");. MAPIFolder inboxFolder = outlookNS.GetDefaultFolder (OlDefaultFolders.olFolderInbox); // Print out some basic info Console. .Writeline ("You Have {0} e-mails.", InboxFolder.Items.count; console.writeline (); foreach (object obj in inboxfolder.items) {mailitem item = Obj as mailitem; if (item! = NULL) {Console.Writeline ("-> received: {0}", item.receivedtime.tostring ()); console.writeline ("-> sero: {0}", item.sendername); console.writeline (" -> Subject: {0} ", item.subject); console.writeline ();}}}

Note that we will use the item obtained by the items property as a general system.Objects, not the desired MailItem type. Also note that we have implemented a dynamic check to determine if the current item can be considered as MailItem (through the C # AS keyword), and if so we will interact with the various attributes of the type. The reason why we perform this dynamic check is that the Outlook Inbox can indeed contain items that exceed the MailItem type (for example, to meet the request). If you set the Foreach logic to:

Foreach (MailItem Item in InboxFolder.Items) {...}

So, if you encounter anything other than MailItem, you can receive the run library exception.

In any case, in addition to the ReceiveDTIME, SenderName, and Subject properties, the MailItem type can access attachments and importance levels, as well as the HTML performance form of the content (via HTMLBODY attribute). For a complete detail of this, see the Outlook 2003 documentation. Handling "SNM" command

The next static method of OpineHelper is SendNewMail (), which is responsible for creating and sending new emails on behalf of the user. As mentioned earlier, we will create a new MailItem type via ApplicationClass.createItem (). Read here, the following code should be easy to understand:

public static void SendNewMail (ApplicationClass o) {// Create a new MailItem MailItem myMail = (MailItem) o.CreateItem (OlItemType.olMailItem); // Now gather input from user Console.Write ( "Receiver Name:")..; MYMAIL.Recipients.Add (console.readline ()); console.write ("Subject:"); mymail.subject = console.readline (); console.write ("Message Body:"); mymail.body = console. Readline (); // send it! Mymail.send ();

Create (CN) and Display (DN) Notes

If we actually need to do just repeat the process used to create new emails and traverse existing email items, then two static methods are simple. In the following code, note that the value specified by OliteMType and OldefaultFolders:

public static void CreateNote (ApplicationClass o) {// Get access to notes NoteItem myNote = (NoteItem) o.CreateItem (OlItemType.olNoteItem); Console.Write ( "Enter your note:");. myNote.Body = Console.ReadLine (); // Now save the note myNote.Save ();.} public static void DisplayNotes (ApplicationClass o) {// Get items in my inbox NameSpace outlookNS = o.GetNamespace ( "MAPI");. MAPIFolder notesFolder = outlookNS .GetDefaultFolder (OlDefaultFolders.olFolderNotes); // Print out some basic info Console.WriteLine ( "You have {0} notes.", notesFolder.Items.Count);. Console.WriteLine (); foreach (NoteItem item in notesFolder. Items) {Console.Writeline ("-> Time Created: {0}", item.creationTIME); console.writeline ("-> body: {0}", item.body); console.writeline ();}} Last contact

The last static method here is only to display a set of options to end users:

Public static void displayopineOptions () {console.writeline ("***** welcome to opine *****"); console.writeline ("DIB: Display Inbox"); console.writeline ("SNM: Send New Mail "); Console.writeline; console.writeline (" DN: DISPLAY Notes "); console.writeline (" Q: quit "); console.writeline (" ******* ********************* ");

This will pack the creation process of the Opine Help class; now you can use it.

Back to top

Implement main () method

Here, we are ready to implement the main () method, which is responsible for performing the following tasks:

• Create an instance of the ApplicationClass type? Get the user's command options through console.readline ()? Accept the string provided by the user, and perform the appropriate method OpineHelper

After these points are given, the following is a possible implementation:

static void Main (string [] args) {// String to hold the user request string userOption;. // Create an Outlook application object ApplicationClass outLookApp = new ApplicationClass ();.. // Display info OPineHelper.DisplayOPineOptions (); do {Console.Write ("/ NPLEASE Enter Your Command:"); useroption = console.readline (); switch (useroption) {// Display Inbox (dib) case "dib": opineHelper.displayInBox (OutlookApp); Break; / / CREATE NOTE (CN): OpineHelper.createnote (OutlookApp); Break; // send new mail (SNM) Case "SNM": opineHelper.sendnewmail (OutlookApp); Break; // Display Notes (DN) Case "dn": opineHelper.displayNotes (OutlookApp); Break; // quit (q) case "q": useroption = "q"; break; default: // anything else? Just Display Options. OpineHelper.displayOpineOptions (); break ;}} while (useroption! = "q");} Processing newMailex event

The last feature we will add to OPINE is to process the ability to pass the new email. First, processes NewMailex events after allocating the ApplicationClass type:

. // Create an Outlook application object ApplicationClass outLookApp = new ApplicationClass (); // Rig up the new message event outLookApp.NewMailEx = new ApplicationEvents_11_NewMailExEventHandler (outLookApp_NewMailEx).;

ApplicationEvents_11_NewMailexEventHandler delegated a target that requires a type of System.String parameters. The value of this string represents the ID of the new MailItem itself (you can get MailItem via the Namespace.GetItemFromid () method).

In the later event handler, note that we use the System.Windows.Forms.MessageBox type to notify the user to have new messages, so be sure to add a reference to System.Windows.Forms.dll (and update your file with the instruction set. ):

private static void outLookApp_NewMailEx (string EntryIDCollection) {if (DialogResult.Yes == MessageBox.Show ( "Do you want to see your message?", "You've got mail!", MessageBoxButtons.YesNo)) {// Get the . incoming MailItem based on ID ApplicationClass o = new ApplicationClass (); NameSpace outlookNS = o.GetNamespace ( "MAPI"); MAPIFolder mFolder = o.Session.GetDefaultFolder (OlDefaultFolders.olFolderInbox); MailItem newMail = (MailItem) outlookNS.GetItemFromID ( EntryidCollection, mfolder.storeid); // Now print out. Console.writeLine ("/ n / n ***** new message *****"); console.writeline ("-> sender: {0}" , newmail.sendername; console.writeline ("-> Subject: {0}", newmail.subject); console.writeline ("-> body: {0}", newmail.body); console.writeline ("* ********************** / N / N ");}} This is the final step. Now we can perform compilation and test Opine (Figure 5).

Figure 5. Opine in operation

I am sure that you can find many ways to extend and improve Opine, including moving from the console-based UI (via Windows Form). Although I obviously knows that you rarely generate command line email programs, I hope that this example has already clarified the process of interacting through custom applications with Outlook.

Back to top

Conflict with Outlook Security Update

When running Opine, you must know the following dialogs started by Outlook (Figure 6)

Figure 6. Outlook 2003 Safety Warning

Although this will interfere with end users, this behavior is designed. Below Outlook 2003, (Select Object) Select members being considered to be safe risk. Thus, the system prompts the user to enter permissions to continue to operate, preventing email worms and viruses to use object models to do bad things.

Note If you want to read the documentation about which Outlook type and members, please refer to the article What's New in Microsoft Office Outlook 2003 for Developers?

If the end user can always reject access to Outlook by programming the security prompt, you can freely use the TRY / CATCH logic when you use Outlook in a custom application. For example, in order to avoid running library failures, OpineHelper.DisplayNotes () should be changed as follows:

Public Static Void DisplayNotes (ApplicationClass O) {// Same As Before ... try {foreach (NoteItem Item in Notesfolder.Items) {// Same as Before ...}} catch {console.writeline ("Can't Access Outlook ");}} Note It is noted that when generating an Outlook Add, the transfer Microsoft.Office.Interop.outlook.Application parameter is assumed to be trusted, in most cases, this will Block the emergence of security alerts.

Back to top

Create an Outlook Outprise using Visual Studio .NET 2003

The next example study how to use custom features to extend Outlook 2003. The entire idea of ​​application scalability is another cornerstone of Microsoft products. Basically, applications such as Outlook, Word or Visual Studio .NET are intended to enable external vendors or individuals to extend the above functions by inserting new objects (assuming the above objects).

Although most of you know only using the C # command line compiler (CSC.exe) and NotePad.exe to generate an add-in, if you use the Visual Studio .NET sharing add-in project template, save some typing time. To clearly explain, we will create an external program called EmailStatsAddin. The add-in will be inserted into the existing UI of Outlook 2003 and provide the following features:

• Display how many emails have received in this day / month. • Display how many emails have been sent in this day / month.

First select this template from the Other Projects | Extensibility Projects folder of the New Project dialog (Figure 7).

Figure 7. Shared external program project template

Once click the OK button, the system will guide you with a five-step wizard to configure the initial shared add-in project. The first step is to select the language you want to use (Microsoft_ Visual Basic_.NET C ) and the Basic Frame (.NET or COM-based ATL). For our example, we obviously hope Visual C #.

The second step is to select the host of an external program. Assume that we are only interested in Outlook 2003, please uncheck all other options (Figure 8).

Figure 8. Select the desired host

Step 3 Allows you to provide the "friendly" name and description of the current external program. These string values ​​are used to control how the add-in will be registered and displayed by the host add-in dialog. Please enter the value you think is appropriate.

The two options shown in step 4 are used to specify whether the add-in should be automatically loaded into the host when starting, and allow which users on the target machine access to the external connection. For EmailStatsAddin, we will select these two options (Figure 9).

Figure 9. Options to load shared add-in.

Step 5 Use only to confirm the selected item. Once the shared add-in wizard is completed, you will find a solution that you have received two projects:

• External program itself (EmailstatsAddin)? Installation item (emailstatsaddinsetup)

This article discusses the role of the installation item later.

Quote

In addition to the standard system.dll, system.data.dll, and system.xml.dll assembly, the shared add-in automatically references an assembly called Extensibility.dll, except for the SYSTEM.DATA.DLL assembly. The assembly contains a single namespace (EXTENSIBILITY), which is exactly three types (see Table 3). table 3. Type of scalability namespace

Scalability Namespace Type Basic Meaning IdTextensibiltity2 All add-on-connections must be implemented. Ext_ConnectMode enumeration indicates a variety of ways to connect hosts to a given external program. Ext_disconnectMode enumeration indicates a variety of ways that can be disconnected from a given external program with hosts.

The referenced additional assembly that needs attention is Office.dll. Although the assembly is confirmed by a variety of types (can be confirmed by the Visual Studio.net 2003 object browser), the most important type must be interacting with the custom widget to extend the host's GUI to interact with the procedures being developed. . Here, I will not discuss too many of the Office object model, please refer to Online Reference on the MSDN website in this regard.

Note that the shared add-in project template does not automatically reference the Microsoft.Office.Interop.outLook.dll assembly, so be sure to make this reference through the Add References dialog. To do this, add a reference to System.Windows.Forms.dll, which will need it when accessing the MessageBox type.

Back to top

Analyze connection type type

The primary file that needs attention should be named Connect.cs. Here, a class type named Connect is found, as shown below (for the sake of simplicity, deleting XML code comments):

[GuidAttribute ( "762B03FF-52D0-4735-9D2B-4DE32DB9393E"), ProgId ( "EMailStatsAddIn.Connect")] public class Connect: Object, Extensibility.IDTExtensibility2 {public Connect () {} public void OnConnection (object application, Extensibility. ext_ConnectMode connectMode, object addInInst, ref System.Array custom) {applicationObject = application; addInInstance = addInInst;} public void OnDisconnection (Extensibility.ext_DisconnectMode disconnectMode, ref System.Array custom) {} public void OnAddInsUpdate (ref System.Array custom) { } Public void onstartupComplete (Ref System.Array Custom) {} public void Onbeginshutdown (Ref System.Array Custom) {} private object applicationObject;}

The first point to note is that the class has [GUID] and [Progid] properties, which are used to identify COM classes. When you create a hosted code base, you may want to know why you need to register the assembly as used by COM. Mill, most hosts that can access the external program type are written as loading COM servers (not .NET assemblies). Therefore, in order to enable interoperability, it is necessary to provide the COM naming convention required for the Connect type (of course, the GUID value will be different). What should be noted next that the Connect type does not extends the base class-centric class with an extraline, but is only derived from System.Object. The reason why the shared add-in has uniqueness is that it implements a key interface: extensibility.idtextensibility2. In fact, members of the Connect class are only the basic implementation of the interface contract.

Finally, note that the Connect class defines two private member variables:

Private Object ApplicationObject; Private Object AddinInstance;

The second member variable indicates an instance of the current add-in from host allocation and insertion. ApplicationObject member variables represent references to host applications.

Assuming that the shared add-in can be inserted into a lot of different applications (Outlook 2003, Visual Studio.Net 2003, Various Microsoft Office Applications, etc.), then applicationObject is defined as a general system.object. However, if our external procedure is just used by Outlook, the ApplicationObject is defined as a Microsoft.Office.Interop.Outlook.Application type:

! // Do not forget to reference the Outlook interop assembly using Microsoft.Office.Interop.Outlook; ... public class Connect: Object, Extensibility.IDTExtensibility2 {... // Change to a strongly typed Outlook Application type /. / private object applicationObject; private microsoft.Office.Interop.outlook.Application applibility }.com

Use this initial code update to let us check the features provided by the IDTEXTENSIBILITY2 interface.

Back to top

IDTEXTENSIBILITY2 interface role

The IDTEXTENSibility2 interface type defines five methods called by each phase of the hosting cycle of the external program. Here are formal definitions:

public interface IDTExtensibility2 {void OnAddInsUpdate (ref Array custom); void OnBeginShutdown (ref Array custom); void OnConnection (object Application, ext_ConnectMode ConnectMode, object AddInInst, ref Array custom); void OnDisconnection (ext_DisconnectMode RemoveMode, ref Array custom); void OnStartupComplete (REF Array Custom);} onConnection () method

The first method that needs attention is to be onConnection (), and the method will call the method when the external program is connected to the host. The first parameter represents the host application itself (Visual Studio.NET, Microsoft Outlook, etc.). The second parameter is an enumeration of type ext_connectMode, which means how the host is specific to load an external program type. Ext_connectMode enumeration defines the following (where ext_cm_commandline, and ext_cm_solution will not be used by Outlook 2003):

public enum ext_ConnectMode {// Add-in loaded after host ext_cm_AfterStartup = 0;.. // Add-in loaded from command line ext_cm_CommandLine = 3;. // Add-in loaded indirectly from host ext_cm_External = 2; // Add-in Loaded by a vs.net solution which required it. ext_cm_solution = 4; // loaded when host starts-up. EXT_CM_STARTUP = 1; // loaded for very first time after installed. EXT_CM_UISETUP = 5;}

The third parameter is an object that represents an external program instance of the IDE host, where the last parameter type is System.Array, which represents any custom data provided by the user (it can be ignored in our example).

The generated code is simple. However, if a strong type of ApplicationObject member variable has been defined, you will now use explicit conversion to allocate the variable:

public void OnConnection (object application, Extensibility.ext_ConnectMode connectMode, object addInInst, ref System.Array custom) {applicationObject = (Microsoft.Office.Interop.Outlook.Application) application; addInInstance = addInInst;}

We need to have an initial update to the onConnection () method. According to Knowledge Base Article, OnConnection () should perform running library tests to determine if the connection mode is different from ext_connectMode.ext_cm_startup, if so, forward the incoming system.Array to an ONSTARTUPCOMPLETE () Add program realization:. public void OnConnection (object application, Extensibility.ext_ConnectMode connectMode, object addInInst, ref System.Array custom) {// Cast to a strongly typed Application ... // If we are not loaded upon startup, forward to OnStartupComplete ( ) // and pass the incoming system.Array. if (connectMode! = ext_connectmode.ext_cm_startup) {onStartupComplete (REF CUSTOM);}}

OndisConnection () method

This method will be called when an external program is disconnected (usually by adding / deleting an add-in dialog or when the host is closed). The disconnect mode is represented by the first parameter of the type ext_disconnectmode:

Public enum ext_disconnectMode {ext_dm_hostshutdown = 0; ext_dm_solutionclosed = 3; ext_dm_uisetupcomplete = 2; ext_dm_userclosed = 1;}

An onDisconnection () creating it is currently empty. Obviously, this is where the add-on execution of any cleaning operation, in order to successfully shut down, the add-in may need to perform this operation. Again, according to Knowledge Base Article, the neat and correct implementation of this method should be tested (this time for any content other than ext_disconnectmode.ext_dm_hostshutdown), and forward the incoming system.Array to our OnbeginshutDown () Implementation:

public void OnDisconnection (Extensibility.ext_DisconnectMode disconnectMode, ref System.Array custom) {if (disconnectMode = ext_DisconnectMode.ext_dm_HostShutdown!) {OnBeginShutdown (ref custom);} applicationObject = null;}

ONADDINSUPDATE () method

If the end user is inserted or deleted in the host, an onaddinsupdate () method () will be called (available with the Application.comAddins property to get the current list at runtime). If you need to perform any special procedures when the end user is added or deleted, this will be where the operation is performed. Automatically generated implementation is currently empty, and this state can be retained.

OnStartUpComplete () method

This method will be called after the host application is loaded. At this time, all host resources are available for use. This is an ideal place for constructing the UI for an external program type because you can safely get the Explorers and Inspectors sets. OnbeginshutDown () method

Last introduction OnBeginShutdown (), it indicates that the host is in a closed process (just before calling the onDisconnection () method). At this time, the host application can still be accessed, so this is an ideal place to delete any UI widget inserted into the Activities Manager.

Back to top

Implement the UI of an external program

Our first business order is a user interface for our external program. If the UI of the add-in is inserted into the host application, we will define a new member variable for Microsoft.Office.Core.commandbarButton for the Connect class type:

Public Class Connect: Object, Extensibility.idtextensibility2 {... // Our Ui Will Consist of a Single CommandbarButton Private Commandbutton BtnetemailsTats;}

CommandBarbutton widget (for displaying title "statistics") will be inserted into Outlook's standard command column (Figure 10):

Figure 10. Custom Statistics CommandbarButton

As mentioned earlier, if the host is completely started, the onStartUpComplete () method is an ideal location for generating the UI element. Below is the steps you need to insert the new CommandBarButton type to the existing command bar:

• Get the command column from the active resource manager. • View the button currently in the control collection of the command bar that wants to modify. If not, create and enable new instances. • Hook the Click event in CommandBarbutton to respond to the customization of the widget.

In this way, the following is the implementation of the updated (and detailed) onStartupComplete ():

public void OnStartupComplete (ref System.Array custom) {// First, get access to the CommandBars on // the active explorer CommandBars commandBars = applicationObject.ActiveExplorer () CommandBars;.. try {// If our button is already // on .. the Standard CommandBar, use it btnGetEMailStats = (CommandBarButton) commandBars [ "Standard"] Controls [ "Statistics"];} catch {// OOPS Our button is not there, so // we need to make a new instance!. // Note that the Add () method was // defined to take optional parameters, // which are not supported in C #. // Thus we must specify Missing.Value. btnGetEMailStats = (CommandBarButton) commandBars [ "Standard"]. Controls .Add (1, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value); btnGetEMailStats.Caption = "Statistics"; btnGetEMailStats.Style = Msobuttonstyle.msobuttoncaption;} // setting the tag protection is not required, but can be used // to quickly recster you Button. Btnge tEMailStats.Tag = "Statistics"; // Setting OnAction is also optional, however if you specify // the ProgID of the Add-in, the host will automatically // load the Add-in if the user clicks on the CommandBarButton when / / the Add-in is not loaded After this point, the Click // event handler is called btnGetEMailStats.OnAction =.. "!"; btnGetEMailStats.Visible = true; // Rig-up the Click event for the new CommandBarButton type. BtngeTemailStats.Click = new _commandbarbuttonevents_clickeventhandler (btnetemailstats_click); We can quickly implement custom logic, but it is just the following Stub code:

Private void btngeetemailstats_click (commandbarbutton ctrl) {// Todo: Implement Custom Logic.} Delete UI

Now, we have completed the logic of CommandBarbutton once the host starts, and then we will modify OnBeginShutdown () to delete this widget when it is closed:

public void OnBeginShutdown (ref System.Array custom) {// Get set of command bars on active explorer CommandBars commandBars = applicationObject.ActiveExplorer () CommandBars;.. try {// Find our button and kill it commandBars [ "Standard"]. .Controls ["getemailstats"]. Delete (system.reflection.missing.value);} catch (system.exception ex) {messagebox.show (ex. measureage);}}

Note You may be guessed, you can extend the Outlook 2003 GUI in many ways. For other techniques, see Creating Managed Outlook Buttons With icons.

Back to top

Implement email statistical logic

The final task is to implement logic in the Click event handler. We will use the Outlook object model to determine the number of emails received and sent every day and monthly. After generating Opine, the following logic should be quite simple:

private void btnGetEMailStats_Click (CommandBarButton Ctrl, ref bool CancelDefault) {string statInfo; DateTime today = DateTime.Today; // The stats we are tracing int eMailsToday = 0;. int eMailsThisMonth = 0; int eMailSentToday = 0; int eMailSentThisMonth = 0; // Get items in user's inbox NameSpace outlookNS = applicationObject.GetNamespace ( "MAPI");. MAPIFolder inboxFolder = outlookNS.GetDefaultFolder (OlDefaultFolders.olFolderInbox); // Compare time received to current day / month // and update our counters foreach. (object item in inboxFolder.Items) {MailItem mi = item as MailItem; if (mi = null!) {if (mi.ReceivedTime.Day == today.Day) eMailsToday ; if (mi.ReceivedTime.Month == today. Month) eMailsThisMonth ;}} // Build first part of statInfo string statInfo = string.Format ( "E-mails received today: {0} / n"., eMailsToday); statInfo = string.Format ( "E-mails received THIS MONTH: {0} / n ", emailsthismonth); Statinfo =" -------------------------------------------------------------------------------------------------------------------------------------------------------- ----- / N "; // Get Items in User's Sen t item folder and // test again MAPIFolder SentFolder = outlookNS.GetDefaultFolder (OlDefaultFolders.olFolderSentMail);. foreach (object item in SentFolder.Items) {// See if current item is a MailItem MailItem mi = item as MailItem; if (mi ! = null) {// IT IS, SO get day / month stats. if (mi.senton.day == Today.day) EmailSentToday ; if (monthon.month == Today.month) EmailSentThismonth ;}} / / Build Last Part of Statinfo String. Statinfo = String.Format ("e-mails Sent Today: {0} / n", emailsenttoday; statinfo = string.format ("

E-mails Sent this Month: {0} / n ", emailsentthism"; // Show results. Messagebox.show (Statinfo, "Current E-mail Stats");} To here, our external procedure is completed! Assume You can compile the project without errors, then you can register and test the emailstatsaddin feature.

Back to top

Register shared add-in

Remember, when you create a shared add-in project with Visual Studio.Net 2003, you receive a installation item. To generate the emailstatsaddin you can use, right-click the EmailstatsAddInsetup item icon in the Solution Explorer and select "Rebuild".

Figure 11. Generating an installer

Since then, the project directory will contain standard installation executables and * MSI installer files. You can use these files to install the add-in, or you can install directly in Visual Studio.net 2003 (Figure 12).

Figure 12. Installing EmailstatsAddin via VisualStudio.NET 2003

Now, when Outlook 2003 is started, you should find the Statistics button in the standard command bar. There is no doubt that today, today's email statistics will be seen (Figure 13).

Figure 13. Run EmailstatsAddin

Note It is noted that in order to meet your needs, you may need to modify the installation logic generated by Visual Studio.net 2003. Your .NET assembly may not be registered properly as you can be used by COM. If such a situation, the hosted add-on can not appear in the Outlook COM Add Direct Dialog box, which is a big problem if the add-in is not configured to start at startup. Microsoft's Omar Shahine is already in this problem with this problem in http://go.microsoft.com/fwlink/?Linkid=30833. Another point of view of this problem can be found at http://blogs.msdn.com/robmen/archive/2004/04/28/122491.aspx.

Back to top

summary

We have seen that using the main interoperable assembly, .NET developers can interact with Outlook 2003 types. The Application Type is the root of the model, and the model discloses a lot of collections representing various Outlook items. During the development of command-driven mail applications (OPINE), you have learned how to create and get access by programming and get each item, and how to respond to selection events. We have clarified that Outlook 2003 itself can be expanded by creating a custom external program. Visual Studio.net 2003 provides specific project templates for this, which can generate classes that implement the IDTEXTENSIBILITY2 interface, and related installer items.

Obviously, in this introductory article has been examined, the external program and the Outlook 2003 object model have more information. My goal is to provide an introduction to the Outlook 2003 object model from the perspective of the C # programmer. I hope that my introduction has made a foundation for programmers. If you are interested in additional information, please refer to the following reference:

? Developing Solutions with Microsoft Outlook 2002? Using Automation in Microsoft Office Access 2003 to Work with Microsoft Office Outlook 2003? Building Outlook 2002 Add-ins with Visual Basic .NET? What's New in Microsoft Office Outlook 2003 for Developers?? Developing COM Add- INS for Microsoft Office 2000 Back to Top

About author

Andrew Troelsen is an Intertech Training consultant and trainer. Andrew is a lot of books, including winning C # and the .NET Platform Second Edition (APRESS Press, 2002). He also writes articles for all version of MacTech's monthly column, in which he explores how to develop .NET on UNIX-based systems using SSCLI, Portible.Net and Mono CLI distribution software.

Go to the original English page

转载请注明原文地址:https://www.9cbs.com/read-6873.html

New Post(0)