- callback mechanism uses defines instead of easy-to-get-wrong hardcoded strings (e.g. .LIB$WTB)
- main init hook no longer calls main() - that was causing stack weirdness and is forbidden. provide support for the app calling init directly (in case someone else is already hooking main) - wdetect: add support for old drivers that set OpenGLDrivers incorrectly (my laptop, so I can test ;p) This was SVN commit r2418.
This commit is contained in:
parent
9c4148aa0c
commit
65f9816a21
@ -31,9 +31,9 @@
|
||||
#define unlock() win_unlock(WAIO_CS)
|
||||
|
||||
|
||||
#pragma data_seg(".LIB$WCC")
|
||||
#pragma data_seg(WIN_CALLBACK_PRE_LIBC(c))
|
||||
WIN_REGISTER_FUNC(waio_init);
|
||||
#pragma data_seg(".LIB$WTX")
|
||||
#pragma data_seg(WIN_CALLBACK_POST_ATEXIT(x))
|
||||
WIN_REGISTER_FUNC(waio_shutdown);
|
||||
#pragma data_seg()
|
||||
|
||||
|
@ -193,9 +193,10 @@ static void dll_list_init(char* buf, size_t chars)
|
||||
// read DLL file version and append that and its name to the list.
|
||||
// return 0 on success or a negative error code.
|
||||
//
|
||||
// dll_path should preferably be the complete path to DLL, to make sure
|
||||
// name should preferably be the complete path to DLL, to make sure
|
||||
// we don't inadvertently load another one on the library search path.
|
||||
static int dll_list_add(const char* dll_path)
|
||||
// we add the .dll extension if necessary.
|
||||
static int dll_list_add(const char* name)
|
||||
{
|
||||
// make sure we're allowed to be called.
|
||||
if(!dll_list_pos)
|
||||
@ -204,9 +205,20 @@ static int dll_list_add(const char* dll_path)
|
||||
return -1;
|
||||
}
|
||||
|
||||
// some driver names are stored in the registry without .dll extension.
|
||||
// if necessary, copy to new buffer and add it there.
|
||||
char buf[MAX_PATH];
|
||||
const char* dll_name = name;
|
||||
char* ext = strrchr(name, '.');
|
||||
if(!ext || stricmp(ext, ".dll") != 0)
|
||||
{
|
||||
snprintf(buf, ARRAY_SIZE(buf), "%s.dll", name);
|
||||
dll_name = buf;
|
||||
}
|
||||
|
||||
// read file version.
|
||||
char dll_ver[128] = "(unknown)";
|
||||
(void)get_ver(dll_path, dll_ver, sizeof(dll_ver));
|
||||
char dll_ver[128] = "unknown"; // enclosed in () below
|
||||
(void)get_ver(dll_name, dll_ver, sizeof(dll_ver));
|
||||
// if this fails, default is already set and we don't want to abort.
|
||||
|
||||
const ssize_t max_chars_to_write = (ssize_t)dll_list_chars - (dll_list_pos-dll_list_buf) - 10;
|
||||
@ -217,8 +229,8 @@ static int dll_list_add(const char* dll_path)
|
||||
dll_list_pos += sprintf(dll_list_pos, ", ");
|
||||
|
||||
// extract filename.
|
||||
const char* slash = strrchr(dll_path, '\\');
|
||||
const char* dll_fn = slash? slash+1 : dll_path;
|
||||
const char* slash = strrchr(dll_name, '\\');
|
||||
const char* dll_fn = slash? slash+1 : dll_name;
|
||||
|
||||
int len = snprintf(dll_list_pos, max_chars_to_write, "%s (%s)", dll_fn, dll_ver);
|
||||
// success
|
||||
@ -286,49 +298,54 @@ static int win_get_gfx_drv_ver()
|
||||
// gfx_card which one is correct; we thus avoid driver-specific
|
||||
// name checks and reporting incorrectly.
|
||||
|
||||
dll_list_init(gfx_drv_ver, GFX_DRV_VER_LEN);
|
||||
|
||||
int ret = -1; // single point of exit (for RegCloseKey)
|
||||
DWORD i;
|
||||
char drv_name[MAX_PATH+1];
|
||||
|
||||
dll_list_init(gfx_drv_ver, GFX_DRV_VER_LEN);
|
||||
|
||||
HKEY hkOglDrivers;
|
||||
const char* key = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\OpenGLDrivers";
|
||||
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_ENUMERATE_SUB_KEYS, &hkOglDrivers) != 0)
|
||||
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hkOglDrivers) != 0)
|
||||
return -1;
|
||||
|
||||
// for each subkey (i.e. set of installed OpenGL drivers):
|
||||
for(DWORD idx = 0; ; idx++)
|
||||
for(i = 0; ; i++)
|
||||
{
|
||||
char set_name[32];
|
||||
DWORD set_name_len = ARRAY_SIZE(set_name);
|
||||
LONG err = RegEnumKeyEx(hkOglDrivers, idx, set_name, &set_name_len, 0, 0,0, 0);
|
||||
if(err != 0) // error or no more items - bail
|
||||
LONG err = RegEnumKeyEx(hkOglDrivers, i, set_name, &set_name_len, 0, 0,0, 0);
|
||||
if(err != ERROR_SUCCESS) // error or no more items - bail
|
||||
break;
|
||||
|
||||
HKEY hkSet;
|
||||
if(RegOpenKeyEx(hkOglDrivers, set_name, 0, KEY_QUERY_VALUE, &hkSet) == 0)
|
||||
{
|
||||
char drv_path[MAX_PATH+1];
|
||||
DWORD drv_path_len = ARRAY_SIZE(drv_path)-5; // for ".dll"
|
||||
if(RegQueryValueEx(hkSet, "Dll", 0, 0, (LPBYTE)drv_path, &drv_path_len) == 0)
|
||||
{
|
||||
// we don't know if .dll extension is present; make sure.
|
||||
char* ext = strrchr(drv_path, '.');
|
||||
if(!ext || stricmp(ext, ".dll") != 0)
|
||||
strcat_s(drv_path, ARRAY_SIZE(drv_path), ".dll");
|
||||
|
||||
// note: drv_path isn't fully-qualified on some systems,
|
||||
// so we may be fooled by other DLLs on the PATH. nothing
|
||||
// we can do about it, though.
|
||||
|
||||
ret = dll_list_add(drv_path);
|
||||
if(ret < 0) // abort if it failed (see dll_list_add)
|
||||
break;
|
||||
}
|
||||
DWORD drv_name_len = ARRAY_SIZE(drv_name)-5; // for ".dll"
|
||||
if(RegQueryValueEx(hkSet, "Dll", 0, 0, (LPBYTE)drv_name, &drv_name_len) == 0)
|
||||
ret = dll_list_add(drv_name);
|
||||
|
||||
RegCloseKey(hkSet);
|
||||
}
|
||||
} // for each subkey
|
||||
|
||||
// for each value:
|
||||
// (some old drivers, e.g. S3 Super Savage, store their ICD name in a
|
||||
// single REG_SZ value. we therefore include those as well.)
|
||||
for(i = 0; ; i++)
|
||||
{
|
||||
char value_name[100]; // we don't need this, but RegEnumValue fails otherwise.
|
||||
DWORD value_name_len = ARRAY_SIZE(value_name);
|
||||
DWORD type;
|
||||
DWORD drv_name_len = ARRAY_SIZE(drv_name)-5; // for ".dll"
|
||||
DWORD err = RegEnumValue(hkOglDrivers, i, value_name,&value_name_len,
|
||||
0, &type, (LPBYTE)drv_name,&drv_name_len);
|
||||
if(err != ERROR_SUCCESS) // error or no more items - bail
|
||||
break;
|
||||
if(type == REG_SZ)
|
||||
ret = dll_list_add(drv_name);
|
||||
} // for each value
|
||||
|
||||
RegCloseKey(hkOglDrivers);
|
||||
return ret;
|
||||
}
|
||||
@ -420,9 +437,9 @@ static void add_oal_dlls_in_dir(const char* dir, DllSet* dlls)
|
||||
}
|
||||
|
||||
|
||||
// path to DS3D driver; filled by ds_enum, used by win_get_snd_info.
|
||||
// DS3D driver name; filled by ds_enum, used by win_get_snd_info.
|
||||
// side effect: remains zeroed if there's no sound card installed.
|
||||
static char ds_drv_path[MAX_PATH+1];
|
||||
static char ds_drv_name[MAX_PATH+1];
|
||||
|
||||
// store sound card name and path to DirectSound driver.
|
||||
// called for each DirectSound driver, but aborts after first valid driver.
|
||||
@ -435,8 +452,8 @@ static BOOL CALLBACK ds_enum(void* guid, const char* description, const char* mo
|
||||
if(module[0] == '\0')
|
||||
return TRUE; // continue calling
|
||||
|
||||
strcpy_s(snd_card, sizeof(snd_card), description);
|
||||
snprintf(ds_drv_path, MAX_PATH, "%s\\drivers\\%s", win_sys_dir, module);
|
||||
strcpy_s(snd_card, SND_CARD_LEN, description);
|
||||
strcpy_s(ds_drv_name, ARRAY_SIZE(ds_drv_name), module);
|
||||
|
||||
// we assume the first "driver name" (sound card) is the one we want;
|
||||
// stick with that and stop calling.
|
||||
@ -452,7 +469,7 @@ int win_get_snd_info()
|
||||
|
||||
// there are apparently no sound card/drivers installed; so indicate.
|
||||
// (the code below would fail and not produce reasonable output)
|
||||
if(ds_drv_path[0] == '\0')
|
||||
if(ds_drv_name[0] == '\0')
|
||||
{
|
||||
strcpy_s(snd_card, SND_CARD_LEN, "(none)");
|
||||
strcpy_s(snd_drv_ver, SND_DRV_VER_LEN, "(none)");
|
||||
@ -462,7 +479,7 @@ int win_get_snd_info()
|
||||
// find all DLLs related to OpenAL, retrieve their versions,
|
||||
// and store in snd_drv_ver string.
|
||||
dll_list_init(snd_drv_ver, SND_DRV_VER_LEN);
|
||||
dll_list_add(ds_drv_path);
|
||||
dll_list_add(ds_drv_name);
|
||||
std::set<std::string> dlls; // ensures uniqueness
|
||||
add_oal_dlls_in_dir(win_exe_dir, &dlls);
|
||||
add_oal_dlls_in_dir(win_sys_dir, &dlls);
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include <list>
|
||||
|
||||
|
||||
#pragma data_seg(".LIB$WTX")
|
||||
#pragma data_seg(WIN_CALLBACK_POST_ATEXIT(x))
|
||||
WIN_REGISTER_FUNC(wdir_watch_shutdown);
|
||||
#pragma data_seg()
|
||||
|
||||
|
@ -133,8 +133,8 @@ PfnDliHook __pfnDliFailureHook2;
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma data_seg(".LIB$WTY") // must be last, since DLLs are unloaded here
|
||||
// note: must be last, since DLLs are unloaded here
|
||||
#pragma data_seg(WIN_CALLBACK_POST_ATEXIT(y))
|
||||
WIN_REGISTER_FUNC(wdll_shutdown);
|
||||
#pragma data_seg()
|
||||
|
||||
|
@ -45,4 +45,33 @@
|
||||
#define WINAPI __stdcall
|
||||
#define WINAPIV __cdecl
|
||||
|
||||
|
||||
//
|
||||
// main() hook
|
||||
//
|
||||
|
||||
// our Windows-specific init code needs to run before the regular main() code.
|
||||
// ideally this would happen automagically, but there are two problems:
|
||||
// - the C standard expressly forbids calling main() directly;
|
||||
// VC apparently makes use of this and changes its calling convention.
|
||||
// if we call it, everything appears to work but stack traces in
|
||||
// release mode are incorrect (symbol address is off by 4).
|
||||
// - other libraries may also want to hook main(); in that case,
|
||||
// "one must fall". we need to provide for disabling our hook.
|
||||
// this is not enough reason to forego a hook entirely -
|
||||
// integration into new projects is easier when there is less
|
||||
// stuff to remember (here, calling our init function directly).
|
||||
//
|
||||
// what we'll do is: redefine the app's main function to app_main, have the
|
||||
// OS call our main, and call app_main from there. in case another library
|
||||
// (e.g. SDL) has the same idea, #define NO_MAIN_REDIRECT prevents the
|
||||
// above; you then need to call win_pre_main_init at the beginning of main().
|
||||
//#define NO_MAIN_REDIRECT
|
||||
|
||||
#ifdef NO_MAIN_REDIRECT
|
||||
extern void win_pre_main_init();
|
||||
#else
|
||||
#define main app_main
|
||||
#endif
|
||||
|
||||
#endif // #ifndef WIN_H__
|
||||
|
@ -357,8 +357,7 @@ extern __declspec(dllimport) int __stdcall WSAAsyncSelect(int s, HANDLE hWnd, un
|
||||
extern __declspec(dllimport) int __stdcall WSAGetLastError(void);
|
||||
#endif // #ifndef NO_WINSOCK
|
||||
|
||||
extern int WinMainCRTStartup(void);
|
||||
extern int main(int, char*[]);
|
||||
extern int mainCRTStartup(void);
|
||||
}
|
||||
|
||||
#define BIT(n) (1ul << (n))
|
||||
@ -391,6 +390,8 @@ enum
|
||||
extern void win_lock(uint idx);
|
||||
extern void win_unlock(uint idx);
|
||||
|
||||
// used in a desperate attempt to avoid deadlock in wdbg_exception_handler.
|
||||
extern int win_is_locked(uint idx);
|
||||
|
||||
|
||||
extern void* win_alloc(size_t size);
|
||||
@ -429,6 +430,9 @@ extern void win_free(void* p);
|
||||
|
||||
#define WIN_REGISTER_FUNC(func) static int func(void); static int(*p##func)(void) = func
|
||||
|
||||
#define WIN_CALLBACK_PRE_LIBC(group) ".LIB$WC" #group
|
||||
#define WIN_CALLBACK_PRE_MAIN(group) ".LIB$WI" #group
|
||||
#define WIN_CALLBACK_POST_ATEXIT(group) ".LIB$WT" #group
|
||||
|
||||
|
||||
|
||||
@ -440,4 +444,8 @@ extern char win_sys_dir[MAX_PATH+1];
|
||||
extern char win_exe_dir[MAX_PATH+1];
|
||||
|
||||
|
||||
// this isn't nice (ideally we would avoid coupling win.cpp and wdbg.cpp), but
|
||||
// necessary; see rationale at function definition.
|
||||
extern LONG WINAPI wdbg_exception_filter(EXCEPTION_POINTERS* ep);
|
||||
|
||||
#endif // #ifndef WIN_INTERNAL_H
|
||||
|
@ -62,9 +62,9 @@
|
||||
#endif
|
||||
|
||||
|
||||
#pragma data_seg(".LIB$WIB")
|
||||
#pragma data_seg(WIN_CALLBACK_PRE_MAIN(b))
|
||||
WIN_REGISTER_FUNC(wsdl_init);
|
||||
#pragma data_seg(".LIB$WTD")
|
||||
#pragma data_seg(WIN_CALLBACK_POST_ATEXIT(d))
|
||||
WIN_REGISTER_FUNC(wsdl_shutdown);
|
||||
#pragma data_seg()
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
#endif
|
||||
|
||||
|
||||
#pragma data_seg(".LIB$WTB")
|
||||
#pragma data_seg(WIN_CALLBACK_POST_ATEXIT(b))
|
||||
WIN_REGISTER_FUNC(wsock_shutdown);
|
||||
#pragma data_seg()
|
||||
|
||||
|
@ -41,9 +41,9 @@ static const int CALIBRATION_FREQ = 1;
|
||||
|
||||
|
||||
// automatic module init (before main) and shutdown (before termination)
|
||||
#pragma data_seg(".LIB$WCB")
|
||||
#pragma data_seg(WIN_CALLBACK_PRE_LIBC(b))
|
||||
WIN_REGISTER_FUNC(wtime_init);
|
||||
#pragma data_seg(".LIB$WTB")
|
||||
#pragma data_seg(WIN_CALLBACK_POST_ATEXIT(b))
|
||||
WIN_REGISTER_FUNC(wtime_shutdown);
|
||||
#pragma data_seg()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user