Accessing TwinCAT configuration

This chapter describes how to create and access a TwinCAT XAE configuration project via Automation interface. The objective of this creation process is to get access to a TwinCAT XAE project (formerly known as a TwinCAT System Manager configuration). The new TwinCAT XAE project is more sophisticated than the TwinCAT System Manager configuration known from TwinCAT2, which implies a slight concept change of project / configuration handling. TwinCAT 3 supports an extra hierarchical level combining several configurations into a Visual Studio solution container. This can for example be used to organize the configurations of distributed resources into a solution or for packaging HMI projects together with the system configuration. The solution is able to bind together all types of Visual Studio and/or TwinCAT XAE projects. When using the TwinCAT XAE Automation inferface, this means an extra level of possiblities.

Basic information

TwinCAT 3 has been fully integrated into Visual Studio to provide users with a standardized and most flexible editor to create and manage TwinCAT projects. To create and/or access a TwinCAT configuration, the combined use of Visual Studio and TwinCAT Automation Interface is possible. For example: If you want to create a new TwinCAT configuration via Automation Interface, you first need to call methods of the Visual Studio API to create a Visual Studio solution container and then add a TwinCAT project by using methods of the TwinCAT Automation Interface. This scenario will be covered in some code snippets below.

Accessing TwinCAT configuration 1:

In addition, the Visual Studio API (so-called Visual Studio DTE ) provide developers with many more features, e.g. accessing the error output window. For more information about Visual Studio DTE please see the Microsoft MSDN website.

Please note:

Creating TwinCAT Projects via templates

Please note that you need to add a reference to the COM object TcatSysManagerLib and EnvDTE.DTE (Microsoft Developement) in order to be able to use the TwinCAT Automation Interface and the Visual Studio API. The ProgID that is used in the GetTypeFromProdID() method depends on the Visual Studio version that should be used. Please have a look at this documentation article for more information about the different ProgIDs.

Code Snippet (C#):

Type t = System.Type.GetTypeFromProgID("VisualStudio.DTE.10.0");
EnvDTE.DTE dte = System.Activator.CreateInstance(t);

dte.SuppressUI = false;
dte.MainWindow.Visible = true;

if (Directory.Exists(@"C:\Temp\SolutionFolder"))
     Directory.Delete(@"C:\Temp\SolutionFolder", true);
Directory.CreateDirectory(@"C:\Temp\SolutionFolder");
Directory.CreateDirectory(@"C:\Temp\SolutionFolder\MySolution1");

dynamic solution = dte.Solution;
solution.Create(@"C:\Temp\SolutionFolder", "MySolution1");
solution.SaveAs(@"C:\Temp\SolutionFolder\MySolution1\MySolution1.sln");

string template = @"C:\TwinCAT\3.1\Components\Base\PrjTemplate\TwinCAT Project.tsproj"; //path to project template
dynamic project = solution.AddFromTemplate(template, @"C:\Temp\SolutionFolder\MySolution1", "MyProject");

ITcSysManager sysManager = project.Object;

sysManager.ActivateConfiguration();
sysManager.StartRestartTwinCAT();

project.Save();
solution.SaveAs(@"C:\Temp\SolutionFolder\MySolution1\MySolution1.sln");

Code Snippet (Powershell):

You can copy and paste the following code snippet into a textfile and save it as "someName.ps1". After that you can execute it directly via Windows PowerShell.

$targetDir = "C:\tmp\TestSolution"
$targetName = "TestSolution.tsp"
$template = "C:\TwinCAT\3.1\Components\Base\PrjTemplate\TwinCAT Project.tsproj"

$dte = new-object -com VisualStudio.DTE.10.0
$dte.SuppressUI = $false
$dte.MainWindow.Visible = $true

if(test-path $targetDir -pathtype container)
{
     Remove-Item $targetDir -Recurse -Force
}

New-Item $targetDir –type directory

$sln = $dte.Solution
$project = $sln.AddFromTemplate($template,$targetDir,$targetName)
$systemManager = $project.Object

$targetNetId = $systemManager.GetTargetNetId()
write-host $targetNetId

$systemManager.ActivateConfiguration()
$systemManager.StartRestartTwinCAT()

$project.Save()
$solutionPath = $targetDir + "\" + $targetName
$sln.SaveAs($solutionPath)

Code Snippet (C++):

Within appropriate Header file (e.g the stdafx.h):

//the following #import imports EnvDTE based on its LIBID.
#import"libid:80cc9f66-e7d8-4ddd-85b6-d9e6cd0e93e2" version("10.0") lcid("0") raw_interfaces_only named_guids
// Imports die "Beckhoff TCatSysManager 1.1 Type Library"
#import"libid:3C49D6C3-93DC-11D0-B162-00A0248C244B" version("1.1") lcid("0")

Because a known issue within VisualStudio 2010 (SP1), the generated proxy code will not be included into the C++ project. Please use the workaround described in #import Known Issue import Known Issue.

#include 

using namespace std
using namespace TCatSysManagerLib;
using namespace EnvDTE;

int _tmain(int argc, _TCHAR* argv[])
{
    CoInitialize(NULL); // COM initialisieren
    cout << "Creating VisualSTudio.DTE.10.0 ...";

    // creating a new instance of Visual Studio
    CComPtr<_DTE> m_pDTE;
    HRESULT hr = m_pDTE.CoCreateInstance(L"VisualStudio.DTE.10.0", 0, CLSCTX_ALL);
    if (FAILED(hr)) { cout << " FAILED"; return 1; }
    cout << " created." << endl;

    // retrieves the EnvDTE.Solution-Objekt
    CComPtr<_Solution> pSolution;
    m_pDTE->get_Solution(&pSolution);
    CComBSTR strSolutionFolder(_T("C:\\SolutionFolder")); // Solution-main directory (has to exist)
    CComBSTR strSolutionName(_T("MySolution1"));
    CComBSTR strTemplatePath(_T("C:\\TwinCAT\\3.1\\Components\\Base\\PrjTemplate\\TwinCAT Project.tsproj"));

    CComBSTR strSolutionPath; // Solution-Pfad (doesn’t exist!)
    strSolutionPath=strSolutionFolder;
    strSolutionPath.Append(_T("\\"));
    strSolutionPath.Append(strSolutionName);
    strSolutionPath.Append(_T(".sln"));

    // create the solution
    hr = pSolution->Create(strSolutionFolder,strSolutionName);
    CComBSTR strProjectPath(strSolutionFolder); // project path
    strProjectPath.Append(_T("\\"));
    strProjectPath.Append(strSolutionName);
    CComBSTR strProjectName = "MyProject"; // project name // create projekt from a template
    CComPtr pProject;
    hr = pSolution->AddFromTemplate(strTemplatePath,strProjectPath,strProjectName,VARIANT_FALSE,&pProject);
    // Wenn z.B. Projekt bereits besteht >> error
    if (FAILED(hr)) { cout << " Project creation FAILED"; return 1; }
    cout << "Project created" << endl;

    // define project automation class (here the Coclass TcSysManager)
    CComPtr pDispatch;
    hr = pProject->get_Object(&pDispatch);

    // retrieve ITcSysManager interface
    CComPtr pSystemManager;
    hr = pDispatch.QueryInterface(&pSystemManager);
    
    // operate with SystemManager interface
    CComBSTR netId;
    netId = (pSystemManager->GetTargetNetId()).GetBSTR();
    cout << "TargetNetId: " << netId << endl;
    hr = pSystemManager->ActivateConfiguration();
    hr = pSystemManager->StartRestartTwinCAT();

    // save project and solution
    hr = pProject->Save(CComBSTR());
    hr = pSolution->SaveAs(strSolutionPath);
    cout << "Succeeded";
    return 0;
}

import Known Issue:

    CComPtr<_DTE> m_pDTE;
    CLSID clsid;
    CLSIDFromProgID(L"VisualStudio.DTE.10.0",&clsid);
    CComPtr punk;
    HRESULT hr = GetActiveObject(clsid,NULL,&punk); // retrieve actual instance of Visual Studio .NET
    m_pDTE = punk;

Please note:

ITcSysManager::NewConfiguration, ITcSysManager::OpenConfiguraiton and ITcSysManager::SaveConfiguration will create error messages in this case, because the project handling is delegated to the Visual Studio IDE (the Solution and Project instances realized by the DTE object).