Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47109 Signed-off-by: Brendan Shanks bshanks@codeweavers.com --- v3: As Zeb suggested, remove key/file in DllUnregisterServer.
dlls/winevulkan/Makefile.in | 2 +- dlls/winevulkan/make_vulkan | 5 +++ dlls/winevulkan/vulkan.c | 75 +++++++++++++++++++++++++++++++++ dlls/winevulkan/winevulkan.spec | 2 + include/wine/vulkan.h | 2 + loader/wine.inf.in | 1 + 6 files changed, 86 insertions(+), 1 deletion(-)
diff --git a/dlls/winevulkan/Makefile.in b/dlls/winevulkan/Makefile.in index e0bca6fad7..2ffff40c3a 100644 --- a/dlls/winevulkan/Makefile.in +++ b/dlls/winevulkan/Makefile.in @@ -1,6 +1,6 @@ MODULE = winevulkan.dll IMPORTLIB = winevulkan -IMPORTS = user32 gdi32 +IMPORTS = user32 gdi32 advapi32
C_SRCS = \ vulkan.c \ diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 3593410041..8dfde00fbf 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -2341,6 +2341,8 @@ class VkGenerator(object): f.write("#define WINE_VK_ALIGN DECLSPEC_ALIGN\n") f.write("#endif\n\n")
+ f.write("#define WINE_VK_SPEC_VERSION "{0}"\n\n".format(VK_XML_VERSION)) + # The overall strategy is to define independent constants and datatypes, # prior to complex structures and function calls to avoid forward declarations. for const in self.registry.consts: @@ -2485,6 +2487,9 @@ class VkGenerator(object): else: f.write("@ stub {0}\n".format(func.name))
+ f.write("@ stdcall -private DllRegisterServer()\n") + f.write("@ stdcall -private DllUnregisterServer()\n") + def generate_vulkan_loader_spec(self, f): self._generate_copyright(f, spec_file=True)
diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 59472bcef8..7282f40805 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -21,6 +21,7 @@
#include "windef.h" #include "winbase.h" +#include "winreg.h" #include "winuser.h"
#include "vulkan_private.h" @@ -1307,3 +1308,77 @@ void *native_vkGetInstanceProcAddrWINE(VkInstance instance, const char *name) { return vk_funcs->p_vkGetInstanceProcAddr(instance, name); } + + +static const WCHAR winevulkan_jsonW[] = {'\','w','i','n','e','v','u','l','k','a','n','.','j','s','o','n',0}; +static const WCHAR vulkan_driversW[] = {'S','o','f','t','w','a','r','e','\','K','h','r','o','n','o','s','\', + 'V','u','l','k','a','n','\','D','r','i','v','e','r','s',0}; +static BOOL writestr(HANDLE handle, const char *str) +{ + DWORD written; + return WriteFile(handle, str, strlen(str), &written, NULL); +} + +HRESULT WINAPI DllRegisterServer(void) +{ + WCHAR path[MAX_PATH]; + HANDLE file; + LRESULT result; + HKEY key; + DWORD zero = 0; + + /* Create the JSON manifest and registry key to register this ICD with the official Vulkan loader. */ + TRACE("\n"); + GetSystemDirectoryW(path, ARRAY_SIZE(path)); + lstrcatW(path, winevulkan_jsonW); + file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (file == INVALID_HANDLE_VALUE) + { ERR("Unable to create JSON manifest.\n"); return E_UNEXPECTED; } + + writestr(file, "{\r\n"); + writestr(file, " "file_format_version": "1.0.0",\r\n"); + writestr(file, " "ICD": {\r\n"); + writestr(file, " "library_path": "winevulkan.dll",\r\n"); + writestr(file, " "api_version": "" WINE_VK_SPEC_VERSION ""\r\n"); + writestr(file, " }\r\n"); + writestr(file, "}\r\n"); + CloseHandle(file); + + result = RegCreateKeyExW(HKEY_LOCAL_MACHINE, vulkan_driversW, + 0, NULL, 0, KEY_SET_VALUE, NULL, &key, NULL); + if (result != ERROR_SUCCESS) + { ERR("Unable to create registry key.\n"); return E_UNEXPECTED; } + + result = RegSetValueExW(key, path, 0, REG_DWORD, (const BYTE *)&zero, sizeof(zero)); + if (result != ERROR_SUCCESS) + { ERR("Unable to set registry value.\n"); return E_UNEXPECTED; } + + RegCloseKey(key); + return S_OK; +} + +HRESULT WINAPI DllUnregisterServer(void) +{ + WCHAR path[MAX_PATH]; + LRESULT result; + HKEY key; + + /* Remove the JSON manifest and registry key */ + TRACE("\n"); + GetSystemDirectoryW(path, ARRAY_SIZE(path)); + lstrcatW(path, winevulkan_jsonW); + if (!DeleteFileW(path)) + ERR("Unable to delete JSON file.\n"); + + result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, vulkan_driversW, + 0, KEY_SET_VALUE, &key); + if (result != ERROR_SUCCESS) + { ERR("Unable to open registry key.\n"); return E_UNEXPECTED; } + + result = RegDeleteValueW(key, path); + if (result != ERROR_SUCCESS) + ERR("Unable to delete registry key.\n"); + + RegCloseKey(key); + return S_OK; +} diff --git a/dlls/winevulkan/winevulkan.spec b/dlls/winevulkan/winevulkan.spec index 8cdf387857..c660d5c552 100644 --- a/dlls/winevulkan/winevulkan.spec +++ b/dlls/winevulkan/winevulkan.spec @@ -226,3 +226,5 @@ @ stdcall -private wine_vkUpdateDescriptorSetWithTemplate(ptr int64 int64 ptr) @ stdcall -private wine_vkUpdateDescriptorSets(ptr long ptr long ptr) @ stdcall -private wine_vkWaitForFences(ptr long ptr long int64) +@ stdcall -private DllRegisterServer() +@ stdcall -private DllUnregisterServer() diff --git a/include/wine/vulkan.h b/include/wine/vulkan.h index fe804fd23e..c30b72f00c 100644 --- a/include/wine/vulkan.h +++ b/include/wine/vulkan.h @@ -59,6 +59,8 @@ #define WINE_VK_ALIGN DECLSPEC_ALIGN #endif
+#define WINE_VK_SPEC_VERSION "1.1.130" + #define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256 #define VK_UUID_SIZE 16 #define VK_LUID_SIZE 8 diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 6e0cb21253..d0b156eb77 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2569,6 +2569,7 @@ HKLM,%CurrentVersion%\Telephony\Country List\998,"SameAreaRule",,"G" 11,,windowscodecs.dll,1 11,,winegstreamer.dll,1 11,,wineqtdecoder.dll,1 +11,,winevulkan.dll,1 11,,wintrust.dll,1 11,,iexplore.exe,1
Red Dead Redemption 2 requires and installs the official Vulkan loader, but the installer requires vulkan-1.dll's FILEVERSION to be lower than what it's installing.
Signed-off-by: Brendan Shanks bshanks@codeweavers.com --- The VulkanLoader installer script implementing the version check is at: https://github.com/KhronosGroup/Vulkan-Tools/blob/master/windows-runtime-ins...
dlls/vulkan-1/version.rc | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/vulkan-1/version.rc b/dlls/vulkan-1/version.rc index ec75462ddf..93cf661525 100644 --- a/dlls/vulkan-1/version.rc +++ b/dlls/vulkan-1/version.rc @@ -20,6 +20,7 @@
#define WINE_FILEDESCRIPTION_STR "Wine Vulkan Loader" #define WINE_FILENAME_STR "vulkan-1.dll" +#define WINE_FILEVERSION 1,0,0,0 /* Set to 1.0.0 so the official Vulkan runtime installer will replace this file */ #define WINE_FILEVERSION_STR PACKAGE_VERSION #define WINE_PRODUCTVERSION_STR PACKAGE_VERSION #define WINE_PRODUCTNAME_STR "Wine Vulkan"
Hi Brendan,
On 23.03.2020 20:16, Brendan Shanks wrote:
+static BOOL writestr(HANDLE handle, const char *str) +{
- DWORD written;
- return WriteFile(handle, str, strlen(str), &written, NULL);
+}
It may be a matter of taste, but it doesn't seem worth a helper. You could just do that with a single WriteFile() call.
+HRESULT WINAPI DllRegisterServer(void) +{
- WCHAR path[MAX_PATH];
- HANDLE file;
- LRESULT result;
- HKEY key;
- DWORD zero = 0;
- /* Create the JSON manifest and registry key to register this ICD with the official Vulkan loader. */
- TRACE("\n");
- GetSystemDirectoryW(path, ARRAY_SIZE(path));
- lstrcatW(path, winevulkan_jsonW);
- file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- if (file == INVALID_HANDLE_VALUE)
{ ERR("Unable to create JSON manifest.\n"); return E_UNEXPECTED; }
Please try to match style of the file you change.
- writestr(file, "{\r\n");
- writestr(file, " "file_format_version": "1.0.0",\r\n");
- writestr(file, " "ICD": {\r\n");
- writestr(file, " "library_path": "winevulkan.dll",\r\n");
It may not be too important in this case, but it's usually better to use full path in such places, something like a result of GetModuleFileNameW(). What do real IDSs use?
- writestr(file, " "api_version": "" WINE_VK_SPEC_VERSION ""\r\n");
- writestr(file, " }\r\n");
- writestr(file, "}\r\n");
- CloseHandle(file);
- result = RegCreateKeyExW(HKEY_LOCAL_MACHINE, vulkan_driversW,
0, NULL, 0, KEY_SET_VALUE, NULL, &key, NULL);
- if (result != ERROR_SUCCESS)
{ ERR("Unable to create registry key.\n"); return E_UNEXPECTED; }
- result = RegSetValueExW(key, path, 0, REG_DWORD, (const BYTE *)&zero, sizeof(zero));
- if (result != ERROR_SUCCESS)
{ ERR("Unable to set registry value.\n"); return E_UNEXPECTED; }
Style aside, you leak a handle in second error path. Error handling could also be simplified a bit.
+HRESULT WINAPI DllUnregisterServer(void) +{
- WCHAR path[MAX_PATH];
- LRESULT result;
- HKEY key;
- /* Remove the JSON manifest and registry key */
- TRACE("\n");
- GetSystemDirectoryW(path, ARRAY_SIZE(path));
- lstrcatW(path, winevulkan_jsonW);
- if (!DeleteFileW(path))
ERR("Unable to delete JSON file.\n");
- result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, vulkan_driversW,
0, KEY_SET_VALUE, &key);
- if (result != ERROR_SUCCESS)
{ ERR("Unable to open registry key.\n"); return E_UNEXPECTED; }
This is not really an error.
- result = RegDeleteValueW(key, path);
- if (result != ERROR_SUCCESS)
ERR("Unable to delete registry key.\n");
- RegCloseKey(key);
- return S_OK;
+}
Those ERRs should we WARNs or removed. Eg. it's not really an error when it's ran with no winevulkan registered or if you run regsvr32 -u twice in a raw. We should report success and print no errors in such case.
Thanks,
Jacek
Hi Jacek,
Thanks for the feedback.
On Mar 23, 2020, at 4:50 PM, Jacek Caban jacek@codeweavers.com wrote:
Hi Brendan,
On 23.03.2020 20:16, Brendan Shanks wrote:
+static BOOL writestr(HANDLE handle, const char *str) +{
- DWORD written;
- return WriteFile(handle, str, strlen(str), &written, NULL);
+}
It may be a matter of taste, but it doesn't seem worth a helper. You could just do that with a single WriteFile() call.
My concern with calling WriteFile directly is that I would have to duplicate the string literals (once for the arg and once for calling strlen()). That would be ok for simple one-word strings, but these include whitespace and escape characters, and could easily get out of sync without being visually obvious.
- writestr(file, "{\r\n");
- writestr(file, " "file_format_version": "1.0.0",\r\n");
- writestr(file, " "ICD": {\r\n");
- writestr(file, " "library_path": "winevulkan.dll",\r\n");
It may not be too important in this case, but it's usually better to use full path in such places, something like a result of GetModuleFileNameW(). What do real IDSs use?
Here’s what the spec says: "The "library_path" specifies either a filename, a relative pathname, or a full pathname to an ICD shared library file. If "library_path" specifies a relative pathname, it is relative to the path of the JSON manifest file. If "library_path" specifies a filename, the library must live in the system's shared object search path."
NVIDIA uses a relative path on Windows, and just a filename on Linux. I think you’re right that a full path would be best, I’ll add that with GetModuleFileName().
- writestr(file, " "api_version": "" WINE_VK_SPEC_VERSION ""\r\n");
- writestr(file, " }\r\n");
- writestr(file, "}\r\n");
- CloseHandle(file);
- result = RegCreateKeyExW(HKEY_LOCAL_MACHINE, vulkan_driversW,
0, NULL, 0, KEY_SET_VALUE, NULL, &key, NULL);
- if (result != ERROR_SUCCESS)
{ ERR("Unable to create registry key.\n"); return E_UNEXPECTED; }
- result = RegSetValueExW(key, path, 0, REG_DWORD, (const BYTE *)&zero, sizeof(zero));
- if (result != ERROR_SUCCESS)
{ ERR("Unable to set registry value.\n"); return E_UNEXPECTED; }
Style aside, you leak a handle in second error path. Error handling could also be simplified a bit.
+HRESULT WINAPI DllUnregisterServer(void) +{
- WCHAR path[MAX_PATH];
- LRESULT result;
- HKEY key;
- /* Remove the JSON manifest and registry key */
- TRACE("\n");
- GetSystemDirectoryW(path, ARRAY_SIZE(path));
- lstrcatW(path, winevulkan_jsonW);
- if (!DeleteFileW(path))
ERR("Unable to delete JSON file.\n");
- result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, vulkan_driversW,
0, KEY_SET_VALUE, &key);
- if (result != ERROR_SUCCESS)
{ ERR("Unable to open registry key.\n"); return E_UNEXPECTED; }
This is not really an error.
- result = RegDeleteValueW(key, path);
- if (result != ERROR_SUCCESS)
ERR("Unable to delete registry key.\n");
- RegCloseKey(key);
- return S_OK;
+}
Those ERRs should we WARNs or removed. Eg. it's not really an error when it's ran with no winevulkan registered or if you run regsvr32 -u twice in a raw. We should report success and print no errors in such case.
Yes you’re right, I’ll fix all these.
Thanks, Brendan