ATTENTIONThis FlexSim Community Forum is read-only. Please post any new questions, ideas, or discussions to our new community (we call it Answers) at https://answers.flexsim.com/. Our new Question & Answer site brings a modern, mobile-friendly interface and more focus on getting answers quickly. There are a few differences between how our new Q&A community works vs. a classic, threaded-conversation-style forum like the one below, so be sure to read our Answers Best Practices. |
flexsim.com |
#1
|
|||
|
|||
Use of user DLL in Flexsim
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.
If somebody has some demo code they can share I would appreciate that. Lars-Olof |
#2
|
|||||
|
|||||
Hi Lars,
We have already done a few projects/libraries with DLL's and I'll try to give you some info: Quote:
Quote:
Quote:
Quote:
Quote:
I hope this helps you any further. Regards, Steven |
The Following 3 Users Say Thank You to Steven Hamoen For This Useful Post: | ||
Paulo Lopes (03-11-2015) |
#3
|
|||
|
|||
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 |
#4
|
|||
|
|||
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 |
The Following User Says Thank You to Lars-Olof Leven For This Useful Post: | ||
Brandon Peterson (10-08-2009) |
#5
|
||||
|
||||
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
__________________
tom the (A)tom: "We have solved our problems ... now we have to fight the solutions." |
#6
|
||||
|
||||
@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 Last edited by Cliff King; 11-20-2007 at 02:17 PM. |
The Following User Says Thank You to Steven Hamoen For This Useful Post: | ||
Brandon Peterson (10-08-2009) |
#7
|
|||
|
|||
Hi Steven,
I get it to work. I will try to explain what happend for me, I maybe do something wrong.
Can someone else replicate this problem? It can be something with my system and installation. Regards, Lars-Olof |
#8
|
||||
|
||||
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
__________________
tom the (A)tom: "We have solved our problems ... now we have to fight the solutions." |
#9
|
|||
|
|||
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:
This is one idea that I think can make use of DLL little easier. Lars-Olof |
#10
|
||||
|
||||
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. Last edited by Anthony Johnson; 11-21-2007 at 10:52 AM. |
#11
|
|||
|
|||
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:
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 |
#12
|
||||
|
||||
Quote:
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 |
#13
|
||||
|
||||
DLL search order
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: Quote:
Last edited by Anthony Johnson; 11-27-2007 at 11:38 PM. |
The Following User Says Thank You to Anthony Johnson For This Useful Post: | ||
Brandon Peterson (10-08-2009) |
#15
|
||||
|
||||
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. |
The Following User Says Thank You to Anthony Johnson For This Useful Post: | ||
Brandon Peterson (10-08-2009) |
#16
|
||||
|
||||
Quote:
Alan |
#17
|
||||
|
||||
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 |
#18
|
||||
|
||||
Quote:
Last edited by Anthony Johnson; 11-27-2007 at 09:57 PM. |
#19
|
||||
|
||||
Quote:
Funny, I think this thread has gotten a little off its original topic, but oh well. Kind of how conversations go anyway. Last edited by Anthony Johnson; 11-27-2007 at 11:35 PM. |
#20
|
||||
|
||||
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. I assume it has something todo with passing a string which is not appreciated by Flexsim Any suggestions? Steven |