.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;
}
似乎通过上面的代码已经解决了所有问题,但是我个人并不满足上面的方案,原因如下:
- 不喜欢直接在.net中调用cmd命令
- 当检查是否注册时,必须预先知道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;
}
}
完毕,希望对大家有用!
.net比较完美的动态注册com组件的更多相关文章
- Vue动态注册异步组件(非同一个工程的组件)
前言:最近在掘金逛的时候,无意中看到前滴滴前端架构黄轶大佬,看到了大佬分享的一篇博客滴滴 webapp 5.0 Vue 2.0 重构经验分享 ,对于其中第5个问题(异步加载的业务线组件,如何动态注册? ...
- react根据传参的不同动态注册不同的子组件
上一篇文章介绍了关于Vue如何根据传参的不同动态注册不同的子组件,实现过程请查阅Vue.extend动态注册子组件,由Vue的这个功能我就自然联想到了使用react该如何实现同样的功能呢.其实,用re ...
- 插件占坑,四大组件动态注册前奏(三) 系统BroadCast的注册发送流程
转载请注明出处:http://blog.csdn.net/hejjunlin/article/details/52204143 前言:为什么要了解系统Activity,Service,BroadCas ...
- 插件占坑,四大组件动态注册前奏(二) 系统Service的启动流程
转载请注明出处:http://blog.csdn.net/hejjunlin/article/details/52203903 前言:为什么要了解系统Activity,Service,BroadCas ...
- 插件占坑,四大组件动态注册前奏(一) 系统Activity的启动流程
转载请注明出处:http://blog.csdn.net/hejjunlin/article/details/52190050 前言:为什么要了解系统Activity,Service,,BroadCa ...
- 使用ServletContainerInitializer动态注册组件
1.背景 在web容器(例如tomcat)启动时为提供给第三方组件机会做一些初始化的工作,例如注册servlet或者filtes等.对此servlet规范提供了ServletContainerInit ...
- Android开发4: Notification编程基础、Broadcast的使用及其静态注册、动态注册方式
前言 啦啦啦~(博主每次开篇都要卖个萌,大家是不是都厌倦了呢~) 本篇博文希望帮助大家掌握 Broadcast 编程基础,实现动态注册 Broadcast 和静态注册 Broadcast 的方式以及学 ...
- Android so lib库远程http下载和动态注册
一.背景 在开发Android应用程序的实现,有时候需要引入第三方so lib库,但第三方so库比较大,例如开源第三方播放组件ffmpeg库, 如果直接打包的apk包里面, 整个应用程序会大很多.经过 ...
- Android实现AppWidget、Broadcast动态注册
Android实现AppWidget.Broadcast动态注册 开发工具:Andorid Studio 1.3 运行环境:Android 4.4 KitKat 工程内容 主界面可以编辑广播的信息,点 ...
随机推荐
- SLP alpha 阶段总结
这学期快结束了,SLP的alpha阶段也结束了.在alpha版中,我实现了SLP的基础练习模块和全局设置模块,其他几个模块由于能力有限.时间有限而没有实现. 其中基础练习模块目前只能支持4/4拍,有三 ...
- mysql时间格式化,按时间段查询的MySQL语句
描述:有一个会员表,有个birthday字段,值为'YYYY-MM-DD'格式,现在要查询一个时间段内过生日的会员,比如'06-03'到'07-08'这个时间段内所有过生日的会员. SQL语句: Se ...
- .NET 泛型分析
.NET 泛型解析 一.问题背景 我们在编程的时候往往因为需要处理不同类型的数据或者对象,重复编写很多类似的代码,造成代码的冗余,代码也显得不那么优雅,泛型的出现,正好是为了解决这个问题,实现继承. ...
- 二十七、JDK1.5新特性---Annotation
上篇文章介绍了反射的一些基础知识以及应用案例,本文将介绍jdk 1.5 出现的新特性——Annotation也就是我们所说的注解,即使用注释的方式加入一些程序的信息. 注解相当于一种标记,在程序中加了 ...
- vbs 中文字符串
vbs 字符串包含中文字符,文件以UTF-8无BOM格式保存,就会出现“编译器错误: 未结束的字符串常量”错误,改以ANSI保存就没有这个问题
- Windows Azure Virtual Machine 之用程序控制Azure VM
我们在很多时候可能会需要用程序来控制VM的创建,删除工作. 而在这些工作之中,用程序创建一个VM将会是一个非常复杂的过程,因为他涉及到很多步骤. 具体步骤如下 1 创建一个Hosted cloud s ...
- hibernate 入门
工程截图 1.jar包 和 hibernate配置文件 /src/hibernate.cfg.xml , /src/log4j.properties , /src/db.sql < ...
- 进制转换及API接口中的转换
//十进制转二进制Console.WriteLine("十进制166的二进制表示: "+Convert.ToString(166, 2));//十进制转八进制Console.Wri ...
- 安装win7的那些事
由于win7系统只支持MBR格式的分区,如果强行将win7安装到UEFI分区方式的硬盘上将不能启动,所以,如果你要给别人的win8或者win10的OEM系统安装win7的话,记得先将重要数据备份出去, ...
- ECMA中的switch语句
switch借鉴自其他语言,但也有自己的特色. 1.可以在switch语句中使用任何数据类型(数值.字符串.对象等),很多其他语言中只能使用数值. 2.每个case的值不一定是常量,可以是变量或者表达 ...