Dominik S
Dominik S

Reputation: 186

MAPISendMail access violation

I have a problem with MapiSendMail function of MAPI32.dll. Everything seems fine, message is completed, then I send it by winapi function, and i get an Access violation error, it happend in MAPISendMail. Here's the fragment of the code:

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;

Also I was trying to change GetProcAddres to MAPISendMailW or MAPISendMailHelper, but then @SM was nil.

@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;

Upvotes: 1

Views: 1091

Answers (1)

Maxim Masiutin
Maxim Masiutin

Reputation: 4812

Under Win32

Under Win32 it should not be a problem. Just first try calling MapiSendMail with very simple MapiMessage and if it will work, add complexity little by little. Your code is just too complex to debug it visually. Did you call MapiSendMail with very simple MapiMessage, just for testing? Please try the following code, it works for sure:

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 := '[email protected]';
  Msg.flFlags := MAPI_RECEIPT_REQUESTED;

  FillChar(Recipients, SizeOf(Recipients), 0);
  with Recipients[0] do
  begin
    ulRecipClass := MAPI_TO;
    lpszName := 'Maxim Masiutin';
    lpszAddress := '[email protected]';
  end;
  with Recipients[1] do
  begin
    ulRecipClass := MAPI_CC;
    lpszName := 'Vasilii Pupkin';
    lpszAddress := '[email protected]';
  end;

  FillChar(Originator, SizeOf(Originator), 0);
  with Originator[0] do
  begin
    ulRecipClass := MAPI_TO;
    lpszName := 'Maxim Masiutin';
    lpszAddress := '[email protected]';
  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;

The MapiSession in the above example is a handle to the session returned by MapiLogon.

This sample code requires that you pass two valid file paths to valid files in APath1 and APath2.

Under Win64

It is the record alignment of MapiMessage and other records that it is important when you work with Simple MAPI from Delphi: (1) make sure the records don't have "packed" prefix; and (2) make sure you have {$A8} compiler directive is explicitly specified before first record definition. This will work fine under both Win32 and Win64.

Upvotes: 0

Related Questions