可自动注册dll的另类实现
看过kean的相关主题,对自动注册dll的方式应该都不会太陌生方法是在程序载入时检查注册表项,如果没有就添加
不过这种方式的弊病是必须在代码中调用自动注册类的相关函数,那么有没有更简单的方式?
我们知道,自动注册dll是在继承IExtensionApplication接口的类的Initialize例程中完成的,那么Cad在遇到这种类就会首先实例化该类,并在载入时运行这个Initialize例程,下面的想法就是利用这一点,在类实例化时自动检查
基类:AutoRegAssem
SerialList在这里
http://bbs.mjtd.com/forum.php?mod=viewthread&tid=79953
InvokeArx在这里
http://bbs.mjtd.com/forum.php?mod=viewthread&tid=78074
using Microsoft.Win32;
using System;
using System.IO;
using System.Linq;
using System.Resources;
using System.Reflection;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.ApplicationServices;
using TlsCad.Utils;
using TlsCad.Collections;
namespace TlsCad.Trans
{
public class AutoRegAssem : SerialList<AssemInfo, Command>
{
private string _infoFileName = null;
private static List<string> _regApps;
private static List<AutoRegAssem> _assems = new List<AutoRegAssem>();
public Assembly Assembly
{ private set; get; }
public static AutoRegAssem CurrAssem
{
get
{
Assembly assembly = Assembly.GetCallingAssembly();
return
_assems.Find(
assem =>
assem.Assembly == assembly);
}
}
protected virtual AssemLoadType LoadType
{
get
{
return AssemLoadType.Startting;
}
}
public static string Location
{
get
{
return Assembly.GetCallingAssembly().Location;
}
}
public static DirectoryInfo Directory
{
get
{
return new DirectoryInfo(Location).Parent;
}
}
public AutoRegAssem()
{
Assembly = Assembly.GetCallingAssembly();
Info.Loader = Assembly.Location;
Info.Fullname = Assembly.FullName;
Info.Name = Assembly.GetName().Name;
Info.LoadType = LoadType;
_infoFileName =
new DirectoryInfo(Assembly.Location).Parent.FullName;
if (_infoFileName.LastIndexOf("\\") != _infoFileName.Length - 1)
_infoFileName += "\\";
_infoFileName += Info.Name + ".assx";
if (!File.Exists(_infoFileName))
{
GetInfoFromAssembly();
WriteXml(_infoFileName);
}
else
{
GetInfoFromFile();
}
if (!SearchForReg())
{
RegApp();
}
_assems.Add(this);
}
#region LoadAndSave
private void GetInfoFromFile()
{
ReadXml(_infoFileName);
this.Sort();
}
private bool GetInfoFromAssembly()
{
List<Command> cmds = new List<Command>();
try
{
Info.Fullname = Assembly.FullName;
foreach (Module m in Assembly.GetModules(true))
{
Type[] types = m.GetTypes();
foreach (Type t in types)
{
ResourceManager rm =
new ResourceManager(t.FullName, Assembly);
rm.IgnoreCase = true;
MethodInfo[] methods = t.GetMethods();
foreach (MethodInfo mi in methods)
{
object[] attbs =
mi.GetCustomAttributes(
typeof(CommandMethodAttribute),
true
);
foreach (object attb in attbs)
{
CommandMethodAttribute cma = attb as CommandMethodAttribute;
if (cma != null)
{
Command cmd = new Command(cma.GlobalName);
if (cma.GroupName != null)
{
cmd.GroupName = cma.GroupName;
}
cmd.TypeName = t.FullName;
cmd.MethodName = mi.Name;
cmd.LocalizedName = cmd.GlobalName;
string lnid = cma.LocalizedNameId;
if (lnid != null)
{
try
{
cmd.LocalizedName = rm.GetString(lnid);
}
catch
{ }
}
cmds.Add(cmd);
}
}
}
}
}
AddRange(cmds);
return true;
}
catch (System.Exception ex)
{
throw ex;
}
}
#endregion
#region Reg
private RegistryKey GetAcAppKey()
{
RegistryKey ackey =
Registry.CurrentUser.OpenSubKey(
HostApplicationServices.Current.RegistryProductRootKey, true);
return ackey.CreateSubKey("Applications");
}
private bool SearchForReg()
{
if (_regApps == null)
{
RegistryKey appkey = GetAcAppKey();
_regApps = new List<string>(appkey.GetSubKeyNames());
appkey.Close();
}
bool find = _regApps.Contains(Info.Name);
if (!find)
{
_regApps.Add(Info.Name);
}
return find;
}
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);
RegistryKey cmdrk = rk.CreateSubKey("Commands");
foreach (Command cmd in this)
{
cmdrk.SetValue(cmd.GlobalName, cmd.GlobalName, RegistryValueKind.String);
}
var groups =
from cmd in this
where cmd.GroupName != null
select cmd.GroupName;
RegistryKey grprk = rk.CreateSubKey("Groups");
foreach (string g in groups.Distinct())
{
grprk.SetValue(g, g, RegistryValueKind.String);
}
appkey.Close();
}
public void UnRegApp()
{
using (RegistryKey appkey = GetAcAppKey())
{
DeleteSubKey(appkey, Info.Name);
}
}
private void DeleteSubKey(RegistryKey parent, params string[] subNames)
{
foreach (string name in subNames)
{
RegistryKey rk = parent.OpenSubKey(name, true);
DeleteSubKey(rk, rk.GetSubKeyNames());
parent.DeleteSubKey(name);
}
}
public static void NetUnReg()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
ed.WriteMessage("\n欢迎使用TlsCad.Net程序注册表卸载工具!\n请从下面的序号中选择需要卸载的程序:(多项选择用逗号分隔)");
if (_assems.Count == 0)
{
ed.WriteMessage("\n没有需要卸载的程序!");
return;
}
InvokeArx.DisplayTextScreen = true;
int i = 0;
foreach (AutoRegAssem assem in _assems)
{
ed.WriteMessage("\n{0}.{1}", ++i, assem.Info.Name);
}
var resStr = ed.GetString("\n请输入序号:");
do
{
if (resStr.Status == PromptStatus.OK)
{
string str = resStr.StringResult;
if (!Regex.IsMatch(str, @"^\d*[,\d]*\d$"))
{
ed.WriteMessage("\n格式错误!");
}
else
{
var ids = str.Split(',').Select(s => Convert.ToInt32(s) - 1).ToList();
if (ids.Any(id => id >= 0 && id < _assems.Count))
{
ids.Sort();
var assems = ids.Select(id => _assems).ToList();
var nassems = new List<AutoRegAssem>();
foreach (var assem in assems)
{
var opts =
new PromptKeywordOptions("\n是否删除" + assem.Info.Name);
opts.Keywords.Add("Yes");
opts.Keywords.Add("No");
opts.Keywords.Default = "No";
var resKey = ed.GetKeywords(opts);
if (resKey.Status == PromptStatus.Cancel)
return;
else if (resKey.Status != PromptStatus.OK || resKey.StringResult == "No")
nassems.Add(assem);
}
assems = assems.Except(nassems).ToList();
assems.ForEach(assem => assem.UnRegApp());
_assems = _assems.Except(assems).ToList();
break;
}
ed.WriteMessage("\n数字超出范围!");
}
}
resStr = ed.GetString("\n请重新输入序号:");
} while (resStr.Status != PromptStatus.Cancel);
InvokeArx.DisplayTextScreen = false;
}
#endregion
#region RunCommand(Test)
public void Run(Command cmd)
{
if (Assembly == null)
{
Assembly[] assemblys = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly assembly in assemblys)
{
if (assembly.FullName == Info.Fullname)
{
Assembly = assembly;
break;
}
}
}
if (Assembly != null)
{
Type t = Assembly.GetType(cmd.TypeName);
object obj = Assembly.CreateInstance(t.FullName);
MethodInfo mi = t.GetMethod(cmd.MethodName);
mi.Invoke(obj, new object);
obj = null;
}
}
#endregion
}
}
相关类
Command
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TlsCad.Trans
{
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
}
}
AssemInfo
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TlsCad.Trans
{
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;
}
}
本帖最后由 作者 于 2010-7-8 15:48:54 编辑
调用的方式:
把上面的类放在一个类库里,或者放在你的内库里:),编译为dll
在你需要自动注册的工程里引用上面的类库
然后:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TlsCad.Trans;
using Autodesk.AutoCAD.Runtime;
namespace TlsTest
{
public class MyApp : AutoRegAssem, IExtensionApplication
{
#region IExtensionApplication 成员
void IExtensionApplication.Initialize()
{
}
void IExtensionApplication.Terminate()
{
}
#endregion
}
}
同时在基类中封装了两个获取当前dll路径的属性
调用方式:
public void test24()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
Database db = doc.Database;
ed.WriteMessage(
"\nPath:{0}\nLocation:{1}",
MyApp.Directory.FullName,
MyApp.Location);
MyApp.CurrAssem.ForEach(cmd => ed.WriteMessage("\n" + cmd.GlobalName));
}
顶!!!!!! Mark,follows! 曲高和寡啊,高山仰止 这个很有用,谢谢了 最近正在找这个资料,非常感谢 顶!!!!!!!!!!!
页:
[1]