Приложения-клиенты СОМ. Пример использования директивы #import

   
На этом шаге мы рассмотрим пример использования директивы #import.

   
В этом упражнении мы научимся использовать директиву #import для импорта библиотеки типов, а также
применять в коде своего клиентского приложения сгенерированные типы "интеллектуальных" указателей и
функции-оболочки. Мы отредактируем созданное ранее приложение EncodeHello.

  • Импорт библиотеки типов EncodeServer.
  • Вернитесь к проекту EncodeHello. В FileView найдите и откройте файл StdAfx.h.
  • Перед строкой с комментарием //{{AFX_INSERT_LOCATION}} вставьте строку следующего вида:
      #import "C:\EncodeServer\Debug\EncodeServer.dll" no_namespace
    


    Рис.1. Добавленная строка

       
    Убедитесь, что путь к файлу EncodeServer.dll указан верно, - на Вашем компьютере он может отличаться от
    указанного в примере. Вы обязаны указать атрибут no_namespace - он информирует, что все классы,
    созданные из библиотеки типов, будут определены в глобальном пространстве имен.

  • Сохраните и закройте файл StdAfx.h. В FileView щелкните правой кнопкой мыши файл StdAfx.cpp и в открывшемся контекстном
    меню выберите Compile StdAfx.cpp.
  • После завершения компиляции найдите в папке EncodeHello\Debug файлы EncodeServer.tlh и
    EncodeServer.tli. Просмотрите TLH-файл. Обратите внимание на объявление "интеллектуального" указателя IEncoderPtr в такой строке:

      _COM_SMARTPTR_TYPEDEF(IEncoder, __uuidof(IEncoder));
    

    А также на следующие функции-члены, объявленные в определении структуры IEncoder:

        //
        // Данные для свойства
        //
    
        __declspec(property(get=GetKey,put=PutKey))
        short Key;
    
        //
        // Методы оболочки для обработки исключений
        //
    
        _bstr_t EncodeString (
            _bstr_t instring );
        short GetKey ( );
        void PutKey (
            short pVal );
    
        //
        // "Сырые" методы интерфейса
        //
    
        virtual HRESULT __stdcall raw_EncodeString (
            BSTR instring,
            BSTR * outstring ) = 0;
        virtual HRESULT __stdcall get_Key (
            short * pVal ) = 0;
        virtual HRESULT __stdcall put_Key (
            short pVal ) = 0;
    

       
    "Сырые" методы в конце кода похожи на аналогичные методы в файле EncodeServer.h, сформированном MIDL-компилятором. Тем не
    менее методы оболочки больше напоминают функции-члены обычного класса C++. Обратите внимание, что для объявления
    переменной-члена Key используется ключевое слово __declspec(property). Это позволяет пользователю класса
    вызывать функции Get() и Put(), просто размещая переменную-член Key справа или слева от оператора присваивания.
    Также обратите внимание, что эти функции используют класс _bstr_t в качестве типа параметра и возвращаемого значения.

       
    Реализация функций-оболочек находится в файле EncodeServer.tli В теле приведенной ниже функции GetKey() показано, как в
    качестве возвращаемого значения передается параметр [out, retval], а значение HRESULT перехватывается и возвращается как
    возможное исключение

    inline short IEncoder::GetKey ( ) {
        short _result;
        HRESULT _hr = get_Key(&_result);
        if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
        return _result;
    }
    

       
    После импорта библиотеки типов можно приступить к изменению кода приложения и воспользоваться классами, созданными в результате импорта.

  • Модификация кода приложения EncodeHello.
  • Удалите следующие директивы #include в начале файла EncodeHello.срр:
    #include "EncodeServer.h"
    #include "EncodeServer_i.c"
    
  • Перепишите функцию main() приложения EncodeHello как показано ниже:
    int main(int argc, char* argv[])
    {
      CoInitialize( NULL );
      {
    	IEncoderPtr pServer;
    
    	HRESULT hr = pServer.CreateInstance( __uuidof( Encoder ) );
    
    	if( SUCCEEDED( hr ) )
    	{
    	  short nKey = 1;
    	  cout << "Enter a code key between -5 and 5: ";
    	  cin >> nKey;
    
    	  _bstr_t bstrHello = "Hello World!";
    	  _bstr_t bstrCodedHello;
    
    	  try
    	  {
    	    pServer->Key = nKey; 
    	    bstrCodedHello = pServer->EncodeString( bstrHello );
    
    	    cout << "\n" << (const char *) bstrCodedHello << "\n\n";  
    
    	  }
    		
    	  catch( _com_error e )
    	  {
    	    cout <<  e.ErrorMessage() << "\n\n";
    	  }
    
    	}
      }
    
      ::CoUninitialize();
    
      return 0;
    }
    

    Текст этого приложения можно взять здесь (162,0 Кб).

   
Обратите внимание, что в этом примере код приложения размещается в собственном блоке между вызовами
CoInitialize() и CoUninitialize(). Это гарантирует, что переменная pServer не выйдет из области
видимости до вызова CoUninitialize(). Когда же pServer выйдет из области видимости, деструктор
_com_ptr_t вызовет метод Release() через инкапсулированный указатель на IEncoder. Если же
это произойдет после закрытия библиотек СОМ, результаты могут быть катастрофическими
Заметьте, что по сравнению с предыдущей версией читать такой код намного легче и что он очень похож на обычный
код C++, в котором СОМ не применяется. Но пусть его простота Вас не обманывает - невозможно
написать высокопроизводительный и безошибочный CОМ-код без глубокого понимания основополагающих
принципов этой технологии.

   
Со следующего шага мы начнем рассматривать повторное использование COM-объектов.



Вы можете оставить комментарий, или Трекбэк с вашего сайта.

Оставить комментарий