Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=48848 Signed-off-by: Jactry Zeng jzeng@codeweavers.com --- dlls/shell32/shell32_classes.idl | 6 + dlls/shell32/shell32_main.h | 1 + dlls/shell32/shellole.c | 1 + dlls/shell32/shlfileop.c | 249 +++++++++++++++++++++++++++++++ dlls/shell32/tests/shlfileop.c | 37 +++++ 5 files changed, 294 insertions(+)
diff --git a/dlls/shell32/shell32_classes.idl b/dlls/shell32/shell32_classes.idl index 6ed497fea5..f2c5ed4a76 100644 --- a/dlls/shell32/shell32_classes.idl +++ b/dlls/shell32/shell32_classes.idl @@ -166,3 +166,9 @@ coclass KnownFolderManager { interface IKnownFolderManager; } threading(apartment), uuid(66e4e4fb-f385-4dd0-8d74-a2efd1bc6178) ] coclass ShellImageDataFactory { interface IShellImageDataFactory; } + +[ + helpstring("Copy/Move/Rename/Delete/Link Object"), + threading(apartment), + uuid(3ad05575-8857-4850-9277-11b85bdb8e09) +] coclass FileOperation { interface IFileOperation; } diff --git a/dlls/shell32/shell32_main.h b/dlls/shell32/shell32_main.h index 11a96309e8..37c74612c0 100644 --- a/dlls/shell32/shell32_main.h +++ b/dlls/shell32/shell32_main.h @@ -103,6 +103,7 @@ HRESULT WINAPI RecycleBin_Constructor(IUnknown * pUnkOuter, REFIID riif, LPVOID HRESULT WINAPI QueryAssociations_Constructor(IUnknown *pUnkOuter, REFIID riid, LPVOID *ppOutput) DECLSPEC_HIDDEN; HRESULT WINAPI ExplorerBrowser_Constructor(IUnknown *pUnkOuter, REFIID riid, LPVOID *ppv) DECLSPEC_HIDDEN; HRESULT WINAPI KnownFolderManager_Constructor(IUnknown *pUnkOuter, REFIID riid, LPVOID *ppv) DECLSPEC_HIDDEN; +HRESULT WINAPI IFileOperation_Constructor(IUnknown *outer, REFIID riid, void **out) DECLSPEC_HIDDEN; extern HRESULT CPanel_GetIconLocationW(LPCITEMIDLIST, LPWSTR, UINT, int*) DECLSPEC_HIDDEN; HRESULT WINAPI CPanel_ExtractIconA(LPITEMIDLIST pidl, LPCSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize) DECLSPEC_HIDDEN; HRESULT WINAPI CPanel_ExtractIconW(LPITEMIDLIST pidl, LPCWSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize) DECLSPEC_HIDDEN; diff --git a/dlls/shell32/shellole.c b/dlls/shell32/shellole.c index e84402d7bc..3c88642512 100644 --- a/dlls/shell32/shellole.c +++ b/dlls/shell32/shellole.c @@ -89,6 +89,7 @@ static const struct { {&CLSID_Shell, IShellDispatch_Constructor}, {&CLSID_DestinationList, CustomDestinationList_Constructor}, {&CLSID_ShellImageDataFactory, ShellImageDataFactory_Constructor}, + {&CLSID_FileOperation, IFileOperation_Constructor}, {NULL, NULL} };
diff --git a/dlls/shell32/shlfileop.c b/dlls/shell32/shlfileop.c index b941db3914..5a507c3c11 100644 --- a/dlls/shell32/shlfileop.c +++ b/dlls/shell32/shlfileop.c @@ -24,6 +24,8 @@ #include "config.h" #include "wine/port.h"
+#define COBJMACROS + #include <stdarg.h> #include <string.h> #include <ctype.h> @@ -1809,3 +1811,250 @@ HRESULT WINAPI SHMultiFileProperties(IDataObject *pdtobj, DWORD flags) FIXME("stub: %p %u\n", pdtobj, flags); return E_NOTIMPL; } + +struct file_operation +{ + IFileOperation IFileOperation_iface; + LONG ref; +}; + +static inline struct file_operation *impl_from_IFileOperation(IFileOperation *iface) +{ + return CONTAINING_RECORD(iface, struct file_operation, IFileOperation_iface); +} + +static HRESULT WINAPI file_operation_QueryInterface(IFileOperation *iface, REFIID riid, void **out) +{ + struct file_operation *This = impl_from_IFileOperation(iface); + + TRACE("(%p, %s, %p).\n", iface, debugstr_guid(riid), out); + + if (IsEqualIID(&IID_IFileOperation, riid) || + IsEqualIID(&IID_IUnknown, riid)) + *out = &This->IFileOperation_iface; + else + { + FIXME("not implemented for %s.\n", debugstr_guid(riid)); + *out = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*out); + return S_OK; +} + +static ULONG WINAPI file_operation_AddRef(IFileOperation *iface) +{ + struct file_operation *This = impl_from_IFileOperation(iface); + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p): ref=%u.\n", iface, ref); + + return ref; +} + +static ULONG WINAPI file_operation_Release(IFileOperation *iface) +{ + struct file_operation *This = impl_from_IFileOperation(iface); + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p): ref=%u.\n", iface, ref); + + if (!ref) + { + HeapFree(GetProcessHeap(), 0, This); + } + + return ref; +} + +static HRESULT WINAPI file_operation_Advise(IFileOperation *iface, IFileOperationProgressSink *sink, DWORD *cookie) +{ + FIXME("(%p, %p, %p): stub.\n", iface, sink, cookie); + + return E_NOTIMPL; +} + +static HRESULT WINAPI file_operation_Unadvise(IFileOperation *iface, DWORD cookie) +{ + FIXME("(%p, %x): stub.\n", iface, cookie); + + return E_NOTIMPL; +} + +static HRESULT WINAPI file_operation_SetOperationFlags(IFileOperation *iface, DWORD flags) +{ + FIXME("(%p, %x): stub.\n", iface, flags); + + return E_NOTIMPL; +} + +static HRESULT WINAPI file_operation_SetProgressMessage(IFileOperation *iface, LPCWSTR message) +{ + FIXME("(%p, %s): stub.\n", iface, debugstr_w(message)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI file_operation_SetProgressDialog(IFileOperation *iface, IOperationsProgressDialog *dialog) +{ + FIXME("(%p, %p): stub.\n", iface, dialog); + + return E_NOTIMPL; +} + +static HRESULT WINAPI file_operation_SetProperties(IFileOperation *iface, IPropertyChangeArray *array) +{ + FIXME("(%p, %p): stub.\n", iface, array); + + return E_NOTIMPL; +} + +static HRESULT WINAPI file_operation_SetOwnerWindow(IFileOperation *iface, HWND owner) +{ + FIXME("(%p, %p): stub.\n", iface, owner); + + return E_NOTIMPL; +} + +static HRESULT WINAPI file_operation_ApplyPropertiesToItem(IFileOperation *iface, IShellItem *item) +{ + FIXME("(%p, %p): stub.\n", iface, item); + + return E_NOTIMPL; +} + +static HRESULT WINAPI file_operation_ApplyPropertiesToItems(IFileOperation *iface, IUnknown *items) +{ + FIXME("(%p, %p): stub.\n", iface, items); + + return E_NOTIMPL; +} + +static HRESULT WINAPI file_operation_RenameItem(IFileOperation *iface, IShellItem *item, LPCWSTR name, + IFileOperationProgressSink *sink) +{ + FIXME("(%p, %p, %s, %p): stub.\n", iface, item, debugstr_w(name), sink); + + return E_NOTIMPL; +} + +static HRESULT WINAPI file_operation_RenameItems(IFileOperation *iface, IUnknown *items, LPCWSTR name) +{ + FIXME("(%p, %p, %s): stub.\n", iface, items, debugstr_w(name)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI file_operation_MoveItem(IFileOperation *iface, IShellItem *item, IShellItem *folder, + LPCWSTR name, IFileOperationProgressSink *sink) +{ + FIXME("(%p, %p, %p, %s, %p): stub.\n", iface, item, folder, debugstr_w(name), sink); + + return E_NOTIMPL; +} + +static HRESULT WINAPI file_operation_MoveItems(IFileOperation *iface, IUnknown *items, IShellItem *folder) +{ + FIXME("(%p, %p, %p): stub.\n", iface, items, folder); + + return E_NOTIMPL; +} + +static HRESULT WINAPI file_operation_CopyItem(IFileOperation *iface, IShellItem *item, IShellItem *folder, + LPCWSTR name, IFileOperationProgressSink *sink) +{ + FIXME("(%p, %p, %p, %s, %p): stub.\n", iface, item, folder, debugstr_w(name), sink); + + return E_NOTIMPL; +} + +static HRESULT WINAPI file_operation_CopyItems(IFileOperation *iface, IUnknown *items, IShellItem *folder) +{ + FIXME("(%p, %p, %p): stub.\n", iface, items, folder); + + return E_NOTIMPL; +} + +static HRESULT WINAPI file_operation_DeleteItem(IFileOperation *iface, IShellItem *item, + IFileOperationProgressSink *sink) +{ + FIXME("(%p, %p, %p): stub.\n", iface, item, sink); + + return E_NOTIMPL; +} + +static HRESULT WINAPI file_operation_DeleteItems(IFileOperation *iface, IUnknown *items) +{ + FIXME("(%p, %p): stub.\n", iface, items); + + return E_NOTIMPL; +} + +static HRESULT WINAPI file_operation_NewItem(IFileOperation *iface, IShellItem *folder, DWORD attributes, + LPCWSTR name, LPCWSTR template, IFileOperationProgressSink *sink) +{ + FIXME("(%p, %p, %x, %s, %s, %p): stub.\n", iface, folder, attributes, + debugstr_w(name), debugstr_w(template), sink); + + return E_NOTIMPL; +} + +static HRESULT WINAPI file_operation_PerformOperations(IFileOperation *iface) +{ + FIXME("(%p): stub.\n", iface); + + return E_NOTIMPL; +} + +static HRESULT WINAPI file_operation_GetAnyOperationsAborted(IFileOperation *iface, BOOL *aborted) +{ + FIXME("(%p, %p): stub.\n", iface, aborted); + + return E_NOTIMPL; +} + +static const IFileOperationVtbl file_operation_vtbl = +{ + file_operation_QueryInterface, + file_operation_AddRef, + file_operation_Release, + file_operation_Advise, + file_operation_Unadvise, + file_operation_SetOperationFlags, + file_operation_SetProgressMessage, + file_operation_SetProgressDialog, + file_operation_SetProperties, + file_operation_SetOwnerWindow, + file_operation_ApplyPropertiesToItem, + file_operation_ApplyPropertiesToItems, + file_operation_RenameItem, + file_operation_RenameItems, + file_operation_MoveItem, + file_operation_MoveItems, + file_operation_CopyItem, + file_operation_CopyItems, + file_operation_DeleteItem, + file_operation_DeleteItems, + file_operation_NewItem, + file_operation_PerformOperations, + file_operation_GetAnyOperationsAborted +}; + +HRESULT WINAPI IFileOperation_Constructor(IUnknown *outer, REFIID riid, void **out) +{ + struct file_operation *object; + HRESULT hr; + + object = heap_alloc_zero(sizeof(*object)); + if (!object) + return E_OUTOFMEMORY; + + object->IFileOperation_iface.lpVtbl = &file_operation_vtbl; + object->ref = 1; + + hr = IFileOperation_QueryInterface(&object->IFileOperation_iface, riid, out); + IFileOperation_Release(&object->IFileOperation_iface); + + return hr; +} diff --git a/dlls/shell32/tests/shlfileop.c b/dlls/shell32/tests/shlfileop.c index 27c7244042..3aa40ab271 100644 --- a/dlls/shell32/tests/shlfileop.c +++ b/dlls/shell32/tests/shlfileop.c @@ -2697,8 +2697,39 @@ static BOOL is_old_shell32(void) return FALSE; }
+static BOOL is_vista_plus; + +static void test_file_operation(void) +{ + IFileOperation *operation; + IUnknown *unk; + HRESULT hr; + + if (!is_vista_plus) + { + win_skip("IFileOperation isn't supported.\n"); + return; + } + + hr = CoCreateInstance(&CLSID_FileOperation, NULL, CLSCTX_INPROC_SERVER, + &IID_IFileOperation, (void **)&operation); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IFileOperation_QueryInterface(operation, &IID_IUnknown, (void **)&unk); + ok(hr == S_OK, "Got hr %#x.\n", hr); + IUnknown_Release(unk); + + IFileOperation_Release(operation); +} + START_TEST(shlfileop) { + static HRESULT (WINAPI *pSHQueryUserNotificationState)(QUERY_USER_NOTIFICATION_STATE *state); + HMODULE mod = GetModuleHandleA("shell32.dll"); + + pSHQueryUserNotificationState = (void*)GetProcAddress(mod, "SHQueryUserNotificationState"); + is_vista_plus = pSHQueryUserNotificationState != NULL; + clean_after_shfo_tests();
init_shfo_tests(); @@ -2742,4 +2773,10 @@ START_TEST(shlfileop) test_unicode();
test_shlmenu(); + + CoInitialize(NULL); + + test_file_operation(); + + CoUninitialize(); }
On 3/30/20 12:52 PM, Jactry Zeng wrote:
+static void test_file_operation(void) +{
- IFileOperation *operation;
- IUnknown *unk;
- HRESULT hr;
- if (!is_vista_plus)
- {
win_skip("IFileOperation isn't supported.\n");
return;
- }
- hr = CoCreateInstance(&CLSID_FileOperation, NULL, CLSCTX_INPROC_SERVER,
&IID_IFileOperation, (void **)&operation);
- ok(hr == S_OK, "Got hr %#x.\n", hr);
- hr = IFileOperation_QueryInterface(operation, &IID_IUnknown, (void **)&unk);
- ok(hr == S_OK, "Got hr %#x.\n", hr);
- IUnknown_Release(unk);
- IFileOperation_Release(operation);
+}
Will it work if you skipped on object creation instead of using indirectly set condition?
On Mon, Mar 30, 2020 at 10:01 AM Nikolay Sivov nsivov@codeweavers.com wrote:
Will it work if you skipped on object creation instead of using indirectly set condition?
I sent another try. Thanks for review!
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=68462
Your paranoid android.
=== debiant (32 bit report) ===
shell32: shlfileop.c:2716: Test failed: Got hr 0x80040154. Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x0045590c).
Report validation errors: shell32:shlfileop crashed (c0000005)
=== debiant (32 bit French report) ===
shell32: shlfileop.c:2716: Test failed: Got hr 0x80040154. Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x0045590c).
Report validation errors: shell32:shlfileop crashed (c0000005)
=== debiant (32 bit Japanese:Japan report) ===
shell32: shlfileop.c:2716: Test failed: Got hr 0x80040154. Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x0045590c).
Report validation errors: shell32:shlfileop crashed (c0000005)
=== debiant (32 bit Chinese:China report) ===
shell32: shlfileop.c:2716: Test failed: Got hr 0x80040154. Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x0045590c).
Report validation errors: shell32:shlfileop crashed (c0000005)
=== debiant (32 bit WoW report) ===
shell32: shlfileop.c:2716: Test failed: Got hr 0x80040154. Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x0045590c).
Report validation errors: shell32:shlfileop crashed (c0000005)
=== debiant (64 bit WoW report) ===
shell32: shlfileop.c:2716: Test failed: Got hr 0x80040154. Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x0045590c).
Report validation errors: shell32:shlfileop crashed (c0000005)