自定义实体的CLI封装

在进行CAD二次开发的技术选型时,建议主体使用.NET技术栈(.NET生态丰富,开发效率较高);当涉及自定义实体等高级功能时,可以切换到C++技术栈,并且用CLI混合编程方式对其进行封装供.NET项目使用。这样就可以兼顾开发效率和功能两个因素了!

在创建自定义实体(详见:自定义实体的创建和使用)的基础上,如何对自定义实体进行CLI封装,请看下文!

下一篇文章将讲解如何使用COM技术封装自定义实体,从而为自定义实体添加属性面板,这可以给用户提供修改自定义实体属性的界面接口,非常实用,敬请期待!

自定义实体的CLI封装

ObjectARX向导创建自定义实体的项目模板比较方便,主要步骤如下:

  • 创建ObjectARX项目

  • 添加混合编程支持

接下来的主要工作就是实现自定义实体包装类的代码逻辑。

  • 头文件
    • 定义继承自Autodesk::AutoCAD::DatabaseServices::Entity的C#自定义实体
    • 核心机关在CustomEntity1CLIWrapper(System::IntPtr unmanagedPointer, bool autoDelete)构造函数,可以通过System::IntPtr(new CustomEntity1())向其传递C++对象实例,后续方法实现中就可以调用自定义实体中的方法了
    • 这里设计CLI属性用法
    • 在C#项目中,就转变成C#类和属性
    • GetImpObj()方法返回非托管自定义实体对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#pragma once
#include "StdAfx.h"
#include "../MyCustomEntity/CustomEntity1.h"

using namespace System;
using namespace Autodesk::AutoCAD::Geometry;
using namespace Autodesk::AutoCAD::DatabaseServices;

namespace CLIWrapper {
[Autodesk::AutoCAD::Runtime::Wrapper("CustomEntity1")]
public ref class CustomEntity1CLIWrapper :public Autodesk::AutoCAD::DatabaseServices::Entity
{
public:
CustomEntity1CLIWrapper();

internal:
CustomEntity1CLIWrapper(System::IntPtr unmanagedPointer, bool autoDelete);

inline CustomEntity1* GetImpObj()
{
return static_cast<CustomEntity1*>(UnmanagedObject.ToPointer());
}

public:
property Point3d Center {
void set(Point3d point);
Point3d get();
}

property double R1 {
void set(double d);
double get();
}

property double R2 {
void set(double d);
double get();
}

property int N {
void set(int i);
int get();
}
};
}
  • 源文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include "stdafx.h"
#include "CustomEntity1CLIWrapper.h"
#include "mgdinterop.h"
#include "../MyCustomEntity/CustomEntity1.h"

CLIWrapper::CustomEntity1CLIWrapper::CustomEntity1CLIWrapper()
:Autodesk::AutoCAD::DatabaseServices::Entity(System::IntPtr(new CustomEntity1()), true){}
CLIWrapper::CustomEntity1CLIWrapper::CustomEntity1CLIWrapper(System::IntPtr unmanagedPointer, bool autoDelete)
: Autodesk::AutoCAD::DatabaseServices::Entity(unmanagedPointer, autoDelete){}

void CLIWrapper::CustomEntity1CLIWrapper::Center::set(Point3d point) {
Autodesk::AutoCAD::Runtime::Interop::Check(GetImpObj()->setCenter(GETPOINT3D(point)));
}
Point3d CLIWrapper::CustomEntity1CLIWrapper::Center::get() {
return ToPoint3d(GetImpObj()->getCenter());
}

void CLIWrapper::CustomEntity1CLIWrapper::R1::set(double d) {
Autodesk::AutoCAD::Runtime::Interop::Check(GetImpObj()->setR1(d));
}
double CLIWrapper::CustomEntity1CLIWrapper::R1::get() {
return GetImpObj()->getR1();
}

void CLIWrapper::CustomEntity1CLIWrapper::R2::set(double d) {
Autodesk::AutoCAD::Runtime::Interop::Check(GetImpObj()->setR2(d));
}
double CLIWrapper::CustomEntity1CLIWrapper::R2::get() {
return GetImpObj()->getR2();
}

void CLIWrapper::CustomEntity1CLIWrapper::N::set(int i) {
Autodesk::AutoCAD::Runtime::Interop::Check(GetImpObj()->setN(i));
}
int CLIWrapper::CustomEntity1CLIWrapper::N::get() {
return GetImpObj()->getN();
}
  • 修改入口文件

    On_kInitAppMsg()On_kUnloadAppMsg()中添加注册代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    #include "StdAfx.h"
    #include "resource.h"
    #include "../MyCustomEntity/CustomEntity1.h"
    #include "CustomEntity1CLIWrapper.h"

    #define szRDS _RXST("LH")
    // 添加这里
    static AcMgObjectFactoryBase** g_PEs = NULL;

    class CMyCustomEntityCLIWrapperApp : public AcRxArxApp {
    public:
    CMyCustomEntityCLIWrapperApp() : AcRxArxApp() {}

    virtual AcRx::AppRetCode On_kInitAppMsg(void* pkt) {
    // TODO: Load dependencies here
    // You *must* call On_kInitAppMsg here
    AcRx::AppRetCode retCode = AcRxArxApp::On_kInitAppMsg(pkt);

    // 添加这里
    static AcMgObjectFactoryBase* PEs[] =
    {
    new AcMgObjectFactory<CLIWrapper::CustomEntity1CLIWrapper ,CustomEntity1>(),
    NULL
    };
    g_PEs = PEs;

    return (retCode);
    }

    virtual AcRx::AppRetCode On_kUnloadAppMsg(void* pkt) {
    // TODO: Add your code here
    // You *must* call On_kUnloadAppMsg here
    AcRx::AppRetCode retCode = AcRxArxApp::On_kUnloadAppMsg(pkt);

    // 添加这里
    int i = 0;
    while (g_PEs[i] != NULL)
    delete g_PEs[i++];

    return (retCode);
    }

    virtual void RegisterServerComponents() {
    }
    };

    IMPLEMENT_ARX_ENTRYPOINT(CMyCustomEntityCLIWrapperApp)

测试

下面在.NET项目中进行测试,通过Add()添加一个自定义实体,然后通过Modify()修改其圆心坐标。使用起来与内置实体无异。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using CLIWrapper;
using AcadApp = Autodesk.AutoCAD.ApplicationServices.Application;

[assembly: CommandClass(typeof(TestWrapper.Cmds))]

namespace TestWrapper
{
public static class Cmds
{
[CommandMethod("Add")]
public static void Add()
{
var doc = AcadApp.DocumentManager.MdiActiveDocument;
var db = doc.Database;

using(var tr = db.TransactionManager.StartTransaction())
{
var blockTable = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
var modelSpace = tr.GetObject(blockTable[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;

CustomEntity1CLIWrapper ent = new CustomEntity1CLIWrapper();
ent.Center = new Autodesk.AutoCAD.Geometry.Point3d(1000,1000,0);

modelSpace.AppendEntity(ent);
tr.AddNewlyCreatedDBObject(ent, true);
tr.Commit();
}
}

[CommandMethod("Modify")]
public static void Modify()
{
var doc = AcadApp.DocumentManager.MdiActiveDocument;
var db = doc.Database;
var ed = doc.Editor;

var res = ed.GetEntity("请选择目标自定义实体");
if (res.Status != Autodesk.AutoCAD.EditorInput.PromptStatus.OK)
return;
var id = res.ObjectId;
using (var tr = db.TransactionManager.StartTransaction())
{
var ent = id.GetObject(OpenMode.ForWrite) as CustomEntity1CLIWrapper;
ent.Center = new Autodesk.AutoCAD.Geometry.Point3d(2000,2000,0);
ent.N = 6;

tr.Commit();
}
}
}
}

测试无误,封装成功!

评论