KiCad PCB EDA Suite
Loading...
Searching...
No Matches
windows/app.cpp
Go to the documentation of this file.
1/*
2* This program source code file is part of KiCad, a free EDA CAD application.
3*
4* Copyright (C) 2020 Mark Roszko <[email protected]>
5* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6*
7* This program is free software: you can redistribute it and/or modify it
8* under the terms of the GNU General Public License as published by the
9* Free Software Foundation, either version 3 of the License, or (at your
10* option) any later version.
11*
12* This program is distributed in the hope that it will be useful, but
13* WITHOUT ANY WARRANTY; without even the implied warranty of
14* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15* General Public License for more details.
16*
17* You should have received a copy of the GNU General Public License
18* along with this program. If not, see <https://www.gnu.org/licenses/>.
19*/
20
21#include <kiplatform/app.h>
22
23#include <wx/app.h>
24#include <wx/log.h>
25#include <wx/string.h>
26#include <wx/window.h>
27#if wxCHECK_VERSION( 3, 3, 0 )
28#include <wx/msw/darkmode.h>
29#endif
30
31#include <windows.h>
32#include <strsafe.h>
33#include <config.h>
34#include <versionhelpers.h>
35#include <iostream>
36#include <cstdio>
37#include <io.h>
38
39#if defined( _MSC_VER )
40#include <werapi.h> // issues on msys2
41#endif
42
43#ifdef _WIN32
44extern "C"
45{
46 // So there exists this malware called Nahimic by A-Volute, which is marketed as an audio enhancement
47 // software. In reality it's an aggressive form of malware that injects itself wildly into every process
48 // on the system for god knows what reason. It even includes a tracking/analytics package, <insert tinfoil hat>
49 // Our problem is this garbage basically bugs out OpenGL (why an audio driver does that, who knows, its made by morons)
50 // And then we get issues reported both in our issue tracker and sentry reports as a result
51 // At least these malware authors were nice to include a dumb "disable" trick where it checks if the exe is exporting
52 // a symbol called NoHotPatch, so here we are.
53 // Hopefully this works and stops the bug reports. Apparently the worst part is this malware aggressively gets reinstalled
54 // by awful low-tier motherboard vendors like MSI, Alienware and others who bundled it into their driver packages
55 // and distributed it over Windows Update
56 // Did I mention they clearly had issues with other apps so instead of fixing their malware, they blacklisted a hundred common
57 // apps and even some games in their own config? Obviously kicad isn't on that blacklist :(
58 // This malware seems to no longer be distributed as Nahimic and replaced with "Sonar" by SteelSeries.
59 // Time will tell if it's the same garbage, I'm not volunteering to install it.
60 __declspec(dllexport) void NoHotPatch()
61 {
62 // this is a intentionally empty function
63 return;
64 }
65}
66#endif
67
68#if wxCHECK_VERSION( 3, 3, 0 )
69class KICAD_DARK_MODE_SETTINGS : public wxDarkModeSettings
70{
71public:
72 wxColour GetColour( wxSystemColour index ) override
73 {
74 switch( index )
75 {
76 // This fixes "Control Light"
77 case wxSYS_COLOUR_3DLIGHT:
78 return wxColour( 0x2B2B2B );
79
80 default: return wxDarkModeSettings::GetColour( index );
81 }
82 }
83};
84#endif
85
86
88{
89#if defined( _MSC_VER ) && defined( DEBUG )
90 // wxWidgets turns on leak dumping in debug but its "flawed" and will falsely dump
91 // for half a hour _CRTDBG_ALLOC_MEM_DF is the usual default for MSVC.
92 _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF );
93#endif
94
95#if defined( DEBUG )
96 // undo wxwidgets trying to hide errors
97 SetErrorMode( 0 );
98#else
99 SetErrorMode( SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX );
100#endif
101
102 // remove CWD from the dll search paths
103 // just the smallest of security tweaks as we do load DLLs on demand
104 SetDllDirectory( wxT( "" ) );
105
106 // Moves the CWD to the end of the search list for spawning processes
107 SetSearchPathMode( BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE | BASE_SEARCH_PATH_PERMANENT );
108
109 // In order to support GUI and CLI
110 // Let's attach to console when it's possible, or allocate if requested.
111 AttachConsole( wxGetEnv( wxS( "KICAD_ALLOC_CONSOLE" ), nullptr ) );
112
113 // It may be useful to log up to traces in a console, but in Release builds the log level changes to Info
114 // Also we have to force the active target to stderr or else it goes to the void
115 bool forceLog = wxGetEnv( wxS( "KICAD_FORCE_CONSOLE_TRACE" ), nullptr );
116
117 if( forceLog )
118 {
119 wxLog::EnableLogging( true );
120#ifndef DEBUG
121 wxLog::SetLogLevel( wxLOG_Trace );
122#endif
123 const int fd = _fileno( stderr );
124 wxLog::SetActiveTarget( fd >= 0 && !_isatty( fd ) ? new wxLogStderr( stderr, wxConvUTF8 )
125 : new wxLogStderr );
126 }
127
128 return true;
129}
130
131
132void KIPLATFORM::APP::EnableDarkMode( bool aForce )
133{
134#if wxCHECK_VERSION( 3, 3, 0 )
135 wxTheApp->MSWEnableDarkMode( aForce ? wxApp::DarkMode_Always : wxApp::DarkMode_Auto, new KICAD_DARK_MODE_SETTINGS() );
136#endif
137}
138
139
140bool KIPLATFORM::APP::AttachConsole( bool aTryAlloc )
141{
142 if( ::AttachConsole( ATTACH_PARENT_PROCESS ) || ( aTryAlloc && ::AllocConsole() ) )
143 {
144 #if !defined( __MINGW32__ ) // These redirections create problems on mingw:
145 // Nothing is printed to the console
146
147 if( ::GetStdHandle( STD_INPUT_HANDLE ) != INVALID_HANDLE_VALUE )
148 {
149 freopen( "CONIN$", "r", stdin );
150 setvbuf( stdin, NULL, _IONBF, 0 );
151 }
152
153 if( ::GetStdHandle( STD_OUTPUT_HANDLE ) != INVALID_HANDLE_VALUE )
154 {
155 freopen( "CONOUT$", "w", stdout );
156 setvbuf( stdout, NULL, _IONBF, 0 );
157 }
158
159 if( ::GetStdHandle( STD_ERROR_HANDLE ) != INVALID_HANDLE_VALUE )
160 {
161 freopen( "CONOUT$", "w", stderr );
162 setvbuf( stderr, NULL, _IONBF, 0 );
163 }
164 #endif
165
166 std::ios::sync_with_stdio( true );
167
168 std::wcout.clear();
169 std::cout.clear();
170 std::wcerr.clear();
171 std::cerr.clear();
172 std::wcin.clear();
173 std::cin.clear();
174
175 return true;
176 }
177
178 return false;
179}
180
181
183{
184#if defined( PYTHON_VERSION_MAJOR ) && ( ( PYTHON_VERSION_MAJOR == 3 && PYTHON_VERSION_MINOR >= 8 ) \
185 || PYTHON_VERSION_MAJOR > 3 )
186 // Python 3.8 switched to Windows 8+ API, we do not support Windows 7 and will not
187 // attempt to hack around it. A normal user will never get here because the Python DLL
188 // is missing dependencies - and because it is not dynamically loaded, KiCad will not even
189 // start without patching Python or its WinAPI dependency. This is just to create a nag dialog
190 // for those who run patched Python and prevent them from submitting bug reports.
191 return !IsWindows8OrGreater();
192#else
193 return false;
194#endif
195}
196
197
198bool KIPLATFORM::APP::RegisterApplicationRestart( const wxString& aCommandLine )
199{
200 // Command line arguments with spaces require quotes.
201 wxString restartCmd = wxS( "\"" ) + aCommandLine + wxS( "\"" );
202
203 // Ensure we don't exceed the maximum allowable size
204 if( restartCmd.length() > RESTART_MAX_CMD_LINE - 1 )
205 {
206 return false;
207 }
208
209 HRESULT hr = S_OK;
210
211 hr = ::RegisterApplicationRestart( restartCmd.wc_str(), RESTART_NO_PATCH );
212
213 return SUCCEEDED( hr );
214}
215
216
218{
219 // Note, this isn't required to be used on Windows if you are just closing the program
220 return SUCCEEDED( ::UnregisterApplicationRestart() );
221}
222
223
225{
226 return true;
227}
228
229
230void KIPLATFORM::APP::RemoveShutdownBlockReason( wxWindow* aWindow )
231{
232 // Destroys any block reason that may have existed
233 ShutdownBlockReasonDestroy( aWindow->GetHandle() );
234}
235
236
237void KIPLATFORM::APP::SetShutdownBlockReason( wxWindow* aWindow, const wxString& aReason )
238{
239 // Sets up the pretty message on the shutdown page on why it's being "blocked"
240 // This is used in conjunction with handling WM_QUERYENDSESSION (wxCloseEvent)
241 // ShutdownBlockReasonCreate does not block by itself
242
243 ShutdownBlockReasonDestroy( aWindow->GetHandle() ); // Destroys any existing or nonexisting reason
244
245 ShutdownBlockReasonCreate( aWindow->GetHandle(), aReason.wc_str() );
246}
247
248
250{
251 // Taken from https://devblogs.microsoft.com/oldnewthing/20191108-00/?p=103080
252 MSG msg;
253 PeekMessage( &msg, nullptr, WM_TIMER, WM_TIMER, PM_NOREMOVE );
254}
255
256
257void KIPLATFORM::APP::AddDynamicLibrarySearchPath( const wxString& aPath )
258{
259 SetDllDirectory( aPath.c_str() );
260}
int index
void SetShutdownBlockReason(wxWindow *aWindow, const wxString &aReason)
Sets the block reason why the window/application is preventing OS shutdown.
Definition unix/app.cpp:102
bool UnregisterApplicationRestart()
Unregisters the application from automatic restart.
Definition unix/app.cpp:84
bool AttachConsole(bool aTryAlloc)
Tries to attach a console window with stdout, stderr and stdin.
Definition unix/app.cpp:63
void RemoveShutdownBlockReason(wxWindow *aWindow)
Removes any shutdown block reason set.
Definition unix/app.cpp:97
bool RegisterApplicationRestart(const wxString &aCommandLine)
Registers the application for restart with the OS with the given command line string to pass as args.
Definition unix/app.cpp:77
bool Init()
Perform application-specific initialization tasks.
Definition unix/app.cpp:40
void ForceTimerMessagesToBeCreatedIfNecessary()
Forces wxTimers to fire more promptly on Win32.
Definition unix/app.cpp:107
bool IsOperatingSystemUnsupported()
Checks if the Operating System is explicitly unsupported and we want to prevent users from sending bu...
Definition unix/app.cpp:70
bool SupportsShutdownBlockReason()
Whether or not the window supports setting a shutdown block reason.
Definition unix/app.cpp:91
void EnableDarkMode(bool aForce)
Definition unix/app.cpp:58
void AddDynamicLibrarySearchPath(const wxString &aPath)
Inserts a search path for loading dynamic libraries.
Definition unix/app.cpp:112