Determining the file path of a TwinCAT project

This chapter shows two ways to determine the file path of a TwinCAT project:

Path to the .tsproj file via DTE

SolutionBuild.BuildProject requires the file path of the TwinCAT project. This can be determined using the FileName property of the DTE Project object.

C#:

EnvDTE.DTE dte = (EnvDTE.DTE)Marshal.GetActiveObject("TcXaeShell.DTE.17.0");

foreach (EnvDTE.Project project in dte.Solution.Projects)
{
    // FileName returns the full path to the .tsproj file
    string projectPath = project.FileName;
    Console.WriteLine(projectPath);
    // Output e.g.: C:\Projects\MyProject\MyProject.tsproj
}

PowerShell:

$dte = [Runtime.InteropServices.Marshal]::GetActiveObject("TcXaeShell.DTE.17.0")

foreach ($project in $dte.Solution.Projects) {
    $projectPath = $project.FileName
    Write-Host $projectPath
}

# For use with SolutionBuild.BuildProject
$dte.Solution.SolutionBuild.BuildProject(
    "Debug|TwinCAT RT (x64)",  # ConfigurationName
    $projectPath,               # ProjectUniqueName (FileName or UniqueName)
    $true                       # WaitForBuildToFinish
)

Path to the .plcproj file via ProduceXml

The path to the .plcproj file for a PLC project is not directly accessible via DTE. Instead, the PLC node TIPC is iterated over, and the ProjectPath value is read from the XML of each PLC child object.

ITcSmTreeItem plcNode = sysMan.LookupTreeItem("TIPC");

// Dictionary [key = project name | value = project file path]
Dictionary<string, string> projectPaths = [];

int padWidth = plcNode.ChildCount.ToString().Length;
int maxNameLength = Enumerable.Range(1, plcNode.ChildCount).Max(i => plcNode.Child[i].Name.Length);

// Iterate through all PLC projects and extract their project paths and names
for (int i = 1; i <= plcNode.ChildCount; i++)
{
    var child = plcNode.Child[i];
    var doc = XDocument.Parse(child.ProduceXml());
    string projectPath = doc.Descendants("ProjectPath").FirstOrDefault()?.Value ?? "Unknown";
    projectPaths.Add(child.Name, projectPath);
    Console.WriteLine($"{i.ToString().PadLeft(padWidth)}: Project Name: {child.Name.PadRight(maxNameLength)}, Project Path: {projectPath}");
}