首页 文章

使用管道连接到控制台程序时如何处理缓冲

提问于
浏览
1

我有一个win32程序(是的,我坚持使用win32)启动子进程并通过匿名管道连接到它的stdin / stdout . 大多数时候我不拥有子进程(因此,我无法访问代码) . 我发现孩子的stdout缓冲正在阻碍 . 在我终止这个过程之前,我没有看到孩子的任何输出;但是,我确实知道输入是在收到时处理的 .

所以,我已经阅读了http://support.microsoft.com/kb/190351/en-us,它警告了子进程的问题's use of printf (etc) regarding buffering, and microsoft'这个很棒的解决办法就是用fflush()跟踪子进程中的所有printfs(更简单的方法就是使用setbuf(stdout,0);但是,假设您有权访问子源代码) .

显然,子进程在连接到父管道时不会刷新stdout . 有没有办法绕过这个而不需要修改孩子?

我用一个简单的孩子证实了这一点:

#include <stdio.h>
    #include <fcntl.h>

    char line[256];

    int
    main(int argc, char *argv[])
    {
            char *lp;

    //      setbuf(stdout,0);
            while(1) {
                    printf("Prompt:");
                    lp = gets(line);
                    printf("Got: <%s>\n",lp);
                    if (strcmp(lp,"yada") == 0) {
                            int fd = open("C:/tmp/yada123",O_BINARY|O_RDWR|O_CREAT);
                            if (fd > 0) {
                                    write (fd,"hi!\n",4);
                                    close(fd);
                            }
                    }
                    if (strcmp(lp,"exit") == 0) {
                            printf("bye!\n");
                            break;
                    }
            }
}

如果我取消注释顶部的setbuf()调用,那么交互是干净的;但请注意,我通常无法修改子代码 . 另外,我验证了另一个方向没有缓冲(即使我看不到输出);因为在收到字符串“yada”时会写入文件 .

1 回答

  • 0

    前言:在概述的问题的评论中,代码注入可能解决问题 . 这篇文章展示了一个可能的dll注入实现,因此补充了评论 . 我将代码发布为普通帖子,以便更好地呈现多行代码 .

    以下代码可能是dll注入的良好起点 . 它使用全局钩子 . 这是一个非常简单的方法,但它会将您的dll注入到所有正在运行的进程中(仅限于您拥有权限的那些进程) . 所以你必须要求当前的程序名称并仅在你所需的应用程序中调用 setbuf(stdout,0); :-)也许你需要添加一些头文件(我只有一些代码片段在一起而没有测试它) .

    必须将 void InstallHook(void)void RemoveHook(void) 函数声明为dll导出函数,因此要么使用* .def文件,要么将它们声明为 __declspec( dllexport ) . 这可能取决于您的编译器和您的设置 .

    #include <windows.h>
    #include <cstdlib>
    #include <cstdio>
    
    BOOL WINAPI DllMain( HINSTANCE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
    {
      UNREFERENCED_PARAMETER(lpReserved);
    
      switch (ul_reason_for_call)
      {
      case DLL_PROCESS_ATTACH:
      {
        wchar_t buffer [1024];
        // get the path and executable name of the current process
        GetModuleFileNameW( GetModuleHandle( NULL ), buffer, 1024 );
        //test if we are in the target app
        if ( _wcsicmp( buffer, "C:/some_dir/some_app.exe" ) == 0 )
        {
          setbuf(stdout,0);
        }
        break;
      }
      case DLL_PROCESS_DETACH:
        break;
      default:
        break;
      }
    
      return (true);
    }
    
    HHOOK gl_hHook = NULL;
    LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam)
    {
      return (CallNextHookEx( gl_hHook, nCode, wParam, lParam));
    }
    
    // call this function before or after you have started the child process
    // the hook gets installed and your dll is loaded into each running process
    // and the DllMain functions gets called by each process
    void InstallHook(void)
    {
      gl_hHook = SetWindowsHookEx( WH_CBT, HookProc, gl_hThisInstance, 0 );
    }
    
    void RemoveHook(void)
    {
      UnhookWindowsHookEx( gl_hHook );
    }
    

相关问题