You must load dynamically the right MAPI32.DLL, like the LoadDefaultMailProvider in the SDK
Otherwise, you can test the code with IDataObject I just posted in this thread : Opening the default e-email app
This browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
A community member has associated this post with a similar question:
Problem with default email client
Only moderators can edit this content.
I use this code to open the default application and attach the file.
But this code tries to open the Outlook app.
For example, my default email app is the Windows 11 main app, but some other people in window seven, or XP, might be another app
So, this code doesn't work for me
private void ShareAction(FileItem file) {
string subject = string.Empty;
string body = string.Empty;
string recipient = string.Empty;
MapiMessage msg = new()
{
subject = subject,
noteText = body,
recipCount = 1,
recips = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(MapiRecipDesc)))
};
Marshal.StructureToPtr(new MapiRecipDesc(recipient), msg.recips, false);
msg.files = IntPtr.Zero;
msg.fileCount = 0;
int result = MAPISendMail(new IntPtr(0), new IntPtr(0), msg, 0x00000001, 0);
if (result > 0) {
throw new Exception("Error sending email. Error code: " + result);
}
}
[DllImport("MAPI32.dll")]
public static extern int MAPISendMail(IntPtr sess, IntPtr hwnd, MapiMessage message, int flg, int rsv);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class MapiMessage {
public int reserved;
public string subject;
public string noteText;
public string messageType;
public string dateReceived;
public string conversationID;
public int flags;
public IntPtr originator;
public int recipCount;
public IntPtr recips;
public int fileCount;
public IntPtr files;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class MapiRecipDesc {
public int reserved;
public int recipClass;
public string name;
public string address;
public int eIDSize;
public IntPtr entryID;
public MapiRecipDesc(string recip) {
reserved = 0;
recipClass = 1; // MAPI_TO
name = recip;
address = recip;
eIDSize = 0;
entryID = IntPtr.Zero;
}
}
Hi,@Eduardo Gomez . Maybe you could try to see if the solution here is helpful to you?
Well this is an interesting solution, but I want to let people use their default email client. For example in my case is The email app in windows 12
You must load dynamically the right MAPI32.DLL, like the LoadDefaultMailProvider in the SDK
Otherwise, you can test the code with IDataObject I just posted in this thread : Opening the default e-email app
Ok so I created a MAPI class
public class MAPI {
[DllImport("MAPI32.dll")]
public static extern int MAPISendMail(IntPtr sess, IntPtr hwnd, MapiMessage message, int flg, int rsv);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class MapiMessage {
public int reserved;
public string subject;
public string noteText;
public string messageType;
public string dateReceived;
public string conversationID;
public int flags;
public IntPtr originator;
public int recipCount;
public IntPtr recips;
public int fileCount;
public IntPtr files;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class MapiFileDesc {
public int reserved;
public int flags;
public int position;
public string path;
public string name;
public IntPtr type;
}
public static void OpenEmailClient(string to, string subject, string body, string attachmentPath) {
MapiMessage msg = new()
{
subject = subject,
noteText = body,
fileCount = 1
};
MapiFileDesc file = new()
{
position = -1,
path = attachmentPath,
name = Path.GetFileName(attachmentPath)
};
msg.files = Marshal.AllocHGlobal(Marshal.SizeOf(file));
Marshal.StructureToPtr(file, msg.files, false);
int result = MAPISendMail(new IntPtr(0), new IntPtr(0), msg, 0x00000001, 0);
if (result > 0) {
throw new Exception("Error sending email. Error code: " + result);
}
}
Then I implemented it here
private void ShareAction(FileItem file) {
string subject = string.Empty;
string body = string.Empty;
string recipient = string.Empty;
MAPI.OpenEmailClient("", "test", "test", file.FilePath);
}
But now I get this error
and there is no description of the error
I don't see the link with what I answered...
Sorry
I copied this and put it in his own class
// Below is the source code and simple test class for creating and displaying emails.
// It uses the MAPI API and is therefore not subject to the same restrictions as
// the "mailto" shell extension.
//
// Using the MapiMailMessage you can set the title, subject, recipients and attach files.
// Then show the resulting email to the user, ready from them to send. This class is very
// useful for supporting applications and enriching addins.
//
// Note, that the class is a port from a VB version I had and although it does have
// comments, it is not up to my usual standard. I will be revisiting this and tidying
// it up shortly.
namespace TranscribeMe.Model {
#region Public MapiMailMessage Class
/// <summary>
/// Represents an email message to be sent through MAPI.
/// </summary>
public class MapiMailMessage {
#region Private MapiFileDescriptor Class
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
private class MapiFileDescriptor {
public int reserved = 0;
public int flags = 0;
public int position = 0;
public string path = null;
public string name = null;
public IntPtr type = IntPtr.Zero;
}
#endregion Private MapiFileDescriptor Class
#region Enums
/// <summary>
/// Specifies the valid RecipientTypes for a Recipient.
/// </summary>
public enum RecipientType : int {
/// <summary>
/// Recipient will be in the TO list.
/// </summary>
To = 1,
/// <summary>
/// Recipient will be in the CC list.
/// </summary>
CC = 2,
/// <summary>
/// Recipient will be in the BCC list.
/// </summary>
BCC = 3
};
#endregion Enums
#region Member Variables
private string _subject;
private string _body;
private RecipientCollection _recipientCollection;
private ArrayList _files;
private ManualResetEvent _manualResetEvent;
#endregion Member Variables
#region Constructors
/// <summary>
/// Creates a blank mail message.
/// </summary>
public MapiMailMessage() {
_files = new ArrayList();
_recipientCollection = new RecipientCollection();
_manualResetEvent = new ManualResetEvent(false);
}
/// <summary>
/// Creates a new mail message with the specified subject.
/// </summary>
public MapiMailMessage(string subject)
: this() {
_subject = subject;
}
/// <summary>
/// Creates a new mail message with the specified subject and body.
/// </summary>
public MapiMailMessage(string subject, string body)
: this() {
_subject = subject;
_body = body;
}
#endregion Constructors
#region Public Properties
/// <summary>
/// Gets or sets the subject of this mail message.
/// </summary>
public string Subject {
get { return _subject; }
set { _subject = value; }
}
/// <summary>
/// Gets or sets the body of this mail message.
/// </summary>
public string Body {
get { return _body; }
set { _body = value; }
}
/// <summary>
/// Gets the recipient list for this mail message.
/// </summary>
public RecipientCollection Recipients {
get { return _recipientCollection; }
}
/// <summary>
/// Gets the file list for this mail message.
/// </summary>
public ArrayList Files {
get { return _files; }
}
#endregion Public Properties
#region Public Methods
/// <summary>
/// Displays the mail message dialog asynchronously.
/// </summary>
public void ShowDialog() {
// Create the mail message in an STA thread
Thread t = new Thread(new ThreadStart(_ShowMail));
t.IsBackground = true;
t.ApartmentState = ApartmentState.STA;
t.Start();
// only return when the new thread has built it's interop representation
_manualResetEvent.WaitOne();
_manualResetEvent.Reset();
}
#endregion Public Methods
#region Private Methods
/// <summary>
/// Sends the mail message.
/// </summary>
private void _ShowMail(object ignore) {
MAPIHelperInterop.MapiMessage message = new MAPIHelperInterop.MapiMessage();
using (RecipientCollection.InteropRecipientCollection interopRecipients
= _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) {
// Add attachments
message.Files = _AllocAttachments(out message.FileCount);
}
// Signal the creating thread (make the remaining code async)
_manualResetEvent.Set();
const int MAPI_DIALOG = 0x8;
//const int MAPI_LOGON_UI = 0x1;
const int SUCCESS_SUCCESS = 0;
int error = MAPIHelperInterop.MAPISendMail(IntPtr.Zero, IntPtr.Zero, message, MAPI_DIALOG, 0);
if (_files.Count > 0) {
// Deallocate the files
_DeallocFiles(message);
}
// Check for error
if (error != SUCCESS_SUCCESS) {
_LogErrorMapi(error);
}
}
}
/// <summary>
/// Deallocates the files in a message.
/// </summary>
/// <param name="message">The message to deallocate the files from.</param>
private void _DeallocFiles(MAPIHelperInterop.MapiMessage message) {
if (message.Files != IntPtr.Zero) {
Type fileDescType = typeof(MapiFileDescriptor);
int fsize = Marshal.SizeOf(fileDescType);
// Get the ptr to the files
long runptr = (long)message.Files;
// Release each file
for (int i = 0; i < message.FileCount; i++) {
Marshal.DestroyStructure((IntPtr)runptr, fileDescType);
runptr += fsize;
}
// Release the file
Marshal.FreeHGlobal(message.Files);
}
}
/// <summary>
/// Allocates the file attachments
/// </summary>
/// <param name="fileCount"></param>
/// <returns></returns>
private IntPtr _AllocAttachments(out int fileCount) {
fileCount = 0;
if (_files == null) {
return IntPtr.Zero;
}
if (_files.Count <= 0 || _files.Count > 100) {
return IntPtr.Zero;
}
Type atype = typeof(MapiFileDescriptor);
int asize = Marshal.SizeOf(atype);
IntPtr ptra = Marshal.AllocHGlobal(_files.Count * asize);
MapiFileDescriptor mfd = new MapiFileDescriptor();
mfd.position = -1;
long runptr = (long)ptra;
for (int i = 0; i < _files.Count; i++) {
string path = _files[i] as string;
mfd.name = Path.GetFileName(path);
mfd.path = path;
Marshal.StructureToPtr(mfd, (IntPtr)runptr, false);
runptr += asize;
}
fileCount = _files.Count;
return ptra;
}
/// <summary>
/// Sends the mail message.
/// </summary>
private void _ShowMail() {
_ShowMail(null);
}
/// <summary>
/// Logs any Mapi errors.
/// </summary>
private void _LogErrorMapi(int errorCode) {
const int MAPI_USER_ABORT = 1;
const int MAPI_E_FAILURE = 2;
const int MAPI_E_LOGIN_FAILURE = 3;
const int MAPI_E_DISK_FULL = 4;
const int MAPI_E_INSUFFICIENT_MEMORY = 5;
const int MAPI_E_BLK_TOO_SMALL = 6;
const int MAPI_E_TOO_MANY_SESSIONS = 8;
const int MAPI_E_TOO_MANY_FILES = 9;
const int MAPI_E_TOO_MANY_RECIPIENTS = 10;
const int MAPI_E_ATTACHMENT_NOT_FOUND = 11;
const int MAPI_E_ATTACHMENT_OPEN_FAILURE = 12;
const int MAPI_E_ATTACHMENT_WRITE_FAILURE = 13;
const int MAPI_E_UNKNOWN_RECIPIENT = 14;
const int MAPI_E_BAD_RECIPTYPE = 15;
const int MAPI_E_NO_MESSAGES = 16;
const int MAPI_E_INVALID_MESSAGE = 17;
const int MAPI_E_TEXT_TOO_LARGE = 18;
const int MAPI_E_INVALID_SESSION = 19;
const int MAPI_E_TYPE_NOT_SUPPORTED = 20;
const int MAPI_E_AMBIGUOUS_RECIPIENT = 21;
const int MAPI_E_MESSAGE_IN_USE = 22;
const int MAPI_E_NETWORK_FAILURE = 23;
const int MAPI_E_INVALID_EDITFIELDS = 24;
const int MAPI_E_INVALID_RECIPS = 25;
const int MAPI_E_NOT_SUPPORTED = 26;
const int MAPI_E_NO_LIBRARY = 999;
const int MAPI_E_INVALID_PARAMETER = 998;
string error = string.Empty;
switch (errorCode) {
case MAPI_USER_ABORT:
error = "User Aborted.";
break;
case MAPI_E_FAILURE:
error = "MAPI Failure.";
break;
case MAPI_E_LOGIN_FAILURE:
error = "Login Failure.";
break;
case MAPI_E_DISK_FULL:
error = "MAPI Disk full.";
break;
case MAPI_E_INSUFFICIENT_MEMORY:
error = "MAPI Insufficient memory.";
break;
case MAPI_E_BLK_TOO_SMALL:
error = "MAPI Block too small.";
break;
case MAPI_E_TOO_MANY_SESSIONS:
error = "MAPI Too many sessions.";
break;
case MAPI_E_TOO_MANY_FILES:
error = "MAPI too many files.";
break;
case MAPI_E_TOO_MANY_RECIPIENTS:
error = "MAPI too many recipients.";
break;
case MAPI_E_ATTACHMENT_NOT_FOUND:
error = "MAPI Attachment not found.";
break;
case MAPI_E_ATTACHMENT_OPEN_FAILURE:
error = "MAPI Attachment open failure.";
break;
case MAPI_E_ATTACHMENT_WRITE_FAILURE:
error = "MAPI Attachment Write Failure.";
break;
case MAPI_E_UNKNOWN_RECIPIENT:
error = "MAPI Unknown recipient.";
break;
case MAPI_E_BAD_RECIPTYPE:
error = "MAPI Bad recipient type.";
break;
case MAPI_E_NO_MESSAGES:
error = "MAPI No messages.";
break;
case MAPI_E_INVALID_MESSAGE:
error = "MAPI Invalid message.";
break;
case MAPI_E_TEXT_TOO_LARGE:
error = "MAPI Text too large.";
break;
case MAPI_E_INVALID_SESSION:
error = "MAPI Invalid session.";
break;
case MAPI_E_TYPE_NOT_SUPPORTED:
error = "MAPI Type not supported.";
break;
case MAPI_E_AMBIGUOUS_RECIPIENT:
error = "MAPI Ambiguous recipient.";
break;
case MAPI_E_MESSAGE_IN_USE:
error = "MAPI Message in use.";
break;
case MAPI_E_NETWORK_FAILURE:
error = "MAPI Network failure.";
break;
case MAPI_E_INVALID_EDITFIELDS:
error = "MAPI Invalid edit fields.";
break;
case MAPI_E_INVALID_RECIPS:
error = "MAPI Invalid Recipients.";
break;
case MAPI_E_NOT_SUPPORTED:
error = "MAPI Not supported.";
break;
case MAPI_E_NO_LIBRARY:
error = "MAPI No Library.";
break;
case MAPI_E_INVALID_PARAMETER:
error = "MAPI Invalid parameter.";
break;
}
Debug.WriteLine("Error sending MAPI Email. Error: " + error + " (code = " + errorCode + ").");
}
#endregion Private Methods
#region Private MAPIHelperInterop Class
/// <summary>
/// Internal class for calling MAPI APIs
/// </summary>
internal class MAPIHelperInterop {
#region Constructors
/// <summary>
/// Private constructor.
/// </summary>
private MAPIHelperInterop() {
// Intenationally blank
}
#endregion Constructors
#region Constants
public const int MAPI_LOGON_UI = 0x1;
#endregion Constants
#region APIs
[DllImport("MAPI32.DLL", CharSet = CharSet.Ansi)]
public static extern int MAPILogon(IntPtr hwnd, string prf, string pw, int flg, int rsv, ref IntPtr sess);
#endregion APIs
#region Structs
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class MapiMessage {
public int Reserved = 0;
public string Subject = null;
public string NoteText = null;
public string MessageType = null;
public string DateReceived = null;
public string ConversationID = null;
public int Flags = 0;
public IntPtr Originator = IntPtr.Zero;
public int RecipientCount = 0;
public IntPtr Recipients = IntPtr.Zero;
public int FileCount = 0;
public IntPtr Files = IntPtr.Zero;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class MapiRecipDesc {
public int Reserved = 0;
public int RecipientClass = 0;
public string Name = null;
public string Address = null;
public int eIDSize = 0;
public IntPtr EntryID = IntPtr.Zero;
}
[DllImport("MAPI32.DLL")]
public static extern int MAPISendMail(IntPtr session, IntPtr hwnd, MapiMessage message, int flg, int rsv);
#endregion Structs
}
public void Dispose() {
throw new NotImplementedException();
}
#endregion Private MAPIHelperInterop Class
}
#endregion Public MapiMailMessage Class
#region Public Recipient Class
/// <summary>
/// Represents a Recipient for a MapiMailMessage.
/// </summary>
public class Recipient {
#region Public Properties
/// <summary>
/// The email address of this recipient.
/// </summary>
public string Address = null;
/// <summary>
/// The display name of this recipient.
/// </summary>
public string DisplayName = null;
/// <summary>
/// How the recipient will receive this message (To, CC, BCC).
/// </summary>
public MapiMailMessage.RecipientType RecipientType = MapiMailMessage.RecipientType.To;
#endregion Public Properties
#region Constructors
/// <summary>
/// Creates a new recipient with the specified address.
/// </summary>
public Recipient(string address) {
Address = address;
}
/// <summary>
/// Creates a new recipient with the specified address and display name.
/// </summary>
public Recipient(string address, string displayName) {
Address = address;
DisplayName = displayName;
}
/// <summary>
/// Creates a new recipient with the specified address and recipient type.
/// </summary>
public Recipient(string address, MapiMailMessage.RecipientType recipientType) {
Address = address;
RecipientType = recipientType;
}
/// <summary>
/// Creates a new recipient with the specified address, display name and recipient type.
/// </summary>
public Recipient(string address, string displayName, MapiMailMessage.RecipientType recipientType) {
Address = address;
DisplayName = displayName;
RecipientType = recipientType;
}
#endregion Constructors
#region Internal Methods
/// <summary>
/// Returns an interop representation of a recepient.
/// </summary>
/// <returns></returns>
internal MapiMailMessage.MAPIHelperInterop.MapiRecipDesc GetInteropRepresentation() {
MapiMailMessage.MAPIHelperInterop.MapiRecipDesc interop = new MapiMailMessage.MAPIHelperInterop.MapiRecipDesc();
if (DisplayName == null) {
interop.Name = Address;
} else {
interop.Name = DisplayName;
interop.Address = Address;
}
interop.RecipientClass = (int)RecipientType;
return interop;
}
#endregion Internal Methods
}
#endregion Public Recipient Class
#region Public RecipientCollection Class
/// <summary>
/// Represents a colleciton of recipients for a mail message.
/// </summary>
public class RecipientCollection : CollectionBase {
/// <summary>
/// Adds the specified recipient to this collection.
/// </summary>
public void Add(Recipient value) {
List.Add(value);
}
/// <summary>
/// Adds a new recipient with the specified address to this collection.
/// </summary>
public void Add(string address) {
Add(new Recipient(address));
}
/// <summary>
/// Adds a new recipient with the specified address and display name to this collection.
/// </summary>
public void Add(string address, string displayName) {
Add(new Recipient(address, displayName));
}
/// <summary>
/// Adds a new recipient with the specified address and recipient type to this collection.
/// </summary>
public void Add(string address, MapiMailMessage.RecipientType recipientType) {
Add(new Recipient(address, recipientType));
}
/// <summary>
/// Adds a new recipient with the specified address, display name and recipient type to this collection.
/// </summary>
public void Add(string address, string displayName, MapiMailMessage.RecipientType recipientType) {
Add(new Recipient(address, displayName, recipientType));
}
/// <summary>
/// Returns the recipient stored in this collection at the specified index.
/// </summary>
public Recipient this[int index] {
get {
return (Recipient)List[index];
}
}
internal InteropRecipientCollection GetInteropRepresentation() {
return new InteropRecipientCollection(this);
}
/// <summary>
/// Struct which contains an interop representation of a colleciton of recipients.
/// </summary>
internal struct InteropRecipientCollection : IDisposable {
#region Member Variables
private IntPtr _handle;
private int _count;
#endregion Member Variables
#region Constructors
/// <summary>
/// Default constructor for creating InteropRecipientCollection.
/// </summary>
/// <param name="outer"></param>
public InteropRecipientCollection(RecipientCollection outer) {
_count = outer.Count;
if (_count == 0) {
_handle = IntPtr.Zero;
return;
}
// allocate enough memory to hold all recipients
int size = Marshal.SizeOf(typeof(MapiMailMessage.MAPIHelperInterop.MapiRecipDesc));
_handle = Marshal.AllocHGlobal(_count * size);
// place all interop recipients into the memory just allocated
long ptr = (long)_handle;
foreach (Recipient native in outer) {
MapiMailMessage.MAPIHelperInterop.MapiRecipDesc interop = native.GetInteropRepresentation();
// stick it in the memory block
Marshal.StructureToPtr(interop, (IntPtr)ptr, false);
ptr += size;
}
}
#endregion Costructors
#region Public Properties
public IntPtr Handle {
get { return _handle; }
}
#endregion Public Properties
#region Public Methods
/// <summary>
/// Disposes of resources.
/// </summary>
public void Dispose() {
if (_handle != IntPtr.Zero) {
Type type = typeof(MapiMailMessage.MAPIHelperInterop.MapiRecipDesc);
int size = Marshal.SizeOf(type);
// destroy all the structures in the memory area
long ptr = (long)_handle;
for (int i = 0; i < _count; i++) {
Marshal.DestroyStructure((IntPtr)ptr, type);
ptr += size;
}
// free the memory
Marshal.FreeHGlobal(_handle);
_handle = IntPtr.Zero;
_count = 0;
}
}
#endregion Public Methods
}
}
}
#endregion Public RecipientCollection Class
But it doesn't do anything
MapiMailMessage message = new("Test Message", "Test Body");
message.Recipients.Add("Test@Test.com");
message.Files.Add(@"C:\del.txt");
message.ShowDialog();
It does not open anything
I still don't see the link with what I answered : test code with IDataObject or loading MAPI32.DLL dynamically...
The problem is that I do not understand currently when you say load dynamically
The problem is, that I do not understand what you mean by loading dynamically
[https://learn.microsoft.com/en-us/answers/questions/1162850/opening-the-default-e-email-app
Loading dynamically is loading the right MAPI32.DLL and functions with LoadLibrary/GetProcAddress/Marshal.GetDelegateForFunctionPointer from the location returned by the method used by LoadDefaultMailProvider
But did you test MAPI with IDataObject, which is simpler ?
Yes, I copy and paste your code, but did not work, I ill try to use the IDataObject
like
IDataObject data = new DataObject();
data.SetData(DataFormats.Text, "Hello, this is some text to share");
data.SetData(DataFormats.FileDrop, new[] { "C:\\path\\to\\file.txt" });
DataObject.OleDataObject oleData = new DataObject.OleDataObject(data);
oleData.SetData("FileGroupDescriptor", FileGroupDescriptorWrap.SerializeToBytes(new[] { "C:\\path\\to\\file.txt" }));
oleData.SetData("FileContents", FileContents.SerializeToBytes("C:\\path\\to\\file.txt"));
oleData.DoDragDrop(DragDropEffects.Copy);
But this is not the code I posted.
The code I posted with SHCreateFileDataObject works for me on Windows 10 (and on older OS) : it opens the default Mail client, which is Sea Monkey for me, with the file as attachment.
If it does not work on Windows 11, what is the returned error or message ?
Which hr does not return HRESULT.S_OK and which value ?
It doesn't do anything and yes, I am using windows eleven.
And I do not want to update to WinUI 3 because I lose the windows seven support
You did not say :
What is the returned error or message ?
Which hr does not return HRESULT.S_OK and which value ?
I am sorry your code works, I was not putting the right attachment. but I still got this error
This is what I am doing
public enum HRESULT : int {
S_OK = 0,
S_FALSE = 1,
E_NOINTERFACE = unchecked((int)0x80004002),
E_NOTIMPL = unchecked((int)0x80004001),
E_FAIL = unchecked((int)0x80004005),
}
[ComImport]
[Guid("00000122-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IDropTarget {
HRESULT DragEnter(
[In] System.Runtime.InteropServices.ComTypes.IDataObject pDataObj,
[In] int grfKeyState,
[In] System.Windows.Point pt,
[In, Out] ref int pdwEffect);
HRESULT DragOver(
[In] int grfKeyState,
[In] System.Windows.Point pt,
[In, Out] ref int pdwEffect);
HRESULT DragLeave();
HRESULT Drop(
[In] System.Runtime.InteropServices.ComTypes.IDataObject pDataObj,
[In] int grfKeyState,
[In] System.Windows.Point pt,
[In, Out] ref int pdwEffect);
}
public const int DROPEFFECT_NONE = (0);
[DllImport("Shell32.dll", CharSet = CharSet.Unicode, SetLastError = true, EntryPoint = "#740")]
public static extern HRESULT SHCreateFileDataObject(IntPtr pidlFolder, uint cidl, IntPtr[] apidl, System.Runtime.InteropServices.ComTypes.IDataObject pdtInner, out System.Runtime.InteropServices.ComTypes.IDataObject ppdtobj);
[DllImport("Shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern HRESULT SHILCreateFromPath([MarshalAs(UnmanagedType.LPWStr)] string pszPath, out IntPtr ppIdl, ref uint rgflnOut);
[DllImport("Shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr ILFindLastID(IntPtr pidl);
[DllImport("Shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr ILClone(IntPtr pidl);
[DllImport("Shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern Boolean ILRemoveLastID(IntPtr pidl);
[DllImport("Shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern void ILFree(IntPtr pidl);
Guid CLSID_MapiMail = new Guid("9E56BE60-C50F-11CF-9A2C-00A0C90A90CE");
This is the code you gave me
I forgot this
private void ShareAction(FileItem file) {
HRESULT hr = HRESULT.E_FAIL;
uint rgflnOut = 0;
System.Runtime.InteropServices.ComTypes.IDataObject pDataObject;
IntPtr pidlParent = IntPtr.Zero, pidlFull = IntPtr.Zero, pidlItem = IntPtr.Zero;
var aPidl = new IntPtr[255];
hr = SHILCreateFromPath(file.FilePath, out pidlFull, ref rgflnOut);
if (hr == HRESULT.S_OK) {
pidlItem = ILFindLastID(pidlFull);
aPidl[0] = ILClone(pidlItem);
ILRemoveLastID(pidlFull);
pidlParent = ILClone(pidlFull);
ILFree(pidlFull);
hr = SHCreateFileDataObject(pidlParent, 1, aPidl, null, out pDataObject);
if (hr == HRESULT.S_OK) {
Type DropTargetType = Type.GetTypeFromCLSID(CLSID_MapiMail, true);
object DropTarget = Activator.CreateInstance(DropTargetType);
IDropTarget pDropTarget = (IDropTarget)DropTarget;
int pdwEffect = DROPEFFECT_NONE;
System.Windows.Point pt = new System.Windows.Point {
X = 0,
Y = 0
};
hr = pDropTarget.Drop(pDataObject, 0, pt, pdwEffect);
}
if (pidlParent != IntPtr.Zero)
ILFree(pidlParent);
if (aPidl[0] != IntPtr.Zero)
ILFree(aPidl[0]);
}
}
As the message says, did you create a Profile ?
Or if you type "you need to create a microsoft outlook profile" on Google, there are several threads about this problem
Okay, so I need to create an outlook account, what about my users, will they have to create an outlook user as well? If that is the case, this solution doesn't work.
What I am trying to do is that when I click share
it will open the default client
for example. My default client is the Mail App, and your default client is Thunderbird.
Tomorrow, I decide to go to the setting page and change my default client
So, if this app is opened by someone on Windows 7, and the use something else, that would not work
Or am I wrong
On my PC (Windows 10 22H2), it opens the default client, which is configured in registry
For example, I have "Microsoft Outlook" or "SeaMonkey" in
HKEY_CURRENT_USER\SOFTWARE\Clients\Mail
then it reads values in
HKEY_LOCAL_MACHINE\SOFTWARE\Clients\Mail\Microsoft Outlook
or
HKEY_LOCAL_MACHINE\SOFTWARE\Clients\Mail\SeaMonkey
and launches Outlook or SeaMonkey composition dialogbox
So, how I cat let the Users Open their own email client
I also have a question If I go to the settings page and change my email client, it will change it in the registry
string emailClientPath = (string)Registry.GetValue(@"HKEY_CLASSES_ROOT\mailto\shell\open\command", "", null);
this will give me outlook, but my default client is mail app
Ok, I found a solution, but I need your help.
I will create a storage account on Azure and upload the file
and use the Mailo protocol to send the link, how can I put a Link
So, how I cat let the Users Open their own email client
As I tested on Windows 10 (and older OS), the code with IDataObject opens the default Mail client, read from registry keys I posted
But I use the Code you posted
The code does the same thing as Send To Mail recipient (right-click on a file)
This does not work either for you ?
no, it did not work, what I ended up doing is something like this
AzureStorageService azureStorageService = new();
await azureStorageService.UploadToAzureBlobStorage(file.FilePath);
string link = $"https://transcribemedocs.blob.core.windows.net/cloudfilesshare/{Path.GetFileName(file.FilePath)}";
string subject = "Here is the link for your file";
var destinationurl = $"mailto:?subject={subject}&body={link}%0D";
var sInfo = new ProcessStartInfo(destinationurl) {
UseShellExecute = true,
};
Process.Start(sInfo);
The problem is that I cannot click on the link inside the email and when I put that link in my browser the user can see the document, but what I want, is to let them download
no, it did not work
If "Send To Mail recipient" does not work, it is a problem on your configuration (it has always worked for me since Vista or XP)
yes, but that "sent to the recipient is outside the app" I am trying to open the email client when I click this
that "sent to the recipient is outside the app" I am trying to open the email client when I click this
As I said above, the code with IDataObject does the same thing as "Send To Mail recipient"
On my PC, "Send To Mail recipient" opens the Mail client,
so the code with IDataObject works and opens the Mail client too.
If you fix your "Send To Mail recipient" problem, it should fix the code with IDataObject...
string filePath = "path/to/file.ext";
IDataObject data = new DataObject(DataFormats.FileDrop, new[] { filePath });
Clipboard.SetDataObject(data, true);
Then in your mailto link, you can add the attachment like this:
var destinationurl = $"mailto:?subject={subject}&body={body}&attachment='{filePath}'";
The problem is that I cannot get the path to my client, if I use this, I get "Outlook"
But my default client is mail app
object mailClient = Microsoft.Win32.Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Clients\Mail", "", "none");
because I could do something like
string filepath = file.FilePath;
// Set the file path as the data to be copied
var dataObject = new DataObject(DataFormats.FileDrop, new[] { filepath });
// Copy the data to the clipboard
Clipboard.SetDataObject(dataObject, true);
// Get the default email client's file path
string emailClientPath = "path of your email client exe file";
// Start the default email client
var sInfo = new ProcessStartInfo(emailClientPath) { UseShellExecute = true };
Process.Start(sInfo);
IDataObject must be used like the code I posted with SHCreateFileDataObject, pDropTarget.Drop and so on
No need to read the registry.
This code simulates Right-Click on a file then "Send To Mail recipient", (read from
"%USERPROFILE%\AppData\Roaming\Microsoft\Windows\SendTo" ,
which should be "Mail Recipient.MAPIMail"
If this works, the code with IDataObject should work.
let me try
you mean this code
public partial class Form1 : Form
{
public enum HRESULT : int
{
S_OK = 0,
S_FALSE = 1,
E_NOINTERFACE = unchecked((int)0x80004002),
E_NOTIMPL = unchecked((int)0x80004001),
E_FAIL = unchecked((int)0x80004005),
}
[ComImport]
[Guid("00000122-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IDropTarget
{
HRESULT DragEnter(
[In] System.Runtime.InteropServices.ComTypes.IDataObject pDataObj,
[In] int grfKeyState,
[In] Point pt,
[In, Out] ref int pdwEffect);
HRESULT DragOver(
[In] int grfKeyState,
[In] Point pt,
[In, Out] ref int pdwEffect);
HRESULT DragLeave();
HRESULT Drop(
[In] System.Runtime.InteropServices.ComTypes.IDataObject pDataObj,
[In] int grfKeyState,
[In] Point pt,
[In, Out] ref int pdwEffect);
}
public const int DROPEFFECT_NONE = (0);
[DllImport("Shell32.dll", CharSet = CharSet.Unicode, SetLastError = true, EntryPoint = "#740")]
public static extern HRESULT SHCreateFileDataObject(IntPtr pidlFolder, uint cidl, IntPtr[] apidl, System.Runtime.InteropServices.ComTypes.IDataObject pdtInner, out System.Runtime.InteropServices.ComTypes.IDataObject ppdtobj);
[DllImport("Shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern HRESULT SHILCreateFromPath([MarshalAs(UnmanagedType.LPWStr)] string pszPath, out IntPtr ppIdl, ref uint rgflnOut);
[DllImport("Shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr ILFindLastID(IntPtr pidl);
[DllImport("Shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr ILClone(IntPtr pidl);
[DllImport("Shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern Boolean ILRemoveLastID(IntPtr pidl);
[DllImport("Shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern void ILFree(IntPtr pidl);
Guid CLSID_MapiMail = new Guid("9E56BE60-C50F-11CF-9A2C-00A0C90A90CE");
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
HRESULT hr = HRESULT.E_FAIL;
uint rgflnOut = 0;
System.Runtime.InteropServices.ComTypes.IDataObject pDataObject;
IntPtr pidlParent = IntPtr.Zero, pidlFull = IntPtr.Zero, pidlItem = IntPtr.Zero;
var aPidl = new IntPtr[255];
hr = SHILCreateFromPath("E:\\test.docx", out pidlFull, ref rgflnOut);
if (hr == HRESULT.S_OK)
{
pidlItem = ILFindLastID(pidlFull);
aPidl[0] = ILClone(pidlItem);
ILRemoveLastID(pidlFull);
pidlParent = ILClone(pidlFull);
ILFree(pidlFull);
hr = SHCreateFileDataObject(pidlParent, 1, aPidl, null, out pDataObject);
if (hr == HRESULT.S_OK)
{
Type DropTargetType = Type.GetTypeFromCLSID(CLSID_MapiMail, true);
object DropTarget = Activator.CreateInstance(DropTargetType);
IDropTarget pDropTarget = (IDropTarget)DropTarget;
int pdwEffect = DROPEFFECT_NONE;
Point pt = new Point();
pt.X = 0;
pt.Y = 0;
hr = pDropTarget.Drop(pDataObject, 0, pt, pdwEffect);
}
if (pidlParent != IntPtr.Zero)
ILFree(pidlParent);
if (aPidl[0] != IntPtr.Zero)
ILFree(aPidl[0]);
}
}
}
This code?
We already tried, and it will try to open outlook. But not everyone uses outlook by default