トップ回答者
Excel2007で、ブックの保護を行ったxlsxをVBAで開こうとするとエラーが発生する

質問
-
Excel2010をインストールしたマシンで、
タイプライブラリを利用して、暗号化がかかっているxlsファイルを
チェックするモジュールを作っています。下記のようなコードを使用し、暗号化され、パスワード問い合わせのダイアログが表示されるファイルであれば、
Openでエラーを発生させて、処理から弾いています。ですが、Excel2007でブックの保護のみを行ったxlsxファイルを処理すると、
Workbooks.Openの際に、暗号化されたファイル同様、
「入力したパスワードが間違っています。CapsLockキーの状態に注意して、大文字と小文字が正しく使われていることを確認してください。」
とエラーが発生します。
エラーになるファイルは、Excel上で開いてもパスワード問い合わせはされず、
また、同様の操作であっても、Excel2010で作成したxlsxファイルであれば、エラーになりません。暗号化されたものと、ブック保護されたものを判別する方法はないでしょうか。
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Office.Interop.Excel;
using System.Windows.Forms;
using System.IO;static public bool CheckExcel(string strPrintFile)
{
Microsoft.Office.Interop.Excel.Application oXL = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel._Workbook objExcelXls = null;
Microsoft.Office.Interop.Excel.Workbooks objBooks = oXL.Workbooks;
Microsoft.Office.Interop.Excel._Worksheet objSheetXls;
Microsoft.Office.Interop.Excel._Chart objChartXls;try
{
oXL.AutomationSecurity = Microsoft.Office.Core.MsoAutomationSecurity.msoAutomationSecurityForceDisable;objExcelXls = oXL.Workbooks.Open(
strPrintFile,
0, Type.Missing, Type.Missing, "password", "password", true,
Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);catch (Exception ex)
{
string strErrMsg = ex.Message;
return false;
}
finally
{
if (objExcelXls != null)
{
objExcelXls.Close(false, Type.Missing, Type.Missing);
}
objExcelXls = null;
oXL.Quit();
oXL = null;
}
回答
-
Excel 2007とExcel 2010で
- 何もしない
- パスワード無しでブックを保護
- パスワード有りでブックを保護
- 暗号化(パスワードは必ず必要)
を実行したファイルをメモ帳で開いてみたところ、
- どちらも暗号化なし
- どちらも暗号化なし
- Excel 2007は暗号化される。Excel 2010は暗号化なし
- どちらも暗号化される
という結果でした。
そして、ファイルの中身が暗号化されている場合
- Password引数に文字列(空であっても)を指定 → 一致しなければエラー
- Password引数を省略 or Type.Missingを指定 → 上記3の場合には開ける、上記4の場合にはパスワード入力ダイアログ表示
となってました。
したがって、Passwordに文字列を入れてしまうと判別不能になるので、
Password指定せずにパスワード入力ダイアログの有無で判断するしかないような気がします。
たとえば、こんな感じで。(Excelのプロセスが大量に残る恐れあり)
class OfficePasswordChecker { private Excel.Application _app; private int _waitTimeAfterCallOpenMethod = 1000; private int _waitTimeAfterSendEnterKey = 1000; public OfficePasswordChecker(string path) { _app = new Excel.Application(); ( new Thread( new ThreadStart( delegate { try { _app.Workbooks.Open(Filename: path); } catch { } // パスワード入力後に例外が発生するのでとりあえず握りつぶしておく } ) ) ).Start(); Thread.Sleep(_waitTimeAfterCallOpenMethod); // パスワード入力の要不要にかかわらずここまでくるため、 // この時点での判断は無理 } public bool GetResult() { try { _app.Quit(); // パスワード入力ダイアログが開かれている場合はQuitでエラーが発生 // ->エラーがあった場合には、パスワードが必要であったと仮定する // ※実際には他の影響によりエラーが出る場合もありうるが、それは無視する return true; } catch { // このまま終了するとExcelが起動したままになるため、 // パスワード入力ダイアログに、パスワード入力無しでOKを押す操作を行う SendKeys.SendWait("{ENTER}"); Thread.Sleep(_waitTimeAfterSendEnterKey); _app.Quit(); return false; } } }
- 回答としてマーク sviurr 2011年2月9日 4:23
すべての返信
-
Excel 2007とExcel 2010で
- 何もしない
- パスワード無しでブックを保護
- パスワード有りでブックを保護
- 暗号化(パスワードは必ず必要)
を実行したファイルをメモ帳で開いてみたところ、
- どちらも暗号化なし
- どちらも暗号化なし
- Excel 2007は暗号化される。Excel 2010は暗号化なし
- どちらも暗号化される
という結果でした。
そして、ファイルの中身が暗号化されている場合
- Password引数に文字列(空であっても)を指定 → 一致しなければエラー
- Password引数を省略 or Type.Missingを指定 → 上記3の場合には開ける、上記4の場合にはパスワード入力ダイアログ表示
となってました。
したがって、Passwordに文字列を入れてしまうと判別不能になるので、
Password指定せずにパスワード入力ダイアログの有無で判断するしかないような気がします。
たとえば、こんな感じで。(Excelのプロセスが大量に残る恐れあり)
class OfficePasswordChecker { private Excel.Application _app; private int _waitTimeAfterCallOpenMethod = 1000; private int _waitTimeAfterSendEnterKey = 1000; public OfficePasswordChecker(string path) { _app = new Excel.Application(); ( new Thread( new ThreadStart( delegate { try { _app.Workbooks.Open(Filename: path); } catch { } // パスワード入力後に例外が発生するのでとりあえず握りつぶしておく } ) ) ).Start(); Thread.Sleep(_waitTimeAfterCallOpenMethod); // パスワード入力の要不要にかかわらずここまでくるため、 // この時点での判断は無理 } public bool GetResult() { try { _app.Quit(); // パスワード入力ダイアログが開かれている場合はQuitでエラーが発生 // ->エラーがあった場合には、パスワードが必要であったと仮定する // ※実際には他の影響によりエラーが出る場合もありうるが、それは無視する return true; } catch { // このまま終了するとExcelが起動したままになるため、 // パスワード入力ダイアログに、パスワード入力無しでOKを押す操作を行う SendKeys.SendWait("{ENTER}"); Thread.Sleep(_waitTimeAfterSendEnterKey); _app.Quit(); return false; } } }
- 回答としてマーク sviurr 2011年2月9日 4:23