Кажется, наступает некое просветление... Все аргументы с указанием их типов передаются в fpc_dispinvoke_variant, которая с ними разбирается дальше. Уже хорошо, т.к. преобразованиями может заняться RTL. Для типа WideString передается 8 (varolestr, определена в начале файла rtl/inc/varianth.inc), для типа AnsiString - $48 (varstrarg) (а при обычном присвоении AnsiString->Variant будет тип $100 varstring, почему-то ), для UnicodeString вообще никакого подходящего типа не наблюдается.
Иван Шихалев писал(а):Кстати, насчет «что передается»... А где искать структуру последнего параметра DispInvoke?
Это который Params: Pointer? По смыслу должен указывать на аргументы вызова, которых может быть переменное число, а типы определяются параметром CallDesc.
В винде по идее должно все приводиться к WideString, включая и литералы и ansistring. Что должно быть "не в винде" - без понятия Вообще я раньше почти не соприкасался с предметной областью, так что, возможно, где-то и неправ. Параметры, наверное, лежат по порядку (а что еще можно придумать?)
Напишу-ка я, пожалуй, в багтрекер все как оно есть на текущий момент...
Еще, кстати, не автоматизируются Int64 и QWord. Интересно, а не нужны ли они в Win64...
Добавлено спустя 2 минуты 10 секунд: Вообще, на мой взгляд, идеальным решением было бы проверять все эти ограничения только в отдельно включаемом/отключаемом режиме OLE Compatible...
Иван Шихалев писал(а):Еще, кстати, не автоматизируются Int64 и QWord. Интересно, а не нужны ли они в Win64...
Как мне кажется, для выяснения этого вопроса нужно брать что-то типа Platform SDK для Win64 с примерами и смотреть, как там оно работает.
Иван Шихалев писал(а):Вообще, на мой взгляд, идеальным решением было бы проверять все эти ограничения только в отдельно включаемом/отключаемом режиме OLE Compatible...
Для OLE-совместимости вроде бы предназначается тип OleVariant.
Sergei I. Gorelkin писал(а):Для OLE-совместимости вроде бы предназначается тип OleVariant.
Тем более непонятно, зачем ограничивать CustomVariant. Правда, есть у меня подозрение, что контролировать совместимость в зависимости от типа может быть не так просто.
Дык там просто конь не валялся. TCustomVariantType, TInvokeableVariantType не реализованы вообще никак. Вот для начала написал нормальный конструктор и десяток тестов.
Про коня верно подмечено. Я щас ковыряю DispInvoke в Invokable... Наверное, к завтрему доковыряю до рабочего состояния.
И еще такой момент: там, ИМХО, DispInvoke в TCustomVariantType, и все кроме DispInvoke в TInvokeableVariantType, надо объявить как abstract, поскольку по сути оно таковым и является. В делфевой версии оно генерит ошибку и больше ничего не делает. На мой взгляд abstract лучше тем, что генерирует кроме run-time error еще и compile-time warning.
Ненене, TCustomVariantType является базой для создания типов Variant, которых просто хранят данные (нет dispatch-методов), делать в нем DispInvoke абстрактным и заставлять всех в обязательном порядке его перекрывать - прямо скажем, не умно. Точно так же с TInvokeableVariantType, в его наследниках не обязательно реализовывать все четыре метода (DoFunction, DoProcedure, GetProperty, SetProperty), достаточно чего-то одного.
Точно так же и с TStream.Read и TStream.Write: реализация по умолчанию, бросающая исключение, позволила вычистить пол-тонны однотипного кода (который к тому же и не должен никогда выполняться!) из всего FCL, где почти все наследники либо только для чтения, либо только для записи.
С точки зрения "для протокола и истории" лучше, наверное, в багтрекер. Формат - git diff люди точно присылают, и они успешно применяются, насчет diff так уверенно сказать не могу, но каких-то проблем и с ним быть не должно.
ОК. Учитывая, что тестить буду на локальном git-ответвлении...
Добавлено спустя 16 часов 59 минут 43 секунды: Мда... Со строками вот еще что интересно — соответствие ArgType при автоматизации и vType в вариантном представлении, точнее — несоответствие.
литерал: ArgType = varUnicodeString, vType = varString или varOleStr (в зависимости от того, что в нем) AnsiString: ArgType = varStrArg, vType = varString WideString/UnicodeString: ArgType = varUnicodeString, vType = varOleStr Utf8String: ArgType = varStrArg, vType = varOleStr
Непонятно, как быть с Utf8 vs Ansi...
Добавлено спустя 1 минуту 37 секунд: Т.е., как я это вижу — Utf8String по хорошему не должна передаваться как varStrArg, а должна как varUnicodeString.
Sergei I. Gorelkin Что-то с последними изменениями (rev. 16389) посыпалась передача всего кроме строк...
Добавлено спустя 6 минут 13 секунд: Кажется, понял. Теперь сдвиг нужно делать не на sizeof(pointer), а в зависимости от типа... Или все-таки минимум на 4 байта?
Добавлено спустя 4 минуты 53 секунды: И, кстати, это так задумано, что UnicodeString по значению передается, а по ссылке — нет?
Попробую по порядку: - В генерации сдвига в компиляторе был тупой баг, считалось что все передается по ссылке и под каждый аргумент отводилось sizeof(pointer) байт, хотя double передавался по значению и для него нужно sizeof(double). Из-за этого на x86_64, собственно, все было хорошо, а на i386 твой патч не работал. Это я поправил в ревизии 16350. - Потом в ревизии 16360 я в добавил проверки в парсинг dispinterface, чтобы в них можно было использовать только automatable типы. Заодно убрал ограничения времен windows 95 на перечисляемые типы, и решил проблему не-передачи перечисляемых типов по ссылке. Т.к. вызовы методов variant полностью динамические и для них нет объявлений с указанием как что передавать, то используется следующая логика: если можно передать по ссылке, то передаем по ссылке, иначе по значению. А по ссылке можно передавать все, кроме результата вызова другой функции, свойств и непосредственно заданных значений. - Затем нужно было забороть тип variant, который всегда передавался по ссылке. Что и было сделано в 16389. В параметрах по-прежнему передается ссылка, но бит $80 устанавливается не всегда. Из-за этого в патч для DispInvoke придется вносить изменения, аналогичные тем, что внесены в winunits-base/src/comobj.pp ревизии 16388. Но это я и сам могу сделать.
Теперь эта UnicodeString, будь она неладна. Ее я даже еще не начинал копать. Но уже понятно, что с ней надо обходиться примерно так, как с AnsiString. Откуда растут ноги у varString и varStrArg? varString=$100, т.е. находится в диапазоне "псевдо-пользовательских" типов. "Псевдо" - потому что настоящий TCustomVariant начинается с $10F. А находится в этом диапазоне потому, что это специфичный для Delphi/FPC тип, и COM с ним работать просто не умеет. А varStrArg используется только для передачи типа AnsiString в DispInvoke, потому что в CallDesc на каждый аргумент отводится только 1 байт, и varString в него просто не помещается. Т.е, действуя по образу и подобию, нужно изменять varUnicodeString на $102 (кстати в последних Delphi оно так и есть, только имя varUString), добавлять какой-нибудь varUStrArg=73, и дальше по аналогии...
Что с этой радостью делать в самой процедуре DispInvoke - тоже непонятно. Просто так подставлять varOleStr вместо varUnicodeString нельзя, это разные типы, нужно выделять память с помощью SysAllocateString и копировать строку туда, но это возможно только для windows...