Named pipeのラッパ作った

template<typename T=void>
struct WinResult {
	WinResult<T>() {
		success=false;
		error=::GetLastError();
	}
	WinResult<T>(BOOL res,T val)  {
		if(res) {success=true;value=val;}
		else {success=false;error=::GetLastError();}
	}
	WinResult(const WinResult& rhs):success(rhs.success),error(rhs.error),value(rhs.value) {}
	operator bool() {return success;}
	bool success;
	DWORD error;
	T value;
};
template<>
struct WinResult<void> {
	WinResult(BOOL res) {
		if(res) {success=true;}
		else {success=false;error=::GetLastError();}
	}
	WinResult(const WinResult& rhs):success(rhs.success),error(rhs.error) {}
	operator bool() {return success;}
	bool success;
	DWORD error;
};

class WinError {
public:
	WinError(DWORD err):error(err) {}
	WinError() {error=::GetLastError();}
	DWORD error;
};

class NamedPipeWrapper {
public:
	NamedPipeWrapper(HANDLE h) : m_handle(h) {}
	WinResult<std::string> Read() {
		const int bufsize=1024;
		char buf[bufsize];
		DWORD read_bytes;
		std::string result;
		while(!::ReadFile(m_handle,buf,bufsize,&read_bytes,0)) {
			if(GetLastError() != ERROR_MORE_DATA) return WinResult<std::string>();
			result.append(buf,read_bytes);
		}
		result.append(buf,read_bytes);
		return WinResult<std::string>(true,result);
	}
	WinResult<> Write(std::string content) {
		DWORD writen_bytes;
		return ::WriteFile(m_handle,content.c_str(),content.length()+1,&writen_bytes,0);
	}
	WinResult<> Flush() {
		return ::FlushFileBuffers(m_handle);
	}
	void Close() {
		Challange( ::CloseHandle(m_handle) );
	}
	bool IsValid() { return m_handle != INVALID_HANDLE_VALUE; }

	~NamedPipeWrapper() {
		Disconnect();
		Close();
	}

	// ================= for server ================= 
	WinResult<> Connect() {
		return ::ConnectNamedPipe(m_handle,0);
	}
	void Disconnect() {
		Challange( ::DisconnectNamedPipe(m_handle) );
	}
private:
	NamedPipeWrapper(const NamedPipeWrapper &rhs){}
	void Challange(BOOL success) {
		if(THROW_ON_ERROR && !success) throw WinError();
	}
	HANDLE m_handle;
	const static bool THROW_ON_ERROR=false;
};

ほんのちょっとコーディングが楽になった。

使用例(クライアント):

int _tmain(int argc, _TCHAR* argv[])
{
	NamedPipeWrapper pipe(CreateFile(
		L"\\\\.\\pipe\\my_named_pipe",
		GENERIC_READ | GENERIC_WRITE,
		0,
		NULL,
		OPEN_EXISTING,
		0,
		NULL));
	if(!pipe.IsValid()) {
		
		cerr << "couldn't open pipe" << endl;
		return -1;
	}

	//send msg
	string msg;
	while(msg!="exit") {
		getline(cin,msg);
		WinResult<> res=pipe.Write(msg); 
		pipe.Flush(); //flushすると相手が受信するまでブロックする(明示的にflushしないとバッファがいっぱいになるまでブロックしない)
		if(!res) {
			if(res.error==ERROR_PIPE_NOT_CONNECTED) {
				cout << "disconnected." << endl;
				break;
			}
			cerr << "WriteFile failed:" << GetLastError() << endl;
			break;
		}
	}
	pipe.Flush();
	pipe.Close();

	return 0;
}

サーバサイド:

int _tmain(int argc, _TCHAR* argv[])
{
	NamedPipeWrapper pipe( CreateNamedPipe(L"\\\\.\\pipe\\my_named_pipe",
		PIPE_ACCESS_DUPLEX,
		0,
		PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_NOWAIT,
		1,
		1024,
		NMPWAIT_NOWAIT,
		NULL) );
	if(!pipe.IsValid()) {
		cerr << "failed create pipe" << endl;
		return -1;
	}
	bool quit=false;
	while(!quit) {
		cout << "wait for client..." << endl;
		while(1) { //wait for connect
			WinResult<> res=pipe.Connect();
			if(!res && res.error==ERROR_PIPE_CONNECTED) break;
		}
		cout << "connected." << endl;
		while(1) {
			WinResult<string> res=pipe.Read();
			if(!res) {
				if(res.error == ERROR_BROKEN_PIPE) {
					cout << "disconnected." << endl;
					break;
				}
				cerr << "ReadFile() failed." << endl;
				break;
			}
			if(res.value=="server_exit") {quit=true;break;}
			cout << res.value << endl;
		}
		pipe.Disconnect();
	}
	pipe.Close();
	return 0;
}

汚いソースだ しかし修正する気はない