[PATCH 0/1] MR11700: windows.storage.applicationdata: Implement IApplicationData local/roaming/temporary folders.
Implement IApplicationData::get_LocalFolder(), get_RoamingFolder() and get_TemporaryFolder() by returning a minimal IStorageFolder backed by a real directory, instead of the current E_NOTIMPL stub. Needed for SteelSeries GG, whose GGEZ.exe uses Microsoft.Data.Sqlite, which probes Windows.Storage.ApplicationData at startup to detect whether it's running in a packaged (UWP) context. Under Wine the ApplicationData object is obtained successfully, but querying any of these folder properties throws a NotImplementedException that isn't caught by the caller, crashing the whole process before it gets a chance to run. Signed-off-by: Jaco van Zyl <jvanzyl5@outlook.com> (pyr0hax) -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11700
From: Jaco van Zyl <jvanzyl5@outlook.com> Implement IApplicationData::get_LocalFolder(), get_RoamingFolder() and get_TemporaryFolder() by returning a minimal IStorageFolder backed by a real directory, instead of the current E_NOTIMPL stub. Needed for SteelSeries GG, whose GGEZ.exe uses Microsoft.Data.Sqlite, which probes Windows.Storage.ApplicationData at startup to detect whether it's running in a packaged (UWP) context. Under Wine the ApplicationData object is obtained successfully, but querying any of these folder properties throws a NotImplementedException that isn't caught by the caller, crashing the whole process before it gets a chance to run. Signed-off-by: Jaco van Zyl <jvanzyl5@outlook.com> (pyr0hax) --- .../applicationdata.c | 413 +++++++++++++++++- 1 file changed, 405 insertions(+), 8 deletions(-) diff --git a/dlls/windows.storage.applicationdata/applicationdata.c b/dlls/windows.storage.applicationdata/applicationdata.c index dbe42b3a8d6..eb8b171cab0 100644 --- a/dlls/windows.storage.applicationdata/applicationdata.c +++ b/dlls/windows.storage.applicationdata/applicationdata.c @@ -29,11 +29,404 @@ struct application_data_statics LONG ref; }; +struct storage_folder +{ + IStorageFolder IStorageFolder_iface; + IStorageItem IStorageItem_iface; + LONG ref; + WCHAR path[MAX_PATH]; +}; + +static inline struct storage_folder *impl_from_IStorageFolder( IStorageFolder *iface ) +{ + return CONTAINING_RECORD( iface, struct storage_folder, IStorageFolder_iface ); +} + +static inline struct storage_folder *impl_from_IStorageItem( IStorageItem *iface ) +{ + return CONTAINING_RECORD( iface, struct storage_folder, IStorageItem_iface ); +} + static inline struct application_data_statics *impl_from_IActivationFactory( IActivationFactory *iface ) { return CONTAINING_RECORD( iface, struct application_data_statics, IActivationFactory_iface ); } +static HRESULT WINAPI storage_folder_QueryInterface( IStorageFolder *iface, REFIID iid, void **out ) +{ + struct storage_folder *impl = impl_from_IStorageFolder( iface ); + + TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, &IID_IStorageFolder )) + { + *out = &impl->IStorageFolder_iface; + IInspectable_AddRef( *out ); + return S_OK; + } + + if (IsEqualGUID( iid, &IID_IStorageItem )) + { + *out = &impl->IStorageItem_iface; + IInspectable_AddRef( *out ); + return S_OK; + } + + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI storage_folder_AddRef( IStorageFolder *iface ) +{ + struct storage_folder *impl = impl_from_IStorageFolder( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + + TRACE( "iface %p increasing refcount to %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI storage_folder_Release( IStorageFolder *iface ) +{ + struct storage_folder *impl = impl_from_IStorageFolder( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + + TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref ); + + if (!ref) free( impl ); + return ref; +} + +static ULONG WINAPI storage_item_AddRef( IStorageItem *iface ) +{ + struct storage_folder *impl = impl_from_IStorageItem( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + + TRACE( "iface %p increasing refcount to %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI storage_item_Release( IStorageItem *iface ) +{ + struct storage_folder *impl = impl_from_IStorageItem( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + + TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref ); + + if (!ref) free( impl ); + return ref; +} + +static HRESULT WINAPI storage_folder_GetIids( IStorageFolder *iface, ULONG *iid_count, IID **iids ) +{ + FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids ); + return E_NOTIMPL; +} + +static HRESULT WINAPI storage_folder_GetRuntimeClassName( IStorageFolder *iface, HSTRING *class_name ) +{ + FIXME( "iface %p, class_name %p stub!\n", iface, class_name ); + return E_NOTIMPL; +} + +static HRESULT WINAPI storage_folder_GetTrustLevel( IStorageFolder *iface, TrustLevel *trust_level ) +{ + FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level ); + return E_NOTIMPL; +} + +static HRESULT WINAPI storage_item_GetIids( IStorageItem *iface, ULONG *iid_count, IID **iids ) +{ + FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids ); + return E_NOTIMPL; +} + +static HRESULT WINAPI storage_item_GetRuntimeClassName( IStorageItem *iface, HSTRING *class_name ) +{ + FIXME( "iface %p, class_name %p stub!\n", iface, class_name ); + return E_NOTIMPL; +} + +static HRESULT WINAPI storage_item_GetTrustLevel( IStorageItem *iface, TrustLevel *trust_level ) +{ + FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level ); + return E_NOTIMPL; +} + +static HRESULT WINAPI storage_folder_CreateFileAsyncOverloadDefaultOptions( + IStorageFolder *iface, HSTRING name, + __FIAsyncOperation_1_Windows__CStorage__CStorageFile **operation ) +{ + FIXME( "iface %p, name %p, operation %p stub!\n", iface, name, operation ); + return E_NOTIMPL; +} + +static HRESULT WINAPI storage_folder_CreateFileAsync( + IStorageFolder *iface, HSTRING name, + __x_ABI_CWindows_CStorage_CCreationCollisionOption options, + __FIAsyncOperation_1_Windows__CStorage__CStorageFile **operation ) +{ + FIXME( "iface %p, name %p, options %d, operation %p stub!\n", + iface, name, options, operation ); + return E_NOTIMPL; +} + +static HRESULT WINAPI storage_folder_CreateFolderAsyncOverloadDefaultOptions( + IStorageFolder *iface, HSTRING name, + __FIAsyncOperation_1_Windows__CStorage__CStorageFolder **operation ) +{ + FIXME( "iface %p, name %p, operation %p stub!\n", iface, name, operation ); + return E_NOTIMPL; +} + +static HRESULT WINAPI storage_folder_CreateFolderAsync( + IStorageFolder *iface, HSTRING name, + __x_ABI_CWindows_CStorage_CCreationCollisionOption options, + __FIAsyncOperation_1_Windows__CStorage__CStorageFolder **operation ) +{ + FIXME( "iface %p, name %p, options %d, operation %p stub!\n", + iface, name, options, operation ); + return E_NOTIMPL; +} + +static HRESULT WINAPI storage_folder_GetFileAsync( + IStorageFolder *iface, HSTRING name, + __FIAsyncOperation_1_Windows__CStorage__CStorageFile **operation ) +{ + FIXME( "iface %p, name %p, operation %p stub!\n", iface, name, operation ); + return E_NOTIMPL; +} + +static HRESULT WINAPI storage_folder_GetFolderAsync( + IStorageFolder *iface, HSTRING name, + __FIAsyncOperation_1_Windows__CStorage__CStorageFolder **operation ) +{ + FIXME( "iface %p, name %p, operation %p stub!\n", iface, name, operation ); + return E_NOTIMPL; +} + +static HRESULT WINAPI storage_folder_GetItemAsync( + IStorageFolder *iface, HSTRING name, + __FIAsyncOperation_1_Windows__CStorage__CIStorageItem **operation ) +{ + FIXME( "iface %p, name %p, operation %p stub!\n", iface, name, operation ); + return E_NOTIMPL; +} + +static HRESULT WINAPI storage_folder_GetFilesAsyncOverloadDefaultOptionsStartAndCount( + IStorageFolder *iface, + __FIAsyncOperation_1___FIVectorView_1_Windows__CStorage__CStorageFile **operation ) +{ + FIXME( "iface %p, operation %p stub!\n", iface, operation ); + return E_NOTIMPL; +} + +static HRESULT WINAPI storage_folder_GetFoldersAsyncOverloadDefaultOptionsStartAndCount( + IStorageFolder *iface, + __FIAsyncOperation_1___FIVectorView_1_Windows__CStorage__CStorageFolder **operation ) +{ + FIXME( "iface %p, operation %p stub!\n", iface, operation ); + return E_NOTIMPL; +} + +static HRESULT WINAPI storage_folder_GetItemsAsyncOverloadDefaultStartAndCount( + IStorageFolder *iface, + __FIAsyncOperation_1___FIVectorView_1_Windows__CStorage__CIStorageItem **operation ) +{ + FIXME( "iface %p, operation %p stub!\n", iface, operation ); + return E_NOTIMPL; +} + +static HRESULT WINAPI storage_item_get_Path(IStorageItem *iface, HSTRING *value) +{ + struct storage_folder *impl = impl_from_IStorageItem(iface); + + return WindowsCreateString(impl->path, wcslen(impl->path), value); +} + +static HRESULT WINAPI storage_item_get_Name(IStorageItem *iface, HSTRING *value) +{ + struct storage_folder *impl = impl_from_IStorageItem(iface); + const WCHAR *name; + + name = wcsrchr(impl->path, '\\'); + if (name) + name++; + else + name = impl->path; + + return WindowsCreateString(name, wcslen(name), value); +} + +static HRESULT WINAPI storage_item_get_Attributes( + IStorageItem *iface, + __x_ABI_CWindows_CStorage_CFileAttributes *value) +{ + *value = 0x10; + return S_OK; +} + +static HRESULT WINAPI storage_item_get_DateCreated( + IStorageItem *iface, + __x_ABI_CWindows_CFoundation_CDateTime *value) +{ + value->UniversalTime = 0; + return S_OK; +} + +static HRESULT WINAPI storage_item_IsOfType( + IStorageItem *iface, + __x_ABI_CWindows_CStorage_CStorageItemTypes type, + boolean *value) +{ + *value = (type & 0x1) != 0; + return S_OK; +} + +static const struct IStorageFolderVtbl storage_folder_vtbl = +{ + storage_folder_QueryInterface, + storage_folder_AddRef, + storage_folder_Release, + storage_folder_GetIids, + storage_folder_GetRuntimeClassName, + storage_folder_GetTrustLevel, + storage_folder_CreateFileAsyncOverloadDefaultOptions, + storage_folder_CreateFileAsync, + storage_folder_CreateFolderAsyncOverloadDefaultOptions, + storage_folder_CreateFolderAsync, + storage_folder_GetFileAsync, + storage_folder_GetFolderAsync, + storage_folder_GetItemAsync, + storage_folder_GetFilesAsyncOverloadDefaultOptionsStartAndCount, + storage_folder_GetFoldersAsyncOverloadDefaultOptionsStartAndCount, + storage_folder_GetItemsAsyncOverloadDefaultStartAndCount +}; + +static HRESULT WINAPI storage_item_RenameAsyncOverloadDefaultOptions( + IStorageItem *iface, HSTRING name, + __x_ABI_CWindows_CFoundation_CIAsyncAction **operation ) +{ + FIXME( "iface %p, name %p, operation %p stub!\n", iface, name, operation ); + return E_NOTIMPL; +} + +static HRESULT WINAPI storage_item_RenameAsync( + IStorageItem *iface, HSTRING name, + __x_ABI_CWindows_CStorage_CNameCollisionOption option, + __x_ABI_CWindows_CFoundation_CIAsyncAction **operation ) +{ + FIXME( "iface %p, name %p, option %d, operation %p stub!\n", + iface, name, option, operation ); + return E_NOTIMPL; +} + +static HRESULT WINAPI storage_item_DeleteAsyncOverloadDefaultOptions( + IStorageItem *iface, + __x_ABI_CWindows_CFoundation_CIAsyncAction **operation ) +{ + FIXME( "iface %p, operation %p stub!\n", iface, operation ); + return E_NOTIMPL; +} + +static HRESULT WINAPI storage_item_DeleteAsync( + IStorageItem *iface, + __x_ABI_CWindows_CStorage_CStorageDeleteOption option, + __x_ABI_CWindows_CFoundation_CIAsyncAction **operation ) +{ + FIXME( "iface %p, option %d, operation %p stub!\n", + iface, option, operation ); + return E_NOTIMPL; +} + +static HRESULT WINAPI storage_item_GetBasicPropertiesAsync( + IStorageItem *iface, + __FIAsyncOperation_1_Windows__CStorage__CFileProperties__CBasicProperties **operation ) +{ + FIXME( "iface %p, operation %p stub!\n", iface, operation ); + return E_NOTIMPL; +} + +static HRESULT WINAPI storage_item_QueryInterface( IStorageItem *iface, REFIID iid, void **out ) +{ + struct storage_folder *impl = impl_from_IStorageItem( iface ); + + TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, &IID_IStorageItem )) + { + *out = &impl->IStorageItem_iface; + IInspectable_AddRef( *out ); + return S_OK; + } + + if (IsEqualGUID( iid, &IID_IStorageFolder )) + { + *out = &impl->IStorageFolder_iface; + IInspectable_AddRef( *out ); + return S_OK; + } + + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static const struct IStorageItemVtbl storage_item_vtbl = +{ + storage_item_QueryInterface, + storage_item_AddRef, + storage_item_Release, + storage_item_GetIids, + storage_item_GetRuntimeClassName, + storage_item_GetTrustLevel, + storage_item_RenameAsyncOverloadDefaultOptions, + storage_item_RenameAsync, + storage_item_DeleteAsyncOverloadDefaultOptions, + storage_item_DeleteAsync, + storage_item_GetBasicPropertiesAsync, + storage_item_get_Name, + storage_item_get_Path, + storage_item_get_Attributes, + storage_item_get_DateCreated, + storage_item_IsOfType +}; + + +static HRESULT create_storage_folder(const WCHAR *path, IStorageFolder **value) +{ + struct storage_folder *impl; + + if (!(impl = calloc(1, sizeof(*impl)))) + return E_OUTOFMEMORY; + + impl->IStorageFolder_iface.lpVtbl = &storage_folder_vtbl; + impl->IStorageItem_iface.lpVtbl = &storage_item_vtbl; + impl->ref = 1; + lstrcpynW(impl->path, path, ARRAY_SIZE(impl->path)); + + *value = &impl->IStorageFolder_iface; + return S_OK; +} + +static void get_data_folder_path(const WCHAR *env_var, const WCHAR *subdir, + WCHAR *path, DWORD path_len) +{ + if (!GetEnvironmentVariableW(env_var, path, path_len) && + !GetEnvironmentVariableW(L"TEMP", path, path_len)) + lstrcpynW(path, L"C:\\", path_len); + + lstrcatW(path, L"\\"); + lstrcatW(path, subdir); + CreateDirectoryW(path, NULL); +} + static HRESULT WINAPI factory_QueryInterface( IActivationFactory *iface, REFIID iid, void **out ) { struct application_data_statics *impl = impl_from_IActivationFactory( iface ); @@ -221,24 +614,28 @@ static HRESULT WINAPI application_data_get_RoamingSettings( IApplicationData *if return E_NOTIMPL; } -static HRESULT WINAPI application_data_get_LocalFolder( IApplicationData *iface, IStorageFolder **value ) +static HRESULT WINAPI application_data_get_LocalFolder( IApplicationData *iface, IStorageFolder **value) { - FIXME( "iface %p, value %p stub!\n", iface, value ); - return E_NOTIMPL; + WCHAR path[MAX_PATH]; + get_data_folder_path( L"LOCALAPPDATA", L"Local", path, ARRAY_SIZE(path) ); + return create_storage_folder( path, value ); } static HRESULT WINAPI application_data_get_RoamingFolder( IApplicationData *iface, IStorageFolder **value ) { - FIXME( "iface %p, value %p stub!\n", iface, value ); - return E_NOTIMPL; + WCHAR path[MAX_PATH]; + get_data_folder_path( L"APPDATA", L"Roaming",path, ARRAY_SIZE(path) ); + return create_storage_folder( path, value ); } -static HRESULT WINAPI application_data_get_TemporaryFolder( IApplicationData *iface, IStorageFolder **value ) +static HRESULT WINAPI application_data_get_TemporaryFolder( IApplicationData *iface, IStorageFolder **value) { - FIXME( "iface %p, value %p stub!\n", iface, value ); - return E_NOTIMPL; + WCHAR path[MAX_PATH]; + get_data_folder_path( L"TEMP", L"Temp",path, ARRAY_SIZE(path) ); + return create_storage_folder( path, value ); } + static HRESULT WINAPI application_data_add_DataChanged( IApplicationData *iface, ITypedEventHandler_ApplicationData_IInspectable *handler, EventRegistrationToken *token ) { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11700
The error that failed on the Linux 32 build is unrelated to my patch {width=900 height=531} -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11700#note_149209
This merge request was approved by Jaco van Zyl. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11700
participants (2)
-
Jaco van Zyl -
Jaco van Zyl (@pyr0hax)