2012年11月15日木曜日

VBAのソースコードを保守し易くするためのツール vbac

【目次】

  • まえがき
  • vbac の入手方法
  • vbac の使い方
  • vbac の仕様・注意点
  • 余談1
  • 余談2

【まえがき】

Microsoft Office製品で利用可能なVBAのコードは、ExcelやWordなどのバイナリファイルに内包される形で保存されます。このために、いわゆるバージョン管理システムでは適切に管理することができず、メンテナンス性が悪いという問題があります。
 また、バイナリファイルに内包されるために、コードの確認や微修正などの細々した作業のためにも、WordやExcelを立ち上げ、VBEを開く手間がかかります。小規模にVBAコードを書いている分には困らないのですが、コード量が増えてきた場合(*1)や、複数人に配布したものを保守する場合などにおいては、お世辞にも使い勝手が良いとは言えません。

(*1)個人的な感覚ですが、1ファイルに含まれる総コード量が2,3千行を越えると、どうにも保守面倒にってくる気がします

 この問題に対する解決策として、古くはVBAコードを用いて、バイナリファイルに含まれるVBAコードをエクスポート/インポートする方法が知られています(*2)。この方法であれば、バージョン管理システムを併用することで、コード量が増えてきた場合にも比較的楽に対応できるようになります。
  しかしながら、この方法はExcelやWordの起動が前提にあり、複数人に配布したものを保守する場合の作業性は改善されません。

(*2)参考: Excel ソースコードの管理 関するまとめ- ClockAhead 記憶の欠片

 これらの問題に対する最適解の1つとしては、スタンドアロンで、バイナリファイルからVBAコードのエクスポート/インポートが可能なプログラムが考えられます。
 このようなプログラムとしては、2012年11月現在、@igeta(*3)が開発されている vbac (vbac is not VBA compiler)があります。vbacは、それ単体で完結したスタンドアロンのプログラムであることに加え、Excel/Word/Accessのいずれにも対応しており、同種のツールの中ではダントツで完成度が高いように思います。以下では、このvbac を紹介したいと思います。

(*3) 日本国内におけるMicrosoft F# MVP であるとともに、VBAで精力的にコードを書かれている(らしい)方。VBAに限らずコーディング能力がハンパない(気がする)にも関わらず、TwitterではVBAのことを常につぶやき続けていて、ちょっとな雰囲気。

2012年10月22日月曜日

特許明細書の段落番号等を振りなおすためのWordマクロ

【概要】

特許明細書の段落番号、図、化学式、数式、表の番号を一括して振りなおすためのVBAコード(マクロ)を書きました。
 文章の先頭から、連番になるように振りなおします。

※ 2014/12/17追記

段落番号の振り直し(再付与)以外の機能も加え、1つのWordアドインにまとめました。
下記記事をご参照ください。

2012年10月16日火曜日

.NETプログラマのためのインストーラ作成プログラムまとめ

【まえがき】

2012/10月現在において .NET Framework を利用したアプリケーションの配布に適したインストーラ作成プログラムについての資料が見当たらなかったので、調べてみました。
具体的には、アプリケーションのインストールに先立って、動作に必要となる.NET Frameworkの自動インストールを行えるものを探して、まとめてみました。

【インストーラ作成プログラム一覧】

2012/10月現在においても、継続的に開発が続けられているものをまとめています。
  • Wix Toolset
    • もともとMSが開発。現在はオープンソース。.NET 製。XMLでソースコード記述。
    • Ver3.5以降、単体で .NET Frameworkなしで起動可能。
      • それ以前は、別途bootstarapperが必要
  • InnnoSetup
    • オープンソース。Delphi製。Pascalでソースコード記述
  • InstallShield 
    • 有償。GUIで設定。
    • VisualStudio Proffesional以上に機能限定版(Limited Edition)が付属。 

2012年10月6日土曜日

Windows をスリープ状態に移行させる方法まとめ

【まえがき】

hiyohiyoさんのblog 「Windows 8 用 スリープ/再起動/シャットダウン スクリプト」 にて、Windowsの終了コマンドを実行するためにSendKeys が使われていたのが気になったので、他にどういった実装方法があるのか調べてみました。
 また、各方法の実装方法をまとめました。

【一覧表】

Windows8 で終了/再起動/スリープ を素早く行う

【まえがき】

HDD/SDDのベンチマークソフト CrystalDiskMark などで有名な hiyohiyoさんがblogの「Windows 8 用 スリープ/再起動/シャットダウン スクリプト」という記事で、
Windows 8 の終了/スリープって本当に面倒臭い!! というわけで、ネットでショートカットの作成方法などを調べてみたですがなぜか強制シャットダウン orz でうまくいかない。  
で、色々考えた結果デスクトップに対して Alt + F4 するのが一番簡単という結論に達しました。が、他のウィンドウがある場合は最小化するなりしてデスクトップを表示しないといけない・・・うん、やっぱり面倒くさい。というわけで、簡単なスクリプトを作ってみました。
とのことで、終了コマンド(終了、スリープなど)を実行するためのVBSスクリプトを公開されていました。上記記事でも言われているように、Windows 8の終了コマンドを実行する手順って
  1. 画面右上(または下)端で一旦カーソル待機
  2. 表示されたサイドメニューから「設定」を選択
  3. さらに「電源」を選択
  4. 終了コマンドを選択
と手数だけ見ても増えており、それに加えてカーソルを上下に移動させる必要があったりと、結構めんどくさいのです。
 Windows8を使い始めた当初は、「新しいOSだし、使っているうちに慣れるかな」と思っていたのですが、ここ2、3ヶ月 RP版を含め Windows8を使ってみた結論は

全然慣れません。マジめんどくさいです。

2012年10月3日水曜日

知財業界のソフトウェアに思う

■はじめに

IT業界におけるソフトウェアの進化には目を見張るものがあり、ここ20年の間にソフトウェアの品質(使い易さや機能)は大幅に改善されたように感じています。

 少し昔話になりますが、多くの人がコンピュータを扱うきっかけとなったであろうWindows95の頃は、ソフトウェアは「たまにはバグでエラーを発生させる」のが当たり前のような雰囲気があったのではないでしょうか。また、ソフトウェアで「何かができる」というだけでも何か凄いことのように感じられたのではないでしょうか。
 翻って、現在においては「バグで落ちるなど論外」、「何かができるのは当たり前」と考えるのが一般的かと思います。
 この20年の間に、IT業界において何が起きたのでしょうか?

 その背景には、ときには過剰と思えるまでの過当競争があると思われます。より掘り下げて見れば、開発手法や品質の管理手法といったソフトウェアの作り方自体が、すなわちソフトウェアの生産性が改善され続けていることが挙げられると思います。
 生産性の大幅な改善により、今となっては特段能力を必要としない『(単に)仕様を満たすだけのソフトウェア』を作る時代は終わりを告げ、さらに一歩踏み込み『使い易さ(今風に言うならば、ユーザー・エクスペリエンス)を考慮したソフトウェア』を作る時代へと進んだと考えられます。


2012年9月17日月曜日

NonStopIPDL Ver.0.0.1β を公開しました

 日本特許庁の公式検索サイト・IPDLで公開されている特許公報や審査書類を、ワンクリックで(ダイレクトに)開くプログラムを試験的に公開しました。
 『ちょっと気になった番号の特許公報を読みたい』『ちょっと審査過程を確認したい』などの、ちょっとした用途を想定しています。

 現状かなり荒削りな作りですが、バグや要望などありましたらコメント頂けると幸いです。

【おしながき】

  • 使い方
  • 公報番号の入力規則
  • 制限・仕様など
  • 既知のバグ
  • ダウンロード

【最初に】

 Windows8以外の場合、プログラムの動作に別途 .NET Framework4.0をインストールする必要があります。
 未インストール場合には、Microsoftの .NET Framework 4.0 のページよりダウンロード・インストールしてください。

【使い方】


  • 画面左端の特許公報の番号を入力してください。
  • 見たい書類のボタンをクリックしてください。
    • [公報] のボタンをクリックすると、公報のページを開きます。
    • [審査書類] のボタンをクリックすると、審査書類のページを開きます。

【番号の入力規則】

入力方法は、一般的な公報番号の記載法のほか、IPDLの入力法が使えます。
 例えば、特許公開公報2003-003123号であれば、以下のような入力が可能です。
  • 西暦-番号  (例: 2003-3213)
  • 特開西暦-番号 (例: 特開2003-3213)
  • A西暦-番号  (例: A2003-3213)
さらに、
  • 和暦(例えば、H12,平12など)の記載もOKです
  • 番号の後ろに「号公報」などの記載があってもOKです
  • 全角・半角はどちらでも/混在していてもOKです
  • 文字の途中に空白が入っていてもOKです

【制限・仕様など】

  • たぶん特許公開公報しか開けません
    • 特許番号や再公表番号などを入れるとエラーが出るかもしれません。
    • 対応する文献種別は要望に合わせて今後増やしていきたいと思っています。
  • 暫定的に、公報・審査書類のページをダイレクトに開ける回数を、
    1日あたり10回までとしています
    • 不正利用やバグによりIPDLに過負荷がかかることを避けるため
    • 11回目以降は、IPDLの検索サービス一覧のページを開きます
    • 開いた回数をカウントするため、ボタンクリック時にサーバ(activate4ipdl.appspot.com)にアクセスしています。PCの識別には、MACアドレスと日付に基づくハッシュ値を用いています。
  • 2012年10月31日まで利用可能です
    • それ以降は、使用できなくなります。
    • それまでに新しいVersionを作成・配布する予定です。

【既知のバグ】

  • Windows8 (IE10)では、公報のページをダイレクトに開けません。
    • 公報を開くためにはワンクリック余分に操作が必要です。

【ダウンロード】

 下記リンクからダウンロードしてください。

2012年9月15日土曜日

秀丸エディタでC#のコードを実行する

【まえがき】

普段使っているテキストエディタ (秀丸エディタ)の公式サイトで公開されていた ohtorii 氏作の


が便利だったので、紹介もかねて解説してみたいと思います。

【この記事のおしながき】


  • マクロの紹介
  • 使い方
  • マクロの実装内容
  • 小改良
  • 改良案

【マクロの紹介】


 マクロ名の通り、秀丸エディタで編集中のC#のソースコードを実行するためのマクロです。
 内部的には、ソースコードのコンパイルから実行までを行ってくれます。

マクロ実行例

 このマクロを実行すると 標準出力への出力結果を、秀丸エディタのアウトプット枠へ書き出してくれます。このため、コーディングから実行までの一連の流れをまでを、秀丸エディタだけで完結させることができます。特に秀逸だなと思った点が、

秀丸エディタで、編集中の内容(コード)を実行する

という仕様です。 このおかげで、ちょっと動作を確認したい、といったレベルのコードは、ファイルに保存すること実行できます。まさに、ワンライナーのスクリプトを書く感覚で、C#のコードを文字通り書き捨てることができます。
 また、個人的には、『 VisualStudio などの開発環境がインストールされていないマシンでも、気楽に C# でコードを書ける (*)』というのが嬉しいです。

 (*) マクロ内部で C#のコードをコンパイルするために呼び出している csc.exe(C# コンパイラ)は、 .NET Framework がインストールされていれば存在するため

【使い方】

マクロを実行する前に、一手間かける必要があります(*)。

(*) 必ずしも必要ではないのですが、デフォルトでは、マクロ内部で 64bit版 の .NET Framework 4.0のcsc.exe を呼び出すように設定されています。このため、当該.NET Frameworkがインストールされていない場合には、そのままではマクロを実行できません。

 マクロファイル (cmd_c#.mac) を開いて、ファイル冒頭箇所(37~42行目) をマクロを実行するPC環境に合わせて編集します。
 具体的には、コードの実行に用いる .NET Frameworkの Versionに合う行をアンコメントするだけです。なお、必要ない行は忘れずコメントアウトして下さい。

設定箇所 (32bit版 .NET Framework 3.5 を用いる場合)
作者の方が、あらかじめ各Versionのcsc.exeのパスを用意してくれているおかげでお手軽です。感謝。

【マクロの実装内容】

どうやってこの機能を実現しているのか気になったので、マクロの中身を読んでみました。
 コード量自体は多くないので、詳しくはコードそのものに譲るとして、ここでは概略だけを記しておこうと思います。

コードの構造

  • Main:
    • Main() 関数的なもの
    • 秀丸の設定変更
    • Start: を呼び出し
  • Start:
    • 実質的には、このマクロのMain()関数
    • GetTempFile: で、作成するcsファイル、exeファイルの絶対パスを取得
    • MakeFile: で、csファイルを作成
    • SpawnCompiler:で、exeファイルを作成
    • SpawnExe: で、exeファイルを実行
    • csファイル、exeファイルを削除
  • MakeFile:
    • 編集中の内容(コード)をコピーして、テンポラリファイルを作成
    • csファイルを作成
  • SpawnCompiler:
    • csc.exeを用いてcsファイルをコンパイル(exeファイルを作成)
  • SpawnExe:
    • exeファイルを実行
  • CreateDir:
    • フォルダを作成
    • テンポラリフォルダ内に、マクロ実行時に使うフォルダを作成
  • GetTempFile:
    • テンポラリファイルの絶対パスを取得
    • CreateDir: を利用
  • WriteOutput:
    • 秀丸のアウトプット枠に文字列を出力
    • マクロ内で発生したエラーを出力するために使用

処理の流れ

  • 秀丸で編集中のファイル内容をコピーして、テンポラリフォルダに csファイルを作成
    • テンポラリフォルダは、環境変数 tmpを参照
    • (サブルーチン GetTempFile, MakeFile)
  • csc.exe を用いて、テンポラリフォルダ内で exeファイルを作成
    • (サブルーチン SpawnCompiler)
  • 作成したexeファイルを実行して、出力を秀丸のアウトプット枠に表示
    • 標準出力、標準エラー出力の両方を出力
    • (サブルーチン SpawnExe)
  • 作成したcsファイル、exeファイルを削除

【小改良】

csc.exe のデバッグオプションが有効になるように、$g_exe に直接 /debug+ を書き加えました。
 (自分の場合は横着をして $g_exeに書き加えましたが、今後の拡張を考えマクロにちゃんと手を加えるのであれば、SpawnCompilerサブルーチン 内にデバッグオプション用の変数を用意した方が良いかもしれません。)

x86版 .NET3.5の場合 (末尾の+は書かなくてもOK)
デバッグオプションを有効にしておくと、下図に示すように、実行時にエラーが発生した際、エラーの原因がコードの何行目かを明記してくれるようになります。

デバッグオプションを有効にした場合のエラー表示

 デバッグが必要になるほどのコードを書くことは、そうないとは思うのですが、念のため設定しておいてもよいのではないでしょうか。

 なお、/debug を有効にすると、exeファイル作成時に、同名のpdbファイルが作成されます。気になる方は、Startサブルーチンの末尾にpdbファイルを削除するためのコードを追加した方が良いかもしれません。(個人的には、テンポラリフォルダ内なので気にしていません。)

【改良案】

外部アセンブリの読み込みに対応できると、ネットの海から拾ってきたdllの動作確認ができるので何かしら使い勝手が良いかもなぁと思ったりします。(近々でそういった使い方をしたいというわけではないのですが)

 csc.exe 自体は /r: オプションでアセンブリの参照設定を追加できるので、例えば
  • 開いているファイルと同階層にあるdll一覧を取得
  • 各dllの絶対パスを /r: オプションで指定
とすれば、実現できそうです。

2012年9月13日木曜日

文字の装飾をワンタッチで消すWordマクロ

【まえがき】

こういう文章中の装飾をまとめて消したい
文章に施した装飾 (蛍光ペン ・ 斜体 ・ 文字色 ・ 下線 ・ 囲い線などなど)をまとめて消したい場合、Wordの標準機能を用いるのであれば

  • [Ctrl] + [Shift] + [Z] または [Ctrl] + [Space] 
    • (VBAから呼び出したい場合) コマンド名 ResetChar

で、文字の装飾をまとめて消せます。消せるのですが、このコマンドでは

  • 上付き文字下付き文字
まで一緒に消えてしまいます。このため、装飾を消したい範囲内に、化学式(例えば、HO)や、数式(例えば、y=ax)が混じっている場合には、ちょっと使うのをためらってしまいます。

 上付き文字・下付き文字は残しつつ、文字の装飾のみを消せた方が助かるのですが、標準のコマンドとしてはどうも用意されていないようなので、マクロを組んでみました。

【実装したコード】


【実装したコードに関するメモ】

太字斜体打ち消し線など基本的な装飾に関しては問題ないと思うのですが、網掛け囲み線などについても消すことを忘れないようにしたいところです。
 (私事ですが、普段自分では使わない装飾が消えないと、手動での消し方がパッと思い出せず、消し方を調べる羽目になり「何や、この装飾!」 とフラストレーションが溜まります。閑話休題)


 上記コードに関しては、蛍光ペンだけ消す機能(EraseHighlight)など、それ単体でもマクロとして、または他のマクロの一部として使える機能を、プロシージャ単位で切り分けています。

 余談ですが、このマクロ、自分はけっこう頻繁に使うので、ショートカットキーの設定で Ctrl + Q (比較的押しやすい位置)に割り当てて使っています。

【使い方】

1.文字の装飾をまとめて消したい範囲を選択
2.マクロを実行
以上です!

2012年8月30日木曜日

VBAでWordのウィンドウを水平方向に並べようとしたらWin32APIを連呼していた

【概要】

にて、Wordのウィンドウを水平方向に並べる(敷き詰める)マクロとともに、『Word2010に関してはApplication.Documents プロパティの挙動がおかしいため、正しく動かないことがある』という話が載っていました。

 手元のWord2010で確認したところ、たしかに正しく動かなかったので、Word2010におけるApplication.Documents プロパティの挙動について確認したところ、『Application.Documents プロパティは使えない』という結論に至ったので代替案を考えました。
 また、Word2000 ~ Word2013Preview のいずれのVersionにおいても、Wordのウィンドウを(プライマリモニタにおいて)水平方向に並べることができるようにマクロに手を加えてみました。

【Word2007以前の Application.Documents プロパティ】

まずはじめに、Word2007以前のApplication.Documents プロパティの挙動を確認しました。手元の環境で調べた限りでは、だいたい以下の通り。
  1. Application.Documents(Index) で、現在開いているDocumentオブジェクトにアクセスができる
  2. Indexには、"番号"もしくは"ファイル名"を用いることができる
  3. Index の番号は、現在開いているDocumentに対して
    新しく開いた順に1から連番で振られる
  4. どれか1つDocumentを閉じると、即座に
    残っているDocumentに対して新しく開いた順に1から連番で振り直される
このうち、1. 2.に関しては、MSDNに記載されている仕様の通りです。
 一方、3. 4.に関しては、特にMSDNに記載されているわけではないので、「たまたまこうなった」という程度の話かもしれません。(とりあえずは、常識的な挙動かなぁという印象を受けます。)

【Word2010の Application.Documents プロパティ】

MSDNを確認すると、Word2010の仕様として、保護ビューで表示されているDocumentに関しては、Appication.Documentsには含まれず、ProtectedViewsプロパティに含まれることが記載されています。もっとも、この仕様は今回の件には関係ありませんが…。

 Word 2010 Documents collection corrupted if work with several documents にて議論されているように、Word2010においては Application.Documents の挙動がかなり歪です。また、場合によっては、現在開いてるDocumentの情報を正しく保持しておらず、MSDNの記載とさえ一致していません。バグと言っても構わないレベルのような気がします。
 フォーラムでの議論内容を実際に手元で確認した限りでは、
  1. Application.Documents(Index) で、現在開いているDocumentオブジェクトにアクセスができる
  2. Indexには、"番号"もしくは"ファイル名"を用いることができる
  3. Index の番号は、現在開いているDocumentに対して
    新しく開いた順に1から連番で振られる
  4. どれか1つDocumentを閉じても、即座には
    残っているDocumentに対して新しく開いた順に1から連番で振り直されない
    1. Index 番号が飛び飛びになる(ことがある)
    2. Index 番号が存在しないDocumentが生じる (ことがある)
    3. Index 番号を複数持つ Documentが生じる (ことがある)
  5. それなりに時間が経つと、 現在開いているDocumentに対して
    新しく開いた順に1から連番で振り直されている
1. ~ 3.に関しては、Word2007以前と同様です。
 4. の Documentを閉じたときの挙動がかなり奇妙です。正直、奇妙というより、バギー過ぎて使い物にならないと考えた方がいいレベルだなと思いました。
 5. に関しても、数十秒から数分程度かかる場合まであり、どの程度の時間が経過すると、Index番号が振り直されるのかよくわかりません。

【Application.Documents の注意点】

そもそもの問題として、Application.Documentsでは、(当該コードを走らせている)単一のプロセスにおいて開かれているDocumentしか取得できません。このため、画面上に表示されているDocumentが、2つ以上のプロセスにわたっている場合には、画面上に表示されているDocument全てを操作するのに、Application.Documents は使えません。

 デフォルトの関連付けでは、Wordファイルを開く際には、1つのプロセス上で新しいウィンドウを作成するようになっているので、この点は一見問題にならなさそうに思えるのですが、実際にファイルを閉じたり開いたりしていると、たまに別プロセスで起動することがあり、この問題の発生確率は低くないと思われます。(もしかすると自分の環境だけかもしれませんが…。原因は未確認です。)
 また、コマンドラインオプションを使えば(*)別プロセスでの起動が可能なので、複数のプロセスが立ち上がっている可能性は考慮しておいた方がいいように思えます。

(*) Word のコマンド ライン スイッチ /n または /wで別プロセスを起動可能。

【Application.Documents に代わる代替策】

 以上の仕様を確認してみて、Application.Documentsは今回のマクロのように、Wordのウィンドウを操作するのには適さないという結論に至りました。そこで、いずれのVer.でも確実に使える代替方法を考えた結果、
  1. Win32APIのEnumWindowsを用いてWordのウィンドウハンドルを拾い
  2. MoveWindowでリサイズする
方法が良いかなと思いました。この方法がベストなのかはよく分かりませんが、自分の中では最終的にこの方法に落ち着きました。(実際のところ、Win32APIを使わないで済むように色々試してはみたのですが、いい方法が見つかりませんでした…。スマートな解決法をゆるく募集しております。)

 実際に、書いたコードは以下の通りです。
 1つ目のファイルは、Wordのウィンドウハンドルを取得するプロシージャ(GetAllWindowHandlesOfWord) を作成するためだけのもので、2つ目のファイルで、このプロシージャを用いて実際にウィンドウを水平方向に並べています。


Win32APIを使うにあたって、
EnumWindows関数 に関しては、列挙(EnumWindows by VBA) を、
MoveWindows関数 に関しては、「Win32API(C言語)編 第60章 ウィンドウの操作①」 を、
SystemParametersInfo関数 に関しては「エクセルVBAで画面の大きさを取得する方法!」 を、
参考にしました。各記事の作者の方々にはこの場を借りてお礼を申し上げます。

 なお、上記コードでは、プライマリモニタにウィンドウを並べる仕様になっています。マルチディスプレイ環境において、他のディスプレイに並べたい場合は、SystemPatametersInfoに代えて、GetSystemMetrics, GetMonitorInfo あたりを使うと良いかもしれません。(未検証です。) 

 また、上記コードは、64bit環境ではそのままでは動作しません。Win32APIを参照するためのDeclare の後ろに PtrSafeを記載してください。

【ウィンドウを並べる際の注意点】

 オリジナルのマクロは簡易的な仕様なので、色々考慮されていないのは当然なのですが、参考までに、汎用的に使えるプログラムを作る場合に考慮したほうが良いのではないかなと思う点を下記に列挙してみました。
  • 作業領域の左上の座標が(0,0)でない場合
    • タスクバーの位置が左または上の場合
  • マルチディスプレイ環境において、XY座標がマイナスの場合
    • プライマリモニタの左または上にモニタがある場合
  • マルチディスプレイ環境において、ディスプレイのサイズがそれぞれ異なる場合
    • Wordのウィンドウが異なるサイズのディスプレイ上に配置されている場合
 また、これは手元の環境特有かもしれないのですが、Word2002においては、ウィンドウを画面を最大化した場合に、Application.Width 及び.Heightプロパティでは最大化したウィンドウサイズを拾えない(通常時のウィンドウサイズを拾う)という挙動を示しました。もしかすると、ウィンドウを最大化して作業領域の大きさを取得するというテクニックはOfficeのVer.によっては使えないのかもしれません。




2012年8月25日土曜日

Word でキーボードショートカットキーを一括して登録する

【まえがき】

Word には、キーボードショートカットキーの割り当てを、デフォルト設定(Ctrl+Sが「上書き保存」など)も含め自由にカスタマイズできるようになっているのですが、
その設定方法が、Office2010を例にとると、

[ファイル] → [オプション] → [リボンのユーザー設定] → ショートカットキー:[ユーザー設定]を選択

と設定画面を開くだけでもめんどくさいです。
おまけに、設定画面も小さく、1つ1つ手作業でショートカットキーを登録するのは、苦痛以外の何物でもありません。私的に。
ショートカットキーの設定画面
もっとも、ショートカットキーを1個、2個登録するだけであれば、気にならないかもしれないのですが、普段使っているPCとは、別のPCでショートカットキーの設定を再現しようとして

  1. 普段使っているPCの設定を確認して
  2. 小さな画面で 1個1個設定する

という作業をしていたら、発狂しかけました。
将来OSを入れ替えた時など『忘れた頃にまたしなければならないのか』と思うと、絶望のあまり倒れてしまいそうなので、VBAでショートカットキーを一括して登録するコードを書いてみました。

【書いたコード】


配列 (macroSetting, commandSetting)に、
  • 実行するマクロ/コマンド名
  • 割り当てるショートカットキー
の順で、ショートカットキーの設定 (詳しくは後述)をまとめて格納した後、KeyBindings.Add()メソッド を用いてショートカットキーを登録しています。

ショートカットキーにマクロを割り当てる場合と、「上書き保存」など標準で組み込まれているコマンド (fixed command) を割り当てる場合とではAdd() メソッドの引数が変わるので、それぞれ設定を格納する配列を分けています。

点線より上側に、ショートカットキーの設定を書き並べれば使えるので、
ショートカットキーの設定を確認するのも楽かなと思ってこんな風に書いてみました。

なお、配列の末尾の要素の "***END***"は、単に、各行の書式を揃えてコピペし易くする (全行が","で終わるようにする)ためだけに挿入しています。

【ショートカットキーの設定について】

ショートカットキーの設定に用いるキーの定数一覧は、MSDNの
に記載されています。ただ、自分が確認した範囲では、日本語キーボードの場合
  • wdKeySemiColon は、": "(コロン)のキーに
  • wdKeyEquals は、 ";"(セミコロン)のキーに
相当しています。たとえば、Ctrl + ":" にマクロを割り当てたい場合、『wdKeyControl + wdKeySemiColon』を使う必要があります。(英語キーボードを想定して、定数が決め打ちされているのでしょうか…。)

また、複合キーの設定は、BuildKeyCode() メソッドを用いて BuildKeyCode(wdKeyControl, wdKeySemiColon) のように書けるのですが、冗長なだけなので上記コードでは直接加算しています。

標準で組み込まれているコマンド (fixed command)名については、MSDNの
に記載されています。

【どうでもいい話】

過去に、無意識に Ctrl +S を押して、書き損じた文書を上書き保存してしまうという失敗をしたことがあったので、
Ctrl + Sには、「名前をつけて保存」を割り当てて、意図的に、ファイルの保存ダイアログが出るように(一旦、本当に保存していいか確認できるように)しています。

まぁ、自動でバックアップとるなり、差分管理しておけよって感じではあるのですが…。

WordからExcelを操作するサンプルコード(Excelで作った辞書データを用いてWordで一括置換)

【まえがき】

Excelファイルに記載されたデータをもとにWord上で文章を作成するツールを作りたいという動機で、手始めに参考になりそうなプログラムを探していたところ、水野麻子さんの
というblog記事にて紹介されていた、渡辺真さんによる
というマクロが、『WordからExcelを操作する』実例としてコードの分量的にちょうど良かったので、参考に読んでみました。
マクロの概要を簡単に紹介すると、英日翻訳の補助ツールのようなもので、『下図に示すようなExcelに記載した日本語と英語の対訳表(以下では、「辞書ファイル」と呼んでいます)に基づいて、Wordファイル中の日本語を、対応する英語に置換する』といった内容になっています。

辞書ファイルの参考例 (渡辺真さんのマクロに付属のもの)
読んでみて、いくつか気になった点があったので、WordからExcelを操作するコードの動作テストも兼ねて、渡辺真さんが公開されているコードに自分なりに手を加えてみました。
「手を加えた」といいながら、練習もかねて、動作の流れのみオリジナルに合わせ、フルスクラッチで書き直しています。

 【オリジナルの仕様 (個人的に気になった点のみ)】

  • マクロ付きのWordファイルとして配布されている
    • Wordファイルの本文に配置した 「ボタン」からマクロを起動
    • 置換対象のWordファイルをダイアログで選択する必要あり
    • 置換に用いるExcelファイル(辞書ファイル)の配置場所が固定
    • 辞書ファイルのファイル名を、Wordファイル中の所定欄に記入することで指定
  • 利用にあたり「参照設定」が必要
    • ※ 使用中のOfficeが2010以外の場合
  • 辞書ファイルの仕様
    • あらかじめ 、置換に用いる語句を語数順(降順)に並べ替えておく必要あり
  • マクロ実行中にWordの画面が固まる

 【変更点】

  • アドインに変更
    • 現在開いている文章を置換対象に
      • マクロ実行にあたりWordファイルを開く手間を削減
      • 置換対象のWordファイルの選択を不要に
    • 辞書ファイルをダイアログで選択するように
  • 「参照設定」なしで動作するように
  • 辞書ファイルの仕様変更
    • 手作業での単語の並べ替えを不要に
  • マクロ実行中も、適宜、画面の更新を行うように
なお、翻訳を生業としているわけではないので、これらの変更が、実際の翻訳作業における使い勝手を改善するものなのか正直よくわかりません(『一般的には、こうした方がいいんじゃないかなぁ』という程度の曖昧とした感覚で変更を加えています)。

また、一部、オリジナルのマクロに比べ、改悪している(設定の自由度が落ちている)部分があります。具体的には、オリジナルのマクロでは、辞書ファイルの記入方法(置換対象の語句、置換後の語句を何列目に記載するか、どのシートを使うかなど)は、Wordファイル中の所定欄に記入することで変更できたのに対し、今回作成したコードでは、辞書ファイルの記入方法が固定(コード中で指定)されています。

【今回作成したコード】

以下に、メインのモジュール(ModuleReplaceWithExcel.bas) を表示しています。


実際に作成したコードには、他に、
  • 処理時間計測用のクラスモジュール (Stopwatch.cls) 
  • 辞書データ用の構造体を定義したモジュール (TypeReplaceData.bas) 
  • アドインとして機能させるためにドキュメントに直接記載したコード (ThisDocument.dcm)
が含まれています。これらを含む全コードを、GitHubで公開しています。
実際にテンプレートファイルとして使ってみたい場合は、下記の手順でご利用ください。
  1. GitHubを開いて [↓ ZIP]ボタンを押して、全コードをダウンロード
  2. 解凍後、build.bat を実行(ダブルクリック)
  3. binフォルダ内に、テンプレートファイルが作成されるので、適宜インストール
    ※ アドインのインストール方法については、添付のマニュアル(manual.doc)にも記載しています。
なお、ソースコードのライセンスについてですが

  クリエイティブ・コモンズ・ライセンス

余談ながら、オリジナルのものに従ってライセンスにCC(Creative Commons)を適用したのですが、プログラムのソースコードに対してCCを適用することにどの程度の意味があるのか自分自身よくわかっていません。識者の方からのコメントをお待ちしております。CCJapan自身、ソフトウェアへの適用は非推奨としているので、なにか不都合があるような気もするのですが…。閑話休題。

最後に、参考までに、渡辺真さんによるオリジナルのコードと、今回作成したコード(ModuleReplaceWithExcel.bas) との対応関係を下図に示しています。
変数名をはじめ、全面的に書き変えてはいますが、色を塗った範囲で実現している『機能』に関しては基本的に同等です。
同じ機能でも異なる書き方ができるという程度のサンプルになれば幸いです。

左:オリジナルのコード、右:今回作成したコード

2012年8月23日木曜日

Word,Excelのコンテキストメニューを初期化する

【まえがき】

  • VBAでWordのコンテキストメニューを操作していたら、うっかりコンテキストメニューにゴミ(不要なメニュー)を大量生成してしまった。
  • WordやExcelのアドインを色々試していたら、アドインをアンインストールしたのに、種々のコンテキストメニューに必要のないメニュー(ゴミ)が残った
ゲンナリする状況を示す図 (一例)

などなど、WordまたはExcelのコンテキストメニュー周りでゲンナリするような気分を味わったときには、『コンテキストメニューなんてなかった』と開き直り、『この件は水に流そう(綺麗さっぱり初期化しよう)』と思うのが人の常だと思うのです。というわけで、Word, ExcelのコンテキストメニューをVBAで初期化するコードを書いてみました。

【先に結論を書いておく】
検索してみると、Microsoftのサポートサイトに
という、まさに今回の問題解決にぴったりのページがありました(機械語訳のページなので、日本語がおかしい気がしますが…)。解決策を簡単にまとめると、
  • VBAコードを書かない方法
    • 「ユーザー設定」 を開いて、『リセット』ボタンを選択
      • ※ この方法は、Office2003以前のみ可能なように思います。自分の曖昧な記憶に基づけば、2007以降では下記のVBAのコードを書く方法を使う必要があるのではないかと思います。(手元ではOffice2003, 2013Previewでのみ確認)
  • VBAコードを書く方法
    • Excelの場合: 
      • Application.CommandBars("Worksheet Menu Bar").Reset
    • Wordなどの Excel以外のOfficeソフトの場合:
      • Application.CommandBars("Menu Bar").Reset
ボタン1つ、もしくは、コードを書く場合でも一行で完結、とめっちゃ簡単でした(*)。

にも関わらず、以下ではVBAでわざわざコードを書いています(コードを書き終わってから検索したためです)。『また、つまらぬコードを書いてしまった』感がハンパないです。あらかじめご了承ください。

(*) この方法、必要であればVBEのイミディエイトウィンドウで実行できるので、ほんとお手軽です。

【対処法】
コンテキストメニューの実態であるCommandBarオブジェクトには、(アドインなどによりボタンを追加・削除するなどの変更が加わった状態から)初期状態に戻すためのReset()メソッド が用意されています。
というわけで、片っ端からCommandBarのReset()を実行するコードを書いてみました。なお、今回コードを書くにあたり、MSDNのコマンドバーに関する解説ページ(*1)を参考にしました。MSDNに開示されているコードは全体的にすっきりしていたので、お手本にするにはちょうど良いなと感じました。

上記コードの補足説明を加えると、CommandBar.Resetメソッドは、 MSDN(*2)に記載されているように、Officeにデフォルトで組み込まれている(BuiltInプロパティが True の) CommandBarでしか利用できないため、ループ内でBuiltInプロパティをチェックしています。

(*1) VBA コードでコマンド バーとコマンド バー コントロールを操作する
   Programming Microsoft Office Command Bars

(*2) CommandBar.Reset メソッド

【蛇足】
上記コードに限れば、全てのCommandBarについてResetメソッドを呼び出しているだけなので、On Error Resume Next でエラーを握りつぶすのもありかなと思ったりします。エラーを握りつぶすのは個人的には好きくないのですが…、こちらの方が「水に流す」感がアリアリと感じられて、蒸し暑い夏の夜にはちょうど良いかなと思ったりします。

-

Task.Existsが役に立たないときのための代替方法

【まえがき】
VBAで実行中のタスクの情報(存在)を知る方法を検索してみると

に記載されているように、Wordにのみ用意されている TaskオブジェクトのExists()メソッドを用いる方法が紹介されているのを見かけます。
しかしながら、実際に使ってみると『実行中のプロセス全てが列挙されるわけではない(*)』という問題や、当たり前ですが『Excelでは使えない』という問題がありました。

というわけで、Task.Exists()の代替策として Excel含めVBAで汎用的に使えような関数を作ってみました。

(*) 何分、だいぶ前に気付いたことなので、どういう状況下でプロセスの取得がうまくいかないのだったか忘れてしまいました。いまいち役に立たない話ですみません。

【やったこと】
プログラムの二重起動を防止したいといった用途で使いたいという背景があったので
  1. WMI (Windows Management Infomation)を使ってプロセス一覧を取得し、
  2. 引数で指定した実行ファイル名に一致するプロセスが存在するか否かをチェックする
ようにしました。
この動作は、Task.Exists() の『引数で指定した文字列にウィンドウのタイトルが一致するか否かをチェックする動作』とは異なっています。もし、下記コードを利用される場合は、この点ご注意ください。


余談ですが、WMIの使い方に関しては、VBAに限らず、VB6.0やVBSのサンプルコードが参考になります。(大抵は、ほぼそのまま流用可能です。)

2012年8月19日日曜日

Office用アプリとしてテトリスを実装してみた

【最初に】
完全に出落ちです。
「読んで損した!」という気分になること請け合いなので、その辺よろしくお願いします。

【やったこと】
Office用アプリって、つまるところ

 HTML5のsandbox属性がついたIFRAME + Office操作用API (office.js)

なので、単純に『HTML製のアプリを動かすための箱として(IFRAMEの機能だけ)利用したって問題ないよね。』ってことで、HTML5だけで完結してるようなアプリを探してきて移植してみました。「Office操作用のAPIを一切使わない」という清々しいまでにOfficeと全く関係のないOffice用アプリの完成です。

これで仕事中に堂々とテトリスができますね!(できません)



【実装したコード】
コードリーディングに最適!たった200行で作れるHTML5製テトリスのプログラミング学習ムービー
で紹介されているテトリスのコードを使いました。99% そのままです。何のひねりもありません。

実際に動かしてみたい場合は、GitHubからオリジナルのコードをダウンロードして、下記のファイル(HelloTetris.html, HelloTetris.xml)と同階層に、
  • 「style.css」
  • 「js」というフォルダ
をコピーしてください。
また、HelloTetris.xmlの ***Catalog*** の部分は、(Office用アプリ用の)カタログに使うフォルダを指定してください。


【移植する上でつまづいたところ】
HTMLファイルのヘッダ部分の、
  • 1行目: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  • 2行目: <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
  • 4行目: <meta charset="UTF-8" />
  • 5行目: <meta http-equiv="X-UA-Compatible" content="IE=9"/>
あたりは、必須事項…かも。
今回Office用アプリを作るにあたって、適当に省略してみたところ、アプリの読み込みはできるものの、作業ウィンドウ(task pane)に何も表示されないという残念なことになりました。

どんなに探してもカスタムツールバーが見当たらない


【概要】
Office2007以降では、通常、VBAでカスタムツールバーを作成する(CommandsBar.Addを実行する)と、「アドイン」タブ内に「ユーザー設定のツールバー」という名前のグループとして表示されるようになっています。
しかしながら、とある条件下では、
 『カスタムツールバーを作成しても「アドイン」タブが表示されない』
ことがあるのに気づいたので、それについてまとめています。

実験環境は、Office2013(Excel2013) Preview版です。
(未検証ですが、Office2007, 2010でも同様かと思われます。)

【実験環境と内容】

走らせたコードは以下の通り。


【いきなり結論】
こんなとこにあった。


「DATANITRO」っていうタブは、DataNitroアドインをインストールした際に作成されたものです。この「DATANITRO」タブ、どうも実態は「アドイン」タブっぽく、ユーザー設定のツールバーはここに追加されていました。

Commands.Barで追加したカスタムツールバーは、「アドイン」って名前のタブに追加されると思い込んでいたので、まったく気づきませんでした…。

【たぶんこういう原因】
  • DataNitroは、「アドイン」タブのタイトル名を改変してる。
    (「DATANITRO」タブ = 「アドイン」タブ)
→ 「DATANITRO」という名の「アドイン」タブにカスタムツールバーが追加される。

【勝手にこう思う】
そうそうないと思うのですが、
DataNitroに限らず、タブが追加されるタイプのアドインをインストールすることがあれば、
そのタブが「アドイン」タブと同一なのかという点に
気をつけた方が良いのかもしれないなぁと思ったりします。

(※ 汎用の「アドイン」タブとは別に、各アドイン専用のタブを作成するのが一般的じゃないかなと思ったりもするので、
   DataNitroの仕様が特殊なだけかもしれないです。)

Wordファイルに自動的に記録される情報の削除方法

【概要】
Wordファイルには、ファイルの作成者の情報をはじめ、種々の情報が自動的に記録されます。これらの情報は、第3者に渡ることは望ましくない場合があります。このため、以下では、これらの情報の削除の仕方を調べました。
Wordファイルに自動的に記録される情報には、

  • 「個人情報」 
  • 「隠し情報」 
と呼ばれる2種類の情報が含まれています。
このうち「個人情報」は、Wordのオプションで保存しないように設定が可能です。
また、「隠し情報」は、Microsoftが配布しているアドインを使って削除が可能です。

なお、以下ではWord2003での削除方法について記載しています。
(Word2007以降の場合は、手順が異なります。)

【「個人情報」の削除の方法】
  1. Word の上部メニュー[ツール(T)]から[オプション] を選択
  2. [セキュリティ] タブをクリックします。
  3. [保存時にファイルのプロパティから個人情報を削除する]をチェック
上記オプションをチェックすることで、「個人情報」が削除されるようです。
なお、「個人情報」として含まれている情報は、下記のようです。 (*1)
  • ファイルのプロパティに表示される作成者、管理者、会社名
  • コメントに付加されるユーザー名
  • 文書の版に付加されるユーザー名
  • [標準] ツールバーの [電子メール] ボタンをクリックしたときに
    生成される電子メールメッセージのヘッダー
  • 回覧先
【「隠し情報」の削除の方法】
Microsoftが公開しているアドイン(*2) を追加して手動で削除する必要があるようです。
「隠し情報」としては以下の情報が含まれているようです(*3)。
  • 保存された版の内容
  • Word の高速保存オプションで記録された変更情報など
Wordファイルを渡す相手が一般的なユーザであれば、「隠し情報」に関しては見られることはないと思いますが、念には念を入れて、削除しておいた方がいいかなと思います。

【参考情報】
(*1)[WD2003] Word 文書に保存されている個人情報と 個人情報の削除方法について
http://support.microsoft.com/kb/899877/ja

(*2)Microsoft DownloadCenter : Office 2003/XP アドイン: 隠しデータの削除
http://www.microsoft.com/ja-jp/download/details.aspx?id=8446

(*3)[WD2003] Word 文書に保存されている隠し情報と 隠し情報の削除方法について