明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 5891|回复: 9

[运行时] 可自动注册dll的另类实现

[复制链接]
发表于 2010-7-8 14:46 | 显示全部楼层 |阅读模式
看过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
  1. using Microsoft.Win32;
  2. using System;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Resources;
  6. using System.Reflection;
  7. using System.Collections.Generic;
  8. using System.Text.RegularExpressions;
  9. using Autodesk.AutoCAD.Runtime;
  10. using Autodesk.AutoCAD.EditorInput;
  11. using Autodesk.AutoCAD.DatabaseServices;
  12. using Autodesk.AutoCAD.ApplicationServices;
  13. using TlsCad.Utils;
  14. using TlsCad.Collections;
  15. [assembly: CommandClass(typeof(TlsCad.Trans.AutoRegAssem))]
  16. namespace TlsCad.Trans
  17. {
  18.     [Serializable]
  19.     public class AutoRegAssem : SerialList<AssemInfo, Command>
  20.     {
  21.         private string _infoFileName = null;
  22.         private static List<string> _regApps;
  23.         private static List<AutoRegAssem> _assems = new List<AutoRegAssem>();
  24.         public Assembly Assembly
  25.         { private set; get; }
  26.         public static AutoRegAssem CurrAssem
  27.         {
  28.             get
  29.             {
  30.                 Assembly assembly = Assembly.GetCallingAssembly();
  31.                 return
  32.                     _assems.Find(
  33.                         assem =>
  34.                         assem.Assembly == assembly);
  35.             }
  36.         }
  37.         protected virtual AssemLoadType LoadType
  38.         {
  39.             get
  40.             {
  41.                 return AssemLoadType.Startting;
  42.             }
  43.         }
  44.         public static string Location
  45.         {
  46.             get
  47.             {
  48.                 return Assembly.GetCallingAssembly().Location;
  49.             }
  50.         }
  51.         public static DirectoryInfo Directory
  52.         {
  53.             get
  54.             {
  55.                 return new DirectoryInfo(Location).Parent;
  56.             }
  57.         }
  58.         public AutoRegAssem()
  59.         {
  60.             Assembly = Assembly.GetCallingAssembly();
  61.             Info.Loader = Assembly.Location;
  62.             Info.Fullname = Assembly.FullName;
  63.             Info.Name = Assembly.GetName().Name;
  64.             Info.LoadType = LoadType;
  65.             _infoFileName =
  66.                 new DirectoryInfo(Assembly.Location).Parent.FullName;
  67.             if (_infoFileName.LastIndexOf("\") != _infoFileName.Length - 1)
  68.                 _infoFileName += "\";
  69.             _infoFileName += Info.Name + ".assx";
  70.             if (!File.Exists(_infoFileName))
  71.             {
  72.                 GetInfoFromAssembly();
  73.                 WriteXml(_infoFileName);
  74.             }
  75.             else
  76.             {
  77.                 GetInfoFromFile();
  78.             }
  79.             if (!SearchForReg())
  80.             {
  81.                 RegApp();
  82.             }
  83.             _assems.Add(this);
  84.         }
  85.         
  86.         #region LoadAndSave
  87.         private void GetInfoFromFile()
  88.         {
  89.             ReadXml(_infoFileName);
  90.             this.Sort();
  91.         }
  92.         private bool GetInfoFromAssembly()
  93.         {
  94.             List<Command> cmds = new List<Command>();
  95.             try
  96.             {
  97.                 Info.Fullname = Assembly.FullName;
  98.                 foreach (Module m in Assembly.GetModules(true))
  99.                 {
  100.                     Type[] types = m.GetTypes();
  101.                     foreach (Type t in types)
  102.                     {
  103.                         ResourceManager rm =
  104.                             new ResourceManager(t.FullName, Assembly);
  105.                         rm.IgnoreCase = true;
  106.                         MethodInfo[] methods = t.GetMethods();
  107.                         foreach (MethodInfo mi in methods)
  108.                         {
  109.                             object[] attbs =
  110.                                 mi.GetCustomAttributes(
  111.                                     typeof(CommandMethodAttribute),
  112.                                     true
  113.                                 );
  114.                             foreach (object attb in attbs)
  115.                             {
  116.                                 CommandMethodAttribute cma = attb as CommandMethodAttribute;
  117.                                 if (cma != null)
  118.                                 {
  119.                                     Command cmd = new Command(cma.GlobalName);
  120.                                     if (cma.GroupName != null)
  121.                                     {
  122.                                         cmd.GroupName = cma.GroupName;
  123.                                     }
  124.                                     cmd.TypeName = t.FullName;
  125.                                     cmd.MethodName = mi.Name;
  126.                                     cmd.LocalizedName = cmd.GlobalName;
  127.                                     string lnid = cma.LocalizedNameId;
  128.                                     if (lnid != null)
  129.                                     {
  130.                                         try
  131.                                         {
  132.                                             cmd.LocalizedName = rm.GetString(lnid);
  133.                                         }
  134.                                         catch
  135.                                         { }
  136.                                     }
  137.                                     cmds.Add(cmd);
  138.                                 }
  139.                             }
  140.                         }
  141.                     }
  142.                 }
  143.                 AddRange(cmds);
  144.                 return true;
  145.             }
  146.             catch (System.Exception ex)
  147.             {
  148.                 throw ex;
  149.             }
  150.         }
  151.         #endregion
  152.         #region Reg
  153.         private RegistryKey GetAcAppKey()
  154.         {
  155.             RegistryKey ackey =
  156.                 Registry.CurrentUser.OpenSubKey(
  157.                     HostApplicationServices.Current.RegistryProductRootKey, true);
  158.             return ackey.CreateSubKey("Applications");
  159.         }
  160.         private bool SearchForReg()
  161.         {
  162.             if (_regApps == null)
  163.             {
  164.                 RegistryKey appkey = GetAcAppKey();
  165.                 _regApps = new List<string>(appkey.GetSubKeyNames());
  166.                 appkey.Close();
  167.             }
  168.             bool find = _regApps.Contains(Info.Name);
  169.             if (!find)
  170.             {
  171.                 _regApps.Add(Info.Name);
  172.             }
  173.             return find;
  174.         }
  175.         public void RegApp()
  176.         {
  177.             RegistryKey appkey = GetAcAppKey();
  178.             RegistryKey rk = appkey.CreateSubKey(Info.Name);
  179.             rk.SetValue("DESCRIPTION", Info.Fullname, RegistryValueKind.String);
  180.             rk.SetValue("LOADCTRLS", Info.LoadType, RegistryValueKind.DWord);
  181.             rk.SetValue("LOADER", Info.Loader, RegistryValueKind.String);
  182.             rk.SetValue("MANAGED", 1, RegistryValueKind.DWord);
  183.             RegistryKey cmdrk = rk.CreateSubKey("Commands");
  184.             foreach (Command cmd in this)
  185.             {
  186.                 cmdrk.SetValue(cmd.GlobalName, cmd.GlobalName, RegistryValueKind.String);
  187.             }
  188.             var groups =
  189.                 from cmd in this
  190.                 where cmd.GroupName != null
  191.                 select cmd.GroupName;
  192.             RegistryKey grprk = rk.CreateSubKey("Groups");
  193.             foreach (string g in groups.Distinct())
  194.             {
  195.                 grprk.SetValue(g, g, RegistryValueKind.String);
  196.             }
  197.             appkey.Close();
  198.         }
  199.         public void UnRegApp()
  200.         {
  201.             using (RegistryKey appkey = GetAcAppKey())
  202.             {
  203.                 DeleteSubKey(appkey, Info.Name);
  204.             }
  205.         }
  206.         private void DeleteSubKey(RegistryKey parent, params string[] subNames)
  207.         {
  208.             foreach (string name in subNames)
  209.             {
  210.                 RegistryKey rk = parent.OpenSubKey(name, true);
  211.                 DeleteSubKey(rk, rk.GetSubKeyNames());
  212.                 parent.DeleteSubKey(name);
  213.             }
  214.         }
  215.         [CommandMethod("NetUnReg")]
  216.         public static void NetUnReg()
  217.         {
  218.             Document doc = Application.DocumentManager.MdiActiveDocument;
  219.             Editor ed = doc.Editor;
  220.             ed.WriteMessage("\n欢迎使用TlsCad.Net程序注册表卸载工具!\n请从下面的序号中选择需要卸载的程序:(多项选择用逗号分隔)");
  221.             if (_assems.Count == 0)
  222.             {
  223.                 ed.WriteMessage("\n没有需要卸载的程序!");
  224.                 return;
  225.             }
  226.             InvokeArx.DisplayTextScreen = true;
  227.             int i = 0;
  228.             foreach (AutoRegAssem assem in _assems)
  229.             {
  230.                 ed.WriteMessage("\n{0}.{1}", ++i, assem.Info.Name);
  231.             }
  232.             var resStr = ed.GetString("\n请输入序号:");
  233.             do
  234.             {
  235.                 if (resStr.Status == PromptStatus.OK)
  236.                 {
  237.                     string str = resStr.StringResult;
  238.                     if (!Regex.IsMatch(str, @"^\d*[,\d]*\d$"))
  239.                     {
  240.                         ed.WriteMessage("\n格式错误!");
  241.                     }
  242.                     else
  243.                     {
  244.                         var ids = str.Split(',').Select(s => Convert.ToInt32(s) - 1).ToList();
  245.                         if (ids.Any(id => id >= 0 && id < _assems.Count))
  246.                         {
  247.                             ids.Sort();
  248.                             var assems = ids.Select(id => _assems[id]).ToList();
  249.                             var nassems = new List<AutoRegAssem>();
  250.                             foreach (var assem in assems)
  251.                             {
  252.                                 var opts =
  253.                                     new PromptKeywordOptions("\n是否删除" + assem.Info.Name);
  254.                                 opts.Keywords.Add("Yes");
  255.                                 opts.Keywords.Add("No");
  256.                                 opts.Keywords.Default = "No";
  257.                                 var resKey = ed.GetKeywords(opts);
  258.                                 if (resKey.Status == PromptStatus.Cancel)
  259.                                     return;
  260.                                 else if (resKey.Status != PromptStatus.OK || resKey.StringResult == "No")
  261.                                     nassems.Add(assem);
  262.                             }
  263.                             assems = assems.Except(nassems).ToList();
  264.                             assems.ForEach(assem => assem.UnRegApp());
  265.                             _assems = _assems.Except(assems).ToList();
  266.                             break;
  267.                         }
  268.                         ed.WriteMessage("\n数字超出范围!");
  269.                     }
  270.                 }
  271.                 resStr = ed.GetString("\n请重新输入序号:");
  272.             } while (resStr.Status != PromptStatus.Cancel);
  273.             InvokeArx.DisplayTextScreen = false;
  274.         }
  275.         #endregion
  276.         #region RunCommand(Test)
  277.         public void Run(Command cmd)
  278.         {
  279.             if (Assembly == null)
  280.             {
  281.                 Assembly[] assemblys = AppDomain.CurrentDomain.GetAssemblies();
  282.                 foreach (Assembly assembly in assemblys)
  283.                 {
  284.                     if (assembly.FullName == Info.Fullname)
  285.                     {
  286.                         Assembly = assembly;
  287.                         break;
  288.                     }
  289.                 }
  290.             }
  291.             if (Assembly != null)
  292.             {
  293.                 Type t = Assembly.GetType(cmd.TypeName);
  294.                 object obj = Assembly.CreateInstance(t.FullName);
  295.                 MethodInfo mi = t.GetMethod(cmd.MethodName);
  296.                 mi.Invoke(obj, new object[0]);
  297.                 obj = null;
  298.             }
  299.         }
  300.         #endregion
  301.     }
  302. }

 楼主| 发表于 2010-7-8 14:48 | 显示全部楼层
相关类

Command
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. namespace TlsCad.Trans
  6. {
  7.     [Serializable]
  8.     public class Command : IComparable<Command>
  9.     {
  10.         public string GlobalName;
  11.         public string LocalizedName;
  12.         public string GroupName;
  13.         public string TypeName;
  14.         public string MethodName;
  15.         public string Description;
  16.         public Command() { }
  17.         public Command(string globalName)
  18.         {
  19.             GlobalName = globalName;
  20.         }
  21.         #region IComparable<Command> 成员
  22.         int IComparable<Command>.CompareTo(Command other)
  23.         {
  24.             return this.GlobalName.CompareTo(other.GlobalName);
  25.         }
  26.         #endregion
  27.     }
  28. }

AssemInfo
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. namespace TlsCad.Trans
  6. {
  7.     public enum AssemLoadType
  8.     {
  9.         Startting = 2,
  10.         ByCommand = 12,
  11.         Disabled = 20
  12.     }
  13.     [Serializable]
  14.     public struct AssemInfo
  15.     {
  16.         /// <summary>
  17.         /// 注册名
  18.         /// </summary>
  19.         public string Name;
  20.         /// <summary>
  21.         /// 程序集全名
  22.         /// </summary>
  23.         public string Fullname;
  24.         /// <summary>
  25.         /// 程序集路径
  26.         /// </summary>
  27.         public string Loader;
  28.         /// <summary>
  29.         /// 加载方式
  30.         /// </summary>
  31.         public AssemLoadType LoadType;
  32.         /// <summary>
  33.         /// 程序集说明
  34.         /// </summary>
  35.         public string Description;
  36.     }
  37. }



 楼主| 发表于 2010-7-8 14:54 | 显示全部楼层
本帖最后由 作者 于 2010-7-8 15:48:54 编辑

调用的方式:
把上面的类放在一个类库里,或者放在你的内库里:),编译为dll

在你需要自动注册的工程里引用上面的类库
然后:
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using TlsCad.Trans;
  6. using Autodesk.AutoCAD.Runtime;
  7. [assembly: ExtensionApplication(typeof(TlsTest.MyApp))]
  8. namespace TlsTest
  9. {
  10.     public class MyApp : AutoRegAssem, IExtensionApplication
  11.     {
  12.         #region IExtensionApplication 成员
  13.         void IExtensionApplication.Initialize()
  14.         {
  15.         }
  16.         void IExtensionApplication.Terminate()
  17.         {
  18.         }
  19.         #endregion
  20.     }
  21. }

 楼主| 发表于 2010-7-8 15:47 | 显示全部楼层
同时在基类中封装了两个获取当前dll路径的属性
调用方式:
  1.         [CommandMethod("tt4")]
  2.         public void test24()
  3.         {
  4.             Document doc = Application.DocumentManager.MdiActiveDocument;
  5.             Editor ed = doc.Editor;
  6.             Database db = doc.Database;
  7.             ed.WriteMessage(
  8.                 "\nPath:{0}\nLocation:{1}",
  9.                 MyApp.Directory.FullName,
  10.                 MyApp.Location);
  11.             MyApp.CurrAssem.ForEach(cmd => ed.WriteMessage("\n" + cmd.GlobalName));
  12.         }
复制代码
发表于 2010-8-29 15:38 | 显示全部楼层
顶!!!!!!
发表于 2011-11-8 17:08 | 显示全部楼层
Mark,follows!
发表于 2012-9-24 15:43 | 显示全部楼层
曲高和寡啊,高山仰止
发表于 2012-10-14 17:55 | 显示全部楼层
这个很有用,谢谢了
发表于 2015-4-25 16:07 | 显示全部楼层
最近正在找这个资料,非常感谢
发表于 2015-4-28 16:16 | 显示全部楼层
顶!!!!!!!!!!!
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|CAD论坛|CAD教程|CAD下载|联系我们|关于明经|明经通道 ( 粤ICP备05003914号 )  
©2000-2023 明经通道 版权所有 本站代码,在未取得本站及作者授权的情况下,不得用于商业用途

GMT+8, 2024-3-28 23:07 , Processed in 0.196320 second(s), 22 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表