概述
由於自 netcore 3.0 以來,dotnet 將許多東西都在往 netcore 上般,甚至連 windows gui 的 Winform 和 WPF 都搬了過去,這看起來要放棄framework 的節奏啊,而且最新的vs還在大更新中支持了 netcore 的 windows 窗體設計器,而且 netcore 中的項目組織方式也變化了許多,最主要的就是可以通過配置項目文件同時生成多版本的庫(最近才知道,慚愧啊)。
預覽
這次搬遷的是以前的一個Windows 10 Toast Notification 模塊,這個模塊不是很大,但裏面用的工具類不是很常用,搬遷時就碰到了一個問題:
COM 註冊方法被 Net Core 團隊移除了 !去看 NetCore 團隊的 git 發現 System.Runtime.InteropServices 下的好多類都被刪除了,而且有一個也不知道是誰的回答(link),感覺應該不會再添加回去這個方法了。
var regService = new RegistrationServices();
regService.RegisterTypeForComClients(
typeof(T),
RegistrationClassContext.LocalServer,
RegistrationConnectionType.MultipleUse);
以我目前用到的功能,我覺得這個方法的作用就是將一個類型註冊到COM中,使你可以在其他進程中通過GUID去獲得一個這個類型的實例進行某種操作
當然,上面的回答中也給了代替解決方法 就是用 RunningObjectTable 來實現類型的註冊,也不知道是不是我這個應用環境比較特殊還是怎麼的,
[DllImport("Ole32.dll")]
public static extern void GetRunningObjectTable(int reserved,out IRunningObjectTable pprot);
[DllImport("Ole32.dll")]
static extern int CreateClassMoniker([In] ref Guid rclsid, out IMoniker ppmk);
IMoniker moniker;
IRunningObjectTable rot;
GetRunningObjectTable(0, out rot);
CreateMoniker([你的一個類型的GUID的ref],out moniker);
rot.Register(1, obj, moniker);
//這樣調用成功了以後好像沒有什麼用
好吧,我只能去找 RegisterTypeForComClients 的源碼,找到源碼後我直接呆了(ref):
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private static extern int RegisterTypeForComClientsExNative(Type t, RegistrationClassContext clsContext, RegistrationConnectionType flags);
//遇見這種方法在 NET 中就很難受了,因爲 framework 的 clr 沒有開源,而這個類剛好又是被core刪掉的類,所以就沒法找了
//不過這裏官方給了個提示 CoRegisterClassObject ,不過很可惜,這個方法的第二個參數沒什麼資料,這個也是卡了最久的地方
//只能在 PInvoke上找到
[DllImport("ole32.dll")]
static extern int CoRegisterClassObject(
[MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,
[MarshalAs(UnmanagedType.IUnknown)] object pUnk,
uint dwClsContext,
uint flags,
out uint lpdwRegister);
// IUnknown 也是一個 COM 類型
不過在差不多查了一天以後,終於還是有些收穫的 在 excel Dna 的 git 上發現了其一個使用實例,因此就進行了搬遷工作。
[ComImport]
[Guid(gstrIClassFactory)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IClassFactory
{
// For HRESULTs use
[PreserveSig]
HRESULT CreateInstance([In] IntPtr pUnkOuter,
[In] ref IID riid,
[Out] out IntPtr ppvObject);
[PreserveSig]
HRESULT LockServer([In, MarshalAs(UnmanagedType.VariantBool)] bool fLock);
// HRESULT STDMETHODCALLTYPE CreateInstance(
// /* [unique][in] */ IUnknown *pUnkOuter,
// /* [in] */ REFIID riid,
// /* [iid_is][out] */ void **ppvObject) = 0;
// virtual /* [local] */ HRESULT STDMETHODCALLTYPE LockServer(
// /* [in] */ BOOL fLock) = 0;
}
然後是繼承這個接口實現一個類 並在 CreateInstance 中返回你要創建類型的實例 (ref)
最後有一點不同的是在 exceldna 中,最後傳入 CoRegisterClassObject 的是
Marshal.GetIUnknownForObject(factory);
獲得的IUnknown接口,但在我這裏這個不好使,而直接傳入這個工廠類是好使的
最後我的項目 ToastHelper
碼雲
Github
是讓你的 net desktop app 發送win10樣式通知的工具庫