首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >程序外程序Exe服务器

程序外程序Exe服务器
EN

Stack Overflow用户
提问于 2014-09-22 21:57:34
回答 1查看 1.1K关注 0票数 2

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

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

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

有人能告诉我这是自然的吗,还是我在封装ActiveX-Exe组件时做错了什么?

我是这样测试的:

代码语言:javascript
复制
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“中,声明为

代码语言:javascript
复制
Module Module1
    ''' <summary>
    ''' Get current process ID.
    ''' </summary>
    ''' <returns></returns>
    <DllImport("kernel32.dll")> _
    Public Function GetCurrentProcessId() As UInt32
    End Function

End Module

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

代码语言:javascript
复制
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
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-10-02 06:04:46

我已经找到了一个在我的开发环境中工作的解决方案。我从这里中选取了OP的示例项目,在评论中引用了该示例。我已经创建了一个新的 outofproc.zip,我希望它能为OP工作。我沿途所发现和学到的东西的一些历史如下。

我重新构建了VBExeComServer项目(该项目安装并注册了COM可执行文件)。我尝试用通过caller实例化SimpleObject的方法来使用OP的CreateObject("VBExeCOMServer.SimpleObject")项目,它的挂起方式与OP在注释中描述的方式相同。我觉得很困惑。

然后,我决定更深入地研究VBExeComServer项目。这基本上是OP在他的问题中发布的一个样本。由于这个项目是已知的工作,它很可能是环保的东西。经过一些尝试和错误和几个谷歌搜索,我发现了这个关于StackOverflow的问题。虽然这个问题没有得到答案,但我觉得所提供的信息似乎与我所经历的有些相似。它特别指出:

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

我发现hangs for a while的评论与我们看到的相当相似。当我试图使用Powershell实例化对象时,我也得到了相同的错误。尽管有迹象表明,他没有让它发挥作用,但我觉得有足够的证据来调查我们项目的设置。首先,VBExeComServer使用任意CPU作为平台类型。鉴于上面的节选,我决定修改项目,通过配置管理器创建'x64‘和'x86’平台选项。然后,我尝试构建x64,它未能注册可执行文件并构建类型库。我试过x86,它编译/注册了。我发现这个关于微软文章程序集的x64程序集使我走上了正确的轨道。特别是,它有以下指示:

为了解决这个问题,添加一个post build命令,使用以下步骤调用64位版本的RegAsm.exe。

  1. 项目属性中,选择“Build…”来自编译页
  2. 添加以下"%Windir%\Microsoft.NET\Framework64\v2.0.50727\regasm“post build命令行 "$(TargetPath)”

我没有使用他们推荐的内容,因为它将项目限制为只构建x64。我决定通过查看构建平台类型来增强这个想法。如果是x64,我会像上面那样使用Framework64正则表达式。不幸的是,VBExeComServer项目(由MS制作)默认假定32位程序集,而不是64位程序集,因为它们在生成后事件中使用了32位regasm。最后我在post-build events中使用了这个

代码语言:javascript
复制
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.

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

接下来,我进入了任务管理器(这很重要)。我删除了所有可能一直存在的旧的VBExeComServer进程。人们可以求助于重新启动窗户来确保。未能从内存中清除旧的可执行文件可能会导致未定义的行为。

那么现在caller (客户端)代码可以工作了吗?我把项目装填好了,运行得很好。我甚至对caller项目进行了修改,将其构建为x86x64Any CPU平台,并且它们都起了作用。他们都找到了一个与客户端进程的processid不相等的SimpleObject

特别注意事项:如果您希望caller项目正常工作,并且在64位系统上使用平台类型Any CPU,或者使用平台类型x64,则需要确保如上所述构建64位VBExeComServer。如果不这样做,就会导致我们所经历的悬念。

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

代码语言:javascript
复制
Private _Com As VBExeCOMServer.SimpleObject
_Com = New VBExeCOMServer.SimpleObject

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

其他人可能有一个想法,如何使这一工作的另一种方式。以下使用后期绑定

代码语言:javascript
复制
Private _Com As Object
_Com = CreateObject("VBExeCOMServer.SimpleObject")

CreateObject通过COM/Interop强制创建VBExeCOMServer.SimpleObject。如果它还没有运行,我们的COM服务器就会启动。一旦服务器运行以处理我们的请求,一个新的SimpleObject将被实例化。

前面引用的我的outofproc.zip文件已经用上面提到的所有项目进行了修改。至少在我的环境中,它确实能像预期的那样工作。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25983730

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档