Здрасте. Может вопрос и заюзаный, но он есть: как сделать выборку данных из БД.
Я пишу приложение Win32 и мне нужны данные из 1С(например контрагенты). Насколько я понял есть несколько способов выборки, но я реально понял только 2:
1. Делать запрос к БД - но в MSSQL базы сохранены с произвольным именем, тут и проблемы;
2. Сделать экспорт БД у файл и розпарсить файл.
Первый способ отпадает потому, что не факт, что после обновления имя базы не поменяеться.
Второй способ плох потому, что явно нужно заходить в 1С и выбирать экспорт у файл.
Может есть третий способ, при котором не нужно заходить непосредственно в программу для экспорта и выбирать файл с данными(может есть статический файл данных для прописки пути в коде программы)
1С Предприятие 7.7(сетевая версия)
Конфигурация: "FORT:2000" редакция 3.77 от 23.01.2007
Можно подключаться непосредственно к 1с и общаться с ней.
xunicorn, на чем пишете?
Самый лёгкий способ - на сервером компьютере автоматом периодически запускается 1с и автоматом выполняет обработку.
Обработка сохраняет нужные данные в файл; кладёт на фтп.
Потом 1с автоматом закрывается. Или не закрывается и остается открытой и переодически выполняет обработку.
1С Предприятие предоставляем пользователям механизм OLE DB. Если Вам вдруг захотелось использовать какие либо данные из 1С Предприятия в вашей программе – вы можете воспользоваться этим механизмом. Совсем просто это делается в таких языках, как Visual Basic или Delphi. В них вся работа с OLE-интерфейсами замаскирована от программиста насколько возможно. Это, с одной стороны, очень удобно, но с другой стороны – у нас всегда есть возможность повысить производительность путём использования С++. Он от своих адептов ничего не маскирует, это позволяет кое где сэкономить лишний байт или миллисекунду, но превращает работу с OLE DB в ад. Дело в том, что 1С не предоставляет для своих пользователей библиотеки импорта (*.tlb), поэтому единственный способ работы (если не использовать какие либо обёртки) – это позднее связывание. В Сети полно информации, как работать с 1С Предприятием из Delphi или Visual Basic, но практически совсем нет примеров с Visual C++.
Наиболее разумным и удобным будет следующее решение: мы организуем всю необходимую работу с 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С Предприятие");
}
Функция ПриветМир (Слово) Экспорт
ВозврСтрока = "Привет мир: " + Слово + " спасибо за весточку в красно-желтую темницу!";
Возврат ВозврСтрока;
КонецФункции
VARIANT vRetEvalExpr;
UINT nArgErrRetEvalExpr;
DISPPARAMS argsRetEvalExpr = {0, 0, 0, 0};
VARIANT varsRetEvalExpr [1];
///.......///
argsRetEvalExpr.cArgs = 1;
argsRetEvalExpr.rgvarg = varsRetEvalExpr;
BSTR bstrEvalExpr = L"EvalExpr";
DISPID dispIDEvalExpr;
hr = pv77->GetIDsOfNames(IID_NULL, &bstrEvalExpr, 1, 0, &dispIDEvalExpr);
if (FAILED(hr))
{
AfxMessageBox("Невозможно получить ID от EvalExpr");
if (pv77)
pv77->Release();
CoUninitialize();
}
varsRetEvalExpr [0] = _variant_t("ПриветМир(\"Весточка 1С Предприятию\")");
/*
После этого Invoke можете проверить переменную vRetEvalExpr,
в ней должна располагаться строка-ответ от 1С Предприятия.
*/
hr = pv77->Invoke(dispIDEvalExpr, IID_NULL, 0, DISPATCH_PROPERTYGET,
&argsRetEvalExpr, &vRetEvalExpr, NULL, NULL);
BSTR bstrHelloWorld = L"ПриветМир";
DISPID dispIDHelloWorld;
hr = pv77->GetIDsOfNames(IID_NULL, &bstrHelloWorld, 1, 0, &dispIDHelloWorld);
if (FAILED(hr))
{
AfxMessageBox("Сначала добавьте в глобальный модуль фукнцию ПриветМир");
if (pv77)
pv77->Release();
CoUninitialize();
}
VARIANT vRetHelloWorld;
DISPPARAMS argsHelloWorld = {0, 0, 0, 0};
VARIANT varsHelloWorld[1];
argsHelloWorld.cArgs = 1;
argsHelloWorld.rgvarg = varsHelloWorld;
varsK[0] = _variant_t("Привет в жёлто красную темницу");
hr = pv77->Invoke(dispIDHelloWorld, IID_NULL, 0, DISPATCH_METHOD, &argsHelloWorld,
&vRetHelloWorld, NULL, NULL);
Я за web сервис.
Конечно возникает проблема с обновлением при добавлении изменении реквизитов(но вроде у контрагентов давно ничего не менялось и в теории там нечему меняться) , но и с OLE тоже проблема с обновлениями никуда не девается.
Прошу прощения, осваиваю высокие технологии, так сказать 8.3 за вымя щупаю и не заметил такого маленького уточнения 7.7 , да еще и FORT да еще и 2007 года.
ок, спс за инфу, буду дальше копать
Украинский 1С форум: всё про 1С 8.3, 1С 8.2, 1С 8.1, 1С 8.0, 1С 7.7
https://pro1c.org.ua