- - PR -
System.Reflection.Assembly.LoadFileでファイルが開けなくなる
1
投稿者 | 投稿内容 | ||||
---|---|---|---|---|---|
|
投稿日時: 2009-02-04 17:42
連続質問ですみません。
exeファイルのマニフェスト情報を取得するために System.Reflection.Assemblyをつかってファイルオープンしたのですが プログラムが起動している間、オープンしたファイルがつかまれてしまいます。 clsGuid------------------------------------------------------------ 'マニフェストGUID取得のためにファイルをオープン Dim strGuid As String strGuid = System.Reflection.Assembly.LoadFile(FileName).ManifestModule.ModuleVersionId.ToString '↑この処理はクラスで行っている FileWiteForm-------------------------------------------------------- '別画面で同じファイルをオープンしようとすると、エラーが発生します。 Dim Fs As New System.IO.FileStream(FileName, IO.FileMode.Create, IO.FileAccess.Write) '←エラー発生 ------------------------------------------------------------ 原因はSystem.Reflection.Assembly.LoadFileでファイルがつかまれているからですが、 処理を行っているクラスをNothingにしてもファイルはつかまれたままになっています。 (Nothigが適当なのかよくわかりませんが) いろいろと調べたのですが System.Reflection.Assembly.LoadFileで読み込んだファイルを解放する方法がわかりません。 「開発環境」 Microsoft Visual Studio 2008 Microsoft .NET Framework 3.5 Professional Edition Microsoft Visual Basic 2008 どなたかご存知の方がいらっしゃいましたら宜しくお願いします。 [ メッセージ編集済み 編集者: ブリンク 編集日時 2009-02-04 17:42 ] [ メッセージ編集済み 編集者: ブリンク 編集日時 2009-02-04 17:44 ] | ||||
|
投稿日時: 2009-02-04 18:07
一度ロードしたアセンブリは、アプリケーション ドメインごとアンロードしないとダメだったかと思います (記憶あいまい)。 _________________ C# と VB.NET の入門サイト じゃんぬねっと日誌 | ||||
|
投稿日時: 2009-02-04 19:16
じゃんぬねっとさん
さっそくのご報告ありがとうございます。
参考になる情報ありがとうございます。 他のロード方法を試したり調べたりしているのですが、今のところ解決の糸口がつかめておりません。 やりたいことは、 指定したファイルのマニフェスト情報のModuleVersionId(MVID:モジュールバージョンID)の取得と更新 なのですが、 もうひとつの方向として考えているのは System.Reflection.Assembly.LoadFileを使わずにMVIDを取得できないか ということです。 最初にファイルをコピーして、そこからMVIDだけを読み取るとか バイナリモードで直接ファイルを開き、 MVID直後に書かれている”D5 0A 3A 03 20 00 01 03”を検索してみようとか くだらないアイデアは思いつくのですが。 今考えている候補はとりあえず以下のようなものです。 ○System.Reflection.AssemblyをつかわずにMVIDを取得できないか? ○一度ファイル情報を自分の中に取り込み、ファイルではなく、 データとしてSystem.Reflection.Assemblyから開くことはできないか? 逆アセンブリツールに[Reflector.exe]というものがあり http://www.red-gate.com/products/reflector/ このツールは読み込んだファイルをつかまずにマニフェスト情報を取得しています。 一応、可能なことは可能なようなんです。(当然VB.Netでは作られていないと思います) | ||||
|
投稿日時: 2009-02-04 19:17
AppDomain.CreateDomainを使って
AppDomainを作成し、そこにEXEアセンブリをLoadする。 用が済んだら、作成したAppDomainをUnloadすると いいです。 | ||||
|
投稿日時: 2009-02-04 19:55
やじゅさん
ご報告ありがとうございます。
AppDomainがよくわからず、サンプルをつかってみたのですが 申し訳ないのですが、処理イメージがつかめませんでした。 よくわからないのですが、 >>そこにEXEアセンブリをLoadする ということはLoadするまえにLoad可能なアセンブリを取得するようなイメージしか思いつかなかったのですが。 起動されていないexeファイル名を指定してEXEアセンブリをロードすることは可能なのでしょうか。 おしえてちゃん、で申し訳ないのですが、 どなたか参考情報をご存知の方がいらっしゃいましたら宜しくお願いします。 | ||||
|
投稿日時: 2009-02-05 12:25
これかな
http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=46665&forum=7 | ||||
|
投稿日時: 2009-02-05 18:26
まるくさん ご報告ありがとうございます。まさにこちらの内容でした。 過去ログにあったようで、自分の調査が甘いためみなさんに手間をとらせてしまい 申し訳ありませんでした。 "DLL 解放"で調べたらすぐに検索できたようです。 じゃんぬねっとさん、やじゅさん、まるくさん お手数をおかけして申し訳ありませんでした。ありがとうございました。 [ メッセージ編集済み 編集者: ブリンク 編集日時 2009-02-05 18:28 ] | ||||
|
投稿日時: 2009-02-10 17:54
DLLを動的に使用することには成功したのですが、複雑という理由から実装しないことになってしまいました。
参考のため、まるくさんに教えて頂いた記事を参考にMVIDを動的に取得する方法をまとめてみました。 (まだ他に方法があるかもしれないのでもう少し調査します) 実行用DLLとインターフェース用のDLLを用意することと、各DLLの参照設定があるのがポイントです。 DLLのアセンブリ名やクラス名やファンクション名が入り乱れるので理解するのに時間がかかりました。 必要なもの MVID取得を実行するDLL インターフェース用DLL 実際に呼び出すEXE *参照設定があるので、上から順につくってください ==インターフェース用DLL== ソリューション(プロジェクト)名:TestInterface.sln(vbproj)(仮) クラス名:clsInterface(仮) --TestInterface.sln-- Public Class clsInterface Public Interface PublicInterFace1 Function GetMVID(ByVal byFileName As String, ByRef MVIDbinary() As Byte) As Boolean End Interface End Class →ビルドしてTestInterface.dllを作る ==MVID取得用DLL== ソリューション(プロジェクト)名:GetMVID.sln(vbproj)(仮) クラス名:clsGetMVID(仮) TestInterface.dll(インターフェース用DLL)を参照設定に追加する '↓シリアライズが必要 <Serializable()> _ Public Class clsGetMVID Inherits MarshalByRefObject 'アプリケーションドメイン境界を超えてオブジェクトにアクセス Implements MVIDInterface.clsInterface.PublicInterFace1 'インターフェースの継承 Public Function GetMVID(ByVal byFileName As String, ByRef MVIDbinary() As Byte) As Boolean Implements MVIDInterface.clsInterface.PublicInterFace1.GetMVID Try System.Reflection.Assembly.LoadFile(IO.Path.GetFullPath(byFileName)).ManifestModule.ModuleVersionId.ToByteArray.CopyTo(MVIDbinary, 0) Catch ex As Exception Return False End Try Return True End Function End Class ==実際に呼び出すEXE== TestInterface.dllとTestInterface.dllを参照設定に追加する Private Sub GetMVIDtest() Dim hanlde As System.Runtime.Remoting.ObjectHandle 'ドメインを生成 Dim ad As AppDomain = AppDomain.CreateDomain("") Dim MVIDBinary(15) As Byte Dim FineName As String = "MVIDを取得したいexe(フルパス)" 'ハンドルにインスタンス生成 ("関数実行DLL名","関数実行DLL名.クラス名") hanlde = ad.CreateInstance("GetMVID", "GetMVID.clsGetMVID") 'ラップされたオブジェクトをハンドルに取得し、インターフェースにキャスト DirectCast(hanlde.Unwrap, MVIDInterface.clsInterface.PublicInterFace1).GetMVID(byFineName, MVIDBinary) 'ドメイン解放前に実行するとエラーとなる '書き込みモードでファイルをオープンしてみる 'Dim Fs As New IO.FileStream(byFineName, IO.FileMode.Open, IO.FileAccess.Write) 'Fs.Close() 'ドメインを開放 AppDomain.Unload(ad) '書き込みモードでファイルをオープンしてみる Dim Fs As New IO.FileStream(byFineName, IO.FileMode.Open, IO.FileAccess.Write) Fs.Close() End End Sub ==================== |
1