A CDO 1.21 .NET Sample Application
To show you how to use some of the existing COM interfaces in your .NET applications, I'll show you a simple application (in both Visual Basic .NET and Visual C#) that uses the CDO 1.21 object model.The application creates a new CDO session, logs on, queries the user's inbox to display some information, and then sends an e-mail from the user's account. Here it is in Visual Basic:Imports MAPI
Public Class Form1
Inherits System.Windows.Forms.Form
#Region " Windows Form Designer generated code "
#End Region
Dim oSession As New MAPI.Session()
Private Sub cmdLogon_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles cmdLogon.Click
Err.Clear()
'Attempt to Logon
'Check to make sure server and user alias are filled in
If txtExServer.Text = " Then
MsgBox("You must enter a server name!")
Exit Sub
End If
If txtAlias.Text = " Then
MsgBox("You must enter an alias!")
Exit Sub
End If
Try
'Attempt to logon
oSession.Logon(", ", True, True, 0, True, _
txtExServer.Text & vbLf & txtAlias.Text)
'Get the Inbox
Dim oInbox As MAPI.Folder = oSession.GetDefaultFolder( _
MAPI.CdoDefaultFolderTypes.CdoDefaultFolderInbox)
Dim oMessages As MAPI.Messages = oInbox.Messages
lblInbox.Text = "There are "
lblInbox.Text &= oMessages.Count & " items in your inbox."
MsgBox("Logon successful.")
Catch
'Some error has occurred!
Dim oException As System.Exception
oException = Err.GetException
MsgBox("ERROR: " & Err.Number & " " & Err.Description & _
" Line number: " & Err.Erl & " Stack dump: " & _
oException.StackTrace)
End Try
End Sub
Private Sub cmdSend_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles cmdSend.Click
Try
If txtTo.Text = " Then
MsgBox("You must enter a To address!")
Exit Sub
End If
If txtSubject.Text = " Then
MsgBox("Please enter a subject.")
Exit Sub
End If
If txtBody.Text = " Then
MsgBox("Please enter a body.")
Exit Sub
End If
'Send the message
Dim oMessage As MAPI.Message
Dim oOutbox As MAPI.Folder
oOutbox = oSession.GetDefaultFolder( _
MAPI.CdoDefaultFolderTypes.CdoDefaultFolderOutbox)
oMessage = oOutbox.Messages.Add()
Dim oRecips As MAPI.Recipients
oRecips = oMessage.Recipients
Dim oRecip As MAPI.Recipient = oRecips.Add(txtTo.Text, , _
MAPI.CdoRecipientType.CdoTo)
oMessage.Subject = txtSubject.Text
oMessage.Text = txtBody.Text
'Resolve the recipients
oRecips.Resolve(True)
If oRecips.Resolved <> True Then
MsgBox("You must resolve the recipients!")
Exit Sub
End If
oMessage.Send(True)
Catch
'Some error has occurred!
Dim oException As System.Exception
oException = Err.GetException
MsgBox("ERROR: " & Err.Number & " " & Err.Description & _
" Line number: " & Err.Erl & " Stack dump: " & _
oException.StackTrace)
End Try
End Sub
End Class
The C# sample has the same functionality as the Visual Basic version. You need to know a couple of things about programming with C# to be successful programming against CDO 1.21. First, you must declare the default threading for your application to be a single-threaded apartment (STA). You do this by using the [STAThread] attribute. This is what CDO expects your application threading model to be. If you skip this step, you will probably get a MAPI_E_UNKNOWN error.Second, you must pass Missing.Value for any optional object arguments in the method calls in CDO. Otherwise, C# will throw a compilation error because it will not be able to find CDO function prototypes that match your calls. Be sure to include the System.Reflection namespace to take advantage of the Missing.Value statement.Besides these two differences and the difference in language semantics between Visual Basic and C#, the code is pretty much the same. Here is the C# version:
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Reflection;
namespace CDO121CSharp
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class frmMain : System.Windows.Forms.Form
{
private System.Windows.Forms.Button cmdGo;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
public frmMain()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after
// InitializeComponent call
//
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
. . .
#endregion
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new frmMain());
}
private void cmdGo_Click(object sender, System.EventArgs e)
{
// Class variables
MAPI.Session oSession;
string strExchangeServer = "thomrizwin2k";
string strUserName = "thomriz";
// Establish a new Session
oSession = new MAPI.Session();
// Connect to the Exchange Server and establish
try
{
oSession.Logon( Missing.Value, Missing.Value,
false, true, -1, true, strExchangeServer +
"\n" + strUserName);
MessageBox.Show("Logon Successful!");
MAPI.Folder oInbox =
MAPI.Folder)oSession.GetDefaultFolder(
MAPI.CdoDefaultFolderTypes.CdoDefaultFolderInbox);
MAPI.Messages oMessages =
(MAPI.Messages)oInbox.Messages;
MessageBox.Show("There are " + oMessages.Count +
" items in your inbox!");
//Send a new message
MAPI.Folder oOutBox =
(MAPI.Folder)oSession.GetDefaultFolder(
MAPI.CdoDefaultFolderTypes.CdoDefaultFolderOutbox);
MAPI.Messages oOutMessages =
(MAPI.Messages)oOutBox.Messages;
MAPI.Message oMsg =
(MAPI.Message)oOutMessages.Add(Missing.Value,
Missing.Value,Missing.Value,Missing.Value);
MAPI.Recipients oRecips =
(MAPI.Recipients)oMsg.Recipients;
MAPI.Recipient oRecip =
(MAPI.Recipient)oRecips.Add("Thomas Rizzo",
Missing.Value,Missing.Value,Missing.Value);
oRecips.Resolve(true);
oMsg.Subject = "New Test Message";
oMsg.Text = "Test 123";
oMsg.Send(Missing.Value,Missing.Value,Missing.Value);
}
catch (System.Exception oException)
{
throw new Exception(
"Could not logon to Exchange Server " +
strExchangeServer, oException);
}
}
}
}
Note | To use ASP.NET with CDO 1.21, you must have the nonsecure version of CDO 1.21 on your server machines by installing Exchange or Outlook Web Access (OWA) on the server. (The version of CDO that ships with Outlook is secure, so it will not work.) This is the only way to get CDO 1.21 on the machine. You can get CDO 1.21 installed on your Web server with the administration-tools-only installation of Exchange. You will not run into issues when an ASP.NET application that uses CDO 1.21 and your Exchange server are on the same machine. However, if they are on separate machines, you might get a MAPI_E_FAILONEPROVIDER error or a MAPI_E_LOGON_FAILED error. Removing the secure CDO installation and installing a server-side version of CDO should fix this problem. Also, with ASP.NET the worker thread does not have access to the Windows file directory; if you use dynamic profiles with CDO, you might get errors. To fix this problem, follow the steps in Microsoft Knowledge Base Article Q166599. |