Возврат Struct из VC++ в C#

Я написал структуру в VС++. Я сделал dll из кода VC++ и вызвал эту dll на С# с помощью PInvoke.

DLL VC++ выглядит так

#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#include <iostream>
#if defined(_MSC_VER)
#include <windows.h>
#define DLL extern "C" __declspec(dllexport)
#else
#define DLL
#endif


struct SYSTEM_OUTPUT
{
    int status;
};


DLL SYSTEM_OUTPUT* getStatus()
{
    SYSTEM_OUTPUT* output;
    output->status = 7;

    return output;
}

Я вызываю функцию getStatus() из dll в моем коде C#, который выглядит следующим образом:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace UsingReturnStructDLL
{
    [StructLayout(LayoutKind.Sequential)]
    public struct SYSTEM_OUTPUT
    {
        [MarshalAs(UnmanagedType.I4)]
        int Status;
    }



public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

        public SYSTEM_OUTPUT output;

        [DllImport("ReturnStructDLL", EntryPoint = "getStatus")]
        [return: MarshalAs(UnmanagedType.Struct)]
        public extern static SYSTEM_OUTPUT getStatus();



        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                SYSTEM_OUTPUT output = getStatus();
            }
            catch (AccessViolationException e)
            {
                label1.Text = e.Message;
            }

        }
    }
}

Я хочу получить значения в структуре в моем коде С#. С приведенной выше настройкой моего кода я получаю следующую ошибку:

Cannot marshal 'return value': Invalid managed/unmanaged type combination (Int32/UInt32
must be paired with I4, U4, or Error).

Может ли кто-нибудь помочь мне с проблемой?

Спасибо.


person Jayesh    schedule 01.09.2010    source источник
comment
Ваш собственный метод возвращает указатель на SYSTEM_OUTPUT, но в управляемом коде такого указателя нет. Возможно MarshalAs(UnmanagedType.LPStruct)?   -  person Mark H    schedule 01.09.2010
comment
Я изменил его на: [DllImport(ReturnStructDLL, EntryPoint = getStatus)] [return: MarshalAs(UnmanagedType.LPStruct)] public extern static SYSTEM_OUTPUT getStatus(); ... но та же ошибка   -  person Jayesh    schedule 01.09.2010


Ответы (1)


Сначала заставьте ваш код C++ работать. Это мусор, как опубликовано, вы не инициализируете указатель. Он выйдет из строя с AccessViolation.

Возвращение указателей на структуры очень также сложно реализовать в C/C++, клиент вашего кода не будет знать, как нужно освобождать память. Что также наносит ущерб маршаллеру P/Invoke, он попытается освободить указатель с помощью CoTaskMemFree(). Это бред в Vista и выше, утечка памяти в XP.

Все эти проблемы исчезнут, если вы позволите клиенту передать указатель на структуру в качестве аргумента:

void getStatus(SYSTEM_OUTPUT* buffer)

Что затем в С# становится:

[DllImport("mumble.dll")]
private static extern void getStatus(out SYSTEM_OUTPUT buffer);
person Hans Passant    schedule 01.09.2010
comment
Привет, если я заставлю свой клиент С# передать структуру в качестве аргумента, как я смогу установить значение для члена структуры в cpp. По-вашему, в С++, buffer.status = 7; дает мне ошибку. Извините, если этот вопрос очень детский, я новичок! Спасибо за помощь - person Jayesh; 01.09.2010
comment
Время обратиться к книге по языку C++. Состояние буфера = 7. - person Hans Passant; 01.09.2010