概述
由于自 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样式通知的工具库