[PATCH v6 0/1] MR10193: dlls/comdlg32:Add the implementation of IServiceProvider_fnQueryService to obtain IFolderView2
An application adds a new button using IFileDialogCustomize_AddPushButton. The application obtains IServiceProvider_iface through QueryInterface using the parameter IFileDialogCustomize_iface of the callback function IFileDialogControlEvents_OnButtonClicked, and then uses IServiceProvider_iface to pass IID_IFolderView and IID_IFolderView2 through IServiceProvider_fnQueryService to obtain IFolderView2. After that, it obtains the selected files and folders through IFolderView2_GetSelection. Currently, the implementation of obtaining IFolderView2 through IServiceProvider_fnQueryService is missing and needs to be added. -- v6: dlls/comdlg32:Add the implementation of IServiceProvider_fnQueryService to obtain IFolderView2 https://gitlab.winehq.org/wine/wine/-/merge_requests/10193
From: panhui <panhui@uniontech.com> --- dlls/comdlg32/itemdlg.c | 4 + dlls/comdlg32/tests/itemdlg.c | 351 ++++++++++++++++++++++++++++++++++ 2 files changed, 355 insertions(+) diff --git a/dlls/comdlg32/itemdlg.c b/dlls/comdlg32/itemdlg.c index 830d88bb661..c12ae22e1c7 100644 --- a/dlls/comdlg32/itemdlg.c +++ b/dlls/comdlg32/itemdlg.c @@ -3602,6 +3602,10 @@ static HRESULT WINAPI IServiceProvider_fnQueryService(IServiceProvider *iface, hr = IExplorerBrowser_QueryInterface(This->peb, riid, ppv); else if(IsEqualGUID(guidService, &SID_SExplorerBrowserFrame)) hr = IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppv); + else if((IsEqualIID(riid, &IID_IFolderView) || IsEqualIID(riid, &IID_IFolderView2)) && This->peb) + { + hr = IExplorerBrowser_GetCurrentView(This->peb, riid, ppv); + } else FIXME("Interface %s requested from unknown service %s\n", debugstr_guid(riid), debugstr_guid(guidService)); diff --git a/dlls/comdlg32/tests/itemdlg.c b/dlls/comdlg32/tests/itemdlg.c index e31ce3592c3..ae67e753c5b 100644 --- a/dlls/comdlg32/tests/itemdlg.c +++ b/dlls/comdlg32/tests/itemdlg.c @@ -356,6 +356,8 @@ static BOOL test_instantiation(void) IUnknown *punk, *unk2; HRESULT hr; LONG ref; + IFolderView *pfv; + IFolderView2 *pfv2; /* Instantiate FileOpenDialog */ hr = CoCreateInstance(&CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, @@ -414,6 +416,13 @@ static BOOL test_instantiation(void) ok(hr == E_NOTIMPL || broken(hr == E_FAIL), "got 0x%08lx (expected E_NOTIMPL)\n", hr); if(SUCCEEDED(hr)) IUnknown_Release(punk); + hr = IServiceProvider_QueryService(psp, &IID_IFolderView, &IID_IFolderView, (void**)&pfv); + ok(hr == E_NOTIMPL || broken(hr == E_FAIL), "got 0x%08lx (expected E_NOTIMPL)\n", hr); + if(SUCCEEDED(hr)) IFolderView_Release(pfv); + hr = IServiceProvider_QueryService(psp, &IID_IFolderView, &IID_IFolderView2, (void**)&pfv2); + ok(hr == E_NOTIMPL || broken(hr == E_FAIL), "got 0x%08lx (expected E_NOTIMPL)\n", hr); + if(SUCCEEDED(hr)) IFolderView2_Release(pfv2); + IServiceProvider_Release(psp); } @@ -2557,6 +2566,347 @@ static void test_double_show(void) IFileDialog_Release(pfd); } +typedef struct { + IFileDialogEvents IFileDialogEvents_iface; + IFileDialogControlEvents IFileDialogControlEvents_iface; + LONG ref; + LPCWSTR button_text; + DWORD button_id; + BOOL button_clicked; + BOOL test_passed; + IFileDialog *pfd; +} ITestEventsImpl; + +static inline ITestEventsImpl *test_impl_from_IFileDialogEvents(IFileDialogEvents *iface) +{ + return CONTAINING_RECORD(iface, ITestEventsImpl, IFileDialogEvents_iface); +} + +static HRESULT WINAPI test_events_QueryInterface(IFileDialogEvents *iface, REFIID riid, void **ppv) +{ + ITestEventsImpl *This = test_impl_from_IFileDialogEvents(iface); + + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IFileDialogEvents)) + { + *ppv = &This->IFileDialogEvents_iface; + } + else if (IsEqualIID(riid, &IID_IFileDialogControlEvents)) { + *ppv = &This->IFileDialogControlEvents_iface; + } + else + { + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI test_events_AddRef(IFileDialogEvents *iface) +{ + ITestEventsImpl *This = test_impl_from_IFileDialogEvents(iface); + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI test_events_Release(IFileDialogEvents *iface) +{ + ITestEventsImpl *This = test_impl_from_IFileDialogEvents(iface); + LONG ref = InterlockedDecrement(&This->ref); + if (!ref) free(This); + return ref; +} + +static HRESULT WINAPI test_events_OnFileOk(IFileDialogEvents *iface, IFileDialog *pfd) +{ + return S_OK; +} +static HRESULT WINAPI test_events_OnFolderChanging(IFileDialogEvents *iface, IFileDialog *pfd, IShellItem *psi) +{ + return S_OK; +} +static HRESULT WINAPI test_events_OnSelectionChange(IFileDialogEvents *iface, IFileDialog *pfd) +{ + return S_OK; +} +static HRESULT WINAPI test_events_OnShareViolation(IFileDialogEvents *iface, IFileDialog *pfd, + IShellItem *psi, FDE_SHAREVIOLATION_RESPONSE *resp) +{ + return S_OK; +} +static HRESULT WINAPI test_events_OnTypeChange(IFileDialogEvents *iface, IFileDialog *pfd) +{ + return S_OK; +} +static HRESULT WINAPI test_events_OnOverwrite(IFileDialogEvents *iface, IFileDialog *pfd, + IShellItem *psi, FDE_OVERWRITE_RESPONSE *resp) +{ + return S_OK; +} + +static LRESULT CALLBACK test_control_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); + +static HRESULT WINAPI test_events_OnFolderChange(IFileDialogEvents *iface, IFileDialog *pfd) +{ + ITestEventsImpl *This = test_impl_from_IFileDialogEvents(iface); + HWND hwnd; + WNDPROC oldproc; + + hwnd = get_hwnd_from_ifiledialog(pfd); + ok(hwnd != NULL, "Failed to get dialog window\n"); + + if (GetPropA(hwnd, "TEST_THIS")) return S_OK; + + IFileDialogEvents_AddRef(iface); + + oldproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC); + SetPropA(hwnd, "OLD_PROC", (HANDLE)oldproc); + SetPropA(hwnd, "TEST_THIS", (HANDLE)This); + SetPropA(hwnd, "IFD", (HANDLE)pfd); + SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)test_control_wndproc); + + PostMessageW(hwnd, WM_APP + 1, 0, 0); + + return S_OK; +} + +static const IFileDialogEventsVtbl test_events_vtbl = { + test_events_QueryInterface, + test_events_AddRef, + test_events_Release, + test_events_OnFileOk, + test_events_OnFolderChanging, + test_events_OnFolderChange, + test_events_OnSelectionChange, + test_events_OnShareViolation, + test_events_OnTypeChange, + test_events_OnOverwrite +}; + +static inline ITestEventsImpl *test_impl_from_IFileDialogControlEvents(IFileDialogControlEvents *iface) +{ + return CONTAINING_RECORD(iface, ITestEventsImpl, IFileDialogControlEvents_iface); +} + +static HRESULT WINAPI test_control_QueryInterface(IFileDialogControlEvents *iface, REFIID riid, void **ppv) +{ + ITestEventsImpl *This = test_impl_from_IFileDialogControlEvents(iface); + return IFileDialogEvents_QueryInterface(&This->IFileDialogEvents_iface, riid, ppv); +} + +static ULONG WINAPI test_control_AddRef(IFileDialogControlEvents *iface) +{ + ITestEventsImpl *This = test_impl_from_IFileDialogControlEvents(iface); + return IFileDialogEvents_AddRef(&This->IFileDialogEvents_iface); +} + +static ULONG WINAPI test_control_Release(IFileDialogControlEvents *iface) +{ + ITestEventsImpl *This = test_impl_from_IFileDialogControlEvents(iface); + return IFileDialogEvents_Release(&This->IFileDialogEvents_iface); +} + +static HRESULT WINAPI test_control_OnItemSelected(IFileDialogControlEvents *iface, + IFileDialogCustomize *pfdc, DWORD dwIDCtl, DWORD dwIDItem) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_control_OnButtonClicked(IFileDialogControlEvents *iface, + IFileDialogCustomize *pfdc, DWORD dwIDCtl) +{ + ITestEventsImpl *This = test_impl_from_IFileDialogControlEvents(iface); + IServiceProvider *psp; + IFolderView2 *pfv2; + IShellItemArray *psia; + HRESULT hr; + IFileDialog *pfd; + + ok(dwIDCtl == This->button_id, "Expected button ID %lu, got %lu\n", This->button_id, dwIDCtl); + + hr = IFileDialogCustomize_QueryInterface(pfdc, &IID_IServiceProvider, (void**)&psp); + ok(hr == S_OK, "QI for IServiceProvider failed: 0x%08lx\n", hr); + if (FAILED(hr)) + { + return S_OK; + } + + hr = IServiceProvider_QueryService(psp, &IID_IFolderView, &IID_IFolderView2, (void**)&pfv2); + ok(hr == S_OK, "QueryService for IFolderView2 failed: 0x%08lx\n", hr); + if (SUCCEEDED(hr)) + { + psia = NULL; + hr = IFolderView2_GetSelection(pfv2, TRUE, &psia); + todo_wine_if(hr == E_NOTIMPL) + ok(hr == S_OK, "GetSelection(TRUE) returned 0x%08lx\n", hr); + + if (hr == S_OK) + { + ok(psia != NULL, "psia should not be NULL when hr == S_OK\n"); + if (psia) + { + DWORD count; + hr = IShellItemArray_GetCount(psia, &count); + ok(hr == S_OK, "GetCount failed: 0x%08lx\n", hr); + ok(count == 1, "Expected 1 item (the current folder), got %lu\n", count); + IShellItemArray_Release(psia); + } + } + IFolderView2_Release(pfv2); + } + IServiceProvider_Release(psp); + + This->test_passed = TRUE; + This->button_clicked = TRUE; + + hr = IFileDialogCustomize_QueryInterface(pfdc, &IID_IFileDialog, (void**)&pfd); + ok(hr == S_OK, "QI for IFileDialog failed: 0x%08lx\n", hr); + if (SUCCEEDED(hr)) + { + hr = IFileDialog_Close(pfd, S_FALSE); + ok(hr == S_OK, "Close failed: 0x%08lx\n", hr); + IFileDialog_Release(pfd); + } + + return S_OK; +} + +static HRESULT WINAPI test_control_OnCheckButtonToggled(IFileDialogControlEvents *iface, + IFileDialogCustomize *pfdc, + DWORD dwIDCtl, BOOL bChecked) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_control_OnControlActivating(IFileDialogControlEvents *iface, + IFileDialogCustomize *pfdc, + DWORD dwIDCtl) +{ + return E_NOTIMPL; +} + +static const IFileDialogControlEventsVtbl test_control_vtbl = { + test_control_QueryInterface, + test_control_AddRef, + test_control_Release, + test_control_OnItemSelected, + test_control_OnButtonClicked, + test_control_OnCheckButtonToggled, + test_control_OnControlActivating +}; + +static LRESULT CALLBACK test_control_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + WNDPROC oldproc; + switch (msg) + { + case WM_APP + 1: + SetTimer(hwnd, 1000, 100, NULL); + return 0; + + case WM_TIMER: + if (wparam == 1000) + { + ITestEventsImpl *This = (ITestEventsImpl*)GetPropA(hwnd, "TEST_THIS"); + if (This) + { + HWND btn = find_window(hwnd, L"Button", This->button_text); + if (btn) + { + SendMessageW(btn, BM_CLICK, 0, 0); + } + else + { + trace("Button not found!\n"); + } + } + KillTimer(hwnd, 1000); + oldproc = (WNDPROC)GetPropA(hwnd, "OLD_PROC"); + if (oldproc) + { + SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)oldproc); + RemovePropA(hwnd, "OLD_PROC"); + RemovePropA(hwnd, "TEST_THIS"); + RemovePropA(hwnd, "IFD"); + } + + if (This) + IFileDialogEvents_Release(&This->IFileDialogEvents_iface); + + return 0; + } + break; + } + oldproc = (WNDPROC)GetPropA(hwnd, "OLD_PROC"); + if (oldproc) + return CallWindowProcW(oldproc, hwnd, msg, wparam, lparam); + return DefWindowProcW(hwnd, msg, wparam, lparam); +} + +static void test_control_events_selection(void) +{ + IFileDialog *pfd; + IFileDialogCustomize *pfdc; + ITestEventsImpl *events; + IFileDialogEvents *pEvents; + DWORD cookie; + HRESULT hr; + static const WCHAR button_text[] = L"testButton"; + DWORD button_id = 1001; + + hr = CoCreateInstance(&CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, + &IID_IFileDialog, (void**)&pfd); + ok(hr == S_OK, "CoCreateInstance failed: 0x%08lx\n", hr); + if (FAILED(hr)) return; + + hr = IFileDialog_QueryInterface(pfd, &IID_IFileDialogCustomize, (void**)&pfdc); + ok(hr == S_OK, "QI for IFileDialogCustomize failed: 0x%08lx\n", hr); + if (FAILED(hr)) + { + IFileDialog_Release(pfd); + return; + } + + hr = IFileDialogCustomize_AddPushButton(pfdc, button_id, button_text); + ok(hr == S_OK, "AddPushButton failed: 0x%08lx\n", hr); + + events = calloc(1, sizeof(*events)); + events->IFileDialogEvents_iface.lpVtbl = &test_events_vtbl; + events->IFileDialogControlEvents_iface.lpVtbl = &test_control_vtbl; + events->ref = 1; + events->button_text = button_text; + events->button_id = button_id; + events->pfd = pfd; + pEvents = &events->IFileDialogEvents_iface; + + hr = IFileDialog_Advise(pfd, pEvents, &cookie); + ok(hr == S_OK, "Advise failed: 0x%08lx\n", hr); + + { + IShellItem *psi; + WCHAR path[MAX_PATH]; + GetCurrentDirectoryW(MAX_PATH, path); + hr = pSHCreateItemFromParsingName(path, NULL, &IID_IShellItem, (void**)&psi); + if (SUCCEEDED(hr)) + { + IFileDialog_SetFolder(pfd, psi); + IShellItem_Release(psi); + } + } + + hr = IFileDialog_Show(pfd, NULL); + ok(hr == S_FALSE || hr == HRESULT_FROM_WIN32(ERROR_CANCELLED), + "Show returned 0x%08lx (expected S_FALSE or ERROR_CANCELLED)\n", hr); + + ok(events->button_clicked, "Button was not clicked\n"); + ok(events->test_passed, "Test in OnButtonClicked failed\n"); + + IFileDialog_Unadvise(pfd, cookie); + IFileDialogCustomize_Release(pfdc); + IFileDialog_Release(pfd); + IFileDialogEvents_Release(pEvents); +} + START_TEST(itemdlg) { OleInitialize(NULL); @@ -2583,6 +2933,7 @@ START_TEST(itemdlg) test_overwrite(); test_customize_remove_from_empty_combobox(); test_double_show(); + test_control_events_selection(); } else skip("Skipping all Item Dialog tests.\n"); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10193
Esme Povirk (@madewokherd) commented about dlls/comdlg32/tests/itemdlg.c:
+ ok(dwIDCtl == This->button_id, "Expected button ID %lu, got %lu\n", This->button_id, dwIDCtl); + + hr = IFileDialogCustomize_QueryInterface(pfdc, &IID_IServiceProvider, (void**)&psp); + ok(hr == S_OK, "QI for IServiceProvider failed: 0x%08lx\n", hr); + if (FAILED(hr)) + { + return S_OK; + } + + hr = IServiceProvider_QueryService(psp, &IID_IFolderView, &IID_IFolderView2, (void**)&pfv2); + ok(hr == S_OK, "QueryService for IFolderView2 failed: 0x%08lx\n", hr); + if (SUCCEEDED(hr)) + { + psia = NULL; + hr = IFolderView2_GetSelection(pfv2, TRUE, &psia); + todo_wine_if(hr == E_NOTIMPL) `todo_wine_if` should not depend on the result of the thing we're testing. Since Wine is theoretically fixed by the same patch, this todo should be removed.
(If Wine were not fixed by the same patch, we'd want a regular `todo_wine`, to be removed when Wine is fixed.) -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10193#note_130976
participants (3)
-
Esme Povirk (@madewokherd) -
pan hui (@panhui) -
panhui