[Delphi] Wyjście aplikacji konsolowej a Unicode.

[Delphi] Wyjście aplikacji konsolowej a Unicode.
ZB
  • Rejestracja:około 19 lat
  • Ostatnio:9 miesięcy
0

Witam!

Niedawno przesiadłem się na Delphi 2010 i już pojawił się pierwszy problem z Unicode.
Przy pomocy mojego programu, uruchamiam zewnętrzną aplikację konsolową, a następnie przechwytuję jej wyjście, a przynajmniej takie jest założenie ;).
Niestety jestem marnym programistą, więc przy tym muszę posługiwać się modułem Redirect Console, napisanym przez Sonic'a (do ściągnięcia ze strony torry.net).

Kod modułu RedirectConsole.pas:

Kopiuj
unit RedirectConsole;

interface

const
  CRLF=#13#10;

var
  RC_SendBuf: string;
  RC_End: Boolean;
  RC_ExitCode: Cardinal;

procedure RC_Run(Command: string);
procedure RC_LineIn(s: string);
var       RC_LineOut: procedure(s: string);

implementation

uses Windows, Forms;

procedure RC_LineIn(s: string);
begin
  RC_SendBuf:=RC_SendBuf+s+CRLF;
end; // RC_LineIn;

function IsWinNT: Boolean;
var osv: tOSVERSIONINFO;
begin
  osv.dwOSVersionInfoSize:=sizeof(osv);
  GetVersionEx(osv);
  result:=osv.dwPlatformID=VER_PLATFORM_WIN32_NT;
end; // IsWinNT

procedure SplitLines(s: string);
var t: string;
begin
  while pos(CRLF, s)<>0 do begin
    t:=copy(s, 1, pos(CRLF, s)-1);
    RC_LineOut(t);
    delete(s, 1, pos(CRLF, s)+1);
  end;
  if length(s)>0 then RC_LineOut(s);
end; // SplitLines

procedure RC_Run(Command: string);
const bufsize=1024; // 1KByte buffer
var
  buf: array [0..bufsize-1] of char;
  si: tSTARTUPINFO;
  sa: tSECURITYATTRIBUTES;
  sd: tSECURITYDESCRIPTOR;
  pi: tPROCESSINFORMATION;
  newstdin, newstdout, read_stdout, write_stdin: tHandle;
  bread, avail: dword;
begin
  // Configuraciones de seguridad para WinNT
  if IsWinNT then begin
    InitializeSecurityDescriptor(@sd, SECURITY_DESCRIPTOR_REVISION);
    SetSecurityDescriptorDacl(@sd, true, nil, false);
    sa.lpSecurityDescriptor:=@sd;
  end else sa.lpSecurityDescriptor:=nil;
  // Creamos Pipe A
  if not CreatePipe(newstdin, write_stdin, @sa, 0) then begin
    RC_LineOut('Error creating Pipe A');
    exit;
  end;
  // Creamos Pipe B
  if not CreatePipe(read_stdout, newstdout, @sa, 0) then begin
    RC_LineOut('Error creating Pipe B');
    CloseHandle(newstdin);
    CloseHandle(write_stdin);
    exit;
  end;
  // Configuramos si
  GetStartupInfo(si);
  si.dwFlags:=STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;
  si.wShowWindow:=SW_HIDE;
  si.hStdOutput:=newstdout;
  si.hStdError:=newstdout;
  si.hStdInput:=newstdin;
  // Creamos proceso
  if not CreateProcess(PChar(command), nil, nil, nil, true,
    CREATE_NEW_CONSOLE, nil, nil, si, pi) then begin
    RC_LineOut('Error creating process: '+command);
    CloseHandle(newstdin);
    CloseHandle(newstdout);
    CloseHandle(read_stdout);
    CloseHandle(write_stdin);
    exit;
  end;
  // Loop principal
  fillchar(buf, sizeof(buf), 0);
  RC_End:=false;
  RC_SendBuf:='';
  repeat
    // application.processmessages;
    Application.HandleMessage;
    GetExitCodeProcess(pi.hProcess, RC_ExitCode);
    if (RC_ExitCode<>STILL_ACTIVE) then RC_End:=True;
    PeekNamedPipe(read_stdout, @buf, bufsize, @bread, @avail, nil);
    // Comprobamos texto de salida
    if (bread<>0) then begin
      fillchar(buf, bufsize, 0);
      if (avail>bufsize) then
        while (bread>=bufsize) do begin
          ReadFile(read_stdout, buf, bufsize, bread, nil);
          SplitLines(buf);
          fillchar(buf, bufsize, 0);
        end
      else begin
        ReadFile(read_stdout, buf, bufsize, bread, nil);
        SplitLines(buf);
      end;
    end;
    // Comprobamos texto de entrada
    while (Length(RC_SendBuf)>0) do begin
      WriteFile(write_stdin, RC_SendBuf[1], 1, bread, nil);
      Delete(RC_SendBuf, 1, 1);
    end;
  until RC_End;
  // Cerramos las cosas
  CloseHandle(pi.hThread);
  CloseHandle(pi.hProcess);
  CloseHandle(newstdin);
  CloseHandle(newstdout);
  CloseHandle(read_stdout);
  CloseHandle(write_stdin);
end; // RC_Run

end.

Jednak ze względu na Unicode w Delphi 2010, zamiast normalnych liter dostaję w moim programie krzaczki w stylu: "楍牣獯景⁴楗摮睯⁳". Próbowałem coś z tym zrobić, próbowałem różnych funkcji do konwersji znaków znalezionych w necie, niektórzy wręcz sugerowali, żeby zmienić czcionkę w komponencie wyświetlającym wynik, jednak nic z tych rzeczy nie pomaga, a mój poziom wiedzy nie pozwala mi wybrnąć z tego problemu. Sam kod Redirect Console jest dla mnie zbyt skomplikowany, żebym mógł z niego cokolwiek wywnioskować. Próbowałem modyfikować na różne sposoby zmienną s w procedurze SplitLines (ona zawiera przechwycony tekst, więc chyba właśnie ją powinienem przekonwertować na Unicode ?), jednak wszystkie moje próby okazały się bezskuteczne.
Tak więc, czy mógłby ktoś bardziej doświadczony w tym temacie, pomóc mi dostosować ten kod do standardów Unicode ?

Z góry dziękuję za odpowiedzi
Pozdrawiam

olesio
  • Rejestracja:prawie 17 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Szczecin
  • Postów:4191
0

Te komponenty też mają dla mnie skomplikowany kod,
a przynajmniej taki, w który nie wnikałem, ale spróbuj:
TDosCommand lub tego, ktory nazywa się o ile dobrze
pamiętam UnitedCmd. Może z nimi będzie ok. Chociaż
z tego co wiem - powstały dla wcześniejszych Delphi.


Pozdrawiam.
ZB
  • Rejestracja:około 19 lat
  • Ostatnio:9 miesięcy
0

Szukając odpowiedzi na mój problem, spotkałem się właśnie z tymi komponentami i niestety oba nie działają jak należy (pisane były przed wyjściem Delphi z Unicode, o czym zresztą wspomniałeś). Nad tym problemem siedzę już pół dnia i niestety wciąż nie zbliżyłem się nawet do rozwiązania.
Coś czuję, że zbyt szybko odinstalowałem Delphi 7. Na nim ten kod działał bezbłędnie, stąd wiem, że to problem z Unicode.

SA
  • Rejestracja:ponad 14 lat
  • Ostatnio:około 13 lat
  • Postów:28
0

Też przeniosłem się z d7 na d2010 i oczywiście mam identyczny problem xD
Do teraz nie znalazłem rozwiązania dla tego problemu bo między innymi nie miałem syper potrzeby aby przenieść projekt z d7 na 2010.
Mój projekt w d7 działa bez problemu... po poprawieniu i skomplikowaniu problem z tymi znaczkami wydaje się najmniejszym.

Będę śledził ten temat.

PS. sprawdź sobie wpisywanie unicode do stringgrid (np z memo + cyrylica). Wszędzie wyświetla się ok tylko nie w grid-zie. (Wyświetlają się ??? co ciekawe po pobraniu stringu z komórki w edicie cyrylica wyświetlana jest poprawnie.)

Misiekd
  • Rejestracja:ponad 21 lat
  • Ostatnio:ponad 12 lat
  • Postów:7923
0

zamień string na AnsiString


- Ciemna druga strona jest.
- Nie marudź Yoda, tylko jedz tego tosta.
Google NIE GRYZIE!
Pomogłem - kliknij
ZB
  • Rejestracja:około 19 lat
  • Ostatnio:9 miesięcy
0
Misiekd napisał(a)

zamień string na AnsiString

Jeśli chodzi Ci o zmienne, to próbowałem pozamieniać wszystko ze String (czyli w nowym Delphi UnicodeString) na ANSIString, jednak wtedy krzaczki wciąż występowały (choć zmieniały się głównie na pytajniki: "????4???????‹????4???").

ZB
  • Rejestracja:około 19 lat
  • Ostatnio:9 miesięcy
0

Ok, doszedłem do tego :). Jednak po południu się zupełnie inaczej myśli niż w nocy.

Więc tak:

  • zamieniłem wszystkie Stringi na ANSIString (w Delphi 2009+ String to domyślnie UnicodeString).
  • zamieniłem Char na ANSIChar (w Delphi 2009+ Char nie jest już jednobajtowy, domyślnie jest to WideChar)
  • w związku z powyższymi zmianami, program się wykrzaczał. Okazuje się, że w nowych Delphi funkcja CreateProcess zmieniła się, w związku z powyższymi zmianami. Tak więc musiałem użyć funkcji w wersji ANSI, czyli CreateProcessA, a to znowu pociągnęło za sobą kilka prostych zmian w kodzie (głównie używanie funkcji w wersji ANSI, zamiast domyślnych Unicodowych).

Jeśli kogoś interesują wszystkie zmiany, których trzeba dokonać w module Redirect Console, to oto ich lista:

Kopiuj
RC_SendBuf: AnsiString;
procedure RC_Run(Command: AnsiString);
procedure RC_LineIn(s: AnsiString);
var       RC_LineOut: procedure(s: AnsiString);
buf: array [0..bufsize-1] of AnsiChar;
si: tSTARTUPINFOA;
GetStartupInfoA(si);
CreateProcessA(PAnsiChar(command),

Tak przy okazji - znalazłem serię znakomitych artykułów (po angielsku), dzięki którym można szybko podłapać o co chodzi z tym Unicode (dopóki nie zainstalowałem Delphi 2010, to omijałem te tematy):
Część 1
Część 2
Część 3

Dziękuję wszystkim za pomoc, program działa teraz jak należy :).
Pozdrawiam

SA
  • Rejestracja:ponad 14 lat
  • Ostatnio:około 13 lat
  • Postów:28
0

dzieki...okazało sie ze nie trzeba zmieniać CreateProcessw na CreateProcessa
chodziło o buffor: Bufor:array[0..127] of ansichar;

Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)