我有一个Java 9应用程序,我正在尝试为Windows应用商店打包。奇怪的是,当我直接运行exe-launcher时,它按预期工作,但是当我通过APPX包运行启动器时,我得到以下奇怪的错误:
Exception in thread "Swing-Shell" java.lang.InternalError: Could not
initialize COM: HRESULT=0x80010106
at java.desktop/sun.awt.shell.Win32ShellFolderManager2.initializeCom(Native Method)
at java.desktop/sun.awt.shell.Win32ShellFolderManager2$ComInvoker$1.run(Unknown Source at java.base/java.lang.Thread.run(Unknown Source)
HRESULT=0x80010106
的意思是RPC_E_CHANGED_MODE
,我猜这意味着COM已经以某种方式在MTA模式下初始化了。但为什么这只是Windows Bridge沙箱中的一个问题?由于某种原因,Windows桥以某种方式某种方式pre-initialize
COM吗?
我不确定这是Java 9问题,还是Desktop Bridge问题,或两者兼而有之。有没有人对如何确定问题的原因或解决方法有任何想法?
我做了一个最小的Sample Project来重现这个问题
应用程序在直接执行时有效,但在通过APPX启动程序执行时无效。为什么?
依赖于COM初始化的JDK部分(D3DPipeline,Sound和windows shellfolder访问)都遵循相同的模式:
CoInitialize
被称为CoUnitialize
这与MSDN为COM保存的文档一致,并且分析正确,错误表明COM子系统已初始化为MTA线程。
所以我修改了java启动器(jvm.dll)并将调试语句插入到os_windows.cpp中的一些本机方法中。我专注于线程方法。我发现的是:
create_main_thread
,create_os_thread
,pd_start_thread
都运行COM还没有初始化thread_native_entry
)已经在初始化COM的情况下运行我在_beginthreadex
中看得更多,事实上我终于在stackoverflow上找到了领先优势。这向我指出了threadex.c的源代码,它是Visual Studio 2013 Express安装的一部分。
在那里你发现,_beginthreadex
不会直接启动提供的线程函数,而是首先运行库初始化器(_threadstartex
)。该初始化程序的一部分内容为:
_ptd->_initapartment = __crtIsPackagedApp();
if (_ptd->_initapartment)
{
_ptd->_initapartment = _initMTAoncurrentthread();
}
_callthreadstartex();
_crtIsPackagedApp
通过内核函数检测应用程序是否作为“PackagedApp”(即AppX包)运行,如果是,则调用RoInitialize
函数,我的理解就像CoInitialize的大哥一样。
简而言之:如果您的应用程序是使用Visual Studio 2013构建并作为打包应用程序运行的,那么您将获得破碎的环境。
经证实,Oracle JDK的工作版本是使用VS2010 SP1构建的,破解版本是使用VS2013SP4构建的。
有了上述信息,谷歌终于找到了一个参考,支持分析:
https://blogs.msdn.microsoft.com/vcblog/2016/07/07/using-visual-c-runtime-in-centennial-project/
从那篇文章引用:
请注意,在Windows 8时间范围内创建的现有VC ++ 12.0库具有运行时检查,以确定应用程序是否在应用程序容器下运行。将桌面应用程序作为打包应用程序运行时,这些检查可能会限制桌面应用程序的功能或导致其行为类似于UWA(通用Windows应用程序)(有限的文件系统访问或创建初始化MTA的线程等)。我们已在这些框架包中包含的VC ++库中修复了此行为,从而从桌面应用程序中删除了现代应用程序限制。
所以我看到了修复应用程序的选项,它们将作为AppX包分发:
msvcr120.dll
(我也假设也是Java 10)我会选择第二个版本,我测试了这个。从一个干净的最新Windows 10系统开始,我安装了JDK 9.0.4,我克隆了提供的测试用例,使用本地安装的JRE(而不是JDK!)修改它并构建appx包。运行这个,我重现了这个问题。然后我将系统安装的JRE文件夹中的msvcr120.dll
替换为APPX容器中包含的https://www.microsoft.com/en-us/download/details.aspx?id=53176:
qazxswpoi
提示:* .appx只是带有其他签名的ZIP文件,因此您只需重命名它们并提取内容即可。
我重建了测试用例,它正常工作(不再有COM初始化错误)。