Imports System.IO Imports System.Runtime.InteropServices Imports System.Threading Imports EgtUILib #Region "Public MapiMailMessage Class" ''' ''' Represents an email message to be sent through MAPI. ''' Public Class MapiMailMessage Public Shared m_ErrorCode As Integer Public Enum MAPIError As Integer MAPI_USER_ABORT = 1 MAPI_E_FAILURE = 2 MAPI_E_LOGIN_FAILURE = 3 MAPI_E_DISK_FULL = 4 MAPI_E_INSUFFICIENT_MEMORY = 5 MAPI_E_BLK_TOO_SMALL = 6 MAPI_E_TOO_MANY_SESSIONS = 8 MAPI_E_TOO_MANY_FILES = 9 MAPI_E_TOO_MANY_RECIPIENTS = 10 MAPI_E_ATTACHMENT_NOT_FOUND = 11 MAPI_E_ATTACHMENT_OPEN_FAILURE = 12 MAPI_E_ATTACHMENT_WRITE_FAILURE = 13 MAPI_E_UNKNOWN_RECIPIENT = 14 MAPI_E_BAD_RECIPTYPE = 15 MAPI_E_NO_MESSAGES = 16 MAPI_E_INVALID_MESSAGE = 17 MAPI_E_TEXT_TOO_LARGE = 18 MAPI_E_INVALID_SESSION = 19 MAPI_E_TYPE_NOT_SUPPORTED = 20 MAPI_E_AMBIGUOUS_RECIPIENT = 21 MAPI_E_MESSAGE_IN_USE = 22 MAPI_E_NETWORK_FAILURE = 23 MAPI_E_INVALID_EDITFIELDS = 24 MAPI_E_INVALID_RECIPS = 25 MAPI_E_NOT_SUPPORTED = 26 MAPI_E_NO_LIBRARY = 999 MAPI_E_INVALID_PARAMETER = 998 End Enum #Region "Private MapiFileDescriptor Class" _ Private Class MapiFileDescriptor Public reserved As Integer = 0 Public flags As Integer = 0 Public position As Integer = 0 Public path As String = Nothing Public name As String = Nothing Public type As IntPtr = IntPtr.Zero End Class #End Region #Region "Enums" ''' ''' Specifies the valid RecipientTypes for a Recipient. ''' Public Enum RecipientType As Integer ''' ''' Recipient will be in the TO list. ''' [To] = 1 ''' ''' Recipient will be in the CC list. ''' CC = 2 ''' ''' Recipient will be in the BCC list. ''' BCC = 3 End Enum #End Region #Region "Member Variables" Private _subject As String Private _body As String Private _recipientCollection As RecipientCollection Private _files As ArrayList Private _manualResetEvent As ManualResetEvent #End Region #Region "Constructors" ''' ''' Creates a blank mail message. ''' Public Sub New() _files = New ArrayList() _recipientCollection = New RecipientCollection() _manualResetEvent = New ManualResetEvent(False) End Sub ''' ''' Creates a new mail message with the specified subject. ''' Public Sub New(subject As String) Me.New() _subject = subject End Sub ''' ''' Creates a new mail message with the specified subject and body. ''' Public Sub New(subject As String, body As String) Me.New() _subject = subject _body = body End Sub #End Region #Region "Public Properties" ''' ''' Gets or sets the subject of this mail message. ''' Public Property Subject() As String Get Return _subject End Get Set(value As String) _subject = value End Set End Property ''' ''' Gets or sets the body of this mail message. ''' Public Property Body() As String Get Return _body End Get Set(value As String) _body = value End Set End Property ''' ''' Gets the recipient list for this mail message. ''' Public ReadOnly Property Recipients() As RecipientCollection Get Return _recipientCollection End Get End Property ''' ''' Gets the file list for this mail message. ''' Public ReadOnly Property Files() As ArrayList Get Return _files End Get End Property #End Region #Region "Public Methods" ''' ''' Displays the mail message dialog asynchronously. ''' Public Sub ShowDialog() _ShowMail() End Sub #End Region #Region "Private Methods" ''' ''' Sends the mail message. ''' Private Sub _ShowMail(ignore As Object) Dim message As New MAPIHelperInterop.MapiMessage() Using interopRecipients As RecipientCollection.InteropRecipientCollection = _recipientCollection.GetInteropRepresentation() message.Subject = _subject message.NoteText = _body message.Recipients = interopRecipients.Handle message.RecipientCount = _recipientCollection.Count ' Check if we need to add attachments If _files.Count > 0 Then ' Add attachments message.Files = _AllocAttachments(message.FileCount) End If ' Signal the creating thread (make the remaining code async) _manualResetEvent.[Set]() Const MAPI_DIALOG As Integer = &H8 'const int MAPI_LOGON_UI = 0x1; Const SUCCESS_SUCCESS As Integer = 0 Dim [error] As Integer = MAPIHelperInterop.MAPISendMail(IntPtr.Zero, IntPtr.Zero, message, MAPI_DIALOG, 0) If _files.Count > 0 Then ' Deallocate the files _DeallocFiles(message) End If ' Check for error m_ErrorCode = [error] If [error] <> SUCCESS_SUCCESS Then EgtOutLog(_LogErrorMapi(CType([error], MAPIError))) End If End Using End Sub ''' ''' Deallocates the files in a message. ''' ''' The message to deallocate the files from. Private Sub _DeallocFiles(message As MAPIHelperInterop.MapiMessage) If message.Files <> IntPtr.Zero Then Dim fileDescType As Type = GetType(MapiFileDescriptor) Dim fsize As Integer = Marshal.SizeOf(fileDescType) ' Get the ptr to the files Dim runptr As IntPtr = message.Files ' Release each file For i As Integer = 0 To message.FileCount - 1 Marshal.DestroyStructure(runptr, fileDescType) runptr += fsize Next ' Release the file Marshal.FreeHGlobal(message.Files) End If End Sub ''' ''' Allocates the file attachments ''' ''' ''' Private Function _AllocAttachments(ByRef fileCount As Integer) As IntPtr fileCount = 0 If _files Is Nothing Then Return IntPtr.Zero End If If (_files.Count <= 0) OrElse (_files.Count > 100) Then Return IntPtr.Zero End If Dim atype As Type = GetType(MapiFileDescriptor) Dim asize As Integer = Marshal.SizeOf(atype) Dim ptra As IntPtr = Marshal.AllocHGlobal(_files.Count * asize) Dim mfd As New MapiFileDescriptor() With { .position = -1 } Dim runptr As IntPtr = ptra For i As Integer = 0 To _files.Count - 1 Dim path__1 As String = TryCast(_files(i), String) mfd.name = Path.GetFileName(path__1) mfd.path = path__1 Marshal.StructureToPtr(mfd, runptr, False) runptr += asize Next fileCount = _files.Count Return ptra End Function ''' ''' Sends the mail message. ''' Private Sub _ShowMail() _ShowMail(Nothing) End Sub ''' ''' Logs any Mapi errors. ''' Friend Shared Function _LogErrorMapi(errorCode As MAPIError) As String Dim [error] As String = String.Empty Select Case errorCode Case MAPIError.MAPI_USER_ABORT [error] = "User Aborted." Exit Select Case MAPIError.MAPI_E_FAILURE [error] = "MAPI Failure." Exit Select Case MAPIError.MAPI_E_LOGIN_FAILURE [error] = "Login Failure." Exit Select Case MAPIError.MAPI_E_DISK_FULL [error] = "MAPI Disk full." Exit Select Case MAPIError.MAPI_E_INSUFFICIENT_MEMORY [error] = "MAPI Insufficient memory." Exit Select Case MAPIError.MAPI_E_BLK_TOO_SMALL [error] = "MAPI Block too small." Exit Select Case MAPIError.MAPI_E_TOO_MANY_SESSIONS [error] = "MAPI Too many sessions." Exit Select Case MAPIError.MAPI_E_TOO_MANY_FILES [error] = "MAPI too many files." Exit Select Case MAPIError.MAPI_E_TOO_MANY_RECIPIENTS [error] = "MAPI too many recipients." Exit Select Case MAPIError.MAPI_E_ATTACHMENT_NOT_FOUND [error] = "MAPI Attachment not found." Exit Select Case MAPIError.MAPI_E_ATTACHMENT_OPEN_FAILURE [error] = "MAPI Attachment open failure." Exit Select Case MAPIError.MAPI_E_ATTACHMENT_WRITE_FAILURE [error] = "MAPI Attachment Write Failure." Exit Select Case MAPIError.MAPI_E_UNKNOWN_RECIPIENT [error] = "MAPI Unknown recipient." Exit Select Case MAPIError.MAPI_E_BAD_RECIPTYPE [error] = "MAPI Bad recipient type." Exit Select Case MAPIError.MAPI_E_NO_MESSAGES [error] = "MAPI No messages." Exit Select Case MAPIError.MAPI_E_INVALID_MESSAGE [error] = "MAPI Invalid message." Exit Select Case MAPIError.MAPI_E_TEXT_TOO_LARGE [error] = "MAPI Text too large." Exit Select Case MAPIError.MAPI_E_INVALID_SESSION [error] = "MAPI Invalid session." Exit Select Case MAPIError.MAPI_E_TYPE_NOT_SUPPORTED [error] = "MAPI Type not supported." Exit Select Case MAPIError.MAPI_E_AMBIGUOUS_RECIPIENT [error] = "MAPI Ambiguous recipient." Exit Select Case MAPIError.MAPI_E_MESSAGE_IN_USE [error] = "MAPI Message in use." Exit Select Case MAPIError.MAPI_E_NETWORK_FAILURE [error] = "MAPI Network failure." Exit Select Case MAPIError.MAPI_E_INVALID_EDITFIELDS [error] = "MAPI Invalid edit fields." Exit Select Case MAPIError.MAPI_E_INVALID_RECIPS [error] = "MAPI Invalid Recipients." Exit Select Case MAPIError.MAPI_E_NOT_SUPPORTED [error] = "MAPI Not supported." Exit Select Case MAPIError.MAPI_E_NO_LIBRARY [error] = "MAPI No Library." Exit Select Case MAPIError.MAPI_E_INVALID_PARAMETER [error] = "MAPI Invalid parameter." Exit Select End Select Return "Error sending MAPI Email. Error: " & [error] & " (code = " & errorCode & ")." End Function #End Region #Region "Private MAPIHelperInterop Class" ''' ''' Internal class for calling MAPI APIs ''' Friend Class MAPIHelperInterop #Region "Constructors" ' Intenationally blank Private Sub New() End Sub #End Region #Region "Constants" Public Const MAPI_LOGON_UI As Integer = &H1 #End Region #Region "APIs" _ Public Shared Function MAPILogon(hwnd As IntPtr, prf As String, pw As String, flg As Integer, rsv As Integer, ByRef sess As IntPtr) As Integer End Function #End Region #Region "Structs" _ Public Class MapiMessage Public Reserved As Integer = 0 Public Subject As String = Nothing Public NoteText As String = Nothing Public MessageType As String = Nothing Public DateReceived As String = Nothing Public ConversationID As String = Nothing Public Flags As Integer = 0 Public Originator As IntPtr = IntPtr.Zero Public RecipientCount As Integer = 0 Public Recipients As IntPtr = IntPtr.Zero Public FileCount As Integer = 0 Public Files As IntPtr = IntPtr.Zero End Class _ Public Class MapiRecipDesc Public Reserved As Integer = 0 Public RecipientClass As Integer = 0 Public Name As String = Nothing Public Address As String = Nothing Public eIDSize As Integer = 0 Public EntryID As IntPtr = IntPtr.Zero End Class _ Public Shared Function MAPISendMail(session As IntPtr, hwnd As IntPtr, message As MapiMessage, flg As Integer, rsv As Integer) As Integer End Function #End Region End Class #End Region End Class #End Region #Region "Public Recipient Class" ''' ''' Represents a Recipient for a MapiMailMessage. ''' Public Class Recipient #Region "Public Properties" ''' ''' The email address of this recipient. ''' Public Address As String = Nothing ''' ''' The display name of this recipient. ''' Public DisplayName As String = Nothing ''' ''' How the recipient will receive this message (To, CC, BCC). ''' Public RecipientType As MapiMailMessage.RecipientType = MapiMailMessage.RecipientType.[To] #End Region #Region "Constructors" ''' ''' Creates a new recipient with the specified address. ''' Public Sub New(address__1 As String) Address = address__1 End Sub ''' ''' Creates a new recipient with the specified address and display name. ''' Public Sub New(address__1 As String, displayName__2 As String) Address = address__1 DisplayName = displayName__2 End Sub ''' ''' Creates a new recipient with the specified address and recipient type. ''' Public Sub New(address__1 As String, recipientType__2 As MapiMailMessage.RecipientType) Address = address__1 RecipientType = recipientType__2 End Sub ''' ''' Creates a new recipient with the specified address, display name and recipient type. ''' Public Sub New(address__1 As String, displayName__2 As String, recipientType__3 As MapiMailMessage.RecipientType) Address = address__1 DisplayName = displayName__2 RecipientType = recipientType__3 End Sub #End Region #Region "Internal Methods" ''' ''' Returns an interop representation of a recepient. ''' ''' Friend Function GetInteropRepresentation() As MapiMailMessage.MAPIHelperInterop.MapiRecipDesc Dim interop As New MapiMailMessage.MAPIHelperInterop.MapiRecipDesc() If DisplayName Is Nothing Then interop.Name = Address Else interop.Name = DisplayName interop.Address = Address End If interop.RecipientClass = CInt(RecipientType) Return interop End Function #End Region End Class #End Region #Region "Public RecipientCollection Class" ''' ''' Represents a colleciton of recipients for a mail message. ''' Public Class RecipientCollection Inherits CollectionBase ''' ''' Adds the specified recipient to this collection. ''' Public Sub Add(value As Recipient) List.Add(value) End Sub ''' ''' Adds a new recipient with the specified address to this collection. ''' Public Sub Add(address As String) Me.Add(New Recipient(address)) End Sub ''' ''' Adds a new recipient with the specified address and display name to this collection. ''' Public Sub Add(address As String, displayName As String) Me.Add(New Recipient(address, displayName)) End Sub ''' ''' Adds a new recipient with the specified address and recipient type to this collection. ''' Public Sub Add(address As String, recipientType As MapiMailMessage.RecipientType) Me.Add(New Recipient(address, recipientType)) End Sub ''' ''' Adds a new recipient with the specified address, display name and recipient type to this collection. ''' Public Sub Add(address As String, displayName As String, recipientType As MapiMailMessage.RecipientType) Me.Add(New Recipient(address, displayName, recipientType)) End Sub ''' ''' Returns the recipient stored in this collection at the specified index. ''' Default Public ReadOnly Property Item(index As Integer) As Recipient Get Return DirectCast(List(index), Recipient) End Get End Property Friend Function GetInteropRepresentation() As InteropRecipientCollection Return New InteropRecipientCollection(Me) End Function ''' ''' Struct which contains an interop representation of a colleciton of recipients. ''' Friend Structure InteropRecipientCollection Implements IDisposable #Region "Member Variables" Private _handle As IntPtr Private _count As Integer #End Region #Region "Constructors" ''' ''' Default constructor for creating InteropRecipientCollection. ''' ''' Public Sub New(outer As RecipientCollection) _count = outer.Count If _count = 0 Then _handle = IntPtr.Zero Return End If ' allocate enough memory to hold all recipients Dim size As Integer = Marshal.SizeOf(GetType(MapiMailMessage.MAPIHelperInterop.MapiRecipDesc)) _handle = Marshal.AllocHGlobal(_count * size) ' place all interop recipients into the memory just allocated Dim ptr As IntPtr = _handle For Each native As Recipient In outer Dim interop As MapiMailMessage.MAPIHelperInterop.MapiRecipDesc = native.GetInteropRepresentation() ' stick it in the memory block Marshal.StructureToPtr(interop, ptr, False) ptr += size Next End Sub #End Region #Region "Public Properties" Public ReadOnly Property Handle() As IntPtr Get Return _handle End Get End Property #End Region #Region "Public Methods" ''' ''' Disposes of resources. ''' Public Sub Dispose() If _handle <> IntPtr.Zero Then Dim type As Type = GetType(MapiMailMessage.MAPIHelperInterop.MapiRecipDesc) Dim size As Integer = Marshal.SizeOf(type) ' destroy all the structures in the memory area Dim ptr As IntPtr = _handle For i As Integer = 0 To _count - 1 Marshal.DestroyStructure(ptr, type) ptr += size Next ' free the memory Marshal.FreeHGlobal(_handle) _handle = IntPtr.Zero _count = 0 End If End Sub #End Region Public Sub Dispose1() Implements IDisposable.Dispose End Sub End Structure End Class #End Region