最近、IS-MLを見ていて、ちょっと気になること。
MLの性質上、技術面の話題が多くなるのは望むところなのだが、
ここしばらくは聞くばかりの人が多いような気がする。
ヘルプはさすがに見ているようだが、英語版KBを調べた人はあまりいないような気がする。
ISやISWIの日本語版にバグが多いのは分かっているし、英語を読むのが辛いのも分かる。
ましてや日本語KBがどの程度使えるかも分かっているつもりだ。
ただ質問するならそれなりのことを自分でやった上で質問して欲しい。
答える人もそのためだけに時間を割くことはそうそう無いだろうが、
回答メールを書くだけでもその人の時間を使っていると言うことに気づいて欲しい。
上から押し付けられたものであれ、それで金をもらっている以上自分の仕事なのだから。

・拡張子関連付け

基本的には対応するレジストリに値を書き込むだけである。
OSによっては再起動しなければアイコン登録されない場合があるので、注意。
手順は
1.HKEY_CLASSES_ROOTに.xxx(拡張子)のエントリ作成
2.1.にREG_SZでデータ識別子をつける(アプリ名.識別子などの形式)
3.2.のデータ識別子と同じ名前のエントリ作成
4.3.にREG_SZでデータの説明を入れる(「詳細」表示時に「種類」として表示される)
5.3.以下にDefaultIconエントリを作り、「実行ファイルパス,アイコンインデックス」を値として入れる。
6.3.以下にshell\open\commandエントリを作り、「実行ファイルパス /dde」を値として入れる
7.3.以下にshell\open\ddeexecエントリを作り、「[open("%1")]」を値として入れる

※dde対応でない場合は6.で実行パスのみを入れる

・レジストリ書き込み/読込(V.6.3)
今更書くまでも無いとは思うが、個人用メモってことで書いておこう。
読込も書き込みもほぼ同じ手順で行う。
1.RegDBSetDefaultRootでルートパスを設定し、
2.RegDBCreateKeyExでキーを作成(新規に作る場合)
3.RegDBSet(Get)KeyValueExで値を読み書きする。

たとえば、
RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE); //ルートパス
szKey = "Software\\foo\\foo" ; //アクセスするキー
nvResult = RegDBGetKeyValueEx(szKey , "foo" , nvType , szType , nvSize) ;
//fooの値を取得(szTypeに内容が取得される)
書き込むなら、
上2行は同じにして、
szValue="foo" ;
if'RegDBCreateKeyEx(szKey , "")<0) then
//キーが作成できたら
RegDBSetKeyValueEx(szKey , "foo" , REGDB_STRING , szValue , -1);
//szKey内のfooに値szValue(文字列)を書き込む
endif ;

・外部アプリからの戻り値取得(その2)(V6.2)
と、下のように書いた後、InstallSiteを探していたら発見した。
詳しくはここをみること。
というのはちょっと冷たいので、内部についてすこしだけ。
まあ、Kernel32.dllの関数であるGetExitCodeProcessを使っているのだが、
その為には普通のLaunchApp(AndWait)では駄目なのは下に書いたとおりである。
アプリの呼出にもKernel32からCreateProcessA利用し自力でプロセスを作成する。
で、その前準備、特にSTARTUPINFO構造体の設定がこのスクリプトの大半を占めている。
begin行の次行から見てみよう。
cbとはこの構造体のサイズをあらわす。CならSizeOfを使うところだが、ここでは定数をセット。
lpReservedには予約領域である。ここはNULLをセット。
lpDesktopには、NT/2000環境では意味があるが、この場合はNULLをセットする。
lpTitle。これはコンソールアプリの場合のタイトルを設定できるものだが、ここもNULL.
dwX/Y,dwX/YCountChars,dwFillAttributeはどれも起動時のウインドウの状態を設定するフラグである。
ここも通常のアプリを呼び出す場合は必要なしと思われるので、をセット。
dwFlagsには次行のwShowWindowを有効にするために0を設定する.
で、そのwShowWindowなぜかSW_HIDEがセットされている。
残りは必要ないので全てNULLをセット。
ここまでやってようやくプロセスを起動、その情報が取れるようになる。
後はそのプロセス情報piDataからGetExitCodeProcessで戻り値を取得するだけ
NUMBERでアプリケーションからの戻り値が返される。
アプリケーションの側で値を返すよう作らなければならないのはいうまでもない
追記:
ソースに一部不具合があることが判明。
prototype宣言が間違っているのである。私は実装部にあわせたので、LaunchAppGetExitCodeに修正。
また、SW_HIDEを送ってしまうとまずそうだったので、wShowWindowにはNULLをセットした。
コンパイル時に一部Warningが出るが、とりあえず動作することを確認。

・外部アプリからの戻り値取得(V5.1/V6.2)
InstallScriptからはLaunchApp(andWait)外部のEXEファイルを呼べるのだが、
困ったことにアプリケーションが返す戻り値をとってくれない。
Win32APIを呼ぶ関数を作ればInstallScriptのみでできるようだが、
サンプルが見つからなかったのでカスタムDLLを作成、そこから呼び出す関数を書いた。

呼出関数のソースはここの通り。(VC6+MFC利用)

かなり汚いコードではあるが、とりあえず動いている。
まあ、APIバイブルなんかを見れば解説は不要であろう。
int(ISではNUMBER)で戻り値を返してくる。
この関数を呼び出しているのがこれである。
申し訳ないが、仕事で使っているので一部ファイル名を伏せさせていただいた。
当然、戻り値は呼び出される実行ファイルがきちんと返してやる必要がある。


・既インストールファイルのバージョンチェック(V6.3)

パッチインストールの際に、現在インストールしてあるEXEファイルの
バージョンをチェックし、古いバージョンには適用できないようにした。
パッチといいつつEXEそのものを上書きする仕様の為であり、
本来ならそれも含めた仕様で作るべきインストーラの作り直しをしていないせいで
こんなものばかり作ることになってしまう。

まあ、それはともかく、手順である。
1.アップデートするファイル毎にコンポーネント分けする。
チェックするまでインストールしてよいファイルがわからないためであり、
面倒なのでインストールされているファイルのみチェックの対象とした。

2.MoveDataのIntallイベントを取り、コンポーネント毎に関数を書く。
内容は以下の通り。
・ComponentSelectItemでコンポーネントを無効化
・インストール先フォルダ内の対応ファイルを探し、無ければ関数終了。
・ファイルがあったらVerGetFileVersionで取得したバージョンをStrFindでチェック
 適応バージョンならばComponentSelectItemで有効化。
・念のためバージョンが違う場合の無効化処理も記述。

3.この関数をすべてのコンポーネントに記述。
加えてコンポーネントの設定を「バージョンが新しいときのみ上書き」に設定。

以上である。
特に難しい事は無いが、取得されるVerGetFileVersionで取得できる値が
文字列なのが注意である。


mailto: sagami@mars.dti.ne.jp