|
|
Работа с 1C Предприятие из Visual C++
|
|
Страница 1 из 2 В данной статье показано, как можно работать с 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С. В конце концов пришлось удалить старого пользователя, и создать нового. Осторожнее при разработке сервисов! Это окно будет появляеться на виртуальном десктопе, и Вы просто ничего не увидите (если конечно, не поставите галочку «взаимодействовать с рабочим столом»).
|
|
-
Visual C++,
Работа с СУБД Oracle через интерфейс OCCI
OCCI - расшифровывается как Oracle C++ Call Interface и представляет собой специализированное апи для работы с СУБД Oracle используя C++ что в общем то явствует из названия. Для использования необходимо подключить заголовочный файл "occi.h"....
-
Visual C++,
Задача Майхилла для Microsoft Visual C++
О синхронизации процессов в среде Windows. Задача Майхилла - еще один (наряду с задачей RS-триггера) пример решения нетривиальных проблем создания сложных систем. Справившись с ней, мы научимся организовывать взаимодействие параллельно работающих компонентов сложных программных комплексов в жестких условиях. ...
-
Visual C++,
Использование ODBC в Visual C++
Класс CDatabase представляет собой класс, который обеспечивает связь с источником данных. Под источником данных может пониматься как непосредсвенно файл, в котором находится таблица, например dBase, так и файл с многими таблицами, например Microsoft Access или сервер баз данных Oracle, MS SQL Server и т.д. Для связи с источником данных используется интерфейс ODBC. У данного класса есть папа в виде класса
-
Visual C++,
Создание простого приложения с плагинами
В этой статье описываются принципы и решения, применяемые при проектировании приложений, которые будут использовать внешние, динамически подключаемые, модули. Эта статья более ориентирована на тех, кто хочет использовать механизмы подключения/отключения функциональности приложения, наподобии механизма Aobe Photoshop или Far, а не просто многократного использования кода в разных приложениях....
-
Visual C++,
Как самому сделать plug-in к FAR на Visual C++
Трудно найти человека, которые не знает или не использует Far - IMHO лучший клон NC для Windows. Кроме того, что это просто очень хороший файл менеджер, к нему есть огромное количество plug-in модулей. Plug-in модуль это DLL-файл, который вместо стандартных Windows функций по работе с монитором, клавиатурой и т.д. обращается к функциям Far-а. Far поддерживает весь набор функций для работы в текстовом режиме. Установка plug-in модуля происходит предельно просто - DLL файл и файлы данных коп...
-
Visual C++,
Использование директивы #import в Visual C++
В данной статье я попытаюсь объяснить то, как работает эта директива и привести несколько примеров её использования. Надеюсь, после этого вы тоже найдёте её полезной. Директива #import введена в Visual C++, начиная с версии 5.0. Её основное назначение облегчить подключение и использование интерфейсов COM, описание которых реализовано в библиотеках типов....
-
Visual C++,
Создание VxD на Visual C++ без ассемблерных модулей
Виртуальные драйверы устройств (VxD) в Windows во многих случаях являются единственным «честным» способом обхода ограничений, установленных системой для приложений Win32: невозможности прямого доступа к портам ввода-вывода и служебной памяти, эффективной обработки аппаратных прерываний, использования сервисных функций существующих VxD и т.п. Кроме того, без VxD не обходится практически ни один полноценный драйвер физического или виртуального устройства....
-
Visual C++,
Основы разработки прикладных виртуальных драйверов
Как уже отмечалось ранее, виртуальные драйверы служат прежде всего для виртуализации аппаратуры, то есть для предоставления одновременно выполняемым задачам возможности совместного использования устройств компьютера. Измерительная или управляющая аппаратура, подключаемая к компьютеру с целью создания автоматизированной установки, вряд ли будет эксплуатироваться в многозадачном режиме, однако использование для ее управления виртуального драйвера может заметно сократить программные издержки ...
|
|
|