[原创]arx调用dll中的函数
www.dimcax.com
[原创]arx调用dll中的函数
在网上曾经看见有人问这样的一个问题:在arx中如何调用另一个arx中所定义的函数。对于这个问题,我不知道他真正的用意何在,但从技术而言,这是可以做到的。windows系统把大部分的函数和功能都封装在dll中供其它程序调用,从节约内存开支和压缩应用程序大小而言都是意义重大的。因此,看到上面这个朋友提的这个问题,我就有了另外一个想法:把arx中常用的函数封装在dll中供其它程序调用岂不是更好。
于是,我开始着手研究这方面的工作,可是,进程并不如想象中的美好。在纯mfc中程序没有问题,一使用arx中的函数就出问题,搞了好长一段时间都不出结果,加之网上一点这方面的资料都没有,刚开始还怀疑是autodesk公司在arx函数中做了手脚,可是rax在本质上也是dll啊,本着不成功誓不罢休的角度出发,终于探出了点眉目。再次声明,由于本人水平有限,加之这方面资料匮乏,难免有遗漏或不正确的地方,还望朋友们指出。
下面这个例子是把addtomodelspace()函数添加到dll中,然后在arx程序中调用它。函数的功能是把对象添加到数据库中,并返回对象的id。
一、创建dll工程
1、启动vc++6.0并新建一个名为adesksampe的mfc appwizard(dll)工程。
2、选择 regular dll using shared mfc dll(动态链接库使用共享mfc dll) 选项创建工程。
3、链接arx库文件。
在[工程]-[设置]-[连接]-[对象/库模块]中添加下面几个链接:
rxapi.lib acrx15.lib acdb15.lib acutil15.lib acge15.lib acgiapi.lib achapi15.lib acismobj15.lib acad.lib acedapi.lib
acsiobj.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib
uuid.lib
4、将指定的函数名添加到def文件的exports中
exports
; explicit exports can go here
;本例中要添加的函数
addtomodelspace
5、打开adesksampe.h文件添加函数声明:
该头文件声明了要供其它应用程序调用的函数原型。在这个例子中我只增加了一个函数addtomodelspace(),它用于把arx中的对象添加到数据库中。
//需要包含的头文件
#include "geassign.h"
#include "dbsymtb.h" // symboltables
#include "dbapserv.h" // acdbhostapplicationservices()
#include "dbtrans.h" // actransaction
#include "actrans.h" // actransactionmanager
#include "acdb.h" // acdb definitions
#include "rxregsvc.h" // arx linker
#include "aced.h" // aced stuff
#include "adslib.h" // rxads definitions
#include "dbents.h"
#include "resource.h" // main symbols
//这条语句是新增加的导出函数声明
__declspec(dllexport) acad::errorstatus winapi addtomodelspace(acdbobjectid &objid, acdbentity *pent);
class cadesksamperapp : public cwinapp
{
............
};
5、打开adesksampe.cpp文件添加函数实现:
cadesksamperapp theapp;
__declspec(dllexport) acad::errorstatus winapi addtomodelspace(acdbobjectid &objid, acdbentity *pent)
{
//注意!
//如果此dll是与mfc dll动态链接的,则其输出的任何调用mfc的函数都必须
//在其前面加上afx_manage_state()宏,这个宏必须出现在任何mfc调用之前。
//这意味着它必须是函数内部的第一条语句,甚至在任何对象变量声明之前,
//因为它们的构造函数有可能会调用mfc dll。
afx_manage_state(afxgetstaticmodulestate());
acad::errorstatus es = acad::eok;
acdbblocktable *pblocktable = null;
acdbblocktablerecord *pblocktablerecord = null;
es=acdbhostapplicationservices()->workingdatabase()->getsymboltable(pblocktable, acdb::kforread);
if( es != acad::eok )
{
return es;
}
es=pblocktable->getat(acdb_model_space, pblocktablerecord, acdb::kforwrite);
if( es != acad::eok )
{
pblocktable->close();
return es;
}
es=pblocktablerecord->appendacdbentity(objid, pent);
pent->close();
pblocktable->close();
pblocktablerecord->close();
return es;
}
二、dll调用
通过前面的例子我们设计了一个动态链接库adesksampe.dll,此库声明了一个函数addtomodelspace()供其它程序调用。下面我们再开发一个arx应用程序,程序将调用刚才设计好的dll。
1、用arx向导新建一个工程,记得一定要把use mfc复选框选中。
2、将上一节dll工程所生成的adesksampe.lib文件和adesksampe.dll文件拷入当前工程所在的目录。
3、在命令执行的文件中添加函数声明,关键字extern把它声明为外部的win api函数,然后在程序中就可以正常使用addtomodelspace()了。
下面是完整的程序清单:
// objectarx defined commands
#include "stdafx.h"
#include "stdarx.h"
//指定本文件生成的.obj文件应与adesksampe.lib一起连接。
#pragma comment(lib, "adesksampe.lib")
//告诉编译器此函数是在当前程序的外部定义的
extern acad::errorstatus winapi addtomodelspace(acdbobjectid &objid, acdbentity *pent);
// this is command 'windo'
void windo()
{
ads_name en;
ads_point pt;
if(acedentsel("\n选择要分解的对象:", en, pt) != rtnorm)
return;
acdbobjectid id;
acdbgetobjectid(id, en);
acdbentity* pent = null;
acdbopenobject(pent, id, acdb::kforwrite);
if(pent == null) return;
acdbvoidptrarray pvoidptrarray;
if(pent->explode(pvoidptrarray) != acad::eok)
{
pent->close();
acedalert("对象不能分解!");
return;
}
for(int i=0; i<pvoidptrarray.length(); i++)
{
acdbentity* pexpent = null;
pexpent = (acdbentity*) pvoidptrarray.at(i);
acutprintf("\n分解后的对象类型是: %s", pexpent->isa()->name());
// 现在,就可以象使用内部函数一样使用它了
if(addtomodelspace(id, pexpent) != acad::eok)
delete pexpent;
}
pent->erase(true);
pent->close();
}
三、允许arx程序
程序创建好了,接下来就该运行它看看效果了。在autocad中加载刚才创建好的arx程序,竟然提示找不到指定的动态链接库,无法加载,看来肯定是某个环节出了问题。
其实,windows中的大部分dll文件都放在系统的windows\\system和windows\\system32目录下,这是windows系统缺省的库搜索路径,因此,在加载arx程序前,必须让系统能找到相应的dll文件。所以,在应用程序中调用动态链接库中的函数必须进行适当的设置,我们可以采用以下几种方法:
1、把adesksampe.dll文件复制到系统的system目录下。
2、或者把adesksampe.dll文件所在目录设置成系统搜索路径。
3、或者把dll文件和arx文件放在同一个目录下。
只要做了上面几件事中的任意一件,嘿嘿,应该大功告成了。