2011-04-04 103 views
0

因此,我一直試圖在使用visual studio測試環境的解決方案上設置測試。設置看起來像這樣:從Visual Studio測試環境中加載C++ DLL問題

Third party native library --> Managed C++ wrapper DLL --> C# project being tested 
             ^     ^
Foundation C# Projects -----------------|------------------------| 

有兩個理論上可互換的第三方庫和相應的包裝器。我需要能夠支持兩者。

所以,當我跑我的測試項目,這裏發生了什麼:

  1. 下測試該項目被成功加載
  2. 基礎C#項目獲得成功加載
  3. C++包裝器加載失敗;如果我使用包裝B,一切都很好。

用於包裝對異常調用堆棧是:

mscorlib.dll!System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(int errorCode) + 0x23 bytes 
msvcm90d.dll!<CrtImplementationDetails>::DoCallBackInDefaultDomain(int* function = 0x1018E1D0, bool cookie = false) Line 451 C++ 
[Native to Managed Transition] 
[Managed to Native Transition] 
Wrapper.dll!<CrtImplementationDetails>::DefaultDomain::Initialize() Line 284 C++ 
Wrapper.dll!<CrtImplementationDetails>::LanguageSupport::InitializeDefaultAppDomain() Line 519 C++ 
Wrapper.dll!<CrtImplementationDetails>::LanguageSupport::_Initialize() Line 730 C++ 
Wrapper.dll!<CrtImplementationDetails>::LanguageSupport::Initialize() Line 876 C++ 
[email protected]@$$FYMXXZ() Line 922 + 0x9 bytes C++ 
[Native to Managed Transition] 
[Managed to Native Transition] 
TestProject.dll!TestProject.TestProjectBase.TestProjectBase() Line 44 + 0x8 bytes C# 
[Native to Managed Transition] 
[Managed to Native Transition] 
TestProject.dll!TestProject.Test.Test() Line 17 + 0x8 bytes C# 
[Native to Managed Transition] 
[Managed to Native Transition] 
Microsoft.VisualStudio.QualityTools.Tips.UnitTest.Adapter.dll!Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestExecuter.CreateTestClassInstance() + 0x174 bytes 

我做了搜索這個網上,發現很多人詢問有關答覆的方式用很少的同一調用堆棧。

我看着ProcMon發生了什麼。我比較了加載包裝器A和包裝器B時發生的情況。在包裝器B完成加載之前,情況看起來或多或少相同。同樣,包裝器A莫名其妙地重新開始加載,這次試圖加載已經被測試項目加載的C#基礎DLL。但它沒有找到這些DLL,因爲DLL搜索路徑不包含測試文件夾(它在GAC和VSTestHost目錄中查找DLL)。

我注意到的另一件事是C#代碼沒有運行在默認的appdomain中。所以我的理論是,以下情況正在發生:

  1. 包裝A嘗試加載沙盒應用程序域。
  2. 發生某些事情使系統認爲Wrapper A未成功加載
  3. 系統嘗試在默認appdomain中加載Wrapper A.在這個AppDomain中,C#DLLs不會被加載,所以它會嘗試並且無法加載它們。

那麼,給出了什麼?第2步可能會發生什麼?什麼是可能的原因爲什麼包裝B會成功加載和包裝A不會?

如果您想知道包裝器A和包裝器B的不同之處:他們的項目具有相同的設置,並且它們支持相同的接口;否則它們完全不同。但是我想知道可能會導致這種情況的差異

我應該補充說,如果我將這些DLL添加到GAC或將它們複製到VSTestHost目錄,包裝器A將找到這些DLL並加載成功。不過,我仍然想知道發生了什麼問題。

+0

你的包裝A在做什麼?它是否像本機C++代碼一樣開始生命,而不是以後開始運行託管代碼? – 2011-04-04 19:02:11

回答

0

也許你的Wrapper A正在創建一個本地線程,稍後開始運行託管代碼。如果是這樣,然後嘗試this API

msclr::call_in_appdomain(appDomainId, func, object); 

這允許您指定的AppDomain該線程func應該運行在否則,當本地線程試圖運行託管代碼,線程使用的任何過程認爲默認的AppDomain。這會解釋你問題中的#1和#3點。因此,如果你的代碼被卡在錯誤的AppDomain中,它將不會找到任何依賴的DLL /程序集,因爲當前的工作目錄可能與你想要的不同。

編輯:運行的ProcessMonitor和設置過濾器來監視包裝A和其所有相關的,這將有助於確保所有的這些,當你運行你的測試項目實際上是越來越加載。

+0

DLL在加載時如何執行代碼?我知道有這樣的事情是DllMain,但有問題的DLL沒有。 – reveazure 2011-04-04 21:19:37

+0

我在[相關主題]中找到了一條評論(http://connect.microsoft.com/VisualStudio/feedback/details/316549/c-runtime-initialization-problem-causes-serialization-error-in-c-cli- project-ported-to-vs-2008):「我們發現這是由於我們的C++代碼中的靜態表的初始化引起的,這些靜態表使用了其他DLL中定義的函數,其中一些函數在C運行時被初始化之前被調用對於那個DLL ...一旦我們將這些表的初始化更改爲我們控制的順序,那麼錯誤就消失了。「這鈴響嗎?我怎麼能這樣做? – reveazure 2011-04-04 21:47:48

+0

我知道如何做到這一點的唯一方法是如果你有本地庫的源代碼。在這種情況下,您可以控制靜態對象的創建方式/時間。例如,一個人想避免在構造函數中做任何事情。你必須確保靜態初始化的工作量少很多,或者使用lazy-init或者其他的東西。 – 2011-04-04 22:06:47