Созданный COM-компонент становится недействительным после выхода из метода (но не в область его действия)

В настоящее время я тестирую два внешних компонента COM. У меня большая проблема с одним из них, но я не могу найти причину такого поведения. Позвольте мне привести пример.

const
  CLASS_SomeClas: TGUID = '{SomeGUID}';
type

ISomeInterface = interface(IDispatch)
  ['{SomeGUID}']
  function SomeMethod(const AInput: WideString): WideString; safecall;
end;

TWrappingClass = class(TObject)
strict private
  FInstance: ISomeInterface;
  procedure CreateInstance;
public
  procedure DoYourActualJob;
end;

procedure TWrappingClass.CreateInstance;
begin
  FInstance := CreateComObject(CLASS_SomeClass) as ISomeInterface;
  dbg(FInstance._AddRef); // Debugs 3
  dbg(FInstance._AddRef); // Debugs 4
  dbg(FInstance.Release); // Debugs 3
  dbg(FInstance._AddRef); // Debugs 4
  FInstance.SomeMethod(''); //Runs as expected
end;

procedure TWrappingClass.DoYourActualJob;
begin
  CreateInstance;
  dbg(FInstance._AddRef); //Debugs -1!
  FInstance.SomeMethod(''); //AV
end;

В соответствии с примером экземпляр становится недействительным после того, как он уходит CreateInstance метод. Компонент предназначен для работы со многими последовательными вызовами SomeMethod и он работает, когда вызывается внутри одного метода. Может ли кто-нибудь дать мне понять, что на самом деле там происходит, почему мой экземпляр становится недействительным? Это проблема с моим кодом, с Delphi или с кодом компонента? Когда я меняю реализацию TWrappingClass другому поставщику (то есть я меняю оба ISomeInterface а также CLASS_SomeClass) тогда все отлично работает.

РЕДАКТИРОВАТЬ: Поведение не меняется, когда я даже не звоню SomeMethod, То есть после того как я уйду CreateInstance, позвонить _AddRef возвращает -1. Компонент, который я тестирую, находится здесь CadEditorX Вероятно, мне не разрешено подключать OCX без нарушения его лицензии.

1 ответ

Решение

Вы четко указали в вопросе, что ошибочное поведение происходит только с одним конкретным COM-объектом. Учитывая этот факт и то, что подсчет ссылок в Delphi COM, как известно, работает правильно, единственный разумный вывод заключается в том, что ошибка заключается в этом конкретном COM-объекте.

Единственный выход - связаться с продавцом этого COM-объекта и отправить ему отчет об ошибке.


Одна вещь, на которую стоит обратить внимание, с точки зрения возможного обхода, - это то, как вы создаете объект. Ты используешь CreateComObject, Это получает идентификатор класса и возвращает IUnknown, Это вызывает CoCreateInstance передача идентификатора класса и запрос IUnknown интерфейс. Затем вам нужно запросить ваш интерфейс, ISomeInterface, Итак, ваш код выглядит так:

var
  iunk: IUnknown;
  intf: ISomeInteface;
....
CoCreateInstance(ClassID, nil, CLSCTX_INPROC_SERVER or CLSCTX_LOCAL_SERVER, 
  IUnknown, iunk);
iunk.QueryInterface(ISomeInterface, intf);

Тот факт, что у вас есть две интерфейсные переменные, одна IUnknown и один ISomeInterface объясняет, почему вы видите количество ссылок, которые вы делаете. Теперь вы можете подумать, что у вас есть только одна переменная интерфейса, но это не так. Их два, только один из них является неявным локальным. Вы можете увидеть это, посмотрев скомпилированный код и пройдя через отладчик.

Этот код:

procedure TWrappingClass.CreateInstance;
begin
  FInstance := CreateComObject(CLASS_SomeClass) as ISomeInterface;
end;

компилируется так, как если бы это было (игнорируя проверку ошибок):

procedure TWrappingClass.CreateInstance;
var
  iunk: IUnknown;
begin
  iunk := CreateComObject(CLASS_SomeClass);
  try
    FInstance := CreateComObject(CLASS_SomeClass) as ISomeInterface;
  finally
    iunk := nil;
  end;
end;

Возможно, COM-компонент не может обработать вызов Release сделано на его IUnknown интерфейс.

Таким образом, вы можете попытаться обойти это, используя CoCreateInstance вместо CreateComObject, Проходить ISomeInterface как riid параметр.

OleCheck(CoCreateInstance(CLASS_SomeClass, nil, CLSCTX_INPROC_SERVER 
  or CLSCTX_LOCAL_SERVER, ISomeInterface, FInstance));
Другие вопросы по тегам