• .net比较完美的动态注册com组件


    .net中经常需要使用com组件,怎么样注册com组件呢?

    一般想到的当然是直接通过系统cmd 调用regsvr32注册程序去注册,如下:

    regsvr32 name.dll
    

    在.net中可以直接执行cmd命令如下:

    System.Diagnostics.Process.Start("regsvr32.exe","name.dll");
    

    问题来了,那怎么去检查一个dll已经注册了呢?不能每次都注册吧!我们知道每一个com组件都有一个clsid,如果已经注册了,那么在系统注册表里面会有注册信息的。 csharp代码如下:

    private static bool IsExistRegister(Guid guid)
    {
    	RegistryKey rkTest = Registry.ClassesRoot.OpenSubKey(String.Format("CLSID\{{{0}}}\InprocServer32", guid.ToString()));
    	if (rkTest != null)
    	{
    		var val = rkTest.GetValue("");//获取注册表中注册的dll路径
    		if (val != null)
    		{
    			return System.IO.File.Exists(val.ToString());
    		}
    
    	}
    	return false;
    }
    

    似乎通过上面的代码已经解决了所有问题,但是我个人并不满足上面的方案,原因如下:

    1. 不喜欢直接在.net中调用cmd命令
    2. 当检查是否注册时,必须预先知道com的clsid。

    那么有么有方法解决上面2个问题呢?答案当然是肯定的! 通过查询资料得知:
    regsvr32 name.dll 实际上就是调用name.dll中的一个方法:DllRegisterServer。
    在.net中我们可以通过pinvoke直接调用dll这个方法就可以了,代码如下:

    static class NameDll
    {
    	[DllImport("name.dll")]
    	public static extern int DllRegisterServer();
    
    	[DllImport("name.dll")]
    	public static extern int DllUnregisterServer();
    }
    

    然后在.net中直接通过NameDll.DllRegisterServer();即可完成注册。 这个办法不需要在.net中调用cmd命令,但是有个缺点。
    每一个dll都需要这么定义下。因为[DllImport("name.dll")]这个路径不能动态给。所以也不是很好。其实在.net中有可以动态加载dll并根据需要调用dll中方法的代码如下:

    public class Win32DllWrap : IDisposable
    {
    	[DllImport("kernel32.dll")]
    	private extern static IntPtr LoadLibrary(String path);
    
    	[DllImport("kernel32.dll")]
    	private extern static IntPtr GetProcAddress(IntPtr lib, String funcName);
    
    	[DllImport("kernel32.dll")]
    	private extern static bool FreeLibrary(IntPtr lib);
    
    	private IntPtr hLib;
    	public Win32DllWrap(String DLLPath)
    	{
    		hLib = LoadLibrary(DLLPath);
    	}
    
    	/// <summary>
    	/// 根据函数名获取dll中的函数指针,并转化为指定的TDelegate类型
    	/// </summary>
    	/// <typeparam name="TDelegate"></typeparam>
    	/// <param name="name"></param>
    	/// <returns></returns>
    	public TDelegate GetFunc<TDelegate>(String name) where TDelegate : class
    	{
    		IntPtr api = GetProcAddress(hLib, name);
    		return Marshal.GetDelegateForFunctionPointer(api, typeof(TDelegate)) as TDelegate;
    	}
    
    
    	public void Dispose()
    	{
    		FreeLibrary(hLib);
    	}
    }
    
    
    /*
    using(var dll = new Win32DllWrap(path)){
         var method = dll.GetFunc<Action>("DllRegisterServer");//根据名字获取方法,并返回对于的委托
         method();//完成注册
    }
    */
    
    

    这个方法避免了每一个com组件要定义个类的弊端。而且完全可以根据com路径动态注册。但是大家别忘了,上面还有一个问题没解决。

    那就是在检查com是否注册时,怎么动态得知指定路径com的clsid。 废话也不多说。代码如下

    private static List<Guid> GetClsids(string path)
    {
    	if (!System.IO.File.Exists(path))
    	{
    		throw new Exception(path + "文件不存在");
    	}
    	List<Guid> list = new List<Guid>();
    	ITypeLib lib;
    	IntPtr attrPtr;
    	ITypeInfo info;
    	LoadTypeLib(path, out lib);
    	if (lib == null)
    	{
    		throw new Exception(path + "不是com组件");
    	}
    	var n = lib.GetTypeInfoCount();
    	for (int i = 0; i < n; i++)
    	{
    		lib.GetTypeInfo(i, out info);
    		if (info != null)
    		{
    			info.GetTypeAttr(out attrPtr);
    			if (attrPtr != null)
    			{
    				var v = (System.Runtime.InteropServices.ComTypes.TYPEATTR)Marshal.PtrToStructure(attrPtr, typeof(System.Runtime.InteropServices.ComTypes.TYPEATTR));
    				if (v.typekind == System.Runtime.InteropServices.ComTypes.TYPEKIND.TKIND_COCLASS)
    				{
    					list.Add(v.guid);
    				}
    				info.ReleaseTypeAttr(attrPtr);
    			}
    		}
    	}
    	return list;
    }
    

    上面这个方法可以获取给定路径的dll中的clsid列表。 老实讲:这个方法我是真的费尽心力,网上几乎没.net的资料。
    至此所有问题都已经解决。我们完全可以根据指定路径注册动态注册com组件,并能判断是否已经注册。我简单封装一下代码:

    /// <summary>
    /// Com组件注册类
    /// </summary>
    public class ComRegHelp
    {
    
       
    
    	private delegate void comDelegate();
    
    	/// <summary>
    	/// 注册指定路径的dll,如果已经注册,就不注册
    	/// </summary>
    	/// <param name="dllPath"></param>
    	public static void Registe(string dllPath)
    	{
    		if (!IsRegistered(dllPath))
    		{
    			using (var dll = new Win32DllWrap(dllPath))
    			{
    				dll.GetFunc<comDelegate>("DllRegisterServer")();
    			}
    		}
    	}
    
    	/// <summary>
    	/// 取消注册指定路径的dll
    	/// </summary>
    	/// <param name="dllPath"></param>
    	public static void UnRegiste(string dllPath)
    	{
    		using (var dll = new Win32DllWrap(dllPath))
    		{
    			dll.GetFunc<comDelegate>("DllUnregisterServer")();
    		}
    	}
    
    	private static List<Guid> GetClsids(string path)
    	{
    		if (!System.IO.File.Exists(path))
    		{
    			throw new Exception(path + "文件不存在");
    		}
    		List<Guid> list = new List<Guid>();
    		ITypeLib lib;
    		IntPtr attrPtr;
    		ITypeInfo info;
    		LoadTypeLib(path, out lib);
    		if (lib == null)
    		{
    			throw new Exception(path + "不是com组件");
    		}
    		var n = lib.GetTypeInfoCount();
    		for (int i = 0; i < n; i++)
    		{
    			lib.GetTypeInfo(i, out info);
    			if (info != null)
    			{
    				info.GetTypeAttr(out attrPtr);
    				if (attrPtr != null)
    				{
    					var v = (System.Runtime.InteropServices.ComTypes.TYPEATTR)Marshal.PtrToStructure(attrPtr, typeof(System.Runtime.InteropServices.ComTypes.TYPEATTR));
    					if (v.typekind == System.Runtime.InteropServices.ComTypes.TYPEKIND.TKIND_COCLASS)
    					{
    						list.Add(v.guid);
    					}
    					info.ReleaseTypeAttr(attrPtr);
    				}
    			}
    		}
    		return list;
    	}
    
    	[DllImport("oleaut32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
    	static extern int LoadTypeLib(string fileName, out ITypeLib typeLib);
    
    	/// <summary>
    	/// 判断指定路径dll是否已经注册
    	/// </summary>
    	/// <param name="path"></param>
    	/// <returns></returns>
    	public static bool IsRegistered(string path)
    	{
    		var guids = GetClsids(path);
    		foreach (var item in guids)
    		{
    			if (IsExistRegister(item))
    			{
    				return true;
    			}
    		}
    		return false;
    	}
    
    
    	private static bool IsExistRegister(Guid guid)
    	{
    		RegistryKey rkTest = Registry.ClassesRoot.OpenSubKey(String.Format("CLSID\{{{0}}}\InprocServer32", guid.ToString()));
    		if (rkTest != null)
    		{
    			var val = rkTest.GetValue("");
    			if (val != null)
    			{
    				return System.IO.File.Exists(val.ToString());
    			}
    
    		}
    		return false;
    	}
    }
    

    完毕,希望对大家有用!

  • 相关阅读:
    Python + unittest + HTMLTestRunnerCN 生成接口自动化测试报告
    python 读写操作CSV文件
    with关键字
    Django常规命令大全
    科技阅读与写作资料
    Topics in Service Computing
    学习总结100515
    【论文收集】PQDT硕博库中的搜索结果service composition
    毕业开题结束感想
    excle操作备忘
  • 原文地址:https://www.cnblogs.com/tianqiq/p/4538194.html
Copyright © 2020-2023  润新知