Vista 以降で CFileDialog において SetTemplate が使えない場合の代替方法


Mimura です。
先ほど、STEP_M 1.053 をリリースしました。

 

今回のネックは CFileDialog において Vista 以降の新しいファイルダイアログでは、
SetTemplate が使用できないことでした。

 

そこで、私もこの情報を見つけるまでにかなり時間がかかりましたので、
メモとして、また同じ悩みを抱えている人に有用な物となればいいかなと思います。

 

(あらかじめ断っておきますと、あんまりMFC を使いたくない人です。私。)

 

 

SetTemplate を使用する場合、大体が以下のようなコードとなっていると思います。

CMyFileDialog::CMyFileDialog(BOOL bOpenFileDialog, LPCTSTR lpszDefExt, LPCTSTR lpszFileName,
        DWORD dwFlags, LPCTSTR lpszFilter, CWnd* pParentWnd) :
        CFileDialog(bOpenFileDialog, lpszDefExt, lpszFileName, dwFlags, lpszFilter, pParentWnd)
{
    SetTemplate(0, IDD_CUSTOM_FILE_OPEN);
}

(STEP_M ソースコード MyFileDialog.cpp より)

XP,2000 ではこのコードで通りますが、

Vista, 7 では「サポートされていない機能を実行しようとしました。」
というエラーダイアログが表示されてしまいます。

 

 

そこで考えたくなるのが、Vista 以降のOSで SetTemplate を使う方法ですが、
現時点ではあきらめた方がいいと思います。

 

Visual C++ Team Blog  Vista-style File Dialogs with MFC
Microsoft 社の Visual C++ Team のブログでも、

the new Vista dialogs no longer supports hwnd template customization, your CFileDialog object will throw CNotSupportedException if SetTemplate is called on it. 

適当訳:[英語苦手なので、あまりにも訳が違っていたら指摘お願いします]
Vista の新しいダイアログは、テンプレートによるカスタマイズには対応しません。SetTemplate を CFileDialog で呼び出したら、CNotSupportedException をスローするよー。

というようなことが書かれています。

 

 

それではどうするかですが、
Vista 以降のダイアログにはそれの為の弄る方法が用意されています。

 

CMyFileDialog::CMyFileDialog(BOOL bOpenFileDialog, LPCTSTR lpszDefExt, LPCTSTR lpszFileName,
        DWORD dwFlags, LPCTSTR lpszFilter, CWnd* pParentWnd) :
        CFileDialog(bOpenFileDialog, lpszDefExt, lpszFileName, dwFlags, lpszFilter, pParentWnd)
{

    IFileDialogCustomize* custom;
    custom = this->GetIFileDialogCustomize();
    if(custom != NULL){
            // チェックボックスを追加する場合は以下のように。
            custom->AddCheckButton(IDC_CH_FILE_ADDPEND,L"ボタンのついか。",false);
        }
        custom->Release();
    }
}

 

抜粋して書きますと上記のようになります。

this->GetIFileDialogCustomize();

で IFileDialogCustomize のインスタンスを取得し、
custom->Add****

によって、ボタンやエディットボックス、ラベルやらを追加していきます。

なお、IFileDialogCustomize 系は、WINVER が 0x0600 以上でないと利用できません。
StdAfx.h 等で設定している方はご注意下さい。

 

設置した内容を取得する場合、上記の例のサンプルで行きますと、

 

IFileDialogCustomize* custom;
custom = this->GetIFileDialogCustomize();
custom->GetCheckButtonState(IDC_CH_FILE_ADDPEND,&checkstate);
custom->Release();

 

上記にありますように、
custom->Get****

によって、値を取得します。

 

どのような命令があるか、また、オブジェクトが使えるかということにつきましては、

IFileDialogCustomize Interface (Windows)
上記リンクを参照して下さい。

 

最後に、XP,2000 上でも、Vista 以降のWindows でも、両方で動くようにするソースですが、

CMyFileDialog::CMyFileDialog(BOOL bOpenFileDialog, LPCTSTR lpszDefExt, LPCTSTR lpszFileName,
        DWORD dwFlags, LPCTSTR lpszFilter, CWnd* pParentWnd) :
        CFileDialog(bOpenFileDialog, lpszDefExt, lpszFileName, dwFlags, lpszFilter, pParentWnd)
{
    IFileDialogCustomize* custom;
    custom = NULL;
    TRY {
        // Legacy OS [ – Windows XP]
        SetTemplate(0,IDC_CH_FILE_ADDPEND);
    } CATCH (CNotSupportedException,e){
        // New OS [ Windows Vista – ]
        custom = this->GetIFileDialogCustomize();
        if(custom != NULL){
            custom->AddCheckButton(IDC_CH_FILE_ADDPEND,L"ちぇっく。",false);
        }
        custom->Release();
    }
    END_CATCH
}

(STEP_M ソースコード MyFileDialog.cpp より)

というような、上記のコードはいかがでしょうか。
MFC 上では try – catch 構文は使えないらしく、TRY – CATCH – END_CATCH を使うようです。

そこで、まずは SetTemplate を動かし、
非対応エラー(CNotSupportedException) が発生してしまったら、
Vista 以降の IFileDialogCustomize を用いたカスタマイズを行う。という形です。

 

 

開発のご参考になりましたら幸いです。


 

関連記事