内部構造>マクロ全般
サクラエディタのマクロは大まかに以下の部分に分かれています.
CSMacroMgr
マクロ全体の管理.マクロ名称と引数の定義.
CMacroFactory
拡張子からマクロエンジンのインスタンスを生成するファクトリクラス.
CMacro
キーボードマクロの記録処理.マクロの各コマンド個別処理.キーマクロ実行本体部.
CMacroManagerBase
各マクロエンジンの基底クラス.ここから派生させることで各種マクロエンジンを定義する.
CKeyMacroMgr
組み込みキーボードマクロのエンジン.
CPPAMacroMgr
PPAマクロのエンジン(というかBridge).ppa.dllを管理する''CPPA''を使用してマクロを実行する.
CWSH
WSHマクロのエンジン(というかBridge).
メニューやキーボードからコマンドを選択するとWM_COMMANDメッセージがウィンドウズからエディタに渡されて処理が実行されます.
マクロでは基本的にそれと同一の仕組みを使っており,マクロコマンドが実行されるとコマンドからコマンドID (WM_COMMANDで使用するもの)とコマンドによっては引数の解釈が行われます.
コマンドを受け取るのはCEditDoc::HandleCommand()です.ウィンドウ操作以外のコマンドはそのままCEditView::HandleCommand()へ渡されます.
値を返す関数も基本的には同じですが,CMacroの中で完結している点が異なります.
CSMacroMgrがポインタの配列+キーマクロのポインタを持っています.マクロが読み込まれると拡張子に応じてインスタンスが生成され,この配列からリンクされます.
マクロエンジンはそれぞれ自分がどの拡張子のマクロを実行できるかを知っています.これが大前提.CWSHは各種ActiveScriptを実行できるので,レジストリからActiveScriptに関連づけられているかをチェックしています.
各マクロエンジンのdeclare()を呼びだすと,それぞれCMacroFactory (Singleton) のRegisterCreator()によって各エンジンの持つFactory関数を登録します.
実際にマクロエンジンが必要なときはCMacroFactory::Ext2Key()が呼びだされます.この関数では登録されたCreator関数をインスタンスが取得できるまで順次呼びだします.
Note:
この部分は柔軟性を持たせたつもりながら,結局はWSHが複数言語を扱えることからマクロエンジンは3種類にとどまっています.また,CMacroFactoryへの最初の登録のためにCSMacroManagerから各エンジンのdeclareを呼びだすことから,エンジン部分とマクロ本体の関連が残っています.
現在の構造だと,外部DLLから新たなエンジンを登録するようなことも理論的には可能ですが,複雑な登録メカニズムを排除してCMacroFactoryの固定配列に変えた方が無駄が無くて良いかもしれません.
マクロはCEditView::Command_EXECKEYMACRO(),あるいはCEditView::HandleCommand()でのマクロ用コマンド番号を契機に実行が開始されます.マクロの実行中はm_bExecutingKeyMacroフラグが設定され,キーリピートと補完が抑制されます.
実行はLoadとExecに分かれており,それぞれCSMacroManager::Load(), CSMacroManager::Exec()に相当します.CSMacroManagerでは与えられたマクロ番号に対応するインスタンスのLoadKeyMacro(), ExecKeyMacro()を呼びだします.
ここから先はそれぞれのエンジンによって処理が分かれますが,エディタの機能を呼びだすためにCSMacroMgr::GetFuncInfoByName()を使います.この関数は文字列として与えられた関数から機能番号を返します.さらにその機能番号からCSMacroMgr::GetFuncInfoByID()を呼びだして引数の型情報などを取得します.
この操作はマクロエンジンによって実行前に最初に一括して行うものと実行の都度行われるものの二種類があります.
CEditView::Command_RECKEYMACRO()でキーマクロの記録が開始されると,CSMacroMgr::Clear()でキーマクロを初期化します.
また,DLLSHAREDATA::m_bRecordingKeyMacro, DLLSHAREDATA::m_hwndRecordingKeyMacroにマクロ記録中である旨を登録します.
bRecordingKeyMacroが共有メモリにあるため,あるウィンドウでマクロを記録している間は他ではマクロの記録はできません.他のウィンドウではキーボードマクロ関連コマンドは使用できなくなります.これは複数エディタから同一ファイルに記録することを防ぐ措置と考えられます.
bRecordingKeyMacroがTRUEのときはCEditView::HandleCommand()でコマンド実行に先立ってCSMacroMgr::CanFuncIsKeyMacro()で記録対象コマンドかどうかが判定されます.
対象コマンドであればCSMacroMgr::Append()でコマンドの追加が行われます.
CSMacroMgr::Append()はCKeyMacroMgrのインスタンスがなければ生成した上で,CKeyMacroMgr::Append()を呼びだします.そこでは対応するマクロコマンド1つのインスタンス(CMacro)を作成してリンクの最後につなげます.
CEditView::Command_SAVEKEYMACRO()かCommand_RECKEYMACRO()によって終了します.Command_RECKEYMACRO()では規定のファイル名で自動的に保存するのに対して,Command_SAVEKEYMACRO()ではユーザにファイル名を問い合わせます.
保存ではCSMacroMgrを経由してCKeyMacroMgr::SaveKeyMacro()が呼ばれます.各コマンドに対してCMacro::Save()を呼びだすことで1つずつ文字列化されます.
エディタの提供するコマンドには値を返さないマクロコマンドと値を返す関数があり,前者はCMacro::HandleCommand(),後者はCMacro::HandleFunction()で処理されます.
コマンドはFunccode.hにて定義されたコマンド番号にて識別されます.
void CMacro::HandleCommand( CEditView* pcEditView, const int Index, const char* Argument[], const int ArgSize ) bool CMacro::HandleFunction( CEditView *View, int ID, VARIANT *Arguments, int ArgSize, VARIANT &Result)
CMacro::HandleCommand()ではマクロから渡された引数の違いを吸収した上でCEditView::HandleFunction()を呼びだして処理を実行します.引数は常に文字列(最大4つ)として渡されます.PPAでは常に引数は文字列として渡されることに合わせた仕様と考えられますが,WSH利用時は文字列変換のオーバーヘッドが入ります.
CMacro::HandleFunction()は比較的新しい関数のため,引数がVARIANTに変更されています.そのため引数を渡す時のオーバーヘッドはありません(WSHの場合).引数・戻り値の型はVARIANTで表現できるものが全て渡せますが,PPAではCSMacroManagerで定義された型に制約されます.
マクロ名と引数の型はCSMacroMgr.cppに配列として定義されています.