Delphi World - это проект, являющийся сборником статей и малодокументированных возможностей  по программированию в среде Delphi. Здесь вы найдёте работы по следующим категориям: delphi, delfi, borland, bds, дельфи, делфи, дэльфи, дэлфи, programming, example, программирование, исходные коды, code, исходники, source, sources, сорцы, сорсы, soft, programs, программы, and, how, delphiworld, базы данных, графика, игры, интернет, сети, компоненты, классы, мультимедиа, ос, железо, программа, интерфейс, рабочий стол, синтаксис, технологии, файловая система...
Получение интерфейса объекта из OleVariant

Microsoft выпускает новый многосерийный триллер:
OLE
OLE 2
OLE Возвращается

В примерах Delphi по использованию COM-объектов, как правило, используется примерно следующая конструкция:


var
  _ComServer: variant;
begin
  _ComServer := CreateComObject(CLSID_ComServer);
  // что-то делаем с COM-объектом
  _ComServer.DoSomething;
end;

Здесь после создания объекта вызывается некоторый гипотетический метод созданного объекта - DoSomething. После создания объекта можно также изменять значения его свойств, передавать его в качестве параметра в другие методы и процедуры и пр. Единственное видимое неудобство заключается в том, что при использовании переменной типа вариант компилятор не в состоянии проверить синтаксическую корректность обращений к объекту и, соответственно, в редакторе Delphi не работает on-line подстановка (когда вы, например, вводите точку после имени переменной объектного типа, редактор выводит окно с перечнем наиболее подходящих свойств и методов объекта).

Применение переменных типа интерфейс устраняют это неудобство. Достаточно написать так (в предположении, что действительно существует интерфейс IMyInterface):


var
  _ComServer: variant;
begin
  _ComServer := CreateComObject(CLSID_ComServer);
  // что-то делаем с COM-объектом
  _ComServer.DoSomething;
end;

Кроме того, что компилятор теперь совершенно четко понимает, какого типа переменная используется и что с ней можно делать, "за кулисами" происходит еще и повышение быстродействия работы с объектом, т.к. в первом случае вся работа с объектом осуществляется опосредованно через метод Invoke его интерфейса IDispatch (любознательные читатели могут более подробно прочитать про IDispatch в справочной системе Delphi и MSDN).

Если же объект передается в какой-либо модуль через переменную (параметр) типа Variant (OleVariant), то, к сожалению, Delphi опять возвращает все на круги своя (см. пример 1). Для того, чтобы получить из Variant требуемый типизованный интерфейс, достаточно выполнить простейшее преобразование:


procedure MyProc(_MyObject: variant);
var
  _ComServer: IMyInterface;
begin
  _ComServer := IMyInterface(TVarData(_MyObject).VUnknown);
  // что-то делаем с COM-объектом
  _ComServer.DoSomething;
end;

Можно усилить контроль за передаваемым объектом, проверяя тип данных в variant:


procedure MyProc(_MyObject: variant);
var
  _ComServer: IMyInterface
begin
  if (VarType(_MyObject) and varUnknown) = varUnknown then
  begin
    _ComServer := IMyInterface(TVarData(_MyObject).VUnknown);
    // что-то делаем с COM-объектом
    _ComServer.DoSomething;
  end;
end;

Можно использовать еще более строгую проверку наличия в variant ожидаемого интерфейса:


procedure MyProc(_MyObject: variant);
var
  _ComServer: IMyInterface;
  _IUnknown: IUnknown;
begin
  if (VarType(_MyObject) and varUnknown) = varUnknown then
  begin
    _IUnknown := IUnknown(TVarData(_MyObject).VUnknown);
    if _IUnknown.QueryInterface(IID_IMyInterface, _ComServer) = S_OK then
      // что-то делаем с COM-объектом
      _ComServer.DoSomething;
  end;
end;

Проект Delphi World © Выпуск 2002 - 2004
Автор проекта: ___Nikolay