2014-06-22 24 views
3

在大圖中,我嘗試從主域中的dll執行方法,但之後卸載該dll。到目前爲止,我已經創建了新的AppDomain加載了Assembly \ dll那裏,用MarshalByRefObject我提取了該方法的主體和MaxStackSize到主域,在那裏創建了DynamicMethod,重新創建了它內部的主體並調用它。 但是,當我調用它時,我得到異常: System.BadImageFormatException: Signature is not IMAGE_CEE_CS_CALLCONV_LOCAL_SIG從另一個AppDomain的程序集複製方法,並從CurrentDomain執行它

,其獲取並調用它的代碼:

DynamicMethod method = new DynamicMethod("func", typeof(void), new Type[ 0 ]); 
var info = method.GetDynamicILInfo(); 
info.SetCode(marshal.GetILCode(), marshal.GetMaxStackSize()); 
info.SetLocalSignature(
    SignatureHelper.GetMethodSigHelper(CallingConventions.Standard, typeof(void)).GetSignature()); 
method.Invoke(null, new object[ 0 ]); //<-- exception here 

marshalProxy類型的對象。 的一些注意事項,可能是必要的:

  1. ,我取\調用方法是public static void Run();
  2. 試圖調用方法的AppDomain和加載dll \ assembly的AppDomain具有相同的引用。

編輯

我與第一個字節從GetSignature方法改變爲0x07固定簽名。 但還有新的問題System.InvalidProgramException: Common Language Runtime detected an invalid program.

+2

你不能在其他appdomain中調用該方法的任何原因?你不能只是撕掉一些代碼。誰知道它取決於什麼?它肯定依賴於包含程序集的元數據表中的確切標記值。 – usr

+0

@usr我需要它,因爲代碼可能會創建新對象,我需要在卸載AppDomain後保留它們。它不依賴於該dll內的任何內容。只是在參考。我試圖重新創建的代碼是:'Console.WriteLine(AppDomain.CurrentDomain.FriendlyName);' – KugBuBu

+0

它抱怨你使用GetMethodSigHelper()。 CallingConvention.Standard僅適用於使用__stdcall約定的非託管代碼。不知道什麼樣的風格應該看起來像,我一定會先嚐試DynamicMethod.CreateDelegate()。 –

回答

1

你實現了一個大錯,從MethodBase.GetMethodBody字節數組是不可移植

使用OpCodes.CallOpCodes.Callvirt的方法調用會生成幾個字節,其中一個表示調用(call/callvirt)的類型,後跟表示元數據標記的四個字節。在這種情況下,該令牌可以解析爲Int32並使用Module.ResolveMethod解析爲MethodBase。

請注意,這些元數據標記是在編譯時生成的;他們可能在編輯之間有所不同。 (雖然它是編譯器的實現細節,但我相信它們只是基於編譯期間看到的方法順序自動遞增的數字。)

這意味着您嘗試使用的實際字節包含元數據令牌在您的動態模塊中無效。他們可能會指向一個現有方法,其簽名不同於您期望的方式,或者可能根本不存在於您的模塊中。

您需要解析您的il代碼並再次發送所有內容,從而生成新的有效元數據令牌。

相關問題