最後にCommandProc.hを(解説:)付きで載せます。
【CommandProc.h】
//////////////////////////////////////////
// CommandProc.h
// Copyright (c) 11/15/2021 by BCCSkelton
//////////////////////////////////////////
/////////////////////////////////
//主ウィンドウCMyWndの関数の定義
//ウィンドウメッセージ関数
/////////////////////////////////
bool CMyWnd::OnInit(WPARAM wPram, LPARAM lParam) {
//起動時のカレントディレクトリーを記録
GetCurrentDirectory(MAX_PATH, m_CPath);
//(解説:起動時のCommand.exeのパスをカレントディレクトリーのメンバー変数に記録しておきます。)
//ボタンにツールヒントコントロールを付ける
SetToolTip(m_hWnd, IDC_CD, "ディレクトリーを変更します");
SetToolTip(m_hWnd, IDC_EXE, "引数付きで外部コマンド(実行ファイル)を実行します");
SetToolTip(m_hWnd, IDC_DIR, "現在のディレクトリーでExplorerを起動します");
SetToolTip(m_hWnd, IDC_CMD, "現在のディレクトリーでコマンドプロンプトを起動します");
SetToolTip(m_hWnd, IDC_PS, "現在のディレクトリーでパワーシェルを起動します");
SetToolTip(m_hWnd, IDOK, "終了します");
//(解説:前にやったようにコントロールに吹き出しヒントを付けます。)
return TRUE;
}
bool CMyWnd::OnClose(WPARAM wPram, LPARAM lParam) {
//終了時にログがあれば記録する
if(*m_Log.ToChar()) {
//本日のローカル日付をdate文字列に入れる
SYSTEMTIME st;
char date[12];
GetLocalTime(&st);
wsprintf(date, "%2d-%2d-%4d", st.wMonth, st.wDay, st.wYear);
//(解説:dateは"mm-dd-yy"書式の日付を記憶します。)
//ファイル名("(ファイルパス)\LogOfMM/DD/YYYY.log")をnmにセット
CSTR nm;
CARG arg;
nm = arg.Path();
nm = nm + "\\LogOf";
nm = nm + date;
nm = nm + ".log";
//(解説:CSTR変数nmにファイルパス、名を入れます。)
//ログを保存する(後にバッチファイルとして使える)
m_Log.ToFile(nm.ToChar());
//(解説:CSTRのメンバー変数m_Logにあるデータを書き出します。)
MessageBox(m_hWnd, "操作ログを保存しました\n(バッチファイルとして使用することができます)", "操作ログ", MB_OK | MB_ICONINFORMATION);
}
return TRUE;
}
//ダイアログベースの場合はこれが必要
bool CMyWnd::OnDestroy(WPARAM wPram, LPARAM lParam) {
PostQuitMessage(0);
return TRUE;
}
/////////////////////////////////
//主ウィンドウCMyWndの関数の定義
//メニュー項目、コントロール関数
/////////////////////////////////
bool CMyWnd::OnCd() {
//移動先パスを取得
char* cp = cmndlg.GetPath(m_hWnd, "移動先ディレクトリーの選択");
if(cp) {
SetCurrentDirectory(cp);
//移動先パスを(m_CPathに記録
lstrcpy(m_CPath, cp);
//操作ログを記録
m_Log = m_Log + "cd \"";
m_Log = m_Log + cp;
m_Log = m_Log + "\"\n";
return TRUE;
//(解説:フォールダー(ディレクトリー)選択ダイアログを使って移動先のパスを取り、カレントディレクトリーとして記録して、ログに書きます。)
}
else {
MessageBox(m_hWnd, "操作がキャンセルされました", "エラー", MB_OK | MB_ICONERROR);
return FALSE;
}
}
bool CMyWnd::OnDir() {
//エクスプローラーを/eオプションで起動
CSTR path = "explorer.exe /e, ";
path = path + m_CPath;
WinExec(path.ToChar(), SW_SHOWNORMAL);
return TRUE;
//(解説:コメント通りです。)
}
bool CMyWnd::OnExe() {
//IDD_ARGダイアログを開く
exedlg.DoModal(m_hWnd, "IDD_EXE", exedlgProc, m_hInstance);
//(解説:IDD_EXEダイアログに処理を任せます。)
//ダイアログの操作でカレントディレクトリーが変更された可能性がある為
SetCurrentDirectory(m_CPath);
//(解説:IDD_EXEダイアログを開く前のカレントディレクトリーに移動します。)
return TRUE;
}
bool CMyWnd::OnCmd() {
//コマンドプロンプトを起動
WinExec("cmd.exe", SW_SHOWNORMAL);
//(解説:DOS窓が開きます。)
return TRUE;
}
bool CMyWnd::OnPs() {
//コマンドプロンプトを起動
WinExec("powershell.exe", SW_SHOWNORMAL);
//(解説:PowerShellを起動します。)
return TRUE;
}
bool CMyWnd::OnIdok() {
SendMsg(WM_CLOSE, 0, 0);
return TRUE;
}
bool CMyWnd::OnCancel() {
SendMsg(WM_CLOSE, 0, 0);
return TRUE;
}
//(解説:前にも書きましたが、コントロールが無くても'Esc'キー対応の為に書いておきます。)
///////////////////////////////
//IDD_EXEダイアログの関数定義
//ウィンドウメッセージ関数
///////////////////////////////
bool EXEDLG::OnInit(WPARAM wPram, LPARAM lParam) {
//クライアントエリア初期化
RECT rec;
GetClientRect(m_hWnd, &rec);
m_Width = rec.right - rec.left; //405
m_Height = rec.bottom - rec.top; //371
//(解説:コメントの数値はCommand.rcのダイアログの初期値です。)
//コモンコントロールの初期化
InitCommonControls();
//(解説:ステータスバーの為に必要です。)
//ステータスバー登録-SetHandle(hWnd))
SBar.SetHandle(GetDlgItem(m_hWnd, IDC_STATUSBAR));
//ステータスバー区画設定
int sec[1] = {-1};
SBar.SetSection(1, sec);
//ステータスバー文字列設定
SBar.SetText(0, "実行ファイル名-「ファイル」ボタンで選択");
//(解説:ステータスバーの初期化です。ステータスバーには実行ファイルを表示させます。)
//ファイルボタンにツールヒントコントロールを付ける
SetToolTip(m_hWnd, IDC_FILE1, "実行ファイルを選択します");
SetToolTip(m_hWnd, IDC_FILE2, "引数1にファイルパス・名を使用します");
SetToolTip(m_hWnd, IDC_FILE3, "引数2にファイルパス・名を使用します");
SetToolTip(m_hWnd, IDC_FILE4, "引数3にファイルパス・名を使用します");
SetToolTip(m_hWnd, IDC_DONE, "最終コマンドを標示します");
SetToolTip(m_hWnd, IDOK, "最終コマンドを実行します");
SetToolTip(m_hWnd, IDCANCEL, "終了します");
//(解説:ツールヒントの設定です。)
//コマンドエディットコントロールの初期化
g_CE.m_hWnd = GetDlgItem(m_hWnd, IDC_EXEDIT);
g_CE.m_hInstance = m_hInstance;
g_CE.SetFont(8, "MS 明朝");
//(解説:CCMDEDITのインスタンスg_CEのウィンドウとインスタンスのハンドルにIDC_EXEのものを代入し、フォントを設定します。)
return TRUE;
}
bool EXEDLG::OnSize(WPARAM wParam, LPARAM lParam) {
//ステータスバー再設定
SBar.AutoSize();
//コントロールの位置、サイズ変更
RECT rec; //矩形取得用
POINT pt; //スクリーン座標変換用
int w, h; //幅、高さ計算用
int diffx = LOWORD(lParam) - m_Width; //前回と今回の差分
int diffy = HIWORD(lParam) - m_Height; //前回と今回の差分
m_Width = LOWORD(lParam); //今回の幅
m_Height = HIWORD(lParam); //今回の高さ
//(解説:今回のサイズ変更の際のコントロール移動は差異を使って行います。考え方はWM_SIZEが呼ばれる度に前回の幅と高さとの差異を計算し、コントロールの位置にx, yの差異を反映させ、新しい幅と高さを記録する、という処理です。)
//左右移動のみ
//IDC_FILE1
GetWindowRect(GetDlgItem(m_hWnd, IDC_FILE1), &rec); //ウィンドウ位置取得
w = rec.right - rec.left;
h = rec.bottom - rec.top;
pt.x = rec.left;
pt.y = rec.top;
ScreenToClient(m_hWnd, &pt);
MoveWindow(GetDlgItem(m_hWnd, IDC_FILE1), pt.x + diffx, pt.y, w, h, TRUE);
//IDC_DONE
GetWindowRect(GetDlgItem(m_hWnd, IDC_DONE), &rec); //ウィンドウ位置取得
w = rec.right - rec.left;
h = rec.bottom - rec.top;
pt.x = rec.left;
pt.y = rec.top;
ScreenToClient(m_hWnd, &pt);
MoveWindow(GetDlgItem(m_hWnd, IDC_DONE), pt.x + diffx, pt.y, w, h, TRUE);
//(解説:前回の位置を取得し、コントロールのサイズは変更しないのでw, hを変えずにx位置のみに差異を反映させます。)
//幅変更のみ
//IDC_EDIT1, IDC_EDIT2, IDC_EDIT3
for(int i = IDC_EDIT1; i <= IDC_EDIT3; i++) {
GetWindowRect(GetDlgItem(m_hWnd, i), &rec); //ウィンドウ位置取得
w = rec.right - rec.left;
h = rec.bottom - rec.top;
pt.x = rec.left;
pt.y = rec.top;
ScreenToClient(m_hWnd, &pt);
MoveWindow(GetDlgItem(m_hWnd, i), pt.x, pt.y, w + diffx, h, TRUE);
}
//(解説:前回の位置を取得し、コントロールの高さは変更しないのでwとx位置のみに差異を反映させます。)
//上下移動のみ
//IDCANCEL
GetWindowRect(GetDlgItem(m_hWnd, IDCANCEL), &rec); //ウィンドウ位置取得
w = rec.right - rec.left;
h = rec.bottom - rec.top;
pt.x = rec.left;
pt.y = rec.top;
ScreenToClient(m_hWnd, &pt);
MoveWindow(GetDlgItem(m_hWnd, IDCANCEL), pt.x, pt.y + diffy, w, h, TRUE);
//(解説:前回の位置を取得し、コントロールのサイズは変更しないのでw, hを変えずにy位置のみに差異を反映させます。)
//左右上下移動
//IDOK
GetWindowRect(GetDlgItem(m_hWnd, IDOK), &rec); //ウィンドウ位置取得
w = rec.right - rec.left;
h = rec.bottom - rec.top;
pt.x = rec.left;
pt.y = rec.top;
ScreenToClient(m_hWnd, &pt);
MoveWindow(GetDlgItem(m_hWnd, IDOK), pt.x + diffx, pt.y + diffy, w, h, TRUE);
//(解説:前回の位置を取得し、コントロールのサイズは変更しないのでw, hを変えずにx, y位置のみに差異を反映させます。)
//幅高さ変更
//IDC_EXEDIT
GetWindowRect(GetDlgItem(m_hWnd, IDC_EXEDIT), &rec); //ウィンドウ位置取得
w = rec.right - rec.left;
h = rec.bottom - rec.top;
pt.x = rec.left;
pt.y = rec.top;
ScreenToClient(m_hWnd, &pt);
MoveWindow(GetDlgItem(m_hWnd, IDC_EXEDIT), pt.x, pt.y, w + diffx, h + diffy, TRUE);
//(解説:前回の位置を取得し、左上の未固定してサイズ位置に差異を反映させます。)
//クライアントエリアを再描画
InvalidateRect(m_hWnd, NULL, TRUE);
return TRUE;
}
bool EXEDLG::OnMinMax(WPARAM wParam, LPARAM lParam) {
//典型的なウィンドウのサイズ制限処理
MINMAXINFO *pmmi;
pmmi = (MINMAXINFO*)lParam;
pmmi->ptMinTrackSize.x = 421; //クライアントエリア405
pmmi->ptMinTrackSize.y = 410; //クライアントエリア371
//(解説:前にもやりましたが、ウィンドウの最小サイズ設定の定番処理です。)
return FALSE; //処理はDefWndProcに任す
}
///////////////////////////////
//IDD_ARGダイアログの関数定義
//コントロール関数
///////////////////////////////
bool EXEDLG::OnFile1() {
//実行ファイルパス、名を取得
char* cp = cmndlg.GetFileName(m_hWnd, "実行ファイル(*.exe)\0*.exe\0\0");
if(!cp) {
MessageBox(m_hWnd, "操作がキャンセルされました", "エラー", MB_OK | MB_ICONERROR);
return FALSE;
}
//ステータスバー標示
SBar.SetText(0, cp);
SBar.SendMsg(SB_SETTIPTEXT, 0, (LPARAM)cp); //ToolTipをつける
//実行ファイル名を""で囲んで保存
m_FileName = "\"";
m_FileName = m_FileName + cp;
m_FileName = m_FileName + "\"";
return TRUE;
//(解説:ファイル選択ダイアログで実行ファイルを選択しメンバー変数に記録します。また、ファイルパス、名は""で囲みます。)
}
bool EXEDLG::OnFile2() {
char* cp = cmndlg.GetFileName(m_hWnd, "対象ファイル(*.*)\0*.*\0\0");
if(cp) {
//引数を""で囲む
CSTR Arg = "\"";
Arg = Arg + cp;
Arg = Arg + "\"";
SendItemMsg(IDC_EDIT1, WM_SETTEXT, 0, (LPARAM)Arg.ToChar());
return TRUE;
}
else
return FALSE;
}
bool EXEDLG::OnFile3() {
char* cp = cmndlg.GetFileName(m_hWnd, "対象ファイル(*.*)\0*.*\0\0");
if(cp) {
//引数を""で囲む
CSTR Arg = "\"";
Arg = Arg + cp;
Arg = Arg + "\"";
SendItemMsg(IDC_EDIT2, WM_SETTEXT, 0, (LPARAM)Arg.ToChar());
return TRUE;
}
else
return FALSE;
}
bool EXEDLG::OnFile4() {
char* cp = cmndlg.GetFileName(m_hWnd, "対象ファイル(*.*)\0*.*\0\0");
if(cp) {
//引数を""で囲む
CSTR Arg = "\"";
Arg = Arg + cp;
Arg = Arg + "\"";
SendItemMsg(IDC_EDIT3, WM_SETTEXT, 0, (LPARAM)Arg.ToChar());
return TRUE;
}
else
return FALSE;
}
//(解説:ファイルボタンを押すとファイル選択ダイアログが開き、引数としてのファイルパス、名をカッコつきでエディットボックスに表示します。引数がファイルではない場合は直接エディットボックスにオプション等を入力します。)
bool EXEDLG::OnDone() {
char arg[MAX_PATH];
CSTR Arg = m_FileName; //最初に実行ファイル名が入る
if(SendItemMsg(IDC_EDIT1, WM_GETTEXT, MAX_PATH,(LPARAM)arg)) {
Arg = Arg + " ";
Arg = Arg + arg;
}
if(SendItemMsg(IDC_EDIT2, WM_GETTEXT, MAX_PATH, (LPARAM)arg)) {
Arg = Arg + " ";
Arg = Arg + arg;
}
if(SendItemMsg(IDC_EDIT3, WM_GETTEXT, MAX_PATH, (LPARAM)arg)) {
Arg = Arg + " ";
Arg = Arg + arg;
}
//(解説:最終コマンドをCSTR変数Argに入れます。まず実行ファイル名を入れ、引数があればスペースと引数を追加します。)
//最終編集処理のためにIDC_EXEDITへ
SendItemMsg(IDC_EXEDIT, WM_SETTEXT, 0, (LPARAM)Arg.ToChar());
//(解説:IDC_EDITに最終コマンドを表示させます。)
return TRUE;
}
bool EXEDLG::OnIdok() {
//最終編集後のIDC_EXEDITの文字列をbuffに取得
char buff[MAX_PATH * 2]; //260 x 2 = 520
//(解説:もっと長くしてもらっても結構ですが、まずこの程度でよいでしょう。)
if(SendItemMsg(IDC_EXEDIT, WM_GETTEXTLENGTH, 0, 0) > MAX_PATH * 2) {
MessageBox(m_hWnd, "文字数が多すぎます", "エラー", MB_OK | MB_ICONERROR);
return FALSE;
}
SendItemMsg(IDC_EXEDIT, WM_GETTEXT, MAX_PATH * 2, (LPARAM)buff);
//m_Cmdへ代入して引き渡す
Command.m_Cmd = buff;
//m_Logに記録
Command.m_Log = Command.m_Log + Command.m_Cmd;
Command.m_Log = Command.m_Log + "\n";
//コマンドの実行
g_CE.Exec(Command.m_Cmd.ToChar());
//(解説:m_Cmdというメンバー変数に代入、主ダイアログのログ変数に記録して実行します。ダイアログは開きっぱなしです。)
return TRUE;
}
bool EXEDLG::OnCancel() {
//ESCキー対応
EndModal(TRUE);
return TRUE;
}
//(解説:今回はIDOKでダイアログを閉めないようにしたので、IDCANCELのみがダイアログを終了させます。)
如何でしょう?処理内容はCCMDEDITクラスのみが初出ですが、BCCFOrmandBCCSkeltonの復習課題として簡単かつ分かりやすいと思います。これを使ってCUIのコマンドツールを色々といじくってください。うまくいけばログを編集してバッチファイルにできます。