web-dev-qa-db-ja.com

HRESULTからの例外:0x800401E3(MK_E_UNAVAILABLE)回避策

次の呼び出しから

Marshal.GetActiveObject("Excel.Application")

私は

操作を利用できません(HRESULTからの例外:0x800401E3(MK_E_UNAVAILABLE))

このエラーは、アプリケーションとExcelの間のユーザー権限が一致しない場合に発生すると思います。

Excelを開いた方法に関係なく、開いたExcelアプリケーションにアクセスする方法についての回避策があるかどうかを知りたいのですが、管理者としてExcelにアクセスしたいプログラムを開くことができます。

また、どのパーミッションプロセスで開かれたかを知る方法を知りたいですか?私はProcessExplorerを使用してUserProfile(両方のアプリケーションで同じ)とOwner(これも同じBUILTIN\Administrators)を調べてきました。

背景 NUnit-console-x86を呼び出してさまざまなテストを実行するプログラムがあります。テスト中のアプリケーションはExcelフォームを開きます。これは、データを読み取りたいフォームです。また、プログラムを管理者として実行した場合、またはこれらのエラーが発生しない場合は、Process.StartInfo.Verb = "runas";に追加しようとしました。 NUnitを起動する私のプログラムに、それでもこれらのエラーが発生します

Visual Studioをインストールすると問題が解決するようですが、すべてのコンピューターにVisualStudioをインストールする必要はありません。誰かが私にこれのいずれかを説明できますか?

16
user1227708

Microsoftサポート情報 を見ると、Excel(または一般的なオフィス)がアクティブでないか、実行中のオブジェクトテーブルで実行されていない場合に0x800401e3が生成されているようです。これを呼び出す前に、Excelのコピーを開く必要があります。まだコードでExcelを開いていないか、まだ完全に登録されていません。これが問題でしょうか?

5
Dylan Corriveau

これは、VisualStudioとExcelの間で特権が一致しないという問題です。マイクロソフトのドキュメントにはそのようには書かれていませんが、確かにそうです。より深刻な問題は、例外がスローされることもあれば、管理上の特権を知らない古いバージョンのExcel、つまりバージョン2007を介さないこともあります。

それが発生した場合は、管理者-管理者またはなし-なしとして特権を一致させる必要があります。 Excelnone-previlegeおよびVisualStudio管理者でさえ機能しない場合があります。

1
SHIN JaeGuk

「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を使用しましたが、本当に必要かどうかはわかりません。

1

@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");

このコードをExcel2016のRDPセッションで実行すると、非常に扱いにくい場合があります。最小化された状態を無視するようにRDPをカスタマイズする必要があることがわかりました。私は見つけました この記事は非常に役に立ちました

リモートサーバー上のある種の自動ビルド/リリースプラットフォーム(TFS/Azure DevOpsなど)を介してExcelを呼び出そうとする場合は、 autologin を試してみる必要があります。私はそれを持っていません まだ働いています 私自身。

0
David Rogers