none
MFCアプリのエクスプローラファイルのダブルクリック対応

    質問

  • お世話になっております。

    VC++2010、MDIアプリ(MFC)

    CMyApp::InitInstance関数内に、起動許可ダイアログ(ID,PWを入力)を表示することになりました。

    ただ、このダイアログを表示することで、ファイルのダブルクリックでの処理が正しく動作しなくなりました。
    現象は、「子ウィンドウが作成されず、ファイルを読み込まない」です。

    ※スタートメニューからアプリケーション起動、「ファイルを開く」からファイルを開くことはできています。

    1.EnableShellOpen()でDDEメッセージ受付許可
    2.次のコードでメッセージループ開始

    	// メイン MDI フレーム ウィンドウを作成
    	CMainFrame* pMainFrame = new CMainFrame;
    	if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
    		return FALSE;
    	m_pMainWnd = pMainFrame;
    

    上記処理が終わったところで、起動許可ダイアログを表示しています。
    ※ここでは、Internet通信を行い、サーバーから許可判定をもらうことになります。

    なにか、上記の内容で問題点等ありましたら教えてください。
    また、なにか調べるべき点、確認する点がありましたら教えてください。


    2018年2月13日 7:12

すべての返信

  • 回答ではありません。あしからず。
    ID、PW入力処理内で、後の処理、例えば
    OnFileNew()やOpenDocumentFile()の処理結果が「失敗を戻す」ような内部フラグ制御などしている場合は
    「ファイルを読み込まない」やドキュメントの新規作成などができないといったルートにはなりえます。
    まずはどこで失敗しているのかMessageBox()やOutputDebugString()等でトレースしてみることをお勧めします。
    例えば(2)で戻ってしまうなどですかね。

    MyApp::InitInstance()
    {
        :
      m_pMainWnd = pMainFrame;
      // (1)★★現在はここでしょうか(質問)
        :
      // 標準コマンドライン処理・・・・こんな処理がありませんでしょうか。
      CCommandLineInfo cmdInfo;
      ParseCommandLine( cmdInfo);
      if( !ProcessShellCommand(cmdInfo)){ // ★★OnFileNew()やOpenDocumentFile()はここから呼ばれる
          return FALSE;// (2)上記処理に失敗した場合はここで終了
      }

    ◇DBMON.exe等を使えばダブルクリックの起動(IDEからのデバッグ起動でない場合など)でもOutputDebugString()の出力が見えます。

    2018年2月13日 7:59
  • >>// (1)★★現在はここでしょうか(質問)

    はい。

    >>return FALSE;// (2)上記処理に失敗した場合はここで終了

    アプリケーション自体は終了していないので、上記に入ってい無いと思われます。。

    if( !ProcessShellCommand(cmdInfo)){ return FALSE;// (2)上記処理に失敗した場合はここで終了 }

    //ここに、起動許可ダイアログを実装しましたが、子ウィンドウは表示されませんでした。

    ただ、OpenDocumentFile()が呼ばれていません。



    • 編集済み Brillia 2018年2月13日 8:18
    2018年2月13日 8:12
  • 問題のある部分が、

    (1)アプリケーション本体側のコード
    (2)ID、PW入力DLG側のコード

    のどちらに起因しているのかを切り分けた方が良いかもしれません。
    そのためには「ID、PW入力DLGの表示」部分を「何もしないOKだけのDLG表示」に
    置き換えてやってみてはどうでしょう。

    この置き換えで問題なれば(2)の部分に問題があると予測できます。

    2018年2月13日 8:29
  • DebugViewを起動してみると次のメッセージが表示されていました。

    [5116] Warning: DDE command '[open("C:\Users\testuser\Documents\Data\SAMPLE.abc")]' ignored because window is disabled.
    

    Windowが無効だから DDEコマンドを無視する的なメッセージっぽいのですが。。。

    どの関数がこのデバックを出力しているのか。

    また、内容が理解できません。


    • 編集済み Brillia 2018年2月13日 8:41
    • 回答としてマーク Brillia 2018年2月14日 5:43
    • 回答としてマークされていない Brillia 2018年2月14日 5:43
    2018年2月13日 8:40
  • モーダルDLGを表示中は、メインフレームが非活性(ディスエーブル)になります。
    この状態ではDDEメッセージは無視されるということを示唆していると考えられます。
    • 回答としてマーク Brillia 2018年2月14日 5:43
    • 回答としてマークされていない Brillia 2018年2月14日 8:37
    2018年2月13日 9:04
  • CFrameWnd::OnDDEExecute のソースを見て、対応方法が考えるところだと思います。

    • 回答としてマーク Brillia 2018年2月14日 5:43
    • 回答としてマークされていない Brillia 2018年2月14日 8:37
    2018年2月13日 13:09
    モデレータ
  • ::PostMessage( hWndClient, WM_DDE_ACK, (WPARAM)m_hWnd, MAKELPARAM( 0x8000, hMem ) );

    で、送っている先が、ディスエーブルということなのか???

    InitInstanceでダイアログを出すことは難しい・・・

    2018年2月13日 13:53
  • ::PostMessage( hWndClient, WM_DDE_ACK, (WPARAM)m_hWnd, MAKELPARAM( 0x8000, hMem ) );

    で、送っている先が、ディスエーブルということなのか???

    違うんじゃないですか?
    手元の VS2010 のソースコードでは形が違うので見ているものが違う可能性もあるので、断言できませんが…。
    (m_hWnd が自分自身のウィンドウハンドルであることを考えれば、「違う」で外していないと思いますけれども)

    とりあえず、言えることは、CFrameWnd::OnDDEExecute が実施している処理を理解し、ご自身の継承クラスで都合の良いように再実装されたら良いのでは?と言うことです。ただし、私自身は未検証なので、できなかったとしてもなんとも言えませんが…。

    それが難しいようでしたら、InitInstance でダイアログを出すというアプローチが成り立たないのでそれ自体を諦めるか、DDE をやめる道筋を探すかになりそうです。(後者の話の実現性があるかは未調査。道がない可能性もある)

    2018年2月13日 14:15
    モデレータ
  • CFrameWnd::OnDDEExecuteをオーバーライドして、動作を確認してみます。
    2018年2月14日 5:43
  • デバック実行で、CFrameWnd::OnDDEExecute関数と起動認証ダイアログとの処理を見てみたのですが、

    起動認証ダイアログの表示する処理を行っているのに、起動認証ダイアログを呼び出したところで、
    そのままステップ実行すると、
    起動認証ダイアログが表示されず、CFrameWnd::OnDDEExecute関数が実行されていました。

    CFrameWnd::OnDDEExecute関数内で、IsWindowEnabled関数の戻り値によって、
    DDE処理が中止され、そのあと起動認証ダイアログが表示されている感じです。

    1.起動認証ダイアログが表示(IDPW入力)
    2.CFrameWnd::OnDDEExecute関数が実行

    という順番に処理が行われていないのが原因みたいです。

    ためしに、起動認証ダイアログの代わりに、
    MessageBox関数をInitInstance関数内に実装してみたのですが、
    MessageBox関数を読んだところで表示されず、InitInstance関数処理が完了され、

    そのあとにメッセージボックスが表示されました。

    これは言ったどういった現象なのでしょうか?



    2018年2月14日 8:00
  • デバッグされたのであれば、呼び出し履歴を見れば呼び出し元はわかるかと。
    1. クライアント(この場合はエクスプローラー)がWM_DDE_INITIATEメッセージを投げる
    2. アプリケーションはWM_DDE_INITIATEメッセージを処理するCFrameWnd::OnDDEInitiate()を呼び出す
    3. アプリケーションはCFrameWnd::OnDDEInitiate()でWM_DDE_ACKメッセージを返す
    4. クライアントはWM_DDE_ACKを受けてWM_DDE_EXECUTEメッセージを投げる
    5. アプリケーションはWM_DDE_EXECUTEメッセージを処理するCFrameWnd::OnDDEExecute()を呼び出す
    6. アプリケーションはCFrameWnd::OnDDEExecute()でIsWindowEnabled()がfalseを返したのでDDE処理を中止する

    という流れかと。

    ためしに、起動認証ダイアログの代わりに、MessageBox関数をInitInstance関数内に実装してみたのですが、MessageBox関数を読んだところで表示されず、InitInstance関数処理が完了され、そのあとにメッセージボックスが表示されました。

    MessageBoxとてGUIでありメッセージループを処理しなければ表示できません。表示する過程で上記メッセージの方が先に処理されたのでしょう。

    2018年2月14日 8:41
  • OnDDEExecute( LPTSTR lpszCommand)で、引数のDDEコマンド文字列lpszCommandをコピーして取っておき、
    その後の「起動認証ダイアログ」処理の後で、
    派生元のOnDDEExecute(コピーしておいたDDEコマンド文字列);
    の様にやってみてはどうでしょう(あまり自信なし)。
    2018年2月14日 9:16
  • 認証ダイアログを使用しない場合、

    InitInstance関数 内では、次のDDE関数は呼ばれていませんでした。
    InitInstance関数処理後に、次のDDE関数は実行されていました。

    ・CFrameWnd::OnDDEInitiate()
    ・CFrameWnd::OnDDEExecute()

    つまり、認証ダイアログを表示させることで、メッセージループが開始されてしまい、
    InitInstance関数内で、上記DDE関数の処理が実行されてしまっているように思えます。

    本来、CMainFrame(メインフレームウィンドウ)は、InitInstance関数処理後に、
    EnableWindow状態になる(?)ので、InitInstance関数内でメッセージ処理が
    おこなわれ、DDE処理が失敗するということだと思います。

    じゃ、認証ダイアログを呼ぶ前に、次のコードを入れて見たのですが、
    DDE関数内のIsWindowEnable()はTRUEにならずでした。。。

    	// メイン MDI フレーム ウィンドウを作成
    	CMainFrame* pMainFrame = new CMainFrame;
    	if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
    		return FALSE;
    	m_pMainWnd = pMainFrame;
        // Enable状態に
        m_pMainWnd->EnableWindow();
    
        ここで認証ダイアログを呼ぶ。。。

    InitInstance関数内で、認証ダイアログを呼ぶこと自体が問題なのか。。。
    ※認証ダイアログが、提供されたもの(DLL)なので、認証ダイアログ自体何をしているのかわからないのがネックですが。。。

    >>OnDDEExecute( LPTSTR lpszCommand)で、引数のDDEコマンド文字列lpszCommandをコピーして取っておき、

    この方法を試してみたところ、確かにファイルが開くことができました。
    が、アプリケーション起動時の動きが、ちらちら表示しながら、後ろに隠れるという

    なんともおかしな動きとなりました。。。

    現状報告です。
    • 編集済み Brillia 2018年2月15日 6:21
    2018年2月15日 6:21