Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Console: OEM nach ANSI (https://www.delphipraxis.net/152163-console-oem-nach-ansi.html)

Zacherl 13. Jun 2010 18:10

Console: OEM nach ANSI
 
Hey,

ich lese die Ausgabe einer Konsolenanwendung mit Pipes aus und sende ebenso Eingaben an das Programm. Jetzt muss ich die ausgelesenen Daten von OEM nach ANSI konvertieren, damit Umlaute wie öäüß richtig dargestellt werden können. Momentan versuche ich das folgendermaßen:

Delphi-Quellcode:
function OEM2Ansi(OEMString: AnsiString): AnsiString;
begin
  OEMString := OEMString + #0;
  OemToChar(PAnsiChar(OEMString), @OEMString[1]);
  Delete(OEMString, Length(OEMString), 1);
  Result := OEMString;
end;
Leider hat die Funktion, wie es scheint, einfach komplett keine Wirkung auf meinen ausgelesenen AnsiString. :x
Das hier ist zum Beispiel einer der Problemkandidaten:
Zitat:

S 'dir'#$D#$A' Datentr„ger in Laufwerk C: ist BOOT'#$D#$A'
In die andere Richtung funktioniert es ebenfalls nicht. Wenn ich Ansi2OEM benutze und den String dann über die Pipe an die Konsole schicke, und z.b. einen Ordner namens "ötest" mit mkdir anlege, wird das ö zu irgendeinem komischen Zeichen konvertiert.

Kennt jemand eine Lösung für dieses Problem?

Viele Grüße
Zacherl

DeddyH 13. Jun 2010 18:17

AW: Console: OEM nach ANSI
 
Unter Delphi 2007 funktioniert das hier:
Delphi-Quellcode:
function OEM2ANSI(const aStr: AnsiString): AnsiString;
begin
  Result := aStr;
  OEMToChar(PAnsiChar(Result),PAnsiChar(Result));
end;

Zacherl 13. Jun 2010 18:25

AW: Console: OEM nach ANSI
 
Leider ebenfalls kein Effekt. Ich verstehe das nicht. Ich lese die Daten von der Pipe direkt in einen AnsiString aus. Da sollte es ja auch keine Probleme durch das Unicode Delphi geben.

himitsu 13. Jun 2010 18:31

AW: Console: OEM nach ANSI
 
Wie ließt du denn die Daten genau aus? (also kompletter Code)

Seit Delphi 2009 wird blöder Weise oftmals im String direkt die CodePage gespeichert, welches Probleme bereiten kann, wenn man selber die CodePage ändert und dieses nicht anpaßt.


z.B. dieses reagiert seit D2009 nicht mehr so wie ich es mir denke (es wird kein UTF-8-kodierter Text angezeigt :wall: )
Delphi-Quellcode:
var
  A: AnsiString;
  S: String;

A := UTF8Encode('äöü');
S := A;
ShowMessage(S);

Zacherl 13. Jun 2010 19:00

AW: Console: OEM nach ANSI
 
Delphi-Quellcode:
function ShellReadThread(lpParam: Pointer): Cardinal;
var
  ExitCode: Cardinal;
  BytesRead: DWord;
  Buffer: array[0..1024 * 8 - 1] of AnsiChar;
begin
  while (not Terminated) do
  begin
    GetExitCodeProcess(FProcessInfo.hProcess, ExitCode);
    if (ExitCode <> STILL_ACTIVE) then
    begin
      Terminate;
      Break;
    end;
    if (ReadFile(hoRead, Buffer[0], Length(Buffer), BytesRead, nil)) and
      (BytesRead > 0) then
    begin
      SendPriorityCommand(ParentThread.IDTPWriter, CMDS_SHELLOUTPUT,
        @Buffer[0], BytesRead, true);
    end;
    Sleep(50);
  end;
  Result := 0;
end;
Wie man sieht landen die Daten direkt in einem ByteArray. Wenn ich die Daten an OEM2ANSI übergebe, wird das Teil halt zwangsweise kurzzeitig in einen AnsiString konvertiert.

Zacherl 13. Jun 2010 19:13

AW: Console: OEM nach ANSI
 
Okay fail :| Ich hatte das ByteArray zu Testzwecken in ein array of AnsiChar geändert. Daran lags wohl, auch wenn ich nicht verstehe warum. Allerdings gibt es nun ein weiteres Problem:

Delphi-Quellcode:
function OEM2Ansi(Value: AnsiString): String;
begin
  Result := Value;
  OEMToChar(PAnsiChar(Value), PChar(Result));
end;
Die Umlaute werden nun korrekt umgewandelt, aber als "netter" Nebeneffekt werden alle enthaltenen Zeilenumbrüche (#13#10) in irgendeinen Quatsch konvertiert :wall:

Zitat:

'dir?? Datenträger in Laufwerk C: ist BOOT??'

omata 13. Jun 2010 19:17

AW: Console: OEM nach ANSI
 
Also ich habe das so gelöst...
Delphi-Quellcode:
function Oem2Ansi(AText:AnsiString):AnsiString;
const cMaxLength = 255;
var PText : PAnsiChar;
begin
  Result:='';
  PText:=AnsiStrAlloc(cMaxLength);
  while AText <> '' do begin
    StrPCopy(PText, copy(AText, 1, cMaxLength-1));
    OemToAnsi(PText, PText);
    Result:=Result + StrPas(PText);
    delete(AText, 1, cMaxLength-1);
  end;
  StrDispose(PText);
end;
Und ab Delphi2009...
Delphi-Quellcode:
function Convert(Data:AnsiString):string;
begin
  Data:=Oem2Ansi(Data);
  {$WARNINGS OFF}
  Result:=AnsiToUtf8(Data);
  {$WARNINGS ON}
end;

himitsu 13. Jun 2010 19:22

AW: Console: OEM nach ANSI
 
Du könntest statt dem CharToOem einfach mal SetFileApisToOEM versuchen.

> MSDN-Library durchsuchenSetFileApisToOEM, MSDN-Library durchsuchenSetFileApisToANSI und MSDN-Library durchsuchenAreFileApisANSI



Meckert dein Delphi 2009+ eigentlich nicht über den Ansi-Unicode-Mischmasch?

Für AnsiString mußt du OemToCharA verwenden.
Delphi-Quellcode:
function OEM2Ansi(const OEMString: AnsiString): AnsiString;
begin
  Result := OEMString;
  if Result <> '' then
    OemToCharA(PAnsiChar(Result), PAnsiChar(Result));
end;
oder mal so versuchen:
Delphi-Quellcode:
function OEM2Ansi(const OEMString: AnsiString): AnsiString;
begin
  Result := OEMString;
  if Result = '' then Exit;
  OemToCharA(PAnsiChar(Result), PAnsiChar(Result));
  PWord(Integer(Result) - 12)^ := 0;
end;


PS
Delphi-Quellcode:
type
  PStrRec = ^StrRec;
  StrRec = packed record
    codePage: Word;
    elemSize: Word;
    refCnt: Longint;
    length: Longint;
  end;
  OEMString = type AnsiString(CP_OEMCP);

procedure TForm5.FormCreate(Sender: TObject);
var A: AnsiString;
begin
  A := UTF8Encode('äöü');
  ShowMessage(A);
  {$IF CompilerVersion >= 20.0}
    if A <> '' then PStrRec(Integer(A) - SizeOf(StrRec)).codePage := CP_NONE;
    ShowMessage(A);
  {$IFEND}

  A := 'äöü';
  UniqueString(A); // Konstante in Variable umwandeln
  CharToOemA(PAnsiChar(A), PAnsiChar(A));
  {$IF CompilerVersion >= 20.0}
  //if A <> '' then PStrRec(Integer(A) - SizeOf(StrRec)).codePage := CP_NONE;
    ShowMessage(A);
    if A <> '' then PStrRec(Integer(A) - SizeOf(StrRec)).codePage := CP_OEMCP;
  {$IFEND}
  ShowMessage(A);
end;
Delphi-Quellcode:
var S: AnsiString;

SetString(S, P, BytesRead);         // von PAnsiChar
//SetString(S, @Buf[0], BytesRead); // von AnsiChar-Array
if S <> '' then PWord(Integer(S) - 12)^ := CP_OEMCP;
// und schon wandelt Delphi automatisch die Codepage um

ShowMessage(A);
Delphi-Quellcode:
var S: AnsiString;

SetString(S, P, BytesRead);         // von PAnsiChar
//SetString(S, @Buf[0], BytesRead); // von AnsiChar-Array
if S <> '' then PWord(Integer(S) - 12)^ := CP_OEMCP;

ShowMessage(A);
und schon wandelt Delphi automatisch die Codepage um, wenn dieser AnsiString z.B. an einen String/UnicodeString übergeben wird.
(also ab Delphi 2009)

Zacherl 13. Jun 2010 20:07

AW: Console: OEM nach ANSI
 
Argh in der ganzen Hektik habe ich tatsächlich nicht bemerkt, dass ich die Unicode Funktion aufgerufen habe. Der Compiler hat lustigerweise auch nicht gemeckert :mrgreen: Jetzt klappt aber alles. Vielen Dank :thumb:


Alle Zeitangaben in WEZ +1. Es ist jetzt 20:01 Uhr.

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