4

给定一些文件(或 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

在此处输入图像描述

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

在此处输入图像描述

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

HKEY_CLASSES_ROOT\.mapimail

如何在临时.mapimail文件上调用 drop?

你不能只看注册表吗?

现在,我可能是一个糟糕的开发人员,并且拼写注册表,.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编程了

我想要的是可能涉及外壳的东西(伪代码):

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 客户端。所以我需要能够完成用户已经可以完成的事情。

4

1 回答 1

3

虽然它没有回答我的问题,但雷蒙德指出这是一个愚蠢的问题。头脑正常的人都不应该尝试向收件人发送邮件。但我很绝望!

事实证明我并没有完全陷入困境。虽然从 32 位应用程序(或反之亦然)处理 64 位 Outlook(MAPI 提供程序)时会有一点噩梦,但还是有一个问题

如果我 MapiSendMail使用,而不使用其他MAPI 函数,则可以安全地跨越 32 位/64 位障碍。从在 32 位和 64 位平台上构建 MAPI 应用程序

32 位 MAPI 应用程序和 64 位 Outlook

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

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

例外:MAPISendMail

但是,所有 Simple 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 函数调用成功。

在此处输入图像描述

因此,作为 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;

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

于 2013-07-27T16:48:50.300 回答