vendredi 27 juin 2014

Is this usage of TBytes as a PAnsiChar "memory manager" correct?


Vote count:

0




The Simple MAPI makes memory management pretty hard unless you write a lot of pointer (PAnsiChar) allocation and deallocation code.


I like to use compiler managed data types as much as possible, so I tried to use a TList<TBytes> to store my PAnsiChar data for me:



type
TMapiEmailSender = class(TEmailSender)
private
FRecipDescs : TList<TMapiRecipDesc>;
FStrings : TList<TBytes>;
procedure AddRecipient(AClass: Cardinal; const ARecipient: string);
procedure AddRecipients(AClass: Cardinal; ARecipients: TStrings);
function GetString(const S: string): PAnsiChar;
public
constructor Create;
destructor Destroy; override;
procedure Run; override;
end;

procedure TMapiEmailSender.AddRecipient(AClass: Cardinal;
const ARecipient: string);
var
D: TMapiRecipDesc;
begin
FillChar(D, SizeOf(D), 0);
D.ulRecipClass := AClass;
D.lpszName := GetString(ARecipient);
FRecipDescs.Add(D);
end;

procedure TMapiEmailSender.AddRecipients(AClass: Cardinal;
ARecipients: TStrings);
var
Recipient: string;
begin
for Recipient in ARecipients do begin
AddRecipient(AClass, Recipient);
end;
end;

constructor TMapiEmailSender.Create;
begin
inherited Create;
FStrings := TList<TBytes>.Create;
FRecipDescs := TList<TMapiRecipDesc>.Create;
end;

destructor TMapiEmailSender.Destroy;
begin
FRecipDescs.Free;
FStrings.Free;
inherited;
end;

function TMapiEmailSender.GetString(const S: string): PAnsiChar;
var
Bytes: TBytes;
begin
Bytes := TEncoding.Default.GetBytes(S);
SetLength(Bytes, Length(Bytes) + 1);
Bytes[High(Bytes)] := 0;
FStrings.Add(Bytes);
Result := @Bytes[0];
end;

procedure TMapiEmailSender.Run;
var
Msg: TMapiMessage;
begin
try
AddRecipients(MAPI_TO, FEmail.ToRecipients);
AddRecipients(MAPI_CC, FEmail.CcRecipients);
AddRecipients(MAPI_BCC, FEmail.BccRecipients);
FillChar(Msg, SizeOf(Msg), 0);
Msg.nRecipCount := FRecipDescs.Count;
Msg.lpRecips := @FRecipDescs.ToArray[0];
// Code that uses Msg to send a MAPI message here
finally
FRecipDescs.Clear;
FStrings.Clear;
end;
end;


The code seems to be correct (this is only a fragment of the whole thing). I tried it and FastMM is not reporting any memory leaks.


I don't like that I have to resize the Result from TEncoding.Default.GetBytes() to include a trailing zero byte.


Otherwise I think the code is fine.


So the question is: Is the code correct and is it simple enough? Am I overcomplicating things?



asked 1 min ago






Aucun commentaire:

Enregistrer un commentaire