进程外 Exe 服务器 [英] Out-Of-Proc Exe Server

查看:25
本文介绍了进程外 Exe 服务器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am using the example code for creating an ActiveX-Exe COM server in VB.Net:

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

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

When I call the GetCurrentProcessID from within the Active-X-Exe, it returns the same ID as the calling application.

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

Can somebody tell me if that is natural or whether I did something wrong in encapsulating the ActiveX-Exe component?

我是这样测试的:

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"被声明为

In the calling application "GetCurrentProcessID" is declared as

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 中,它是这样声明的:

In the Out-Of-Proc-COM-Server, it is declared like this:

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

推荐答案

我找到了一个适用于我的开发环境的解决方案.我从评论中引用的 here 中获取了 OP 的示例项目.我创建了一个 new outofproc.zip 我希望对 OP 有用.我在此过程中发现和学到的一些历史如下.

I have found a solution that works in my development environment. I took the OP's example project from here that was referenced in a comment. I have created a new outofproc.zip that I hope works for the OP. Some history of what I found and learned along the way follows.

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

I rebuilt the VBExeComServer project (which installed and registered the COM executable). I tried to use the OP's caller project with my method of instantiating a SimpleObject via CreateObject("VBExeCOMServer.SimpleObject") and it hung the same way the OP described in a comment. I found that puzzling.

然后我决定更彻底地研究 VBExeComServer 项目.它基本上与 OP 在他的问题中发布的样本相同.由于该项目有效,因此很可能与环境有关.经过一些反复试验和一些谷歌搜索,我发现了这个 StackOverflow 上的问题.虽然这个问题没有得到答案,但我觉得所提供的信息似乎与我所经历的有些相似.特别是它说:

I then decided to look at the VBExeComServer project more thoroughly. It is basically the same sample one the OP posted in his question. Since this project is known to work it was likely something environmental. After some trial and error and a few Google searches I found this question on StackOverflow. Although this question didn't get an answer I felt the information provided seemed somewhat similar to what I was experiencing. In particular it says:

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

I am trying to get COM to start my out-of-process .NET COM server. It works if the server process is compiled with x64, but if I use AnyCPU (which is what I want) then it hangs for a while and eventually fails with 0x80080005 (CO_E_SERVER_EXEC_FAILURE). How can I get this to work?

我发现 挂起一段时间 注释与我们看到的非常相似.当我尝试使用 Powershell 实例化对象时,我也遇到了同样的错误.虽然有迹象表明他没有让它工作,但我觉得有足够的东西来调查我们项目的设置.首先 VBExeComServer 使用 Any CPU 作为平台类型.鉴于上面的摘录,我决定通过配置管理器修改创建x64"和x86"平台选项的项目.然后我尝试构建 x64 它未能注册可执行文件并构建类型库.我试过 x86 并编译/注册.我发现这篇关于 x64 程序集的微软文章让我走上了正轨.特别是它有以下说明:

I found the hangs for a while comment rather similar to what we are seeing. I got the same error they did when I tried to use Powershell to instantiate the object too. Although indications are he didn't get it to work I felt there was enough to investigate the settings of our project. First off VBExeComServer was using Any CPU as a platform type. Given the excerpt above I decided to amend the project creating 'x64' and 'x86' platform options via the configuration manager. Then I tried to build the x64 it failed to register the executable and build a type library. I tried x86 and it compiled/registered. I found this Microsoft Article regarding x64 assemblies that got me on the right track. In particular it had these instructions:

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

To work around the problem, add a post build command to call the 64-bit version of RegAsm.exe using the following steps.

  1. 项目属性中,从编译页面中选择构建事件...".
  2. 添加以下构建后命令行%Windir%\Microsoft.NET\Framework64\v2.0.50727\regasm"$(TargetPath)"
  1. In the project properties, select "Build Events…" from the Compile page.
  2. Add the following post build command line "%Windir%\Microsoft.NET\Framework64\v2.0.50727\regasm" "$(TargetPath)"

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

I didn't use what they recommended since it would limit the project to only building x64. I decided to enhance this idea by looking at the build platform type. If it was x64 I would use the Framework64 regasm as above. Unfortunately, the VBExeComServer project (made by MS) assumed 32-bit assemblies by default not 64-bit since they used 32-bit regasm in the post build event. I ended up using this for the 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构建,并且它正确编译和注册.然后我做了 x86x64 构建.所有这些都按预期构建和注册.请注意,在构建 COM 服务器时,我以 管理员 身份运行 Visual Studio,以便 COM 注册过程具有更新整个注册表系统的适当权限.

I then tried building for platform Any CPU, and it compiled and registered properly. I then did x86 and then x64 builds. All of them built and registered as expected. Please note when building COM servers I run Visual Studio as administrator so that the process of COM registration has proper permissions to update the registry system wide.

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

Next I went into task manager (and this is important). I killed off all the old VBExeComServer processes that may have been laying around. One could resort to restarting windows to make sure. Failure to clean up old executables from memory could lead to undefined behavior.

那么 caller(客户端)代码现在可以工作了吗?我加载了项目并且运行良好.我什至修改了 caller 项目,将其构建为 x86x64Any CPU 平台,并且它们都有效.他们都发现SimpleObjectprocessid与客户端进程的不相等.

So now does the caller (client) code work? I loaded the project up and it ran fine. I even modified the caller project to be built as x86, x64 and Any CPU platforms, and they worked. All of them found a processid of the SimpleObject that was not equal to that of the client process.

特别说明:如果您希望 caller 项目能够工作并且您在 64 位系统上使用平台类型 Any CPU,或者使用平台类型 x64 您需要确保构建 64 位 VBExeComServer 如上所述.不这样做将导致我们遇到挂起.

Special note: If you want the caller project to work and you use platform type Any CPU on a 64-bit system, or use platform type x64 you will need to make sure you build a 64-bit VBExeComServer as above. Failure to do this will result in the hangs we experienced.

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

Next I restored the OP's early binding code:

Private _Com As VBExeCOMServer.SimpleObject
_Com = New VBExeCOMServer.SimpleObject

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

I had a hunch this would not load the out-of-proc-server via COM/Interop. I was right. When I restored these lines I was able to run the caller program but the Process IDs were the same. The reason for this is that the VB.Net COM object is created as an assembly that happens to provide an out of process COM Server. However if you try to import the EXE as a reference (or the TLB) it will tell you that you can't do it that way because it is a CLR assembly. When you do _Com As VBExeCOMServer.SimpleObject VB.Net will bypass all the COM/Interop code and add that executable as an assembly with direct access to the objects natively.

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

Someone else may have an idea how to make this work another way. The following uses late binding:

Private _Com As Object
_Com = CreateObject("VBExeCOMServer.SimpleObject")

CreateObject 通过 COM/Interop 强制创建 VBExeCOMServer.SimpleObject.如果它尚未运行,我们的 COM 进程外服务器将启动.一旦服务器运行以处理我们的请求,一个新的 SimpleObject 将被实例化.

CreateObject forces creation of VBExeCOMServer.SimpleObject through COM/Interop. If it isn't already running our COM out-of-proc server will be launched. Once a server is running to handle our request a new SimpleObject will be instantiated.

我之前引用的outofproc.zip 文件已用上述所有项目进行了修改.至少在我的环境中它确实按预期工作.

My outofproc.zip file referenced earlier has been amended with all the items mentioned above. At least in my environment it does work as expected.

这篇关于进程外 Exe 服务器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆