Hi All,
I'm working on a C++ MDL Application using OpenCities Map CONNECT Edition 10.6.1.2.
(Microstation CONNECT Edition SDK version: 10.14.00.111)
My application is frequently crashing when I call mdlRefFile_completeAttachment.
The error message says it is an Internal error: Access violation.
Could you please help me what am I doing wrong?
Here you can find my Test.cpp code:
#include <Mstn\MdlApi\MdlApi.h> #include <DgnPlatform\DgnPlatformApi.h> #include "test.h" #include "test_cmd.h" #define MAP_LENGTH 20 USING_NAMESPACE_BENTLEY_DGNPLATFORM DgnModelRefP tMapsRef[MAP_LENGTH]; int nTerkep = MAP_LENGTH; MAPS tMaps[MAP_LENGTH]; bool tMapIsSwitchedOn[MAP_LENGTH]; int IsUpdate = 0, IsCommand = 0, counter = 0; static void func_updateRef() { int i; WString logical, err; StatusInt stat; //randomize map attach and detach //originally this information is stored in a database but now i try to //mimic the behaviour that maps are detached and attached as we move the map in the view for (i = 0; i < nTerkep; i++) { tMapIsSwitchedOn[i] = rand() % 2 == 1 ? true : false; } /* .............................. detach maps ..................................... */ mdlOutput_messageCenter(OutputMessagePriority::Debug, L"func_updateRef detach maps.", L"", OutputMessageAlert::None); for (i = 0; i < nTerkep; i++) { if (tMapsRef[i] && !tMapIsSwitchedOn[i]) { err.Sprintf(L"detach map: %s", tMaps[i].full_file_path.GetWCharCP()); mdlOutput_messageCenter(OutputMessagePriority::Debug, err.GetWCharCP(), err.GetWCharCP(), OutputMessageAlert::None); stat = mdlRefFile_detach(tMapsRef[i]); if (stat != SUCCESS) { err.Sprintf(L"mdlRefFile_detach error. Reference file name: %s -- error code: %d", tMaps[i].full_file_path, stat); mdlOutput_messageCenter(OutputMessagePriority::Debug, err.GetWCharCP(), err.GetWCharCP(), OutputMessageAlert::None); } tMapsRef[i] = NULL; } } /* .............................. level switch .................................... */ mdlOutput_messageCenter(OutputMessagePriority::Debug, L"func_updateRef level switch.", L"", OutputMessageAlert::None); for (i = 0; i < nTerkep; i++) { if (tMapsRef[i] && tMapIsSwitchedOn[i]) { err.Sprintf(L"level switch %s", tMaps[i].full_file_path.GetWCharCP()); mdlOutput_messageCenter(OutputMessagePriority::Debug, err.GetWCharCP(), err.GetWCharCP(), OutputMessageAlert::None); //func_setLevel(i); stat = mdlRefFile_updateReference(tMapsRef[i], DgnPlatform::DRAW_MODE_Normal); if (stat != SUCCESS) { err.Sprintf(L"mdlRefFile_completeAttachment error. Reference file name: %s, Error code: %d", tMaps[i].full_file_path.GetWCharCP(), stat); mdlOutput_messageCenter(OutputMessagePriority::Debug, err.GetWCharCP(), err.GetWCharCP(), OutputMessageAlert::None); } } } /* .............................. attach maps ..................................... */ mdlOutput_messageCenter(OutputMessagePriority::Debug, L"func_updateRef attach maps ", L"", OutputMessageAlert::None); DgnAttachmentP attachment = 0; WString fileName; for (i = 0; i < nTerkep; i++) { if (!tMapsRef[i] && tMapIsSwitchedOn[i]) { err.Sprintf(L"attaching map: %s", tMaps[i].full_file_path.GetWCharCP()); mdlOutput_messageCenter(OutputMessagePriority::Debug, err.GetWCharCP(), err.GetWCharCP(), OutputMessageAlert::None); logical.Sprintf(L"%d", tMaps[i].id); DgnAttachmentBuilder builder; fileName = tMaps[i].full_file_path; fileName.ReplaceAll(L"\\", L"/"); stat = mdlRefFile_beginAttachmentToModel(builder, fileName.GetWCharCP(), L"Default", logical.GetWCharCP(), L"Default description", MASTERFILE); if (stat != SUCCESS) { err.Sprintf(L"mdlRefFile_completeAttachment error. Reference file name: %s, Error code: %d", fileName, stat); mdlOutput_messageCenter(OutputMessagePriority::Debug, err.GetWCharCP(), err.GetWCharCP(), OutputMessageAlert::None); return; } if (builder.GetDgnAttachmentP() == NULL) return; builder->SetAttachDescription(L""); stat = mdlRefFile_completeAttachment(attachment, builder, RefAttachNestMode::None, -1, false); if (stat != SUCCESS) { err.Sprintf(L"mdlRefFile_completeAttachment error. Reference file name: %s, Error code: %d", fileName, stat); return; } tMapsRef[i] = attachment->GetDgnModelP(); if (tMapsRef[i] == NULL) return; //func_setLevel(i); stat = mdlRefFile_updateReference(tMapsRef[i], DgnPlatform::DRAW_MODE_Normal); if (stat != SUCCESS) { err.Sprintf(L"mdlRefFile_updateReference error. Reference file name: %s, Error code: %d", tMaps[i].full_file_path.GetWCharCP(), stat); mdlOutput_messageCenter(OutputMessagePriority::Debug, err.GetWCharCP(), err.GetWCharCP(), OutputMessageAlert::None); } } } } static void func_getRefInfo() { DgnModelRefP pRef; ModelRefIteratorP iter; WChar str[250]; int i; mdlOutput_messageCenter(OutputMessagePriority::Debug, L"func_getRefInfo -- Delete tMapsRef array and load references from MASTERFILE.", L"", OutputMessageAlert::None); for (i = 0; i < nTerkep; i++) { tMapsRef[i] = NULL; } mdlModelRefIterator_create(&iter, MASTERFILE, MRITERATE_PrimaryChildRefs, 0); while (NULL != (pRef = mdlModelRefIterator_getNext(iter))) { str[0] = 0; mdlRefFile_getStringParameters(str, sizeof(str) - 1, REFERENCE_FILENAME, pRef); for (i = 0; i < nTerkep; i++) { if (tMaps[i].full_file_path.CompareToI(str) == 0) { tMapsRef[i] = pRef; break; } } } mdlModelRefIterator_free(&iter); } static void func_autoUpdateRef() { func_getRefInfo(); func_updateRef(); } void viewUpdate(WCharCP) { mdlOutput_messageCenter(OutputMessagePriority::Debug, L"----------View Update Start-----------", L"", OutputMessageAlert::None); /* turn off undo in the views */ for (int vn = 0; vn < DgnPlatform::MAX_VIEWS; vn++) mdlUndo_setViewUndoActive(vn, FALSE); IsUpdate = 1; func_autoUpdateRef(); /* turn on undo in the views */ for (int vn = 0; vn < DgnPlatform::MAX_VIEWS; vn++) mdlUndo_setViewUndoActive(vn, TRUE); IsUpdate = 0; IsCommand = 0; mdlOutput_messageCenter(OutputMessagePriority::Debug, L"-----------View Update End------------", L"", OutputMessageAlert::None); } static int func_viewUpdate(bool preUpdate, /* => TRUE if called before update */ DgnPlatform::DgnDrawMode eraseMode, /* => display mode */ DgnModelRefListP modelRefList, /* => files involved in update */ int numberRegions, /* => number of regions */ Asynch_update_view regions[], /* => region descriptions */ ViewContextP context, /* => view context */ int numCovers[], /* => cover list sizes */ MSDisplayDescr *displayDescr[] /* => display descriptors */) { if (preUpdate) return SUCCESS; if (IsUpdate) return SUCCESS; if (IsCommand) return SUCCESS; IsCommand = 1; mdlInput_sendSynchronizedKeyin(L"mdl keyin test eegis test viewupdate", TRUE, INPUTQ_EOQ, NULL); return SUCCESS; } void init_map_arrays() { WString filename; for (int i = 0; i < nTerkep; i++) { tMaps[i].id = i; filename.Sprintf(L"C:\\temp\\%d.dgn", i); tMaps[i].full_file_path = filename; tMapIsSwitchedOn[i] = true; } } extern "C" DLLEXPORT void MdlMain(int argc, WCharCP argv[]) { RscFileHandle rF; if (mdlParse_loadCommandTable(NULL) == NULL) { exit(1); return; } mdlResource_openFile(&rF, NULL, FALSE); MdlCommandNumber commandNumbers[] = { { viewUpdate , CMD_EEGIS_TEST_VIEWUPDATE }, 0 }; mdlSystem_registerCommandNumbers(commandNumbers); init_map_arrays(); ViewCallback::SetUpdatePostFunction(func_viewUpdate); }
And the included header Test.h:
#pragma once typedef struct MAPS { int id; WString full_file_path; }MAPS;
My resource file is Test_cmd.r:
#include <Mstn\MdlApi\rscdefs.r.h> #include <Mstn\MdlApi\cmdclass.r.h> /*----------------------------------------------------------------------+ | | | Local Defines | | | +----------------------------------------------------------------------*/ #define DLLAPP_TEST 1 #define CT_NONE 0 #define CT_MAIN 1 #define CT_EEGIS 2 #define CT_TEST 3 /*----------------------------------------------------------------------+ | | Register Application and DLL | +----------------------------------------------------------------------*/ DllMdlApp DLLAPP_TEST = { L"TEST", L"test" // taskid, dllName } /*----------------------------------------------------------------------+ | | | Main Align Commands | | | +----------------------------------------------------------------------*/ CommandTable CT_MAIN = { { 1, CT_EEGIS, INPUT, NONE, "EEGIS" }, }; CommandTable CT_EEGIS = { { 1, CT_TEST , INPUT, NONE, "TEST" }, }; CommandTable CT_TEST = { { 1, CT_NONE, INPUT, NONE, "VIEWUPDATE" } };
I've also attached the project in a zip file. I'm compiling it with VS2017.
Test.zip
Br,
Miklos
One more addition:
The Test application is registering a view event handler by calling ViewCallback::SetUpdatePostFunction(func_viewUpdate);
Each time the view is updated the application is randomly attaching and detaching some reference files. The reference files are stored in C:\temp directory and named like 0.dgn, 1.dgn, 2.dgn, 3.dgn, ... etc. up to 20.dgn.