Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi String zu PAnsiChar (https://www.delphipraxis.net/149446-string-zu-pansichar.html)

Berni68 21. Mär 2010 19:05


String zu PAnsiChar
 
Hallo, auch auf die Gefahr hin, daß ich langsam nerve,
aber ich hab es noch nicht kapiert,

die folgende einfache Prozedur zeigt mein Problem:

Delphi-Quellcode:
procedure TTestForm.Test2Click(Sender: TObject);
var
  s: TStrings;
  i:integer;
  x: array of PAnsiChar;
begin
  s:= TStringList.Create;
  s.Add('#0#');
  s.Add('#1#');
  s.Add('#2#');

  SetLength(x, 3);

  for i:=0 to 2 do x[i]:= PAnsiChar(AnsiString(s[i]));
  for i:=0 to 2 do showmessage(x[i]); // liefert: #2# #2# #2#  WARUM ???????????????????ß

  x[0]:='##0##';
  x[1]:='##1##';
  x[2]:='##2##';
  for i:=0 to 2 do showmessage(x[i]); // -> liefert: ##0## ##1## ##2##

  Finalize(x);
  s.Free;
end;
PAnsiChar(AnsiString(s[i])) war das bisherige Fazit, ist aber offensichtlich nicht richtig oder nicht ausreichend.

Wie bekommt man die Strings von s in das array?

Garfield 21. Mär 2010 19:13

Re: String zu PAnsiChar
 
Delphi-Quellcode:
for i:=0 to 2 do x[i]:= PAnsiChar(AnsiString(s.strings[i]));
müsste richtig sein.

ghost007 21. Mär 2010 19:14

Re: String zu PAnsiChar
 
Servus, zunächst einmal kann das ja gar nich funktionieren, da ein PAnsiChar auf einen Character zeigt, also nur ein Zeichen.
Hab dein Codeschnipsel mal etwas abgewandelt:

Delphi-Quellcode:
procedure TForm1.Button2Click(Sender: TObject);
var
  s: TStrings;
  i:integer;
  x: array of PAnsiString; //hier
begin
  s:= TStringList.Create;
  s.Add('#0#');
  s.Add('#1#');
  s.Add('#2#');

  SetLength(x, 3);

  for i:=0 to 2 do x[i]:= PAnsiString(s[i]); //hier
  for i:=0 to 2 do showmessage(AnsiString(x[i])); //hier

  Finalize(x);
  s.Free;
end;
Die abgeänderten Stellen sind markiert.

daywalker9 21. Mär 2010 19:15

Re: String zu PAnsiChar
 
So funktioniert es:

Delphi-Quellcode:
x[i]:=StrNew(pAnsiChar(AnsiString(s[i])));

Berni68 21. Mär 2010 19:37

Re: String zu PAnsiChar
 
Danke an daywalker9 das ist es!!! :dancer2:

Berni68 21. Mär 2010 19:40

Re: String zu PAnsiChar
 
Jetzt bleibt nur die Frage:

Reicht da
Finalize(x);
oder muß zuvor noch für jedes
StrDispose[i];
her?

daywalker9 21. Mär 2010 19:45

Re: String zu PAnsiChar
 
Es reicht eigentlich wenn du für alle Elemente im Array StrDispose() aufrufst.

Matze 21. Mär 2010 19:57

Re: String zu PAnsiChar
 
Nun habt ihr mich aber neugierig gemacht:
Was sind denn ##0## bzw. ##1## oder ##2##?

Bisher sind mit nur die ASCII-Zeichen wie #10 (= line feed) etc. bekannt. Die genannte Schreibweise ist mir neu.

Berni68 21. Mär 2010 20:18

Re: String zu PAnsiChar
 
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.

delphifan2004 21. Okt 2020 13:13

AW: String zu PAnsiChar
 
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.

.


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:10 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz