Stub added for the IEnumObjects interface, so that programs won't crash when calling it.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53620
-- v3: shell32: Added stub for IObjectCollection interface.
From: Kevin Martinez 137180189+kevinrmartinez@users.noreply.github.com
--- dlls/shell32/Makefile.in | 1 + dlls/shell32/enumobjects.c | 163 +++++++++++++++++++++++++++++++ dlls/shell32/shell32_classes.idl | 5 + dlls/shell32/shell32_main.h | 1 + dlls/shell32/shellole.c | 1 + include/shobjidl.idl | 18 ++++ 6 files changed, 189 insertions(+) create mode 100644 dlls/shell32/enumobjects.c
diff --git a/dlls/shell32/Makefile.in b/dlls/shell32/Makefile.in index 4a906ac59db..c2df32b62ec 100644 --- a/dlls/shell32/Makefile.in +++ b/dlls/shell32/Makefile.in @@ -21,6 +21,7 @@ SOURCES = \ dragdrophelper.c \ ebrowser.c \ enumidlist.c \ + enumobjects.c \ folders.c \ iconcache.c \ new_menu.c \ diff --git a/dlls/shell32/enumobjects.c b/dlls/shell32/enumobjects.c new file mode 100644 index 00000000000..7175e22de4d --- /dev/null +++ b/dlls/shell32/enumobjects.c @@ -0,0 +1,163 @@ + /* + * IEnumObjects + * + * Copyright 2024 Kevin Martinez + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> + +#define COBJMACROS + +#include "wine/debug.h" +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "shlwapi.h" + +#include "shell32_main.h" + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +struct enum_objects +{ + IEnumObjects IEnumObjects_iface; + LONG ref; +}; + +static inline struct enum_objects *impl_from_IEnumObjects(IEnumObjects *iface) +{ + return CONTAINING_RECORD(iface, struct enum_objects, IEnumObjects_iface); +} + +static HRESULT WINAPI enum_objects_QueryInterface(IEnumObjects *iface, REFIID riid, void **obj) +{ + struct enum_objects *This = impl_from_IEnumObjects(iface); + + TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), obj); + + if (IsEqualIID(&IID_IUnknown, riid) || + IsEqualIID(&IID_IEnumObjects, riid)) + { + *obj = &This->IEnumObjects_iface; + } + else + { + WARN("no interface for %s\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*obj); + return S_OK; +} + +static ULONG WINAPI enum_objects_AddRef(IEnumObjects *iface) +{ + struct enum_objects *This = impl_from_IEnumObjects(iface); + ULONG refcount = InterlockedIncrement(&This->ref); + + TRACE("(%p/%p)->(%lu)\n", This, iface, refcount); + + return refcount; +} + + static ULONG WINAPI enum_objects_Release(IEnumObjects *iface) +{ + struct enum_objects *This = impl_from_IEnumObjects(iface); + ULONG refcount = InterlockedDecrement(&This->ref); + + TRACE("(%p/%p)->(%lu)\n", This, iface, refcount); + + if (!refcount) + { + free(This); + } + + return refcount; +} + +static HRESULT WINAPI enum_objects_Next(IEnumObjects *iface, ULONG celt, REFIID riid, void **rgelt, ULONG *celtFetched) +{ + struct enum_objects *This = impl_from_IEnumObjects(iface); + + FIXME("(%p/%p %ld, %p)->(%p, %p): stub!\n", This, iface, celt, debugstr_guid(riid), rgelt, celtFetched); + + if (celtFetched) + celtFetched = 0; + + return S_FALSE; +} + +static HRESULT WINAPI enum_objects_Skip(IEnumObjects *iface, ULONG celt) +{ + struct enum_objects *This = impl_from_IEnumObjects(iface); + + FIXME("(%p/%p %ld): stub!\n", This, iface, celt); + + return E_NOTIMPL; +} + +static HRESULT WINAPI enum_objects_Reset(IEnumObjects *iface) +{ + struct enum_objects *This = impl_from_IEnumObjects(iface); + + FIXME("(%p/%p): stub!\n", This, iface); + + return E_NOTIMPL; +} + +static HRESULT WINAPI enum_objects_Clone(IEnumObjects *iface, IEnumObjects **ppenum) +{ + struct enum_objects *This = impl_from_IEnumObjects(iface); + + FIXME("(%p/%p)->(%p): stub!\n",This, iface, ppenum); + + return E_NOTIMPL; +} + +static const IEnumObjectsVtbl enum_objects_vtbl = +{ + enum_objects_QueryInterface, + enum_objects_AddRef, + enum_objects_Release, + enum_objects_Next, + enum_objects_Skip, + enum_objects_Reset, + enum_objects_Clone, +}; + +HRESULT WINAPI IEnumObjects_Constructor(IUnknown *outer, REFIID riid, void **obj) +{ + struct enum_objects *This; + + TRACE("(%p, %s, %p)\n", outer, debugstr_guid(riid), obj); + + if (outer) + return CLASS_E_NOAGGREGATION; + + if (!(This = heap_alloc(sizeof(*This)))) + return E_OUTOFMEMORY; + + This->ref = 1; + This->IEnumObjects_iface.lpVtbl = &enum_objects_vtbl; + + hr = IEnumObjects_QueryInterface(&This->IEnumObjects_iface, riid, obj); + IEnumObjects_Release(&This->IEnumObjects_iface); + return hr; +} diff --git a/dlls/shell32/shell32_classes.idl b/dlls/shell32/shell32_classes.idl index 135ef52f7b0..872ecb31630 100644 --- a/dlls/shell32/shell32_classes.idl +++ b/dlls/shell32/shell32_classes.idl @@ -189,3 +189,8 @@ coclass KnownFolderManager { interface IKnownFolderManager; } uuid(d969a300-e7ff-11d0-a93b-00a0c90f2719) ] coclass NewMenu {} + +[ + threading(apartment), + uuid(2d3468c1-36a7-43b6-ac24-d3f02fd9607a) +] coclass EnumerableObjectCollection { interface IEnumObjects; } diff --git a/dlls/shell32/shell32_main.h b/dlls/shell32/shell32_main.h index 6b5575c6879..b25cba56317 100644 --- a/dlls/shell32/shell32_main.h +++ b/dlls/shell32/shell32_main.h @@ -103,6 +103,7 @@ HRESULT WINAPI ExplorerBrowser_Constructor(IUnknown *pUnkOuter, REFIID riid, LPV HRESULT WINAPI KnownFolderManager_Constructor(IUnknown *pUnkOuter, REFIID riid, LPVOID *ppv); HRESULT WINAPI IFileOperation_Constructor(IUnknown *outer, REFIID riid, void **out); HRESULT WINAPI ActiveDesktop_Constructor(IUnknown *outer, REFIID riid, void **out); +HRESULT WINAPI IEnumObjects_Constructor(IUnknown *outer, REFIID riid, void **obj);
extern HRESULT CPanel_GetIconLocationW(LPCITEMIDLIST, LPWSTR, UINT, int*); HRESULT WINAPI CPanel_ExtractIconA(LPITEMIDLIST pidl, LPCSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize); diff --git a/dlls/shell32/shellole.c b/dlls/shell32/shellole.c index aa9bd3e0f3e..b9cf6e633a0 100644 --- a/dlls/shell32/shellole.c +++ b/dlls/shell32/shellole.c @@ -87,6 +87,7 @@ static const struct { {&CLSID_ShellImageDataFactory, ShellImageDataFactory_Constructor}, {&CLSID_FileOperation, IFileOperation_Constructor}, {&CLSID_ActiveDesktop, ActiveDesktop_Constructor}, + {&CLSID_EnumerableObjectCollection, IEnumObjects_Constructor}, {NULL, NULL} };
diff --git a/include/shobjidl.idl b/include/shobjidl.idl index 886cff89ef9..bb87fc31587 100644 --- a/include/shobjidl.idl +++ b/include/shobjidl.idl @@ -4126,3 +4126,21 @@ interface IFileOperation : IUnknown HRESULT PerformOperations(); HRESULT GetAnyOperationsAborted([out] BOOL *aborted); } + +[ + object, + uuid(2c1c7e2e-2d0e-4059-831e-1e6f82335c2e), + pointer_default(unique) +] +interface IEnumObjects : IUnknown +{ + HRESULT Next( + [in] ULONG celt, + [in] REFIID riid, + [out, iid_is(riid)] void **rgelt, + [out, optional] ULONG *pceltFetched ); + + HRESULT Skip([in] ULONG celt); + HRESULT Reset(); + HRESULT Clone([out] IEnumObjects **ppenum); +}
From: Kevin Martinez 137180189+kevinrmartinez@users.noreply.github.com
--- dlls/shell32/enumobjects.c | 122 +++++++++++++++++++++++++++++++++--- dlls/shell32/shell32_main.h | 2 +- dlls/shell32/shellole.c | 2 +- 3 files changed, 114 insertions(+), 12 deletions(-)
diff --git a/dlls/shell32/enumobjects.c b/dlls/shell32/enumobjects.c index 7175e22de4d..2b22e6080f1 100644 --- a/dlls/shell32/enumobjects.c +++ b/dlls/shell32/enumobjects.c @@ -1,5 +1,5 @@ /* - * IEnumObjects + * EnumerableObjectCollection * * Copyright 2024 Kevin Martinez * @@ -37,6 +37,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(shell); struct enum_objects { IEnumObjects IEnumObjects_iface; + IObjectCollection IObjectCollection_iface; LONG ref; };
@@ -45,26 +46,37 @@ static inline struct enum_objects *impl_from_IEnumObjects(IEnumObjects *iface) return CONTAINING_RECORD(iface, struct enum_objects, IEnumObjects_iface); }
+static inline struct enum_objects *impl_from_IObjectCollection(IObjectCollection *iface) +{ + return CONTAINING_RECORD(iface, struct enum_objects, IObjectCollection_iface); +} + static HRESULT WINAPI enum_objects_QueryInterface(IEnumObjects *iface, REFIID riid, void **obj) { struct enum_objects *This = impl_from_IEnumObjects(iface);
TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), obj);
- if (IsEqualIID(&IID_IUnknown, riid) || - IsEqualIID(&IID_IEnumObjects, riid)) + *obj = NULL; + + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumObjects)) { *obj = &This->IEnumObjects_iface; } - else + else if (IsEqualIID(riid, &IID_IObjectCollection) || IsEqualIID(riid, &IID_IObjectArray)) { - WARN("no interface for %s\n", debugstr_guid(riid)); - *obj = NULL; - return E_NOINTERFACE; + *obj = &This->IObjectCollection_iface; }
- IUnknown_AddRef((IUnknown*)*obj); - return S_OK; + if (*obj) + { + IUnknown_AddRef((IUnknown*)*obj); + return S_OK; + } + + FIXME("No interface for %s\n", debugstr_guid(riid)); + + return E_NOINTERFACE; }
static ULONG WINAPI enum_objects_AddRef(IEnumObjects *iface) @@ -142,9 +154,98 @@ static const IEnumObjectsVtbl enum_objects_vtbl = enum_objects_Clone, };
-HRESULT WINAPI IEnumObjects_Constructor(IUnknown *outer, REFIID riid, void **obj) +static HRESULT WINAPI object_collection_QueryInterface(IObjectCollection *iface, REFIID riid, void **obj) +{ + struct enum_objects *This = impl_from_IObjectCollection(iface); + return IEnumObjects_QueryInterface(&This->IEnumObjects_iface, riid, obj); +} + +static ULONG WINAPI object_collection_AddRef(IObjectCollection *iface) +{ + struct enum_objects *This = impl_from_IObjectCollection(iface); + return IEnumObjects_AddRef(&This->IEnumObjects_iface); +} + +static ULONG WINAPI object_collection_Release(IObjectCollection *iface) +{ + struct enum_objects *This = impl_from_IObjectCollection(iface); + return IEnumObjects_Release(&This->IEnumObjects_iface); +} + +static HRESULT WINAPI object_collection_GetCount(IObjectCollection *iface, UINT *count) +{ + struct enum_objects *This = impl_from_IObjectCollection(iface); + + FIXME("(%p/%p)->(%n): stub!\n", This, iface, count); + + if (count) + count = 0; + + return S_FALSE; +} + +static HRESULT WINAPI object_collection_GetAt(IObjectCollection *iface, UINT index, REFIID riid, void **obj) +{ + struct enum_objects *This = impl_from_IObjectCollection(iface); + + FIXME("(%p/%p %d, %s)->(%p): stub!\n", This, iface, index, debugstr_guid(riid), obj); + + return E_NOTIMPL; +} + +static HRESULT WINAPI object_collection_AddObject(IObjectCollection *iface, IUnknown *obj) +{ + struct enum_objects *This = impl_from_IObjectCollection(iface); + + FIXME("(%p/%p %p): stub!\n", This, iface, obj); + + return E_NOTIMPL; +} + +static HRESULT WINAPI object_collection_AddFromArray(IObjectCollection *iface, IObjectArray *source_array) +{ + struct enum_objects *This = impl_from_IObjectCollection(iface); + + FIXME("(%p/%p %p): stub!\n", This, iface, source_array); + + return E_NOTIMPL; +} + +static HRESULT WINAPI object_collection_RemoveObjectAt(IObjectCollection *iface, UINT index) +{ + struct enum_objects *This = impl_from_IObjectCollection(iface); + + FIXME("(%p/%p %i): stub!\n", This, iface, index); + + return E_NOTIMPL; +} + +static HRESULT WINAPI object_collection_Clear(IObjectCollection *iface) +{ + struct enum_objects *This = impl_from_IObjectCollection(iface); + + FIXME("(%p/%p): stub!\n", This, iface); + + return E_NOTIMPL; +} + +static const IObjectCollectionVtbl object_collection_vtbl = +{ + object_collection_QueryInterface, + object_collection_AddRef, + object_collection_Release, + object_collection_GetCount, + object_collection_GetAt, + object_collection_AddObject, + object_collection_AddFromArray, + object_collection_RemoveObjectAt, + object_collection_Clear +}; + +HRESULT WINAPI EnumerableObjectCollection_Constructor(IUnknown *outer, REFIID riid, void **obj) { struct enum_objects *This; + HRESULT hr;
TRACE("(%p, %s, %p)\n", outer, debugstr_guid(riid), obj);
@@ -156,6 +257,7 @@ HRESULT WINAPI IEnumObjects_Constructor(IUnknown *outer, REFIID riid, void **obj
This->ref = 1; This->IEnumObjects_iface.lpVtbl = &enum_objects_vtbl; + This->IObjectCollection_iface.lpVtbl = &object_collection_vtbl;
hr = IEnumObjects_QueryInterface(&This->IEnumObjects_iface, riid, obj); IEnumObjects_Release(&This->IEnumObjects_iface); diff --git a/dlls/shell32/shell32_main.h b/dlls/shell32/shell32_main.h index b25cba56317..c4b301f500a 100644 --- a/dlls/shell32/shell32_main.h +++ b/dlls/shell32/shell32_main.h @@ -103,7 +103,7 @@ HRESULT WINAPI ExplorerBrowser_Constructor(IUnknown *pUnkOuter, REFIID riid, LPV HRESULT WINAPI KnownFolderManager_Constructor(IUnknown *pUnkOuter, REFIID riid, LPVOID *ppv); HRESULT WINAPI IFileOperation_Constructor(IUnknown *outer, REFIID riid, void **out); HRESULT WINAPI ActiveDesktop_Constructor(IUnknown *outer, REFIID riid, void **out); -HRESULT WINAPI IEnumObjects_Constructor(IUnknown *outer, REFIID riid, void **obj); +HRESULT WINAPI EnumerableObjectCollection_Constructor(IUnknown *outer, REFIID riid, void **obj);
extern HRESULT CPanel_GetIconLocationW(LPCITEMIDLIST, LPWSTR, UINT, int*); HRESULT WINAPI CPanel_ExtractIconA(LPITEMIDLIST pidl, LPCSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize); diff --git a/dlls/shell32/shellole.c b/dlls/shell32/shellole.c index b9cf6e633a0..fc3f6b032cd 100644 --- a/dlls/shell32/shellole.c +++ b/dlls/shell32/shellole.c @@ -87,7 +87,7 @@ static const struct { {&CLSID_ShellImageDataFactory, ShellImageDataFactory_Constructor}, {&CLSID_FileOperation, IFileOperation_Constructor}, {&CLSID_ActiveDesktop, ActiveDesktop_Constructor}, - {&CLSID_EnumerableObjectCollection, IEnumObjects_Constructor}, + {&CLSID_EnumerableObjectCollection, EnumerableObjectCollection_Constructor}, {NULL, NULL} };
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=147322
Your paranoid android.
=== debian11 (32 bit report) ===
Report validation errors: shell32:shelllink crashed (c0000005)
On Wed Jul 24 21:17:51 2024 +0000, Kevin Martinez wrote:
changed this line in [version 2 of the diff](/wine/wine/-/merge_requests/6130/diffs?diff_id=123639&start_sha=2fbe5633507f80116671c4aed0d834de4369f9ff#9718da1edbba0f34e8a2e9e282c5e291ab926c91_157_129)
Changed to FIXME
The merge request was extended, and another commit added to fix a major bug [related to GUIDs](https://gitlab.winehq.org/wine/wine/-/merge_requests/6130#note_76721) and other minor fixes. With stubs for both interfaces the games mentioned [on this thread](https://gitlab.winehq.org/wine/wine/-/merge_requests/6130#note_76698) now work without further patches.
Alfred Agrell (@Alcaro) commented about dlls/shell32/enumobjects.c:
celtFetched = 0;
- return S_FALSE;
}
-/**************************************************************************
- IEnumObjects::Skip
- */
-static HRESULT WINAPI IEnumObjects_fnSkip(IEnumObjects *iface, ULONG celt) +static HRESULT WINAPI enum_objects_Skip(IEnumObjects *iface, ULONG celt) {
- IEnumObjectsImpl *This = impl_from_IEnumObjects(iface);
- struct enum_objects *This = impl_from_IEnumObjects(iface);
- FIXME("(%p)->(%ld): stud!\n", This, celt);
- FIXME("(%p/%p %ld): stub!\n", This, iface, celt);
Trailing whitespace. I think our CI complains about that.
Alfred Agrell (@Alcaro) commented about dlls/shell32/enumobjects.c:
- /*
Is that line supposed to be indented?
Alfred Agrell (@Alcaro) commented about dlls/shell32/enumobjects.c:
- /*
- EnumerableObjectCollection
Trailing whitespace. I think our CI complains about that.
Alfred Agrell (@Alcaro) commented about dlls/shell32/enumobjects.c:
+#include "wine/debug.h" +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "shlwapi.h"
+#include "shell32_main.h"
+WINE_DEFAULT_DEBUG_CHANNEL(shell);
+struct enum_objects +{
- IEnumObjects IEnumObjects_iface;
- IObjectCollection IObjectCollection_iface;
- LONG ref;
If you're adding a member with a longer type, you should probably add more spaces to all existing ones, so it still lines up.
(Alternatively flatten the whitespace, so nothing lines up. It's better than being inconsistent.)
Alfred Agrell (@Alcaro) commented about dlls/shell32/enumobjects.c:
+{
- struct enum_objects *This = impl_from_IEnumObjects(iface);
- FIXME("(%p/%p %ld, %p)->(%p, %p): stub!\n", This, iface, celt, debugstr_guid(riid), rgelt, celtFetched);
- if (celtFetched)
celtFetched = 0;
- return S_FALSE;
+}
+static HRESULT WINAPI enum_objects_Skip(IEnumObjects *iface, ULONG celt) +{
- struct enum_objects *This = impl_from_IEnumObjects(iface);
- FIXME("(%p/%p %ld): stub!\n", This, iface, celt);
Trailing whitespace here too. (There may be a duplicate comment on this line, gitlab glitched out somehow and I can't determine if the duplicate actually exists or not.)
Alfred Agrell (@Alcaro) commented about dlls/shell32/enumobjects.c:
- if (!refcount)
- {
free(This);
- }
- return refcount;
+}
+static HRESULT WINAPI enum_objects_Next(IEnumObjects *iface, ULONG celt, REFIID riid, void **rgelt, ULONG *celtFetched) +{
- struct enum_objects *This = impl_from_IEnumObjects(iface);
- FIXME("(%p/%p %ld, %p)->(%p, %p): stub!\n", This, iface, celt, debugstr_guid(riid), rgelt, celtFetched);
- if (celtFetched)
celtFetched = 0;
Mayhaps you forgot an asterisk, perchance?
Alfred Agrell (@Alcaro) commented about dlls/shell32/enumobjects.c:
- return IEnumObjects_AddRef(&This->IEnumObjects_iface);
+}
+static ULONG WINAPI object_collection_Release(IObjectCollection *iface) +{
- struct enum_objects *This = impl_from_IObjectCollection(iface);
- return IEnumObjects_Release(&This->IEnumObjects_iface);
+}
+static HRESULT WINAPI object_collection_GetCount(IObjectCollection *iface, UINT *count) +{
- struct enum_objects *This = impl_from_IObjectCollection(iface);
- FIXME("(%p/%p)->(%n): stub!\n", This, iface, count);
- if (count)
I don't think that argument is optional. Better delete this check and just segfault, unless winetest says otherwise.
Yep, much better. Looks good to me, other than these nitpicks. I would appreciate seeing some tests for this stuff, but I won't insist on it. (I'm not sure if my approval is worth anything, anyways.)
Oh, and Wine-Bugs isn't a thing. It's supposed to be machine readable, better use Wine-Bug twice.
I don't think anything cares about MR descriptions, but keep it in mind for commit messages. (No need to worry about these commits, though; they fix one bug each.)