На работе у нас есть собственный код C, отвечающий за чтение и запись в собственную базу данных плоских файлов. У меня есть оболочка, написанная на C #, которая инкапсулирует вызовы P / Invoke в модель OO. С момента запуска проекта управляемые оболочки для вызовов P / Invoke значительно усложнились. Как ни странно, с текущей оболочкой все в порядке, но я думаю, что мне действительно нужно сделать больше, чтобы обеспечить правильную работу.
Пара замечаний, поднятых ответами:
- Вероятно, не нужен KeepAlive
- Вероятно, не нужен пиннинг GCHandle
- Если вы используете GCHandle, попробуйте ... наконец то дело (хотя вопросы CER не рассматриваются)
Вот пример пересмотренного кода:
[DllImport(@"somedll", EntryPoint="ADD", CharSet=CharSet.Ansi,
ThrowOnUnmappableChar=true, BestFitMapping=false,
SetLastError=false)]
[ReliabilityContract(Consistency.MayCorruptProcess, Cer.None)]
internal static extern void ADD(
[In] ref Int32 id,
[In] [MarshalAs(UnmanagedType.LPStr)] string key,
[In] byte[] data, // formerly IntPtr
[In] [MarshalAs(UnmanagedType.LPArray, SizeConst=10)] Int32[] details,
[In] [MarshalAs(UnmanagedType.LPArray, SizeConst=2)] Int32[] status);
public void Add(FileId file, string key, TypedBuffer buffer)
{
// ...Arguments get checked
int[] status = new int[2] { 0, 0 };
int[] details = new int[10];
// ...Make the details array
lock (OPERATION_LOCK)
{
ADD(file.Id, key, buffer.GetBytes(), details, status);
// the byte[], details, and status should be auto
// pinned/keepalive'd
if ((status[0] != 0) || (status[1] != 0))
throw new OurDatabaseException(file, key, status);
// we no longer KeepAlive the data because it should be auto
// pinned we DO however KeepAlive our 'file' object since
// we're passing it the Id property which will not preserve
// a reference to 'file' the exception getting thrown
// kinda preserves it, but being explicit won't hurt us
GC.KeepAlive(file);
}
}
Мои (исправленные) вопросы:
- Будут ли автоматически прикреплены данные, сведения и статус / KeepAlive'd?
- Я что-то пропустил, чтобы это работало правильно?
РЕДАКТИРОВАТЬ: Я недавно нашел диаграмму, которая именно то, что вызвало мое любопытство. В основном говорится, что после вызова метода P / Invoke GC может вытеснить ваш нативный код . Таким образом, хотя собственный вызов может выполняться синхронно, GC может выбрать запуск и перемещение / удаление моей памяти. Думаю, теперь мне интересно, достаточно ли автоматического закрепления (или оно вообще работает).