Compare commits

...

1 Commits

Author SHA1 Message Date
Luca Bacci
5b4d4b17ed WIP 2024-10-10 10:39:15 +02:00
9 changed files with 943 additions and 1 deletions

200
gdk/win32/apisets.c Normal file
View File

@@ -0,0 +1,200 @@
/* GTK - The GIMP Toolkit
*
* Copyright (C) 2024 the GTK team
*
* 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 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/>.
*/
#include "config.h"
#include "apisets.h"
#include "procedures.h"
#include "gdkprivate-win32.h"
static struct api_set
api_sets[] = {
# define API_SET(id, name, os_version) \
{name, L"" name, NULL, FALSE, os_version},
API_SETS
# undef API_SET
};
static struct module
modules[] = {
# define MODULE(id, name, folder, flags) \
{L"" name, folder, flags, NULL, FALSE},
MODULES
# undef MODULE
};
static void
load_api_set_internal (struct api_set *api_set)
{
if (ptrIsApiSetImplemented)
if (!ptrIsApiSetImplemented (api_set->name_narrow))
return;
/* Use LOAD_LIBRARY_SEARCH_SYSTEM32 for security (if IsApiSetImplemented
* is not present)
*
* If we can't use IsApiSetImplemented, we should try loading the api set
* directly. However, if the OS is too old and the api set is unknown,
* LoadLibrary will look for a corresponding DLL file in the search paths.
* Here we use LOAD_LIBRARY_SEARCH_SYSTEM32 to restrict search to a safe
* folder. */
const DWORD flags = LOAD_LIBRARY_SEARCH_SYSTEM32;
api_set->module_handle = LoadLibraryEx (api_set->name_wide, NULL, flags);
if (api_set->module_handle == NULL)
{
DWORD code = GetLastError ();
if (code == ERROR_INVALID_PARAMETER)
{
/* LOAD_LIBRARY_SEARCH_SYSTEM32 is supported on Windows Vista/7
* only with update KB2533623 installed. If we can't use that
* flag, it's best to return early and rely on classic modules.
*/
return;
}
else if (code == ERROR_MOD_NOT_FOUND)
{
if (strncmp (api_set->name_narrow, "api", strlen ("api")) == 0 &&
api_set->os_version <= gdk_win32_get_os_version ())
{
g_message ("%s missing\n", api_set->name_narrow);
}
}
else
WIN32_API_FAILED ("LoadLibraryEx");
}
}
static void
load_api_set (struct api_set *api_set)
{
g_assert (api_set->module_handle == NULL);
g_assert (api_set->checked == false);
load_api_set_internal (api_set);
api_set->checked = true;
}
/** gdk_win32_get_api_set:
*/
struct api_set *
gdk_win32_get_api_set (int api_set_id)
{
if (api_set_id >= 0 && api_set_id < API_SET_COUNT)
{
struct api_set *api_set = &api_sets[api_set_id];
if (!api_set->checked)
load_api_set (api_set);
return api_set;
}
return NULL;
}
static void
load_module_internal (struct module *module)
{
if (module->flags & MODULE_FLAG_PACKAGED)
{
if (gdk_win32_check_app_packaged ())
{
g_assert (ptrLoadPackagedLibrary);
module->module_handle = ptrLoadPackagedLibrary (module->name, 0);
if (module->module_handle == NULL)
{
if (GetLastError () != ERROR_MOD_NOT_FOUND)
WIN32_API_FAILED ("LoadPackagedLibrary");
}
return;
}
else
{
/* TODO
*
* https://learn.microsoft.com/en-us/windows/apps/desktop/modernize/framework-packages/use-the-dynamic-dependency-api
* https://learn.microsoft.com/en-us/windows/apps/windows-app-sdk/use-windows-app-sdk-run-time
* https://github.com/microsoft/WindowsAppSDK/issues/89
*/
}
}
switch (module->folder)
{
case FOLDER_APP:
if (can_use_app_folder < 0)
can_use_app_folder = check_can_use_app_folder ();
if (can_use_app_folder)
{
module->module_handle = gdk_win32_load_library_from_app_folder (module->name);
break;
}
G_GNUC_FALLTHROUGH;
case FOLDER_SYSTEM32:
module->module_handle = gdk_win32_load_library_from_system32 (module->name, false, true);
break;
}
}
static void
load_module (struct module *module)
{
g_assert (module->module_handle == NULL);
g_assert (module->checked == false);
load_module_internal (module);
module->checked = true;
}
/** gdk_win32_get_module:
*/
struct module *
gdk_win32_get_module (int module_id)
{
if (module_id >= 0 && module_id < MODULE_COUNT)
{
struct module *module = &modules[module_id];
if (!module->checked)
load_module (module);
return module;
}
return NULL;
}
// TODO:
// Check Dynamic-link library redirection
// Check .exe.manifest file alongside exe
// PSP_USEFUSIONCONTEXT
// Manifest and WinRT activatable classes?
// Check if GetProcAddress works in app container (do we really need a delay-load table for it to work?)
// (can it really access the calling module?)
// Is it possible to generate a synthetic delay-load import table?

87
gdk/win32/apisets.h Normal file
View File

@@ -0,0 +1,87 @@
/* GTK - The GIMP Toolkit
*
* Copyright (C) 2024 the GTK team
*
* 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 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/>.
*/
#pragma once
#include "config.h"
#include "gdkmain-win32.h"
#include <windows.h>
#include <stdbool.h>
#undef API_SET
/* Api sets whose name starts with 'api' can be removed from the table once
* support for older OSes is dropped. On the countrary, api sets whose name
* starts with 'ext' must remain in the table because they are not present
* on all Windows editions (Core, Desktop, Hololens, etc.) */
#define API_SETS \
API_SET (API_CORE_APIQUERY_2 , "api-ms-win-core-apiquery-l2-1-0.dll" , OSVersionWindows10) \
API_SET (API_APPMODEL_RUNTIME_1 , "api-ms-win-appmodel-runtime-l1-1-0.dll" , OSVersionWindows8 ) \
API_SET (API_CORE_LIBRARYLOADER_2 , "api-ms-win-core-libraryloader-l2-1-0.dll" , OSVersionWindows8 ) \
#define MODULES \
MODULE (MODULE_KERNEL32 , "kernel32.dll" , FOLDER_SYSTEM32 , 0 ) \
MODULE (MODULE_USER32 , "user32.dll" , FOLDER_SYSTEM32 , 0 ) \
#define API_SET(id, name, os_version) id,
enum ApiSets {
API_SETS
API_SET_COUNT
};
#undef API_SET
#define MODULE(id, name, folder, flags) id,
enum Modules {
MODULES
MODULE_COUNT
};
#undef MODULE
struct api_set {
const char *name_narrow;
const wchar_t *name_wide;
HMODULE module_handle;
bool checked;
OSVersion os_version;
};
struct api_set * gdk_win32_get_api_set (int api_set_id);
enum ModuleFolder {
FOLDER_SYSTEM32,
FOLDER_APP,
};
#define MODULE_FLAG_PACKAGED (1U << 0)
#define MODULE_FLAG_DIRECT (1U << 1)
struct module {
const wchar_t *name;
enum ModuleFolder folder;
unsigned int flags;
HMODULE module_handle;
bool checked;
};
struct module * gdk_win32_get_module (int module_id);

View File

@@ -38,6 +38,14 @@
#include <windows.h>
#include <wintab.h>
#include <imm.h>
#include <shlwapi.h> /* for DLLVERSIONINFO */
#include "gdkmain-win32.h"
#include "apisets.h"
#include "procedures.h"
#include <stdarg.h>
#include <stdbool.h>
/* Whether GDK initialized COM */
gboolean
@@ -106,6 +114,361 @@ gdk_win32_ensure_ole (void)
return ole_initialized;
}
struct invoke_context
{
void (*callback)(void*);
void *user_data;
va_list setup_funcs;
};
typedef void (*invoke_setup_func_t)(invoke_context_t *);
#define gdk_win32_invoke_finish(context) \
do \
{ \
context->callback (context->user_data); \
} \
while (0)
#define gdk_win32_invoke_continue(context) \
do \
{ \
invoke_setup_func_t setup_func; \
setup_func = va_arg ((context)->setup_funcs, invoke_setup_func_t); \
\
if (setup_func) \
setup_func (context); \
else \
gdk_win32_invoke_finish (context); \
} \
while (0)
/** gdk_win32_invoke_callback:
*
* Invoke a callback with a list of prepare functions setting
* up the necessary context (thread error mode, activation context,
* etc.)
*
* Prepare functions are called recursively, so it's possible to
* use Structured Exception Handling for cleanup even in case of
* exceptions.
*
* Note: diverging control-flow via signals / structured exceptions
* is not supported, but it's good practice to cleanup some things
* on exceptions for the sake of error handling or debugging.
*/
void
gdk_win32_invoke_callback (void (*callback)(void *arg),
void *user_data,
...)
{
invoke_context_t context = {
callback, user_data,
};
va_start (context.setup_funcs, user_data);
gdk_win32_invoke_continue ((&context));
va_end (context.setup_funcs);
}
/** gdk_win32_with_loader_error_mode:
*
* Setup function that sets the error mode to prevent interactive
* mesage boxes from the loader. To be used with gdk_win32_invoke_callback()
*/
void
gdk_win32_with_loader_error_mode (invoke_context_t *context)
{
/* It seems that both SEM_NOOPENFILEERRORBOX, SEM_FAILCRITICALERRORS
* are relevant for DLL loading:
*
* -> https://devblogs.microsoft.com/oldnewthing/20240208-00/?p=109374
* -> https://www.betaarchive.com/wiki/index.php?title=Microsoft_KB_Archive/111610
*
* Now, it could be that SEM_NOOPENFILEERRORBOX is not needed anymore
* on modern Windows, but let's just be safe */
const DWORD error_mode = SEM_FAILCRITICALERRORS |
SEM_NOOPENFILEERRORBOX;
const DWORD original_error_mode = GetThreadErrorMode ();
SEH_TRY
{
SetThreadErrorMode (original_error_mode | error_mode, NULL);
gdk_win32_invoke_continue (context);
}
SEH_FINALLY
{
SetThreadErrorMode (original_error_mode, NULL);
}
}
static HANDLE
get_activation_context (void)
{
static HANDLE handle_activation_context = NULL;
static GOnce once = G_ONCE_INIT;
if (g_once_init_enter (&handle_activation_context))
{
ACTCTX actctx = {0};
HANDLE handle;
actctx.cbSize = sizeof (actctx);
actctx.dwFlags = ACTCTX_FLAG_HMODULE_VALID |
ACTCTX_FLAG_RESOURCE_NAME_VALID;
actctx.hModule = this_module_handle ();
#ifndef GTK_STATIC_COMPILATION
actctx.lpResourceName = MAKEINTRESOURCE (ISOLATIONAWARE_MANIFEST_RESOURCE_ID);
#else
actctx.lpResourceName = L"GTK_MANIFEST";
#endif
handle = CreateActCtx (&actctx);
if (handle == INVALID_HANDLE_VALUE)
WIN32_API_FAILED ("CreateActCtx");
g_once_init_leave (&handle_activation_context, handle);
}
return handle_activation_context;
}
/** gdk_win32_with_activation_context:
*
* Setup function that activates the GTK's activation context.
* To be used with gdk_win32_invoke_callback().
*/
void
gdk_win32_with_activation_context (invoke_context_t *context)
{
HANDLE handle_activation_context = get_activation_context ();
bool activated = false;
ULONG_PTR cookie = 0;
SEH_TRY
{
if (handle_activation_context != INVALID_HANDLE_VALUE)
{
if (!ActivateActCtx (handle_activation_context, &cookie))
WIN32_API_FAILED ("ActivateActCtx");
else
activated = true;
}
gdk_win32_invoke_continue (context);
}
SEH_FINALLY
{
if (activated)
{
if (!DeactivateActCtx (0, cookie) &&
!SEH_ABNORMAL_TERMINATION ())
{
WIN32_API_FAILED ("DeactivateActCtx");
}
}
}
}
#ifdef ISOLATION_AWARE_ENABLED
# ifndef GTK_STATIC_COMPILATION
# warning "Defining ISOLATION_AWARE_ENABLED is not needed. GTK implements manual activation context handling"
# else
# error "Cannot build with ISOLATION_AWARE_ENABLED. GTK implements manual activation context handling"
# endif
#endif
/* TODO:
*
* Free the activation context on unload (ReleaseActCtx)
* Perhaps call ZombifyActCtx if a debugger is present
*/
/** gdk_win32_check_app_packaged:
*
* Check if the app is running with identity.
*
* Even if the app was installed with package identity (e.g with MSIX),
* example using MSIX), it may still be launched in classic mode;
* that happens, for example, if the user launches the exe from
* File Explorer, or when using CreateProcess(). Package identity
* is applied only when the app is activated by the system.
*/
bool
gdk_win32_check_app_packaged (void)
{
UINT32 wchars_count = 0;
LONG code;
if (!ptrGetCurrentPackageFullName)
return false;
code = ptrGetCurrentPackageFullName (&wchars_count, NULL);
if (code == APPMODEL_ERROR_NO_PACKAGE)
return false;
else if (code == ERROR_SUCCESS || code == ERROR_INSUFFICIENT_BUFFER)
return true;
WIN32_API_FAILED_WITH_CODE ("GetCurrentPackageFullName", code);
return false;
}
/** gdk_win32_check_app_container:
*
* Check if running sandboxed in an app container
*/
bool
gdk_win32_check_app_container (void)
{
HANDLE token_handle = NULL;
DWORD is_app_container = 0;
DWORD size = sizeof (is_app_container);
bool result = false;
/* Since Windows 8: use GetCurrentProcessToken() and remove the call to CloseHandle() */
if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &token_handle))
{
WIN32_API_FAILED ("OpenProcessToken");
return false;
}
if (!GetTokenInformation (token_handle, TokenIsAppContainer, &is_app_container, size, &size))
WIN32_API_FAILED ("GetTokenInformation");
else if (size > 0)
result = !!is_app_container;
CloseHandle (token_handle);
return result;
}
/** gdk_win32_check_high_integrity:
*
* Check if the app is running with high integrity
*
* Code based on:
* https://devblogs.microsoft.com/oldnewthing/20221017-00/?p=107291
* https://github.com/microsoft/WindowsAppSDK/blob/main/dev/Common/Security.IntegrityLevel.h
*/
bool
gdk_win32_check_high_integrity (void)
{
HANDLE token_handle = NULL;
TOKEN_MANDATORY_LABEL integrity_level;
DWORD size = sizeof (integrity_level);
bool result = false;
/* Since Windows 8: use GetCurrentProcessToken() and remove the call to CloseHandle() */
if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &token_handle))
{
WIN32_API_FAILED ("OpenProcessToken");
return false;
}
memset (&integrity_level, 0, sizeof (integrity_level));
if (!GetTokenInformation (token_handle, TokenIntegrityLevel, &integrity_level, size, &size))
WIN32_API_FAILED ("GetTokenInformation");
else if (size > 0 && IsValidSid (integrity_level.Label.Sid))
{
UCHAR subauthority_count = *GetSidSubAuthorityCount (integrity_level.Label.Sid);
if (subauthority_count > 0)
{
DWORD level = *GetSidSubAuthority (integrity_level.Label.Sid, subauthority_count - 1);
result = (level >= SECURITY_MANDATORY_HIGH_RID);
}
}
CloseHandle (token_handle);
return result;
}
/** gdk_win32_check_manually_elevated:
*
* Code based on:
* https://devblogs.microsoft.com/oldnewthing/20241003-00/?p=110336
*/
bool
gdk_win32_check_manually_elevated (void)
{
HANDLE token_handle = NULL;
TOKEN_ELEVATION_TYPE elevation_type = TokenElevationTypeDefault;
DWORD size = sizeof (elevation_type);
bool result = false;
/* Since Windows 8: use GetCurrentProcessToken() and remove the call to CloseHandle() */
if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &token_handle))
{
WIN32_API_FAILED ("OpenProcessToken");
return false;
}
if (!GetTokenInformation (token_handle, TokenElevationType, &elevation_type, size, &size))
WIN32_API_FAILED ("GetTokenInformation");
else if (size > 0)
result = (elevation_type == TokenElevationTypeFull);
CloseHandle (token_handle);
return result;
}
static int
get_comctl32_version (HMODULE module_handle)
{
DLLGETVERSIONPROC ptrDllGetVersion;
DLLVERSIONINFO info = {0};
HRESULT hr = E_FAIL;
int result = 0;
ptrDllGetVersion = (DLLGETVERSIONPROC) GetProcAddress (module_handle, "DllGetVersion");
if (!ptrDllGetVersion)
return 1;
// TODO: Add support for DLLVERSIONINFO2
// TODO: This won't work in app containers, probably
info.cbSize = sizeof (info);
hr = ptrDllGetVersion (&info);
if (FAILED (hr))
HR_LOG ("DllGetVersion", hr);
else
result = ;
return result;
}
/** gdk_win32_get_comctl32_version:
*
* Get the major version of the Common Controls library. Note that
* common controls may not be present on modern Windows editions
* (Core, Hololens, etc.)
*
* Returns: TODO
*/
int
gdk_win32_get_comctl32_version (void)
{
struct api_set *api_set;
struct module *module;
HMODULE module_handle;
api_set *api_set = gdk_win32_get_api_set (API_SET_EXT_WIN_SHELL_INIT);
if (api_set)
return get_comctl32_version (api_set->module_handle);
module = gdk_win32_get_module (MODULE_COMCTL32);
if (module)
return get_comctl32_version (module->module_handle);
return 0;
}
void
_gdk_win32_api_failed (const char *where,
const char *api)

42
gdk/win32/gdkmain-win32.h Normal file
View File

@@ -0,0 +1,42 @@
#pragma once
#include <stdbool.h>
typedef enum {
OSVersionWindows7,
OSVersionWindows8,
OSVersionWindows8_1,
OSVersionWindows10,
OSVersionWindows11,
} OSVersion;
OSVersion
gdk_win32_get_os_version (void);
void
gdk_win32_invoke_callback (void (*callback)(void *arg),
void *user_data,
...);
struct invoke_context;
typedef struct invoke_context invoke_context_t;
void
gdk_win32_with_loader_error_mode (invoke_context_t *context);
void
gdk_win32_with_activation_context (invoke_context_t *context);
bool
gdk_win32_check_app_packaged (void);
#ifdef _MSC_VER
#define SEH_TRY __try
#define SEH_FINALLY __finally
#define SEH_ABNORMAL_TERMINATION() AbnormalTermination()
#else
#define SEH_TRY
#define SEH_FINALLY
#define SEH_ABNORMAL_TERMINATION() FALSE
#endif

View File

@@ -288,4 +288,3 @@ this_module (void)
{
return (HMODULE) &__ImageBase;
}

View File

@@ -13,6 +13,7 @@ gdk_win32_public_sources = files([
])
gdk_win32_sources = gdk_win32_public_sources + files([
'apisets.c',
'gdkcairocontext-win32.c',
'gdkclipboard-win32.c',
'gdkclipdrop-win32.c',
@@ -34,6 +35,7 @@ gdk_win32_sources = gdk_win32_public_sources + files([
'gdkwin32cursor.h',
'gdkwin32display.h',
'gdkwin32keys.h',
'procedures.c',
])
gdk_win32_public_headers = files([

View File

@@ -0,0 +1,56 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2024 the GTK team
*
* 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 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/>.
*/
#include "config.h"
#include "procedures.h"
#include <windows.h>
#include <apiquery2.h>
#include <appmodel.h>
#include <stdint.h>
/* This file is used to generate entries in the delayload import table for
* all the optional procedures used by GTK. That's needed for appcontainer
* environments, where procedures can be obtained dynamically only when
* present in the delayload import table (even though we don't use delay
* loading)
*/
/* This file must be compiled with OneCoreUAP_apiset.lib
* and WINAPI_PARTITION_DESKTOP
*/
# if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
# error "Invalid WINAPI_FAMILY_PARTITION, WINAPI_PARTITION_DESKTOP is required"
# endif
static void
api_entries_dummy_ctor (void)
{
uintptr_t dummy_value =
# define PROCEDURE(name, api_set_id, module_id, os_version) \
((uintptr_t) (void*) name) +
PROCEDURES
# endif
0;
EncodePointer ((void*)dummy_value);
}
G_DEFINE_CONSTRUCTOR (api_entries_dummy_ctor)

147
gdk/win32/procedures.c Normal file
View File

@@ -0,0 +1,147 @@
/* GTK - The GIMP Toolkit
*
* Copyright (C) 2024 the GTK team
*
* 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 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/>.
*/
#include "config.h"
#include "apisets.h"
#include "procedures.h"
#include "gdkmain-win32.h"
#include "gdkprivate-win32.h"
# define PROCEDURE(name, api_set_id, module_id, os_version) \
name##_t ptr##name;
PROCEDURES
# undef PROCEDURE
struct procedure {
void **pp;
char *name;
int api_set_id;
int module_id;
OSVersion os_version;
};
static struct procedure
procedures[] = {
# define PROCEDURE(name, api_set_id, module_id, os_version) \
{(void**)&ptr##name, #name, api_set_id, module_id, os_version},
PROCEDURES
# undef PROCEDURE
};
static void *
load_common (HMODULE module_handle,
const char *type,
const wchar_t *m_name,
const char *name,
OSVersion os_version)
{
void *proc = GetProcAddress (module_handle, name);
if (proc == NULL)
{
DWORD code = GetLastError ();
if (code != ERROR_PROC_NOT_FOUND)
WIN32_API_FAILED ("GetProcAddress");
else if (gdk_win32_get_os_version () >= os_version)
g_warning ("Could not find procedure %s in %s %S",
name, type, m_name);
}
return proc;
}
static bool
load_by_api_set (struct procedure *procedure)
{
struct api_set *api_set = gdk_win32_get_api_set (procedure->api_set_id);
if (api_set->module_handle)
*procedure->pp = load_common (api_set->module_handle,
"api set",
api_set->name_wide,
procedure->name,
procedure->os_version);
return *procedure->pp != NULL;
}
static bool
load_by_module (struct procedure *procedure)
{
struct module *module = gdk_win32_get_module (procedure->module_id);
if (module->module_handle)
*procedure->pp = load_common (module->module_handle,
"module",
module->name,
procedure->name,
procedure->os_version);
return *procedure->pp != NULL;
}
#if 0
static void
load_by_package (struct procedure *procedure)
{
struct package *package = gdk_win32_get_package (procedure->package_id);
if (package->module_handle)
*procedure->pp = load_common (package->module_handle,
"package",
package->name,
procedure->name,
procedure->os_version);
}
#endif
static void
procedures_load_internal (void *)
{
for (size_t i = 0; i < G_N_ELEMENTS (procedures); i++)
{
struct procedure *procedure = &procedures[i];
g_assert (*procedure->pp == NULL);
load_by_api_set (procedure) ||
load_by_module (procedure) ||
load_by_package (procedure);
}
}
void
gdk_win32_procedures_load (void)
{
gdk_win32_invoke_callback (procedures_load_internal,
NULL,
gdk_win32_with_loader_error_mode,
gdk_win32_with_activation_context,
NULL);
}
void
gdk_win32_procedures_unload (void)
{
for (size_t i = 0; i < G_N_ELEMENTS (procedures); i++)
*procedures[i].pp = NULL;
}

46
gdk/win32/procedures.h Normal file
View File

@@ -0,0 +1,46 @@
/* GTK - The GIMP Toolkit
*
* Copyright (C) 2024 the GTK team
*
* 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 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/>.
*/
#pragma once
#include <windows.h>
typedef BOOL
(APIENTRY *IsApiSetImplemented_t) (PCSTR Contract);
typedef LONG
(WINAPI *GetCurrentPackageFullName_t) (UINT32 packageFullNameLength,
PWSTR packageFullName);
typedef HMODULE
(WINAPI *LoadPackagedLibrary_t) (LPCWSTR lpwLibFileName,
DWORD Reserved);
#define PROCEDURES \
PROCEDURE (IsApiSetImplemented , API_CORE_APIQUERY_2 , -1 , -1 ) \
PROCEDURE (GetCurrentPackageFullName , API_APPMODEL_RUNTIME_1 , MODULE_KERNEL32 , OSVersionWindows8) \
PROCEDURE (LoadPackagedLibrary , API_CORE_LIBRARYLOADER_2 , MODULE_KERNEL32 , OSVersionWindows8) \
#define PROCEDURE(name, api_set_id, module_id, os_version) \
extern name##_t ptr##name;
PROCEDURES
#undef PROCEDURE
void gdk_win32_procedures_load (void);
void gdk_win32_procedures_unload (void);