I have a client program that uses a MarshalByRefObject to get a variable from a remote server. Sometimes the program hoses up on the remote server and when I try to get that variable my client program simply hangs. Is there a way to time out the call on this variable?
MyClass^ refObject = (MyClass^)System::Activator::GetObject(MyClass::typeid, url);
THEVARIABLE objectVariable = refObject->theVariable;
The only way I see is to implement an IMessageFilter (COM). In some cases it is possible to detect that there is an out of process call from the current STA to another. But AFAIK this is only done when an input message (keyboard/mouse) arrives.
With a message filter you can show something like "waiting for external com call...". Also in this case you may abort the external call.
See CoRegisterMessageFilter, and IMessageFilter
Related
How to get the name of the calling program from within an asynchronous remote function call (aRFC) ?
CALL FUNCTION 'BAPI_MATERIAL_SAVEREPLICA' STARTING NEW TASK lv_taskname
DESTINATION IN GROUP DEFAULT
The called BAPI triggers a user exit that I need to disable for this particular calling program. However, the local part of the stack is lost after the RFC and the name of the calling program on the local system is unknown.
The closest solution I could think of was disabling the user exit when the calling program is SAPMSSY1 (RFC calls), but that it not as accurate.
Maybe the parameter CALLER_PROGRAM of the function module RFC_GET_ATTRIBUTES. I'm not sure it works in all kinds of RFC calls.
I am using pywin32 and calling the Dispatch function to create a COM object, but this means a new instance of the application is created (in this case PTV Vissim) whenever I call the function. Is it possible, instead, to attach to an already existing Vissim application? This would speed up development, since I wouldn't have to wait for the application to start every time I run a test.
This is my existing relevant code:
import win32com.client as com
Vissim = com.Dispatch("Vissim.Vissim.540")
Specifically for PTV Vissim, there is an option to start Vissim with the extension -automation (for example: vissim100.exe -automation). If you start PTV Vissim with the extension -automation, it provides PTV Vissim as a COM server in the automation mode for COM scripts that are started subsequently.
See chapter "Starting PTV Vissim via the command prompt" of the PTV Vissim Help.
In general, you can not "attach" to an existing Vissim instance as a COM server. Each client connection should be at best backed-up by an independent Vissim instance.
That being said, it is still possible to accomplish your goal, that is - use the command line switch "-automation" to launch Vissim.exe, and that running Vissim.exe will act as an automation server as you desired.
--
What is under-the-hood?
The truth is, right in Vissim.exe's startup code, CoRegisterClassObject(CLSID, pUnk, dwClsContext, flags, &dwRegister) is by default called with flag = REGCLS_SINGLEUSE.
REGCLS_SINGLEUSE simply means, after a client application has been connected to an Vissim class object as hosted by a running Vissim.exe, the Vissim class object's class factory is removed from public view (i.e., not in the OS system's Class Table anymore). This means, a new client connection will have to launch a new Vissim instance in order to obtain the class factory, hence the creation of a new Vissim instance is in order.
However, if you use the command line switch "-automation" while launching a Vissim.exe instance, that Vissim.exe will use REGCLS_MULTIPLEUSE flag to register the class factory instead. That allows multiple client connections to the same running Vissim.exe instance afterwards.
I have more detailed blog on this matter and other relevant issues here. You might want to check them out at blog.wupingxin.net
I'm building a server and a client for a chat that runs on Tcp and Sockets, I want the client to handle more than one connection (to servers) so I made a class called "Client" to manage the async connection, so that I can run more instances at the same time like:
Dim ConnectionToServer1 as new Client
Dim ConnectionToServer2 as new Client
Since it's async when the the "connection" receives a message it generates an event (AsyncCallback) where I can convert the received bytes into a string.
The problem is: I've tried to set this string to a RichTextBox on my Form from inside the Client class, but nothing happens, I've tried to create a delegate in the form code but nothing works, the only way I was able to put the received message in the RichTextBox is by creating a public variable called LastMessage in the Client class where the last message is stored (every time it receives a message, the sub overrides the string), and then running a thread created by the Form which keeps checking for data (since the thread has been created by the form it has access to the controls, including the RichTextBox, right?)
Although I find this a bit clunky, is there any other way (through delegates maybe?) I can do it?
Here's some code:
Client class: http://pastebin.com/GF9um8Ss
Form code: http://pastebin.com/xW7mDj8j
Sounds like you started down all the right paths.
Now, on threaded applications one of the challenges that you will face is you can have tons of worker threads, but only the main, UI thread can actually make any updates to the UI. So keeping that in mind, if you have async code that needs to update the ui you will need to use what is effectively a delegate.
You can do this using tasks these days a lot easier, so read up on the Task Parallel Library, but essentially you need a delegate/task that is marshaled to run on the ui thread to handle the UI updates.
Set this global property as false
Control.CheckForIllegalCrossThreadCalls = false
this will let you edit any control of your form from any thread
How can i restrict my program to run only instance? Currently i'm running my program as daemon(starts and stops automatically), and when user clicks and tries to launch again(which is not a valid usecase), process gets launched in user context and i would like to avoid this for many reasons.
How can i achieve this?
As of now i'm getting list of processes and doing some checks and exiting at the begining itself but this method is not clean, though it solves my problem.
can someone give me a better solution?
And i'm using ps to get process list, is there any reliable API to get this done?
Use a named semaphore with count of 1. On startup, check if this semaphore is taken. If it is, quit. Otherwise, take it.
Proof of concept code: (put somewhere near application entry point)
#include <semaphore.h>
...
if (sem_open(<UUID string for my app>, O_CREAT, 600, 1) == SEM_FAILED) {
exit(0);
}
From the sem_open documentation,
The returned semaphore descriptor is available to the calling process until it is closed with sem_close(), or until the caller exits or execs.
I'm trying to upload a file from a server directory to the SAP CRM System (attachment to an Opportunity), therefore I am using the method create_with_file of the cl_crm_documents class.
To call this method I am using a RFC-Function created by myself.
If I test my RFC-Function within the Function Builder, everything works fine.
If I execute the RFC from a external System (in my case MS-Outlook) an error occurs: "Exception: RFC callback server not available".
I started the debugger and the program runs about half way through (So the connection works):
The create_with_file calls a couple of functions until the RFC_START_PROGRAM function is called. The error occurs exactly at this line.
Does anybody know why the error occurs only if I call the function remotely? How to solve this?
I don't have access to a CRM system, but this is what's probably happening: The class you use tries to perform some action on the front-end PC using the SAP GUI. For this, it performs an RFC call back or the SAP GUI. This works fine as long as you are using the function builder because there's a GUI connection available. Once you use some other means to invoke the function module, the GUI is no longer there and the program won't work. I'd suggest you check the code to see whether there is some parameter or customization that allows you to suppress the RFC call...