Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "WinAPI";
Текущий архив: 2002.08.26;
Скачать: [xml.tar.bz2];

Вниз

почему не работает сие ?   Найти похожие ветки 

 
Polevi   (2002-06-22 21:03) [0]

Господа, помогите найти ошибку..
У меня складывается впечатление что CreateProcess игнорирует StartupInfo - si.wShowWindow:=SW_MINIMIZE не приводит к нужному результату.. Хендлы видимо тоже не подменяются - пайп пуст, почему ??

procedure TForm1.Button1Click(Sender: TObject);
var
si:StartupInfo;
pi:Process_Information;
sa:Security_Attributes;
bytesRead:DWORD;
readHandle,writeHandle:THandle;
buffer:Pointer;
begin
sa.nLength:=sizeof(Security_Attributes);
sa.lpSecurityDescriptor:=nil;
sa.bInheritHandle:=true;

if not CreatePipe(readHandle,writeHandle,@sa,0) then ShowMessage("cant create pipe");

GetStartupInfo(si);
si.cb:=sizeof(StartupInfo);
si.dwFlags:=STARTF_USESHOWWINDOW and STARTF_USESTDHANDLES;
si.wShowWindow:=SW_MINIMIZE;
si.hStdOutput:=writeHandle;
si.hStdError:=writeHandle;

if not CreateProcess(nil,PChar("c:\windows\ping.exe"),nil,nil,true,
0,nil,nil,si,pi) then ShowMessage("cant create process");

CloseHandle(writeHandle);

GetMem(buffer,1024);
if not ReadFile(readHandle,buffer,1024,bytesRead,nil) then ShowMessage("cant read from pipe");
end;


PS
Не знаю как у вас, у меня данный код приводит к "cant read from pipe"


 
Polevi   (2002-06-22 23:08) [1]

блин
si.dwFlags:=STARTF_USESHOWWINDOW and STARTF_USESTDHANDLES;
хехе, энд с ором перепутал :-)))

надо так
si.dwFlags:=STARTF_USESHOWWINDOW OR STARTF_USESTDHANDLES;


 
Юрий Зотов   (2002-06-23 08:41) [2]

Если убрать подозрительную (слишком раннее освобождение хэндла) строку

CloseHandle(writeHandle);

то сообщение "cant read from pipe" исчезает, а программа начинает как бы "зависать". На самом деле она, видимо, не зависает, а просто синхронныый вызов ReadFile ждет своих 1024 байт в буфере - то есть, все работает так, как и должно.

Похоже, копать надо в этом направлении. Если хотите, могу привести пример из MSDN на эту тему (на Си, естественно).

В коде куча возможностей для утечки ресурсов. Для теста сойдет, для рабочей программы - ни в коем случае. Надеюсь, Вы об этом и без меня знаете.


 
Polevi   (2002-06-23 11:50) [3]

Уважаемый Юрий Зотов, возможно вы сможете объяснить мне мою ошибку.
Происходит непонятная штука - если ReadFile возвращает false - поток принудительно завершается (не попадаю даже в секцию finally) - причем данные читаются корректно, пока они есть в пайпе.

И почему не получается в качестве WaitObject указываю хендл пайпа ? Хочется получать данные из консоли во время работы консольного приложения а не после его завершения. Или это невозможно в принципе ?

Буду рад любой информации.

unit console;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

type
TConsole=class(TThread)
private
FCommandLine:string;
FOutputStream:TMemoryStream;
procedure ShowResult;
public
constructor Create(ACommandLine:string);
procedure Execute;override;
end;

implementation

{ TConsole }

uses unit1;

constructor TConsole.Create(ACommandLine: string);
begin
inherited Create(true);
FreeOnTerminate:=true;
FCommandLine:=ACommandLine;
Resume;
end;

procedure TConsole.Execute;
var
readHandle,writeHandle:THandle;
si:StartupInfo;
pi:Process_Information;
sa:Security_Attributes;
msg: TMsg;
WaitTime: DWord;
buffer:Pointer;
bufferSize:integer;
bytesRead:DWORD;
WaitObject:THandle;
begin
FOutputStream:=TMemoryStream.Create;
bufferSize:=16384;
GetMem(buffer,bufferSize);

sa.nLength:=sizeof(Security_Attributes);
sa.lpSecurityDescriptor:=nil;
sa.bInheritHandle:=true;
CreatePipe(readHandle,writeHandle,@sa,bufferSize);

GetStartupInfo(si);
si.cb:=sizeof(StartupInfo);
si.dwFlags:=STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
si.wShowWindow:=SW_HIDE;
si.hStdOutput:=writeHandle;
si.hStdError:=writeHandle;
si.hStdInput:=GetStdHandle(STD_INPUT_HANDLE);

CreateProcess(nil,PChar(FCommandLine),nil,nil,true,0,nil,nil,si,pi);
WaitObject:=pi.hProcess;
try
PeekMessage(msg, 0, WM_USER, WM_USER, PM_NOREMOVE);
WaitTime := INFINITE;
while not Terminated do
try
case MsgWaitForMultipleObjects(1, WaitObject, False, WaitTime, QS_ALLEVENTS) of
WAIT_OBJECT_0:
begin
FOutputStream.Clear;
while true do
begin
if not ReadFile(readHandle,buffer^,bufferSize,bytesRead,nil) then break;
FOutputStream.Write(buffer^,bytesRead);
end;
if FOutputStream.Size>0 then Synchronize(ShowResult);
end;
WAIT_OBJECT_0 + 1:
while PeekMessage(msg, 0, 0, 0, PM_REMOVE) do
DispatchMessage(msg);
WAIT_TIMEOUT:
end;
except
Terminate;
end;
finally
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
FOutputStream.Free;
FreeMem(buffer);
end;
end;

procedure TConsole.ShowResult;
begin
Form1.Memo1.Lines.Add(PChar(FOutputStream.Memory));
end;

end.


 
MBo   (2002-06-23 11:57) [4]

>Polevi
На master-brain.boom.ru есть DosCommand, посмотри, как там сделано, IMHO, весьма прилично.


 
Юрий Зотов   (2002-06-23 12:27) [5]

Не работал я с пайпами, не доводилось. В файл - перенаправлял, и вполне успешно, а вот в пайп - нет. Поэтому судить не берусь, а лучше приведу тот самый пример из MSDN. Пример большой, разбиваю на 4 части.

Creating a Child Process with Redirected Input and Output

The example in this topic demonstrates how to create a child process from a console process. It also demonstrates a technique for using anonymous pipes to redirect the child process"s standard input and output handles.

The CreatePipe function uses the SECURITY_ATTRIBUTES structure to create inheritable handles to the read and write ends of two pipes. The read end of one pipe serves as standard input for the child process, and the write end of the other pipe is the standard output for the child process. These pipe handles are specified in the SetStdHandle function, which makes them the standard handles inherited by the child process. After the child process is created, SetStdHandle is used again to restore the original standard handles for the parent process.

The parent process uses the other ends of the pipes to write to the child process"s input and read the child process"s output. The handles to these ends of the pipe are also inheritable. However, the handle must not be inherited. Before creating the child process, the parent process must use DuplicateHandle to create a duplicate of the application-defined hChildStdinWr global variable that cannot be inherited. It then uses CloseHandle to close the inheritable handle. For more information, see Pipes.


 
Юрий Зотов   (2002-06-23 12:29) [6]

The following is the parent process.


#include <stdio.h>
#include <windows.h>

#define BUFSIZE 4096

HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup,
hInputFile, hSaveStdin, hSaveStdout;

BOOL CreateChildProcess(VOID);
VOID WriteToPipe(VOID);
VOID ReadFromPipe(VOID);
VOID ErrorExit(LPTSTR);
VOID ErrMsg(LPTSTR, BOOL);

DWORD main(int argc, char *argv[])
{
SECURITY_ATTRIBUTES saAttr;
BOOL fSuccess;

// Set the bInheritHandle flag so pipe handles are inherited.

saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;

// The steps for redirecting child process"s STDOUT:
// 1. Save current STDOUT, to be restored later.
// 2. Create anonymous pipe to be STDOUT for child process.
// 3. Set STDOUT of the parent process to be write handle to
// the pipe, so it is inherited by the child process.
// 4. Create a noninheritable duplicate of the read handle and
// close the inheritable read handle.

// Save the handle to the current STDOUT.

hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE);

// Create a pipe for the child process"s STDOUT.

if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0))
ErrorExit("Stdout pipe creation failed\n");

// Set a write handle to the pipe to be STDOUT.

if (! SetStdHandle(STD_OUTPUT_HANDLE, hChildStdoutWr))
ErrorExit("Redirecting STDOUT failed");

// Create noninheritable read handle and close the inheritable read
// handle.

fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
GetCurrentProcess(), &hChildStdoutRdDup , 0,
FALSE,
DUPLICATE_SAME_ACCESS);
if( !fSuccess )
ErrorExit("DuplicateHandle failed");
CloseHandle(hChildStdoutRd);

// The steps for redirecting child process"s STDIN:
// 1. Save current STDIN, to be restored later.
// 2. Create anonymous pipe to be STDIN for child process.
// 3. Set STDIN of the parent to be the read handle to the
// pipe, so it is inherited by the child process.
// 4. Create a noninheritable duplicate of the write handle,
// and close the inheritable write handle.

// Save the handle to the current STDIN.

hSaveStdin = GetStdHandle(STD_INPUT_HANDLE);

// Create a pipe for the child process"s STDIN.

if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0))
ErrorExit("Stdin pipe creation failed\n");



 
Юрий Зотов   (2002-06-23 12:31) [7]


// Set a read handle to the pipe to be STDIN.

if (! SetStdHandle(STD_INPUT_HANDLE, hChildStdinRd))
ErrorExit("Redirecting Stdin failed");

// Duplicate the write handle to the pipe so it is not inherited.

fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
GetCurrentProcess(), &hChildStdinWrDup, 0,
FALSE, // not inherited
DUPLICATE_SAME_ACCESS);
if (! fSuccess)
ErrorExit("DuplicateHandle failed");

CloseHandle(hChildStdinWr);

// Now create the child process.

if (! CreateChildProcess())
ErrorExit("Create process failed");

// After process creation, restore the saved STDIN and STDOUT.

if (! SetStdHandle(STD_INPUT_HANDLE, hSaveStdin))
ErrorExit("Re-redirecting Stdin failed\n");

if (! SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout))
ErrorExit("Re-redirecting Stdout failed\n");

// Get a handle to the parent"s input file.

if (argc > 1)
hInputFile = CreateFile(argv[1], GENERIC_READ, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
else
hInputFile = hSaveStdin;

if (hInputFile == INVALID_HANDLE_VALUE)
ErrorExit("no input file\n");

// Write to pipe that is the standard input for a child process.

WriteToPipe();

// Read from pipe that is the standard output for child process.

ReadFromPipe();

return 0;
}

BOOL CreateChildProcess()
{
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;


 
Юрий Зотов   (2002-06-23 12:32) [8]


// Set up members of the PROCESS_INFORMATION structure.

ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );

// Set up members of the STARTUPINFO structure.

ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
siStartInfo.cb = sizeof(STARTUPINFO);

// Create the child process.

return CreateProcess(NULL,
"child", // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
0, // creation flags
NULL, // use parent"s environment
NULL, // use parent"s current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo); // receives PROCESS_INFORMATION
}

VOID WriteToPipe(VOID)
{
DWORD dwRead, dwWritten;
CHAR chBuf[BUFSIZE];

// Read from a file and write its contents to a pipe.

for (;;)
{
if (! ReadFile(hInputFile, chBuf, BUFSIZE, &dwRead, NULL) ||
dwRead == 0) break;
if (! WriteFile(hChildStdinWrDup, chBuf, dwRead,
&dwWritten, NULL)) break;
}

// Close the pipe handle so the child process stops reading.

if (! CloseHandle(hChildStdinWrDup))
ErrorExit("Close pipe failed\n");
}

VOID ReadFromPipe(VOID)
{
DWORD dwRead, dwWritten;
CHAR chBuf[BUFSIZE];
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);

// Close the write end of the pipe before reading from the
// read end of the pipe.

if (!CloseHandle(hChildStdoutWr))
ErrorExit("Closing handle failed");

// Read output from the child process, and write to parent"s STDOUT.

for (;;)
{
if( !ReadFile( hChildStdoutRdDup, chBuf, BUFSIZE, &dwRead,
NULL) || dwRead == 0) break;
if (! WriteFile(hSaveStdout, chBuf, dwRead, &dwWritten, NULL))
break;
}
}

VOID ErrorExit (LPTSTR lpszMessage)
{
fprintf(stderr, "%s\n", lpszMessage);
ExitProcess(0);
}

// The code for the child process.

#include <windows.h>
#define BUFSIZE 4096

VOID main(VOID)
{
CHAR chBuf[BUFSIZE];
DWORD dwRead, dwWritten;
HANDLE hStdin, hStdout;
BOOL fSuccess;

hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
hStdin = GetStdHandle(STD_INPUT_HANDLE);
if ((hStdout == INVALID_HANDLE_VALUE) ||
(hStdin == INVALID_HANDLE_VALUE))
ExitProcess(1);

for (;;)
{
// Read from standard input.
fSuccess = ReadFile(hStdin, chBuf, BUFSIZE, &dwRead, NULL);
if (! fSuccess || dwRead == 0)
break;

// Write to standard output.
fSuccess = WriteFile(hStdout, chBuf, dwRead, &dwWritten, NULL);
if (! fSuccess)
break;
}
}


 
Polevi   (2002-06-23 16:16) [9]

2Mbo
Посмотрел я код, по моему ничего хорошего, каша какая-то :-)

2Юрий Зотов ©
Спасибо, это вроде то что нужно.

Переделал я код, читает отлично, а вот писать чтото не желает в консоль. У меня уже мозги пухнут, больше не могу :-)
Если будет время и желание - посмотрите, наверняка опять где-нибудь энд с ором перепутал :-))


 
Polevi   (2002-06-23 16:17) [10]

unit console;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

const WM_SENDLINE=WM_USER+100;

type
TConsole=class(TThread)
private
FCommandLine:string;
FLine:string;
FOutputStream:TMemoryStream;
hChildStdOutReadDup,hChildStdInWriteDup:THandle;
hSaveStdOut,hSaveStdIn:THandle;
hChildStdOutRead,hChildStdOutWrite:THandle;
hChildStdInRead,hChildStdInWrite:THandle;

procedure ShowResult;
procedure ReadData(AHandle:THandle);
procedure WriteData(AHandle:THandle);
public
constructor Create(ACommandLine:string);
procedure Execute;override;
procedure SendLine(ALine:string);
end;

implementation

{ TConsole }

uses unit1;

constructor TConsole.Create(ACommandLine: string);
begin
inherited Create(true);
FreeOnTerminate:=true;
FCommandLine:=ACommandLine;
Resume;
end;

procedure TConsole.Execute;
var
si:StartupInfo;
pi:Process_Information;
sa:Security_Attributes;
msg: TMsg;
WaitTime: DWord;
WaitObject:THandle;
begin
FOutputStream:=TMemoryStream.Create;

sa.nLength:=sizeof(Security_Attributes);
sa.lpSecurityDescriptor:=nil;
sa.bInheritHandle:=true;

hSaveStdOut:= GetStdHandle(STD_OUTPUT_HANDLE);
CreatePipe(hChildStdOutRead,hChildStdOutWrite,@sa,0);
SetStdHandle(STD_OUTPUT_HANDLE, hChildStdOutWrite);
DuplicateHandle(GetCurrentProcess(), hChildStdOutRead,
GetCurrentProcess(), @hChildStdOutReadDup , 0,
FALSE,
DUPLICATE_SAME_ACCESS);
CloseHandle(hChildStdOutRead);

hSaveStdIn:= GetStdHandle(STD_INPUT_HANDLE);
CreatePipe(hChildStdInRead,hChildStdInWrite,@sa,0);
SetStdHandle(STD_INPUT_HANDLE, hChildStdInWrite);
DuplicateHandle(GetCurrentProcess(), hChildStdInWrite,
GetCurrentProcess(), @hChildStdInWriteDup , 0,
FALSE,
DUPLICATE_SAME_ACCESS);
CloseHandle(hChildStdInWrite);

GetStartupInfo(si);
si.cb:=sizeof(StartupInfo);
CreateProcess(nil,PChar(FCommandLine),nil,nil,true,0,nil,nil,si,pi);

SetStdHandle(STD_INPUT_HANDLE, hSaveStdIn);
SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdOut);

WaitObject:=pi.hProcess;
try
PeekMessage(msg, 0, WM_USER, WM_USER, PM_NOREMOVE);
WaitTime := 500;
while not Terminated do
try
case MsgWaitForMultipleObjects(1, WaitObject, False, WaitTime, QS_ALLEVENTS) of
WAIT_OBJECT_0:
begin
ReadData(hChildStdOutReadDup);
Terminate;
end;
WAIT_OBJECT_0 + 1:
while PeekMessage(msg, 0, 0, 0, PM_REMOVE) do
if msg.message=WM_SENDLINE then WriteData(hChildStdInWriteDup)
else
DispatchMessage(msg);
WAIT_TIMEOUT:
begin
ReadData(hChildStdOutReadDup);
end;
end;
except
Terminate;
end;
finally
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
FOutputStream.Free;
end;
end;

procedure TConsole.ReadData(AHandle:THandle);
var
buffer:Pointer;
bytesRead:DWORD;
begin
GetMem(Buffer,1024);
try
while true do
begin
if not ReadFile(AHandle,buffer^,1024,bytesRead,nil) then break;
FOutputStream.Clear;
FOutputStream.Write(buffer^,bytesRead);
if FOutputStream.Size>0 then Synchronize(ShowResult);
end;
finally
FreeMem(buffer);
end;
end;

procedure TConsole.WriteData(AHandle:THandle);
var
bytesWrite:DWORD;
begin
WriteFile(AHandle,FLine,Length(FLine),bytesWrite,nil);
end;

procedure TConsole.SendLine(ALine: string);
begin
FLine:=ALine+#13#10;
PostThreadMessage(ThreadID,WM_SENDLINE,0,0);
end;

procedure TConsole.ShowResult;
begin
Form1.Memo1.Lines.Add(PChar(FOutputStream.Memory));
end;

end.



Страницы: 1 вся ветка

Форум: "WinAPI";
Текущий архив: 2002.08.26;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.51 MB
Время: 0.006 c
1-85123
kerkonst
2002-08-15 11:02
2002.08.26
Как дождатся конца работы проги, запущенной через ShellExecutе


3-84885
ioRaptor
2002-08-05 10:12
2002.08.26
Использование файла БД IB из программы


1-84947
Александр
2002-08-15 11:16
2002.08.26
Проверка ввода


4-85306
Igit
2002-06-20 20:35
2002.08.26
Работа с реестром


14-85178
Snake2000
2002-07-29 09:21
2002.08.26
http://www.fsgs.com





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский