MAPI.cs 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Runtime.InteropServices;
  5. using System.IO;
  6. namespace FastReport.Export.Email
  7. {
  8. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
  9. internal class MapiMessage
  10. {
  11. public int reserved;
  12. public string subject;
  13. public string noteText;
  14. public string messageType;
  15. public string dateReceived;
  16. public string conversationID;
  17. public int flags;
  18. public IntPtr originator;
  19. public int recipCount;
  20. public IntPtr recips;
  21. public int fileCount;
  22. public IntPtr files;
  23. }
  24. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
  25. internal class MapiRecipDesc
  26. {
  27. public int reserved;
  28. public int recipClass;
  29. public string name;
  30. public string address;
  31. public int eIDSize;
  32. public IntPtr entryID;
  33. }
  34. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
  35. internal class MapiFileDesc
  36. {
  37. public int reserved;
  38. public int flags;
  39. public int position;
  40. public string pathName;
  41. public string fileName;
  42. public IntPtr fileType;
  43. }
  44. /// <summary>
  45. /// Allows to send message using MAPI interface.
  46. /// </summary>
  47. public static class MAPI
  48. {
  49. #region static
  50. const int MapiLogonUI = 0x00000001;
  51. const int MAPI_DIALOG = 0x8;
  52. const int MAPI_TO = 1;
  53. const int MAPI_CC = 2;
  54. [DllImport("MAPI32.DLL", CharSet = CharSet.Ansi)]
  55. private static extern int MAPISendMail(IntPtr session, IntPtr uiParam,
  56. MapiMessage message, int flags, int reserved);
  57. [DllImport("MAPI32.DLL", CharSet = CharSet.Ansi)]
  58. private static extern int MAPILogon(IntPtr hwnd, string profileName, string password,
  59. int flags, int reserved, ref IntPtr session);
  60. [DllImport("MAPI32.DLL", CharSet = CharSet.Ansi)]
  61. private static extern int MAPILogoff(IntPtr session, IntPtr hwnd,
  62. int flags, int reserved);
  63. private static string[] errors = new string[] {
  64. "OK [0]", "User abort [1]", "General MAPI failure [2]",
  65. "MAPI login failure [3]", "Disk full [4]",
  66. "Insufficient memory [5]", "Access denied [6]",
  67. "-unknown- [7]", "Too many sessions [8]",
  68. "Too many files were specified [9]",
  69. "Too many recipients were specified [10]",
  70. "A specified attachment was not found [11]",
  71. "Attachment open failure [12]",
  72. "Attachment write failure [13]", "Unknown recipient [14]",
  73. "Bad recipient type [15]", "No messages [16]",
  74. "Invalid message [17]", "Text too large [18]",
  75. "Invalid session [19]", "Type not supported [20]",
  76. "A recipient was specified ambiguously [21]",
  77. "Message in use [22]", "Network failure [23]",
  78. "Invalid edit fields [24]", "Invalid recipients [25]",
  79. "Not supported [26]"
  80. };
  81. #endregion
  82. private static MapiMessage CreateMessage(string[] files, string mailSubject, string mailBody,
  83. string[] recipientName, string[] recipientAddress)
  84. {
  85. MapiMessage msg = new MapiMessage();
  86. msg.subject = mailSubject;
  87. msg.noteText = mailBody;
  88. if (files.Length > 0)
  89. {
  90. msg.fileCount = files.Length;
  91. msg.files = GetFilesDesc(files);
  92. }
  93. if (recipientAddress.Length > 0)
  94. {
  95. msg.recipCount = recipientAddress.Length;
  96. msg.recips = GetRecipDesc(recipientName, recipientAddress);
  97. }
  98. return msg;
  99. }
  100. private static IntPtr GetFilesDesc(string[] files)
  101. {
  102. IntPtr ptra = AllocMemory(typeof(MapiFileDesc), files.Length);
  103. for (int i = 0; i < files.Length; i++)
  104. {
  105. MapiFileDesc fileDesc = new MapiFileDesc();
  106. fileDesc.position = -1;
  107. fileDesc.fileName = Path.GetFileName(files[i]);
  108. fileDesc.pathName = files[i];
  109. Marshal.StructureToPtr(fileDesc, OffsetPtr(ptra, typeof(MapiFileDesc), files.Length - 1 - i), false);
  110. }
  111. return ptra;
  112. }
  113. private static IntPtr GetRecipDesc(string[] recipientName, string[] recipientAddress)
  114. {
  115. IntPtr ptra = AllocMemory(typeof(MapiRecipDesc), recipientAddress.Length);
  116. for (int i = 0; i < recipientAddress.Length; i++)
  117. {
  118. MapiRecipDesc recipDesc = new MapiRecipDesc();
  119. recipDesc.recipClass = i == 0 ? MAPI_TO : MAPI_CC;
  120. if (recipientName.Length > i)
  121. recipDesc.name = recipientName[i];
  122. recipDesc.address = recipientAddress[i];
  123. Marshal.StructureToPtr(recipDesc, OffsetPtr(ptra, typeof(MapiRecipDesc), recipientAddress.Length - 1 - i), false);
  124. }
  125. return ptra;
  126. }
  127. private static IntPtr AllocMemory(Type structureType, int count)
  128. {
  129. return Marshal.AllocHGlobal(Marshal.SizeOf(structureType) * count);
  130. }
  131. private static IntPtr OffsetPtr(IntPtr ptr, Type structureType, int offset)
  132. {
  133. return (IntPtr)((long)ptr + offset * Marshal.SizeOf(structureType));
  134. }
  135. private static void Logoff(IntPtr hwnd, IntPtr session)
  136. {
  137. if (session != IntPtr.Zero)
  138. {
  139. MAPILogoff(session, hwnd, 0, 0);
  140. session = IntPtr.Zero;
  141. }
  142. }
  143. private static bool Logon(IntPtr hwnd, ref IntPtr session)
  144. {
  145. int error = MAPILogon(hwnd, null, null, 0, 0, ref session);
  146. if (error != 0)
  147. error = MAPILogon(hwnd, null, null, MapiLogonUI, 0, ref session);
  148. return error == 0;
  149. }
  150. private static void DisposeMessage(MapiMessage msg)
  151. {
  152. FreeMemory(msg.files, typeof(MapiFileDesc), msg.fileCount);
  153. FreeMemory(msg.recips, typeof(MapiRecipDesc), msg.recipCount);
  154. msg = null;
  155. }
  156. private static void FreeMemory(IntPtr ptr, Type structureType, int count)
  157. {
  158. if (ptr != IntPtr.Zero)
  159. {
  160. for (int i = 0; i < count; i++)
  161. {
  162. Marshal.DestroyStructure(OffsetPtr(ptr, structureType, i), structureType);
  163. }
  164. Marshal.FreeHGlobal(ptr);
  165. }
  166. }
  167. /// <summary>
  168. /// Sends a message.
  169. /// </summary>
  170. /// <param name="handle">Parent window handle.</param>
  171. /// <param name="files">Files to attach.</param>
  172. /// <param name="mailSubject">Email subject.</param>
  173. /// <param name="mailBody">Email body.</param>
  174. /// <param name="recipentName">Recipient names.</param>
  175. /// <param name="recipientAddress">Recipient addresses.</param>
  176. /// <returns>Error code. <b>0</b> if operation was completed succesfully.</returns>
  177. public static int SendMail(IntPtr handle, string[] files, string mailSubject, string mailBody,
  178. string[] recipentName, string[] recipientAddress)
  179. {
  180. IntPtr session = IntPtr.Zero;
  181. int error = 0;
  182. if (Logon(handle, ref session))
  183. {
  184. MapiMessage msg = CreateMessage(files, mailSubject, mailBody, recipentName, recipientAddress);
  185. error = MAPISendMail(session, handle, msg, MAPI_DIALOG, 0);
  186. Logoff(handle, session);
  187. DisposeMessage(msg);
  188. }
  189. return error;
  190. }
  191. /// <summary>
  192. /// Returns a text describing an error.
  193. /// </summary>
  194. /// <param name="error">The error code.</param>
  195. /// <returns>The text describing an error.</returns>
  196. public static string GetErrorText(int error)
  197. {
  198. if (error <= 26)
  199. return errors[error];
  200. return "MAPI error [" + error.ToString() + "]";
  201. }
  202. }
  203. }