├── HeadlessExample.2021 ├── HeadlessExample.ini ├── App.config ├── HeadlessExample.2021.csproj └── Program.cs ├── README.md ├── .gitignore ├── HeadlessExample.sln ├── LICENSE └── .github └── workflows └── contrast_security_app.yaml /HeadlessExample.2021/HeadlessExample.ini: -------------------------------------------------------------------------------- 1 | /** HeadlessExample.ini */ 2 | call %cd%teklastructures.ini 3 | 4 | set XS_LOG_LEVEL=WARNING 5 | 6 | 7 | -------------------------------------------------------------------------------- /HeadlessExample.2021/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HeadlessTeklaStructuresExample 2 | This example shows how to use Headless Tekla Structures to interact with model without opening TS UI. 3 | 4 | ## Licensing 5 | Currently on Flex is supported. Start TS with flex, close TS and Headless applications can be run. -------------------------------------------------------------------------------- /HeadlessExample.2021/HeadlessExample.2021.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net48 4 | ..\BuildDrop 5 | x64 6 | Exe 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #ignore thumbnails created by windows 2 | Thumbs.db 3 | 4 | # Ignore files built by Visual Studio 5 | *.aps 6 | *.bak 7 | *.bu 8 | *.cache 9 | *.DotSettings 10 | *.idb 11 | *.ilk 12 | *.log 13 | *.metaproj 14 | *.ncb 15 | *.obj 16 | *.opensdf 17 | *.pch 18 | *.pdb 19 | *.sbr 20 | *.sdf 21 | *.sonar 22 | *.suo 23 | *.tlb 24 | *.tlh 25 | *.tmp 26 | *.user 27 | *.vspscc 28 | *.vsscc 29 | *_p.c 30 | 31 | # Developer tool generated files 32 | *My Amplifier XE Results - * 33 | *My Inspector XE Results - * 34 | *StyleCop.Cache 35 | *.orig 36 | *.rej 37 | *unittest-report* 38 | 39 | #Movies 40 | *.avi 41 | *.mkv 42 | *.mpg 43 | 44 | #Folders with generated stuff 45 | packages/ 46 | obj/ 47 | [Dd]ebug/ 48 | [Rr]elease/ 49 | [Tt]est[Rr]esult*/ 50 | 51 | # Other version control 52 | .svn/ 53 | *.MySCMServerInfo 54 | 55 | 56 | /BuildDrop/ 57 | /.vs/ 58 | -------------------------------------------------------------------------------- /HeadlessExample.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.32126.317 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HeadlessExample.2021", "HeadlessExample.2021\HeadlessExample.2021.csproj", "{9AFC3EEF-658B-4901-938E-C5A93EF49973}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {9AFC3EEF-658B-4901-938E-C5A93EF49973}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {9AFC3EEF-658B-4901-938E-C5A93EF49973}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {9AFC3EEF-658B-4901-938E-C5A93EF49973}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {9AFC3EEF-658B-4901-938E-C5A93EF49973}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {E9BBD204-26CA-43B1-AD3E-E8B89D310222} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2018, Tekla Structures 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /.github/workflows/contrast_security_app.yaml: -------------------------------------------------------------------------------- 1 | # DISCLAIMER: This workflow file has been auto-generated and committed to the repo by the GitHub App from Contrast Security. 2 | # Manual edits to this file could cause the integration to produce unexpected behavior or break. 3 | # Version: 1.0.0 4 | # Last updated: 2024-02-13T15:58:06.296050105Z 5 | name: Contrast Security App Workflow 6 | on: 7 | workflow_dispatch: 8 | push: 9 | branches: 10 | - master 11 | pull_request: 12 | types: [opened, synchronize, reopened] 13 | branches: 14 | - master 15 | jobs: 16 | fingerprint_repo: 17 | if: ${{ github.actor != 'dependabot[bot]' }} 18 | runs-on: ubuntu-22.04 19 | steps: 20 | - name: Clone repository 21 | uses: actions/checkout@v3 22 | - name: Run Contrast SCA Fingerprint 23 | id: fingerprint 24 | uses: 'Contrast-Security-OSS/contrast-sca-action@v2' 25 | with: 26 | apiKey: ${{ secrets.CONTRAST_GITHUB_APP_API_KEY }} 27 | authHeader: ${{ secrets.CONTRAST_GITHUB_APP_AUTH_HEADER }} 28 | orgId: ${{ vars.CONTRAST_GITHUB_APP_ORG_ID }} 29 | apiUrl: ${{ vars.CONTRAST_GITHUB_APP_TS_URL }} 30 | repoUrl: ${{ github.server_url }}/${{ github.repository }} 31 | repoName: ${{ github.repository }} 32 | externalId: ${{ vars.CONTRAST_GITHUB_APP_ID }} 33 | command: fingerprint 34 | outputs: 35 | fingerprint: ${{ steps.fingerprint.outputs.fingerprint }} 36 | analyze_dependencies: 37 | if: ${{ needs.fingerprint_repo.outputs.fingerprint != '' }} 38 | needs: fingerprint_repo 39 | runs-on: ubuntu-22.04 40 | strategy: 41 | fail-fast: false 42 | matrix: 43 | manifest: 44 | - ${{ fromJson(needs.fingerprint_repo.outputs.fingerprint) }} 45 | steps: 46 | - name: Clone repository 47 | uses: actions/checkout@v3 48 | - name: Run Contrast SCA Audit 49 | uses: 'Contrast-Security-OSS/contrast-sca-action@v2' 50 | with: 51 | apiKey: ${{ secrets.CONTRAST_GITHUB_APP_API_KEY }} 52 | authHeader: ${{ secrets.CONTRAST_GITHUB_APP_AUTH_HEADER }} 53 | orgId: ${{ vars.CONTRAST_GITHUB_APP_ORG_ID }} 54 | apiUrl: ${{ vars.CONTRAST_GITHUB_APP_TS_URL }} 55 | filePath: ${{ matrix.manifest.filePath }} 56 | repositoryId: ${{ matrix.manifest.repositoryId }} 57 | projectGroupId: ${{ matrix.manifest.projectGroupId }} 58 | -------------------------------------------------------------------------------- /HeadlessExample.2021/Program.cs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------------------------- 2 | // 3 | // 4 | // -------------------------------------------------------------------------------------------------------------------- 5 | namespace HeadlessExample 6 | { 7 | using System; 8 | using System.IO; 9 | using System.Reflection; 10 | 11 | using Tekla.Structures.Model; 12 | using Tekla.Structures.Service; 13 | 14 | class Program 15 | { 16 | /// 17 | /// Main entry point 18 | /// 19 | /// additional version field: Ex: HeadlessExample.2021.exe 2021.0 for running example against 2021 version of ts 20 | static void Main(string[] args) 21 | { 22 | // default ts to use. change to 2021 as example. 23 | var tsVersion = "2022.0"; 24 | if (args.Length != 0) 25 | { 26 | tsVersion = args[0]; 27 | } 28 | 29 | var binDir = $@"C:\Program Files\Tekla Structures\{tsVersion}\bin"; 30 | if (tsVersion.Equals("2021.0")) 31 | { 32 | // backwards compitbility 33 | binDir = $@"C:\Program Files\Tekla Structures\{tsVersion}\nt\bin"; 34 | } 35 | 36 | ConfigureHeadlessIniFiles(binDir); 37 | 38 | AppDomain.CurrentDomain.AssemblyResolve += (s, a) => CurrentDomainAssemblyResolve(a, binDir); 39 | // TeklaStructuresService needs to know the location of the TS binaries. 40 | // additionally we need to set a resolver to load dlls from binary folder 41 | using (var service = new TeklaStructuresService( 42 | new DirectoryInfo(binDir), 43 | "ENGLISH", 44 | new FileInfo($@"C:\ProgramData\Trimble\Tekla Structures\{tsVersion}\Environments\default\env_Default_environment.ini"), 45 | new FileInfo($@"C:\ProgramData\Trimble\Tekla Structures\{tsVersion}\Environments\default\role_Steel_Detailer.ini"))) 46 | { 47 | // change for model path 48 | var modelPath = @"C:\TeklaStructuresModels\New model"; 49 | // see Initialize for role, license and identity 50 | service.Initialize(new DirectoryInfo(modelPath)); 51 | 52 | //!IMPORTANT NOTICE! 53 | //!IMPORTANT NOTICE! 54 | //!IMPORTANT NOTICE! 55 | //You cannot run the above code when in debugger. 56 | //You can add a ReadKey here, so you can attach debugger to be able to debug your own code. 57 | //Console.ReadKey(); 58 | 59 | // at this point we can call TeklaOpen api to do TS operations 60 | Console.WriteLine("ProjectInfo.Name : " + new Model().GetProjectInfo().Name); 61 | Console.WriteLine("ProjectInfo.Description : " + new Model().GetProjectInfo().Description); 62 | } // service must be disposed so that a clean exit is done. Once disposed, it cannot be used again during the process lifetime. 63 | } 64 | 65 | /// 66 | /// Helpers function to set need patching for licensing or any other things required 67 | /// 68 | /// 69 | private static void ConfigureHeadlessIniFiles(string binDir) 70 | { 71 | var licenseServer = "27001@yourserver"; 72 | var runPath = @"C:\TeklaStructuresModels\RunPath"; 73 | var overrideIniFile = Path.Combine(runPath, "TeklaStructures.ini"); 74 | Directory.CreateDirectory(runPath); 75 | // Always make a copy of a main the ini file so we dont break TS installation. 76 | File.Copy(Path.Combine(binDir, "TeklaStructures.ini"), overrideIniFile, true); 77 | File.AppendAllText(overrideIniFile, $"\r\nset XS_LICENSE_SERVER_HOST={licenseServer}\r\n"); 78 | File.AppendAllText(overrideIniFile, $"set XS_DEFAULT_LICENSE=Full\r\n"); 79 | 80 | var envVar = Environment.GetEnvironmentVariable("TS_OVERRIDE_INI_FILE"); 81 | if (envVar == null || !envVar.Equals(overrideIniFile)) 82 | { 83 | throw new ArgumentException($"Please set TS_OVERRIDE_INI_FILE, before exec the program: set TS_OVERRIDE_INI_FILE={overrideIniFile}"); 84 | } 85 | } 86 | 87 | /// 88 | /// assembly resolver - for loading dlls from bin without copying dlls into exectution path 89 | /// 90 | /// event args 91 | /// ts binary folder 92 | /// assembly to load 93 | private static System.Reflection.Assembly CurrentDomainAssemblyResolve(ResolveEventArgs args, string binDir) 94 | { 95 | var requestedAssembly = new AssemblyName(args.Name); 96 | 97 | if (File.Exists(Path.Combine(binDir, requestedAssembly.Name + ".dll"))) 98 | { 99 | return System.Reflection.Assembly.LoadFile(Path.Combine(binDir, requestedAssembly.Name + ".dll")); 100 | } 101 | 102 | return null; 103 | } 104 | } 105 | } 106 | --------------------------------------------------------------------------------