2011年11月4日金曜日

ファイルをダブルクリックしてからアプリが起動するまで


ファイルをダブルクリックしてからアプリが起動するまで



デスクトップ等にある、ファイルをダブルクリックするとアプリが起動すると思います。
例えば、拡張子 .XLS ファイルをダブルクリックすると Excel が起動し
その中に、ファイルの内容が表示されます。
当たり前の動作と思いますが、実は奥が深い。
今回は、その仕組みについて、簡単に書きたいと思います。

特に、アプリを仮想化しているとMS-Officeの複数バージョンを稼働させたり
することが多々あります。Excel2003 と Excel2007 、Excel2010 等
その時に、XLSの拡張子を持つファイルをダブルクリックで開くときに
どのバージョンの Excel で開かせるか。等々。考えないといけません。



その際に大切なのは、XLSをダブルクリックしてからアプリが起動するまでの
一連の仕組みを理解しておく必要があります。

ほんとに拡張子からのファイル起動に関しては、奥が深くて
長い Windows の歴史を知る必要があります。
あと私が知らない事もこの分野では、たくさんあるので、間違っていたり時代遅れだったりするかもしれませんがご容赦ください。



【はじめに ファイル関連付けとは】
ファイル関連付けとは、ファイルの拡張子と特定のアプリを対応付けるための仕組みです。
デスクトップにあるファイルをダブルクリックした際には、この仕組みを利用し対象となる
アプリを起動しファイルを開きます。
 Windows (Explorer ,別名Shell)は、アプリ起動方式として「標準」「DDE」の2パターンを提供しています。
  重要な事として1つのファイル拡張子には、1つのアプリケーションしか対応付けられません。
※画像、動画系のファイルは、実は複数アプリを関連付けられたりするようです。


既定と異なるアプリでファイルを開く場合は、右クリックメニューにある
「プログラムから開く」、「送る」を活用します。











【#1.ファイル関連付けによりアプリが開くまでの動作について(通常パターン)
ファイルをダブルクリックすると、Explorer(shellと呼ばれたりします)は
主に以下の順番で開くアプリを特定し、そのアプリを起動しています。

  1. 開くファイルの拡張子を取得
  2. レジストリのHKEY_CLASSES_ROOTから、その拡張子の「既定値」を取得
  3. レジストリのHKEY_CLASSES_ROOTから、「既定値」にセットされている「shell\open\command」を参照
  4. 「command」の「既定値」情報を取得
  5. アプリ起動パラメータの作成
  6. アプリを起動

例)「テキスト.txt」をダブルクリックした際の流れ

1.拡張子を取得します。 [.txt]






2.HKEY_CLASSES_ROOT [.txt]を開きます。 (既定)値:txtfile








3.HKEY_CLASSES_ROOT [txtfile]を開きます。 [shell]\[open]\[command]を開きます。










4.(既定)値: %SystemRoot%\system32\NOTEPAD.EXE %1







※「%1」について:開くファイルのフルパスを意味する特別なパラメータです。


5.アプリ起動パラメータを作成します。
C:\Windows\system32\NOTEPAD.exe C:\Documents and Settings\<UserID>\デスクトップ\テキスト.txt

6.メモ帳が起動し、ファイルの内容が表示されます。

















【#2.ファイル関連付けによりアプリが開くまでの動作について(DDEパターン)
ファイルをダブルクリックすると、Explorer(shellと呼ばれたりします)は
主に以下の順番で開くアプリを特定し、そのアプリを起動しています。

  1. 開くファイルの拡張子を取得
  2. レジストリのHKEY_CLASSES_ROOTから、その拡張子の「既定値」を取得
  3. レジストリのHKEY_CLASSES_ROOTから、「既定値」にセットされている「shell\open\ddeexec」を参照
  4. 「open\ddeexec」の「既定値」情報を取得
  5. 「application」の「既定値」情報を取得
  6. DDE接続パラメータの作成
  7. アプリに接続、もしくは起動

例)「Book1.xls」をダブルクリックした際の流れ



1.拡張子を取得します。 [.xls]









2.HKEY_CLASSES_ROOT [.xls]を開きます。 (既定)値:Excel.Sheet.8










3.HKEY_CLASSES_ROOT [Excel.Sheet.8]を開きます。 [shell]\[open]\[ddeexec]を開きます。












※[Open]キー配下に[ddeexec]キーが存在する場合は、DDEを利用しアプリを起動します。








4.ターゲットDDEアプリケーション名[application]を取得 既定値:Excel













5.アプリにDDE接続し起動パラメータを引渡します。
 ターゲットアプリが起動していない場合は、ターゲットアプリを起動します。
 起動している場合は、既に起動しているターゲットアプリにDDE接続しパラメータを引渡します。

この例では、[Excel]と言う名称のDDEサーバーに接続し、パラメータ(開くファイルのフルパス)を引渡します。 [Open("%1")]

6.Excelにファイルの内容が表示されます。













【アプリ側から見たファイル関連付けによる起動について】
今までのトピックは、Explorer(shell)から見た関連付けによるアプリ起動でした。
ここからは、アプリ側から見たファイルを開くまでの流れについて書きたいと思います。

ポイントは、「アプリを作る人の作り方(設計)次第」ってことです。

アプリ開発者がファイルの関連付けから、そのファイルを開く場合は以下の2パターン分類されると思います。

  1. 通常のファイル関連付けからの起動
  2. DDEを利用したファイル関連付けからの起動


【通常のファイル関連付けからの起動】
アプリ起動時には、必ずコマンドライン引数が Windows 側から渡されます。
GetCommandLineで取得するか、WinMainのArgsから貰ったりします。
ファイル関連付けからの起動の場合は、引数に開きたいファイルのフルパスが付いています。
簡単に実装した場合は、アプリを起動してから、そのファイルを開けばOKです。

しかしながら、この場合だと1ファイルに付き、1つのEXE(Process)が起動してしまいます。
タスクマネージャーで見ると、おなじアプリのEXEがたくさん動いている状態。

最近は、プロセスをたくさん動かすのが流行っていますが。それはクラッシュに対する防御だったり
マシンの性能があがっているお陰だったりしますので、良し悪しはここでは抜きで。。。

そこで、1つのEXEで複数のファイルを開くように、実装する必要があります。
古くはMDIとか呼ばれてましたが見た目SDIでも実は、EXEは1つの物もあったりします。

どのように実装するかと、ざっくり説明すると、
1.初めに開くファイルのフルパスを取得
2.既に起動している自分と同じプロセスを検索
3.起動しているプロセスに、開くファイルのフルパスを「引渡し」て、自らを終了させます。

既に起動してる物がない場合は、そのまま、動きます。
Powerpointは、このタイプです。

ポイントは、ファイルをダブルクリックすると、関連するアプリが(一瞬)起動する。
その後はアプリ任せ。ってことです。

【DDEを利用したファイル関連付けからの起動】
これは、ちょっとややこしいのでDDE自体の仕組みを説明する必要があります。

DDEはクライアントとサーバーがあります。
ざっくり説明すると、データをプロセス(EXE)間でやり取りする一つの方式です。
昔々からあります。
ファイルを開くために必要な情報は何?と考えると
それは、「命令:開く」「データ:開くファイルのフルパス」になります。

DDEクライアントは、Explorerです。
DDEサーバーは、対象のアプリです。

そこで、このDDEの仕組みを使って、「命令:開け」「データ:開くファイルのフルパス」を
送信する事になります。

受け取り側のDDEサーバーの機能をアプリ側で実装します。
自らをDDEサーバーとして「アプリケーション名」と対応する「命令」を Windows 側(レジストリ)に設定します。

ファイルの関連付けからの起動の場合は、DDEクライアントのExplorerは
アプリケーション名を元にDDEサーバーに接続を行い
接続できたら、「命令:開け」「データ:ファイルのフルパス」の情報を送信します。
接続できない場合は、プロセスを作成します。

ポイントは、DDE接続できる場合には、プロセスの追加生成を行わないって事です。
Excel、WordはDDEの仕組みを利用してファイルを開いています。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
今回は、ここまでですが、Excel を複数バージョン仮想化していると
意図したExcelのバージョンでファイルが開かない現象が発生することがあります。
不具合ではなく、仕様です。(笑)

ポイントは、DDE を利用している Excel とその識別子であるアプリケーション名が
バージョンが違えども「Excel」という同じ名前ってのがミソです。

Office2003形式のファイル(xls)は、Office2003で表示し、
Office2007形式のファイル(xlsx)はOffice2007で表示させようと思った場合に、
Powerpointは意図した動作となり、 Excel、Wordは異なる動作結果となるため
混乱する事になりますが、DDEを理解すると、対処方法が自ずと見えてきます。


参考:
動的データ交換
http://ja.wikipedia.org/wiki/%E5%8B%95%E7%9A%84%E3%83%87%E3%83%BC%E3%82%BF%E4%BA%A4%E6%8F%9B

DDE を用いて Excel ファイルを開く方法
http://www.accessclub.jp/samplefile/samplefile_245.htm

DDE サーバーを作る
http://hp.vector.co.jp/authors/VA016117/ddeserv.html

他のアプリケーションの起動(API関数,OLE,DDE)
http://homepage2.nifty.com/kasayan/vba/vba4.htm