2017-06-13 84 views
1

我必須更新一些舊應用程序(vb6),並且我一直使用COM interop在c#(Visual Studio 2010)中編寫新代碼。它的大部分工作正常,但我遇到了一個問題,我不知道是什麼導致它。BinaryFormatter Deserialisation在通過COM interop使用時拋出異常

我用下面的方法來出於某種原因執行對象

public static T CloneObject<T>(T source) 
    { 
     T destination = default(T); 

     if (!typeof(T).IsSerializable) 
     { 
      throw new ArgumentException("The type must be serialisable.", "source"); 
     } 

     if (Object.ReferenceEquals(source, null)) 
     { 
      return default(T); 
     } 

     using (Stream ms = new MemoryStream()) 
     { 
      BinaryFormatter formatter = new BinaryFormatter(); 
      formatter.Serialize(ms, source); 
      ms.Position = 0; 

      destination = (T)formatter.Deserialize(ms); 
     } 

     return destination; 
    } 

的深層副本誤碼出來的時候,反序列化函數被調用。它引發的異常是找不到代碼所在的程序集。

無法找到程序集「AssemblyBeingUsed,版本= 1.0.0.0,文化=中立,公鑰=空」

這是稍微有一些混亂我爲集已被訪問及其說它無法找到。格式化錯誤消息的代碼是同一個程序集的一部分!

以下是異常的堆棧跟蹤。

在System.Runtime.Serialization.Formatters.Binary.BinaryAssemblyInfo.GetAssembly() 在System.Runtime.Serialization.Formatters.Binary.ObjectReader.GetType(BinaryAssemblyInfo集信息,字符串名稱) 在System.Runtime。 Serialization.Formatters.Binary.ObjectMap..ctor(String objectName,String [] memberNames,BinaryTypeEnum [] binaryTypeEnumA,Object [] typeInformationA,Int32 [] memberAssemIds,ObjectReader objectReader,Int32 objectId,BinaryAssemblyInfo assemblyInfo,SizedArray assemIdToAssemblyTable) at System。 Runtime.Serialization.Formatters.Binary .__ BinaryParser.ReadObjectWithMapTyped(BinaryObjectWithMapTyped record) at System.Runtime.Serialization.Formatters.Binary .__ BinaryParser。 ReadObjectWithMapTyped(BinaryHeaderEnum binaryHeaderEnum) at System.Runtime.Serialization.Formatters.Binary .__ BinaryParser.Run() at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler,__BinaryParser serParser,Boolean fCheck,Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage) 在System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(流serializationStream,HeaderHandler處理器,布爾FCHECK,布爾isCrossAppDomain,IMethodCallMessage methodCallMessage)

編輯:更多有用的信息。

此功能從不直接從vb6調用。因爲它使用泛型,我敢肯定,這是不可能的。該函數是從vb6應用程序加載的表單中調用的。當從c#應用程序使用這個表單時,即使它執行完全相同的操作也沒有問題。

Visual Studio項目使用「Register for COM interop」選項,程序集作爲參考加載到vb6項目中。

編輯:從fuslogvw.exe

輸出的輸出從fuslogvw.exe示出了具有我感興趣的(BarcodeAndOperatorDatabase)的組件相關聯5名的條目。由於它們合併時間相當長,我已將所有輸出上傳到 this file

說實話,我不知道我在看什麼。有3個操作,我認爲當程序集綁定發生時對應於:

15:29:06:VB6應用程序啓動,操作成功。 (2條目):從程序集加載的表單(我認爲),操作失敗。這是令人困惑的表單加載正確,並可以交互。

15:29:50(2個條目):當調用CloneObject方法時操作失敗的按鈕單擊失敗。

+0

一個狂野的鏡頭,但你有多個目錄中的dll?如果你有這樣的暮光區行爲時,可以發現exe的2個相同的DLL副本。 –

+0

它看起來像解析一個整數有問題。輸入是否有空值?嘗試int?而不是int。整數是否有小數位(句點或逗號)? +/-和數字之間有空格嗎? VB在處理不同的數字格式方面稍微好一些。 – jdweng

+0

顯然不使用GAC,我聞到Assembly.LoadFile()鼠。 –

回答

1

TLDR版本:

系統找不到組件。解決方案是爲事件添加處理程序,並返回對所需程序集的引用。

長的版本:

堆棧跟蹤與System.Runtime.Serialization.Formatters.Binary.BinaryAssemblyInfo.GetAssembly()完成。如果你沿源代碼中的方法調用進一步向下,你會看到下面的代碼被調用。

internal static Assembly LoadAssemblyFromString(String assemblyName) { 
     // 
     // Try using the stringized assembly name to load from the fusion cache. 
     // 
     BCLDebug.Trace("SER", "[LoadAssemblyFromString]Looking for assembly: ", assemblyName); 
     Assembly found = Assembly.Load(assemblyName); 
     return found; 
    } 

這一呼籲的融合日誌:

*** Assembly Binder Log Entry (14/06/2017 @ 15:29:50) *** 

The operation failed. 
Bind result: hr = 0x80070002. The system cannot find the file specified. 

Assembly manager loaded from: C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll 
Running under executable C:\Program Files (x86)\Microsoft Visual Studio\VB98\vb6.exe 
--- A detailed error log follows. 

=== Pre-bind state information === 
LOG: DisplayName = BarcodeAndOperatorDatabase, Version=1.0.4.0, Culture=neutral, PublicKeyToken=null 
(Fully-specified) 
LOG: Appbase = file:///C:/Program Files (x86)/Microsoft Visual Studio/VB98/ 
LOG: Initial PrivatePath = NULL 
LOG: Dynamic Base = NULL 
LOG: Cache Base = NULL 
LOG: AppName = vb6.exe 
Calling assembly : (Unknown). 
=== 
LOG: This bind starts in default load context. 
LOG: No application configuration file found. 
LOG: Using host configuration file: 
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config. 
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind). 
LOG: The same bind was seen before, and was failed with hr = 0x80070002. 
ERR: Unrecoverable error occurred during pre-download check (hr = 0x80070002). 

的問題是,該系統的探測下「Appbase`(C列出的目錄:\程序文件(x86)\微軟的Visual Studio \ VB98),因爲所需的程序集不在該目錄下,所以找不到它。

在COM加載CLR和CLR加載程序集時,它基於存儲在註冊表中的路徑。這可以從這個日誌條目中看到。

=== Pre-bind state information === 
LOG: Where-ref bind. Location = D:/Development/Library/C Sharp/BarcodeAndOperatorDatabase/BarcodeAndOperatorDatabase/bin/x86/ComInterop/BarcodeAndOperatorDatabase.dll 
LOG: Appbase = file:///C:/Program Files (x86)/Microsoft Visual Studio/VB98/ 
LOG: Initial PrivatePath = NULL 
LOG: Dynamic Base = NULL 
LOG: Cache Base = NULL 
LOG: AppName = vb6.exe 
Calling assembly : (Unknown). 
=== 
LOG: This bind starts in LoadFrom load context. 
WRN: Native image will not be probed in LoadFrom context. Native image will only be probed in default load context, like with Assembly.Load(). 
LOG: No application configuration file found. 
LOG: Using host configuration file: 
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config. 
LOG: Attempting download of new URL file:///D:/Development/Library/C Sharp/BarcodeAndOperatorDatabase/BarcodeAndOperatorDatabase/bin/x86/ComInterop/BarcodeAndOperatorDatabase.dll. 
LOG: Assembly download was successful. Attempting setup of file: D:\Development\Library\C Sharp\BarcodeAndOperatorDatabase\BarcodeAndOperatorDatabase\bin\x86\ComInterop\BarcodeAndOperatorDatabase.dll 
LOG: Entering run-from-source setup phase. 
LOG: Assembly Name is: BarcodeAndOperatorDatabase, Version=1.0.4.0, Culture=neutral, PublicKeyToken=null 
LOG: Re-apply policy for where-ref bind. 
LOG: Where-ref bind Codebase does not match what is found in default context. Keep the result in LoadFrom context. 
LOG: Binding succeeds. Returns assembly from D:\Development\Library\C Sharp\BarcodeAndOperatorDatabase\BarcodeAndOperatorDatabase\bin\x86\ComInterop\BarcodeAndOperatorDatabase.dll. 
LOG: Assembly is loaded in LoadFrom load context. 

最初組件只存在於LoadFrom load context和探測default load context當不能找到。因此,在探測default load context時,需要提供一種方法來通過LoadFrom組件。這可以通過處理AppDomain.AssemblyResolve事件來完成。

以下摘錄自:Best Practices for Assembly Loading提供了各種背景的描述。

內的應用領域,組件可被裝載到 之一三個上下文,或者它們可以在沒有上下文被加載:

默認負載上下文包含通過探測 全局程序集緩存發現組件,所述主機程序集存儲(如果運行時爲 )(例如,在SQL Server中)以及ApplicationBase和 應用程序域的PrivateBinPath。 Load的大部分重載方法都會將程序集加載到此上下文中。

來自上下文的負載包含從加載程序未搜索的 位置加載的程序集。例如,加載項 可能安裝在不在應用程序 路徑下的目錄中。 System.Reflection.Assembly.LoadFrom, System.AppDomain。CreateInstanceFrom和 System.AppDomain.ExecuteAssembly是通過 路徑加載的方法示例。

僅反射上下文包含使用ReflectionOnlyLoad和ReflectionOnlyLoadFrom方法加載的程序集。此 上下文中的代碼無法執行,因此不在此討論。有關更多 信息,請參閱如何:將組件加載到僅反射 上下文中。