From f3944cf503966a93a124e389d9232d7f833c0077 Mon Sep 17 00:00:00 2001 From: Ray Molenkamp Date: Wed, 26 May 2021 20:02:35 -0600 Subject: [PATCH] Win: Add launcher to hide the console window flash This patch fixes a long-standing complaint from users: the console window shortly flashing when they start blender. This is done by adding a new executable called blender-launcher.exe which starts blender.exe while hiding the console. Any command line parameters given to blender-launcher will be passed on to blender.exe so it'll be a drop in replacement. Starting blender.exe on its own will still function as a proper console app so no changes required here for users that use blender for batch processing. Notable changes: Registering blender (-R switch) will now register blender-launcher as the preferred executable. This patch updates the installer and updates the shortcuts to start blender-launcher.exe rather than blender.exe Differential Revision: https://developer.blender.org/D11094 Reviewed by: brecht, harley --- build_files/cmake/packaging.cmake | 4 +- source/blender/blenlib/intern/winstuff.c | 4 +- .../windowmanager/intern/wm_init_exit.c | 9 +- source/creator/CMakeLists.txt | 11 ++- source/creator/blender-launcher.c | 92 +++++++++++++++++++ 5 files changed, 113 insertions(+), 7 deletions(-) create mode 100644 source/creator/blender-launcher.c diff --git a/build_files/cmake/packaging.cmake b/build_files/cmake/packaging.cmake index 4a0a4f2493d..265b3c0e2ab 100644 --- a/build_files/cmake/packaging.cmake +++ b/build_files/cmake/packaging.cmake @@ -104,8 +104,8 @@ if(WIN32) set(CPACK_WIX_LIGHT_EXTRA_FLAGS -dcl:medium) endif() -set(CPACK_PACKAGE_EXECUTABLES "blender" "blender") -set(CPACK_CREATE_DESKTOP_LINKS "blender" "blender") +set(CPACK_PACKAGE_EXECUTABLES "blender-launcher" "blender") +set(CPACK_CREATE_DESKTOP_LINKS "blender-launcher" "blender") include(CPack) diff --git a/source/blender/blenlib/intern/winstuff.c b/source/blender/blenlib/intern/winstuff.c index 333b6783087..3aa61d1fec5 100644 --- a/source/blender/blenlib/intern/winstuff.c +++ b/source/blender/blenlib/intern/winstuff.c @@ -94,9 +94,9 @@ void BLI_windows_register_blend_extension(const bool background) GetModuleFileName(0, BlPath, MAX_PATH); /* Replace the actual app name with the wrapper. */ - blender_app = strstr(BlPath, "blender-app.exe"); + blender_app = strstr(BlPath, "blender.exe"); if (blender_app != NULL) { - strcpy(blender_app, "blender.exe"); + strcpy(blender_app, "blender-launcher.exe"); } /* root is HKLM by default */ diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 56fd51ac6fd..0dcb817ad15 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -343,8 +343,13 @@ void WM_init(bContext *C, int argc, const char **argv) (void)argv; /* unused */ #endif - if (!G.background && !wm_start_with_console) { - GHOST_toggleConsole(3); + if (!G.background) { + if (wm_start_with_console) { + GHOST_toggleConsole(1); + } + else { + GHOST_toggleConsole(3); + } } BKE_material_copybuf_clear(); diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index c2893317924..baea3ad1f9b 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -285,6 +285,15 @@ if(WITH_PYTHON_MODULE) else() add_executable(blender ${EXETYPE} ${SRC}) + if(WIN32) + add_executable(blender-launcher WIN32 + blender-launcher.c + ${CMAKE_SOURCE_DIR}/release/windows/icons/winblender.rc + ${CMAKE_BINARY_DIR}/blender.exe.manifest + ) + target_compile_definitions (blender-launcher PRIVATE -D_UNICODE -DUNICODE) + target_link_libraries(blender-launcher Pathcch.lib) + endif() endif() if(WITH_BUILDINFO) @@ -1212,7 +1221,7 @@ endif() if(WIN32 AND NOT WITH_PYTHON_MODULE) install( - TARGETS blender + TARGETS blender blender-launcher COMPONENT Blender DESTINATION "." ) diff --git a/source/creator/blender-launcher.c b/source/creator/blender-launcher.c new file mode 100644 index 00000000000..86b0f4f3b97 --- /dev/null +++ b/source/creator/blender-launcher.c @@ -0,0 +1,92 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include + +int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) +{ + STARTUPINFO siStartInfo = {0}; + PROCESS_INFORMATION procInfo; + wchar_t path[MAX_PATH]; + + siStartInfo.wShowWindow = SW_HIDE; + siStartInfo.dwFlags = STARTF_USESHOWWINDOW; + + /* Get the path to the currently running executable (blender-launcher.exe) */ + + DWORD nSize = GetModuleFileName(NULL, path, MAX_PATH); + if (!nSize) { + return -1; + } + + /* GetModuleFileName returns the number of characters written, but GetLastError needs to be + * called to see if it ran out of space or not. However where would we be without exceptions + * to the rule: "If the buffer is too small to hold the module name, the function returns nSize. + * The last error code remains ERROR_SUCCESS." - source: MSDN. */ + + if (GetLastError() == ERROR_SUCCESS && nSize == MAX_PATH) { + return -1; + } + + /* Remove the filename (blender-launcher.exe) from path. */ + if (PathCchRemoveFileSpec(path, MAX_PATH) != S_OK) { + return -1; + } + + /* Add blender.exe to path, resulting in the full path to the blender executable. */ + if (PathCchCombine(path, MAX_PATH, path, L"blender.exe") != S_OK) { + return -1; + } + + int required_size_chars = lstrlenW(path) + /* Module name */ + 3 + /* 2 quotes + Space */ + lstrlenW(pCmdLine) + /* Original command line */ + 1; /* Zero terminator */ + size_t required_size_bytes = required_size_chars * sizeof(wchar_t); + wchar_t *buffer = (wchar_t *)malloc(required_size_bytes); + if (!buffer) { + return -1; + } + + if (StringCbPrintfEx(buffer, + required_size_bytes, + NULL, + NULL, + STRSAFE_NULL_ON_FAILURE, + L"\"%s\" %s", + path, + pCmdLine) != S_OK) { + free(buffer); + return -1; + } + + BOOL success = CreateProcess( + path, buffer, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &siStartInfo, &procInfo); + + if (success) { + /* Handles in PROCESS_INFORMATION must be closed with CloseHandle when they are no longer + * needed - MSDN. Closing the handles will NOT terminate the thread/process that we just + * started. */ + CloseHandle(procInfo.hThread); + CloseHandle(procInfo.hProcess); + } + + free(buffer); + return success ? 0 : -1; +}