如何确定 VB6 应用程序和使用 CreateObject() 实例化的 exe 之间的关联

发布于 2024-10-07 06:01:54 字数 512 浏览 0 评论 0原文

我们需要弄清楚服务如何查看正在运行的 VB6 应用程序和/或其 DCOM 生成的 exe,并找出哪个 VB6 应用程序与哪个 DCOM exe 配合使用。 VB6 应用程序和生成的 exe 均位于同一服务器上。

我们有一个 VB6 应用程序,它通过 CreateObject() 调用生成一个 Bartender 实例(来自 Seagull Scientific)。在给定的服务器上,我们可能有十到二十个应用程序实例,每个实例代表仓库中的手持式射频枪客户端。这些 VB6 应用程序中 95% 或更多都会有自己的 Bartender。

由于我们无法控制的情况,我们的 VB6 实例之一将被随机杀死,就像您使用任务管理器杀死它一样。这使得调酒师仍然活着并消耗资源。在几个小时或几天的时间里,大约有五十个调酒师被杀后,这些孤儿调酒师变得对资源的贪婪程度足以让服务器崩溃。

我们正在尝试开发一个观察者服务来检测哪些调酒师仍然处于连接状态,因此这项新服务可以杀死孤立的调酒师。我们试图在不更改 VB6 应用程序的情况下实现这一目标,但如果有必要,我们将修改我们的应用程序。

We need to figure out how a service can peek at a running VB6 app and/or its DCOM spawned exe and figure out which VB6 app goes with which DCOM exe. The VB6 app and the spawned exe are both on the same server.

We have a VB6 app that spawns an instance of Bartender (from Seagull Scientific) by way of a CreateObject() call. On a given server, we may have ten or twenty instances of our app, each represents a handheld RF gun client in a warehouse. 95% or more of these VB6 apps will have their own Bartender.

Due to circumstances beyond our control, randomly, one of our VB6 instances will be killed, just as if you killed it using Task Manager. This leaves it's Bartender still alive and consuming resources. After fifty or so have been killed over the course of a few hours or days, these orphaned Bartenders become enough of a resource hog to bring the server to its knees.

We are trying to develop a watcher service to detect which of the Bartenders are still connected, so this new service can kill the orphaned Bartenders. We are trying to accomplish this without changing our VB6 app, but we will modify our app if we have to.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

眼前雾蒙蒙 2024-10-14 06:01:54

我认为这个例程,恰当地命名为“谁是你的爸爸”,可能对你有用。它找出谁产生了这个过程。它可能无法解决您的全部问题,但这是一个开始。

I think this routine, aptly named Who's Your Daddy, might be of use to you. It figures out who spawned the process. It probably won't solve your entire problem, but it's a start.

_蜘蛛 2024-10-14 06:01:54

这即使不是不可能,也是很难做到的。进程外 COM 组件(即 ActiveX EXE)始终由 COM 服务控制管理器启动,而不是由调用 CreateObject 的进程启动。这就是为什么 ActiveX EXE 的父进程是 svchost.exe

因此,调用CreateObject的进程和被创建的进程之间不存在直接的父子关系。只有实际在两个进程之间来回传递方法调用的远程过程调用 (RPC) 层才知道所涉及进程的身份,但 RPC 机制是专门设计为对 COM 子系统透明的,并且没有获取我所知道的这些信息的简单方法。

然而,如果您愿意更改 VB6 应用程序,有一种相当黑客的方法可以处理孤立进程问题:

  1. 让您的监视器服务定期终止所有正在运行的 Bartender EXE(每天一次或无论如何)经常是必要的,以防止服务器速度减慢太多)。

  2. 为 Bartender 功能编写一个包装器 DLL,并让您的 VB6 类使用此包装器库,而不是直接实例化原始 Bartender 对象。该库将包含一个包装类,该类创建 Bartender 对象,并且具有委托给该对象的方法。每个包装器方法都应捕获错误 462(“远程服务器计算机不存在或不可用”),如果发生这种情况,请重新创建 Bartender 对象,然后重试该方法。

例如(我实际上没有查看 Bartender 文档,所以这只是演示这个想法):

'BartenderWrapper.cls

Private m_bartender As Object

Private Sub Class_Initialize()
   Set m_bartender = CreateObject("Bartender.Application")    
End Sub

Public Sub PrintLabel(Byval sLabelData As String)

    On Error Goto ErrorHandler

    m_bartender.PrintLabel sLabelData

    Exit Sub

ErrorHandler:

    If IsRpcError(Err) Then
       Set m_bartender = CreateObject("Bartender.Application")
       Resume
    End If

    Err.Raise Err.Number, Err.Source, Err.Description

End Sub

Private Function IsRpcError(Byval e As ErrObject) As Boolean
    IsRpcError = (e.Number = 462)
End Function

这里的想法是,由于您无法可靠地确定哪些 Bartender 进程仍然连接到 VB6 应用程序的实例,因此您可以可以定期终止所有正在运行的 Bartender 进程,并且您的应用程序仍然能够正常运行(在大多数情况下),因为如果您终止 VB6 应用程序的正在运行的实例正在使用的 Bartender EXE,您的应用程序将创建一个新的 Bartender 实例并继续正常运行。

这个解决方案绝对不是万无一失的,如果您使用很多方法或者您创建的 Bartender 实例具有重要的内部状态,在创建新实例时可能会丢失这些状态,那么可能很难实现。

归根结底,如果您不控制所涉及的所有应用程序,则没有一种干净的方法来检测孤立的 ActiveX EXE(当您确实控制 ActiveX EXE 时,这是一种常见的解决方案)是让 ActiveX EXE 每秒左右引发一个带有 ByRef 参数的事件,如果客户端不更改参数的值,则让它自行关闭)。

This is going to be hard, if not impossible, to do. Out-of-process COM components (i.e. ActiveX EXE's) are always started by the COM Service Control Manager, not by the process that called CreateObject. This is why the parent process for the ActiveX EXE is svchost.exe.

Therefore, there is no direct parent-child relationship between the process that calls CreateObject and the process that gets created. Only the remote procedure call (RPC) layer that actually passes method calls back and forth between the two processes knows the identities of the processes involved, but the RPC mechanism is specifically designed to be transparent to the COM subsystem, and there isn't an easy way to get access to this information that I know of.

However, there is a pretty hackish way to handle the orphaned process problem if you are willing to change the VB6 application:

  1. Have your monitor service periodically terminate all running Bartender EXE's (once a day or however often is necessary to prevent the server from slowing down too much).

  2. Write a wrapper DLL for the Bartender functionality, and have your VB6 class use this wrapper library instead of directly instantiating raw Bartender objects. This library would contain a wrapper class that creates a Bartender object, and that has methods that delegate to this object. Each wrapper method should catch error 462 ("The remote server machine does not exist or is unavailable"), recreate the Bartender object if this occurs, and then retry the method.

For example (I haven't actually looked at the Bartender documentation, so this is just demonstrating the idea):

'BartenderWrapper.cls

Private m_bartender As Object

Private Sub Class_Initialize()
   Set m_bartender = CreateObject("Bartender.Application")    
End Sub

Public Sub PrintLabel(Byval sLabelData As String)

    On Error Goto ErrorHandler

    m_bartender.PrintLabel sLabelData

    Exit Sub

ErrorHandler:

    If IsRpcError(Err) Then
       Set m_bartender = CreateObject("Bartender.Application")
       Resume
    End If

    Err.Raise Err.Number, Err.Source, Err.Description

End Sub

Private Function IsRpcError(Byval e As ErrObject) As Boolean
    IsRpcError = (e.Number = 462)
End Function

The idea here is that since you can't reliably determine which Bartender processes are still connected to an instance of your VB6 application, you can kill all of the running Bartender processes periodically, and your application will still be able to run properly (in most cases), because if you kill a Bartender EXE that was being used by a running instance of your VB6 application, your application will create a new Bartender instance and continue running normally.

This solution definitely isn't fool-proof, and may be hard to implement if you are using a lot of methods or the Bartender instance you create has important internal state that could be lost when creating a new instance.

When it comes down to it, there isn't a clean way to detect orphaned ActiveX EXE's if you don't control all of the applications that are involved (one common solution when you do control the ActiveX EXE is to have the ActiveX EXE raise an event with a ByRef parameter every second or so, and have it shut itself down if the client doesn't change the value of the parameter).

想念有你 2024-10-14 06:01:54

我们决定做的是让客户端在每次创建 Bartender 时编写一个提示文件。客户端在公共文件夹中写入一个微小的 XML 文件,该文件的 XML 内容相当于“我的 PID 号为 n。在时间 x 和时间 y 之间,我创建了一个调酒师”。时间 x 和 y 是在 CreateObject 调用之前和之后立即获取的时间戳。我们将有一个监控服务来监控新客户、新调酒师和提示文件。通过观察所有这些,我们认为我们可以创建客户及其相关调酒师的小组或协会。在任何给定的组中,当所有客户都离开时,该组中剩余的调酒师都可能被杀死!

What we have decided to do is to have the client write a hint file each time the Client creates a Bartender. The client writes a tiny XML file in a common folder that says an XML equivalent of "I am PID number n. Between time x and time y, I created a Bartender." The times x and y are timestamps obtained immediately before and after the CreateObject call. We will have a monitor service that watches for new Clients, new Bartenders and hint files. By watching all these, we think we can create small groups or associations of clients and their associated bartenders. In any given group, when all the clients go away, any remaining Bartenders that were in that group can be KILLED!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文