When creating TwinCAT software I’ve come across a use case where I want to print out and store the actual version of the project that the program resides in. This can be pretty neat when you do version control, and for instance create a release of your program and want this information available somewhere in the output of the program. I’ve had this scenario when we had a project that was continuously updated. The test/integration team needed constant bug fixes/new software releases. As a software engineer I needed to keep track of what version the test/integration team were actually running at a specific time. By updating the version number in the project information I was being able to log the actual running version of the software in a database, which is important to know when going back to fault trace any strange behavior in a particular test.

The actual information is available under Project ➡️ properties in Visual Studio 2015.

Menu project properties

This will give you the following:

Project properties common

Now, how do you access this from PLC-code? To start with, for libraries this is easy and is actually documented in the Beckhoff documentation. Here you are supposed to use the type ST_LibVersion, and Beckhoff documentation explicitly states

Each library contains a global structure of this data type. This struct type provides the following data:

TYPE ST_LibVersion : 
STRUCT
    iMajor    : UINT;
    iMinor    : UINT;
    iBuild    : UINT;
    iRevision : UINT;
    sVersion  : STRING(23);
END_STRUCT
END_TYPE

For instance, if you need access to the version of the commonly used TC2_Standard-library:

VAR
    sVersion : STRING(23);
END_VAR
--------------------------
sVersion := stLibVersion_Tc2_Standard;

stLibVersion_Tc2_Standard is defined as a constant global variable in the project library. In this case it will for instance give you the string ‘3.3.1.0'.

Now, what if you want to include the version of your running program (not library!) that you have defined in your project properties? Because your program is not a library this constant global variable is not available per default as in library projects. What you need to do is to click Add next to POUs for property access under the project properties.

Project properties common POUs

This will create the folder Project Information and the three functions F_GetCompany(), F_GetTitle() and F_GetVersion() in your project. Opening F_GetVersion() gives the following:

F_GetVersion()

Perfect, a function returning a ST_LibVersion structure holding the Major/Minor/Build/Revision numbers! Even though the ST_LibVersion in itself holds a String(23), for some reason this is not included in the call to F_GetVersion() (at least not in TwinCAT 3.1.4020.28). Whether this is a bug or not is unknown to me. If you update the project information, this function automatically gets updated with the correct numbers! Now that we have access to this information by calling this function in our own program, we can easily convert this to a string by a mixture of UDINT_TO_STRING and CONCAT.

VAR
    sVersion : STRING(23);
    stProgramVersion : ST_LibVersion;
END_VAR
-------------------------------------
stProgramVersion := F_GetVersion();
 
sVersion := CONCAT(UDINT_TO_STRING(stProgramVersion.iMajor), '.');
sVersion := CONCAT(sVersion, UDINT_TO_STRING(stProgramVersion.iMinor));
sVersion := CONCAT(sVersion, '.');
sVersion := CONCAT(sVersion, UDINT_TO_STRING(stProgramVersion.iBuild));
sVersion := CONCAT(sVersion, '.');
sVersion := CONCAT(sVersion, UDINT_TO_STRING(stProgramVersion.iRevision));

Running this code gives the end result:

String program version