(495) 925-0049, ITShop интернет-магазин 229-0436, Учебный Центр 925-0049
  Главная страница Карта сайта Контакты
Поиск
Вход
Регистрация
Рассылки сайта
 
 
 
 
 

Работа с 1C Предприятие из Visual C++

Источник: cyberguru
форум visual c++

В данной статье показано, как можно работать с 1С Предприятием из С++ с помощью OLE DB. Так же она будет интересна тем, кто не пользуется C++, но хочет узнать подробности "а как оно устроено внутри 1С". В данной статье речь пойдет об 1С Предприятии версии 7.7. Полагаю, что в версии 8 мало что изменилось. Предполагается, что читатель хотя бы чуть-чуть знаком с 1С Предприятием. Так же предполагается, что вы изучали официальное руководство 1С по вопросам OLE DB (часть вторая описания языка), но осталься недоволен - т.к. исходники там приведены для Visual Basic, а вам ну очень нужен именно C++ (кстати - не обязательно Visual - главное что бы в вашем компиляторе была возможность работать с OLE). 1С Предприятие предоставляем пользователям механизм OLE DB. Если Вам вдруг захотелось использовать какие либо данные из 1С Предприятия в вашей программе - вы можете воспользоваться этим механизмом. Совсем просто это делается в таких языках, как Visual Basic или Delphi. В них вся работа с OLE-интерфейсами замаскирована от программиста насколько возможно. Это, с одной стороны, очень удобно, но с другой стороны - у нас всегда есть возможность повысить производительность путём использования С++. Он от своих адептов ничего не маскирует, это позволяет кое где сэкономить лишний байт или миллисекунду, но превращает работу с OLE DB в ад. Дело в том, что 1С не предоставляет для своих пользователей библиотеки импорта (*.tlb), поэтому единственный способ работы (если не использовать какие либо обёртки) - это позднее связывание. В Сети полно информации, как работать с 1С Предприятием из Delphi или Visual Basic, но практически совсем нет примеров с Visual C++.

Эта статья призвана заполнить этот пробел. Здесь Вы найдете кусочки рабочего кода, который Вы можете дописывать и модифицировать по своему усмотрению. По себе знаю, что порою достаточно подсмотреть одним глазком, что бы стало ясно, что к чему. Кроме того, я расскажу про некоторые "тонкие" моменты работы с 1С, которые мягко обойдены в официальных изданиях, имеющих красивый красно-желтый цвет.

Наиболее разумным и удобным будет следующее решение: мы организуем всю необходимую работу с 1С в виде отдельной экспортируемой функции глобального модуля (я надеюсь, Вы уже научились открывать в 1С Глобальный модуль и добавлять в него экспортируемые функции). Мы будем вызывать нужную функцию глобального модуля, которая будет возвращать нужное значение. Для многих практических приложений этого вполне достаточно.

#include <objbase.h>
#include <comdef.h>

//для начала инициализируем COM
HRESULT hr = CoInitialize(NULL);
if(FAILED(hr))
{
  AfxMessageBox("Невозможно инициализировать COM!");
  return FALSE;
}

/*
Прежде всего, нам необходимо получить
ID сервера OLE Automation 1С Предприятия.
*/
CLSID   cls77;

/*
Используем универсальный ключ 1С Предприятия

Подробнее см. КЖК - если у Вас установлена единственная
версия 1С - то этого достаточно, если несколько разных,
то нужно загрузить нужный. Вот краткий список возможных значений:

V1CEnterprise.Application - версия независимый ключ;
V77.Application - версия зависимый ключ;
V77S.Application - версия зависимый ключ, SQL-версия;
V77L.Application - версия зависимый ключ, локальная-версия;
V77M.Application - версия зависимый ключ, сетевая-версия.
*/

hr = CLSIDFromProgID(L"V77.Application", &cls77);
if(FAILED(hr))
{
  AfxMessageBox("Переустановите 1С Предприятие!");
  CoUninitialize();
  return FALSE;
}

//основной интерфейс, за который мы будем "дёргать"
IDispatch *pv77;

/*
Создаём инстанцию 1С Предприятия.

CLSCTX_LOCAL_SERVER - это значит, что 1С Предприятие
будет запущено в виде отдельного процесса - по другому оно не умеет.
*/

hr = CoCreateInstance(cls77, NULL, CLSCTX_LOCAL_SERVER, IID_IDispatch, (void**)&pv77);

if(FAILED(hr)  //  !pv77)
{
  AfxMessageBox("Невозможно инициализировать интерфейс 1С Предприятия");
  CoUninitialize();
  return FALSE;
}

/*
пока всё было понятно и очевидно, дальше начинаются сложности…
1С предоставляет для запуска приложения функцию Initialize.
Вызов этой функции выглядит в VB элементарно

V7.Initialize(V7.RMTrade,"D:\1C\ТипаБаза /N"+Пользователь ,"NO_SPLASH_SHOW");

- мы практически забываем, что же происходит внутри.
Но занимающиеся С++ люди хладнокровные, трудностей не боятся.
Во-первых: мы должны помнить, что аргументы необходимо заталкивать задом наперёд…
Во-вторых: мы должны помнить, что RMTrade - это доже IDispatch интерфейс.. и его сперва нужно
получить.
*/

VARIANT       vRet;
DISPID dispIDRmTrade, dispIDInitialize;
DISPPARAMS args = {0, 0, 0, 0};
VARIANT vars[3];  // Параметры для вызова Initialize

//Мы получим IDispatch интерфейс от RMTrade сразу в vars[2]

BSTR rmTrade = L"RMTrade";

hr = pv77->GetIDsOfNames(IID_NULL, &rmTrade, 1, 0, &dispIDRmTrade);

if (FAILED(hr))
{
  AfxMessageBox("Невозможно получить ID от RMTrade");
  if (pv77)
    pv77->Release();
  CoUninitialize();
  return FALSE;
}

hr = pv77->Invoke(dispIDRmTrade, IID_NULL, 0, DISPATCH_PROPERTYGET, &args,
      &vars[2], NULL, NULL);

if (FAILED(hr))
{
  AfxMessageBox("Невозможно получить интерфейс от RMTrade");
  if (pv77)
    pv77->Release();
  CoUninitialize();
  return FALSE;
}

//нужно получить ID для Initialize(..);
BSTR init = L"Initialize";
hr = pv77->GetIDsOfNames(IID_NULL, &init, 1, 0, &dispIDInitialize);
if (FAILED(hr))
{
  AfxMessageBox ("Не удалось получить ID от Initialize")
  if (pv77)
    pv77->Release();
  CoUninitialize();
  return FALSE;
}

/*
а теперь - вызвать этот самый Initialize(..),
но сперва необходимо заполнить массив аргументов функции
*/

args.cArgs = 3;
args.rgvarg = vars;
vars[0] = _variant_t("NO_SPLASH_SHOW");
vars[1] = _variant_t("/D D:\1S /N Denis /P Denis ");

/*
vars[2] - у нас уже есть, мы его получили при запросе
интерфейса RMTrade в момент предыдущего Invoke
*/

hr = pv77->Invoke(dispIDInitialize, IID_NULL, 0, DISPATCH_PROPERTYGET, &args,
   &vRet, NULL, NULL);

if(FAILED(hr) //  (vRet.vt ==  VT_BOOL && vRet.bstrVal == 0x00))
{
  AfxMessageBox("Невозможно запустить 1С Предприятие");
}

Надо заметить, что с этим последним Invoke нужно быть вообще осторожнее. У меня было такое, что даже при правильной командной строке вызов не удавался. При этом должно появиться окно, предлагающее задать имя базы, имя пользователя и т.п., возможно, это такая особенность дизайна 1С. В конце концов пришлось удалить старого пользователя, и создать нового. Осторожнее при разработке сервисов! Это окно будет появляеться на виртуальном десктопе, и Вы просто ничего не увидите (если конечно, не поставите галочку "взаимодействовать с рабочим столом").

Ссылки по теме


 Распечатать »
 Правила публикации »
  Написать редактору 
 Рекомендовать » Дата публикации: 27.10.2009 
 

Магазин программного обеспечения   WWW.ITSHOP.RU
Microsoft Office 365 для Дома 32-bit/x64. 5 ПК/Mac + 5 Планшетов + 5 Телефонов. Подписка на 1 год.
Microsoft Office 365 Персональный 32-bit/x64. 1 ПК/MAC + 1 Планшет + 1 Телефон. Все языки. Подписка на 1 год.
Microsoft Office 365 Бизнес. Подписка на 1 рабочее место на 1 год
Microsoft Office 365 Профессиональный Плюс. Подписка на 1 рабочее место на 1 год
Microsoft 365 Business Basic (corporate)
 
Другие предложения...
 
Курсы обучения   WWW.ITSHOP.RU
 
Другие предложения...
 
Магазин сертификационных экзаменов   WWW.ITSHOP.RU
 
Другие предложения...
 
3D Принтеры | 3D Печать   WWW.ITSHOP.RU
 
Другие предложения...
 
Новости по теме
 
Рассылки Subscribe.ru
Информационные технологии: CASE, RAD, ERP, OLAP
Безопасность компьютерных сетей и защита информации
Новости ITShop.ru - ПО, книги, документация, курсы обучения
Программирование на Microsoft Access
CASE-технологии
Вопросы и ответы по MS SQL Server
Один день системного администратора
 
Статьи по теме
 
Новинки каталога Download
 
Исходники
 
Документация
 
 



    
rambler's top100 Rambler's Top100