CallNamedPipe 和 TransactNamedPipe 不起作用

CallNamedPipe and TransactNamedPipe don't work

我想将消息发送到服务器并使用命名管道读取它。当我使用 WriteFile 函数时,消息到达服务器,但 TransactNamedPipe 失败并出现错误 230 (ERROR_BAD_PIPE),CallNamedPipe 失败并出现错误 87 (INVALID_PARAMETER) 或 231 (PIPE_BUSY)。我试过 MSDN 示例,还有很多其他的东西,但仍然没有结果。请帮忙。

客户:

#include <windows.h> 
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#include <string>

#define BUFSIZE 512

int _tmain(int argc, TCHAR *argv[])
{
    OVERLAPPED ov;
    ZeroMemory(&ov, sizeof(OVERLAPPED));

    HANDLE hPipe;
    // Try to open a named pipe; wait for it, if necessary. 
    while (1)
    {
        hPipe = CreateFile(
            L"\\.\pipe\PipeTest",   // pipe name 
            GENERIC_READ |  // read and write access 
            GENERIC_WRITE,
            0,              // no sharing 
            NULL,           // default security attributes
            OPEN_EXISTING,  // opens existing pipe 
            FILE_FLAG_OVERLAPPED,             
            NULL);          // no template file 

                            // Break if the pipe handle is valid. 
        if (hPipe != INVALID_HANDLE_VALUE)
            break;

        DWORD lastErr = GetLastError();

        // Exit if an error other than ERROR_PIPE_BUSY occurs. 
        if (GetLastError() != ERROR_PIPE_BUSY)
        {
            printf("Could not open pipe\n");
            return 0;
        }

        // All pipe instances are busy, so wait for 2 seconds. 
        if (!WaitNamedPipe(L"\\.\pipe\PipeTest", 2000))
        {
            printf("Could not open pipe\n");
            return 0;
        }
    }

    std::wstring s;
    s.resize(1024);
    DWORD cbRead;

    BOOL fSuccess = TransactNamedPipe(
        hPipe,                  // pipe handle 
        L"Hello",              // message to server
        sizeof(wchar_t) * 5, // message length
        &s[0],
        s.size() * sizeof(wchar_t),
        &cbRead,                // bytes read
        &ov);                  // not overlapped 

    DWORD lastErr = GetLastError();
    GetOverlappedResult(hPipe, &ov, &cbRead, TRUE);
    DWORD lastErr2 = GetLastError();

    CloseHandle(hPipe);

    return 0;
}

服务器:

#include <iostream>
#include <string>
#include <Windows.h>

const std::wstring pipeName = L"\\.\pipe\PipeTest";

int main(void)
{
    HANDLE hPipe;
    wchar_t buffer[256];
    DWORD dwRead;

    OVERLAPPED ov;
    ZeroMemory(&ov, sizeof(OVERLAPPED));

    hPipe = CreateNamedPipe(pipeName.c_str(),
        PIPE_ACCESS_DUPLEX | PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,   // FILE_FLAG_FIRST_PIPE_INSTANCE is not needed but forces CreateNamedPipe(..) to fail if the pipe already exists...
        PIPE_WAIT,
        1,
        1024 * 16,
        1024 * 16,
        NMPWAIT_USE_DEFAULT_WAIT,
        NULL);

    if (hPipe != INVALID_HANDLE_VALUE)
    {
        if (ConnectNamedPipe(hPipe, &ov) != FALSE)   // wait for someone to connect to the pipe
        {
            while (ReadFile(hPipe, buffer, 255, &dwRead, &ov) != FALSE)
            {
                WriteFile(hPipe, L"lalala", 6 * sizeof(wchar_t), &dwRead, &ov);

                DWORD lastErr1 = GetLastError();
                GetOverlappedResult(hPipe, &ov, &dwRead, TRUE);
                DWORD lastrr2 = GetLastError();

                printf("%s", buffer);
            }
        }

        DisconnectNamedPipe(hPipe);
    }

    return 0;
}

如果您阅读了 TransactNamedPipe

TransactNamedPipe fails if the server did not create the pipe as a message-type pipe or if the pipe handle is not in message-read mode.

CallNamedPipe

Calling CallNamedPipe is equivalent to calling the CreateFile (or WaitNamedPipe, if CreateFile cannot open the pipe immediately), TransactNamedPipe, and CloseHandle functions

因此此函数仅适用于消息类型管道

但是当你创建服务器管道时你使用 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE 所以 CallNamedPipe and/or TransactNamedPipe 必须失败。

您需要改用 ReadFile/WriteFile。或使用标志 PIPE_TYPE_MESSAGE|PIPE_READMODE_MESSAGE 创建服务器并为客户端句柄调用 SetNamedPipeHandleState 以设置消息读取模式(使用 PIPE_READMODE_MESSAGE