Я не могу сделать IO с Gawk, используя функцию WINAPI CreateProcess

У меня есть небольшая программа, которая принимает входные данные и выполняет некоторую предварительную обработку, прежде чем продолжить свою деятельность. (Классический случай "сделайте нас программой; о, мы еще не знаем точный формат данных".) Чтобы этот шаг был более пригодным для сценариев, я решил использовать AWK для этапа предварительной обработки (потому что данные будут табличный характер).

Достаточно фона. Это сводится к тому, что я пытаюсь вызвать GAWK с CreateProcess.

  • Я вполне уверен, что мой GAWK ожидает UTF-8 (то есть, нет Windows "Unicode"/UTF-16, и я вполне уверен, что я кормлю это так).
  • Это GnuWin32-AWK, поэтому он должен знать пути стилей окон.
  • Я также вполне уверен, что анонимные каналы, которые используются для связи, установлены правильно; Я сделал скрипт test.bat, который работал правильно. Кроме того, я могу читать сообщения об ошибках AWK из входного канала (дочерний выход), если в командной строке есть тип.
  • Единственный выход, который мне удалось получить, был 0A 0D, то есть \n\r.
  • Если командная строка в порядке, WaitForSingleObject() возвращает ошибку 259, указывающую на тупик.

РЕДАКТИРОВАТЬ 1: Это упрощенная версия функции. Я сейчас держу основной цикл. В обоих случаях он делает два витка в цикле.

wstring path = L"C:\\MODBUSSINATOR\\awk\\awk.exe";
wstring args = L"C:\\MODBUSSINATOR\\awk\\awk.exe --file=.\\awk\\recipe.awk";
string source = "PERSE PERSE PERSE";
wchar_t argbuff[args.size()+1];   // MSDN says the arg-buff may be modified by client
wcscpy(argbuff,args.c_str());             // so copy args into array
istringstream inpus(source);
ostringstream resus;

DWORD written=0,retcode=0,read=0,readable=0,inpusize=0,resusize=0;
char inpu_buff[1024],resu[1024],*inpu;

SECURITY_ATTRIBUTES cia = {sizeof(SECURITY_ATTRIBUTES),nullptr,true}, coa = cia;
HANDLE oh,ih,cih,coh;
if(!CreatePipe(&cih,&oh,&cia,BUFF_SZ))  //BUFF_SZ = 1024
  abort();
if(!CreatePipe(&ih,&coh,&cia,BUFF_SZ))
  abort();

PROCESS_INFORMATION procinfo;
STARTUPINFO startinfo;
memset(&procinfo,0,sizeof(PROCESS_INFORMATION)); // The documentation says to do this.
memset(&startinfo,0,sizeof(STARTUPINFO));        // Though I set all the fields exclusively.
startinfo = {
  sizeof(STARTUPINFO),nullptr,nullptr,nullptr,0,0,0,0,0,0,0,    
  STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES,SW_HIDE,0,nullptr,
  cih,coh,coh
};

if(!CreateProcess(
  path.c_str(),argbuff,nullptr,nullptr,true, 0 // true, handles are inherited
  ,nullptr,nullptr,&startinfo,&procinfo
))
  abort();

while(true){
  if(inpusize <= 0){
    inpu = inpu_buff;
    inpus.get(inpu,1024);
    inpusize = inpus.gcount();
    if(inpusize){
      if(WriteFile(oh,inpu,inpusize,&written,nullptr)){
        inpusize -= written;
        inpu += written;
      }else
        abort();
    }else
      CloseHandle(oh);
  }
  if(!PeekNamedPipe(ih,nullptr,0,nullptr,&readable,nullptr))
    abort();
  if(readable > 0){
    if(!ReadFile(ih,resu,readable,&read,nullptr))
      abort();
    resu[read] = '\0';
    resus << resu;
  }
  if(!written && !read)
    break;
  read = 0,written = 0;
}

CloseHandle(coh);
CloseHandle(cih);
CloseHandle(ih);
if(WaitForSingleObject(procinfo.hProcess,conf.script_to) == WAIT_TIMEOUT)
  abort();

cout << "AWK SAYS:" << endl <<
  resus.str() << endl;

Перед упрощениями я читал следующую ошибку из канала:

msgstr "awk: fatal: не могу открыть исходный файл`.\aD'".

Теперь файл тестовой летучей мыши будет заблокирован на WaitForSingleObject() функционировать до истечения времени ожидания. Но вывод происходит через ОК ("PERSE PERSE PERSE"), а AWK по-прежнему ничего не выводит. Я расследую.

Обратите внимание, что точка доступа вокруг кода, вероятно, находится вокруг CreateProcess() функция. Все остальное - ваше нормальное многословие WinAPI.

Мой recipe.awk на данный момент является просто проходным:

BEGIN { print "paskaa" > "paska.txt" ; }
/.*/ { print $0; }    
END { exit 999; }

Выше я использую файл paska.txt, чтобы указать, что скрипт начинает выполняться. Такого никогда не было.

Это был мой equivalant.bat, который работал как положено:

@ECHO OFF
:LOOP
SET VAR=
SET /P VAR=
IF "%VAR%" NEQ "" (
  ECHO %VAR%
  GOTO :LOOP
)

Пожалуйста, потерпите мою некомпетентность. Мне бы очень понадобился ваш свежий вклад.


РЕДАКТИРОВАТЬ 2: мне удалось решить проблему, мне не хватало этого:

SetHandleInformation(ihh,HANDLE_FLAG_INHERIT,0)
SetHandleInformation(ohh,HANDLE_FLAG_INHERIT,0)

То есть, не позволяйте дочернему процессу наследовать дескрипторы связи моей стороны. Если это произойдет, будет две копии, поэтому канал никогда не закроется.

Было очень грустно провести полтора рабочих дня с этим.


РЕДАКТИРОВАТЬ 3: И в качестве дополнительной помощи для странных гуглеров там:

Вы хотите закрыть экземпляры дочерних дескрипторов каналов после создания дочернего процесса! Если нет, канал остается действительным, даже если дочерний элемент закрывает свою копию дескриптора, поэтому ваши PeekNamedPipe и ReadFile будут либо возвращать 0 для чтения, либо блокироваться бесконечно (в зависимости от своих аргументов).

0 ответов

Другие вопросы по тегам