Out-Of-Proc服务器

时间:2014-09-22 21:57:34

标签: vb.net

我正在使用示例代码在VB.Net中创建ActiveX-Exe COM服务器:

http://code.msdn.microsoft.com/windowsapps/VBExeCOMServer-74ecdb1c

当我从Active-X-Exe中调用GetCurrentProcessID时,它返回与调用应用程序相同的ID。

有人可以告诉我这是否自然或者我是否在封装ActiveX-Exe组件时做错了什么?

我正在测试它:

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

    _MouseIndicator = New twsMouseIndicator.clsMouseIndicator
    With _MouseIndicator
        .ImagePath = "d:\dev\projects\osc\gui\autoclick\prog4.png"
        .Size = 300
        .Alpha = 155
        .FollowMouse = True
        .Active = True
    End With

    Dim iProcessIDOutOfProcID As Integer = _MouseIndicator.CurrentProcessID
    Dim iCallerProcessID As Integer = GetCurrentProcessId()

    If iProcessIDOutOfProcID = iCallerProcessID Then
        MessageBox.Show("ProcIDs are the same, namely " & iCallerProcessID & ". This can not be right!")
    Else
        MessageBox.Show("Everything is okay.")
    End If

End Sub

在调用应用程序“GetCurrentProcessID”中声明为

Module Module1
    ''' <summary>
    ''' Get current process ID.
    ''' </summary>
    ''' <returns></returns>
    <DllImport("kernel32.dll")> _
    Public Function GetCurrentProcessId() As UInt32
    End Function

End Module

在Out-Of-Proc-COM-Server中,声明如下:

Public Function CurrentProcessID() As UInt32

    Return NativeMethod.GetCurrentProcessId

End Function

 Friend Class NativeMethod

    ''' <summary>
    ''' Get current process ID.
    ''' </summary>
    ''' <returns></returns>
    <DllImport("kernel32.dll")> _
    Friend Shared Function GetCurrentProcessId() As UInt32
    End Function

1 个答案:

答案 0 :(得分:2)

我找到了一个适用于我的开发环境的解决方案。我从评论中引用的here中获取了OP的示例项目。我创建了一个 new outofproc.zip,希望能为OP工作。我沿途发现和学习的一些历史如下。

我重建了VBExeComServer项目(安装并注册了COM可执行文件)。我尝试使用OP的caller项目和我通过SimpleObject实例化CreateObject("VBExeCOMServer.SimpleObject")的方法,它的挂起方式与评论中描述的OP相同。我发现这令人费解。

然后我决定更彻底地查看VBExeComServer项目。它与OP在他的问题中发布的样本基本相同。由于这个项目已知可行,因此它可能具有环保性。经过一些试验和错误以及一些Google搜索后,我发现了question on StackOverflow。虽然这个问题没有得到答案,但我觉得所提供的信息似乎与我的体验有些相似。特别是它说:

  

我正在尝试让COM启动我的进程外.NET COM服务器。如果服务器进程使用x64编译,它可以正常工作,但如果我使用 AnyCPU (这就是我想要的),那么它挂起一段时间并最终以0x80080005(CO_E_SERVER_EXEC_FAILURE)失败。我怎样才能让它发挥作用?

我发现hangs for a while评论与我们看到的相似。当我尝试使用Powershell来实例化对象时,我得到了同样的错误。虽然有迹象表明他没有上班,但我觉得有足够的东西可以调查我们项目的设置。首先,VBExeComServer使用任意CPU 作为平台类型。鉴于上面的摘录,我决定修改项目,创建&#39; x64&#39;和&#39; x86&#39;平台选项通过配置管理器。然后我尝试构建 x64 它无法注册可执行文件并构建类型库。我尝试了 x86 并编译/注册。我发现这个Microsoft Article关于x64程序集让我走上正轨。特别是它有这些指示:

  

要解决此问题,请使用以下步骤添加post build命令以调用64位版本的RegAsm.exe。

     
      
  1. 项目属性中,从编译页面中选择“构建事件...”
  2.   
  3. 添加以下发布后命令行   &#34;%WINDIR%\ Microsoft.NET \ Framework64 \ V2.0.50727 \ regasm&#34; &#34; $(TARGETPATH)&#34;
  4.   

我没有使用他们推荐的内容,因为它会将项目限制为仅构建x64。我决定通过查看构建平台类型来增强这个想法。如果它是x64,我将使用上面的Framework64 regasm。不幸的是,VBExeComServer项目(由MS制作)假设默认情况下不是64位的32位程序集,因为它们在后期构建事件中使用了32位regasm。我最终将其用于post-build events

echo Generate and register type library.
if "$(PlatformName)" == "x64" (
    C:\Windows\Microsoft.NET\Framework64\v2.0.50727\regasm.exe /tlb "$(TargetPath)"
) else  (
    C:\Windows\Microsoft.NET\Framework\v2.0.50727\regasm.exe /tlb "$(TargetPath)"
)
echo Register the component.
if "$(PlatformName)" == "x64" (
    C:\Windows\Microsoft.NET\Framework64\v2.0.50727\regasm.exe "$(TargetPath)"
) else (
    C:\Windows\Microsoft.NET\Framework\v2.0.50727\regasm.exe "$(TargetPath)"
)
echo Generate and register type library.

然后我尝试构建平台Any CPU,并正确编译和注册。然后我做了x86然后x64构建。所有这些都按预期建造和注册。请注意,在构建COM服务器时,我将Visual Studio作为管理员运行,以便COM注册过程具有更新注册表系统范围的适当权限。

接下来我进入任务经理(这很重要)。我杀死了可能已经存在的所有旧的VBExeComServer进程。人们可以通过重新启动窗口来确保。无法从内存中清除旧的可执行文件可能会导致未定义的行为。

那么caller(客户端)代码现在有效吗?我加载了项目,运行正常。我甚至修改了要构建为callerx86x64平台的Any CPU项目,并且他们工作了。所有人都发现processid的{​​{1}}与客户流程的SimpleObject不同。

特别说明:如果您希望caller项目正常工作,并且您在64位系统上使用平台类型Any CPU,或使用平台类型{{1}您将需要确保如上所述构建64位x64。如果不这样做,将导致我们遇到的问题。

接下来,我恢复了OP的早期绑定代码:

VBExeComServer

我预感到这不会通过COM / Interop加载进程外服务器。我是正确的。当我恢复这些行时,我能够运行Private _Com As VBExeCOMServer.SimpleObject _Com = New VBExeCOMServer.SimpleObject 程序,但caller是相同的。原因是VB.Net COM对象被创建为一个恰好提供进程外COM服务器的程序集。但是,如果您尝试将EXE作为参考(或TLB)导入,它将告诉您不能这样做,因为它是CLR程序集。执行Process IDs时,VB.Net将绕过所有COM / Interop代码,并将该可执行文件添加为可直接访问对象的程序集。

其他人可能知道如何以另一种方式使这项工作。以下使用后期绑定

_Com As VBExeCOMServer.SimpleObject

Private _Com As Object _Com = CreateObject("VBExeCOMServer.SimpleObject") 强制通过COM / Interop创建CreateObject。如果它还没有运行我们的COM out-of-proc服务器将被启动。一旦服务器运行以处理我们的请求,将实例化新的VBExeCOMServer.SimpleObject

前面提到的我的SimpleObject文件已经修改了上面提到的所有项目。至少在我的环境中,它确实按预期工作。