Я работаю с интерфейсом плагина COM, который имеет следующее определение функции:
HRESULT foo ( [out, ref] VARIANT* a, [out, ref] VARIANT* b );
При использовании tlbimp (tlbimp2.exe из codeplex) библиотека .NET имеет следующую интерфейсную функцию:
int foo ( out object a, out object b );
Проблема в том, что вызывающее приложение выполнит вызов функции:
VARIANT a;
::InitVariant( &a );
plugin->foo( &a, NULL );
А в C # я реализовал функцию:
int foo ( out object a, out object b )
{
a = 1;
b = 2;
return 0; // S_OK
}
Когда все сказано и сделано, приложение фактически получает возврат E_POINTER, а не S_OK. Я предполагаю, что это из-за того, что NULL передал параметр out.
Есть ли способ проверить, равен ли указатель адреса NULL в реализации C #?
Примечание: выходные параметры не инициализируются, поэтому вы не можете использовать параметры вообще.
Я пытался реализовать интерфейс как [in, out, ref], чтобы заставить C # использовать (ref object a, ref object b), но это тоже не сработало.
Обновление
Ганс абсолютно прав, что мы должны были вызывать функцию с нулевым ptr, если мы объявили ее как [out, ref].
erurainon также был прав, что мы могли просто использовать IntPtr, чтобы добраться до варианта *.
Вот как это было исправлено:
int foo ([MarshalAs(UnmanagedType.Struct)]out object a, [MarshalAs(UnmanagedType.Struct)]out object b);
стал
int foo ([MarshalAs(UnmanagedType.Struct)]out object a, IntPtr b );
Теперь мы можем проверить на NULL случаи с:
if ( b == IntPtr.Zero )
Однако, поскольку мы имеем дело с Variant, вы не можете просто скопировать значение в IntPtr, например:
Marshal.StructureToPtr( myValue, b, false );
Итак, следуя этой записи , вам нужно создать класс struct:
[StructLayout(LayoutKind.Explicit, Size = 16)]
public struct PropVariant
{
[FieldOffset(0)]
public VarEnum variantType;
[FieldOffset(8)]
public IntPtr pointerValue;
[FieldOffset(8)]
public byte byteValue;
[FieldOffset(8)]
public long longValue;
[FieldOffset(8)]
public double dateValue;
[FieldOffset(8)]
public short boolValue;
}
И последняя функция выглядит следующим образом:
int foo( out object a, IntPtr b )
{
a = 100;
if ( b != IntPtr.Zero )
{
var time = new PropVariant();
time.dateTime = DateTime.Now.ToOADate();
time.variantType = VarEnum.VT_DATE;
Marshal.StructureToPtr( time, b, false );
}
return 0; // S_OK
}
Надеюсь, это поможет кому-то еще в будущем