【问题标题】:How to make Windows file associations work with non-ASCII file names?如何使 Windows 文件关联与非 ASCII 文件名一起使用?
【发布时间】:2012-11-09 17:53:49
【问题描述】:

我需要为某个文件类型注册文件关联 - 事实上,我只需要启动一个带有某些参数和该文件名称的某个 Java 程序。

我得到了以下几点:

// in fff-assoc.cmd file:
assoc .fff=SomeFile
ftype SomeFile=java -jar some.jar <arguments1> "%%1" <arguments2>

它适用于 ASCII 文件名。但是当我尝试双击名称中包含非 ASCII 符号的文件时,传递的参数看起来像“????” (每个 char 的 int 值 = 63)。

如何解决这些关联?

【问题讨论】:

    标签: java windows unicode batch-file file-association


    【解决方案1】:

    如果 bobince 所说的是准确的,并且您无法可靠地将数据直接传输到 java,则另一种解决方案是用另一种语言(例如 C、C++ 或 C#)编写一个小的“shim”程序。

    这个想法是程序将输入获取为 UNICODE,对其进行编码,以便仅使用 ASCII 字符(例如使用 base64,或者甚至像将每个字符编码为其数字等价物一样简单),然后组装命令行参数使用并使用 CreateProcess 启动 java 本身。

    您的 Java 代码可以“撤消”编码,重构 UNICODE 名称并继续使用它。这是一种迂回的方式,需要为您的软件添加一个额外的组件,但它应该可以解决上面详述的限制,如果这确实是一个实际限制的话。

    更新:这是 shim 程序的基本代码。它将输入编码为整数序列,用冒号分隔。它在错误检查方面没有多大作用,您可能希望稍微改进它,但它至少应该让您开始并朝着正确的方向前进。

    您应该使用 Visual Studio Express(如果您还没有 Visual Studio)并创建一个新的 Visual C++ 项目,选择“Win32”并选择“Win32 Project”。选择“Win32 应用程序”。创建项目后,将显示的 .cpp 文件中的所有内容替换为以下代码:

    #include "stdafx.h"
    #include <string>
    
    int APIENTRY _tWinMain(HINSTANCE, HINSTANCE, LPTSTR lpCmdLine, int)
    {
        std::string filename;
    
        while((lpCmdLine != NULL) && (*lpCmdLine != 0))
        {
            if(filename.length() != 0)
                filename.append(":");
    
            char buf[32];
    
            sprintf(buf, "%u", (unsigned int)(*lpCmdLine++));
    
            filename.append(buf);   
        }
    
        if(filename.length() == 0)
            return 0;
    
        PROCESS_INFORMATION pi;
        memset(&pi, 0, sizeof(PROCESS_INFORMATION));
    
        STARTUPINFOA si;
        memset(&si, 0, sizeof(STARTUPINFOA));
        si.cb = sizeof(STARTUPINFOA);
    
        char *buf = new char[filename.length() + 256]; // ensure that 256 is enough for your extra arguments!
    
        sprintf(buf, "java.exe -jar some.jar <arguments1> \"%s\" <arguments2>", filename.c_str());
    
        // CHECKME: You hard-coded the path for java.exe here. While that may work on your system
        // is it guaranteed that it will work on every system?
    
        if(CreateProcessA("C:\\Program Files\\Java\\jre7\\bin\\java.exe", buf, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
        {
            CloseHandle(pi.hThread);
            CloseHandle(pi.hProcess);
        }
    
        delete[] buf;
    
        return 0;
    }
    

    您应该能够相当容易地弄清楚如何编译等细节。

    【讨论】:

    • 是的,这可能行得通。你能举一个这样的程序的小例子吗——不是转换代码(我自己可能会弄清楚),而是打包细节——例如,我应该如何编译它,我应该把它打包成.exe(我既不精通 C 也不精通 Windows api)?
    • 我在 iPhone 上打字,所以我现在不能轻易地给你一个示例,但我会在明天发布一个小型“框架”应用程序。
    • 非常感谢这个例子!
    • 我下载了 VSE 2010,创建了项目,粘贴了代码和其他东西,但运行部分真的让我很困惑。如果我将配置更改为“发布”并按 F7(构建解决方案),我会在 Release 目录中获得 Program.exe。但是当我尝试运行它(从命令行,program.exe)时,我一无所获。即使我在 filename 声明之前包含 std::cout &lt;&lt; "Hello\n";
    • 啊,这不是控制台项目。
    【解决方案2】:

    我只需要使用某些参数和该文件的名称启动某个 Java 程序。

    不幸的是,由于 Java 用于接收参数输入(以及其他内容)的标准 C 库的 MS 实现,这种“公正”实际上是不可能的。除非您绕过标准 Java 或 C 接口直接使用本机 Win32 API,

    请参阅this question 了解背景信息。

    【讨论】:

    • 我理解正确吗 - 完全不可能将文件关联 + java(或 javaws)与非 ascii 文件名一起使用?我不坚持为此使用命令行,我会对任何其他解决方案完全满意。
    • 一般来说,它更多的是关于命令行参数,而不是具体的文件关联。但是,查看您的示例,我看到您正在使用 %1 - 通常它将在命令行上传递 DOS 样式的 8.3 文件名,这应该可以避免问题(而不是 %L,它可以为您提供完整的,长/Unicode 名称)。机器上是否禁用了 8.3 文件名?还是文件名以外的一些其他参数中的非 ASCII 字符?
    • 不,没有其他非 ASCII 参数。据我记得,如果我从 .bat 文件运行它,那么将传递 DOS 样式的名称 - 但切换到 .cmd 使其传递正确的名称。
    • 切换运行ftype 命令的方式有什么不同吗?这不应该发生 - 据我所知,两种格式都应该以相同的方式处理百分比。检查HKEY_CLASSES_ROOT\Somefile\Shell\Open\Command 下的注册表,看看通过.bat.cmd 调用ftype 有何不同(如果有)。
    • 有一件事让我很烦恼 - 例如,如果我启动的不是带有该参数的 java 程序,而是带有该参数的 iexplore.exe (IE 7),它会在地址中显示正确的名称吧,即使它是非ascii。所以可能有一些不明显的方式来启动一个带有适当参数的应用程序。
    【解决方案3】:

    从命令行调用java时,可以指定参数的编码(将用于在args[]中创建字符串):

    java -jar -Dsun.jnu.encoding=cp1252 yourFileName
    

    使用非 ASCII 字符时,指定的字符集对args[0] 的值有影响。不确定这是否适用于文件关联。

    注意:我不确定该参数还有什么其他用途 - this post 似乎没有。

    【讨论】:

    • 我不确定普通的 java 进程,但它不能通过 javaws+associations 工作,当然 - 它只是挂起进程。
    • 你没有提到javaws。您也可以在 jnlp 中传递参数(不确定是否允许未签名的 jar 使用该参数) - 例如:&lt;j2se version="1.7+" java-vm-args="-Dsun.jun.encodinf=cp1252"/&gt;
    • 我试着用javaws "-JDsun.jnu.encoding=cp1252" ...来做。
    • 我想应该是javaws -J-Dsun.jnu.encoding=cp1252
    • 是的,你是对的。但这并没有帮助 - 它仍然无法识别这些论点。
    猜你喜欢
    • 1970-01-01
    • 2023-03-28
    • 2016-10-11
    • 2018-04-12
    • 2014-09-06
    • 2020-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多