У меня есть управляемая функция со следующим объявлением (как интерфейс, так и реализация):
[return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)]
String[] ManagedFunction()
{
String[] foo = new String[1];
foo[0] = "bar";
return foo;
}
Существует также собственный интерфейс C ++ с теми же методами, что и управляемый интерфейс, внутри этого интерфейса этот метод имеет следующее объявление:
void ManagedFunction(SAFEARRAY* foo);
Эта функция вызывается собственным кодом следующим образом:
void NativeFunction(ManagedBinding binding)
{
CComSafeArray<BSTR> cComSafeArray;
cComSafeArray.Create();
LPSAFEARRAY safeArray = cComSafeArray.Detach();
binding.comObject->ManagedFunction(safeArray);
}
Я не уверен, что я делаю неправильно, но после того, как моя управляемая функция была вызвана, safeArray
кажется, что значения мусора, что-то идет не так, когда маршалинг возвращаемого значения возвращается к нативному коду. Может ли кто-то с большим опытом, чем я, с .Net Interop, пожалуйста, пролить свет на это? Кроме того, может быть уместно упомянуть, что у меня не было проблем с возвратом ValueType
s из моей управляемой функции (boolean
если вам интересно), что-то о возвращении String
Массив все портит. Спасибо!
1) Ваша функция возвращает SAFEARRAY
так почему вы выделяете его перед вызовом функции?
2) ManagedFunction
должен вернуть SAFEARRAY
так что он должен получить SAFEARRAY*
чтобы иметь возможность вернуть его! так что вы должны сказать:
LPSAFEARRAY lpsa;
binding.comObject->ManagedFunction(&lpsa);
CComSafeArray<BSTR> cComSafeArray;
cComSafeArray.Attach(lpsa);
Ну, я наконец-то получил его на работу. Я создал управляемое представление SAFEARRAY
называется ManagedSafeArray
(украдено отсюда: http://social.msdn.microsoft.com/Forums/en-US/clr/thread/6641abfc-3a9c-4976-a523-43890b2b79a2/):
[StructLayout(LayoutKind.Sequential)]
struct ManagedSafeArray
{
public ushort dimensions; // Count of dimensions in the SAFEARRAY
public ushort features; // Flags to describe SAFEARRAY usage
public uint elementSize; // Size of an array element
public uint locks; // Number of times locked without unlocking
public IntPtr dataPtr; // Pointer to the array data
public uint elementCount; // Element count for first (only) dimension
public int lowerBound; // Lower bound for first (only) dimension
}
Я изменил подпись моего метода на:
void ManagedMethod(ref ManagedSafeArray foo);
Внутри моего метода я вручную обновил dataPtr
поле по телефону Marshal.AllocCoTaskMem(...)
а затем скопировал строки, которые я хотел SAFEARRAY
содержать.
Я понятия не имею, почему CLR не смог автоматически упорядочить параметры в нативный код и из него, и я все равно буду признателен, если кто-нибудь попытается объяснить это.