I'm fairly new to COM programming so please excuse if this is a stupid question.
After (successfully) creating a COM object using CoCreateInstance or CoCreateInstanceEx with class context CLSCTX_LOCAL_SERVER is there any way to tell if this call caused a new process to be spawned?
Related
I have implemented a COM automation interface for my application (which is in C++). The application is automated via VBScript.
My question pertains to error handling in the VB script. Some argument values are considered invalid by my implementation of the COM interface, which returns E_INVALIDARG to indicate this. When this occurs, the VB script displays a message box and terminates. Is there a way to handle the error in VB Script (maybe catch an exception somehow?) and avoid the script from terminating?
Using Visual c++ 6.0, I have created an ATL based .EXE server .
(VC6 as I am dealing with legacy code, a .exe server as I need to test operation in an out of process context, currently the .exe server is essentialy a no op)
I have built and registered the corresponding proxy stub DLL.
I have a client app that does
CoCreateInstance of IUnknown which invokes FinalConstruct in server object and succeeds (so server is correctly invoked)
OleRun of returned IUnknown interface succeeds
QueryInterface on IUnknown pointer for my server object fails with error code of 0x8000402 (No such interface supported) for the IMarshall interface
These steps were copied from (comip.h::CreateInstance)
The problem appears to be that the proxystub dll is not being invoked (it doesn't appear in the Modules list in the IDE, nor in loaded modules list in debug window)
The OleCom Object viewer for my class and interface can be seen here https://skydrive.live.com/redir?resid=AE43106917EBD9E1!191&authkey=!AIOWeS5P3o2mlpw
8891..ca4d is the class interface id for my object
A298...420c is the interface ID for my server object (IDispatch based)
TIA for any assistance
It's possible that your issue is that the component that is implementing the IRunnableObject interface isn't registering itself in the Running Object Table. This will mean that the CoCreateInstance itself will succeed, however, when the object it called on, the RPC code will be unable to find it.
This MSDN page indicates:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms694517(v=vs.85).aspx
Notes to Implementers
The object should register in the running object table if it has a
moniker assigned. The object should not hold any strong locks on itself;
instead, it should remain in the unstable, unlocked state. The object
should be locked when the first external connection is made to the object.
I'm a little worried about why you're also using the IMarshall interface. Normally it's not necessary to write custom marshaling code, thus you won't need to use this interface.
As long as you don't reference a custom interface the default marshaller in ole32.dll or oleauto32.dll will be used. That's most likely why you don't see your proxy being loaded.
In the case of most COM interfaces, the proxies and stubs for standard
marshaling are in-process component objects which are loaded from a
systemwide DLL provided by COM in Ole32.dll.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms692621(v=vs.85).aspx
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
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!
i'm developing a multi-platform C++ fuzzing application. The app spawns a child process and checks whether it stopped unexpectedly. I've already managed to do this on linux, however, windows exception handling mechanism is making things hard for me.
My code right now does the following:
- Call CreateProcess to spawn the process.
- WaitForSingleObject to wait for it to terminate.
- Then call GetExitCodeProcess and check if the exit code corresponds to an exception.
Everything works as it should, i've tested it with a null dereferencing test application, and i can catch the exception gracefully. However, each time i test this, a Windows error message box spawns telling me to Send or Not Send the error report. Since the fuzzer is supposed to be an automatic testing application, i'd need to somehow disable this notification, so that even if an exception is caught, the fuzzer can continue testing.
I've already tried installing a SEH handler, but had no luck(apparently these handlers aren't inherited by child processes). I've read something about using vectored exception handling, but suppose it would be the same, i believe vector handlers aren't inherited.
Could anybody help me with this problem? I don't know what to search for, i've already googled a lot and haven't found anyhing.
Thanks!
Debug API is one option. Here is a starting point in MSDN.
Following on frast's answer, you can spawn the process as a child of a process with a suitable SetErrorMode. This (inheritable) setting determines which errors will result in dialogs popping out - I found your question while trying to achieve the exact same thing for an automated testing application.
To avoid any error dialogs, use
SetErrorMode(
SEM_FAILCRITICALERRORS
| SEM_NOALIGNMENTFAULTEXCEPT
| SEM_NOGPFAULTERRORBOX
| SEM_NOOPENFILEERRORBOX);
Injection is probably overkill - better to use a wrapper process.
Try to inject the following code into your child process:
SetErrorMode(SEM_NOGPFAULTERRORBOX);
Lookup the details of SetErrorMode in MSDN.
Read about injection technique here:
Injective Code inside Import Table