ドキュメントを単独で開けないようにする

VSTOを使用したOfficeアプリケーションを、より大きなアプリケーションの一部で使うようになった場合、生成されたOfficeドキュメントに直接触られると困ることがあります。
ここでは、Excelにアドインでパスワード認証をつけておき、上位アプリケーションからパスワードを指定して開く、ということを行います*1

名前を付けて保存と印刷を無効化する

Excelアドインプロジェクトを新規作成し、ThisAddIn.csのコードを開きます。
名前を付けて保存、及び、印刷機能を無効化するため、WorkbookのBeforeSaveとBeforePrintのイベントハンドラを実装します。

private void ThisWorkBook_BeforeSave(bool b, ref bool Cancel)
{
    if (b == true)
    {
        Cancel = true;
        MessageBox.Show("保存はキャンセルされました。");
    }
}
private void ThisWorkBook_BeforePrint(ref bool Cancel)
{
    Cancel = true;
    MessageBox.Show("印刷はキャンセルされました。");
}

BeforeSaveは、ファイル選択ダイアログが出るケース(引数bがtrueの場合)のみキャンセルし、上書き保存は通るようになっています。
これらのイベントハンドラは、ファイルオープン時に設定出来るように、Openイベントハンドラ内に実装します*2

private void ThisAddIn_Open(Excel.Workbook wb)
{
    this.Application.ActiveWorkbook.BeforePrint +=
        new Excel.WorkbookEvents_BeforePrintEventHandler(
            ThisWorkBook_BeforePrint);
    this.Application.ActiveWorkbook.BeforeSave +=
        new Excel.WorkbookEvents_BeforeSaveEventHandler(
            ThisWorkBook_BeforeSave);
    MessageBox.Show("名前を付けて保存、印刷、の機能を無効化しました。");
}

最後に、Openイベントハンドラを登録します。

private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
    this.Application.WorkbookOpen
        += new Excel.AppEvents_WorkbookOpenEventHandler(ThisAddIn_Open);
}

これは、Startupイベントハンドラ中で行います。

パスワードを設定する

Excelブックにパスワードを設定するため、上書き保存時に処理を追加します。上書き保存は、BeforeSaveイベントハンドラの第一引数がfalseの場合に相当するので、以下のように実装します。

private void ThisWorkBook_BeforeSave(bool b, ref bool Cancel)
{
    if (b == true)
    {
        Cancel = true;
        MessageBox.Show("保存はキャンセルされました。");
    }
    else
    {
        this.Application.ActiveWorkbook.Password = "hogehoge";
        MessageBox.Show("ドキュメントにパスワードを設定しました。");
    }
}

これで、既存のExcelファイルを開いて上書き保存すると、常にパスワードが付加されるようになります。
パスワード付きドキュメントを開くと、次のようなダイアログが表示され、パスワードを入力する旨を知らせます。

アプリケーションからExcelファイルを開く

新規にWindowsフォームプロジェクトを作成し、フォームにボタンを配置します。
ソリューションエクスプローラの[参照設定]を右クリックし、[参照の追加]を選択します。

この画面から、以下を全て選択し、OKを押します。

さらに、Form1.csのusing宣言に以下を追加します。

using Excel = Microsoft.Office.Interop.Excel;
using Office = Microsoft.Office.Core;

フォームデザイナ上のボタンをダブルクリックして、イベントハンドラを生成します。イベントハンドラ内では、ファイル選択ダイアログを表示し、選択されたファイルをExcelで開く処理を実装します。この時、パスワード認証を回避するためにExcelワークブックのOpenメソッドでパスワードを指定します。
コードを以下に示します。

private void button1_Click(object sender, EventArgs e)
{
    OpenFileDialog dialog = new OpenFileDialog();
    if (dialog.ShowDialog() == DialogResult.OK)
    {
        Excel.Application app = new Excel.Application();
        try
        {
            this.Visible = false;
            app.Visible = true;
            Excel.Workbook wb = app.Workbooks.Open(
                dialog.FileName, Type.Missing, Type.Missing,
                Type.Missing, "hogehoge", Type.Missing,
                Type.Missing, Type.Missing, Type.Missing,
                Type.Missing, Type.Missing, Type.Missing,
                Type.Missing, Type.Missing, Type.Missing);
            while (app.Visible) ;
            this.Visible = true;
        }
        catch
        {
            app.Workbooks.Close();
        }
        finally
        {
            System.Runtime.InteropServices.Marshal.ReleaseComObject(app);
            GC.Collect();
        }
    }
}

これにより、このアプリケーションを用いれば、同じパスワードのついた文書を開くことができるようになります。
なお、この例においても、登録されたCOMアドインを削除しておく必要があります。

*1:アプリケーションレベルで行った場合、全てのExcelブックに適用されてしまうため、本来なら、ドキュメントレベルで行うべき処理だと思います。

*2:Startupイベントハンドラ内ではうまく設定できなかったため、ファイルオープン時まで遅らせて対処しました。