MS-Wordのマクロの取扱いについて記します。
マクロについての組み込み・取り出し、削除、一覧情報の取得、実行などを扱います。
以降で掲げるサンプルスクリプトを実行した環境は次のとおり。
サンプルのスクリプトは、いずれもrubyスクリプトです。 macro_wrd.zipに含まれています。
MS-Wordを自動操縦するためのruby用ライブラリ wrdap.rb は、 wrdap104.zip に含まれています。
MS-Wordでマクロを扱う場合の仕組みとして、まずプロジェクト(VBProject)というのがあり、その中に複数のコンポーネント(VBComponent)が含まれています。そして、コンポーネントの本体(ソースコード)を見ると、「Sub Macro1 …… End Sub」などのマクロ(プロシージャ)が書かれています。一つのコンポーネントに複数のプロシージャが書かれていることもしばしばです。
コンポーネントには、標準モジュールとかクラスモジュールなどの種類(Type)と、「Module1」とか「Class1」などの名前(Name)の属性があります。これら属性の値は、component.Type(数値)、component.Name(文字列)で知ることができます。
wrdap.rb(v1.04)のメソッドが対象とするのは、コンポーネントのタイプ 1:標準モジュール、2:クラスモジュール、3:ユーザーフォームの3種類です。他にタイプ 100 の ThisDocument などがありますが、それらは対象にしません。以下の解説でも、タイプ1〜3を取り上げます。
rubyスクリプトでマクロの組み込みや取り出しを行う場合、MS-Wordのマクロのセキュリティを調整する必要があります。
MS-WordをGUI操作して、次の設定変更を行います。具体的な操作方法は、MS-Wordのバージョンによって違うのでここでは言及しません。他のサイトなどを参考にして下さい。
この調整は、rubyスクリプトでマクロを扱う場合、必須です。
rubyスクリプトでMS-Wordを操縦するだけなら、マクロのセキュリティレベルを気にする必要はないと思います。
ただ、rubyスクリプトでワード文書にマクロを組み込んで、後でその文書を開いてGUI操作中にマクロを実行しようとする場合は、マクロのセキュリティレベルをゆるめる必要があります。
ワードのメニューの「マクロのセキュリティ」において、「すべてのマクロを有効にする」にします。
rubyスクリプトで、変数 str にマクロのソースコードが記録されているとします。つまり “Sub Macro1 …… End Sub” が str にセットされているものとします。
このとき、docが1つのワード文書を指しているとすれば、
doc.macro_add(str)
と記述することで、マクロを組み込むことができます。標準モジュールの「Module1」という名前のコンポーネントとして組み込まれます。「Module1」が既に存在するのであれば「Module2」になります。
ワード文書の先頭に「はじめに」という1行を挿入するマクロの組み込み例を示します。
組み込むだけでは何なので、それを実行してからワード文書を保存して終了することにします。保存されたワード文書の先頭には「はじめに」が書き込まれているはずです。
マクロの実行は、「doc.macro_run(“Macro1”)」で行います。
−−−− wmcr01.rb ここから
# encoding: Windows-31J
require "wrdap"
str = DATA.read # マクロソースコードをstrに代入
filename = "wmcr01.doc"
File.unlink(filename) if test(?e, filename)
Wrdap.new(filename) do |doc|
component = doc.macro_add(str) # マクロの組込み
puts "#{component.Name}にマクロを組み込みました."
doc.macro_run("Macro1") # マクロの実行
doc.save # 文書の保存
end
__END__
Sub Macro1
Dim rng As Range
Set rng = ActiveDocument.Range(0,0)
With rng
.InsertParagraph
.InsertBefore "はじめに"
End With
End Sub
−−−− wmcr01.rb ここまで
「str = DATA.read」は、スクリプトの最後の方にある「__END__」よりも後ろを読み込んで、それを文字列 str に代入するものです。マクロのソースコードの代入です。
変数 str への代入は、もちろん「str = “Sub Macro1 ……”」のようにしてもいいわけですが、後で長めのVBAプログラムも出てくるので、rubyスクリプトと交じってごちゃごちゃしないよう、VBAプログラムを最後の方に置くようにしました。
「doc.macro_add(str)」とした場合、コンポーネント(今回は標準モジュール)の名前をどうするかは、MS-Wordにお任せになります。
どんな名前が割り当てられたかを知りたい場合は、
component = doc.macro_add(str)
として、component.Name の値を確認します。component.Type の方は、数値が代入されているはずです。1なら標準モジュール、2であればクラスモジュールなどです。
コンポーネントの名前を指定したい時は、
doc.macro_add(str, 1, "Module5")
のようにします。第2引数がタイプ、第3引数が名前です。
マクロがテキストファイルに書かれている場合は、
doc.macro_add("macro.txt")
のようにして、引数にファイル名を与えることができます。
第1引数の文字列が、キャリッジリターン(CR)も改行(LF)も含んでおらず、かつ、それがファイル名として有効な場合(実際に該当のファイルが存在する場合)、その文字列をファイル名とみなして、その中身をマクロとして組み込みます。
macro_run(“Macro1”) は、Macro1を実行します。
もしMacro1が引数を受け取るタイプのものであれば、「macro_run(“Macro1”, arg1, arg2)」のようにします。
macro_runにはrunという別名が割り当てられているので、doc.run(“Macro1”) のように書くこともできます。
ワード文書に組み込まれているマクロのソースコードを取り出して、文字列に代入するには、
str = doc.macro_code()
のようにします。この場合、引数を省略しているので、タイプ1〜3の全コンポーネントのソースコードを取得します。
str = doc.macro_code(1, "Module1")
とすれば、標準モジュールで「Module1」というコンポーネントのソースコードを取り出します。
str = doc.macro_code(1)
のように、タイプのみ指定して、名前を省略すると、タイプ1(標準モジュール)である全コンポーネントのソースコードを取り出します。
取り出したソースコード(文字列)には、要所要所に
' <<type:Standard, name:Module1>>
のようなコメント行が挿入されています。これは、コンポーネントのタイプと名前をコメントとして挿入したものです。オリジナルのソースコードにはありません。
サンプルの wmcr02.rb は、二つのマクロを組み込んで、後の方でそれを文字列として取り出し、ファイル wmcr02.txt に書き出しています。
一つ目のマクロMacro1は、文書の先頭に「昨日は朝から雨が降っていた。」という1行を挿入します。
2つ目のMacro2は、「雨」を太字にするものです。
前掲の wmcr01.rb と共通するところが多いですが、参考まで下に掲げます。
−−−− wmcr02.rb ここから
# encoding: Windows-31J
require "wrdap"
str = DATA.read # マクロソースコードをstrに代入
filename = "wmcr02.doc"
File.unlink(filename) if test(?e, filename)
Wrdap.new(filename) do |doc|
doc.macro_add(str) # マクロの組込み
doc.macro_run("Macro1")
doc.macro_run("Macro2")
code_str = doc.macro_code() # マクロのソースコードを取得
File.open("wmcr02.txt", "w") {|ff| ff.print code_str}
doc.save
end
__END__
Sub Macro1
Dim rng As Range
Set rng = ActiveDocument.Range(0,0)
With rng
.InsertParagraph
.InsertBefore "昨日は朝から雨が降っていた。"
End With
End Sub
Sub Macro2
Dim rng As Range
Set rng = ActiveDocument.Content
rng.Find.Execute FindText:="雨", Forward:=True
If rng.Find.Found = True Then rng.Bold = True
End Sub
−−−− wmcr02.rb ここまで
Macro2において、最初、変数rngには文書全体を指し示すRangeをセットするわけですが、rng.Find.Executeで「雨」を栓索すると(そして、みつかると)、rngは、「雨」だけを指し示すRangeに変更されるようです。
そのため、「rng.Bold = True」とすれば、「雨」だけが太字になります。
この項では、コンポーネントのタイプ、名前、ソースコード、そのソースコードに書かれているプロシージャ名の一覧を取得する方法を取り上げます。プロシージャ名は、これまでのサンプルでいうと Macro1, Macro2 といった名前のことです。
情報取得の前に、標準モジュールしか組み込まれていないのはつまらないので、クラスモジュールも組み込むことにします。そのやり方から始めます。
サンプルの wmcr03.rb では、JamDocというクラスを設定しています。ごく簡単なクラスで、メンバー変数を持たず、二つのメソッドがあるだけです。わざわざクラスにしなくても、そのまま標準モジュールにして差し支えない内容ですが、あえてクラスにしてみます。
このクラスの目的は、ワード文書にテキストファイルもしくは別のワード文書を取り込むというものです。
メソッド MergeText(fname) がテキストファイルの取り込み、MergeDoc(fname) は別のワード文書の取り込みに用います。
rubyでクラスを設定する時は、「class JamDoc …… end」のように書きますが、VBAでクラスを設ける場合は、ソースコード中に「JamDoc」というクラス名を書く必要がありません。
「doc.macro_add(str, 2, “JamDoc”)」のようにして、コンポーネントを組み込む際に、クラスモジュールの名前「JamDoc」を指定します。すると、これがクラスの名前になります。
wmcr03.rb では、クラス JamDoc をテストするためのマクロ Macro1(fname) を標準モジュールとして組み込んでいます。
この Macro1 を実行する際、引数として “test.txt” のように拡張子が「.txt」のファイル名を引きわたすと、テキストファイルが取り込まれます。それ以外の拡張子の場合は、ワード文書として取り込まれます。いずれも文書末尾に追加挿入されます。
テキストファイルは単純な挿入の形で取り込まれますが、ワード文書は、セクション区切りを挿入した上で、ページも改める形で取り込まれます。
この項の本旨はコンポーネントの情報を取得することですが、とりあえずそれは横に置いておいて、wmcr03.rb では、クラスモジュールと標準モジュールの組み込み、およびその実行を行っています。
ここで作成されるワード文書 wmcr03.doc は、以降の wmcr04.rb〜wmcr06.rb で使うので、消去せずに残しておいて下さい。
以下、wmcr03.rb を掲げます。
−−−− wmcr03.rb ここから
# encoding: Windows-31J
require "wrdap"
txt_file = Wrd::fullpath( "insert01.txt" ) # 取り込むテキストファイル
doc_file = Wrd::fullpath( "insert02.doc" ) # 取り込むワード文書
filename = "wmcr03.doc" # これから作るワード文書
cls_str, mdl_str = DATA.read.split(/\n########*\n+/) # マクロ定義の読込み
File.unlink(filename) if test(?e, filename)
Wrdap.new(filename) do |doc|
doc.macro_add(cls_str, 2, "JamDoc") # クラスモジュールの組み込み
doc.macro_add(mdl_str) # 標準モジュールの組み込み
doc.macro_run("Macro1", txt_file) # マクロ実行(テキストファイルの取込み)
doc.macro_run("Macro1", doc_file) # マクロ実行(ワード文書の取込み)
doc.save # 文書の保存
end
__END__
' JamDocというクラスの定義。2つのメソッドを持つ。
Sub MergeText(fname As String) 'テキストファイルの取込み
Dim rng As Range
Set rng = ActiveDocument.Content '文書全体を代入
rng.Collapse Direction:=wdCollapseEnd '範囲解除&範囲末尾に移動
rng.InsertFile FileName:=fname, _
Range:="", ConfirmConversions:=False, _
Link:=False, Attachment:=False
Set rng = Nothing
End Sub
Sub MergeDoc(fname As String) 'ワード文書の取込み
Dim rng As Range
Set rng = ActiveDocument.Content '文書全体を代入
rng.Collapse Direction:=wdCollapseEnd '範囲解除&範囲末尾に移動
With rng
.InsertBreak wdSectionBreakNextPage '次のページ上にセクション区切りを挿入
.InsertFile fname
.Collapse Direction:=wdCollapseEnd '範囲解除&範囲末尾に移動
End With
Set rng = Nothing
End Sub
########
' JamDocクラスを利用するためのマクロ
Sub Macro1(fname As String)
Dim jam As JamDoc
Set jam = New JamDoc
If LCase(fname) Like "*.txt" Then
jam.MergeText(fname)
Else
jam.MergeDoc(fname)
End If
End Sub
−−−− wmcr03.rb ここまで
VBAノソースコードは、「########」という行で区切られています。それより前がクラスモジュール、それより後が標準モジュールです。
rubyスクリプトの先頭に近いところで
cls_str, mdl_str = DATA.read.split(/\n########*\n+/)
としているのは、「########」を区切りとして、cls_strにクラスモジュールのソースコードを、mdl_strに標準モジュールのソースコードを代入するものです。
コンポーネントのソースコードを macro_code() で得られることは先述したとおりです。
その他、ワード文書に組み込まれているコンポーネントのタイプと名前の組みを得る macro_list() があります。このメソッドに対する引数(type, name)の与え方は、macro_code() と同様です。
戻り値は [[type1, name1], [type2, name2], ……] のような配列です。
全コンポーネントの一覧を出力するには次のようにします。
mlist = doc.macro_list()
mlist.each do |type, name|
printf("type:%d name:%s\n", type, name)
end
なお、macro_list2() を用いると、該当のコンポーネントオブジェクトを配列に入れて返します。使い方は macro_list() と同じです。
次に、プロシージャ名の取得ですが、これは macro_name() で行います。
引数を与えなければ、タイプ1〜3の全コンポーネントのプロシージャ名を取得します。
「doc.macro_name(1, “Module1”)」のようにすると、標準モジュール「Module1」に含まれるプロシージャの名前群を取得します。
戻り値が少々ややこしいですが、ハッシュの形で返されます。ハッシュの key は、コンポーネントを指す [type, name] 形式の配列です。具体的には「[1, “Module1”]」などです。これが key です。
ハッシュの value の方は、プロシージャ名を要素とする配列で、例えば「[“Macro1”, “Macro2”]」のような形になります。
プロシージャ名の一覧を出力するには、例えば次のようにします。
hs = doc.macro_name()
hs.each do |key, proc_names|
type, name = key
printf("%d %s: ", type, name)
puts proc_names.join(", ")
end
サンプル wmcr04.rb は、上の macro_list, macro_name を wmcr03.doc に対して適用しています。
また、各コンポーネントのソースコードは、macro_code() で取得して、それをテキストファイルに書き出しています。
以下、wmcr04.rb を掲げます。
−−−− wmcr04.rb ここから
# encoding: Windows-31J
require "wrdap"
filename = "wmcr03.doc"
Wrdap.new(filename) do |doc|
# コンポーネントの type, name を出力
puts "コンポーネント一覧"
mlist = doc.macro_list()
mlist.each do |type, name|
printf("type:%d name:%s\n", type, name)
end
printf("\n")
# プロシージャ名一覧の出力
puts "プロシージャ名一覧"
hs = doc.macro_name
hs.each do |key, proc_names|
type, name = key
printf("%d %s: ", type, name)
puts proc_names.join(", ")
end
# ソースコードをファイルに出力
mlist.each do |type, name|
str = doc.macro_code(type, name)
fname = "#{name}_code.txt"
File.open(fname, "w") {|ff| ff.write str}
end
end
−−−− wmcr04.rb ここまで
各コンポーネントの情報を取得できるようになったので、それらを別のワード文書にコピーしてみます。
マクロを別のワード文書にコピーすることについては、後述の macro_export, macro_import を使う方が確実です。これらはファイルを経由してコピーする方法です。
一方、ここで紹介するのは、ファイルを介さずにコピーする方法です。wmcr05.rbがそのサンプルです。
二つのワード文書 wmcr03.doc と wmcr05.doc を同時に開いて、前者のコンポーネント情報を取得し、それに基づいて後者にマクロを組み込みます。
macro_remove(マクロの削除)を別にすれば、これまで紹介したメソッドだけで行っていますので、説明を付け加える必要はないと思います。
以下、wmcr05.rbを掲げます。
このスクリプトを実行する時は、wmcr03.doc, insert01.txt, insert02.doc の3つのファイルがカレントディレクトリにないとエラーになるので注意して下さい。
−−−− wmcr05.rb ここから
# encoding: Windows-31J
require "wrdap"
txt_file = Wrd::fullpath( "insert01.txt" ) # 取り込むテキストファイル
doc_file = Wrd::fullpath( "insert02.doc" ) # 取り込むワード文書
File.unlink("wmcr05.doc") if test(?e, "wmcr05.doc")
wrd = Wrdap.new # ワードの起動
wrd.opens_once("wmcr03.doc", "wmcr05.doc") do |doc1, doc2|
doc2.macro_remove # 念のためdoc2(wmcr05.doc)のマクロを削除
mlist = doc1.macro_list
mlist.each do |type, name|
str = doc1.macro_code(type, name)
doc2.macro_add(str, type, name)
end
doc2.macro_run("Macro1", txt_file) # テキストファイル取込み
doc2.macro_run("Macro1", doc_file) # 別のワード文書取込み
doc2.save # wmcr05.docの保存
end
wrd.quit # ワードの終了
−−−− wmcr05.rb ここまで
「doc2.macro_remove」は、doc2(wmcr05.doc)に組み込まれているタイプ1〜3の全コンポーネントを削除します。doc2にマクロが何も組み込まれていなければ、結果として何も行われません。
「doc.macro_remove(1, “Module1”)」のように引数を指定すれば、標準モジュールの「Module1」だけを削除します。
「doc.macro_remove(1)」のようにタイプだけ指定すれば、該当のタイプ1(標準モジュール)を総て削除します。
「doc.macro_remove(nil, “Module5”)」とすれば、タイプを問わず、「Module5」という名前のコンポーネントを削除します。
[補足]
wmcr05.rb で採用したマクロコピーの方法は、要するにマクロのソースコードをコピーしているだけです。ソースコード以外の情報も必要になるケースでは適切なコピーが行われないことになります。
例えば、コンポーネントのタイプ3(ユーザーフォーム)には、多くの場合、ソースコード以外にも付随情報があります。なので、wmcr05.rbのやり方でコピーすることはできません。
標準モジュールとクラスモジュールについては概ね大丈夫だと思いますが、確実にコピーするなら、次項の macro_export, macro_import を用いるのがいいと思います。
ここでは、マクロをファイルとして書き出す方法と、そのファイルを読み込んでマクロを組み込む方法について記します。
ここでいうファイルは、単にマクロのソースコードが書かれているものではなく、コンポーネントの各種Attributeが一緒に記録されているファイルです。
「doc.macro_export()」とすれば、タイプ1〜3のコンポーネント総てをファイルとして書き出します。
そのとき、標準モジュールの拡張子は “.bas”、クラスモジュールは “.cls”、ユーザーフォームは “.frm” になります。
ファイル名本体(拡張子を除く)は、コンポーネントの名前がそのまま用いられます。つまり「Module1」とか「Class1」などになります。ファイル名は、「Module1.bas」 「Class1.cls」のようになります。
ファイルが書き出されるフォルダは、ワード文書が存在するのと同じフォルダです。
「doc.macro_export(1, “Module1”)」とすれば、「Module1.bas」だけが書き出されます。
macro_export() の戻り値は、出力成功コンポーネントのタイプと名前の組みが複数含まれる配列 [[type1, name1], [type2, name2]] などになります。
何も出力しなかった時は、空配列 [] を返します。
rubyスクリプト中で、漏れなくexportが行われたかどうかをチェックするには、例えば次のような方法があります。
full_list = doc.macro_list
export_list = doc.macro_export
ary = full_list - export_list
上のようにして、ary が空配列 [] でない時は、exportに失敗したコンポーネントがあることになります。
ワード文書 wmcr03.doc の全コンポーネントを書き出すrubyスクリプト wmcr06a.rb を下に掲げます。ごく簡単なものです。
これを実行すると、Module1.bas, JamDoc.cls の二つのファイルが書き出されます。
−−−− wmcr06a.rb ここから
# encoding: Windows-31J
require "wrdap"
Wrdap.new("wmcr03.doc") do |doc|
doc.macro_export
end
−−−− wmcr06a.rb ここまで
[補足]
macro_export()の第3引数に true を与えると、書き出しファイル名にワード文書名を付加します。「test.doc!Module1.bas」のようなファイル名に書き出します。
すべてのコンポーネントをワード文書名つきで書き出すには
doc.macro_export(nil, nil, true)
とします。
「doc.macro_import(“Module1.bas”)」とすれば、ファイル「Module1.bas」を読み込みます。
「doc.macro_import(“Module1.bas”, true)」のように、第2引数として true または false を指定できます。これは、ワード文書内に既に同名のコンポーネントがあるかどうかをチェックするかしないかのフラグです。いわば重複チェックの有無です。
第2引数が true だと、重複チェックを行います。指定したファイルが「Module1.bas」のとき、拡張子を除いた「Module1」という名前のコンポーネントがワード文書中に既に存在するかを確認し、存在する場合は読込みを行いません。
false であれば、重複チェックは行わず、ファイルを読み込みます。その場合のコンポーネントの名前は、MS-Wordが自動的に調整することになります。
第2引数のデフォルト値は false です。
先述の macro_export で書き出したファイルを、別のワード文書において macro_import で読み込めば、そのワード文書に同じマクロを組み込むことができます。
macro_import() の戻り値は、読み込みによって生成されたコンポーネントのタイプと名前 [type, name] となります。
読み込みが行われなかった時は nil を返します。
先の wmcr06a.rb で書き出された Module1.bas, JamDoc.cls を読み込むサンプル wmcr06b.rb を下に掲げます。ワード文書 wmcr06.doc に読み込みます。
マクロがちゃんと組み込まれているのを確認する意味で、Macro1を実行しています。そのため insert01.txt, insert02.doc も必要になるので注意して下さい。
−−−− wmcr06b.rb ここから
# encoding: Windows-31J
require "wrdap"
txt_file = Wrd::fullpath( "insert01.txt" ) # 取り込むテキストファイル
doc_file = Wrd::fullpath( "insert02.doc" ) # 取り込むワード文書
File.unlink("wmcr06.doc") if test(?e, "wmcr06.doc")
Wrdap.new("wmcr06.doc") do |doc|
doc.macro_remove # 念のためマクロを削除
Dir.glob("*.bas\0*.cls\0*.frm") do |filename|
doc.macro_import(filename)
end
# 読み込んだマクロを試しに実行してみる
doc.macro_run("Macro1", txt_file)
doc.macro_run("Macro1", doc_file)
doc.save
end
−−−− wmcr06b.rb ここまで
「Dir.glob(“.bas\0.cls\0*.frm”) ……」は、3種類のワイルドカード指定 *.bas, *.cls, *.frm に該当するファイルの名前を検出するものです。”\0” は、3つのワイルドカードを区切るための区切り文字です。
「.frm」に該当するファイルはみつからないと思いますが、「.bas」と「*.cls」は一つづつ検出されるはずです。その検出されたファイルを macro_import() で読み込んでいます。
正しく読み込みが行われていれば、wmcr06.doc でも Macro1() を実行できるはずなので、macro_run() でそれを実行しています。
以上、wrdap.rbで用意した「マクロを取り扱うためのメソッド」についての説明は一通り終了です。
これまで取り上げた macro_code(), macro_add() などのメソッドは、作業中のワード文書(ActiveDocument)に帰属するものでした。それらメソッドを使ってマクロを登録すると、作業中のワード文書にそれが組み込まれます。
一方、ワードを起動した場合、暗黙のうちに取り扱われる標準テンプレートの Normal.dot というファイルがあります。Word2007以降では Normal.dotm です。ActiveDocumentとは別に、こちらにマクロを組み込むこともできます。
以下では、標準テンプレートにマクロを組み込んだり、標準テンプレートに登録されているマクロの情報を取り出す方法について述べます。といっても、これまで言及してきた macro_code(), macro_add() などをほぼそのまま用いるだけです。
標準テンプレートは、VBA風に書くと Application.NormalTemplate で参照できます。
そのファイル名は Application.NormalTemplate.Name で知ることができます。ファイル名のフルパスを知りたければ Application.NormalTemplate.FullName を見ます。
rubyでそれらを確認するためのスクリプトを下に掲げます。
−−−− wmcr07.rb ここから
# encoding: Windows-31J
require "wrdap"
filename = "dummy.doc"
Wrdap.new(filename) do |doc|
puts doc.Application.NormalTemplate.Name
puts doc.Application.NormalTemplate.FullName
puts doc.app.ntpl.Name
puts doc.app.ntpl.FullName
end
−−−− wmcr07.rb ここまで
上では puts の書かれた行が4行出てきます。最初の2行と、その後の2行は、見た目は違いますが実質的に同じものです。最初の2行がVBAに即した記述、後半の2行はwrdap独自の記述です。
後半に出てくる doc.app は、「wrd = Wrdap.new」とした場合のwrdに該当します。このオブジェクトには ntpl というメソッドがあり、NormalTemplateを指し示しています。
上のスクリプトで、わざわざ dummy.doc をオープンしています。このワード文書に何か処理を加えているわけではないので、「開かなくてもいいのではないか?」と思われるかもしれません。
しかし、実際に試してみると、ワード文書を何も開かない状態で標準テンプレートを取り扱おうとしても、うまくいきません。何か1つくらいは文書を開いていないと駄目なようです。
それから、VBAの書き方でいうと、ActiveDocument.AttachedTemplate というのがあります。作業中のワード文書に結びつけられているテンプレートを参照するものです。
これを確認してみると、いつもというわけではないでしょうが、通常は NormalTemplate と同じものを指し示しています。
rubyで記述すると次のようになります。
puts doc.obj.AttachedTemplate.Name
puts doc.obj.AttachedTemplate.FullName
「doc.obj」は、VBAの ActiveDocument に該当します。
標準テンプレートに何が書かれているかをテキストとして取得し、合わせて、標準テンプレートのバックアップファイルをカレントディレクトリに保存するサンプルを掲げてみます。
バックアップファイルの名前は、backup.dot あるいは backup.dotm です。
−−−− wmcr08.rb ここから
# encoding: Windows-31J
require "wrdap"
wrd = Wrdap.new
wrd.opens("dummy.doc")
fname = wrd.ntpl.Name
out_file = Wrd::fullpath("backup" + File.extname(fname))
tpl_doc = wrd.ntpl.OpenAsDocument # テンプレートを文書として開く
str = tpl_doc.Content.Text # 内容をテキストとして取得
tpl_doc.SaveAs('FileName'=>out_file) # テンプレートのBackUp保存
tpl_doc.Close('SaveChanges'=>WdDoNotSaveChanges) # テンプレートを閉じる
wrd.quit
puts "テンプレートの内容: #{str}"
−−−− wmcr08.rb ここまで
標準テンプレートを文書として開く時は、OpenAsDocument というメソッドを用います。
標準テンプレートの内容をテキストとして取り出しても、おそらく改行コードが書かれているだけ、つまり、実質的には空っぽだと思いますが、上のスクリプトでは一応、標準出力に出力しています。
先に述べた macro_code() や macro_add() などのメソッドは、Wrdap.new で生成されるオブジェクトについても定義されており、同じように使うことができます。例えば次のような具合です。
wrd = Wrdap.new
wrd.opens("dummy.doc")
wrd.macro_add(str, 1, "DummyTest") # マクロの登録
wrd.macro_run("Normal.DummyTest.Macro1") # マクロの実行
puts wrd.macro_code() # マクロのソースコードを出力
wrd.quit
上のようにしてマクロを登録すると、標準テンプレートに組み込まれます。ある特定のワード文書に組み込まれるわけではないので、どんなワード文書を処理している時でもそのマクロを利用できます。
標準テンプレートは、暗黙のうちに保存されるようなので、わざわざ保存するための処理を施す必要はありません。
標準テンプレートにマクロを登録したり、それを実行する場合に注意しなければならないのは、個別のワード文書に登録されているマクロなどと混同しないことです。Module1 というモジュール名や Macro1 というプロシージャ名は有り触れた名前なので、標準テンプレートでは、できれば別の名前にした方が無難だと思います。
また、マクロを実行する時は、マクロの名前をモジュール名等を含めたフルネームで指定するのが安全です。標準テンプレートに登録されているマクロの場合、「Normal.Module1.Macro1」のようになります。こうしておけば、標準テンプレート以外に登録されているマクロと混同してしまう危険を避けられます。
といったことに留意しながら、標準テンプレートにおけるマクロの取扱いを書いてみたのが wmcr09.rb です。
wmcr01.rbを少し変形したマクロ(文書の冒頭に現在時刻を挿入するもの)を標準テンプレートに登録します。プロシージャ名は Macro1 ですが、モジュール名をDummyTestにしています。
このマクロが標準テンプレートにずっと残ってしまうのは気持ちよくないので、スクリプトの最後の方で削除しています。
以下、wmcr09.rb です。
−−−− wmcr09.rb ここから
# encoding: Windows-31J
require "wrdap"
str = DATA.read # マクロソースコードをstrに代入
filename = "wmcr09.doc"
File.unlink(filename) if test(?e, filename)
module_name = "DummyTest"
wrd = Wrdap.new
wrd.opens(filename) do |doc|
component = wrd.macro_add(str, 1, module_name) # マクロの組込み
puts "#{component.Name}にマクロを組み込みました."
wrd.macro_run("Normal.#{module_name}.Macro1") # マクロの実行
doc.save
end
wrd.quit
filename = "wmcr09b.doc"
File.unlink(filename) if test(?e, filename)
wrd = Wrdap.new
wrd.opens(filename) do |doc|
str = wrd.macro_code
puts str
wrd.macro_run("Normal.#{module_name}.Macro1") # マクロの実行
doc.save
wrd.macro_remove(1, module_name) # 今回登録したマクロを消去
end
wrd.quit
__END__
Sub Macro1
Dim rng As Range
Set rng = ActiveDocument.Range(0,0)
With rng
.InsertParagraph
.InsertDateTime DateTimeFormat:="HH':'mm':'ss", _
InsertAsField:=False, InsertAsFullWidth:=False, _
DateLanguage:=wdJapanese, CalendarType:=wdCalendarWestern
End With
End Sub
−−−− wmcr09.rb ここまで
上ではワードを2回起動しています。標準テンプレートに登録したマクロが、別のワード文書を開いている時にも使えるかどうかを確認するためそのようにしました。
あと、あまり利用することはないと思いますが、「wrd.ntpl = xxx」のようにして、ntplの値をNormalTemplateとは別のものに切り替えることができます。
例えば、ActiveDocument.AttachedTemplate が NormalTemplate とは異なるテンプレートを指し示している場合、rubyの記述で次のようにすると、macro_add() などのメソッドが NormalTemplate ではなく ActiveDocument.AttachedTemplate の方に適用されるようになります。
wrd = Wrdap.new
wrd.opens("test.doc") do |doc|
wrd.ntpl = doc.obj.AttachedTemplate
wrd.macro_add(str, 1, "TestModule")
end
wrd.quit
なお、「wrd.ntpl = nil」とすれば、ntplの値がnilになるのでなく NormalTemplate に戻ります。
標準テンプレートにおけるマクロの取扱いに関する説明は、これくらいにします。
マクロにショートカットキーを割り当てる場合も、標準テンプレートのマクロなのか、個別のワード文書のマクロなのかの区別が必要になりますが、それについては後述します。
MS-Wordのマクロを扱う際に、比較的よく用いると思われるノウハウを補足的に記します。
Module1 と Module2 の両方に Macro1 という名前のマクロが登録されていたとします。このとき、その二つのマクロを実行するには、それぞれ次のようにします。
doc.macro_run("Module1.Macro1")
doc.macro_run("Module2.Macro1")
モジュール名の後に半角ピリオドを置いて、その後にマクロの名前を記します。
全モジュールを見わたして、同名のマクロが他にないのであれば、わざわざモジュール名を付けなくて大丈夫です。
ここには掲げませんが、サンプルとして wmcr10.rb を同梱しておきます。内容は wmcr02.rb と同じです。
1つ目のマクロで、文書の先頭に「昨日は朝から雨が降っていた。」という1行を挿入し、2つ目のマクロでは「雨」を太字にします。
2つのマクロの名前をあえて Macro1 という同じものにして、1つ目をModule1、2つ目をModule2に組み込んでいます。
ところで、標準テンプレートにもマクロを登録できることは前述したとおりですが、そちらにも Module1.Macro1, Module2.Macro1 がある場合はどうしたらいいでしょうか。
標準テンプレートのマクロを実行したい時は、Normal.Module1.Macro1, Normal.Module2.Macro1 とします。これがマクロのフルネームです。
ワードは、おそらく、作業中の文書に登録されているマクロから探索をはじめて、その後に標準テンプレートのマクロを探索するのだと思います。
なので、作業中の文書のマクロを呼び出す際は、モジュール名よりも大きな枠組みの名前を省略してかまわないと思います。
省略せずに、あえてフルネームを指定するとすれば、作業中の文書のマクロには Project を付けます。Project.Module1.Macro1 というような名前がフルネームです。
正直なところ、Projectが作業中の文書への帰属を必ず示すものなのかどうかについて、明示している解説をみつけることができませんでした。なので確証があるわけではありませんが、たぶん大丈夫だと思います。
組み込んだマクロにショートカットキーを割り当てる場合、VBAでいうところの「Application.Keybindings.Add()」を用います。
ショートカットキーを割り当てると、MS-WordをGUI操作している最中に、例えば、コントロールキーとシフトキーを押しながらuキーをたたくことによって、マクロを実行できるようになります。
rubyスクリプトでこの Keybindings.Add を実行するサンプル wmcr11.rb を下に掲げます。
wmcr01.rbを少し書き換えて、文書の先頭に「はじめに」という行を挿入するマクロに、ショートカットキーを割り当てます。
新たに生成されたwmcr11.docを開いてGUI操作している時に、キーボードから「コントロール+シフト+u」を入力すると、Macro1が実行されて、「はじめに」が冒頭に挿入されます。
以下、サンプル wmcr11.rb です。
−−−− wmcr11.rb ここから
# encoding: Windows-31J
require "wrdap"
str = DATA.read # マクロソースコードをstrに代入
filename = "wmcr11.doc"
File.unlink(filename) if test(?e, filename)
Wrdap.new(filename) do |doc|
doc.macro_add(str, 1, "Module1") # マクロの組込み
app = doc.Application
app.CustomizationContext = doc.obj # 保存先を作業中の文書にする
key_code = app.BuildKeyCode(WdKeyControl, WdKeyShift, WdKeyU)
app.Keybindings.Add('KeyCategory'=>WdKeyCategoryMacro,
'Command'=>"Module1.Macro1",
'KeyCode'=>key_code)
doc.save # 文書の保存
end
__END__
Sub Macro1
Dim rng As Range
Set rng = ActiveDocument.Range(0,0)
With rng
.InsertParagraph
.InsertBefore "はじめに"
End With
End Sub
−−−− wmcr11.rb ここまで
KeyBindings.Add() には次の引数をわたします。
第1引数のKeyCategoryとして指定できる値は次のものです。
定数名 | 値 | 説明 |
---|---|---|
WdKeyCategoryNil | -1 | キーの割り当てはない |
WdKeyCategoryDisable | 0 | キーを無効にする |
WdKeyCategoryCommand | 1 | キーをコマンドに割り当てる |
WdKeyCategoryMacro | 2 | キーをマクロに割り当てる |
WdKeyCategoryFont | 3 | キーをフォントに割り当てる |
WdKeyCategoryAutoText | 4 | キーを定型句に割り当てる |
WdKeyCategoryStyle | 5 | キーをスタイルに割り当てる |
WdKeyCategorySymbol | 6 | キーを記号に割り当てる |
WdKeyCategoryPrefix | 7 | キーを接頭辞に割り当てる |
第3引数の KeyCode として指定できるのは、下の98種類、もしくは、それらの組合せです。
定数名 | 値 | 16進 | 説明 |
---|---|---|---|
WdKeyBackspace | 8 | 0x08 | BackSpaceキー |
WdKeyTab | 9 | 0x09 | Tabキー |
WdKeyNumeric5Special | 12 | 0x0c | .ちキー |
WdKeyReturn | 13 | 0x0d | Enterキー |
WdKeyPause | 19 | 0x13 | Pauseキー |
WdKeyEsc | 27 | 0x1b | Escキー |
WdKeySpacebar | 32 | 0x20 | Spaceキー |
WdKeyPageUp | 33 | 0x21 | PageUpキー |
WdKeyPageDown | 34 | 0x22 | PageDownキー |
WdKeyEnd | 35 | 0x23 | Endキー |
WdKeyHome | 36 | 0x24 | Homeキー |
WdKeyInsert | 45 | 0x2d | Insキー |
WdKeyDelete | 46 | 0x2e | Delキー |
WdKey0 | 48 | 0x30 | 0キー |
WdKey1 | 49 | 0x31 | 1キー |
WdKey2 | 50 | 0x32 | 2キー |
WdKey3 | 51 | 0x33 | 3キー |
WdKey4 | 52 | 0x34 | 4キー |
WdKey5 | 53 | 0x35 | 5キー |
WdKey6 | 54 | 0x36 | 6キー |
WdKey7 | 55 | 0x37 | 7キー |
WdKey8 | 56 | 0x38 | 8キー |
WdKey9 | 57 | 0x39 | 9キー |
WdKeyA | 65 | 0x41 | Aキー |
WdKeyB | 66 | 0x42 | Bキー |
WdKeyC | 67 | 0x43 | Cキー |
WdKeyD | 68 | 0x44 | Dキー |
WdKeyE | 69 | 0x45 | Eキー |
WdKeyF | 70 | 0x46 | Fキー |
WdKeyG | 71 | 0x47 | Gキー |
WdKeyH | 72 | 0x48 | Hキー |
WdKeyI | 73 | 0x49 | Iキー |
WdKeyJ | 74 | 0x4a | Jキー |
WdKeyK | 75 | 0x4b | Kキー |
WdKeyL | 76 | 0x4c | Lキー |
WdKeyM | 77 | 0x4d | Mキー |
WdKeyN | 78 | 0x4e | Nキー |
WdKeyO | 79 | 0x4f | Oキー |
WdKeyP | 80 | 0x50 | Pキー |
WdKeyQ | 81 | 0x51 | Qキー |
WdKeyR | 82 | 0x52 | Rキー |
WdKeyS | 83 | 0x53 | Sキー |
WdKeyT | 84 | 0x54 | Tキー |
WdKeyU | 85 | 0x55 | Uキー |
WdKeyV | 86 | 0x56 | Vキー |
WdKeyW | 87 | 0x57 | Wキー |
WdKeyX | 88 | 0x58 | Xキー |
WdKeyY | 89 | 0x59 | Yキー |
WdKeyZ | 90 | 0x5a | Zキー |
WdKeyNumeric0 | 96 | 0x60 | 0キー |
WdKeyNumeric1 | 97 | 0x61 | 1キー |
WdKeyNumeric2 | 98 | 0x62 | 2キー |
WdKeyNumeric3 | 99 | 0x63 | 3キー |
WdKeyNumeric4 | 100 | 0x64 | 4キー |
WdKeyNumeric5 | 101 | 0x65 | 5キー |
WdKeyNumeric6 | 102 | 0x66 | 6キー |
WdKeyNumeric7 | 103 | 0x67 | 7キー |
WdKeyNumeric8 | 104 | 0x68 | 8キー |
WdKeyNumeric9 | 105 | 0x69 | 9キー |
WdKeyNumericMultiply | 106 | 0x6a | *キー(テンキー) |
WdKeyNumericAdd | 107 | 0x6b | +キー(テンキー) |
WdKeyNumericSubtract | 109 | 0x6d | -キー(テンキー) |
WdKeyNumericDecimal | 110 | 0x6e | .キー(テンキー) |
WdKeyNumericDivide | 111 | 0x6f | /キー(テンキー) |
WdKeyF1 | 112 | 0x70 | F1キー |
WdKeyF2 | 113 | 0x71 | F2キー |
WdKeyF3 | 114 | 0x72 | F3キー |
WdKeyF4 | 115 | 0x73 | F4キー |
WdKeyF5 | 116 | 0x74 | F5キー |
WdKeyF6 | 117 | 0x75 | F6キー |
WdKeyF7 | 118 | 0x76 | F7キー |
WdKeyF8 | 119 | 0x77 | F8キー |
WdKeyF9 | 120 | 0x78 | F9キー |
WdKeyF10 | 121 | 0x79 | F10キー |
WdKeyF11 | 122 | 0x7a | F11キー |
WdKeyF12 | 123 | 0x7b | F12キー |
WdKeyF13 | 124 | 0x7c | F13キー |
WdKeyF14 | 125 | 0x7d | F14キー |
WdKeyF15 | 126 | 0x7e | F15キー |
WdKeyF16 | 127 | 0x7f | F16キー |
WdKeyScrollLock | 145 | 0x91 | ScrollLockキー |
WdKeySemiColon | 186 | 0xba | ;キー |
WdKeyEquals | 187 | 0xbb | =キー |
WdKeyComma | 188 | 0xbc | ,キー |
WdKeyHyphen | 189 | 0xbd | -キー |
WdKeyPeriod | 190 | 0xbe | .キー |
WdKeySlash | 191 | 0xbf | /キー |
WdKeyBackSingleQuote | 192 | 0xc0 | `キー |
WdKeyOpenSquareBrace | 219 | 0xdb | [キー |
WdKeyBackSlash | 220 | 0xdc | \キー |
WdKeyCloseSquareBrace | 221 | 0xdd | ]キー |
WdKeySingleQuote | 222 | 0xde | ‘キー |
WdNoKey | 255 | 0xff | 指定キーなし |
WdKeyShift | 256 | 0x100 | Shiftキー |
WdKeyCommand | 512 | 0x200 | Ctrlキー |
WdKeyControl | 512 | 0x200 | Ctrlキー |
WdKeyAlt | 1024 | 0x400 | Altキー |
WdKeyOption | 1024 | 0x400 | マウスのオプションキー |
シフトキーやコントロールキーと、アルファベットキーや数字キーを組み合わせる場合は、サンプルで記述したように BuildKeyCode() を用いてキーコードを算出します。
実は、BuildKeyCode() を用いなくても、キーに対応する整数値をプラスしてもかまいません。単純な ‘+’ でもいいでしょうし、ビット演算子の論理和 ‘|’ でもいいと思います。例えば次のように算出できます。
key_code = WdKeyControl + WdKeyShift + WdKeyU
「app.CustomizationContext = doc.obj」というのは、ショートカットキーの保存先を作業中の文書(ActiveDocument)に設定するものです。
通常、この設定をしない時は、標準テンプレート(NormalTemplate)が保存先になっていると思います。
CustomizationContextは、「ユーザー設定」ダイアログボックスにおいて「ツール」→「コマンド」→「保存先」の値に対応するようです。
標準テンプレートにショートカットキーの割当情報を保存したい時は、VBA形式で下のように書きます。
CustomizationContext = NormalTemplate
CustomizationContextもNormalTemplateも、Globalの下で定義されているものです。なので上のように書くことができます。
しかし、rubyでは単にCustomizationContextとだけ書くわけにはいかないので、あえてApplicationに帰属する形にして、次のように書くことになります。
app.CustomizationContext = app.NormalTemplate
言わずもがなですが、今回の wmcr11.rb は、マクロを作業中の文書に登録しているので、標準テンプレートにショートカットキーを保存するのは避けるのがいいと思います。
それから、マクロに対してショートカットキーを割り当てている場合、そのショートカットキーを無効にするには、KeyBinding.Disableを用います。エッセンスのみ抜き出すと次のとおり。
key_code = app.BuildKeyCode(WdKeyControl, WdKeyShift, WdKeyU)
key_binding = app.FindKey(key_code)
ary = nil
if key_binding.Command != "" # キーに割り当てられているものがある
ary = [key_binding.KeyString, key_binding.Command]
key_binding.Disable # キーの割り当てを無効にする
end
if ary != nil
printf("'%s' → '%s' を無効にしました.\n", ary[0], ary[1])
else
puts "該当のキーに割り当てられているものがみつかりませんでした."
end
FindKey() は、指定のキーコードにまつわる1つのKeyBindingオブジェクトを返します。この戻り値は、wmcr11.rbにおいて KeyBindings.Add() によって生成されたオブジェクトと同一です。
この戻り値を変数kbに代入したとすると、kb.Command で割り当てられているコマンドやマクロの名前を知ることができます。この値が空文字列 “” であれば、該当のキーコードに割り当てられているものがないことを意味します。
kb.KeyString は、キーコードを整数値ではなく文字列で示すものです。
kb.Disable とすれば、kb.Command が “” になり、キーの割り当てが無効になります。
ここには掲げませんが、キーの割り当てを無効にするためのサンプル wmcr11b.rb, wmcr11c.rb を同梱しておきます。一つは FindKey() を用いる例、もう一つは KeyBindings.each を用いる例です。
FindKey() を用いる方が作業効率はいいと思いますが、KeyBindings.each でKeyBindingオブジェクトを一つづつ辿る方法は、汎用性が高く応用がきくといえます。例えば、Macro1という名前のすべてのマクロ(モジュール名は問わない)に対し、すべてのキーの割り当てを無効にする、といった処理を行えます。
ここでは取り上げませんが、他に KeysBoundTo() というのもあります。指定された項目に割り当てられているすべてのキーの組み合わせを表すオブジェクトを取得します。引数として Command や KeyCategory を指定できます。
これまでのサンプルは、拡張子が “.doc” のワード文書を扱ってきました。
一方、MS-Word2007以降では、マクロ付きのワード文書として、拡張子 “.docm” を扱うことができます。
もし MS-Word2007 以降を動かせる環境にあるなら、これまでのサンプルの wmcr01.doc などを wmcr01.docm のように変更しても、そのまま問題なく動きます。
MS-Wordのバージョンが判然としない場合に、2003までならdoc、2007以降の時はdocmにしたいということであれば、例えば次のようにします。
wrd = Wrdap.new
filename = (wrd.word_version < 12.0) ? "test.doc" : "test.docm"
wrd.opens(filename) do |doc|
…………
end
wrd.quit
参考まで、wmcr01.rb を上の流儀で書き換えたものを wmcr12.rb として同梱しておきます。
コンポーネントのタイプ1〜3を対象にすると言いながら、タイプ3(ユーザーフォーム)については触れないままでした。
遅ればせながら、ここでサンプルとして wmcr13.rb を掲げておきます。
SampleFormという名前のコンポーネント(ユーザーフォーム)を設けて、それにテキストボックス、リストボックス、コマンドボタン2つの計4つを貼り付けます。そして、そのユーザーフォームをテストするための標準モジュールを組み込みます。プロシージャ名は Macro1 です。最後に、このテストのためのマクロにショートカットキーを割り当てます。これら一連の作業は rubyスクリプト側で行います。
VBAソースコードの方では、Finishボタンとキャンセルボタンがおされた時の終了処理のほか、テキストボックス・リストボックス・コマンドボタンのプロパティ設定等を行っています。
wmcr13.rbを実行すると wmcr13.doc が作られます。これをMS-Wordで開いてGUI操作します。
Macro1が組み込まれているので、それを実行します。ショートカットキー「コントロール+シフト+u」を入力すると、そのマクロが実行されるはずです。
テキストボックスとリストボックスでそれぞれ適当に入力または選択し、Finishというコマンドボタンをクリックすると、入力・選択したものがそれぞれ第1パラグラフと第2パラグラフに書き込まれます。
キャンセルボタンをクリックすると(エスケープキーを押すのでもよい)、何も行わずに文書編集の状態に戻ります。
以下、wmcr13.rb です。
−−−− wmcr13.rb ここから
# encoding: Windows-31J
require "wrdap"
uf_str, mdl_str = DATA.read.split(/\n########\n+/)
filename = "wmcr13.doc"
File.unlink(filename) if test(?e, filename)
Wrdap.new(filename) do |doc|
uf = doc.macro_add(uf_str, 3, "SampleForm") # add UserForm component
uf.Designer.Controls.Add("Forms.TextBox.1") # add TextBox
uf.Designer.Controls.Add("Forms.ListBox.1") # add ListBox
uf.Designer.Controls.Add("Forms.CommandButton.1") # add CommandButton
uf.Designer.Controls.Add("Forms.CommandButton.1") # add CommandButton
doc.macro_add(mdl_str, 1, "Module1") # add standard module component
app = doc.Application
app.CustomizationContext = doc.obj # 保存先を作業中の文書にする
app.Keybindings.Add('KeyCategory'=>WdKeyCategoryMacro,
'Command'=>"Module1.Macro1",
'KeyCode'=>WdKeyControl + WdKeyShift + WdKeyU)
slc = doc.Application.Selection
slc.TypeText "ユーザーフォームをテストするためのドキュメント"
slc.TypeParagraph()
slc.TypeText "コントロールキー+シフトキー+Uを入力して、ユーザーフォームを試して下さい。"
slc.TypeParagraph()
doc.save
end
__END__
' UserForm module
Private Sub CommandButton1_Click()
ActiveDocument.Paragraphs(1).Range.Text = Me.TextBox1.Value & vbCrLf
ActiveDocument.Paragraphs(2).Range.Text = Me.ListBox1.Value & vbCrLf
Unload Me
End Sub
Private Sub CommandButton2_Click()
Unload Me
End Sub
Private Sub UserForm_Initialize()
With TextBox1
.AutoSize = True
.MultiLine = False
End With
With ListBox1
.AddItem "月曜日"
.AddItem "火曜日"
.AddItem "水曜日"
.AddItem "木曜日"
.AddItem "金曜日"
End With
With CommandButton1
.Caption = "Finish"
End With
With CommandButton2
.Caption = "Cancel"
.Cancel = True
End With
End Sub
########
' standard module
Sub Macro1()
SampleForm.Show
End Sub
−−−− wmcr13.rb ここまで
上記スクリプトで作成される wmcr13.doc に対して macro_export を適用すると(wmcr06a.rb参照)、SampleForm.frm の他に SampleForm.frx というファイルも書き出されます。前者はテキストファイル、後者はバイナリーファイルです。
このユーザーフォームに関する二つのファイルを macro_import で読み込む時は、テキストファイルの SampleForm.frm の方を読み込めば大丈夫です。そうすれば、バイナリーの方も付随して読み込まれます。バイナリーファイルが同じフォルダにないと正しく読込みが行われないので注意して下さい。
なお、wmcr13.rbで設定したショートカットキーの割当を解除するためのスクリプト wmcr13b.rb を同梱しておきますので、必要に応じて実行して下さい。
また、コマンドボタンとして cmdOK, cmdCancel の記述がよく用いられるようなので、その名前を用いるサンプルをwmcr13c.rbとして同梱しておきます。FinishボタンでなくOKボタンにして、エンターキーの押下がOKボタンのクリックと同じ扱いになるよう設定しています。
ワード文書においてユーザーフォームを利用する典型的なケースは、定型文書の雛形テンプレートにそれを組み込んで、ユーザーが入力・選択したものを所定の箇所に挿入する、というケースだと思います。
そうした例をサンプルで示せればとも思いましたが、雛形テンプレートの処理については様々な事柄が関係してきて、実践的なものであればあるほど、サンプルとしては複雑で分かりにくくなると考えてやめました(弁解モード)。
それから、ワード文書を開くと、直ちにユーザーフォームが立ち上がるようにするといったノウハウも、比較的よく利用されると思います。
wmcr13.rbの中の「Sub Macro1()」のところを「Sub AutoOpen()」に書き換えれば、wmcr13.docを開いた時に直ちにユーザーフォームが立ち上がるようになります。その場合は、マクロにショートカットキーを割り当てる必要がないので、rubyスクリプトの該当箇所を削除する必要があります。
また、あまりお勧めはできませんが、標準テンプレート(NormalTemplate)に「Sub AutoExec() …… End Sub」という標準モジュールを組み込めば、ワード文書を開いた直後にそれが立ち上がるようになります。
最後に、VBE(Visual Basic Editor)を非表示にする方法を記しておきます。
VBA記述では「Application.VBE.MainWindow.Visible = False」と書きます。
rubyでは(wrdap利用時)「doc.app.obj.VBE.MainWindow.Visible = false」です。
マクロの取扱いについて、この辺でおわりにします。
〜 以上 〜
Copyright (C) T. Yoshiizumi, 2015 All rights reserved.