乐筑天下

搜索
欢迎各位开发者和用户入驻本平台 尊重版权,从我做起,拒绝盗版,拒绝倒卖 签到、发布资源、邀请好友注册,可以获得银币 请注意保管好自己的密码,避免账户资金被盗
查看: 55|回复: 4

“可写”;只读系统变量”;

[复制链接]

27

主题

193

帖子

5

银币

后起之秀

Rank: 20Rank: 20Rank: 20Rank: 20

铜币
300
发表于 2009-8-25 02:16:16 | 显示全部楼层 |阅读模式
下面概述了一种对只读系统变量进行读/写访问的方法,特别是系统变量TDCREATE、TDUCREATE、TDUPATE、TDUUPDATE、TDUSRTIMER和TDINDWG将是可修改的,此外,目标平台是AutoCAD 2004,其他版本可能会工作,但计划对代码进行一点调整,因为不同版本的函数名称可能不同。让我也强调一下,您可能不希望下面的代码用于您控制范围之外的程序,除非您计划测试和支持AutoCAD的每一种风格和垂直。 为了避免被细节埋没,我必须假设目标受众了解C++调用约定、C++名称混淆以及如何消除它们(至少了解使用Dependency Walker的水平)。如果您计划进一步开发这个项目,理解VTables也会有所帮助,但对于本文来说不是必需的。很好,我觉得这篇文章缩短了3页。 对于那些饥肠辘辘的人来说,这是最后一段代码。
  1.         // Define callbacks for functions
  2.         typedef AcDbDate (CALLBACK* TDDINDWG)(void);
  3.         typedef Acad::ErrorStatus (CALLBACK* SET_TDD_INDWG) (AcDbDate const &);
  4.         typedef Acad::ErrorStatus (CALLBACK* SET_TDD_USR_TIMER) (AcDbDate const &);
  5.         typedef Acad::ErrorStatus (CALLBACK* SET_TDL_CREATE) (AcDbDate const &);
  6.         typedef Acad::ErrorStatus (CALLBACK* SET_TDL_UPDATE) (AcDbDate const &);
  7.         typedef Acad::ErrorStatus (CALLBACK* SET_TDU_CREATE) (AcDbDate const &);
  8.         typedef Acad::ErrorStatus (CALLBACK* SET_TDU_UPDATE) (AcDbDate const &);
  9.         typedef void * (CALLBACK* SLOW_DB_HEADER) (void);
  10.         void SetDwgDate(void)
  11.         {
  12.                 HMODULE hMod = GetModuleHandle("acdb16.dll");
  13.                 SET_TDD_INDWG setTddInDwg = (SET_TDD_INDWG) GetProcAddress(hMod, "?setTddInDwg@AcDbHeader@@QAE?AW4ErrorStatus@Acad@@ABVAcDbDate@@@Z");
  14.                 SET_TDD_USR_TIMER setTddUsrTimer = (SET_TDD_USR_TIMER) GetProcAddress(hMod, "?setTddUsrTimer@AcDbHeader@@QAE?AW4ErrorStatus@Acad@@ABVAcDbDate@@@Z");
  15.                 SET_TDL_CREATE setTdlCreate = (SET_TDL_CREATE) GetProcAddress(hMod, "?setTdlCreate@AcDbHeader@@QAE?AW4ErrorStatus@Acad@@ABVAcDbDate@@@Z");
  16.                 SET_TDL_UPDATE setTdlUpdate = (SET_TDL_UPDATE) GetProcAddress(hMod, "?setTdlUpdate@AcDbHeader@@QAE?AW4ErrorStatus@Acad@@ABVAcDbDate@@@Z");
  17.                 SET_TDU_CREATE setTduCreate = (SET_TDU_CREATE) GetProcAddress(hMod, "?setTduCreate@AcDbHeader@@QAE?AW4ErrorStatus@Acad@@ABVAcDbDate@@@Z");
  18.                 SET_TDU_UPDATE setTduUpdate = (SET_TDU_UPDATE) GetProcAddress(hMod, "?setTduUpdate@AcDbHeader@@QAE?AW4ErrorStatus@Acad@@ABVAcDbDate@@@Z");
  19.                
  20.                 SLOW_DB_HEADER slowDbHeader = (SLOW_DB_HEADER) GetProcAddress(hMod, "?slowDbHeader@AcDbStub@@ABEPAVAcDbHeader@@XZ");
  21.                 SLOW_DB_HEADER * pSlowDbHeader = NULL;
  22.                 Acad::ErrorStatus es;
  23.                 AcDbDate dbDate;
  24.                 // set _thiscall to 0
  25.                 _asm mov ecx, 0
  26.                 _asm call slowDbHeader
  27.                 // store the returned instance of AcDbHeader
  28.                 _asm mov pSlowDbHeader, eax
  29.                
  30.                 // set _thiscall to the instance of AcDbHeaer and call
  31.                 // setTdlCreate like any other function.
  32.                 _asm mov ecx, pSlowDbHeader
  33.                 es = setTdlCreate(dbDate);
  34.                 _asm mov ecx, pSlowDbHeader
  35.                         es = setTduCreate(dbDate);
  36.                 _asm mov ecx, pSlowDbHeader
  37.                         es = setTdlUpdate(dbDate);
  38.                 _asm mov ecx, pSlowDbHeader
  39.                         es = setTduUpdate(dbDate);
  40.                 _asm mov ecx, pSlowDbHeader
  41.                         es = setTddInDwg(dbDate);
  42.                 _asm mov ecx, pSlowDbHeader
  43.                         es = setTddUsrTimer(dbDate);
  44.         }
特别感兴趣的是我们通过C++乱码名称检索的函数指针,下面是解开的函数签名。函数指针本身是无用的,因为它们是AcDbHeader的成员,AcDbHeader也没有文档记录,我们需要acdb header的一个实例。函数
  1. class AcDbHeader * AcDbStub::slowDbHeader(void)
用于获取指向AcDbHeader的实例指针,剩下的代码只是设置一些寄存器并调用AcDbHeader成员函数。AcDbHeader、AcDbStub和_thiscall要了解如何将所有这些整合在一起,我们需要了解一些细节。一、AcDbHeader是如何实现的?我们可以做几个猜测,要么AcDbDatabase派生自AcDbHeader,要么AcDbHeader是AcDbDatabase的成员。下面的陈述很容易回答这个问题:1,AcDbDatabase是AcDbHeader(不太可能)= FALSE。
2.AcDbDatabase有一个AcDbHeader -(这更有意义,但事实证明不是这样)尽管第2项有意义,但我们在AcDbDatabase中找不到AcDbHeader的任何getter/setter。相反,我们找到的唯一getter是slowDbHeader(void),它是AcDbStub的成员函数。ARX文档在AcDbObjectId描述中这样描述AcDbStub:这实际上是说AcDbStub是AcDbObjectId的组合,更具体地说,AcDbObjectId强烈拥有AcDbStub。查看AcDbObjectId的类定义的ARX头文件dbid.h,您会看到其中的关系。有了这些信息,我们似乎可以通过解引用AcDbObjectId并调用slowDbHeader()来获得指向AcDbHeader的指针。其代码为:
  1. void * pStub = (void *&) * acdbHostApplicationServices()->workingDatabase()->textStyleTableId();
  2. _asm mov ecx, pStub
  3. _asm call slowDbHeader
  4. _asm mov pAcDbHeader, eax
但是它导致了一个异常,我没有调查原因,因为对slowDbHeader的快速反汇编显示它将0作为thiscall指针(寄存器ecx)异常。设置slowDbHeader调用就这样完成了,
  1. _asm mov ecx, 0
  2. _asm call slowDbHeader
  3. _asm mov pAcDbHeader, eax
并且pAcDbHeader现在指向AcDbHeader的有效实例。现在很容易进行AcDbHeader::setTd*调用,只需确保ecx寄存器包含pAcDbHeader的实例指针。摘要现在,您有了一种更改以前只读的绘制时间属性的方法。在32位系统上,调用约定是_thiscall,它就像_stdcall一样,只是ecx寄存器保存类的实例指针。在64位Windows上,调用约定是_fastcall,需要修改代码来处理它。只要堆栈和寄存器设置正确,任何AcDbHeader函数都可以被调用。即使这里只使用了很少的函数,您也可以看到代码很快就变成了维护的噩梦,并且容易出错。在下一篇文章中,我将以一种更加可移植和类型安全的方式包装我们使用的AcDbHeader函数。保罗。

本帖以下内容被隐藏保护;需要你回复后,才能看到!

游客,如果您要查看本帖隐藏内容请回复
回复

使用道具 举报

27

主题

193

帖子

5

银币

后起之秀

Rank: 20Rank: 20Rank: 20Rank: 20

铜币
300
发表于 2009-8-25 02:27:55 | 显示全部楼层

我仍在吸收这一点,但请注意,x64不支持内联asm,我认为需要使用Intrinsic
回复

使用道具 举报

27

主题

193

帖子

5

银币

后起之秀

Rank: 20Rank: 20Rank: 20Rank: 20

铜币
300
发表于 2009-8-25 03:05:35 | 显示全部楼层

谢谢,
我将在几周内无法测试2010 64位版本。不过,我可以在直接的windows exe上测试内联asm。
回复

使用道具 举报

27

主题

193

帖子

5

银币

后起之秀

Rank: 20Rank: 20Rank: 20Rank: 20

铜币
300
发表于 2009-8-25 03:23:21 | 显示全部楼层
我想知道从哪里调用它们会有多难。网?
回复

使用道具 举报

27

主题

193

帖子

5

银币

后起之秀

Rank: 20Rank: 20Rank: 20Rank: 20

铜币
300
发表于 2009-8-25 03:34:36 | 显示全部楼层
第2部分将原始代码
包装到类型安全模板函数中。
回复

使用道具 举报

发表回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

  • 微信公众平台

  • 扫描访问手机版

  • 点击图片下载手机App

QQ|关于我们|小黑屋|乐筑天下 繁体中文

GMT+8, 2025-2-6 00:55 , Processed in 0.194694 second(s), 62 queries .

© 2020-2025 乐筑天下

联系客服 关注微信 帮助中心 下载APP 返回顶部 返回列表