Example 5 (Microsoft Visual C++)

Example 5 (Microsoft Visual C++ 2022)

Remarks

This example is written for Microsoft Visual C++ 2022. It is based on the SAP2000 verification problem Example 1-001.

This example creates the example verification problem from scratch, runs the analysis, extracts results, and compares the results with hand calculated values.

Example

Create a Visual C++ project of type "Console App.

LocateSAP2000v1.tlb

With the release of SAP2000 v26.0.0 , users will need to select the TLB file that corresponds to the bitness of their API client, e.g. 32-bit or 64-bit. To locate these files, the user should navigate to the directory where SAP2000 is installed. This is typically C:\Program Files\Computers and Structures\SAP2000 26\

Within this directory, the 32-bit library is found at NativeAPI\x86\ SAP2000v1.tlb The 64-bit library is found at NativeAPI\x64\ SAP2000v1.tlb.

Copy the 64-bit SAP2000v1.tlb file from the installation folder to the project directory. It should be copied to the same level as your client applications project file.

Open the .cpp file generated by the wizard by double-clicking on it and paste in the following code. Please pay attention to the comments in this code block, they contain important information about running the script.

#define _CRT_SECURE_NO_WARNINGS

#include <atlbase.h>

#include <atlstr.h>

#include <atlsafe.h>

#include <iostream>

#include <iomanip>

#include <sstream>

using namespace std;

#import "SAP2000v1.tlb" no_dual_interfaces rename("GetObject", "GetObject_") rename("Yield", "Yield_") rename("GetProp", "GetProp_") rename("SetProp", "SetProp_")

bool CheckHRESULT(HRESULT hRes, const wchar_t* msg)

{

if (hRes == S_FALSE || FAILED(hRes)) {

MessageBox(0, msg, L"ERROR!", MB_SETFOREGROUND);

return (false);

}

return (true);

}

int main(int argc, char* argv[])

{

::SetConsoleOutputCP(CP_UTF8);

// set the following flag to true to attach to an existing instance of the program

// otherwise a new instance of the program will be started

bool bAttachToInstance = false;

// set the following flag to true to manually specify the path to SAP2000.exe

// this allows for a connection to a version of SAP2000 other than the latest installation

// otherwise the latest installed version of SAP2000 will be launched

bool bSpecifyPath = false;

// if the above flag is set to true, specify the path to SAP2000 below

std::wstring ProgramPath;

ProgramPath = L"C:\\Program Files\\Computers and Structures\\SAP2000 26\\SAP2000.exe";

// use res to check if functions return successfully (res = 0) or fail (res = nonzero)

HRESULT hRes = 0;

int res = 0;

// initialize COM

hRes = CoInitialize(NULL);

if (!CheckHRESULT(hRes, L"Error initializing COM subsystem!")) return (hRes);

// SapObject pointer

CComPtr<SAP2000v1::cOAPI> pSapObject;

try {

// create Helper

CComPtr<SAP2000v1::cHelper> pHelper;

hRes = pHelper.CoCreateInstance(L"SAP2000v1.Helper", NULL, CLSCTX_INPROC_SERVER);

if (!CheckHRESULT(hRes, L"Cannot instantiate helper!")) return (hRes);

if (bAttachToInstance) {

 // attach to a running instance of SAP2000

 pSapObject = pHelper->GetObject_(L"CSI.SAP2000.API.SapObject");

 hRes = ((pSapObject) ? S_OK : S_FALSE);

 if (!CheckHRESULT(hRes, L"Cannot attach to SapObject!")) return (hRes);

}

else {

 // start a new instance of SAP2000

 if (bSpecifyPath) {

 // create an instance of the SAP2000 object from the specified path

 pSapObject = pHelper->CreateObject(ProgramPath.c_str());

 hRes = ((pSapObject) ? S_OK : S_FALSE);

 if (!CheckHRESULT(hRes, L"Cannot instantiate SapObject!")) return (hRes);

 }

 else {

 // create an instance of the SapObject from the latest installed SAP2000

 pSapObject = pHelper->CreateObjectProgID(L"CSI.SAP2000.API.SapObject");

 hRes = ((pSapObject) ? S_OK : S_FALSE);

 if (!CheckHRESULT(hRes, L"Cannot instantiate SapObject!")) return (hRes);

 }

 // start SAP2000 application

 res = pSapObject->ApplicationStart(SAP2000v1::eUnits_kip_in_F, true, "");

 if (!CheckHRESULT(hRes, L"SapObject.ApplicationStart failed!")) return (hRes);

}

// full path to the model

// set it to an already existing folder

const wchar_t* ModelPath = L"C:\\CSiAPIexample\\API_1-001.sdb";

// initialize model

res = pSapObject->SapModel->InitializeNewModel(SAP2000v1::eUnits_kip_in_F);

// create new blank model

res = pSapObject->SapModel->File->NewBlank();

// define material property

_bstr_t bstrPropMaterial = "CONC";

res = pSapObject->SapModel->PropMaterial->SetMaterial(bstrPropMaterial, SAP2000v1::eMatType_Concrete, -1, L"", L"");

// assign isotropic mechanical properties to material

res = pSapObject->SapModel->PropMaterial->SetMPIsotropic(bstrPropMaterial, 3600, 0.2, 0.0000055, 0.0);

// define rectangular frame section property

_bstr_t bstrPropFrame("R1");

res = pSapObject->SapModel->PropFrame->SetRectangle(bstrPropFrame, bstrPropMaterial, 12, 12, -1, L"", L"");

// define frame section property modifiers

CComSafeArray<double> saMod(8); // CComSafeArray is a wrapper for the SAFEARRAY structure.

for (int i = 0; i < 8; i++)

 saMod[i] = 1.;

saMod[0] = 1000.;

saMod[1] = 0.;

saMod[2] = 0.;

LPSAFEARRAY psaMod = saMod.Detach();

res = pSapObject->SapModel->PropFrame->SetModifiers(bstrPropFrame, &psaMod);

saMod.Attach(psaMod);

// switch to k-ft units

res = pSapObject->SapModel->SetPresentUnits(SAP2000v1::eUnits_kip_ft_F);

// add frame object by coordinates

BSTR name1 = ::SysAllocString(L"");

BSTR name2 = ::SysAllocString(L"");

BSTR name3 = ::SysAllocString(L"");

_bstr_t FrameName0("1");

_bstr_t FrameName1("2");

_bstr_t FrameName2("3");

_bstr_t bstrCoordSys("Global");

res = pSapObject->SapModel->FrameObj->AddByCoord(0, 0, 0, 0, 0, 10, &name1, bstrPropFrame, FrameName0, bstrCoordSys);

res = pSapObject->SapModel->FrameObj->AddByCoord(0, 0, 10, 8, 0, 16, &name2, bstrPropFrame, FrameName1, bstrCoordSys);

res = pSapObject->SapModel->FrameObj->AddByCoord(-4, 0, 10, 0, 0, 10, &name3, bstrPropFrame, FrameName2, bstrCoordSys);

// assign point object restraint at base

BSTR PointName;

BSTR PointName0 = ::SysAllocString(L"");

BSTR PointName1 = ::SysAllocString(L"");

CComSafeArray<VARIANT_BOOL, VT_BOOL> saRest(6);

for (int i = 0; i < 4; i++)

 saRest[i] = VARIANT_TRUE;

for (int i = 4; i < 6; i++)

 saRest[i] = VARIANT_FALSE;

res = pSapObject->SapModel->FrameObj->GetPoints(FrameName0, &PointName0, &PointName1);

LPSAFEARRAY psaRest = saRest.Detach();

res = pSapObject->SapModel->PointObj->SetRestraint(PointName0, &psaRest, SAP2000v1::eItemType_Objects);

saRest.Attach(psaRest);

// assign point object restraint at top

for (int i = 0; i < 2; i++)

 saRest[i] = VARIANT_TRUE;

for (int i = 2; i < 6; i++)

 saRest[i] = VARIANT_FALSE;

res = pSapObject->SapModel->FrameObj->GetPoints(FrameName1, &PointName0, &PointName1);

psaRest = saRest.Detach();

res = pSapObject->SapModel->PointObj->SetRestraint(PointName1, &psaRest, SAP2000v1::eItemType_Objects);

saRest.Attach(psaRest);

// refresh view, update (initialize) zoom

long window = 0;

VARIANT_BOOL zoom = VARIANT_FALSE;

res = pSapObject->SapModel->View->RefreshView(window, zoom);

// add load patterns

double SelfWTMultiplier = 1.0;

VARIANT_BOOL AddLoadCase = VARIANT_TRUE;

res = pSapObject->SapModel->LoadPatterns->Add("1", SAP2000v1::eLoadPatternType_Other, SelfWTMultiplier, AddLoadCase);

SelfWTMultiplier = 0.;

res = pSapObject->SapModel->LoadPatterns->Add("2", SAP2000v1::eLoadPatternType_Other, SelfWTMultiplier, AddLoadCase);

res = pSapObject->SapModel->LoadPatterns->Add("3", SAP2000v1::eLoadPatternType_Other, SelfWTMultiplier, AddLoadCase);

res = pSapObject->SapModel->LoadPatterns->Add("4", SAP2000v1::eLoadPatternType_Other, SelfWTMultiplier, AddLoadCase);

res = pSapObject->SapModel->LoadPatterns->Add("5", SAP2000v1::eLoadPatternType_Other, SelfWTMultiplier, AddLoadCase);

res = pSapObject->SapModel->LoadPatterns->Add("6", SAP2000v1::eLoadPatternType_Other, SelfWTMultiplier, AddLoadCase);

res = pSapObject->SapModel->LoadPatterns->Add("7", SAP2000v1::eLoadPatternType_Other, SelfWTMultiplier, AddLoadCase);

// assign loading for load pattern 2

res = pSapObject->SapModel->FrameObj->GetPoints(FrameName2, &PointName0, &PointName1);

CComSafeArray<double> saPLoad(6);

for (int i = 0; i < 6; i++)

 saPLoad[i] = 0.;

saPLoad[2] = -10.;

bstrCoordSys = L"Global";

LPSAFEARRAY psaPLoad = saPLoad.Detach();

res = pSapObject->SapModel->PointObj->SetLoadForce(PointName0, "2", &psaPLoad, VARIANT_FALSE, bstrCoordSys, SAP2000v1::eItemType_Objects);

saPLoad.Attach(psaPLoad);

res = pSapObject->SapModel->FrameObj->SetLoadDistributed(FrameName2, "2", 1, 10, 0., 1., 1.8, 1.8, bstrCoordSys, VARIANT_TRUE, VARIANT_TRUE, SAP2000v1::eItemType_Objects);

// assign loading for load pattern 3

res = pSapObject->SapModel->FrameObj->GetPoints(FrameName2, &PointName0, &PointName1);

for (int i = 0; i < 6; i++)

 saPLoad[i] = 0.;

saPLoad[2] = -17.2;

saPLoad[4] = -54.4;

psaPLoad = saPLoad.Detach();

res = pSapObject->SapModel->PointObj->SetLoadForce(PointName1, "3", &psaPLoad, VARIANT_FALSE, bstrCoordSys, SAP2000v1::eItemType_Objects);

saPLoad.Attach(psaPLoad);

// assign loading for load pattern 4

res = pSapObject->SapModel->FrameObj->SetLoadDistributed(FrameName1, "4", 1, 10, 0, 1, 1.8, 1.8, bstrCoordSys, VARIANT_TRUE, VARIANT_TRUE, SAP2000v1::eItemType_Objects);

// assign loading for load pattern 5

bstrCoordSys = L"Local";

res = pSapObject->SapModel->FrameObj->SetLoadDistributed(FrameName0, "5", 1, 2, 0, 1, 2, 2, bstrCoordSys, VARIANT_TRUE, VARIANT_TRUE, SAP2000v1::eItemType_Objects);

res = pSapObject->SapModel->FrameObj->SetLoadDistributed(FrameName1, "5", 1, 2, 0, 1, -2, -2, bstrCoordSys, VARIANT_TRUE, VARIANT_TRUE, SAP2000v1::eItemType_Objects);

// assign loading for load pattern 6

res = pSapObject->SapModel->FrameObj->SetLoadDistributed(FrameName0, "6", 1, 2, 0, 1, 0.9984, 0.3744, bstrCoordSys, VARIANT_TRUE, VARIANT_TRUE, SAP2000v1::eItemType_Objects);

res = pSapObject->SapModel->FrameObj->SetLoadDistributed(FrameName1, "6", 1, 2, 0, 1, -0.3744, 0, bstrCoordSys, VARIANT_TRUE, VARIANT_TRUE, SAP2000v1::eItemType_Objects);

// assign loading for load pattern 7

res = pSapObject->SapModel->FrameObj->SetLoadPoint(FrameName1, "7", 1, 2, 0.5, -15, bstrCoordSys, VARIANT_TRUE, VARIANT_TRUE, SAP2000v1::eItemType_Objects);

// switch to k-in units

res = pSapObject->SapModel->SetPresentUnits(SAP2000v1::eUnits_kip_in_F);

// save model

_bstr_t bstrFileName(ModelPath);

res = pSapObject->SapModel->File->Save(bstrFileName);

// run model (this will create the analysis model)

res = pSapObject->SapModel->Analyze->RunAnalysis();

// initialize for SAP2000 results

long NumberResults = 0;

double SapResult[7];

for (int i = 0; i < 7; i++)

 SapResult[i] = 0.;

CComSafeArray<BSTR> saResObj(1);

CComSafeArray<BSTR> saResElm(1);

CComSafeArray<BSTR> saResLoadCase(1);

CComSafeArray<BSTR> saResStepType(1);

CComSafeArray<double> saResStepNum(1);

CComSafeArray<double> saResU1(1);

CComSafeArray<double> saResU2(1);

CComSafeArray<double> saResU3(1);

CComSafeArray<double> saResR1(1);

CComSafeArray<double> saResR2(1);

CComSafeArray<double> saResR3(1);

res = pSapObject->SapModel->FrameObj->GetPoints(FrameName1, &PointName0, &PointName1);

// get SAP2000 results for load cases 1 through 7

for (int i = 0; i < 7; i++) {

 res = pSapObject->SapModel->Results->Setup->DeselectAllCasesAndCombosForOutput();

 _bstr_t bstrLoadPattern = std::to_string(i + 1).c_str();

 res = pSapObject->SapModel->Results->Setup->SetCaseSelectedForOutput(bstrLoadPattern, VARIANT_TRUE);

 PointName = (i <= 3) ? PointName1 : PointName0;

 // result arrays get reallocated inside the response call so we have to detach first

 LPSAFEARRAY psaResObj = saResObj.Detach();

 LPSAFEARRAY psaResElm = saResElm.Detach();

 LPSAFEARRAY psaResLoadCase = saResLoadCase.Detach();

 LPSAFEARRAY psaResStepType = saResStepType.Detach();

 LPSAFEARRAY psaResStepNum = saResStepNum.Detach();

 LPSAFEARRAY psaResU1 = saResU1.Detach();

 LPSAFEARRAY psaResU2 = saResU2.Detach();

 LPSAFEARRAY psaResU3 = saResU3.Detach();

 LPSAFEARRAY psaResR1 = saResR1.Detach();

 LPSAFEARRAY psaResR2 = saResR2.Detach();

 LPSAFEARRAY psaResR3 = saResR3.Detach();

 res = pSapObject->SapModel->Results->JointDispl(PointName, SAP2000v1::eItemTypeElm_ObjectElm, &NumberResults,

 &psaResObj, &psaResElm, &psaResLoadCase, &psaResStepType, &psaResStepNum,

 &psaResU1, &psaResU2, &psaResU3, &psaResR1, &psaResR2, &psaResR3);

 //re-attach to the result arrays

saResObj.Attach(psaResObj);

 saResElm.Attach(psaResElm);

 saResLoadCase.Attach(psaResLoadCase);

 saResStepType.Attach(psaResStepType);

 saResStepNum.Attach(psaResStepNum);

 saResU1.Attach(psaResU1);

 saResU2.Attach(psaResU2);

 saResU3.Attach(psaResU3);

 saResR1.Attach(psaResR1);

 saResR2.Attach(psaResR2);

 saResR3.Attach(psaResR3);

 if (i <= 3)

 SapResult[i] = saResU3[0];

 else

 SapResult[i] = saResU1[0];

}

// close SAP2000 application

res = pSapObject->ApplicationExit(VARIANT_FALSE);

// fill independent results (hand calculated)

double IndResult[7];

IndResult[0] = -0.02639;

IndResult[1] = 0.06296;

IndResult[2] = 0.06296;

IndResult[3] = -0.2963;

IndResult[4] = 0.3125;

IndResult[5] = 0.11556;

IndResult[6] = 0.00651;

// fill percent difference

double PercentDiff[7];

for (int i = 0; i < 7; i++)

 PercentDiff[i] = fabs((SapResult[i] / IndResult[i]) - 1);

// print results

stringstream sMsg;

sMsg << fixed << setfill(' ');

sMsg << "LC Sap2000 Independent % Diff" << endl;

for (int i = 0; i < 7; i++)

 sMsg << setprecision(5) << showpoint << setiosflags(ios::left)

 << setw(2) << i + 1 << " "

 << setw(11) << IndResult[i] << " "

 << setw(11) << SapResult[i] << " "

 << setprecision(0) << noshowpoint << setiosflags(ios::right)

 << setw(5) << PercentDiff[i] << '%' << endl;

MessageBoxA(0, sMsg.str().c_str(), " Results", MB_SETFOREGROUND);

// uninitialize COM

CoUninitialize();

// we're done!

return (EXIT_SUCCESS);

}

catch (_com_error& ex) {

CheckHRESULT(ex.Error(), ex.ErrorMessage());

// close SAP2000

CComVariant vRes = pSapObject->ApplicationExit(false);

// uninitialize COM

CoUninitialize();

return (-1);

}

}

Release Notes

Initial release in version 15.0.1

Updated in version 22.1.0.

Updated for version 26.0.0.