[英]C# Running Active Automation Object - How to Source events?
我有一個用C#編寫的(長期運行)控制台應用程序,我希望它能夠通過COM進行操作(因此,沒有InProc DLL和regasm.exe)。 我只需要IDispatch
一個經典的OLE自動化對象。
在這里,我將介紹我嘗試做的最低版本。 我已經定義了這樣的COM類:
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[Guid("9009311a-c0b2-42a4-8e7c-f42091d71594")]
public interface ITestEvents {
void OnEvent();
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDispatch)]
[ComSourceInterfaces(typeof(ITestEvents))]
public class ComClass {
public event Action OnEvent;
public int Test() {
return 100;
}
}
在Main()
我只需使用"comTestApp"
Moniker在“運行對象表”(ROT)中注冊對象,然后使應用程序休眠。 您可以在此處查看完整的源代碼。
當我嘗試調用該對象的方法時,這很好用。 例如,此VBScript可以正常運行:
Set obj = GetObject("comTestApp")
WScript.Echo obj.Test() Rem prints 100
但是當我嘗試連接事件時:
Set obj = GetObject("comTestApp")
WScript.Echo obj.Test() Rem Works
WScript.ConnectObject obj, "obj_" Rem Fails
Sub obj_OnEvent
WScript.Echo "Wish it worked"
End Sub
我在調用ConnectObject
遇到錯誤(錯誤0x80020009“無法連接對象”)。
如果我使用regasm.exe將程序集注冊為InProc對象,則可以使用相同的代碼(只需添加類GUID / ProgID),但我不需要這樣做。 我需要訪問正在運行的應用程序,因此才使用ROT。
我創建了一個簡單的C ++測試,以查看是否可以找到有關該問題的更多信息。 來源在這里 。 我編寫了一個實現IDispatch
接口的最小COM對象,該接口應充當事件接收器。 首先,我從ROT獲取對象,查詢IConnectionPointContainer
,然后為ITestEvents
的IID獲取IConnectionPoint
,最后調用其Advise()
方法。 與VBScript一樣,它也會失敗(盡管我收到另一個錯誤-0x80040202)。 我在事件接收器的QueryInterface
方法上放置了一個斷點,以查看調用Advise()
時發生的情況。 我可以看到QueryInterface
被各種接口調用,最后它請求我的ITestEvents
,我返回並設置狀態S_OK
。 但是, Advise()
方法仍然返回上述錯誤。
我還嘗試了另一件事:我已將ITestEvents
的GUID設置為{00020400-0000-0000-C000-000000000046}
,這是IDispatch
的IID。 現在Advise()
返回S_OK
! 我什至模擬了一個事件,並且Invoke()
了事件接收器的Invoke()
方法! las,這通常不能解決問題。 如果您是通過IID直接從IConnectionPointContainer
請求的,則可以獲取它,但是ITypeInfo
似乎沒有對其進行正確枚舉,因此VBScript仍然無法正常工作。
我幾乎沒有COM方面的經驗,所以我不確定從這里去哪里。 如果我使用IDispatch
IID可以正常工作,這使我想知道ITestEvents
接口是否需要一些自定義封送處理,盡管它是純IDispatch
所以我認為應該在運行時很好地處理它。
謝謝!
我的結論是,不可能提供接口IID未在注冊表中注冊的連接接收器(到“進程外”對象)。
為了將接收器接口發送到服務器,似乎必須進行封送處理。 我希望由於C#類提供完整的ITypeInfo
,因此COM運行時將確定該接口是IDispatch
類型,並使用默認代理。 las,似乎並非如此,因此唯一的選擇仍然是-注冊表。
至少我發現這是必需的:
[HKEY_CLASSES_ROOT\Interface\{9009311a-c0b2-42a4-8e7c-f42091d71594}\ProxyStubClsid32]
@="{00020424-0000-0000-C000-000000000046}"
這定義了我們的事件接口,並說我們使用標准IDispatch代理作為代理。
我已經在Windows 7和10上對此進行了測試,並且可以正常工作! ConnectObject
可以使用ConnectObject
並且一切正常。
我偶然發現了一個Win7安裝程序,該安裝程序不起作用(win ver 6.1 build 7601 sp1)。 僅在注冊類型庫( regasm.exe /tlb
)后,此方法才有效。 有問題的安裝已禁用Windows Updates(我的其他Win7已完全更新),因此我猜有些地方已更改,這基於我們指定默認IDispatch代理的事實,即使沒有類型庫也可以封送接口。
最后,由於我想讓我的應用程序具有可移植性並且獨立於注冊表,因此我采用了手動事件實現。 在這里可以看到類似的東西。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.