cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
Showing results for 
Search instead for 
Did you mean: 
Archicad C++ API
About Archicad add-on development using the C++ API.
SOLVED!

Call ArchiCAD api functions from Wpf window button

hossamamer7
Contributor

Hi folks,
I'm working on an Addon where I need to have a wpf window so now I'm trying to create a prototype and what I did up till now is to use c++/CLI as a bridge between wpf project and c++ project.
I managed to call an ArchiCAD api function when a button in wpf window is clicked but ArchiCAD crashes I think because I'm in the wpf thread and I'm not in ArchiCAD context.

Does anyone have an idea how can I handle that ? 

#include "ExportIfcUtils.h"
#include <shlobj.h>
#include <iostream>
#include <string>

bool ShowFolderSelectionDialog(IO::Location& selectedFolder) {
BROWSEINFO bi;
ZeroMemory(&bi, sizeof(bi));
TCHAR path[MAX_PATH];
bi.pszDisplayName = path;
bi.lpszTitle = L"Select a folder";
bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;

LPITEMIDLIST pidl = SHBrowseForFolder(&bi);
if (pidl != 0) {
if (SHGetPathFromIDList(pidl, path)) {
// Ensure that the path is properly converted to a wide string and used to construct IO::Location
std::wstring wPath(path);
std::string nPath = ConvertWideToNarrow(wPath); // Convert wide string to narrow string
IO::Name folderName(nPath.c_str()); // Construct IO::Name from the narrow string
selectedFolder = IO::Location(folderName); // Construct IO::Location from IO::Name

// Free memory used
IMalloc* imalloc = 0;
if (SUCCEEDED(SHGetMalloc(&imalloc))) {
imalloc->Free(pidl);
imalloc->Release();
}
// Add logging to verify the value of selectedFolder
ACAPI_WriteReport("Selected Folder: " + folderName.ToString(), false);
return true;
}
}
return false;
}
void PrintError(GSErrCode err) {
char errorMessage[256];
sprintf(errorMessage, "Error code: 0x%X", err);
ACAPI_WriteReport(errorMessage, true);
}

void Do_Save_IfcFile(API_IfcTypeID ifcFileType)
{
IO::Location selectedFolder;
if (!ShowFolderSelectionDialog(selectedFolder)) {
ACAPI_WriteReport("Folder selection canceled.", false);
return;
}
try
{
API_IFCTranslatorIdentifier firstTranslator;
GS::Array<API_IFCTranslatorIdentifier> ifcExportTranslators;
GSErrCode err = ACAPI_IFC_GetIFCExportTranslatorsList(ifcExportTranslators);
if (err != NoError) {
ACAPI_WriteReport("Can't get IFC export translator", true);
return;
}

if (DBVERIFY(!ifcExportTranslators.IsEmpty())) {
firstTranslator = ifcExportTranslators.GetFirst();
}

API_SavePars_Ifc pars_ifc = {};
pars_ifc.subType = ifcFileType;
pars_ifc.translatorIdentifier = firstTranslator;
//pars_ifc.elementsToIfcExport = API_VisibleElementsOnAllStories;
pars_ifc.elementsToIfcExport = API_EntireProject;

pars_ifc.elementsSet = nullptr;

API_FileSavePars fsp = {};
fsp.fileTypeID = APIFType_IfcFile;
IO::Name fileName;

switch (ifcFileType) {
case API_IFCZIP:
fileName = IO::Name("IFCTest.ifczip");
break;
case API_IFC:
default:
fileName = IO::Name("IFCTest.ifc");
break;
}
IO::Location outputIFCFile(selectedFolder, fileName);

fsp.file = &outputIFCFile;
err = ACAPI_ProjectOperation_Save(&fsp, &pars_ifc);
if (err == APIERR_READONLY) {
ACAPI_WriteReport("The plan could not be saved either because it's open in read-only mode, or has never been saved to a file and the fileSavePars is nullptr.", true);
}
if (err == APIERR_REFUSEDCMD) {
ACAPI_WriteReport("You are running from Demo version", true);
}
if (err != NoError) {
ACAPI_WriteReport("Error in APIDo_SaveID (IFC): %s", true);
}
}
catch (const std::exception& ex)
{
ACAPI_WriteReport("Exception", true);
}
}
1 ACCEPTED SOLUTION

Accepted Solutions
Solution

Thanks for your contribution, 
Actually, the problem wasn't in the attached code, the problem was that I was trying to open the wpf window as a modeless window which I think ArchiCAD doesn't support so I had to make it modal window and open it with ShowDialog() instead of Show() and the issue now is solved.

View solution in original post

3 REPLIES 3
Islam_Mohamed
Newcomer

Up

Hi. I don't have any experience with WPF so can't comment on that part specifically.
But it's possible to expose add-on functions that can than be called by other programs fia http calls. (That's how the python API works and can be extended).
So an alternative would be to create an add-on that exposes the needed functionality and have the WPF part as a separate program that calls into the API via http requests.
Check out ACAPI_AddOnAddOnCommunication_InstallAddOnCommandHandler, the CommandTest example Add-On and also this project https://github.com/tlorantfy/archicad-additional-json-commands to see how it's used.

Hope that helps,
Bernd

Solution

Thanks for your contribution, 
Actually, the problem wasn't in the attached code, the problem was that I was trying to open the wpf window as a modeless window which I think ArchiCAD doesn't support so I had to make it modal window and open it with ShowDialog() instead of Show() and the issue now is solved.