翻译《The Old New Thing》- What did MakeProcInstance do?

What did MakeProcInstance do? - The Old New Thing (microsoft.com)icon-default.png?t=N7T8https://devblogs.microsoft.com/oldnewthing/20080207-00/?p=23533

Raymond Chen 2008年02月07日


 MakeProcInstance 做了什么?

      MakeProcInstance 宏实际上什么也不做。

#define MakeProcInstance(lpProc,hInstance) (lpProc)

        一个什么也不做的宏有什么意义呢?

        在16位Windows系统中,MakeProcInstance 是有作用的。

        回想一下,在16位Windows系统中,HINSTANCE 是用来标识数据段的机制;也就是说,是代表模块使用中的变量集合的一块内存。如果你运行了两个记事本的副本,代码只有一个副本,但变量有两套(每份副本一套)。正是这第二套变量建立了记事本的第二个副本。

        当你设置一个回调函数,比如窗口过程时,回调函数需要知道它被调用是为了哪一套变量。例如,如果一个记事本副本调用 EnumFonts 并传递一个回调函数,这个函数需要知道它正在哪个记事本副本中运行,以便它可以访问正确的变量集合。这就是 MakeProcInstance 函数的作用。

  MakeProcInstance 的参数是一个函数指针和一个实例句柄。MakeProcInstance 函数会即时生成代码,将数据段寄存器设置为实例句柄,然后跳转到原始函数指针。MakeProcInstance 的返回值是指向那个动态生成的代码片段(称为 thunk)的指针,并且你在使用该代码片段作为函数指针时,需要其他函数回调你。这样,当你的函数被调用时,它的变量就会正确设置。

        当你不再需要代码片段时,你可以使用 FreeProcInstance 函数释放它。

        那些使用过ATL的人已经在 CStdCallThunk 类中看到过这种代码片段生成。操作与 MakeProcInstance 完全类似。你使用函数指针和 this 参数初始化 CStdCallThunk,它即时生成代码,通过在调用你初始化thunk时使用的函数之前设置 this 指针,将静态函数转换为 C++ 成员函数。

        在16位Windows上创建这些代码片段必须由内核完成,因为8086处理器没有内存管理单元。没有通过转换表的间接寻址;所有地址都是物理的。因此,如果内存管理器需要移动内存,它还必须知道所有移动内存的引用位置,以便可以更新指针。如果数据段移动了,内核必须去修复所有的 MakeProcInstance thunks,以便它们使用新的实例句柄而不是旧的。

        是 Michael Geary 发现所有这些 MakeProcInstance 工作是不必要的。如果回调函数位于DLL中,那么函数可以硬编码其实例句柄,并在函数开始时加载它;这种技术最终被称为 loadds。由于DLL是单实例的,DLL已经知道它应该使用哪一套变量,因为从一开始就只有一套DLL变量!

当然,硬编码的值必须作为修正记录,因为实例句柄是在运行时确定的。另外,内核需要知道如果实例句柄的值改变,需要更新哪些值。

        另一方面,如果回调函数位于可执行文件中,那么它可以从堆栈选择器中获取其实例句柄;这种技术最终被称为 export。每个程序在一个堆栈上运行(这里没有多线程),堆栈、数据段和本地堆都按照惯例位于同一个选择器中。

        在我写这篇回忆录时,我发现了一个奇怪的回环,Michael Geary 的 FixDS 程序的原始自述文件中,有一段介绍与我有关,链接回我本人…

  • 29
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

0x0007

可不可奖励我吃只毛嘴鸡 馋😋

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值