DLL
|
Description
|
rotor_pal.dll
|
和平台相关的PAL的实现
|
rotor_palrt.dll
|
PAL Runtime,和平台无关的公共代码都在这里。比如加密/解密,资源,Assert,String等等
|
rotor_palrt_s.dll
|
静态GUID的定义
|
PALIMPORT
int
PALAPI
PAL_Initialize(
int argc,
char *argv[])
{
int RetVal = 0;
LONG RefCount;
RefCount = InterlockedIncrement(&PalReferenceCount);
if (RefCount == 1)
{
RetVal = PAL_Startup(argc, argv);
}
LOGAPI("PAL_Initialize(argc=0x%x, argv=%p)\n", argc, argv);
LOGAPI("PAL_Initialize returns int 0x%x\n", RetVal);
return RetVal;
}
|
1. 首先PAL_Startup获得rotor_pal.dll的FullPathName:
Int
PALAPI
PAL_Startup(
int argc,
char *argv[])
{
int RetVal = -1;
HMODULE hMod;
WCHAR ModulePath[_MAX_PATH];
hMod = GetModuleHandleW(L"rotor_pal.dll");
if (!hMod) {
return RetVal;
}
if (!GetModuleFileNameW(hMod,
ModulePath,
sizeof(ModulePath)/sizeof(WCHAR))) {
return RetVal;
}
|
2. 设置ErrorMode,从而在无法打开文件的和CriticalError的情况下不显示错误对话框,直接返回错误。3. 调用RegisterWithEventLog在注册表中注册Rotor,这样RegisterEventSource才可以注册Rotor这个Source,ReportEvent才能工作。具体请参看MSDN。4. 调用InitializeObjecNameMangler初始化NameMangler。NameMangler的作用是根据rotor_pal.dll的所在位置用SHA1算法计算出一个Hash值,再转换为一个合法路径名。在很多需要名字的地方,如CreateEvent, CreateMutex…等均会将传入的名字进行Mangle处理,从而使得这些名字在不同的rotor_pal.dll实例中互不冲突。详情下面会有一节专门讲述。
SetErrorMode(SEM_NOOPENFILEERRORBOX|SEM_FAILCRITICALERRORS);
RegisterWithEventLog(ModulePath);
if (!InitializeObjectNameMangler(ModulePath)) {
return RetVal;
}
|
5. 接下来,仅当在调试版本中,根据PAL_API_TRACING的值设置LogFileHandle打开对PAL API的跟踪输出。PAL_API_TRACING 可以是stdout, stderr, debugger或者指定文件名,PAL通过PalLogApi, PalLogApiCore, PalAssertFired函数来调用WriteFile(LogFileHandle)或OutputDebugString(当PAL_API_TRACING的值为debugger时)来输出TRACE的内容。
#if DBG
//
// Do one-time initialization of the API tracing mechanism
//
{
DWORD dw;
WCHAR buffer[_MAX_PATH];
dw = GetEnvironmentVariableW(L"PAL_API_TRACING",
buffer,
sizeof(buffer)/sizeof(WCHAR));
if (dw != 0 && dw < sizeof(buffer)/sizeof(WCHAR)) {
// Environment variable exists and fit in the buffer
if (wcscmp(buffer, L"stdout") == 0) {
LogFileHandle = GetStdHandle(STD_OUTPUT_HANDLE);
} else if (wcscmp(buffer, L"stderr") == 0) {
LogFileHandle = GetStdHandle(STD_ERROR_HANDLE);
} else if (wcscmp(buffer, L"debugger") == 0) {
LogFileHandle = 0;
} else {
LogFileHandle = CreateFileW(buffer,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
}
}
}
#endif //DBG
|
6. 之后,安装PAL自己的Exception Filter,这样PAL便可以接管对Unhandled Exceptions的处理,下篇文章会详细解释7. 获得当前线程一个TLS(Thread Local Storage)的Slot,被SEH用到,同样,下篇文章会详细讲到8. 检查PAL_TRY_LOCAL_SIZE,在下篇文章会解释9. 设置浮点运算的控制字(Control Word)
// Note: MSVCRT has already registered their exception filter at this point
// SEH_CurrentTopLevelFilter won't be NULL
SEH_CurrentTopLevelFilter = (PAL_LPTOP_LEVEL_EXCEPTION_FILTER)
SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)PAL_ExceptionFilter);
if ((SEH_Tls = TlsAlloc()) == TLS_OUT_OF_INDEXES) {
goto LExit;
}
PALASSERT(PAL_TRY_LOCAL_SIZE >= sizeof(jmp_buf));
// exceptions masked, round to nearest, 53 bit precision.
_controlfp(_MCW_EM | _RC_NEAR | _PC_53 | _IC_PROJECTIVE | _DN_SAVE,
_MCW_EM | _MCW_RC | _MCW_PC | _MCW_IC | _MCW_DN);
RetVal = 0;
LExit:
return RetVal;
}
|
1. 释放NameManager所占用的内存和资源2. 释放SEH Tls所占用的TLS 的Slot,恢复之前的Exception Filter3. 在调试版本中,关闭LogFileHandle
void
PALAPI
PAL_Shutdown(
void)
{
PAL_LPTOP_LEVEL_EXCEPTION_FILTER PreviousFilter;
if (hCryptProv != NULL) {
CryptReleaseContext(hCryptProv, 0);
hCryptProv = NULL;
}
free(NameManglerA);
NameManglerA = NULL;
free(NameManglerW);
NameManglerW = NULL;
if (SEH_Tls != TLS_OUT_OF_INDEXES) {
TlsFree(SEH_Tls);
}
// Reset the global exception filter
PreviousFilter = (PAL_LPTOP_LEVEL_EXCEPTION_FILTER)
SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)SEH_CurrentTopLevelFilter);
#if DBG
// Do this after the LOGAPI, so the output gets logged
if (LogFileHandle != INVALID_HANDLE_VALUE) {
//
// Refcount is zero and logging is enabled - close the
// file handle now in preparation for unload.
//
if (LogFileHandle) {
CloseHandle(LogFileHandle);
}
LogFileHandle = INVALID_HANDLE_VALUE;
}
#endif
}
|
// This is the main DLL entrypoint
BOOL
WINAPI
DllMain(
HANDLE hDllHandle,
DWORD dwReason,
LPVOID lpReserved)
{
if (dwReason == DLL_PROCESS_ATTACH) {
hInstPal = (HINSTANCE)hDllHandle;
DisableThreadLibraryCalls(hDllHandle);
}
return TRUE;
}
|
extern "C"
BOOL WINAPI DllMain( HINSTANCE hInst, DWORD dwReason, LPVOID pvReserved )
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
ROTOR_PAL_CTOR_TEST_RUN(ROTOR_PALRT);
// initialize PAL
if (PAL_Initialize(NULL, NULL) != 0)
return FALSE;
// initialize APP_DATA
if ((g_itlsAppData = TlsAlloc()) == ITLS_EMPTY) {
return FALSE;
}
InitNumInfo(TRUE);
break;
|
case DLL_PROCESS_DETACH:
ReleaseAppData();
InitNumInfo(FALSE);
if (g_itlsAppData != ITLS_EMPTY) {
TlsFree(g_itlsAppData);
}
PAL_Terminate();
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
ReleaseAppData();
break;
}
return TRUE;
}
|
int __cdecl main(int argc, char **argv) {
struct _mainargs mainargs;
#ifdef _MSC_VER
if (PAL_Initialize(0, NULL)) {
return 1;
}
#else
if (PAL_Initialize(argc, argv)) {
return 1;
}
#endif
// PAL_Terminate is a stdcall function, but it takes no parameters
// so the difference doesn't matter.
atexit((void (__cdecl *)(void)) PAL_Terminate);
mainargs.argc = argc;
mainargs.argv = argv;
exit((int)PAL_EntryPoint((PTHREAD_START_ROUTINE)run_main, &mainargs));
return 0; // Quiet a compiler warning
}
|
1.初始化PAL2.调用atexit注册退出函数PAL_Terminate,这样PAL_Terminate便会在程序正常结束的时候被调用。注意虽然PAL_Terminate和atexit所要求的函数调用协定不同,PAL_Terminate是__stdcall而atexit参数要求__cdecl,由于PAL_Terminate是无参数的,__stdcall/__pascal在无参数的时候是没有区别的,因此可以直接强制转换成__cdecl3.调用PAL_EntryPoint入口函数,此函数调用run_main,并最后调用PAL_startup_main函数。如上所述,PAL_startup_main才是clix中的main4.退出时候,自动调用PAL_Terminate
作者: ATField
E-Mail: [email protected]
Blog: http://blog.csdn.net/atfield