ATTENTION

This 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

Go Back   FlexSim Community Forum > FlexSim Software > Q&A
Downloads

Q&A Using Flexsim and building models

  #1  
Old 05-17-2010
Samuel Jack Samuel Jack is offline
Flexsim User
 
Join Date: May 2010
Location: Birmingham, UK
Posts: 3
Downloads: 0
Uploads: 0
Thanks: 2
Thanked 0 Times in 0 Posts
Rep Power: 0
Samuel Jack is on a distinguished road
Default Calling COM Components from within Flexsim

Is it possible to call COM components from Flexsim? I've done a pretty thorough search through the forums, but nobody seems to have addressed this question. I've seen Anthony Johnson's post about calling FlexSim through COM, but I'm trying to call out from FlexSim.

I'm presuming I'd need to write a C++ user command that would talk to COM. But where would be the most appropriate place to call CoInitialize/CoUninitialize? I don't think I'd want to be doing that every time the user command is called.
  #2  
Old 05-17-2010
Lars-Olof Leven Lars-Olof Leven is offline
Flexsim Distributor
 
Join Date: Aug 2007
Location: Sweden, Borlnge
Posts: 312
Downloads: 278
Uploads: 2
Thanks: 300
Thanked 256 Times in 139 Posts
Rep Power: 330
Lars-Olof Leven is a splendid one to beholdLars-Olof Leven is a splendid one to beholdLars-Olof Leven is a splendid one to beholdLars-Olof Leven is a splendid one to beholdLars-Olof Leven is a splendid one to beholdLars-Olof Leven is a splendid one to beholdLars-Olof Leven is a splendid one to behold
Default

Hi,

I can think about at least 2 way to do it.

First approach is to create 3 user commands. One for initializing the COM object, one for uninitializing the COM object and my user command.

The second approach is to have variable in your C++ that will indicate if the CoInitialize is done or not. In your C++ code you will check if the CoInitialize is done. If not, do the CoInitialize otherwise skip CoInitialize and run rest of the code.

There are probably more ways to do this, but I hope this will get you some ideas how to do this.

Lars-Olof
  #3  
Old 05-17-2010
Samuel Jack Samuel Jack is offline
Flexsim User
 
Join Date: May 2010
Location: Birmingham, UK
Posts: 3
Downloads: 0
Uploads: 0
Thanks: 2
Thanked 0 Times in 0 Posts
Rep Power: 0
Samuel Jack is on a distinguished road
Default

Lars-Olof,
Thanks, that's helpful.

Do you know whether the standard C++ means of working with COM objects (e.g. #import .tlb) will work with FlexSim?

Do you have any samples, by any chance?
  #4  
Old 05-17-2010
Lars-Olof Leven Lars-Olof Leven is offline
Flexsim Distributor
 
Join Date: Aug 2007
Location: Sweden, Borlnge
Posts: 312
Downloads: 278
Uploads: 2
Thanks: 300
Thanked 256 Times in 139 Posts
Rep Power: 330
Lars-Olof Leven is a splendid one to beholdLars-Olof Leven is a splendid one to beholdLars-Olof Leven is a splendid one to beholdLars-Olof Leven is a splendid one to beholdLars-Olof Leven is a splendid one to beholdLars-Olof Leven is a splendid one to beholdLars-Olof Leven is a splendid one to behold
Default

Hi,

You should be able to use #import .tlb in your C++ code, if you know that it is the same version of your COM application on your development machine and the machine that will run the model I think using #import .tlb will be eaiser.

Sorry, I do not have any sample code because I have never done this type of coding. Have only start looking at it and searched for information on the net.

What I would do is first to get the COM communication to work in a small C++ program (use for example Excel as a test software) after that I would transfer the code to my code for the DLL and get it work in the DLL before I add what I really want to do.

Hope someone else have some sample code.

Lars-Olof
  #5  
Old 05-18-2010
Anthony Johnson's Avatar
Anthony Johnson Anthony Johnson is offline
Manager of Product Development
 
Join Date: Jul 2007
Posts: 440
Downloads: 86
Uploads: 4
Thanks: 171
Thanked 899 Times in 288 Posts
Rep Power: 735
Anthony Johnson has a reputation beyond reputeAnthony Johnson has a reputation beyond reputeAnthony Johnson has a reputation beyond reputeAnthony Johnson has a reputation beyond reputeAnthony Johnson has a reputation beyond reputeAnthony Johnson has a reputation beyond reputeAnthony Johnson has a reputation beyond reputeAnthony Johnson has a reputation beyond reputeAnthony Johnson has a reputation beyond reputeAnthony Johnson has a reputation beyond reputeAnthony Johnson has a reputation beyond repute
Default

Samuel,
I'm posting an example here. I created a simple ATL COM class called SimpleAdder with one method: Add(), that just adds two numbers. I then implemented a model that calls the COM object's method as part of a user command named COMAdd.

To get this working on your computer, run a command line console as administrator, then cd to the FlexsimModel directory, and call regsvr32 TestATLCOMObject.dll. If this works (you don't get any errors), then you should be able to open the model in Flexsim, compile, and execute the script in the script console: COMAdd(5, 8), etc. and it should return back a valid sum of the two numbers.

What I did in Visual Studio to Create the COM Object


I think you can only use ATL if you have a standard version of Visual Studio (not Express). I think you can still create COM objects using VC++ Express, but you have to do it manually. I'm not a COM guru, so I'd have to spend hours figuring out all the files to edit to get it all right. Luckily for VS standard users, VS gives you easy wizards that streamline the process. So here's what I did in my VS 2008 Standard.
  1. Go to New > Project
  2. Choose ATL Project, enter the name TestATLCOMObject, and press OK
  3. Hit Finish in the ATL Project Wizard, using all the default settings.
  4. In the Solution Explorer pane, right-click on the TestATLCOMObject project, and choose Add > Class...
  5. Choose ATL Simple Object, and hit Add
  6. Type "SimpleAdder" as the Short Name, and that should fill in all the rest of the fields automatically. Hit Finish, leaving all the other settings as default.
  7. Now go to the Class View pane, right-click on the ISimpleAdder interface, and choose Add > Add Method...
  8. Enter "Add" as the name for the method.
  9. In this Add Method wizard, you're going to specify 3 parameters. For the first and second parameters, check the "in" box, choose DOUBLE as the type, and name them p1 and p2 respectively, then hit Add. For the third parameter, choose DOUBLE* as the type, check the "retval" box, then give it the name returnval, and hit Add.
  10. Finally, go back to the Solution Explorer pane, find SimpleAdder.cpp, and open it. You should see that a stub for the Add method should have been added for you. Now just enter the code: *returnval = p1 + p2; just before the return statement.

What I did to Create the Flexsim Model
  1. Add a node into the Tools folder, give it text data, and toggle it as Global C++ (not C++, but Global C++). Then give it the text: #import "TestATLCOMObject.tlb". I can do this because I've put the tlb file in the same directory as the model. In version 5, the model directory is included as one of the include directories when compiling.
  2. Add a user command, give it the name COMAdd, specify the parameters as taking two number parameters, and in the code editor toggle it as C++, and give it the following code:
    Code:
    
    /**Call a COM object method*/
    // This is a static int, so its value is preserved across multiple calls 
    // to this function.
    static int initializedCOM = 0;
    if(!initializedCOM)
    {
      CoInitialize(NULL);
      initializedCOM = 1;
    }
    // declare a COM smart pointer to the simple adder interface 
    TestATLCOMObjectLib::ISimpleAdderPtr myAdder;
    // create an instance of the simple adder class
    myAdder.CreateInstance(__uuidof(TestATLCOMObjectLib::SimpleAdder));
    // get accessor values
    double p1 = parval(1);
    double p2 = parval(2);
    double returnval;
    // call the add method on the interface
    myAdder->Add(p1, p2, &returnval);
    // return the value
    return returnval;
    
  3. Apply, and compile the model, then test it by calling COMAdd() in the script console.
You can also implement this through a DLL if you like. Just move the user command's code into a DLL according to the instructions in the DLL wiki. In this case you will no longer need to use the Global C++ toggled node in the model, since you can just call the #import command directly in your DLL's c++ file at the global scope.
Attached Files
File Type: zip TestATLCOMObject.zip (90.3 KB, 156 views)
The Following 8 Users Say Thank You to Anthony Johnson For This Useful Post:
Steven Hamoen (05-18-2010)
  #6  
Old 05-11-2011
Mike Goebel's Avatar
Mike Goebel Mike Goebel is offline
Flexsim User
 
Join Date: Jul 2008
Posts: 3
Downloads: 27
Uploads: 0
Thanks: 4
Thanked 0 Times in 0 Posts
Rep Power: 0
Mike Goebel is on a distinguished road
Default I know that this is a year late but...

Thanks Anthony for the COM code and instructions. To make this brief, I cannot get the Usercommand to compile because of the following error:

1>.\all.cpp(7724) : error C2660: 'TestATLCOMObjectLib::ISimpleAdder::Add' : function does not take 3 arguments

It does not like the return parameter in the Add function (myAdder->Add(p1, p2, &returnval). When I remove returnval it compiles correctly but then doesn't return anything of course, as well as throwing an exception.

I am using your TestATLCOMObject code as is. I created the usercommand as a C++ node and created the GLobal C++ node to import the tlb file.

Any suggestions?

Thanks

EDITED: I found a solution. Replace the line myAdder->Add(p1, p2, &returnval);
with returnval = myAdder->Add(p1, p2);

Last edited by Mike Goebel; 05-11-2011 at 01:17 PM. Reason: Found a solution
  #7  
Old 05-12-2011
Anthony Johnson's Avatar
Anthony Johnson Anthony Johnson is offline
Manager of Product Development
 
Join Date: Jul 2007
Posts: 440
Downloads: 86
Uploads: 4
Thanks: 171
Thanked 899 Times in 288 Posts
Rep Power: 735
Anthony Johnson has a reputation beyond reputeAnthony Johnson has a reputation beyond reputeAnthony Johnson has a reputation beyond reputeAnthony Johnson has a reputation beyond reputeAnthony Johnson has a reputation beyond reputeAnthony Johnson has a reputation beyond reputeAnthony Johnson has a reputation beyond reputeAnthony Johnson has a reputation beyond reputeAnthony Johnson has a reputation beyond reputeAnthony Johnson has a reputation beyond reputeAnthony Johnson has a reputation beyond repute
Default

Yeah, I'm not an expert on all the ins and outs of COM, but I think it may be that the smart pointer type ISimpleAdderPtr creates new overloads that return the return value instead of taking it as a parameter. If you were to instead use a raw pointer (ISimpleAdder*), then I think you would use the 3 parameters interface.


Thread Thread Starter Forum Replies Last Post
Keep calling the same operator for transport Jorge Toucet Q&A 3 11-05-2008 01:27 PM


All times are GMT -6.
Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2020, vBulletin Solutions Inc.
Copyright 1993-2018 FlexSim Software Products, Inc.