「マクロ覚え書き(開発者向け)」の版間の差分

提供: MeryWiki
ナビゲーションに移動 検索に移動
Sukemaru (トーク | 投稿記録)
「リンク」を追加
MSY-07 (トーク | 投稿記録)
文章の構成を変更
 
(3人の利用者による、間の22版が非表示)
1行目: 1行目:
= 概要 =
マクロ開発者向けの覚え書きです。
マクロ開発者向けの覚え書きです.<br>
リファレンスなどに載っていない,豆知識的なことを集めています.


= 覚え書き =
リファレンスなどに載っていない、豆知識的なことを集めています。


== 開発言語について ==
== 開発言語について ==
WSH(Windows Script Host) が対応している言語であれば利用が可能です.<br>
WSH (Windows Script Host) が対応している言語であれば利用が可能です。
標準では JScript(≒javascript)と VBScript が入っています.<br>
 
他の言語(Perl や Python)もインストールすれば使えますが,一般配布する場合利用者もインストールが必要になります.<br>
標準では JScript(≒JavaScript)と VBScript が入っています。
どの言語でも良いですが,JScript での開発者が多いため,JScript の方が情報が集まりやすくお勧めです.
 
他の言語(Perl や Python)もインストールすれば使えますが、一般配布する場合利用者もインストールが必要になります。
 
どの言語でも良いですが、JScript での開発者が多いため、JScript の方が情報が集まりやすくお勧めです。


== マクロを保存する際の文字コード ==
== マクロを保存する際の文字コード ==
基本的に単体で利用する場合はどの文字コードでも構いません.<br>
基本的に単体で利用する場合はどの文字コードでも構いません。
ただし「他のマクロから読まれる」場合は文字コードの選択が重要になります.<br>
 
今のマクロでは #title のようなプリプロセス処理が必要で,それに対応したロードができる include ライブラリの IO.Include はデフォルトで UTF-8 対応なので,UTF-8 をお勧めします(個別の指定は可能).<br>
ただし「他のマクロから読まれる」場合は文字コードの選択が重要になります。
ただし読み込む側が FileSystemObject を利用している場合,SJIS/Unicode しか対応できないのでその場合は SJIS をお勧めします(Mery 1 時代のマクロなどはコレです).


== window.Document と Editor.ActiveDocument の違い ==
今のマクロでは #title のようなプリプロセス処理が必要で、それに対応したロードができる [[includeライブラリ]]の IO.Include はデフォルトで UTF-8 対応なので、UTF-8 をお勧めします(個別の指定は可能)。
window.Document は,マクロ開始時にアクティブなドキュメントを指し続けます.マクロで別のドキュメントを Activate しても変わりません.<br>
 
Editor.ActiveDocument は,その時点でアクティブなドキュメントを指します.マクロで別のドキュメントを Activate すると当然変わります.
ただし読み込む側が FileSystemObject を利用している場合、SJIS/Unicode しか対応できないのでその場合は SJIS をお勧めします(Mery 1 時代のマクロなどはコレです)。
<source lang="javascript">
 
Editor.Documents.Item(0).Activate();
== window.Document と editor.ActiveDocument の違い ==
Alert(Document.Name);
window.Document は、マクロ開始時にアクティブなドキュメントを指し続けます。マクロで別のドキュメントを Activate しても変わりません。
Alert(Editor.ActiveDocument.Name);
 
</source>
editor.ActiveDocument は、その時点でアクティブなドキュメントを指します。マクロで別のドキュメントを Activate すると当然変わります。
また,window.Document は Documents.Item() と一致しませんが,Editor.ActiveDocument は一致します.
 
<source lang="javascript">
<syntaxhighlight lang="javascript">
for (var i=0; i<Editor.Documents.Count; i++) {
editor.documents.Item(0).Activate();
  if (Editor.ActiveDocument == Editor.Documents.Item(i)) {
Alert(document.Name);
    Alert("Editor.ActiveDocument が一致");
Alert(editor.ActiveDocument.Name);
  }
</syntaxhighlight>
  if (Document == Editor.Documents.Item(i)) {
 
    Alert("window.Document が一致");
また、window.Document は documents.Item() と一致しませんが、editor.ActiveDocument は一致します。
  }
 
<syntaxhighlight lang="javascript">
for (var i = 0; i < editor.documents.Count; i++) {
if (editor.ActiveDocument == editor.documents.Item(i)) {
Alert("editor.ActiveDocument が一致");
}
if (Document == editor.documents.Item(i)) {
Alert("window.Document が一致");
}
}
}
</source>
</syntaxhighlight>


== window.Redraw = true は必要か ==
== window.Redraw = true は必要か ==
マクロで
マクロで
<source lang="javascript">
 
<syntaxhighlight lang="javascript">
Redraw = false;
Redraw = false;
</source>
</syntaxhighlight>
にしたとき,最後
 
<source lang="javascript">
にしたとき、最後
 
<syntaxhighlight lang="javascript">
Redraw = true;
Redraw = true;
</source>
</syntaxhighlight>
が必要かという点については,現状確認する限りでは不要です.
 
が必要かという点については、現状確認する限りでは不要です。


== 矩形選択の扱い ==
== 矩形選択の扱い ==
マクロで矩形選択は扱えません(プラグインですら無理).<br>
マクロで矩形選択は扱えません(プラグインですら無理)。
ただし,矩形選択中かの判定だけは以下の方法で可能です.
 
<source lang="javascript">
ただし、矩形選択中かの判定だけは以下の方法で可能です。
var s = Document.Selection;
var isBoxed = (s.GetBottomPointY(mePosView) - s.GetTopPointY(mePosView)) != (s.Text.match(/\n/g) || []).length;
</source>
2019/06/11追記(有志):使い道は限られますが、Alt + Shit + カーソル移動のキーコードを送ることで、矩形範囲指定の開始と範囲変更は可能です。
  new ActiveXObject("WScript.Shell").SendKeys("+%{left}");//{right},{up},{down}


== Document.GetLines の引数 ==
<syntaxhighlight lang="javascript" copy>
リファレンスには '''meGetLineView''' しか書かれていませんが,論理行単位での行数取得には引数に 0 を渡します.<br>
var sel = document.selection;
'''meGetLineLogical''' という定数はありません.
var isBoxed = (sel.GetBottomPointY(mePosView) - sel.GetTopPointY(mePosView)) != (sel.Text.match(/\n/g) || []).length;
</syntaxhighlight>
 
使い道は限られますが、Alt + Shit + カーソル移動のキーコードを送ることで、矩形範囲指定の開始と範囲変更は可能です。
 
<syntaxhighlight lang="javascript" copy>
new ActiveXObject("WScript.Shell").SendKeys("+%{left}"); //{right},{up},{down}
</syntaxhighlight>
 
== document.GetLines の引数 ==
Ver 3.3.2 以降では引数を省略すると論理行単位での行数取得になります。
 
Ver 3.3.1 以前では引数に 0 を渡すと論理行単位での行数取得になります。
 
meGetLineLogical という定数はありません。


== プリプロセス(#title など) ==
== プリプロセス(#title など) ==
対応しているプリプロセスコードは以下の通りです.
対応しているプリプロセスコードは以下の通りです(詳細は[https://www.haijin-boys.com/wiki/%E3%83%9E%E3%82%AF%E3%83%AD%E3%83%AA%E3%83%95%E3%82%A1%E3%83%AC%E3%83%B3%E3%82%B9:3:%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%86%E3%82%A3%E3%83%96 ディレクティブ]を参照)。
* #icon = "****" [, アイコン番号]
* #title = "****"
* #tooltip = "****"
* #include "****.js"


* [https://www.haijin-boys.com/software/mery/mery-2-6-6#5 #language = "****"] (スクリプトの言語を指定. ※[https://www.haijin-boys.com/software/mery/mery-2-6-7#9 省略時は "JScript(Chakra)"]
* <code>#title = "****"</code> ツール バーのボタンに表示するタイトルの文字列を指定します。
* [https://www.haijin-boys.com/software/mery/mery-2-8-0#4 #begingroup = true] (または 1 - 3 の数値. ※Mery 2.8.0 以降のみ)
* <code>#tooltip = "****"</code> ツール バーのボタンにマウスを乗せたときに表示されるヒントの文字列を指定します。
* <code>#begingroup = true</code> [マクロ] メニューおよびマクロ バーの項目の手前に区切りバーを挿入します。
* <code>#icon = "****" [, アイコン番号]</code> ツール バーのボタンに表示するアイコンを指定します。
* <code>#icondark = "****" [, アイコン番号]</code> ダークモード有効時にツール バーのボタンに表示するアイコンを指定します。
* <code>#include "****.js"</code> 指定したファイルをマクロの先頭に含めます。
* <code>#language = "****"</code> スクリプト言語を指定します。


これらは必ず '''ファイル先頭''' に書かなければなりません(コメントや VBS の Option Explicit などよりも先).<br>
これらは必ず ファイル先頭 に書かなければなりません(コメントや VBS の Option Explicit などよりも先)。
:・ #title は、マクロメニューやマクロバー、「ツールバーのカスタマイズ」に表示される '''マクロ名''' です(未指定の場合はファイル名の ****.js で表示されます).
:・ #tooltip は、マクロバーにマウスカーソルをあてたときにポップアップ表示される黄色い小窓(ヒント/ツールチップ/トースト)内の '''説明文''' の文字列に使用されます.
:・ #language の詳細は、Mery.txt 内の更新履歴 『▼ 2018/03/22 (2.6.6)』 に記載されています.


== 他のファイルのロード方法 ==
== 他のファイルのロード方法 ==
マクロから他のファイルを直接ロードするには以下の方法があります.
マクロから他のファイルを直接ロードするには以下の方法があります。
 
* FileSystemObject を利用する
* FileSystemObject を利用する
* ADODB.Stream を利用する
* ADODB.Stream を利用する
* include ライブラリの IO クラスを利用する
* [[includeライブラリ]]の IO クラスを利用する


=== FileSystemObject を利用する ===
=== FileSystemObject を利用する ===
コードが短く簡単に扱えます.<br>
コードが短く簡単に扱えます。
また FileSystemObject 自体に,ファイルの有無やフォルダ作成の機能があります.<br>
 
ただし扱える文字コードは SJIS または Unicode 限定.
また FileSystemObject 自体に、ファイルの有無やフォルダ作成の機能があります。
<source lang="javascript">
 
ただし扱える文字コードは SJIS または Unicode 限定。
 
<syntaxhighlight lang="javascript" copy>
// Scripting.FileSystemObject の定数
// Scripting.FileSystemObject の定数
var ForReading = 1;           // ファイルを読み取り専用として開きます。このファイルには書き込むことができません。
var ForReading = 1;         // ファイルを読み取り専用として開きます。このファイルには書き込むことができません。
var ForWriting = 2;           // ファイルを書き込み専用として開きます。
var ForWriting = 2;         // ファイルを書き込み専用として開きます。
var ForAppending = 8;         // ファイルを開き、ファイルの最後に追加して書き込みます。
var ForAppending = 8;       // ファイルを開き、ファイルの最後に追加して書き込みます。
var TristateUseDefault = -2; // システム デフォルトを使ってファイルを開きます。
var TristateUseDefault = -2; // システム デフォルトを使ってファイルを開きます。
var TriStateTrue = -1;       // ファイルを Unicode ファイルとして開きます。
var TriStateTrue = -1;       // ファイルを Unicode ファイルとして開きます。
var TristateFalse = 0;       // ファイルを ASCII ファイルとして開きます。
var TristateFalse = 0;       // ファイルを ASCII ファイルとして開きます。


var fso = new ActiveXObject("Scripting.FileSystemObject");
var fso = new ActiveXObject("Scripting.FileSystemObject");


// ファイルの読み込み
// ファイルの読み込み
var fsIn = fso.OpenTextFile(Document.FullName, ForReading, false, TristateUseDefault);
var fsIn = fso.OpenTextFile(document.FullName, ForReading, false, TristateUseDefault);
var text = fsIn.ReadAll();
var text = fsIn.ReadAll();
fsIn.Close();
fsIn.Close();
108行目: 131行目:
fsOut.Write(text);
fsOut.Write(text);
fsOut.Close();
fsOut.Close();
</source>
</syntaxhighlight>


=== ADODB.Stream を利用する ===
=== ADODB.Stream を利用する ===
書き方は若干複雑ですが,システムが対応している文字コードであれば全て扱えます.<br>
書き方は若干複雑ですが、システムが対応している文字コードであれば全て扱えます。
また(信頼性は低いが)文字コードの自動判定も可能です.
 
<source lang="javascript">
また(信頼性は低いが)文字コードの自動判定も可能です。
var adTypeBinary = 1;           // バイナリ データを表します。
 
var adTypeText = 2;             // 既定値です。Charset で指定された文字セットにあるテキスト データを表します。
<syntaxhighlight lang="javascript" copy>
var adReadAll = -1;             // 既定値です。現在の位置から EOS マーカー方向に、すべてのバイトをストリームから読み取ります。これは、バイナリ ストリームに唯一有効な StreamReadEnum 値です。
var adTypeBinary = 1;         // バイナリ データを表します。
var adReadLine = -2;           // ストリームから次の行を読み取ります (LineSeparator プロパティで指定)。
var adTypeText = 2;           // 既定値です。Charset で指定された文字セットにあるテキスト データを表します。
var adSaveCreateNotExist = 1;   // 既定値です。FileName パラメータで指定したファイルがない場合は新しいファイルが作成されます。
var adReadAll = -1;           // 既定値です。現在の位置から EOS マーカー方向に、すべてのバイトをストリームから読み取ります。これは、バイナリ ストリームに唯一有効な StreamReadEnum 値です。
var adSaveCreateOverWrite = 2; // FileName パラメータで指定したファイルがある場合は、現在開かれている Stream オブジェクトのデータでファイルが上書きされます。
var adReadLine = -2;           // ストリームから次の行を読み取ります (LineSeparator プロパティで指定)。
var adSaveCreateNotExist = 1; // 既定値です。FileName パラメータで指定したファイルがない場合は新しいファイルが作成されます。
var adSaveCreateOverWrite = 2; // FileName パラメータで指定したファイルがある場合は、現在開かれている Stream オブジェクトのデータでファイルが上書きされます。


// ファイルの読み込み
// ファイルの読み込み
126行目: 151行目:
adodb.Charset = 'utf-8';
adodb.Charset = 'utf-8';
adodb.Open();
adodb.Open();
adodb.LoadFromFile(Document.FullName);
adodb.LoadFromFile(document.FullName);
var text = adodb.ReadText(adReadAll);
var text = adodb.ReadText(adReadAll);
adodb.Close();
adodb.Close();
139行目: 164行目:
adodb.SaveToFile("hoge.txt", adSaveCreateOverWrite);
adodb.SaveToFile("hoge.txt", adSaveCreateOverWrite);
adodb.Close();
adodb.Close();
</source>
</syntaxhighlight>


=== include ライブラリの IO クラスを利用する ===
=== includeライブラリの IO クラスを利用する ===
ファイルの読み書きを簡単にするクラスです.<br>
ファイルの読み書きを簡単にするクラスです。
簡単に扱えることと,BOM なしの UTF-8 を書き込めることがメリットです.<br>
 
逆にソースを読むしか資料がないこと,ユーザに導入してもらう必要があるのが欠点です.
簡単に扱えることと、BOM なしの UTF-8 を書き込めることがメリットです。
<source lang="javascript">
 
逆にソースを読むしか資料がないこと、ユーザに導入してもらう必要があるのが欠点です。
 
<syntaxhighlight lang="javascript" copy>
#include "include/IO.js"
#include "include/IO.js"


// ファイルの読み込み
// ファイルの読み込み
var text = IO.LoadFromFile(Document.FullName, "utf-8");
var text = IO.LoadFromFile(document.FullName, "utf-8");
Alert(text);
Alert(text);


// ファイルの書き込み
// ファイルの書き込み
IO.SaveToFile("hoge.txt", text, "utf-8");
IO.SaveToFile("hoge.txt", text, "utf-8");
</source>
</syntaxhighlight>


== 他のマクロの実行方法 ==
== 他のマクロの実行方法 ==
他のマクロを実行するには,以下の方法があります.
他のマクロを実行するには、以下の方法があります。
 
* #include で取り込む
* #include で取り込む
* ファイルをロードして eval する
* ファイルをロードして eval する
前者は先頭でしかかけない上,動的にロードの切り替えができません.<br>
* [[マクロリファレンス:3:Editor オブジェクト#ExecuteMacro メソッド|editor.ExecuteMacro メソッド]]を使用する(Ver 3.7.13 で追加)
後者は文字コードの問題とプリプロセス処理に関する問題があります.<br>
 
include ライブラリの IO.Include を使うことで,プリプロセス処理に関しては解決できます.
1つ目は先頭でしか書けない上、動的にロードの切り替えができません。
<source lang="javascript">
 
2つ目は文字コードの問題とプリプロセス処理に関する問題があります。
 
[[includeライブラリ]]の IO.Include を使うことで、プリプロセス処理に関しては解決できます。
 
<syntaxhighlight lang="javascript" copy>
#include "include/IO.js"
#include "include/IO.js"


eval(IO.Include("test.js", "utf-8")); // #include なども処理される
eval(IO.Include("test.js", "utf-8")); // #include なども処理される
</source>
</syntaxhighlight>
 
3つ目は任意の場所で指定したマクロを実行することができます。


== マクロからファイル選択ダイアログ ==
== マクロからファイル選択ダイアログ ==
できません.<BR>
以下の関数で可能です。
2019/06/11追記 (有志): 以下の関数で可能です。
 
  function OpenFileDlg(){
<syntaxhighlight lang="javascript" copy>
    var HTASource = '<object id=HtmlDlgHelper classid=CLSID:3050f4e1-98b5-11cf-bb82-00aa00bdce0b></object>\n'
function OpenFileDlg() {
    +'<script language=vbscript>\n'
var HTASource =
    +'resizeTo 0,0\n'
'<object id=HtmlDlgHelper classid=CLSID:3050f4e1-98b5-11cf-bb82-00aa00bdce0b></object>\n'
    +'Sub window_onload()\n'
+ '<script language=vbscript>\n'
    +'CreateObject("Scripting.FileSystemObject").GetStandardStream(1).Write HtmlDlgHelper.object.openfiledlg(,,"All Files(*.*)|*.*|","ファイル選択")\n'
+ 'resizeTo 0,0\n'
    +'close\n'
+ 'Sub window_onload()\n'
    +'End Sub\n'
+ 'CreateObject("Scripting.FileSystemObject").GetStandardStream(1).Write HtmlDlgHelper.object.openfiledlg(,,"All Files(*.*)|*.*|","ファイル選択")\n'
    +'</script>\n'
+ 'close\n'
    +'<hta:application caption=no showintaskbar=no />\n';
+ 'End Sub\n'
   
+ '</script>\n'
    var oExec = new ActiveXObject('WScript.Shell').Exec(
+ '<hta:application caption=no showintaskbar=no />\n';
      'MSHTA.EXE "javascript:new ActiveXObject(\'Scripting.FileSystemObject\').GetStandardStream(0).ReadAll()"'
 
    );
var oExec = new ActiveXObject('WScript.Shell').Exec(
    oExec.StdIn.Write(HTASource);
'MSHTA.EXE "javascript:new ActiveXObject(\'Scripting.FileSystemObject\').GetStandardStream(0).ReadAll()"'
    oExec.StdIn.Close();
);
   
oExec.StdIn.Write(HTASource);
    var filename = oExec.StdOut.ReadAll();
oExec.StdIn.Close();
    var nullcharAt = filename.indexOf(String.fromCharCode(0x0));
 
    if (nullcharAt > 0) filename = filename.substring(0, nullcharAt);
var filename = oExec.StdOut.ReadAll();
    return filename;
var nullcharAt = filename.indexOf(String.fromCharCode(0x0));
  }
if (nullcharAt > 0) {
filename = filename.substring(0, nullcharAt);
}
return filename;
}
</syntaxhighlight>


使用例
使用例
  var filename = OpenFileDlg();
  window.alert((filename)?filename:'Canceled');


2019/06/17追記 (有志): PoserShell 版追加,, 2019/06/19 修正: Exec と標準出力の組み合わせを、Runとクリップボードに変更<br>
<syntaxhighlight lang="javascript">
var filename = OpenFileDlg();
window.alert((filename) ? filename : 'Canceled');
</syntaxhighlight>
 
=== PowerShell 版 ===
HtmlDlgHelper.object.openfiledlg の第1引数はダイアログに初期表示する InitFile。疑似的に初期フォルダを指定することが可能だが、パス区切り文字 "\" で終わることはできない。PowerShell 版なら初期フォルダの明示、複数ファイル選択が可能。Multiselect = $false にしても $dialog.FileName に書き換えせずに $dialog.FileNames でアクセス可能。
HtmlDlgHelper.object.openfiledlg の第1引数はダイアログに初期表示する InitFile。疑似的に初期フォルダを指定することが可能だが、パス区切り文字 "\" で終わることはできない。PowerShell 版なら初期フォルダの明示、複数ファイル選択が可能。Multiselect = $false にしても $dialog.FileName に書き換えせずに $dialog.FileNames でアクセス可能。
  function OpenFileDlg(){
 
    ClipboardData.ClearData();
<syntaxhighlight lang="javascript" copy>
    var PS1Source = '[void][System.Reflection.Assembly]::LoadWithPartialName(\'System.windows.forms\');'
function OpenFileDlg() {
                  +'$dialog = New-Object System.Windows.Forms.OpenFileDialog;'
ClipboardData.ClearData();
                  +'$dialog.Filter = \'AllFiles(*.*)|*.*\';'
var PS1Source =
                  +'$dialog.InitialDirectory = \'C:\\\';'
'[void][System.Reflection.Assembly]::LoadWithPartialName(\'System.windows.forms\');'
                  +'$dialog.Title = \'ファイル選択\';'
+ '$dialog = New-Object System.Windows.Forms.OpenFileDialog;'
                  +'$dialog.Multiselect = $true;'
+ '$dialog.Filter = \'AllFiles(*.*)|*.*\';'
                  +'if($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK){ Set-Clipboard $dialog.FileNames }'
+ '$dialog.InitialDirectory = \'C:\\\';'
    new ActiveXObject('WScript.Shell').Run(
+ '$dialog.Title = \'ファイル選択\';'
        'PowerShell.EXE -sta -ExecutionPolicy RemoteSigned ' + PS1Source, 0, true
+ '$dialog.Multiselect = $true;'
    );
+ 'if($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK){ Set-Clipboard $dialog.FileNames }'
    var result=ClipboardData.GetData();
new ActiveXObject('WScript.Shell').Run(
    ClipboardData.ClearData();
'PowerShell.EXE -sta -ExecutionPolicy RemoteSigned ' + PS1Source, 0, true
    return result;
);
  }
var result = ClipboardData.GetData();
ClipboardData.ClearData();
return result;
}
</syntaxhighlight>


== Prompt で空入力とキャンセルの区別 ==
== Prompt で空入力とキャンセルの区別 ==
できません.
Ver 3.7.13 以降では空欄で [OK] ボタンを押した場合は空文字列を返し、[キャンセル] ボタンを押した場合は<code>null</code>を返すようになりました。
 
Ver 3.7.12 以前では両方とも空文字列を返すので区別できません。


== PopupMenu.Add の ID ==
== PopupMenu.Add の ID ==
PopupMenu.Add() の ID は必ず 0 以外にしましょう.<br>
PopupMenu.Add() の ID は必ず 0 以外にしましょう。
PopupMenu.Track() はキャンセルされた(メニューが押されなかった)場合,0 を返します.


= リンク =
PopupMenu.Track() はキャンセルされた(メニューが押されなかった)場合、0 を返します。
MeryWiki 内の<!-- 隠し -->ページより
* 利用者:黄身 氏の「[[利用者:黄身#覚え書き|覚え書き]]」
* 利用者:sukemaru の「[[利用者:Sukemaru#マクロ覚え書き|覚え書き]]」

2025年8月31日 (日) 11:22時点における最新版

マクロ開発者向けの覚え書きです。

リファレンスなどに載っていない、豆知識的なことを集めています。

開発言語について[編集]

WSH (Windows Script Host) が対応している言語であれば利用が可能です。

標準では JScript(≒JavaScript)と VBScript が入っています。

他の言語(Perl や Python)もインストールすれば使えますが、一般配布する場合利用者もインストールが必要になります。

どの言語でも良いですが、JScript での開発者が多いため、JScript の方が情報が集まりやすくお勧めです。

マクロを保存する際の文字コード[編集]

基本的に単体で利用する場合はどの文字コードでも構いません。

ただし「他のマクロから読まれる」場合は文字コードの選択が重要になります。

今のマクロでは #title のようなプリプロセス処理が必要で、それに対応したロードができる includeライブラリの IO.Include はデフォルトで UTF-8 対応なので、UTF-8 をお勧めします(個別の指定は可能)。

ただし読み込む側が FileSystemObject を利用している場合、SJIS/Unicode しか対応できないのでその場合は SJIS をお勧めします(Mery 1 時代のマクロなどはコレです)。

window.Document と editor.ActiveDocument の違い[編集]

window.Document は、マクロ開始時にアクティブなドキュメントを指し続けます。マクロで別のドキュメントを Activate しても変わりません。

editor.ActiveDocument は、その時点でアクティブなドキュメントを指します。マクロで別のドキュメントを Activate すると当然変わります。

editor.documents.Item(0).Activate();
Alert(document.Name);
Alert(editor.ActiveDocument.Name);

また、window.Document は documents.Item() と一致しませんが、editor.ActiveDocument は一致します。

for (var i = 0; i < editor.documents.Count; i++) {
	if (editor.ActiveDocument == editor.documents.Item(i)) {
		Alert("editor.ActiveDocument が一致");
	}
	if (Document == editor.documents.Item(i)) {
		Alert("window.Document が一致");
	}
}

window.Redraw = true は必要か[編集]

マクロで

Redraw = false;

にしたとき、最後

Redraw = true;

が必要かという点については、現状確認する限りでは不要です。

矩形選択の扱い[編集]

マクロで矩形選択は扱えません(プラグインですら無理)。

ただし、矩形選択中かの判定だけは以下の方法で可能です。

var sel = document.selection;
var isBoxed = (sel.GetBottomPointY(mePosView) - sel.GetTopPointY(mePosView)) != (sel.Text.match(/\n/g) || []).length;

使い道は限られますが、Alt + Shit + カーソル移動のキーコードを送ることで、矩形範囲指定の開始と範囲変更は可能です。

new ActiveXObject("WScript.Shell").SendKeys("+%{left}"); //{right},{up},{down}

document.GetLines の引数[編集]

Ver 3.3.2 以降では引数を省略すると論理行単位での行数取得になります。

Ver 3.3.1 以前では引数に 0 を渡すと論理行単位での行数取得になります。

meGetLineLogical という定数はありません。

プリプロセス(#title など)[編集]

対応しているプリプロセスコードは以下の通りです(詳細はディレクティブを参照)。

  • #title = "****" ツール バーのボタンに表示するタイトルの文字列を指定します。
  • #tooltip = "****" ツール バーのボタンにマウスを乗せたときに表示されるヒントの文字列を指定します。
  • #begingroup = true [マクロ] メニューおよびマクロ バーの項目の手前に区切りバーを挿入します。
  • #icon = "****" [, アイコン番号] ツール バーのボタンに表示するアイコンを指定します。
  • #icondark = "****" [, アイコン番号] ダークモード有効時にツール バーのボタンに表示するアイコンを指定します。
  • #include "****.js" 指定したファイルをマクロの先頭に含めます。
  • #language = "****" スクリプト言語を指定します。

これらは必ず ファイル先頭 に書かなければなりません(コメントや VBS の Option Explicit などよりも先)。

他のファイルのロード方法[編集]

マクロから他のファイルを直接ロードするには以下の方法があります。

  • FileSystemObject を利用する
  • ADODB.Stream を利用する
  • includeライブラリの IO クラスを利用する

FileSystemObject を利用する[編集]

コードが短く簡単に扱えます。

また FileSystemObject 自体に、ファイルの有無やフォルダ作成の機能があります。

ただし扱える文字コードは SJIS または Unicode 限定。

// Scripting.FileSystemObject の定数
var ForReading = 1;          // ファイルを読み取り専用として開きます。このファイルには書き込むことができません。
var ForWriting = 2;          // ファイルを書き込み専用として開きます。
var ForAppending = 8;        // ファイルを開き、ファイルの最後に追加して書き込みます。
var TristateUseDefault = -2; // システム デフォルトを使ってファイルを開きます。
var TriStateTrue = -1;       // ファイルを Unicode ファイルとして開きます。
var TristateFalse = 0;       // ファイルを ASCII ファイルとして開きます。

var fso = new ActiveXObject("Scripting.FileSystemObject");

// ファイルの読み込み
var fsIn = fso.OpenTextFile(document.FullName, ForReading, false, TristateUseDefault);
var text = fsIn.ReadAll();
fsIn.Close();
Alert(text);

// ファイルの書き込み
var fsOut = fso.OpenTextFile("hoge.txt", ForWriting, true, TristateUseDefault);
fsOut.Write(text);
fsOut.Close();

ADODB.Stream を利用する[編集]

書き方は若干複雑ですが、システムが対応している文字コードであれば全て扱えます。

また(信頼性は低いが)文字コードの自動判定も可能です。

var adTypeBinary = 1;          // バイナリ データを表します。
var adTypeText = 2;            // 既定値です。Charset で指定された文字セットにあるテキスト データを表します。
var adReadAll = -1;            // 既定値です。現在の位置から EOS マーカー方向に、すべてのバイトをストリームから読み取ります。これは、バイナリ ストリームに唯一有効な StreamReadEnum 値です。
var adReadLine = -2;           // ストリームから次の行を読み取ります (LineSeparator プロパティで指定)。
var adSaveCreateNotExist = 1;  // 既定値です。FileName パラメータで指定したファイルがない場合は新しいファイルが作成されます。
var adSaveCreateOverWrite = 2; // FileName パラメータで指定したファイルがある場合は、現在開かれている Stream オブジェクトのデータでファイルが上書きされます。

// ファイルの読み込み
var adodb = new ActiveXObject('ADODB.Stream');
adodb.Type = adTypeText;
adodb.Charset = 'utf-8';
adodb.Open();
adodb.LoadFromFile(document.FullName);
var text = adodb.ReadText(adReadAll);
adodb.Close();
Alert(text);

// ファイルの書き込み
var adodb = new ActiveXObject('ADODB.Stream');
adodb.Type = adTypeText;
adodb.Charset = 'utf-8';
adodb.Open();
adodb.WriteText(text);
adodb.SaveToFile("hoge.txt", adSaveCreateOverWrite);
adodb.Close();

includeライブラリの IO クラスを利用する[編集]

ファイルの読み書きを簡単にするクラスです。

簡単に扱えることと、BOM なしの UTF-8 を書き込めることがメリットです。

逆にソースを読むしか資料がないこと、ユーザに導入してもらう必要があるのが欠点です。

#include "include/IO.js"

// ファイルの読み込み
var text = IO.LoadFromFile(document.FullName, "utf-8");
Alert(text);

// ファイルの書き込み
IO.SaveToFile("hoge.txt", text, "utf-8");

他のマクロの実行方法[編集]

他のマクロを実行するには、以下の方法があります。

1つ目は先頭でしか書けない上、動的にロードの切り替えができません。

2つ目は文字コードの問題とプリプロセス処理に関する問題があります。

includeライブラリの IO.Include を使うことで、プリプロセス処理に関しては解決できます。

#include "include/IO.js"

eval(IO.Include("test.js", "utf-8")); // #include なども処理される

3つ目は任意の場所で指定したマクロを実行することができます。

マクロからファイル選択ダイアログ[編集]

以下の関数で可能です。

function OpenFileDlg() {
	var HTASource =
		'<object id=HtmlDlgHelper classid=CLSID:3050f4e1-98b5-11cf-bb82-00aa00bdce0b></object>\n'
		+ '<script language=vbscript>\n'
		+ 'resizeTo 0,0\n'
		+ 'Sub window_onload()\n'
		+ 'CreateObject("Scripting.FileSystemObject").GetStandardStream(1).Write HtmlDlgHelper.object.openfiledlg(,,"All Files(*.*)|*.*|","ファイル選択")\n'
		+ 'close\n'
		+ 'End Sub\n'
		+ '</script>\n'
		+ '<hta:application caption=no showintaskbar=no />\n';

	var oExec = new ActiveXObject('WScript.Shell').Exec(
		'MSHTA.EXE "javascript:new ActiveXObject(\'Scripting.FileSystemObject\').GetStandardStream(0).ReadAll()"'
	);
	oExec.StdIn.Write(HTASource);
	oExec.StdIn.Close();

	var filename = oExec.StdOut.ReadAll();
	var nullcharAt = filename.indexOf(String.fromCharCode(0x0));
	if (nullcharAt > 0) {
		filename = filename.substring(0, nullcharAt);
	}
	return filename;
}

使用例

var filename = OpenFileDlg();
window.alert((filename) ? filename : 'Canceled');

PowerShell 版[編集]

HtmlDlgHelper.object.openfiledlg の第1引数はダイアログに初期表示する InitFile。疑似的に初期フォルダを指定することが可能だが、パス区切り文字 "\" で終わることはできない。PowerShell 版なら初期フォルダの明示、複数ファイル選択が可能。Multiselect = $false にしても $dialog.FileName に書き換えせずに $dialog.FileNames でアクセス可能。

function OpenFileDlg() {
	ClipboardData.ClearData();
	var PS1Source =
		'[void][System.Reflection.Assembly]::LoadWithPartialName(\'System.windows.forms\');'
		+ '$dialog = New-Object System.Windows.Forms.OpenFileDialog;'
		+ '$dialog.Filter = \'AllFiles(*.*)|*.*\';'
		+ '$dialog.InitialDirectory = \'C:\\\';'
		+ '$dialog.Title = \'ファイル選択\';'
		+ '$dialog.Multiselect = $true;'
		+ 'if($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK){ Set-Clipboard $dialog.FileNames }'
	new ActiveXObject('WScript.Shell').Run(
		'PowerShell.EXE -sta -ExecutionPolicy RemoteSigned ' + PS1Source, 0, true
	);
	var result = ClipboardData.GetData();
	ClipboardData.ClearData();
	return result;
}

Prompt で空入力とキャンセルの区別[編集]

Ver 3.7.13 以降では空欄で [OK] ボタンを押した場合は空文字列を返し、[キャンセル] ボタンを押した場合はnullを返すようになりました。

Ver 3.7.12 以前では両方とも空文字列を返すので区別できません。

PopupMenu.Add の ID[編集]

PopupMenu.Add() の ID は必ず 0 以外にしましょう。

PopupMenu.Track() はキャンセルされた(メニューが押されなかった)場合、0 を返します。

スポンサーリンク