Прикрепление updateble структуры прежде, чем передать неуправляемому коду?

Я могу только вспомнить использование goto однажды. У меня была серия пяти вложенных считаемых циклов, и я должен был быть в состоянии убежать из всей структуры с внутренней части рано на основе определенных условий:

for{
  for{
    for{
      for{
        for{
          if(stuff){
            GOTO ENDOFLOOPS;
          }
        }
      }
    }
  }
}

ENDOFLOOPS:

я, возможно, просто легко объявил булеву переменную повреждения и использовал ее в качестве части условного выражения для каждого цикла, но в этом экземпляре я решил, что GOTO был так же практичен и так же читаем.

Никакой velociraptors не напал на меня.

10
задан DxCK 5 December 2009 в 00:36
поделиться

4 ответа

Является ли небезопасный код вариантом?

// allocate unmanaged memory
Foo* foo = (Foo*)Marshal.AllocHGlobal(sizeof(Foo));

// initialize struct
foo->bar = 0;

// invoke unmanaged function which remembers foo
UnsafeNativeMethods.Bar(foo);
Console.WriteLine(foo->bar);

// update struct
foo->bar = 10;

// invoke unmanaged function which uses remembered foo
UnsafeNativeMethods.Qux();
Console.WriteLine(foo->bar);

// free unmanaged memory
Marshal.FreeHGlobal((IntPtr)foo);

Это компилируется и не генерирует исключение, но у меня нет под рукой неуправляемой функции, чтобы проверить, работает ли она.

From MSDN :

Когда AllocHGlobal вызывает LocalAlloc, он передает флаг LMEM_FIXED, который приводит к блокировке выделенной памяти на месте. Кроме того, выделенная память не заполняется нулями.

3
ответ дан 4 December 2019 в 01:31
поделиться

Использование закрепленной памяти в этом случае не является хорошей идеей, учитывая, что память для структуры должна быть действительной в течение длительного времени. GCHandle.Alloc () закроет структуру и сохранит ее в куче. Когда он закреплен, сборщик мусора будет постоянно обременять его, поскольку ему необходимо постоянно находить обходной путь.

Простое решение - выделить память для структуры в неуправляемой памяти. Используйте Marshal.SizeOf (), чтобы получить размер структуры, и Marshal.AllocCoTaskMem (), чтобы выделить память. Это дает вам указатель, который нужно передать на неуправляемый код. Инициализируйте память с помощью Marshal.StructureToPtr (). И прочтите обновления структуры, написанные неуправляемым кодом, с помощью PtrToStructure ().

Если вы будете делать это часто, вы будете постоянно копировать структуру. Это может быть дорого, в зависимости от размеров конструкции. Чтобы этого избежать, используйте небезопасный указатель для прямого доступа к неуправляемой памяти. Базовый синтаксис:

using System;
using System.Runtime.InteropServices;

class Program {
  unsafe static void Main(string[] args) {
    int len = Marshal.SizeOf(typeof(Test));
    IntPtr mem = Marshal.AllocCoTaskMem(len);
    Test* ptr = (Test*)mem;
    ptr->member1 = 42;
    // call method
    //..
    int value = ptr->member1;
    Marshal.FreeCoTaskMem(mem);
  }
  public struct Test {
    public int member1;
  }
}
6
ответ дан 4 December 2019 в 01:31
поделиться

Вместо закрепления вам необходимо использовать Marshal.StructureToPtr и Marshal.PtrToStructure для маршалинга структуры в память, которая может использоваться в машинном коде.

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

Пример структуры:

[StructLayout(LayoutKind.Sequential)]
public struct OVERLAPPED_STRUCT
{
   public IntPtr InternalLow;
   public IntPtr InternalHigh;
   public Int32 OffsetLow;
   public Int32 OffsetHigh;
   public IntPtr EventHandle;
}

Как закрепить ее в структуре и использовать:

OVERLAPPED_STRUCT over_lapped = new OVERLAPPED_STRUCT();
// edit struct in managed code
over_lapped.OffsetLow = 100;
IntPtr pinned_overlap_struct = Marshal.AllocHGlobal(Marshal.SizeOf(over_lapped));
Marshal.StructureToPtr(over_lapped, pinned_overlap_struct, true);

// Pass pinned_overlap_struct to your unmanaged code
// pinned_overlap_struct changes ...

// Get resulting new struct
OVERLAPPED_STRUCT nat_ov = (OVERLAPPED_STRUCT)Marshal.PtrToStructure(pinned_overlap_struct, typeof(OVERLAPPED_STRUCT));
// See what new value is
int offset_low = nat_ov.OffsetLow;
// Clean up
Marshal.FreeHGlobal(pinned_overlap_struct);
0
ответ дан 4 December 2019 в 01:31
поделиться
Другие вопросы по тегам:

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