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

Winapi 如何在管道上使用WriteFile修复乱码文本?,winapi,named-pipes,Winapi,Named Pipes,我正在制作一个Win32应用程序,它通过命名管道将字符串从一个进程发送到另一个进程。但是,在管道上调用ReadFile的进程会获取包含一些乱码数据的字符串。它返回正确写入的字节数,但字符串的最后8个字符左右是乱码 以下是创建管道并写入管道的代码: myPipe = CreateNamedPipe(L"\\\\.\\pipe\\testpipe", PIPE_ACCESS_OUTBOUND, PIPE_NOWAIT, 10, 512, 512, 10, NULL); TCHAR title[128

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

以下是创建管道并写入管道的代码:

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);
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.
当显示MessageBox时,字符串的结尾被弄乱了,我不知道为什么。有什么想法吗


谢谢

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

  • 您需要1)显式发送以null结尾的字节,或2)在读取的数据中追加一个字节
  • 既然您正在读取512字节,那么您也应该正好发送512字节
  • 您可以通过先发送字符串的大小,然后发送那么多字节来发送可变长度的字符串。这样,当您读取数据时,您将知道实际字符串需要读取多少字节
  • 当你通过管道发送两件东西,并且你在第一次阅读中读到了你真正想要的东西,你所做的事情的问题就会被发现
  • 如果只通过管道发送1个内容,则可以保留代码,但在写入管道时发送size()+1
  • ReadFile/WriteFile用于发送二进制数据,不一定是字符串。因此,您可以创建一个名为ReadString和WriteString的函数,该函数实现了我的建议,即先读取/写入大小,然后读取/写入实际字符串
试着这样做:

以下是创建管道并写入管道的代码:

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);
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.

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


这是来自MSDN的。请注意,客户端如何准确地发送消息中的字符数+1(包括终止字符)并将其接收到大小为512的固定缓冲区中。如果您查看,您将看到相同的模式。

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

如果管道数据不是以空终止符结尾,我将最后一个字符替换为一个!这似乎对我有用。在我的数据块末尾有空值和没有空值的地方,我完全看到了这项工作

我担心我可能会丢失一个关键的最后一个字符(你也可能会),但就我眼前的目的而言,这并没有发生。在某些情况下,您可以考虑添加NULL,而不是替换EX/P> 下面是代码snippit:

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';
}
const unsigned int MAX_PIPE_peek=100;
DWORD字节输入管道=0;
无符号int-pipeek=0;
而((bytesInPipe==0)和&(pipepeek0)
{
//读取写入管道的数据(并隐式清除)
德沃德·德雷德;
CHAR*pipeContents=新字符[bytesInPipe];
bSuccess=ReadFile(g_hchildsd_OUT_Rd,管道内容,
bytesInPipe,&dwRead,NULL);
如果(!bSuccess | | dwRead==0)返回FALSE;//严重故障时退出
//“作弊”-清除管道末端的垃圾
if(管道内容[bytesInPipe]!='\0')
管道内容[bytesInPipe]='\0';
}
更新:


经过进一步的测试,我发现这不太可靠(令人震惊,嗯?)。不过,我认为我找到了一个相对简单的解决方案。有什么想法可以让这个快速补丁工作吗?

谢谢,我没有意识到管道需要精确的长度。我以为他们会为我做那件事。它正在工作!谢谢我现在遇到了发送一半字符串的问题。我需要(lstrlen(…)+1)*sizeof(TCHAR),如示例所示。啊,是的。多字节字符。我甚至都没想到。很好,我更新了我的答案,用*sizeof(TCHAR)修复了它