QA@IT
この質問・回答は、@ITの旧掲示板からインポートされたものです。

動的DLLの解放について

こんにちは!
VB.NET2005で、EXEから動的にロードしたDLLを解放する方法がわからないため、書き込みさせて頂きました。
①EXEを実行(EXEは24h常駐です。)
②動的にDLLをロード・実行し、DLLの処理終了(EXEは終了しない。)
③DLLのPGを改訂し、実行環境にコピーすると、エラーMSGがでる。
 「○○.dllをコピーできません。他の人またはプログラムによって使用されています。ファイルを使用している可能性があるプログラムを全て閉じてから、やり直してください。」

EXEを24h常駐させ、実行条件によって、ロードするDLLを変更したいと考えています。
今後業務要件によってDLLを改訂する可能性があります。

【EXE側のコード(動的DLLのロード・実行方法)】
Dim asm As Assembly
Dim objClass As New Object

'動的DLLのLoad
asm = Assembly.LoadFrom("ClassLibrary1.dll")

'インスタンス生成
objClass = asm.CreateInstance("ClassLibrary1.Class1")

'動的DLLのメソッド取得
Dim mi As MethodInfo = objClass.GetType.GetMethod("test")
'動的DLLのメソッド実行
Dim objInvoke As Object = mi.Invoke(objClass, Nothing)

'実行結果をTraceに出力
Trace.WriteLine(objInvoke.ToString)

'開放方法?

以上です。ご教授の方、よろしくお願いいたします。

質問者:ゆうか

回答

.NETは、Win32の時のFreelibrary関数(DLLを呼び出しプロセスの
アドレス空間から切り離す)のようなものはなく、一旦DLLを
ロードしたらプロセスを終了するまでメモリに残り続けます。

あえて動的な方法を調べると、CreateDomainでAppDomainを
作成し、そこにDLLをロードして実行、終了時にUnloadすると
いった方法となります。
[ メッセージ編集済み 編集者: やじゅ 編集日時 2008-10-07 13:08 ]

投稿者:やじゅ

編集 履歴 (0)

やじゅさん、返信ありがとうございます!
ドメインを作成?なんて、聞いた事が無かったので、
少し時間がかかってしまいました。

しかしUnloadした後も、解放されているはずのDLLに対して、
上書きコピーしましたが、エラーとなってしまいます。
初めての事でで、コードをチェックして頂けませんか?

よろしくお願いします。

【現在のコード】
Dim ad As AppDomain
Dim hanlde As System.Runtime.Remoting.ObjectHandle
Dim obj As Object

'ドメインを生成
ad = AppDomain.CreateDomain("TEST")

'インスタンス生成
hanlde = ad.CreateInstance("ClassLibrary1", "ClassLibrary1.Class1")

'ラップされたオブジェクトを取得
obj = hanlde.Unwrap

'DLLのメソッド実行
obj.test()

'ドメインを開放
AppDomain.Unload(ad)

  処理後、解放したDLLファイルをコピーするとエラーになってしまいます。

投稿者:ゆうか

編集 履歴 (0)

Unwrap メソッド呼び出したあとに、test メソッドを呼び出していますが、この時に遅延バインディングが発生してますよね?
ここで、ClassLibrary1.Class1 の型情報及び ClassLibrary1 アセンブリがロードされてるんじゃないかと思います。 (VB 詳しくないので推測です。)

アンロード対象でないアセンブリに test メソッドを持つインターフェイス (仮に IClass1) を予め用意しておいて、ClassLibrary1.Class1 に実装させてください。
そして、Unwrap で取得したオブジェクトは IClass1 にキャストして使用するようにします。
それでいけるはずです。

//追記
それと、Class1 に MarshalByRefObject クラスを忘れずに継承させてください。


C#と諸々

[ メッセージ編集済み 編集者: よこけん 編集日時 2008-10-06 16:05 ]
[ メッセージ編集済み 編集者: よこけん 編集日時 2008-10-06 16:08 ]

投稿者:よこけん

編集 履歴 (0)

お世話になってます。ゆうかです。
よこけんさん、返答ありがとうございます!!
できました〜☆

よこけんさんのほぼアドバイス通りでした。
今後どなたかが、動的にDLLを呼出して解放するソフト構築の参考に少しでもなれるよう、
簡単ですが纏めさせて頂きます。
コーディングレベルと参照設定内容です。

【メインコード(動的にDLLを呼ぶ側)】
 Dim ad As AppDomain
 Dim hanlde As System.Runtime.Remoting.ObjectHandle
Try 
  'ドメインを生成
  ad = AppDomain.CreateDomain("TEST")
  'インスタンス生成
  hanlde = ad.CreateInstance("ClassLibrary1", "ClassLibrary1.Class1")
  'ラップされたオブジェクトを取得し、IClass1インターフェースにキャスト
  CType(hanlde.Unwrap, IClass.IClass.IClass1).test()
 Finally
  'ドメインを開放
  AppDomain.Unload(ad)
End Try
 
  参照設定:IClassのDLL(IClass1インターフェースを持つDLL)

【IClass1インターフェースを持つクラス(DLL)のコード】
 'インターフェース実装
Public Class IClass
Public Interface IClass1
Function test() As Integer
End Interface
End Class

【ClassLibrary1を持つDLLのコード(今後動的に変更させるDLL)】
_ 'シリアライズを入れる必要がある。
Public Class Class1
Inherits MarshalByRefObject 'アプリケーションドメイン境界を超えてオブジェクトにアクセス
Implements IClass.IClass.IClass1 'インターフェースの継承
Public Function test() As Integer Implements IClass.IClass.IClass1.test
Return (任意値)
End Function
End Class

   参照設定:IClassのDLL(IClass1インターフェースを持つDLL)

投稿者:ゆうか

編集 履歴 (0)
ウォッチ

この質問への回答やコメントをメールでお知らせします。