当 Delphi 32 位应用程序的相同代码工作时,从 Delphi 64 位应用程序调用 MAPI 电子邮件不起作用?
Posted
技术标签:
【中文标题】当 Delphi 32 位应用程序的相同代码工作时,从 Delphi 64 位应用程序调用 MAPI 电子邮件不起作用?【英文标题】:Calling MAPI email from Delphi 64 bit app does not work when same code for Delphi 32 bit app works? 【发布时间】:2015-06-20 04:34:03 【问题描述】:我正在构建一个 64 位 Delphi XE2 应用程序来处理通过 Outlook 发送 MAPI 邮件。这适用于 Outlook 2010、2013 等的 64 位安装,因为您无法从 32 位应用程序调用 64 位 MAPI。
我的 Delphi 代码在编译为 32 位应用程序时可与 32 位版本的 Outlook 客户端完美配合。 32 位应用程序在 Win7 64 上运行。
当将相同的代码重新编译到 64 位应用程序中时,该代码总是失败并显示 MAPI_E_FAILURE 错误代码为 2。 64 位应用程序在安装了 Outlook 2013 64 位客户端的 Win 8 上运行。
知道为什么 64 位应用程序会失败吗?对于 64 位代码,我是否正在做一些明显的事情?
干杯! TJ
代码如下:
function SendEMailByMAPI(SenderName, SenderAddress, Subject, Body: Ansistring; Recipients, Attachments: TStringList): Integer;
var i: Integer;
var EmailMessage: TMapiMessage;
var lpSender: TMapiRecipDesc;
var MAPI_Session : Cardinal;
var RecipientArray : array of TMapiRecipDesc;
var AttachmentsArray : array of TMapiFileDesc;
begin
FillChar(EmailMessage, SizeOf(EmailMessage), 0);
//add sender address if not blank.
if (SenderAddress <> '') then begin
lpSender.ulRecipClass := MAPI_ORIG;
if (SenderName <> '') then begin
lpSender.lpszName := PAnsiChar(SenderAddress);
end
else begin
lpSender.lpszName := PAnsiChar(SenderName);
end;
lpSender.lpszAddress := PAnsiChar(SenderAddress);
lpSender.ulReserved := 0;
lpSender.ulEIDSize := 0;
lpSender.lpEntryID := nil;
EmailMessage.lpOriginator := @lpSender;
end;
EmailMessage.lpszSubject := PAnsiChar(Subject);
EmailMessage.lpszNoteText := PAnsiChar(Body);
EmailMessage.nFileCount := Attachments.Count;
SetLength(AttachmentsArray, Attachments.Count);
//Loop and add file path and name
for i := 0 to Attachments.Count-1 do begin
AttachmentsArray[i].nPosition := Cardinal(-1);
AttachmentsArray[i].lpszPathName := PAnsiChar(AnsiString(Attachments[i]));
AttachmentsArray[i].lpszFileName := PAnsiChar(AnsiString(ExtractFileName(Attachments[i])));
end;
if EmailMessage.nFileCount > 0 then begin
EmailMessage.lpFiles := Pointer(AttachmentsArray);
end
else begin
EmailMessage.lpFiles := nil;
end;
SetLength(RecipientArray, Recipients.Count);
for i := 0 to Recipients.Count-1 do begin
RecipientArray[i].ulReserved := 0;
RecipientArray[i].ulRecipClass := MAPI_TO;
RecipientArray[i].lpszName := StrNew(PAnsiChar(AnsiString(Recipients[i])));
RecipientArray[i].lpszAddress := StrNew(PAnsiChar('SMTP:' + AnsiString(Recipients[i])));
RecipientArray[i].lpEntryID := nil;
RecipientArray[i].ulEIDSize := 0;
end;
EmailMessage.nRecipCount := Recipients.Count;
EmailMessage.lpRecips := Pointer(RecipientArray);
//Send the message
Result:= MapiLogon(Application.Handle, PAnsiChar(''), PAnsiChar(''), MAPI_LOGON_UI or MAPI_NEW_SESSION, 0, @MAPI_Session);
if (Result = SUCCESS_SUCCESS) then begin
ShowMessage('Before calling MAPISendMail');//used as a timing device to see how long it takes for Outlook to respond to request and show email dialog
Result := MAPISendMail(MAPI_Session, Application.Handle, EmailMessage, MAPI_DIALOG or MAPI_LOGON_UI , 0);
if Result <> 0 then begin
case result of
MAPI_E_AMBIGUOUS_RECIPIENT : ShowMessage('Receiver is not unique.');
MAPI_E_ATTACHMENT_NOT_FOUND : ShowMessage('File for appending not found');
MAPI_E_ATTACHMENT_OPEN_FAILURE : ShowMessage('File could not be opened for appending.');
MAPI_E_BAD_RECIPTYPE : ShowMessage('Type of receiver not MAPI_TO, MAPI_CC or MAPI_BCC.');
MAPI_E_FAILURE : ShowMessage('Unknown Error.');
MAPI_E_INSUFFICIENT_MEMORY : ShowMessage('Not enough memory.');
MAPI_E_LOGIN_FAILURE : ShowMessage('User Login failed.');
MAPI_E_TEXT_TOO_LARGE : ShowMessage('Text too large.');
MAPI_E_TOO_MANY_FILES : ShowMessage('Too many file attachments.');
MAPI_E_TOO_MANY_RECIPIENTS : ShowMessage('Too many recipients specified.');
MAPI_E_UNKNOWN_RECIPIENT : ShowMessage('Receiver not found in the address book.');
MAPI_E_USER_ABORT : ShowMessage('User canceled or MAPI Send not installed.');
else
ShowMessage('Error sending email. Error code: ' + inttostr(Result));
end;
end;
end
else begin
ShowMessage('Failure to get MAPI call handle: ' + inttostr(Result));
end;
end;
这个函数是这样调用的:
procedure TForm1.ButtonClick(Sender: TObject);
var SenderName: Ansistring;
var SenderAddress: Ansistring;
var Subject: Ansistring;
var Body: Ansistring;
var Recipients: TStringList;
var Attachments: TStringList;
begin
Recipients := TStringList.Create;
Attachments := TStringList.Create;
Recipients.Add('test@test.com');
Attachments.Add('c:\temp\test.xlsx');
SenderName := 'TJ Asher';
SenderAddress := 'sender@test.com';
Subject := 'email test 64 bit subject';
Body := 'Email test 64 bit body';
SendEMailByMAPI(SenderName, SenderAddress, Subject, Body, Recipients, Attachments);
end;
【问题讨论】:
您的记录可能翻译错误。我们看不到它们。您对StrNew
的使用是错误的。它泄漏。创建一个TList<AnsiString>
来存储可以使用PAnsiChar
强制转换的临时字符串值。在 finally 块中销毁列表以进行整理。
这里发布的代码可能是好是坏,这取决于我们看不到的代码。如果您遇到问题甚至无法发布您可能正在工作的 MAPI 包装器,那么没有人可以帮助您。
@David Heffernan - 不确定您所说的错误翻译记录是什么意思?没有记录。我会按照您的建议查看StrNew
位。
@Warren P - 这是整个代码。按钮单击代码调用的一个函数。 MAPISendMail
调用是所有现有的 Delphi VCL 代码。如果需要,我可以发布 Delphi VCL 代码。
XE2 WinApi MAPI 包装单元在 64 位目标中使用时可能不正确。
【参考方案1】:
在 Windows 8 64 位上可能不支持 MAPISendMail (A) 接口:
https://msdn.microsoft.com/is-is/library/dd296721.aspx 建议使用宽字符界面。
也有可能 MAPISendMail 不是 Outlook 2013 64 位支持的接口:它已经贬值了一段时间。我无法在 Outlook 2013/64 上使用该界面,但存在(与 MAPI 一样)复杂的因素。
【讨论】:
以上是关于当 Delphi 32 位应用程序的相同代码工作时,从 Delphi 64 位应用程序调用 MAPI 电子邮件不起作用?的主要内容,如果未能解决你的问题,请参考以下文章
Delphi:如何确定应用程序是不是在 Win32 / Win64 下运行并在 64 位上自动启动 64 位版本?