前回、ほとんど話題のなかったRTWEditor.rcとResRTWEditor.hでしたが、今回はコンパイルの対象となるRTWEditor.cppと基本的な定義ファイルであるRTWEditor.hをやります。なお、本プログラムはこの他メインウィンドウとダイアログのメンバー関数の実装を行うRTWEditorProc.hの他、User.hと今回移植のために大幅に修正したCREDIT.hの当該部分も紹介したいと考えています。
また、これらのファイルは基本的にBCCForm and BCCSkeltonのSkeltonWizardで生成したコードを基に修正したもので、RTWEditor作成の際のSkeltonWizardへの入力は次のようになります。
第1ページ:SDIウィンドウ、ツールバー、ステータスバー、コモンダイアログ、メニュー、アイコン、アクセラレーターを選択
第2ページ:コモンコントロールのスタンダードビットマップを使用
第3ページ:ウィンドウメッセージは、WM_CREATE、WM_NOTIFY、WM_SIZE、WM_CLOSEを選択(注-重要)
注:ECCSkeltonではこれらSkeltonWizardで選択できるメッセージの他、OnDropFiles、OnGetMaxInfo等を仮想関数として有し、そのままメンバー関数に使用できます。また、それ以外のメッセージに対しては「bool OnOthers(UINT Msg, WPARAM wParam, LPARAM lParam); //既定のメッセージ以外の処理」を利用し、"if(Msg == ~)"や"switch(Msg)"で処理するようにしています。今回のRTWEditorではCREDITのFindReplaceダイアログのメッセージ処理で実際に使っていますので参考にしてください。
【RTWEditor.cpp】
//////////////////////////////////////////
// RTWEditor.cpp
//Copyright (c) 08/30/2022 by ECCSkelton
//////////////////////////////////////////
#include "RTWEditor.h"
#include "User.h" //(解説:User.hは.hとProc.hの間に挟むように入れてください。)
#include "RTWEditorProc.h"
////////////////
// WinMain関数
////////////////
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPWSTR lpCmdLine, int nCmdShow) {
//(解説:ワイド文字対応部分です。bcc102cでコンパイルする際には "-tWU" スイッチを使ってください。)
//ファイルドロップによる起動(g_ByFileフラグを立てる)
if(g_Arg.c() > 1)
g_ByFile = TRUE;
//(解説:データファイルのドロップによる起動用です。なお、SkeltonWizardが書く「2重起動防止用コード」は2重起動を容認するので、今回外しています。)
//ウィンドウ登録 - Init(ClassName, hInstance, "IDM_MAIN",
// (以下省略可)MAKEINTRESOURCE(IDI_ICON), IDC_ARROW, Brush)
RTWEditor.Init(L"MainWnd", hInstance, L"MAIN_MENU", MAKEINTRESOURCE(IDI_ICON));
//(解説:BCCSkeltonではhInstanceの後に外部コールバック関数が引数になっていましたが、ECCSkeltonでは不要です。)
//ウィンドウ作成と表示-Create(WindowTitle, (以下省略可)Style,
// ExStyle, hParent, hMenu, x, y, w, h)
if(!RTWEditor.Create(L"RTWEditor"))
return 0L;
//アクセラレーター登録-InclAccel("(Accelerator ID)")
RTWEditor.InclAccel(L"IDA_ACCEL");
//(解説:今回はアクセラレーターを使うのでこのようになっています。)
//メッセージループに入る
return RTWEditor.Loop();
//解説:(注参照)
}
/*注:このループ処理の中にはアクセラレータ処理の他、m_hDlgメンバー関数をハンドルとするモードレスダイアログのメッセージ処理も含まれます。RTWEditorではCREDITクラスのFindReplace関数を呼ぶために使用しています。
//メインウィンドウの場合のメッセージループ
UINT CSDI::Loop() {
while(GetMessageW(&m_Msg, NULL, 0, 0)) {
//アクセラレータやモードレスダイアログのメッセージでなければ
//モードレスダイアログがある場合
if(!IsDialogMessageW(m_hDlg, &m_Msg) &&
//アクセラレーター処理
!TranslateAcceleratorW(m_hWnd, m_Accel, &m_Msg)) {
TranslateMessage(&m_Msg);
DispatchMessageW(&m_Msg);
}
}
return m_Msg.wParam;
}
*/
【RTWEditor.h】
//////////////////////////////////////////
// RTWEditor.h
// Copyright (c) 08/30/2022 by ECCSkelton
//////////////////////////////////////////
//システム定数定義
#define IDC_TAB 1000 //タブのコントロールID
#define IDC_EDIT 2000 //最初のタブページのエディットコントロールID
//(解説:プログラムで生成するメインウィンドウに張り付けるタブとリッチテキストコントロール用です。)
//最小ウィンドウサイズの規定(ツールバーボタンが全て見える最小値)
#define MINW 510
#define MINH 255
//(解説:OnGetMaxInfoを使っています。サイズは「ツールバーボタンが全て見える最小値」としています。)
//対象ファイルのフィルター
#define FILEFILTER L"テキストファイル(*.rtf;*.txt)\0*.rtf;*.txt\0C++ファイル(*.h;*.cpp;*.rc;*.mak;*.ini)\0*.h;*.cpp;*.rc;*.mak;*.ini\0全てのファイル(*.*)\0*.*\0\0"
//(解説:CCHKEXTクラスを使っています。ワイド文字対応は、""文字列の直前のスペース付き「 "」を「 L"」へ一括変換すると効率的です。)
//BCCSkeltonのヘッダー-これに必要なヘッダーが入っている
#include "ECCSkelton.h"
//リソースIDのヘッダー
#include "ResRTWEditor.h"
/////////////////////////////////////////////////////////////////////
//CMyWndクラスをCSDIクラスから派生させ、メッセージ用の関数を宣言する
/////////////////////////////////////////////////////////////////////
class CMyWnd : public CSDI
//(解説:CSDIクラスからCMyWndクラスを派生させます。)
{
private:
CTAB m_Tab; //メインウィンドウに貼り付けるタブコントロール
CREDIT m_Edit; //タブページのRichEditコントロールのカプセルインスタンス
int m_EditID = IDC_EDIT; //新規タブページのリッチエディット用コントロールID(注)
//注:ユニークである為にコントロールを削除しても永久欠番にする
//(解説:タブとリッチテキストコントロールのインスタンスをメンバーとして持ちます。各タブに一つのリッチテキストコントロールが付くので、タブを消去するとそのリッチエディットコントロールも消去されます。その際、「消去されるコントロールのIDは使いまわししない」とすることで不測の重複トラブルを避けています。)
public: //以下はコールバック関数マクロと関連している
//2重起動防止用のMutex用ID名称
CMyWnd(WCHAR* UName) : CSDI(UName) {}
//(解説:二重起動防止用のコンストラクターですが、二重起動は容認しています。charになっていたものですが、"char"を"WCHAR"に一括変換して修正します。)
//メニュー項目、ダイアログコントロール関連
bool OnNew();
bool OnOpen();
bool OnSave();
bool OnSaveas();
bool OnSetprint();
bool OnPrint();
bool OnExit();
bool OnUndo();
bool OnCut();
bool OnCopy();
bool OnPaste();
bool OnSelall();
bool OnFind();
bool OnReplace();
bool OnDelete();
bool OnFont();
bool OnLeft();
bool OnCenter();
bool OnRight();
bool OnLindent();
bool OnLoutdent();
bool OnRindent();
bool OnRoutdent();
bool OnBrief();
bool OnShortcut();
bool OnVer();
//(解説:これらメニューやコントロールからの割り込みメッセージはWM_COMMANDに対応する、OnCommand関数で処理します。)
//ウィンドウメッセージ関連
CMDTABLE //CMyWndクラスのOnCommand()関数宣言
//(解説:このCMDTABLEという文字列が"bool OnCommand(WPARAM, LPARAM);"に展開されます。これは手書きで追加します。)
bool OnCreate(WPARAM, LPARAM);
bool OnNotify(WPARAM, LPARAM);
bool OnSize(WPARAM, LPARAM);
bool OnClose(WPARAM, LPARAM);
bool OnDropFiles(WPARAM, LPARAM);
bool OnGetMaxInfo(WPARAM, LPARAM);
bool OnOthers(UINT, WPARAM, LPARAM); //既定のメッセージ以外の処理
//(解説:これらウィザードが作った関数は既にCSDIクラスに仮想関数として定義済ですので、自由にオーバーライドできます。)
//ユーザー定義関数
bool AddTabEdit(WCHAR*);
bool DelTabEdit();
bool PopupMenu();
//(解説:これらは純粋なユーザー定義メンバー関数で、手書きで追加します。順にタブとリッチテキストコントロールの追加、削除とポップアップメニュ処理の関数です。)
};
////////////////////////////////////////////////////////////////////////
//派生させたCMyWndクラスのインスタンスとコールバック関数(マクロ)の作成
//主ウィンドウはダイアログと違い、コールバック関数は一つしか作れない
////////////////////////////////////////////////////////////////////////
CMyWnd RTWEditor(L"RTWEditor"); //ウィンドウクラスインスタンスの生成
//(解説:「 "」の「 L"」一括変換で修正します。)
//CMyWndクラスのOnCommand()関数定義
/*(解説:BCCSkeltonでは次のようになっていましたが、ECCDSkeltonではBIGIN_CMDTABLE(クラス名)~END_CMDTABLEに一本化されました。)
BEGIN_MDIMSG(RTEditor) //ダイアログと違い、コールバック関数名を特定しない
//メニュー項目、ダイアログコントロール関連
ON_COMMAND(RTEditor, IDM_NEW, OnNew())
(略)
//ウィンドウメッセージ関連
//MDIFrame親ウィンドウは自動的にOnMDIFrameCreate()を呼ぶ
(略)
ON_CLOSE(RTEditor)
ON_(RTEditor, WM_DROPFILES, OnDropFiles(wParam))
END_MDIMSG(RTEditor)
*/
BEGIN_CMDTABLE(CMyWnd)
//メニュー項目、ダイアログコントロール関連
ON(IDM_NEW, OnNew())
ON(IDM_OPEN, OnOpen())
ON(IDM_SAVE, OnSave())
ON(IDM_SAVEAS, OnSaveas())
ON(IDM_SETPRINT, OnSetprint())
ON(IDM_PRINT, OnPrint())
ON(IDM_EXIT, OnExit())
ON(IDM_UNDO, OnUndo())
ON(IDM_CUT, OnCut())
ON(IDM_COPY, OnCopy())
ON(IDM_PASTE, OnPaste())
ON(IDM_SELALL, OnSelall())
ON(IDM_FIND, OnFind())
ON(IDM_REPLACE, OnReplace())
ON(IDM_DELETE, OnDelete())
ON(IDM_FONT, OnFont())
ON(IDM_LEFT, OnLeft())
ON(IDM_CENTER, OnCenter())
ON(IDM_RIGHT, OnRight())
ON(IDM_LINDENT, OnLindent())
ON(IDM_LOUTDENT, OnLoutdent())
ON(IDM_RINDENT, OnRindent())
ON(IDM_ROUTDENT, OnRoutdent())
ON(IDM_BRIEF, OnBrief())
ON(IDM_SHORTCUT, OnShortcut())
ON(IDM_VER, OnVer())
/*(解説:SkeltonWizardでは↓の(1)の様になっているので、
(1)ON_COMMAND(RTEditor, IDM_NEW, OnNew())
(2)ON(IDM_NEW, OnNew())
(2)にするために
"_COMMAND(RTEditor, " を
↓
"("
に一括変換します。)
*/
END_CMDTABLE
///////////////////
//ツールバーの作成
///////////////////
CTBAR TBar;
///////////////////////
//ステータスバーの作成
///////////////////////
CSBAR SBar;
////////////////////////
//コモンダイアログの作成
////////////////////////
CMNDLG cmndlg;
//////////////////////
//CEXTCHKのインスタンス
//////////////////////
CEXTCHK g_ExtChk;
//(解説:ここら辺は全くBCCSkeltonのままです。)
///////////////////////////////////////////
// CDLGクラスからVERSIONDLGクラスを派生
// 複数の同一ダイアログ変数とダイアログも作
// れるが、一つのダイアログに一つの派生ダイ
// アログクラスを作成するのが基本
///////////////////////////////////////////
class VERSIONDLG : public CDLG {
public:
CMDTABLE //VERSIONDLGクラスのOnCommand()関数宣言
bool OnIdok();
};
////////////////////////////////////////////////////////////////////////////
// VERSIONDLGクラスダイアログ変数の生成とそのコールバック関数(マクロ)を定義
// 複数同一クラスのダイアログを作成することを予期してコールバック関数を明記
////////////////////////////////////////////////////////////////////////////
VERSIONDLG versiondlg;
//VERSIONDLGクラスのOnCommand()関数定義
BEGIN_CMDTABLE(VERSIONDLG)
//メニュー項目、ダイアログコントロール関連
ON(IDOK, OnIdok())
END_CMDTABLE
//(解説:メインウィンドウのCMyWndクラスと全く同じ様にVERSIONDLGクラスを修正します。)
如何でしょうか?最初は慣れないので面倒くさそうですが(私もそうでした)、慣れると一括変換を利用して3分程度で修正完了できます。
では、次回は今回のRTWEditorでいじったCTABとCREDIT両クラスの変更点を解説してみましょう。(これらはBCCSkeltonでも修正しています。以下はBCCSkeltonのREADME.txtからです。)
CTAB-指定ページのタイトルを取得するGetTitle(int)を追加
CREDIT-文字列の検索、置換に関わるコードをRichEdit20に合わせて見直しを実施