editor.hsp
/***********************************************************


	名なしパイプと独自メッセージによるプロセス間通信
	のサンプル。エディタ側スクリプト


		動作確認環境:  HSP3.1 beta3 / WinXP Pro SP2

		更新日:        2006/6/20


***********************************************************/


/******************************/
/* 実行ファイル作成オプション */
/******************************/
#packopt	name	"editor"
#packopt	runtime	"hsp3c.hrt"

/****************************/
/* Win32API用ヘッダファイル */
/****************************/
#include	"kernel32.as"

/********************************/
/* Editコントロール用メッセージ */
/********************************/
#const	WM_COPY		0x0301
#const	EM_GETSEL		0x00b0	// 選択範囲取得	wprm=pStart, lprm=pEnd
				//		戻り値=範囲
#const	EM_REPLACESEL	0x00c2	// 選択テキストを置換
				//	置換後、UNDO機能を有効にするとき	wprm=1
				//	置換後、UNDO機能を無効にするとき	wprm=0
				//	lprm=文字列変数のポインタ
				//	戻り値=0(エラーのとき)

/******************************************/
/* 外部プログラムとの通信用独自メッセージ */
/******************************************/
#const	WM_APP		0x8000
#const	EDT_WM_GETSELTEXT	WM_APP+0	// 外部プログラムからの選択テキスト送信要求
#const	EDT_WM_SETSELTEXT	WM_APP+1	// 外部プログラムからの置換用テキスト受信要求

/**************/
/* その他定数 */
/**************/
#const	TRUE	1
#const	FALSE	0
#const	NULL	0

#const	ERR_WRITEFILE	0	// WriteFile APIが失敗した

#const	SIZE_BUF		1024	// ReadFile/WriteFile用バッファサイズ

/**********************/
/* 自作汎用モジュール */
/**********************/
#include	"gm_clipboard_text.hsp"


	title "editor"


	/********************/
	/* 割り込み実行指定 */
	/********************/
	oncmd	gosub *OnToolMsg, EDT_WM_GETSELTEXT
	oncmd	gosub *OnToolMsg, EDT_WM_SETSELTEXT


	/**************/
	/* mesbox作成 */
	/**************/
	sdim 	_mboxbuf, 256*256
	notesel	_mboxbuf
	noteload	"editor.hsp"
	mesbox	_mboxbuf, ginfo(12), ginfo(13)-20, 5
	id	= stat
	_hmbox	= objinfo(id,2)		// mesboxのウィンドウハンドル


	/**********************************/
	/* 外部プログラム起動用ボタン作成 */
	/**********************************/
	objsize 200, 20
	button gosub "外部プログラム起動", *StartTool
;	pos 200,ginfo(13)-20 : mes hwnd


	/****************/
	/* メインループ */
	/****************/
	_toolmsg	= NULL	// メインループの中で0以外の値になったら
			// 外部プログラムから通信要求が来た合図
	_hpipe	= NULL	// 外部プログラムから受け取るパイプハンドル
			// (書き込み・読み出し兼用)
	_htoolwnd	= NULL	// 外部プログラムから受け取る外部プログラムのウィンドウハンドル
			// (このスクリプトの中では特に使用していません)

*EventLoop
	await 1

	switch	_toolmsg

	case	EDT_WM_GETSELTEXT
		gosub	*SendSelText
		swbreak

	case	EDT_WM_SETSELTEXT
		gosub	*ReplaceSelText
		swbreak

	swend

	goto *EventLoop


	/****************************/
	/* 割り込み実行サブルーチン */
	/****************************/

*OnToolMsg
	/* メッセージ、WPARAM、LPARAMを記録 */
	_toolmsg		= iparam
	_hpipe		= wparam
	_htoolwnd		= lparam
	return

*StartTool
	/* 外部プログラム起動 */
	exec "tool"
	return


	/********************************/
	/* 選択テキスト送信サブルーチン */
	/********************************/
*SendSelText

	/* mesboxから選択テキストを取得 */
	startidx	= 0
	endidx	= 0
	sendmsg	_hmbox, EM_GETSEL, varptr(startidx), varptr(endidx)
	if (endidx - startidx)=0 {
		goto *@f	// 選択テキストがなければなにも送らない
	}
	sendmsg	 _hmbox, WM_COPY, 0, 0
	seltext	 = ""
	getcbtext	 seltext

	/* WriteFileするべき回数を取得 */
	seltextlen	= strlen(seltext)
	loopcnt		= seltextlen / SIZE_BUF
	if (seltextlen \ SIZE_BUF)!0 {
		loopcnt ++
	}

	/* パイプを通じてデータを送信 */
	curidx	= 0
	size	= 0			// WriteFile書き込みサイズ
	repeat loopcnt
	
		sdim buf, SIZE_BUF + 1	// WriteFile用バッファ
	
		/* WriteFileするデータを取得 */
		if cnt=(loopcnt-1) {	// 最後のループ
			memcpy buf, seltext, seltextlen-curidx, 0, curidx
		}
		else {
			memcpy buf, seltext, SIZE_BUF, 0, curidx
			curidx += SIZE_BUF
		}
	
		WriteFile _hpipe, buf, strlen(buf), varptr(size), NULL
		if stat=ERR_WRITEFILE {	
			break
		}
	loop

*@
	CloseHandle _hpipe
	_hpipe	= NULL
	_toolmsg	= NULL

	return


	/**********************************************/
	/* テキスト受信・選択テキスト置換サブルーチン */
	/**********************************************/
*ReplaceSelText

	/* パイプを通じてデータを受け取る */
	seltext	= ""			// データ受け取り用バッファ
	size	= 0			// ReadFile読み取りサイズ
	repeat
		sdim buf, SIZE_BUF + 1	// ReadFile用バッファ

		ReadFile _hpipe, varptr(buf), SIZE_BUF, varptr(size), NULL
		if stat {			// ReadFile成功
			if size=0 {	// 読み取り完了
				break
			}
			seltext += buf
		}
		else {			// ReadFile失敗
			break
		}
	loop

	CloseHandle _hpipe
	_hpipe	= NULL
	_toolmsg	= NULL

	/* 受け取ったテキストと選択テキストを置換 */
	sendmsg _hmbox, EM_REPLACESEL, TRUE, varptr(seltext)

	return


tool.hsp
/***********************************************************


	名なしパイプと独自メッセージによるプロセス間通信
	のサンプル。外部プログラム側スクリプト


		動作確認環境:  HSP3.1 beta3 / WinXP Pro SP2

		更新日:        2006/6/20


***********************************************************/


/******************************/
/* 実行ファイル作成オプション */
/******************************/
#packopt	name	"tool"
#packopt	runtime	"hsp3c.hrt"
#packopt	hide	1

/****************************/
/* Win32API用ヘッダファイル */
/****************************/
#include	"user32.as"
#include	"kernel32.as"

/************************************/
/* エディタとの通信用独自メッセージ */
/************************************/
#const	WM_APP		0x8000
#const	EDT_WM_GETSELTEXT	WM_APP+0	// エディタへの選択テキスト送信要求
#const	EDT_WM_SETSELTEXT	WM_APP+1	// エディタへの置換用テキスト受信要求

/**************/
/* その他定数 */
/**************/
#const	TRUE	1
#const	FALSE	0
#const	NULL	0

#const	OK	0
#const	ERROR	-1

#define	ERR_MES_0		"エラー"
#define	ERR_MES_1		"エディタのプロセスハンドルの取得に失敗しました。tool.exeを終了します。"
#define	ERR_MES_2		"パイプの作成に失敗しました。tool.exeを終了します。"

#const	SIZE_SEC_ATTR		12	// SECURITY_ATTRIBUTES構造体サイズ

#const	SIZE_BUF			1024	// ReadFile/WriteFile用バッファサイズ

#const	PROCESS_DUP_HANDLE		0x40	// OpenProcess API引数用
					// (プロセスハンドルをDuplicateHandle APIで使えるように)

#const	DUPLICATE_CLOSE_SOURCE	0x01	// DuplicateHandle API動作オプション指定用
					// (コピー元のハンドルをクローズする)
#const	DUPLICATE_SAME_ACCESS	0x02	// DuplicateHandle API動作オプション指定用
					// (第5引数を無視する)


	/******************/
	/* 重要な変数一覧 */
	/******************/
	_heditwnd		= NULL		// エディタのウィンドウハンドル
	_heditproc	= NULL		// エディタのプロセスハンドル
	_hmyproc		= NULL		// 自分の(擬似)プロセスハンドル
	_hpread		= NULL		// 名なしパイプの読み出し側ハンドル
	_hpwrite		= NULL		// 名なしパイプの書き込み側ハンドル
	_hpedit		= NULL		// エディタに渡すパイプハンドル(書き込み・読み出し兼用)


	/**********************************************************/
	/* フォアグラウンドウィンドウ(エディタ)のハンドルを取得 */
	/*  -> プロセスIDを取得 -> プロセスハンドルを取得         */
	/**********************************************************/
	GetForegroundWindow
	_heditwnd = stat

	procid	= NULL
	GetWindowThreadProcessId _heditwnd, varptr(procid)

	desiredaccess	= PROCESS_DUP_HANDLE
	OpenProcess desiredaccess, FALSE, procid
	_heditproc	= stat
	if _heditproc=NULL {
		dialog ERR_MES_1, 1, ERR_MES_0
		end
	}


	/****************************************/
	/* 自分の(擬似)プロセスハンドルを取得 */
	/****************************************/
	GetCurrentProcess
	_hmyproc	= stat


	/****************************************/
	/* エディタのmesboxの選択テキストを取得 */
	/****************************************/

	/* 名なしパイプを作成 */
	gosub *CreatePipe_
	if result=ERROR {
		dialog ERR_MES_2, 1, ERR_MES_0
		goto *Quit
	}

	/* エディタに渡すパイプハンドル(書き込み側)を複製 */
	_hpedit	= NULL
	opt	= DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS
	DuplicateHandle _hmyproc, _hpwrite, _heditproc, varptr(_hpedit), NULL, FALSE, opt

	/* 通信の準備を促すメッセージをパイプハンドルと共にエディタに送信 */
	sendmsg _heditwnd, EDT_WM_GETSELTEXT, _hpedit, hwnd
	await 1		// これを入れないとなぜかうまくいかない

	/* 不要なハンドルを閉じる */
	CloseHandle _hpedit

	/* パイプを通じてデータを受け取る */
	seltext	= ""			// データ受け取り用バッファ
	size	= 0			// ReadFile読み取りサイズ
	repeat
		sdim buf, SIZE_BUF + 1	// ReadFile用バッファ
		ReadFile _hpread, varptr(buf), SIZE_BUF, varptr(size), NULL
		if stat {			// ReadFile成功
			if size=0 {	// 読み取り完了
				break
			}
			seltext += buf
		}
		else {			// ReadFile失敗
			break
		}
	loop

	/* 残りのハンドルを閉じる */
	CloseHandle _hpread


	/**************************************/
	/* エディタから取得したテキストを加工 */
	/**************************************/
	textlen = strlen(seltext)
	if textlen=0 {	// エディタでテキストが選択されていなければなにもしない
		goto *Quit
	}

	// 全行頭に"// "を追加
	notesel seltext
	repeat notemax
		noteget linestr, cnt
		linestr = "// " + linestr
		noteadd linestr, cnt, 1
	loop


	/**************************************************************************/
	/* エディタのmesboxの選択テキストと置換するためのテキストをエディタに送信 */
	/**************************************************************************/

	/* 名なしパイプを作成 */
	gosub *CreatePipe_
	if result=ERROR {
		dialog ERR_MES_2, 1, ERR_MES_0
		goto *Quit
	}

	/* エディタに渡すパイプハンドル(読み出し側)を複製 */
	_hpedit	= NULL
	opt	= DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS
	DuplicateHandle _hmyproc, _hpread, _heditproc, varptr(_hpedit), NULL, FALSE, opt

	/* 通信の準備を促すメッセージをパイプハンドルと共にエディタに送信 */
	sendmsg _heditwnd, EDT_WM_SETSELTEXT, _hpedit, hwnd

	/* 不要なハンドルを閉じる */
	CloseHandle _hpedit

	/* WriteFileするべき回数を取得 */
	seltextlen	= strlen(seltext)
	loopcnt		= seltextlen / SIZE_BUF
	if (seltextlen \ SIZE_BUF)!0 {
		loopcnt ++
	}

	/* パイプを通じてデータを送信 */
	curidx	= 0
	size	= 0			// WriteFile書き込みサイズ
	repeat loopcnt
	
		/* WriteFile用バッファ */
		sdim buf, SIZE_BUF + 1
	
		/* WriteFileするデータを取得 */
		if cnt=(loopcnt-1) {	// 最後のループ
			memcpy buf, seltext, seltextlen-curidx, 0, curidx
		}
		else {
			memcpy buf, seltext, SIZE_BUF, 0, curidx
			curidx += SIZE_BUF
		}
	
		WriteFile _hpwrite, buf, strlen(buf), varptr(size), NULL
		if stat=ERR_WRITEFILE {	
			break
		}
	loop

	/* 残りのハンドルを閉じる */
	CloseHandle _hpwrite


	/**********/
	/* 後始末 */
	/**********/
*Quit
	CloseHandle _heditproc
	end


	/********************************/
	/* 名なしパイプ作成サブルーチン */
	/********************************/
*CreatePipe_
	_hpread	= NULL				// 読み出し側ハンドル
	_hpwrite	= NULL				// 書き込み側ハンドル
	secattr	= SIZE_SEC_ATTR, NULL, FALSE	// SECURITY_ATTRIBUTES構造体
	CreatePipe varptr(_hpread), varptr(_hpwrite), varptr(secattr), 0
	if stat=FALSE {
		result = ERROR
	}
	else {
		result = OK
	}
	return