簡體   English   中英

從C#將結構傳遞給非托管代碼

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM