[英]Passing structure to unmanaged code from C#
我已經為這個問題解決了一段時間,希望有人可以提供幫助。 我正在將VB6應用程序轉換為C#。 我要展示的所有內容都可以在VB6中完美運行,但在C#中卻無法實現。
我正在通過一個結構對C dll進行API調用。 該結構在C端修改了值,我應該在返回結構中看到修改后的值。
注意,Sig是一個int,Status是一個int,CLIENTID是UINT_PTR。
這是C結構:
typedef struct
{
short vers;
short flags;
short cmd;
short objtype;
DWORD id;
DWORD client;
char buf[MAX_TOOLBUF];
DWORD toolID;
NMSG msg;
DWORD caller;
CLIENTID clientID;
DWORD ticket;
ToolResult PTR result;
long spare[4];
} Request;
typedef struct
{
DWORD hwnd;
DWORD message;
DWORD wParam;
DWORD lParam;
} NMSG;
typedef struct
{
Sig sig;
short cnt;
Status error;
DWORD ticket;
DWORD toolID;
long spare[4];
} ToolResult;
在我的C#代碼中,我定義了以下結構以映射到上面的C結構:
[StructLayout(LayoutKind.Sequential)]
public struct NMSG
{
public int hWnd;
public int msg;
public int wParam;
public int lParam;
}
[StructLayout(LayoutKind.Sequential)]
public struct Request
{
public Int16 vers;
public Int16 flags;
public Int16 cmd;
public int16 objType;
public int id;
public int Client;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string buf;
public int toolID;
public NMSG msg;
public int caller;
public IntPtr clientID;
public int ticket;
public ToolResult result;
[MarshalAs(UnmanagedType.ByValArray, SizeConst= 4) ]
public int64[] spare;
}
這是C代碼中的方法修飾:
SendRequest(Request PTR req)
{
....
}
這是我在C#中使用以下結構的C中API的PInvoke聲明:
[DllImport("TheCDLL.dll", EntryPoint = "_Request@4", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern void Request(ref Request req);
這是我的C#代碼,它填充了結構並進行了API調用:
Request req = new Request();
req.vers = 1;
req.toolID = 4000;
req.Client = 0;
req.cmd = 11;
req.objType = 1;;
req.id = 1;
req.msg.hWnd = Hwnd; // verified this is a valid window handle
req.msg.msg = 1327;
req.msg.wParam = 101;
req.msg.lParam = 0;
req.spare = new int[4];
req.buf = new string(' ', 260);
req.flags = 11;
Request(ref req);
問題是,在VB6代碼中,我進行API調用后,結構項“結果”被填充了一個值。 在C#中,“結果”始終始終為0。我想我編組的方式一定有問題嗎? 我已經閱讀了數十篇文章,並嘗試了許多不同的方法來使此方法沒有成功。 任何幫助表示贊賞!
更新:現在,我已根據以下建議更新了代碼(修復類型和清理原始編寫的代碼),我遇到了一個異常:
System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
我發現這是在我的Request結構中從“ public int vers”更改為“ public int vers”后立即發生的。 思考?
實際上,UnmanagedType.Struct不是用於子結構的。 它使Marshaler將相關對象作為VARIANT傳遞。 那不是你想要的。 嘗試刪除所有的MarshalAs語句,除了字符串(用於長度),數組(也用於長度)和枚舉類型(我在這里沒有看到,但在我的DLL中它們一直是UnmanagedType.I4),然后查看如果可行。
C#結構中還有一些其他的東西不在您的C版本中,兩個變量在這兩個變量之間不匹配,並且您給定的C函數不返回任何東西,但您的C#extern期望IntPtr。 這些都需要匹配才能順利進行。 (我想這只是網站的簡化,但要牢記這一點。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.