簡體   English   中英

如何通過禁用名稱管理來啟用實例方法

[英]How to PInvoke an Instance Method by disabling Name Mangling

給出foo.dll中的以下c ++類

class a{
  private:
    int _answer;

  public:
    a(int answer) { _answer = answer; }
    __declspec(dllexport) int GetAnswer() { return _answer; }
}

我想從C#獲得pInvoke GetAnswer。 為此,我使用以下方法:

[DllImport("foo.dll", CallingConvention = CallingConvention.ThisCall, EntryPoint= "something")]
public static extern int GetAnswer(IntPtr thisA);

我傳入一個指向a的IntPtr(我從其他地方得到的,這並不重要)。 CallingConvention = CallingConvention.ThisCall確保它被正確處理

這個問題很酷,我知道我到目前為止是因為它已經很好了! 使用Depends.exe,我可以看到“GetAnswer”被導出為?GetAnswer @ a @@ UAEHXZ(或者某些東西很接近 - 這就是它的名字被破壞了)。 當我將受損的名稱插入EntryPoint的“東西”時,一切都很棒! 我花了大約一天的時間才意識到我使用了Depends.exe,所以我將把這個留在這里作為對任何有類似問題的人的幫助。

我的真實問題是:有沒有辦法在GetAnswer上禁用C ++名稱修改,這樣我就不需要將受損的名稱作為我的入口點。 在那里有一個受損的名稱似乎可能會破壞,因為我對名稱修改的理解是,如果編譯器改變它可以改變。 對於我想要pInvoke的每個實例方法使用Depends.exe也很痛苦。

編輯:忘了添加我嘗試過的東西:我似乎無法在函數聲明上放置extern“C”,雖然我可以堅持定義。 這似乎沒有幫助(當你想到這一點時很明顯)

我能想到的唯一其他解決方案是包含實例方法的c風格函數,並將a的實例作為參數。 然后,禁用該包裝上的名稱修改和pInvoke。 不過,我寧願堅持我已有的解決方案。 我已經告訴我的同事,pInvoke很棒。 如果我必須在我們的c ++庫中放置特殊函數以使pInvoke工作,我將會看起來像個白痴。

您不能為C ++類方法禁用修改,但您可以使用/EXPORT或.def文件以您選擇的名稱導出該函數。

但是,因為你靠的實現細節,即你的整個做法是易碎this將作為隱式參數傳遞。 更重要的是,輸出一個類的單個方法是痛苦的一個方法。

將C ++類暴露給.net語言的最明智的策略是:

  1. 創建平面C包裝函數並調用它們。
  2. 創建一個C ++ / CLI混合模式層,用於發布包裝本機類的托管類。

在我看來,選項2更可取。

您可以使用comment / linker #pragma將/EXPORT開關傳遞給鏈接器,該鏈接器允許您重命名導出的符號:

#pragma comment(linker, "/EXPORT:GetAnswer=?GetAnswer@a@@UAEHXZ")

不幸的是,這並不能解決您使用依賴或其他工具查找損壞名稱的需要。

您不必禁用實際包含有關如何聲明函數本身的大量信息的受損名稱,它基本上表示函數名稱被去除后的函數的整個簽名。 我知道你已經發現了一個單詞,而另一個答案已被標記為正確的答案。 我在下面寫的是我們如何使它按照您的期望工作。

[DllImport("foo.dll", CallingConvention = CallingConvention.ThisCall, EntryPoint = "#OrdinalNumber")]
public static extern int GetAnswer(IntPtr thisA);

如果將“#OrdinalNumber”替換為GetAnsweer的實數序號,例如“#1”,它將按您的需要工作。

您可以只考慮EntryPoint屬性與我們傳遞給GetProcAddress的函數名稱相同,您可以在其中傳遞函數名稱或函數的序號。

您調用C ++類的非靜態函數成員的方法確實是正確的,並且正確使用了此調用,這正是調用約定在C#P / Invoke中發揮作用。 這種方法的問題是你必須查看DLL的PE信息,導出函數信息並找出你想要調用的每個函數的序號,如果你有大量的C ++函數可以調用,你可以想要自動化這樣一個過程。

來自問題作者:我實際上采用的解決方案

我結束了與C風格的功能封裝了實例方法和采用的一個實例作為一個參數去。 這樣,如果類繼承自繼承,則會調用正確的虛方法。

我故意選擇不使用C ++ / CLI,因為它只是另一個要管理的項目。 如果我需要在類上使用所有方法,我會考慮它,但我真的只需要這個序列化類數據的方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM