雪山飞狐_lzh 发表于 2015-4-2 16:47:28

netload时注册dll并加载局部cui

本帖最后由 雪山飞狐_lzh 于 2015-4-3 12:49 编辑

自2006版本以后,cad的用户界面变成了cui/cuix,使用局部cui可以简单的加载界面要素,比如菜单、工具栏
但cui的加载一直没有提供NetApi的版本,而Com库提供的该功能,问题是Com库通常要加载组件,使跨版本成为问题
那么有办法简单解决这个问题吗,显然反射可以,下面的代码就是基于这个想法的实现
AxObject类, Com对象代理类,封装了属性设置/读取和函数调用

using System;using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;

namespace TlsCad.Runtime
{
    public class AxObject
    {

      public static AxObject AcadApplication
      {
            get { return new AxObject(Application.AcadApplication); }
      }

      public static AxObject Preferences
      {
            get { return new AxObject(Application.Preferences); }
      }

      public object Object
      { protected set; get; }

      protected Type _type;

      protected AxObject()
      { }

      public AxObject(DBObject obj)
            : this(obj.AcadObject)
      { }

      public AxObject(object value)
      {
            Object = value;
            _type = Type.GetTypeFromHandle(Type.GetTypeHandle(Object));
      }

      public AxObjectList AsList()
      {
            return new AxObjectList(Object, _type);
      }

      public AxObject GetProperty(string propertyName)
      {
            try
            {
                object obj =
                  _type.InvokeMember(
                  propertyName,
                  BindingFlags.GetProperty,
                  null,
                  Object,
                  new object);
                if (obj != null)
                  return new AxObject(obj);
            }
            catch
            { }

            return null;

      }

      public void SetProperty(string propertyName, object value)
      {
            try
            {
                _type.InvokeMember(
                  propertyName,
                  BindingFlags.SetProperty,
                  null,
                  Object,
                  new object[] { value });
            }
            catch
            { }
      }

      public AxObject Invoke(string methodName, params object[] args)
      {
            try
            {
                object obj = _type.InvokeMember(methodName, BindingFlags.InvokeMethod, null, Object, args);
                if (obj != null)
                  return new AxObject(obj);
            }
            catch
            { }

            return null;

      }

      public override string ToString()
      {
            return Object.ToString();
      }

    }
}


AxObjectList类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace TlsCad.Runtime
{
    public class AxObjectList : AxObject,IEnumerable<AxObject>
    {


      internal AxObjectList(object value, Type type)
      {
            Object = value;
            _type = type;
      }

      public AxObject this
      {
            get { return this.Invoke("Item", index); }
      }

      public AxObject this
      {
            get { return this.Invoke("Item", name); }
      }

      public int Count
      {
            get { return (int)this.GetProperty("Count").Object; }
      }

      public void ForEach(Action<AxObject> action)
      {
            for (int i = 0; i < Count; i++)
                action(this.Invoke("Item", i));
      }

      public IEnumerator<AxObject> GetEnumerator()
      {
            for (int i = 0; i < Count; i++)
                yield return this.Invoke("Item", i);
      }

      IEnumerator IEnumerable.GetEnumerator()
      {
            for (int i = 0; i < Count; i++)
                yield return this.Invoke("Item", i);
      }

    }
}


AutoRegAessem类,自动注册dll的简化类,改写自kean
using System;
using System.IO;
using System.Linq;
using System.Reflection;

using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using Microsoft.Win32;


namespace TlsCad.Runtime
{


    public enum AssemLoadType
    {
      Startting = 2,
      ByCommand = 12,
      Disabled = 20
    }

   
    public struct AssemInfo
    {
      /// <summary>
      /// 注册名
      /// </summary>
      public string Name;

      /// <summary>
      /// 程序集全名
      /// </summary>
      public string Fullname;

      /// <summary>
      /// 程序集路径
      /// </summary>
      public string Loader;

      /// <summary>
      /// 加载方式
      /// </summary>
      public AssemLoadType LoadType;

      /// <summary>
      /// 程序集说明
      /// </summary>
      public string Description;

    }

   
    public class Command : IComparable<Command>
    {

      public string GlobalName;
      public string LocalizedName;
      public string GroupName;

      public string TypeName;
      public string MethodName;

      public string Description;

      public Command() { }

      public Command(string globalName)
      {
            GlobalName = globalName;
      }

      #region IComparable<Command> 成员

      int IComparable<Command>.CompareTo(Command other)
      {
            return this.GlobalName.CompareTo(other.GlobalName);
      }

      #endregion

    }

    public abstract class AutoRegAssem : IExtensionApplication
    {

      private AssemInfo _info = new AssemInfo();

      public static Assembly CurrAssembly
      {
            get { return Assembly.GetCallingAssembly(); }
      }

      public static string Location
      {
            get { return CurrAssembly.Location; }
      }

      public static string Path
      {
            get
            {
                DirectoryInfo di = new DirectoryInfo(Location).Parent;
                string path = di.FullName;
                if (path.LastIndexOf('\\') != path.Length - 1)
                  path += '\\';
                return path;
            }
      }

      public AutoRegAssem()
      {

            Assembly assem = Assembly.GetCallingAssembly();
            _info.Loader = assem.Location;
            _info.Fullname = assem.FullName;
            _info.Name = assem.GetName().Name;
            _info.LoadType = AssemLoadType.Startting;

            if (!SearchForReg())
            {
                RegApp();
            }

      }


      #region Reg

      private RegistryKey GetAcAppKey()
      {

            RegistryKey ackey =
                Registry.CurrentUser.OpenSubKey(
                  HostApplicationServices.Current.RegistryProductRootKey, true);

            return ackey.CreateSubKey("Applications");

      }

      private bool SearchForReg()
      {

            RegistryKey appkey = GetAcAppKey();
            var regApps = appkey.GetSubKeyNames();
            return regApps.Contains(_info.Name);

      }

      public void RegApp()
      {

            RegistryKey appkey = GetAcAppKey();
            RegistryKey rk = appkey.CreateSubKey(_info.Name);
            rk.SetValue("DESCRIPTION", _info.Fullname, RegistryValueKind.String);
            rk.SetValue("LOADCTRLS", _info.LoadType, RegistryValueKind.DWord);
            rk.SetValue("LOADER", _info.Loader, RegistryValueKind.String);
            rk.SetValue("MANAGED", 1, RegistryValueKind.DWord);
            appkey.Close();

      }

      #endregion

      

      #region IExtensionApplication 成员

      public abstract void Initialize();

      public abstract void Terminate();

      #endregion

    }
}


调用方式



namespace TlsCad.Parts
{
    class MyArx : AutoRegAssem
    {

      public override void Initialize()
      {

            var files = AxObject.Preferences.GetProperty("Files");
            var oldPath = files.GetProperty("SupportPath").ToString();
            if (!oldPath.ToLower().Contains(Path.ToLower()))
                files.SetProperty("SupportPath", oldPath + ";" + Path);

            var acapp = AxObject.AcadApplication;
            var groups = acapp.GetProperty("MenuGroups").AsList();
            var cui = groups["TlsCad"];

            if (cui == null)
            {
                cui = groups.Invoke("Load", "TlsCad.cui");
                var menus = cui.GetProperty("Menus").AsList();
                foreach (var menu in menus)
                {
                  menus.Invoke(
                        "InsertMenuInMenuBar",
                        menu.GetProperty("Name"),
                        "");
                }
            }

            SystemManager.Editor.WriteMessage("\nTlsPart Loading!......");

      }

      public override void Terminate()
      {

      }

雪山飞狐_lzh 发表于 2015-4-2 18:10:11

本帖最后由 雪山飞狐_lzh 于 2015-4-3 07:42 编辑

二、Com集合的处理
让AxObject类继承IEnumerable接口,可以实现集合的遍历
修改如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using System.Collections;

namespace TlsCad.Runtime
{
    public class AxObject: IEnumerable<AxObject>
    {

      public static AxObject AcadApplication
      {
            get { return new AxObject(Application.AcadApplication); }
      }

      public static AxObject Preferences
      {
            get { return new AxObject(Application.Preferences); }
      }

      public object Value
      { private set; get; }

      Type _type;

      public AxObject(DBObject obj) :this(obj.AcadObject)
      {   }

      public AxObject(object value)
      {
            Value = value;
            _type = Type.GetTypeFromHandle(Type.GetTypeHandle(Value));
      }

      public AxObject GetProperty(string propertyName)
      {
            try
            {
                object obj =
                  _type.InvokeMember(
                        propertyName,
                        BindingFlags.GetProperty,
                        null,
                        Value,
                        new object);
                if (obj != null)
                  return new AxObject(obj);
            }
            catch
            { }

            return null;

      }

      public void SetProperty(string propertyName, object value)
      {
            try
            {
                _type.InvokeMember(
                  propertyName,
                  BindingFlags.SetProperty,
                  null,
                  Value,
                  new object[] { value });
            }
            catch
            { }
      }

      public AxObject Invoke(string methodName, params object[] args)
      {
            try
            {
                object obj =
                  _type.InvokeMember(
                        methodName,
                        BindingFlags.InvokeMethod,
                        null,
                        Value,
                        args);
                if (obj != null)
                  return new AxObject(obj);
            }
            catch
            { }

            return null;

      }

      public void ForEach(Action<AxObject> action)
      {
            int count = (int)this.GetProperty("Count").Value;
            for (int i = 0; i < count; i++)
                action(this.Invoke("Item", i));
      }

      public IEnumerator<AxObject> GetEnumerator()
      {
            int count = (int)this.GetProperty("Count").Value;
            for (int i = 0; i < count; i++)
                yield return this.Invoke("Item", i);
      }

      IEnumerator IEnumerable.GetEnumerator()
      {
            int count = (int)this.GetProperty("Count").Value;
            for (int i = 0; i < count; i++)
                yield return this.Invoke("Item", i);
      }
    }
}

调用代码如下修改
            if (cui == null)
            {
                cui = groups.Invoke("Load", "TlsCad.cui");
                var menus = cui.GetProperty("Menus");
                foreach (var menu in menus)
                {
                  menus.Invoke(
                        "InsertMenuInMenuBar",
                        menu.GetProperty("Name").Value,
                        "");
                }
            }

雪山飞狐_lzh 发表于 2015-4-3 12:51:51

添加AxObjectList类以支持集合类,一楼代码已更新

zzyong00 发表于 2015-4-6 20:06:35

帮版主顶帖,好像.net版人气也很凋零

cheng5276 发表于 2015-5-9 22:07:55

我也顶,老大威武!

ydw621 发表于 2015-5-9 22:42:03

顶,老大威武!

cheng5276 发表于 2015-5-9 23:45:32

本帖最后由 cheng5276 于 2015-5-9 23:47 编辑

老大,现碰到个问题,采用您这种方法,CUI是加载了,工具栏显示了,但是菜单不显示
                  var acapp = AxObject.AcadApplication;
                  var groups = acapp.GetProperty("MenuGroups").AsList();
                  var cui = groups["我的工具"];
                  if (cui == null)
                  {
                        cui = groups.Invoke("Load", "MyTool.cuix");
                        var menus = cui.GetProperty("Menus").AsList();
                        foreach (var menu in menus)
                        {
                            menus.Invoke( "InsertMenuInMenuBar",menu.GetProperty("Name"),"");
                        }

                  }

//没办法,只好模拟LISP的语句 (menucmd "p99=+我的工具.POP1") ,再次设置菜单项

                  string loadmenu = "(menucmd \"p99=+我的工具.POP1\") ";
                  Application.DocumentManager.MdiActiveDocument.SendStringToExecute(loadmenu, true, false, false);
虽然目前能够显示菜单了,但这种发送命令行的方式总是不太保险,很可能会出现执行不了的情况(如CAD未完全启动好,调用会失败)

请问老大,能直接用.net方法解决这个问题么;

cheng5276 发表于 2015-5-9 23:48:47

还有请教老大,用这种COM方法,如何直接加载LISP文件?

雪山飞狐_lzh 发表于 2015-5-9 23:57:06

我的示例菜单应该是可以显示的 08 10 12 我都测试过

鱼与熊掌 发表于 2015-5-10 22:49:02

其实用Autolisp加载很简单的...
页: [1] 2
查看完整版本: netload时注册dll并加载局部cui