.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. iOS设置cell选中时文字颜色的变化

    cell.titleStr.highlightedTextColor = EMCGreenColor;

  2. jqGrid设置指定行的背景色

    1.在页面中加样式 <style type="text/css"> .SelectBG{ background-color:#AAAAAA; } </style& ...

  3. linux遇到 软件包系统已损坏 怎么解决

    软件包系统已损坏检查您是否使用了第三方源.如果是就禁用它们,它们常常导致问题. 然后在终端中运行以下命令:apt-get install -f 如果遇到以上问题 输入以下命令可以解决 sudo apt ...

  4. C++11基于范围的for循环

    C++11包含一种新的 for 循环,称为基于范围的 for 循环,可以简化对数组元素的遍历.格式如下: for(Type VarName : Array){ //每个元素的值会依次赋给 VarNam ...

  5. Azure VM上传小文件

    因为需要传一些脚本到Azure的VM里,有个简单方法可以实现,如下 编辑这个rdp文件 点击确定,连接远程计算机 可以在我的电脑里看到本地硬盘

  6. select in 在postgresql的效率问题

    在知乎上看到这样一个问题: MySQL 查询 select * from table where id in (几百或几千个 id) 如何提高效率?修改 电商网站,一个商品属性表,几十万条记录,80M ...

  7. YbSoftwareFactory 代码生成插件【十五】:Show 一下最新的动态属性扩展功能与键值生成器功能

    YbSoftwareFactory 各种插件的基础类库中又新增了两个方便易用的功能:动态属性扩展与键值生成器,本章将分别介绍这两个非常方便的组件. 一.动态属性扩展 在实际的开发过程中,你肯定会遇到数 ...

  8. python学习笔记之迭代器和函数(第三天)

    一.collection系列: 1.counter计数器 如果counter(dict)是对字典的一个补充,如果counter(list)则是对列表的补充,初步测试对字典的值进行排序. ####### ...

  9. IntelliJ IDEA 12.0 +Maven 初使用 - WEB项目的建立

    新建项目 1.Fiew菜单 - New Project,选择Maven Module项,输入Project name,选择项目所在的路径,选择SDK,其余默认即可,点击Next按钮

  10. 老电脑如果从windows7升级到windows10不断重启进不了系统,还是想用windows10,怎么办?

    先说一下我的配置:08年的acer aspire 5520g,很老的电脑,除了内存加到4g,其他都不变.官方只支持到windows7,并且官方说明该型号不在官方支持windows10之列. 之前win ...