AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

String zu PAnsiChar

Ein Thema von Berni68 · begonnen am 21. Mär 2010 · letzter Beitrag vom 21. Okt 2020
Antwort Antwort
Berni68

Registriert seit: 9. Jan 2006
Ort: Villingen
162 Beiträge
 
Delphi XE5 Professional
 
#1

Re: String zu PAnsiChar

  Alt 21. Mär 2010, 20:18
Das hat garnichts mit Steuerzeichen zu tun, das waren lediglich Beispielstrings.
Der Hintergrung ist die Unit Mapi um eMails mit dem Standard eMail-client zu versenden.
Hat in Delphi2010 nicht mehr funktioniert.

Aber jetzt klappt's wieder; wer's gebrauchen kann:
Delphi-Quellcode:
function SendEMail(Handle:THandle; Mail:TStrings):Cardinal;
var
  MapiMessage: TMapiMessage;
  Receip: TMapiRecipDesc;
  Attachments: array of TMapiFileDesc;
  i, AttachCount: Integer;
  FileName: string;
  MAPI_Session: Cardinal;
  WndList: Pointer;
begin
Result:= MAPI_E_FAILURE;
  if (MapiLogon(Handle, PAnsiChar(''), PAnsiChar(''), MAPI_LOGON_UI or MAPI_NEW_SESSION, 0, @MAPI_Session) <> SUCCESS_SUCCESS)
  then
    MessageBox(Handle, PChar('Error while trying to send email'), PChar('Error'), MB_ICONERROR or MB_OK)
  else
    begin
      if Mail.Values['to']<>'then begin
        Receip.ulReserved:= 0;
        Receip.ulRecipClass:= MAPI_TO;
        Receip.lpszName:= PAnsiChar(AnsiString(Mail.Values['to']));
        Receip.lpszAddress:= PAnsiChar(AnsiString('SMTP:' + Mail.Values['to']));
        Receip.ulEIDSize:= 0;
        MapiMessage.nRecipCount:= 1;
        MapiMessage.lpRecips:= @Receip;
      end;
      if Mail.Values['subject']<>'then MapiMessage.lpszSubject:= PAnsiChar(AnsiString(Mail.Values['subject']));
      if Mail.Values['body']<>'then MapiMessage.lpszNoteText:= PAnsiChar(AnsiString(Mail.Values['body']));

      AttachCount:= 0;
      for i:= 0 to MaxInt do begin
        if Mail.Values['attachment' + IntToStr(i)] = 'then break;
        Inc(AttachCount);
      end;
      SetLength(Attachments, AttachCount);

      if AttachCount>0 then begin
        for i:=0 to AttachCount-1 do begin
          FileName:= Mail.Values['attachment' + IntToStr(i)];
          Attachments[i].ulReserved:= 0;
          Attachments[i].flFlags:= 0;
          Attachments[i].nPosition:= ULONG($FFFFFFFF);
          Attachments[i].lpszPathName:= StrNew(PAnsiChar(AnsiString(FileName)));
          Attachments[i].lpszFileName:= StrNew(PAnsiChar(AnsiString(ExtractFileName(FileName))));
          Attachments[i].lpFileType:= nil;
        end;
        MapiMessage.nFileCount := AttachCount;
        MapiMessage.lpFiles := Pointer(Attachments);
      end;

      WndList:= DisableTaskWindows(0);
      try
        Result:= MapiSendMail(MAPI_Session, Handle, MapiMessage, MAPI_DIALOG, 0);
      finally
        EnableTaskWindows(WndList);
        for i:=0 to AttachCount-1 do begin
          StrDispose(Attachments[i].lpszPathName);
          StrDispose(Attachments[i].lpszFileName);
        end;
        Finalize(Attachments);
      end;
      MapiLogOff(MAPI_Session, Handle, 0, 0);
    end;
end;
so zu verwenden:
Delphi-Quellcode:
procedure TTestForm.Mail1Click(Sender: TObject);
var
  mail: TStringList;
begin
  mail:= TStringList.Create;
  try
      mail.values['to']:= 'fifi@abc.de';
      mail.values['subject']:= 'subject';
      mail.values['body']:= 'text text text';
      mail.values['attachment0']:= 'C:\Anhang1.txt';
      mail.values['attachment1']:= 'C:\Anhang2.txt';
      mail.values['attachment2']:= 'C:\Anhang3.txt';
    SendEMail(Self.Handle, mail);
  finally
    mail.Free;
  end;
end;
Allerdings gab' hierzu mehrmals die Bemerkung, daß Mapi bereits fast tot ist.
Ich hab auch bei Indy geschaut, aber so wie ich das dort verstanden hab, geht der eMail versand
dann nicht über das Mailprogramm Thundrbird outlook etc. ist also dort nicht drin, was ich aber will.
Ausserdem dar ganze Anmeldekram
Aber wenn das auch mit Indy geht lass ich mich gerne aufklären.
Bernhard
  Mit Zitat antworten Zitat
delphifan2004

Registriert seit: 26. Nov 2004
Ort: Dresden
277 Beiträge
 
Delphi 10.3 Rio
 
#2

AW: String zu PAnsiChar

  Alt 21. Okt 2020, 13:13
Ich beschäftige mich auch gerade mit solchen Stringumwandlungen und da erhalte ich eine Accessviolation beim Beenden meines Programmes, obwohl der String zunächst korrekt angezeigt wird, an folgender Stelle in der System Unit, wie mir mein Debugger zeigt (Delphi 10.3.3 Community Edition). Kann der Quellcode aus der System Unit hier so stehen bleiben?


Delphi-Quellcode:
procedure _UStrClr(var S);
{$IFDEF CPUX86}
asm
        { ->    EAX     pointer to str  }
        { <-    EAX     pointer to str  }

        MOV EDX,[EAX] { fetch str                     }
        TEST EDX,EDX { if nil, nothing to do         }
        JE @@done
        MOV dword ptr [EAX],0 { clear str                     }
        MOV ECX,[EDX-skew].StrRec.refCnt { fetch refCnt                  } /// Hier knallt es
        DEC ECX { if < 0: literal str           }
        JL @@done
   LOCK DEC [EDX-skew].StrRec.refCnt { threadsafe dec refCount       }
        JNE @@done
Hier mein Quellcode zu verschiedenen Stringkonvertierungen:

Delphi-Quellcode:
program Strconv;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  Windows;

var
  AnsiStr: AnsiString;
  AnsiChr: PAnsiChar;
  WideStr: WideString;
  WideChr: PWideChar;

procedure AnsiStrToWideStr(aStr: AnsiString; var waStr: WideString);
begin
  waStr := aStr;
end;

procedure AnsiStrToPAnsiChr(aStr: AnsiString; var paChr: LPCSTR);
begin
  paChr := PAnsiChar(aStr);
end;

procedure AnsiStrToPWideChar(aStr: AnsiString; var pwChr: LPCWSTR);
var ws: WideString;
begin
  ws := aStr;
  pwChr := LPCWSTR(ws);
end;

procedure PWideCharToWideString(pwChr: LPCWSTR; var ws: WideString); //Diese Prozedur macht die Probleme
var
  wchr: array of WideChar absolute pwChr;
  i: Integer;
  wch: array of WideChar;
begin
  SetLength(wch,StrLen(pwChr));
  move(wchr,ws,StrLen(pwChr));
  ws := WideString(wchr);
end;
{
procedure PWideCharToPAnsiChar(pwChr: LPCWSTR; var a: LPCSTR);
var
  wchr: array of WideChar absolute pwChr;
  ansiStr: AnsiString;
  wideStr: WideString;
begin

  move(wchr,wideStr,StrLen(pwChr));

  //PWideCharToWideString(pwChr,wideStr);

  ansiStr := WideStr;
  a := @ansiStr;


end;
}

procedure PWideCharToAnsiString(pwChr: LPCWSTR; var s: AnsiString);
var wideStr: WideString;
begin
  PWideCharToWideString(pwChr,wideStr);
  s := AnsiString (WideStr);
end;



begin
  try
    { TODO -oUser -cConsole Main : Code hier einfügen }
    AnsiStr := 'Dieser String';
    //AnsiStrToPAnsiChr(AnsiStr,AnsiChr);
    //AnsiStrToWideStr(AnsiStr,WideStr);
    AnsiStrToPWideChar(AnsiStr,WideChr);
    //PWideCharToPAnsiChar(WideChr,AnsiChr);
    //PWideCharToWideString(WideChr,WideStr);
    //PWideCharToPAnsiChar(WideChr,AnsiChr); funktioniert nicht

    PWideCharToAnsiString(WideChr,AnsiStr);

    writeln(AnsiStr); //wird korrekt angezeigt

    readln; //Nach Drücken der Enter Taste zum Beenden meines Programmes kommt die Exceptioen EAccessviolation.
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.
Warum wird da diese Exception geworfen, was muss ich da anders machen?



Ist zwar ein uralter Thread, aber dessen Thema passt so gut zu meinem Problem.

.

Geändert von delphifan2004 (21. Okt 2020 um 13:17 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.339 Beiträge
 
Delphi 12 Athens
 
#3

AW: String zu PAnsiChar

  Alt 21. Okt 2020, 13:18
Zitat:
Delphi-Quellcode:
procedure AnsiStrToPWideChar(aStr: AnsiString; var pwChr: LPCWSTR);
var ws: WideString;
begin
  ws := aStr;
  pwChr := LPCWSTR(ws);
end;
Wozu soeine Funktion? Direkt der Cast reicht ja
In der Funktion gibt es die Variable ws.
Der zurückgegeben Zeiger zeigt auf diesen String und jener wird am Ende der Funktion natürlich freigegeben, womit der Pointer auf etwas zeigt, wo "nichts" mehr ist. (womöglich ist inzwischen sogar schon irgendwas Anderes dort)

Zitat:
move(wchr,ws,StrLen(pwChr));
Und hier wird der Speicher der Zeiger kopiert, anstatt des Inhalts, womit natürlich hinter der Variable alles kaputt gemacht wird, weil der Pointer nur 4 Byte groß ist. -> Buffer-Overflow

Außerdem wird hier nur die Hälfte der Bytes kopiert, da WideChar jeweils 2 Byte groß ist.



Sollen PChars "länger" bestehen, dann muß auch der referenzierte Speicher so lange existieren.
* man fummelt an der Referenzzählung der Strings rum
* oder man reserviert Speicher für die Chars, worauf der PChar dann zeigt (am ende natürlich wieder freigeben)
Ein Therapeut entspricht 1024 Gigapeut.

Geändert von himitsu (21. Okt 2020 um 13:23 Uhr)
  Mit Zitat antworten Zitat
delphifan2004

Registriert seit: 26. Nov 2004
Ort: Dresden
277 Beiträge
 
Delphi 10.3 Rio
 
#4

AW: String zu PAnsiChar

  Alt 21. Okt 2020, 20:53
Ok! Danke @himitsu. Hab das jetzt auch mit Casting gemacht. Damit funktioniert es wie ich will.
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:01 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz