Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/258.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#运行主动自动化对象-如何源事件?_C#_Com_Ole Automation_Active Objects_Running Object Table - Fatal编程技术网

C#运行主动自动化对象-如何源事件?

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”)

我有一个(长时间运行的)控制台应用程序,用C#编写,我希望能够通过COM操作它(因此没有InProc DLL和regasm.exe)
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,不依赖于注册表。但事实证明这是不可能的。我有点明白了。我很快会在这里写下我自己的答案来澄清。