乐筑天下

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

“可写”;只读系统变量”;(打包)

[复制链接]

27

主题

193

帖子

5

银币

后起之秀

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

铜币
300
发表于 2009-8-25 03:03:16 | 显示全部楼层 |阅读模式
好吧,前面关于可写的“只读系统变量”的主题的代码有点原始,并且是
维护的噩梦。 在这里,我打包了代码,使其更易于移植,并且不
易出现错误。 概述的方法不使用类,因为这只是导致我符合
THISCALL调用约定,将“MyAcDbHeader”的“this”指针自动填充到
ecx寄存器上。
该代码的目标是以类型安全和
半可移植的方式使AcDbHeader的调用成员函数。 大多数代码是针对编译器的,允许它在
编译时捕获语法错误和类型不匹配。 模板函数完成了大部分实际
工作,编译器为发布版本很好地优化了这些工作。
我再次首先介绍完整的代码:
  1. // MyAcDbHeader.h
  2. #pragma once
  3. #if defined(_M_IX86)
  4. // code is stricly for 32bit x86
  5. namespace MyAcDbHeader {
  6.         // AutoCAD AcDbHeader typedefs.  Get these from the undecorated names
  7.         typedef Acad::ErrorStatus (CALLBACK* SET_TDD_INDWG) (AcDbDate const &);
  8.         typedef Acad::ErrorStatus (CALLBACK* SET_TDD_USR_TIMER) (AcDbDate const &);
  9.         typedef Acad::ErrorStatus (CALLBACK* SET_TDL_CREATE) (AcDbDate const &);
  10.         typedef Acad::ErrorStatus (CALLBACK* SET_TDL_UPDATE) (AcDbDate const &);
  11.         typedef Acad::ErrorStatus (CALLBACK* SET_TDU_CREATE) (AcDbDate const &);
  12.         typedef Acad::ErrorStatus (CALLBACK* SET_TDU_UPDATE) (AcDbDate const &);
  13.         typedef void * (CALLBACK* SLOW_DB_HEADER) (void);
  14.         //// defined to test different template definitions
  15.         //typedef double (CALLBACK* DIM_SCALE) (void);
  16.         //typedef Acad::ErrorStatus (CALLBACK* GET_DIMSTYLE_CHILE_DATA) (AcRxClass const *, AcDbDimStyleTableRecord * &, AcDbObjectId &);
  17.         // pointers to AutoCAD AcDbHeader function pointers.
  18.         // Before using these function they first need to be initialized by calling
  19.         // InitAcDbHeader, otherwise they are set to NULL and will GPF.
  20.         extern SET_TDD_INDWG setTddInDwg;
  21.         extern SET_TDD_USR_TIMER setTddUsrTimer;
  22.         extern SET_TDL_CREATE setTdlCreate;
  23.         extern SET_TDL_UPDATE setTdlUpdate;
  24.         extern SET_TDU_CREATE setTduCreate;
  25.         extern SET_TDU_UPDATE setTduUpdate;
  26.         extern SLOW_DB_HEADER slowDbHeader;
  27.         extern SLOW_DB_HEADER * pAcDbHeader;
  28.         //// declared to test different template definitions
  29.         //extern DIM_SCALE dimScale;
  30.         //extern GET_DIMSTYLE_CHILE_DATA getDimStyleChildData;
  31.         // InitAcDbHeader, must be called prior to using any other function pointers.
  32.         // Makes call to SetAcDbHeaderInstance before returning.
  33.         void InitAcDbHeader(AcDbObjectId stubId = AcDbObjectId::kNull);
  34.        
  35.         // SetAcDbHeaderInstanceFrom retieves the AcDbHeader from AutoCAD by
  36.         // dereferencing stubId to _thiscall (ecx) prior to calling slowDbHeader.
  37.         // If stubId == AcDbObjectId::kNull then _thiscall (ecx) is set to 0 prior
  38.         // to calling slowDbHeader.
  39.         void SetAcDbHeaderInstanceFrom(AcDbObjectId stubId);
  40. // set 1 byte alignment
  41. #pragma pack(push, 1)
  42.         // define typesafe template for AcDbHeader functions that have
  43.         // no parameters.
  44.         // T is the return type
  45.         // T1 is the type of the callee
  46.         template
  47.         T func(T1 callee)
  48.         {
  49.                 _asm mov ecx, pAcDbHeader
  50.                         T rVal = callee();
  51.                 return rVal;
  52.         }
  53.         // define typesafe template for AcDbHeader functions that have
  54.         // 1 parameter.
  55.         // T is the return type
  56.         // T1 is the type of the callee
  57.         // T2 is the type for parameter 1
  58.         template
  59.         T func(T1 callee, T2 const & inObj)
  60.         {
  61.                 _asm mov ecx, pAcDbHeader
  62.                         T rVal = callee(inObj);
  63.                 return rVal;
  64.         }
  65.         // define typesafe template for AcDbHeader functions that have
  66.         // 3 parameters.
  67.         // T is the return type
  68.         // T1 is the type of the callee
  69.         // T2 is the type for parameter 1, T3 for parameter 2, T4 for parameter 3
  70.         template
  71.         T func(T1 callee, T2 const * inPtr, T3 *& refPtr, T4 & outObj)
  72.         {
  73.                 _asm mov ecx, pAcDbHeader
  74.                         T rVal = callee(inPtr, refPtr, outObj);
  75.                 return rVal;
  76.         }
  77. #pragma pack(pop)
  78. }
  79. #endif
  1. // MyAcDbHeader.cpp
  2. #include
  3. #include "MyAcDbHeader.h"
  4. namespace MyAcDbHeader {
  5.         #if defined(_M_IX86)
  6.         // code is stricly for 32bit x86
  7.         // Define acad family from 2004 to 2006.  They should all have
  8.         // the same mangled AcDbHeader function names, but needs to be
  9.         // varified and coded accordingly.
  10.         // Calling convention is THISCALL, so register ECX needs to be
  11.         // set properly prior to making function calls.
  12.         #if defined(ARX2004)
  13.                 #define ACAD2004_FAMILY 1
  14.         #elif defined(ARX2005)
  15.                 #define ACAD2004_FAMILY 1
  16.         #elif defined(ARX2006)
  17.                 #define ACAD2004_FAMILY 1
  18.         #endif
  19.         // 2007 through 2009 should also have the same mangled AcDbHeader function names
  20.         // Place family check code here, and Place mangled names in InitAcDbHeader.
  21.         // 2010 32 bit, same as 2007 family.
  22.         // 2010 64 bit, calling convention is FASTCALL, Guessing the _thiscall will need to be placed
  23.         // in RCX, but haven't really looked into it
  24.         // Declare instances of AcDbHeader functions.
  25.         SET_TDD_INDWG setTddInDwg = NULL;
  26.         SET_TDD_USR_TIMER setTddUsrTimer = NULL;
  27.         SET_TDL_CREATE setTdlCreate = NULL;
  28.         SET_TDL_UPDATE setTdlUpdate = NULL;
  29.         SET_TDU_CREATE setTduCreate = NULL;
  30.         SET_TDU_UPDATE setTduUpdate = NULL;
  31.         SLOW_DB_HEADER slowDbHeader = NULL;
  32.         SLOW_DB_HEADER * pAcDbHeader = NULL;
  33.         //// declared to test different template definitions
  34.         //DIM_SCALE dimScale = NULL;
  35.         //GET_DIMSTYLE_CHILE_DATA getDimStyleChildData = NULL;
  36.         void InitAcDbHeader(AcDbObjectId stubId) {
  37.                 HMODULE hMod = GetModuleHandle("acdb16.dll");
  38. #ifdef ACAD2004_FAMILY
  39.                 // Get addresses of AcDbHeader functions, using mangled string names.
  40.                 setTddInDwg = (SET_TDD_INDWG) GetProcAddress(hMod, "?setTddInDwg@AcDbHeader@@QAE?AW4ErrorStatus@Acad@@ABVAcDbDate@@@Z");
  41.                 setTddUsrTimer = (SET_TDD_USR_TIMER) GetProcAddress(hMod, "?setTddUsrTimer@AcDbHeader@@QAE?AW4ErrorStatus@Acad@@ABVAcDbDate@@@Z");
  42.                 setTdlCreate = (SET_TDL_CREATE) GetProcAddress(hMod, "?setTdlCreate@AcDbHeader@@QAE?AW4ErrorStatus@Acad@@ABVAcDbDate@@@Z");
  43.                 setTdlUpdate = (SET_TDL_UPDATE) GetProcAddress(hMod, "?setTdlUpdate@AcDbHeader@@QAE?AW4ErrorStatus@Acad@@ABVAcDbDate@@@Z");
  44.                 setTduCreate = (SET_TDU_CREATE) GetProcAddress(hMod, "?setTduCreate@AcDbHeader@@QAE?AW4ErrorStatus@Acad@@ABVAcDbDate@@@Z");
  45.                 setTduUpdate = (SET_TDU_UPDATE) GetProcAddress(hMod, "?setTduUpdate@AcDbHeader@@QAE?AW4ErrorStatus@Acad@@ABVAcDbDate@@@Z");
  46.                 slowDbHeader = (SLOW_DB_HEADER) GetProcAddress(hMod, "?slowDbHeader@AcDbStub@@ABEPAVAcDbHeader@@XZ");
  47.                 //// a couple extra's to test different template definitions
  48.                 //dimScale = (DIM_SCALE) GetProcAddress(hMod, "?dimscale@AcDbHeader@@QBENXZ");
  49.                 //getDimStyleChildData = (GET_DIMSTYLE_CHILE_DATA) GetProcAddress(hMod, "?getDimstyleChildData@AcDbHeader@@QBE?AW4ErrorStatus@Acad@@PBVAcRxClass@@AAPAVAcDbDimStyleTableRecord@@AAVAcDbObjectId@@@Z");
  50. #endif
  51.                 SetAcDbHeaderInstanceFrom(stubId);
  52.         }
  53.         void SetAcDbHeaderInstanceFrom(AcDbObjectId stubId)
  54.         {
  55.                 void * pStub = stubId.isValid() ? (void *&) *stubId : NULL;
  56.                 _asm mov ecx, pStub
  57.                 _asm call slowDbHeader
  58.                 _asm mov pAcDbHeader, eax
  59.         }
  60.         #endif
  61. }
  1. // acrxEntryPoint.cpp
  2. ...
  3. ...
  4. #include "MyAcDbHeader.h"
  5. ...
  6. ...
  7. // - navSetDwgDate.setDwgDate command (do not rename)
  8.         static void navSetDwgDatesetDwgDate(void)
  9.         {
  10.                 using namespace MyAcDbHeader;
  11.                 InitAcDbHeader();
  12.                 AcDbDate dt;
  13.                 Acad::ErrorStatus es;
  14.                 es = func(*setTddInDwg, dt);
  15.                 es = func(*setTddUsrTimer, dt);
  16.                 es = func(*setTdlCreate, dt);
  17.                 es = func(*setTdlUpdate, dt);
  18.                 es = func(*setTduCreate, dt);
  19.                 es = func(*setTduUpdate, dt);
  20.                 // double d = func(*dimScale);
  21.                 // AcRxClass * rxClass = NULL; // needs to point to an instance of dimension class descriptor
  22.                 // AcDbDimStyleTableRecord * pRcd = NULL; // needs to point to instance of AcDbDimStyleTableRecord
  23.                 // AcDbObjectId styleId; // if es == eOk then will == dimension style ID
  24.                 // es = func(*getDimStyleChildData, rxClass, pRcd, styleId);
  25.         }

模板“func”(忘记将其重命名为更好的名称)被3个不同的签名覆盖。 其中2个只是测试用例,
以确保覆盖工作(确实如此)。 希望代码有足够的文档记录来理解。 如果不是我自己或这里的其他人
,将很乐意回答您的问题。
哦,没有错误捕获。 如果有异常,我希望程序GPF可以修复代码。
可以添加错误处理,但是如果发生异常,则应用程序和AutoCAD的状态将是未知的,因此我认为最好只是出现故障。
挑战
我没有对代码做任何事情,这里有它。 因此,挑战在于添加对AutoCAD其他风格的支持,甚至可能弄清楚
如何将其包装在自己的漂亮类中。

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

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

使用道具 举报

15

主题

190

帖子

5

银币

后起之秀

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

铜币
250
发表于 2009-8-25 08:43:34 | 显示全部楼层
保罗,这是很有趣的事。   
回复

使用道具 举报

27

主题

193

帖子

5

银币

后起之秀

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

铜币
300
发表于 2009-9-1 12:47:10 | 显示全部楼层
可以在不使用任何内联程序集的情况下有效地执行此操作,并且仅依赖C++指向成员的指针。有关此方法的示例,请参阅例如http://otb.manusoft.com/2009/03/objectarx-2010-dealing-with-missing.htm。
回复

使用道具 举报

15

主题

190

帖子

5

银币

后起之秀

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

铜币
250
发表于 2009-9-1 15:30:56 | 显示全部楼层
很好的密码,欧文。我本来打算走一条类似的路线,但因为我不知道AcDbHeader是否派生或派生自哪个类,所以拒绝了它,以便与vtbl保持同步
由于vtables是在编译时构建的,AcDbHeader需要知道,正如页面上的
示例所知道的AcGiFaceData<这是一个很好的解决方案,如果类结构在编译时已知,则效果良好。否则,必须采用不太优雅的方法
回复

使用道具 举报

15

主题

190

帖子

5

银币

后起之秀

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

铜币
250
发表于 2009-9-1 15:48:04 | 显示全部楼层
实际上,您可以在不知道原始vtable结构的情况下欺骗和使用功能。只需以您想要的任何方式声明您自己的 AcDbHeader 类即可。您添加的任何虚拟成员都可以声明为__declspec(dllimport),瞧!唯一的限制是,您无法将自己的 AcDbheader 对象传递给未使用 AcDbheader 声明的任何人(在实践中,这意味着您需要跳过一些箍,以确保在调用函数时将 AutoCAD 的 AcDbHeader 对象之一作为 *this* 指针传递)。
回复

使用道具 举报

27

主题

193

帖子

5

银币

后起之秀

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

铜币
300
发表于 2009-9-1 15:55:01 | 显示全部楼层
哦,只是为了澄清一下:我帖子中的vtable技巧只有在函数*未*导出时才是必要的。只要函数被导出,你就不需要知道vtable顺序。
回复

使用道具 举报

27

主题

193

帖子

5

银币

后起之秀

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

铜币
300
发表于 2009-9-1 15:57:06 | 显示全部楼层
哎呀,忘了去掉第一段。
谢谢,总是有不止一种方法...(在这里插入隐喻)...
回复

使用道具 举报

发表回复

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

本版积分规则

  • 微信公众平台

  • 扫描访问手机版

  • 点击图片下载手机App

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

GMT+8, 2025-5-1 17:52 , Processed in 1.208380 second(s), 71 queries .

© 2020-2025 乐筑天下

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