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

完毕,希望对大家有用!

转载于:https://www.cnblogs.com/tianqiq/p/4538194.html

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值