【问题标题】:Create process and anonymous pipe创建进程和匿名管道
【发布时间】:2016-05-25 05:51:23
【问题描述】:

更新问题:所以我已经能够创建进程并编译程序。但是,我遇到了一个新问题。当我尝试将 Source 程序通过管道传输到 Filter 程序中时。它似乎没有为 sink 程序提供任何输入。没有错误信息。我还使用 Windows cmd 中的管道运算符测试了我所有的独立程序。

我正在尝试做这个小项目来了解匿名管道和创建过程。我创建了 3 个小型独立程序,分别称为 Source、Filter 和 Sink。这 3 个已经编译并且运行良好。以下是 3 个独立程序的说明。

Source:从命令行获取源文本文件文件名,打开文件,一次一个字符地读取文件内容并将其直接复制到标准输出(stdout)。复制文件后,Source 终止(关闭所有打开的文件句柄)。

过滤程序不使用任何文件名命令行参数。相反,Filter 从标准输入 (stdin) 读取文本文件,并将所有大写字母转换为小写的输入副本写入标准输出 (stdout)。过滤器具体必须设计成读取一个字符,转换它,输出它,然后循环,直到传入的数据完成。

Sink 程序从其命令行获取目标文本文件文件名,打开文件进行写入,然后从标准输入文件 (stdin) 一次读取一个字符,并将每个传入字符直接写入目标 sink 文件。

接下来,我将分别驱动一个主驱动程序,该程序创建 2 个管道并生成 3 个独立的子进程,其输入和输出配置为执行指定的并发执行和数据流。像这样的:

  • srcfile -> Source -> pipe1 -> Filter -> Pipe2 -> Sink -> destfile

驱动程序需要2个命令行参数:

  • C:\> Driver.exe srcfile destfile

其中 srcfile 是现有的数据文本文件,而 destfile 是要由 Sink 应用程序创建的新目标文件的文件名。

这是我的驱动程序代码。它还没有完成。但是我在尝试为 Source 程序创建进程时遇到了问题。

更新代码:

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


#define DELAY_A_WHILE() {volatile long j; for(j = 1; j< 10000; j++) ; } 

int main(int argc, char *argv[])
{
    HANDLE hPipeRead, hPipeWrite, hPipeRead2, hPipeWrite2;
    STARTUPINFO StartupInfoSource;
    STARTUPINFO StartupInfoFilter;
    STARTUPINFO StartupInfoSink;
    PROCESS_INFORMATION ProcInfoSource;
    PROCESS_INFORMATION ProcInfoFilter;
    PROCESS_INFORMATION ProcInfoSink;
    SECURITY_ATTRIBUTES PipeAttributes;
    SECURITY_ATTRIBUTES PipeAttributes2;
    char cmdline[200];

    PipeAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
    PipeAttributes.lpSecurityDescriptor = NULL;     //ignore
    PipeAttributes.bInheritHandle = TRUE;           //child can inherit

    //Create first pipe
    if (!CreatePipe(&hPipeRead, &hPipeWrite, &PipeAttributes, 0)) {
        fprintf(stderr, "Error creating pipe: %d\n", GetLastError());
        exit(1);
    }

    sprintf_s(cmdline, 200, "Source.exe %s", argv[1]);
    printf("Create process: %s\n", cmdline);

    GetStartupInfo(&StartupInfoSource);
    StartupInfoSource.dwFlags = StartupInfoSource.dwFlags | STARTF_USESTDHANDLES;


    //Mapping
    StartupInfoSource.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
    StartupInfoSource.hStdOutput = hPipeWrite;
    StartupInfoSource.hStdError = GetStdHandle(STD_ERROR_HANDLE);

    if (!CreateProcess(
        NULL, cmdline, NULL, NULL,
        TRUE,
        CREATE_NEW_CONSOLE, NULL, NULL,
        &StartupInfoSource,
        &ProcInfoSource))
    {
        fprintf(stderr, "Error creating child process: %d",GetLastError());
        exit(1);
    }

    CloseHandle(hPipeWrite);
    CloseHandle(ProcInfoSource.hProcess);
    CloseHandle(ProcInfoSource.hThread);

    PipeAttributes2.nLength = sizeof(SECURITY_ATTRIBUTES);
    PipeAttributes2.lpSecurityDescriptor = NULL;        //ignore
    PipeAttributes2.bInheritHandle = TRUE;          //child can inherit
    //Create Second Pipe
    if (!CreatePipe(&hPipeRead2, &hPipeWrite2, &PipeAttributes2, 0)) {
        fprintf(stderr, "Error creating pipe: %d\n", GetLastError());
        exit(1);
    } 

    GetStartupInfo(&StartupInfoFilter);
    StartupInfoFilter.dwFlags = StartupInfoFilter.dwFlags | STARTF_USESTDHANDLES;

    //Mapping
    StartupInfoFilter.hStdInput = hPipeRead;
    StartupInfoFilter.hStdOutput = hPipeWrite2;
    StartupInfoFilter.hStdError = GetStdHandle(STD_ERROR_HANDLE);

    sprintf_s(cmdline, 200, "Filter.exe");
    printf("Create process: %s\n", cmdline);

    //Filter
    GetStartupInfo(&StartupInfoFilter);
    if (!CreateProcess(
        NULL, cmdline, NULL, NULL,
        TRUE,
        CREATE_NEW_CONSOLE, NULL, NULL,
        &StartupInfoFilter,
        &ProcInfoFilter))
    {
        fprintf(stderr, "Error creating child process: %d", GetLastError());
        exit(1);
    }
//  int exitStatus;
    //  GetExitCodeProcess(ProcInfoFilter.hProcess, &exitStatus);
    CloseHandle(hPipeRead);
    CloseHandle(hPipeWrite2);
    CloseHandle(ProcInfoFilter.hProcess);
    CloseHandle(ProcInfoFilter.hThread);


    GetStartupInfo(&StartupInfoSink);
    StartupInfoSink.dwFlags = StartupInfoSink.dwFlags | STARTF_USESTDHANDLES;



    //Mapping
    StartupInfoSink.hStdInput = hPipeRead2;
    StartupInfoSink.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
    StartupInfoSink.hStdError = GetStdHandle(STD_ERROR_HANDLE);

    sprintf_s(cmdline, 200, "Sink.exe %s", argv[2]);
    printf("Create process: %s\n", cmdline);

    GetStartupInfo(&StartupInfoSink);
    if (!CreateProcess(
        NULL, cmdline, NULL, NULL,
        TRUE,
        CREATE_NEW_CONSOLE, NULL, NULL,
        &StartupInfoSink,
        &ProcInfoSink))
    {
        fprintf(stderr, "Error creating child process: %d", GetLastError());
        exit(1);
    }

    CloseHandle(hPipeRead2);
    CloseHandle(ProcInfoSink.hProcess);
    CloseHandle(ProcInfoSink.hThread);


    return 0;
}

程序编译良好。但是,当它尝试创建进程时,它总是失败并退出。 cmdline 解析时的值是“Source.exe test.txt”,这正是我用来执行我的独立源程序的。有人可以解释为什么我的CreateProcess 失败了吗?是不是因为我解析了错误的参数?

【问题讨论】:

  • 所以你是说CreateProcess 失败了?然后您应该查看GetLastError 返回的错误代码。顺便说一句,您传递调用进程的STARTUPINFO 是否正确?这是将句柄传递给标准输入和标准输出吗?
  • 当我尝试调试时,程序总是执行 if(!CreateProcess()) 里面的代码块,当它创建和退出程序失败时打印错误。

标签: c winapi pipeline createprocess


【解决方案1】:

我在这里看到的唯一问题是 Source.exe 应用程序可能不在 Driver.exe 所在的同一目录中。我试过你的代码,这是 CreateProcess 失败的唯一情况。

【讨论】:

  • 我的 source.exe 与 Driver.c 文件位于同一文件夹中。它所在的位置是否正确?
  • 不。您的二进制文件通常放置在 Release 或 Debug 文件夹中(取决于您使用的构建配置)。如果您创建项目时启用了“为解决方案创建目录”选项,那么您将看到 2 个不同的 Release 和 2 个不同的 Debug 文件夹。您需要位于目录结构上层的那个。无论如何,只要尝试找到您的 driver.exe 文件的确切位置并将 source.exe 放到这个文件夹中。
  • 您能否提供来自 GetLastError() 的错误代码?
  • 所以我尝试了 fprintf(stderr, "Error Creating child process: %d",GetLastError());它返回了那个值 2
  • 错误代码 2 = ERROR_FILE_NOT_FOUND。您确定 source.exe 与 driver.exe 位于同一文件夹中吗?您还可以硬编码 source.exe 的完整路径,但在这种情况下,请先查看在 MSDN CreateProcess page 上应该如何格式化它
【解决方案2】:

我已经弄清楚原因了。我的项目的属性是使用 Unicode 字符集。当我切换到多字节字符集时,它工作正常。

【讨论】:

  • 这显然不累。问题中的代码不会编译。当您丢失伪造的代码时会发生这种情况。你太无耻了。切换到多字节是错误的方法。现在是 2016 年。已经使用 Unicode!
  • 我在问题中的代码确实已编译。我在 stackoverflow 上查看了其他一些问题,说 Unicode 字符集在 Win32 控制台中的支持很差,并且无法正确显示,因此最好避免。那么你有什么建议用 Unicode 字符集来做吗?
  • 如果该代码编译,则未定义 Unicode。 Windows 控制台支持 Unicode。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-02
  • 2012-07-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多