在上一篇文章,讲到了双击一个应用程序之后,操作系统如何初始化Process,以及创建相关的context,最后引导到应用程序的Main方法中。

在托管代码中,对于Main的启动还有点不同,有一个PAL层在启动main方法之前启动:

#ifdef __cplusplus

extern "C"

#endif

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

可以参考上篇文章里面的call stack,找到对main(int argc, char **argv)方法的调用。_MSC_VER是预编译控制,标识microsoft的C编译器的版本。

DotNet中,对于PAL层的initialization和terminal,是通过PAL_Initialize/PAL_Terminate两个方法来完成的,打开d:/Rotor/sscli20/pal/win32/win32pal.c就可以看到:

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);//Responsible for Start.

}

return RetVal;

}

PALIMPORT void PALAPI PAL_Terminate(void)

{

LONG RefCount;

LOGAPI("PAL_Terminate()/n");

RefCount = InterlockedDecrement(&PalReferenceCount);

//

// if this hits, the host has a refcounting bug - the

// count has underflowed.  This is not a PAL bug.

//

PALASSERT(RefCount >= 0);

if (RefCount == 0) {

PAL_Shutdown();//Responsible for terminate

}

}

这里可以看出,PAL_Initialize和PAL_Terminate只是负责PAL Startup和shotdown的一个转换的函数,在PAL_Initializae中,维护一个LONG PalReferenceCount;这个变量主要是为了避免对PAL初始化或者shutdown的重复调用,使用c:/Program Files/Microsoft SDKs/Windows/v6.0A/Include/WinBase.h中的两个函数来维护这个PalReferenceCount:

WINBASEAPI

LONG

WINAPI

InterlockedIncrement (

__inout LONG volatile *lpAddend

);

WINBASEAPI

LONG

WINAPI

InterlockedDecrement (

__inout LONG volatile *lpAddend

);

然后通过执行RetVal = PAL_Startup(argc, argv)来启动PAL:

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;

}

SetErrorMode(SEM_NOOPENFILEERRORBOX|SEM_FAILCRITICALERRORS);

这里,首先加载rotor_pal.dll,然后获取这个DLL文件的ModulePath。同时设置错误模式。

RegisterWithEventLog(ModulePath);

if (!InitializeObjectNameMangler(ModulePath)) {

return RetVal;

}

// 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;

}

RegisterWithEventLog(ModulePath);

记录EventLog的source,被忽略掉的错误信息,以防这个程序是non-admin权限的。如果没有注册成功的话,这个信息同样会被保留,但是在Event Viewer里面,就会以“The description for Event ID ( 0 ) in Source ( Rotor ) cannot be found.”开头。记录到:

SYSTEM//CurrentControlSet//Services//EventLog//Application//Rotor

InitializeObjectNameMangler(ModulePath)所做的工作,就是初始化一个Object Name的Mangler,使用了OS提供的SHA1加密算法,来得到一个hash过后的字符串。这就会使用在不同的Rotor实例中,rotor_pal.dll不会冲突。

接下来,在调试版本中,会初始化API tracing机制,首先获取到PAL_API_TRACING的值,然后设置对不同的API的tracing。

SEH_CurrentTopLevelFilter = (PAL_LPTOP_LEVEL_EXCEPTION_FILTER) SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)PAL_ExceptionFilter);

这里,注册安装PAL自己的TOP exception handle。因为这个地方MSVCRT已经注册了一个Exception handle,所以这个地方的SEH_CurrentTopLevelFilter不会为空。这样注册之后,就可以由PAL自己来处理Unhandled Exception。

这里也是调用了OS的Base API:

WINBASEAPI

LPTOP_LEVEL_EXCEPTION_FILTER

WINAPI

SetUnhandledExceptionFilter(

__in LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter

);

if ((SEH_Tls = TlsAlloc()) == TLS_OUT_OF_INDEXES) {

goto LExit;

}

获取当前线程的一个TLS的SLOT,暂时不清楚哪里会用到。

PALASSERT(PAL_TRY_LOCAL_SIZE >= sizeof(jmp_buf));

保证PAL_TRY_LOCAL_SIZE会大于一个获取程序状态的缓冲区。

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

设置浮点数的控制字,读写浮点控制或者状态字时候用的,managed code不支持,所以这里需要手工设置。

OK,到这里PAL启动完毕,下面一章看看如何启动EE并且launch应用程序的Main函数的。

Tuesday, December 09, 2008

lbq1221119@bj first post at sscli.cnblogs.com

From double Click to Main: PAL initialization相关推荐

  1. ALV GRID学习笔记----Double Click事件

    10月底的时候进行了BC412课程的培训,课后自己做了一些实验,从今天开始就将这些实验记录下来,以便于以后需要使用的时候能够查询一下!(很遗憾的是公司组织了很多的培训,但是在实际工作中很少能够运到,所 ...

  2. 取消pycharm双击shift出现搜索框,但新版找不到ide.suppress.double.click.handler的问题解决

    取消pycharm/IDEA双击shift出现搜索框,但新版找不到ide.suppress.double.click.handler的问题解决 在使用Jetbrains产品时,例如IDEA.Pycha ...

  3. 24. Vue防抖,禁止double click

    Vue 防抖 如果按钮不做防抖限制,用户手滑或者其他场景大概率会出现重复调用接口的情况,比如编辑角色时,多次点击submit,会出现非预期请求. 为避免重复点击问题,可以加一个自定义组件将按钮禁用一段 ...

  4. CL_ABAP_COMPILER - get ID - double click on local variable

    要获取更多Jerry的原创文章,请关注公众号"汪子熙":

  5. double click items in SBWP

    Created by Wang, Jerry, last modified on Apr 01, 2017

  6. BSP UI Workbench double click component and see view list

  7. 陈年佳酿之 - Winform ListView 控件 double click 事件中获取选中的row与column

    背景 最近收到了一个关于以前项目的维护请求,那时的楼主还是刚刚工作的小青年~~~ 项目之前使用的是.net/winform.今天重新打开代码,看着之前在FrameWork2.0下面的代码, 满满的回忆 ...

  8. C++类型转换实现不同类型相加【复数与double类型相加】

    文章目录 一.现double数据与Complex类型相加,得出double 二.复数与double相加,得出复数 一.现double数据与Complex类型相加,得出double #include & ...

  9. CodeForces - 93B(贪心+vectorpairint,double +double 的精度操作

    题目链接:http://codeforces.com/problemset/problem/93/B B. End of Exams time limit per test 1 second memo ...

  10. click是哪个键 wheel_Click是什么意思?键盘上的Click键在哪里?

    Click是什么意思?还有它的读音.?? 答:click在电脑中通常译为:点击. 也就是点击进入黄金屋 Clickwraps? 答:"点击生效"的意思范例:生效的许可协议 Clic ...

最新文章

  1. java 流的方式抓取网页 但是显示不全_用java抓取网页源代码时总是无法获取完整的源代码信息,求指导...
  2. 实现正则表达式的*和?匹配
  3. html5行级标签,8、html5哪些标签时块级、行内、行内块?2021-01-30
  4. 幅度为a0的载波由峰峰值_十个医疗箱都不够用?戒掉这些坏习惯,满活跃值闯进决赛圈不是梦!...
  5. 如何更改Joomla中的默认语言
  6. linq to xml 操作sitemap
  7. [html] 如何禁止手机端页面缩放?
  8. Win7系统桌面右下角托盘图标不显示原因和解决方法
  9. java面向服务架构_面向服务的体系架构 SOA(一) --- 基于TCP、HTTP协议的RPC
  10. 计算机组成原理 第五章 中央处理器
  11. php表单美化,使用css美化html表单控件详细示例(表单美化)_HTML/Xhtml_网页制作
  12. 怎样制作文章视频gif插图?视频gif格式图片如何在线制作?
  13. 使用Jena-TDB存储RDF本体、知识图谱文件
  14. *p++、*(p++)、(*p)++、*++p、++*p的区别
  15. 南华大学计算机学院软件工程双一流,南华大学计算机学院软件工程与网络工程两个专业喜获湖南省高校专业综合评价A级...
  16. SQL函数lpad()以及rpad()的用法
  17. 配置 Rails 应用程序
  18. C++ 时间计算器 之 超级无敌小白版 刚入门的快点看过来!
  19. R 语言求 复合函数的极值
  20. 27_linux笔记-sed

热门文章

  1. 基于STM32C8T6的MLX90614-DCC红外无线测温系统
  2. 解决Java应用的后台错误:“操作符不存在: character varying = bytea“
  3. 如何解决DNS解析错误故障
  4. 计算机语言描述正确,关于计算机语言的描述,正确的是( )
  5. html 怎么设置hr的颜色,html hr标签能设置黄颜色吗
  6. 幼儿园计算机网络教室工作计划,幼儿园2017-2018学年游戏教学工作计划
  7. Codeforces 1485D - Multiples and Power Differences (构造)
  8. MySQL 8.0+版本 导入.csv文件错误,出错号:1148 The used command is not allowed with this MySQL version问题
  9. SWUST OJ 480: Locker doors
  10. java实现deflate数据压缩和gzip数据压缩