From the following call
Marshal.GetActiveObject("Excel.Application")
I get a
Operation unavailable (Exception from HRESULT: 0x800401E3 (MK_E_UNAVAILABLE))
I believe that this error is caused when the user permissions between my application and excel do not match.
I want to know if there is a workaround as to how I can access the opened excel application regardless of how excel is opened, I can open the program that I want to access excell from as an administrator.
Also I would like to know how I can tell what permissions processes were opened with? I have been using ProcessExplorer to look at the UserProfile (which was the same in both applications), and Owner (which was also the same BUILTIN\Administrators)
Background
I have a program that run different tests by calling NUnit-console-x86. The application that is being tested opens up an excel form, this is the form that I want to read the data from. And when i run my program as administrator, or not I get these errors, I have also tried adding in Process.StartInfo.Verb = "runas"; to my program that starts up NUnit but I still get these errors
It appears installing visual studio fixes the problem although I do not want to have to install visual studio on every computer.
Can anyone explain any of this to me?
Looking at Microsoft Support Information, 0x800401e3 seems to be generated when excel (or office in general) isn't active or running in the Running Object Table. You have to have a copy of excel opened before you call this. Its either you haven't opened excel in code yet, or its not fully registered yet. Could this be the problem?
It's the problem of mismatching previleges between Visual Studio and Excel. Microsoft documents don't say that but it definitely is. The more serious problem is that the exception is sometimes thrown and sometimes not through old versions of Excel which don't know the administrative previliges i.e. version 2007.
When it happens you should match the previleges as administrator-administrator or none-none. Even Excel none-previlege and Visual Studio administrator may not work.
Add reference only of "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;
}
This worked for me.
Advantage: No need to copy Microsoft.Office.Interop.Excel.dll to your installed folder. Since MS excel is installed it will take from GAC.
I used Office.dll too but not sure if its really required.
To extend what @DylanCorriveau says, I've found that you'll need to take one the following methods to avoid this issue.
Method 1
I found that in some cases (Excel 2010) starting excel first resolves this issue. You'll need to adjust the path and wait to fit you needs and version.
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
Method 2
Another approach I've taken in the past is invoking Excel in a different way:
var oExcelApp = new Microsoft.Office.Interop.Excel.Application();
Method 3
Finally in my application (for both excel 2010 and 2016) I've used a bit of a workaround:
[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");
If you running this code in Excel 2016 in a RDP session it can be very picky, I've found that you need to customize RDP to ignore it's minimized state. I found this article quite helpful.
If your trying to invoke excel through some sort of automated build/release platform on a remote server (such as TFS/Azure DevOps), you need to play around with autologin. I haven't got that working yet myself.