開発用メモ

背景

何時の頃からか解らないが、FreeTrainでヘルプメニューから
「オンラインヘルプ」を選ぶとエラーが出るようになった。
また、プラグインエラーダイアログで、「バグを報告」ボタンを押すと
同じようなエラーが出るようになった。

これはどちらも、ソースコード上は
System.Diagnostics.ProcessクラスのStartメソッドに
URL文字列を与えて、標準のブラウザで対象URLを開く操作であり、
C#の本やWebなどでも、サンプルとして紹介されている一般的なコードである。
http://dobon.net/vb/dotnet/process/openbrowser.html

概要

特定の外部ライブラリなどを組み込むと、Process.Startで実行ファイルをシェルに解決させる
(所謂、ファイル名を指定して実行)機能が働かない場合がある。

この場合の一つの解決方法は、自分でレジストリの関連づけを調べて、
明示的に関連づけられたアプリケーションを起動することである。

詳細

本やWebで、指定のURLをブラウザで開くサンプルとして
一般的に紹介されている以下のようなコードですが、

System.Diagnostics.Process.Start("http://www.google.co.jp/");

プロジェクトによっては、以下のようなエラーで正常に機能しない場合があります。

System.ComponentModel.Win32Exception: 指定されたファイルが見つかりません。
  at System.Diagnostics.Process.StartWithShellExecuteEx(ProcessStartInfo startInfo)

色々調べたのですが、どこか海外のサイトでは、特定ライブラリを組み込むと
このような現象に陥る、と報告されていました。(当該URL失念)
しかし残念ながら、そのサイトにも解決法は示されていませんでした。

さらに試行錯誤した結果、ProcessStartInfoクラスで実行ファイルと
ワーキングディレクトリを絶対パスで指定すれば、
例えばIExplorer.exeに引数としてURLを与えて起動できることが解りました。

実用上はIExplorer.exeではなく、「通常使うブラウザ」として設定されている
アプリケーションを起動したいところですが、
これは下記のレジストリを読むことで解決できます。

HKEY_CLASSES_ROOT\http\shell\open\command

例えば、元々以下のようなコードが、正常に機能しなかったなら・・・

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
-
-
-
!
!
 // 指定のURLを標準ブラウザで開く
 public void openUrl(String targetUrl) { 
    // 理由は解らないが、以下のコードは機能しない
    System.Diagnostics.Process.Start(targetUrl);
 }

次のように修正すれば、問題なくブラウザを起動できます。

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 
 
 
 
 
-
-
|
-
!
|
-
|
!
-
|
|
|
!
|
-
|
|
|
!
-
!
-
!
|
!
 using System;
 using System.Diagnostics;
 using System.IO;
 using Microsoft.Win32;
    
 // 指定のURLを標準ブラウザで開く
 public void openUrl(String targetUrl) { 
    ProcessStartInfo info = new ProcessStartInfo();
    // URLに関連づけられたアプリケーションを探す
    RegistryKey rkey = Registry.ClassesRoot.OpenSubKey(@"http\shell\open\command");
    String val = rkey.GetValue("").ToString();
    // レジストリ値には、起動パラメータも含まれるので、
    // 実行ファイル名と起動パラメータを分離する
    if(val.StartsWith("\""))
    {
        int n = val.IndexOf("\"",1);
        info.FileName = val.Substring(1,n-1);
        info.Arguments = val.Substring(n+1);
    }
    else
    {
        string[] a = val.Split(new char[]{' '});
        info.FileName = a[0];
        info.Arguments = val.Substring(a[0].Length+1);
    }
    // 作業ディレクトリも指定しないとダメなようだ・・・
    info.WorkingDirectory = Path.GetDirectoryName(info.FileName);
    // 引数の最後にURLを加える
    info.Arguments += targetUrl;
    Process.Start(info);
 }

MainWindow.cs ソース
UrlLinkLabel.cs ソース

1/3851

Last-modified: 2008-05-10 (土) 11:04:52 (944d)