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

完毕,希望对大家有用!

.net比较完美的动态注册com组件的更多相关文章

  1. Vue动态注册异步组件(非同一个工程的组件)

    前言:最近在掘金逛的时候,无意中看到前滴滴前端架构黄轶大佬,看到了大佬分享的一篇博客滴滴 webapp 5.0 Vue 2.0 重构经验分享 ,对于其中第5个问题(异步加载的业务线组件,如何动态注册? ...

  2. react根据传参的不同动态注册不同的子组件

    上一篇文章介绍了关于Vue如何根据传参的不同动态注册不同的子组件,实现过程请查阅Vue.extend动态注册子组件,由Vue的这个功能我就自然联想到了使用react该如何实现同样的功能呢.其实,用re ...

  3. 插件占坑,四大组件动态注册前奏(三) 系统BroadCast的注册发送流程

    转载请注明出处:http://blog.csdn.net/hejjunlin/article/details/52204143 前言:为什么要了解系统Activity,Service,BroadCas ...

  4. 插件占坑,四大组件动态注册前奏(二) 系统Service的启动流程

    转载请注明出处:http://blog.csdn.net/hejjunlin/article/details/52203903 前言:为什么要了解系统Activity,Service,BroadCas ...

  5. 插件占坑,四大组件动态注册前奏(一) 系统Activity的启动流程

    转载请注明出处:http://blog.csdn.net/hejjunlin/article/details/52190050 前言:为什么要了解系统Activity,Service,,BroadCa ...

  6. 使用ServletContainerInitializer动态注册组件

    1.背景 在web容器(例如tomcat)启动时为提供给第三方组件机会做一些初始化的工作,例如注册servlet或者filtes等.对此servlet规范提供了ServletContainerInit ...

  7. Android开发4: Notification编程基础、Broadcast的使用及其静态注册、动态注册方式

    前言 啦啦啦~(博主每次开篇都要卖个萌,大家是不是都厌倦了呢~) 本篇博文希望帮助大家掌握 Broadcast 编程基础,实现动态注册 Broadcast 和静态注册 Broadcast 的方式以及学 ...

  8. Android so lib库远程http下载和动态注册

    一.背景 在开发Android应用程序的实现,有时候需要引入第三方so lib库,但第三方so库比较大,例如开源第三方播放组件ffmpeg库, 如果直接打包的apk包里面, 整个应用程序会大很多.经过 ...

  9. Android实现AppWidget、Broadcast动态注册

    Android实现AppWidget.Broadcast动态注册 开发工具:Andorid Studio 1.3 运行环境:Android 4.4 KitKat 工程内容 主界面可以编辑广播的信息,点 ...

随机推荐

  1. Infinite V1 Release Note

      游戏地址 PLAY 玩法说明 WASD 控制角色移动 更新内容 - 初步完成了角色移动(攻击状态) 开发心得 独立做游戏 其实最耽误时间的就是在自己的短板上, 对于我来说 就是3D建模和动作制作. ...

  2. tk画图

    Page 387 of chapter 7 """ 6-23 page 343 play media files """ def odd() ...

  3. Mac下好用的编辑器VIM GUI版本 VimR 推荐

    vim号称是编辑器之神,轮其功能和扩展性的确少有编辑器能比,但是大多数编辑器都有的文件浏览功能它确没有,虽然有些插件可以实现,但用起来都不是很方便,偶然发现了一个GUI版本的VIM,与普通的GUI版本 ...

  4. table 边框显示

    .td{border:solid #add9c0; border-width:0px 1px 1px 0px;}.table{border:solid #add9c0; border-width:1p ...

  5. PMP考试

    今天是第二次PMP模拟考试,得了146分,比上次高25分,这次题目相对简单些,看来昨晚的复习没有白费,还是有效果的. 有些题目影响还是比较深刻,老外的项目管理思想是先规划好一切再执行(管理),比如信息 ...

  6. 机器学习实战4:Adaboost提升:病马实例+非均衡分类问题

    Adaboost提升算法是机器学习中很好用的两个算法之一,另一个是SVM支持向量机:机器学习面试中也会经常提问到Adaboost的一些原理:另外本文还介绍了一下非平衡分类问题的解决方案,这个问题在面试 ...

  7. XAF 如何基于业务规则禁用属性

    // Developer Express Code Central Example: // How to: Disable Property Editors Based on a Business R ...

  8. python学习笔记之基础一(第一天)

    1. python字符介绍 在C语言中没有字符串,只有字符 在python中的字符串hello,在C语言中是以字符数组在内存存放['h','e','l','l','o'],如果对字符串修改,则是在内存 ...

  9. Oracle Partition By 的使用

    1.概述 Parttion by 关键字是Oracle中分析性函数的一部分,它和聚合函数不同的地方在于它能够返回一个分组中的多条记录,儿聚合函数一般只有一条反映统计值的结果. 2.使用方式 场景:查询 ...

  10. C# 隐藏标题栏 调整大小 并且移动窗口

    隐藏标题栏(窗口属性): 1.设置在该窗体的标题栏中是否显示控件框: this.ControlBox = false; 2.设置在该窗体的标题为空: this.Text = string.Empty; ...