2016年8月2日、マイクロソフトからWindows 10の2回目の大型アップデート「Windows 10 アニバーサリーアップデート(Anniversary Update)」が提供されました。
このアップデートを適用後、プログラムからExcel出力するアプリケーションで、エラーが発生するようになりました。
エラーメッセージはこんな感じです。
System.Runtime.InteropServices.COMException: サーバーによって例外が返されました。 (HRESULT からの例外:0x80010105 (RPC_E_SERVERFAULT))
目次
Windows 10 Anniversary Update(バージョン1607、ビルド14393)とは?
Windows 10 Anniversary Updateは、バージョン1607、ビルド14393です。
Windows 10 Anniversary Updateでは、多くのセキュリティ修正の他、「Windows Ink」などの新機能や、OSのアクティベーション関連も改善されています。
ちなみに、開発コードは「Red Stone1」ということで「Windows 10 RS1」とも言われています。
特別理由がない限り、アップデートは当てた方がよいでしょう。
Windows Anniversary Update (1607) & ComException
Windows Anniversary Update適用後、COMを使ってExcelで出力するアプリケーションが正常に動作しなくなりました。
System.Runtime.InteropServices.COMException: サーバーによって例外が返されました。 (HRESULT からの例外:0x80010105 (RPC_E_SERVERFAULT))
場所 System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)
場所 System.Dynamic.ComRuntimeHelpers.CheckThrowException(Int32 hresult, ExcepInfo& excepInfo, UInt32 argErr, String message)
困った。
どうしよう?
「Windowsで通常使うプリンターを管理する」をオフにする
いろいろと解決策を調べてみると、同様の現象を発見しました。
どうやら、アニバーサリーアップデートを適用すると、Windows10で「通常使うプリンター」が勝手に変わるようです。
Windows 10 Anniversary Update (バージョン 1607 ビルド 14393)を適用後、それまで動いていたVB .NETで作られたアプリケーションの動作が不安定になる現象が発生しています。
今までに確認した発生タイミングは「VB .NETからExcelを使用するとき」で、ワークブックを開くときであったり、ワークブックを保存するときであったり、PDF書き出しをするときであったりとまちまちです。
この問題がWindowsまたはOffice製品としての仕様なのかが明確になるまで弊社製品での適切な対処ができません。
マイクロソフトから新たな情報が報告されるまで皆様には大変ご不便をお掛けしますが暫くお待ちください。
確かにこの通りです。
私のプログラムの場合も、これらを参考に以下の方法でエラーを回避できました。
1.デスクトップ左下にある「Windows」マークをクリックして、
[設定]ボタンをクリック
2.画面内に表示される[デバイス]メニューをクリック
3.「Windowsの通常使うプリンタを管理する」設定を「オフ」にする
ほとんど、論理的な解決策ではないですが、確かに「Windowsで通常使うプリンターを管理する」をオフにすると、この問題は回避されます。
プログラム的な修正方法
この問題をプログラム的に修正する案は2つあります。
案1の方がおすすめです。
案1. レジストリの変更
プログラムでレジストリを変更して、Excel出力の前で「Windowsで通常使うプリンターを管理する」をオフしてみます。
レジストリは以下の通りです。
Windows で通常使うプリンターを管理する | |
---|---|
キー | HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows |
値の名前 | LegacyDefaultPrinterMode |
型 | REG_DWORD |
値の内容 | 0 → 有効【既定】 1 → 無効 |
プログラムのサンプルは次の通りです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
String registryKeyName = @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\"; String registryValueName = "LegacyDefaultPrinterMode"; int iGetValue = -1; using (RegistryKey registryKey = Registry.CurrentUser.OpenSubKey(registryKeyName, true)) { // レジストリの値を取得 // iGetValueが0なら「Windowsで通常使うプリンターを管理する」が有効 // iGetValueが1なら「Windowsで通常使うプリンターを管理する」が無効 try { iGetValue = (int)registryKey.GetValue(registryValueName); } catch { //値が存在しない場合 } // 「Windowsで通常使うプリンターを管理する」が有効な場合、Excel作成中はいったん無効にする if (iGetValue == 0) { registryKey.SetValue(registryValueName, 1, RegistryValueKind.DWord); } //ここにExcel出力のプログラムを入れる // 「Windowsで通常使うプリンターを管理する」が元々有効だった場合、元に戻す if (iGetValue == 0) { registryKey.SetValue(registryValueName, 0, RegistryValueKind.DWord); } } |
案2. スリープを入れてみる
Excelオブジェクトをオープンしたりクローズしたりする際に多少、タイミングを遅らせると問題なくExcel出力が出来ることがありました。
以下のように、Excelを操作する際に、Thread.Sleepを入れてタイミングを待つのですが、あまり論理的でないので入れたくないなぁ。
System.Threading.Thread.Sleep(1000);
最後まで読んでいただきありがとうござました。
この記事が気に入っていただけたらシェアしてくれると嬉しいです。
コメント
[…] Windows Anniversary Update (1607) 適用後、Excel出力プログラムでComExceptionが発生 201… […]