Adam Smith писал(а):VB6 компилит VERSIONINFO только для языка 1033, из параметров проекта, в которых даже с версией не всё ладно.
Напиши подробнее, что именно не ладно с версией.
То, что используется язык 1033 логично, потому что берётся язык, используемый на машине разработчика. Логично, что программа, компилируемая на китайском компьютере китайского разработчика будет в качестве языка иметь китайский язык. Как ещё нужно было поступить во времена, когда большинство использовало операционную систему, плохо дружащую с юникодом, а мир не был таким глобализированным, как сегодня?
Adam Smith писал(а):И этот кривой процесс компиляции ресурса захардкоден в VBIDE.dll по-моему, если не ошибаюсь, читал в Интернетах.
Всё не так.
Начнём с
VBIDE.dll. Такая библиотека действительно есть. Но в ней нет никакого кода. Вообще. Эта DLL-библиотека лишь хранит в себе разные ресурсы (картинки, строки, иконки, диалоги). И в ней ничего не захардкожено.
Среда VB — это главным образом связка из
VB6.EXE и
VBA6.DLL. Эти два файла представляют собой два фундаментальных компонента, из которых состоит VB как продукт: Ruby и EB. Рассказ о Ruby и EB — то, с чего я хотел начать цикл статей о внутреннем устройстве VB (давно задуманный). Он был готов в прошлом году, как и два перевода, сопровождающих его, но я не хотел публиковать его, пока значительная часть цикла не будет готова к публикации.
И всё-таки ты вынудил меня опубликовать эту первую главу цикла.
Моя
статья о Ruby+EB,
перевод (1) чужой статьи,
перевод (2) чужой статьи. Прочитай как минимум мою статью (переводы не обязательно), чтобы понять, о чём речь пойдёт дальше.
Теперь, предполагая, что ты понимаешь, что такое Ruby и EB, я скажу следующее.
Генерация obj-файлов, формирование командной строки и вызов линкера (LINK.EXE) для получения конечного EXE-файла — это чисто EB-шная вещь. Весь этот процесс закодирован в VBA6.DLL. При этом, хотя Microsoft-овский линкер умеет принимать на вход res-файлы наряду с obj-файлами (получив на вход res-файл, он с помощью CVTRES.EXE конвертирует .res в .obj и обходится с этим .obj так же, как с остальными obj-файлами на входе), в VB такой прямолинейный подход не используется. RES-файл, привязанный к VB-проекту, на вход линкеру никогда не попадает.
В процессе компиляции на каждый «модуль» (форма, класс, обычный модуль, юзерконтрол и т.п) генерируется свой obj-файл, по имени совпадающий с именем модуля, плюс генерируется дополнительный obj-файл, имя которого соответствует имени проекта. Именно в этом общем OBJ-файле находятся все ресурсы, именно таким путём ресурсы попадают в конечный EXE-файл.
И здесь наступает очень важный момент: EB понятия не имеет и знать ничего не хочет о ресурсах. EB не знает о том, что в Ruby есть редактор ресурсов, что там есть диалог свойств проекта, где можно задать данные для VERSIONINFO. EB ничего не знает об ограничениях на язык ресурсов, об ограничениях на размер и битность иконок.
EB самостоятельно не формирует ресурсы — и это главное.
Редактор ресурсов, возможность привязать res-файл к проекту, тот факт, что иконкой программы обязательно выступает иконка одной из форм (и нельзя задать произвольную иконку), диалог свойств проекта с полями для указания версии, компании разработчика, описания — всё это заморочки уровня
Ruby. Точнее, редактор ресурсов не относится вообще ни к EB, ни к Ruby, потому что это сторонний Add-in с точки зрения VB, но вот возможность присоединять внешний res-файл (без возможности редактирования) к проекту — это, как я выше и сказал, концепции уровня Ruby.
Так что за формирование ресурсов, за содаржание этих ресурсов ответственность несёт
Ruby, а не
EB. То есть, выражаясь твоим языком, всё это захардкожено в
VB6.EXE. EB лишь предоставляет внешнему хосту (которым выступает Ruby) возможность предоставить данные, которые EB любезно поместит сначала в obj, а потом и (не без участия линкера) в итоговый EXE.
Поэтому слово «захардкоженно» по отношению к формированию ресурсов, и попытка мыслить о ресурсах так, будто из генерация целиком запрограммирована в одном месте — это неправильный подход.
Таких места два: в одном (Ruby, VB6.EXE) месте решают, что положить в ресурсы, а в другом месте (EB, VBA6.DLL) определяются с тем, как и куда.
И поскольку взаимодействие между Ruby и EB идёт не напрямую, а через малочисленные фиксированные и более-менее доступные API (которыми выступают обычные экспортируемые/импортируемые функции и объектно-ориентированные интерфейсы), нам, как желающим вмешаться в этот процесс, не придётся преодолевать непреодолимое и совершать невозможное.
Процесс компиляции проекта в EXE работает примерно следующим образом.
В недрах Ruby есть огромная функция
ExeMake, которая делает кучу работы, и которая от начала до конца отвечает за генерацию исполняемого файла. В общем и целом, она обходит все сущности, собирает все данные и скармливает это всё EB.
С позиции взаимодействия Ruby и EB есть три ключевых точки, а именно три вызова из Ruby в EB:
- TipStartMakeExe
- TipMakeExe2
- TipFinishExe2
Это всё экспортируемые из VBA6.DLL функции (это к вопросу о лёгкости их перехвата).
Основная часть работы, которую выполняет Ruby при компиляции, находится между вызовами
TipMakeExe2 и
TipFinishExe2.
TipMakeExe2, помимо прочего, возвращает вызывающей стороне ссылку на объект, поддерживающий интерфейс
IExeFile. Вызывающей стороной является Ruby, Ruby получает ссылку на этот интерфейс и именно через него скармливает EB все ресурсы, которые должны попасть в итоговый EXE-файл.
И, наконец, происходит вызов
TipFinishExe2. Именно
TipFinishExe2 проходится по всем данным, которые хост скормил EB, собирает их в кучу, записывает в obj-файл, затем берёт все obj-файлы, вызывает линкер и собирает конечный EXE-файл.
Мораль в том, что: если нас каким-то образом не устраивает то, как формируются ресурсы, мы можем написать Add-in, который перехватив
TipMakeExe2 получит ссылку на объект, поддерживающий
IExeFile, а перехватив методы этого интерфейса, получит
полный контроль над тем, как формируются ресурсы, что в них попадает, а что не попадает.
И это довольно таки легко: перехват экспортируемой функции и перехват методов интерфейса делаются очень легко по сравнению с, например, перехватом неэкспортируемых функций где-то в недрах неведомой DLL или неведомого EXE.