How to use the AcDbVoidPtrArray from acedTraceBoundary function properly?

How to use the AcDbVoidPtrArray from acedTraceBoundary function properly?

cre8or
Contributor Contributor
4,590 Views
19 Replies
Message 1 of 20

How to use the AcDbVoidPtrArray from acedTraceBoundary function properly?

cre8or
Contributor
Contributor

I wrote an arx command under CAD2012 to trace the boundaries just like what the "bpoly" command do: pick a point inside polylines, then get a bpoly. Everytime I load the arx file, the first pick is fine, the boundaries created smoothly, but after 3 or 4 picks, it crashes, always...

The warning is "Fatal error: Unhandled Access Violation Reading 0x... ". So it seems that the acedTraceBoundary function returns an array that can not be released...

I am just using the acdbVoidPtrarray& as in the help file to get the returned entities then append them into the modelspace,

 

static void MyGroupTest1 ()
{
    AcGePoint3d seedPt;
    //AcAxDocLock docLock;
    acedGetPoint(NULL, _T("\nSelect a point inside the rectangle: "),asDblArray(seedPt));
    AcDbVoidPtrArray Boundaries;
    bool detectIslands = Adesk::kTrue;
    if (acedTraceBoundary(seedPt, detectIslands, Boundaries) == Acad::eOk) 
    {
    AcDbBlockTableRecordPointer pCurSpace(acdbCurDwg()->currentSpaceId(), AcDb::kForWrite);
    if (pCurSpace.openStatus() == Acad::eOk) 
    {
        for (int i = 0; i < Boundaries.length(); i++) 
        {
            AcDbEntity *pEnt = static_cast<AcDbEntity *>(Boundaries[i]);
            pCurSpace->appendAcDbEntity(pEnt);
            pEnt->close();
        }
    }
   pCurSpace->close();
}
}

 

 

it's quite simple, but not working.

 

 

The platform is CAD 2012 x32 and x64 on windows 7 with Visual studio 2010. Someone said it works fine on his cad2014 x64 edtion when I sent it to him, quite weird... I don't know the reason. Is anyone facing the same problem?

 

 

 

0 Likes
Accepted solutions (2)
4,591 Views
19 Replies
Replies (19)
Message 2 of 20

cre8or
Contributor
Contributor

With an addtional remark, the original code is generally copied from another topic about acedtraceboundary() of this forum. I am quite new on objectarx. Learning needs example,I didn't mean any offence

0 Likes
Message 3 of 20

tbrammer
Advisor
Advisor

The code looks OK to me. I would recomment to call

    pEnt->setDatabaseDefaults();

before
  pCurSpace->appendAcDbEntity(pEnt);

but I don't think that this will prohibit the crash.

 

I would assume that the AcDbVoidPtrArray returned from acedTraceBoundary() contains AcDbEntitys that must be either deleted or added to the database (like you did). But the docs don't state this explicitly. Maybe AutoCAD frees these objects with every new call. This would explain the crash. So you could try to append clones to the database and leave the objects in the AcDbVoidPtrArray untouched like this:

 

AcDbEntity *pEnt = static_cast<AcDbEntity *>(Boundaries[i]);
AcDbEntity *pClone = AcDbEntity::cast(pEnt->clone());
pClone->setDatabaseDefaults();
pCurSpace->appendAcDbEntity(pClone);

 

Have you tested your code in a "totally simple" application to make sure that there are no effects ouside of your function that cause the crash (like reactors etc.)?


Thomas Brammer ● Software Developer ● imos AGLinkedIn
If an answer solves your problem please [ACCEPT SOLUTION]. Otherwise explain why not.

0 Likes
Message 4 of 20

cre8or
Contributor
Contributor

You mean just make a clone of each entity and immediately delete the original one in the Acdbvoidprtarray?  Seems reasonable, maybe it is a solution... But it may not explain that the results from the other guys using CAD 2013 or 2014. They kept saying that the program acts well, nothing bad happened... So, maybe the function in 2012 is special? ... Like unfinished? I don't have the chance to upgrade my platform... So I won't know if it's exactly the answer till I have money to buy new licence... > <  But I will try to clone them for now.

0 Likes
Message 5 of 20

tbrammer
Advisor
Advisor
Accepted solution

@Anonymous wrote:

You mean just make a clone of each entity and immediately delete the original one in the Acdbvoidprtarray? 


No. My suggestion is to not delete and not append the original entities in the AcDbVoidPtrArray!

Just clone the entities and add the clones to the DB.

 

The docs don't state completely clear whether the entities are released/used by AutoCAD or must be released by the caller.

So I would try to leave them untouched and see whether the crash vanishes.

 

For comparison look at the docs for

AcDbRegion::createFromCurve(const AcDbVoidPtrArray& curveSegments, AcDbVoidPtrArray& regions):

 

     It is the calling application's responsibility to either add the AcDbRegion objects returned in the regions

     array to an AcDbDatabase or to delete them when they are no longer needed.

 

Here we have a clear statement how to deal with the entities in the resulting AcDbVoidPtrArray regions.

This statement is missing in the docs to acedTraceBoundary().


Thomas Brammer ● Software Developer ● imos AGLinkedIn
If an answer solves your problem please [ACCEPT SOLUTION]. Otherwise explain why not.

0 Likes
Message 6 of 20

cre8or
Contributor
Contributor

Thank you, I will try.

0 Likes
Message 7 of 20

autodaug
Autodesk
Autodesk

About the entity pointers being returned, that's correct that they are currently not db resident, and the caller is expected to either add them to the db or delete them. And I believe the entities should all be AcDbPolylines, btw.

 

It might be helpful to check the status being returned by appendAcDbEntity(), in case that is failing for some reason.

 

Also, it looks like this function in 2012 was not initially clearing the incoming array. So if its length is not zero, then the entity pointers will be appended to the existing pointers in the array. This was fixed in a later version. But your code as shown above does not appear to have this problem, since it's using a new local AcDbVoidPtrArray each time, meaning the array will always be empty when passed to acedTraceBoundary().

 

So I don't yet have an explanation of why it would crash. Do you know if it is crashing during the acedTraceBoundary() call or the appendAcDbEntity() call?

 

 

 

0 Likes
Message 8 of 20

tbrammer
Advisor
Advisor

I have just tested the original code with AutoCAD 2018. It runs without any problems - even if the entities are appended to the DB.

I can call the function as many times as I want.

 

It is a little bit unsatisfactory that my answer was accepted although my suggestion was wrong.

There seems to be a difference between AutoCAD 2012 and 2018 leading to the crash in 2012. I can't test with 2012.

 

I would appreciate if someone from Autodesk would take a closer look. Can you do this @autodaug?

It would also be good to add a clear statement to the docs of acedTraceBoundary() that the entities should be deleted or added to the DB.


Thomas Brammer ● Software Developer ● imos AGLinkedIn
If an answer solves your problem please [ACCEPT SOLUTION]. Otherwise explain why not.

0 Likes
Message 9 of 20

autodaug
Autodesk
Autodesk

I don't like to leave mysteries unsolved either, but it would not be easy for me to set up a 2012 environment to debug. And even if we found the problem, I doubt that a hotfix would be created for such an old release.

 

An easier option might be for cre8or to send in a crash report (CER) from when their app crashes. Hopefully we could use that to view the stack at the time of crash and figure out what's going on.  cre8or, if you do that, please let me know so I can look for the report.

 

Another option could be for the app to check for whether each entity is already db-resident, and if so, then skip over it instead of adding it to the db. The array should not point to resident entities, so if you find one, then that is a bug in 2012. To check for an object being db-resident, you can see if it has a non-null id. Like this:  if (pObj->objectId().isNull())     // if object is non-resident

 

About the docs, I agree they could be more informative. We'll improve it..

 

 

 

0 Likes
Message 10 of 20

cre8or
Contributor
Contributor

Thank you very much @autodaug. I tried again as @tbrammer's solution and the problem remains. So I will search the latest hotfix first, I think, and try it again, if still unsolved I will send you the CER file and notify you here.

Sorry I tagged this discussion as a accepted one because... Even the problem remains unsolved, I think @tbrammer still helped a lot, to remind me to exclude those detailed possibilities. I am new to Objextarx, I really need this kind of help. So I think maybe it was not so fair for me to leave this always unaccepted. Or maybe it's the fault from environment finally? who knows...

0 Likes
Message 11 of 20

autodaug
Autodesk
Autodesk

Good idea to search for a 2012 hotfix, @cre8or. I'm fairly sure this was a bug in 2012, but I'm not sure when it got fixed. If the fix came out close enough in time to 2012, then there could be a hotfix available. I'll try to get specifics on the bug..

 

I think @tbrammer also had a good idea, to leave the original entities alone and instead add clones to the database. The clones would definitely be non-db-resident and separate from whatever was going on inside the TraceBoundary() function. But I'm also not surprised that the workaround didn't work.

 

If you are able to grab a crash dump file and send it to me, that would be great. Or, even if you can generate a stack in msvc on your machine at the crash point and send that to me (or post it), that would help too. Your stack won't have acad symbols, but it may still show some dll entry points that provide clues.

 

Thanks for bearing with us in your introduction to ObjectARX and the forum 🙂

 

0 Likes
Message 12 of 20

autodaug
Autodesk
Autodesk

One more thing, I think the bug may be due to acad/acdb holding on to the pointer to your result set array and using it later, after your local array variable has been destroyed. Can you try making it a static variable, and setting its length to zero before you call BoundaryTrace() ?

 

Message 13 of 20

autodaug
Autodesk
Autodesk
Accepted solution

So it would look something like this:

 

    static AcDbVoidPtrArray Boundaries;   // valid for app's lifetime
    Boundaries.removeAll();     // make sure we pass in an empty array
    bool detectIslands = Adesk::kTrue;
    if (acedTraceBoundary(seedPt, detectIslands, Boundaries) == Acad::eOk)
    {
        << process the array >>
    }
    Boundaries.removeAll();     // in case acad is still pointing to the array

 

0 Likes
Message 14 of 20

cre8or
Contributor
Contributor
Ah, thank you @autodaug, I am away from my computer these days.. Once I go back to my office I will check if it's the way, and collect the  crash dump file... I am on business trip this week. The requirement from client is totally mess... That's one of the reasons I tagged "solved" first, because maybe next time I touch my keyboard will be weeks later. 
0 Likes
Message 15 of 20

autodaug
Autodesk
Autodesk

Okay, well as soon as you can give it a try (using static), it would be great to hear if it works. It should be pretty easy to do that simple change and test it. Hopefully it solves the problem and we don't have to worry about crash dumps..

 

Message 16 of 20

autodaug
Autodesk
Autodesk

Hi @cre8or, I hope the trip went well and the customer figured out their requirements 🙂

Regarding this issue with acedTraceBoundary(), would you have time to try the "static" experiment I mentioned above? The main change is just to put "static" in front of the array variable declaration. The other, less important changes, would be to call removeAll() on the array before calling acedTraceBoundary() and after your processing is done, as shown above. I think it would benefit the community to know the result of that exercise, if you have time to run it. Thanks.

 

Message 17 of 20

cre8or
Contributor
Contributor

I have a really really good news for the result!!!  @autodaug @tbrammer

 

After I inserted these 2 words as you told me here, IT WORKS PERFECTLY!! ANY TIMES AS I WANT!!!@

 

It's exiting!! because I was always worried about this problem on my trip.... 😛  Not so good for my clients.. And I just arrived today.. And gave it a simple try. IT'S AMAZING... Although I am still not completely sure about the reason..

 

So I added these 2 words step by step.

It appears that if I keep the "static" declaration, it always works fine no matter if the "removeall()" was added.

So it's a problem of scope finally?

 

Thank you guys again for the help!! @autodaug and @tbrammer. Both taught me a lot, really really helpful!

 

It's really amazing because I almost gave up and decided to find another way to solve this... 

 

The following is the working code. Working both on Autocad 2012 x32 and x64 edtion. The platfom is vs 2010 on windows 7 64bit. 

I will try it on win 10 later, but can't help exciting...

 

static void Group1test1(void)
{
AcGePoint3d seedPt;
//AcAxDocLock docLock;
acedGetPoint(NULL, _T("\nSelect a point inside the rectangle: "), asDblArray(seedPt));
static AcDbVoidPtrArray Boundaries;
//Boundaries.removeAll();
bool detectIslands = Adesk::kTrue;
if (acedTraceBoundary(seedPt, detectIslands, Boundaries) == Acad::eOk)
{
AcDbBlockTableRecordPointer pCurSpace(acdbCurDwg()->currentSpaceId(), AcDb::kForWrite);
if (pCurSpace.openStatus() == Acad::eOk)
{
for (int i = 0; i < Boundaries.length(); i++)
{
AcDbEntity *pEnt = static_cast<AcDbEntity *>(Boundaries[i]);
pCurSpace->appendAcDbEntity(pEnt);
pEnt->close();

}

}

}
}

 

0 Likes
Message 18 of 20

cre8or
Contributor
Contributor

And additionally, I just tested it on the autocad without any hotfix... Works fine! Cheers

0 Likes
Message 19 of 20

cre8or
Contributor
Contributor

And of course now I am using the edition with "Boundaries.removeAll();" Apparently it's seems neater than the one I posted without it... 

The original code under CAD 2012 only patched with hotfix is not working. So maybe it's a bug of acedTraceBoundary as you told.

 

And on another side, sorry for the late as my business trip became complicate... And made this discussion an unsolved mystery for 2 weeks.. Thank you @autodaug for your patience and guidance. 

 

0 Likes
Message 20 of 20

autodaug
Autodesk
Autodesk

That's great, @cre8or, thanks for verifying the fix!

0 Likes