Blender V4.3
winstuff.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10#ifdef WIN32
11
12# include <conio.h>
13# include <shlwapi.h>
14# include <stdio.h>
15# include <stdlib.h>
16# define COBJMACROS /* Remove this when converting to C++ */
17# include <dxgi.h>
18
19# include "MEM_guardedalloc.h"
20
21# define WIN32_SKIP_HKEY_PROTECTION /* Need to use HKEY. */
22# include "BLI_fileops.h"
23# include "BLI_path_utils.hh"
24# include "BLI_string.h"
25# include "BLI_utildefines.h"
26# include "BLI_winstuff.h"
27
28# include "utf_winfunc.hh"
29# include "utfconv.hh"
30
31/* FILE_MAXDIR + FILE_MAXFILE */
32
33int BLI_windows_get_executable_dir(char r_dirpath[/*FILE_MAXDIR*/])
34{
35 char filepath[FILE_MAX];
36 char dir[FILE_MAX];
37 int a;
38 /* Change to utf support. */
39 GetModuleFileName(NULL, filepath, sizeof(filepath));
40 BLI_path_split_dir_part(filepath, dir, sizeof(dir)); /* shouldn't be relative */
41 a = strlen(dir);
42 if (dir[a - 1] == '\\') {
43 dir[a - 1] = 0;
44 }
45
46 BLI_strncpy(r_dirpath, dir, FILE_MAXDIR);
47
48 return 1;
49}
50
52{
53 char install_dir[FILE_MAXDIR];
55 return (BLI_strcasestr(install_dir, "\\WindowsApps\\") != NULL);
56}
57
58static void registry_error(HKEY root, const char *message)
59{
60 if (root) {
61 RegCloseKey(root);
62 }
63 fprintf(stderr, "%s\n", message);
64}
65
66static bool open_registry_hive(bool all_users, HKEY *r_root)
67{
68 if (RegOpenKeyEx(all_users ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
69 "Software\\Classes",
70 0,
71 KEY_ALL_ACCESS,
72 r_root) != ERROR_SUCCESS)
73 {
74 registry_error(*r_root, "Unable to open the registry with the required permissions");
75 return false;
76 }
77 return true;
78}
79
80static bool register_blender_prog_id(const char *prog_id,
81 const char *executable,
82 const char *friendly_name,
83 bool all_users)
84{
85 LONG lresult;
86 HKEY root = 0;
87 HKEY hkey_progid = 0;
88 char buffer[256];
89 DWORD dwd = 0;
90
91 if (!open_registry_hive(all_users, &root)) {
92 return false;
93 }
94
95 lresult = RegCreateKeyEx(
96 root, prog_id, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_progid, &dwd);
97
98 if (lresult == ERROR_SUCCESS) {
99 lresult = RegSetValueEx(
100 hkey_progid, NULL, 0, REG_SZ, (BYTE *)friendly_name, strlen(friendly_name) + 1);
101 }
102 if (lresult == ERROR_SUCCESS) {
103 lresult = RegSetValueEx(
104 hkey_progid, "AppUserModelId", 0, REG_SZ, (BYTE *)prog_id, strlen(prog_id) + 1);
105 }
106 if (lresult != ERROR_SUCCESS) {
107 registry_error(root, "Unable to register Blender App Id");
108 return false;
109 }
110
111 SNPRINTF(buffer, "%s\\shell\\open", prog_id);
112 lresult = RegCreateKeyEx(
113 root, buffer, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_progid, &dwd);
114
115 lresult = RegSetValueEx(
116 hkey_progid, "FriendlyAppName", 0, REG_SZ, (BYTE *)friendly_name, strlen(friendly_name) + 1);
117
118 SNPRINTF(buffer, "%s\\shell\\open\\command", prog_id);
119
120 lresult = RegCreateKeyEx(
121 root, buffer, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_progid, &dwd);
122
123 if (lresult == ERROR_SUCCESS) {
124 SNPRINTF(buffer, "\"%s\" \"%%1\"", executable);
125 lresult = RegSetValueEx(hkey_progid, NULL, 0, REG_SZ, (BYTE *)buffer, strlen(buffer) + 1);
126 RegCloseKey(hkey_progid);
127 }
128 if (lresult != ERROR_SUCCESS) {
129 registry_error(root, "Unable to register Blender App Id");
130 return false;
131 }
132
133 SNPRINTF(buffer, "%s\\DefaultIcon", prog_id);
134 lresult = RegCreateKeyEx(
135 root, buffer, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_progid, &dwd);
136
137 if (lresult == ERROR_SUCCESS) {
138 SNPRINTF(buffer, "\"%s\", 1", executable);
139 lresult = RegSetValueEx(hkey_progid, NULL, 0, REG_SZ, (BYTE *)buffer, strlen(buffer) + 1);
140 RegCloseKey(hkey_progid);
141 }
142 if (lresult != ERROR_SUCCESS) {
143 registry_error(root, "Unable to register Blender App Id");
144 return false;
145 }
146 return true;
147}
148
149bool BLI_windows_register_blend_extension(const bool all_users)
150{
152 fprintf(stderr, "Registration not possible from Microsoft Store installation.");
153 return false;
154 }
155
156 HKEY root = 0;
157 char blender_path[MAX_PATH];
158 char *blender_app;
159 HKEY hkey = 0;
160 LONG lresult;
161 DWORD dwd = 0;
162 const char *prog_id = BLENDER_WIN_APPID;
163 const char *friendly_name = BLENDER_WIN_APPID_FRIENDLY_NAME;
164
165 GetModuleFileName(0, blender_path, sizeof(blender_path));
166
167 /* Prevent overflow when we add -launcher to the executable name. */
168 if (strlen(blender_path) > (sizeof(blender_path) - 10))
169 return false;
170
171 /* Replace the actual app name with the wrapper. */
172 blender_app = strstr(blender_path, "blender.exe");
173 if (!blender_app) {
174 return false;
175 }
176 strcpy(blender_app, "blender-launcher.exe");
177
178 if (!open_registry_hive(all_users, &root)) {
179 return false;
180 }
181
182 if (!register_blender_prog_id(prog_id, blender_path, friendly_name, all_users)) {
183 registry_error(root, "Unable to register Blend document type");
184 return false;
185 }
186
187 lresult = RegCreateKeyEx(
188 root, ".blend", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, &dwd);
189 if (lresult == ERROR_SUCCESS) {
190 /* Set this instance the default. */
191 lresult = RegSetValueEx(hkey, NULL, 0, REG_SZ, (BYTE *)prog_id, strlen(prog_id) + 1);
192
193 if (lresult != ERROR_SUCCESS) {
194 registry_error(root, "Unable to register Blend document type");
195 RegCloseKey(hkey);
196 return false;
197 }
198 RegCloseKey(hkey);
199
200 lresult = RegCreateKeyEx(root,
201 ".blend\\OpenWithProgids",
202 0,
203 NULL,
204 REG_OPTION_NON_VOLATILE,
205 KEY_ALL_ACCESS,
206 NULL,
207 &hkey,
208 &dwd);
209
210 if (lresult != ERROR_SUCCESS) {
211 registry_error(root, "Unable to register Blend document type");
212 RegCloseKey(hkey);
213 return false;
214 }
215 lresult = RegSetValueEx(hkey, prog_id, 0, REG_NONE, NULL, 0);
216 RegCloseKey(hkey);
217 }
218
219 if (lresult != ERROR_SUCCESS) {
220 registry_error(root, "Unable to register Blend document type");
221 return false;
222 }
223
224 if (!BLI_windows_update_pinned_launcher(blender_path)) {
225 fprintf(stderr, "Update of pinned launcher failed.");
226 return false;
227 }
228
229# ifdef WITH_BLENDER_THUMBNAILER
230 {
231 char reg_cmd[MAX_PATH * 2];
232 char install_dir[FILE_MAXDIR];
233 char system_dir[FILE_MAXDIR];
235 GetSystemDirectory(system_dir, sizeof(system_dir));
236 const char *thumbnail_handler = "BlendThumb.dll";
237 SNPRINTF(reg_cmd, "%s\\regsvr32 /s \"%s\\%s\"", system_dir, install_dir, thumbnail_handler);
238 system(reg_cmd);
239 }
240# endif
241
242 RegCloseKey(root);
243 char message[256];
244 SNPRINTF(message,
245 "Blend file extension registered for %s.",
246 all_users ? "all users" : "the current user");
247 printf("%s\n", message);
248
249 return true;
250}
251
252bool BLI_windows_unregister_blend_extension(const bool all_users)
253{
255 fprintf(stderr, "Unregistration not possible from Microsoft Store installation.");
256 return false;
257 }
258
259 HKEY root = 0;
260 HKEY hkey = 0;
261 LONG lresult;
262
263 if (!open_registry_hive(all_users, &root)) {
264 return false;
265 }
266
267 /* Don't stop on failure. We want to allow unregister after unregister. */
268
269 RegDeleteTree(root, BLENDER_WIN_APPID);
270
271 lresult = RegOpenKeyEx(root, ".blend", 0, KEY_ALL_ACCESS, &hkey);
272 if (lresult == ERROR_SUCCESS) {
273 char buffer[256] = {0};
274 DWORD size = sizeof(buffer);
275 lresult = RegGetValueA(hkey, NULL, NULL, RRF_RT_REG_SZ, NULL, &buffer, &size);
276 if (lresult == ERROR_SUCCESS && STREQ(buffer, BLENDER_WIN_APPID)) {
277 RegSetValueEx(hkey, NULL, 0, REG_SZ, 0, 0);
278 }
279 }
280
281# ifdef WITH_BLENDER_THUMBNAILER
282 {
283 char reg_cmd[MAX_PATH * 2];
284 char install_dir[FILE_MAXDIR];
285 char system_dir[FILE_MAXDIR];
287 GetSystemDirectory(system_dir, sizeof(system_dir));
288 const char *thumbnail_handler = "BlendThumb.dll";
289 SNPRINTF(reg_cmd, "%s\\regsvr32 /u /s \"%s\\%s\"", system_dir, install_dir, thumbnail_handler);
290 system(reg_cmd);
291 }
292# endif
293
294 lresult = RegOpenKeyEx(hkey, "OpenWithProgids", 0, KEY_ALL_ACCESS, &hkey);
295 if (lresult == ERROR_SUCCESS) {
296 RegDeleteValue(hkey, BLENDER_WIN_APPID);
297 }
298
299 RegCloseKey(root);
300 char message[256];
301 SNPRINTF(message,
302 "Blend file extension unregistered for %s.",
303 all_users ? "all users" : "the current user");
304 printf("%s\n", message);
305
306 return true;
307}
308
315static bool BLI_windows_file_operation_is_registered(const char *extension, const char *operation)
316{
317 HKEY hKey;
318 HRESULT hr = AssocQueryKey(ASSOCF_INIT_IGNOREUNKNOWN,
319 ASSOCKEY_SHELLEXECCLASS,
320 (LPCTSTR)extension,
321 (LPCTSTR)operation,
322 &hKey);
323 if (SUCCEEDED(hr)) {
324 RegCloseKey(hKey);
325 return true;
326 }
327 return false;
328}
329
330bool BLI_windows_external_operation_supported(const char *filepath, const char *operation)
331{
332 if (STREQ(operation, "open") || STREQ(operation, "properties")) {
333 return true;
334 }
335
336 if (BLI_is_dir(filepath)) {
337 return BLI_windows_file_operation_is_registered("Directory", operation);
338 }
339
340 const char *extension = BLI_path_extension(filepath);
341 return BLI_windows_file_operation_is_registered(extension, operation);
342}
343
344bool BLI_windows_external_operation_execute(const char *filepath, const char *operation)
345{
346 WCHAR wpath[FILE_MAX];
347 if (conv_utf_8_to_16(filepath, wpath, ARRAY_SIZE(wpath)) != 0) {
348 return false;
349 }
350
351 WCHAR woperation[FILE_MAX];
352 if (conv_utf_8_to_16(operation, woperation, ARRAY_SIZE(woperation)) != 0) {
353 return false;
354 }
355
356 SHELLEXECUTEINFOW shellinfo = {0};
357 shellinfo.cbSize = sizeof(SHELLEXECUTEINFO);
358 shellinfo.fMask = SEE_MASK_INVOKEIDLIST;
359 shellinfo.lpVerb = woperation;
360 shellinfo.lpFile = wpath;
361 shellinfo.nShow = SW_SHOW;
362
363 return ShellExecuteExW(&shellinfo);
364}
365
366bool BLI_windows_execute_self(const char *parameters,
367 const bool wait,
368 const bool elevated,
369 const bool silent)
370{
371 char blender_path[MAX_PATH];
372 GetModuleFileName(0, blender_path, MAX_PATH);
373
374 SHELLEXECUTEINFOA shellinfo = {0};
375 shellinfo.cbSize = sizeof(SHELLEXECUTEINFO);
376 shellinfo.fMask = wait ? SEE_MASK_NOCLOSEPROCESS : SEE_MASK_DEFAULT;
377 shellinfo.hwnd = NULL;
378 shellinfo.lpVerb = elevated ? "runas" : NULL;
379 shellinfo.lpFile = blender_path;
380 shellinfo.lpParameters = parameters;
381 shellinfo.lpDirectory = NULL;
382 shellinfo.nShow = silent ? SW_HIDE : SW_SHOW;
383 shellinfo.hInstApp = NULL;
384 shellinfo.hProcess = 0;
385
386 DWORD exitCode = 0;
387 if (!ShellExecuteExA(&shellinfo)) {
388 return false;
389 }
390 if (!wait) {
391 return true;
392 }
393
394 if (shellinfo.hProcess != 0) {
395 WaitForSingleObject(shellinfo.hProcess, INFINITE);
396 GetExitCodeProcess(shellinfo.hProcess, &exitCode);
397 CloseHandle(shellinfo.hProcess);
398 return (exitCode == 0);
399 }
400
401 return false;
402}
403
404void BLI_windows_get_default_root_dir(char root[4])
405{
406 char str[MAX_PATH + 1];
407
408 /* the default drive to resolve a directory without a specified drive
409 * should be the Windows installation drive, since this was what the OS
410 * assumes. */
411 if (GetWindowsDirectory(str, MAX_PATH + 1)) {
412 root[0] = str[0];
413 root[1] = ':';
414 root[2] = '\\';
415 root[3] = '\0';
416 }
417 else {
418 /* if GetWindowsDirectory fails, something has probably gone wrong,
419 * we are trying the blender install dir though */
420 if (GetModuleFileName(NULL, str, MAX_PATH + 1)) {
421 printf(
422 "Error! Could not get the Windows Directory - "
423 "Defaulting to Blender installation Dir!\n");
424 root[0] = str[0];
425 root[1] = ':';
426 root[2] = '\\';
427 root[3] = '\0';
428 }
429 else {
430 DWORD tmp;
431 int i;
432 int rc = 0;
433 /* now something has gone really wrong - still trying our best guess */
434 printf(
435 "Error! Could not get the Windows Directory - "
436 "Defaulting to first valid drive! Path might be invalid!\n");
437 tmp = GetLogicalDrives();
438 for (i = 2; i < 26; i++) {
439 if ((tmp >> i) & 1) {
440 root[0] = 'a' + i;
441 root[1] = ':';
442 root[2] = '\\';
443 root[3] = '\0';
444 if (GetFileAttributes(root) != 0xFFFFFFFF) {
445 rc = i;
446 break;
447 }
448 }
449 }
450 if (0 == rc) {
451 printf("ERROR in 'BLI_windows_get_default_root_dir': can't find a valid drive!\n");
452 root[0] = 'C';
453 root[1] = ':';
454 root[2] = '\\';
455 root[3] = '\0';
456 }
457 }
458 }
459}
460
461bool BLI_windows_get_directx_driver_version(const wchar_t *deviceSubString,
462 long long *r_driverVersion)
463{
464 IDXGIFactory *pFactory = NULL;
465 IDXGIAdapter *pAdapter = NULL;
466 if (CreateDXGIFactory(__uuidof(IDXGIFactory), (void **)&pFactory) == S_OK) {
467 for (UINT i = 0; pFactory->EnumAdapters(i, &pAdapter) != DXGI_ERROR_NOT_FOUND; ++i) {
468 LARGE_INTEGER version;
469 if (pAdapter->CheckInterfaceSupport(__uuidof(IDXGIDevice), &version) == S_OK) {
470 DXGI_ADAPTER_DESC desc;
471 if (pAdapter->GetDesc(&desc) == S_OK) {
472 if (wcsstr(desc.Description, deviceSubString)) {
473 *r_driverVersion = version.QuadPart;
474
475 pAdapter->Release();
476 pFactory->Release();
477 return true;
478 }
479 }
480 }
481
482 pAdapter->Release();
483 }
484 pFactory->Release();
485 }
486
487 return false;
488}
489
490#else
491
492/* intentionally empty for UNIX */
493
494#endif
File and directory operations.
bool BLI_is_dir(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:433
#define FILE_MAX
void void BLI_path_split_dir_part(const char *filepath, char *dir, size_t dir_maxncpy) ATTR_NONNULL(1
const char * BLI_path_extension(const char *filepath) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
#define FILE_MAXDIR
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
int char * BLI_strcasestr(const char *s, const char *find) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define ARRAY_SIZE(arr)
#define STREQ(a, b)
Compatibility-like things for windows.
bool BLI_windows_external_operation_supported(const char *filepath, const char *operation)
bool BLI_windows_unregister_blend_extension(bool all_users)
bool BLI_windows_execute_self(const char *parameters, const bool wait, const bool elevated, const bool silent)
bool BLI_windows_get_directx_driver_version(const wchar_t *deviceSubString, long long *r_driverVersion)
void BLI_windows_get_default_root_dir(char root_dir[4])
bool BLI_windows_update_pinned_launcher(const char *launcher_path)
bool BLI_windows_external_operation_execute(const char *filepath, const char *operation)
int BLI_windows_get_executable_dir(char r_dirpath[])
bool BLI_windows_is_store_install(void)
bool BLI_windows_register_blend_extension(bool all_users)
Read Guarded memory(de)allocation.
#define printf
#define NULL
#define str(s)
double parameters[NUM_PARAMETERS]
int conv_utf_8_to_16(const char *in8, wchar_t *out16, size_t size16)
Definition utfconv.cc:182