* /\ _ \ /\_ \ /\_ \
* \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
* \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
* \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
* \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
* \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
* /\____/
* \_/__/
*
* New Windows system driver
*
* Based on the X11 OpenGL driver by Elias Pschernig.
*
* Heavily modified by Trent Gamblin.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include "allegro5/allegro.h"
#include "allegro5/internal/aintern.h"
#include "allegro5/internal/aintern_bitmap.h"
#include "allegro5/internal/aintern_system.h"
#include "allegro5/platform/aintwin.h"
#include "allegro5/internal/aintern_wunicode.h"
#if defined ALLEGRO_CFG_OPENGL
#include "allegro5/allegro_opengl.h"
#endif
#include <windows.h>
#include <mmsystem.h>
ALLEGRO_DEBUG_CHANNEL("system")
{ */
#include <psapi.h>
#if _WIN32_IE < 0x500
#undef _WIN32_IE
#define _WIN32_IE 0x500
#endif
#include <shlobj.h>
#include <shlwapi.h>
bool _al_win_disable_screensaver = false;
static ALLEGRO_SYSTEM_INTERFACE *vt = 0;
static bool using_higher_res_timer;
static ALLEGRO_SYSTEM_WIN *_al_win_system;
static ALLEGRO_MUTEX* win_mutex;
* Entry point for Windows GUI programs, hooked by a macro in alwin.h,
* which makes it look as if the application can still have a normal
* main() function.
*/
int _WinMain(void *_main, void *hInst, void *hPrev, char *Cmd, int nShow)
{
int (*mainfunc) (int argc, char *argv[]) = (int (*)(int, char *[]))_main;
char *argbuf;
char **argv;
int argc;
int argc_max;
int i, q;
(void)hInst;
(void)hPrev;
(void)Cmd;
(void)nShow;
argbuf = _twin_tchar_to_utf8(GetCommandLine());
argc = 0;
argc_max = 64;
argv = al_malloc(sizeof(char *) * argc_max);
if (!argv) {
al_free(argbuf);
return 1;
}
i = 0;
while (argbuf[i]) {
while ((argbuf[i]) && (isspace(argbuf[i])))
i++;
if (argbuf[i]) {
if ((argbuf[i] == '\'') || (argbuf[i] == '"')) {
q = argbuf[i++];
if (!argbuf[i])
break;
}
else
q = 0;
argv[argc++] = &argbuf[i];
if (argc >= argc_max) {
argc_max += 64;
argv = al_realloc(argv, sizeof(char *) * argc_max);
if (!argv) {
al_free(argbuf);
return 1;
}
}
while ((argbuf[i]) && ((q) ? (argbuf[i] != q) : (!isspace(argbuf[i]))))
i++;
if (argbuf[i]) {
argbuf[i] = 0;
i++;
}
}
}
argv[argc] = NULL;
i = mainfunc(argc, argv);
al_free(argv);
al_free(argbuf);
return i;
}
static void set_dpi_awareness(void)
{
bool dpi_awareness_set = false;
* not often included in MinGW headers. */
HMODULE shcore_dll = _al_win_safe_load_library("shcore.dll");
if (shcore_dll) {
typedef enum _AL_PROCESS_DPI_AWARENESS {
AL_PROCESS_DPI_UNAWARE = 0,
AL_PROCESS_SYSTEM_DPI_AWARE = 1,
AL_PROCESS_PER_MONITOR_DPI_AWARE = 2
} AL_PROCESS_DPI_AWARENESS;
typedef HRESULT (WINAPI *SetProcessDpiAwarenessPROC)(AL_PROCESS_DPI_AWARENESS);
SetProcessDpiAwarenessPROC imp_SetProcessDpiAwareness =
(SetProcessDpiAwarenessPROC)GetProcAddress(shcore_dll, "SetProcessDpiAwareness");
if (imp_SetProcessDpiAwareness) {
HRESULT ret = imp_SetProcessDpiAwareness(AL_PROCESS_PER_MONITOR_DPI_AWARE);
if (ret == E_INVALIDARG) {
ret = imp_SetProcessDpiAwareness(AL_PROCESS_SYSTEM_DPI_AWARE);
}
if (ret == S_OK) {
dpi_awareness_set = true;
}
}
FreeLibrary(shcore_dll);
}
* awareness above. This is the only option on pre-8.1 systems. */
if (!dpi_awareness_set) {
HMODULE user32_dll = _al_win_safe_load_library("user32.dll");
if (user32_dll) {
typedef BOOL (WINAPI *SetProcessDPIAwarePROC)(void);
SetProcessDPIAwarePROC imp_SetProcessDPIAware =
(SetProcessDPIAwarePROC)GetProcAddress(user32_dll, "SetProcessDPIAware");
if (imp_SetProcessDPIAware) {
imp_SetProcessDPIAware();
}
FreeLibrary(user32_dll);
}
}
}
static ALLEGRO_SYSTEM *win_initialize(int flags)
{
(void)flags;
set_dpi_awareness();
_al_win_system = al_calloc(1, sizeof *_al_win_system);
if (timeBeginPeriod(1) != TIMERR_NOCANDO) {
using_higher_res_timer = true;
}
_al_win_init_time();
_al_win_init_window();
_al_vector_init(&_al_win_system->system.displays, sizeof (ALLEGRO_SYSTEM_WIN *));
_al_win_system->system.vt = vt;
win_mutex = al_create_mutex();
return &_al_win_system->system;
}
static void win_shutdown(void)
{
ALLEGRO_SYSTEM *s;
ASSERT(vt);
s = al_get_system_driver();
while (_al_vector_size(&s->displays) > 0) {
ALLEGRO_DISPLAY **dptr = _al_vector_ref(&s->displays, 0);
ALLEGRO_DISPLAY *d = *dptr;
al_destroy_display(d);
}
_al_vector_free(&s->displays);
#ifdef ALLEGRO_CFG_D3D
_al_d3d_shutdown_display();
#endif
_al_win_shutdown_window();
_al_win_shutdown_time();
if (using_higher_res_timer) {
timeEndPeriod(1);
}
al_free(vt);
vt = NULL;
al_destroy_mutex(win_mutex);
ASSERT(_al_win_system);
al_free(_al_win_system);
}
static ALLEGRO_DISPLAY_INTERFACE *win_get_display_driver(void)
{
const int flags = al_get_new_display_flags();
ALLEGRO_SYSTEM *sys = al_get_system_driver();
ALLEGRO_CONFIG *sys_cfg = al_get_system_config();
ALLEGRO_SYSTEM_WIN *syswin = (ALLEGRO_SYSTEM_WIN *)sys;
const char *s;
* to do it, but the config file is not available in win_initialize,
* and this is neutral between the D3D and OpenGL display drivers.
*/
if (!syswin->toggle_mouse_grab_keycode) {
const char *binding = al_get_config_value(sys_cfg, "keyboard",
"toggle_mouse_grab_key");
if (binding) {
syswin->toggle_mouse_grab_keycode = _al_parse_key_binding(binding,
&syswin->toggle_mouse_grab_modifiers);
if (syswin->toggle_mouse_grab_keycode) {
ALLEGRO_DEBUG("Toggle mouse grab key: '%s'\n", binding);
}
else {
ALLEGRO_WARN("Cannot parse key binding '%s'\n", binding);
}
}
}
#ifdef ALLEGRO_CFG_D3D
if (flags & ALLEGRO_DIRECT3D_INTERNAL) {
al_lock_mutex(win_mutex);
ALLEGRO_DISPLAY_INTERFACE* iface = _al_display_d3d_driver();
al_unlock_mutex(win_mutex);
if (iface == NULL)
ALLEGRO_WARN("Direct3D graphics driver not available.\n");
return iface;
}
#endif
#ifdef ALLEGRO_CFG_OPENGL
if (flags & ALLEGRO_OPENGL) {
return _al_display_wgl_driver();
}
#endif
* The user may unknowingly set a value which was configured out at compile
* time. The value should have no effect instead of causing a failure.
*/
s = al_get_config_value(sys_cfg, "graphics", "driver");
if (s) {
ALLEGRO_DEBUG("Configuration value graphics.driver = %s\n", s);
if (0 == _al_stricmp(s, "DIRECT3D") || 0 == _al_stricmp(s, "D3D")) {
#ifdef ALLEGRO_CFG_D3D
al_lock_mutex(win_mutex);
ALLEGRO_DISPLAY_INTERFACE* iface = _al_display_d3d_driver();
al_unlock_mutex(win_mutex);
if (iface != NULL) {
al_set_new_display_flags(flags | ALLEGRO_DIRECT3D_INTERNAL);
return iface;
}
#endif
}
else if (0 == _al_stricmp(s, "OPENGL")) {
#ifdef ALLEGRO_CFG_OPENGL
al_set_new_display_flags(flags | ALLEGRO_OPENGL);
return _al_display_wgl_driver();
#endif
}
else if (0 != _al_stricmp(s, "DEFAULT")) {
ALLEGRO_WARN("Graphics driver selection unrecognised: %s\n", s);
}
}
#ifdef ALLEGRO_CFG_D3D
{
al_lock_mutex(win_mutex);
ALLEGRO_DISPLAY_INTERFACE* iface = _al_display_d3d_driver();
al_unlock_mutex(win_mutex);
if (iface != NULL) {
al_set_new_display_flags(flags | ALLEGRO_DIRECT3D_INTERNAL);
return iface;
}
}
#endif
#ifdef ALLEGRO_CFG_OPENGL
{
al_set_new_display_flags(flags | ALLEGRO_OPENGL);
return _al_display_wgl_driver();
}
#endif
ALLEGRO_WARN("No graphics driver available.\n");
return NULL;
}
static ALLEGRO_KEYBOARD_DRIVER *win_get_keyboard_driver(void)
{
return _al_keyboard_driver_list[0].driver;
}
* Also returns false if the configuration entry was not set.
*/
static bool win_configured_joystick_driver_is(const char * name)
{
const char * driver;
ALLEGRO_CONFIG * sysconf = al_get_system_config();
if (!sysconf) return false;
driver = al_get_config_value(sysconf, "joystick", "driver");
if (!driver) return false;
ALLEGRO_DEBUG("Configuration value joystick.driver = %s\n", driver);
return (0 == _al_stricmp(driver, name));
}
* to configuration.
*/
static bool win_use_xinput(void)
{
return win_configured_joystick_driver_is("XINPUT");
}
* to configuration.
*/
static bool win_use_directinput(void)
{
return win_configured_joystick_driver_is("DIRECTINPUT");
}
* or xinput exclusive is set.*/
static ALLEGRO_JOYSTICK_DRIVER *win_get_joystick_driver(void)
{
if (win_use_directinput()) {
ALLEGRO_DEBUG("Selected DirectInput joystick driver.\n");
return &_al_joydrv_directx;
}
if (win_use_xinput()) {
#ifdef ALLEGRO_CFG_XINPUT
ALLEGRO_DEBUG("Selected XInput joystick driver.\n");
return &_al_joydrv_xinput;
#else
ALLEGRO_WARN("XInput joystick driver not supported.\n");
#endif
}
#ifdef ALLEGRO_CFG_XINPUT
ALLEGRO_DEBUG("Selected combined XInput/DirectInput joystick driver.\n");
return &_al_joydrv_windows_all;
#else
ALLEGRO_WARN("Combined XInput/DirectInput joystick driver not supported. Usign DirectInput in stead.\n");
return &_al_joydrv_directx;
#endif
}
* xinput exclusive is set in the configuration.*/
static ALLEGRO_HAPTIC_DRIVER *win_get_haptic_driver(void)
{
if (win_use_directinput()) {
ALLEGRO_DEBUG("Selected DirectInput haptic driver.\n");
return &_al_hapdrv_directx;
}
if (win_use_xinput()) {
#ifdef ALLEGRO_CFG_XINPUT
ALLEGRO_DEBUG("Selected XInput haptic driver.\n");
return &_al_hapdrv_xinput;
#else
ALLEGRO_WARN("XInput haptic driver not supported.\n");
#endif
}
#ifdef ALLEGRO_CFG_XINPUT
ALLEGRO_DEBUG("Selected combined XInput/DirectInput haptic driver.\n");
return &_al_hapdrv_windows_all;
#else
ALLEGRO_WARN("Combined XInput/DirectInput haptic driver not supported. Using DirectInput in stead.\n");
return &_al_hapdrv_directx;
#endif
}
static int win_get_num_display_modes(void)
{
int format = _al_deduce_color_format(_al_get_new_display_settings());
int refresh_rate = al_get_new_display_refresh_rate();
int flags = al_get_new_display_flags();
#if defined ALLEGRO_CFG_OPENGL
if (flags & ALLEGRO_OPENGL) {
return _al_wgl_get_num_display_modes(format, refresh_rate, flags);
}
#endif
#if defined ALLEGRO_CFG_D3D
return _al_d3d_get_num_display_modes(format, refresh_rate, flags);
#endif
return 0;
}
static ALLEGRO_DISPLAY_MODE *win_get_display_mode(int index,
ALLEGRO_DISPLAY_MODE *mode)
{
int format = _al_deduce_color_format(_al_get_new_display_settings());
int refresh_rate = al_get_new_display_refresh_rate();
int flags = al_get_new_display_flags();
#if defined ALLEGRO_CFG_OPENGL
if (flags & ALLEGRO_OPENGL) {
return _al_wgl_get_display_mode(index, format, refresh_rate, flags, mode);
}
#endif
#if defined ALLEGRO_CFG_D3D
return _al_d3d_get_display_mode(index, format, refresh_rate, flags, mode);
#endif
return NULL;
}
static int win_get_num_video_adapters(void)
{
DISPLAY_DEVICE dd;
int count = 0;
int c = 0;
memset(&dd, 0, sizeof(dd));
dd.cb = sizeof(dd);
while (EnumDisplayDevices(NULL, count, &dd, 0) != false) {
if (dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)
c++;
count++;
}
return c;
}
static int win_find_nth_adapter_with_desktop(DISPLAY_DEVICE* pdd, int adapter)
{
int count = 0;
int c = 0;
while (EnumDisplayDevices(NULL, count, pdd, 0)) {
if (pdd->StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) {
if (c == adapter)
return true;
c++;
}
count++;
}
return false;
}
static int win_get_monitor_refresh_rate(int adapter)
{
DISPLAY_DEVICE dd;
DEVMODE dm;
memset(&dd, 0, sizeof(dd));
dd.cb = sizeof(dd);
if (!win_find_nth_adapter_with_desktop(&dd, adapter)) {
return 0;
}
memset(&dm, 0, sizeof(dm));
dm.dmSize = sizeof(dm);
if (!EnumDisplaySettings(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm)) {
return 0;
}
return dm.dmDisplayFrequency;
}
static bool win_get_monitor_info(int adapter, ALLEGRO_MONITOR_INFO *info)
{
DISPLAY_DEVICE dd;
DEVMODE dm;
memset(&dd, 0, sizeof(dd));
dd.cb = sizeof(dd);
if (!win_find_nth_adapter_with_desktop(&dd, adapter)) {
return false;
}
memset(&dm, 0, sizeof(dm));
dm.dmSize = sizeof(dm);
if (!EnumDisplaySettings(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm)) {
return false;
}
ASSERT(dm.dmFields & DM_PELSHEIGHT);
ASSERT(dm.dmFields & DM_PELSWIDTH);
info->x1 = dm.dmPosition.x;
info->y1 = dm.dmPosition.y;
info->x2 = info->x1 + dm.dmPelsWidth;
info->y2 = info->y1 + dm.dmPelsHeight;
return true;
}
static BOOL CALLBACK monitor_enum_proc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
{
HMONITOR *h_monitor = (HMONITOR *) dwData;
(void)hdcMonitor;
(void)lprcMonitor;
if (hMonitor) {
*h_monitor = hMonitor;
return false;
}
return true;
}
static HMONITOR win_get_monitor(ALLEGRO_MONITOR_INFO *info)
{
HMONITOR h_monitor;
RECT rect;
rect.left = info->x1;
rect.top = info->y1;
rect.right = info->x2;
rect.bottom = info->y2;
EnumDisplayMonitors(NULL, &rect, monitor_enum_proc, (LPARAM) &h_monitor);
return h_monitor;
}
static int win_get_monitor_dpi(int adapter)
{
ALLEGRO_MONITOR_INFO info;
HMODULE shcore_dll = _al_win_safe_load_library("shcore.dll");
UINT dpi_hori;
UINT dpi_vert;
typedef enum _AL_MONITOR_DPI_TYPE {
AL_MDT_EFFECTIVE_DPI = 0,
AL_MDT_ANGULAR_DPI = 1,
AL_MDT_RAW_DPI = 2,
AL_MDT_DEFAULT = AL_MDT_EFFECTIVE_DPI
} AL_MONITOR_DPI_TYPE;
typedef HRESULT (WINAPI *GetDpiForMonitorPROC)(HMONITOR hmonitor, AL_MONITOR_DPI_TYPE dpiType, UINT *dpiX, UINT *dpiY);
GetDpiForMonitorPROC imp_GetDpiForMonitor =
(GetDpiForMonitorPROC) GetProcAddress(shcore_dll, "GetDpiForMonitor");
if (!shcore_dll) {
FreeLibrary(shcore_dll);
return 0;
}
if (!win_get_monitor_info(adapter, &info)) {
FreeLibrary(shcore_dll);
return 0;
}
imp_GetDpiForMonitor(win_get_monitor(&info), 0, &dpi_hori, &dpi_vert);
FreeLibrary(shcore_dll);
return sqrt(dpi_hori * dpi_vert);
}
static bool win_get_cursor_position(int *ret_x, int *ret_y)
{
POINT p;
GetCursorPos(&p);
*ret_x = p.x;
*ret_y = p.y;
return true;
}
static bool win_grab_mouse(ALLEGRO_DISPLAY *display)
{
ALLEGRO_SYSTEM_WIN *system = (void *)al_get_system_driver();
ALLEGRO_DISPLAY_WIN *win_disp = (void *)display;
RECT rect;
GetWindowRect(win_disp->window, &rect);
if (ClipCursor(&rect) != 0) {
system->mouse_grab_display = display;
return true;
}
return false;
}
static bool win_ungrab_mouse(void)
{
ALLEGRO_SYSTEM_WIN *system = (void *)al_get_system_driver();
ClipCursor(NULL);
system->mouse_grab_display = NULL;
return true;
}
static ALLEGRO_MOUSE_DRIVER *win_get_mouse_driver(void)
{
return _al_mouse_driver_list[0].driver;
}
static ALLEGRO_TOUCH_INPUT_DRIVER *win_get_touch_input_driver(void)
{
return _al_touch_input_driver_list[0].driver;
}
* Returns full path to various system and user diretories
*/
ALLEGRO_PATH *_al_win_get_path(int id)
{
char path[MAX_PATH];
wchar_t pathw[MAX_PATH];
ALLEGRO_USTR *pathu;
uint32_t csidl = 0;
HRESULT ret = 0;
ALLEGRO_PATH *cisdl_path = NULL;
switch (id) {
case ALLEGRO_TEMP_PATH: {
DWORD ret = GetTempPathW(MAX_PATH, pathw);
if (ret > MAX_PATH) {
return NULL;
}
pathu = al_ustr_new_from_utf16(pathw);
al_ustr_to_buffer(pathu, path, sizeof path);
al_ustr_free(pathu);
return al_create_path_for_directory(path);
} break;
case ALLEGRO_RESOURCES_PATH: {
HANDLE process = GetCurrentProcess();
char *ptr;
GetModuleFileNameExW(process, NULL, pathw, MAX_PATH);
pathu = al_ustr_new_from_utf16(pathw);
al_ustr_to_buffer(pathu, path, sizeof path);
al_ustr_free(pathu);
ptr = strrchr(path, '\\');
if (!ptr) {
return NULL;
}
*ptr = '\0';
return al_create_path_for_directory(path);
} break;
case ALLEGRO_USER_DATA_PATH:
case ALLEGRO_USER_SETTINGS_PATH:
csidl = CSIDL_APPDATA;
break;
case ALLEGRO_USER_HOME_PATH:
csidl = CSIDL_PROFILE;
break;
case ALLEGRO_USER_DOCUMENTS_PATH:
csidl = CSIDL_PERSONAL;
break;
case ALLEGRO_EXENAME_PATH: {
HANDLE process = GetCurrentProcess();
GetModuleFileNameExW(process, NULL, pathw, MAX_PATH);
pathu = al_ustr_new_from_utf16(pathw);
al_ustr_to_buffer(pathu, path, sizeof path);
al_ustr_free(pathu);
return al_create_path(path);
} break;
default:
return NULL;
}
ret = SHGetFolderPathW(NULL, csidl, NULL, SHGFP_TYPE_CURRENT, pathw);
if (ret != S_OK) {
return NULL;
}
pathu = al_ustr_new_from_utf16(pathw);
al_ustr_to_buffer(pathu, path, sizeof path);
al_ustr_free(pathu);
cisdl_path = al_create_path_for_directory(path);
if (!cisdl_path)
return NULL;
if (csidl == CSIDL_APPDATA) {
const char *org_name = al_get_org_name();
const char *app_name = al_get_app_name();
if (!app_name || !app_name[0]) {
al_destroy_path(cisdl_path);
return NULL;
}
if (org_name && org_name[0]) {
al_append_path_component(cisdl_path, org_name);
}
al_append_path_component(cisdl_path, app_name);
}
return cisdl_path;
}
static bool win_inhibit_screensaver(bool inhibit)
{
_al_win_disable_screensaver = inhibit;
return true;
}
static HMODULE load_library_at_path(const TCHAR *path_str)
{
HMODULE lib;
* XXX LoadLibrary will search the current directory for any dependencies of
* the library we are loading. Using LoadLibraryEx with the appropriate
* flags would fix that, but when I tried it I was unable to load dsound.dll
* on Vista.
*/
char* upath_str = _twin_tchar_to_utf8(path_str);
ALLEGRO_DEBUG("Calling LoadLibrary %s\n", upath_str);
lib = LoadLibrary(path_str);
if (lib) {
ALLEGRO_INFO("Loaded %s\n", upath_str);
}
else {
DWORD error = GetLastError();
HRESULT hr = HRESULT_FROM_WIN32(error);
(void)hr;
ALLEGRO_WARN("Failed to load %s (error: %ld)\n", upath_str, error);
}
al_free(upath_str);
return lib;
}
static bool is_build_config_name(const char *s)
{
return s &&
( 0 == strcmp(s, "Debug")
|| 0 == strcmp(s, "Release")
|| 0 == strcmp(s, "RelWithDebInfo")
|| 0 == strcmp(s, "Profile"));
}
static ALLEGRO_PATH *maybe_parent_dir(const ALLEGRO_PATH *path)
{
ALLEGRO_PATH *path2;
if (!path)
return NULL;
if (!is_build_config_name(al_get_path_tail(path)))
return NULL;
path2 = al_clone_path(path);
if (path2) {
al_drop_path_tail(path2);
al_set_path_filename(path2, NULL);
ALLEGRO_DEBUG("Also searching %s\n", al_path_cstr(path2, '\\'));
}
return path2;
}
* Calling LoadLibrary with a relative file name is a security risk:
* see e.g. Microsoft Security Advisory (2269637)
* "Insecure Library Loading Could Allow Remote Code Execution"
*/
HMODULE _al_win_safe_load_library(const char *filename)
{
ALLEGRO_PATH *path1 = NULL;
ALLEGRO_PATH *path2 = NULL;
TCHAR buf[MAX_PATH];
const TCHAR *other_dirs[3];
HMODULE lib = NULL;
bool msvc_only = false;
TCHAR* tfilename;
* which is also just under the current directory, then also try to load the
* library from the current directory. This leads to less surprises when
* running example programs.
*/
#if defined(ALLEGRO_MSVC)
msvc_only = true;
#endif
* executable, the Windows system directories, or directories on the PATH.
* Do NOT try to load the library from the current directory.
*/
if (al_is_system_installed()) {
path1 = al_get_standard_path(ALLEGRO_RESOURCES_PATH);
}
else if (GetModuleFileName(NULL, buf, sizeof(buf)) < sizeof(buf)) {
char* tmp = _twin_tchar_to_utf8(buf);
path1 = al_create_path(tmp);
al_free(tmp);
}
if (msvc_only) {
path2 = maybe_parent_dir(path1);
}
other_dirs[0] = path1 ? _twin_ustr_to_tchar(al_path_ustr(path1, '\\')) : NULL;
other_dirs[1] = path2 ? _twin_ustr_to_tchar(al_path_ustr(path2, '\\')) : NULL;
other_dirs[2] = NULL;
tfilename = _twin_utf8_to_tchar(filename);
_tcsncpy(buf, tfilename, MAX_PATH);
al_free(tfilename);
if (PathFindOnPath(buf, other_dirs)) {
char* tmp = _twin_tchar_to_utf8(buf);
ALLEGRO_DEBUG("PathFindOnPath found: %s\n", tmp);
al_free(tmp);
lib = load_library_at_path(buf);
}
else {
ALLEGRO_WARN("PathFindOnPath failed to find %s\n", filename);
}
al_free((void*) other_dirs[0]);
al_free((void*) other_dirs[1]);
al_destroy_path(path1);
al_destroy_path(path2);
return lib;
}
static void *win_open_library(const char *filename)
{
return _al_win_safe_load_library(filename);
}
static void *win_import_symbol(void *library, const char *symbol)
{
ASSERT(library);
return GetProcAddress(library, symbol);
}
static void win_close_library(void *library)
{
ASSERT(library);
FreeLibrary(library);
}
static ALLEGRO_SYSTEM_INTERFACE *_al_system_win_driver(void)
{
if (vt) return vt;
vt = al_calloc(1, sizeof *vt);
vt->id = ALLEGRO_SYSTEM_ID_WINDOWS;
vt->initialize = win_initialize;
vt->get_display_driver = win_get_display_driver;
vt->get_keyboard_driver = win_get_keyboard_driver;
vt->get_mouse_driver = win_get_mouse_driver;
vt->get_touch_input_driver = win_get_touch_input_driver;
vt->get_haptic_driver = win_get_haptic_driver;
vt->get_joystick_driver = win_get_joystick_driver;
vt->get_num_display_modes = win_get_num_display_modes;
vt->get_display_mode = win_get_display_mode;
vt->shutdown_system = win_shutdown;
vt->get_num_video_adapters = win_get_num_video_adapters;
vt->create_mouse_cursor = _al_win_create_mouse_cursor;
vt->destroy_mouse_cursor = _al_win_destroy_mouse_cursor;
vt->get_monitor_info = win_get_monitor_info;
vt->get_monitor_dpi = win_get_monitor_dpi;
vt->get_monitor_refresh_rate = win_get_monitor_refresh_rate;
vt->get_cursor_position = win_get_cursor_position;
vt->grab_mouse = win_grab_mouse;
vt->ungrab_mouse = win_ungrab_mouse;
vt->get_path = _al_win_get_path;
vt->inhibit_screensaver = win_inhibit_screensaver;
vt->open_library = win_open_library;
vt->import_symbol = win_import_symbol;
vt->close_library = win_close_library;
vt->get_time = _al_win_get_time;
vt->rest = _al_win_rest;
vt->init_timeout = _al_win_init_timeout;
return vt;
}
void _al_register_system_interfaces()
{
ALLEGRO_SYSTEM_INTERFACE **add;
add = _al_vector_alloc_back(&_al_system_interfaces);
*add = _al_system_win_driver();
}
const char* _al_win_error(DWORD err) {
LPTSTR msg = NULL;
int len;
static char buf[2048];
len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, err, 0, (LPTSTR)&msg, 0, NULL);
if (len == 0) {
_al_sane_strncpy(buf, "(Unable to decode the error code)", sizeof(buf));
}
else {
if (len >= 2 && _tcscmp(msg + len - 2, TEXT("\r\n")) == 0) {
msg[len - 2] = (TCHAR)0;
}
_twin_copy_tchar_to_utf8(buf, msg, sizeof(buf));
LocalFree(msg);
}
return buf;
}
const char* _al_win_last_error() {
return _al_win_error(GetLastError());
}