2013-02-11 84 views
1

我需要關閉MSI文件的幫助。如何在閱讀或更新後關閉MSI文件

我正在製作MSI文件編輯器,在那裏我可以打開並更新msi文件。但問題是,當我試圖重新打開相同的文件(只是交叉檢查更新的MSI),它拋出一個錯誤

的openDatabase,DatabasePath,用於openmode

在這條線

database = installer.OpenDatabase(msiFile.FullName, MsiOpenDatabaseMode.msiOpenDatabaseModeTransact); 

所以,我相信它是因爲msi文件已經打開。任何人都可以幫助我關閉已打開的msi。

+0

你在'using()'語句中尋找'Close()'方法還是試圖封裝'database'變量? – Grx70 2013-02-11 09:52:06

+0

數據庫沒有close()方法,「using」語句不起作用。 – Bravo 2013-02-11 12:16:56

+0

我的回答將解決您的問題。如果沒有,你做錯了。 – 2013-02-11 13:53:47

回答

1

將數據庫設置爲變量爲null或者只是強制變量超出範圍。這應該釋放打開的句柄。

或者,您可能需要強制垃圾收集器運行以放棄句柄。 Best Practice for Forcing Garbage Collection in C#

+0

你爲什麼不把這個班級處理掉? – 2013-02-11 13:48:42

2

我猜你正在使用從WindowsInstaller.Installer COM對象生成的互操作庫。你不想這樣做。相信我這一個。請下載Windows安裝程序XML並查找SDK文件夾中的Microsoft.Deployment.WindodsInstaller程序集。該庫是部署工具基礎(DTF)的一部分,是與Windows Installer進行對接的黃金標準。

在DTF中,Database類實現了IDisposable接口,因此最優雅的方法是將其放入using語句中。

using(Database database = new Database(...)) 
{ 
// Do Stuff Here 
} 

一旦塊完成,.NET將自動調用Dispose()方法,並且這又會關閉數據庫並釋放非託管手柄。垃圾收集器隨後將被通知在稍後的非重要時間清理託管類。如果你不能調用Dispose(隱式或顯式),那麼在垃圾回收器開始清理之前,不會釋放未調整的資源,這不會像你所看到的那樣是一件好事。

+0

謝謝克里斯,我得到你想要解釋的。但現在,我已經使用interop庫實現了它。我想我會用你的方法,一旦我打算更新這個應用程序。再次感謝你的幫助。 – Bravo 2013-02-12 07:13:49

+0

我有這方面的經驗的船載。相信我,重構並不會那麼困難,而且你會處於更好的狀態。你等待的時間越長,你就會有更多的返工。 DTF使用比COM Interop更清潔的P/Invoke,並且還支持WPF Databinding和LINQ to MSI查詢。 – 2013-02-12 12:07:46

1

嘿斯蒂芬和克里斯托弗,這是我如何解決我的問題,使用你的寶貴意見。

我使用數據庫作爲全局變量,因爲我需要它在整個應用程序中的許多不同事務,所以在打開msi文件之前添加了這些行。

if (view != null) 
    { 
     System.Runtime.InteropServices.Marshal.FinalReleaseComObject(view); 
     view = null; 
    } 
if (database != null) 
    { 
     System.Runtime.InteropServices.Marshal.FinalReleaseComObject(database); 
     database = null; 
    } 
GC.Collect(); 

希望我的回答也幫助人們陷入同樣的​​情況。

0

你將不得不釋放每手柄,例如:

Database database = _installer.OpenDatabase(...); 
View view = database.OpenView(query); 
view.Execute(); 
Record record = view.Fetch(); 

Marshal.FinalReleaseComObject(record); 
view.Close(); 
Marshal.FinalReleaseComObject(record); 
Marshal.FinalReleaseComObject(database); 
record = null; 
view = null; 
database = null; 
GC.Collect(); 

做,在一個嘗試......終於,你應該是不錯的。