Передача параметров ByVal (ByRef) в MIDL

Обсуждение вопросов, касающихся указанной технологии.
Diamock
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 388
Зарегистрирован: 26.10.2009 (Пн) 4:19
Откуда: Кемерово

Передача параметров ByVal (ByRef) в MIDL

Сообщение Diamock » 12.11.2015 (Чт) 15:34

Здравствуйте Уважаемые!
При объявлении API функций в модуле VB, параметры передаются ByVal или ByRef. Учусь создавать tlb, соответственно возник вопрос, каким образом это описывается в MIDL'е.
Проштудировал msdn, там написано следующее:
Атрибут [in] - передача значения ByVal.
Атрибут [in,out] - передача значения ByRef.
Я всё правильно понял? Потому что меня смущает атрибут [ref].
In der Beschrankung zeigt sich erst der Meister
Графоманю...

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: Передача параметров ByVal (ByRef) в MIDL

Сообщение ger_kar » 12.11.2015 (Чт) 16:17

Ну вообще логика примерно такая:
Что есть передача аргумента ByVal? - Это передача его значения.
Что есть передача аргумента ByRef? - Это передача указателя (ссылки).
MIDL Использует Си подобный синтаксис и соответственно, то что на VB6 соответствует передаче ByRef в MIDL/C будет передача указателя, который обозначается символом "*". Причем звездочку можно поставить как после указания типа, так и перед наименованием самого аргумента.
[in] long* pMemory, [in] long *pMemory - Передача указателя(ссылки).
[in] long pMemory - Передача значения.
Теперь о том как соотносятся с этим атрибуты [in], [out], [in, out], тут тоже все очень просто.
Если параметр есть [in] то передача возможна хоть по указателю (ссылке), хоть по значению. Например передали в функцию значение5 и 10, они туда так в стек и запишутся. А теперь стоит задача не просто туда значение передать, а еще и возвратить обратно, естественно, что при таком раскладе передача по значению ну никак не подходит. Тут нужно передать не значение переменной а ее адрес, т.е. указатель. Тогда функция по этому адресу (указателю) может это значение получить и записать туда новое, которое и вернется в вызывающую процедуру. Поэтому передача аргументов с атрибутами [in, out] и [out] возможна только по указателю(ссылке).
Вот как то так.
Бороться и искать, найти и перепрятать

Diamock
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 388
Зарегистрирован: 26.10.2009 (Пн) 4:19
Откуда: Кемерово

Re: Передача параметров ByVal (ByRef) в MIDL

Сообщение Diamock » 12.11.2015 (Чт) 16:55

ger_kar, спасибо за ответ. Что-то подобное я и предполагал, только сформулировать не мог, поэтому и спросил.
In der Beschrankung zeigt sich erst der Meister
Графоманю...

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Передача параметров ByVal (ByRef) в MIDL

Сообщение Хакер » 12.11.2015 (Чт) 23:42

Атрибуты in и out напрямую с ByVal и ByRef не коррелируют вообще никак.

Будет ли со стороны VB аргумент представлен как ByVal или ByRef зависит от типа аргумента в IDL-объявлении, и никак не зависит от атрибутов.

Атрибуты in и out играют совершенно другую роль. Их предназначение — подсказки для маршаллинга.

Вообще-то от высказывания ger_kar'а немножко уши вянут. То, что он называл Си-подобным синтаксисом, на самом деле является не каким-то там суррогатом, похожим на Си, а самостоятельным описательным языком MIDL.

Язык MIDL является небольшим расширением над языком IDL.

На языке IDL стоит остановиться и рассказать чуть подробнее. Язык IDL создан комитетом The Open Group (той же организацией, которая подарила нам такие вещи как LDAP и X11).

IDL был частью концепции DCE/RPC — которая предлагала механизм RPC (remote procedure call) услуг, то есть услуг по вызову неких процедур через границы разных машин (или как минимум — разных программ). Центральной идеей DCE/RPC было понятие «интерфейс» и «точки входа».

Точка входа — это нечто, что можно вызвать удалённо, то есть некая процедура.
Интерфейс — это группа точек входа, собранная по какому-то принципу, причём предполагается, что содержимое интерфейса продумывается и потом провозглашается (как некий микро-стандарт), и затем с интерфейсом может работать кто угодно, вызывая через границы разных машин некие процедуры.

Эти интерфейсы в рамках DCE/RPC были совершенно в стороне от ActiveX и COM, от Microsoft и вообще от ООП. Это была чисто процедурная штука, и интерфейсы тут были в том же смысли, в каком это слово применимо к понятию «сетевой интерфейс» или «USB-интерфейс» — как нечто, с чем можно взаимодействовать, следуя заранее провозглашённым правилам игры.

Так вот, интерфейс представлял собой группу точек входа — другими словами процедур. У процедур были имена, и, что куда важнее, были аргументы.

Здесь начинается самое главное. Поскольку весь разговор о вызове удалённых процедур через сеть, то если кто-то вызывает процедуру, имеющую некий набор аргументов, то нужно при вызове аргументы передавать по сети сначала от вызывающей стороны к вызываемой, а затем (если вызванная процедура их как-либо меняет) передавать изменённые агументы обратно.

Собственно говоря, атрибуты in и out возникли ещё на этом этапе и предназначались для этого чисто-процедурного RPC-механизма.

Это потом уже корпорация Microsoft придумала OLE, COM и ActiveX с DCOM, и для этих технологий взяла стандарт DCE/RPC (и соответсвующий ему протокол) как базу, и поверх него построила собственную технологию и протокол MS-ORPC.

И только у Microsoft изначально чисто процедурное понятие «интерфейса» (из DCE/RPC) стало играть роль интерфейса-из-мира-ООП.

Так вот, поскольку корпорация Microsoft тоже делала RPC-механизм, но на этот раз главным образом ООП-основанный RPC-механизм. И поскольку были возможны объектные вызовы через границы процессов или машин, стало необходимо делать маршалинг (упаковывать параметры вызова, передавать их на другую машину, затем упаковывать результат и передавать вызывающей стороне), уже имеющиеся атрибуты in и out оказались полезными и здесь (не по чистой удачи, а потому что и тут и там решалась принципиально одна и та же задача — вызов удалённой процедуры).

Так что in и out нужны для маршалинга.

Что касается такой сущности TLB как «модуль», то я не представляю себе случая при которых вызов модульной функции подвергся бы маршалингу. Обычно в случае вызова модульной функции имеет место просто вызов импортированной из DLL функции.

Так что атрибуты in и out в рамках модулей в TLB на первый взгляд никакой роли не играют и никак не используются.

Можно ли их вообще не ставить? Технически — конечно можно. Но есть несколько случаев, когда от них может быть польза.

Во-первых, некая гипотетическая IDE, работающая с TLB, может учитывать их при отображении подсказки/справки по функциям, объявленным в TLB. И тогда эти атрибуты повлияют на отображаемые подсказки и помогут программисту.

Во-вторых, они могут быть напрямую восприняты программистами, читающими исходник TLB или декомпилированный код TLB. Собственно говоря, в С/С++ распространённой практикой является объявление чисто разметочных макросов (с помощью #define), которые, раскрываясь, подменяются на пустое место. Роль таких макросов чисто в том, чтобы они повышали читаемость кода. Как раз есть макроы _IN, _OUT, _OPTIONAL.

В-третьих, нельзя исключать, что кто-нибудь захочет написать некий механизм, который берёт TLB и содержащиеся в ней модули и для каждого модуля с импортируемыми сущностями генерирует объект-обёртку, методы которого олицетворяют модульные функции (импортируемые из DLL). Простейший пример того, зачем это может быть нужно, это идея подарить VBScript-пользователям (или пользователям любых других скриптовых языков, где для безтиповых переменных под капотом используется тип Variant, а для ООП — COM, либо где просто есть возможность работы с COM (как в PHP)) возможность находясь в рамках безтипового языка вызывать функции из DLL-библиотек.

В этом случае при реализации такого механизма in/out-атрибуты, данные изначально в TLB-шном модуле, понадобятся механизму, чтобы правильно проводить маршалинг аргументов вызываемых функций.

А вот, к слову, атрибут retval играет совсем другую роль, и со стороны VB/VBA он влияет на то, как будет выглядеть функция/метод.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: Передача параметров ByVal (ByRef) в MIDL

Сообщение ger_kar » 13.11.2015 (Пт) 7:33

Хакер писал(а):Вообще-то от высказывания ger_kar'а немножко уши вянут. То, что он называл Си-подобным синтаксисом, на самом деле является не каким-то там суррогатом, похожим на Си, а самостоятельным описательным языком MIDL.
Ну и что? Да MIDL это отдельный язык (я обратное и не утверждал), но это не мешает ему быть Си подобным. 1С тоже совершенно самостоятельный язык, так же как AutoIt и другие и это никак не мешает им быть бейсикоподобными.
Вот например цитата из MSDN:
MSDN писал(а):...There are a few key areas in which the MIDL compiler differs from MkTypLib. Most of these differences arise because MIDL is oriented more toward C-syntax than MkTypLib.
[/quote=][quote"машинный перевод"]Есть несколько ключевых областей, в которых компилятор MIDL отличается от MkTypLib. Большинство этих различий возникают потому, что MIDL более ориентирована на синтаксис C чем MkTypLib.


Хакер писал(а):Атрибуты in и out напрямую с ByVal и ByRef не коррелируют вообще никак.
Нет, зависимость таки есть. Достаточно объявить аргумент имеющий [out] не указателем, и библа уже не скомпилируется, так как начнет вываливаться ошибка
"error MIDL2042 : [out] parameter is not a pointer :"
что и понятно.
Бороться и искать, найти и перепрятать

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Передача параметров ByVal (ByRef) в MIDL

Сообщение Хакер » 13.11.2015 (Пт) 7:39

ger_kar писал(а):
Хакер писал(а):Атрибуты in и out напрямую с ByVal и ByRef не коррелируют вообще никак.
Нет, зависимость таки есть. Достаточно объявить аргумент имеющий [out] не указателем, и библа уже не скомпилируется, так как начнет вываливаться ошибка
"error MIDL2042 : [out] parameter is not a pointer :"
что и понятно.


Советую внимательно вдуматься в смысл отцитированного, прежде чем писать такое.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: Передача параметров ByVal (ByRef) в MIDL

Сообщение ger_kar » 13.11.2015 (Пт) 20:29

Хакер писал(а):Советую внимательно вдуматься в смысл отцитированного, прежде чем писать такое.
А может ты пояснишь? Ведь зависимость есть, а прямая она или кривая это не суть важно я думаю.
Бороться и искать, найти и перепрятать

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Передача параметров ByVal (ByRef) в MIDL

Сообщение Хакер » 13.11.2015 (Пт) 21:32

Хакер писал(а):А может ты пояснишь? Ведь зависимость есть, а прямая она или кривая это не суть важно я думаю.


Её нет. То, что написал, что атрибут out требует степень индирекции >0 (то есть, говоря по колхозному — хотя бы одну звёздочку между базовым типом и именем аргумента), ещё не устанавливает никакой зависимости между ByVal и ByRef.

Во-первых, это совершенно ненавязчивая проверка разумности на уровне самого компилятора. Какой-нибудь другой компилятор IDL на это бы не ругнулся, а спокойно бы сгенерировал соответствующий TLB-файл. И сам формат TLB спокойно пережил бы хранение неуказательного аргумента с атрибутом out.

Но, что самое главное, наличие указательного типа не означает автоматически, что со стороны VB это будет непременно ByRef-аргумент. Не будет.


Код: Выделить всё
typedef IDispatch AsObjectInVb6

module foo
{
     void Test([out]AsObjectInVb6* arg)
}


Атрибут out есть? Есть.
Звёздочка есть? Есть.
MIDL не ругается? Не ругается.

Со стороны VB6 это будет ByVal arg As Object.

Ну и о какой зависимости ByRef-ности от наличия out-атрибута может идти речь? Или о прямой корреляции?

out-атрибут может присутствовать, и это будет ByVal со стороны VB.
out-атрибут может присутствовать, и это будет ByRef со стороны VB.
out-атрибут может отсутствовать, и это будет ByVal со стороны VB.
out-атрибут может отсутствовать, и это будет ByRef со стороны VB.

Когда наблюдаем такие 4 комбинации, это повод твёрдо сказать, что одно от другого не зависит.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.


Вернуться в OLE / COM / ActiveX

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1

    TopList