Передача структуры в неуправляемый код из C # - PullRequest
2 голосов
/ 13 октября 2011

Я уже давно борюсь с этой проблемой и надеюсь, что кто-нибудь может помочь.Я конвертирую приложение VB6 в C #.Все, что я собираюсь показать, прекрасно работает в VB6, но терпит неудачу в C #.

Я делаю вызов API в Cll, передавая структуру.Структура получает значения, измененные на стороне 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)
{
    ....
}

Вот мое объявление PInvoke в C # для API в C, который использует эти структуры:

    [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 элемент структуры 'result' заполняется значением после того, как я сделаю вызов API.В C # 'result' всегда равно 0. Я предполагаю, что у меня что-то не так с тем, как я собираюсь?Я прочитал десятки статей и попробовал много разных способов, чтобы это работало безуспешно.Любая помощь приветствуется!

ОБНОВЛЕНИЕ: Теперь, когда я обновил код на основе приведенных ниже предложений (исправление типов и очистка кода в том виде, в котором оно было написано изначально), я получаю исключение:

System.AccessViolationException: Attempted to read or write protected memory. This is        often an indication that other memory is corrupt.

Я обнаружил, что это происходит, как только я изменил «public int16 vers» с «public int vers» в моей структуре запросов.Мысли?

1 Ответ

1 голос
/ 13 октября 2011

UnmanagedType.Struct на самом деле не для подструктур; это заставляет Маршалера передать связанный объект как ВАРИАНТ. Это не то, что вы хотите здесь. Попробуйте снять все операторы MarshalAs, за исключением строк (для длины), массивов (также для длины) и перечислимых типов (здесь я их не вижу, но в моих DLL они были UnmanagedType.I4) и посмотрите если это работает.

В вашей структуре C # также есть некоторые дополнительные вещи, которых нет в вашей версии C, пара переменных не совпадает между ними, и ваша заданная функция C не возвращает ничего, но ваш C # extern ожидает IntPtr , Они должны соответствовать, чтобы все прошло гладко. (Полагаю, это просто упрощение для сайта, но об этом нужно помнить.)

...