|
v8: Особенности dll, написанной на С++ | ☑ | ||
---|---|---|---|---|
0
Menjoy
03.12.11
✎
21:07
|
Добрый день.
Понадобилось написать компоненту с нуля на С++ (visual studio 2008). Был реализован основной интерфейс IInitDone, но dll не загружается 1Ской: Ошибка при вызове метода контекста (ЗагрузитьВнешнююКомпоненту): Ошибка при загрузке внешней компоненты Проект создан с поддержкой mfc. Кто сталкивался с написанием внешних компонент именно на с++ с нуля? Просьба подсказать, где могут быть подводные камни. За основу брал статью http://oksla.narod.ru/vk.htm#_Toc502332887 и уже готовую компоненту. |
|||
1
SnarkHunter
03.12.11
✎
21:11
|
Видимо включен UAC...
|
|||
2
Menjoy
03.12.11
✎
21:11
|
(1) можно чуть подробнее? Что это?
|
|||
3
Menjoy
03.12.11
✎
21:14
|
Уже прочитал в вики, все делается на win хр sp3
|
|||
4
bezgudroman
03.12.11
✎
21:34
|
А точно нужна именно внешняя компонента?
|
|||
5
bezgudroman
03.12.11
✎
21:39
|
Может вот так попробовать: http://unnstudioreport.googlecode.com/files/examplVK.zip
|
|||
6
Menjoy
03.12.11
✎
21:56
|
(4) да, нужна именно внешняя.
Ваша компонента тоже не подгружается 1С и в исходниках нужных интерфейсов и функций я не вижу. У вас работает? |
|||
7
bezgudroman
03.12.11
✎
22:05
|
(6) >> У вас работает?
Конечно. Там же написано: "Сразу оговорюсь, в итоге получится обыкновенный inprocess server, а не "внешняя компонента" в понимании 1С. В этом примере не используется "Технология создания внешних компонент" от 1С (где-то она у меня на старом винте заблудилась - найти не могу), и поэтому описанная ниже технология подходит для задач типа "вы спрашиваете - мы отвечаем"." |
|||
8
bezgudroman
03.12.11
✎
22:05
|
Что делает твоя ВК?
|
|||
9
bezgudroman
03.12.11
✎
22:13
|
тут попробуй: http://www.1cpp.ru/forum/YaBB.pl?board=general
|
|||
10
Menjoy
03.12.11
✎
22:24
|
(8) компонента получает данные от 1С (сервер, порт, логин, пароль) и подключается к серверу, который в свою очередь постоянно передает данные компоненте, эти данные обрабатываются и уже в нужном виде попадают в 1С.
Кхм, попробовал твою компоненту подключить как ЗагрузитьВнешнююКомпоненту("E:\Example.dll"); предварительно зарегистрировав, та же ошибка. |
|||
11
Menjoy
03.12.11
✎
22:27
|
Есть исходники уже рабочей компоненты, но без поддержки MFC.
Поэтому решил создать проект с нуля, взял из предыдущего все обязательные интерфейсы и методы, все равно не подключает. p.s. а каким образом подключается эта компонента у тебя? |
|||
12
bezgudroman
03.12.11
✎
22:45
|
В архиве есть файло: example.htm
Там в конце написано: Процедура Сформировать() В=СоздатьОбъект("example.Random"); // Random возвращает значение от 0 до 1000 в данном случае Всп=В.GetRandomValue(1000); Сообщить(Всп); КонецПроцедуры |
|||
13
Rie
03.12.11
✎
22:46
|
(11) v8 - имеется в виду 8.1 или 8.2?
|
|||
14
Rie
03.12.11
✎
22:48
|
+(13) И какую компоненту рисуешь: под NativeAPI или под COM?
|
|||
15
Menjoy
03.12.11
✎
22:59
|
v8 в моем случае 8.2
(14) СОМ |
|||
16
Rie
03.12.11
✎
23:01
|
(15) Покажи реализацию IInitDone.
|
|||
17
Rie
03.12.11
✎
23:06
|
+(16) И ещё деталь - права на запись в реестр в HKEY_CLASSES_ROOT у пользователя есть?
|
|||
18
Rie
03.12.11
✎
23:12
|
+(17) Ну и ещё вопрос - а IDispatch реализован (хотя бы заглушками)?
|
|||
19
orefkov
04.12.11
✎
00:14
|
Никаких особенностей в длл на С++ нет.
Реализуйте все правильно, и все будет работать. В ТВК пример на С++ есть. И что все у народа какие-то сложности с ВК? Делов то там - ПРАВИЛЬНО реализовать inproc server да пару интерфейсов. Ну и в реестре правильно описать. |
|||
20
Menjoy
04.12.11
✎
01:38
|
(16)
права на запись в реестр есть, все записывается, искал в реестре по прогид. Реализация интерфейса IInitDone [ object, uuid(8FE5C6B3-2758-4557-B8AB-9E8C2D764E4B), helpstring("IInitDone Interface"), pointer_default(unique) ] interface IInitDone : IUnknown //инициализация и выгрузка 1С { [helpstring("method Init")] HRESULT Init([in] IDispatch *pConnection); [helpstring("method Done")] HRESULT Done(); [helpstring("method GetInfo")] HRESULT GetInfo([in,out] SAFEARRAY (VARIANT) *pInfo); }; Методы упростил и сделал так, чтобы они только возвращали S_OK. |
|||
21
Menjoy
04.12.11
✎
01:45
|
(19) в реестре все прописывается правильно - CLSID и ProgID добавляются.
Ошибка именно при вызове метода ЗагрузитьВнешнююКомпоненту(); У меня у самого есть исходник внешней компоненты (которая у меня корректно работает), но без поддержки MFC, да и нужно научится просто создавать заготовку dll для 1С. А примера на С++ из ТВК не видел, выслать можете? |
|||
22
orefkov
04.12.11
✎
01:57
|
(21)
Ну и скажи, каков ProgID твоей ВК ? |
|||
23
orefkov
04.12.11
✎
02:11
|
+(22)
Надеюсь, удовлетворяет вот этому: "При загрузке внешней компоненты функцией ЗагрузитьВнешнююКомпоненту 1С:Предприятие определяет ProgID OLE-объекта компоненты следующим образом: ProgID имеет вид <Vendor>.<Component>; в качестве первой части (<Vendor>) используется строка "AddIn"; в качестве второй части (<Component>) используется строка с ID 100 из таблицы строк компоненты. Cтрока может иметь вид "Name1|Name2|...|NameN", и в этом случае будут созданы все объекты с ProgID вида "AddIn.NameX". Если такая строка отсутствует, то используется имя файла внешней компоненты без расширения." |
|||
24
Rie
04.12.11
✎
07:57
|
(20) Это не _реализация_, это _описание_ интерфейса.
Что касается "упростил" - то метод GetInfo должен не только вернуть S_OK, но и правильное значение версии установить. |
|||
25
Menjoy
04.12.11
✎
12:52
|
(23)
ProgID следующий - com_1c.TSoc.1 - такой прописался в реестре. А <vendor> обязательно должен быть "AddIn". Если так, то возможно именно в этом проблема, проверю. (24) GetInfo() так же пробовал использовать из рабочего исходника. |
|||
26
Rie
04.12.11
✎
13:10
|
(25) Ещё обрати внимание на ресурс 100.
|
|||
27
orefkov
04.12.11
✎
13:50
|
(25)
Смени прогид на "Addin.ИмяТвоегоФайлаБезРасширения" |
|||
28
Menjoy
04.12.11
✎
17:21
|
Теперь, судя по всему ЗагрузитьВнешнююКомпоненту(); срабатывает, ошибки нет.
Но не создается объект - ВК = Новый ("AddIn.AddInSoc"); Ошибка - Тип не определен (AddIn.SocDll). ProgID (независимый от версии) в реестре прописан такой же, пробовал и с AddIn.SocDll.1 |
|||
29
Rie
04.12.11
✎
17:23
|
(28) Что в ресурсе 100? Какой ProgID в реестре?
|
|||
31
Menjoy
04.12.11
✎
17:28
|
Под ID 100 лежит AddInSoc
В реестре AddIn.AddInSoc |
|||
33
Rie
04.12.11
✎
17:33
|
(28) Новый COMОбъект("AddIn.AddInSoc")?
|
|||
34
Menjoy
04.12.11
✎
17:33
|
В сообщение (28) кое что перепутал, там везде AddIn.AddInSoc вместо SocDll
|
|||
36
Menjoy
04.12.11
✎
17:35
|
(33) Ошибка при вызове конструктора (COMОбъект): Интерфейс не поддерживается: Интерфейс не поддерживается
При таком подходе, получается что интерфейс какой-то не реализован просто. В этой длл есть только IInitDone и все. Кстати, исходник, который у меня есть, его длл подключается через Новый (""); т.е. без COMОбъект. |
|||
37
Rie
04.12.11
✎
17:36
|
(36) Заглушка IDispatch есть? И как именно сейчас выглядит GetInfo?
|
|||
39
Menjoy
04.12.11
✎
17:41
|
Вот GetInfo()
STDMETHODIMP CAddInSoc::GetInfo(SAFEARRAY **pInfo) { // Component should put supported component technology version // in VARIANT at index 0 long lInd = 0; VARIANT varVersion; V_VT(&varVersion) = VT_I4; V_I4(&varVersion) = 2000; SafeArrayPutElement(*pInfo,&lInd,&varVersion); return S_OK; } А что за заглушка IDispatch? |
|||
40
Rie
04.12.11
✎
17:44
|
(39) Реализовать IDispatch - пусть его методы просто возвращают E_NOTIMPL.
|
|||
41
Menjoy
04.12.11
✎
17:54
|
(40) Он же реализован по умолчанию.
#if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("00020400-0000-0000-C000-000000000046") IDispatch : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount( /* [out] */ __RPC__out UINT *pctinfo) = 0; virtual HRESULT STDMETHODCALLTYPE GetTypeInfo( /* [in] */ UINT iTInfo, /* [in] */ LCID lcid, /* [out] */ __RPC__deref_out_opt ITypeInfo **ppTInfo) = 0; virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames( /* [in] */ __RPC__in REFIID riid, /* [size_is][in] */ __RPC__in_ecount_full(cNames) LPOLESTR *rgszNames, /* [range][in] */ UINT cNames, /* [in] */ LCID lcid, /* [size_is][out] */ __RPC__out_ecount_full(cNames) DISPID *rgDispId) = 0; virtual /* [local] */ HRESULT STDMETHODCALLTYPE Invoke( /* [in] */ DISPID dispIdMember, /* [in] */ REFIID riid, /* [in] */ LCID lcid, /* [in] */ WORD wFlags, /* [out][in] */ DISPPARAMS *pDispParams, /* [out] */ VARIANT *pVarResult, /* [out] */ EXCEPINFO *pExcepInfo, /* [out] */ UINT *puArgErr) = 0; }; |
|||
42
Rie
04.12.11
✎
17:58
|
(41) Твой код я не вижу, а телетяпией не страдаю :-)
Какой интерфейс не реализован - вероятно, ILanguageExtender. |
|||
43
Menjoy
04.12.11
✎
18:02
|
Да-да, именно, только что сам к этому пришел - ILanguageExtender.
Подгрузил другую компоненту как СОМ и увидел, что она вернула два значения: 1) Включено - 0; 2) ТаймерПрисутствует - 1; Отсюда и понял )) Спасибо, пожалуй займусь в рабочий день. |
|||
44
orefkov
04.12.11
✎
18:13
|
ILanguageExtender надо
|
|||
45
Menjoy
04.12.11
✎
19:21
|
(42) (44)
а если будет реализован ILanguageExtender сработает ли просто ВК = Новый ("ProgID")? |
|||
46
Rie
04.12.11
✎
19:44
|
(45) Новый COMОбъект("ProgID")
|
|||
47
Rie
04.12.11
✎
19:47
|
+(46) Хотя нет. Тут я соврал насчёт COMОбъект.
|
|||
48
Menjoy
04.12.11
✎
20:01
|
(47) немного не понял :)
Есть исходники компоненты, на которую я полагался в своей разработке, так вот она вызывается просто как Новый("ProgID") и получается ком-объект, проверял в отладчике. |
|||
49
Rie
04.12.11
✎
20:07
|
(48) Я и говорю - соврал я насчёт того, что надо писать именно Новый COMОбъект.
|
|||
50
Rie
04.12.11
✎
20:09
|
+(49) Ты б поставил в методах IInitDone и ILanguageExtender вызовы MessageBox - и сразу стало бы ясно, на каком этапе у тебя проблемы.
|
|||
51
Menjoy
04.12.11
✎
20:10
|
(50) Займусь дальше только в понедельник ;) Если что, то буду продолжать тему )) Не нашел подобных на просторах интернета, потому и начал свою.
Спасибо за совет на счет MessageBox, попробую. |
|||
52
Rie
04.12.11
✎
20:11
|
(51) Если действовать "строго по инструкции", соблюдая все требования - проблем не будет. Проверено :-)
|
|||
53
Menjoy
08.12.11
✎
13:02
|
По-тиху продвигаюсь вперед и возник такой вопрос.
Как правильно создается внешнее событие? Сделал спец. функцию и повесил ее на кнопку в 1С, чтобы тренироваться. Функция в срр имеет следующий вид: VOID CALLBACK Connection(CString value1, CString value2) { BSTR who, what, data; CString whois; whois = L"DLL"; who = whois.AllocSysString(); what = value1.AllocSysString(); data = value2.AllocSysString(); pAsyncEvent->ExternalEvent(who, what, data); } Но внешнее событие не ловится формой :( В модуле формы 1С прописано: Процедура ВнешнееСобытие(Источник, Событие, Данные) Если Событие = "1" Тогда Сообщить("Внешнее событие получено!"); КонецЕсли; КонецПроцедуры При отладке value1 задаю 1. |
|||
54
Menjoy
08.12.11
✎
13:05
|
При отладке еще выловил такую ошибку:
Unhandled exception at 0x06375e01 (AddInCOM.dll) in 1cv8.exe: 0xC0000005: Access violation reading location 0x00000000. |
|||
55
Rebelx
08.12.11
✎
13:07
|
(10) а может ну ее эту компоненту? что нельзя сделать на 1С? а еще можно использовать JS для бинарных данных
|
|||
56
Menjoy
08.12.11
✎
13:12
|
(55) нужно, возможностей куча, к тому же с++ быстрее обрабатывает информацию ;)
Меня больше интересует ответ на вопрос, нежели споры о полезности компонент) |
|||
57
Serginio1
08.12.11
✎
13:15
|
Возьми отсюда http://1c.proclub.ru/modules/mydownloads/personal.php?cid=115&lid=2019
Исходник ВК которая загружает Объект Автоматизации поддерживающий ITypeInfo и выполняет все его свойства и методы через IlanguageExtender. Где там есть еще и исходники аналогичной приблуды на C++ |
|||
58
Menjoy
08.12.11
✎
13:20
|
(57) то, что вы скинули - на delphi
И все же хочется найти ошибку у себя. |
|||
59
Serginio1
08.12.11
✎
13:20
|
||||
60
jsmith82
08.12.11
✎
13:25
|
я пишу на остром си - всё без проблем
|
|||
61
Rie
08.12.11
✎
13:38
|
(54) Эта ошибка произошла в коде на С++! Там её и надо искать, сам механизм внешних компонент тут ни при чём.
Поставь отладочный вывод. Определи, в какой строке происходит исключение. Или перехвати его try ... catch - и выдай результат. Где вызывается Connection - никому, кроме тебя не известно. Что за значения у каких переменных - тоже. |
|||
62
Menjoy
08.12.11
✎
13:56
|
Connection вызываю из 1С, он доступен через внешнюю компоненту.
Ошибку выдает именно в этой строке: pAsyncEvent->ExternalEvent(who, what, data); Думаю, что может быть связано с строкой в срр файле: static IAsyncEvent *pAsyncEvent = NULL; |
|||
63
Rie
08.12.11
✎
13:59
|
(62) Нет, ну трах-тибидох! Естественно с этим связано!!!
Обращаться к методу объекта по указателю NULL - это круто! pAsyncEvent инициализируй в IInitDone::Init. |
|||
64
Menjoy
08.12.11
✎
13:59
|
Ошибка при вызове любого из методов pAsyncEvent.
|
|||
65
Menjoy
08.12.11
✎
13:59
|
(63) извиняюсь за такие вопросы, но я пару дней как вижу С++ ;)
|
|||
66
Rie
08.12.11
✎
13:59
|
(64) Меня это не удивляет. Когда вызываются методы объекта по указателю NULL - так всегда бывает.
|
|||
67
Rie
08.12.11
✎
14:02
|
(65) Тогда зря ты сел за написание на нём ВК. Лучше освой язык - а потом уже пиши.
|
|||
68
Menjoy
08.12.11
✎
14:10
|
(63)
а каким образом правильно инициализировать pAsyncEvent в IInitDone::Init? в данном контексте просто не ясно, что значит инициализовать |
|||
69
Rie
08.12.11
✎
14:14
|
(68) При помощи GetInterface получить IAsyncEvent из того IDispatch, который тебе в Init передан.
|
|||
70
Menjoy
08.12.11
✎
14:16
|
Упс, (68) было очень поспешным.
Действительно, нужно было просто добавить строку pAsyncEvent = m_iAsyncEvent; в объявлении метода Connection. Т.к. в IInitDone::Init инициализирован: m_iConnect->QueryInterface(IID_IAsyncEvent,(void **)&m_iAsyncEvent); |
|||
71
Menjoy
08.12.11
✎
14:16
|
(69) согласен конечно с замечанием про подучить язык, но так обучаться интереснее. К тому же мне нужно изучить всего лишь некоторые аспекты языка :)
Тем не менее, спасибо за уже оказанную помощь и что тему поглядываешь )) |
|||
72
Rie
08.12.11
✎
14:29
|
(70) Если у тебя уже есть член с именем m_iConnect (а судя по префиксу m_ - это именно член) - зачем ещё static-переменную заводить?
|
|||
73
Menjoy
08.12.11
✎
14:57
|
(72) вот уж не знаю, она объявлена была в исходниках, по-немногу разгребаюсь с ними :)
|
|||
74
Menjoy
13.12.11
✎
13:03
|
Пытаюсь сделал возвращаемое функцией значение, причем не булево, а допустим результат сложения двух чисел.
Может кто пример описания метода в HRESULT CallAsFunc(long lMethodNum, VARIANT *pRetValue, SAFEARRAY**pVars) показать? |
|||
75
orefkov
13.12.11
✎
13:09
|
pRetValue->vt = VT_I4;
pRetValue->intVal = 10; |
|||
76
Menjoy
13.12.11
✎
13:28
|
(75) спасибо.
Сейчас буду учиться возвращать результат выполнения другой функции, тут уже по срр нужно читать. |
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |