Add OS profile sources for Windows

This commit is contained in:
Luca Bacci
2025-08-27 14:44:43 +02:00
parent 298fa45f90
commit c836a71114
6 changed files with 223 additions and 1 deletions

1
.gitignore vendored
View File

@@ -9,7 +9,6 @@ tags
*.pc
.*.swp
.sw?
*.rc
*.gcno
*.gcda
*.gcov

1
build-aux/meson.build Normal file
View File

@@ -0,0 +1 @@
subdir('win32')

162
build-aux/win32/app.c Normal file
View File

@@ -0,0 +1,162 @@
/*
* Copyright © 2025 Luca Bacci
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
* Author: Luca Bacci <luca.bacci@outlook.com>
*/
#include "config.h"
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <crtdbg.h>
#ifdef _MSC_VER
#include <vcruntime.h>
#endif
static void
set_process_wide_settings (void)
{
#if defined (_M_IX86) || defined (__i386__)
/* https://learn.microsoft.com/en-us/archive/blogs/michael_howard/faq-about-heapsetinformation-in-windows-vista-and-heap-based-buffer-overruns */
/* https://web.archive.org/web/20080825034220/https://blogs.msdn.com/sdl/archive/2008/06/06/corrupted-heap-termination-redux.aspx */
HeapSetInformation (NULL, HeapEnableTerminationOnCorruption, NULL, 0);
/* https://learn.microsoft.com/en-us/archive/blogs/michael_howard/new-nx-apis-added-to-windows-vista-sp1-windows-xp-sp3-and-windows-server-2008 */
SetProcessDEPPolicy (PROCESS_DEP_ENABLE | PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION);
#endif
SetErrorMode (GetErrorMode () | SEM_FAILCRITICALERRORS);
}
static void
set_crt_non_interactive (void)
{
/* The Debug CRT may show UI dialogs even in console applications.
* Direct to stderr instead.
*/
_CrtSetReportFile (_CRT_ASSERT, _CRTDBG_FILE_STDERR);
_CrtSetReportMode (_CRT_ASSERT, _CRTDBG_MODE_FILE);
_CrtSetReportFile (_CRT_ERROR, _CRTDBG_FILE_STDERR);
_CrtSetReportMode (_CRT_ERROR, _CRTDBG_MODE_FILE);
_CrtSetReportFile (_CRT_WARN, _CRTDBG_FILE_STDERR);
_CrtSetReportMode (_CRT_WARN, _CRTDBG_MODE_FILE);
}
static void
set_stderr_unbuffered_mode (void)
{
/* MSVCRT.DLL can open stderr in full-buffering mode. That depends on
* the type of output device; for example, it's fully buffered for
* named pipes but not for console devices.
*
* Having a fully buffered stderr is not a good default since we can
* loose important messages before a crash. Moreover, POSIX forbids
* full buffering on stderr. So here we set stderr to unbuffered mode.
*
* Note: line buffering mode would be good enough, but the Windows C
* RunTime library implements it the same as full buffering:
*
* "for some systems, _IOLBF provides line buffering. However, for
* Win32, the behavior is the same as _IOFBF: Full Buffering"
*
* https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setvbuf#remarks
*
* References:
*
* - https://sourceforge.net/p/mingw/mailman/message/27121137/
*/
#if !defined (_UCRT)
int ret = setvbuf (stderr, NULL, _IONBF, 0);
assert (ret == 0);
#endif
}
static void
early_flush_exit_handler (void)
{
/* There are two ways to flush open streams: calling fflush with NULL
* argument and calling _flushall. The former flushes output streams
* only, the latter flushes both input and output streams.
* We should not do anything with input streams here since flushing
* means * discarding * data.
*/
fflush (NULL);
}
static void
register_early_flush_at_exit (void)
{
/* Implement the two-phase flushing at process exit.
*
* The C RunTime library flushes open streams within its DllMain handler.
* This goes against the rules for DllMain, as each stream is protected
* by a lock and locks must not be acquired in DllMain.
*
* So we flush from app code using an atexit handler. The handler runs when
* the application is in a fully working state and thus is completely safe.
*
* This ensures that all important data is flushed. Anything that is written
* after exit will be flushed lately by the C RunTime library (and therefore
* may be skipped).
*
* See comments in "%ProgramFiles(x86)%\Windows Kits\10\Source\<version>\
* \ucrt\stdio\fflush.cpp" for more informations.
*
* References:
*
* - https://devblogs.microsoft.com/oldnewthing/20070503-00/?p=27003
* - https://devblogs.microsoft.com/oldnewthing/20100122-00/?p=15193
* - https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-best-practices
*/
int ret = atexit (early_flush_exit_handler);
assert (ret == 0);
}
/* Boilerplate for CRT constructor */
#ifdef _MSC_VER
static void startup (void);
__pragma (section (".CRT$XCT", long, read))
__declspec (allocate (".CRT$XCT"))
const void (*ptr_startup) (void) = startup;
#ifdef _M_IX86
__pragma (comment (linker, "/INCLUDE:" "_ptr_startup"))
#else
__pragma (comment (linker, "/INCLUDE:" "ptr_startup"))
#endif
#else
static void __attribute__((constructor)) startup (void);
#endif
static void
startup (void)
{
set_crt_non_interactive ();
set_process_wide_settings ();
set_stderr_unbuffered_mode ();
register_early_flush_at_exit ();
}

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly manifestVersion="1.0"
xmlns="urn:schemas-microsoft-com:asm.v1"
xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<asmv3:application>
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">
<activeCodePage>UTF-8</activeCodePage>
</asmv3:windowsSettings>
</asmv3:application>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 10 and Windows 11 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
</application>
</compatibility>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<!--
UAC settings:
- app should run at same integrity level as calling process
- app does not need to manipulate windows belonging to
higher-integrity-level processes
-->
<requestedExecutionLevel
level="asInvoker"
uiAccess="false"
/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

6
build-aux/win32/app.rc Normal file
View File

@@ -0,0 +1,6 @@
#pragma code_page(65001)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "app.manifest.xml"

View File

@@ -0,0 +1,14 @@
if host_system == 'windows'
static_lib = static_library('os-profile-app-static-lib',
sources: ['app.c'],
include_directories: [configinc])
resources = windows.compile_resources('app.rc',
depend_files: ['app.manifest.xml'])
app_profile_dep = declare_dependency(link_whole: [static_lib],
sources: [resources])
else
app_profile_dep = declare_dependency()
endif