通常想到的固然是直接經過系統cmd 調用regsvr32註冊程序去註冊,以下:css
regsvr32 name.dll
在.net中能夠直接執行cmd命令以下:api
System.Diagnostics.Process.Start("regsvr32.exe","name.dll");
問題來了,那怎麼去檢查一個dll已經註冊了呢?不能每次都註冊吧!咱們知道每個com組件都有一個clsid,若是已經註冊了,那麼在系統註冊表裏面會有註冊信息的。 csharp代碼以下:ssh
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; }
彷佛經過上面的代碼已經解決了全部問題,可是我我的並不知足上面的方案,緣由以下:函數
那麼有麼有方法解決上面2個問題呢?答案固然是確定的! 經過查詢資料得知:
regsvr32 name.dll 實際上就是調用name.dll中的一個方法:DllRegisterServer。
在.net中咱們能夠經過pinvoke直接調用dll這個方法就能夠了,代碼以下:ui
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中方法的代碼以下:.net
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。 廢話也很少說。代碼以下code
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組件,並能判斷是否已經註冊。我簡單封裝一下代碼:orm
/// <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; } }
完畢,但願對你們有用!cmd