我从this问题的第一个答案中得到了以下c代码,我在VS2008中使用C89编译它,所以我对代码进行了一些更改以正常工作,它只编译很好,但是在成功创建namedpipe之后无法创建进程(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 >
之间的界限只是评论。
为了成功创建命名管道需要哪些更正?
#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;
}
答案 0 :(得分:6)
问题出在这里:
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()生成的错误代码。应该给你一个更好的诊断问题的机会。如果您在解释问题时仍然有问题,请更新您的问题。