Blender V4.5
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
9
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(nullptr, 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\\") != nullptr);
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(root,
96 prog_id,
97 0,
98 nullptr,
99 REG_OPTION_NON_VOLATILE,
100 KEY_ALL_ACCESS,
101 nullptr,
102 &hkey_progid,
103 &dwd);
104
105 if (lresult == ERROR_SUCCESS) {
106 lresult = RegSetValueEx(
107 hkey_progid, nullptr, 0, REG_SZ, (BYTE *)friendly_name, strlen(friendly_name) + 1);
108 }
109 if (lresult == ERROR_SUCCESS) {
110 lresult = RegSetValueEx(
111 hkey_progid, "AppUserModelId", 0, REG_SZ, (BYTE *)prog_id, strlen(prog_id) + 1);
112 }
113 if (lresult != ERROR_SUCCESS) {
114 registry_error(root, "Unable to register Blender App Id");
115 return false;
116 }
117
118 SNPRINTF(buffer, "%s\\shell\\open", prog_id);
119 lresult = RegCreateKeyEx(root,
120 buffer,
121 0,
122 nullptr,
123 REG_OPTION_NON_VOLATILE,
124 KEY_ALL_ACCESS,
125 nullptr,
126 &hkey_progid,
127 &dwd);
128
129 lresult = RegSetValueEx(
130 hkey_progid, "FriendlyAppName", 0, REG_SZ, (BYTE *)friendly_name, strlen(friendly_name) + 1);
131
132 SNPRINTF(buffer, "%s\\shell\\open\\command", prog_id);
133
134 lresult = RegCreateKeyEx(root,
135 buffer,
136 0,
137 nullptr,
138 REG_OPTION_NON_VOLATILE,
139 KEY_ALL_ACCESS,
140 nullptr,
141 &hkey_progid,
142 &dwd);
143
144 if (lresult == ERROR_SUCCESS) {
145 SNPRINTF(buffer, "\"%s\" \"%%1\"", executable);
146 lresult = RegSetValueEx(hkey_progid, nullptr, 0, REG_SZ, (BYTE *)buffer, strlen(buffer) + 1);
147 RegCloseKey(hkey_progid);
148 }
149 if (lresult != ERROR_SUCCESS) {
150 registry_error(root, "Unable to register Blender App Id");
151 return false;
152 }
153
154 SNPRINTF(buffer, "%s\\DefaultIcon", prog_id);
155 lresult = RegCreateKeyEx(root,
156 buffer,
157 0,
158 nullptr,
159 REG_OPTION_NON_VOLATILE,
160 KEY_ALL_ACCESS,
161 nullptr,
162 &hkey_progid,
163 &dwd);
164
165 if (lresult == ERROR_SUCCESS) {
166 SNPRINTF(buffer, "\"%s\", 1", executable);
167 lresult = RegSetValueEx(hkey_progid, nullptr, 0, REG_SZ, (BYTE *)buffer, strlen(buffer) + 1);
168 RegCloseKey(hkey_progid);
169 }
170 if (lresult != ERROR_SUCCESS) {
171 registry_error(root, "Unable to register Blender App Id");
172 return false;
173 }
174 return true;
175}
176
177bool BLI_windows_register_blend_extension(const bool all_users)
178{
180 fprintf(stderr, "Registration not possible from Microsoft Store installation.");
181 return false;
182 }
183
184 HKEY root = 0;
185 char blender_path[MAX_PATH];
186 char *blender_app;
187 HKEY hkey = 0;
188 LONG lresult;
189 DWORD dwd = 0;
190 const char *prog_id = BLENDER_WIN_APPID;
191 const char *friendly_name = BLENDER_WIN_APPID_FRIENDLY_NAME;
192
193 GetModuleFileName(0, blender_path, sizeof(blender_path));
194
195 /* Prevent overflow when we add -launcher to the executable name. */
196 if (strlen(blender_path) > (sizeof(blender_path) - 10))
197 return false;
198
199 /* Replace the actual app name with the wrapper. */
200 blender_app = strstr(blender_path, "blender.exe");
201 if (!blender_app) {
202 return false;
203 }
204 strcpy(blender_app, "blender-launcher.exe");
205
206 if (!open_registry_hive(all_users, &root)) {
207 return false;
208 }
209
210 if (!register_blender_prog_id(prog_id, blender_path, friendly_name, all_users)) {
211 registry_error(root, "Unable to register Blend document type");
212 return false;
213 }
214
215 lresult = RegCreateKeyEx(
216 root, ".blend", 0, nullptr, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, nullptr, &hkey, &dwd);
217 if (lresult == ERROR_SUCCESS) {
218 /* Set this instance the default. */
219 lresult = RegSetValueEx(hkey, nullptr, 0, REG_SZ, (BYTE *)prog_id, strlen(prog_id) + 1);
220
221 if (lresult != ERROR_SUCCESS) {
222 registry_error(root, "Unable to register Blend document type");
223 RegCloseKey(hkey);
224 return false;
225 }
226 RegCloseKey(hkey);
227
228 lresult = RegCreateKeyEx(root,
229 ".blend\\OpenWithProgids",
230 0,
231 nullptr,
232 REG_OPTION_NON_VOLATILE,
233 KEY_ALL_ACCESS,
234 nullptr,
235 &hkey,
236 &dwd);
237
238 if (lresult != ERROR_SUCCESS) {
239 registry_error(root, "Unable to register Blend document type");
240 RegCloseKey(hkey);
241 return false;
242 }
243 lresult = RegSetValueEx(hkey, prog_id, 0, REG_NONE, nullptr, 0);
244 RegCloseKey(hkey);
245 }
246
247 if (lresult != ERROR_SUCCESS) {
248 registry_error(root, "Unable to register Blend document type");
249 return false;
250 }
251
252 if (!BLI_windows_update_pinned_launcher(blender_path)) {
253 fprintf(stderr, "Update of pinned launcher failed.");
254 return false;
255 }
256
257# ifdef WITH_BLENDER_THUMBNAILER
258 {
259 char reg_cmd[MAX_PATH * 2];
260 char install_dir[FILE_MAXDIR];
261 char system_dir[FILE_MAXDIR];
263 GetSystemDirectory(system_dir, sizeof(system_dir));
264 const char *thumbnail_handler = "BlendThumb.dll";
265 SNPRINTF(reg_cmd, "%s\\regsvr32 /s \"%s\\%s\"", system_dir, install_dir, thumbnail_handler);
266 system(reg_cmd);
267 }
268# endif
269
270 RegCloseKey(root);
271 char message[256];
272 SNPRINTF(message,
273 "Blend file extension registered for %s.",
274 all_users ? "all users" : "the current user");
275 printf("%s\n", message);
276
277 return true;
278}
279
280bool BLI_windows_unregister_blend_extension(const bool all_users)
281{
283 fprintf(stderr, "Unregistration not possible from Microsoft Store installation.");
284 return false;
285 }
286
287 HKEY root = 0;
288 HKEY hkey = 0;
289 LONG lresult;
290
291 if (!open_registry_hive(all_users, &root)) {
292 return false;
293 }
294
295 /* Don't stop on failure. We want to allow unregister after unregister. */
296
297 RegDeleteTree(root, BLENDER_WIN_APPID);
298
299 lresult = RegOpenKeyEx(root, ".blend", 0, KEY_ALL_ACCESS, &hkey);
300 if (lresult == ERROR_SUCCESS) {
301 char buffer[256] = {0};
302 DWORD size = sizeof(buffer);
303 lresult = RegGetValueA(hkey, nullptr, nullptr, RRF_RT_REG_SZ, nullptr, &buffer, &size);
304 if (lresult == ERROR_SUCCESS && STREQ(buffer, BLENDER_WIN_APPID)) {
305 RegSetValueEx(hkey, nullptr, 0, REG_SZ, 0, 0);
306 }
307 }
308
309# ifdef WITH_BLENDER_THUMBNAILER
310 {
311 char reg_cmd[MAX_PATH * 2];
312 char install_dir[FILE_MAXDIR];
313 char system_dir[FILE_MAXDIR];
315 GetSystemDirectory(system_dir, sizeof(system_dir));
316 const char *thumbnail_handler = "BlendThumb.dll";
317 SNPRINTF(reg_cmd, "%s\\regsvr32 /u /s \"%s\\%s\"", system_dir, install_dir, thumbnail_handler);
318 system(reg_cmd);
319 }
320# endif
321
322 lresult = RegOpenKeyEx(hkey, "OpenWithProgids", 0, KEY_ALL_ACCESS, &hkey);
323 if (lresult == ERROR_SUCCESS) {
324 RegDeleteValue(hkey, BLENDER_WIN_APPID);
325 }
326
327 RegCloseKey(root);
328 char message[256];
329 SNPRINTF(message,
330 "Blend file extension unregistered for %s.",
331 all_users ? "all users" : "the current user");
332 printf("%s\n", message);
333
334 return true;
335}
336
343static bool BLI_windows_file_operation_is_registered(const char *extension, const char *operation)
344{
345 HKEY hKey;
346 HRESULT hr = AssocQueryKey(ASSOCF_INIT_IGNOREUNKNOWN,
347 ASSOCKEY_SHELLEXECCLASS,
348 (LPCTSTR)extension,
349 (LPCTSTR)operation,
350 &hKey);
351 if (SUCCEEDED(hr)) {
352 RegCloseKey(hKey);
353 return true;
354 }
355 return false;
356}
357
358bool BLI_windows_external_operation_supported(const char *filepath, const char *operation)
359{
360 if (STREQ(operation, "open") || STREQ(operation, "properties")) {
361 return true;
362 }
363
364 if (BLI_is_dir(filepath)) {
365 return BLI_windows_file_operation_is_registered("Directory", operation);
366 }
367
368 const char *extension = BLI_path_extension(filepath);
369 return BLI_windows_file_operation_is_registered(extension, operation);
370}
371
372bool BLI_windows_external_operation_execute(const char *filepath, const char *operation)
373{
374 WCHAR wpath[FILE_MAX];
375 if (conv_utf_8_to_16(filepath, wpath, ARRAY_SIZE(wpath)) != 0) {
376 return false;
377 }
378
379 WCHAR woperation[FILE_MAX];
380 if (conv_utf_8_to_16(operation, woperation, ARRAY_SIZE(woperation)) != 0) {
381 return false;
382 }
383
384 SHELLEXECUTEINFOW shellinfo = {0};
385 shellinfo.cbSize = sizeof(SHELLEXECUTEINFO);
386 shellinfo.fMask = SEE_MASK_INVOKEIDLIST;
387 shellinfo.lpVerb = woperation;
388 shellinfo.lpFile = wpath;
389 shellinfo.nShow = SW_SHOW;
390
391 return ShellExecuteExW(&shellinfo);
392}
393
394bool BLI_windows_execute_self(const char *parameters,
395 const bool wait,
396 const bool elevated,
397 const bool silent)
398{
399 char blender_path[MAX_PATH];
400 GetModuleFileName(0, blender_path, MAX_PATH);
401
402 SHELLEXECUTEINFOA shellinfo = {0};
403 shellinfo.cbSize = sizeof(SHELLEXECUTEINFO);
404 shellinfo.fMask = wait ? SEE_MASK_NOCLOSEPROCESS : SEE_MASK_DEFAULT;
405 shellinfo.hwnd = nullptr;
406 shellinfo.lpVerb = elevated ? "runas" : nullptr;
407 shellinfo.lpFile = blender_path;
408 shellinfo.lpParameters = parameters;
409 shellinfo.lpDirectory = nullptr;
410 shellinfo.nShow = silent ? SW_HIDE : SW_SHOW;
411 shellinfo.hInstApp = nullptr;
412 shellinfo.hProcess = 0;
413
414 DWORD exitCode = 0;
415 if (!ShellExecuteExA(&shellinfo)) {
416 return false;
417 }
418 if (!wait) {
419 return true;
420 }
421
422 if (shellinfo.hProcess != 0) {
423 WaitForSingleObject(shellinfo.hProcess, INFINITE);
424 GetExitCodeProcess(shellinfo.hProcess, &exitCode);
425 CloseHandle(shellinfo.hProcess);
426 return (exitCode == 0);
427 }
428
429 return false;
430}
431
432void BLI_windows_get_default_root_dir(char root[4])
433{
434 char str[MAX_PATH + 1];
435
436 /* the default drive to resolve a directory without a specified drive
437 * should be the Windows installation drive, since this was what the OS
438 * assumes. */
439 if (GetWindowsDirectory(str, MAX_PATH + 1)) {
440 root[0] = str[0];
441 root[1] = ':';
442 root[2] = '\\';
443 root[3] = '\0';
444 }
445 else {
446 /* if GetWindowsDirectory fails, something has probably gone wrong,
447 * we are trying the blender install dir though */
448 if (GetModuleFileName(nullptr, str, MAX_PATH + 1)) {
449 printf(
450 "Error! Could not get the Windows Directory - "
451 "Defaulting to Blender installation Dir!\n");
452 root[0] = str[0];
453 root[1] = ':';
454 root[2] = '\\';
455 root[3] = '\0';
456 }
457 else {
458 DWORD tmp;
459 int i;
460 int rc = 0;
461 /* now something has gone really wrong - still trying our best guess */
462 printf(
463 "Error! Could not get the Windows Directory - "
464 "Defaulting to first valid drive! Path might be invalid!\n");
465 tmp = GetLogicalDrives();
466 for (i = 2; i < 26; i++) {
467 if ((tmp >> i) & 1) {
468 root[0] = 'a' + i;
469 root[1] = ':';
470 root[2] = '\\';
471 root[3] = '\0';
472 if (GetFileAttributes(root) != 0xFFFFFFFF) {
473 rc = i;
474 break;
475 }
476 }
477 }
478 if (0 == rc) {
479 printf("ERROR in 'BLI_windows_get_default_root_dir': can't find a valid drive!\n");
480 root[0] = 'C';
481 root[1] = ':';
482 root[2] = '\\';
483 root[3] = '\0';
484 }
485 }
486 }
487}
488
489bool BLI_windows_get_directx_driver_version(const wchar_t *deviceSubString,
490 long long *r_driverVersion)
491{
492 IDXGIFactory *pFactory = nullptr;
493 IDXGIAdapter *pAdapter = nullptr;
494 if (CreateDXGIFactory(__uuidof(IDXGIFactory), (void **)&pFactory) == S_OK) {
495 for (UINT i = 0; pFactory->EnumAdapters(i, &pAdapter) != DXGI_ERROR_NOT_FOUND; ++i) {
496 LARGE_INTEGER version;
497 if (pAdapter->CheckInterfaceSupport(__uuidof(IDXGIDevice), &version) == S_OK) {
498 DXGI_ADAPTER_DESC desc;
499 if (pAdapter->GetDesc(&desc) == S_OK) {
500 if (wcsstr(desc.Description, deviceSubString)) {
501 *r_driverVersion = version.QuadPart;
502
503 pAdapter->Release();
504 pFactory->Release();
505 return true;
506 }
507 }
508 }
509
510 pAdapter->Release();
511 }
512 pFactory->Release();
513 }
514
515 return false;
516}
517
518#else
519
520/* intentionally empty for UNIX */
521
522#endif
File and directory operations.
bool BLI_is_dir(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:456
#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:599
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.
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
#define str(s)
#define printf(...)
i
Definition text_draw.cc:230
int conv_utf_8_to_16(const char *in8, wchar_t *out16, size_t size16)
Definition utfconv.cc:182