簡體   English   中英

C#運行Active Automation對象-如何生成事件?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM