首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在管道上使用WriteFile修复乱码文本?

如何在管道上使用WriteFile修复乱码文本?
EN

Stack Overflow用户
提问于 2009-03-15 12:21:36
回答 3查看 1.7K关注 0票数 4

我正在制作一个Win32应用程序,它通过命名管道将字符串从一个进程发送到另一个进程。但是,在管道上调用ReadFile的进程会得到其中包含一些乱码数据的字符串。它返回正确写入的字节数,但字符串的最后8个字符左右是乱码。

下面是创建管道和写入管道的代码:

代码语言:javascript
复制
myPipe = CreateNamedPipe(L"\\\\.\\pipe\\testpipe", PIPE_ACCESS_OUTBOUND, PIPE_NOWAIT, 10, 512, 512, 10, NULL);
TCHAR title[128];
GetWindowText(foundHwnd, title, 128);
wstring windowTitle(title);
vector<wstring> splitVec;
boost::split(splitVec, windowTitle, boost::algorithm::is_any_of(wstring(L"|")));
WriteFile(myPipe, splitVec[0].c_str(), splitVec[0].size(), &wrote, NULL);

下面是读取它的代码:

代码语言:javascript
复制
if (WaitNamedPipe(L"\\\\.\\pipe\\testpipe", 5000) == 0) {
    MessageBox(NULL, L"Unable to wait for pipe", L"Error", MB_OK);
    return false;
}

myPipe = CreateFile(L"\\\\.\\pipe\\testpipe", GENERIC_READ, FILE_SHARE_READ, NULL,
    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (myPipe == INVALID_HANDLE_VALUE) {
    MessageBox(NULL, L"Unable to open pipe", L"Error", MB_OK);
    return false;
}
    // Other code here...
    TCHAR buf[512];
    DWORD read;
    success = ReadFile(myPipe, buf, 512, &read, NULL);
    if (read > 0)
        MessageBox(NULL, buf, L"Got Data", MB_OK);

当显示MessageBox时,字符串的末尾是乱码,我不知道为什么。有什么想法吗?

谢谢!

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2009-03-15 13:13:21

我认为这里的关键是确保您的字符串是null终止的,并且您也发送了终止字符。如果通信是同步的,或者如果是在PIPE_READMODE_MESSAGE中设置的,则不必发送整个缓冲区。当指定的字节数已被读取或在管道的另一端完成写入操作时,ReadFile将返回。我认为“乱码”文本实际上是管道客户端读取缓冲区中的垃圾,因为您没有传输字符串终止字符,所以它将其包含在发送到消息框的文本中。要么在发送前清除读缓冲区,要么随消息一起发送字符串终止字符,我认为这将在没有发送满缓冲区的开销的情况下工作。

这是来自微软的sample client。注意客户端如何准确地发送消息+ 1中的字符数(包括终止字符),并将其接收到大小为512的固定缓冲区中。如果你看一下server example,你会看到同样的模式。

票数 3
EN

Stack Overflow用户

发布于 2009-03-15 12:26:35

对您发布的代码的一些观察:

  • 您需要1)显式发送null终止字节,或者2)将1附加到您读取的数据。
  • 由于您读取的是512字节,因此您也应该恰好发送512字节。
  • 您可以发送可变长度的字符串,方法是先发送字符串的大小,然后发送那么多字节。这样,当您读取数据时,您将知道要为实际字符串读取多少字节。当你通过管道发送两个东西,并且你在第一次读取时读到了你真正想要的东西之后,你所做的事情的问题就会显现出来。
  • 如果你只通过管道发送一个东西,你可以保留你的代码,但是当你写到管道时发送

()+1。

  • ReadFile / WriteFile旨在发送二进制数据,而不一定是字符串。因此,您可以创建一个名为ReadString和WriteString的函数,该函数实现我关于首先读取/写入大小,然后是实际字符串的建议。

尝试如下所示:

下面是创建管道和写入管道的代码:

代码语言:javascript
复制
myPipe = CreateNamedPipe(L"\\\\.\\pipe\\testpipe", PIPE_ACCESS_OUTBOUND, PIPE_NOWAIT, 10, 512, 512, 10, NULL);
TCHAR title[128];
GetWindowText(foundHwnd, title, 128);
WriteFile(myPipe, title, 128*sizeof(TCHAR), &wrote, NULL);//<---In this case we are sending a null terminated string buffer.

下面是读取它的代码:

代码语言:javascript
复制
if (WaitNamedPipe(L"\\\\.\\pipe\\testpipe", 5000) == 0) {
    MessageBox(NULL, L"Unable to wait for pipe", L"Error", MB_OK);
    return false;
}

myPipe = CreateFile(L"\\\\.\\pipe\\testpipe", GENERIC_READ, FILE_SHARE_READ, NULL,
    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (myPipe == INVALID_HANDLE_VALUE) {
    MessageBox(NULL, L"Unable to open pipe", L"Error", MB_OK);
    return false;
}
    // Other code here...
    TCHAR buf[128];
    DWORD read;
    success = ReadFile(myPipe, buf, 128*sizeof(TCHAR), &read, NULL);
    if (read > 0)
        MessageBox(NULL, buf, L"Got Data", MB_OK);
票数 2
EN

Stack Overflow用户

发布于 2015-07-01 22:38:12

当我编写一个泛型函数从命令提示符下执行的任何进程中读取stdout时,我遇到了这个“管道中的垃圾”问题。因此,我不能改变正在写入管道的内容(通常建议的那样),我只能改变读取端。所以,我“作弊”了。

如果管道数据没有以空终止符结束,我会用一个字符替换最后一个字符!它似乎对我很管用。在我的数据块末尾有空值和没有空值的情况下,我完美地看到了这一点。

我担心我可能会丢失关键的最后一个字符(您可能会丢失!),但对于我的直接目的来说,这并没有发生。在某些情况下,您可能会考虑添加null而不是替换结尾...

下面是代码片段:

代码语言:javascript
复制
const unsigned int MAX_PIPE_PEEKS = 100;
DWORD bytesInPipe = 0;
unsigned int pipePeeks=0;
while( (bytesInPipe==0) && (pipePeeks < MAX_PIPE_PEEKS) )
{
    bSuccess = PeekNamedPipe( g_hChildStd_OUT_Rd, NULL, 0, NULL, 
                              &bytesInPipe, NULL );
    if( !bSuccess ) return bSuccess;  // Bail on critical failure                
    ++pipePeeks;
}
if( bytesInPipe > 0 )
{
    // Read the data written to the pipe (and implicitly clear it)
    DWORD dwRead; 
    CHAR *pipeContents = new CHAR[ bytesInPipe ];    
    bSuccess = ReadFile( g_hChildStd_OUT_Rd, pipeContents, 
                         bytesInPipe, &dwRead, NULL );
    if( !bSuccess || dwRead == 0  )  return FALSE;  // Bail on critical failure              

    // "Cheat" - eliminate garbage at the end of the pipe
    if( pipeContents[ bytesInPipe ] != '\0' )
        pipeContents[ bytesInPipe ] = '\0';
}

更新:

在进一步测试后,我发现这不太可靠(令人震惊,是吧?)。我认为我走在了一个相对简单的解决方案的正确轨道上。有什么办法让这个快速补丁生效吗?

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/647723

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档