Skip to content

C++ sample

C++ drives the API as a COM client. Import the type library with #import to generate strongly typed interface wrappers in the SIDRASolutions_SI_API namespace, then activate the API with CoCreateInstance. This sample opens a SIDRA project, processes every site, and prints its level of service and degree of saturation.

Note

Complete the Getting started prerequisites first (SIDRA Intersection installed, 64-bit, .NET 8). You also need a SIDRA project (.sipx) file to open. Save one from SIDRA Intersection, or point the sample at any existing project. Replace C:\Samples\Demo.sipx below with its path. If anything fails, see Troubleshooting.

Important

Build for x64. The SIDRA API is x64-only; a 32-bit build fails to activate it. The sample uses ATL helpers (CComPtr, CComBSTR), so build with the Microsoft Visual C++ toolset (Visual Studio with the ATL component installed).

1. Import the type library

The installer ships the type library SIDRASolutions.SI.API.tlb in the SIDRA Intersection program folder. Import it with #import so the compiler generates the interface declarations. The raw_interfaces_only attribute keeps the raw get_/put_ accessors (rather than throwing wrapper methods), which is what this sample uses.

#include <atlbase.h>   // CComPtr, CComBSTR
#include <iostream>

// Adjust the path to match your install.
#import "C:\\Program Files\\SIDRA SOLUTIONS\\SIDRA INTERSECTION 11\\SIDRASolutions.SI.API.tlb" raw_interfaces_only
using namespace SIDRASolutions_SI_API;

2. Write the program

int main()
{
    if (FAILED(CoInitialize(nullptr)))
    {
        std::wcerr << L"Failed to initialize COM.\n";
        return 1;
    }

    {   // inner scope so every CComPtr releases before CoUninitialize()
        CComPtr<ISIAPI> api;
        if (FAILED(api.CoCreateInstance(__uuidof(SIAPI))))
        {
            std::wcerr << L"SIDRA Intersection COM API is not registered.\n";
            CoUninitialize();
            return 1;
        }

        VARIANT_BOOL opened = VARIANT_FALSE;
        api->OpenProject(CComBSTR(L"C:\\Samples\\Demo.sipx"), &opened);
        if (!opened)
        {
            CComBSTR error;
            api->get_LastErrorMessage(&error);
            std::wcerr << L"Could not open project: "
                       << (error.m_str ? error.m_str : L"") << L"\n";
            api->Close(&opened);
            CoUninitialize();
            return 1;
        }

        CComPtr<ISIAPIProject> project;
        api->get_Project(&project);

        CComBSTR projectName;
        project->get_Name(&projectName);
        std::wprintf(L"Project: %ls\n", projectName.m_str);

        // Project -> SiteFolders -> Sites. In SIDRA a "site" is an intersection.
        CComPtr<ISIAPISiteFolders> folders;
        project->get_SiteFolders(&folders);

        long folderCount = 0;
        folders->get_Count(&folderCount);
        for (long f = 0; f < folderCount; ++f)
        {
            CComPtr<ISIAPISiteFolder> folder;
            folders->get_Item_2(f, &folder);   // get_Item_2 retrieves by position

            CComPtr<ISIAPISites> sites;
            folder->get_Sites(&sites);

            long siteCount = 0;
            sites->get_Count(&siteCount);
            for (long s = 0; s < siteCount; ++s)
            {
                CComPtr<ISIAPISite> site;
                sites->get_Item_2(s, &site);

                VARIANT_BOOL processed = VARIANT_FALSE;
                site->Process(&processed);   // run the analysis for this site

                // Site-level vehicle results live under Outputset.OutputSiteVehicle.
                CComPtr<ISIAPIOutputset> outputset;
                site->get_Outputset(&outputset);

                CComPtr<ISIAPIOutputSiteVehicle> result;
                outputset->get_OutputSiteVehicle(&result);

                CComBSTR siteName, los;
                site->get_Name(&siteName);
                result->get_Level_of_service(&los);

                float degSatn = 0.0f;
                result->get_Deg_satn(&degSatn);

                std::wprintf(L"  %ls: LOS %ls, degree of saturation %.3f\n",
                             siteName.m_str, los.m_str, degSatn);
            }
        }

        api->Close(&opened);   // shuts down the SIDRA Intersection runtime
    }

    CoUninitialize();
    return 0;
}

3. Build and run

Build the project for the x64 configuration in Visual Studio, then run the resulting executable. The #import directive resolves at compile time and generates the .tlh/.tli headers for the type library automatically.

Expected output (values depend on your project):

Project: Demo
  North Rd / Main St: LOS B, degree of saturation 0.742
  East Ave / Main St: LOS C, degree of saturation 0.871

Working with raw COM interfaces

With raw_interfaces_only, every member is a method that returns an HRESULT and hands back its value through an out-parameter:

  • Properties become get_<Name> / put_<Name> calls. site.Name in the other samples is site->get_Name(&bstr) here.
  • CComPtr<I...> owns the interface pointer and calls Release for you when it goes out of scope. CComBSTR owns string values, and booleans are VARIANT_BOOL (VARIANT_TRUE / VARIANT_FALSE).
  • Collections expose get_Count and two indexers: get_Item looks up by name and get_Item_2 retrieves by position (the same split the PowerShell sample notes). This sample iterates by position with get_Item_2.

See the API reference for the full surface. The per-member pages show the C#, Python, and PowerShell forms; for C++, read a documented property Foo as get_Foo / put_Foo and call methods directly, each returning an HRESULT with results passed back through out-parameters.

Releasing the API

Call Close() when you are finished, then CoUninitialize(). Each CComPtr releases its interface automatically when it leaves scope, so keep the API objects in a narrower scope than the CoUninitialize() call, as the sample does above. Releasing the COM objects after the apartment has already been torn down is undefined behaviour.