View Full Version : Use of user DLL in Flexsim
Lars-Olof Leven
11-02-2007, 04:12 AM
Hi,
I am looking at how to use my own DLL in Flexsim and I understand to use the DLL from a trigger as in the demo model in the old forum.
What I really want to do is in a trigger call a function in a DLL with parameters that I supply the DLL with and the DLL should return a value. The call of the function in the DLL will be on a line in a Flexscript code, the trigger is toggled as Flexscript and not as a DLL.
What is the best way to call a function in a DLL with my own parameters?
What is the best way to call a function without toggle the whole trigger as a DLL? Probably I need to use nodefunction.
Is it possibly to send my own parameters to a DLL function from a trigger call? The trigger is toggled as a DLL.
Must all functions in a DLL have FLEXSIMINTERFACE declartion?
If I have FLEXSIMINTERFACE declaration and want my own parameters passed to the function. How do I do that from Flexsim?I have lost my link to the old forum so I can not use the old forum to find the discussion about the use of DLL.
If somebody has some demo code they can share I would appreciate that.
Lars-Olof
Steven Hamoen
11-02-2007, 07:03 AM
Hi Lars,
We have already done a few projects/libraries with DLL's and I'll try to give you some info:
What is the best way to call a function in a DLL with my own parameters?
If you have a node(trigger, label, variable) toggled as DLL, you can simply call nodefunction on that node and specify all the parameters that you want (max. 10). Within the DLL you extract the parameters with parval and parnode. (parval(1) is the first parameter)
What is the best way to call a function without toggle the whole trigger as a DLL? Probably I need to use nodefunction.
yes, you can use a nodefunction, but what is even easier with reading and programming is making a usercommand and toggle the node with the code as DLL. That way it is just as using a function directly. Simpy pass the parameters and the usercommand will pass them on. I attached a bitmap of this usercommand option.
Is it possibly to send my own parameters to a DLL function from a trigger call? The trigger is toggled as a DLL.
Yes, if you call a trigger with nodefunction you can specify max 10 parameters.
Must all functions in a DLL have FLEXSIMINTERFACE declartion?
No, but in that case you can't call them directly from within Flexsim. You can make an interface functions that has the FLEXSIMINTERFACE and call a different function from within that interface function. But that 2nd function can only be accessed from within the DLL.
If I have FLEXSIMINTERFACE declaration and want my own parameters passed to the function. How do I do that from Flexsim?
See above.
I hope this helps you any further.
Regards,
Steven
Lars-Olof Leven
11-02-2007, 07:11 AM
Hi Steven,
Thanks for the answer and help.
This will help me a lot.
Now it I need to start do some testing before I start asking more questions.
Regards,
Lars-Olof
Lars-Olof Leven
11-05-2007, 10:02 AM
Hi Steven,
I am trying to use User Command to call my own function in a dll, but I can not get it to work. I managed to get work once (do not know how) and when I saved the model and did a small change to the dll, after that I can not get it to work.
Even when I go back to my original code I can not get it to work.
The error I get is
Flexscript Error MAIN:/project/model/Tools/GlobalVarGen>variables/commands/kalle/code line 2 parse error, expecting `$'
Could not finish parsing because of previous errors.
I have tried to use dll: and code directly from a trigger in the user command still same problem.
When I call my function in the dll from a trigger direct, there is no problem. For example when I toggle the OnExit trigger on a processor to dll and write in "../libraries/dll.dll" "exitmessage" I get it to work. When I use the same information in a User Command I do not get it to work.
The problem I have, is for the User Command to understand that I want to call a dll. I have toggled the User Command as dll.
Any tips how I should get User Command to understand that I want to call a dll? How should I do the User Command to get it to call the dll?
Hope somebody can help me.
Lars-Olof
Tom David
11-20-2007, 03:57 AM
Steven,
looks like you have some experience with DLL's.
Can I also pass a string over to a DLL?
You only speak from parnode and parval. So no parstring?
If I understand it right, you need for every DLL call an own User Command, right?
So if you have 10 DLL calls for 10 different DLL functions, you need 10 different User Commands?
Is there a way to make the DLL call dynamic?
What I am looking for is, that I could call e.g. a nodefunction or the User Command to call the DLL function and hand over the function name.
I am pretty sure you understand what I am trying to do.
Than I would only need one User Command to call all my DLL functions.
Does anyone has an idea how to do this?
Another way would be maybe something to put the function call in the DLL itself together to call an internal function.
Unfortunately I am not a C++ programmer but this might be a way. But it is still needed to pass a string over to the DLL.
Thanks in advance.
tom the (A)tom
Steven Hamoen
11-20-2007, 01:02 PM
@Lars-Olof:
Could you send me a small model example containing the usercommand and the cpp files/h files of the dll? Than I can take a look what is going wrong.
@Tom:
Tom, as far as I know you can't pass strings because the flexsim interface doesn't support strings in this way. So I use a workaround. I take a node somewhere under tools and write the string that I want to pass onto that node. And then either pass the node reference or in the DLL I simply refer to that node and get the string out. But there are some problems with strings in DLL, so to be on the safe side I always use gets and sets.
Concerning your calling different DLL functions with 1 usercommand, you can quite easily use a case statement based on a parameter that you pass in the usercommand. And if you do it properly you define a global variable as a constant and use that. For instance you make a global variable MYOBJECT_RESETTRIGGER and give it the value 1. That way you don't have to pass in strings, simply use numbers. Inside the case statement you call different nodefunctions that do the actual DLL call.
This could be done the same way inside the DLL. Inside the Overal function that you call, you use the case statement to distinguish the different functions you want to call.
But the disadvantage of both approaches is that if you want to do this for the triggers, every trigger has different parameters and those are not passed in or you have to do that for every trigger seperately.
So my question is why you want to do this? Because if you use this to have code on triggers you simply toggle the variable trigger nodes as DLL and call the DLL functions directly. Once you have that in place you never have to look at it again and inside Visual Studio you can create seperate cpp file to keep functions together and you have all kinds of tools like outlining to make it easier to work with.
let me know if you want to know more.
Regards,
Steven
Lars-Olof Leven
11-20-2007, 11:54 PM
Hi Steven,
I get it to work.
I will try to explain what happend for me, I maybe do something wrong.
First I create the User Command from the Tools menu.
Now I open up the tree for the User Command and toggle the code section to DLL.
What happens now is that the icon looks like D overlapping a S. If I stop now, I get the error.
After toggle the code section to a D I now toggle it back to Flexscript. Now I have only the D and the call to the DLL works.
Strange????The problem for me was the toggling of the code section of the User Command.
Can someone else replicate this problem?
It can be something with my system and installation.
Regards,
Lars-Olof
Tom David
11-20-2007, 11:58 PM
Lars-Olof,
As far as I see this issue everything is right with your system and installation.
If a node is already toggled (e.g. Flexscript) you need to toggle it as Flexscript to make it blank again. Than you can toggle it to the one you like to have it (e.g. DLL).
This is how Flexsim works as far as I know.
Take care
tom the (A)tom
Lars-Olof Leven
11-21-2007, 12:15 AM
Hi,
This thought is maybe not on the right place.
I have start looking into using DLL in Flexsim and the only thing I do not like (a matter of taste) is this toggle to DLL. It is probably easier for Flexsim do the coding for this solution.
What I had prefer is to have under Tools menu something like User Add In.
In user Add In the user tells which DLL and functions from that DLL he want to use in the model.
When this is done we could the use the functions from the DLL directly in Flexscript or C++.
The advantage I see that is:
I do not need to create User Commands
I have one place to see if I use DLL.
Do not need to toggle between Flexecript/C++/DLLDisadvantage is:
If using more than one DLL, you can not have the same function name in both DLL.There are probably more disadvantage.
This is one idea that I think can make use of DLL little easier.
Lars-Olof
Anthony Johnson
11-21-2007, 09:26 AM
Lars-Olof,
The reason that the user command/dll thing isn't very user friendly right now is simply because we haven't extended the features of the regular code editor (including quick buttons for toggling code as dll/flexscript/c++) to the user command code editor yet. This will be addressed in the next release, so it will be much easier to connect user commands to dll's in future releases. You will just check the "DLL" radio buttion at the bottom of the user command editor, then specify the dll path and function name for that user command.
I disagree, though, with your assertion that we shouldn't use the user commands window to add dll commands. That's what the user command window is there for, to extend flexscript/c++ functionality, and your suggestion would simply add another unnecessary method by which the user basically does the same thing. Also, the user command mechanism provides a method and encourages the documentation of those commands that you are adding, so that they will be included with the standard command documentation and will be documented for other users who use the model.
Also, on the string issue, right now there are problems in passing strings into and out of user commands. Depending on the calling environment (flexscript/c++/dll), and the callee/user command's internal environment (flexscript/c++/dll), sometimes it can cause memory leaks (I think) and even crashing (I've seen it with the saker guys). The crashing problem was caused when caller was flexscript and callee was c++, and it was fixed when caller was changed to c++. I need to take some time to figure out exactly what the issue is and resolve it. So for now there's no guarantee on passing strings into user commands, meaning do it at your own risk, but eventually I hope to fix that.
Lars-Olof Leven
11-21-2007, 10:48 AM
Anthony,
If you are planing to change the behaviour of the code editor I will wait and try it to see if I like it better.
One thing more. When setting the dll path, how are Flexsim checking for the dll? Is it under Flexsim4\program, Flexsim4\libraries, or are Flexsim checking the model directory?
What I want Flexsim to do when I only write testdll.dll for the dll is ti chech in this order:
In the directory I have the model
In libraries or program under Flexsim installation directory
In the path for Windows.I can see me to do 2 different type of dll. The first one is unique for each model and the second
is more general that can be used in more then one model.
I in the school that all files belong to one model (program) should be in the same directory, this
make it easier to delete files and move to another computer.
At least think to add a command that returns the path to the model, like the cdir command.
It is easier for user to use a command instead of reading from the tree.
Both cdir and the new command should be able to be used when declaring the path to the dll.
Then the user developing a model can have one structure of directories and a user who only will run models can have a different structure.
I prefer to have the model directory as base, some else want to have Flexsim installation directory as base when calling dll, for input and output files.
Here in Sweden will it be that we at Rejlers will do most of the models and the hand them over to a customer. Therefor would it be great for us to have the model directory as base for all calls for input and output.
Lars-Olof
Steven Hamoen
11-26-2007, 01:44 AM
Also, on the string issue, right now there are problems in passing strings into and out of user commands.
Anthony,
Does this mean that you can pass strings into a usercommand or even a nodefunction? I know that there is also a parstr function but I thought that it could not be used because then you (being Flexsim) have to overload the functions in every possible parameter combination of string and double? And I have never seen it being used.
Steven
Anthony Johnson
11-26-2007, 09:56 AM
Lars-Olof,
Flexsim uses the Windows API's LoadLibrary command to load dll's. I'm attaching the documentation for the dll search found in Visual Studio help. I think the SafeDllSearchMode is a machine specific parameter found in the Windows registry, but it shouldn't matter either way. Right now, you will have to either put the dll in the directory where the executable is found, which is Flexsim4\program\, or make the path to the dll relative to that directory, such as "..\libraries\mydll.dll" and put the dll in the libraries directory. You can also put the dll in the Windows directory, although I personally don't like that idea because I stay away from the Windows system directory as much as I can. Also, the "current directory" is one of the items in the search. In the next release we have changed it so that before loading a dll, Flexsim will change the current directory to the directory of the model, so that if you have your dll stored in the model directory, it can be loaded from there as well.
As a side note, we've also changed it so that media paths can be relative to the model directory, so you can put all of your media in the model directory, and then move the model directory anywhere you want, so you're no longer strapped to the userprojects directory. There will also be additional commands: modeldir(), documentsdir() (for My Documents), and currentfile() (for the path of the current model), and we're going to make default model save/open paths in a My Documents\Flexsim 4 Projects\ directory, so it will be much more of a "windows standard" functionality.
Here's the dll search path documentation:
Dynamic-Link Library Search Order
Starting with Windows XP, the dynamic-link library (DLL) search order used by the system depends on the setting of the HKLM\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode value.Windows Server 2003: The default value is 1.Windows XP: The default value is 0.If SafeDllSearchMode is 1, the search order is as follows:
The directory from which the application loaded.
The system directory. Use the GetSystemDirectory function to get the path of this directory.
The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched.
The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
The current directory.
The directories that are listed in the PATH environment variable.If SafeDllSearchMode is 0, the search order is as follows:
The directory from which the application loaded.
The current directory.
The system directory. Use the GetSystemDirectory function to get the path of this directory.
The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched.
The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
The directories that are listed in the PATH environment variable.
Lars-Olof Leven
11-26-2007, 10:12 AM
Anthony,
That sounds perfect.
Will it be for version 4.1 or 5?
Lars-Olof
Anthony Johnson
11-26-2007, 10:12 AM
Steven,
The capability of user commands taking a string is really dependent on how you want users to interact with those user commands. User commands have really always supported the capability to pass strings in, there are just some caveats, depending on the "caller's" environment. If the caller is using c++, then in c++, the user command is always declared as usercommandname(double p1, double p2, double p3,...). So if that is the only overload available to the caller, then he will have to pass in all doubles. If the command wants one of the parameters passed as a string, then the caller (in c++) has to cast the string to a double with tonum(), or else he'll get a compile error. But as long as he uses tonum(), he should be fine calling the user command directly, and the user command would use parstr() to get that parameter out. Now, since the caller is using c++, you can always overload the user command with your own implementations of that command, so that the caller can pass whatever he wants. If the caller is flexscript, however, it's quite different. In flexscript, all calls to that user command will be routed to the nodefunction for that user command, so it doesn't really care whether you pass in "my string" or 5.5 as a parameter, it just calls the nodefunction. And even then, I think you should be able to get a string parameter properly using parstr(). However, I have found that there are some issues with memory leaks/memory corruption if caller is flexscript and callee is (I think) c++. But I'll have to look into this and dig a little deeper before I can say exactly what the issue is. Also, there's the other caveat of how you go about having a user command return a string, which I think might work, but you have to do some special things for it. So for now, even though it may seem to work properly, we discourage people from passing strings into user commands.
Once I have the time to figure out all of this stuff, I'd like to put a detailed help document together to help people out in figuring out how to do all of these caller/callee caveats.
AlanZhang
11-27-2007, 12:02 AM
As a side note, I've also changed it so that media paths can be relative to the model directory, so you can put all of your media in the model directory, and then move the model directory anywhere you want, so you're no longer strapped to the userprojects directory. There will also be additional commands: modeldir(), documentsdir() (for My Documents), and currentfile() (for the path of the current model), ...
This is nice to know. Putting model specific files in the same directory as the model improves portability. And to be get the model directory and the model name is a lacking feature of the current version of the Flexsim.
Alan
AlanZhang
11-27-2007, 12:18 AM
I have one place to see if I use DLL.
This could be really an advantage. When I download a new model, I always need to go into each object and to see if any default code have been changed, not only for DLL, but also for Flexscript or C++ code. If the model is big, that is not a simple task. Is there any easy and quick way to know what part of default Flexsim code has been changed when we get a model at the first time? Such a way could benifit both model builders and viewers.
Alan
Anthony Johnson
11-27-2007, 08:49 PM
Will it be for version 4.1 or 5?This will all be in 4.1 (actually, I think we're going to call it 4.3 so as not to confuse it with 4.01. We've made a quasi rule to have our "feature" releases be odd numbers whereas our minor or bug-fix releases are even, i.e. 4.02, 4.04 for minor releases, 4.1,4.3,4.5 for feature releases, but we haven't been holding to that rule very well)
Anthony Johnson
11-27-2007, 08:54 PM
Is there any easy and quick way to know what part of default Flexsim code has been changed when we get a model at the first time? Such a way could benifit both model builders and viewers.For the next release, we've changed the Model Documentation feature in the Reports and Statistics menu so that it is a little more picky as to what it prints out (and it writes to more reader-friendly html format). If you don't check the "Verbose" box, then it will only document parts of objects that have actually been changed from the default.
Funny, I think this thread has gotten a little off its original topic, but oh well. Kind of how conversations go anyway.
Steven Hamoen
02-20-2009, 04:42 AM
I have added it to this thread because there is already a string issue mentioned here. I have the following problem and I think only Anthony can answer it but I invite anybody else to say something about it.
I have a usercommand that calls a DLL function and it should return a string, so the DLL functions is defined as a string function:
visible string DLL_GetDateStringFromOfficeDays ( FLEXSIMINTERFACE )
{
int OfficeDays = parval(1);
return GetDateStringFromOfficeDays ( OfficeDays );
}
But when I now call the usercommand from within Flexsim via the script window:
string Date = GetDateStringFromOfficeDays( 31000.0);
I get the following error message:
ex: double F_parval(parametersinterface) ex:
exception: parval retrieval
warning: throw - code may have been terminated.
ex: double linkedlist::executememberfunctionwithexceptionhand ling(FLEXSIMINTERFACE) #3 ex: MAIN:/project/model/Tools/GlobalVarGen>variables/commands/GetDateStringFromOfficeDays/code
member function exception handled
details: class: code instance: code code: 0
warning: throw - code may have been terminated.
ex: Exception caught in flexscript execution of ex: line 1 instruction 3. Discontinuing execution.
ex: Exception caught in flexscript execution of ex: line 1 instruction 3. Discontinuing execution.
ex: Exception caught in flexscript execution of ex: line 1 instruction 3. Discontinuing execution.
And I have no idea what exactly is going on:confused:. I assume it has something todo with passing a string which is not appreciated by Flexsim:)
Any suggestions?
Steven
Anthony Johnson
02-20-2009, 10:06 AM
Hey Steven,
If you're declaring a flexsim-accessible function in a dll, the function must be declared exactly as:
visible double functionname ( FLEXSIMINTERFACE );
You can't have the function declaration return a string. However, you can still effectively return a string without explicitly returning a string type. The catch (although this doesn't really apply to you) is that you have to do it differently in flexscript vs. c++/dll. In c++/dll, to return a string you have to first import the stringreturn function. This is done in flexsimfuncs.h. In the typedef section add:
typedef void (*_stringreturn)(char *instr, _callpoint *cp);And in the DECLARE... section add:
DECLARE_FLEXSIM_FUNCTION(stringreturn)Then, in your code, to return a string, you call the following:
stringreturn(thestringtoreturn, callpoint);
return 0;Obviously, more stuff needs to be added to declaration.h and definition.h if you want to be able to pass a straight string into stringreturn, instead of a char*, but that's the start of how to do it.
To do this in flexscript, you can just return the string directly, whether it be a string literal, a call to a function, or a global or local variable.
return "hello";
return getthestringfromafunction();
Carsten Seehafer
03-18-2009, 02:25 AM
If you're declaring a flexsim-accessible function in a dll, the function must be declared exactly as:
Code:
visible double functionname ( FLEXSIMINTERFACE );
Is it possible to make functions which expect an array and return an array in flexsim? I want to use them like normal user commands in the triggers without compile.
I thought about user commands which connect the dll and his functions with flexsim to prevent compiling. But how can I pass an array from flexsim to dll and backwards?
Thanks ;)
Steven Hamoen
03-18-2009, 03:39 AM
Carsten,
I don't think that you can pass an array directly, because on the DLL side you only have the parnode, parval and parstr command to get the parameters out.
You can use global variables from within the DLL although I haven't tested it, so a global array should be possible.
Other option is that you use a node structure as an array and pass in the main node as a parameter. (or use a table for that matter)
Or you create a flexscript function that gets or sets a value from the array and call that function from within the DLL with nodefunction.
That is what I can think of for the moment.
Steven
david_white
01-12-2010, 12:34 PM
I've got an external DLL and can now successfully call into it with integers, doubles, and strings. I can also get the DLL to return integers and doubles, but I'm still having problems getting it to return a string. I tried what Anthony Johnson suggested in his 20 Feb 2009 post (actually it was already in the version of FlexsimDefs.h and FlexsimFuncs.h that I downloaded).
But when I try this, I get a runtime error from Flexsim when that function executes saying, "A dll attempted to call a Flexsim function that could not be bound. Unsuccessful Bindings: ....". It then lists a bunch of what appear to be commands. The error is definitely tripping up on the stringreturn("xyz", callpoint); that I have right before the return(0); statement in the DLL.
Within the Flexsim model, the function is called on a trigger with, string retval = DLL_strings(current, 1, 2, 3); , which is calling a User Command that's toggled to DLL. Everything else is working right...if I comment out the stringreturn(..) line in the DLL, everything executes as expected...well, except that it returns a NULL string.
Thoughts?
Thanks,
David White
david_white
01-13-2010, 09:09 AM
Anthony,
Actually, after looking around, I think what I really want to use is the COM object that you created (http://www.flexsim.com/community/forum/downloads.php?do=file&id=180) (http://www.flexsim.com/community/forum/downloads.php?do=file&id=180%29)). I think this does what I need, but I do have a few questions. This could be very powerful and useful if Flexsim had the time to fill it out all the way and write up the documentation.
1. How does the FlexsimRPC.fsm get loaded? Does that get loaded first when you call the openmodel() method? It looks like that simply loads the FlexsimRPC.fsl and copies over the RPCManager object to the Tools node of model that was opened.
2. It doesn't copy over the usernotifycom object that's next to the RPCManager (of course that object is empty anyway)....does that mean the OnUserNotify event isn't installed and working yet?
3. There's no methods to "setup" the OnUserNotify event...so how's that work? Can I just add a FlexsimApp_OnUserNotify function in my host? What parameters comes in on that and what triggers it?
4. Related to #3, if I want an event (such as OnConveyEnd) to poke my host, can I put something in the model that will do that? Since the RPCManager isn't loaded until run time, I'm assuming that adding code to an event trigger to cause a OnUserNotify event would confuse Flexsim as I make a model??? Help?
5. What's the getinterfacename method do?
6. What's the second parameter in the SetUpdateInterval method do? I noticed a switch/case statement in the OnTimerEvent in the RPCManager...is that for that?
7. What were to happen if the host were to call the Stop method asynchronously? For instance, you call the Stop method during the OnNotificationTime event...so Flexsim is at a "good" stopping point then. But if Flexsim is chunking along and the Stop method gets called while it's mid-processing on a time slice, could that mess things up? I presume it's no different than hitting the stop button normally, but I just want to make sure.
We've been using Flexsim for development of a new product that has lots of interacting hardware. And so far, we've been using it in the normal fashion that it was intended. But now, we're wanting/hoping to use Flexsim to actually simulate the hardware during development of the controlling software. For instance, the sw group can write/test their code....interfacing the simulated hardware thru the COM object. Then when the real hardware is ready (which could be a year or so), an interface layer of software can be substituted in for the COM object and everything should work!
But to do this, we obviously need the Flexsim to act like the real hardware will, which includes having it send messages to the controlling software on trigger events, which is why question #4 is critical. Also, whatever host I choose to run the FlexsimAXApp on (probably will be a dialog-based c# program) would allow us to simulate an operator on the floor pushing buttons, loading objects, interacting with the hardware, etc., and that would go thru the COM interface to affect the model's behavior within Flexsim. Does this make sense? We want our controlling software that we're developing to be able to go in and affect the model while it's running, and have the model send messages to the controlling software as things happen.
8. Does this sound do-able? Do you think there's enough in your first cut of the COM object to pull this off?
Thanks very much,
David White
david_white
01-13-2010, 09:47 AM
Oh.... just found the answer to 3 and 4.
Event OnUserNotify(ByVal p1 As Double, ByVal p2 As Double, ByVal p3 As Double, ByVal p4 As Double, ByVal p5 As Double, ByVal p6 As Double, ByVal p7 As Double, ByVal p8 As Double, ByVal p9 As Double, ByVal p10 As Double, returnval As Double) As Double
Member of FlexsimAXDLLLib.FlexsimAXApp
method OnUserNotify : fires whenever the model calls a special flexsim command called usernotifycom(). Designed to let the model builder notify com clients at any time in the model.
Sorry I didn't notice that in the Object Browser before the above post. But I'd still like your opinion overall on what I'm trying.
Thanks,
David White
david_white
01-13-2010, 03:00 PM
Ok. I have a c# app running that kind of works. I have all the methods on buttons. The StartApplication method starts up Flexsim and ExitApplication closes Flexsim. So I'm pretty sure my hooks are right. But when I try to OpenModel (after StartApplication of course), it just hangs. I can see that Flexsim still has the FlexsimRPC.fsm model open and never changes to the one I specify (FlexsimRPCTest.fsm). I've stepped thru the code and know that it's sending a good string...full path. I even copied it to c:\FlexsimRPCTest.fsm and tried it there thinking that maybe the space in Program Files was causing problems. Nothing. Flexsim never changes to the new test model and my host app quits responding.
Thoughts on that? Thanks,
David White
Steven Hamoen
01-14-2010, 12:19 AM
Just a thought, have you tried with double slashes "\\" ?.
So something like C:\\FlexsimRPCTest.fsm
david_white
01-14-2010, 07:48 AM
Steven,
You're on the right track....
It looks like the *something* is stripping the "\\"'s out of the string....entirely.
If my input string to OpenModel is "c:\\FlexsimRPCTest.fsm", it doesn't work...but I noticed that if you minimize/maximize Flexsim while it's hung up during this, the title banner changes to "c:FlexsimRPCTest.fsm". So I made my input string "c:\\\\FlexsimRPCTest.fsm", and it works.
Similarly, "C:\\Program Files\\Flexsim4\\libraries\\FlexsimRPC\\FlexsimRPC Test.fsm" doesn't work (hangs), but, neither does "C:\\\\Program Files\\Flexsim4\\libraries\\FlexsimRPC\\FlexsimRPC Test.fsm"....this at least generates an error that say it can't find the file "C:\Program FilesFlexsim4librariesFlexsimRPCFlexsimRPCTest.fsm". So, if I replace all the "\\"'s with "\\\\"'s, changing the input string to "C:\\\\Program Files\\\\Flexsim4\\\\libraries\\\\FlexsimRPC\\\\Fl exsimRPCTest.fsm"...then it works. This is regardless of whether the input to OpenModel is a string variable or a literal.
This is odd because the Excel example that Anthony made doesn't have double-double backslashes... So I would have to assume the OpenModel method itself isn't removing the backslashes. But when I'm using a literal in the call, that goes straight into the .NET framework, so I don't think anything on my side would be removing them. In fact, if something was specifically removing backslashes, it would remove all of them...my doubling them up wouldn't have worked. Odd.
Incidentally, it would be nice if OpenModel returned a success/failure value. When it says it couldn't find/load the file, my software can't realize that and do something about it.
Anyway, it's up and running now. Going to play with the OnUserNotify next.
Thanks,
David White
Lars-Olof Leven
01-14-2010, 10:53 AM
Hi David,
I know that you have gone for a different approach but I did a check regarding your problem with
stringreturn("xyz", callpoint);
This works for me.
Are you sure that your are using the latest version from Google Code?
If yes, I can not see whay it should not work.
Lars-Olof
david_white
01-14-2010, 03:29 PM
Yeah, pretty sure I am.
However, I have an update with the c# app I'm writing. (I'll try to post the project tomorrow). I'm still using the FlexsimRPCTest.fsm project for testing/debugging. I have most everything working. I can change lables, invoke functions while the model is running, I can change the period of the OnUpdateInterval on the fly too. I changed the function that sets the number of operators a little and moved it to a User Command, so I can change the number of operators up and down on the fly while the model's running too. I didn't quite get to the OnNotificationTime yet, but I should have that by tomorrow.
I lost a lot of time trying to figure out why the OnUserNotify isn't working. Still haven't figure that out. And for my ultimate goal, that's the important one. Since I'm getting the OnUpdateInterval events, I'm pretty sure the hooks are right...but it just never gets called. In the OnExit trigger of one of the processors I have it call usernotifycom(). I have it print out a debug msg to the OutputConsole, so I know it's executing. I can't actually find the usernotifycom() function in the model. I know it's there because after it's been loaded by the RPCManager, it's blue and hovering over it gives you the parameters in a tool tip. But I can't find it. If I load FlexsimRPC.fsm manually, I can see it as a User Command...it simply calls a function in a FlexsimServer.dll.
So. Has anybody tried the OnUserNotify with anythinng they've done yet? If I get the OnNotificationTime event working tomorrow and still can't get the OnUserNotify, I'm going to have to assume it's not working on the Flexsim side. Does anyone know if Anthony Johnson still works for Flexsim?
Thanks,
David White
Phil BoBo
01-14-2010, 03:53 PM
Anthony is meeting with clients in Europe this week and has probably been too busy to check the forum.
david_white
01-15-2010, 08:49 AM
It's too bad Anthony is busy...I'm sure he could weigh in on this pretty good. I'm not sure what day next week we have to make a decision on whether we can use this concept...maybe he'll have a chance early next week.
I have everything working except the OnUserNotify. Here is the Visual Studio C# project with all the source code. I modified the FlexsimRPCTest.fsm slightly (included in zip but named FlexsimRPCTest_mod.fsm). Basically I only changed where the function that sets up the number of operators is and I added the call to usernotifycom() in the top processor's (Processor 3's) OnExit trigger. Here's the file (http://www.flexsim.com/community/forum/downloads.php?do=file&id=222).
If I can't get the OnUserNotify to work, we won't be able to use this to simulate the hardware. If anyone wants to take a look and see if they can figure it out, feel free. Even if you don't, this project is a nice starting point for someone who wants to control Flexsim via an external application...as long as you don't need the OnUserNotify. I think if I understood a little better about what's going on on the Flexsim side I could maybe figure it out.
I appreciate everyone's help.
David White
Anthony Johnson
02-01-2010, 09:54 AM
David,
Unfortunately I don't know c# that well, especially in regards to COM, so I can't help you directly on your project. But I was able to get the user notify to work in VBA using the excel example originally posted with the COM object, here: 902. I just put in the entry trigger of the sink a call to usernotifycom when the sink's input hits 40. Then, in the excel file I added an event sink for the user notify, that just shows a message box.
If you still can't figure out what's wrong, I'm also including the source code and Visual Studio Project for the COM dll's used. The "code trace" for calling usernotifycom is:
1. usernotifycom_commmand() is called, defined in FlexsimRPCServer>DLLMain.cpp.
2. A new thread is created that calls NewThreadOnUserNotify(), defined in FlexsimRPCServer>DLLMain.cpp. The main thread will then wait for that thread to finish. (I think I have to create a new thread because I want to allow the client to call functions from his side, and have the main thread available to perform those calls).
3. NewThreadOnUserNotify() calls RPC_OnUserNotify(), which is the rpc call that performs the inter-process communication
4. On the other process' side, the RPC_OnUserNotify() rpc event sink is fired, defined in FlexsimAXDLL>FlexsimAXApp.cpp, which fires the OnUserNotify() COM event sink.
Hope this helps. Sorry it's a bit late.
cedric molthoff
03-23-2010, 09:35 AM
Hi,
Thanks Anthony, for the FlexsimRPCDLL.zip (http://www.flexsim.com/community/forum/attachment.php?attachmentid=903&d=1265042461) upload! I think this COM-Object is exactly what I need to control Flexsim from the outside. I'm experimenting with this RPC-server for over a week now, but it still doesn’t work.
Does somebody has a (small) example of a RPC-Client written in C(++) that will work with this RPC-Server?
Please help, I’m getting a little discouraged.
Cedric
Luciano
03-30-2010, 04:19 AM
Hi,
I've not found nothing in the forum about debug a user DLL.
I use this steps:
1 - compile in debug mode and be sure that the output folder contatin also
the <mydllproject>.mdb (the debug database)
2 - If necessary I call an my exported dll function to force Flexsim to load
my dll (something like 'libstartup')
3 - in VS2008 start a debug session using the 'attach to process'
and select current Flexsim run process (usually flexsimrunner.exe)
4 - place my breakpoints in source code
5 - enjoy with debug!
Esther Bennett
05-11-2010, 02:27 AM
Hello,
Thanks Luciano, I like this very much! I now use it frequently to debug my DLL code.
I have a question though, do you (or does anybody) know if it is possible to make the treenode names of the Flexsim objects visible in the Autos, Watch or Locals window in Visual Studio? What I mean is that an interger for example has a value of 1. A treenode (such as current) has a value of something like: 0x0a5d4a88. It would be great to be able to see the name of the current object somewhere in the Visual Studio window.
Esther
Jason Lightfoot
05-11-2010, 06:54 AM
I've just been adding a string variable where I've needed to know the name/path:
string currentname=nodetopath(current,1);
which will then show in the list of locals/auto.
I agree it would be nice if we could have some 'plug-in' that would do that automatically for treenodes. Maybe there's something in here (http://msdn.microsoft.com/en-us/library/aa730838%28VS.80%29.aspx)that could help if someone has the time to figure it out.
vBulletin® v3.8.7, Copyright ©2000-2012, vBulletin Solutions, Inc.