Ответ 1
У вас есть несколько вариантов
1) Используйте class
вместо struct
Я думаю, что этот метод является самым простым. Просто объявите struct
как class
:
[StructLayout(LayoutKind.Sequential)]
public class CStruct
{
//member-list
}
а затем объявите свой метод:
[DllImport("mydll.dll", OptionName = optionValue, ...)]
static extern int DLLFunction(CStruct cStruct, ...);
Если ваш необязательный параметр является последним, вместо этого вместо CStruct cStruct = null
можно использовать параметр. Это позволяет исключить его, а не передавать null
явно. Вы также можете написать метод-обертку, который использует это и гарантирует, что дополнительные параметры будут последними.
2) Используйте IntPtr
и IntPtr.Zero
Используйте struct
:
[StructLayout(LayoutKind.Sequential)]
public struct CStruct
{
//member-list
}
и объявите свой метод как:
[DllImport("mydll.dll", OptionName = optionValue, ...)]
static extern int DLLFunction(IntPtr cStruct, ...);
В случае не null
маршал struct указателю и вызовите метод:
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CStruct)));
try{
Marshal.StructureToPtr(myCStruct, ptr, false);
DLLFunction(ptr, ...);
} finally {
Marshal.FreeHGlobal(ptr);
}
В случае null
вызовите метод с IntPtr.Zero
:
DLLFunction(IntPtr.Zero, ...);
Опять же, вы можете сделать этот параметр опционным, если это окажется последним в списке (или вы используете обертку, чтобы сделать это). Сделайте это, используя IntPtr cStruct = default(IntPtr)
в качестве параметра. (As default(IntPtr)
создает IntPtr.Zero
.)
3) Перегрузите свой метод, чтобы избежать маршалинга
Используйте struct
, как в 2).
Просто объявите один вариант для случая null
:
[DllImport("mydll.dll", OptionName = optionValue, ...)]
static extern int DLLFunction(ref cStruct, ...);
и другой для случая null
:
[DllImport("mydll.dll", OptionName = optionValue, ...)]
static extern int DLLFunction(IntPtr cStruct, ...);
Первый метод будет автоматически вызван при передаче struct
, а второй при передаче IntPtr.Zero
. Если объявить версию IntPtr
с необязательным параметром (как показано внизу 2) выше), она автоматически вызывается, когда вы исключаете параметр cStruct
.
4) Исходные указатели с использованием unsafe
Используйте структуру как в 2) и объявите свой метод (обратите внимание на ключевое слово unsafe
):
[DllImport("mydll.dll", OptionName = optionValue, ...)]
static unsafe extern int DLLFunction(CStruct* cStruct, ...);
В случае с null
вы передаете &myCStruct
и просто null
в случае null
. Как и в 1), если этот необязательный параметр последний, вы можете объявить параметр как CStruct* cStruct = null
для автоматического пропуска null
, когда cStruct
исключен.
Спасибо @dialer за предложение этого метода.