I am using SystemCallback::SetElmDscrToFileFunction() to catch when a user creates new elements. My "command" establishes the callback function and then open a DialogBox where one of any number of ItemTypes can be selected. As new elements are created, the desire is to add the selected ItemType to the "new" element automatically. The callback function provides the "proposed" MSElementDescrP and a "replacement" MSElementDescrPP for when you return ELMDTF_STATUS_REPLACE. I am unable to add the ItemType successfully to the replacement MSElementDescrPP. I'm thinking it's because the EditElementHandle created from the "proposed" MSElementDescrP (newEdP), although "IsValid()", is not persistent. I get a MicroStation crash. Is there another way to attach the ItemType ?
static ItemTypeLibraryPtr itemTypeLib; ElmDscrToFile_Status AddFeatureItemOld(ElmDscrToFile_Actions action, DgnModelRefP modelRef, UInt32 filePos, MSElementDescrP newEdP, // new elem being written to file (NULL when ELMDTF_ACTION_DELETE) MSElementDescrCP oldEdP, // elem in original state (NULL when ELMDTF_ACTION_APPEND) MSElementDescrH replacementEdPP)// used if we return ELMDTF_STATUS_REPLACE { // ... EditElementHandle eeh(newEdP, false, false); // eeh does NOT own the elementDescr WString itemTypeName(L"Air Tunnel"); LookForItemTypes(itemTypeName); // searches for ItemTypeLibrary with "Air Tunnel",sets "itemTypeLib" if (itemTypeLib.IsValid()) { wprintf(L"itemTypeLib.IsValid()\n"); ItemTypeP pItemType = itemTypeLib->GetItemTypeByName(itemTypeName.c_str() ); if (pItemType != nullptr) { wprintf(L"pItemType != nullptr\n"); wprintf(L"eeh.IsValid %d\n", eeh.IsValid()); wprintf(L"eeh.IsPersistent %d\n", eeh.IsPersistent()); CustomItemHost itemHost = CustomItemHost(eeh); wprintf(L"itemHost %08x\n", itemHost); DgnECInstancePtr pInstance = itemHost.ApplyCustomItem(*pItemType, true); //CRASHES Here wprintf(L"pInstance.IsValid %d\n", pInstance.IsValid()); // Never gets to here... } else { wprintf(L"pItemType == nullptr\n"); } } else { wprintf(L"NOT itemTypeLib.IsValid()\n"); } mdlElmdscr_duplicate(replacementEdPP, eeh.GetElementDescrP()); return ELMDTF_STATUS_REPLACE; // use the update element descriptor }
Bruce
Bruce, please confirm you are not *actually* going to indiscriminately attach your Item to every new element no matter what type of element it is.
Well, not indiscriminately to every new element .....
ok good because that's what your code currently does. Be aware that you may see the Type 9 element coming through there, as well as named groups, reference attachments, element templates, ECSchemas, etc etc etc...
Also holding a static ItemTypeLibraryPtr is a bad idea - what happens when the DgnFile associated with it gets destroyed?
I still have not been able to successfully attach an ItemType to anything using the ::SetElmDscrToFileFunction(). The same approach when used in a DgnElementSetTool::_OnElementModify() works fine. When inside the ::SetElmDscrToFileFunction() callback, the DgnECInstancePtr returned from CustomItemHost::ApplyCustomItem() is always invalid. Should I be using the DgnECManager/DgnECInstanceEnabler API's instead of the CustomItemHost API for this? .
No, use the CustomItemHost API. Post full code? e.g., your LookForItemTypes() function remains a mystery.
Thanks,
Paul
LookForItemTypes() function was just a "check" to make sure the desired ItemTypeLibrary existed.
Here is the abbreviated relevant code...
ElmDscrToFile_Status AddFeatureItem(ElmDscrToFile_Actions action, // [in] DgnModelRefP modelRef, // [in] UInt32 filePos, // [in] MSElementDescrP newEdP, // [in] new elem being written to file (NULL when ELMDTF_ACTION_DELETE) MSElementDescrCP oldEdP, // [in] elem in original state (NULL when ELMDTF_ACTION_APPEND) MSElementDescrH replacementEdPP)// [in] used if we return ELMDTF_STATUS_REPLACE, frees elmDscr when done { if (action == ELMDTF_ACTION_APPEND) { //... EditElementHandle eeh(newEdP, false, false); // eeh does NOT own the elementDescr WString itemTypeName(L"Air Tunnel"); // Just for this test ItemTypeLibraryPtr itemTypeLib = ItemTypeLibrary::FindByName(L"SRSFeature",*ACTIVEMODEL->GetDgnFileP()); if (itemTypeLib.IsValid()) { wprintf(L"itemTypeLib.IsValid()\n"); ItemTypeP pItemType = itemTypeLib->GetItemTypeByName(itemTypeName.c_str() ); if (pItemType != nullptr) { wprintf(L"pItemType != nullptr\n"); wprintf(L"eeh.IsValid %d\n", eeh.IsValid()); wprintf(L"eeh.IsPersistent %d\n", eeh.IsPersistent()); CustomItemHost itemHost (eeh, false); wprintf(L"itemHost %08x\n", itemHost); DgnECInstancePtr pInstance = itemHost.ApplyCustomItem(*pItemType); wprintf(L"pInstance.IsValid %d\n", pInstance.IsValid()); // <<<< never returns "IsValid()" //... } } mdlElmdscr_duplicate(replacementEdPP, eeh.GetElementDescrP()); return ELMDTF_STATUS_REPLACE; // use the update element descriptor } return ELMDTF_STATUS_SUCCESS; // just return }
Everything *seems* OK until the ApplyCustomItem() call. the DgnECInstancePtr returned never "IsValid()"
You must schedule the Item here, not attempt to rewrite the element.
Pass true to ApplyCustomItem to indicate this and report back.
Paul Connelly said:Pass true to ApplyCustomItem to indicate this
CustomItemHost::ApplyCustomItem() documentation indicates that the bool parameter is for "importLibrariesIfRequired"...
Anyway, when I pass "true" as the second parameters, "pInstance" is still reported as not "IsValid()"
Sorry - I meant the second argument to CustomItemHost constructor.
Answer Verified By: Robert Hook
That seems to resolve the issue for my test case !!
Thanks - I thought it has something to do with ApplyCustomItem(). Since the created CustomItemHost was non-null, I just figured it was successfully created and didn't look any more at it.