c++ 进程间通信之管道

进程间通信的方式有很多:匿名管道,有名管道,win32 WM_COPYDATA, 共享内存,消息队列,本地起socket ,或者本地起websockt。等等。
问题背景:windows c++程序和 QT已支持跨平台的项目,做进程间通信传输数据。
QT项目接洽了electron,electron不支持管道通信,所以管道排除,因为跨平台,win32的WM_COPYDATA也排除。
想要约定为标注输入输出做为通信方式,对应到win32这边,就是匿名管道通过创建子进程的方式重定向IO,但是匿名管道在win32平台是阻塞的,无法改为非阻塞,影响主程序的执行,这和linux很不同,linux下匿名管道可以设置为非阻塞,匿名管道排除。
为了改为非阻塞,使用有名管道,看微软官方文档,说有名管道也可以重定向子进程IO,但是本人愚钝,多次尝试未能成功通信。有名管道客户端测需要设置管道状态为非阻塞,非阻塞才能生效。有名管道+重定向子进程IO 目前失败。
最后没办法,使用本地起websocket作为通信方式。

匿名管道

使用重定向输入和输出创建子进程
这个案列可以参考微软给的demo,思路很清晰。
在这里插入图片描述

HANDLE g_hChildStd_IN_Rd = NULL;
HANDLE g_hChildStd_IN_Wr = NULL;
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;
//1. 第一步,创建匿名管道
void MyCreatePipe() {
    //使用匿名管道实现父子进程通信
    SECURITY_ATTRIBUTES saAttr;
    // Set the bInheritHandle flag so pipe handles are inherited. 
    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
    saAttr.bInheritHandle = TRUE;
    saAttr.lpSecurityDescriptor = NULL;

    // Create a pipe for the child process's STDOUT. 
    if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0))
        ErrorExit(TEXT("StdoutRd CreatePipe"));

    // Ensure the read handle to the pipe for STDOUT is not inherited.
    if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))
        ErrorExit(TEXT("Stdout SetHandleInformation"));

    // Create a pipe for the child process's STDIN. 
    if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0))
        ErrorExit(TEXT("Stdin CreatePipe"));

    // Ensure the write handle to the pipe for STDIN is not inherited. 
    if (!SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0))
        ErrorExit(TEXT("Stdin SetHandleInformation"));
}
     
 //2. 创建子进程
 void CreateChildProcess(const std::wstring sCmd)
// Create a child process that uses the previously created pipes for STDIN and STDOUT.
{
	PROCESS_INFORMATION piProcInfo;
	STARTUPINFO siStartInfo;
	BOOL bSuccess = FALSE;

	// Set up members of the PROCESS_INFORMATION structure. 
	ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));

	// Set up members of the STARTUPINFO structure. 
	// This structure specifies the STDIN and STDOUT handles for redirection.
	ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
	siStartInfo.cb = sizeof(STARTUPINFO);
	siStartInfo.hStdError = g_hChildStd_OUT_Wr;
	siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
	siStartInfo.hStdInput = g_hChildStd_IN_Rd;
    siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
    siStartInfo.wShowWindow = SW_HIDE;

	// Create the child process. 
	bSuccess = CreateProcess(NULL,
		(LPWSTR)sCmd.c_str(),     // command line 
		NULL,          // process security attributes 
		NULL,          // primary thread security attributes 
		TRUE,          // handles are inherited 
		0,             // creation flags 
		NULL,          // use parent's environment 
		NULL,          // use parent's current directory 
		&siStartInfo,  // STARTUPINFO pointer 
		&piProcInfo);  // receives PROCESS_INFORMATION 

	// If an error occurs, exit the application. 
	if (!bSuccess)
		ErrorExit(TEXT("CreateProcess"));
	else
	{
		// Close handles to the child process and its primary thread.
		// Some applications might keep these handles to monitor the status
		// of the child process, for example. 

		CloseHandle(piProcInfo.hProcess);
		CloseHandle(piProcInfo.hThread);

		// Close handles to the stdin and stdout pipes no longer needed by the child process.
		// If they are not explicitly closed, there is no way to recognize that the child process has ended.

		CloseHandle(g_hChildStd_OUT_Wr);
		CloseHandle(g_hChildStd_IN_Rd);
	}
}

//3. 写管道
bool WriteToPipe(const std::string& sMsg)
{
	DWORD dwWritten;
	BOOL bSuccess = FALSE;

	bSuccess = WriteFile(g_hChildStd_IN_Wr, sMsg.c_str(), sMsg.size(), &dwWritten, NULL);
	if (!bSuccess) return false;

	// Close the pipe handle so the child process stops reading. 

	if (!CloseHandle(g_hChildStd_IN_Wr))
		ErrorExit(TEXT("StdInWr CloseHandle"));
    return true;
}

//4. 读管道
void ReadFromPipe(std::string& sReadedMsg)
// Read output from the child process's pipe for STDOUT
// and write to the parent process's pipe for STDOUT. 
// Stop when there is no more data. 
{
    sReadedMsg = "";
	DWORD dwRead;
    char szBuf[2048] = { 0 };
	HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);

    while (ReadFile(g_hChildStd_OUT_Rd, szBuf, sizeof(szBuf), &dwRead, NULL))
	{
        sReadedMsg += szBuf;
	}
}

有名管道

在这里插入图片描述
上述方式我测试不通。
下面的重叠IO,有名管道服务器和客户端我测试可以。客户端设置管道为非阻塞。

使用重叠 I/O 的命名管道服务器 微软的demo在这里插入图片描述

#include <windows.h> 
#include <stdio.h>
#include <tchar.h>
#include <strsafe.h>
#include <iostream>

#define CONNECTING_STATE 0 
#define READING_STATE 1 
#define WRITING_STATE 2 
#define INSTANCES 4
#define PIPE_TIMEOUT 5000
#define BUFSIZE 4096

typedef struct
{
	OVERLAPPED oOverlap;
	HANDLE hPipeInst;
	TCHAR chRequest[BUFSIZE];
	DWORD cbRead;
	TCHAR chReply[BUFSIZE];
	DWORD cbToWrite;
	DWORD dwState;
	BOOL fPendingIO;
} PIPEINST, * LPPIPEINST;


VOID DisconnectAndReconnect(DWORD);
BOOL ConnectToNewClient(HANDLE, LPOVERLAPPED);
VOID GetAnswerToRequest(LPPIPEINST);
std::string ws2s(const std::wstring& ws);
void CreateChildProcess();

PIPEINST Pipe[INSTANCES];//0 IN-red; 1 IN-write; 2 OUT-red; 3 OUT-write
HANDLE hEvents[INSTANCES];

int _tmain(VOID)
{
	DWORD i, dwWait, cbRet, dwErr;
	BOOL fSuccess;
	LPCTSTR lpszPipename = TEXT("\\\\.\\pipe\\mynamedpipe");
	
	// The initial loop creates several instances of a named pipe 
	// along with an event object for each instance.  An 
	// overlapped ConnectNamedPipe operation is started for 
	// each instance. 
	for (i = 0; i < INSTANCES; i++)
	{
		// Create an event object for this instance. 
		hEvents[i] = CreateEvent(
			NULL,    // default security attribute 
			TRUE,    // manual-reset event 
			TRUE,    // initial state = signaled 
			NULL);   // unnamed event object 

		if (hEvents[i] == NULL)
		{
			//printf("CreateEvent failed with %d.\n", GetLastError());
			return 0;
		}

		Pipe[i].oOverlap.hEvent = hEvents[i];
		Pipe[i].oOverlap.Offset = 0;
		Pipe[i].oOverlap.OffsetHigh = 0;

		std::wstring sPipeName = lpszPipename;
		Pipe[i].hPipeInst = CreateNamedPipe(
			sPipeName.c_str(),            // pipe name 
			PIPE_ACCESS_DUPLEX |     // read/write access 
			FILE_FLAG_OVERLAPPED,    // overlapped mode 
			PIPE_TYPE_MESSAGE |      // message-type pipe 
			PIPE_READMODE_MESSAGE |  // message-read mode 
			PIPE_WAIT,               // blocking mode 
			INSTANCES,               // number of instances 
			BUFSIZE * sizeof(TCHAR),   // output buffer size 
			BUFSIZE * sizeof(TCHAR),   // input buffer size 
			PIPE_TIMEOUT,            // client time-out 
			NULL);                   // default security attributes 

		if (Pipe[i].hPipeInst == INVALID_HANDLE_VALUE)
		{
			//printf("CreateNamedPipe failed with %d.\n", GetLastError());
			return 0;
		}

		// Call the subroutine to connect to the new client
		Pipe[i].fPendingIO = ConnectToNewClient(
			Pipe[i].hPipeInst,
			&Pipe[i].oOverlap);

		Pipe[i].dwState = Pipe[i].fPendingIO ?
			CONNECTING_STATE : // still connecting 
			READING_STATE;     // ready to read 
	}
	
	//CreateChildProcess();

	while (1)
	{
		// Wait for the event object to be signaled, indicating 
		// completion of an overlapped read, write, or 
		// connect operation. 
		dwWait = WaitForMultipleObjects(
			INSTANCES,    // number of event objects 
			hEvents,      // array of event objects 
			FALSE,        // does not wait for all 
			INFINITE);    // waits indefinitely 

		// dwWait shows which pipe completed the operation. 
		i = dwWait - WAIT_OBJECT_0;  // determines which pipe 
		if (i < 0 || i >(INSTANCES - 1))
		{
			//printf("Index out of range.\n");
			return 0;
		}

		// Get the result if the operation was pending. 
		if (Pipe[i].fPendingIO)
		{
			fSuccess = GetOverlappedResult(
				Pipe[i].hPipeInst, // handle to pipe 
				&Pipe[i].oOverlap, // OVERLAPPED structure 
				&cbRet,            // bytes transferred 
				FALSE);            // do not wait 

			switch (Pipe[i].dwState)
			{
				// Pending connect operation 
			case CONNECTING_STATE:
				if (!fSuccess)
				{
					//printf("Error %d.\n", GetLastError());
					return 0;
				}
				Pipe[i].dwState = READING_STATE;
				break;

				// Pending read operation 
			case READING_STATE:
				if (!fSuccess || cbRet == 0)
				{
					DisconnectAndReconnect(i);
					continue;
				}
				Pipe[i].cbRead = cbRet;
				Pipe[i].dwState = WRITING_STATE;
				break;

				// Pending write operation 
			case WRITING_STATE:
				if (!fSuccess || cbRet != Pipe[i].cbToWrite)
				{
					DisconnectAndReconnect(i);
					continue;
				}
				Pipe[i].dwState = READING_STATE;
				break;

			default:
			{
				//printf("Invalid pipe state.\n");
				return 0;
			}
			}
		}

		// The pipe state determines which operation to do next. 
		switch (Pipe[i].dwState)
		{
			// READING_STATE: 
			// The pipe instance is connected to the client 
			// and is ready to read a request from the client. 

		case READING_STATE:
			Pipe[i].cbRead = 0;
			fSuccess = ReadFile(
				Pipe[i].hPipeInst,
				Pipe[i].chRequest,
				BUFSIZE * sizeof(TCHAR),
				&Pipe[i].cbRead,
				&Pipe[i].oOverlap);

			// The read operation completed successfully. 
			if (fSuccess && Pipe[i].cbRead != 0)
			{
				Pipe[i].fPendingIO = FALSE;
				Pipe[i].dwState = WRITING_STATE;
				continue;
			}

			// The read operation is still pending. 
			dwErr = GetLastError();
			if (!fSuccess && (dwErr == ERROR_IO_PENDING))
			{
				Pipe[i].fPendingIO = TRUE;
				continue;
			}

			// An error occurred; disconnect from the client. 
			DisconnectAndReconnect(i);
			break;

			// WRITING_STATE: 
			// The request was successfully read from the client. 
			// Get the reply data and write it to the client. 
		case WRITING_STATE:
			GetAnswerToRequest(&Pipe[i]);
			fSuccess = WriteFile(
				Pipe[i].hPipeInst,
				Pipe[i].chReply,
				Pipe[i].cbToWrite,
				&cbRet,
				&Pipe[i].oOverlap);

			// The write operation completed successfully. 
			if (fSuccess && cbRet == Pipe[i].cbToWrite)
			{
				Pipe[i].fPendingIO = FALSE;
				Pipe[i].dwState = READING_STATE;
				std::cout << "[" << Pipe[i].hPipeInst << "] 响应客户端:" << ws2s(Pipe[i].chReply) << std::endl;
				continue;
			}

			// The write operation is still pending. 
			dwErr = GetLastError();
			if (!fSuccess && (dwErr == ERROR_IO_PENDING))
			{
				Pipe[i].fPendingIO = TRUE;
				continue;
			}

			// An error occurred; disconnect from the client. 
			DisconnectAndReconnect(i);
			break;
		default:
		{
			//printf("Invalid pipe state.\n");
			return 0;
		}
		}
	}

	return 0;
}


// DisconnectAndReconnect(DWORD) 
// This function is called when an error occurs or when the client 
// closes its handle to the pipe. Disconnect from this client, then 
// call ConnectNamedPipe to wait for another client to connect. 
VOID DisconnectAndReconnect(DWORD i)
{
	// Disconnect the pipe instance. 

	if (!DisconnectNamedPipe(Pipe[i].hPipeInst))
	{
		//printf("DisconnectNamedPipe failed with %d.\n", GetLastError());
	}

	// Call a subroutine to connect to the new client. 

	Pipe[i].fPendingIO = ConnectToNewClient(
		Pipe[i].hPipeInst,
		&Pipe[i].oOverlap);

	Pipe[i].dwState = Pipe[i].fPendingIO ?
		CONNECTING_STATE : // still connecting 
		READING_STATE;     // ready to read 
}

// ConnectToNewClient(HANDLE, LPOVERLAPPED) 
// This function is called to start an overlapped connect operation. 
// It returns TRUE if an operation is pending or FALSE if the 
// connection has been completed. 
BOOL ConnectToNewClient(HANDLE hPipe, LPOVERLAPPED lpo)
{
	BOOL fConnected, fPendingIO = FALSE;

	// Start an overlapped connection for this pipe instance. 
	fConnected = ConnectNamedPipe(hPipe, lpo);

	// Overlapped ConnectNamedPipe should return zero. 
	if (fConnected)
	{
		//printf("ConnectNamedPipe failed with %d.\n", GetLastError());
		return 0;
	}

	switch (GetLastError())
	{
		// The overlapped connection in progress. 
	case ERROR_IO_PENDING:
		fPendingIO = TRUE;
		break;

		// Client is already connected, so signal an event. 

	case ERROR_PIPE_CONNECTED:
		if (SetEvent(lpo->hEvent))
			break;

		// If an error occurs during the connect operation... 
	default:
	{
		//printf("ConnectNamedPipe failed with %d.\n", GetLastError());
		return 0;
	}
	}

	return fPendingIO;
}

VOID GetAnswerToRequest(LPPIPEINST pipe)
{
	std::wstring sMsg = L"------Default answer from server---- - Default answer from server Defaul\
		swer from server Default answer from serverDefault answer from serverDefault answer from server Default \
		Hello Message answer from server Default answer from serverDefault answer from serverDefault \
		answer from server Default answer from server Default answer from serverDefault answer from serverDefault \
		from serverDefault answer from serverDefault answer from serverDefault answer from serverDefault answer from serverDefault answer from";
	std::cout << "[" << pipe->hPipeInst << "] 接收到客户端消息:" << ws2s(pipe->chRequest) << std::endl;
	StringCchCopy(pipe->chReply, sMsg.size(), sMsg.c_str());
	pipe->cbToWrite = sMsg.size();
}

std::string ws2s(const std::wstring& ws)
{
	std::string curLocale = setlocale(LC_ALL, NULL); // curLocale = "C";  

	setlocale(LC_ALL, "chs");

	const wchar_t* _Source = ws.c_str();
	size_t _Dsize = 2 * ws.size() + 1;
	char* _Dest = new char[_Dsize];
	memset(_Dest, 0, _Dsize);
	wcstombs(_Dest, _Source, _Dsize);
	std::string result = _Dest;
	delete[]_Dest;

	setlocale(LC_ALL, curLocale.c_str());

	return result;
}

void CreateChildProcess()
// Create a child process that uses the previously created pipes for STDIN and STDOUT.
{
	TCHAR szCmdline[] = TEXT("D:\\xxx\\ConsoleApplication1\\Release\\TestPipe\\TestPipe.exe");
	PROCESS_INFORMATION piProcInfo;
	STARTUPINFO siStartInfo;
	BOOL bSuccess = FALSE;

	// Set up members of the PROCESS_INFORMATION structure. 

	ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));

	// Set up members of the STARTUPINFO structure. 
	// This structure specifies the STDIN and STDOUT handles for redirection.

	ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
	siStartInfo.cb = sizeof(STARTUPINFO);
	siStartInfo.hStdError = Pipe[1].hPipeInst;
	siStartInfo.hStdOutput = Pipe[1].hPipeInst;
	siStartInfo.hStdInput = Pipe[0].hPipeInst;
	siStartInfo.dwFlags |= STARTF_USESTDHANDLES ;
	siStartInfo.wShowWindow = SW_SHOW;

	// Create the child process. 

	bSuccess = CreateProcess(NULL,
		szCmdline,     // command line 
		NULL,          // process security attributes 
		NULL,          // primary thread security attributes 
		TRUE,          // handles are inherited 
		0,             // creation flags 
		NULL,          // use parent's environment 
		NULL,          // use parent's current directory 
		&siStartInfo,  // STARTUPINFO pointer 
		&piProcInfo);  // receives PROCESS_INFORMATION 

	// If an error occurs, exit the application. 
	if (!bSuccess)
		return;
	else
	{
		// Close handles to the child process and its primary thread.
		// Some applications might keep these handles to monitor the status
		// of the child process, for example. 

		CloseHandle(piProcInfo.hProcess);
		CloseHandle(piProcInfo.hThread);

		// Close handles to the stdin and stdout pipes no longer needed by the child process.
		// If they are not explicitly closed, there is no way to recognize that the child process has ended.

		//CloseHandle(g_hChildStd_OUT_Wr);
		//CloseHandle(g_hChildStd_IN_Rd);
	}
}

客户端步骤:
在win32种,因为有名管道可以是非血缘关系的进程,还可以是跨域的不通电脑设备,因此,管道名称的保存位置就很重要,方便各个客户端连接同一个服务端,管道名称可以写在注册表里面等。

  1. 创建文件(文件名是有名管道名称)
  2. 等待连接有名管道
  3. 设置管道状态特性
  4. 读写管道(业务操作)
//客户端侧,有名管道测试代码

// TestPipe.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#if 0 //匿名管道客户端
#include <windows.h>
#include <iostream>
#include <string>
int main()
{
	HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
	HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
    char szBuf[2048] = { 0 };
    DWORD nReaded = 0, nWrited = 0;
    std::string sReaded(""),sDefSendMsg(" TestPipe 发送给服务端Pipe的数据!\n"), sWrited("");
	BOOL bSuccess(FALSE);
	FILE* fp = fopen("d://xxx//TestPipe.txt", "a+");
	if (!fp)
		return -1;
    for (int i = 0; i < 10; i++)
    {
        //Sleep(1000 * 10);
        ZeroMemory(szBuf, 2048);
        sReaded = "第";
		sReaded += std::to_string(i + 1);
		sReaded += "个接收到服务端数据: ";
		ReadFile(hStdIn, szBuf, 2048, &nReaded, nullptr);
		sReaded += szBuf;
		
		sReaded += "\n";
        //::CloseHandle(hStdIn);
		fwrite(sReaded.c_str(), 1, sReaded.size(), fp);

		sWrited = "第";
		sWrited += std::to_string(i + 1);
		sWrited += sDefSendMsg;
		bSuccess = WriteFile(hStdOut, sWrited.c_str(), sWrited.size(), &nWrited, nullptr);
		if (!bSuccess)
			return -1;
		fwrite(sWrited.c_str(), 1, sWrited.size(), fp);
        //::CloseHandle(hStdOut);
		//getchar();
		fclose(fp);
    }
	fclose(fp);
	CloseHandle(hStdIn);
	CloseHandle(hStdOut);
	return 0;
}
#else //有名管道客户端
#include <windows.h> 
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#include <iostream>
#include <string>
#include <thread>
#define BUFSIZE 1024
std::string ws2s(const std::wstring& ws);

int _tmain(int argc, TCHAR* argv[])
{
	HANDLE hPipe;
	std::wstring sDefaultMsg = L"Default message from client.";
	std::wstring sWriteMsg = L"";
	std::wstring sReadedMsg = L"";
	TCHAR  chBuf[BUFSIZE];
	BOOL   fSuccess = FALSE;
	DWORD  cbRead, cbToWrite, cbWritten, dwMode;
	LPTSTR lpszPipename = (LPTSTR)L"\\\\.\\pipe\\mynamedpipe";

	if (argc > 1)
		sWriteMsg = argv[1];

	// Try to open a named pipe; wait for it, if necessary. 

	while (1)
	{
		hPipe = CreateFile(
			lpszPipename,   // pipe name 
			GENERIC_READ |  // read and write access 
			GENERIC_WRITE,
			0,              // no sharing 
			NULL,           // default security attributes
			OPEN_EXISTING,  // opens existing pipe 
			0,              // default attributes 
			NULL);          // no template file 

		// Break if the pipe handle is valid. 

		if (hPipe != INVALID_HANDLE_VALUE)
			break;

		// Exit if an error other than ERROR_PIPE_BUSY occurs. 

		if (GetLastError() != ERROR_PIPE_BUSY)
		{
			_tprintf(TEXT("Could not open pipe. GLE=%d\n"), GetLastError());
			return -1;
		}

		// All pipe instances are busy, so wait for 20 seconds. 

		if (!WaitNamedPipe(lpszPipename, 20000))
		{
			printf("Could not open pipe: 20 second wait timed out.");
			return -1;
		}
	}

	// The pipe connected; change to message-read mode. 

	dwMode = PIPE_READMODE_MESSAGE | PIPE_NOWAIT; //设置管道为非阻塞才生效
	fSuccess = SetNamedPipeHandleState(
		hPipe,    // pipe handle 
		&dwMode,  // new pipe mode 
		NULL,     // don't set maximum bytes 
		NULL);    // don't set maximum time 
	if (!fSuccess)
	{
		_tprintf(TEXT("SetNamedPipeHandleState failed. GLE=%d\n"), GetLastError());
		return -1;
	}

    //有名管道设置为非阻塞后,多线程也可以正常读取,不阻塞。有数据就读出来,没数据就立马返回。
	for (int i = 0; i < 10; i++)
	{
		// Send a message to the pipe server. 
		std::cout << "------第" << i + 1 << "次开始发送给服务器 Server Pipe" << std::endl;
		sWriteMsg = std::to_wstring(i + 1) + L" " + sDefaultMsg;
		fSuccess = WriteFile(
			hPipe,                  // pipe handle 
			sWriteMsg.c_str(),      // message 
			sWriteMsg.size() + 1,   // message length 
			&cbWritten,             // bytes written 
			NULL);                  // not overlapped 

		if (!fSuccess)
		{
			_tprintf(TEXT("WriteFile to pipe failed. GLE=%d\n"), GetLastError());
			return -1;
		}

		std::cout << __FUNCTION__ << "      发送成功:" << ws2s(sWriteMsg) << std::endl;

		std::thread th([&]() {
			// Read from the pipe. 
			ZeroMemory(chBuf, sizeof(chBuf));
		sReadedMsg = L"";
		while (ReadFile(
			hPipe,    // pipe handle 
			chBuf,    // buffer to receive reply 
			BUFSIZE * sizeof(TCHAR),  // size of buffer 
			&cbRead,  // number of bytes read 
			NULL) > 0)    // not overlapped 
		{
			sReadedMsg += chBuf;
			if (sReadedMsg.find(L"Hello Message"))
			{
				if (WriteFile(hPipe,
					"******** Hi,It's m e ******",
					27,
					&cbRead,
					nullptr) > 0)
				{
					std::cout << "Find Sucess!\n";
				}
			}
			if (cbRead <= 0)
				break;
		}
		std::cout << __FUNCTION__ << "      接收成功:" << ws2s(sReadedMsg) << std::endl;
			
		});
		th.detach();

		getchar();
	}

	CloseHandle(hPipe);
	getchar();

	return 0;
}

std::string ws2s(const std::wstring& ws)
{
	std::string curLocale = setlocale(LC_ALL, NULL); // curLocale = "C";  

	setlocale(LC_ALL, "chs");

	const wchar_t* _Source = ws.c_str();
	size_t _Dsize = 2 * ws.size() + 1;
	char* _Dest = new char[_Dsize];
	memset(_Dest, 0, _Dsize);
	wcstombs(_Dest, _Source, _Dsize);
	std::string result = _Dest;
	delete[]_Dest;

	setlocale(LC_ALL, curLocale.c_str());

	return result;
}

#endif


  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值