J++ to J#: как конвертировать ресурсы?
У меня есть проект Visual J++, который я хочу перенести в J #. Код не использует какой-либо специфичный для Microsoft API (например, WFC) или нестандартные языковые расширения, поэтому технически он полностью совместим с Java 1.1.
Единственная проблема - ресурсы (к которым в мире Java обычно обращаются, используя Class.getResourceAsStream()
API).
ВJ ++ было достаточно указать шаблоны имен файлов ресурсов в конфигурации проекта, и все ресурсы, сопоставленные с шаблонами, были бы встроены в результирующий *.exe (как собственные ресурсы Win32) и доступны как программно, используя Class.getResourceAsStream()
и вручную используя любой редактор ресурсов:
Эта проблема
После того, как проект был перенесен вVisual J #(VS 2005), я сразу потерял способность загружать любые ресурсы (Class.getResourceAsStream()
начал возвращатьсяnull
значения), несмотря на то, что параметр "Build Action" был установлен на "Embedded Resource" для каждого интересующего ресурса:
и ресурсы фактически внедряются в сборку (это может быть подтверждено увеличенным размером файла *.exe; кроме того, я вижу эти ресурсы с помощью инструмента dotPeek). Уникальное имя ресурса генерируется с использованием следующего шаблона:
<assembly's default namespace>.<Java package>.<file name with extension>
так что если бы у меня был файл с именем README.txt
вложенный под com.example
пакета, полученное имя ресурса сборки будет default.com.example.README.txt
:
Visual Studio 2003 отличается от версии 2005: Class.getResourceAsStream()
не возвращает null
но ArgumentOutOfRangeException
брошен mscorlib.dll
во время выполнения:
mscorlib.dll!System.String.Substring(int startIndex = 0, int length = -1) + 0xbb bytes
vjslib.dll!com.ms.vjsharp.lang.VJSClassLoader.__findResource(System.Reflection.Assembly currentAssembly = {System.Reflection.Assembly}, string resName = "com/example/README.txt") + 0xc5 bytes
vjslib.dll!com.ms.vjsharp.lang.VJSClassLoader.__getResourcefromAssembly(System.Reflection.Assembly callingAssembly = {System.Reflection.Assembly}, string resName = "com.example.Main/+/com/example/README.txt") + 0x1b7 bytes
vjslib.dll!com.ms.vjsharp.lang.VJSClassLoader.getResourceAsStream(string resName = "com.example.Main/+/com/example/README.txt") + 0x57 bytes
vjslib.dll!java.lang.Class.getResourceAsStream(string resourceName = "com.example.Main/+/com/example/README.txt") + 0x10d bytes
test-resource-loading.exe!com.example.Main.main(String[] args = {Length=0}) Line 21 + 0x26 bytes
- но я считаю, что это всего лишь ошибка, исправленная в версии 2.0 .NET Framework.
com.ms.vjsharp.lang.VJSClassLoader
по-видимому, это не публичный класс, чтобы я мог играть с ним напрямую.
Попытки обойти
- Замените относительный путь ресурса на абсолютный, точки с косой чертой и наоборот, с или без начального слеша или с предварительно добавленным пространством имен сборки по умолчанию - безрезультатно.
Скомпилируйте весь проект в исполняемый файл *.jar, используя
javac
компилятор и передает полученный JAR в J # Binary Converter Tool (jbimp.exe
) - не вариант. J # Binary Converter Tool практически бесполезен из-за его ограничений (я пробовал обе версии - от VS 2003 и VS 2005):- один звонок
Class.getResourceAsStream(...)
в Java байт-код приводит кSystem.InvalidProgramException
генерируется во время выполнения, несмотря на успешное преобразование байт-кода в MSIL. всякий раз, когда есть блок try-finally (именно так обычно осуществляется потоковый ввод / вывод в Java),
jbimp.exe
терпит неудачу с этими сообщениями (я прекратил попытки переписать 5-строчный блок кода, который просто читал из файла):JbImp error: Internal Conversion Error : 'exc-unclosed-blocks' JbImp error: Failed to create type for class 'com/example/Main'. Creating stub type JbImp error: Internal Conversion Error : 'JbImp fatal error: Conversion failed'
- один звонок
Мастер миграции проектов J ++ из VS 2003/2005 не помогает: он просто игнорирует любые ресурсы, на которые нет ссылок из
*.rc
/*.res
файл.- Вручную создать
*.resx
файл, добавить все ресурсы к нему и избавиться отClass.getResourceAsStream()
звонки полностью (измените код Java для загрузки ресурсов какSystem.String
(для текста) иSystem.Drawing.Bitmap
(для изображений)). Это единственный рабочий подход, но если у вас есть десятки маленьких*.gif
файлы в вашем проекте, это становится действительно утомительным.
Вопрос
Почему не vjslib.dll
реализация Class.getResourceAsStream()
работать как положено? Что мне здесь не хватает?
1 ответ
Хотя документация Microsoft по Java API, реализованная во время выполнения J#, расплывчата (в частности, страница для Class.getResourceAsStream()
утверждает, что, в отличие от J ++, этот метод не поддерживается в J#), существует решение.
Дальнейшие исследования показывают, что, кроме пользовательских загрузчиков классов (которые были отброшены), была реализована вся Java 1.1 и даже некоторые из API Java 1.2 - включая коллекции и Swing.
Говоря о ресурсах, они описаны в статье Как: обновить приложения Visual J++ 6.0, использующие ресурсы. Ресурсы в стиле Java можно преобразовать в .resx
с использованием vjsresgen.exe
Утилита, которая поставляется с примерами приложений Visual Studio 2005, с исходным кодом, доступным от Microsoft.
Каждый ресурс преобразуется в байтовый массив. Вот скриншот образца vjsresgen.exe
-порожденной .resx
файл, открытый в Visual Studio: