【问题标题】:Events raised in .net code is does not seem to occur in COM code when deployed with Side by side manifests当与并行清单一起部署时,.net 代码中引发的事件似乎不会在 COM 代码中发生
【发布时间】:2020-08-27 15:38:18
【问题描述】:

这是一个非常简单的 .net 使用事件的 COM 互操作示例。

只要我在 .net 库的 Visual Studio 构建选项中使用 regasm 或 register for com interop 选项,此示例就可以正常工作。 但我需要使用启用免注册互操作的并排清单进行部署。

应用程序在并排模式下运行得很好,只是事件似乎消失了。我怀疑这是一些线程编组问题,但我似乎找不到正确的解决方案。

这当然是试图复制我在稍微复杂的互操作集成中遇到的问题。与实际问题相比,我在这里遇到的问题有一个区别:

在无注册部署上运行时,这两种解决方案都无法正确接收 .net 代码中引发的事件,当 .net dll 在注册表中注册时,两种解决方案都可以正常工作。 但是:在“真实”项目中,当 System.Reflection.Target 失败时出现运行时错误。在这个简化的例子中,它只是默默地失败了。

我完全坚持这一点,因此非常欢迎任何和所有建议和解决方案。

如果有人在回答之前需要玩弄它,我已将完整代码放在 github 上:https://github.com/Vidarls/InteropEventTest

.net 部分

using System.Runtime.InteropServices;
using System.Threading.Tasks;

namespace InteropEventTest
{
    [Guid("E1BC643E-0CCF-4A91-8499-71BC48CAC01D")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [ComVisible(true)]
    public interface ITheEvents
    {
        void OnHappened(string theMessage);
    }

    [Guid("77F1EEBA-A952-4995-9384-7228F6182C32")]
    [ComVisible(true)]
    public interface IInteropConnection
    {
        void DoEvent(string theMessage);
    }

    [Guid("2EE25BBD-1849-4CA8-8369-D65BF47886A5")]
    [ClassInterface(ClassInterfaceType.None)]
    [ComSourceInterfaces(typeof(ITheEvents))]
    [ComVisible(true)]
    public class InteropConnection : IInteropConnection
    {
        [ComVisible(false)]
        public delegate void Happened(string theMessage);
        public event Happened OnHappened;


        public void DoEvent(string theMessage)
        {

            if (OnHappened != null)
            {
                Task.Factory.StartNew(() => OnHappened(theMessage));
            }
        }
    }
}

COM (VB6) 部分

Private WithEvents tester As InteropEventTest.InteropConnection

Private Sub Command1_Click()
    Call tester.DoEvent(Text1.Text)
End Sub

Private Sub Form_Load()
    Set tester = New InteropConnection
End Sub

Private Sub tester_OnHappened(ByVal theMessage As String)
    Text2.Text = theMessage
End Sub

我目前有以下用于部署的文件/文件夹结构:

Root
|-> [D] Interop.Event.Tester
    |-> Interop.Event.Tester.manifest
|-> [D] InteropEventTest
    |-> InteropEventTest.dll
|-> InteropEventTest.manifest
|-> InteropEventTest.tlb
|-> tester.exe
|-> tester.exe.manifest

清单文件的内容:

Interop.Event.Test.manifest

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

<assemblyIdentity name="Interop.Event.Tester" version="1.0.0.0" type="win32" processorArchitecture="x86"/>

</assembly>

InteropEventTest.manifest

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

<assemblyIdentity name="InteropEventTest" version="1.0.0.0" type="win32"/>

<clrClass
   name="InteropEventTest.InteropConnection"
   clsid="{2EE25BBD-1849-4CA8-8369-D65BF47886A5}"
   progid="InteropEventTest.InteropConnection"
   runtimeVersion="v4.0.30319"
   threadingModel="Both"/>

<file name="InteropEventTest.tlb">
 <typelib
     tlbid="{5CD6C635-503F-4103-93B0-3EBEFB91E500}"
     version="1.0"
     helpdir=""
     flags="hasdiskimage"/>
</file>
<comInterfaceExternalProxyStub 
    name="ITheEvents" 
    iid="{E1BC643E-0CCF-4A91-8499-71BC48CAC01D}"
    proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"
    baseInterface="{00000000-0000-0000-C000-000000000046}"
    tlbid="{5CD6C635-503F-4103-93B0-3EBEFB91E500}" />
</assembly>

tester.exe.manifest

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

<assemblyIdentity name="tester.exe" version="1.0.0.0" type="win32" processorArchitecture="x86"/>

<dependency>
 <dependentAssembly>
  <assemblyIdentity name="InteropEventTest" version="1.0.0.0" type="win32"/>
 </dependentAssembly>
</dependency>

<dependency>
 <dependentAssembly>
  <assemblyIdentity name="Interop.Event.Tester" version="1.0.0.0" type="win32" processorArchitecture="x86"/>
 </dependentAssembly>
</dependency>

</assembly>

【问题讨论】:

    标签: c# vb6 com-interop


    【解决方案1】:

    经过很长一段时间(以及几次失败的尝试),结果证明我可以通过做一个微小的改变来完成这项工作:

    将 VB6 代码编译为 P-Code 而不是本机代码。

    我很确定这会以某种方式影响线程之间的编组处理方式,但我一直无法找到任何证实该理论的信息。

    至少它有效......

    还是不行! (2013 年 10 月 24 日)

    事实证明,在现实生活中编译成 P-Code 是不够的。在此模式的另一个实现中,我们以事件消失告终,没有例外(我们认为),也没有任何痕迹。 因此需要进行更多调查:

    1.真正的问题

    将事件触发包装在 try-catch 子句中表明实际上有一个异常被抛出,它只是从未出现在任何地方

    if (OnHappened != null)        
    {  
      try 
      {
        OnHappened(theMessage));
      }
      catch (Exception e)
      {
        Messagebox.Show(e.GetType().Name + " : " +  e.message)
      }
    }
    

    例外是TargetException (the object does not match the target type)。一些研究表明,这很可能是线程问题(正如我之前所怀疑的那样。)

    2。解决方案

    关于这个问题的大部分文章似乎都通过使用 Invoke 方法解决了这个问题。事实证明,大多数其他试图解决这个问题的人都是在构建 winforms 应用程序,因此在所有表单和控件上都有一个方便的 Ìnvoke(Delegate) 方法。

    由于 Winforms 在幕后也做了相当多的 COM 互操作(根据现在已被遗忘的 google 结果列表中的文章),invoke 方法用于确保在创建给定组件,从而确保它发生在消息泵送的 UI 线程上。

    我认为这也可能与我的案件有关,所以我作弊了。

    我让我的互操作类继承自 winforms 控件

    public class InteropConnection : Control, IInteropConnection
    

    现在我将调用封装在 Invoke 方法中

    if (OnHappened != null)        
    {  
      try 
      {
        Invoke(OnHappened, theMessage);
      }
      catch (Exception e)
      {
        Messagebox.Show(e.GetType().Name + " : " +  e.message)
      }
    }
    

    现在我遇到了一个异常,因为控件没有分配 WindowHandle

    事实证明,Control 类有一个方便的CreateHandle() 方法,可以调用并解决这个特定问题。 (我不知道这有什么可能的后果,as the documentation does not recommend calling this method directly

    现在一切似乎一直在工作,但如果现在有新的东西跳起来咬我,我不会感到惊讶......

    【讨论】:

    【解决方案2】:

    我遇到了同样的问题。 COM 可以将事件/调用编组到正确的线程,但它需要有一个代理存根。如果您使用带有 regasm 的 /tlb 选项,这些将添加到注册表中,并且清单文件中的等效元素是元素 typelibcomInterfaceExternalProxyStub。 VB6 可执行文件可以编译为本机二进制文件。

    有关更多信息,请参阅我的 SO 主题:Regfree COM event fails from other thread

    【讨论】:

    • 谢谢,我在清单中使用代理存根,但我无法让它工作。试试看我能不能用你的方法让它工作。
    【解决方案3】:

    我们遇到了同样的问题。 在我们的例子中,我们必须将 proxyStubClsid32 更改为 {00020420-0000-0000-C000-000000000046}。

    注意:一位数有变化!

    更多信息在这里:http://www.mazecomputer.com/sxs/help/proxy.htm

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-08
      • 1970-01-01
      • 2017-12-22
      • 1970-01-01
      • 1970-01-01
      • 2021-10-28
      相关资源
      最近更新 更多