【发布时间】:2011-10-13 16:11:03
【问题描述】:
我一直在与这个问题作斗争一段时间,希望有人能提供帮助。我正在将 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# 中的 PInvoke 声明,用于 C 中使用这些结构的 API:
[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.
我发现,当我在请求结构中从“public int vers”更改为“public Int16 vers”时,就会发生这种情况。想法?
【问题讨论】:
-
'vers' 似乎是 C# 结构中的错误大小类型。
-
'objtype' 的大小也有误。请改用short。
-
未管理的SendRequest方法的返回值是多少?你能给我们完整的定义吗?
标签: c# dll pinvoke marshalling