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