C#运行主动自动化对象-如何源事件?
我有一个(长时间运行的)控制台应用程序,用C#编写,我希望能够通过COM操作它(因此没有InProc DLL和regasm.exe)C#运行主动自动化对象-如何源事件?,c#,com,ole-automation,active-objects,running-object-table,C#,Com,Ole Automation,Active Objects,Running Object Table,我有一个(长时间运行的)控制台应用程序,用C#编写,我希望能够通过COM操作它(因此没有InProc DLL和regasm.exe)IDispatch是我所需要的全部-因此是一个经典的OLE自动化对象 在这里,我将介绍我尝试做的一个最简单的版本。我定义了一个COM类,如下所示: [ComVisible(true)] [接口类型(ComInterfaceType.InterfaceIsIDispatch)] [Guid(“9009311a-c0b2-42a4-8e7c-f42091d71594”)
IDispatch
是我所需要的全部-因此是一个经典的OLE自动化对象
在这里,我将介绍我尝试做的一个最简单的版本。我定义了一个COM类,如下所示:
[ComVisible(true)]
[接口类型(ComInterfaceType.InterfaceIsIDispatch)]
[Guid(“9009311a-c0b2-42a4-8e7c-f42091d71594”)]
公共接口设备{
void OnEvent();
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDispatch)]
[ComSourceInterfaces(类型(ITestvents))]
公共课{
公共事件行动事件;
公共int测试(){
返回100;
}
}
在Main()
中,我只需使用“comTestApp”
名字对象在运行对象表(ROT)中注册对象,然后休眠应用程序。
您可以看到完整的源代码
当我尝试调用对象的方法时,这一切都很好。例如,此VBScript工作正常:
Set obj=GetObject(“comTestApp”)
WScript.Echo obj.Test()Rem打印100
但当我尝试连接事件时:
Set obj=GetObject(“comTestApp”)
WScript.Echo obj.Test()Rem有效
WScript.ConnectObject obj,“obj_”Rem失败
子对象事件
Echo“希望它能工作”
端接头
调用ConnectObject
时出错(错误0x80020009“无法连接对象”)
如果我使用regasm.exe将程序集注册为InProc对象,则相同的代码(只需添加类GUID/ProgID)也可以工作,但我不需要这样做。我需要访问正在运行的应用程序,这就是我使用ROT的原因
我创建了一个简单的C++测试,看看我能否发现更多的问题。消息来源是。我已经编写了一个最小的COM对象来实现IDispatch
接口,它应该充当事件接收器。首先,我从ROT中获取对象,查询IConnectionPointContainer
,然后获取ITestvents
的IID的IConnectionPoint
,最后调用其advice()
方法。与VBScript一样,它失败了(尽管我收到另一个错误-0x80040202)。我在事件接收器的QueryInterface
方法上放置了一个断点,以查看调用advice()
时会发生什么。我可以看到对各种接口调用了QueryInterface
,最后它请求我的ITestEvents
,我返回并设置状态S_OK
。但是,advice()
方法仍然返回上述错误
我还尝试了另一件事:我将ITestEvents
的GUID设置为{00020400-0000-0000-C000-0000000000 46}
,这是IDispatch
的IID。现在advice()
返回suok
!我甚至模拟了一个事件,调用了事件接收器的Invoke()
方法!唉,总的来说,这并不能解决问题。如果您通过IID直接从IConnectionPointContainer
请求它,您会得到它,但它似乎没有被ITypeInfo
正确枚举,VBScript仍然无法工作
我几乎没有使用COM的经验,所以我不确定从这里可以走到哪里。事实上,如果我使用IDispatch
IID,它就可以工作,这让我怀疑ITestvents
接口是否需要一些自定义封送处理,尽管它是纯IDispatch
,所以我认为运行时应该很好地处理它
谢谢大家! 我的结论是,不可能提供接口IID未在注册表中注册的连接接收器(到进程外对象) 为了将接收器接口发送到服务器,封送信息似乎是必需的。我希望由于C#类提供了完整的
ITypeInfo
,COM运行时会发现接口是IDispatch
类型,并使用默认代理。唉,情况似乎并非如此,因此唯一的选择仍然存在——注册表
至少我发现这是必要的:
[HKEY_CLASSES_ROOT\Interface\{9009311a-c0b2-42a4-8e7c-f42091d71594}\ProxyStubClsid32]
@="{00020424-0000-0000-C000-000000000046}"
这定义了我们的事件接口,并表示我们使用标准IDispatch代理作为代理
我已经在Windows7和10上测试过了,它可以正常工作VBScript可以ConnectObject
并且一切正常
我无意中发现了一个Win7安装,但它不起作用(win ver 6.1 build 7601 sp1)。它仅在注册类型库(regasm.exe/tlb
)后才起作用。所讨论的安装已禁用Windows更新(我的另一个Win7已完全更新),因此我猜在某个点上发生了更改,这使得即使没有类型库,也可以封送接口,因为我们指定了默认的IDispatch代理
最后,由于我想保持我的应用程序的可移植性和独立于注册表,我求助于手动事件实现。可以看到类似的情况。不清楚OneEvent在脚本代码中是如何变成OnUpdate的。目前还不清楚obj是否用events正确声明。我们也无法判断您是否使用/tlb选项注册了服务器。@HansPassant抱歉,我在OneEvent/Update中犯了错误。修好了。VBScript中没有WithEvents。不,我没有向/tlb注册,因为我希望应用程序是可移植的exe,不依赖于注册表。但事实证明这是不可能的。我有点明白了。我很快会在这里写下我自己的答案来澄清。