Blender V5.0
blender_launcher_win32.c
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include <Windows.h>
6#include <strsafe.h>
7
8#include <PathCch.h>
9#include <tlhelp32.h>
10
12{
13 HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
14 BOOL isSteam = FALSE;
15 if (!hSnapShot) {
16 return (FALSE);
17 }
18
19 PROCESSENTRY32 process_entry;
20 process_entry.dwSize = sizeof(PROCESSENTRY32);
21
22 if (!Process32First(hSnapShot, &process_entry)) {
23 CloseHandle(hSnapShot);
24 return (FALSE);
25 }
26
27 /* First find our parent process ID. */
28 DWORD our_pid = GetCurrentProcessId();
29 DWORD parent_pid = -1;
30
31 do {
32 if (process_entry.th32ProcessID == our_pid) {
33 parent_pid = process_entry.th32ParentProcessID;
34 break;
35 }
36 } while (Process32Next(hSnapShot, &process_entry));
37
38 if (parent_pid == -1 || !Process32First(hSnapShot, &process_entry)) {
39 CloseHandle(hSnapShot);
40 return (FALSE);
41 }
42 /* Then do another loop to find the process name of the parent.
43 * this is done in 2 loops, since the order of the processes is
44 * unknown and we may already have passed the parent process by
45 * the time we figure out its pid in the first loop. */
46 do {
47 if (process_entry.th32ProcessID == parent_pid) {
48 if (_wcsicmp(process_entry.szExeFile, L"steam.exe") == 0) {
49 isSteam = TRUE;
50 }
51 break;
52 }
53 } while (Process32Next(hSnapShot, &process_entry));
54
55 CloseHandle(hSnapShot);
56 return isSteam;
57}
58
59int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
60{
61 /* Silence unreferenced formal parameter warning. */
62 (void)hInstance;
63 (void)hPrevInstance;
64 (void)nCmdShow;
65
66 STARTUPINFO siStartInfo = {0};
67 PROCESS_INFORMATION procInfo;
68 wchar_t path[MAX_PATH];
69
70 siStartInfo.wShowWindow = SW_HIDE;
71 siStartInfo.dwFlags = STARTF_USESHOWWINDOW;
72
73 /* Get the path to the currently running executable (`blender-launcher.exe`). */
74
75 DWORD nSize = GetModuleFileName(NULL, path, MAX_PATH);
76 if (!nSize) {
77 return -1;
78 }
79
80 /* #GetModuleFileName returns the number of characters written, but GetLastError needs to be
81 * called to see if it ran out of space or not. However where would we be without exceptions
82 * to the rule: "If the buffer is too small to hold the module name, the function returns nSize.
83 * The last error code remains ERROR_SUCCESS." - source: MSDN. */
84
85 if (GetLastError() == ERROR_SUCCESS && nSize == MAX_PATH) {
86 return -1;
87 }
88
89 /* Remove the filename (blender-launcher.exe) from path. */
90 if (PathCchRemoveFileSpec(path, MAX_PATH) != S_OK) {
91 return -1;
92 }
93
94 /* Add blender.exe to path, resulting in the full path to the blender executable. */
95 if (PathCchCombine(path, MAX_PATH, path, L"blender.exe") != S_OK) {
96 return -1;
97 }
98
99 int required_size_chars = lstrlenW(path) + /* Module name. */
100 3 + /* 2 quotes + Space. */
101 lstrlenW(pCmdLine) + /* Original command line. */
102 1; /* Zero terminator. */
103 size_t required_size_bytes = required_size_chars * sizeof(wchar_t);
104 wchar_t *buffer = (wchar_t *)malloc(required_size_bytes);
105 if (!buffer) {
106 return -1;
107 }
108
109 if (StringCbPrintfEx(buffer,
110 required_size_bytes,
111 NULL,
112 NULL,
113 STRSAFE_NULL_ON_FAILURE,
114 L"\"%s\" %s",
115 path,
116 pCmdLine) != S_OK)
117 {
118 free(buffer);
119 return -1;
120 }
121
122 BOOL success = CreateProcess(
123 path, buffer, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &siStartInfo, &procInfo);
124
125 DWORD returnValue = success ? 0 : -1;
126
127 if (success) {
128 /* If blender-launcher is called with background command line flag or launched from steam,
129 * wait for the blender process to exit and return its return value. */
130 BOOL background = LaunchedFromSteam();
131 int argc = 0;
132 LPWSTR *argv = CommandLineToArgvW(pCmdLine, &argc);
133 for (int i = 0; i < argc; i++) {
134 if ((wcscmp(argv[i], L"-b") == 0) || (wcscmp(argv[i], L"--background") == 0)) {
135 background = TRUE;
136 break;
137 }
138 }
139
140 if (background) {
141 WaitForSingleObject(procInfo.hProcess, INFINITE);
142 GetExitCodeProcess(procInfo.hProcess, &returnValue);
143 }
144
145 /* Handles in PROCESS_INFORMATION must be closed with CloseHandle when they are no longer
146 * needed - MSDN. Closing the handles will NOT terminate the thread/process that we just
147 * started. */
148 CloseHandle(procInfo.hThread);
149 CloseHandle(procInfo.hProcess);
150 }
151
152 free(buffer);
153 return returnValue;
154}
void BLI_kdtree_nd_ free(KDTree *tree)
#define FALSE
BOOL LaunchedFromSteam()
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
#define L
i
Definition text_draw.cc:230