Кнопки IFileOpenDialog не работают при использовании с другим открытым диалогом - PullRequest
0 голосов
/ 11 апреля 2020

Мое приложение состоит из стандартного диалогового окна и пары кнопок. Одна из кнопок должна открывать диалог выбора папки, поэтому я использовал IFileOpenDialog. Однако, когда это диалоговое окно открывается после создания основного диалогового окна, кнопки «Выбрать папку», «Отмена» и «X» не работают, как если бы никто не обрабатывал событие щелчка (навигация по файловой системе по-прежнему работает).

Пример минимальной воспроизводимости (компилируется с UNICODE):

Resource.r c

// Microsoft Visual C++ generated resource script.
//
#include "resource.h"

#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"

/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS

/////////////////////////////////////////////////////////////////////////////
// English (United States) resources

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US

#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//

1 TEXTINCLUDE 
BEGIN
    "resource.h\0"
END

2 TEXTINCLUDE 
BEGIN
    "#include ""winres.h""\r\n"
    "\0"
END

3 TEXTINCLUDE 
BEGIN
    "\r\n"
    "\0"
END

#endif    // APSTUDIO_INVOKED

#endif    // English (United States) resources
/////////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////////////

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_LTH)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US

/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//

IDD_DIALOG1 DIALOGEX 0, 0, 191, 52
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
    PUSHBUTTON      "Browse...",IDC_BUTTON_BROWSE,71,19,50,14
END


/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//

#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
    IDD_DIALOG1, DIALOG
    BEGIN
        LEFTMARGIN, 7
        RIGHTMARGIN, 184
        TOPMARGIN, 7
        BOTTOMMARGIN, 45
    END
END
#endif    // APSTUDIO_INVOKED


/////////////////////////////////////////////////////////////////////////////
//
// AFX_DIALOG_LAYOUT
//

IDD_DIALOG1 AFX_DIALOG_LAYOUT
BEGIN
    0
END

#endif
/////////////////////////////////////////////////////////////////////////////



#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//


/////////////////////////////////////////////////////////////////////////////
#endif    // not APSTUDIO_INVOKED

Программа. cpp

#include <assert.h>

#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>

#include <shobjidl_core.h>
#include <wrl.h>

#include "resource.h"

static void PickDirectory(HWND hwnd)
{
    Microsoft::WRL::ComPtr<IFileDialog> folderPicker;
    auto hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&folderPicker));
    assert(SUCCEEDED(hr));

    DWORD pickerOptions;
    hr = folderPicker->GetOptions(&pickerOptions);
    assert(SUCCEEDED(hr));

    hr = folderPicker->SetOptions(pickerOptions | FOS_PICKFOLDERS);
    assert(SUCCEEDED(hr));

    if (SUCCEEDED(folderPicker->Show(hwnd)))
    {
        Microsoft::WRL::ComPtr<IShellItem> folderShellItem;
        hr = folderPicker->GetResult(&folderShellItem);
        assert(SUCCEEDED(hr));

        PWSTR folderPath = nullptr;
        hr = folderShellItem->GetDisplayName(SIGDN_FILESYSPATH, &folderPath);
        assert(SUCCEEDED(hr));

        OutputDebugStringW(L"Picked folder: ");
        OutputDebugStringW(folderPath);
        OutputDebugStringW(L"\r\n");

        CoTaskMemFree(folderPath);
    }

    return;
}

static LRESULT WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_COMMAND:
        if (LOWORD(wParam) == IDC_BUTTON_BROWSE && HIWORD(wParam) == BN_CLICKED)
        {
            PickDirectory(hwnd); // <------- freezes!
            return 0;
        }

        break;

    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }

    return DefWindowProcW(hwnd, uMsg, wParam, lParam);
}

int CALLBACK wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR, int nCmdShow)
{
    auto hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
    assert(SUCCEEDED(hr));

    PickDirectory(nullptr); // <------- works!

    auto hwnd = CreateDialogParamW(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), nullptr, WndProc, 0);
    assert(hwnd != nullptr);

    ShowWindow(hwnd, nCmdShow);

    PickDirectory(nullptr); // <------- freezes!

    for (;;)
    {
        MSG msg;
        auto getMessageResult = GetMessageW(&msg, nullptr, 0, 0);

        if (getMessageResult == 0 || getMessageResult == -1)
            break;

        TranslateMessage(&msg);
        DispatchMessageW(&msg);
    }

    return 0;
}

Примечание что средство выбора папок работает, прежде чем я создаю основной диалог приложения. После его создания он больше не работает.

Есть ли какой-нибудь секретный соус, который вы должны использовать при открытии IFileOpenDialog при использовании других диалогов?

1 Ответ

0 голосов
/ 13 апреля 2020

Как заметил @Igor Tandetnik, CreateDialogParam занимает DialogProc вместо WndProc. Хотя они оба имеют одинаковые подписи (поэтому вы не увидите ошибку компилятора), их возвращаемое значение отличается: DialogProc не вызывает DefWindowProc.

Исправление, которое заставило средство выбора файлов снова работать .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...