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


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

Разработка внешних компонент

Разработка внешних компонент
Я
   lEvGl
 
24.11.18 - 18:59
Уважаемые, нужна ваша помощь
Хочу сделать компоненту на шарпе, которая будет посылать во внешнее событие (или другие, насколько понял можно назначить ОбработчикСобытия) 1С данные, полученные из ком порта, созданного в MS VS, тип проекта БибилиотекаКлассов C#

Взял базовый компонент отсюда http://rsdn.org/forum/dotnet/3471534.1
Оттуда же "рабочий" компонент, написал так
namespace OneC.ExternalComponents
{все что включено в базовый
все что включено в итоговый}
под одним NameSpace
поставил в свойствах проекта Регистрацию для СОМ взаимодействия, назначил строгое имя, [assembly: ComVisible(true)] и зарегал
C:\Windows\Microsoft.NET\Framework\v4.0.30319\regasm.exe "D:\DLL\New\New\bin\Release\New.dll" /codebase
Прошло нормально, компоненты зарегистрированы

Но, во первых когда пишу
ЗагрузитьВнешнююКомпоненту("D:/DLL/New/New/bin/Release/New.dll"); -- ок
Объект = Новый("AddIn.CardReaderMR2000");  -- тип не определен
 
 
   lEvGl
 
1 - 24.11.18 - 19:09
Так создается и есть доступ к методам
МойОбъект = Новый COMОбъект("AddIn.CardReaderMR2000");
МойОбъект.Initialization();

Много вариантов перебрал, дошел до такого варианта

 [GuidAttribute("0E2BFC3D-7FF8-4bb8-AC4D-2FAA332B80A3")]
    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
    [ComImport]
    public interface IWorkCompsMain
    {

        string Version { get; }

    }

    [Guid("38B5DCD1-8FE9-4a46-B9C3-C9A1CD60F6E4")]
    [ProgId("AddIn.CardReaderMR2000")]
    [ClassInterface(ClassInterfaceType.AutoDispatch)]
    [ComVisible(true)]
    public class CardReader : ExtComponentBase, IWorkCompsMain
    {
        private SerialPort sp;
        private string inputData = "";
        private string _version = "";
        public string Version
        {

            get { return _version; }
            set { _version = value; }

        }

        [Export1c]
        public string Port
        {
            get { return sp.PortName; }
            set { sp.PortName = value; }
        }
        public CardReader()
        {
            ComponentName = "CardReaderMR2000";
            InitEvent += new InitEventHandler(Initialization);
        }

        public void Initialization()
        {
            sp = new SerialPort();
            sp.PortName = "COM4";
            sp.ReadTimeout = -1;
            sp.BaudRate = 9600;
            sp.Parity = Parity.None;
            sp.DataBits = 8;
            sp.StopBits = StopBits.One;
            sp.Handshake = Handshake.None;
            sp.DtrEnable = true;
            sp.RtsEnable = true;
            sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
            inputData += "123321";
            Thread t = new Thread(new ThreadStart(ReadData));
            t.Start();
        }

        void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            string chr = sp.ReadExisting();
            if (chr != string.Empty && chr[0] != Convert.ToChar(10))
            {
                if (chr[0] != Convert.ToChar(13))
                {
                    inputData += chr;
                }
                else
                {
                    Thread t = new Thread(new ThreadStart(ReadData));
                    t.Start();
                }
            }
        }

        private void ReadData()
        {
            lock (inputData)
            {
                this.Async.ExternalEvent("AddIn.CardReaderMR2000", "ДанныеКарты", "123");
                inputData = "";
            }
        }

        [Export1c]
        public void Open()
        {
            sp.Open();
        }

        [Export1c]
        public void Close()
        {
            sp.Close();

То есть в начальном варианте изменил вызов ExternalEvent  из событий КОМ порта на Initialize(), вроде срабатывает, но результат - вываливается 1сv8.exe. Изменил потому что физически нет доступа к порту, послать нечего
   formista2000
 
2 - 24.11.18 - 19:11
продолжайте наблюдения
   lEvGl
 
3 - 24.11.18 - 19:16
(0) Не Загрузить а ПодключитьВнешнююКомопоненту("D:/DLL/New/New/bin/Release/New.dll"); -- ок)
   lEvGl
 
4 - 24.11.18 - 19:16
пробовал варианты
   lEvGl
 
5 - 24.11.18 - 19:16
(2)чего не хватает?
   lEvGl
 
6 - 24.11.18 - 19:17
винда 64, 8.2, обычное приложение
   lEvGl
 
7 - 24.11.18 - 19:26
+(2) то есть вариант через создание КОМОбъекта - методы работают (ранее делал компоненты Так и этого хватало: метод - ответ, теперь возникла необходимость получать события в компоненте DataRecivied в 1С), но при передаче данных в Программу она вываливается (
   lEvGl
 
8 - 24.11.18 - 19:28
+(6) C:\Windows\Microsoft.NET\Framework64\v4.0.30319\regasm.exe пробовал тоже
   Emery
 
9 - 24.11.18 - 19:38
(0) > Хочу сделать компоненту на шарпе

А я вот разбираюсь с внешними компонентами на С++. Кстати, примеров на Си куда меньше, чем на любом другом языке. На С# примеров в Интернете достаточно. Если имеется в виду работа по технологии СОМ. А в 1С внешняя компонента это просто адаптация СОМ «под себя» (т.е., фирму 1С). Есть еще поддержка нативных компонентов в «восьмерке». Но в любом случае, знание СОМ / OLE / ActiveX / ATL / WTL / MFC и т.п. может быть не вредным. Много информации на codeproject.com и github.com .

> которая будет посылать в… 1С данные, полученные из ком порта

Я себе задачу придумал более интересную. Вынести всю бизнес логику из собственной конфигурации во внешнюю компоненту. Причем это может быть общая компонента и для «семерки» и для «восьмерки». 1С используется только как интерфейсный контейнер. Движок базы данных будет работать параллельно родному и реализован на SQLite. Макеты отчетов будут в 1С, но данные будут получаться из ВК по запросу в SQLite. По крайней мере, это интересней, чем разрабатывать какую-нибудь игрушку. Ибо играми сейчас никого не удивишь :) .
   lEvGl
 
10 - 24.11.18 - 19:56
(9) На ИТС пример именно на С++, поэтому я и гуглил, на шарпе хоть что то делал (тоже компоненты, сом, но вызвать метод из компоненты, получить данные и сгенерировать внешнее событие - оказалось разные вещи)
Насчет нативных - насколько понял на шарпе нельзя, на ++ можно, на том же ИТС
>Вынести всю бизнес логику из собственной конфигурации во внешнюю компоненту
тоже надо вынести логику, правда не бизнеса, в 7 нет необходимости, к счастью
 
 Рекламное место пустует
   lEvGl
 
11 - 24.11.18 - 20:00
   lEvGl
 
12 - 24.11.18 - 22:22
может пример тогда наглядный дадите?
   Emery
 
13 - 24.11.18 - 23:26
(12) > может пример тогда наглядный дадите?

Примеров путных практически нет. Все, что приводится на дисках ИТС (да и в других публикациях тоже), относительно ВК, по большому счету халтура. Другими словами, повторять их концепцию нет ни малейшего желания. Поэтому нужно въезжать в тему самостоятельно. А тема, кстати, очень непростая. Для «семерки» интересен «шаблон Орефкова» на базе исходников «TurboMD». Я, например, использую фичу, открытую, по-моему, Альфом («волшебные строки Орефкова - Фёдорова»), т.е. в ресурсах прописать строки вида:

STRINGTABLE DISCARDABLE
BEGIN
    100 "\0SomeString"
END

И тогда загрузчик (функция) «ЗагрузитьВнешнююКомпонентыу()» ВК успешно внедрит практически ЛЮБУЮ dll-ку в адресное пространство как «семерки», так и «восьмерки»).

Подобный закидон позволяет, скажем, поменять фон в клиентской области «семерки» и в «толстых» формах «восьмерки», безо всякой СОМовской регистрации в реестре. Если проделать тоже самое с помощью Формекса, то будут жуткие тормоза при загрузке 5-6 мегабайтного bmp-файла, а так можно использовать WinAPI, что позволяет ускорить подобный процесс на порядок.

А то, что фэйс «восьмерки» можно изменить до неузнаваемости, с помощью ВК, доказывает «Трактиръ: Front-Office» https://www.youtube.com/watch?v=qK3sup51VKU . Но как они это делают, они не скажут. Хоть используй «IDA-Pro» для прояснения ситуации.

Нераскрытой (т.е., практически никому неизвестной) остается тема доступа к IDispatch интерфейсу для InProc сервера. Для OutProc сервера решение дает OLE-сервер 1С, но он запускает новый экземпляр 1С, что очень неинтересно. Как этого добиться внутри процесса уже запущенного экземпляра 1С – неизвестно.

Вот и приходится осваивать фундамент – технологию СОМ, как таковую и ее производные. А она жуть, как сложная, особенно когда ATL перемешана с MFC, как в 1С.

Правда, у вас задача выглядит попроще, поскольку это частный случай ВК, причем во внутренности 1С лезть не нужно. Но специально ею заниматься не интересно, поэтому подсказать ничего не могу. Сам я пока копаюсь в теории технологий СОМ.
   H A D G E H O G s
 
14 - 24.11.18 - 23:29
(13) Ну у вас и каша в голове.
   H A D G E H O G s
 
15 - 24.11.18 - 23:30
String table сильной и независимой компоненты.

STRINGTABLE
{
100, "Windows|Processes|Sounds|Keyboard|TrayIcon|System|Events|FileStream|COMPort|Clipboard|FileWatch|Network|Images|Library|DataTransfer|Information|Printers|DataManager"
}
   H A D G E H O G s
 
16 - 24.11.18 - 23:32
AppDispatch сильной и независимой компоненты

procedure TBaseVKObject.OnCallFunction;
var
  winmode: integer;
  res: Cardinal;
begin
  if fAppDispatchSeted = false then
  begin
    fAppDispatchSeted := true;
    AppDispatch := OleVariant(PConnect).AppDispatch;
  end;
end;
   H A D G E H O G s
 
17 - 24.11.18 - 23:35
Запуск без регистрации в реестре без прав администратора сильной и независимой компоненты.
Ах, да, мы не консультировались с 1С и не уверены, что это нарушает лицензионку. Поэтому вам не скажем. Но если вы откроете rtfm по COM технологиям от Windows, вам будет понятно как выеденное яйцо, как это реализуется.
   Emery
 
18 - 24.11.18 - 23:39
(15) А вы уверены, что ваша STRINGTABLE загрузит любую dll в адресное пространство 1С?
   H A D G E H O G s
 
19 - 24.11.18 - 23:40
(18) Нет конечно. Причем здесь Stringtable и загрузка Любой DLL. Вы в DLL реализуйте Фабрики COM классов и живите щастливо. StringTable лишь говорит 1C-у, какие PROGID есть в этой DLL.
   Emery
 
20 - 24.11.18 - 23:44
(16)  А вы уверены, что ваш AppDispatch будет получен для CLSCTX_INPROC_SERVER, а не для CLSCTX_LOCAL_SERVER?
   H A D G E H O G s
 
21 - 24.11.18 - 23:52
(20) Конечно.
   H A D G E H O G s
 
22 - 24.11.18 - 23:55
(20) Самое забавное, что об этом написано ВОООТ здесь
https://1c-dn.com/library/add_in_creation_technology_accessing_1c_enterprise_methods_and_properties_using_ole_automation/
   Emery
 
23 - 24.11.18 - 23:56
(19) > Нет конечно. Причем здесь Stringtable и загрузка Любой DLL. Вы в DLL реализуйте Фабрики COM классов и живите щастливо. StringTable лишь говорит 1C-у, какие PROGID есть в этой DLL.

Я говорил именно о фиче – загрузке любой длл. Как работать со стандартными ВК, в принципе понятно из примеров на ИТС дисках. Но эти примеры очень ущербные и удовлетворить могут «не только лишь всех» :) .

Чтобы полноценно работать с 1С из ВК нужен внутрипроцессный доступ к ее IDispatch интерфейсу. В «семерке» это достигается хакерскими методами в шаблоне Орефкова. А в «восьмерке» таких известных инструментов нет. Но может быть, если хорошо знать теорию СОМ, решение найти можно, по крайней мере, я в это верю, потому и вожусь с теорией СОМ и порожденных ею технологий.
   H A D G E H O G s
 
24 - 25.11.18 - 00:00
(23) Мистец.
Вон, в (22) все написано официально от 1С.
   Emery
 
25 - 25.11.18 - 00:07
(22) Но вы ведь даете ссылку на работу с 1С, как с OLE-сервером. Но это ведь не секрет. Секрет, как работать с 1С, как с СОМ-сервером. Просто потому, что 1С таковым не является. Однако через интерфейс 1C IInitDone можно внутрипроцессно получить доступ к указателю IDispatch. Но вот как раз интерфейсами 1С я и не хочу пользоваться.

В общем, чтобы говорить о полноценном решении, нужен полный проект нетривиального кода, желательно (для меня) на С++. Частичных решений как бы более, чем, но полноценного примера нет. И автор топика говорит об этом же.
   H A D G E H O G s
 
26 - 25.11.18 - 00:09
(25) шта?
   Emery
 
27 - 25.11.18 - 00:11
(25) Терминологическая путаница, однако. Мы говорим о разных вещах.
   kihor
 
28 - 25.11.18 - 00:12
(0) А у Вас разрядность regasm.exe и клиента 1С совпадают? У меня такое было, когда я регистрировал DLL-ку 64-битным regasm.exe, а, в то же время, клиент 1С был 32-разрядный.
   H A D G E H O G s
 
29 - 25.11.18 - 00:20
(25) Если вы под OLE сервером подразумеваете работу через Idispatch, а под COM сервером - через специализированные интерфейсы, запрашиваемые через QueryInterface() - то да, такого нет, ибо - занахера? Вам не нравится позднее связывание или что?
   Emery
 
30 - 25.11.18 - 00:25
(21) > Конечно.

Правильнее было бы сказать: «Конечно, нет!» :) .

Кстати, как вы получаете «PConnect» в (16)?
   H A D G E H O G s
 
31 - 25.11.18 - 00:39
(30) Он прихолдит в Init() от 1С.
   Emery
 
32 - 25.11.18 - 00:52
(29) > Если вы под OLE сервером подразумеваете работу через Idispatch

Смотрите, когда вы используете OLE-сервер (1С, Эксел, Ворд, Визуал ФоксПро и т.п.) вы всегда запускаете новый экземпляр программы, даже, если вы находитесь внутри этой самой программы. Т.е. OLE-сервер это всегда ехе-сервер. А СОМ-сервер всегда dll-сервер, который может запускаться внутри процесса либо проецироваться на адресное пространство текущей программы.

>  а под COM сервером - через специализированные интерфейсы, запрашиваемые через QueryInterface() 

Поскольку 1С не реализована в виде отдельной длл, а использует ехе-загрузчик, то СОМ-сервером она не может быть по определению. Но это не означает, что доступ к указателю IDispatch нельзя получить в принципе, находясь внутри процесса 1С (скажем, получив туда доступ любой длл, с помощью «волшебных строк» Фёдорова и Орефкова). И «шаблон Орефкова» для 1С77 подобную (хакерскую) технику демонстрирует. Но для «восьмерки» подобного инструмента нет. Интерфейсы самого 1С, типа IInitDone, сильно ограничены по своим возможностям. Кроме того, они требуют СОМ-регистрации, которую делать, имея возможность загружать любые длл в адресное пространство 1С, как-то не вполне серьезно, по разным причинам.

В «семерке» можно вместо хакерской техники Орефкова использовать вполне легальный DDE-сервер, коим является 1С77. Эта лошадка хоть и старая, но вполне рабочая. Однако 1С8х DDE-сервером не является.

Выход только в глубоком понимании процессов основанных на СОМ технологиях. Другого способа я пока не вижу. Т.е., идея простая, коли мы уже попали в адресное пространство любой 1С (безо всякого СОМа), то найти в этих внутренностях указатель на интерфейс IDispatch должно быть только делом техники, хотя и уровня know-how.

> - то да, такого нет, ибо - занахера? Вам не нравится позднее связывание или что?

Понятно, что не об этом речь.
   Гобсек
 
33 - 25.11.18 - 00:52
(9) >Вынести всю бизнес логику из собственной конфигурации во внешнюю компоненту.

Фирма 1С проблему быстродействия решает за счет укрупнения и оптимизации запросов. Когда переносил базу данных из ЗУП 2.5 в ЗУП 3.1 я обнаружил, что в ЗУП 3.1 расчет зарплаты идет значительно быстрее. По времени не засекал, но чисто визуально при запуске расчета для одной и той же группы сотрудников в ЗУП 3 расчет уже выполнился, а в ЗУП 2.5 еще довольно долго ждешь.
 
 
   Emery
 
35 - 25.11.18 - 01:33
(33) Решать, не значит решить. Кстати, никто не хочет сказать сколько времени нужно ЗУПу, что посчитать, скажем, 1000 человек для относительно сложного производственного предприятия. Мне нужно порядка часа (примерно 50 минут).

Однако вынос всей бизнес логики «наружу» это не столько делается ради производительности, сколько ради других идей.

1. Одна ВК с этой «логикой» может быть использована и в 1С77 и в 1С83.
2. Бинарная защита конфигурации при ее распространении в Интернете.
3. Поддержка внешней модульной структуры, например, через систему плагинов, которыми будет управлять наша ВК.
4. Весь расчет зарплаты будет вестись в оперативной памяти, и использоваться, при необходимости, разрядность 64х операционной системы.
5. Две (параллельные) базы данных обеспечивают дополнительную надежность хранения.
6. Внешние запросы можно хранить в sql-скриптах.
И т.д.

Как видим, неплохо для систем типа «зарплаты».
   Emery
 
36 - 25.11.18 - 01:35
[31] > Он приходит в Init() от 1С.

Который является методом интерфейса IInitDone, о чем я уже писал.

Т.е., это стандартная техника ВК, продемонстрированная на дисках ИТС. Новой информации здесь никакой нет. Опять же, я сейчас точно не помню, но, по-моему, там не совсем тот интерфейс IDispatch получается, который нам нужен. Если не ошибаюсь (давно уже экспериментировал), мы получаем (ограниченный) IDispatch интерфейс, который выставляет наружу фирма 1С. А нам, на самом деле, нужен другой, родной IDispatch интерфейс, которым пользуется внутри себя сама 1С. Если я правильно помню, об этих двух IDispatch интерфейсах говорит Орефков в комментариях к своему коду «TurboMD». Так что это не самый лучший вариант доступа к внутренней «кухне» 1С. Иначе не было бы необходимости изобретать «шаблон Орефкова». Причем в 1С8х нет и такого.
   Гобсек
 
37 - 25.11.18 - 02:03
(35) >сколько времени нужно ЗУПу, что посчитать, скажем, 1000 человек для относительно сложного производственного предприятия

Есть штатная процедура переноса из ЗУП 2.5 в ЗУП 3.1. Переносишь данные, запускаешь расчет, получаешь информацию из первых рук. Но разница большая.
Как говорит Грянина на курсах, на скорость расчета влияет еще использование или неиспользование табелей рабочего времени.
   Emery
 
38 - 25.11.18 - 10:34
(37) > Как говорит Грянина на курсах, на скорость расчета влияет еще использование или неиспользование табелей рабочего времени.

Основные принципы, которых я придерживаюсь в новой концепции учета и расчета заработной платы, ориентированной на повременный учет, следующие:

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

2. Расчет заработной платы должен быть основан на стоимости одного рабочего часа (с точностью до его долей, при необходимости). Другие временные интервалы должны использоваться только, если для конкретного вида расчета часовая расценка не имеет смысла, либо не может быть вычислена. В любом случае, расценка для каждого повременного вида расчета должна быть основана на однозначном временном интервале. Если расценка задана для другого периода, например, месячный оклад, то использоваться должна ее эквивалентная часовая ставка с необходимой степенью точности.

3. Естественно, что нужно разработать такую структуру базы данных, чтобы учет рабочего и любого другого времени имеющего отношение к расчету зарплаты, а в перспективе и сдельных учетных единиц, был максимально удобен и эффективен. При этом важно добиваться необходимой детализации, касающейся учетных и расчетных параметров, но без хранения чрезмерно избыточной информации в базе.

Таким образом, перефразируя Елену Грянину: «Оклад по дням не нужен! НЕ НУЖЕН!!!».

Из приведенных принципов следует, что фактический табель учета рабочего времени, создаваемый в том числе автоматизированными средствами учета рабочего времени, совместно с плановыми графиками работы и плановых отклонений это «НАШЕ ВСЁ»!

Именно в силу концептуальных различий в учете «зарплаты» от фирмы «1С» приходится писать собственный вариант. Тем более, что это особенно актуально для наших непризнанных республик ЛНР и ДНР.
   lEvGl
 
39 - 25.11.18 - 10:59
Продолжаю разбираться

(28) 1с 32 бита, винда 64, сначала регал 32regasm, потом подумал, что может в этом дело и зарегал 64, толку нет

да и дело не в этом видимо, а в том что я очень поверхностно работал с VS
когда указатель приходит сюда
this.Async.ExternalEvent("AddIn.CardReaderMR2000", "123", "123");
Async у меня null, так понимаю потому что не было инициализации компоненты, я думал это должно произойти в момент подключения
ПодключитьВнешнююКомпоненту();
Объект = Новый("AddIn.CardReaderMR2000");
но так как таким способом у меня не получается, подключить отрабатывает, а Новый("AddIn") нет - тип не определен, хотя и пробовал
ПодключитьВнешнююКомпоненту("Путь");
Новый ("AddIn.CardReaderMR2000")

потом 
ПодключитьВнешнююКомпоненту("Путь", "CardReaderMR2000", ТипКомпоненты.СОМ);
Новый ("AddIn.CardReaderMR2000.CardReaderMR2000")
тоже нет
   lEvGl
 
40 - 25.11.18 - 11:13
соответственно вопрос
Как при подключении через СомОбъект инициализировать компоненту?
   lEvGl
 
41 - 25.11.18 - 12:15
Получилось подключиться

ПодключитьВнешнююКомпоненту("AddIn.CardReaderMR2000");
Объект = Новый("AddIn.CardReaderMR2000");

но теперь при вызове любого метода говорит что недостаточно фактических параметров, хотя процедура не имеет параметров
public void Initialization()
        {
            sp = new SerialPort();
            sp.PortName = "COM4";
            sp.ReadTimeout = -1;
            sp.BaudRate = 9600;
            sp.Parity = Parity.None;
            sp.DataBits = 8;
            sp.StopBits = StopBits.One;
            sp.Handshake = Handshake.None;
            sp.DtrEnable = true;
            sp.RtsEnable = true;
            sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
        }
   lEvGl
 
42 - 25.11.18 - 12:42
ну получилось
теперь вылавливать проблемные места


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