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-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,
"");
}
} 添加AxObjectList类以支持集合类,一楼代码已更新 帮版主顶帖,好像.net版人气也很凋零 我也顶,老大威武! 顶,老大威武! 本帖最后由 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方法解决这个问题么;
还有请教老大,用这种COM方法,如何直接加载LISP文件? 我的示例菜单应该是可以显示的 08 10 12 我都测试过 其实用Autolisp加载很简单的...
页:
[1]
2