src/dynapi/SDL_dynapi.c
author Ryan C. Gordon
Mon, 01 Jan 2018 19:16:51 -0500
changeset 11803 454f6dc9cb85
parent 11376 91e5e5a2cb71
child 11811 5d94cb6b24d3
permissions -rw-r--r--
windows: Remove references to GetVersionExA (thanks, Andrew Pilley!).

"GetVersionExA is deprecated in windows 8.1 and above's SDK, causing a warning
when building against the win10 SDK. Attached patch cleans up the usage for a
warning-free build.

GetVersionExA was being used to test to see if SDL was running on win9x or
winnt. A quick chat with Ryan on twitter suggested that SDL doesn't
officially support win9x anymore, so the call to this can be outright removed.

As an aside, replacing the call to GetVersionExA with VerifyVersionInfoA (the
recommended path) would have been pointless, as VerifyVersionInfoA only
supports VER_PLATFORM_WIN32_NT and doesn't officially support any other value
for dwPlatformId currently. (And it's probable that win9x SDKs didn't have
VerifyVersionInfo* in them anyway.)"

Fixes Bugzilla #4019.
icculus@8094
     1
/*
icculus@8094
     2
  Simple DirectMedia Layer
slouken@10737
     3
  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
icculus@8094
     4
icculus@8094
     5
  This software is provided 'as-is', without any express or implied
icculus@8094
     6
  warranty.  In no event will the authors be held liable for any damages
icculus@8094
     7
  arising from the use of this software.
icculus@8094
     8
icculus@8094
     9
  Permission is granted to anyone to use this software for any purpose,
icculus@8094
    10
  including commercial applications, and to alter it and redistribute it
icculus@8094
    11
  freely, subject to the following restrictions:
icculus@8094
    12
icculus@8094
    13
  1. The origin of this software must not be misrepresented; you must not
icculus@8094
    14
     claim that you wrote the original software. If you use this software
icculus@8094
    15
     in a product, an acknowledgment in the product documentation would be
icculus@8094
    16
     appreciated but is not required.
icculus@8094
    17
  2. Altered source versions must be plainly marked as such, and must not be
icculus@8094
    18
     misrepresented as being the original software.
icculus@8094
    19
  3. This notice may not be removed or altered from any source distribution.
icculus@8094
    20
*/
icculus@8094
    21
icculus@8094
    22
#include "SDL_config.h"
icculus@8094
    23
#include "SDL_dynapi.h"
icculus@8094
    24
icculus@8094
    25
#if SDL_DYNAMIC_API
icculus@8094
    26
icculus@11348
    27
#if defined(__OS2__)
icculus@11348
    28
#define INCL_DOS
icculus@11348
    29
#define INCL_DOSERRORS
icculus@11348
    30
#include <dos.h>
icculus@11348
    31
#endif
icculus@11348
    32
icculus@8094
    33
#include "SDL.h"
icculus@8094
    34
slouken@11376
    35
/* These headers have system specific definitions, so aren't included above */
icculus@8094
    36
#include "SDL_syswm.h"
slouken@11376
    37
#include "SDL_vulkan.h"
icculus@8094
    38
icculus@8094
    39
/* This is the version of the dynamic API. This doesn't match the SDL version
icculus@8094
    40
   and should not change until there's been a major revamp in API/ABI.
icculus@8094
    41
   So 2.0.5 adds functions over 2.0.4? This number doesn't change;
icculus@8094
    42
   the sizeof (jump_table) changes instead. But 2.1.0 changes how a function
icculus@8094
    43
   works in an incompatible way or removes a function? This number changes,
icculus@8094
    44
   since sizeof (jump_table) isn't sufficient anymore. It's likely
icculus@8094
    45
   we'll forget to bump every time we add a function, so this is the
icculus@8094
    46
   failsafe switch for major API change decisions. Respect it and use it
icculus@8094
    47
   sparingly. */
icculus@8094
    48
#define SDL_DYNAPI_VERSION 1
icculus@8094
    49
icculus@8094
    50
static void SDL_InitDynamicAPI(void);
icculus@8094
    51
icculus@8094
    52
icculus@8094
    53
/* BE CAREFUL CALLING ANY SDL CODE IN HERE, IT WILL BLOW UP.
icculus@8094
    54
   Even self-contained stuff might call SDL_Error and break everything. */
icculus@8094
    55
icculus@8094
    56
icculus@8094
    57
/* behold, the macro salsa! */
icculus@8094
    58
icculus@8094
    59
/* !!! FIXME: ...disabled...until we write it.  :) */
icculus@8094
    60
#define DISABLE_JUMP_MAGIC 1
icculus@8094
    61
icculus@8094
    62
#if DISABLE_JUMP_MAGIC
icculus@8094
    63
/* Can't use the macro for varargs nonsense. This is atrocious. */
icculus@8094
    64
#define SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, logname, prio) \
slouken@11360
    65
    _static void SDLCALL SDL_Log##logname##name(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) { \
icculus@8094
    66
        va_list ap; initcall; va_start(ap, fmt); \
icculus@8094
    67
        jump_table.SDL_LogMessageV(category, SDL_LOG_PRIORITY_##prio, fmt, ap); \
icculus@8094
    68
        va_end(ap); \
icculus@8094
    69
    }
icculus@8094
    70
icculus@8094
    71
#define SDL_DYNAPI_VARARGS(_static, name, initcall) \
slouken@11360
    72
    _static int SDLCALL SDL_SetError##name(SDL_PRINTF_FORMAT_STRING const char *fmt, ...) { \
icculus@8094
    73
        char buf[512]; /* !!! FIXME: dynamic allocation */ \
icculus@8094
    74
        va_list ap; initcall; va_start(ap, fmt); \
icculus@8094
    75
        jump_table.SDL_vsnprintf(buf, sizeof (buf), fmt, ap); \
icculus@8094
    76
        va_end(ap); \
icculus@8094
    77
        return jump_table.SDL_SetError("%s", buf); \
icculus@8094
    78
    } \
slouken@11360
    79
    _static int SDLCALL SDL_sscanf##name(const char *buf, SDL_SCANF_FORMAT_STRING const char *fmt, ...) { \
icculus@8094
    80
        int retval; va_list ap; initcall; va_start(ap, fmt); \
icculus@8094
    81
        retval = jump_table.SDL_vsscanf(buf, fmt, ap); \
icculus@8094
    82
        va_end(ap); \
icculus@8094
    83
        return retval; \
icculus@8094
    84
    } \
slouken@11360
    85
    _static int SDLCALL SDL_snprintf##name(SDL_OUT_Z_CAP(maxlen) char *buf, size_t maxlen, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) { \
icculus@8094
    86
        int retval; va_list ap; initcall; va_start(ap, fmt); \
slouken@8820
    87
        retval = jump_table.SDL_vsnprintf(buf, maxlen, fmt, ap); \
icculus@8094
    88
        va_end(ap); \
icculus@8094
    89
        return retval; \
icculus@8094
    90
    } \
slouken@11360
    91
    _static void SDLCALL SDL_Log##name(SDL_PRINTF_FORMAT_STRING const char *fmt, ...) { \
icculus@8094
    92
        va_list ap; initcall; va_start(ap, fmt); \
icculus@8094
    93
        jump_table.SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, fmt, ap); \
icculus@8094
    94
        va_end(ap); \
icculus@8094
    95
    } \
slouken@11360
    96
    _static void SDLCALL SDL_LogMessage##name(int category, SDL_LogPriority priority, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) { \
icculus@8094
    97
        va_list ap; initcall; va_start(ap, fmt); \
icculus@8094
    98
        jump_table.SDL_LogMessageV(category, priority, fmt, ap); \
icculus@8094
    99
        va_end(ap); \
icculus@8094
   100
    } \
icculus@8094
   101
    SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Verbose, VERBOSE) \
icculus@8094
   102
    SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Debug, DEBUG) \
icculus@8094
   103
    SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Info, INFO) \
icculus@8094
   104
    SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Warn, WARN) \
icculus@8094
   105
    SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Error, ERROR) \
icculus@8094
   106
    SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Critical, CRITICAL)
icculus@8094
   107
#endif
icculus@8094
   108
icculus@8094
   109
icculus@8094
   110
/* Typedefs for function pointers for jump table, and predeclare funcs */
icculus@8094
   111
/* The DEFAULT funcs will init jump table and then call real function. */
icculus@8094
   112
/* The REAL funcs are the actual functions, name-mangled to not clash. */
icculus@8094
   113
#define SDL_DYNAPI_PROC(rc,fn,params,args,ret) \
slouken@11360
   114
    typedef rc (SDLCALL *SDL_DYNAPIFN_##fn) params; \
slouken@11360
   115
    static rc SDLCALL fn##_DEFAULT params; \
slouken@11360
   116
    extern rc SDLCALL fn##_REAL params;
icculus@8094
   117
#include "SDL_dynapi_procs.h"
icculus@8094
   118
#undef SDL_DYNAPI_PROC
icculus@8094
   119
icculus@8094
   120
/* The jump table! */
icculus@8094
   121
typedef struct {
icculus@8094
   122
    #define SDL_DYNAPI_PROC(rc,fn,params,args,ret) SDL_DYNAPIFN_##fn fn;
icculus@8094
   123
    #include "SDL_dynapi_procs.h"
icculus@8094
   124
    #undef SDL_DYNAPI_PROC
icculus@8094
   125
} SDL_DYNAPI_jump_table;
icculus@8094
   126
icculus@8094
   127
/* Predeclare the default functions for initializing the jump table. */
slouken@11360
   128
#define SDL_DYNAPI_PROC(rc,fn,params,args,ret) static rc SDLCALL fn##_DEFAULT params;
icculus@8094
   129
#include "SDL_dynapi_procs.h"
icculus@8094
   130
#undef SDL_DYNAPI_PROC
icculus@8094
   131
icculus@8094
   132
/* The actual jump table. */
icculus@8094
   133
static SDL_DYNAPI_jump_table jump_table = {
icculus@8094
   134
    #define SDL_DYNAPI_PROC(rc,fn,params,args,ret) fn##_DEFAULT,
icculus@8094
   135
    #include "SDL_dynapi_procs.h"
icculus@8094
   136
    #undef SDL_DYNAPI_PROC
icculus@8094
   137
};
icculus@8094
   138
icculus@8094
   139
/* Default functions init the function table then call right thing. */
icculus@8094
   140
#if DISABLE_JUMP_MAGIC
icculus@8094
   141
#define SDL_DYNAPI_PROC(rc,fn,params,args,ret) \
slouken@11360
   142
    static rc SDLCALL fn##_DEFAULT params { \
icculus@8094
   143
        SDL_InitDynamicAPI(); \
icculus@8094
   144
        ret jump_table.fn args; \
icculus@8094
   145
    }
icculus@8094
   146
#define SDL_DYNAPI_PROC_NO_VARARGS 1
icculus@8094
   147
#include "SDL_dynapi_procs.h"
icculus@8094
   148
#undef SDL_DYNAPI_PROC
icculus@8094
   149
#undef SDL_DYNAPI_PROC_NO_VARARGS
icculus@8094
   150
SDL_DYNAPI_VARARGS(static, _DEFAULT, SDL_InitDynamicAPI())
icculus@8094
   151
#else
icculus@8094
   152
/* !!! FIXME: need the jump magic. */
icculus@8094
   153
#error Write me.
icculus@8094
   154
#endif
icculus@8094
   155
icculus@8094
   156
/* Public API functions to jump into the jump table. */
icculus@8094
   157
#if DISABLE_JUMP_MAGIC
icculus@8094
   158
#define SDL_DYNAPI_PROC(rc,fn,params,args,ret) \
slouken@11360
   159
    rc SDLCALL fn params { ret jump_table.fn args; }
icculus@8094
   160
#define SDL_DYNAPI_PROC_NO_VARARGS 1
icculus@8094
   161
#include "SDL_dynapi_procs.h"
icculus@8094
   162
#undef SDL_DYNAPI_PROC
icculus@8094
   163
#undef SDL_DYNAPI_PROC_NO_VARARGS
icculus@8094
   164
SDL_DYNAPI_VARARGS(,,)
icculus@8094
   165
#else
icculus@8094
   166
/* !!! FIXME: need the jump magic. */
icculus@8094
   167
#error Write me.
icculus@8094
   168
#endif
icculus@8094
   169
icculus@8094
   170
icculus@8094
   171
icculus@8094
   172
/* Here's the exported entry point that fills in the jump table. */
icculus@8094
   173
/*  Use specific types when an "int" might suffice to keep this sane. */
icculus@8094
   174
typedef Sint32 (SDLCALL *SDL_DYNAPI_ENTRYFN)(Uint32 apiver, void *table, Uint32 tablesize);
icculus@8094
   175
extern DECLSPEC Sint32 SDLCALL SDL_DYNAPI_entry(Uint32, void *, Uint32);
icculus@8094
   176
icculus@8094
   177
Sint32
icculus@8094
   178
SDL_DYNAPI_entry(Uint32 apiver, void *table, Uint32 tablesize)
icculus@8094
   179
{
icculus@8094
   180
    SDL_DYNAPI_jump_table *output_jump_table = (SDL_DYNAPI_jump_table *) table;
icculus@8094
   181
icculus@8094
   182
    if (apiver != SDL_DYNAPI_VERSION) {
icculus@8094
   183
        /* !!! FIXME: can maybe handle older versions? */
icculus@8094
   184
        return -1;  /* not compatible. */
icculus@8094
   185
    } else if (tablesize > sizeof (jump_table)) {
icculus@8094
   186
        return -1;  /* newer version of SDL with functions we can't provide. */
icculus@8094
   187
    }
icculus@8094
   188
icculus@8094
   189
    /* Init our jump table first. */
icculus@8094
   190
    #define SDL_DYNAPI_PROC(rc,fn,params,args,ret) jump_table.fn = fn##_REAL;
icculus@8094
   191
    #include "SDL_dynapi_procs.h"
icculus@8094
   192
    #undef SDL_DYNAPI_PROC
icculus@8094
   193
icculus@8094
   194
    /* Then the external table... */
icculus@8094
   195
    if (output_jump_table != &jump_table) {
icculus@8094
   196
        jump_table.SDL_memcpy(output_jump_table, &jump_table, tablesize);
icculus@8094
   197
    }
icculus@8094
   198
icculus@8094
   199
    /* Safe to call SDL functions now; jump table is initialized! */
icculus@8094
   200
icculus@8094
   201
    return 0;  /* success! */
icculus@8094
   202
}
icculus@8094
   203
icculus@8094
   204
icculus@8094
   205
/* Obviously we can't use SDL_LoadObject() to load SDL.  :)  */
icculus@8094
   206
/* Also obviously, we never close the loaded library. */
icculus@8101
   207
#if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__)
icculus@8094
   208
#ifndef WIN32_LEAN_AND_MEAN
icculus@8094
   209
#define WIN32_LEAN_AND_MEAN 1
icculus@8094
   210
#endif
icculus@8094
   211
#include <windows.h>
icculus@8094
   212
static SDL_INLINE void *get_sdlapi_entry(const char *fname, const char *sym)
icculus@8094
   213
{
icculus@8094
   214
    HANDLE lib = LoadLibraryA(fname);
icculus@9305
   215
    void *retval = NULL;
icculus@9305
   216
    if (lib) {
icculus@9305
   217
        retval = GetProcAddress(lib, sym);
icculus@9305
   218
        if (retval == NULL) {
icculus@9305
   219
            FreeLibrary(lib);
icculus@9305
   220
        }
icculus@9305
   221
    }
icculus@9305
   222
    return retval;
icculus@8094
   223
}
icculus@8094
   224
icculus@11119
   225
#elif defined(unix) || defined(__unix__) || defined(__APPLE__) || defined(__HAIKU__) || defined(__QNX__)
icculus@8094
   226
#include <dlfcn.h>
icculus@8094
   227
static SDL_INLINE void *get_sdlapi_entry(const char *fname, const char *sym)
icculus@8094
   228
{
icculus@8094
   229
    void *lib = dlopen(fname, RTLD_NOW | RTLD_LOCAL);
icculus@9305
   230
    void *retval = NULL;
icculus@9305
   231
    if (lib != NULL) {
icculus@9305
   232
        retval = dlsym(lib, sym);
icculus@9305
   233
        if (retval == NULL) {
icculus@9305
   234
            dlclose(lib);
icculus@9305
   235
        }
icculus@9305
   236
    }
icculus@9305
   237
    return retval;
icculus@8094
   238
}
icculus@11345
   239
icculus@11345
   240
#elif defined(__OS2__)
icculus@11345
   241
static SDL_INLINE void *get_sdlapi_entry(const char *fname, const char *sym)
icculus@11345
   242
{
icculus@11345
   243
    HMODULE hmodule;
icculus@11345
   244
    PFN retval = NULL;
icculus@11345
   245
    char error[256];
slouken@11359
   246
    if (DosLoadModule(&error, sizeof(error), fname, &hmodule) == NO_ERROR) {
slouken@11359
   247
        if (DosQueryProcAddr(hmodule, 0, sym, &retval) != NO_ERROR) {
icculus@11345
   248
            DosFreeModule(hmodule);
icculus@11345
   249
        }
icculus@11345
   250
    }
icculus@11345
   251
    return (void *) retval;
icculus@11345
   252
}
icculus@11345
   253
icculus@8094
   254
#else
icculus@8094
   255
#error Please define your platform.
icculus@8094
   256
#endif
icculus@8094
   257
icculus@8094
   258
icculus@8094
   259
static void
icculus@8094
   260
SDL_InitDynamicAPILocked(void)
icculus@8094
   261
{
icculus@8094
   262
    const char *libname = SDL_getenv_REAL("SDL_DYNAMIC_API");
icculus@8094
   263
    SDL_DYNAPI_ENTRYFN entry = SDL_DYNAPI_entry;  /* funcs from here by default. */
icculus@8094
   264
icculus@8094
   265
    if (libname) {
icculus@8094
   266
        entry = (SDL_DYNAPI_ENTRYFN) get_sdlapi_entry(libname, "SDL_DYNAPI_entry");
icculus@8094
   267
        if (!entry) {
icculus@8094
   268
            /* !!! FIXME: fail to startup here instead? */
icculus@8094
   269
            /* !!! FIXME: definitely warn user. */
icculus@8094
   270
            /* Just fill in the function pointers from this library. */
icculus@8094
   271
            entry = SDL_DYNAPI_entry;
icculus@8094
   272
        }
icculus@8094
   273
    }
icculus@8094
   274
icculus@8094
   275
    if (entry(SDL_DYNAPI_VERSION, &jump_table, sizeof (jump_table)) < 0) {
icculus@8094
   276
        /* !!! FIXME: fail to startup here instead? */
icculus@8094
   277
        /* !!! FIXME: definitely warn user. */
icculus@8094
   278
        /* Just fill in the function pointers from this library. */
icculus@8094
   279
        if (entry != SDL_DYNAPI_entry) {
icculus@8094
   280
            if (!SDL_DYNAPI_entry(SDL_DYNAPI_VERSION, &jump_table, sizeof (jump_table))) {
icculus@8094
   281
                /* !!! FIXME: now we're screwed. Should definitely abort now. */
icculus@8094
   282
            }
icculus@8094
   283
        }
icculus@8094
   284
    }
icculus@8094
   285
icculus@8094
   286
    /* we intentionally never close the newly-loaded lib, of course. */
icculus@8094
   287
}
icculus@8094
   288
icculus@8094
   289
static void
icculus@8094
   290
SDL_InitDynamicAPI(void)
icculus@8094
   291
{
icculus@8094
   292
    /* So the theory is that every function in the jump table defaults to
icculus@8094
   293
     *  calling this function, and then replaces itself with a version that
icculus@8094
   294
     *  doesn't call this function anymore. But it's possible that, in an
icculus@8094
   295
     *  extreme corner case, you can have a second thread hit this function
icculus@8094
   296
     *  while the jump table is being initialized by the first.
icculus@8094
   297
     * In this case, a spinlock is really painful compared to what spinlocks
icculus@8094
   298
     *  _should_ be used for, but this would only happen once, and should be
icculus@8094
   299
     *  insanely rare, as you would have to spin a thread outside of SDL (as
icculus@8094
   300
     *  SDL_CreateThread() would also call this function before building the
icculus@8094
   301
     *  new thread).
icculus@8094
   302
     */
icculus@10003
   303
    static SDL_bool already_initialized = SDL_FALSE;
icculus@8094
   304
icculus@8094
   305
    /* SDL_AtomicLock calls SDL mutex functions to emulate if
icculus@8094
   306
       SDL_ATOMIC_DISABLED, which we can't do here, so in such a
icculus@8094
   307
       configuration, you're on your own. */
icculus@8094
   308
    #if !SDL_ATOMIC_DISABLED
icculus@8094
   309
    static SDL_SpinLock lock = 0;
icculus@8094
   310
    SDL_AtomicLock_REAL(&lock);
icculus@8094
   311
    #endif
icculus@8094
   312
icculus@8094
   313
    if (!already_initialized) {
icculus@8094
   314
        SDL_InitDynamicAPILocked();
icculus@8094
   315
        already_initialized = SDL_TRUE;
icculus@8094
   316
    }
icculus@8094
   317
icculus@8094
   318
    #if !SDL_ATOMIC_DISABLED
icculus@8094
   319
    SDL_AtomicUnlock_REAL(&lock);
icculus@8094
   320
    #endif
icculus@8094
   321
}
icculus@8094
   322
icculus@8094
   323
#endif  /* SDL_DYNAMIC_API */
icculus@8094
   324
icculus@8094
   325
/* vi: set ts=4 sw=4 expandtab: */