Создание DLL на основании примера из SDK
Создание DLL на основании примера из SDK
Здравствуйте! Я пишу внешнюю компоненту 1С для работы с SpRecord. Пишу на делфи 10.1.
Мне надо что бы моя dll могла получать сообщения от COM сервера SpRecord с событиями. Для этого я попытался интегрировать в свою dll кусок из примера CommonClient - MyCOMEventsHookUnit.
Однако, даже просто указание данного файла в uses моей компоненты приводит к крашу с Runtime еrror 217 при загрузке в 1С и даже без 1С просто при попытке регистрации dll в Windows (например через команду Regsvr32).
Без MyCOMEventsHookUnit, все остальные функции работают, получают из SpRecord данные и все такое успешно. Так же и в Windows спокойно регистрируется.
Я в делфях любитель (профи я в 1С). Можете подсказать почему происходит краш? Быть может нельзя из dll так создавать COM сервера в данном случае и нужен какой то принципиально другой подход?
Мне надо что бы моя dll могла получать сообщения от COM сервера SpRecord с событиями. Для этого я попытался интегрировать в свою dll кусок из примера CommonClient - MyCOMEventsHookUnit.
Однако, даже просто указание данного файла в uses моей компоненты приводит к крашу с Runtime еrror 217 при загрузке в 1С и даже без 1С просто при попытке регистрации dll в Windows (например через команду Regsvr32).
Без MyCOMEventsHookUnit, все остальные функции работают, получают из SpRecord данные и все такое успешно. Так же и в Windows спокойно регистрируется.
Я в делфях любитель (профи я в 1С). Можете подсказать почему происходит краш? Быть может нельзя из dll так создавать COM сервера в данном случае и нужен какой то принципиально другой подход?
Re: Создание DLL на основании примера из SDK
Что то не залогинелось сразу. Автор темы я.
- sannx
- Администратор
- Сообщения: 2306
- Зарегистрирован: 02 ноя 2011, 14:00
- Skype: sann-x
- Контактная информация:
Re: Создание DLL на основании примера из SDK
Поищите здесь на форуме темы про интеграцию с 1С. Можете обратиться к пользователям, у которых что-то получалось, написав им на е-маил или в личку.
Re: Создание DLL на основании примера из SDK
Вопрос не про интеграцию с 1С. Я просто озвучил решаемую задачу.
Забудем про 1С.... скажем я просто пишу некую DLL для каких-то своих задач. Обычную делфевую DLL. В примере SDK - CommonClient - используется юнит MyCOMEventsHookUnit.
В своей DLL я реализовал подключение к библиотеке SDK (так же как в примере CommonClient). Моя DLL успешно подключается, получает номера версий, списки каналов. Проблема возникает, когда я хочу реализовать в своей DLL получение событий так же как оно реализовано в MyCOMEventsHookUnit (без каких либо изменений кода... ну разве что GUID поменял). Компиляция моей dll происходит успешно, без ошибок и предупреждений. Но, даже не доходя до 1С, просто команда в системе Regsvr32 приводит к крашу (полагаю что и в 1С краш происходит по той же причине, но фиг с ним... не рассматриваем 1С). Методом исключения я определил что краш возникает просто при объявлении MyCOMEventsHookUnit в uses, даже без использования её в коде.
Вопрос - почему возникает краш. Может в dll нельзя использовать классы типа TAutoObject... может что то еще. Может я, по неопытности, вообще задаю неправильный вопрос. Я пока не смог нагуглить что именно не так. Быть может вы подскажете хотя бы направление куда копать.
Прикладываю часть кода относящуюся к этому вопросу и скрины ошибок.
Забудем про 1С.... скажем я просто пишу некую DLL для каких-то своих задач. Обычную делфевую DLL. В примере SDK - CommonClient - используется юнит MyCOMEventsHookUnit.
В своей DLL я реализовал подключение к библиотеке SDK (так же как в примере CommonClient). Моя DLL успешно подключается, получает номера версий, списки каналов. Проблема возникает, когда я хочу реализовать в своей DLL получение событий так же как оно реализовано в MyCOMEventsHookUnit (без каких либо изменений кода... ну разве что GUID поменял). Компиляция моей dll происходит успешно, без ошибок и предупреждений. Но, даже не доходя до 1С, просто команда в системе Regsvr32 приводит к крашу (полагаю что и в 1С краш происходит по той же причине, но фиг с ним... не рассматриваем 1С). Методом исключения я определил что краш возникает просто при объявлении MyCOMEventsHookUnit в uses, даже без использования её в коде.
Вопрос - почему возникает краш. Может в dll нельзя использовать классы типа TAutoObject... может что то еще. Может я, по неопытности, вообще задаю неправильный вопрос. Я пока не смог нагуглить что именно не так. Быть может вы подскажете хотя бы направление куда копать.
Прикладываю часть кода относящуюся к этому вопросу и скрины ошибок.
- Вложения
-
- Код и скрины ошибок.7z
- код и скрины ошибок
- (66.16 КБ) 403 скачивания
- sannx
- Администратор
- Сообщения: 2306
- Зарегистрирован: 02 ноя 2011, 14:00
- Skype: sann-x
- Контактная информация:
Re: Создание DLL на основании примера из SDK
К сожалению, по событиям я не смогу помочь. Вы можете поискать в интернете общую информацию про события от COM-объектов в dll. Это общая проблема, а не частная, привязанная к нашему SDK. Другой вариант - не использовать события, а через короткие промежутки времени опрашивать на наличие сообщений от SDK.
Re: Создание DLL на основании примера из SDK
Вас понял. Буду искать сам.
Re: Создание DLL на основании примера из SDK
Продолжение истории...
Отказался от событий COM.
Воспользовался стандартным функционалом делфи - потоками TThread .
Т.е. Есть основной класс, где создается и храниться вся информация. Там же происходит подключение к COM серверу SpRecord и все такое.
После создания COM объекта SpRecrod (успешного) и подключения к нему (то же успешного), инициирую поток, который каждые 1000 миллисекунд должен выполнять метод PeekMessage из функционала Sprecord (ссылка на переменную основного класса передается при создании потока). В итоге поток висит именно на выполнении метода PeekMessage. Просто висит без всяких крашей и сообщений.
Методом исключения все проверил.
- Поток без вызова PeekMessage работает без проблем.
- Так же без проблем поток выполняет любые методы основного класса не связанные с обращением к методам COM объекта SpRecord.
- Вызов других методов SpRecord, кроме PeekMessage , так же приводит к зависанию потока. Пробовал например GetLibVersion.
- Вызовы методов SpRecord из методов моего основного класса (не в потоке) работают корректно, не приводя к зависанию.
- Проверял это как в своей dll так и прямо на примере CommonClient - результаты абсолютно идентичны.
Скажите это опять общий вопрос про делфи или все же вопрос к функционированию SDK SpRecord ?
Отказался от событий COM.
Воспользовался стандартным функционалом делфи - потоками TThread .
Т.е. Есть основной класс, где создается и храниться вся информация. Там же происходит подключение к COM серверу SpRecord и все такое.
После создания COM объекта SpRecrod (успешного) и подключения к нему (то же успешного), инициирую поток, который каждые 1000 миллисекунд должен выполнять метод PeekMessage из функционала Sprecord (ссылка на переменную основного класса передается при создании потока). В итоге поток висит именно на выполнении метода PeekMessage. Просто висит без всяких крашей и сообщений.
Методом исключения все проверил.
- Поток без вызова PeekMessage работает без проблем.
- Так же без проблем поток выполняет любые методы основного класса не связанные с обращением к методам COM объекта SpRecord.
- Вызов других методов SpRecord, кроме PeekMessage , так же приводит к зависанию потока. Пробовал например GetLibVersion.
- Вызовы методов SpRecord из методов моего основного класса (не в потоке) работают корректно, не приводя к зависанию.
- Проверял это как в своей dll так и прямо на примере CommonClient - результаты абсолютно идентичны.
Скажите это опять общий вопрос про делфи или все же вопрос к функционированию SDK SpRecord ?
- sannx
- Администратор
- Сообщения: 2306
- Зарегистрирован: 02 ноя 2011, 14:00
- Skype: sann-x
- Контактная информация:
Re: Создание DLL на основании примера из SDK
Coinitialize вызывали в начале потока?
Re: Создание DLL на основании примера из SDK
Нет. Нигде таким не пользовался. Ушел гуглить. Если дадите пример, буду благодарен.
- sannx
- Администратор
- Сообщения: 2306
- Зарегистрирован: 02 ноя 2011, 14:00
- Skype: sann-x
- Контактная информация:
Re: Создание DLL на основании примера из SDK
Это общий вопрос для работы с СОМ-объектами в потоках. Гуглите в яндексе. Например, вот.
Re: Создание DLL на основании примера из SDK
Итого. Пишу для тех, кто наступит на те же грабли что и я.
Coinitialize не помог.
Менял модели апартаментов и STA и MTA - не помогло.
Пробовал делать маршалинг (в модели STA) - получил AV при попытке обратиться к методу COM объекта.
Для реализации второго потока на базе примера CommonClient, помогло сочетание явного указания апартаментов MTA и использования метода Synchronize во вспомогательном потоке (маршалинг не потребовался, что для MTA логично).
Для DLL компоненты добился нужного мне функционала просто путем создания другого COM объекта внутри вспомогательного потока. Так как все эти COM объекты получают одни и те же события от одной и той же АТС - получилась просто параллельная обработка одних и тех же данных. Мне нужна была только независимая от основного потока реакция на события - я её получил.
Я не настолько уверен в своих знаниях Delphi что бы утверждать что все мои пробы были корректны с точки зрения языка и приведения ссылок. Есть только предположение что зависания при обращении к методам COM во вспомогательном потоке как то связанны с тем, что в DLL нет объекта типа формы с обработкой очереди сообщений. Но тогда непонятно почему тогда в одном потоке все прекрасно работает.
Спасибо sannx за терпение в ответах на мои вопросы![Улыбается :)](./images/smilies/icon_e_smile.gif)
Coinitialize не помог.
Менял модели апартаментов и STA и MTA - не помогло.
Пробовал делать маршалинг (в модели STA) - получил AV при попытке обратиться к методу COM объекта.
Для реализации второго потока на базе примера CommonClient, помогло сочетание явного указания апартаментов MTA и использования метода Synchronize во вспомогательном потоке (маршалинг не потребовался, что для MTA логично).
Для DLL компоненты добился нужного мне функционала просто путем создания другого COM объекта внутри вспомогательного потока. Так как все эти COM объекты получают одни и те же события от одной и той же АТС - получилась просто параллельная обработка одних и тех же данных. Мне нужна была только независимая от основного потока реакция на события - я её получил.
Я не настолько уверен в своих знаниях Delphi что бы утверждать что все мои пробы были корректны с точки зрения языка и приведения ссылок. Есть только предположение что зависания при обращении к методам COM во вспомогательном потоке как то связанны с тем, что в DLL нет объекта типа формы с обработкой очереди сообщений. Но тогда непонятно почему тогда в одном потоке все прекрасно работает.
Спасибо sannx за терпение в ответах на мои вопросы
![Улыбается :)](./images/smilies/icon_e_smile.gif)