/////////////////////////////////////////
//CmdLine EditクラスCCMDEDIT定義ファイル
/////////////////////////////////////////

class CCMDEDIT : public CCTRL
{
public:
	int m_BuffSize;								//プロセス出力用文字列バッファー
	HANDLE m_hRead;								//読込用パイプハンドル
	HANDLE m_hProcess;							//子プロセスのハンドル
	char* m_Pre;								//表示先頭文字列
	char* m_Post;								//表示末尾文字列

public:
	CCMDEDIT();									//引数無しコンストラクター
	CCMDEDIT(int);								//引数付コンストラクター
	void SetSize(int);							//プロセス出力文字の最大数の設定
	bool Create(HWND, HINSTANCE, int, int,
				int, int, int);					//CCMDEDITコントロール作成関数
	char* GetLine(char*, WPARAM, LPARAM);		//カーソルのある1行を取得
	void Move(int, int, int, int);				//エデイットコントロールの移動
	bool Exec(char*, char*, char*);				//exeファイルの実行
	static DWORD WINAPI WaitThreadProc(LPVOID);	//プロセス終了待プロシジャー
};

//引数無しコンストラクター
CCMDEDIT::CCMDEDIT() {

	m_hWnd			= 0;
	m_dwExStyle		= WS_EX_CLIENTEDGE;
	m_lpClassName	= "EDIT";
	m_dwStyle		= WS_CHILD | WS_VISIBLE |
						WS_VSCROLL | ES_AUTOVSCROLL |
						WS_HSCROLL | ES_AUTOHSCROLL |
						ES_MULTILINE | ES_NOHIDESEL | ES_READONLY;
	SetSize(2);		//出力バッファーの規定値は2K byte
	m_Pre = 0;
	m_Post = 0;
}

//引数付コンストラクター
CCMDEDIT::CCMDEDIT(int i) {

	m_hWnd			= 0;
	m_dwExStyle		= WS_EX_CLIENTEDGE;
	m_lpClassName	= "EDIT";
	m_dwStyle		= WS_CHILD | WS_VISIBLE |
						WS_VSCROLL | ES_AUTOVSCROLL |
						WS_HSCROLL | ES_AUTOHSCROLL |
						ES_MULTILINE | ES_NOHIDESEL | ES_READONLY;
	SetSize(i);
	m_Pre = 0;
	m_Post = 0;
}

//プロセス出力文字の最大数の設定
void CCMDEDIT::SetSize(int i) {

	if(i < 1 || i > 64) {
		MessageBox(NULL, "サイズは1Kバイト単位で1-64で指定して下さい。", "エラー", MB_OK | MB_ICONSTOP);
		return;
	}
	m_BuffSize = i * 1024 - 1;
}

//CTABウィンドウ作成関数
bool CCMDEDIT::Create(HWND hWnd, HINSTANCE hInstance, int ID,
						int x = 0, int y = 0, int w = 0, int h = 0) {

	m_hInstance = hInstance;
	return CCTRL::Create("", m_dwStyle, m_dwExStyle, hWnd, ID, x, y, w, h);
}

//EDITコントロールは親にWM_COMMANDメッセージで通知を行うので
//LOWORD(wParam)でIDを調べて、このコントロールなら、
//フォーカスが当たった時のカーソルのある1行の文字列を取得
char* CCMDEDIT::GetLine(char* Buffer, WPARAM wParam, LPARAM lParam) {

	DWORD cp1, cp2, ln;
	switch(HIWORD(wParam)) {			//メッセージを調べて
	case EN_SETFOCUS:					//フォーカスが来た時に
		//カーソルのキャラクターインデックスを取得し
		SendMessage(m_hWnd, EM_GETSEL, (WPARAM)&cp1, (LPARAM)&cp2);
		//その行の最初と最後の文字キャラクターインデックスを取得し
		ln = SendMessage(m_hWnd, EM_LINEFROMCHAR, cp1, 0);
		cp1 = SendMessage(m_hWnd, EM_LINEINDEX, ln, 0);
		cp2 = SendMessage(m_hWnd, EM_LINEINDEX, ln + 1, 0);
		//その行を選択すると共に１行の文字列を取得する
		SendMessage(m_hWnd, EM_SETSEL, cp1, cp2);
		ln = SendMessage(m_hWnd, EM_GETLINE, ln, (LPARAM)Buffer);
		Buffer[ln] = NULL;				//取得した文字列をNULL終端する
		SetFocus(m_hParent);			//フォーカスを外す（親に移す）
		break;
	default:
		return NULL;
	}
	return Buffer;
}

//エデイットコントロールの移動
void CCMDEDIT::Move(int x, int y, int w, int h) {

	MoveWindow(m_hWnd, x, y, w, h, TRUE);
}

//exeファイルの実行
bool CCMDEDIT::Exec(char* FileName, char* Pre = 0, char* Post = 0) {

	//先頭、末尾の文字列の設定
	if(Pre)	m_Pre = Pre;
	if(Post)	m_Post = Post;
	//ローカル変数
	HANDLE hWrite;
	SECURITY_ATTRIBUTES sa;
	STARTUPINFO si;
	PROCESS_INFORMATION pi;
	//Security_Attributeの設定
	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
	sa.lpSecurityDescriptor = NULL;
	sa.bInheritHandle = TRUE;
	//親プロセスのパイプを作る
	if (!CreatePipe(&m_hRead, &hWrite, &sa, 0)) {
		MessageBox(m_hWnd, "パイプの作成に失敗しました", "エラー", MB_OK | MB_ICONSTOP);
		return FALSE;
	}
	//親の読込パイプを承継しない
	if (!DuplicateHandle(GetCurrentProcess(),	//ソースプロセス
			m_hRead,							//duplicateするハンドル(オリジナルハンドル)
			GetCurrentProcess(),				//ターゲットプロセス(行先)
			NULL,								//複製ハンドルへのポインタ(コピーハンドル)
			0,									//アクセス権
			FALSE,								//子供がハンドルを継承するかどうか
			DUPLICATE_SAME_ACCESS)) {			//オプション
				MessageBox(m_hWnd, "DuplicateHandleに失敗しました", "エラー", MB_OK | MB_ICONSTOP);
				CloseHandle(hWrite);
				CloseHandle(m_hRead);
				m_hRead = NULL;
				return FALSE;
	}
	//スタートアップ情報の設定（書込承継）
	ZeroMemory(&si, sizeof(STARTUPINFO));
	si.cb = sizeof(STARTUPINFO);
	si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
	si.wShowWindow = SW_HIDE;	//消して実行
	si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
	si.hStdOutput = hWrite;
	si.hStdError = GetStdHandle(STD_ERROR_HANDLE );
	if(!CreateProcess(NULL, FileName, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
		MessageBox(m_hWnd, "CreateProcessに失敗しました", "エラー", MB_OK);
		CloseHandle(m_hRead);
		m_hRead = NULL;
		return FALSE;
	} 
	m_hProcess = pi.hProcess;
	CloseHandle(hWrite);
	CloseHandle(pi.hThread);

	DWORD dwThreadID;
	HANDLE hThread;
	hThread = CreateThread(NULL, 0,
							(LPTHREAD_START_ROUTINE)WaitThreadProc,
							(LPVOID)this, 0, &dwThreadID);
	return TRUE;
}

//プロセス終了待プロシジャー
DWORD WINAPI CCMDEDIT::WaitThreadProc(LPVOID lpV) {

	CCMDEDIT* lpThis = (CCMDEDIT*)lpV;
	DWORD dwResult = 0;
	BOOL bSuccess;
	char* Buffer = new char [lpThis->m_BuffSize];
	lstrcpy(Buffer, lpThis->m_Pre);		//先頭文字列の設定
	char* cp = Buffer + lstrlen(lpThis->m_Pre);
	while(TRUE) {
		bSuccess = ReadFile(lpThis->m_hRead, cp += dwResult, sizeof(lpThis->m_BuffSize), &dwResult, NULL);
		if(!bSuccess) {
			break;
		}
	}
	Buffer[cp - Buffer] = NULL;
	lstrcat(Buffer, lpThis->m_Post);	//末尾文字列の設定
	SendMessage(lpThis->m_hWnd, WM_SETTEXT, 0, (LPARAM)Buffer);
	CloseHandle(lpThis->m_hRead);
	CloseHandle(lpThis->m_hProcess);
	delete [] Buffer;
	return dwResult;
}
