I was able to communicate with Freemaster 3.1 within my application using the provided activeX object and everything works fine. But now I need to move all the communication procedure to a secondary thread to allow the program to have a higher reading frequency without making the main thread too heavy. Unfortunately it seems that on the secondary thread it is not in any way possible to instantiate the interface of the activeX object, during the creation phase the procedure goes into error. I also tried to create the interface on the main thread and then pass it to the secondary one, but again, as soon as the secondary thread references the interface pointer I have an exception.
Is it a solvable problem? Does it just depend on my development system (Delphi) or is it an intrinsic limitation of this object and cannot be solved?
thanks
Lorenzo
Solved! Go to Solution.
Dear Lorenzo,
I have made a test C++/MFC dialog-based UI application which starts several background threads. Each thread creates the FreeMASTER ActiveX object and invokes some of its methods (GetAppVersion, ReadVariable, StartStopComm).
The test works as expected. No crash or bad behavior is observed. Each thread is able to access the object without problems. Also, no synchronization was needed. Actually the only synchronization I used was when printing to internal log buffer. Only the main UI thread is then able to update the log text on the screen (the EDIT dialog control).
I'm sorry I cannot help you with a Delphi issue, but this C++ test proves the multi-threaded access is possible.
Regards,
Michal
Hello Lorenzo,
the FreeMASTER ActiveX server's proxy-stub DLL is registered to support "Both" threading models. So it should be possible to be created in both single-threaded and multi-threaded applications.
I don't have an experience with Delphi, so I can only give some general Win32 API advices. It is likely that Delphi wraps the functionality to some more "easy-to-use" API. Anyway:
Unfortunately, thread-safe COM+ is not an easy topic, but there is a lot of documentation available.
Regards,
Michal
I was already using the CoInitializeEx function like so:
CoInitializeEx(nil,COINIT_MULTITHREADED);
FM_DEV:=CoMcbPcm.Create;
IF FM_DEV.OpenProject(MyO) then
FM_DEV.StartStopComm(Olevariant(True))
CoUninitialize;
While I had not used CoMarshalInterThreadInterfaceInStream because I thought it was only needed if there were more threads that shared the COM resource, while in my case everything would be only on this secondary thread where the object is born, lives and then is destroyed.
Do I still have to use this feature?
Hello Lorenzo,
understood. So in this case, the marshaling should not be needed and the object access should work. Can you describe what action raises an exception? Is there any context information behind the exception like 32bit error code etc.?
Also, make sure the CoInitialize (or the Ex) is called from the main gui thread.
FYI: Actually, the FreeMASTER code itself proves the multi-threaded access to its own ActiveX object is possible. Its multi-threded JSON-RPC interface uses the ActiveX interface internally to perform the desired operation. In this case, the ActiveX object is created by the TCP/IP listening thread and is marshalled to JSON-RPC worker thread where it is used.
Would it be possible for you to experiment a bit with splitting the object creation and object usage into two different threads and use the interface marshalling calls? As the marshalling calls are ready to handle multi-threaded operations, they could return some useful error codes for us to better understand what is the problem here (instead of when accessing the object just crashes).
Thanks,
Michal
I did not understand that CoInitialize should be used inside the main thread, I was calling it in the secondary one before the creation of the COM object!?
I'll try to make the change.
For the rest, unfortunately, at the moment I am unable to carry out realistic tests, as the system is already installed by the customer and I can simply try the connection to Freemaster but without HW. To understand if it works I rely on the answers that the functions give me, now for example I have managed, by putting the code in a critical section (?), To ensure that the program does not crash in the creation of the COM object and the functions project loading and start seem to work because they return TRUE value (and in fact FREEMASTER loads the project). To understand if it works I have to wait to be able to do some tests by the customer.
Thanks MichalH !
Dear Lorenzo,
I have made a test C++/MFC dialog-based UI application which starts several background threads. Each thread creates the FreeMASTER ActiveX object and invokes some of its methods (GetAppVersion, ReadVariable, StartStopComm).
The test works as expected. No crash or bad behavior is observed. Each thread is able to access the object without problems. Also, no synchronization was needed. Actually the only synchronization I used was when printing to internal log buffer. Only the main UI thread is then able to update the log text on the screen (the EDIT dialog control).
I'm sorry I cannot help you with a Delphi issue, but this C++ test proves the multi-threaded access is possible.
Regards,
Michal
Dear Michal,
first of all thank you for the time you have dedicated to me!
I just finished testing the changes made directly on my client's workstation and I can tell you that everything worked perfectly!
Unfortunately I have not been able to improve the data download rate much, but I think it depends on the fact that my client's PC is not fast enough. The two applications (Freemaster + mine) together bring the CPU usage over 80% and I was unable to exchange data with a frequency higher than 5Hz. We will do more tests as soon as my client has replaced the current system with a more performing one.
Anyway thanks for the help.
The CoInitialize should be called from each thread which makes any COM+/ActiveX activities. It should also be called from the main UI thread which processes the windows messages as WIndows use the messages internally to communicate between the client and server apps (as both are standalone executables).
Let me also do some tests (in C++ & plain Win32 API) to see if your scenario where the FreeMASTER object is created/used/deleted from a worker threads is viable.
I will reply as soon as I have any news.
Regards,
Michal