2009-10-22 46 views
3

我無法訪問COM接口中的某些字符串字段。調用整數字段不會導致錯誤。當嘗試撥打clientID(),deviceID()key()時,我收到舊的「試圖讀取或寫入受保護的內存」錯誤。PInvoke - 讀取字符串字段的值 - 「嘗試讀取或寫入受保護的內存」

這裏是源接口代碼:(代碼從here來源)

[scriptable, uuid(fab51c92-95c3-4468-b317-7de4d7588254)] 
interface nsICacheEntryInfo : nsISupports 
{ 
    readonly attribute string clientID; 
    readonly attribute string deviceID; 
    readonly attribute ACString key; 
    readonly attribute long fetchCount; 
    readonly attribute PRUint32 lastFetched; 
    readonly attribute PRUint32 lastModified; 
    readonly attribute PRUint32 expirationTime; 
    readonly attribute unsigned long dataSize; 
    boolean isStreamBased(); 
}; 

這裏是用於訪問接口C#代碼:

[Guid("fab51c92-95c3-4468-b317-7de4d7588254"), ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
interface nsICacheEntryInfo 
{ 
    string clientID(); 
    string deviceID(); 
    nsACString key(); 
    int fetchCount(); 
    Int64 lastFetched(); 
    Int64 lastModified(); 
    Int64 expirationTime(); 
    uint dataSize(); 
    [return: MarshalAs(UnmanagedType.Bool)] 
    bool isStreamBased(); 
} 

任何建議,爲什麼簡單地試圖讀取​​一個字段應該對我進行訪問違規?

+0

該接口的成員lastFetched,lastModified等作爲PRUint32。我不確定這是什麼,但它似乎是32位,但你在你的C#代碼中使用Int64。這可能是一個問題嗎? – 2009-10-22 17:08:15

+0

我做了改變,但得到了相同的異常:( – 2009-10-23 11:12:19

+0

C++代碼導出什麼樣的字符串? – 2009-10-25 22:56:10

回答

3

此接口中的字符串是C風格字符串(char *'s)上的變體,但COM Interop默認將字符串視爲BSTR。編組人員嘗試讀取錯誤類型的字符串,然後使用CoTask內存分配器釋放它,因此訪問衝突並不奇怪。如果你的字符串是[In]參數,你可以用適當的MarshalAs屬性裝飾它們,但是這對於返回值參數不起作用。所以你需要將它們編組爲IntPtrs,然後手動編組並釋放底層內存。

我會嘗試以下方法:

[Guid("fab51c92-95c3-4468-b317-7de4d7588254"), ComImport, 
    InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
interface nsICacheEntryInfo 
{ 
    IntPtr clientID { get; } 
    IntPtr deviceID { get; } 
    IntPtr key { get; } 
    int fetchCount { get; } 
    uint lastFetched { get; } 
    uint lastModified { get; } 
    uint expirationTime { get; } 
    uint dataSize { get; } 
    [return: MarshalAs(UnmanagedType.Bool)] 
    bool isStreamBased(); 
} 

由於克里斯PRUint32s上面提到的實際上是32個不是64位無符號整數,所以我已經改變了他們。此外,我已經將方法更改爲屬性,因爲它更好地捕獲了idl的含義,因爲它們都是隻讀的,它實際上並不影響佈局。

爲clientID的和設備ID的字符串可以使用Marshal.PtrToStrAnsi爲使閱讀:

 nsIMemory memoryManagerInstance = /*maybe get this from somewhere*/; 
     nsICacheEntryInfo cacheEntryInstance = /*definitely get this from somewhere*/; 
     IntPtr pClientID = cacheEntryInstance.clientID; 
     string clientID = Marshal.PtrToStringAnsi(pClientID); 

     NS_Free(pClientID); 

     //or 

     memoryManagerInstance.free(pClientID); 

無論您使用NS_Free或存儲器接口以釋放字符串取決於你如何使用整個XPCOM設置。鍵值是一個抽象字符串,因此它的表示取決於它來自哪裏。看起來它通常可以被看作是一個像其他字符串一樣的ANSI字符串的指針。

我沒有安裝程序可以爲您嘗試這些操作,而且文檔至少有點不透明,所以您可能需要對此進行一些調整。

+0

你這麼值得+150賞金!允許我添加我的+1 我正在處理C++ DLL中的(非COM)遺留代碼,它從非託管→託管代碼傳遞了一個標準stl c_str() 所有的32位操作都很好,但是打破了64位環境 您的解決方案取得了訣竅 謝謝! – AVIDeveloper 2011-11-04 02:10:59

0

如果將[return:MarshalAs(UnmanagedType.BStr)] statememnt應用於clientID和deviceID會怎麼樣?

+0

謝謝,它並沒有幫助,雖然。 – 2009-10-22 15:59:27

相關問題