我正在通過P/Invoke使用非託管庫,它使用三個結構(雖然它們都具有相同的基本佈局,所以我只會發佈一個):託管和非託管結構的大小不一樣
struct Agraph_t {
int tag:4;
int kind:4;
int handle:24;
char **attr;
char *didset;
char *name;
Agdata_t *univ;
Dict_t *nodes, *inedges, *outedges;
Agraph_t *root;
Agnode_t *meta_node;
Agproto_t *proto;
Agraphinfo_t u;
};
由於我的包裝使用這些對象的方式,我必須參考Agraph_t
中的結構爲IntPtr
s。我添加了訪問比特字段值的屬性。
public struct Agraph_t {
public uint tag_kind_handle;
public IntPtr attr;
public string didset;
public string name;
public IntPtr univ;
public IntPtr nodes, inedges, outedges;
public IntPtr root;
public IntPtr meta_node;
public IntPtr proto;
public IntPtr u;
public uint Tag {
get { return (tag_kind_handle & 15u); }
}
public uint Kind {
get { return (tag_kind_handle & 240u)/16; }
}
public uint Handle {
get { return (tag_kind_handle & 4294967040u)/256; }
}
}
在做任何事情之前,我必須通過給三個結構體中每一個的大小初始化非託管庫。
aginitlib(Marshal.SizeOf(typeof(Agraph_t)), ..., ...);
這樣做時我不會收到錯誤,我可以使用該庫就好了。但是,庫的一部分使用非託管結構的大小自己調用aginitlib(我無法控制這個)。此時,圖書館警告說,它已經初始化爲兩種不同的尺寸,這使得它不穩定(在某些操作之後拋出AccessViolationException
)。
是否將添加的屬性考慮在結構的大小中並使其大於非託管版本?我會刪除它們,看看會發生什麼,但是我的代碼在很大程度上依賴於它們,這使得這很難。
我需要使用StructLayoutAttribute
和Size
屬性嗎?唯一令我困惑的是IntPtr
s。庫是嚴格的32位,所以我可以繼續,並安全地假設這些字段將始終是32位?
哦,我明白了。我沒有注意到缺少'*'。這個解決方案的問題在於'Agraphinfo_t'結構是MASSIVE(根據字段數量),並根據庫的編譯方式使用不同的字段。我不知道使用了哪些編譯器標誌,所以我不確定要包含哪些字段。有小費嗎? – 2010-01-09 01:51:30
不幸的不是。爲了獲得大小匹配,你需要在該插槽中提供* something *,它與非託管的'Agraphinfo_t'結構佔用相同數量的大小(在結構中)。你可能可以使用一個字節數組(使用合適的編組標誌來確保它被視爲內聯空間而不是引用),但是這仍然需要你計算大小......但我想你可以通過編寫一個小C程序來打印'sizeof(Agraphinfo_t)'。沒有承諾,但 - 對不起! – itowlson 2010-01-09 01:56:01
聽起來可行。與此同時,我添加了這樣一個要求,那就是應該在調用'aginitlib'之前調用它自己調用的庫的一部分,並且無法從託管包裝器手動調用它。它有效,但絕對不是我想要保留的要求。 – 2010-01-09 02:01:25