无法在 Windows 7 中的命名管道内创建进程
Posted
技术标签:
【中文标题】无法在 Windows 7 中的命名管道内创建进程【英文标题】:Unable to create process inside a namedpipe in Windows 7 【发布时间】:2014-05-23 11:21:26 【问题描述】:我从this 问题的第一个答案中获取了以下 c 代码,我在 VS2008 中使用 C89 对其进行编译,因此我对代码进行了一些更改以使其正常工作,它编译得很好,但在成功创建命名管道后无法创建进程(CreateProcessA
不起作用)总是返回错误 2 并在 panic
函数中打印消息。
我想在CreateProcessA中运行的程序可以下载here,我正常运行使用如下:
> C:\qhichwa>cmd.exe /c "C:\qhichwa\flookup.exe -bx C:\qhichwa\qhichwa.fst"
wasi <user writes wasi>
wasi <program responds printing wasi>
hola <user writes hola>
+ ? <program responds printing + ?>
<pres ctrl + c to terminate program>
> C:\qhichwa>
< comments >
之间的行只是 cmets。
为了成功创建命名管道需要进行哪些更正?
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
// name of our glorious pipe
#define PIPE_NAME L"\\\\.\\pipe\\whatever" // bloody unicode string
// exit on fatal error
void panic(const char * msg)
int err = GetLastError();
fprintf(stderr, "***PANIC*** %s\n", msg);
printf("In the child thread: Last Error is %lu\n", err);
exit(-1);
// father process
void father(const char * own_name) // name of our own executable to launch a copy of ourselve
printf("Father process starting\n");
// create a monodirectional father->child named pipe
HANDLE pipe = CreateNamedPipe(
PIPE_NAME, // name of the pipe
PIPE_ACCESS_OUTBOUND, // send only
PIPE_TYPE_BYTE, // send data as a byte stream
1, // only one instance
0, 0, 0, NULL); // default junk
if (pipe == INVALID_HANDLE_VALUE) panic("could not create pipe 1");
// spawn child process
STARTUPINFOA si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
if (!CreateProcessA( // using ASCII variant to be compatible with argv
"cmd.exe", // executable name (ourself)
"/c \"C:\\qhichwa\\flookup.exe -bx C:\\qhichwa\\qhichwa.fst\"", // command line. This will be seen as argv[0]
NULL, NULL, FALSE, // default junk
CREATE_NEW_CONSOLE, // launch in another console window
NULL, NULL, // more junk
&si, &pi)) // final useless junk
panic("could not create child process 2");
// connect to child process
BOOL result = ConnectNamedPipe(pipe, NULL);
if (!result) panic("could not connect to child process");
// talk to child
for (;;)
// read an input line
char line[100];
printf("Say something >");
if (fgets(line, sizeof(line), stdin) == NULL)
panic("could not read from standard input");
// exit on an empty line
if (!strcmp(line, "\n")) break;
// send the line to the child
DWORD written = 0;
if (!WriteFile(
pipe,
line, // sent data
strlen(line), // data length
&written, // bytes actually written
NULL))
panic("could not write to pipe");
// close the pipe
CloseHandle(pipe);
void child(void)
printf("Child process starting\n");
// retrieve communication pipe
HANDLE pipe = CreateFile(
PIPE_NAME, // name of the pipe
GENERIC_READ, // read ONLY access (or else the call will fail)
0, NULL, // junk
OPEN_EXISTING, // opens existing pipe
0, NULL); // more junk
if (pipe == INVALID_HANDLE_VALUE) panic("could not connect to the pipe");
// read father's input
for (;;)
char buffer[80];
DWORD read = 0;
if (!ReadFile(
pipe,
buffer, // read data
sizeof(buffer)-1, // max length (leave room for terminator)
&read, // bytes actually read
NULL))
break; // exit if the pipe has closed
// display what our father said
buffer[read] = '\0'; // make sure what we just read will be displayable as a string
printf("Father said: %s", buffer);
// close pipe
CloseHandle(pipe);
int main(int argc, char *argv[])
// wait for a <return> keypress on exit
atexit(getchar);
father(argv[0]);
// decide whether we are the father or the child
//if (!strcmp(argv[0], "child")) child();
//else father(argv[0]);
printf("Done\n");
return 0;
【问题讨论】:
GetLastError()
说什么? "CreateNamedPipe
- 如果函数失败,返回值为INVALID_HANDLE_VALUE
。要获取扩展错误信息,请调用GetLastError
。"
我添加了行 printf("In the child thread: Last Error is %lu\n", GetLastError());我得到以下信息:父进程在子线程中启动:Last Error is 123 PANIC could not create pipe
我该如何解决这个错误? ERROR_INVALID_NAME 123 (0x7B) 文件名、目录名或卷标语法不正确。
ERROR_INVALID_NAME
表示您提供的名称无效。我的猜测是名为name
的内核对象已经存在于另一个内核命名空间中。为您的管道使用更独特的名称。
我改了但是错误不断
【参考方案1】:
问题出在这里:
fprintf(stderr, "***PANIC*** %s\n", msg);
printf("In the child thread: Last Error is %lu\n", GetLastError());
这是一个标准的 Windows 编程错误,每个程序员都会犯一次这个错误。只有一次,这很难诊断,以至于你永远不会忘记失去生命中试图发现它的一周。
根本问题是 GetLastError() 的工作方式。它返回一个内部全局变量的值,它存储在TEB(线程环境块)中。它有一个全局变量的常见问题,每个 你对一个 winapi 函数的调用都有可能改变它,包括那些实际上并没有失败的函数。 Windows 本身也使用该变量。而 ERROR_INVALID_NAME 是一个非常流行的内部错误代码。
由于您无法看到正在进行的这些 winapi 调用,情况更加复杂。破坏错误代码的是 fprintf()。它通过 winapi 调用在 CRT 中实现。必然如此,I/O 是操作系统的职责。
因此,绝对必要的是您立即获取错误代码,然后再执行任何操作。虽然最好将值传递给您的 panic() 函数,因为它无法预测在它之前运行的其他代码,快速解决方法是像这样重写它:
int err = GetLastError();
fprintf(stderr, "***PANIC*** %s\n", msg);
printf("In the child thread: Last Error is %lu\n", err);
您现在将获得真正的错误代码,即由 CreateNamedPipe() 生成的错误代码。应该让您更好地诊断问题。如果您在解释问题时仍有问题,请更新您的问题。
【讨论】:
不完全确定我应该看什么。看起来恭喜是为了,修复错误报告似乎已经解除了您的阻止。 ERROR_FILE_NOT_FOUND 当然是一个非常常见的错误,尤其是在您使用 CreateProcess() 时。我当然不能帮你找回文件。以上是关于无法在 Windows 7 中的命名管道内创建进程的主要内容,如果未能解决你的问题,请参考以下文章