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 Microsoft Visual Studio® to provide users with a standardized and flexible editor for creating and managing TwinCAT projects. When creating and/or accessing a TwinCAT configuration, Microsoft Visual Studio® and the TwinCAT Automation Interface can be used in combination. Example: If you want to create a new TwinCAT configuration via the Automation Interface, you must first call methods of the Visual Studio API to create a Visual Studio Solution Container and then add a TwinCAT project using the methods of the TwinCAT Automation Interface. This scenario is covered in some code snippets below.

Accessing TwinCAT configuration 1:

In addition, the Visual Studio API (the Visual Studio DTE) offers developers many other functions, e.g. access to the error output window. Further information on Visual Studio DTE can be found on 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 as ITcSysManager;

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).