Visioの開くボタンとOnFileOpenの違いとは?Documents.OpenExで読み取り専用・ドック表示する方法

Visio文書を外部のC++/MFCアプリやVBA、C#から「読み取り専用で開きたい」「ステンシルはドック表示で開きたい」「非表示のまま裏で開きたい」――そう思って調べると、OnFileOpen や Documents.OpenEx など似たキーワードが多数出てきて混乱しがちです。この記事では、VisioのUIにある「開く」ボタンが内部で何を呼んでいるのか、そして実際にオプション付きで文書を開くための最短ルートを、C++(MFC)/VBA/C#のコード例付きで整理します。

目次

Visioの「開く」ボタンと OnFileOpen の関係

まずは、よく混同される2つの世界――「MFCアプリの世界」と「Visioアプリ(COMオブジェクト)の世界」をきちんと切り分けておきます。

コンテキストUIの「開く」ボタン実際に呼ばれるものポイント
MFCアプリケーションメニュー[ファイル] > [開く]やツールバーの「フォルダ」アイコンID_FILE_OPEN → CWinApp::OnFileOpen標準のファイルダイアログを出し、選ばれたファイルを開くハンドラー
Visio本体Visioの[ファイル] > [開く]ボタンVisioオブジェクトモデルの
Documents.Open / Documents.OpenEx
内部的にはこれらと同等の処理で文書を開いている

つまり、MFCアプリの「OnFileOpen」はあくまで自分のアプリ用のハンドラーであり、VisioをCOM経由で操作するときに使う関数ではありません。Visio文書を「オプション付きで開く」場合、狙うべきは Documents.OpenEx です。

MFC側での「開く」ボタンの正体

MFCアプリでは、メニューの[ファイル] > [開く]は通常以下のような流れになっています。

  • メニューやボタンから ID_FILE_OPEN コマンドが発行される
  • MFCフレームワークが CWinApp::OnFileOpen を呼び出す
  • OnFileOpen 内でファイルダイアログを表示し、選択されたパスを OpenDocumentFile に渡して文書を開く

ソースコードでは概ね以下のような形になります(実装はMFCの内部に隠れています)。


// フレームに "開く" に対応するコマンドを送る
AfxGetMainWnd()->SendMessage(WM_COMMAND, ID_FILE_OPEN);

// あるいはアプリクラスから直接呼ぶ
AfxGetApp()->OnFileOpen();

// 既知のパスを直接開きたいなら
AfxGetApp()->OpenDocumentFile(L"C:\\path\\file.vsdx");

ここで重要なのは、OnFileOpen 自体には「読み取り専用で」「非表示で」などのオプション引数は存在しないことです。凝った開き方をしたい場合は、OnFileOpen をオーバーライドして、内部でVisioの OpenEx を叩く構成にするのが現実的です。

Visio側での「開く」ボタンの正体

Visio本体のリボンやメニューにある[開く]は、ユーザーから見ると単に「ファイルを開く」ボタンですが、内部的にはほぼ次のような処理を行っていると考えてよいです。

  • ファイルダイアログでパスを取得
  • Application.Documents.Open() または OpenEx() で文書を開く

Visioのオブジェクトモデルでは、対象となるオブジェクトは Application.Documents コレクションであり、これに対して以下の2通りのメソッドが用意されています。

メソッドシグネチャ(簡略)用途
Documents.OpenOpen(path As String)オプションなしで標準的に開く
Documents.OpenExOpenEx(path As String, flags As VisOpenSaveArgs)読み取り専用やドック表示など、詳細オプションを指定して開く

Visioの「開く」と同じ処理をしつつ、さらに細かい制御(読み取り専用・ドック表示・非表示など)を行いたい場合は、Documents.OpenEx 一択と考えて問題ありません。

Documents.Open と OpenEx の違い

両者の差は非常にシンプルです。Open は「普通に開く」だけですが、OpenEx は第2引数で様々なフラグ(VisOpenSaveArgs)を指定できます。

項目Documents.OpenDocuments.OpenEx
読み取り専用で開く不可visOpenRO フラグを指定
ステンシルをドック表示する不可visOpenDocked フラグを指定
非表示で開く不可visOpenHidden フラグを指定
コピーとして開く不可visOpenCopy フラグを指定
複数フラグの組み合わせ不可visOpenRO Or visOpenDocked のように合成

したがって、「VisioのUIにある開くボタン“相当”をしつつ、さらにオプションも指定したい」ときには、OpenではなくOpenEx(path, flags) を使うのが最短ルートです。

VisOpenSaveArgs の代表的なフラグ

よく使うフラグだけを用途別に整理しておきます。

フラグ名想定する主な用途備考
visOpenRO文書を読み取り専用で開くレイアウトツールなど、ユーザーに保存させたくない場合に便利
visOpenDockedステンシル(*.vssxなど)をウィンドウ左側にドック表示通常の図面(*.vsdx)にはあまり意味がない
visOpenHiddenウィンドウを表示せずに開くバッチ処理やサーバーサイド自動処理で使う
visOpenCopy元ファイルを変更せず、コピーを開いて編集テンプレートファイルからの派生図面を作成するときなど
visOpenRW読み書き可能として開くことを明示明示したい場合に使用(通常は省略可)

これらのフラグは整数値として定義されているため、VB/VBAでは Or、C++/C# ではビットOR演算子 | を使って組み合わせます。


' VBA の例
flags = visOpenRO Or visOpenDocked

// C# の例
short flags = (short)(Visio.VisOpenSaveArgs.visOpenRO 
                   |  Visio.VisOpenSaveArgs.visOpenDocked);

Q2: OnFileOpen を「オプション付き」で呼ぶには?という疑問への答え

ここまで整理すると、Q2に対する答えは次のようになります。

  • OnFileOpen は MFC のメンバー関数であり、VisioのCOM APIとは別物。
  • OnFileOpen 自体にオプション引数は存在しない。
  • Visio文書をオプション付きで開きたい場合は、MFCアプリ側で OnFileOpen をオーバーライドし、内部から Visio.Documents.OpenEx(path, flags) を呼ぶのが現実的。

つまり、OnFileOpen を直接「オプション付きで呼び出す」のではなく、OnFileOpen の中で Visio の OpenEx を使うという構成になります。

実際の流れは以下のようなイメージです。

  1. ユーザーが自作MFCアプリの[開く]ボタンを押す
  2. OnFileOpen が呼ばれる
  3. ファイルダイアログでVisio文書(*.vsdx など)のパスを取得
  4. そのパスを使って Visio.Application の Documents.OpenEx(path, flags) を呼び出す

以下のサンプルコードでは、この「OnFileOpenの中でVisioをOpenExで開く」イメージを具体化します。

C++(MFC)から Visio を読み取り専用+ドック表示で開く

まずは、もっとも典型的なシナリオである「C++(MFC)アプリからVisioを起動し、文書を読み取り専用+ステンシルをドック表示で開く」例です。


#include <afxdisp.h>                         // AfxOleInit など
#import "Visio.exe" rename_namespace("Visio") // Visio の型ライブラリ(パスは環境に合わせて調整)

void OpenVisioAsRODocked(const wchar_t* path)
{
    // 1. COM/OLE 初期化(MFCアプリの InitInstance などで一度だけ呼ぶのがベスト)
    if (!AfxOleInit())
    {
        // TODO: エラー処理(メッセージボックスなど)
        return;
    }

    // 2. Visio.Application オブジェクトを起動
    Visio::ApplicationPtr app;
    HRESULT hr = app.CreateInstance(__uuidof(Visio::Application));
    if (FAILED(hr) || app == nullptr)
    {
        // TODO: Visio がインストールされていない、起動できない等のエラー処理
        return;
    }

    // 3. 必要なら Visio 自体を表示
    app->PutVisible(VARIANT_TRUE);

    // 4. フラグを組み合わせる(読み取り専用+ドック表示)
    short flags = Visio::VisOpenSaveArgs::visOpenRO
                | Visio::VisOpenSaveArgs::visOpenDocked;

    // 5. Documents コレクション経由で OpenEx を呼ぶ
    Visio::DocumentsPtr docs = app->Documents;
    Visio::DocumentPtr doc = docs->OpenEx(_bstr_t(path), flags);

    // 6. doc を保持しておけば、後続でページやシェイプにアクセスできる
}

ポイントを箇条書きで整理すると次の通りです。

  • AfxOleInit を忘れない(生のWin32アプリなら CoInitializeEx)。
  • 32bit Visio なら呼び出し側も 32bit、64bit Visio なら 64bit ビルドに揃える。
  • #import "Visio.exe" のパスは環境に応じて書き換える(Officeのインストール場所)。
  • OpenEx に渡すパスは、実運用ではフルパスを推奨(相対パスだとトラブルの原因になりやすい)。

MFCの OnFileOpen から呼び出す例

先ほどの関数を、MFCアプリの CWinApp::OnFileOpen から呼ぶイメージは次のようになります。


void CMyApp::OnFileOpen()
{
    // 1. ファイルダイアログを表示してユーザーに Visio ファイルを選ばせる
    CFileDialog dlg(TRUE, L"vsdx", nullptr,
                    OFN_FILEMUSTEXIST | OFN_HIDEREADONLY,
                    L"Visio 図面 (*.vsdx)|*.vsdx|すべてのファイル (*.*)|*.*||");

    if (dlg.DoModal() != IDOK)
    {
        return; // キャンセル
    }

    CString path = dlg.GetPathName();

    // 2. 選ばれたファイルを Visio で読み取り専用+ドック表示で開く
    OpenVisioAsRODocked(path);
}

このように、MFCの「開く」ハンドラーである OnFileOpen と、Visioの OpenEx を「橋渡し」する設計にしておくと、アプリ全体の見通しが良くなります。

VBA から Visio を読み取り専用+ドック表示で開く

Visio内部のマクロであれば、よりシンプルに Application.Documents.OpenEx を呼ぶだけで済みます。


Sub OpenRODocked()
    ' Visio を表示
    Application.Visible = True

    ' フラグを合成(読み取り専用+ドック表示)
    Dim flags As Integer
    flags = visOpenRO Or visOpenDocked

    ' OpenEx でオプション付きで開く
    Application.Documents.OpenEx "C:\Path\Diagram.vsdx", flags
End Sub

Visioのマクロとして手早く試すには、このVBA例がもっとも手軽です。「どのフラグを組み合わせるとどんな挙動になるか」を確認するためのサンドボックスとしても役立ちます。

C#(.NET Interop)から Visio 文書を開く

C# から Microsoft.Office.Interop.Visio を使って同じことを行う場合は、次のようなコードになります。


using Visio = Microsoft.Office.Interop.Visio;

class VisioSample
{
    public void OpenVisioDoc()
    {
        // 1. Visio.Application を起動
        var app = new Visio.Application();

        // 2. フラグを合成
        short flags = (short)(
            Visio.VisOpenSaveArgs.visOpenRO |
            Visio.VisOpenSaveArgs.visOpenDocked
        );

        // 3. Documents.OpenEx で開く
        Visio.Document doc = app.Documents.OpenEx(
            @"C:\Path\Diagram.vsdx",
            flags
        );

        // 4. 必要に応じてウィンドウやページを操作
    }
}

あらかじめ Visual Studio の「参照の追加」で Microsoft.Office.Interop.Visio を追加しておくことを忘れないようにしましょう。

MFC側で「ボタンを押したのと同じ動き」を起こす方法

自作MFCアプリ内だけで話を完結させたい場合、「UIの[開く]ボタンと同じ動作をコードから発火させる」こともできます。これはVisioではなく、あくまでMFCアプリ自身の話です。


// UI の「開く」相当を発生させる
AfxGetMainWnd()->SendMessage(WM_COMMAND, ID_FILE_OPEN);

// もしくは(アプリが OnFileOpen をオーバーライドしていれば)直接呼ぶ
AfxGetApp()->OnFileOpen();

// 既知のパスを直接開く(Doc/View 構造の場合)
AfxGetApp()->OpenDocumentFile(L"C:\\path\\file.vsdx");

ここで開く対象が Visio 文書であっても、MFCの観点では「単なるファイル」でしかありません。Visio側のオプション付き動作(読み取り専用・ドック表示など)を制御したいなら、最終的にはやはり Visio の OpenEx を叩く必要があることを忘れないようにしましょう。

よくあるハマりどころと対処法

Visio自動化+MFC/COM周りでつまずきやすいポイントを、原因と対処法付きで一覧にしておきます。

症状主な原因対処法
OpenEx で例外/アクセス違反が発生COM/OLE 初期化忘れ、または 32/64bit の不一致AfxOleInit / CoInitializeEx を起動時に実行し、ビルドのビット数を Visio と合わせる
OpenEx が「ファイルが見つからない」エラー相対パスの解決に失敗しているフルパスを渡す/ワークディレクトリを明示的に設定する
visOpenDocked を指定してもドックされない図面(*.vsdx)に対して指定しているvisOpenDocked は主にステンシル(*.vssx 等)に対して有効である点を理解する
OnFileOpen にオプションを渡したいOnFileOpen はパラメータ無しの設計アプリ側で OnFileOpen をオーバーライドし、内部で OpenEx を呼ぶように設計する
Visioが終了してくれないCOM参照が残っている/明示的に Quit していないapp.Quit() を呼び、スマートポインタや RCW をスコープから外す

シナリオ別の使い分け指針

最後に、「どの場面で何を使えばよいか」を一枚の表にまとめます。

やりたいことおすすめのAPI/方法備考
Visio内部でマクロからオプション付きで開きたいApplication.Documents.OpenEx(path, flags)VBAから簡単に試せる。フラグの動作確認にも最適。
外部C++/MFCアプリからVisio文書を読み取り専用で開きたいVisio.Application を COM で生成し、Documents.OpenExAfxOleInit を必ず実行し、ビルドのビット数をVisioと合わせる。
外部C#アプリからVisioを操作したいMicrosoft.Office.Interop.Visio の Application.Documents.OpenEx参照設定を追加し、VisOpenSaveArgs をビットORで組み合わせる。
自作MFCアプリの[開く]ボタンと同じ動きをさせたいAfxGetMainWnd()->SendMessage(WM_COMMAND, ID_FILE_OPEN)Visio操作とは無関係。自アプリのファイル開き動作を再現したいときに使用。
Visioをユーザーに見せずに裏で処理したいOpenEx(path, visOpenHidden) などサーバーサイド自動処理や帳票生成などで便利。エラーハンドリングは特に慎重に。

まとめ

内容をあらためて整理すると、次のようになります。

  • Q1(「開く」ボタンはどの関数?)
    MFCアプリでは、UIの[開く]は ID_FILE_OPEN → CWinApp::OnFileOpen に紐付きます。Visio本体の[開く]は、内部的には Documents.Open / Documents.OpenEx と同等の処理で文書を開いていると考えられます。
  • Q2(OnFileOpenをオプション付きで呼びたい)
    OnFileOpen 自体にオプション引数はありません。代わりに、アプリ側で OnFileOpen をオーバーライドし、その中で Visio の Documents.OpenEx(path, flags) を呼び出すことで、「読み取り専用」「コピーとして開く」「非表示で開く」などの挙動を柔軟にコントロールできます。

Visioの自動化は、「どの世界のAPIの話なのか(MFCなのか、Visioなのか)」を意識して切り分けるだけで一気に理解しやすくなります。OnFileOpen はMFCの世界、オプション付きで文書を開くのはVisioの Documents.OpenEx の仕事――この2つの役割を押さえておくだけで、実装時の迷いがかなり減るはずです。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次