Библиотека «Comtools»

Библиотека предназначеная для облегчения работы с технологией Automation, без использования директивы #import. Automation организует доступ к свойствам и вызов методов некоторого COM-объекта, посредством механизма IDispatch. Библиотека разрабатывалась с использованием компилятора mingw 3.4.5, на других компиляторах тестирование не проводилось. Архив с исходниками лежит здесь

Описание

class Variant: public VARIANT {
public:
  //Конструкторы и операторы '='
  Variant();
  
  Variant(const Variant& value) throw(HRESULT);  
  Variant& operator = (const Variant& other)throw(HRESULT);
  
  template <typename T> Variant(const T& value)throw(HRESULT);
  template <typename T>  Variant& operator = (const T& value)throw(HRESULT)
  
  template <VARTYPE vcode, typename T> Variant(const T& value)throw(HRESULT);
  template <VARTYPE vcode, typename T> Variant& operator = (const T& value)throw(HRESULT);

  // Предикаты
  bool is_signed() const;  
  bool is_unsigned() const;  
  bool is_integral() const;  
  bool is_bstr() const;  
  bool is_floating() const;  
  bool is_pointer() const;
  bool is_null() const;  
  bool empty() const;
  bool operator < (const Variant& other);
  bool operator == (const Variant& other);
  template <typename T> bool operator < (const T& value);
  template <typename T> bool operator == (const T& value);
  
  //Арифметика
  Variant& operator *= (const Variant& other) throw(HRESULT);
  Variant& operator += (const Variant& other) throw(HRESULT);  
  Variant& operator -= (const Variant& other) throw(HRESULT);  
  Variant& operator /= (const Variant& other) throw(HRESULT);

  template <typename T> Variant& operator *= (const T& value);
  template <typename T> Variant& operator += (const T& value);
  template <typename T> Variant& operator -= (const T& value);
  template <typename T> Variant& operator /= (const T& value);

  virtual ~Variant();
};

inline Variant operator * (const Variant& a, const Variant& b);
inline Variant operator + (const Variant& a, const Variant& b);
inline Variant operator - (const Variant& a, const Variant& b);
inline Variant operator / (const Variant& a, const Variant& b);

// Преобразует строку WideChar в строку MultiByte c указанием требуемой кодировки
// Параметр 'enc' одно из значений {CP_ACP,CP_OEMCP ,CP_UTF7, CP_UTF8}
std::string ConvertFromWideChar(const LPOLESTR str, int enc = CP_ACP);
inline std::string ConvertFromWideChar(const Variant& str, int enc = CP_ACP);

// Преобразует строку MultiByte в строку WideChar c указанием исходной кодировки
// Параметр 'enc' одно из значений {CP_ACP,CP_OEMCP ,CP_UTF7, CP_UTF8}
BSTR Convert2WideChar(const std::string& src, int enc = CP_ACP);

// Расшифровка кодов ошибок
std::string translateHRESULT(HRESULT hr);
  

// Запуск сервера автоматизации, параметр ctx должен соответствовать спецификации
// CoCreateInstance
Variant startApp(LPCOLESTR app_name, CLSCTX ctx = CLSCTX_LOCAL_SERVER) throw (HRESULT);

//Установить значение свойства mname у объекта disp значением value.
template <typename T>
inline void invokeSetProperty(const VARIANT& disp, LPOLESTR mname, const T& value);

//Вызвать метод mname у объекта disp. Также возможно указание до
//10 параметров произвольного типа a1—a10
inline Variant invokeMethod(const VARIANT& disp, LPOLESTR mname);

template <typename T1, typename T2,...,typename T10>
inline Variant invokeMethod(const VARIANT& disp, LPOLESTR mname, const T1& a1, const T2& a2,...,const T10& a10);


//Получить значение свойства с именем mname у объекта disp. Также возможно
//указание до 10 параметров произвольного типа a1 — a10
inline Variant invokeGetProperty(const Variant& disp, LPOLESTR mname);

template <typename T1, typename T2,...,typename T10>
inline Variant invokeGetProperty(const VARIANT& disp, LPOLESTR mname, const T1& a1, const T2& a2,...,const T10& a10);

Пример использования

В качестве примера я взял вот этот код и переписал его с использованием Comtools,сохранив функциональность.

#include  <iostream>
#include  "comtools.hpp"
using namespace std;
int main(){
  try{
  CoInitialize(static_cast<LPVOID>(0));
  
  //Запускаем Excel
  Variant xlApp = startApp(OLESTR("Excel.Application"));

  //Делаем Excel видимым
  invokeSetProperty(xlApp,OLESTR("Visible"), true);

  //Получаем свойство 'Application.Workbooks'
  Variant Wkbooks = invokeGetProperty(xlApp, OLESTR("Workbooks"));

  //Вызываем метод 'Workbooks.Add' - создание новой книги
  Variant Wkbook = invokeMethod(Wkbooks,OLESTR("Add"));
  
  //Получаем свойство 'Workbook.ActiveSheet' - Активный лист
  Variant ActSht = invokeGetProperty(Wkbook,OLESTR("ActiveSheet"));
  
  //Получаем свойство 'Range("A1:O15")' активного листа
  Variant Range = invokeGetProperty(ActSht,OLESTR("Range"), Convert2WideChar ( ("A1:O15")));
  
  // Create a 15x15 safearray
  SAFEARRAYBOUND sab[2];
  sab[0].lLbound = 1; sab[0].cElements = 15;
  sab[1].lLbound = 1; sab[1].cElements = 15;
  SAFEARRAY* sarray = SafeArrayCreate (VT_VARIANT, 2, sab);

   // Fill safearray with some values...
  for(int i=1; i<=15; i++) {
    for(int j=1; j<=15; j++) {
      // Create entry value for (i,j)
      Variant tmp = i*j;
      // Add to safearray...
      long indices[] = {i,j};
      HRESULT hr = SafeArrayPutElement(sarray, indices, static_cast<void*>(dynamic_cast<VARIANT*>(&tmp)));
      if (FAILED(hr))
        throw hr;
    }
  }
  //Для автоматической очистки созданного массива
  Variant array = sarray;

  //'Range.Value' заполняем значениями из массива
  invokeSetProperty(Range,OLESTR("Value"),array);

  ::MessageBox(NULL, "All done.", "Notice", 0x10000);
  
  //Типа, книгу мы уже сохранили
  invokeSetProperty(Wkbook, OLESTR("Saved"), true);
  
  //Выход
  invokeMethod(xlApp,OLESTR("Quit"));
  
  CoUninitialize();
  }
  catch(HRESULT hr){
    cerr << hex << hr << "-" << translateHRESULT(hr)<< endl;
  }
  
  return 0;
}

Халин Андрей Борисович