[an error occurred while processing this directive] [an error occurred while processing this directive]

Windowsで名前付きパイプ (Visual C++)

名前付きパイプは、同じマシンで動いている二つのプロセス(プログラム)が通信する仕組みです。 Unix/Linuxではおなじみの名前付きパイプですが、Windowsでも使うことが出来ます。 95, 98, MEはだめらしいですが、そろそろME使ってる人もいなくなってきたんじゃないかな。 実は異なるマシンでも使えるとかいう話もあるようですが、そういう場合はソケットを使うほうが無難でしょう。
はまりどころだったのは、 あたりです。

使い方ですが、空のプロジェクトを用意して、下のソースをコピーして、 ヘッダファイルをstdafx.hあたりでincludeするとコンパイルできます。 片方を
c:\> pipe_server.exe hoge
みたいに引数をなんかつけて実行すると、サーバーモードで、新しく名前付きpipeを作ります。
c:\> pipe_server.exe 
みたいに引数をつけないと、クライアントモードで、既存の名前付きpipeに接続します。
// pipe_server.cpp : パイプのサンプル
//
// includeするもの:
// #include <windows.h>
// #include <conio.h>
// #include <process.h>
// #include <iostream>


#include "stdafx.h"
#define PIPE_NAME "\\\\.\\pipe\\hello_pipe3"
#define TIME_OUT 120 * 1000

bool debug = false;


/** エラーを表示して終了する */
void err_exit(char *cp){
    DWORD eno = GetLastError();
	std::cerr << "Error: " << cp << " errcode=" << eno << std::endl;
	ExitProcess(eno);	
}


/** エラーを表示して、パイプを閉じて終了する */
void err_close_exit(char *cp, HANDLE h){
    int eno = GetLastError();
	std::cerr << "Error: " << cp << " errcode=" << eno << std::endl;
    CloseHandle(h);	
	ExitProcess(eno);	
}




class PipeBase {
	/**
	  * パイプのベースクラス (read/writeを備える) 
	  */

protected:
	HANDLE hPipe;
public:
	void read(char *buf, int buflen, int read_len){
		/** バッファbuf(長さbuflen)に、read_lenで指定されたバイト数読み込む。*/

		int already_read = 0;
		if(read_len >= buflen)
			err_close_exit("Too small buffer", hPipe);

		while(already_read < read_len){
			DWORD actual_len;
			int ret = ReadFile(hPipe, buf + already_read, read_len - already_read, &actual_len, NULL);
			if(debug)
				std::cout << "Read "<< actual_len << " bytes" << std::endl;
			already_read += actual_len;
			if(!ret) err_close_exit("ReadFile", hPipe);
		}
		 // おせっかいかもしれないけど、coutとかでうまく表示できるように最後を\0でつぶしておく。
		buf[read_len] = '\0';
		if(debug) std::cout << "Server read: " << buf << std::endl;
	}


	void write(char *buf, int write_len){
		if(debug)
			std::cerr << "% Writing to HANDLE " << hPipe << std::endl;
		/** バッファbufから、write_lenで指定されたバイト数書き込む。*/
		int already_written = 0;
		while(already_written < write_len){
			DWORD actual_len;
			int ret = WriteFile(hPipe, buf + already_written, write_len - already_written, &actual_len, NULL);
			if(debug)
				std::cout << "% Wrote "<< actual_len << " bytes" << " (tried to write " << write_len << ")" << std::endl;
			already_written += actual_len;
			if(!ret) err_close_exit("WriteFile", hPipe);
		}
	}

};



class PipeServer : public PipeBase {
	/** パイプのサーバ (名前付きパイプを作り、clientからの入力を待つ) */

public:
	PipeServer(char *pipe_name, int dwBufferSize = 1024){ 
	/** 
	  * コンストラクタ。
	 * パイプを作り、クライアントの接続を待つ。 
	  */

		hPipe = CreateNamedPipe(
					pipe_name,                  /* パイプ名 */
					PIPE_ACCESS_DUPLEX,          /* 双方向 */
					PIPE_WAIT                    /* ブロッキング・モード */
					| PIPE_READMODE_BYTE         /* バイト・モード */
					| PIPE_TYPE_BYTE,
					PIPE_UNLIMITED_INSTANCES,    /* インスタンス数の制限なし */
					dwBufferSize,                /* 出力バッファ・サイズ */
					dwBufferSize,                /* 入力バッファ・サイズ */
					TIME_OUT,                    /* タイムアウト */
					NULL);                       /* セキュリティ属性なし */

		if(hPipe == INVALID_HANDLE_VALUE){
			int eno = GetLastError();
			if(eno == 123){
				std::cerr << "Pipename format is wrong" << std::endl;
				ExitProcess(eno);
			} else {
				err_exit("CreateNamedPipe");
			}
		}
		if(debug) 
			std::cerr << "% Pipe has successfully created" << std::endl;

		// クライアントの接続待ち
		int ret = ConnectNamedPipe(hPipe, NULL);
		if(!ret) err_close_exit("ConnectNamedPipe", hPipe);
		if(debug) std::cerr << "% Client has connected" << std::endl;
	}
	
	~PipeServer(){ CloseHandle(hPipe);}
};



class PipeClient : public PipeBase {
	/** パイプのクライアント (名前付きパイプを作り、サーバに接続する) */

public:
	PipeClient(char *pipe_name, int dwBufferSize = 1024){ 
		/** 
		  * コンストラクタ。
		 * 名前を指定して、パイプに接続する。 
		  */

		hPipe = CreateFile(pipe_name,                             /* パイプ名 */
							GENERIC_WRITE | GENERIC_READ,          /* 読み書きアクセス */
							FILE_SHARE_READ | FILE_SHARE_WRITE,    /* 読み書きアクセス共有 */
							NULL,                                  /* セキュリティ属性なし */
							OPEN_EXISTING,                         /* 既存の名前付きパイプに接続 */
							FILE_ATTRIBUTE_NORMAL,                 /* ファイル属性なし */
							NULL);                                 /* テンプレート・ファイルなし */
		std::cerr << "HANDLE " << hPipe << std::endl;
		if (hPipe == INVALID_HANDLE_VALUE) {
			int eno = GetLastError();
			if(eno == ERROR_FILE_NOT_FOUND){
				std::cerr << "Specified Pipe Not Found" << std::endl;
				ExitProcess(eno);	
			} else {
				err_exit("CreateFile");
			}
		}
		if(debug) std::cerr << "Successfully connected to the named-pipe" << std::endl;
	}		

	~PipeClient(){ CloseHandle(hPipe);}
};



int main(int argc, char* argv[])
{
	if(argc == 2){
		PipeServer ps(PIPE_NAME);
		const int LEN = 1024;
		char buf[LEN];
		ps.read(buf, LEN, 5);
		std::cerr << "Received " << buf << std::endl;
	} else {
		char *cp = "hello";
		PipeClient pc(PIPE_NAME);
		pc.write(cp, 5);
		Sleep(100);
		std::cerr << "Sent " << cp << std::endl;
	}
 
	return 0;
}
[an error occurred while processing this directive]