DOBON.NET DOBON.NETプログラミング掲示板過去ログ

プラグイン機能を持つアプリケーションを作成するについて

環境/言語:[Windows2K VS2003(1.1) VS2005(2.0) C#]
分類:[.NET]

はじめまして、Net2003と申します。
よろしくお願い致します。

プラグイン機能を持つアプリケーションを作成する
(NETプログラミング研究 第39,40号)について
質問させてください。

私はこのサンプルを、CodeZineのほうで拝見させて頂きました。
CodeZineよりサンプルコードをダウンロードさせて頂きました。

VS2003のデバッグモードで実行しますと
PluginInfo.cs の public Plugin.IPlugin CreateInstance()メソッド内
で、例外が発生してしまいました。
(Plugin.IPlugin plugin = (Plugin.IPlugin)asm.CreateInstance(this.ClassName);のところでした。)

そこで、VS2005でもデバッグモードでも同様に例外が発生してしまいました。

VS2005の場合は、例外が説明してくれましたので、見てみますと
System.InvalidCastException "型 'CountChars.CountChars' のオブジェクトを型 'Plugin.IPlugin' にキャストできません。"となっておりました。
(ちなみに、MSDNのCreateInstance()の例外一覧には記載されていませんでしたが…)

ただ、CountChars.CountCharsは、'Plugin.IPlugin' インターフェースクラス
からの派生クラスですので、問題なさそうなのですが…。

しかし、VS2005で作成したリリースモードでは、例外がなく動作してくれます。
(VS2003では、リリースでも例外が発生してしまいました。)

プロジェクトの参照にも、Pluginのdllは参照追加しています。

私の環境のせいかもしれませんが、もし情報ございましたら
よろしくお願い致します。
VS.NET2003およびVS2005で正常にビルドと起動ができることを確認しました。普通なら、正常に起動するように思うのですが。
ご連絡ありがとうございます。

ん〜、やっぱりそうですか…。

ただ、私のところではどうしても例外が発生してしまって…。
(オブジェクト参照がオブジェクト インスタンスに設定されていません。)

先ほど、他の人にVS2005をインストールして確認して
貰ったのですが、正常に動作しました。
(当たり前ですよね…)

そのプロジェクトの実行ファイルをそのまま起動すれば
正常に起動してくれます。

ただ、そのプロジェクトを私のところで再コンパイルすると
例外エラーが発生してしまいました。

とりあえず、私の環境だけの問題ですので、
調査します。

どうもお騒がせして、申し訳ありませんでした。

ありがとうございます。
すみません、もしよろしければ1点確認させてください。

先ほどの別のパソコンで調べてもらった件ですが、
WindowsXPでした。

そこで、またもう一人別の方に調べてもらったのですが
Windows2000では、同じように例外が発生してしまいました。

NetFrameworkは1.1がインストールされています。

どうも、VisualStudioの設定に何か違いがあるようですので
その辺りを調べてみます。
私が試した環境ですが、VS2005がWindows XP SP2、VS.NET2003がWindows 2000 SP4です。CodeZineにあるC#のソースのソリューションファイルを開いて、ビルドしただけです。

既にビルドされている実行ファイルも実行できないのでしょうか?
ご連絡ありがとうございます。

実行ファイルのみをダウンロードして実行する分については、例外は発生せず
動作してくれます。

また、Xpで動作するプロジェクトをそのままコピーして、私のNGである環境で
実行します。(リビルドはせずに実行)

すると、例外は発生せずに正常に動作してくれます。(Debug/Release両方ともOK)

ただ、そのプロジェクトで、明示的にリビルドを行い、実行すると
Form1_Load()内の下記で例外が発生します。
//プラグインを実行するメニューを追加する
foreach (Plugin.IPlugin plugin in this._plugins)
{
if (plugin.MainMenuItem != null) <<--------※ここで例外発生!!
this.menuPlugins.MenuItems.Add(plugin.MainMenuItem);
}

直接原因は、その前のCreateInstance()メソッド内の
(Plugin.IPlugin) asm.CreateInstance(this.ClassName);
で、例外が発生し、try句に対するcatch句で捕捉され
nullでreturnされているのが、原因のようです。

例外が発生してしまうWinodws2kはSP4で、VS2003/VS2005を
インストールされた状態と認識しております。
(よって、.NetFramework 1.1/2.0もインスールされた状態と
 なっております。)

ただ、WindowsXpでリビルドされた状態のobj環境であれば、
本来例外が発生してしまうWindows2Kでも正常に動作してくれる
ところから見て、NetFrameworkの設定環境!?が何か影響して
いるのかなと思っています。

それがWindows2KでVS2003/2005を使用する場合、何か設定する
必要があるのかが、知識不足で理解できておりません。

また、VSのインストール時に何かが抜けてしまっているのか…
(あり得ないですが…)

とりあえず、NGが起こっているPCにNetFrameworkをダウンロードして
再度インストールしてみます。
(Windows Updateか、MSDNにありましたよね…!?)

また進展がありましたら、ご連絡いたします。

情報ありがとうございます。


■No15329に返信(管理人さんの記事)
> 私が試した環境ですが、VS2005がWindows XP SP2、VS.NET2003がWindows 2000 SP4です。CodeZineにあるC#のソースのソリューションファイルを開いて、ビルドしただけです。
>
> 既にビルドされている実行ファイルも実行できないのでしょうか?
お世話になっております。

NetFramework1.1をアンインストール/インストールし直して
みましたが、同じく例外が発生してしまいました。

色々調べてまして、1点判ったことがあります。

1)一旦、「ソリューションのリビルド」で実行ファイルをすべて作成します。
2)Plugin.dllのみを削除します。(pluginsフォルダの中も。よって、2つ)
3)今度は、「クラスビュー」から「Plugin」クラスのみリビルドします。
4)デバッガを実行します。
すると、正常に動作してくれます。
※2)の削除を飛ばして、3)のりビルドだけでは、やはり例外が発生します。

なぜか、判らないのですが、正常に動作する条件だけは判りました。

後、このNGとの差なんですが、pluginフォルダのdllを読み出す順序に
差がありました。

PluginInfo.FindPlugins()内の
string[] dlls =System.IO.Directory.GetFiles(pluginDir, "*.dll");
を実行した段階でのdlls[]のファイルの順序が異なっておりました。

NGの場合には、問題の!?Plugin.dllが配列の先頭[0]に配置されておりました。

そこで、
1) 本来NGとなる条件の「ソリューションのリビルド」を行います。
2) PluginInfo.FindPlugins()内の
  string[] dlls =System.IO.Directory.GetFiles(pluginDir, "*.dll");
にブレークポイントを設定し、先にpluginsフォルダからPlugin.dllを削除します。
3) その後、GetFiles()を実行します。
すると、正常に起動してくれました。

FindPlugins()関数からすれば、結果的にPluginInfo[] には、同じ情報が
設定されているように思うんですが…。

まあ、こんな状況を並べたところで、私のところしか発生していないので、
意味ないですが…。

すみません、とりあえず、途中経過報告でした。

また進展ありましたら報告いたします。






宜しければ情報お願い致します。
お世話になっております。

また続報です。

別の方から教えて貰ったのですが、
インターフェースを実装したクラス側(CountCharsクラス等)の
ソリューションエクスプローラの「参照設定」のPluginのプロパティーで
ローカルコピーを「False」にします。

すると、先ほどのスレッドでお伝えしたpluginsフォルダには
Plugin.dllが作成されなくなります。

結果的に、plubingsフォルダにはPlugin.dllが存在しない状態に
なるので、例外は発生しなくなりました。

ただ、Xpではこんなことをしなくても動作しますし、
管理者様を含め、世間一般の方は、同じく動作していますので
関係ないと思いますが…。

ちなみにですが、この「ローカルコピー」って、プロパティー画面の
出力/出力パス にファイルをコピーするかしないかだけのもの
ですよね…。

って、事は、私のところで例外が発生する要因は、dllを読み込んだ時に
展開される順番がPlugin.dllからだと、おかしくなってしまうという
事には、変わりないですね…。

ん〜、とりあえず、途中経過報告でした。
いろいろ調べていただき、ありがとうございました。Net2003さんのご報告を基に試してみたところ、確かに問題が発生しました。その後、デバッグをしてみると、どうやらPlugin.dllがはじめに来る場合は、プラグインのアセンブリ内のPlugin.IPlugin型がpluginsフォルダにあるPlugin.dllのものとなり、そうでない時はexeフォルダにあるPlugin.dllとなるようです。よって別の型であると判断され、エラーとなるようです。

とりあえずの解決法は、pluginsフォルダのPlugin.dllを削除するか、FindPluginsメソッドでPlugin.dllが一番初めにAssembly.LoadFromされないようにするということになりそうです。時間が空き次第、もう少し調べて、もっとよい解決法を考えてみます。
Net2003さん、管理人さん はじめまして。
Suzukin と申します。

■No15369に返信(管理人さんの記事)
> いろいろ調べていただき、ありがとうございました。Net2003さんのご報告を基に試してみたところ、確かに問題が発生しました。その後、デバッグをしてみると、どうやらPlugin.dllがはじめに来る場合は、プラグインのアセンブリ内のPlugin.IPlugin型がpluginsフォルダにあるPlugin.dllのものとなり、そうでない時はexeフォルダにあるPlugin.dllとなるようです。よって別の型であると判断され、エラーとなるようです。
>
> とりあえずの解決法は、pluginsフォルダのPlugin.dllを削除するか、FindPluginsメソッドでPlugin.dllが一番初めにAssembly.LoadFromされないようにするということになりそうです。時間が空き次第、もう少し調べて、もっとよい解決法を考えてみます。

私の場合ですが、勉強用として自作プラグインDLLを作成した場合に
上記現象が発生しました。
やはり、DLLの読み込み順に左右されるようで
Plugin.DLLを読み込んだ後に自作DLLを読み込んだ場合に現象が発生しました。

C#はまだ勉強中ですので、正しい解決方法ではないかもしれませんが
FindPlugins メソッドの Assembly.LoadFrom を Assembly.LoadFileに変更して
対応しました。

よろしかったら、参考にしてみて下さい。
> C#はまだ勉強中ですので、正しい解決方法ではないかもしれませんが
> FindPlugins メソッドの Assembly.LoadFrom を Assembly.LoadFileに変更して
> 対応しました。

全く気が付きませんでした。ご報告ありがとうございました。参考にさせていただきます。

私が考えていた方法は、プラグインを調べる時は、調べ終わった時にアセンブリをすべてアンロードするという方法でした。コードが書けましたら、今までのものをアップデートしたいと思います。

DOBON.NET | プログラミング道 | プログラミング掲示板