外部VBScriptにオブジェクトを渡す

# 概要
- [ExcecuteGlobal]を使って、外部のVBScriptにオブジェクトを渡す
- VisualStudioを使ってVBScriptのデバッグ(ステップ実行,変数の参照など)する

「VisualStudioを使ってVBScriptのデバッグ」は、
[Blogs By Kresten: VBScript Projects in Visual Studio]、[メモ: Visual Studio を使って VBScript の開発を行う - 高東ソフトウェアサービス]、[VBScript でもデバッグしながら開発を行える | ええかげんブログ(本店)]と同じ内容なので割愛します。
ポイントは、「CtrlC+F5(デバッグなしで開始)」で実行することです。
※F5だと別プロセスのVisualStudioでデバッグ開始されてしまうようです。

# 動機

サクラエディタのマクロとプラグインは、マクロ/プラグインのスクリプト内で生成しない(＝スクリプト実行時にエディタから渡される)[インターフェースオブジェクト](http://d.hatena.ne.jp/language_and_engineering/20081021/1224511689)(Editorオブジェクトなど)を使って、エディタの情報取得・操作を行います。※詳しくは、[プラグイン開発者ガイド(plugin.chm)](http://sakura.qp.land.to/?Plugin%2Fchm)を参照

たいていはマクロ/プラグインのスクリプト内に、インターフェースオブジェクトを期待する(=エディタを操作する)ロジックがあるので、↓のようにエディタ経由でvbs実行をすると問題ありませんが、
![a.png](https://qiita-image-store.s3.amazonaws.com/0/34777/e594100c-3d97-779f-e387-ba1985ba06c3.png)

スクリプトをダブルクリックで実行すると、↓のようなエラーが発生するものになります。
![error.png](https://qiita-image-store.s3.amazonaws.com/0/34777/a74ebf5b-5cc0-bea0-55ec-89e8a3efd3f4.png)

ダブルクリックでちょっとしたテストを実施できないのは、もどかしいこともあったので、「vbsをダブルクリックしてテストを実行する方法はないか」と考えていました。


そんなときに、

- [VBScriptで悩んだことメモ - Qiita][外部スクリプトのインクルード2]→「VBSでInclude」
- [VBScript 基礎文法最速マスター - CX's VBScript Diary][外部スクリプトのインクルード1]→「9. 知っておいたほうがよい文法」
- [VBScript でもデバッグしながら開発を行える | ええかげんブログ(本店)](http://algorhythnn.jp/blg/2013/11/06/vbs-debug-use-visual_studio2010/)

を見かけたので使ってみよう・・・というのが今回の動機です。


# 詳細

## [ExcecuteGlobal]を使って、外部のVBScriptにオブジェクトを渡す

### ソース
(1) test_external_script.vbs内に適当なクラス(SharedObjClass)を作る。
(2) SharedObjClassのインスタンス(Editor)を作る
(3) Editorのメンバ変数(GetFilename)にGetRefで適当な関数Func1を割り当てる
(4) 外部のスクリプト(external_script.vbs)を読み込む
(5) ExcecuteGlobalを使って 読み込んだexternal_script.vbs を実行する
(6) external_script.vbs側でEditor.GetFilename を呼び出す
(7) external_script.vbs側でEditor.FuncSetByExternalに適当な関数Func2を割り当てる
(8) test_external_script.vbs側でFuncSetByExternalを呼び出す

VisualStudio側は、[VBScript でもデバッグしながら開発を行える | ええかげんブログ(本店)]とほぼ同じですが、
コマンドとコマンド引数は、
コマンド：wscript.exe
コマンド引数：test_external_script.vbs //X
としています。


```vbscript:test_external_script.vbs
Option Explicit

' (1) test_external_script.vbs内に適当なクラス(SharedObjClass)を作る。
Class SharedObjClass
  Public GetFilename
  Public FuncSetByExternal
End Class

' (2) SharedObjClassのインスタンス(Editor)を作る
Dim Editor
Set Editor = New SharedObjClass

' (3) Editorのメンバ変数(GetFilename)にGetRefで適当な関数Func1を割り当てる
Function Func1()
    Func1 = Wscript.ScriptFullName
End Function
Set Editor.GetFilename = GetRef("Func1") 

'(4) 外部のスクリプト(external_script.vbs)を読み込む
Dim externalScript
Set externalScript = CreateObject("Scripting.FileSystemObject").OpenTextFile("external_script.vbs")

' (5) ExcecuteGlobalを使って 読み込んだexternal_script.vbs を実行する
ExecuteGlobal externalScript.ReadAll
externalScript.close

' (8) test_external_script.vbs側でFuncSetByExternalを呼び出す
MsgBox(Editor.FuncSetByExternal())
```

```vbscript:external_script.vbs
Option Explicit

' (6) external_script.vbs側でEditor.GetFilename を呼び出す
MsgBox(Editor.GetFilename())

' (7) external_script.vbs側でEditor.FuncSetByExternalに適当な関数Func2を割り当てる
Function Func2()
    Func2 = "external_script.vbs"
End Function
Set Editor.FuncSetByExternal = GetRef("Func2")
```

### 実行結果
「(5) ExcecuteGlobalを使って 読み込んだexternal_script.vbs を実行する」の直前で止めます。
![c.png](https://qiita-image-store.s3.amazonaws.com/0/34777/517abe13-42d5-bf9b-e11a-5f737a0b4cb4.png)


F10(ステップオーバー) or F11(ステップイン) で進めていくと、Script Documents内にeval codeが現れ、↓のMsgBoxが出ます。表示されているファイルパスは、test_external_script.vbsのパス(Func1 = Wscript.ScriptFullNameで取得したもの)です。
これで、external_script.vbs側にEditorが渡り、メソッドを呼び出せたことがわかりました。
![d.png](https://qiita-image-store.s3.amazonaws.com/0/34777/6ecc4c44-85c9-1523-370f-86961c97b2b1.png)


eval code内は"external_script.vbs"と同一です。ちなみに、eval code内にブレークポイントを設定することができず、"external_script.vbs"にブレークポイントを設定しても素通りします。
![e.png](https://qiita-image-store.s3.amazonaws.com/0/34777/778f7c52-cd5b-5148-c3f0-2e70aa757c11.png)


(8)を実行すると、(7) のFunc2が呼び出せていることがわかります。
これで、external_script.vbs側でかけたEditorに対する変更がtest_external_script.vbs側にも反映されていることがわかります。
![f.png](https://qiita-image-store.s3.amazonaws.com/0/34777/d9d4635d-d750-676d-a070-cd288bdc1446.png)

最後に、test_external_script.vbsをダブルクリックして実行すると、external_script.vbsをエラーなしで実行することができることが確認できます。

## まとめ
この仕組みを使うと、サクラエディタのマクロ/プラグインのスクリプト内に、模擬インターフェースオブジェクト(Editor)を渡すことができるので、ダブルクリックで実行できるラッパー的なテスト用スクリプトを作ることができます。

# 参考
[ExcecuteGlobal]関連

- [VBScriptで悩んだことメモ - Qiita][外部スクリプトのインクルード2]→「VBSでInclude」
- [VBScript 基礎文法最速マスター - CX's VBScript Diary][外部スクリプトのインクルード1]→「9. 知っておいたほうがよい文法」

[クラス]関連

- [VBSのクラスオブジェクト - FSWikiLite]

[GetRef関数]関連

- [VBS - FSWikiLite]→「関数のリファレンスを使う！！」


VisualStudio関連

-  [VBScript でもデバッグしながら開発を行える | ええかげんブログ(本店)]
-  [Blogs By Kresten: VBScript Projects in Visual Studio]
-  [メモ: Visual Studio を使って VBScript の開発を行う - 高東ソフトウェアサービス]


[ExcecuteGlobal]:https://msdn.microsoft.com/ja-jp/library/cc392448.aspx

[外部スクリプトのインクルード1]:https://vbscript.g.hatena.ne.jp/cx20/20100131/1264906231

[外部スクリプトのインクルード2]:http://qiita.com/honeniq/items/88462b12d2244480026a

[クラス]:https://msdn.microsoft.com/ja-jp/library/cc392441.aspx

[GetRef関数]:https://msdn.microsoft.com/ja-jp/library/cc410245.aspx

[Windows Script Componentの使用-Sakura Editor Macro]:http://sakura.qp.land.to/SakuraMacro/usage/wsc.html

[VBSのクラスオブジェクト - FSWikiLite]:http://tuka.s12.xrea.com/index.xcg?p=VBS%A4%CE%A5%AF%A5%E9%A5%B9%A5%AA%A5%D6%A5%B8%A5%A7%A5%AF%A5%C8

[VBS - FSWikiLite]:http://tuka.s12.xrea.com/index.xcg?p=VBS#p17

[VBScript でもデバッグしながら開発を行える | ええかげんブログ(本店)]:http://algorhythnn.jp/blg/2013/11/06/vbs-debug-use-visual_studio2010/

[メモ: Visual Studio を使って VBScript の開発を行う - 高東ソフトウェアサービス]:http://www.koutou-software.net/junk/use-vs-project-with-vbscript.html

[Blogs By Kresten: VBScript Projects in Visual Studio]:http://krestenm.blogspot.jp/2007/12/vbscript-projects-in-visual-studio2.html