J++ 到 J#:如何转换资源?

J++ to J#: how to convert resources?

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

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

J++中,在项目配置中指定资源文件名模式就足够了,所有与模式匹配的资源都会被嵌入到生成的*.exe (作为本机 Win32 资源)并且可以使用 Class.getResourceAsStream() 以编程方式访问,也可以使用任何 resource editor:

手动访问

问题

项目迁移到 Visual J# (VS 2005) 后,我立即失去了加载任何资源的能力(Class.getResourceAsStream() 开始 returning 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() 没有 return 任何 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 显然不是 public class 让我可以直接玩它。

尝试解决方法

  1. 将相对资源路径替换为绝对资源路径,将点替换为斜杠,反之亦然,使用或 w/o 前导斜杠,使用或 w/o 默认程序集命名空间 - 无效。
  2. 使用 javac 编译器将整个项目编译成可执行文件 *.jar,并将生成的 JAR 提供给 J# 二进制转换器工具 (jbimp.exe) -- 不是一个选项。 J# 二进制转换器工具 由于其局限性几乎没用(我尝试了两个版本——来自 VS 2003 和 VS 2005):

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

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

问题

为什么 Class.getResourceAsStream()vjslib.dll 实现没有按预期工作?我在这里错过了什么?

虽然 MicrosoftJava API 文档在 J#[ 中实现=39=] 运行时是模糊的(特别是 Class.getResourceAsStream() 的页面指出,与 J++ 不同,J#[=39= 不支持此方法]),一个解决方案。

进一步的研究表明,除了习俗 class loaders (which have been dropped), all of Java 1.1 and even some of Java 1.2 API has been implemented -- including collections and Swing

说到 资源 Visual Studio 2005 应用程序附带的 How to: Upgrade Visual J++ 6.0 Applications That Use Resources article. Java-style resources can be converted to .resx using the vjsresgen.exe 实用程序涵盖了这些内容示例,源代码可从 Microsoft.

获得

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