複数バージョンの Excel を WSH 等のスクリプト内で使い分ける方法の検討
約一年前に Excel 2003 と Excel 2007 を共存させる場合の留意点 なんてエントリを書きました。Office 2003 を残したまま Office 2007 をインストールする方法は下記の通りです。(※前エントリの再掲)
複数バージョンをインストールした場合、通常の使い方としてはユーザが明示的にショートカット等で Excel 2003 と Excel 2007 を使い分けていることでしょう。しかしながら WSH 等のスクリプト内では話が別です。
たとえばスクリプト内で Excel を使いたい場合は、
で Excel インスタンスを生成します。引数として渡しているのは「COM コンポーネント名」なのですが、Office オートメーションの設計上?問題がありバージョン管理ができないため基本的に最後にインストールしたバージョンの Excel のインスタンスが生成されてしまいます。
これも前エントリの再掲になりますが、
HKEY_CLASSES_ROOT\Excel.Application\CLSID
デフォルト値 : {00024500-0000-0000-C000-000000000046}
HKEY_CLASSES_ROOT\CLSID\{00024500-0000-0000-C000-000000000046}\LocalServer32
デフォルト値 : C:\PROGRA~1\MICROS~1\Office\EXCEL.EXE /automation
COM は、PROGID から CLSID までのレジストリ キーの値によって Excel の実行可能ファイルのインストール場所を確認し、そのファイルでオートメーションを開始できます。システムに複数バージョンの Office をインストールしているときの Office オートメーションは、一般的にバージョン固有の特定の PROGID を使用して読み込むバージョンを指定できると認識されています。たとえば、
"Excel.Application.9" の場合は Excel 2000、
"Excel.Application.10" の場合は Excel 2002、
"Excel.Application.11" の場合は Office Excel 2003
これは正しくありません。Excel 2000、2002、および 2003 は同一の CLSID を共有しているため、これらの PROGID を使用して読み込まれるバージョンは、単にどのバージョンが最後にインストールされたかということで決まります。
なんて前回書いたことは把握しつつもどうしてもバージョンを分けて起動をする必要が出てきました。さて前置きはこのくらいにしてどのように解決したかのソースを記載します。 excel_2003or207.wsf (右クリックで保存下さい)
<job id="excel_2003or207"> <script language="JScript"> var excel; var book; var ExcelPath var Shell = WScript.CreateObject('WScript.Shell'); var runMode = Shell.Popup("「はい」:Excel2003 「いいえ」:Excel2007", -1, "Excel起動モードの選択", 36); // excel2003 or 2007 の起動を分ける裏技。excel = new ActiveXObject('Excel.Application.12'); を使わない if(runMode==6){ // excel 2003 を起動 ExcelPath = Shell.RegRead("HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\Excel.AddIn\\shell\\Open\\command\\"); } else { // excel 2007 を起動 ExcelPath = Shell.RegRead("HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\Excel.AddInMacroEnabled\\shell\\Open\\command\\"); } ExcelPath = ExcelPath.toLowerCase(); ExcelPath = ExcelPath.replace(/^"(.+\\excel\.exe).+$/, "$1"); excel = Shell.Exec('"' + ExcelPath + '"'); while(!Shell.AppActivate(excel.ProcessID)){ WScript.Sleep(2000); } // excel の起動を待ちます // 最新の Book名 (=今開いたヤツのハズ)のオブジェクトを取得 var findflg = false; while(!findflg){ var i = 1; try { while(GetObject("Book" + i)) { i++; } } catch(e) {} i--; if(i>=1){ book = GetObject("Book" + i); Shell.AppActivate("Book" + i); findflg = true; } WScript.Sleep(800); } // テストで何かデータを書いてみる var sheet = book.worksheets.add; sheet.cells(1,1) = "this is test"; </script> </job>
えーっと・・・どうなっているかというと WshShell オブジェクトの Exec メソッドを使って Excel 2003 / Excel 2007 を起動します。Exec メソッドには起動する Excel のフルパス名を指定します。フルパス名はレジストリからよろしく取得します。Office アプリケーションのパスを調べる方法 なんかにフルパス名の取得方法が記載されていますが、この方法はオートメーションに登録されている Office のフルパスになるので他のレジストリキーから Office11 と Office12 が出てくるキーを探して適当に取得してでっち上げています。
ちょっと手抜きで今起動した Excel のオブジェクトを取得するために最新の Book 名を検索する方法をとっています。見つからなければ終了します。Book 名は Excel を起動する毎に通番号で増えていくはずなので最後の Book が今立ち上げたものという”見なし取得”です。このアイデアの元ネタは
を参考にさせて頂きました。この手法で起動までは当然うまく行くのですが、Book の取得で失敗してしまう端末がいくつかでてしまいました。同じ環境でうまく行く端末といかない端末があるので謎です。専門分野でないのであまり深追いする気力がありません・・・。
コメントやシェアをお願いします!