|
好吧,前面关于可写的“只读系统变量”的主题的代码有点原始,并且是
维护的噩梦。 在这里,我打包了代码,使其更易于移植,并且不
易出现错误。 概述的方法不使用类,因为这只是导致我符合
THISCALL调用约定,将“MyAcDbHeader”的“this”指针自动填充到
ecx寄存器上。
该代码的目标是以类型安全和
半可移植的方式使AcDbHeader的调用成员函数。 大多数代码是针对编译器的,允许它在
编译时捕获语法错误和类型不匹配。 模板函数完成了大部分实际
工作,编译器为发布版本很好地优化了这些工作。
我再次首先介绍完整的代码:
- // MyAcDbHeader.h
- #pragma once
- #if defined(_M_IX86)
- // code is stricly for 32bit x86
- namespace MyAcDbHeader {
- // AutoCAD AcDbHeader typedefs. Get these from the undecorated names
- 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);
- //// defined to test different template definitions
- //typedef double (CALLBACK* DIM_SCALE) (void);
- //typedef Acad::ErrorStatus (CALLBACK* GET_DIMSTYLE_CHILE_DATA) (AcRxClass const *, AcDbDimStyleTableRecord * &, AcDbObjectId &);
- // pointers to AutoCAD AcDbHeader function pointers.
- // Before using these function they first need to be initialized by calling
- // InitAcDbHeader, otherwise they are set to NULL and will GPF.
- extern SET_TDD_INDWG setTddInDwg;
- extern SET_TDD_USR_TIMER setTddUsrTimer;
- extern SET_TDL_CREATE setTdlCreate;
- extern SET_TDL_UPDATE setTdlUpdate;
- extern SET_TDU_CREATE setTduCreate;
- extern SET_TDU_UPDATE setTduUpdate;
- extern SLOW_DB_HEADER slowDbHeader;
- extern SLOW_DB_HEADER * pAcDbHeader;
- //// declared to test different template definitions
- //extern DIM_SCALE dimScale;
- //extern GET_DIMSTYLE_CHILE_DATA getDimStyleChildData;
- // InitAcDbHeader, must be called prior to using any other function pointers.
- // Makes call to SetAcDbHeaderInstance before returning.
- void InitAcDbHeader(AcDbObjectId stubId = AcDbObjectId::kNull);
-
- // SetAcDbHeaderInstanceFrom retieves the AcDbHeader from AutoCAD by
- // dereferencing stubId to _thiscall (ecx) prior to calling slowDbHeader.
- // If stubId == AcDbObjectId::kNull then _thiscall (ecx) is set to 0 prior
- // to calling slowDbHeader.
- void SetAcDbHeaderInstanceFrom(AcDbObjectId stubId);
- // set 1 byte alignment
- #pragma pack(push, 1)
- // define typesafe template for AcDbHeader functions that have
- // no parameters.
- // T is the return type
- // T1 is the type of the callee
- template
- T func(T1 callee)
- {
- _asm mov ecx, pAcDbHeader
- T rVal = callee();
- return rVal;
- }
- // define typesafe template for AcDbHeader functions that have
- // 1 parameter.
- // T is the return type
- // T1 is the type of the callee
- // T2 is the type for parameter 1
- template
- T func(T1 callee, T2 const & inObj)
- {
- _asm mov ecx, pAcDbHeader
- T rVal = callee(inObj);
- return rVal;
- }
- // define typesafe template for AcDbHeader functions that have
- // 3 parameters.
- // T is the return type
- // T1 is the type of the callee
- // T2 is the type for parameter 1, T3 for parameter 2, T4 for parameter 3
- template
- T func(T1 callee, T2 const * inPtr, T3 *& refPtr, T4 & outObj)
- {
- _asm mov ecx, pAcDbHeader
- T rVal = callee(inPtr, refPtr, outObj);
- return rVal;
- }
- #pragma pack(pop)
- }
- #endif
- // MyAcDbHeader.cpp
- #include
- #include "MyAcDbHeader.h"
- namespace MyAcDbHeader {
- #if defined(_M_IX86)
- // code is stricly for 32bit x86
- // Define acad family from 2004 to 2006. They should all have
- // the same mangled AcDbHeader function names, but needs to be
- // varified and coded accordingly.
- // Calling convention is THISCALL, so register ECX needs to be
- // set properly prior to making function calls.
- #if defined(ARX2004)
- #define ACAD2004_FAMILY 1
- #elif defined(ARX2005)
- #define ACAD2004_FAMILY 1
- #elif defined(ARX2006)
- #define ACAD2004_FAMILY 1
- #endif
- // 2007 through 2009 should also have the same mangled AcDbHeader function names
- // Place family check code here, and Place mangled names in InitAcDbHeader.
- // 2010 32 bit, same as 2007 family.
- // 2010 64 bit, calling convention is FASTCALL, Guessing the _thiscall will need to be placed
- // in RCX, but haven't really looked into it
- // Declare instances of AcDbHeader functions.
- SET_TDD_INDWG setTddInDwg = NULL;
- SET_TDD_USR_TIMER setTddUsrTimer = NULL;
- SET_TDL_CREATE setTdlCreate = NULL;
- SET_TDL_UPDATE setTdlUpdate = NULL;
- SET_TDU_CREATE setTduCreate = NULL;
- SET_TDU_UPDATE setTduUpdate = NULL;
- SLOW_DB_HEADER slowDbHeader = NULL;
- SLOW_DB_HEADER * pAcDbHeader = NULL;
- //// declared to test different template definitions
- //DIM_SCALE dimScale = NULL;
- //GET_DIMSTYLE_CHILE_DATA getDimStyleChildData = NULL;
- void InitAcDbHeader(AcDbObjectId stubId) {
- HMODULE hMod = GetModuleHandle("acdb16.dll");
- #ifdef ACAD2004_FAMILY
- // Get addresses of AcDbHeader functions, using mangled string names.
- setTddInDwg = (SET_TDD_INDWG) GetProcAddress(hMod, "?setTddInDwg@AcDbHeader@@QAE?AW4ErrorStatus@Acad@@ABVAcDbDate@@@Z");
- setTddUsrTimer = (SET_TDD_USR_TIMER) GetProcAddress(hMod, "?setTddUsrTimer@AcDbHeader@@QAE?AW4ErrorStatus@Acad@@ABVAcDbDate@@@Z");
- setTdlCreate = (SET_TDL_CREATE) GetProcAddress(hMod, "?setTdlCreate@AcDbHeader@@QAE?AW4ErrorStatus@Acad@@ABVAcDbDate@@@Z");
- setTdlUpdate = (SET_TDL_UPDATE) GetProcAddress(hMod, "?setTdlUpdate@AcDbHeader@@QAE?AW4ErrorStatus@Acad@@ABVAcDbDate@@@Z");
- setTduCreate = (SET_TDU_CREATE) GetProcAddress(hMod, "?setTduCreate@AcDbHeader@@QAE?AW4ErrorStatus@Acad@@ABVAcDbDate@@@Z");
- setTduUpdate = (SET_TDU_UPDATE) GetProcAddress(hMod, "?setTduUpdate@AcDbHeader@@QAE?AW4ErrorStatus@Acad@@ABVAcDbDate@@@Z");
- slowDbHeader = (SLOW_DB_HEADER) GetProcAddress(hMod, "?slowDbHeader@AcDbStub@@ABEPAVAcDbHeader@@XZ");
- //// a couple extra's to test different template definitions
- //dimScale = (DIM_SCALE) GetProcAddress(hMod, "?dimscale@AcDbHeader@@QBENXZ");
- //getDimStyleChildData = (GET_DIMSTYLE_CHILE_DATA) GetProcAddress(hMod, "?getDimstyleChildData@AcDbHeader@@QBE?AW4ErrorStatus@Acad@@PBVAcRxClass@@AAPAVAcDbDimStyleTableRecord@@AAVAcDbObjectId@@@Z");
- #endif
- SetAcDbHeaderInstanceFrom(stubId);
- }
- void SetAcDbHeaderInstanceFrom(AcDbObjectId stubId)
- {
- void * pStub = stubId.isValid() ? (void *&) *stubId : NULL;
- _asm mov ecx, pStub
- _asm call slowDbHeader
- _asm mov pAcDbHeader, eax
- }
- #endif
- }
- // acrxEntryPoint.cpp
- ...
- ...
- #include "MyAcDbHeader.h"
- ...
- ...
- // - navSetDwgDate.setDwgDate command (do not rename)
- static void navSetDwgDatesetDwgDate(void)
- {
- using namespace MyAcDbHeader;
- InitAcDbHeader();
- AcDbDate dt;
- Acad::ErrorStatus es;
- es = func(*setTddInDwg, dt);
- es = func(*setTddUsrTimer, dt);
- es = func(*setTdlCreate, dt);
- es = func(*setTdlUpdate, dt);
- es = func(*setTduCreate, dt);
- es = func(*setTduUpdate, dt);
- // double d = func(*dimScale);
- // AcRxClass * rxClass = NULL; // needs to point to an instance of dimension class descriptor
- // AcDbDimStyleTableRecord * pRcd = NULL; // needs to point to instance of AcDbDimStyleTableRecord
- // AcDbObjectId styleId; // if es == eOk then will == dimension style ID
- // es = func(*getDimStyleChildData, rxClass, pRcd, styleId);
- }
模板“func”(忘记将其重命名为更好的名称)被3个不同的签名覆盖。 其中2个只是测试用例,
以确保覆盖工作(确实如此)。 希望代码有足够的文档记录来理解。 如果不是我自己或这里的其他人
,将很乐意回答您的问题。
哦,没有错误捕获。 如果有异常,我希望程序GPF可以修复代码。
可以添加错误处理,但是如果发生异常,则应用程序和AutoCAD的状态将是未知的,因此我认为最好只是出现故障。
挑战
我没有对代码做任何事情,这里有它。 因此,挑战在于添加对AutoCAD其他风格的支持,甚至可能弄清楚
如何将其包装在自己的漂亮类中。
本帖以下内容被隐藏保护;需要你回复后,才能看到! 游客,如果您要查看本帖隐藏内容请 回复 |
|