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:

dotPeek

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 по-видимому, это не публичный класс, чтобы я мог играть с ним напрямую.

Попытки обойти

  1. Замените относительный путь ресурса на абсолютный, точки с косой чертой и наоборот, с или без начального слеша или с предварительно добавленным пространством имен сборки по умолчанию - безрезультатно.
  2. Скомпилируйте весь проект в исполняемый файл *.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'
      
  3. Мастер миграции проектов J ++ из VS 2003/2005 не помогает: он просто игнорирует любые ресурсы, на которые нет ссылок из *.rc/*.res файл.

  4. Вручную создать *.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:

vjsresgen.exe -генерированный.resx файл

Другие вопросы по тегам