1
0
forked from 0ad/0ad

- 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:
janwas 2005-06-21 16:31:55 +00:00
parent 9c4148aa0c
commit 65f9816a21
9 changed files with 101 additions and 47 deletions

View File

@ -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()

View File

@ -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);

View File

@ -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()

View File

@ -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()

View File

@ -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__

View File

@ -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

View File

@ -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()

View File

@ -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()

View File

@ -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()