How to determine the association between a VB6 app and an exe instanced with CreateObject() - 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.

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.

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:
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).
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).

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!

Related

Start and monitor multiple instances of one process in Windows

I have a Windows application of which I need multiple instances running, with different command line parameters. The application is quite unstable and tends to crash every 48 hours or so.
Since manual checking for failure and restarting in case of one isn't what I love to do I want to write a "manager program" for this. It would launch the program (all its instances) and then watch them. In case a process crashes it would be restarted.
In Linux I could achieve this with fork()s and pids, but this obviously is not available in Windows. So, should I try to implement a CreateProcess version or is there a better way?
When you call CreateProcess, you are returned a handle to the new process in the hProcess member of the process information struct that you pass to CreateProcess. You can use this handle to detect when the process terminates.
For instance, you can create another thread and call WaitForSingleObject(hProcess) and block until the process terminates. Then you can decide whether or not to restart it.
Or your could call GetExitCodeProcess(hProcess, &exitcode) and test exitcode. If it has the value STILL_ACTIVE then your process has not terminated. This approach based on GetExitCodeProcess necessitates polling.
If it can be run as a daemon, the simplest way to ensure it keep running is Non-Sucking Service Manager.
It will allow to run as win32 service applications not designed as services. It will monitor and restart if necessary. And the source code is included, if any customization is needed.
All you need to do is define each of your instances as a service, with the required parameters, at it will do the rest.
If you have some kind of security police limitation and can't use third party tools, then coding will be necessary. The answer from David Heffernan gives you the appropiate direction.
Or it can be done in batch, vbs or js without need of anything out of the system. WMI Win32_Process class should allow you to handle it.

Handling Windows shutdown with out of process ActiveX EXEs

We have an application that uses several out of process COM objects for various tasks.
If the user tells Windows to shut down while our application is running, then it sends all applications (top level windows) a shutdown notification, but the OoP COM objects can shut down before the parent is notified and gets chance to shut down cleanly, causing various errors in different components.
This is made worse as one of the OoP objects was created to host an unstable 3rd party object so it's automatically restarted when it crashes which now fails to restart as Windows is shuttting down.
While we can handle the errors on the parent processes, Is there a way for the ActiveX hosts to tell Windows "I'm not shutting down just yet, but will do in due course", or even better, make Windows not notify them in the first place?
Both the parent processes, the OoP objects and their hosts are in a mixture of C++ and VB6.
Several ways to do this. Your OOP server could just ignore the shutdown request, relying on the client shutting down and remove all reference counts. You probably do want to set a flag so that you'll know to immediately shutdown when the last object is released, a server normally keeps running for a while.
Or you could call SetProcessShutdownParameters() in the OOP server. Pass a level you got from GetProcessShutdownParameters() minus 1 so that the client always gets the shutdown notification before the server. Also works with OOP servers that don't have a hidden toplevel window to get the Windows message.

long running process vb.net

I have a service ticket management application and users want to open several ticket details on a tab in a MDI frame. Since this application has to communicate through Web XML service with other company, it takes around 15 ~20 seconds. The users most complain is that he needs to wait until a saving process is done. Cursor is working while data is being saved and other can't be done.
What is the most effective way to let user open other window and do something else or save data while data is being saved from other windows?
By the way, this is VB.Net / Windows Application.
You could use a BackgroundWorker or new thread. I personally would try using built in asynchronous methods, such as BeginInvoke
http://www.developer.com/net/vb/article.php/1443981/Asynchronous-Web-Services-for-Visual-Basic-NET.htm
Keep in mind that asynchronous operations become complicated very quickly, good desighned in very important.
Use BackgroundWorker ...
Refer to the following:
Manage a background process by using the BackgroundWorker component
I've written a web service which is part of a solution which needs to go off and run a method which takes quite a long while to run through. After some experimenting, I decided it was simplest to kick off the long running task in a new thread within the web service and return a custom object to the calling application (which is then used later).
<WebMethod()> Public Function StartChecks() As ResponseItem
Dim t As New Thread(New ThreadStart(AddressOf Me.StartWork))
t.Start()
Return New ResponseItem(CheckGUID.ToString)
End Function

Remove the process from task manager

Sometimes ActiveX EXE object still remains in task manager even after the object is set to nothing in Client application.
Is there any way to smoothly terminate an Activex thread?
If the ActiveX object is appearing in task manager as a separate process then it must be an out of process COM server, not hosted in a thread in your application.
I can think of two obvious reasons why the server would still be running after your client has released its instance:
Something else still holds a reference (either your process or another)
The server was implemented incorrectly and does not shut down when all references are released

Is it true that COM services can't be used by multiple programs at the same time?

Before the application terminates its
execution, COM must be shut down
again. (Failure to shut down COM could
result in execution errors when
another program attempts to use COM
services .)
The above quote implies that, right?
No it doesn't.
If you fail to properly release all references to an out of process COM server and correctly close down COM it could lead to that instance of that service being in an odd state (everything should be OK after releasing all references, but sometimes COM might cache part of the out of process marshalling layer).
An out of process COM service can be designed to have separate component instances for each client (within or across services) that are completely independent (even if hosted in the same process), in which case it is hard to see how a failure of one client would affect other instances (other than wasting memory on instances until COM finally times them out). If the instances share state they can of course interfere even if the clients operate perfectly to the rules.
It is rather important that you quote the source of that quote so we can get the context. As near as I can see, you got that from a book about DirectShow programming. What it actually refers to is the need to call CoUninitialize().
Yes, that's kinda important. A thread should call CoInitializeEx() to initialize the COM infrastructure before it starts using any of the COM API functions. You really should call CoUninitialize() when that threads ends so stuff is properly cleaned up. Typically at the end of your program's main() function. Failure to do so may make another app fail when it finds a register class factory that in fact is dead.
This otherwise has nothing to do with a COM out-of-process server having to restrict itself in any way. You specify sharing mode with the REGCLS argument to CoRegisterClassObject(). Of course, a server should not exit and call CoUninitialize until all its objects are released.

Resources