ďťż

Ładny brzuch

J.w., jak można to zrobić?

Konkretnie chodzi mi o wywołanie kompilatora G++. Próbowałem zarówno ShellExecute
ShellExecute(0, 'open', PChar(ExtractFilePath(Application.ExeName) + 'MinGW\bin\g++.exe'), PChar('"' + sciezka_pliku_cpp + '" -o "' + sciezka_do_tworzonego pliku_exe + '"'), nil, SW_SHOW);
jak i WinExec,
WinExec(PAnsiChar('"' + ExtractFilePath(Application.ExeName) + 'MinGW\bin\g++.exe" "' + sciezka_pliku_cpp + '" -o "' + sciezka_do_tworzonego pliku_exe + '"'), SW_SHOW);
ale żadna z tych funkcji nie działa we właściwy sposób - nie wywołuje okna i nie przeprowadza kompilacji.

W jaki sposób mam wywołać G++?



Spróbuj CreateProcess (opis tutaj). W drugim parametrze podajesz nazwę aplikacji z parametrami. Ponadto musisz odpowiednio zainicjować struktury przekazywane w dwóch ostatnich parametrach.

Dałem:
var SI:TStartupInfo; PI:TProcessInformation; begin CreateProcess(nil, PWideChar(ExtractFilePath(Application.ExeName) + 'MinGW\bin\g++.exe "' + sciezka_pliku_cpp + '" -o "' + sciezka_do_tworzonego pliku_exe + '"'), nil, nil, FALSE, NORMAL_PRIORITY_CLASS, nil, nil, SI, PI);

Ale wykonanie procedury wyrzuca błąd:
Access violation at address 77B84E20 in module 'ntdll.dll'. Read of address 00000007.
Użytkownik sochalewski edytował ten post 28 marzec 2009, 17:38
1. Po co Ci PWideChar() jak potrzeba PChar()?
2. Brakuje Ci na początku:

si.cb:=sizeof(TStartupInfo);
GetStartupInfo(si);
Użytkownik Cyrkiel edytował ten post 28 marzec 2009, 22:01




Teraz działa, dzięki. ;)

Trochę z innej beczki - jak teraz przechwycić treść komunikatów wyświetlanych przez kompilator w DOSowym okienku (przykładowo błędy, etc.) tak, by pojawiły się w programie wq komponencie typu TMemo?

Zainteresuj się funkcjami CreatePipe, SetHandleInformation, PeekNamedPipe, ReadFile, polem hStdOutput struktury TStartupInfo. Ponadto przyda się funkcja CloseHandle.

Kurczę, nie ogarniam. :mellow:
Mógłbyś dać jakiś konkretniejszy przykład? ;)

:pomocy:

Kiedyś pisałem coś takiego (kod w C, ale łatwo przerobisz na Pascala):

... HANDLE prdout=0; HANDLE pwrout=0; unsigned char rbuf[BUFLEN]; SECURITY_ATTRIBUTES sattr; sattr.nLength=sizeof(SECURITY_ATTRIBUTES); sattr.bInheritHandle=1; sattr.lpSecurityDescriptor=0; if (!CreatePipe(&prdout,&pwrout,&sattr,0)) return 0; //(1) SetHandleInformation(&pwrout,HANDLE_FLAG_INHERIT,0); STARTUPINFO si; memset(&pi,0,sizeof(PROCESS_INFORMATION)); memset(&si,0,sizeof(STARTUPINFO)); si.cb=sizeof(STARTUPINFO); si.hStdError=pwrout; si.hStdOutput=pwrout; //(2) si.hStdInput=GetStdHandle(STD_INPUT_HANDLE); si.dwFlags=STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW; si.wShowWindow=SW_SHOWMINNOACTIVE; if (!CreateProcess(0,nazwa_programu,0,0,1,0,0,0,&si,&pi)) return 0; if (!CloseHandle(pwrout)) return 0; //zamykamy plik do zapisu, o ile pamietam jest to konieczne int readed,total; int ok=PeekNamedPipe(prdout,rbuf,BUFLEN,(DWORD*)&readed,(DWORD*)&total,0); //(3) if (total) ReadFile(prdout,rbuf,BUFLEN,(DWORD*)&readed,0); //(4) //teraz w rbuf mamy to co wyrzucil program do konsoli ... //warto o tym pamietac :P CloseHandle(prdout); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); ...
Działa to mniej więcej tak:
(1) Tworzymy plik do odczytu (prdout) i zapisu (pwrout).
(2) Tutaj przekazujemy procesowi plik do którego ma zapisywać dane.
(3) Przekazujemy dane wytworzone przez uruchomiony program do pliku prdout (do odczytu)
(4) Tutaj odczytujemy z niego do bufora rbuf
Zauważ, że trzeba użyć dwóch uchwytów do pliku - innego do zapisu i innego do odczytu.

Jak chcesz prościej to użyj komponentu, np. TDosCommand ( http://maxxdelphisit...e.fr/doscmd.htm ) lub TUnitedCMD ( http://unitedcrew.or...8...&highlight= ).


Kiedyś pisałem coś takiego (kod w C, ale łatwo przerobisz na Pascala):
Hm, tak łatwo nie poszło. <_<

Linijka
if (!CreatePipe(&prdout,&pwrout,&sattr,0)) return 0;
w Delphi o ile się nie mylę (a C dość słabo ogarniam) powinna wyglądać tak
if CreatePipe(&prdout,&pwrout,&sattr,0) then exit;.
Jeśli mam rację, to wyrzuca ona błąd
E2010 Incompatible types: \'PSecurityAttributes\' and \'_SECURITY_ATTRIBUTES\'.

//Okej, ogarnąłem.
var sattr: TSecurityAttributes; SI: TStartupInfo; PI: TProcessInformation; prdout, pwrout: THandle; WasOK: Boolean; BytesRead: Cardinal; Line: String; Buffer: array[0..255] of Char; begin Application.ProcessMessages; with sattr do begin nLength := SizeOf(sattr); bInheritHandle := True; lpSecurityDescriptor := nil; end; // create pipe for standard output redirection CreatePipe(prdout, // read handle pwrout, // write handle @sattr, // security attributes 0 // number of bytes reserved for pipe - 0 default ); try // Make child process use pwrout as standard out, // and make sure it does not show on screen. with SI do begin FillChar(SI, SizeOf(SI), 0); cb := SizeOf(SI); dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES; wShowWindow := SW_HIDE; hStdInput := GetStdHandle(STD_INPUT_HANDLE); // don't redirect stdinput hStdOutput := pwrout; hStdError := pwrout; end; // launch the command line compiler WasOK := CreateProcess(nil, PChar('"' + ExtractFilePath(Application.ExeName) + 'MinGW\bin\g++.exe" "' + sciezka_do_pliku_cpp + '" -o "' + sciezka_do_pliku_exe + '"'), nil, nil, True, 0, nil, nil, SI, PI); // Now that the handle has been inherited, close write to be safe. // We don't want to read or write to it accidentally. CloseHandle(pwrout); // if process could be created then handle its output if not WasOK then raise Exception.Create('Could not execute command line!') else try // get all output until dos app finishes Line := ''; repeat // read block of characters (might contain carriage returns and line feeds) WasOK := ReadFile(prdout, Buffer, 255, BytesRead, nil); // has anything been read? if BytesRead > 0 then begin // finish buffer to PChar Buffer[BytesRead] := #0; // combine the buffer with the rest of the last run Line := Line + Buffer; end; until not WasOK or (BytesRead = 0); // wait for console app to finish (should be already at this point) WaitForSingleObject(PI.hProcess, INFINITE); finally // Close all remaining handles CloseHandle(PI.hThread); CloseHandle(PI.hProcess); end; finally CloseHandle(prdout); end; Memo1.Lines.Clear; Memo1.Lines[1]:=Line; end;

Problem jest jednak z tym, że w wypadku kodu, który zawiera błąd, Memo zamiast wyświetlić coś sensownego pokazuje jakieś chińskie znaczki. :(
Użytkownik sochalewski edytował ten post 29 marzec 2009, 18:45
W Pascalu używa się (jak sądzę) do pobrania adresu operatora @ (zamiast & jak to jest w C).
Więc raczej (przy okazji warunek był zły) napisz
if not CreatePipe(@prdout,@pwrout,@sattr,0) then exit;
Zresztą porównaj kod do którego link zamieścił Narwany Operator Kombajnu. (np. linia 196)

Dałem edita u góry.

  • zanotowane.pl
  • doc.pisz.pl
  • pdf.pisz.pl
  • zsf.htw.pl
  •