Назовите неуправляемый Код от C# - возврат структуры с массивами

У меня была такая же проблема с этой ошибкой. Я не смог обнаружить project1 из project2. Я добавил ссылку из проекта 2 в проект 1, но она все еще не работала. Затем я выгрузил project1, удалил его из решения. Затем я добавил его снова, сделал ссылку из проекта 2 и та да ... это сработало .....: -)

7
задан Cœur 17 December 2017 в 03:28
поделиться

7 ответов

При возврате информации в структуре стандартный метод заключается в передаче указателя на структуру в качестве параметра метода. Метод заполняет элементы структуры, а затем возвращает какой-либо код состояния (или логическое значение). Так что вы, вероятно, захотите изменить свой метод C ++, чтобы он принимал SYSTEM_OUTPUT * и возвращал 0 в случае успеха или кода ошибки:

public partial class Form1 : Form
{
    public SYSTEM_OUTPUT output;

    [DllImport("testeshm.dll", EntryPoint="getStatus")]
    public extern static int getStatus(out SYSTEM_OUTPUT output);

    public Form1()
    {
        InitializeComponent();           
    }

    private void ReadSharedMem_Click(object sender, EventArgs e)
    {
        try
        {
            if(getStatus(out output) != 0)
            {
                //Do something about error.
            }
        }
        catch (AccessViolationException ave)
        {
            label1.Text = ave.Message;
        }
    }
}
3
ответ дан 7 December 2019 в 01:22
поделиться

кто выделил память для структуры? Вы не можете удалить собственную память из управляемой кучи. Вообще говоря, собственная DLL должна выделяться в куче COM, если она ожидает, что вызывающий объект освободит память или вернет интерфейс обратного вызова, такой как IMalloc, для освобождения возвращаемой памяти. Это означает, что вам нужно получить адрес памяти результата как IntPtr и использовать System.Runtime.InteropServices.Marshal для копирования данных из собственной в управляемую кучу (может быть в структуру) перед освобождением памяти.

Отредактируйте обновленную сигнатуру функции. : использовать общедоступный статический extern int getStatus (ref SYSTEM_OUTPUT output); Вы не выделяете память в куче COM в собственной функции, поэтому в этом нет необходимости.

0
ответ дан 7 December 2019 в 01:22
поделиться
  1. Убедитесь, что ваше поле ReadyForConnect не заполнено до 4 байтов. В моем проекте оказалось, что все короткие поля int (2 байта) были заполнены фиктивными байтами до 4 байтов в неуправляемой DLL. Если это проблема, вы должны маршалировать структуру следующим образом:
    [StructLayout(LayoutKind.Sequential)] 
    public struct SYSTEM_OUTPUT 
    {     
       [MarshalAs(UnmanagedType.I2)] 
       UInt16 ReadyForConnect;
       [MarshalAs(UnmanagedType.ByValArray, ArraySubType=UnmanagedType.I1, SizeConst=2)]
       byte[] aligment;          // 2 byte aligment up to 4 bytes margin
       [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]    
       String VersionStr;    
       [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]    
       String NameOfFile;        // ...
    }
  1. Если строки являются строками ANSI с завершающим нулем, вы можете аннотировать их как:
  [MarshalAs(UnmanagedType.LPStr)]                   public String VersionStr;
3
ответ дан 7 December 2019 в 01:22
поделиться

Фактически вы не маршалируете какие-либо данные управляемой стороне. Когда вы объявляете output на управляемой стороне, его значение по умолчанию - null . Затем на неуправляемой стороне вы никогда не выделяете память для вывода . Вы должны выделить некоторую неуправляемую память, передать указатель на эту память вашей функции dll, а затем упорядочить указатель для этой памяти в вашей структуре:

[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Ansi)]
public struct SYSTEM_OUTPUT
{
    UInt16 ReadyForConnect;        

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
    String VersionStr;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
    String NameOfFile;    
    // actually more of those
}

public partial class Form1 : Form
{
    public SYSTEM_OUTPUT output;

    [DllImport("testeshm.dll", EntryPoint="getStatus")]
    public extern static int getStatus(IntPtr output);

    public Form1()
    {
        InitializeComponent();           

    }

    private void ReadSharedMem_Click(object sender, EventArgs e)
    {
        IntPtr ptr;
        try
        {
            ptr = Marshall.AllocHGlobal(Marshall.SizeOf(typeof(SYSTEM_OUTPUT)));
            int ret = getStatus(ptr);

            if(ret == 0)
            {
                output = (SYSTEM_OUTPUT)Marshal.PtrToStructure(ptr, typeof(SYSTEM_OUTPUT));
            }

        //do something with output

            label1.Text = ret;
        }
        catch (AccessViolationException ave)
        {
            label1.Text = ave.Message;
        }
        finally
        {
            Marshal.FreeHGlobal(ptr);  //make sure to free the memory
        }
    }
}

Изменить:

Ваша проблема может заключаться в разнице между упаковка стратегий. Я обновил определение структуры.

2
ответ дан 7 December 2019 в 01:22
поделиться

То, что вы пытаетесь сделать, возможно, но я думаю, что вы решаете неправильную проблему.

Почему бы не прочитать файл с отображением памяти прямо из C #? Взгляните на Winterdom.IO.FileMap

Я использовал его, и он отлично работает.

MemoryMappedFile file = MemoryMappedFile.Open(FileMapRead, name);
using (Stream stream = memoryMappedFile.MapView(MapAccess.FileMapAllAccess, 0, length))
{
    // here read the information that you need   
}

На этом вы еще не закончили - вам все равно нужно преобразовать байтовый буфер в структуру, но вы все на управляемой стороне, и будет легче.

1
ответ дан 7 December 2019 в 01:22
поделиться

Думали ли вы о добавлении сборки C ++ / CLI в свой проект? Это чрезвычайно простой и эффективный способ преодолеть разрыв между управляемым и неуправляемым кодом. Я сам довольно часто им пользуюсь.

0
ответ дан 7 December 2019 в 01:22
поделиться

РЕДАКТИРОВАТЬ: Я переписываю весь этот ответ.

Я взял весь ваш код C ++ и C #, бросил его в решение и запустил - и все у меня работает. У меня не было вашего конкретного материала для отображения памяти, поэтому я смоделировал его, заполнив pBuf некоторыми поддельными данными, и все вернулось в норму; и возвращаемое значение, и структура вывода верны.

Что-то не так с настройками вашего проекта? Звучит глупо, но вы упомянули запуск и отладку неизмененного кода; вы ведь создаете DLL?

1
ответ дан 7 December 2019 в 01:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: