Print Friendly and PDF

Tutorial: Linking GoldSim to a DLL (C++)

Jason -

The purpose of this tutorial is to help you become comfortable with writing and compiling a DLL that can interface with a GoldSim model. It begins with setup of the programming environment, followed by building a simple standalone program that can be run from a command line. Knowing how to do this is an introductory step but can be skipped if you are already familiar with compiling C programs. To dive right into creating a DLL, please skip to the section called "Linking an Executable to a DLL".

Picture1.png

The tutorial is divided up into the following sections:

This tutorial assumes you are using MS Visual Studio Community 2017. Other versions of Visual Studio should work as well but the configuration might be slightly different. This tutorial assumes you have some experience with GoldSim. It is extremely helpful to have some familiarity with C++ but not necessary to complete the tutorial. Either before or after this tutorial, we recommend that you spend some time with introductory documentation if you plan to build DLLs that interact with GoldSim. Here are some good places to start:

  • http://www.cplusplus.com/doc/tutorial/
  • https://msdn.microsoft.com/en-us/library/1ez7dh12.aspx
  • https://www.visualstudio.com/vs/getting-started/

By the end of this tutorial, you will have a working GoldSim model that interacts dynamically with an external program.

Installation and Configuration

At a bare minimum, you need to have a C++ compiler and text editor to complete this tutorial. We will use a free version of Visual Studio for this tutorial but you are free to use any of your choosing. If you already have an editor and compiler, skip to the section "Write the Program".

  1. Download and install Visual Studio Community 2017 
  2. Make sure to select Visual Studio for desktop Windows applications when asked. You will need to choose between the different flavors (i.e. Web, Windows 8, Desktop, Phone, etc.). 
  3. It is also recommended that you only download what you need for building and debugging Win32-based desktop applications. Below is a screen capture showing the options selected for this recommendation.  desktopoptions
  4. You should expect the installation to take a while (approximately 1 hour). You should also reboot the computer after completion. Once complete, you should see Visual Studio listed in programs

Create a Visual Studio Project

These steps are needed for those using the Visual Studio IDE. If you are using a different platform already, please skip to the next section.

  1. Open Visual Studio and take note of the layout. You will see a Solution Explorer on the left, the main editor pane in the center. 
  2. In the File menu, select New, Project... then select "Windows Console Application"
  3. Give your project a name (I named the project "MyFirstProject"), select a location to save the project, and press OK. You should leave the box checked next to “Create directory for solution” if you plan to create additional projects within the parent directory. 
  4. You now have an open project. By default, you should have a window that looks something like what you see below, with the Editor Pane, Solution Explorer, and the Output Window. There are various ways to organize the panes and you can turn different ones on or off, depending on your needs. 
  5. We are now ready to write the program.

Write a Standalone Program

Before we dive into creating a DLL, we should write, build, and run a standalone program to make sure it is working. If you feel comfortable with this step, continue to the next section.

  1. In the code editor of the file called "MyFirstProject.cpp", write the following code: 
    // MyFirstProject.cpp : Defines the entry point for the console application.
    //


    #include "stdafx.h"
    #include <iostream>
    using namespace std;


    int main()
    {
        cout << "Hello, World!" << endl;

        return 0;
    }
  2. Here is what my code looks like entered into the source file in the editor pane:

  3. Click on the “Build” menu and select “Build Solution”. 
  4. Note the build log should indicate that it built successfully. 
  5. Take a moment to review the files and subdirectories that Visual Studio has created for this project. You should see a main project folder, which is the name of your project as shown in the screen capture below. A subdirectory with the same name as your project contains the source files and another directory called “Debug” contains the output files including the Windows executable. 
  6. Inside the “Debug” folder, you will see the Windows executable program we just created. It is important to note that your program’s location is dependant on the project’s configuration. If you set it to build into “Debug” mode, then your executable will be saved in the “Debug” directory. 
  7. Let’s try running the Hello World program we just created. This program must be run from the Windows command line terminal, which is started by going to the Start Menu, and typing 'cmd'. I copied the program to my Desktop so I can run it from there as a standalone program. Type the name of the executable and press enter (I would type MyFirstProject.exe). It should print ‘Hello world!’ to the console. 
  8. Another way to run your program is from within Visual Studio from the Tools, NuGet Package Manager Console: 
  9. At the bottom of the window, you should now see the console up and running. I entered the command “dir” to review the directories at this location. 
  10. Type the name of the program (MyFirstProject.exe) and hit “Enter”. 
  11. Now you have a running program using C++.

Create a Dynamic Link Library (DLL)

Now that you have been introduced to writing and compiling a very basic console program in Visual Studio, it is time to create a DLL program. Let’s create a DLL that will link to first program created in the previous section (MyFirstProject.exe). The purpose of this DLL is to provide a library containing 1 or more functions that can be called from the main program “MyFirstProject.exe” dynamically.

  1. Let’s start by creating a new project that will reside in the same solution we created before. Open the solution “MyFirstProject”. You should see the Solution name at the top of the Solution Explorer. It will show that you currently have 1 project in this solution. 
  2. Right-click the 'Solution 'MyFirstProject' and Select Add -> New Project... (alternatively, you could go to File -> Add -> New Project...).
  3. This will open the New Project Wizard. Find and click on the "Empty Project" template and give it a name like "MyLibrary" then click OK.
  4. You should now see an empty project. Right click on the "MyLibrary" project (in the browser tree) and click on Properties. 
  5. Go to the "General" section of 'Configuration Properties' and change the ‘Configuration Type’ from 'Application (.exe)' to 'Dynamic Library (.dll)' (see image below). Click OK.
  6. Add a header file to the project. Right-click the 'Header Files' folder under the heading of your new project and select Add -> New Item.... Select the option 'Header File (.h)' and name your file something like “lib.h” (Note that the appropriate file suffix ie .h will be added automatically. You don’t need to type the suffix yourself.) 
  7. Add the source code to the DLL. Right-click the 'Source Files' folder under the heading of your new project and select Add -> New Item.... Select the option 'C++ File (.cpp)' and name your file the same as your header file (“lib.cpp”).
  8. You should now see the following files in your solution explorer. 
  9. Type the following code in the header file:
    #include <string>
    #include <iostream>
    using namespace std;


    __declspec(dllexport) void PrintGreeting(string my_name);

  10. This function will rely on 2 C++ standard libraries (<string> and <iostream>)
    • The #include directives tell the compiler (actually the preprocessor) to treat these libraries as if they appear in the source at this location so that their functionalities are available for use. The third directive is calling the "std" container so that identifiers in std can be called without repeating the name "std".
    • __declspec(dllexport) allows the compiler to generate the export names automatically and place them in a .LIB file. This .LIB file will be used just like a static .LIB to link with a DLL.
    • Our function is called “PrintGreeting” and is intended to print a nice greeting directed at a name that is supplied to the command line terminal screen. The function takes 1 argument as a string, which is the name it is going to print. You will see that the name "PrintGreeting" will be underlined in green because the function has not yet been defined in our source code. Let's add it to the lib.cpp file now.
  11. Type the following code in the source file “lib.cpp”. Note this code will call the "lib.h" file we created in the previous step.

    #include "lib.h"

    void PrintGreeting(string my_name)

    {
        cout << "Oh, hello there, " << my_name << "." << endl;
    }

  12. It should appear like this in your editor pane: 
  13. We are now ready to build our DLL! Right-click the project name in the browser tree and select the option to ‘Build’. It should build successfully. 
  14. The resulting DLL should now be located in the same 'Debug' folder as the .exe 
  15. We cannot run the DLL standalone but it needs to be called from a main executable program. Let's modify our original MyFirstProject.exe program so that it links to the DLL and uses it to execute the DLL's functionality.

Link a Program to a DLL

Now we have a main executable program (which acts like a GoldSim model) that we will want to link to the new DLL. We need to do this by calling the function in the library and also by creating a link between the two. In this example, we'll link our executable (MyFirstProject) to the library we just created.

  1. We need to modify the source code of our executable program “Hello World” so that it includes the header file of our DLL. Go back to 'Hello World.cpp'. Add two lines: (1) type #include "lib.h" above or below the line that has #include <iostream> and (2) type PrintGreeting( "Jason" ); somewhere inside the main function so that your code looks something like this:

    #include "stdafx.h"
    #include "lib.h"


    int main()

    {
        cout << "Hello, World!" << endl;
        PrintGreeting("Jason");

        return 0;
    }

  2. Now we just need to make sure (1) when you build the entire solution, that the project 'MyLibrary', which creates the library, builds before the executable (since the executable depends on the library) and (2) when the executable builds, it is able to find the header file "MyLibrary.h" and find a file called "MyLibrary.lib". This is required to create the link between the executable and the library.
  3. Right-click the ‘MyFirstProject’ item in the browser tree and select 'Properties'. Make sure that you are building to Win32 and that it’s consistent with the DLL build.  
  4. Go into Configuration Properties -> C/C++ -> General, click on the drop-list arrow at the right side of the 'Additional Include Directories' field, select <Edit...>, click the folder icon and browse to the 'MyLibrary' folder where the header file is located ("MyLibrary.h"). On my machine, the full path is ("C:\Users\rroper\Documents\Visual Studio 2010\Projects\TryVisualStudio\MyLibrary"). That will make it so the compiler can find the appropriate header file. Alternatively, you can just use a relative path (..\MyLibrary).
  5. Now go into Configuration Properties -> Linker -> General, click on the drop-list arrow at the right side of the 'Additional Library Directories' field, select <Edit...>, click the folder icon and browse to the main 'Debug' folder where your .exe and your .dll built to. On my machine, the path is "C:\Users\rroper\Documents\Visual Studio 2010\Projects\TryVisualStudio\Debug". Alternatively, you can just use a relative path (..\Debug). After you've selected the appropriate folder, press OK. 
  6. Now we need to provide the name of the .lib file so it can be found when building the solution. Go into Configuration Properties -> Linker -> Input, click the drop-list arrow at the right side of the 'Additional Dependencies' field, click <Edit...> and simply type MyLibrary.lib (assuming you named the library project 'MyLibrary') in the input field and press OK. 
  7. You've now told Visual C++ where to find the header file ('MyLibrary.h') and the name of the .lib file (for linking), 'MyLibrary.lib', and its location. These are standard steps in any build environment for linking an executable to a .dll or for linking a .dll to another .dll. You always need to specify the locations of header files and the locations and names of .lib files.
  8. Ensure that Visual C++ always builds the library before it then builds the executable (since the executable depends on the .dll). Right-click the top-level item in the browser tree ("Solution 'MyFirstProject' (2 Projects)") and select 'Properties'. 
  9. Select Common Properties -> Project Dependencies. From the drop-list labeled 'Project:', select 'MyFirstProject' (or whatever your executable project name is). In the 'Depends on:' field, check the box next to 'MyLibrary' (or whatever the name of your library project is). Press OK. 
  10. At this point, you should be able to right-click on the solution name in the browser tree, which is the top-level item, and select 'Rebuild Solution'. If we've done everything correctly, it should build successfully and display the following at the end of the build log: "Rebuild All: 2 succeeded, 0 failed, 0 skipped". 
  11. Now go back to that command prompt or Visual Studio Package Manager Console and be sure that you're still in the 'Debug' directory that we originally changed to. Run your executable. In my case, I would type "MyFirstProject.exe". When it executes, you should see two lines of text, one that says "Hello world!" and the other that says "Oh, hello there, Jason". That second line means that our executable successfully called the 'PrintMessage' function from our DLL! Amazing stuff, right? 
  12. Now that we have a working program that depends on a DLL for a function, we are now ready to extend our program to work just like a GoldSim model that interacts with a DLL by sending input data to the DLL and return output values back.

Send Data To/From DLL

The next part of this tutorial will allow your main executable program to send data to the DLL, have it use this data in a function and return output to the main program for printing results to the console. This will mimic how GoldSim works with a DLL.

  1. Modify the DLL function as declared in the header file ("lib.h") to return a number and take 2 numbers as input. Also, change the name of the function to "AddNumbers". The <string> library is no longer needed in this program so you should remove it.

    #include <iostream>
    using namespace std;


    __declspec(dllexport) double AddNumbers(double num1, double num2);

  2. Change the function in the lib.cpp file as well.

    #include "lib.h"

    double AddNumbers(double num1, double num2)

    {
        return num1 + num2;
    }

  3. Change the code in the main executable to use this DLL functionality.

    #include "stdafx.h"
    #include "lib.h"


    int main()

    {
        double num1, num2;
        cout << "This program will add 2 numbers!" << endl;
        cout << "Enter your first number:" << endl;
        cin >> num1;
        cout << "Now, enter your second number:" << endl;
        cin >> num2;

        cout << "The answer is " << AddNumbers(num1, num2) << endl;
        return 0;

    }

  4. Rebuild the solution. 
  5. Now execute the program from within a console that is started from the Debug directory. 
  6. This program works similarly to how GoldSim will work when you run a simulation that sends data to the DLL via the External element interface.

Link a GoldSim Model to a DLL

In this next part of the tutorial, we will create a DLL in a similar fashion to that created in the previous steps but it will have some additional functionality and definitions that GoldSim requires. We will write a DLL that has a function that adds 2 numbers and returns the sum. GoldSim will provide the 2 numbers to the DLL and the DLL will return the sum back to GoldSim.

  1. Right click on the solution in the Solution Explorer and select Add, New Project...
  2. Select the Empty Project and give it a name like "GoldSimDLL" then click OK to create the new project in this solution
  3. You should now see an empty project. Right click on the "GoldSimDLL" project (in the browser tree) and click on Properties. 
  4. Go to the "General" section of 'Configuration Properties' and change the ‘Configuration Type’ from 'Application (.exe)' to 'Dynamic Library (.dll)' (see image below). Click OK.
  5. Add a new header file to the GoldSimDLL project and give it a name like "GoldSimHeader.h".
  6. Add a new function "AddNumbers" to the header file ("GoldSimHeader.h") to return a double and take 2 doubles as input. The function declaration should look like this:

    __declspec(dllexport) double AddNumbers(double num1, double num2);

  7. Create a new cpp file that will define this function. We may want to add more functions later, so let's call this file "Functions.cpp" 
  8. Write the function in the "Functions.cpp" file as shown below.

    #include "Functions.h"

    double AddNumbers(double num1, double num2)

    {
        return num1 + num2;
    }

  9. Now that we have the function defined and ready to use, we need to make it accessible to the GoldSim model. GoldSim requires that certain functions be carried out during the process of interacting with the DLL so we need to provide some return values as these functions are being carried out. These functions include initialization, reporting the version number, reporting the number of inputs/outputs, and reporting an error message. You can read more about these functions in Appendix X of this document.
  10. Create a second source file in the GoldSimDLL project. 
  11. Call this file "Interface.cpp" since it will work as the interface between your new AddNumbers function and GoldSim. Now, write the following code into the Interface.cpp file.

    #include "GoldSimHeader.h"

    extern "C" void __declspec(dllexport) GoldSimDLLFunctions(int methodID, int* status, double* inargs, double* outargs)

    {
        *status = 0;

        switch (methodID)
        {
         case 0: // Initialize (called at beginning of each realization)
             break;

            case 1: // Perform function calls
            outargs[0] = AddNumbers(inargs[0], inargs[1]);
            break;

            case 2: // Version number of the DLL
            outargs[0] = 1.03;
            break;

            case 3: // Number of input and output arguments
            outargs[0] = 2.0; // Number of inputs
            outargs[1] = 1.0; // Number of outputs
            break;

            case 99: // Optionally release any memory that's been allocated
            break;

            default: // Error if this point is reached
            *status = 1;
            break;

        }
    }

  12. Every external function in GoldSim must have the 5 cases (0, 1, 2, 3, and 99). Case 1 is where you call the function that we defined in the "Functions.cpp" file.
  13. Right click on the "GoldSim DLL" project and click on "Build". You should see that the project builds without any errors. The DLL is now ready for use and can be found in the Debug folder of your project directory. 
  14. Create a new GoldSim model and save it in that same directory. 
  15. In the GoldSim model, add a new External element and refer to the name of the DLL. 
  16. Add the name of our function "GoldSimDLLFunctions" into the Function Name field. 
  17. Add 2 new Data elements to the model (A and B) then add them to the input interface of the External element. 
  18. Add a single output definition to the output side of the interface and give it the name "Sum". This is where the DLL output will be returned to. 
  19. Now, run the GoldSim model and view the results of the External element. You should see the value of "Sum" is what is expected when the values A and B are added. 

This concludes the tutorial. At this point, you can continue adding functions to the DLL and use them in GoldSim through the External element's interface. If you have any questions, feel free to comment on this article or ask on our Community Forum.

 

 

 

 

 

 

 

 

 

Tags:

  • c++
  • programming
  • DLL
  • external
  • code
  • link
  • tutorial
Have more questions? Submit a request

Comments