Что происходит между уровнем взаимодействия .NET и COM? - PullRequest
3 голосов
/ 09 мая 2011

Я использую COM в своем проекте C # .NET.
Однако один из вызываемых мной методов не работает должным образом.
Поэтому мне любопытно посмотреть, что происходит между моим кодом .NET, Interopслой и COM.
Я знаю, что tlbimp.exe создает оболочку метаданных для компонента COM, и я могу видеть эти сгенерированные методы в обозревателе объектов.
Могу ли я увидеть / отладить, что происходит, когда один из этих оболочекметоды называются?

Я передаю массив в метод ниже и ожидаю, что этот массив будет заполнен, однако массив не заполняется.Я вызываю следующий tlbimp.exe сгенерированный метод с неожиданными результатами:

int GetTags(System.Array buffer)
    Member of CServer.IUser

IDL метода:

[id(0x000000d5)]
HRESULT GetTags(
                [in] SAFEARRAY(long) buffer, 
                [out, retval] long* retval);  

.NET-код, вызывающий этот метод:

Array tagsArray = Array.CreateInstance(typeof(int), tagsLength);
userWrapper.GetTags(tagsArray);

Другие COM-методы, которые я называю, работают нормально.Однако, когда я вызываю любой метод, который ожидает Array в качестве параметра, он не работает должным образом.
Я предполагаю, что с маршаллером взаимодействия COM происходит что-то забавное.
Поэтому я хотел бы знать,Я вижу, что происходит после того, как я вызвал метод GetTags().

Также я прочитал следующее здесь .

"if you are not satisified with the COM Interop marshaller, you can "override" just about every aspect of it through the very large and useful System::Runtime::InteropServices namespace"

Как мне достичь вышеуказанного?

РЕДАКТИРОВАТЬ: Добавление сценария тестирования Delphi, который работает

procedure TComTestForm.TestUserBtnClick(Sender: TObject);
var
  nCnt :integer;
  User :IUser;
  Persona :IUserPersona;
  ArrayBounds :TSafeArrayBound;
  ArrayData :Pointer;
  TagList :PSafeArray;
  nSize :integer;
begin
  User := Session.GetUser;

  ArrayBounds.lLbound   := 0;
  ArrayBounds.cElements := 0;

  TagList := SafeArrayCreate( varInteger, 1, ArrayBounds );
  User.GetTags( TagList );
  if SafeArrayAccessData( TagList, ArrayData ) = S_OK then
    begin
      nSize := TagList.rgsabound[0].cElements;
      OutLine( '----Available Tags, ' + IntToStr(nSize) + ' tags' );
  for nCnt := 0 to nSize - 1 do
    begin
      OutLine( IntToStr( IntegerArray(ArrayData)[nCnt] ) );
    end;
  OutLine( '----');

  SafeArrayUnAccessData( TagList );
  SafeArrayDestroy( TagList );
    end;

end;

Ответы [ 2 ]

2 голосов
/ 09 мая 2011

Еще одно обновление : Я просто понимаю, что, возможно, вы имеете в виду, что сам GetTags должен заполнять этот массив (из кода COM). Но это никогда не может работать, так как этот параметр является параметром [in].

Чтобы компонент COM мог заполнить этот массив, он должен быть передан как параметр [in, out] и по ссылке (SAFEARRAY *).


Обновление : Хорошо, очевидно, я смешивал создание COM-компонента в .NET с вызовом COM-компонента из .NET.

CCW (com-вызываемая оболочка) действительно принимает массив .NET для COM SafeArray. Я вижу, вы создаете свой массив в коде в вашем вопросе, но вы не показываете, как вы на самом деле его заполняете. Может быть, что-то не так с этим кодом? Не могли бы вы поделиться этим?


Не уверен, что это решение вашей проблемы, но в прошлом у меня были проблемы с COM-взаимодействием и SAFEARRAY.

Одна вещь, которую я узнал из этого, состоит в том, что .NET эквивалент COM SAFEARRAY всегда должен быть object, поэтому попробуйте передать ваш массив как object вместо Array.

1 голос
/ 09 мая 2011

Стесняюсь предложить это как ответ, но ...

Если тестовый код Delphi действительно работает, как отмечено в другом месте, это означает, что метод GetTags не должен воспроизводиться должным образом по правилам SAFEARRAY. Если метод COM всегда вызывается внутри процесса, вы МОЖЕТЕ заставить работать код .NET, выполняя некоторое пользовательское упорядочение вручную, точно следуя тому, что делает неуправляемый тестовый код Delphi.

В качестве грубого наброска, я бы предположил, что это будет включать:

  • выделение неуправляемого буфера для хранения значений массива
  • вызов API-интерфейса инициализации SALEARRAY Ole через P / Invoke для выделения структуры SAFEARRAY и присоединения к ней буфера массива в качестве члена pData
  • вызов метода GetTags с этим SAFEARRAY
  • сортировка вашего неуправляемого буфера в управляемый массив до ...
  • вызов Win32 API для уничтожения SAFEARRAY

Но гораздо лучше изменить COM-компонент для правильной работы, если вы можете.

...