2011-10-13 68 views
1

我一直在争取这个问题一段时间,并希望有人可以提供帮助。我将一个VB6应用程序转换为C#。我即将展示的所有东西在VB6中都很完美,但在C#中失败了。将结构传递给来自C#的非托管代码

我正在对C DLL进行API调用,传递一个结构。该结构在C端获得修改值,我应该在返回结构中看到修改后的值。

注意,西格是int,状态是一个int,和客户端ID是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中使用这些str的API中的PInvoke声明uctures:

[DllImport("TheCDLL.dll", EntryPoint = "[email protected]", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] 
    public static extern void Request(ref Request req); 

这里是填充结构,使得API调用我的C#代码:

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#中,'result'总是只有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 Int16 vers',就会发生这种情况。思考?

+2

“VERS”出现在你的C#结构尺寸错误类型。 – Joe

+0

'objtype'也是错误的大小。改为使用短。 – Hans

+0

什么是无人值守SendRequest方法的返回值?你能给我们完整的定义吗? – Hans

回答

1

UnmanagedType.Struct实际上不适用于子结构;它使得Marshaler将相关对象作为VARIANT传递。这不是你想要的。尝试除了字符串(长度),数组(除了长度)和枚举类型(我在这里没有看到,但在我的DLL中它们已经是UnmanagedType.I4)之外的所有MarshalAs语句,并参见如果有效的话。

你的C#结构中还有一些额外的东西不在你的C版本中,两个变量之间不匹配,你给定的C函数不会返回任何东西,但你的C#extern期待IntPtr的。这些确实需要匹配一切顺利。 (我猜它的网站只是简化,但它是值得牢记。)

+0

感谢您的回复!是的,我只注意到我在简化代码时引入了一些错误。我要清理我的错误并在今天晚上实施您的建议。我会回来的结果。 – JSchultz

+0

我已更新上述代码以实施建议。请看我的'更新'评论,看看我现在得到什么。谢谢! – JSchultz

相关问题