如何将文件拖放到.MAPIMail上

时间:2013-05-10 15:42:54

标签: winapi windows-shell mapi

给定一些文件(或shell文件对象)如何用它们调用.MAPIMail已注册的shell扩展处理程序?


问题

我在电脑上有一些文件:

  • C:\Users\ian\AppData\Local\Temp\Contoso_Invoice_141174.pdf
  • C:\Users\ian\AppData\Local\Temp\Contoso_Invoice_141173.pdf
  • C:\Users\ian\AppData\Local\Temp\Contoso_Invoice_141171.pdf

我想将编程等同于将它们放在.MAPIMail已注册的处理程序上:

enter image description here

发送至文件夹的邮件收件人选项实际上是一个特殊注册的.MAPIMail扩展程序:

enter image description here

这是在系统上注册的文件类型:

HKEY_CLASSES_ROOT\.mapimail

如何调用drop到一个短暂的.mapimail文件?

你不能只看一下注册表吗?

现在,我可能是一个糟糕的开发人员,并在注册表中填写.mapimail条目的默认值:

CLSID\{9E56BE60-C50F-11CF-9A2C-00A0C90A90CE}

提取clsid {9E56BE60-C50F-11CF-9A2C-00A0C90A90CE},并确认该类已注册:

HKEY_CLASSES_ROOT\CLSID\{9E56BE60-C50F-11CF-9A2C-00A0C90A90CE}
    (default) = Desktop Shortcut
    \InProcServer32
        (default) = %SystemRoot%\System32\sendmail.dll

使用CoCreateInstance创建该COM对象:

IUnknown unk = CreateComObject("{9E56BE60-C50F-11CF-9A2C-00A0C90A90CE}");

然后我处于一个无证件,不受支持的世界,在那里我不知道我有QueryInterface的接口,以及以什么顺序调用的方法。

所以我们留下了shell编程

我想要的是可能涉及shell的内容(伪代码):

IShellFolder desktop;
OleCheck(SHGetDesktopFolder(out desktop));

List<pidl> pidls = new List<pidl>();

ULONG chEaten = 0;
ULONG dwAttributes = 0;
PIDL pidl;

foreach (String filename in Files) do
{
    OleCheck(desktop.ParseDisplayName(0, nil, filename, out chEaten, out pidl, ref dwAttributes));

    pidls.Add(pidl);
}

//Get the shell folder of the temp folder
IShellFolder tempShellFolder;
desktop.ParseDisplayName(0, nil, GetTemporaryPath, out chEaten, out pidl, ref dwAttributes));
desktop.BindToObject(pidl, nil, IShellFolder, tempShellFolder);

//i have no idea what i've been doing; just throwing reasonable looking code together
//nobody will actually ever read this

IDontCare context;

tempShellFolder.GetUIObjectOf(0, pidls.Count, pidls, IDontCareAnymore, nil, ref context); 

除了所有代码依赖于上下文菜单的延伸,我没有。没有人说.MAPIMail必须在任何情况下发送到菜单。

我问的是如何删除.mapimail文件上的文件。

我的上帝。

为什么不直接使用MAPI?

因为在安装了Office 64位的Windows 64位上运行的32位应用程序中没有安装MAPI客户端。所以我需要能够完成用户已经可以做到的事情。

1 个答案:

答案 0 :(得分:3)

虽然它没有回答我的问题,雷蒙德指出这是一个愚蠢的问题。在他们正确的思想中,没有人应该尝试向收件人发送邮件。但我绝望了!

原来我并没有被完全卡住。虽然从32位应用程序(或反之亦然)处理64位Outlook(MAPI提供程序)时存在 bitness 噩梦,但还有一个。

如果我使用 MapiSendMail没有其他 MAPI功能,则可以安全地跨越32位/ 64位屏障。来自Building MAPI Applications on 32-Bit and 64-Bit Platforms

  

32位MAPI应用程序和64位Outlook

     

不支持在安装了64位Outlook和64位Windows的计算机上运行32位MAPI应用程序。应用程序开发人员必须将应用程序更新并重建为64位平台的64位应用程序。这是因为32位应用程序无法加载64位Msmapi32.dll文件。应用程序开发人员必须包含少量API更改,才能在64位环境中成功构建代码。已使用这些更改更新MAPI头文件以支持64位平台。您可以在Outlook 2010: MAPI Header Files下载这些头文件。开发人员可以使用同一组MAPI头文件来构建32位和64位MAPI应用程序

这听起来好像都失去了希望。但是,在Windows 7上有:

  

异常:MAPISendMail

     

但是,所有简单MAPI和MAPI元素( MAPISendMail )中的一个函数调用将在Windows-32-bit-on-Windows-64-bit(WOW64)或Windows-64-上成功bit-on-Windows-32-bit(WOW32)场景,不会导致上述警报。此WOW64方案仅适用于Windows 7.图2显示了一个WOW64方案,其中32位MAPI应用程序在安装了64位Windows 7的计算机上调用 MAPISendMail 。在此方案中,MAPI库进行COM调用以启动64位Fixmapi应用程序。 Fixmapi应用程序隐式链接到MAPI库,该库将函数调用路由到Windows MAPI存根,后者又将调用转发到Outlook MAPI存根,从而使MAPISendMail函数调用成功。

enter image description here

因此,作为Delphi Jedi用户,他们的简单发送电子邮件功能将失败(因为他们使用太多 MAPI)。所以我必须创建自己的:

procedure MapiSimpleSendMail(slFiles: TStrings; ToEmailAddress: string=''; ToName: string='');
var
    mapiMessage: TMapiMessage;
    flags: LongWord;
//  senderName: AnsiString;
//  senderEmailAddress: AnsiString;
    emailSubject: AnsiString;
    emailBody: AnsiString;
//  sender: TMapiRecipDesc;
    recipients: packed array of TMapiRecipDesc;
    attachments: packed array of TMapiFileDesc;
    i: Integer;
    hr: Cardinal;
    es: string;
const
    MAPI_E_UNICODE_NOT_SUPPORTED = 27; //Windows 8. The MAPI_FORCE_UNICODE flag is specified and Unicode is not supported.
begin
    ZeroMemory(@mapiMessage, SizeOf(mapiMessage));

{   senderName := '';
    senderEmailAddress := '';

    ZeroMemory(@sender, sizeof(sender));
    sender.ulRecipClass := MAPI_ORIG; //MAPI_TO, MAPI_CC, MAPI_BCC, MAPI_ORIG
    sender.lpszName := PAnsiChar(senderName);
    sender.lpszAddress := PAnsiChar(senderEmailAddress);}
    mapiMessage.lpOriginator := nil; //PMapiRecipDesc; { Originator descriptor                  }

    if ToEmailAddress <> '' then
    begin
        SetLength(recipients, 1);
        recipients[0].ulRecipClass := MAPI_TO;
        recipients[0].lpszName := LPSTR(ToName);
        recipients[0].lpszAddress := LPSTR(ToEmailAddress);

        mapiMessage.lpRecips := @recipients[0]; //A value of NULL means that there are no recipients. Additionally, when this member is NULL, the nRecipCount member must be zero.
        mapiMessage.nRecipCount := 1;
    end
    else
    begin
        mapiMessage.lpRecips := nil; //A value of NULL means that there are no recipients. Additionally, when this member is NULL, the nRecipCount member must be zero.
        mapiMessage.nRecipCount := 0;
    end;

    mapiMessage.lpszMessageType := nil;

    if slFiles.Count > 0 then
    begin
        emailSubject := 'Emailing: ';
        emailBody :=
                '          '+#13#10+ //Yes, the shell really does create a blank mail with a leading line of ten spaces
                'Your message is ready to be sent with the following file or link attachments:'+#13#10;


    SetLength(attachments, slFiles.Count);
        for i := 0 to slFiles.Count-1 do
        begin
            attachments[i].ulReserved := 0; // Cardinal;        { Reserved for future use (must be 0)     }
            attachments[i].flFlags := 0; // Cardinal;           { Flags                                   }
            attachments[i].nPosition := $FFFFFFFF; //Cardinal;         { character in text to be replaced by attachment }
            attachments[i].lpszPathName := PAnsiChar(slFiles[i]);    { Full path name of attachment file       }
            attachments[i].lpszFileName := nil; // LPSTR;         { Original file name (optional)           }
            attachments[i].lpFileType := nil; // Pointer;         { Attachment file type (can be lpMapiFileTagExt) }

            if i > 0 then
                emailSubject := emailSubject+', ';
            emailSubject := emailSubject+ExtractFileName(slFiles[i]);
            emailBody := emailBody+#13#10+
                    ExtractFileName(slFiles[i]);
        end;

        emailBody := emailBody+#13#10+
                #13#10+
                #13#10+
                'Note: To protect against computer viruses, e-mail programs may prevent sending or receiving certain types of file attachments.  Check your e-mail security settings to determine how attachments are handled.';


        mapiMessage.lpFiles := @attachments[0];
        mapiMessage.nFileCount := slFiles.Count;
    end
    else
    begin
        emailSubject := '';
        emailBody := '';

        mapiMessage.lpFiles := nil;
        mapiMessage.nFileCount := 0;
    end;

    {
        Subject
        Emailing: 4388_888871544_MVM_10.tmp, amt3.log, swtag.log, wct845C.tmp, ~vs1830.sql

        Body
                  <-- ten spaces
        Your message is ready to be sent with the following file or link attachments:

        4388_888871544_MVM_10.tmp
        amt3.log
        swtag.log
        wct845C.tmp
        ~vs1830.sql


        Note: To protect against computer viruses, e-mail programs may prevent sending or receiving certain types of file attachments.  Check your e-mail security settings to determine how attachments are handled.
    }
    mapiMessage.lpszSubject := PAnsiChar(emailSubject);
    mapiMessage.lpszNoteText := PAnsiChar(emailBody);


    flags := MAPI_DIALOG;

    hr := Mapi.MapiSendMail(0, 0, mapiMessage, flags, 0);
    case hr of
    SUCCESS_SUCCESS: {nop}; //The call succeeded and the message was sent.
    MAPI_E_AMBIGUOUS_RECIPIENT:
        begin
            //es := 'A recipient matched more than one of the recipient descriptor structures and MAPI_DIALOG was not set. No message was sent.';
            raise Exception.CreateFmt('Error %s sending e-mail message: %s', ['MAPI_E_AMBIGUOUS_RECIPIENT', SysErrorMessage(hr)]);
        end;
    MAPI_E_ATTACHMENT_NOT_FOUND:
        begin
            //The specified attachment was not found. No message was sent.
            raise Exception.CreateFmt('Error %s sending e-mail message: %s', ['MAPI_E_ATTACHMENT_NOT_FOUND', SysErrorMessage(hr)]);
        end;
    MAPI_E_ATTACHMENT_OPEN_FAILURE:
        begin
            //The specified attachment could not be opened. No message was sent.
            raise Exception.CreateFmt('Error %s sending e-mail message: %s', ['MAPI_E_ATTACHMENT_OPEN_FAILURE', SysErrorMessage(hr)]);
        end;
    MAPI_E_BAD_RECIPTYPE:
        begin
            //The type of a recipient was not MAPI_TO, MAPI_CC, or MAPI_BCC. No message was sent.
            raise Exception.CreateFmt('Error %s sending e-mail message: %s', ['MAPI_E_BAD_RECIPTYPE', SysErrorMessage(hr)]);
        end;
    MAPI_E_FAILURE:
        begin
            //One or more unspecified errors occurred. No message was sent.
            raise Exception.CreateFmt('Error %s sending e-mail message: %s', ['MAPI_E_FAILURE', SysErrorMessage(hr)]);
        end;
    MAPI_E_INSUFFICIENT_MEMORY:
        begin
            //There was insufficient memory to proceed. No message was sent.
            raise Exception.CreateFmt('Error %s sending e-mail message: %s', ['MAPI_E_INSUFFICIENT_MEMORY', SysErrorMessage(hr)]);
        end;
    MAPI_E_INVALID_RECIPS:
        begin
            //One or more recipients were invalid or did not resolve to any address.
            raise Exception.CreateFmt('Error %s sending e-mail message: %s', ['MAPI_E_INVALID_RECIPS', SysErrorMessage(hr)]);
        end;
    MAPI_E_LOGIN_FAILURE:
        begin
            //There was no default logon, and the user failed to log on successfully when the logon dialog box was displayed. No message was sent.
            raise Exception.CreateFmt('Error %s sending e-mail message: %s', ['MAPI_E_LOGIN_FAILURE', SysErrorMessage(hr)]);
        end;
    MAPI_E_TEXT_TOO_LARGE:
        begin
            //The text in the message was too large. No message was sent.
            raise Exception.CreateFmt('Error %s sending e-mail message: %s', ['MAPI_E_TEXT_TOO_LARGE', SysErrorMessage(hr)]);
        end;
    MAPI_E_TOO_MANY_FILES:
        begin
            //There were too many file attachments. No message was sent.
            raise Exception.CreateFmt('Error %s sending e-mail message: %s', ['MAPI_E_TOO_MANY_FILES', SysErrorMessage(hr)]);
        end;
    MAPI_E_TOO_MANY_RECIPIENTS:
        begin
            //There were too many recipients. No message was sent.
            raise Exception.CreateFmt('Error %s sending e-mail message: %s', ['MAPI_E_TOO_MANY_RECIPIENTS', SysErrorMessage(hr)]);
        end;
    MAPI_E_UNICODE_NOT_SUPPORTED:
        begin
            //The MAPI_FORCE_UNICODE flag is specified and Unicode is not supported.
            //Note  This value can be returned by MAPISendMailW only.
            raise Exception.CreateFmt('Error %s sending e-mail message: %s', ['MAPI_E_UNICODE_NOT_SUPPORTED', SysErrorMessage(hr)]);
        end;
    MAPI_E_UNKNOWN_RECIPIENT:
        begin
            //A recipient did not appear in the address list. No message was sent.
            raise Exception.CreateFmt('Error %s sending e-mail message: %s', ['MAPI_E_UNKNOWN_RECIPIENT', SysErrorMessage(hr)]);
        end;
    MAPI_E_USER_ABORT:
        begin
            es := 'The user canceled one of the dialog boxes. No message was sent.';
            raise Exception.CreateFmt('Error %s sending e-mail message: %s', ['MAPI_E_USER_ABORT', es]);
        end;
    else
        raise Exception.CreateFmt('Error %d sending e-mail message: %s', [hr, SysErrorMessage(hr)]);
    end;
end;
  

注意:任何代码都会发布到公共域中。无需归属。