雪山飞狐_lzh 发表于 2010-7-8 14:46:00

可自动注册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
    }
}


雪山飞狐_lzh 发表于 2010-7-8 14:48:00

相关类

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;
    }
}




雪山飞狐_lzh 发表于 2010-7-8 14:54:00

本帖最后由 作者 于 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
    }
}



雪山飞狐_lzh 发表于 2010-7-8 15:47:00

同时在基类中封装了两个获取当前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));
      }

mycad 发表于 2010-8-29 15:38:00

顶!!!!!!

yanglin112 发表于 2011-11-8 17:08:20

Mark,follows!

革天明 发表于 2012-9-24 15:43:32

曲高和寡啊,高山仰止

lysgyx 发表于 2012-10-14 17:55:43

这个很有用,谢谢了

hfzengzhen 发表于 2015-4-25 16:07:24

最近正在找这个资料,非常感谢

mycad 发表于 2015-4-28 16:16:40

顶!!!!!!!!!!!
页: [1]
查看完整版本: 可自动注册dll的另类实现