パソコン活用研究5番街(Visual Basic、Excel(VBA)、BASIC プログラミング研究)

他のプログラムの起動(Shell関数)

Visual Basic または VBA(EXCELのマクロ)から、他のアプリケーションのプログラムを起動したい
という場合があります。今回はその方法についてとりあげてみます。

他のプログラムを起動する実用例としては、「
EXCEL自作アプリ」に、Browse.lzh(解凍後はBrowse.xls)
がありますのでダウンロードしてご覧下さい。


1 Shell 関数を使う
(1) Shell 関数
Shell 関数は実行可能プログラムを起動する関数です。書式は以下の通りです。

Shell ( パス名、[Windowスタイル])  
[ ]は省略可

パス名には、実行するプログラムのパス、必要な引数名等を記述します。
Windowスタイル 1、5、9   フォーカスをもった通常のWindow
           2       フォーカスをもちアイコン化されているWindow     
           3       フォーカスをもち最大表示されているWindow
           4、8     フォーカスを持たない通常のWindow
           6、7     フォーカスを持たないアオコン化されたWindow
  

なお、Shell関数はプログラムを非同期に実行し、Shell関数が実行され起動されたプログラムが終了したか
どうかにかかわらず、次のコードに制御が移ります。

それでは、上記のBrowse.xls のVer0.0.3 までに使っていた例で、メモ帳(notepad.exe)を起動する部分を
抜粋します。(現在ダウンロードできるのは、Ver0.1.0で下記のコードは使用しておりません)
赤い部分のコードを見て下さい

メモ帳を起動し指定ファイルを読み込む(Browse.xlsからの抜粋)
Sub notepad()
On Error GoTo errline
a& = Shell("c:\windows\notepad.exe", 1)    'ここでShell関数でメモ帳を起動
SendKeys "%FO%N" + Selection + "{ENTER}"
Exit Sub
errline:
Err = 0
If Sheets(2).Cells(1, 1) <> "" Then
txtopen = Sheets(2).Cells(1, 1).Value
a& = Shell(txtopen, 1)
Resume Next
Exit Sub
End If
'
' パスが正しくなければ自分で起動アプリを指定する
'
q = MsgBox("ファイルが開けません。起動するアプリケーションを指定しますか", 1, "起動アプリ指定")
If q = 1 Then
txtopen = Application.GetOpenFilename()
Sheets(2).Cells(1, 1).Value = txtopen
a& = Shell(txtopen, 1)

Resume Next
End If
End Sub

余計な部分は置いといて、ただShell関数にnotepad.exe のパスを記述しているだけです。

(2) Sendkeys
先ほどの赤で表示したShell 関数のすぐ次のコードにSendkeys があります。これは何かというと
アクティブなプログラムに「キーコードを転送する」ステートメントです。
キーコードを転送する、とはすなわち、そのプログラムにキーボードからキーを入力したのと同じ効力を
もちます。

SendKeys "%FO%N" + Selection + "{ENTER}"
とは、つまり、上記の例では「メモ帳」に対してこのようなキーコードを転送したことになります。
ひとつひとつのキーの意味を見ていきます。試しにメモ帳を開いて確認してみて下さい。
%F   メモ帳のメニュー の「ファイル(F)」
O    「開く(O)]
%N   ファイルを開くダイアログの「ファイル名(N)」
Selection はEXCELで現在選択されているオブジェクトを返すプロパティです。上記のプログラムでは
       開きたいファイルのパス名が入っています。
{ENTER} で実行です。

ちなみに % 記号は ALTキーを同時に押しているのと同じ意味になります。

これにより、上記プログラムではShell 関数でメモ帳を起動し、Sendkeysでファイルを読み込ませている
わけです。

(3) Shell 関数の問題点
上記のように、Shell 関数と Sendkeysの組み合わせで、ファイルを開くことができますが、いくつか問題点
があります。

A) 自分のマシンだけであれば、問題ないのですが、他のマシンでは起動したいプログラムのパスが
   違っている可能性があります。起動したいプログラムのパスが違うとなるととShell 関数は、まったく
   使えなくなります。
B) (1)でShell 関数は非同期でプログラムを実行すると述べましたが、重いプログラムを起動すると
   起動に時間がかかり、Sendkeys がプログラムの起動前にキーコードを転送してしまう可能性
   があります。Sendkeys はその時点でアクティブなプログラムにキーコードを転送するので、起動が
   間に合わなければ、その時点でアクティブな別のプログラム(たいていは、このマクロを実行中の
   EXCELになるでしょう)にキーコードを転送してしまいます。
C) これはSendkeysでも問題になりますが、My Documentのように空白のあるフォルダでは
   空白を区切りとして認識してしまい、想定した通りの動きになりません。

さて、上記の問題点の解決策ですが、A)については、パスが正しくないとエラーが発生するので
エラートラップをかけて、自分で起動したいプログラムを見つけさせれば、なんとかなります。上記の例では
そのような形をとっています。 パスが正しくなければ自分で起動アプリを指定する から以下の部分です。
B)については、AppActivate ステートメントを使うという手があります。でも面倒です。
C)には有効は手段が見つかっていません。

AppActivate の書式は AppActivate タイトル, [wait] となります。
タイトルには "無題 - メモ帳" のような各プログラムのタイトルを記述しますが、半角と全角が混在していて
きわめて面倒です。

あるいは、下記のよに起動したいプログラム名(パス含めて)をコマンドラインに記述してしまうのが少し
賢いやりかたかもしれません。これだと、B)の問題は回避できます。
GetOpenFilename で開きたいファイル名(パス含めて)取得し(この場合は、画像ファイル)、
ペイント(Pbrush.exe)を起動。


Sub a()
file = Application.GetOpenFilename
file = "C:\windows\Pbrush.exe " + file

Shell (file)


End Sub



2 Shell 関数は古い
ま、いずれにせよ、Shell 関数とSendkeysの組み合わせは制約が多く、できることも限られているので
もっと他の方法を使う方が良いでしょう。
何より、この方法はかびのはえた古くさいやりかたですから。
他の方法については、別の機会にとりあげます。

TopPage > Visual BasIc&Excel活用研究目次