.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 工程内容 主界面可以编辑广播的信息,点 ...
随机推荐
- Infinite V1 Release Note
游戏地址 PLAY 玩法说明 WASD 控制角色移动 更新内容 - 初步完成了角色移动(攻击状态) 开发心得 独立做游戏 其实最耽误时间的就是在自己的短板上, 对于我来说 就是3D建模和动作制作. ...
- tk画图
Page 387 of chapter 7 """ 6-23 page 343 play media files """ def odd() ...
- Mac下好用的编辑器VIM GUI版本 VimR 推荐
vim号称是编辑器之神,轮其功能和扩展性的确少有编辑器能比,但是大多数编辑器都有的文件浏览功能它确没有,虽然有些插件可以实现,但用起来都不是很方便,偶然发现了一个GUI版本的VIM,与普通的GUI版本 ...
- table 边框显示
.td{border:solid #add9c0; border-width:0px 1px 1px 0px;}.table{border:solid #add9c0; border-width:1p ...
- PMP考试
今天是第二次PMP模拟考试,得了146分,比上次高25分,这次题目相对简单些,看来昨晚的复习没有白费,还是有效果的. 有些题目影响还是比较深刻,老外的项目管理思想是先规划好一切再执行(管理),比如信息 ...
- 机器学习实战4:Adaboost提升:病马实例+非均衡分类问题
Adaboost提升算法是机器学习中很好用的两个算法之一,另一个是SVM支持向量机:机器学习面试中也会经常提问到Adaboost的一些原理:另外本文还介绍了一下非平衡分类问题的解决方案,这个问题在面试 ...
- XAF 如何基于业务规则禁用属性
// Developer Express Code Central Example: // How to: Disable Property Editors Based on a Business R ...
- python学习笔记之基础一(第一天)
1. python字符介绍 在C语言中没有字符串,只有字符 在python中的字符串hello,在C语言中是以字符数组在内存存放['h','e','l','l','o'],如果对字符串修改,则是在内存 ...
- Oracle Partition By 的使用
1.概述 Parttion by 关键字是Oracle中分析性函数的一部分,它和聚合函数不同的地方在于它能够返回一个分组中的多条记录,儿聚合函数一般只有一条反映统计值的结果. 2.使用方式 场景:查询 ...
- C# 隐藏标题栏 调整大小 并且移动窗口
隐藏标题栏(窗口属性): 1.设置在该窗体的标题栏中是否显示控件框: this.ControlBox = false; 2.设置在该窗体的标题为空: this.Text = string.Empty; ...