CFileDialogの使い方

[戻る]
いろは 2003/12/02(火) 16:37:11
いつも勉強させて頂いています。

CFileDialogを用いて、ユーザーにファイル名を入力してもらっています。
今まで気づかなかったのですが、ユーザーが使用していて不思議な現象が出ました。

開発環境
 Windows2000Sp4 + VC6Sp5(MFC使用)

現象
 例えば、C:\tempにAAA.CSVが保存されています。
 下記に提示するコードを用いてファイル保存ダイアログを表示します。
   (以下単にダイアログと記述します)
 ダイアログのリストからAAA.CSVを選択します。
   (テキストボックスにAAA.CSVが設定されますよね。)
 保存をせずに、リスト、コンボボックスを操作してデスクトップを選択します。
   (デスクトップにはAAA.CSVは存在しません。)
 ここで、保存ボタンをクリックすると、なんと上書き確認のメッセージが
 表示されてしまいます。  ←これが問題!!!

ソース抜粋
 //    ファイル保存ダイアログ
 CFileDialog FileDlg( false, "CSV",NULL,
           OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT|OFN_PATHMUSTEXIST,
           "CSV File (*.CSV)|*.CSV||",
           NULL );
 if( FileDlg.DoModal() == IDOK ){

ちょっと文章では伝えにくいのですが、理解していただけたでしょうか?

私がデバッグしたところによると、
 直接テキストボックスに入力しても現象は確認できません。
 デスクトップのパス(C:\defaults and....)を指定したときは発生しません。
 APIのGetSaveFileNameも試してみましたが、同じ現象を確認しました。

何か使い方が間違えていますか?それともMicrosoftの…
対応法をご存知の方がいらっしゃったら、お力をお貸しください。

よろしくお願いします。

秋衛門 2003/12/02(火) 18:32:09
あらん、そんなん起こるんやん……と試してみるものの再現せず。
XP+VC6 で現象確認できずというあまり役に立たない情報まで

HEARTS 2003/12/02(火) 18:57:36
> 保存をせずに、リスト、コンボボックスを操作してデスクトップを選択します。
>   (デスクトップにはAAA.CSVは存在しません。)
> ここで、保存ボタンをクリックすると、なんと上書き確認のメッセージが
> 表示されてしまいます。  ←これが問題!!!

> デスクトップのパス(C:\defaults and....)を指定したときは発生しません。

どっち?
なんかおかしくない?

シャノン 2003/12/02(火) 20:12:50
マイドキュメントやマイコンピュータの上位にあるデスクトップでは発生するけれど、
C:\Documents and Settings\... のデスクトップフォルダでは発生しないということか
な。

ひろぴー 2003/12/02(火) 20:24:21
うわぁ!本当だ!
因みに私の環境ではGetSaveFileName()で左横にOutLookショートカットバー(って言うんでし
たっけ?)出ていましたので、ソコのデスクトップを押すと上書き確認はされません。
う〜ん、怪しい....。
↑解決になってませんが

Win2000 SP4 VC++6 SP5

いろは 2003/12/03(水) 09:01:11
秋衛門 様、シャノン 様、ひろぴー 様 情報ありがとうございます。

>秋衛門 様
>XP+VC6 で現象確認できずというあまり役に立たない情報まで

手近にXP(というか他のOS)が無いので、他のOSでは確認できていないのです。
情報ありがとうございました。

>シャノン 様
>マイドキュメントやマイコンピュータの上位にあるデスクトップでは発生するけれど、
>C:\Documents and Settings\... のデスクトップフォルダでは発生しないということか
>な。

はい。そういうことです。ちょっとわかりにくい文章でしたね。

>ひろぴー 様
>うわぁ!本当だ!
>因みに私の環境ではGetSaveFileName()で左横にOutLookショートカットバー
>(って言うんでしたっけ?)出ていましたので、ソコのデスクトッ
>プを押すと上書き確認はされません。

「APIを使用しても同じだ〜」という事しか確認していなかったので、
後ほど試してみます。

う〜ん…どのように対処したら良いかわからない…。
「どうやらMicrosoftの…」という事で終わりにしてしまおうか…

瀬戸っぷ [E-Mail] 2003/12/03(水) 11:13:43
以前、どかの掲示板でみたような記憶があります。
その時に試しましたが……
Windows98SE(COMDLG32.DLL Ver4.72.3510.2300)では再現せず…でした。<さっきまた試し
た。

APIのレベルで発生しているので、バグと思われますが……
ちなみにWindows2000 SP4(COMDLG32.DLL Ver5.00.3315.3727)では発生しました。
プレースバーは無しの状態…です。

いろは 2003/12/03(水) 16:12:39
[[解決]]
いろはです。

瀬戸っぷ様、情報ありがとうございました。

現在GetSaveFileNameの方で、再度確認中です。
すると、GetSaveFileNameを使用すると現象が出ないようです。
(最初に質問したときに、同様の現象が出るというのは嘘だったようです…)

という事で、CFileDialogを使用するのをあきらめて、APIを使用するように
方針転換することにしました。

一応、解決といたします。ありがとうございました。

瀬戸っぷ [E-Mail] 2003/12/03(水) 17:05:28
> 現在GetSaveFileNameの方で、再度確認中です。
> すると、GetSaveFileNameを使用すると現象が出ないようです。
> (最初に質問したときに、同様の現象が出るというのは嘘だったようです…)
> という事で、CFileDialogを使用するのをあきらめて、APIを使用するように
> 方針転換することにしました。

私の方ではGetSaveileName()API使用でも出ましたが。(Windows2000の方で)
CFileDialogでも最終的にGetOpenFileName()/GetSaveFileName()が使用されるので、
APIに切り替えても同じハズです。
(どちらが使用されるかは、CFileDialogのコンストラクタのbOpenFileDialog引数によります)
詳しくは…MFCのソース(DLGFILE.CPPのCFileDialog::DoModal())を見て下さい。

いろは 2003/12/04(木) 14:36:15
いろはです。

瀬戸っぷ 様、情報ありがとうございます。

>私の方ではGetSaveileName()API使用でも出ましたが。(Windows2000の方で)

おや、そうですか?
昨日は私がデバッグした限りではAPIを使用すれば、現象は出ませんでした。

こんなソースです。

(抜粋)
TCHAR strFile[MAX_PATH];
::memset( strFile, 0, sizeof(strFile) );

OPENFILENAME ofn;
::memset( &ofn, 0, sizeof(OPENFILENAME) );
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.Flags = OFN_PATHMUSTEXIST|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;
ofn.lpstrFilter = "CSV File(*.CSV)\0*.CSV\0\0";
ofn.nMaxFile = MAX_PATH;
ofn.lpstrFile = strFile;
ofn.lpstrDefExt = "CSV";
::GetSaveFileName( &ofn );

>CFileDialogでも最終的にGetOpenFileName()/GetSaveFileName()が使用されるので、
> 以下略
MFCのソースは追っていましたので、これはわかっていました。

Windows2000からOPENFILENAME構造体が拡張されましたよね。
今回の問題は、これが絡んでいるのではないかと思っています。

瀬戸っぷ [E-Mail] 2003/12/04(木) 15:27:56
> Windows2000からOPENFILENAME構造体が拡張されましたよね。
> 今回の問題は、これが絡んでいるのではないかと思っています。

プレースバー…でしたか、拡張されていますね。
私は使っていませんが…
    #ifndef OPENFILENAME_SIZE_VERSION_400
    stGofn.lStructSize  = sizeof(OPENFILENAME);
    #else
    stGofn.lStructSize  = OPENFILENAME_SIZE_VERSION_400;
    #endif
こんなコトして強制使用しています。

ちなみに、その辺の関係かMFC7.0(VC++.net)では
CFileDialogのコンストラクタで引数が1つ増えていたりします。
MFC6.0環境からのソースをコンパイルした場合に、条件によっては問題が出るらしいです。
(Googleで検索すると、その問題を調べたページがみつかるかと)

ちなみに、テストした時のOPENFILENAME構造体の設定は…
    OPENFILENAME stGofn;
    char szTemp[MAX_PATH];

    ZeroMemory(szTemp, MAX_PATH);
    ZeroMemory(&stGofn, sizeof(OPENFILENAME));
    #ifndef OPENFILENAME_SIZE_VERSION_400
    stGofn.lStructSize  = sizeof(OPENFILENAME);
    #else
    stGofn.lStructSize  = OPENFILENAME_SIZE_VERSION_400;
    #endif
    stGofn.hwndOwner    = hwnd;
    stGofn.lpstrFilter  = "全てのファイル(*.*)\0*.*\0";
    stGofn.nFilterIndex = 1;
    stGofn.lpstrTitle   = "名前を付けて保存・てすと";
    stGofn.lpstrFile    = szTemp;
    stGofn.nMaxFile     = (MAX_PATH-3);
    stGofn.Flags        = OFN_OVERWRITEPROMPT | OFN_ENABLEHOOK | 
OFN_EXPLORER | OFN_PATHMUSTEXIST;
    stGofn.lpstrDefExt  = "TXT";
    stGofn.lpfnHook     = (LPOFNHOOKPROC)OFNHookProc;
    GetSaveFileName(&stGofn);
です。(VC++6.0 SDKです。)
フックを使用していますが、各状態での内容を調べる為…なので、今回の問題には無関係です。

いろは 2003/12/04(木) 17:58:28
私が提示したソースに嘘がありました。

>ofn.Flags = OFN_PATHMUSTEXIST|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;
保存なのにOFN_FILEMUSTEXISTって…
正解はこちらです。
ofn.Flags = OFN_PATHMUSTEXIST|OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT;

このように修正した結果、やはり出ました。現象が…
プレースバーのデスクトップを選ぶと大丈夫なのですがね。

結局、バグという事ですかね。
ありがとうございました。

三毛猫 2003/12/05(金) 10:13:20
UINT CALLBACK OFNHookProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM 
lParam) {
    OFNOTIFY* lpOFNotify = (OFNOTIFY*)lParam;

    switch( message ) {
    case WM_NOTIFY:
        if( lpOFNotify->hdr.code == CDN_SELCHANGE ) {
            HWND hEdit = GetDlgItem( GetParent( hwnd ), edt1 );
            if( hEdit ) {
                char FileName[32000];
                GetWindowText( hEdit, FileName, 32000 );
                SetWindowText( hEdit, FileName );
            }
        }
        break;
    }
    return 0;
}

こんな感じで CDN_SELCHANGE 通知時にエディットボックスの内容を
上書きしたら、不要な上書き確認は表示されなくなりました。

# フックを使ったらプレースバーが表示されなくなりましたけど、
# 自前でダイアログを書き換えないとダメなのでしょうか。

瀬戸っぷ [E-Mail] 2003/12/05(金) 14:11:39
> 自作のアプリをXP上で起動し、起動した状態でデスクトップ
> テーマの変更を行うと、フォントをいじっている
> スタティックコントロールが汚く表示されてしまいます。
> なにか解決策はないのでしょうか?

XPは使ったことないですが…
デーマを変更した時になにかメッセージが飛んできませんか?
それらに応答する処理を追加してみてはどうでしょうか?
画面のプロパティのデザインで変更すると、
WM_SYSCOLORCHANGEやWM_SETTINGCHANGEが飛んできたりとかしますが。
Spy++で監視していると関連するメッセージがわかるかも知れません。


> こんな感じで CDN_SELCHANGE 通知時にエディットボックスの内容を
> 上書きしたら、不要な上書き確認は表示されなくなりました。

ソレをヒントにいぢってみました。
 エディトボックスにEM_SETMODIFYで更新フラグを設定してみる……失敗。
 親ウィンドウにEN_CHANGEとEN_UPDATEを送ってみる……成功。
 親ウィンドウにEN_UPDATEを送ってみる……失敗。
 親ウィンドウにEN_CHANGEを送ってみる……成功。
というコトで…
    case WM_NOTIFY:
        if( lpOFNotify->hdr.code == CDN_SELCHANGE ) {
            HWND hEdit = GetDlgItem( GetParent( hwnd ), edt1 );
            if( hEdit ) {
                SendMessage(GetParent( hwnd ), WM_COMMAND, MAKEWPARAM(edt1, 
EN_CHANGE), (LPARAM)hEdit);
            }
        }
で行けました。
まぁ、EN_CHANGEのあとにEN_UPDATEも送っておいた方がよさそうですけど。

> # フックを使ったらプレースバーが表示されなくなりましたけど、
> # 自前でダイアログを書き換えないとダメなのでしょうか。

消えますね。
なんらかの方法で可能なハズ(秀丸では表示させている)と思われますが…
ちょっと調べきれなかったです。
(秀丸のテンプレートではプレースバーは入っていませんでした…)

瀬戸っぷ [E-Mail] 2003/12/05(金) 14:13:36
げ……
テキストファイルで編集してから貼り付けていますが……
要らないモノまで貼り付けてしまいました(^_^;)

> 自作のアプリをXP上で起動し、起動した状態でデスクトップ
から
Spy++で監視していると関連するメッセージがわかるかも知れません。
までは無視して下さい(汗)

いろは 2003/12/05(金) 14:29:27
いろはです。
三毛猫 様、ありがとうございました。

教えて頂いたように、CDN_SELCHANGE 通知時に処理を追加したら、
余計な上書き確認を回避する事が出来ました。

『バグということであきらめよう』と思っていたので、
助かりました。

古いスレッドには追加発言できません。