“可写”;只读系统变量”;
下面概述了一种对只读系统变量进行读/写访问的方法,特别是系统变量TDCREATE、TDUCREATE、TDUPATE、TDUUPDATE、TDUSRTIMER和TDINDWG将是可修改的,此外,目标平台是AutoCAD 2004,其他版本可能会工作,但计划对代码进行一点调整,因为不同版本的函数名称可能不同。让我也强调一下,您可能不希望下面的代码用于您控制范围之外的程序,除非您计划测试和支持AutoCAD的每一种风格和垂直。 为了避免被细节埋没,我必须假设目标受众了解C++调用约定、C++名称混淆以及如何消除它们(至少了解使用Dependency Walker的水平)。如果您计划进一步开发这个项目,理解VTables也会有所帮助,但对于本文来说不是必需的。很好,我觉得这篇文章缩短了3页。 对于那些饥肠辘辘的人来说,这是最后一段代码。 // Define callbacks for functionstypedef AcDbDate (CALLBACK* TDDINDWG)(void);
typedef Acad::ErrorStatus (CALLBACK* SET_TDD_INDWG) (AcDbDate const &);
typedef Acad::ErrorStatus (CALLBACK* SET_TDD_USR_TIMER) (AcDbDate const &);
typedef Acad::ErrorStatus (CALLBACK* SET_TDL_CREATE) (AcDbDate const &);
typedef Acad::ErrorStatus (CALLBACK* SET_TDL_UPDATE) (AcDbDate const &);
typedef Acad::ErrorStatus (CALLBACK* SET_TDU_CREATE) (AcDbDate const &);
typedef Acad::ErrorStatus (CALLBACK* SET_TDU_UPDATE) (AcDbDate const &);
typedef void * (CALLBACK* SLOW_DB_HEADER) (void);
void SetDwgDate(void)
{
HMODULE hMod = GetModuleHandle("acdb16.dll");
SET_TDD_INDWG setTddInDwg = (SET_TDD_INDWG) GetProcAddress(hMod, "?setTddInDwg@AcDbHeader@@QAE?AW4ErrorStatus@Acad@@ABVAcDbDate@@@Z");
SET_TDD_USR_TIMER setTddUsrTimer = (SET_TDD_USR_TIMER) GetProcAddress(hMod, "?setTddUsrTimer@AcDbHeader@@QAE?AW4ErrorStatus@Acad@@ABVAcDbDate@@@Z");
SET_TDL_CREATE setTdlCreate = (SET_TDL_CREATE) GetProcAddress(hMod, "?setTdlCreate@AcDbHeader@@QAE?AW4ErrorStatus@Acad@@ABVAcDbDate@@@Z");
SET_TDL_UPDATE setTdlUpdate = (SET_TDL_UPDATE) GetProcAddress(hMod, "?setTdlUpdate@AcDbHeader@@QAE?AW4ErrorStatus@Acad@@ABVAcDbDate@@@Z");
SET_TDU_CREATE setTduCreate = (SET_TDU_CREATE) GetProcAddress(hMod, "?setTduCreate@AcDbHeader@@QAE?AW4ErrorStatus@Acad@@ABVAcDbDate@@@Z");
SET_TDU_UPDATE setTduUpdate = (SET_TDU_UPDATE) GetProcAddress(hMod, "?setTduUpdate@AcDbHeader@@QAE?AW4ErrorStatus@Acad@@ABVAcDbDate@@@Z");
SLOW_DB_HEADER slowDbHeader = (SLOW_DB_HEADER) GetProcAddress(hMod, "?slowDbHeader@AcDbStub@@ABEPAVAcDbHeader@@XZ");
SLOW_DB_HEADER * pSlowDbHeader = NULL;
Acad::ErrorStatus es;
AcDbDate dbDate;
// set _thiscall to 0
_asm mov ecx, 0
_asm call slowDbHeader
// store the returned instance of AcDbHeader
_asm mov pSlowDbHeader, eax
// set _thiscall to the instance of AcDbHeaer and call
// setTdlCreate like any other function.
_asm mov ecx, pSlowDbHeader
es = setTdlCreate(dbDate);
_asm mov ecx, pSlowDbHeader
es = setTduCreate(dbDate);
_asm mov ecx, pSlowDbHeader
es = setTdlUpdate(dbDate);
_asm mov ecx, pSlowDbHeader
es = setTduUpdate(dbDate);
_asm mov ecx, pSlowDbHeader
es = setTddInDwg(dbDate);
_asm mov ecx, pSlowDbHeader
es = setTddUsrTimer(dbDate);
}
特别感兴趣的是我们通过C++乱码名称检索的函数指针,下面是解开的函数签名。函数指针本身是无用的,因为它们是AcDbHeader的成员,AcDbHeader也没有文档记录,我们需要acdb header的一个实例。函数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的指针。其代码为:void * pStub = (void *&) * acdbHostApplicationServices()->workingDatabase()->textStyleTableId();
_asm mov ecx, pStub
_asm call slowDbHeader
_asm mov pAcDbHeader, eax
但是它导致了一个异常,我没有调查原因,因为对slowDbHeader的快速反汇编显示它将0作为thiscall指针(寄存器ecx)异常。设置slowDbHeader调用就这样完成了,_asm mov ecx, 0
_asm call slowDbHeader
_asm mov pAcDbHeader, eax
并且pAcDbHeader现在指向AcDbHeader的有效实例。现在很容易进行AcDbHeader::setTd*调用,只需确保ecx寄存器包含pAcDbHeader的实例指针。摘要现在,您有了一种更改以前只读的绘制时间属性的方法。在32位系统上,调用约定是_thiscall,它就像_stdcall一样,只是ecx寄存器保存类的实例指针。在64位Windows上,调用约定是_fastcall,需要修改代码来处理它。只要堆栈和寄存器设置正确,任何AcDbHeader函数都可以被调用。即使这里只使用了很少的函数,您也可以看到代码很快就变成了维护的噩梦,并且容易出错。在下一篇文章中,我将以一种更加可移植和类型安全的方式包装我们使用的AcDbHeader函数。保罗。
**** Hidden Message *****
我仍在吸收这一点,但请注意,x64不支持内联asm,我认为需要使用Intrinsic
谢谢,
我将在几周内无法测试2010 64位版本。不过,我可以在直接的windows exe上测试内联asm。
我想知道从哪里调用它们会有多难。网? 第2部分将原始代码
包装到类型安全模板函数中。
页:
[1]