Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Visual C++/MFC/WTL > CFileDialog


Автор: 0x07L 23.8.2006, 09:44
В моем классе, производном от CFileDialog, не вызывается виртуальная функция CFileDialog::OnLBSelChangedNotify. Как я выяснил, функции _AfxCommDlgProc (файл dlgcomm.cpp), которую CFileDialog подставляет в качестве хука, просто не приходит соответствующее сообщение. Немного об OnLBSelChangedNotify:

CFileDialog::OnLBSelChangedNotify

This function is called whenever the current selection in a list box is about to change.
 
virtual void OnLBSelChangedNotify(
   UINT nIDBox,
   UINT iCurSel,
   UINT nCode
);

Parameters
. . .

Remarks
Override this function to provide custom handling of selection changes in the list box. For example, you can use this function to display the access rights or date-last-modified of each file the user selects.


Вот кусочек функции _AfxCommDlgProc:
Код

if (message == WM_INITDIALOG)
    {
        _afxMsgLBSELCHANGE = ::RegisterWindowMessage(LBSELCHSTRING);
         // . . .
    }
// . . .
if (message == _afxMsgLBSELCHANGE)
    {
// Вот сюда мы почему-то никогда не попадаем
        ASSERT_KINDOF(CFileDialog, pDlg);
        ((CFileDialog*)pDlg)->OnLBSelChangedNotify((UINT)wParam, LOWORD(lParam),
                HIWORD(lParam));
        return 0;
    }

Флажок что-ли ему какой-то нужен? Но, во-первых, такого флажка в MSDN я не нашел. Во-вторых, об этом должен заботится не я, а CFileDialog. Кто-нибудь сталкивался с этим? Как всегда, тестовая программка:
Код

#include "stdafx.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

///////////////////////////////////////
// CMyFileDialog

class CMyFileDialog : public CFileDialog
{
    DECLARE_DYNAMIC(CMyFileDialog)

public:

    CMyFileDialog(
        BOOL bOpenFileDialog,
        LPCTSTR lpszDefExt = NULL,
        LPCTSTR lpszFileName = NULL,
        DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
        LPCTSTR lpszFilter = NULL,
        CWnd* pParentWnd = NULL)
    : CFileDialog(
        bOpenFileDialog,
        lpszDefExt, 
        lpszFileName,
        dwFlags,
        lpszFilter,
        pParentWnd) {}

    virtual ~CMyFileDialog() {}

protected:
    
    void OnLBSelChangeNotify(UINT box, UINT sel, UINT code)
    {
        Beep(1600, 40);
        CFileDialog::OnLBSelChangedNotify(box, sel, code);
    }
};

IMPLEMENT_DYNAMIC(CMyFileDialog, CFileDialog)

///////////////////////////////////////
// CApplication

class CApplication : public CWinApp
{
public:

    CApplication() : CWinApp() {}
    ~CApplication() {}

    virtual BOOL InitInstance()
    {
        INITCOMMONCONTROLSEX icc = {sizeof icc, ICC_WIN95_CLASSES};
        InitCommonControlsEx(&icc);

        CWinApp::InitInstance();

        CMyFileDialog dlg (TRUE, 0, 0,
             OFN_ALLOWMULTISELECT | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT);
        m_pMainWnd = &dlg;
        dlg.DoModal();

        // Since the dialog has been closed, return FALSE so that we exit the
        // application, rather than start the application's message pump.
        return FALSE;
    }
};

// The one and only CApplication object
CApplication app;

Автор: Earnest 23.8.2006, 14:41
Вот еще кусочек _AfxCommDlgProc (ДО обработки сообщений)

Код

    if (pDlg->IsKindOf(RUNTIME_CLASS(CFileDialog)))
    {
        // If we're exploring then we are not interested in the Registered messages
        if (((CFileDialog*)pDlg)->m_ofn.Flags & OFN_EXPLORER)
            return 0;
    }

Автор: 0x07L 23.8.2006, 15:14
Ха, в функцию хука вообще не приходят зарегистрированные сообщения! Зато приходит WM_SETREDRAW... Мы не проходим дальше
Код

if (message < 0xC000)
{
    // not a ::RegisterWindowMessage message
    return 0;
}

Что такое?

Автор: Earnest 23.8.2006, 16:53
0x07L, у тебя стиль OFN_EXPLORER? 
// If we're exploring then we are not interested in the Registered messages

Добавлено @ 16:55 
Там другие уведомления приходят:
Цитата

The CDN_SELCHANGE notification message is sent by an Explorer-style Open or Save As dialog box when the selection changes in the list box that displays the contents of the currently opened folder or directory. 

Your OFNHookProc hook procedure receives this message in the form of a WM_NOTIFY message. 


Добавлено @ 16:57 
А дальше - вызываются виртуальные функции OnFileNameChange, OnFolderChange, OnTypeChange.

Автор: 0x07L 23.8.2006, 19:07
Стиль OFN_EXPLORER устанавливает сам CFileDialog. 

Ну я же пробовал днем OnFileNameChange, он приходил, оставалось только найти окно ListView, который отображает файлы. Вот тут-то я и сплоховал. Посмотрел его свойства в Spy, увидел там идентификатор 1, подивился немного тому, что это IDOK и что в диалоге есть кнопка с таким ID, но не обратил на это внимание. Все попытки найти это окно были неудачными и я это дело бросил. А стоило то всего-то посмотреть в окно windows Spy++. Оказывается, это окно - не прямой потомок диалога...

Конечно, удобнее использовать флажки, которые передаются в OnLBSelChange, но что делать, если OnLBSelChange не вызывается. В общем, проблема решена. Однако ради любопытства стоит узнать, почему в MSDN написано не то, что происходит на самом деле. А в тот if-блок, который Вы привели, мы тоже не попадаем, поскольку
Код

if (message < 0xC000)
{
    // not a ::RegisterWindowMessage message
    return 0;
}

Автор: Earnest 24.8.2006, 07:38
Цитата(0x07L @  23.8.2006,  20:07 Найти цитируемый пост)
А в тот if-блок, который Вы привели, мы тоже не попадаем

Да? Ну, возможно, это MS-программисты перестарались...
Но суть в том, что сначала в API был FileDialog, который выглядел немного по-другому (попроще), и документация была написана для него. А потом появился дополнительный стиль эксплорер: это совсем другое окно с совсем другим механизмом уведомлений, который работает через NOTIFY, как common-контролы. Новую документацию написали, а в старой написать, что это только для старого стиля, видимо, забыли. Но если почитать про новые уведомления, то все становится понятным.

Автор: 0x07L 24.8.2006, 14:01
Да, наверное, очень сложно поддерживать MSDN в актуальном состоянии.
Только вот зачем устанавливать процедуру хука для диалога открытия / сохранения файлов, раз она ничего, выходит, не делает.

Автор: Earnest 24.8.2006, 14:22
Да ведь процедура-то на все common-диалоги общая, и там кое-что делается для случая стиля "эксплорер": см. самое начало, про pThreadState->m_pAlternateWndInit. Это как раз CFileDialog сабклассится.
Не самое изящное решение, конечно. Больше напоминает костыль. Ну да такова реальная жизнь кода: в любом "долгом" приложении можно встретить такие костыли.

Автор: 0x07L 24.8.2006, 14:29
Earnest, большое спасибо за помощь!

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)