Конференция "WinAPI" » одно и тоже консольное приложение работает по разному
 
  • Jeyson © (08.09.09 12:40) [0]
    собственно вот в чем дело, сделал на делфи программу которая запускает консольное приложение, которое в свое время связывается с сервером, так вот проблема в том что когда консольное приложение не может связаться с сервером то мне выдается ее результат на экран, а вот когда она связывается с сервером то результата не дождаться, хотя там спрашивают "Хотите зарегистрироваться", может что то упустил из виду
    var
     Form1: TForm1;

    implementation
    var
        FChildStdoutRd, FChildStdoutWr,FChildStdinRd, FChildStdinWr, Tmp1,Tmp2 :THAndle;

    {$R *.DFM}
    function CreateChildProcess(ExeName, CommadLine: String; StdIn,
     StdOut: THandle): Boolean;
    Var
     piProcInfo: TProcessInformation;
     siStartInfo: TStartupInfo;
    begin
    // Set up members of STARTUPINFO structure.
     ZeroMemory(@siStartInfo, SizeOf(TStartupInfo));
     siStartInfo.cb:=SizeOf(TStartupInfo);
     siStartInfo.hStdInput:=StdIn;
     siStartInfo.hStdOutput:=StdOut;
     siStartInfo.dwFlags:=STARTF_USESTDHANDLES;
    // Create the child process.
      Result:=CreateProcess(Nil,
         'c:\cpp\read.exe',//PChar(ExeName+' '+CommadLine),       // command line
         Nil,          // process security attributes
         Nil,          // primary thread security attributes
         TRUE,          // handles are inherited
         0,             // creation flags
         Nil,          // use parent's environment
         '
    c:\cpp\',          // use parent's current directory
         siStartInfo,  // STARTUPINFO pointer
         piProcInfo);  // receives PROCESS_INFORMATION
    end;

    procedure NewPipe;
    var
       FSaAttr:TSECURITYATTRIBUTES;
    begin
       with (FsaAttr) do
       begin
       FsaAttr.nLength:=SizeOf(SECURITY_ATTRIBUTES);
       FsaAttr.bInheritHandle:=True;
       FsaAttr.lpSecurityDescriptor:=Nil;
       end;
       CreatePipe(FChildStdoutRd, FChildStdoutWr, @FsaAttr, 1);
       CreatePipe(FChildStdinRd, FChildStdinWr, @FsaAttr, 1);
    //Делаем НЕ наследуемые дубликаты
    //Это нужно, чтобы не тащить лишние хэндлы в дочерний процесс...
       DuplicateHandle(GetCurrentProcess(), FChildStdoutRd,
    GetCurrentProcess(), @Tmp1, 0, False, DUPLICATE_SAME_ACCESS);
        DuplicateHandle(GetCurrentProcess(), FChildStdinWr,
    GetCurrentProcess(), @Tmp2, 0, False, DUPLICATE_SAME_ACCESS);
    CloseHandle(FChildStdoutRd);//Закроем наследуемый вариант "Читального" хэндла
    CloseHandle(FChildStdinWr); //Закроем наследуемый вариант "Писального" хэндла
    FChildStdoutRd:=Tmp1;       //И воткнем их места НЕ наследуемые дубликаты
    FChildStdinWr:=Tmp2;        //И воткнем их места НЕ наследуемые дубликаты
    CreateChildProcess('cmd.exe', '', FChildStdinRd, FChildStdoutWr)
    end;

    function WriteToChild(Data: String):
    Boolean;
    Var
     dwWritten, BufSize: DWORD;
     chBuf: PChar;
    begin
    //Обратите внимание на Chr($0D)+Chr($0A)!!! Без них - будет работать с ошибками
    //На досуге - подумайте почему...
    //Для тех, кому думать лень - подскажу - это пара символов конца строки.
    //(вообще-то можно обойтись одним, но так надежнее, программы-то бывают разные)
     chBuf:=PChar(Data+Chr($0D)+Chr($0A));
     BufSize:=Length(chBuf);
     Result:=WriteFile(FChildStdinWr, chBuf^, BufSize, dwWritten, Nil);
     Result:=Result and (BufSize = dwWritten);
    end;

    function ReadStrFromChild(Timeout: Integer): String;
    Var
     i: Integer;
     dwRead, BufSize, DesBufSize: DWORD;
     chBuf: PChar;
     Res: Boolean;
    begin
     Try
       BufSize:=0;
       New(chBuf);
       Repeat
         For i:=0 to 9 do
           begin
             Res:=PeekNamedPipe(FChildStdoutRd, nil, 0, nil, @DesBufSize, nil);
             Res:=Res and (DesBufSize > 0);
             If Res Then
               Break;
             Sleep(Round(Timeout/10));
           end;
         If Res Then
           begin
             If DesBufSize > BufSize Then
               begin
                 FreeMem(chBuf);
                 GetMem(chBuf, DesBufSize);
                 BufSize:=DesBufSize;
               end;
             Res:=ReadFile(FChildStdoutRd, chBuf^, BufSize, dwRead, Nil);
             Result:=Result+ChBuf;
           end;
       Until not Res;
     Except
       Result:='Read Err';
     End;
    end;

    function DosToWin(St: string): string;
    var
     Ch: PChar;
    begin
     Ch := StrAlloc(Length(St) + 1);
     OemToAnsi(PChar(St), Ch);
     Result := Ch;
     StrDispose(Ch)
    end;

    procedure TForm1.Button1Click(Sender: TObject);
    begin
       if not WriteToChild(Edit1.Text) then ShowMessage('error');
       Memo1.Lines.Add(DosToWin(ReadStrFromChild(100)));
    end;

    procedure TForm1.Button2Click(Sender: TObject);
    begin
       Memo1.Lines.Add(DosToWin(ReadStrFromChild(100)));
    end;
    procedure TForm1.FormCreate(Sender: TObject);
    begin
           NewPipe;
          Memo1.Lines.Add(DosToWin(ReadStrFromChild(100)));
    end;

  • Jeyson © (08.09.09 12:51) [1]
    Подключение происходит мгновенно, и при нажатии на кнопку должен появляться в мемо результат
  • Медвежонок Пятачок © (08.09.09 13:25) [2]
    оттрассировать рипит внутри ReadStrFromChild не пробовал?
  • Jeyson © (08.09.09 13:33) [3]
    Пробовал, говорит что пайп пуст, ну то есть нет ничего что можно было бы считать
  • Медвежонок Пятачок © (08.09.09 13:36) [4]
    тогда какие вопросы?
  • Jeyson © (08.09.09 13:38) [5]
    Вопрос как раз в том почему говорит что пайп пуст, ведь там есть что надо считать
  • Медвежонок Пятачок © (08.09.09 13:59) [6]
    Там нет ничего, иначе бы ты вышел из цикла репита.

    Либо запускаемы процесс пишет свой вывод не в тот пайп, либо сам процесс создан так, что ему переданы невалидные хендлы.
  • Jeyson © (08.09.09 14:06) [7]
    а как можно решить эту проблему
  • Медвежонок Пятачок © (08.09.09 14:38) [8]
    включать голову и пробовать локализовать проблему.
    например оттрассировать вывод в пайп в дочернем процессе.
    строка до вызова записи
    строка после вызова, результат записи. сколько записалось, последний гетластеррор после записи и так далее.
  • Jeyson © (08.09.09 14:47) [9]
    дело в том что исходников консольной программы нет
  • Медвежонок Пятачок © (08.09.09 14:51) [10]
    в стдаут она пишет при запуске из командной строки?
    если да, то остается вариант с неправильной передачей хендлов в дочерний процесс
  • Jeyson © (09.09.09 07:54) [11]
    Удалено модератором
    Примечание: Создание пустых сообщений
  • Jeyson © (14.09.09 10:11) [12]
    Удалено модератором
    Примечание: Создание пустых сообщений
  • Дмитрий С © (15.09.09 10:24) [13]
    Может в stderror пишет? На всякий случай мысль.
  • Anatoly Podgoretsky © (15.09.09 14:00) [14]
    Обычное дело.
 
Конференция "WinAPI" » одно и тоже консольное приложение работает по разному
Есть новые Нет новых   [134434   +27][b:0][p:0.004]