MAPISendMail访问冲突

时间:2016-09-16 10:16:56

标签: delphi mapi

我遇到MAPI32.dll的MapiSendMail函数问题。一切似乎都很好,消息已经完成,然后我通过winapi函数发送它,并且我收到一个访问冲突错误,它发生在MAPISendMail中。这是代码的片段:

MAPIModule := LoadLibrary(PWideChar(MAPIDLL));
if MAPIModule = 0 then
  Result := -1
else
  try
    @SM := GetProcAddress(MAPIModule, 'MAPISendMail');
    if @SM <> nil then
    begin
      Result := SM(0, application.Handle, Msg,  MAPI_DIALOG {or  MAPI_LOGON_UI}, 0);
    end
    else
      Result := 1;
  finally

  end;

我还试图将GetProcAddres更改为MAPISendMailW或MAPISendMailHelper,但是@SM是零。

@ EDIT1

function TMail._SendMAPIEmail(const aTo, aAtts: array of AnsiString; const body, subject, SenderName, SenderEmail: string; ShowError: Boolean = true): Integer;
var
  SM: TFNMapiSendMail;
  Msg: MapiMessage;
  lpSender: MapiRecipDesc;
  Recips: array of MapiRecipDesc;
  Att: array of MapiFileDesc;
  TempAttNames: array of pAnsiChar;
  TempAttNamesAnsi: array of AnsiString;
  TempAttPaths: array of pAnsiChar;
  TempRecip: array of pAnsiChar;
  p1, LenTo, LenAtts: Integer;
  MAPIModule: HModule;
  sError: String;
  i: integer;
begin
  try
    FillChar(Msg, SizeOf(Msg), 0);
    { get the length of all arrays passed to this function }
    LenTo := length(aTo);
    if Trim(aAtts[0]) <> '' then
      LenAtts := length(aAtts)
    else
      LenAtts := 0;
    { ... }
    SetLength(Recips, LenTo);
    SetLength(TempRecip, LenTo);
    Setlength(Att, LenAtts);
    SetLength(TempAttNames, LenAtts);
    SetLength(TempAttPaths, LenAtts);
    SetLength(TempAttNamesAnsi, LenAtts);
    { to }
    for p1 := 0 to LenTo - 1 do
    begin
      FillChar(Recips[p1], SizeOf(Recips[p1]), 0);
      Recips[p1].ulReserved := 0;
      Recips[p1].ulRecipClass := MAPI_TO;
      { Upgrade }
      Recips[p1].lpszName := '';
      TempRecip[p1] := pAnsichar(aTo[p1]);
      Recips[p1].lpszAddress := TempRecip[p1];
    end;
    { atts }
    for p1 := 0 to LenAtts - 1 do
    begin
      FillChar(Att[p1], SizeOf(Att[p1]), 0);
      FillChar(TempAttPaths[p1], SizeOf(pAnsiChar), 0);
      FillChar(TempAttNames[p1], SizeOf(pAnsiChar), 0);
      FillChar(TempAttNamesAnsi[01], SizeOf(AnsiChar), 0);
      Att[p1].ulReserved := 0;
      Att[p1].flFlags := 0;
      Att[p1].nPosition := Cardinal($FFFFFFFF);
      { Upgrade }
      TempAttPaths[p1] := pAnsichar(aAtts[p1]);
      Att[p1].lpszPathName := TempAttPaths[p1];
      TempAttNamesAnsi[p1] := AnsiString((ExtractFileName(string(aAtts[p1]))));
      TempAttNames[p1] := pAnsiChar(TempAttNamesAnsi[p1]);
      Att[p1].lpszFileName := TempAttNames[p1];
    end;
    { fill the message }
    with Msg do
    begin
      ulReserved := 0;
      if subject <> '' then
        { Upgrade }
        lpszSubject := pAnsichar(AnsiString(subject));
      if body <> '' then
        { Upgrade }
        lpszNoteText := pAnsichar(AnsiString(body));
      if SenderEmail <> '' then
      begin
        lpSender.ulRecipClass := MAPI_ORIG;
        if SenderName = '' then
          lpSender.lpszName := pAnsichar(AnsiString(SenderEmail))
        else
          lpSender.lpszName := pAnsichar(AnsiString(SenderName));
        lpSender.lpszAddress := pAnsichar(AnsiString(SenderEmail));
        lpSender.ulEIDSize := 0;
        lpSender.lpEntryID := nil;
        lpOriginator := @lpSender;
      end
      else
        Msg.lpOriginator := nil;
      Msg.lpszMessageType := nil;
      Msg.lpszDateReceived := nil;
      Msg.lpszConversationID := nil;
      Msg.flFlags := 0;
      Msg.nRecipCount := LenTo;
      Msg.lpRecips := @Recips[0];
      Msg.nFileCount := LenAtts;
      Msg.lpFiles := @Att[0];
    end;
    MAPIModule := LoadLibrary(PWideChar(MAPIDLL));
    if MAPIModule = 0 then
      Result := -1
    else
      try
        @SM := GetProcAddress(MAPIModule, 'MAPISendMail');
        if @SM <> nil then
        begin
          //Result := MapiSendMail(0, application.Handle, Msg, MAPI_DIALOG, 0);
          Result := SM(0, 0, Msg,  MAPI_DIALOG {or  MAPI_LOGON_UI}, 0);
        end
        else
          Result := 1;
      finally
        if Assigned(Att) and (Msg.nFileCount > 0) then
        begin
          for i := 0 to Msg.nFileCount - 1 do
          begin
            if Assigned(Att[i].lpszPathName) then
              Att[i].lpszPathName := nil;
            if Assigned(Att[i].lpszFileName) then
              Att[i].lpszFileName := nil;
              //FreeMem(Att[i].lpszPathName);
            //Dispose(Att[i].lpszPathname);
            //StrDispose(Att[i].lpszPathName);
            //Dispose(Att[i].lpszFileName);
            //StrDispose(Att[i].lpszFileName);
          end;
          Att := nil;
        end;

        if Assigned(Recips) and (Msg.nRecipCount > 0) then
        begin
          for i := 0 to Msg.nRecipCount - 1 do
          begin
          if Assigned(Recips[i].lpszName) then
            Recips[i].lpszName := nil;
          if Assigned(Recips[i].lpszAddress) then
            Recips[i].lpszAddress := nil;
            //if Assigned(Recips[i].lpszName) then
              //Dispose(Recips[i].lpszName);

            //if Assigned(Recips[i].lpszAddress) then
              //Dispose(Recips[i].lpszAddress);
          end;
          Recips := nil;
        end;
      end;

1 个答案:

答案 0 :(得分:0)

在Win32下

在Win32下它应该不是问题。首先尝试使用非常简单的MapiMessage调用MapiSendMail,如果它可以工作,一点一点地增加复杂性。您的代码太复杂,无法直观地调试它。您是否使用非常简单的MapiMessage调用MapiSendMail,仅用于测试?请尝试以下代码,它确实有效:

procedure TestSendExA(const APath1, ACaption1, APath2, ACaption2: AnsiString);
var
  R: Integer;
  MSG: TMapiMessage;
  F: Array [0..1] of TMapiFileDesc;
  Recipients: array[0..1] of TMapiRecipDesc;
  Originator : array[0..0] of TMapiRecipDesc;
begin
  if not FileExists(APath1) or not FileExists(APath2) then raise Exception.Create('File not found');

  FillChar(Msg, SizeOf(Msg), 0);

  Msg.lpszSubject := 'testo';
  Msg.lpszNoteText := 'Hi there!';
  Msg.lpszDateReceived := '2015/01/25 12:34';
  Msg.lpszConversationId := '1234.test@ritlabs.com';
  Msg.flFlags := MAPI_RECEIPT_REQUESTED;

  FillChar(Recipients, SizeOf(Recipients), 0);
  with Recipients[0] do
  begin
    ulRecipClass := MAPI_TO;
    lpszName := 'Maxim Masiutin';
    lpszAddress := 'maxim.test@ritlabs.com';
  end;
  with Recipients[1] do
  begin
    ulRecipClass := MAPI_CC;
    lpszName := 'Vasilii Pupkin';
    lpszAddress := 'pupkin.test@ritlabs.com';
  end;

  FillChar(Originator, SizeOf(Originator), 0);
  with Originator[0] do
  begin
    ulRecipClass := MAPI_TO;
    lpszName := 'Maxim Masiutin';
    lpszAddress := 'max@ritlabs.com';
  end;

  Msg.lpOriginator := @Originator;
  Msg.nRecipCount := 2;
  Msg.lpRecips := @Recipients;

  Msg.nFileCount := 2;
  Msg.lpFiles := @F;
  FillChar(F, SizeOf(F), 0);
  F[0].lpszPathName := PAnsiChar(APath1);
  F[0].lpszFileName := PAnsiChar(ACaption1);
  F[1].lpszPathName := PAnsiChar(APath2);
  F[1].lpszFileName := PAnsiChar(ACaption2);

  R := MAPISendMail(MapiSession, 0, Msg, 0, 0);
end;

上例中的MapiSession是MapiLogon返回的会话句柄。

此示例代码要求您将两个有效文件路径传递给APath1和APath2中的有效文件。

在Win64下

当您使用Delphi的简单MAPI时,MapiMessage和其他记录的记录对齐非常重要:(1)确保记录没有&#34;打包&#34;字首; (2)确保在第一个记录定义之前显式指定{$ A8}编译器指令。这在Win32和Win64下都能正常工作。