Имя: Пароль:
1C
1С v8
Как-то можно инициировать выполнение кода 1с внешней компонентой?
0 rphosts
 
22.05.18
05:15
Есть dll (в смысле как надо так и будет переписано если в этом вопрос), как-то можно заставить из длл на клиентском компе инициировать выполнение кода 1С (ИБ 1С уже запущена на клиенте)?
1 craxx
 
22.05.18
05:29
(0) Зашить в ресурс dll внешнюю обработку и выполнять код из нее. Так кажись ключ защиты раруса работает, насколько я помню
2 rphosts
 
22.05.18
05:32
(1) не-не-не, нужно заставить выполняться код клиентского кода формы. С торговым оборудованием ведь это как-то сделано.
3 Emery
 
22.05.18
07:01
Т.е. задача состоит в том, чтобы из внешней компоненты (ВК) обратиться к 1С как к серверу, ну и, соответственно, выполнить некоторый код в «семерке» либо «восьмерке»?

Если так, то из ВК надо инициировать внешнее событие, которое подхватывает обработчик «ОбработкаВнешнегоСобытия(Источник, Сообщение, Данные)»

В ВК нужно воспользоваться интерфейсом 1С IAsyncEvent и написать что-то, вроде:

if(pIAsyncEvent) {
    pIAsyncEvent->SetEventBufferDepth(2);  // Определяет количество одновременных событий
    pIAsyncEvent->ExternalEvent(L"Emery", L"Hello from DllMain()", L"Привет, Emery!");
    //Sleep(1000);
    pIAsyncEvent->ExternalEvent(L"Emery2", L"Hello from DllMain()", L"Как твои дела?");
    //AfxMessageBox("pIAsyncEvent <> NULL!");
  } else {
    AfxMessageBox("pIStatusLine == NULL!");
}

А в 1С, в предопределенной процедуре, написать примерно следующее:

Процедура ОбработкаВнешнегоСобытия(Источник, Сообщение, Данные)
    Если Источник = "Emery" Тогда
        Сообщить(Сообщение + " : " + Данные);
    Иначе
        Сообщить(Источник + " : " + Сообщение + " : " + Данные);
    КонецЕсли
КонецПроцедуры  // ОбработкаВнешнегоСобытия()

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

Другие варианты это уже специфика 1С77. Например, очень хороший вариант подключиться к «семерке», как к DDE-серверу и выполнить нужную глобальную процедуру. Кстати на этом принципе у меня работает нынешняя версия «зарплаты», только вызов идет не из ВК, а из внешнего приложения Visual FoxPro (которое вызывается из 1С), но в данном случае, это не принципиально.

Опять же, те в «семерке» есть штатный обработчик «ОбработкаОжидания(<ИмяПроцедуры>, <ИнтервалВызова>)». Можно периодически, например, каждую секунду делать опрос некоего состояния (например, наличие существования временного файла, который создает ВК) и, если оно выполнено, то вызывать соответствующую процедуру 1С.

Вот, пожалуй, и все, что я знаю.
4 rphosts
 
22.05.18
07:03
(3) Спасибо! Буду попробовать.
5 Сияющий в темноте
 
22.05.18
09:54
Сказано,что внешняя компонента получает Dispatch к 1с через Init,у него можно получить какие то интерфейсы к 1с,а также основной интерфейс,если у вас восьмерка,только во имя метода не помню.
6 Emery
 
22.05.18
11:14
(5) > внешняя компонента получает Dispatch к 1с через Init

Функция Init(IDispatch *pConnection) дает доступ к указателю pConnection, который можно сохранить глобально, типа:

m_pIDispatch = pConnection;

и воспользоваться затем в другом месте для получения заданных интерфейсов 1С, скажем IAsyncEvent:

IAsyncEvent *pIAsyncEvent = NULL;
m_pIDispatch->QueryInterface(IID_IAsyncEvent, (void **) &pIAsyncEvent);

Но таким образом мы не можем получить «основной интерфейс». Вот, что на эту тему пишут в Интернете (не помню уже, откуда скачал) относительно 1С77:

// У нас есть два указателя IDispatch:

// 1. Передаваемый системой в качестве параметра метода Init. Через него можно получать интерфейсы
// 1С:Предприятия, но нельзя вызывать его методы, например:

IExtWndsSupport *pIExtWndsSupport = NULL;
m_IDispatch->QueryInterface(IID_IExtWndsSupport, (void **) &pIExtWndsSupport);

//[helpstring("method GetAppMainFrame")] HRESULT GetAppMainFrame([in,out]HWND *hwnd);
//[helpstring("method GetAppMDIFrame")] HRESULT GetAppMDIFrame([in,out]HWND *hwnd);
//[helpstring("method CreateAddInWindow")] HRESULT CreateAddInWindow([in]BSTR bstrProgID, [in]BSTR bstrWindowName, [in]long dwStyles, [in]long dwExStyles, [in]RECT *rctl, [in]long Flags, [in,out]HWND *pHwnd, [in,out]IDispatch **pDisp);

// 2. Находящийся в свойстве AppDispach. Он может использоваться для вызова методов 1С:Предприятия,
// при этом используется механизм OLE Automation.

// Получение того указателя IDispatch, который позволяет вызывать методы 1С. Но здесь тоже два варианта,

// Первый вариант это использование вновь созданного экземпляра «семерки», здесь довольно большой код, вот его начало:

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

CLSID clsid = {0};
HRESULT hr = CLSIDFromProgID(L"'V1CEnterprise.Application ", &clsid);

if(FAILED(hr)) {
    AfxMessageBox("Не найден clsid для 'V1CEnterprise.Application'!");
    CoUninitialize();
    return S_FALSE;
}

// Основной интерфейс, за который мы будем "дёргать" IDispatch *pv77;
// Создаём инстанцию 1С Предприятия.
// CLSCTX_LOCAL_SERVER – это значит, что 1С Предприятие
// будет запущено в виде отдельного процесса – по-другому оно не умеет.

IDispatch *pIDispatch = NULL;
IClassFactory *pCF = NULL;
IUnknown *pIUnknown = NULL;

hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC,
    IID_IDispatch, (void **) &pIDispatch);  // Только для CLSCTX_LOCAL_SERVER
    //IID_IClassFactory, (void **) &pCF);  // Только для CLSCTX_LOCAL_SERVER

И т.д.

// Второй вариант, это пока никому неизвестный, когда есть интерфейс при флаге CLSCTX_INPROC или
// CLSCTX_INPROC_SERVER. Пока нам доступен только такой вызов:

hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC,
    IID_IUnknown, (void **) &pIUnknown);  // Это работает для INPROC сервер, но ничего нам реально не дает!

Но можно ли здесь из pIUnknown получить pIDispatch – большой вопрос, так как обычные манипуляции не срабатывают.
7 H A D G E H O G s
 
22.05.18
11:20
Жесть какая
8 H A D G E H O G s
 
22.05.18
11:24
В процедуре Init() параметр PConnect сохраняем в переменной
PConnect:IDispatch;

В процедуре CallAsFunc() (не раньше) получаем контекст 1С и храним в

AppDispatch:OleVariant;

AppDispatch:=OleVariant(PConnect).AppDispatch;
9 Рэйв
 
22.05.18
11:24
Вставь в модуль внешнего соединения:
//---
Функция ИсполнитьВн(КодВыполнить, ВспомПараметр= "") Экспорт
    Ответ= "ОК";//Если ничего не нужно будет возвращать, то при отсутствии ошибок в коде  вернется просто ОК
    
    //Т.к. переданный код может быть с ошибками, то завернем его исполнение в попытку.
    Попытка
        Выполнить(КодВыполнить);
    Исключение
        //если все таки ошибка, то вернем ее текст
        Ответ="ОШИБКА:"+ОписаниеОшибки();
    КонецПопытки;
    Возврат Ответ;
КонецФункции
//----

и выполняй любой код по COM соединению с возвратом любого результата
10 H A D G E H O G s
 
22.05.18
11:25
Ну и потом как душе угодно

ЗапросДанных := LocalDispatch.NewObject('Запрос');
          ЗапросДанных.Текст := ' ВЫБРАТЬ ПЕРВЫЕ 1' +
            '    АСФСоответствияТМИОрганизацийиИхОбособленныхПодразделений.Организация,'
            + '    АСФСоответствияТМИОрганизацийиИхОбособленныхПодразделений.АСФОбособленноеПодразделениеОрганизации'
            + ' ИЗ' + '    РегистрСведений.АСФСоответствияТМИОрганизацийиИхОбособленныхПодразделений КАК АСФСоответствияТМИОрганизацийиИхОбособленныхПодразделений'
            + ' ГДЕ' +
            '    АСФСоответствияТМИОрганизацийиИхОбособленныхПодразделений.ТранспортныйМодульЕГАИС = &ТранспортныйМодульЕГАИС';
          ЗапросДанных.УстановитьПараметр('ТранспортныйМодульЕГАИС',
            ТранспортныйМодуль);
          Выборка := ЗапросДанных.Выполнить().Выбрать();

          if Выборка.Следующий() = true then
          begin
            Организация := Выборка.Организация;
            АСФОбособленноеПодразделениеОрганизации :=
              Выборка.АСФОбособленноеПодразделениеОрганизации;
          end
11 H A D G E H O G s
 
22.05.18
11:25
ЗапросДанных := LocalDispatch.NewObject('Запрос');
заменить на

ЗапросДанных := AppDispatch.NewObject('Запрос');
12 H A D G E H O G s
 
22.05.18
11:26
Com-соединение не нужон.
13 H A D G E H O G s
 
22.05.18
11:27
А всякие извращения с созданием своего инстанса - это уже ближе к теме написания ВК без обращений к реестру Windows, я недавно выкладывал статью, но меня отговорили, опасносте.
14 H A D G E H O G s
 
22.05.18
11:27
Ну или создание инстанса - к извращениям в C++/ C# . В этих ЯП надо пострадать.
15 H A D G E H O G s
 
22.05.18
11:30
Не забываем, что AppDispatch нестабильно работает с глобальным контексом на серверной стороне клиент-сервера. Например, он не увидит ЗаполнитьЗначениеСвойств(). Для обхода - пилим глобальный ОМ, в котором будет реализация

Процедура ЗаполнитьЗначенияСвойствПереопределенный(Приемник, Источник,СписокСвойств=Неопределено,ИсключаяСвойства=Неопределено) Экспорт
    ЗаполнитьЗначенияСвойств(Приемник,Источник,СписокСвойств,ИсключаяСвойства);
КонецПроцедуры

И вызываем

AppDispatch.ЗаполнитьЗначенияСвойствПереопределенный()
16 H A D G E H O G s
 
22.05.18
11:31
Не забываем, что ВК криво работает с несколькими пользователями на сервере. Тут уже появляется необходимость блокировок общих ресурсов и выставление флага IsMultiThread:=true;

в секции иницииации dll
17 H A D G E H O G s
 
22.05.18
11:33
Не забываем, что в ВК нет препроцессора. Поможет это в глобальном ОМ

Функция ЭтоСервер() Экспорт
    Результат=Ложь;
    #Если Сервер Тогда
        Результат=Истина;
    #КонецЕсли
    Возврат Результат;
КонецФункции
18 Tateossian
 
22.05.18
11:35
Я из Java ходил так в 1С - в JVM тоже свой inproc server. В итоге подцеплял api в одной dll. Было весело:)
19 Вафель
 
22.05.18
11:36
(17) а через попытку нельзя вычислить?
20 Tateossian
 
22.05.18
11:40
(16) Можно подключать с разными именами и даже с генератором dll'ек - тогда будет псевдопараллельность.

Помню была компонента, то ли для печати, то ли для операций с текстом. Если печатать этикетки фоновыми заданиями с одной dll - часто были косяки. А вот если наплодить dlleleк и c рандомным именем подключать - таки работать параллельно можно без всяких допилов мьютексов, семафоров и прочих радостей многопоточной парадигмы:)
21 H A D G E H O G s
 
22.05.18
12:19
(20) Не по фуншую.
22 rphosts
 
23.05.18
06:02
О!
Ещё раз спасибо!
23 Сияющий в темноте
 
23.05.18
11:15
И,самое главное,компонента-исполнитель,то есть в нее управление передается при вызове какого то метода,ну или,когда мы зарегестрировали обратный вызов из системных функций.
Чтобы компонента была генератором событий,в ней нужно создавать отдельный поток,но его вызовы в 1с будут идти через удаленный вызов процедур,т.к.у него другое размещение(apartment)
в итоге,из потока проще в web или http сервис в 1с обращаться,будет быстрее,а вместо потока запускать отдельный процесс,следующий вопрос будет-а нужна ли нам внешняя компонента?
24 Сияющий в темноте
 
23.05.18
11:16
компонента в версии 2.0 должна допускать содание нескольких экземпляров обьекта,так что там разные имена не нужны.
25 H A D G E H O G s
 
23.05.18
11:19
(23) (24) Вы пишите какую - то странь.
26 H A D G E H O G s
 
23.05.18
11:20
(24) "компонента в версии 2.0 должна допускать содание нескольких экземпляров обьекта,так что там разные имена не нужны."

Адресное пространство будет едино. DLL-ка в памяти то одна.
27 H A D G E H O G s
 
23.05.18
11:31
(23) Никакого RPC из отдельного потока вызываться не будет, несмотря на Apartment, так как ВК - это внутрипроцессный сервер.
28 H A D G E H O G s
 
23.05.18
11:31
Web сервисы имеют смысл только на стороне Сервера 1С.