浩辰CAD移植过程中遇到的问题及解决方式

2020-05-21  本文已影响0人  yumxuanyi

@版权声明:本文为版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出,
本文链接https://www.jianshu.com/p/6d9bf7b96295
如有问题, 可邮件(yumxuanyi@qq.com)咨询。


关键字:AutoCAD、浩辰CAD、netWrapper 、ComWrapper、objectARX

1. Dbx自定义实体部分处理

注意:不能使用原AutoCAD的宏ACDB_REGISTER_OBJECT_ENTRY_AUTO(className)进行注册
解决方法: 在On_InitAppMsg中手动注册

    CMyLine::rxInit();
    acrxBulidClassHierarchy();

2. NetWrapper部分问题处理

当我们需要封装C++对象供C#调用时,net托管代码需要特殊处理。会出现 如下问题

  1. 在c#中不能new托管对象。
  2. 托管对象插入cad后,操作无反映,比如选择无反应,如果设置了夹点,夹点无显示等。
  3. 通过选择集选择获取id后打开,无法识别到具体类型。
namespace Test 
{
    namespace EntityDb
    {
        //注意要写WrapperAttribute不写Wrapper 
        [GrxCAD::Runtime::WrapperAttribute("CMyLine")]
        public ref class MgMyLine : public GrxCAD::DatabaseServices::Line 
        {
        public:
            //- Constructor
            MgMyLine () ;
            ~MgMyLine () ;

        //internal:
        //internal改为public 因为在c#中要用这个函数创建一个临时对象 net中类型识别是有问题的
       //改为public 可以在c#中调用该函数来创建临时对象 从而进行类型判断
        public:
            MgMyLine (System::IntPtr unmanagedPointer, bool bAutoDelete) ;

            //- Returns the unmanaged ARX Object
            inline CMyLine *GetImpObj () {
                return (static_cast<CMyLine *>(UnmanagedObject.ToPointer ())) ;
            }

        public:
            //- To define properties which get/set values of your object
            //- the format you must use is
            //-     __property void set_Center(Point2d point);
            //-     __property Point2d get_Center();

                    //设置定位点坐标
        property GrxCAD::Geometry::Point3d MStartPoint
            {
                GrxCAD::Geometry::Point3d get()
                {
                    return ToPoint3d(GetImpObj()->get_StartPoint());
                }
                void set(GrxCAD::Geometry::Point3d locationPoint)
                {
                GetImpObj()->set_StartPoint(GETPOINT3D(locationPoint));
                }
            }


           property GrxCAD::Geometry::Point3d MEndPoint
            {
                GrxCAD::Geometry::Point3d get()
                {
                    return ToPoint3d(GetImpObj()->get_EndPoint());
                }
                void set(GrxCAD::Geometry::Point3d locationPoint)
                {
                GetImpObj()->set_EndPoint(GETPOINT3D(locationPoint));
                }
            }

        } ;

    }
}
namespace Test 
{
    namespace EntityDb
    {

        //-----------------------------------------------------------------------------
        //1. GrxCAD::DatabaseServices::Line ( (System::IntPtr)(new CMyLine()),true) //单独这种写法 autodelete = true 为原默认写法
        //    写法1造成. C#中通过new 将MgMyLine添加到块表记录后 选择不了 操作不了 简单的说无法识别
        //2. GrxCAD::DatabaseServices::Line (((System::IntPtr) CMyLine::createObject().get()), true)
        //    写法2 解决了写法1 无法选择的问题。但是会照成
        //        a 通过获取objectID打开后识别不到MgMyLine  
        //        b 当含有有参数的构造函数时 就不行了
        //正确写法如下  注意 autodelete = false 。因为在构造函数中需要重新设置为true
        MgMyLine::MgMyLine () : GrxCAD::DatabaseServices::Line ( (System::IntPtr)(new CMyLine()),false)
        {
            m_imp = UnmanagedObject ;
            m_bAutoDelete = true;
        }

        //-----------------------------------------------------------------------------
        MgMyLine::MgMyLine (System::IntPtr unmanagedPointer, bool bAutoDelete)
            : GrxCAD::DatabaseServices::Line (unmanagedPointer, bAutoDelete)
        {

        }

        MgMyLine::~MgMyLine () 
        {


        }
    }
}

在c#中选择托管对象并进行类型识别的方法如下

        [CommandMethod("SelectLine")]
        static public void SelectLine()
        {
            Document doc = GrxCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            PromptSelectionResult sr = ed.GetSelection();
            ObjectId[] entityIds = new ObjectId[] { } ;
            if (sr.Status == PromptStatus.OK)
            {
              entityIds = sr.Value.GetObjectIds();
            }
                using (DocumentLock dlock = doc.LockDocument())
            {

                using (Transaction trans = doc.TransactionManager.StartTransaction())
                {
                    foreach (ObjectId entityId in entityIds)
                    {
                        //下面注释部分为 传统方法是识别不出来的
                        //Entity ent = trans.GetObject(entityId, OpenMode.ForRead) as Entity;
                        //if (ent is MgMyLine)
                        //{
                        //    MgMyLine theLine = ent as MgMyLine;
                        //    Point3d startPoint = theLine.MStartPoint;
                        //}

                        //改用如下方法
                        Entity ent = trans.GetObject(entityId, OpenMode.ForRead) as Entity;
                        string dxfName = ent.GetRXClass().DxfName;//用这个先进行判断是哪一个类 
                        System.IntPtr unManagedObjectPointer = ent.UnmanagedObject;//获取非托管类的指针 用于创建临时托管对象
                        if (dxfName == "MYLINE")
                        {
                            //判断是这种类型后 根据非托管指针创建临时托管对象
                            //注意第二个参数必须为false,因为这里是临时当临时托管对象析构时不能将原指针给删除了
                            MgMyLine managedLine = new MgMyLine(unManagedObjectPointer, false);

                            //下面就能正常获取属性了
                            //因为该临时托管对象的底层数据时原非托管对象 所以本质上操作的的是同一个对象的属性和方法
                            Point3d startPoint = managedLine.MStartPoint;
                            Point3d endPoint = managedLine.MEndPoint;

                            //下面是修改属性的方法
                            //因为上面是以只读的方式打开的 所以这里升级模式
                            managedLine.UpgradeOpen();
                            managedLine.MStartPoint = new Point3d(100, 100, 0);
                            managedLine.MEndPoint = new Point3d(1000,300, 0);
                            managedLine.DowngradeOpen();
                            trans.Commit();//修改后提交 不修改不提交
                        }
                    }
                }
            } 
        }

3. COMWrapper部分问题处理

该部分内容较多,如有疑问请联系博主。

上一篇下一篇

猜你喜欢

热点阅读