C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[18]: AppDomainのアンロードタイミング


(過去ログ 108 を表示中)

[トピック内 24 記事 (1 - 20 表示)]  << 0 | 1 >>

■64129 / inTopicNo.1)  AppDomainのアンロードタイミング
  
□投稿者/ SS (1回)-(2012/11/08(Thu) 14:23:23)

分類:[.NET 全般] 

Visual Studio 2010
Framework 3.5
VB.NET
Windows Vista/7

お世話になります。

話の発端は、DLLを動的に呼び出して使用したい という事から始まりまして、
Assembly.CreateInstance すれば良い事が分かったのですが、
呼び出し元のアプリが終了するまで解放できないようなので、
AppDomain を使用してみる事にしました。
( 逐一解放しなければいけないのか? についてはスルーしてください(汗 )
そこで、ネット等で調べてみるとだいたい以下の手順で行えば良い事は分かったのですが、

1. AppDomain 作成
2. 呼び出しDLL インスタンス作成
3. メソッド実行
4. AppDomain アンロード

3と4の間、つまり メソッドの実行終了を待って
AppDomainをアンロードしなければならないと思うのですが、
私が見たどのサンプルも待っていないように見えました。


現状、私が直面している問題は、
呼ぶDLLにはフォームがありまして、3.メソッド実行 で実行される
クラスのメソッドに、フォームをShow() する処理があります。
このフォームはモードレスフォームで、
呼び出し元のアプリに制御を戻す?ようにしたいのです。
(DLLではなくExeではダメなのか?についてはスルーでお願いします)

当然の事ながら、上記手順ではフォームは一瞬で消えて終了します。


今回はモードレスフォームという特殊?な例かもしれませんが、
一般的にメソッドの実行に時間がかかるような場合でも
上記手順(コーディング)で問題ないのでしょうか?

また、メソッドの終了が検知出来るとして、
作成したAppDomainを保持しておいて後でアンロードする事は可能でしょうか?

よろしくお願いします。
引用返信 編集キー/
■64130 / inTopicNo.2)  Re[1]: AppDomainのアンロードタイミング
□投稿者/ howling (56回)-(2012/11/08(Thu) 15:00:42)
SS さん

んー…読解力が足りないようで、3回読んでも8割くらいしか理解できてない気がしますが…。

動的にDLLを読み込む必要性がまず謎ですが…(まぁ抑えておいて)
AppDomainについてとりあえず調べてみました。
私もよくわからないのですが、
とりあえずCreateする場合(よくやるなぁと思いますが)、確かにその手順で間違いはなさそうです。
また、アンロードする時に、アンロードしちゃダメな場合は例外が発生するようです。

CannotUnloadAppDomainException が発生するとMSDNに書いてある
http://msdn.microsoft.com/ja-jp/library/c5b8a8f9(v=vs.80).aspx

じゃあ特に問題無いじゃん、と思ったのですが、
みんなが処理を待っていないというのは、同じスレッドから呼び出しをしているからでは?
マルチスレッドにはならないと思うので、処理が終わったら初めて戻ってくる仕組みだと思いました。
で、モードレスダイアログが消えてしまうのは、アンロード処理で内容も全部アンロードされてるからなのかなぁと。

AppDomain自体はそのダイアログが消えてから解放というのでも大丈夫そうといえば大丈夫そうですが、
そもそもそれってモーダルダイアログでやって即アンロードするのが普通なんじゃないか?と思ったけどこれも抑えておいて…(苦笑
まぁ大丈夫そうです。

C#でなんでそんなことするねん、と思いますがね…とだけは言っておきます。抑えずに(笑


引用返信 編集キー/
■64133 / inTopicNo.3)  Re[1]: AppDomainのアンロードタイミング
□投稿者/ とっちゃん (16回)-(2012/11/08(Thu) 15:39:01)
とっちゃん さんの Web サイト
No64129 (SS さん) に返信

> 話の発端は、DLLを動的に呼び出して使用したい という事から始まりまして、
いわゆるアドイン(Addin/Addon/Plugin)の類ですかね?
まぁ、この部分はあまり重要ではないかと。

> 3と4の間、つまり メソッドの実行終了を待って
> AppDomainをアンロードしなければならないと思うのですが、
> 私が見たどのサンプルも待っていないように見えました。
>
そのサンプルでのロードしたDLLの呼び出しは同期メソッドの呼び出しだけではありませんか?
その場合、メソッドから帰ってきた時点で、オブジェクトのインスタンスは解放可能な状態になり
AppDomainのアンロードに伴うインスタンスの解放処理が問題なく行えているだけではないでしょうか?

>
> 現状、私が直面している問題は、
> 呼ぶDLLにはフォームがありまして、3.メソッド実行 で実行される
> クラスのメソッドに、フォームをShow() する処理があります。
> このフォームはモードレスフォームで、
> 呼び出し元のアプリに制御を戻す?ようにしたいのです。
> (DLLではなくExeではダメなのか?についてはスルーでお願いします)
>
> 当然の事ながら、上記手順ではフォームは一瞬で消えて終了します。
>
そうですね。Show()から戻ってきたタイミングでは、

そのオブジェクトのインスタンスは「利用している最中の状態」です。
なので、まだオブジェクト(実際はUnmanagedなデータを含むので、きちんと解放処理がされる必要がある)の
インスタンスエリアがなくなってしまうのが問題があります。

>
> 今回はモードレスフォームという特殊?な例かもしれませんが、
> 一般的にメソッドの実行に時間がかかるような場合でも
> 上記手順(コーディング)で問題ないのでしょうか?
>
現状からもわかるように、問題があります。

ここでいう、「時間がかかる」が何を指しているかわかりませんが
AppDomainのアンロードはそのAppDomainに所属するすべてのインスタンスが
解放されても問題がない状態でアンロードする必要があります。

そうしないと、意図しない解放処理が行われることになります。


> また、メソッドの終了が検知出来るとして、
> 作成したAppDomainを保持しておいて後でアンロードする事は可能でしょうか?
>
可能です。
System.AppDomain クラスオブジェクトですので、ローカルな変数ではなく、クラスメンバーとして用意してやればOKですよ。

引用返信 編集キー/
■64135 / inTopicNo.4)  Re[2]: AppDomainのアンロードタイミング
□投稿者/ SS (1回)-(2012/11/08(Thu) 17:46:01)
howling さん
とっちゃん さん

返信ありがとうございます。

お二人の仰る通り、同一スレッド?同期メソッド? であると思います。
メソッドから帰って来た(メソッドの次行に記述した処理が流れた)という事は、
処理が終わった(アンロード出来る状態になった)という事ですよね?

確かに良く考えれば、お二人の仰る通り別スレッドでメソッドが流れる訳ではないですもんね。
アンロードが即時実行されてしまうのでは?などど勘違いをしていました。
納得です。


>> また、メソッドの終了が検知出来るとして、
>> 作成したAppDomainを保持しておいて後でアンロードする事は可能でしょうか?
>>
> 可能です。
> System.AppDomain クラスオブジェクトですので、ローカルな変数ではなく、クラスメンバーとして用意してやればOKですよ。
おお、出来ますか?!
では後はメソッドの終了(私の今回の場合DLL内のフォームのクローズ?)が検知出来れば良いのですが…。
インターフェースにイベント定義して拾えば良いのでしょうか?
でもイベントだと結局 Raise元へ戻ってから終了ですよね?
完全なDLLの終了は、やはり検知不可能でしょうか?

何か変なこと言ってたらご指摘お願いします。

引用返信 編集キー/
■64136 / inTopicNo.5)  Re[3]: AppDomainのアンロードタイミング
□投稿者/ howling (58回)-(2012/11/08(Thu) 17:58:16)
SSさん

> おお、出来ますか?!
> では後はメソッドの終了(私の今回の場合DLL内のフォームのクローズ?)が検知出来れば良いのですが…。
> インターフェースにイベント定義して拾えば良いのでしょうか?
> でもイベントだと結局 Raise元へ戻ってから終了ですよね?
> 完全なDLLの終了は、やはり検知不可能でしょうか?

少なくとも、フォームの終了検知はできるんじゃないかなぁ…?
DLL側に自分自身のインターフェースクラスを公開してやって、
DLL側メソッドの引数にそのインターフェースクラスのオブジェクトを指定。
DLLメソッド呼び出しに自分自身を渡してやって、そこで呼んでもらうって感じでいけるんじゃないかなと。
インターフェースクラスは、

public interface ICallObjectInterface
{
void RaiseCloseOKFlag();
}

ぐらいの非常に単純なもので、
ここで言うRaiseCloseOKFlagを呼んでもらう感じかなーと。

で、実装側は、

public void RaiseCloseOKFlag()
{
//ここでアンロードをtry〜catchでしてみて、例外が出たら後でもっかいやるとか。
}

かなーと。

適当な事書いてるんで、実際どうだかわかりませんが…。
引用返信 編集キー/
■64139 / inTopicNo.6)  Re[4]: AppDomainのアンロードタイミング
□投稿者/ SS (2回)-(2012/11/08(Thu) 19:38:32)
howling さん
とっちゃん さん

一応、インターフェースを作成してやってみました。
1. AppDomain 作成
2. DLLのクラスのインスタンス作成
3. メソッド実行
4. 呼び出し元のローカルクラス内のAppDomain型変数にAppDomainを保持
5. イベント取得
  DLL内のフォームのクローズイベント(Closed)を
  DLL内のクラス(フォームをShowしているクラス)で拾い、インターフェースのイベントを Raiseし、
  呼び出し元で拾う
6. 呼び出し元の上記イベント内で 4.のAppDomainをアンロード
こんな感じです。ですが、

保持した AppDomain は、
System.Runtime.Remoting.Proxies.__TransparentProxy = 'Class __TransparentProxy' に変換できません。

の状態になり、

スレッドを実行中のアプリケーション ドメインは、アンロードされています。

のエラーとなってしまいました。
これは…アンロードを実行した後にイベントのRaise元(DLL)に処理が戻れなくて出ているのでしょうか?

やはり"AppDomainがアンロード可能な状態になった事"を感知する事は出来ないのでしょうか…。
引用返信 編集キー/
■64140 / inTopicNo.7)  Re[5]: AppDomainのアンロードタイミング
□投稿者/ howling (61回)-(2012/11/08(Thu) 20:26:34)
むむむ???

モーダレスダイアログなら、そもそも戻る処理は必要無くなる気がするのですが…。
それ以前にどこかで勝手にアンロードされている感じがしますね。
自分でなのか、もしくはどこかで抜けてしまうといけないのか…。
GCに取られてしまった場合などは不明ですが、メンバで持つなら問題ないですよね…。
うーん…謎ですねぇ。いわゆる、newとdeleteの関係だと思っていたのですが。

暇な時間にちょっと調べてみます。
とっちゃんさんが何かしてくれるかもしれません、と期待のまなざしをw
答えられずすみません^^;
引用返信 編集キー/
■64141 / inTopicNo.8)  Re[5]: AppDomainのアンロードタイミング
□投稿者/ Azulean (62回)-(2012/11/08(Thu) 22:37:53)
No64139 (SS さん) に返信
> これは…アンロードを実行した後にイベントのRaise元(DLL)に処理が戻れなくて出ているのでしょうか?

その推測は当たっていそうですが、本当にそうかまでの裏付けはとっていません。
とりあえず、SynchronizationContext.Post などでタイミングをずらしてやれば避けられるようですが、それが安全かどうかまでは
わかりません、すみません。

private AppDomain _appDomain;
private SynchronizationContext _context;

private void button1_Click(object sender, EventArgs e)
{
    _appDomain = AppDomain.CreateDomain("test");
    _appDomain.Load("FormLib");

    var obj = _appDomain.CreateInstance("FormLib", "FormLib.TestForm");
    IForm form = (IForm)obj.Unwrap();
    form.FormIsClosed += new EventHandler(form_FormIsClosed);
    form.Show();

    _context = SynchronizationContext.Current;
}

void form_FormIsClosed(object sender, EventArgs e)
{
    _context.Post(o => AppDomain.Unload(_appDomain), null);
}

引用返信 編集キー/
■64149 / inTopicNo.9)  Re[6]: AppDomainのアンロードタイミング
□投稿者/ SS (2回)-(2012/11/09(Fri) 11:27:07)
Azulean さん

返信ありがとうございます。

SynchronizationContext については初見でした。
よく分からないまま、提示して下さったコードを基にやってみようと思ったのですが、

_context.Post(o => AppDomain.Unload(_appDomain), null);

の、"o => AppDomain〜" の部分が分かりません。
"o" とは "=>" とは どういった意味なのでしょうか?
ざっとググっただけですが、調べ上げられませんでした。

ちなみに…、すいませんが VB.NET です。
C# のコードは読めますし、VB.NETへの変換も頑張れば出来ますが、
この一文は分かりませんでした。

よろしくお願いします。
引用返信 編集キー/
■64151 / inTopicNo.10)  Re[7]: AppDomainのアンロードタイミング
□投稿者/ howling (62回)-(2012/11/09(Fri) 11:57:53)
2012/11/09(Fri) 12:02:04 編集(投稿者)

あー…ラムダ式で調べてみてください。
説明も長くなると思いますので…(苦笑
oは…context.Postメソッドの引数なんでしょうね…。
ラムダ式について簡潔に説明できればいいのですが、
そこまで至れていないと思いますし、嘘教えてもなぁ…。
引用返信 編集キー/
■64159 / inTopicNo.11)  Re[8]: AppDomainのアンロードタイミング
□投稿者/ SS (3回)-(2012/11/09(Fri) 13:26:24)
howling さん

補足ありがとうございます。

SynchronizationContext の MSDN のヘルプと、
C#, VB.NET 両方のラムダ式の MSDN のヘルプを見てみましたが…、
・_context.Post() の第一引数が SendOrPostCallBack(Object)デリゲートである
・"o => AppDomain.Un〜" の意味は、"o" を "AppDomain.Un〜" に代入する?

という事は分かりました(様な気がしてます)が、
VB.NET でどう記述するのかまでは、たどり着けていません。
なんかもう少しで ピン と来そうなんですが…。

あ、でもやっぱり "o" って何だろう?
引用返信 編集キー/
■64160 / inTopicNo.12)  Re[6]: AppDomainのアンロードタイミング
□投稿者/ とっちゃん (17回)-(2012/11/09(Fri) 13:32:10)
とっちゃん さんの Web サイト
No64151 (howling さん) に返信
> 2012/11/09(Fri) 12:02:04 編集(投稿者)
>
> あー…ラムダ式で調べてみてください。
> 説明も長くなると思いますので…(苦笑
> oは…context.Postメソッドの引数なんでしょうね…。
> ラムダ式について簡潔に説明できればいいのですが、
> そこまで至れていないと思いますし、嘘教えてもなぁ…。

すんません。VBについてはどうにか読める程度の知識しかないので、VB->C#はできてもその逆はできないですw

呼ばれたほうの、解放のタイミングですが、
SynchronizationContext を使う方法(Azuleanさんが書いてる方法)だと、基本的には即座に解放となります。
頻繁に利用するものではないのであれば、この方法でもOKです。

SynchronizationContextの使い方などはあらかじめリファレンスを読んでおくことをお勧めします。
それほど難しいものではありません。ただ、知ってると結構便利なものものがいろいろあります。
SynchronizationContext.Post は従来の PostMessage による非同期処理と同じですし
Send は SendMessage による同期処理と同じです。
Wait 系統は WaitForMultipleObjects(実装はMsgWaitForMultipleObjectsだと思います) の .NET Framework ラッパーですし...
大半がWin32とのやり取り用なのであまり一般的ではないともいえますけどw


もう一つは、タイマーなどで時間間隔をあけて解放するやり方もあります。

AppDomainの作成、解放処理は、それなりに時間がかかります(実質EXEを起動するのと同様の処理をするため)。

また、ロードしたアセンブリがアンロードされるとそのコードのJITイメージもクリーンナップされます。
すでにロード済みのものを使う&1度実行したコードをもう一度実行する場合の実行時間はJIT処理がないため
高速になります。

同じものをどの程度使うか?やすぐにアンロードされなくてもいいのか?という部分は実装依存なので何とも言えませんが

うまく作れば、AppDomain の構築の実行コストや新規アセンブリのロードコストなどが低減できます。

引用返信 編集キー/
■64161 / inTopicNo.13)  Re[7]: AppDomainのアンロードタイミング
□投稿者/ 魔界の仮面弁士 (87回)-(2012/11/09(Fri) 13:47:14)
No64149 (SS さん) に返信
> _context.Post(o => AppDomain.Unload(_appDomain), null);
> の、"o => AppDomain〜" の部分が分かりません。

上記を、Visual Basic 2010 以降の構文で書くと、

 _context.Post(Sub(o) AppDomain.Unload(_appDomain), Nothing)

となります。ラムダ式の引数の型を明示するなら

 _context.Post(Sub(ByVal o As Object) AppDomain.Unload(_appDomain), Nothing)

という感じです。


VB2008 以下の場合は、戻り値の無いラムダ式を使えないため、代わりに

 Private Sub SendOrPost(ByVal state As Object)
  AppDomain.Unload(_AppDomain)
 End Sub

のようなメソッドを用意しておいて、

 _context.Post(AddressOf SendOrPost, Nothing)

のようにデリゲートで指定することになります。
デリゲートの型も指定する場合はこんな感じ。

 _context.Post(New SendOrPostCallback(AddressOf SendOrPost), Nothing)
引用返信 編集キー/
■64163 / inTopicNo.14)  Re[9]: AppDomainのアンロードタイミング
□投稿者/ SS (4回)-(2012/11/09(Fri) 14:59:15)
とっちゃん さん

SynchronizationContext
WaitForMultipleObjects

うーん…、まだ知らない事が沢山ありますね。
時間を見つけて勉強したいと思います。


魔界の仮面弁士 さん

VB.NET変換ありがとうございますっ。
実は近い所まではたどり着いていたようでした。

おかげ様で文法エラーは無くなりましたが、やはり "o" が使われない?事に
疑問が残ります。

Sub(ByRef o As AppDomain) AppDomain.Unload(o)(_appDomain)

VB.NETのラムダ式のヘルプより上記のように記述するのかと思っていたのですが、
これだと AppDomain.Unload(o) の部分で "式はメソッドではありません。"
のエラーとなってしまいます。

また、ちなみに

Sub() AppDomain.Unload(_appDomain)

と書いても文法エラーにはなりませんでした。


なんか段々スレチな内容になってきた気がしないでもないですが…(汗

とりあえず実行してみました。 が、SynchronizationContext.Current が Nothing でした…。
インターフェースにSynchronizationContext型変数(プロパティ)を用意し、
DLL側で SynchronizationContext.Current をセットして、
呼び出し元で取得し、
SynchronizationContext.Post(Sub(o AS Object) AppDomain.Un〜...
の流れなのですが、SynchronizationContext の使い方がそもそも間違っているのでしょうか?
引用返信 編集キー/
■64164 / inTopicNo.15)  Re[10]: AppDomainのアンロードタイミング
□投稿者/ howling (66回)-(2012/11/09(Fri) 15:30:17)
2012/11/09(Fri) 16:24:47 編集(投稿者)

SSさん

oについてだけ答えておきますね。
oはObjectのoです。
で、実際のPostの引数は
SendOrPostCallbackデリゲートです。
public delegate void SendOrPostCallback(Object state);

本来デリゲートなので、SendOrPostCallbackと同じ形のメソッドを定義して、
そのメソッドを割り当て、なんてやらないといけないのですが、
(どのバージョンからでしたっけ?)ラムダ式で書けるようになりました。

//これは既に定義済みですので、実際には書かない
public delegate void SendOrPostCallback(Object state);

public void MySendOrPostCallback(Object obj)
{
//Postにやって欲しいのはこういうこと
AppDomain.Unload((AppDomain)obj);
}

SendOrPostCallback delPost = MySendOrPostCallback;
_context.Post(delPost, _appDomain);

↓ラムダ式にする

_context.Post(o => AppDomain.Unload(_appDomain), null);
//↑では、Unloadに直接_appDomainを指定しているため、o = Object objは何でもいいのでnullとなっている

というわけで、
SendOrPostCallbackの引数に当たる物がObject型のoということになりますね。

…と、書いたのはいいんですが、ラムダ式と匿名メソッドとデリゲートについての知識が浅すぎた…。
ホント、勉強になります。>Azuleanさん
一回投稿しただけに、冷や汗かいた…(苦笑
わかってないだけに、普段使ってないんですが。

ではでは。
引用返信 編集キー/
■64166 / inTopicNo.16)  Re[10]: AppDomainのアンロードタイミング
□投稿者/ とっちゃん (18回)-(2012/11/09(Fri) 15:54:06)
とっちゃん さんの Web サイト
No64163 (SS さん) に返信
> WaitForMultipleObjects
>
こちらは、Win32 API なので、世の中にはそういうものがあるらしいよ。。。という程度で十分です。

> うーん…、まだ知らない事が沢山ありますね。
> 時間を見つけて勉強したいと思います。
>
必要な時が来たらその時また勉強すればよいかとw


> おかげ様で文法エラーは無くなりましたが、やはり "o" が使われない?事に
> 疑問が残ります。

o は、Post の2個目のパラメータです。
どうしても使う形で実装したいのであれば

_context.Post( Sub(o) AppDomain.Unload( CType( o, AppDomain ) ), _appDomain )

とすれば、利用されますよ。
ラムダ式(というかこの場合無名デリゲートかな?)が、わかりにくいという場合は、
64161 で 魔界の仮面弁士 さんが書いてるように、通常のメソッドとして用意してやればよいでしょう。



> とりあえず実行してみました。 が、SynchronizationContext.Current が Nothing でした…。
> インターフェースにSynchronizationContext型変数(プロパティ)を用意し、
> DLL側で SynchronizationContext.Current をセットして、
> 呼び出し元で取得し、
> SynchronizationContext.Post(Sub(o AS Object) AppDomain.Un〜...
> の流れなのですが、SynchronizationContext の使い方がそもそも間違っているのでしょうか?

SynchronizationContext.Current が Nothing というのはおかしい気がするな。。。

この辺りは具体的なソースを見ないと助言できない可能性が高そうです。

引用返信 編集キー/
■64170 / inTopicNo.17)  Re[11]: AppDomainのアンロードタイミング
□投稿者/ SS (5回)-(2012/11/09(Fri) 17:00:01)
とっちゃん さん

"o" の件、分かりました。 ありがとうございます。
まさか第二引数だとは…、やはり理解出来てませんでしたね。お恥ずかしい。


ソースですが…、長くてすいません。

Public Class DLLCommon
    'イベント
    ' フォームのクローズ
    Public Delegate Sub DllFrmClose()
    ' DLLの終了
    Public Delegate Sub DllEnd(ByVal dmin As Integer)


    'インターフェース
    Public Interface IDll
        ReadOnly Property SyncContxt As System.Threading.SynchronizationContext
        Event MyEnd As DLLCommon.DllEnd
        Sub Start(ByVal PG As PGInfo)
    End Interface
End Class


'呼び出しDLL (HogeDLLプロジェクト) DLLCommon参照
Public Class HogeDLL
    Inherits MarshalByRefObject
    Implements DLLCommon.IDll

    'SynchronizationContextプロパティ
    Private _SynchronizationContext As System.Threading.SynchronizationContext = Nothing

    Public ReadOnly Property SyncContext As System.Threading.SynchronizationContext _
        Implements DLLCommon.IDll.SyncContxt
        Get
            Return Me._SynchronizationContext
        End Get
    End Property

    'メソッド
    Public Sub Start() Implements DLLCommon.IDll.Start
        Me._SynchronizationContext = System.Threading.SynchronizationContext.Current
→→    ※ ここで右辺の SynchronizationContext.Current が Nothing でした。

        'Formクラスのインスタンスを作成する
        Dim frm As New Form1()
        AddHandler frm.MyClose, AddressOf FrmClose

        'モードレスフォームとして表示する
        frm.Show()

    End Sub

    'FormClosedイベント 取得
    Public Sub FrmClose()
        RaiseEvent MyEnd(AppDomain.CurrentDomain.Id)
    End Sub

    'DLL終了イベント定義
    Public Event MyEnd As DLLCommon.DllEnd Implements DLLCommon.IDll.MyEnd
End Class


'DLLを呼ぶ側 (HogeExeプロジェクト) DLLCommon参照
Public Class HogeExe
    'AppDomain 保持用クラス
    Private Class domainTemp
        Public _AppDomain As AppDomain
        Public _SynchroContxt As System.Threading.SynchronizationContext
    End Class
    Private _AppDomainTemp As domainTemp = Nothing

    '実処理
    Private Sub DllExecute()
        Try
            Dim apd As AppDomain = AppDomain.CreateDomain(HogeDLL)
            Dim dllI As DLLCommon.IDll _
                = CType(apd.CreateInstanceAndUnwrap("HogeDLL", "HogeDLL.HogeDLL"), DLLCommon.IDll)
            AddHandler dllI.MyEnd, AddressOf Dll_End

            dllI.Start()

            If Me._AppDomainTemp Is Nothing Then Me._AppDomainTemp = New domainTemp()
            Me._AppDomainTemp._AppDomain = apd
            Me._AppDomainTemp._SynchroContxt = dllI.SyncContxt
        Catch

        End Try
    End Sub

    'DLL終了イベント
    Private Sub Dll_End(ByVal dmin As Integer)
        Try
            'AppDomain.Unload(Me._AppDomainTemp._AppDomain)
            Me._AppDomainTemp._SynchroContxt.Post(Sub(o) AppDomain.Unload(Me._AppDomainTemp._AppDomain), Nothing)
        Catch ex As Exception

        End Try
    End Sub
End Class

引用返信 編集キー/
■64174 / inTopicNo.18)  Re[12]: AppDomainのアンロードタイミング
□投稿者/ とっちゃん (19回)-(2012/11/09(Fri) 17:52:47)
とっちゃん さんの Web サイト
No64170 (SS さん) に返信
> "o" の件、分かりました。 ありがとうございます。
> まさか第二引数だとは…、やはり理解出来てませんでしたね。お恥ずかしい。
>
えっと。。。新しいクラスやメソッドなどを見つけて
使い方をチェックする際には、まず最初にリファレンスを
見るようにしましょう。

掲示板や人に聞いた場合、間違っていなくとも、必要十分な説明をしない場合もあります。



>ソース
ふむ。。。DLL側で用意する、SynchronizationContext.Current がNothingなんですね。
AppDomain の関係かな?

EXEのほうで
Me._AppDomainTemp._SynchroContxt = SyncrhonizationContext.Current
としてみてはどうでしょうか?
というか、今回の場合はこの方がいいのですが。

必要な SynchronizationContext は、作成したAppDomainのものではなく
呼び出し元のDefaultAppDomainのSynchronizationContextです。

むしろ任意のタイミングで解放されてしまうDLL側で用意してしまうと
異なるAppDomainに所属するものを引き出してしまう可能性があり得策とは言えない状況となります。

引用返信 編集キー/
■64177 / inTopicNo.19)  Re[13]: AppDomainのアンロードタイミング
□投稿者/ SS (6回)-(2012/11/09(Fri) 18:36:03)
とっちゃん さん

>>まさか第二引数だとは…、やはり理解出来てませんでしたね。お恥ずかしい。
>>
> えっと。。。新しいクラスやメソッドなどを見つけて
> 使い方をチェックする際には、まず最初にリファレンスを
> 見るようにしましょう。
うぅ、痛いご指摘ありがとうございますっ。 MSDNのヘルプは一応見たんですけどね。
言い訳するならば、ラムダ式に惑わされた感があるんです。 ←あぁ見苦しい(泣

> 必要な SynchronizationContext は、作成したAppDomainのものではなく
> 呼び出し元のDefaultAppDomainのSynchronizationContextです。
そうなんですか! そうなんですね…。
実はここら辺はコーディングしていて迷ったんですよ。ホントですよ。
でも Azulean さん のサンプルから、
Form.Show() している所の SynchronizationContext.Current が必要なのでは?と勝手に思った次第です。
正に SynchronizationContext の使い方を分かってませんでしたね。

とりあえず、インターフェースから SynchronizationContext を外し、
Exe側の Dll_End イベントの中を
 SynchronizationContext.Current.Post(Sub(o) AppDomain.Unload(Me._AppDomainTemp._AppDomain), Nothing)
に変えてやってみました。
が、やっぱり Nothing でした。

うーん…。
引用返信 編集キー/
■64180 / inTopicNo.20)  Re[14]: AppDomainのアンロードタイミング
 
□投稿者/ Azulean (63回)-(2012/11/10(Sat) 00:30:02)
2012/11/10(Sat) 00:33:35 編集(投稿者)

VB.NET だったことを見落としてお騒がせしました。orz

No64177 (SS さん) に返信
> でも Azulean さん のサンプルから、
> Form.Show() している所の SynchronizationContext.Current が必要なのでは?と勝手に思った次第です。
> 正に SynchronizationContext の使い方を分かってませんでしたね。

Show メソッドは Form の Show メソッドと兼ねさせていてわかりづらいですが、インターフェースの呼び出している場所、つまり元の AppDomain の SynchronaizationContext.Current が必要だったわけです。

> とりあえず、インターフェースから SynchronizationContext を外し、
> Exe側の Dll_End イベントの中を
>  SynchronizationContext.Current.Post(Sub(o) AppDomain.Unload(Me._AppDomainTemp._AppDomain), Nothing)
> に変えてやってみました。
> が、やっぱり Nothing でした。

その原理まではきちんと追っていませんが、そうなります。
なので、元の AppDomain での SynchronizationContext.Current をメンバー変数で覚えておき、終了後に呼び出されるイベントで使います。
なお、私のサンプルにおける前提として、AppDomain 構築のメソッド、厳密には SynchronizationContext.Current をフィールド変数に覚えさせるのはメインスレッドです。
バックグラウンドスレッドでは null(Nothing) になりますので注意。

// 前のサンプルにはそういった罠にはまった回避ということで、メンバー変数に入れておくというおまじないが説明なしで埋め込まれていました。

ちなみに、.NET 4 on Win8 で動くことを確認していますが、.NET 3.5 でセーフになるかどうかは見れていません。すみませんが…。
引用返信 編集キー/

次の20件>
トピック内ページ移動 / << 0 | 1 >>

管理者用

- Child Tree -