我构建了一个使用 Adobe ActiveX 控件来显示 PDF 的 C# .NET 应用程序。
它依赖于应用程序随附的几个 DLL。 这些 DLL 与本地安装的 Adobe Acrobat 或机器上安装的 Adobe Acrobat Reader 交互。
这个应用程序已经被一些客户使用并且对几乎所有用户都很好用(我检查本地机器是否已经运行至少第 9 版的 Acrobat 或 Reader)。
我发现了 3 种情况,应用程序在尝试加载时(正在加载 activex 控件时)返回错误消息“Error HRESULT E_FAIL has been returned from a call to a COM component”。
我检查了其中一个用户的机器,他安装了 Acrobat 9 并且经常使用它,没有任何问题。似乎 Acrobat 7 和 8 是同时安装的,因为注册表中有它们的条目以及 Acrobat 9。
我无法在本地重现这个问题,所以我不确定到底该往哪个方向走。
堆栈跟踪顶部的错误是:System.Runtime.InteropServices.COMException (0x80004005):调用 COM 组件返回错误 HRESULT E_FAIL。
对此错误的一些研究表明这是一个注册表问题。
有没有人知道如何解决或解决这个问题,或者确定如何找到问题的核心根源?
错误信息的完整内容是这样的:
System.Runtime.InteropServices.COMException (0x80004005): Error HRESULT E_FAIL has been returned from a call to a COM component. at System.Windows.Forms.UnsafeNativeMethods.CoCreateInstance(Guid& clsid, Object punkOuter, Int32 context, Guid& iid) at System.Windows.Forms.AxHost.CreateWithoutLicense(Guid clsid) at System.Windows.Forms.AxHost.CreateWithLicense(String license, Guid clsid) at System.Windows.Forms.AxHost.CreateInstanceCore(Guid clsid) at System.Windows.Forms.AxHost.CreateInstance() at System.Windows.Forms.AxHost.GetOcxCreate() at System.Windows.Forms.AxHost.TransitionUpTo(Int32 state) at System.Windows.Forms.AxHost.CreateHandle() at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible) at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible) at System.Windows.Forms.AxHost.EndInit() at AcrobatChecker.Viewer.InitializeComponent() at AcrobatChecker.Viewer..ctor() at AcrobatChecker.Form1.btnViewer_Click(Object sender, EventArgs e) at System.Windows.Forms.Control.OnClick(EventArgs e) at System.Windows.Forms.Button.OnClick(EventArgs e) at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent) at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks) at System.Windows.Forms.Control.WndProc(Message& m) at System.Windows.Forms.ButtonBase.WndProc(Message& m) at System.Windows.Forms.Button.WndProc(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m) at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
最佳答案
好的,报告回来回答我自己的问题。
问题与首选项 > Internet 中“在浏览器中显示 PDF”的设置直接相关。 选中此选项后,问题就消失了。取消选中时,它会返回。
以下是我们建议如何以编程方式处理它:
private string defaultPdfProg()
{ //Returns the default program for opening a .pdf file; On Fail returns empty string.
// (see notes below)
string retval = "";
RegistryKey pdfDefault = Registry.ClassesRoot.OpenSubKey(".pdf").OpenSubKey("OpenWithList");
string[] progs = pdfDefault.GetSubKeyNames();
if (progs.Length > 0)
{
retval = progs[1];
string[] pieces = retval.Split('.'); // Remove .exe
if (pieces.Length > 0)
{
retval = pieces[0];
}
}
return retval;
}
private void browserIntegration(string defaultPdfProgram)
{ //Test if browser integration is enabled for Adobe Acrobat (see notes below)
RegistryKey reader = null;
string[] vers = null;
if (defaultPdfProgram.ToLower() == "acrobat")
{ //Default program is Adobe Acrobat
reader = Registry.LocalMachine.OpenSubKey("Software").OpenSubKey("Adobe").OpenSubKey("Adobe Acrobat");
vers = reader.GetSubKeyNames();
}
else if (defaultPdfProgram.ToLower() == "acrord32")
{ //Default program is Adobe Acrobat Reader
reader = Registry.LocalMachine.OpenSubKey("Software").OpenSubKey("Adobe").OpenSubKey("Acrobat Reader");
vers = reader.GetSubKeyNames();
}
else
{
//TODO: Handle non - adobe .pdf default program
}
if (vers.Length > 0)
{
string versNum = vers[vers.Length - 1].ToString();
reader = reader.OpenSubKey(versNum);
reader = reader.OpenSubKey("AdobeViewer",true);
Boolean keyExists = false;
Double keyValue = -1;
foreach(string adobeViewerValue in reader.GetValueNames())
{
if (adobeViewerValue.Contains("BrowserIntegration"))
{
keyExists = true;
keyValue = Double.Parse(reader.GetValue("BrowserIntegration").ToString());
}
}
if (keyExists == false || keyValue < 1)
{
string message = "This application requires a setting in Adobe to be changed. Would you like to attempt to change this setting automatically?";
DialogResult createKey = MessageBox.Show(message, "Adobe Settings", MessageBoxButtons.OKCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);
if (createKey.ToString() == "OK")
{
reader.SetValue("BrowserIntegration", 1, RegistryValueKind.DWord);
//test to make sure registry value was set
}
if (createKey.ToString() == "Cancel")
{
//TODO: Provide instructions to manually change setting
}
}
}
}
需要注意的几点:
- 根据这两篇文章, key 可以位于注册表中的两个不同位置(Originals 与 AdobeViewer): http://support.adobe.com/devsup/devsup.nsf/docs/51722.htm http://support.adobe.com/devsup/devsup.nsf/docs/53556.htm
有谁知道这些位置是否在所有版本中都可以互换,或者注册表项是否基于 Acrobat 的特定版本位于不同位置? Reader 是否遵循与 Acrobat 相同的逻辑?
- 除了 Windows 文件关联之外,Adobe 是否使用任何其他方法来确定“用于打开 PDF 文件的默认 Adobe 应用程序”?我问是因为如果您有非 adobe 产品,例如 FoxIt 作为默认文件关联应用程序安装,但在同时安装了 Reader 和 Acrobat 的机器上使用 Adobe 的 ActiveX 控件,则使用什么逻辑来决定哪个应用程序COM 对象将与之对话?
关于c# - 如何以编程方式诊断原因、修复或解决与 Adobe ActiveX/COM 相关的错误 0x80004005?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2526301/