I am trying to decipher the paragraph below, taken from a blog post here which describes COM history in the context of the development for the Visual Studio IDE:
When everything was C++ native code, COM ensured that almost
everything happened on the main STA thread (i.e. the UI thread). If
code running in another apartment (e.g. a background thread) called
any of these COM components the background thread would block while
the call was re-issued on the main thread. This protected the COM
component from having to deal with concurrent execution, but left it
open to reentrancy (being invoked while in an outbound call). This
technique worked whether the caller was managed (automatically) or
native code (via the proxy stub that COM would generate for the
caller).
The questions I have:
What is the mechanism by which a call is re-issued on another thread? Can you give an example?
Is the problem mentioned as ‘concurrent execution’ the same as that of thread safety?
What is being invoked while on an outbound call?
Thank you.
Related
I am working on a OOB application that does document merging with MS Word.
I need to download the latest MS Word template files, and since this can take some time, I am trying to do so in the background.
Merely instantiating a domaincontext on any thread other than the UI thread throws a cross thread exception.
The easy fix would be to instantiate the domaincontext on the UI thread, but that would defeat the object. Any workarounds? Anything I'm missing?
Regards,
Derick
This is because the default constructor uses a relative url for the service. It needs to get the current application to find the base url. If you use one of the overloads that accepts urls and give it an absolute url it will work. (Hopefully :) ).
Pass the domaincontext as a paremater of RunWorkerAsync(context) and you should be ok. This then allows you to perform all query operations within the background thread.
From what I understand, when a COM component marked as using STA is used from an MTA thread, the calls are supposed to be marshalled to an STA thread and executed from that dedicated thread. In the case of a Windows client application, this would mean that it would execute on the UI thread (if marked as STA), and that callbacks from the COM component to me would be handled by Windows messages sent to a hidden window and processed on the Windows message loop.
What happens though if I use a STA COM component in a WCF service hosted in IIS? Will the worker process have a Windows message loop on a STA thread? Can I fire up my own STA thread with its own message loop?
The COM runtime looks after the dispatching of calls to methods on a COM object inside an STA: you are right that this is based on the same OS mechanism used for dispatching Windows messages, but you don't need to worry about making this happen - COM does this for you under the hood.
What you do need to worry about is which STA your COM objects are going to live in. If you instantiate apartment-threaded COM objects using COM Interop from a WCF service, you need to be careful.
If the thread on which you do this is not an STA thread, then all in-process COM objects will live in the default Host STA for the IIS worker process. You do not want this to happen: all your COM objects for all service operations will end up in this same STA. The clue is in the name - there is just one thread for all the objects - and all calls to their methods will be serialized waiting for the one and only thread in the apartment to execute them. Your service will not scale to handle multiple concurrent clients.
You need to make sure that COM objects you instantiate to service a particular WCF request are in their own STA separate from objects created for other requests. There are broadly two ways to do this:
Spin up your own Thread, specifying ApartmentState.STA in SetApartmentState() before you start it, on which to instantiate the COM objects for a particular request. This is the approach detailed by Scott Seely in the link in Kev's answer: he ensures that each service operation call is invoked on a new STA-initialised Thread. A harder but more scalable solution along these lines would be to implement a pool of reusable STA-initialised Threads.
Host your COM objects in a COM+ Application, so that they live in a separate DllHost process, where COM+ (through its abstraction called the Activity) can take care of putting the objects for different requests into different STAs.
I'm not sure exactly what you mean when you refer to callbacks. Perhaps you mean COM method calls on some COM interface implemented in your managed code, via a reference passed in to the COM objects as an argument to one of the COM objects' methods: if so, this should just work. But perhaps you mean something else, in which case perhaps you could amend the question to clarify.
I've found that you need to pump messages on your STA thread in a WCF service or you miss callbacks from the COM object.
The following code works, but it requires you call the COM object via a Dispatcher.
ComWrapper comWrapper;
Thread localThread;
Dispatcher localThreadDispatcher;
public Constructor()
{
localThread = new Thread(ThreadProc)
{
Name = "test"
};
localThread.SetApartmentState(ApartmentState.STA);
AutoResetEvent init = new AutoResetEvent(false);
localThread.Start(init);
init.WaitOne();
}
private void ThreadProc(object o)
{
localThreadDispatcher = Dispatcher.CurrentDispatcher;
((AutoResetEvent)o).Set();
comWrapper = new ComWrapper()
Dispatcher.Run();
localThreadFinished.Set();
}
And then make calls as follows.
public void UsefulComOperation()
{
localThreadDispatcher.Invoke(new Action( () => comWrapper.UsefulOperation);
}
We are adapting our client side relatively complicated application (ActiveX / .net / Delphi / C++ / COM ) to use SxS to achieve non admin deployment and isolation from older versions of our product.
We were able to achieve this goal for almost all our in proc components such as our .net ui, Delphi ui, and the COM servers we use in proc by composing a manifest file which described all the libraries used by our process, with no registration on the client of any of the components (almost).
And here comes the almost part:
At the moment, our application invokes (from it's c++ portion) an out of proc ActiveX server (Delphi ActiveX EXE), which in turn itself invokes another set of out of proc ActiveX servers (third party plugins, any thing goes here, Delphi, C++, any thing as long as it's out of proc ActiveX EXE and implements our interfaces).
As we know SxS does not support out of proc ActiveX servers. And we can't use these objects as in proc com servers in our main process because that would require a major rewrite of our application and even worst, a break of our public facing API which is used by third party tools and vendors, an api break which we can't allow.
We have stumbled on this article which describes how IHTMLDocument2 can be extracted from an Internet Explorer window running in a separate process. Which made us think of this approach:
We would create a secondary satellite application / process which will run the ActiveX as in process server.
Then we will use LresultFromObject and ObjectFromLresult to transfer a reference of the ActiveX object from the satellite application to the main application process. The satellite application will have it's own manifest file which will allow it to run in SxS mode.
Same approach will be taken to communicate between this Delphi ActiveX EXE and the third party AciveX EXE Plugins
There is an alternative solution, which for the moment we do not prefer over the proposed solution above which is to use .net remoting and .net com proxy classes to open the communication channel between the two processes, by translating the com request to .net remoting, and back to com on the second process.
So here comes the question:
What do you think about this approach ?
Do you see a better solution to the problem ?
It is possible to do. What is needed:
An application needs to start a server itself rather than relying on COM to do it. You don't need the extra indirection provided by the registry, just use CreateProcess().
A server should register its class factories in its main() method with CoRegisterClassObject().
Important: the CLSID it uses for each factory should be altered to be unique for each service instance. This ensures that the client connects to the correct server. I simply XOR the process ID with a class factory CLSID. The client knows the process ID as well so can make the same alteration.
The application should call CoCreateInstance() in a loop with a Sleep() call to wait for the object factory to appear. Don't declare failure until at least 60 seconds have passed (that bit me).
Both the application and the server need a manifest that contains a <file> element for each proxy/stub DLL and <comInterfaceExternProxyStub> elements for each interface that is remoted.
Alex,
nobugz is right, you can access the Running Object Table to create an instance of a COM Object from a currently running process of your Delphi automation exe.
However I have found a big issue that I cant explain. I can only access the object via the variant dispatch method when working this way.
Basically if my Active X exe is not registered, I get an "Interface Not Supported" error if I try to instance the object through interfaces for example:
WebUpdate : IAutomation;
WebUpdate := CoAutomation.Create; <-- Wont Work Error
WebUpdate : Variant;
WebUpdate := CreateOleObject('WebUpdate.Automation'); <-- Works Fine
If I register the active x exe using regserver the problem goes away!!
Go Figure!
I'm creating a Windows Console application written in VB.NET and I have a few processes that need to be called only once during the lifetime of the application. If it was an ASP.NET application, I put these in the Appliction_Start method of the Global.asax.vb file. Since there isn't a Global.asax.vb for Console applications, is there an event I could handle that allows me to call my functions before Main is called?
Is there a problem with just calling them first in main?
Main is the first method where you can grab the needed information / inizialize global stuff.
Why would you need an earlier point? The only thing that is different to Application_Start is that no other method is called automatically (unlike in a web application where the site is opened and the code executed).
We have a third party dll that is used in our web service hosted in IIS6. The problem is that once this dll is loaded into memory, the exception AccessViolationException gets thrown if a thread different then the one that created it tries to execute any code within the dll. The worker process is multi threaded and each call to the web service will get a random thread from the pool. We tried to unload it from memory and reload it each time we needed it, but I guess only the front end is .Net and the rest is unmanaged so it never actually gets completely unloaded from memory. We are using VB and .Net 2.0. Any suggestions?
(Response to Rob Walker)
We thought about creating a new thread and using it to call the dll, but how do we make the thread sit and wait for calls? How do you delegate the call to the thread without having the Dispatcher class supplied by .Net 3.0? Creating a hidden form and putting it in a message loop might work. And then we could call the Invoke() method of the form. But I can see many problems occurring if we create a form inside an IIS hosted web service.
I have read about a class in .net 3.0 called Dispatcher that allows you to put a thread in a loop and then call the method Invoke() using a delegate to execute a method using the thread. But this solution will not work if you cannot update to .Net 3.0. Another solution would be to host the third party dll in another application on the server and use some form of Remoting to access it. But you may still have a problem with the Remoting because it behaves similar to IIS and will also pick a random thread to execute the code . To get around this, you could put a wrapper around the dll and use it to delegate the calls to the UI thread by using the Invoke() method of the form.
I think you need to look at using a wrapper thread that handles all calls to the DLL, and deals with the serialization.
This thread is outside of the managed thread pool, so you control its lifetime. But even this would not be foolproof unless you can prevent IIS from restarting the app domain your web service is in.
You also need to worry about what happens when two web service requests come in at the same time. Is each call into the DLL standalone, or do you have to group together all the calls associated with a single web service request before allowing any other request to be serviced?
You could create a service that hosts the extra DLL. Via remoting you access the service, this will dispatch the calls the the thread that manages the DLL.
This way you have control over the thread that calls the DLL, and over the lifetime of the thread.
I'm a bit rusty, but you might try wrapping calls to the DLL in a single threaded apartment COM object. This would ensure that all calls go through the COM object's windows messaging thread. I think you would have to register the component in a server application within Component Services to do this.
Can you run the dll inside different threads as different instances? Like thread1 creates an instance of this third party dll, and thread2 also does, but as long as thread1 doesn't try to use thread2's instance it won't throw that exception? If thats the case, .Net never unloads any code once its loaded, if you load an assembly and then remove it, it still sits in that application pool. If you can create more than one instance at a time, you could load it up in a separate app pool you control per a request, then unload the app pool. Performance might drop though.