0

我有一个小程序,它接受输入并在继续其业务之前对其进行一些预处理。(“让我们成为一个程序;哦,我们还不知道确切的数据格式。”的经典案例。)为了使这一步更具脚本性,我决定使用 AWK 进行预处理步骤(因为数据将是表格性质)。

足够的背景。这归结为,我试图用CreateProcess调用 GAWK 。

  • 我相当肯定我的 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;

在简化之前,我正在从管道中读取以下错误:

“awk:致命:无法打开源文件 `.\aD'”。

现在测试 bat 文件将在WaitForSingleObject()函数处阻塞,直到超时。但是通过 OK(“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:作为对奇怪的谷歌用户的进一步帮助:

一旦创建了子进程,您想关闭管道的子端句柄的实例!如果不是,即使 Child 关闭其句柄副本,管道仍然有效,因此您的 PeekNamedPipe 和 ReadFile 将返回 0 可读或无限期阻塞(取决于它们的参数)。

4

0 回答 0