4

我有一个想要迁移到J#的Visual J++项目。该代码不使用任何 Microsoft 特定的 API(如WFC)或非标准语言扩展,因此从技术上讲,它完全符合 Java 1.1。

唯一的问题是资源(在 Java 世界中通常使用Class.getResourceAsStream()API 访问)。

J++中,在项目配置中指定资源文件名模式就足够了,与模式匹配的所有资源都将嵌入到生成的 *.exe 中(作为本机 Win32 资源),并且可以通过编程方式使用Class.getResourceAsStream()和手动使用任何资源进行访问编辑

在此处输入图像描述

问题

一旦项目迁移到Visual J#(VS 2005),我立即失去了加载任何资源(Class.getResourceAsStream()开始返回null值)的能力,尽管每个感兴趣的资源的“构建操作”设置都设置为“嵌入式资源”:

在此处输入图像描述

并且资源实际上嵌入到程序集中(可以通过增加的 *.exe 文件大小来确认;此外,我确实使用dotPeek工具看到了这些资源)。使用以下模式生成唯一资源名称:

<assembly's default namespace>.<Java package>.<file name with extension>

因此,如果我在包下有一个名为README.txtnested的文件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

- 但我相信这只是.NET Framework 2.0 版本中修复的一个错误。

com.ms.vjsharp.lang.VJSClassLoader显然不是我可以直接玩的公共课程。

尝试的变通方法

  1. 用绝对路径替换相对资源路径,用斜线替换点,反之亦然,带或不带前导斜线,带或不带默认程序集命名空间 - 无效。
  2. 使用编译器将整个项目编译成可执行的 *.jarjavac并将生成的 JAR 提供给J# Binary Converter Tool ( jbimp.exe) - 这不是一个选项。J# Binary Converter Tool由于其局限性而几乎没用(我尝试了两个版本——来自 VS 2003 和 VS 2005):

    • 尽管字节码到 MSIL 的转换成功,但对 Java 字节码的单个调用会Class.getResourceAsStream(...)导致在运行时抛出。System.InvalidProgramException
    • 每当有一个 try-finally 块(这通常是在Java中完成流 I/O 的方式)时,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. 来自 VS 2003/2005 的J++ 项目迁移向导没有帮助:它只是忽略任何未从*.rc/*.res文件引用的资源。

  4. 手动创建一个*.resx文件,向其中添加所有资源并完全摆脱Class.getResourceAsStream()调用(更改 Java 代码以将资源加载为System.String(对于文本)和System.Drawing.Bitmap(对于图像))。这是唯一可行的方法,但是如果您*.gif的项目中有几十个小文件,它就会变得非常乏味。

问题

为什么没有vjslib.dllClass.getResourceAsStream()预期工作?我在这里想念什么?

4

1 回答 1

0

虽然Microsoft的J#运行时中实现的Java API的文档含糊不清(特别是,页面声明,与J++不同,此方法在J#中不受支持),但一个解决方案。Class.getResourceAsStream()

进一步的研究表明,除了自定义类加载器(已被删除)之外,所有Java 1.1甚至一些Java 1.2 API 都已实现——包括集合Swing

说到资源,如何:升级使用资源的 Visual J++ 6.0 应用程序一文涵盖了这些资源。Java风格的资源可以转换为.resx使用Visual Studio 2005vjsresgen.exe应用程序示例附带的实用程序,源代码可从Microsoft获得。

每个资源都被转换成一个字节数组。这是在Visual Studio中打开的示例vjsresgen.exe生成.resx文件的屏幕截图:

vjsresgen.exe 生成的 .resx 文件

于 2017-03-24T11:13:50.533 回答