来自HRESULT的异常:0x800401E3(MK_E_UNAVAILABLE)解决方法

问题描述 投票:15回答:4

从以下电话

Marshal.GetActiveObject("Excel.Application")

我得到了

操作不可用(HRESULT异常:0x800401E3(MK_E_UNAVAILABLE))

我相信当我的应用程序和excel之间的用户权限不匹配时会导致此错误。

我想知道是否有关于如何访问打开的Excel应用程序的解决方法,无论excel如何打开,我都可以以管理员身份打开我想要访问的程序。

另外我想知道如何判断打开了哪些权限进程?我一直在使用ProcessExplorer来查看UserProfile(在两个应用程序中都是相同的)和Owner(也是相同的BUILTIN \ Administrators)

背景我有一个程序通过调用NUnit-console-x86来运行不同的测试。正在测试的应用程序打开了一个excel表单,这是我想要从中读取数据的表单。当我以管理员身份运行我的程序时,或者我没有得到这些错误,我也尝试添加Process.StartInfo.Verb =“runas”;到我启动NUnit的程序,但我仍然遇到这些错误

虽然我不想在每台计算机上安装visual studio,但看起来安装visual studio解决了这个问题。任何人都可以向我解释这些吗?

c# ms-office
4个回答
4
投票

看看Microsoft Support Information,当excel(或一般办公室)未激活或在运行对象表中运行时,似乎会生成0x800401e3。在打电话之前,您必须打开excel的副本。它要么你尚未在代码中打开excel,要么尚未完全注册。这可能是问题吗?


0
投票

这是Visual Studio和Excel之间不匹配的问题。微软文件没有说,但它肯定是。更严重的问题是有时会抛出异常,有时不会通过不知道管理优势的旧版本的Excel,即版本2007。

如果发生这种情况,您应该以administrator-administrator或none-none匹配权限。即使Excel无权限和Visual Studio管理员也可能无法正常工作。


0
投票

仅添加“Microsoft.Office.Interop.Excel.dll”的引用

try
{
    //This requires excel app (excel.exe*32) to be running means any excel sheet should be open. If excel not running then it will throw error.
    excelApp = (Excel.Application)Marshal.GetActiveObject("Excel.Application");
    excelApp.Visible = false;
}
catch
{
    //create new excel instance
    excelApp = new Excel.Application(); 
    excelApp.Visible = false;
}

这对我有用。

优点:无需将Microsoft.Office.Interop.Excel.dll复制到已安装的文件夹。由于安装了MS excel,因此需要从GAC获取。

我也使用了Office.dll,但不确定它是否真的需要。


0
投票

为了扩展@DylanCorriveau所说的内容,我发现你需要采取以下方法之一来避免这个问题。

方法1

我发现在某些情况下(Excel 2010)启动excel首先解决了这个问题。您需要调整路径并等待以满足您的需求和版本。

string pathToTheVersionOfExcel = @"C:\Program Files (x86)\Microsoft Office\Office14\EXCEL.EXE";
System.Diagnostics.Process.Start(pathToTheVersionOfExcel);
Thread.Sleep(5000); //"WaitForInputIdle" waits for way too long, generally it takes 5 seconds to start for me

方法2

我过去采用的另一种方法是以不同的方式调用Excel:

var oExcelApp = new Microsoft.Office.Interop.Excel.Application();

方法3

最后在我的应用程序中(对于excel 2010和2016)我使用了一些解决方法:

[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

//In your method...
string pathToTheVersionOfExcel = @"C:\Program Files (x86)\Microsoft Office\root\Office16\EXCEL.EXE";
Application oExcelApp = null;

Process process = new Process();
process.StartInfo.FileName = pathToTheVersionOfExcel;
process.Start();

Thread.Sleep(5000);

//Opening a closing notepad seems to "register" excel 2016, not needed for excel 2010 though...
Process processNotepad = new Process();
processNotepad.StartInfo.FileName = @"C:\Windows\system32\notepad.exe";
processNotepad.Start();

ShowWindow(process.MainWindowHandle, 2); //Minimize
ShowWindow(process.MainWindowHandle, 3); //Maximize

Thread.Sleep(5000);

processNotepad.CloseMainWindow();

oExcelApp = (_Application)Marshal.GetActiveObject("Excel.Application");

如果您在RDP会话中在Excel 2016中运行此代码它可能非常挑剔,我发现您需要自定义RDP以忽略它的最小化状态。我找到了this article quite helpful

如果您尝试通过远程服务器(例如TFS / Azure DevOps)上的某种自动构建/发布平台调用excel,则需要使用autologin。我自己没有那个working yet