Signed-off-by: Paul Gofman pgofman@codeweavers.com --- Forza Horizon 4 depends on successfully getting the path for Microsoft.VCLibs.140.00 x64 package by using GetPackagesByPackageFamily(), PackageIdFromFullName(), GetPackagePath(). Since we provide builtin VC runtime 140 in the default prefix it seems reasonable to add the corresponding package info to registry on prefix creation / update.
.../api-ms-win-appmodel-runtime-l1-1-1.spec | 2 +- .../ext-ms-win-kernel32-package-l1-1-1.spec | 2 +- dlls/kernel32/kernel32.spec | 1 + dlls/kernel32/tests/version.c | 173 ++++++++++++++++++ dlls/kernelbase/kernelbase.spec | 2 +- dlls/kernelbase/version.c | 116 ++++++++++++ include/appmodel.h | 31 ++++ 7 files changed, 324 insertions(+), 3 deletions(-)
diff --git a/dlls/api-ms-win-appmodel-runtime-l1-1-1/api-ms-win-appmodel-runtime-l1-1-1.spec b/dlls/api-ms-win-appmodel-runtime-l1-1-1/api-ms-win-appmodel-runtime-l1-1-1.spec index 4c00082a151..99d1d9f3835 100644 --- a/dlls/api-ms-win-appmodel-runtime-l1-1-1/api-ms-win-appmodel-runtime-l1-1-1.spec +++ b/dlls/api-ms-win-appmodel-runtime-l1-1-1/api-ms-win-appmodel-runtime-l1-1-1.spec @@ -22,6 +22,6 @@ @ stub PackageFamilyNameFromFullName @ stub PackageFamilyNameFromId @ stub PackageFullNameFromId -@ stub PackageIdFromFullName +@ stdcall PackageIdFromFullName(wstr long ptr ptr) kernel32.PackageIdFromFullName @ stub PackageNameAndPublisherIdFromFamilyName @ stub ParseApplicationUserModelId diff --git a/dlls/ext-ms-win-kernel32-package-l1-1-1/ext-ms-win-kernel32-package-l1-1-1.spec b/dlls/ext-ms-win-kernel32-package-l1-1-1/ext-ms-win-kernel32-package-l1-1-1.spec index 214cd344716..61fd115cca7 100644 --- a/dlls/ext-ms-win-kernel32-package-l1-1-1/ext-ms-win-kernel32-package-l1-1-1.spec +++ b/dlls/ext-ms-win-kernel32-package-l1-1-1/ext-ms-win-kernel32-package-l1-1-1.spec @@ -18,4 +18,4 @@ @ stub PackageFamilyNameFromFullName @ stub PackageFamilyNameFromId @ stub PackageFullNameFromId -@ stub PackageIdFromFullName +@ stdcall PackageIdFromFullName(wstr long ptr ptr) kernel32.PackageIdFromFullName diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index 0312e044a86..230a2a09ea2 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -1152,6 +1152,7 @@ @ stdcall -import PeekConsoleInputW(ptr ptr long ptr) @ stdcall -import PeekNamedPipe(long ptr long ptr ptr ptr) @ stdcall -import PostQueuedCompletionStatus(long long ptr ptr) +@ stdcall -import PackageIdFromFullName(wstr long ptr ptr) @ stdcall PowerClearRequest(long long) @ stdcall PowerCreateRequest(ptr) @ stdcall PowerSetRequest(long long) diff --git a/dlls/kernel32/tests/version.c b/dlls/kernel32/tests/version.c index 861b870b569..835c5398685 100644 --- a/dlls/kernel32/tests/version.c +++ b/dlls/kernel32/tests/version.c @@ -21,9 +21,11 @@ #include "wine/test.h" #include "winbase.h" #include "winternl.h" +#include "appmodel.h"
static BOOL (WINAPI * pGetProductInfo)(DWORD, DWORD, DWORD, DWORD, DWORD *); static UINT (WINAPI * pGetSystemFirmwareTable)(DWORD, DWORD, void *, DWORD); +static LONG (WINAPI * pPackageIdFromFullName)(const WCHAR *, UINT32, UINT32 *, BYTE *); static NTSTATUS (WINAPI * pNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, void *, ULONG, ULONG *); static NTSTATUS (WINAPI * pRtlGetVersion)(RTL_OSVERSIONINFOEXW *);
@@ -43,6 +45,7 @@ static void init_function_pointers(void)
GET_PROC(GetProductInfo); GET_PROC(GetSystemFirmwareTable); + GET_PROC(PackageIdFromFullName);
hmod = GetModuleHandleA("ntdll.dll");
@@ -746,6 +749,175 @@ static void test_GetSystemFirmwareTable(void) HeapFree(GetProcessHeap(), 0, smbios_table); }
+static const struct +{ + UINT32 code; + const WCHAR *name; + BOOL broken; +} +arch_data[] = +{ + {PROCESSOR_ARCHITECTURE_INTEL, L"X86"}, + {PROCESSOR_ARCHITECTURE_ARM, L"Arm"}, + {PROCESSOR_ARCHITECTURE_AMD64, L"X64"}, + {PROCESSOR_ARCHITECTURE_NEUTRAL, L"Neutral"}, + {PROCESSOR_ARCHITECTURE_ARM64, L"Arm64", TRUE /* Before Win10. */}, + {PROCESSOR_ARCHITECTURE_UNKNOWN, L"Unknown", TRUE /* Before Win10 1709. */}, +}; + +static const WCHAR *arch_string_from_code(UINT32 arch) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(arch_data); ++i) + if (arch_data[i].code == arch) + return arch_data[i].name; + + return NULL; +} + +static unsigned int get_package_str_size(const WCHAR *str) +{ + return str ? (lstrlenW(str) + 1) * sizeof(*str) : 0; +} + +static unsigned int get_package_id_size(const PACKAGE_ID *id) +{ + return sizeof(*id) + get_package_str_size(id->name) + + get_package_str_size(id->resourceId) + 14 * sizeof(WCHAR); +} + +static void packagefullname_from_packageid(WCHAR *buffer, size_t count, const PACKAGE_ID *id) +{ + swprintf(buffer, count, L"%s_%u.%u.%u.%u_%s_%s_%s", id->name, id->version.Major, + id->version.Minor, id->version.Build, id->version.Revision, + arch_string_from_code(id->processorArchitecture), id->resourceId, + id->publisherId); +} + +static void test_PackageIdFromFullName(void) +{ + static const PACKAGE_ID test_package_id = + { + 0, PROCESSOR_ARCHITECTURE_INTEL, + {{.Major = 1, .Minor = 2, .Build = 3, .Revision = 4}}, + (WCHAR *)L"TestPackage", NULL, + (WCHAR *)L"TestResourceId", (WCHAR *)L"0abcdefghjkme" + }; + UINT32 size, expected_size; + PACKAGE_ID test_id; + WCHAR fullname[512]; + BYTE id_buffer[512]; + unsigned int i; + PACKAGE_ID *id; + LONG ret; + + if (!pPackageIdFromFullName) + { + win_skip("PackageIdFromFullName not available.\n"); + return; + } + + packagefullname_from_packageid(fullname, ARRAY_SIZE(fullname), &test_package_id); + + id = (PACKAGE_ID *)id_buffer; + + memset(id_buffer, 0xcc, sizeof(id_buffer)); + expected_size = get_package_id_size(&test_package_id); + size = sizeof(id_buffer); + ret = pPackageIdFromFullName(fullname, 0, &size, id_buffer); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); + ok(size == expected_size, "Got unexpected length %u, expected %u.\n", size, expected_size); + ok(!lstrcmpW(id->name, test_package_id.name), "Got unexpected name %s.\n", debugstr_w(id->name)); + ok(!lstrcmpW(id->resourceId, test_package_id.resourceId), "Got unexpected resourceId %s.\n", + debugstr_w(id->resourceId)); + ok(!lstrcmpW(id->publisherId, test_package_id.publisherId), "Got unexpected publisherId %s.\n", + debugstr_w(id->publisherId)); + ok(!id->publisher, "Got unexpected publisher %s.\n", debugstr_w(id->publisher)); + ok(id->processorArchitecture == PROCESSOR_ARCHITECTURE_INTEL, "Got unexpected processorArchitecture %u.\n", + id->processorArchitecture); + ok(id->version.Version == 0x0001000200030004, "Got unexpected Version %s.\n", + wine_dbgstr_longlong(id->version.Version)); + ok((BYTE *)id->name == id_buffer + sizeof(*id), "Got unexpected name %p, buffer %p.\n", id->name, id_buffer); + ok((BYTE *)id->resourceId == (BYTE *)id->name + (lstrlenW(id->name) + 1) * 2, + "Got unexpected resourceId %p, buffer %p.\n", id->resourceId, id_buffer); + ok((BYTE *)id->publisherId == (BYTE *)id->resourceId + (lstrlenW(id->resourceId) + 1) * 2, + "Got unexpected publisherId %p, buffer %p.\n", id->resourceId, id_buffer); + + ret = pPackageIdFromFullName(fullname, 0, NULL, id_buffer); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %d.\n", ret); + + size = sizeof(id_buffer); + ret = pPackageIdFromFullName(NULL, 0, &size, id_buffer); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %d.\n", ret); + ok(size == sizeof(id_buffer), "Got unexpected size %u.\n", size); + + size = sizeof(id_buffer); + ret = pPackageIdFromFullName(fullname, 0, &size, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %d.\n", ret); + ok(size == sizeof(id_buffer), "Got unexpected size %u.\n", size); + + size = expected_size - 1; + ret = pPackageIdFromFullName(fullname, 0, &size, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %d.\n", ret); + ok(size == expected_size - 1, "Got unexpected size %u.\n", size); + + size = expected_size - 1; + ret = pPackageIdFromFullName(fullname, 0, &size, id_buffer); + ok(ret == ERROR_INSUFFICIENT_BUFFER, "Got unexpected ret %d.\n", ret); + ok(size == expected_size, "Got unexpected size %u.\n", size); + + size = 0; + ret = pPackageIdFromFullName(fullname, 0, &size, NULL); + ok(ret == ERROR_INSUFFICIENT_BUFFER, "Got unexpected ret %d.\n", ret); + ok(size == expected_size, "Got unexpected size %u.\n", size); + + for (i = 0; i < ARRAY_SIZE(arch_data); ++i) + { + test_id = test_package_id; + test_id.processorArchitecture = arch_data[i].code; + packagefullname_from_packageid(fullname, ARRAY_SIZE(fullname), &test_id); + size = expected_size; + ret = pPackageIdFromFullName(fullname, 0, &size, id_buffer); + ok(ret == ERROR_SUCCESS || broken(arch_data[i].broken && ret == ERROR_INVALID_PARAMETER), + "Got unexpected ret %u.\n", ret); + if (ret != ERROR_SUCCESS) + continue; + ok(size == expected_size, "Got unexpected length %u, expected %u.\n", size, expected_size); + ok(id->processorArchitecture == arch_data[i].code, "Got unexpected processorArchitecture %u, arch %S.\n", + id->processorArchitecture, arch_data[i].name); + } + + size = sizeof(id_buffer); + ret = pPackageIdFromFullName(L"TestPackage_1.2.3.4_X86_TestResourceId_0abcdefghjkme", 0, &size, id_buffer); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); + + size = sizeof(id_buffer); + ret = pPackageIdFromFullName(L"TestPackage_1.2.3.4_X86_TestResourceId_abcdefghjkme", 0, &size, id_buffer); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + + size = sizeof(id_buffer); + ret = pPackageIdFromFullName(L"TestPackage_1.2.3.4_X86_TestResourceId_0abcdefghjkmee", 0, &size, id_buffer); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + + size = sizeof(id_buffer); + ret = pPackageIdFromFullName(L"TestPackage_1.2.3_X86_TestResourceId_0abcdefghjkme", 0, &size, id_buffer); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + + size = sizeof(id_buffer); + ret = pPackageIdFromFullName(L"TestPackage_1.2.3.4_X86_TestResourceId_0abcdefghjkme_", 0, &size, id_buffer); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + + size = sizeof(id_buffer); + ret = pPackageIdFromFullName(L"TestPackage_1.2.3.4_X86__0abcdefghjkme", 0, &size, id_buffer); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); + ok(!lstrcmpW(id->resourceId, L""), "Got unexpected resourceId %s.\n", debugstr_w(id->resourceId)); + + size = sizeof(id_buffer); + ret = pPackageIdFromFullName(L"TestPackage_1.2.3.4_X86_0abcdefghjkme", 0, &size, id_buffer); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); +} + START_TEST(version) { init_function_pointers(); @@ -754,4 +926,5 @@ START_TEST(version) test_GetVersionEx(); test_VerifyVersionInfo(); test_GetSystemFirmwareTable(); + test_PackageIdFromFullName(); } diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index 8cb15fff084..615b928bd22 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -1014,7 +1014,7 @@ # @ stub PackageFamilyNameFromProductId # @ stub PackageFullNameFromId # @ stub PackageFullNameFromProductId -# @ stub PackageIdFromFullName +@ stdcall PackageIdFromFullName(wstr long ptr ptr) # @ stub PackageIdFromProductId # @ stub PackageNameAndPublisherIdFromFamilyName # @ stub PackageRelativeApplicationIdFromProductId diff --git a/dlls/kernelbase/version.c b/dlls/kernelbase/version.c index d5bfa081939..1ee82ce019a 100644 --- a/dlls/kernelbase/version.c +++ b/dlls/kernelbase/version.c @@ -39,6 +39,7 @@ #include "winnls.h" #include "winternl.h" #include "winerror.h" +#include "appmodel.h"
#include "kernelbase.h" #include "wine/debug.h" @@ -1565,3 +1566,118 @@ LONG WINAPI /* DECLSPEC_HOTPATCH */ GetPackageFamilyName( HANDLE process, UINT32 FIXME( "(%p %p %p): stub\n", process, length, name ); return APPMODEL_ERROR_NO_PACKAGE; } + + +static const struct +{ + UINT32 code; + const WCHAR *name; +} +arch_names[] = +{ + {PROCESSOR_ARCHITECTURE_INTEL, L"x86"}, + {PROCESSOR_ARCHITECTURE_ARM, L"arm"}, + {PROCESSOR_ARCHITECTURE_AMD64, L"x64"}, + {PROCESSOR_ARCHITECTURE_NEUTRAL, L"neutral"}, + {PROCESSOR_ARCHITECTURE_ARM64, L"arm64"}, + {PROCESSOR_ARCHITECTURE_UNKNOWN, L"unknown"}, +}; + +UINT32 processor_arch_from_string(const WCHAR *str, unsigned int len) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(arch_names); ++i) + if (lstrlenW(arch_names[i].name) == len && !wcsnicmp(str, arch_names[i].name, len)) + return arch_names[i].code; + return ~0u; +} + +/*********************************************************************** + * PackageIdFromFullName (kernelbase.@) + */ +LONG WINAPI PackageIdFromFullName(const WCHAR *full_name, UINT32 flags, UINT32 *buffer_length, BYTE *buffer) +{ + const WCHAR *name, *version_str, *arch_str, *resource_id, *publisher_id, *s; + PACKAGE_ID *id = (PACKAGE_ID *)buffer; + UINT32 size, buffer_size, len; + + TRACE("full_name %s, flags %#x, buffer_length %p, buffer %p.\n", + debugstr_w(full_name), flags, buffer_length, buffer); + + if (flags) + FIXME("Flags %#x are not supported.\n", flags); + + if (!full_name || !buffer_length) + return ERROR_INVALID_PARAMETER; + + if (!buffer && *buffer_length) + return ERROR_INVALID_PARAMETER; + + name = full_name; + if (!(version_str = wcschr(name, L'_'))) + return ERROR_INVALID_PARAMETER; + ++version_str; + + if (!(arch_str = wcschr(version_str, L'_'))) + return ERROR_INVALID_PARAMETER; + ++arch_str; + + if (!(resource_id = wcschr(arch_str, L'_'))) + return ERROR_INVALID_PARAMETER; + ++resource_id; + + if (!(publisher_id = wcschr(resource_id, L'_'))) + return ERROR_INVALID_PARAMETER; + ++publisher_id; + + /* Publisher id length should be 13. */ + size = sizeof(*id) + sizeof(WCHAR) * ((version_str - name) + (publisher_id - resource_id) + 13 + 1); + buffer_size = *buffer_length; + *buffer_length = size; + if (buffer_size < size) + return ERROR_INSUFFICIENT_BUFFER; + + memset(id, 0, sizeof(*id)); + if ((id->processorArchitecture = processor_arch_from_string(arch_str, resource_id - arch_str - 1)) == ~0u) + { + FIXME("Unrecognized arch %s.\n", debugstr_w(arch_str)); + return ERROR_INVALID_PARAMETER; + } + buffer += sizeof(*id); + + id->version.u.s.Major = wcstol(version_str, NULL, 10); + if (!(s = wcschr(version_str, L'.'))) + return ERROR_INVALID_PARAMETER; + ++s; + id->version.u.s.Minor = wcstol(s, NULL, 10); + if (!(s = wcschr(s, L'.'))) + return ERROR_INVALID_PARAMETER; + ++s; + id->version.u.s.Build = wcstol(s, NULL, 10); + if (!(s = wcschr(s, L'.'))) + return ERROR_INVALID_PARAMETER; + ++s; + id->version.u.s.Revision = wcstol(s, NULL, 10); + + id->name = (WCHAR *)buffer; + len = version_str - name - 1; + memcpy(id->name, name, sizeof(*id->name) * len); + id->name[len] = 0; + buffer += sizeof(*id->name) * (len + 1); + + id->resourceId = (WCHAR *)buffer; + len = publisher_id - resource_id - 1; + memcpy(id->resourceId, resource_id, sizeof(*id->resourceId) * len); + id->resourceId[len] = 0; + buffer += sizeof(*id->resourceId) * (len + 1); + + id->publisherId = (WCHAR *)buffer; + len = lstrlenW(publisher_id); + if (len != 13) + return ERROR_INVALID_PARAMETER; + memcpy(id->publisherId, publisher_id, sizeof(*id->publisherId) * len); + id->publisherId[len] = 0; + + return ERROR_SUCCESS; +} diff --git a/include/appmodel.h b/include/appmodel.h index 34da979782d..e4288bbfbb0 100644 --- a/include/appmodel.h +++ b/include/appmodel.h @@ -48,10 +48,41 @@ typedef enum AppPolicyWindowingModel AppPolicyWindowingModel_ClassicPhone = 3 } AppPolicyWindowingModel;
+typedef struct PACKAGE_VERSION +{ + union + { + UINT64 Version; + struct + { + USHORT Revision; + USHORT Build; + USHORT Minor; + USHORT Major; + } + DUMMYSTRUCTNAME; + } + DUMMYUNIONNAME; +} +PACKAGE_VERSION; + +typedef struct PACKAGE_ID +{ + UINT32 reserved; + UINT32 processorArchitecture; + PACKAGE_VERSION version; + WCHAR *name; + WCHAR *publisher; + WCHAR *resourceId; + WCHAR *publisherId; +} +PACKAGE_ID; + LONG WINAPI AppPolicyGetProcessTerminationMethod(HANDLE token, AppPolicyProcessTerminationMethod *policy); LONG WINAPI AppPolicyGetShowDeveloperDiagnostic(HANDLE token, AppPolicyShowDeveloperDiagnostic *policy); LONG WINAPI AppPolicyGetThreadInitializationType(HANDLE token, AppPolicyThreadInitializationType *policy); LONG WINAPI AppPolicyGetWindowingModel(HANDLE processToken, AppPolicyWindowingModel *policy); +LONG WINAPI PackageIdFromFullName(const WCHAR *full_name, UINT32 flags, UINT32 *buffer_length, BYTE *buffer);
#if defined(__cplusplus) }
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- loader/wine.inf.in | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 52c2297fb2f..114fed8b326 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -67,6 +67,7 @@ AddReg=\ Misc,\ Nls,\ OLE,\ + Packages,\ Printing,\ Services, \ SessionMgr,\ @@ -94,6 +95,7 @@ AddReg=\ Misc,\ Nls,\ OLE,\ + Packages.ntamd64,\ Printing,\ Services, \ SessionMgr,\ @@ -121,6 +123,7 @@ AddReg=\ Misc,\ Nls,\ OLE,\ + Packages.ntarm64,\ Printing,\ Services, \ SessionMgr,\ @@ -140,6 +143,7 @@ AddReg=\ DirectX,\ MCI,\ Misc,\ + Packages.wow64,\ Tapi,\ VersionInfo.ntamd64,\ LicenseInformation @@ -230,6 +234,7 @@ CurrentVersion="Software\Microsoft\Windows\CurrentVersion" CurrentVersionNT="Software\Microsoft\Windows NT\CurrentVersion" FontSubStr="Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes" Control="System\CurrentControlSet\Control" +Packages="Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppModel\PackageRepository\Packages"
[Classes] HKCR,.chm,,2,"chm.file" @@ -1111,6 +1116,18 @@ HKLM,System\CurrentControlSet\Control\Nls\Locale\Alternate Sorts,"00030404",,"9" HKLM,"Software\Microsoft\OLE","EnableDCOM",,"Y" HKLM,"Software\Microsoft\OLE","EnableRemoteConnect",,"N"
+[Packages] +HKLM,"%Packages%\Microsoft.VCLibs.140.00_14.0.29231.0_x86__8wekyb3d8bbwe","Path",0x00020002,"%SystemRoot%\system32" + +[Packages.ntamd64] +HKLM,"%Packages%\Microsoft.VCLibs.140.00_14.0.29231.0_x64__8wekyb3d8bbwe","Path",0x00020002,"%SystemRoot%\system32" + +[Packages.wow64] +HKLM,"%Packages%\Microsoft.VCLibs.140.00_14.0.29231.0_x86__8wekyb3d8bbwe","Path",0x00020002,"%SystemRoot%\syswow64" + +[Packages.arm64] +HKLM,"%Packages%\Microsoft.VCLibs.140.00_14.0.29231.0_arm64__8wekyb3d8bbwe","Path",0x00020002,"%SystemRoot%\system32" + [Printing] HKLM,%Control%\Print\Monitors\Local Port,"Driver",2,"localspl.dll" HKLM,%Control%\Print\Printers,"DefaultSpoolDirectory",2,"%11%\spool\printers"
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=87758
Your paranoid android.
=== debiant2 (build log) ===
Task: WineTest did not produce the wow32 report
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- .../api-ms-win-appmodel-runtime-l1-1-1.spec | 2 +- .../ext-ms-win-kernel32-package-l1-1-1.spec | 2 +- dlls/kernel32/kernel32.spec | 1 + dlls/kernel32/tests/version.c | 131 ++++++++++++++++++ dlls/kernelbase/kernelbase.spec | 2 +- dlls/kernelbase/version.c | 115 +++++++++++++++ include/appmodel.h | 2 + 7 files changed, 252 insertions(+), 3 deletions(-)
diff --git a/dlls/api-ms-win-appmodel-runtime-l1-1-1/api-ms-win-appmodel-runtime-l1-1-1.spec b/dlls/api-ms-win-appmodel-runtime-l1-1-1/api-ms-win-appmodel-runtime-l1-1-1.spec index 99d1d9f3835..696bb75be30 100644 --- a/dlls/api-ms-win-appmodel-runtime-l1-1-1/api-ms-win-appmodel-runtime-l1-1-1.spec +++ b/dlls/api-ms-win-appmodel-runtime-l1-1-1/api-ms-win-appmodel-runtime-l1-1-1.spec @@ -15,7 +15,7 @@ @ stub GetPackageInfo @ stub GetPackagePath @ stub GetPackagePathByFullName -@ stub GetPackagesByPackageFamily +@ stdcall GetPackagesByPackageFamily(wstr ptr ptr ptr ptr) kernel32.GetPackagesByPackageFamily @ stub GetStagedPackageOrigin @ stub GetStagedPackagePathByFullName @ stub OpenPackageInfoByFullName diff --git a/dlls/ext-ms-win-kernel32-package-l1-1-1/ext-ms-win-kernel32-package-l1-1-1.spec b/dlls/ext-ms-win-kernel32-package-l1-1-1/ext-ms-win-kernel32-package-l1-1-1.spec index 61fd115cca7..ff5118049e2 100644 --- a/dlls/ext-ms-win-kernel32-package-l1-1-1/ext-ms-win-kernel32-package-l1-1-1.spec +++ b/dlls/ext-ms-win-kernel32-package-l1-1-1/ext-ms-win-kernel32-package-l1-1-1.spec @@ -12,7 +12,7 @@ @ stub GetPackageId @ stub GetPackageInfo @ stub GetPackagePath -@ stub GetPackagesByPackageFamily +@ stdcall GetPackagesByPackageFamily(wstr ptr ptr ptr ptr) kernel32.GetPackagesByPackageFamily @ stub GetStagedPackageOrigin @ stub OpenPackageInfoByFullName @ stub PackageFamilyNameFromFullName diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index 230a2a09ea2..d605ed6e771 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -765,6 +765,7 @@ @ stdcall -import GetOverlappedResultEx(long ptr ptr long long) @ stdcall -import GetUserDefaultGeoName(ptr long) @ stdcall -import GetUserPreferredUILanguages(long ptr ptr ptr) +@ stdcall -import GetPackagesByPackageFamily(wstr ptr ptr ptr ptr) @ stdcall GetPackageFamilyName(long ptr ptr) kernelbase.GetPackageFamilyName @ stdcall GetPackageFullName(long ptr ptr) kernelbase.GetPackageFullName @ stdcall -import GetPhysicallyInstalledSystemMemory(ptr) diff --git a/dlls/kernel32/tests/version.c b/dlls/kernel32/tests/version.c index 835c5398685..9a35d679323 100644 --- a/dlls/kernel32/tests/version.c +++ b/dlls/kernel32/tests/version.c @@ -23,6 +23,7 @@ #include "winternl.h" #include "appmodel.h"
+static LONG (WINAPI * pGetPackagesByPackageFamily)(const WCHAR *, UINT32 *, WCHAR **, UINT32 *, WCHAR *); static BOOL (WINAPI * pGetProductInfo)(DWORD, DWORD, DWORD, DWORD, DWORD *); static UINT (WINAPI * pGetSystemFirmwareTable)(DWORD, DWORD, void *, DWORD); static LONG (WINAPI * pPackageIdFromFullName)(const WCHAR *, UINT32, UINT32 *, BYTE *); @@ -43,6 +44,7 @@ static void init_function_pointers(void)
hmod = GetModuleHandleA("kernel32.dll");
+ GET_PROC(GetPackagesByPackageFamily); GET_PROC(GetProductInfo); GET_PROC(GetSystemFirmwareTable); GET_PROC(PackageIdFromFullName); @@ -918,6 +920,134 @@ static void test_PackageIdFromFullName(void) ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); }
+static void test_package_info(void) +{ + static const WCHAR package_family_msvc140[] = L"Microsoft.VCLibs.140.00_8wekyb3d8bbwe"; + UINT32 count, length, curr_length, size; + WCHAR *full_names[32]; + BYTE id_buffer[512]; + WCHAR buffer[2048]; + BOOL arch_found; + SYSTEM_INFO si; + unsigned int i; + PACKAGE_ID *id; + DWORD arch; + LONG ret; + + if (!pGetPackagesByPackageFamily) + { + win_skip("GetPackagesByPackageFamily not available.\n"); + return; + } + + GetSystemInfo(&si); + arch = si.wProcessorArchitecture; + + count = 0; + length = 0; + ret = pGetPackagesByPackageFamily(L"Unknown_8wekyb3d8bbwe", &count, NULL, &length, NULL); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); + ok(!count, "Got unexpected count %u.\n", count); + ok(!length, "Got unexpected length %u.\n", length); + + count = 0; + length = 0; + ret = pGetPackagesByPackageFamily(L"Unknown_iekyb3d8bbwe", &count, NULL, &length, NULL); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); + ok(!count, "Got unexpected count %u.\n", count); + ok(!length, "Got unexpected length %u.\n", length); + + count = 0xdeadbeef; + length = 0xdeadbeef; + ret = pGetPackagesByPackageFamily(L"Unknown", &count, NULL, &length, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + ok(count == 0xdeadbeef, "Got unexpected count %u.\n", count); + ok(length == 0xdeadbeef, "Got unexpected length %u.\n", length); + + count = 0; + length = 0; + ret = pGetPackagesByPackageFamily(L"Unknown", &count, NULL, &length, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + ok(!count, "Got unexpected count %u.\n", count); + ok(!length, "Got unexpected length %u.\n", length); + + count = 0; + length = 0; + ret = pGetPackagesByPackageFamily(L"Unknown_8wekyb3d8bbwe_b", &count, NULL, &length, NULL); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); + ok(!count, "Got unexpected count %u.\n", count); + ok(!length, "Got unexpected length %u.\n", length); + + count = 0; + length = 0; + ret = pGetPackagesByPackageFamily(L"Unknown_", &count, NULL, &length, NULL); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); + ok(!count, "Got unexpected count %u.\n", count); + ok(!length, "Got unexpected length %u.\n", length); + + length = 0; + ret = pGetPackagesByPackageFamily(package_family_msvc140, NULL, NULL, &length, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + ok(!length, "Got unexpected length %u.\n", length); + + count = 0; + ret = pGetPackagesByPackageFamily(package_family_msvc140, &count, NULL, NULL, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + ok(!count, "Got unexpected count %u.\n", count); + + count = ARRAY_SIZE(full_names); + length = ARRAY_SIZE(buffer); + ret = pGetPackagesByPackageFamily(package_family_msvc140, &count, NULL, &length, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + ok(count == ARRAY_SIZE(full_names), "Got unexpected count %u.\n", count); + ok(length == ARRAY_SIZE(buffer), "Got unexpected length %u.\n", length); + + ret = pGetPackagesByPackageFamily(package_family_msvc140, &count, full_names, &length, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + ok(count == ARRAY_SIZE(full_names), "Got unexpected count %u.\n", count); + ok(length == ARRAY_SIZE(buffer), "Got unexpected length %u.\n", length); + + ret = pGetPackagesByPackageFamily(package_family_msvc140, &count, NULL, &length, buffer); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + ok(count == ARRAY_SIZE(full_names), "Got unexpected count %u.\n", count); + ok(length == ARRAY_SIZE(buffer), "Got unexpected length %u.\n", length); + + count = 0; + length = 0; + ret = pGetPackagesByPackageFamily(package_family_msvc140, &count, NULL, &length, NULL); + if (!ret && !count && !length) + { + win_skip("Package VCLibs.140.00 is not installed.\n"); + return; + } + + ok(ret == ERROR_INSUFFICIENT_BUFFER, "Got unexpected ret %u.\n", ret); + ok(count >= 1, "Got unexpected count %u.\n", count); + ok(length > 1, "Got unexpected length %u.\n", length); + + ret = pGetPackagesByPackageFamily(package_family_msvc140, &count, full_names, &length, buffer); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); + ok(count >= 1, "Got unexpected count %u.\n", count); + ok(length > 1, "Got unexpected length %u.\n", length); + + id = (PACKAGE_ID *)id_buffer; + curr_length = 0; + arch_found = FALSE; + for (i = 0; i < count; ++i) + { + curr_length += lstrlenW(full_names[i]) + 1; + + size = sizeof(id_buffer); + ret = pPackageIdFromFullName(full_names[i], 0, &size, id_buffer); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); + + if (id->processorArchitecture == arch) + arch_found = TRUE; + } + ok(curr_length == length, "Got unexpected length %u.\n", length); + ok(arch_found, "Did not find package for current arch.\n"); +} + START_TEST(version) { init_function_pointers(); @@ -927,4 +1057,5 @@ START_TEST(version) test_VerifyVersionInfo(); test_GetSystemFirmwareTable(); test_PackageIdFromFullName(); + test_package_info(); } diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index 615b928bd22..b385ebd6774 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -614,7 +614,7 @@ # @ stub GetPackageStatusForUser # @ stub GetPackageTargetPlatformProperty # @ stub GetPackageVolumeSisPath -# @ stub GetPackagesByPackageFamily +@ stdcall GetPackagesByPackageFamily(wstr ptr ptr ptr ptr) @ stdcall GetPerformanceInfo(ptr long) @ stdcall GetPhysicallyInstalledSystemMemory(ptr) # @ stub GetPreviousFgPolicyRefreshInfoInternal diff --git a/dlls/kernelbase/version.c b/dlls/kernelbase/version.c index 1ee82ce019a..1efd4adaee7 100644 --- a/dlls/kernelbase/version.c +++ b/dlls/kernelbase/version.c @@ -39,10 +39,12 @@ #include "winnls.h" #include "winternl.h" #include "winerror.h" +#include "winreg.h" #include "appmodel.h"
#include "kernelbase.h" #include "wine/debug.h" +#include "wine/heap.h"
WINE_DEFAULT_DEBUG_CHANNEL(ver);
@@ -154,6 +156,8 @@ static const struct } };
+static const WCHAR packages_key_name[] = L"Software\Classes\Local Settings\Software\Microsoft\Windows" + L"\CurrentVersion\AppModel\PackageRepository\Packages";
/****************************************************************************** * init_current_version @@ -1681,3 +1685,114 @@ LONG WINAPI PackageIdFromFullName(const WCHAR *full_name, UINT32 flags, UINT32 *
return ERROR_SUCCESS; } + + +/*********************************************************************** + * GetPackagesByPackageFamily (kernelbase.@) + */ +LONG WINAPI GetPackagesByPackageFamily(const WCHAR *family_name, UINT32 *count, WCHAR **full_names, + UINT32 *buffer_length, WCHAR *buffer) +{ + UINT32 curr_count, curr_length, package_id_buf_size, size; + unsigned int i, name_len, publisher_id_len; + DWORD subkey_count, max_key_len, length; + const WCHAR *publisher_id; + WCHAR *package_name; + BOOL short_buffer; + PACKAGE_ID *id; + HKEY key; + + TRACE("family_name %s, count %p, full_names %p, buffer_length %p, buffer %p.\n", + debugstr_w(family_name), count, full_names, buffer_length, buffer); + + if (!buffer_length || !count || !family_name) + return ERROR_INVALID_PARAMETER; + + if ((*buffer_length || *count) && (!full_names || !buffer)) + return ERROR_INVALID_PARAMETER; + + if (!(publisher_id = wcschr(family_name, L'_'))) + return ERROR_INVALID_PARAMETER; + + name_len = publisher_id - family_name; + ++publisher_id; + publisher_id_len = lstrlenW(publisher_id); + + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, packages_key_name, 0, KEY_READ, &key)) + { + ERR("Key open failed.\n"); + *count = 0; + *buffer_length = 0; + return ERROR_SUCCESS; + } + if (RegQueryInfoKeyW(key, NULL, NULL, NULL, &subkey_count, &max_key_len, NULL, NULL, NULL, NULL, NULL, NULL)) + { + ERR("Query key info failed.\n"); + RegCloseKey(key); + *count = 0; + *buffer_length = 0; + return ERROR_SUCCESS; + } + + if (!(package_name = heap_alloc((max_key_len + 1) * sizeof(*package_name)))) + { + ERR("No memory.\n"); + RegCloseKey(key); + return ERROR_OUTOFMEMORY; + } + + package_id_buf_size = sizeof(*id) + (max_key_len + 1) * sizeof(WCHAR); + if (!(id = heap_alloc(package_id_buf_size))) + { + ERR("No memory.\n"); + heap_free(package_name); + RegCloseKey(key); + return ERROR_OUTOFMEMORY; + } + + curr_count = curr_length = 0; + for (i = 0; i < subkey_count; ++i) + { + length = max_key_len + 1; + if (RegEnumKeyExW(key, i, package_name, &length, NULL, NULL, NULL, NULL)) + { + ERR("Error enumerating key %u.\n", i); + continue; + } + + size = package_id_buf_size; + if (PackageIdFromFullName(package_name, 0, &size, (BYTE *)id)) + { + ERR("Error getting package id from full name.\n"); + continue; + } + + if (lstrlenW(id->name) != name_len) + continue; + if (wcsnicmp(family_name, id->name, name_len)) + continue; + + if (lstrlenW(id->publisherId) != publisher_id_len) + continue; + if (wcsnicmp(publisher_id, id->publisherId, publisher_id_len)) + continue; + if (curr_length + length < *buffer_length) + { + memcpy(buffer + curr_length, package_name, (length + 1) * sizeof(*package_name)); + if (curr_count < *count) + full_names[curr_count] = buffer + curr_length; + } + curr_length += length + 1; + ++curr_count; + } + + heap_free(id); + heap_free(package_name); + RegCloseKey(key); + + short_buffer = curr_length > *buffer_length || curr_count > *count; + *count = curr_count; + *buffer_length = curr_length; + + return short_buffer ? ERROR_INSUFFICIENT_BUFFER : ERROR_SUCCESS; +} diff --git a/include/appmodel.h b/include/appmodel.h index e4288bbfbb0..27a0d0a8646 100644 --- a/include/appmodel.h +++ b/include/appmodel.h @@ -82,6 +82,8 @@ LONG WINAPI AppPolicyGetProcessTerminationMethod(HANDLE token, AppPolicyProcessT LONG WINAPI AppPolicyGetShowDeveloperDiagnostic(HANDLE token, AppPolicyShowDeveloperDiagnostic *policy); LONG WINAPI AppPolicyGetThreadInitializationType(HANDLE token, AppPolicyThreadInitializationType *policy); LONG WINAPI AppPolicyGetWindowingModel(HANDLE processToken, AppPolicyWindowingModel *policy); +LONG WINAPI GetPackagesByPackageFamily(const WCHAR *family_name, UINT32 *count, WCHAR **full_names, + UINT32 *buffer_length, WCHAR *buffer); LONG WINAPI PackageIdFromFullName(const WCHAR *full_name, UINT32 flags, UINT32 *buffer_length, BYTE *buffer);
#if defined(__cplusplus)
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=87759
Your paranoid android.
=== debiant2 (build log) ===
Task: WineTest did not produce the wow32 report
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- .../api-ms-win-appmodel-runtime-l1-1-1.spec | 2 +- .../ext-ms-win-kernel32-package-l1-1-1.spec | 2 +- dlls/kernel32/kernel32.spec | 1 + dlls/kernel32/tests/version.c | 22 +++++++++- dlls/kernelbase/kernelbase.spec | 2 +- dlls/kernelbase/version.c | 43 +++++++++++++++++++ include/appmodel.h | 1 + 7 files changed, 69 insertions(+), 4 deletions(-)
diff --git a/dlls/api-ms-win-appmodel-runtime-l1-1-1/api-ms-win-appmodel-runtime-l1-1-1.spec b/dlls/api-ms-win-appmodel-runtime-l1-1-1/api-ms-win-appmodel-runtime-l1-1-1.spec index 696bb75be30..72a0a33baf5 100644 --- a/dlls/api-ms-win-appmodel-runtime-l1-1-1/api-ms-win-appmodel-runtime-l1-1-1.spec +++ b/dlls/api-ms-win-appmodel-runtime-l1-1-1/api-ms-win-appmodel-runtime-l1-1-1.spec @@ -21,7 +21,7 @@ @ stub OpenPackageInfoByFullName @ stub PackageFamilyNameFromFullName @ stub PackageFamilyNameFromId -@ stub PackageFullNameFromId +@ stdcall PackageFullNameFromId(ptr ptr ptr) kernel32.PackageFullNameFromId @ stdcall PackageIdFromFullName(wstr long ptr ptr) kernel32.PackageIdFromFullName @ stub PackageNameAndPublisherIdFromFamilyName @ stub ParseApplicationUserModelId diff --git a/dlls/ext-ms-win-kernel32-package-l1-1-1/ext-ms-win-kernel32-package-l1-1-1.spec b/dlls/ext-ms-win-kernel32-package-l1-1-1/ext-ms-win-kernel32-package-l1-1-1.spec index ff5118049e2..42566176b56 100644 --- a/dlls/ext-ms-win-kernel32-package-l1-1-1/ext-ms-win-kernel32-package-l1-1-1.spec +++ b/dlls/ext-ms-win-kernel32-package-l1-1-1/ext-ms-win-kernel32-package-l1-1-1.spec @@ -17,5 +17,5 @@ @ stub OpenPackageInfoByFullName @ stub PackageFamilyNameFromFullName @ stub PackageFamilyNameFromId -@ stub PackageFullNameFromId +@ stdcall PackageFullNameFromId(ptr ptr ptr) kernel32.PackageFullNameFromId @ stdcall PackageIdFromFullName(wstr long ptr ptr) kernel32.PackageIdFromFullName diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index d605ed6e771..4cfcf6df188 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -1153,6 +1153,7 @@ @ stdcall -import PeekConsoleInputW(ptr ptr long ptr) @ stdcall -import PeekNamedPipe(long ptr long ptr ptr ptr) @ stdcall -import PostQueuedCompletionStatus(long long ptr ptr) +@ stdcall -import PackageFullNameFromId(ptr ptr ptr) @ stdcall -import PackageIdFromFullName(wstr long ptr ptr) @ stdcall PowerClearRequest(long long) @ stdcall PowerCreateRequest(ptr) diff --git a/dlls/kernel32/tests/version.c b/dlls/kernel32/tests/version.c index 9a35d679323..ed1ef3e3bf7 100644 --- a/dlls/kernel32/tests/version.c +++ b/dlls/kernel32/tests/version.c @@ -26,6 +26,7 @@ static LONG (WINAPI * pGetPackagesByPackageFamily)(const WCHAR *, UINT32 *, WCHAR **, UINT32 *, WCHAR *); static BOOL (WINAPI * pGetProductInfo)(DWORD, DWORD, DWORD, DWORD, DWORD *); static UINT (WINAPI * pGetSystemFirmwareTable)(DWORD, DWORD, void *, DWORD); +static LONG (WINAPI * pPackageFullNameFromId)(const PACKAGE_ID *, UINT32 *, WCHAR *); static LONG (WINAPI * pPackageIdFromFullName)(const WCHAR *, UINT32, UINT32 *, BYTE *); static NTSTATUS (WINAPI * pNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, void *, ULONG, ULONG *); static NTSTATUS (WINAPI * pRtlGetVersion)(RTL_OSVERSIONINFOEXW *); @@ -47,6 +48,7 @@ static void init_function_pointers(void) GET_PROC(GetPackagesByPackageFamily); GET_PROC(GetProductInfo); GET_PROC(GetSystemFirmwareTable); + GET_PROC(PackageFullNameFromId); GET_PROC(PackageIdFromFullName);
hmod = GetModuleHandleA("ntdll.dll"); @@ -803,9 +805,11 @@ static void test_PackageIdFromFullName(void) { 0, PROCESSOR_ARCHITECTURE_INTEL, {{.Major = 1, .Minor = 2, .Build = 3, .Revision = 4}}, - (WCHAR *)L"TestPackage", NULL, + (WCHAR *)L"TestPackage", (WCHAR *)L"TestResource", (WCHAR *)L"TestResourceId", (WCHAR *)L"0abcdefghjkme" }; + static const WCHAR test_package_fullname[] = + L"TestPackage_1.2.3.4_x86_TestResourceId_0abcdefghjkme"; UINT32 size, expected_size; PACKAGE_ID test_id; WCHAR fullname[512]; @@ -918,6 +922,22 @@ static void test_PackageIdFromFullName(void) size = sizeof(id_buffer); ret = pPackageIdFromFullName(L"TestPackage_1.2.3.4_X86_0abcdefghjkme", 0, &size, id_buffer); ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + + ret = pPackageFullNameFromId(&test_package_id, NULL, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + + size = sizeof(fullname); + ret = pPackageFullNameFromId(&test_package_id, &size, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + + size = 0; + ret = pPackageFullNameFromId(&test_package_id, &size, NULL); + ok(ret == ERROR_INSUFFICIENT_BUFFER, "Got unexpected ret %u.\n", ret); + ok(size == lstrlenW(test_package_fullname) + 1, "Got unexpected size %u.\n", size); + + ret = pPackageFullNameFromId(&test_package_id, &size, fullname); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); + ok(!lstrcmpW(fullname, test_package_fullname), "Got unexpected fullname %s.\n", debugstr_w(fullname)); }
static void test_package_info(void) diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index b385ebd6774..fc7671781f1 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -1012,7 +1012,7 @@ # @ stub PackageFamilyNameFromFullName # @ stub PackageFamilyNameFromId # @ stub PackageFamilyNameFromProductId -# @ stub PackageFullNameFromId +@ stdcall PackageFullNameFromId(ptr ptr ptr) # @ stub PackageFullNameFromProductId @ stdcall PackageIdFromFullName(wstr long ptr ptr) # @ stub PackageIdFromProductId diff --git a/dlls/kernelbase/version.c b/dlls/kernelbase/version.c index 1efd4adaee7..b2a6ceb182e 100644 --- a/dlls/kernelbase/version.c +++ b/dlls/kernelbase/version.c @@ -1597,6 +1597,16 @@ UINT32 processor_arch_from_string(const WCHAR *str, unsigned int len) return ~0u; }
+const WCHAR *string_from_processor_arch(UINT32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(arch_names); ++i) + if (code == arch_names[i].code) + return arch_names[i].name; + return NULL; +} + /*********************************************************************** * PackageIdFromFullName (kernelbase.@) */ @@ -1687,6 +1697,39 @@ LONG WINAPI PackageIdFromFullName(const WCHAR *full_name, UINT32 flags, UINT32 * }
+/*********************************************************************** + * PackageFullNameFromId (kernelbase.@) + */ +LONG WINAPI PackageFullNameFromId(const PACKAGE_ID *package_id, UINT32 *length, WCHAR *full_name) +{ + WCHAR ver_str[5 * 4 + 3 + 1]; + const WCHAR *arch_str; + UINT32 have_length; + + TRACE("package_id %p, length %p, full_name %p.\n", package_id, length, full_name); + + if (!package_id || !length) + return ERROR_INVALID_PARAMETER; + if (!full_name && *length) + return ERROR_INVALID_PARAMETER; + if (!package_id->name || !package_id->resourceId || !package_id->publisherId + || !(arch_str = string_from_processor_arch(package_id->processorArchitecture))) + return ERROR_INVALID_PARAMETER; + + swprintf(ver_str, ARRAY_SIZE(ver_str), L"%u.%u.%u.%u", package_id->version.u.s.Major, + package_id->version.u.s.Minor, package_id->version.u.s.Build, package_id->version.u.s.Revision); + have_length = *length; + *length = lstrlenW(package_id->name) + 1 + lstrlenW(ver_str) + 1 + lstrlenW(arch_str) + 1 + + lstrlenW(package_id->resourceId) + 1 + lstrlenW(package_id->publisherId) + 1; + + if (have_length < *length) + return ERROR_INSUFFICIENT_BUFFER; + + swprintf(full_name, *length, L"%s_%s_%s_%s_%s", package_id->name, ver_str, arch_str, package_id->resourceId, package_id->publisherId); + return ERROR_SUCCESS; +} + + /*********************************************************************** * GetPackagesByPackageFamily (kernelbase.@) */ diff --git a/include/appmodel.h b/include/appmodel.h index 27a0d0a8646..be59bc70f5f 100644 --- a/include/appmodel.h +++ b/include/appmodel.h @@ -84,6 +84,7 @@ LONG WINAPI AppPolicyGetThreadInitializationType(HANDLE token, AppPolicyThreadIn LONG WINAPI AppPolicyGetWindowingModel(HANDLE processToken, AppPolicyWindowingModel *policy); LONG WINAPI GetPackagesByPackageFamily(const WCHAR *family_name, UINT32 *count, WCHAR **full_names, UINT32 *buffer_length, WCHAR *buffer); +LONG WINAPI PackageFullNameFromId(const PACKAGE_ID *package_id, UINT32 *length, WCHAR *full_name); LONG WINAPI PackageIdFromFullName(const WCHAR *full_name, UINT32 flags, UINT32 *buffer_length, BYTE *buffer);
#if defined(__cplusplus)
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=87760
Your paranoid android.
=== debiant2 (build log) ===
Task: WineTest did not produce the wow32 report
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- .../api-ms-win-appmodel-runtime-l1-1-1.spec | 2 +- .../ext-ms-win-kernel32-package-l1-1-1.spec | 2 +- dlls/kernel32/kernel32.spec | 1 + dlls/kernel32/tests/version.c | 64 +++++++++++++-- dlls/kernelbase/kernelbase.spec | 2 +- dlls/kernelbase/version.c | 82 +++++++++++++++++++ include/appmodel.h | 1 + 7 files changed, 146 insertions(+), 8 deletions(-)
diff --git a/dlls/api-ms-win-appmodel-runtime-l1-1-1/api-ms-win-appmodel-runtime-l1-1-1.spec b/dlls/api-ms-win-appmodel-runtime-l1-1-1/api-ms-win-appmodel-runtime-l1-1-1.spec index 72a0a33baf5..e77ac397b03 100644 --- a/dlls/api-ms-win-appmodel-runtime-l1-1-1/api-ms-win-appmodel-runtime-l1-1-1.spec +++ b/dlls/api-ms-win-appmodel-runtime-l1-1-1/api-ms-win-appmodel-runtime-l1-1-1.spec @@ -13,7 +13,7 @@ @ stdcall GetPackageFullName(long ptr ptr) kernel32.GetPackageFullName @ stub GetPackageId @ stub GetPackageInfo -@ stub GetPackagePath +@ stdcall GetPackagePath(ptr long ptr ptr) kernel32.GetPackagePath @ stub GetPackagePathByFullName @ stdcall GetPackagesByPackageFamily(wstr ptr ptr ptr ptr) kernel32.GetPackagesByPackageFamily @ stub GetStagedPackageOrigin diff --git a/dlls/ext-ms-win-kernel32-package-l1-1-1/ext-ms-win-kernel32-package-l1-1-1.spec b/dlls/ext-ms-win-kernel32-package-l1-1-1/ext-ms-win-kernel32-package-l1-1-1.spec index 42566176b56..58bf807b4be 100644 --- a/dlls/ext-ms-win-kernel32-package-l1-1-1/ext-ms-win-kernel32-package-l1-1-1.spec +++ b/dlls/ext-ms-win-kernel32-package-l1-1-1/ext-ms-win-kernel32-package-l1-1-1.spec @@ -11,7 +11,7 @@ @ stdcall GetPackageFullName(long ptr ptr) kernel32.GetPackageFullName @ stub GetPackageId @ stub GetPackageInfo -@ stub GetPackagePath +@ stdcall GetPackagePath(ptr long ptr ptr) kernel32.GetPackagePath @ stdcall GetPackagesByPackageFamily(wstr ptr ptr ptr ptr) kernel32.GetPackagesByPackageFamily @ stub GetStagedPackageOrigin @ stub OpenPackageInfoByFullName diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index 4cfcf6df188..7d5160a51da 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -768,6 +768,7 @@ @ stdcall -import GetPackagesByPackageFamily(wstr ptr ptr ptr ptr) @ stdcall GetPackageFamilyName(long ptr ptr) kernelbase.GetPackageFamilyName @ stdcall GetPackageFullName(long ptr ptr) kernelbase.GetPackageFullName +@ stdcall -import GetPackagePath(ptr long ptr ptr) @ stdcall -import GetPhysicallyInstalledSystemMemory(ptr) @ stdcall -import GetPriorityClass(long) @ stdcall GetPrivateProfileIntA(str str long str) diff --git a/dlls/kernel32/tests/version.c b/dlls/kernel32/tests/version.c index ed1ef3e3bf7..1d5dc550d46 100644 --- a/dlls/kernel32/tests/version.c +++ b/dlls/kernel32/tests/version.c @@ -23,6 +23,7 @@ #include "winternl.h" #include "appmodel.h"
+static LONG (WINAPI * pGetPackagePath)(const PACKAGE_ID *, const UINT32, UINT32 *, WCHAR *); static LONG (WINAPI * pGetPackagesByPackageFamily)(const WCHAR *, UINT32 *, WCHAR **, UINT32 *, WCHAR *); static BOOL (WINAPI * pGetProductInfo)(DWORD, DWORD, DWORD, DWORD, DWORD *); static UINT (WINAPI * pGetSystemFirmwareTable)(DWORD, DWORD, void *, DWORD); @@ -45,6 +46,7 @@ static void init_function_pointers(void)
hmod = GetModuleHandleA("kernel32.dll");
+ GET_PROC(GetPackagePath); GET_PROC(GetPackagesByPackageFamily); GET_PROC(GetProductInfo); GET_PROC(GetSystemFirmwareTable); @@ -943,15 +945,15 @@ static void test_PackageIdFromFullName(void) static void test_package_info(void) { static const WCHAR package_family_msvc140[] = L"Microsoft.VCLibs.140.00_8wekyb3d8bbwe"; - UINT32 count, length, curr_length, size; + UINT32 count, length, curr_length, size, path_length, total_length; + WCHAR buffer[2048], path[MAX_PATH]; + PACKAGE_ID *id, saved_id; WCHAR *full_names[32]; BYTE id_buffer[512]; - WCHAR buffer[2048]; + DWORD arch, attrib; BOOL arch_found; SYSTEM_INFO si; unsigned int i; - PACKAGE_ID *id; - DWORD arch; LONG ret;
if (!pGetPackagesByPackageFamily) @@ -1032,6 +1034,10 @@ static void test_package_info(void) ok(count == ARRAY_SIZE(full_names), "Got unexpected count %u.\n", count); ok(length == ARRAY_SIZE(buffer), "Got unexpected length %u.\n", length);
+ length = 0; + ret = pGetPackagePath(NULL, 0, &length, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + count = 0; length = 0; ret = pGetPackagesByPackageFamily(package_family_msvc140, &count, NULL, &length, NULL); @@ -1050,6 +1056,7 @@ static void test_package_info(void) ok(count >= 1, "Got unexpected count %u.\n", count); ok(length > 1, "Got unexpected length %u.\n", length);
+ total_length = length; id = (PACKAGE_ID *)id_buffer; curr_length = 0; arch_found = FALSE; @@ -1063,9 +1070,56 @@ static void test_package_info(void)
if (id->processorArchitecture == arch) arch_found = TRUE; + + path_length = 0; + ret = pGetPackagePath(id, 0, &path_length, NULL); + ok(ret == ERROR_INSUFFICIENT_BUFFER, "Got unexpected ret %u.\n", ret); + ok(path_length > 1, "Got unexpected path_length %u.\n", path_length); + + length = path_length; + ret = pGetPackagePath(id, 0, &length, path); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); + ok(length == path_length, "Got unexpected length %u.\n", length); + attrib = GetFileAttributesW(path); + ok(attrib != INVALID_FILE_ATTRIBUTES && attrib & FILE_ATTRIBUTE_DIRECTORY, + "Got unexpected attrib %#x, GetLastError() %u.\n", attrib, GetLastError()); } - ok(curr_length == length, "Got unexpected length %u.\n", length); + ok(curr_length == total_length, "Got unexpected length %u.\n", length); ok(arch_found, "Did not find package for current arch.\n"); + + size = sizeof(id_buffer); + ret = pPackageIdFromFullName(full_names[0], 0, &size, id_buffer); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); + saved_id = *id; + + id->publisherId = NULL; + length = ARRAY_SIZE(path); + ret = pGetPackagePath(id, 0, &length, path); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + + *id = saved_id; + id->name = NULL; + length = ARRAY_SIZE(path); + ret = pGetPackagePath(id, 0, &length, path); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + + *id = saved_id; + id->publisher = NULL; + length = ARRAY_SIZE(path); + ret = pGetPackagePath(id, 0, &length, path); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); + + *id = saved_id; + id->processorArchitecture = ~0u; + length = ARRAY_SIZE(path); + ret = pGetPackagePath(id, 0, &length, path); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + + *id = saved_id; + id->name[0] = L'X'; + length = ARRAY_SIZE(path); + ret = pGetPackagePath(id, 0, &length, path); + ok(ret == ERROR_NOT_FOUND, "Got unexpected ret %u.\n", ret); }
START_TEST(version) diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index fc7671781f1..d318313e0f0 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -601,7 +601,7 @@ # @ stub GetPackageInfo # @ stub GetPackageInstallTime # @ stub GetPackageOSMaxVersionTested -# @ stub GetPackagePath +@ stdcall GetPackagePath(ptr long ptr ptr) # @ stub GetPackagePathByFullName # @ stub GetPackagePathOnVolume # @ stub GetPackageProperty diff --git a/dlls/kernelbase/version.c b/dlls/kernelbase/version.c index b2a6ceb182e..e762d446953 100644 --- a/dlls/kernelbase/version.c +++ b/dlls/kernelbase/version.c @@ -1839,3 +1839,85 @@ LONG WINAPI GetPackagesByPackageFamily(const WCHAR *family_name, UINT32 *count,
return short_buffer ? ERROR_INSUFFICIENT_BUFFER : ERROR_SUCCESS; } + + +/*********************************************************************** + * GetPackagePath (kernelbase.@) + */ +LONG WINAPI GetPackagePath(const PACKAGE_ID *package_id, const UINT32 reserved, UINT32 *length, WCHAR *path) +{ + WCHAR *key_name = NULL, *expanded_path = NULL; + UINT32 required_length, have_length; + unsigned int offset; + HKEY key = NULL; + DWORD size; + LONG ret; + + TRACE("package_id %p, reserved %u, length %p, path %p.\n", package_id, reserved, length, path); + + if (!length) + return ERROR_INVALID_PARAMETER; + if (!path && *length) + return ERROR_INVALID_PARAMETER; + + required_length = 0; + if ((ret = PackageFullNameFromId(package_id, &required_length, NULL)) != ERROR_INSUFFICIENT_BUFFER) + return ret; + + offset = lstrlenW(packages_key_name) + 1; + if (!(key_name = heap_alloc((offset + required_length) * sizeof(WCHAR)))) + { + ERR("No memory."); + return ERROR_OUTOFMEMORY; + } + + if ((ret = PackageFullNameFromId(package_id, &required_length, key_name + offset))) + goto done; + + memcpy(key_name, packages_key_name, (offset - 1) * sizeof(WCHAR)); + key_name[offset - 1] = L'\'; + + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, key_name, 0, KEY_READ, &key)) + { + WARN("Key %s not found.\n", debugstr_w(key_name)); + ret = ERROR_NOT_FOUND; + goto done; + } + if (RegGetValueW(key, NULL, L"Path", RRF_RT_REG_SZ, NULL, NULL, &size)) + { + WARN("Path value not found in %s.\n", debugstr_w(key_name)); + ret = ERROR_NOT_FOUND; + goto done; + } + if (!(expanded_path = heap_alloc(size))) + { + ERR("No memory."); + ret = ERROR_OUTOFMEMORY; + goto done; + } + if (RegGetValueW(key, NULL, L"Path", RRF_RT_REG_SZ, NULL, expanded_path, &size)) + { + WARN("Could not get Path value from %s.\n", debugstr_w(key_name)); + ret = ERROR_NOT_FOUND; + goto done; + } + + have_length = *length; + *length = lstrlenW(expanded_path) + 1; + if (have_length >= *length) + { + memcpy(path, expanded_path, *length * sizeof(*path)); + ret = ERROR_SUCCESS; + } + else + { + ret = ERROR_INSUFFICIENT_BUFFER; + } + +done: + if (key) + RegCloseKey(key); + heap_free(expanded_path); + heap_free(key_name); + return ret; +} diff --git a/include/appmodel.h b/include/appmodel.h index be59bc70f5f..c73cb8d26ef 100644 --- a/include/appmodel.h +++ b/include/appmodel.h @@ -82,6 +82,7 @@ LONG WINAPI AppPolicyGetProcessTerminationMethod(HANDLE token, AppPolicyProcessT LONG WINAPI AppPolicyGetShowDeveloperDiagnostic(HANDLE token, AppPolicyShowDeveloperDiagnostic *policy); LONG WINAPI AppPolicyGetThreadInitializationType(HANDLE token, AppPolicyThreadInitializationType *policy); LONG WINAPI AppPolicyGetWindowingModel(HANDLE processToken, AppPolicyWindowingModel *policy); +LONG WINAPI GetPackagePath(const PACKAGE_ID *package_id, const UINT32 reserved, UINT32 *length, WCHAR *path); LONG WINAPI GetPackagesByPackageFamily(const WCHAR *family_name, UINT32 *count, WCHAR **full_names, UINT32 *buffer_length, WCHAR *buffer); LONG WINAPI PackageFullNameFromId(const PACKAGE_ID *package_id, UINT32 *length, WCHAR *full_name);
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=87761
Your paranoid android.
=== debiant2 (build log) ===
Task: WineTest did not produce the wow32 report
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=87757
Your paranoid android.
=== debiant2 (build log) ===
Task: WineTest did not produce the wow32 report