Я работаю с существующей кодовой базой, состоящей из некоторых COM-интерфейсов, написанных на C ++ с внешним интерфейсом C #. Существует некоторая новая функциональность, которую необходимо добавить, поэтому мне приходится изменять части COM. В одном конкретном случае мне нужно передать массив (выделенный из C #) компоненту, который нужно заполнить.
Что я хотел бы сделать, так это уметь передавать массив int в метод из C #, что-то вроде:
// desired C# signature
void GetFoo(int bufferSize, int[] buffer);
// desired usage
int[] blah = ...;
GetFoo(blah.Length, blah);
Пара гаечных ключей в работах:
- C ++ / CLI или Managed C ++ не могут быть использованы (в этом случае с COM можно покончить).
- Сторона C # не может быть скомпилирована с / unsafe (использование Marshal разрешено).
Интерфейс COM используется (и будет использоваться только когда-либо) частью C #, поэтому меня меньше беспокоит взаимодействие с другими потребителями COM. Переносимость между 32 и 64 битами также не является проблемой (все компилируется и запускается с 32-битной машины, поэтому генераторы кода преобразуют указатели в целые числа). В конце концов он будет заменен просто C ++ / CLI, но это далеко не так.
Моя первоначальная попытка
похож на:
HRESULT GetFoo([in] int bufferSize, [in, size_is(bufferSize)] int buffer[]);
И определение выходного TLB (кажется разумным):
HRESULT _stdcall GetFoo([in] int bufferSize, [in] int* buffer);
Что импортируется C # как (не очень разумно):
void GetFoo(int bufferSize, ref int buffer);
Который я мог бы использовать с
int[] b = ...;
fixed(int *bp = &b[0])
{
GetFoo(b.Length, ref *bp);
}
... за исключением того, что я не могу скомпилировать с /unsafe.
На данный момент
Я использую:
HRESULT GetFoo([in] int bufferSize, [in] INT_PTR buffer);
Который импортирует как:
void GetFoo(int bufferSize, int buffer);
И мне нужно использовать его как:
int[] b = ...;
GCHandle bPin = GCHandle.Alloc(b, GCHandleType.Pinned);
try
{
GetFoo(b.Length, (int)Marshal.UnsafeAddrOfPinnedArrayElement(b, 0));
}
finally
{
bPin.Free();
}
Что работает ... но я бы хотел найти более чистый способ.
Итак, вопрос
Существует ли определение IDL, которое подходит для импорта C # из генератора TLB для этого случая? Если нет, что можно сделать на стороне C #, чтобы сделать его немного безопаснее?