Вход | Регистрация


1С:Предприятие :: 1С:Предприятие 8 общая

Как-то можно инициировать выполнение кода 1с внешней компонентой?

Как-то можно инициировать выполнение кода 1с внешней компонентой?
Я
   rphosts
 
22.05.18 - 05:15
Есть dll (в смысле как надо так и будет переписано если в этом вопрос), как-то можно заставить из длл на клиентском компе инициировать выполнение кода 1С (ИБ 1С уже запущена на клиенте)?
 
 
   craxx
 
1 - 22.05.18 - 05:29
(0) Зашить в ресурс dll внешнюю обработку и выполнять код из нее. Так кажись ключ защиты раруса работает, насколько я помню
   rphosts
 
2 - 22.05.18 - 05:32
(1) не-не-не, нужно заставить выполняться код клиентского кода формы. С торговым оборудованием ведь это как-то сделано.
   Emery
 
3 - 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С.

Вот, пожалуй, и все, что я знаю.
   rphosts
 
4 - 22.05.18 - 07:03
(3) Спасибо! Буду попробовать.
   Сияющий в темноте
 
5 - 22.05.18 - 09:54
Сказано,что внешняя компонента получает Dispatch к 1с через Init,у него можно получить какие то интерфейсы к 1с,а также основной интерфейс,если у вас восьмерка,только во имя метода не помню.
   Emery
 
6 - 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 – большой вопрос, так как обычные манипуляции не срабатывают.
   H A D G E H O G s
 
7 - 22.05.18 - 11:20
Жесть какая
   H A D G E H O G s
 
8 - 22.05.18 - 11:24
В процедуре Init() параметр PConnect сохраняем в переменной
PConnect:IDispatch;

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

AppDispatch:OleVariant;

AppDispatch:=OleVariant(PConnect).AppDispatch;
   Рэйв
 
9 - 22.05.18 - 11:24
Вставь в модуль внешнего соединения:
//---

Функция ИсполнитьВн(КодВыполнить, ВспомПараметр= "") Экспорт
    Ответ= "ОК"//Если ничего не нужно будет возвращать, то при отсутствии ошибок в коде  вернется просто ОК

    
    //Т.к. переданный код может быть с ошибками, то завернем его исполнение в попытку.

    Попытка
        Выполнить(КодВыполнить);
    Исключение
        //если все таки ошибка, то вернем ее текст 

        Ответ="ОШИБКА:"+ОписаниеОшибки();
    КонецПопытки;
    Возврат Ответ;
КонецФункции
//----


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

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

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

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

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

И вызываем

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

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

Функция ЭтоСервер() Экспорт
    Результат=Ложь;
    #Если Сервер Тогда

        Результат=Истина;
    #КонецЕсли

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

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

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


Список тем форума
Рекламное место пустует  Рекламное место пустует
ВНИМАНИЕ! Если вы потеряли окно ввода сообщения, нажмите Ctrl-F5 или Ctrl-R или кнопку "Обновить" в браузере.
Рекламное место пустует