ObjectARX
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

dwgInFields/dwgOutFields

14 REPLIES 14
Reply
Message 1 of 15
PSI_Tech
1289 Views, 14 Replies

dwgInFields/dwgOutFields

I have a custom entity with an embedded curve (AcDbPolyline / AcDbCircle / etc...). In an attempt to copy this entity to an external drawing using dotNET, the embedded curve (Circle in test) case is copied to the new drawing, but its properties aren't set, i.e., has 0 radius in the circle test.

 

The following code illustrates how my entity is written and read using the AcDbDwgFiler:

 

/// ---------------------------------------------------------------------------------------------------------
/// <summary> Serializes the objects properties using a drawing filer object. This is called by the framework
/// during save, copy, and clone operations.</summary>
/// ---------------------------------------------------------------------------------------------------------
Acad::ErrorStatus DetailerProfile::dwgOutFields(AcDbDwgFiler* filer) const
{
	Acad::ErrorStatus es = DetailerEntity::dwgOutFields(filer);
	if (es != Acad::eOk)
		return es;

	bool isDef = mCurve ? true : false;
	filer->writeBool(isDef);

	if (isDef)
	{
		AcString name = mCurve->isA()->name();
		filer->writeString(name);

		mCurve->dwgOutFields(filer);
	}

	return filer->filerStatus();
}
/// ---------------------------------------------------------------------------------------------------------
/// <summary> Deserializes the objects properties using a drawing filer object. This is called by the framework
/// during save, copy, and clone operations.</summary>
/// ---------------------------------------------------------------------------------------------------------
Acad::ErrorStatus DetailerProfile::dwgInFields(AcDbDwgFiler* filer)
{
	Acad::ErrorStatus es = DetailerEntity::dwgInFields(filer);
	if (es != Acad::eOk)
		return es;

	if (mCurve)
	{
		delete mCurve;
		mCurve = NULL;
	}

	bool isDef = false;
	filer->readBool(&isDef);

	if (isDef)
	{
		AcString name;
		filer->readString(name);

		AcDbEntity* p = AcDbEntity::cast(AcRxClass::cast(acrxClassDictionary->at(name))->create());
		es = p->dwgInFields(filer);
		if (es != Acad::eOk)
			delete p;

		mCurve = p;
	}

	return filer->filerStatus();
}

 The key here I think is the way I create "mCurve" in the dwgInFields(...) method. Anyone see anything wrong with this approach?

 

Regards,

 

Mike

14 REPLIES 14
Message 2 of 15
PSI_Tech
in reply to: PSI_Tech

I found that the serialization / deserialization for derived entities is working fine. The problem is my DetailerEntity class derives from AcDbEntity and inside of the dwgIn/OutFields(...) methods, calling the base class methods seems to create the issue. If I dont' call the base methods, all my objects properties are properly written out, if I do, all my properties are not.

 

#pragma region " AcDbObject "
/// ---------------------------------------------------------------------------------------------------------
/// <summary> Serializes the objects properties using a drawing filer object. This is called by the framework
/// during save, copy, and clone operations.</summary>
/// ---------------------------------------------------------------------------------------------------------
Acad::ErrorStatus DetailerEntity::dwgOutFields(AcDbDwgFiler* filer) const
{
	//Acad::ErrorStatus es = AcDbEntity::dwgOutFields(filer);
	//if (es != Acad::eOk)
	//	return es;

	filer->writeString(mId);
	filer->writeString(mName);
	filer->writeString(mDescription);
	filer->writeString(mTag);
	filer->writePoint3d(mPlacement);

	Utilities::FilerUtilities::dwgOutFields(filer, mRepresentation);
	return filer->filerStatus();
}
/// ---------------------------------------------------------------------------------------------------------
/// <summary> Deserializes the objects properties using a drawing filer object. This is called by the framework
/// during save, copy, and clone operations.</summary>
/// ---------------------------------------------------------------------------------------------------------
Acad::ErrorStatus DetailerEntity::dwgInFields(AcDbDwgFiler* filer)
{
	Acad::ErrorStatus es = Acad::eOk;
	/*Acad::ErrorStatus es = AcDbEntity::dwgInFields(filer);
	if (es != Acad::eOk)
		return es;*/

	ClearRepresentation();
	
	filer->readString(mId);				
	filer->readString(mName);
	filer->readString(mDescription);
	filer->readString(mTag);
	filer->readPoint3d(&mPlacement); 

	Utilities::FilerUtilities::dwgInFields(filer, mRepresentation);
	return filer->filerStatus();
}
#pragma endregion

 Anyone ever experienced this before? If I uncomment the AcDbEntity dwgIn/OutFields(...) methods, error status is Acad::eOk, but my objects aren't serialized properly.

 

Regards,

 

Mike

Message 3 of 15
owenwengerd
in reply to: PSI_Tech

I don't have time to search at the moment, but there have been past threads on the topic of embedded entities. Look for posts by Art Cooney.

--
Owen Wengerd
ManuSoft
Message 4 of 15
artc2
in reply to: PSI_Tech

Haver you verified in the debugger that calling the base class methods returns Acad::eOk so that the code that handles the embedded entity is actually executed?  Also, what is your class inheritance tree (i.e. what do your classes derive from)?

Message 5 of 15
PSI_Tech
in reply to: artc2

Yes I have verified all calls to dwgIn/OutFields returns Acad::eOk throughout the hierarchy. The inheritance tree is straight forward, AcDbEntity -> DetailerEntity -> DetailerProfile -> ClosedProfile.

 

Mike

Message 6 of 15
PSI_Tech
in reply to: artc2

artc2,

 

It appears that I have been fooled, the issue isn't in the dwgIn/OutFields(...) but rather the Database.WblockCloneObjects(...) (.NET). I don't override this, but I do call it in an attempt to copy objects (my entities in particular) from the current database to another drawing database. I am not sure why this is a problem but it is. I know this isn't the .NET forum, but since my problem is spanning the managed and unmanaged world here, maybe you can help? Is there any reason why the unmanaged entities would not be serializing their transient graphics properly during the cloning operation? Do I need to handle or override something in my custom entities?

 

Regards,

 

Mike

Message 7 of 15
artc2
in reply to: PSI_Tech

Are your entities themselves being correctly cloned (i.e. all but the embedded entity data)?  I don't see anything in the dwgOutFields/dwgInFields implementations that you posted that should cause any problems for wblockClone, but I don't know how the embedded entity's dwgOutFields/dwgInFields methods are implemented, so I don't know if they will do anything different for different filer types.

Message 8 of 15
PSI_Tech
in reply to: artc2

That is the funny part. If I wblock the entity in the current drawing and insert the block. Everything works just fine, including the embedded entities. It is only when I am trying to WblockCloneObjects(....) from "this" to another drawing or from another drawing to "this" drawing that I have problems. I can post an example of how I attempt to bring in my custom entity from an external drawing.

 

       private void LoadFromFile()
        {
            var ids = new ObjectIdCollection();
            var idMap = new IdMapping();
            var curDoc = Application.DocumentManager.MdiActiveDocument;
            var sourceDb = new Database(false, true);
            var targetDb = curDoc.Database;

            try
            {
                using (curDoc.LockDocument())
                {
                    sourceDb.ReadDwgFile(SelectedProfile.FilePath, FileShare.Read, true, "");
                    using (sourceDb)
                    {
                        var modelSpaceId = SymbolUtilityServices.GetBlockModelSpaceId(sourceDb);
                        using (var t = sourceDb.TransactionManager.StartTransaction())
                        {
                            var modelSpace = t.GetObject(modelSpaceId, OpenMode.ForRead) as BlockTableRecord;
                            foreach (ObjectId id in modelSpace)
                            {
                                Entity e = t.GetObject(id, OpenMode.ForRead) as Entity;
                                if (e.GetType() == typeof(ClosedProfileWrapper))
                                    ids.Add(id);
                            }
                            t.Abort();

                            using(var targetT = targetDb.TransactionManager.StartTransaction())
                            {
                                var targetSpaceId = SymbolUtilityServices.GetBlockModelSpaceId(targetDb);
                                targetDb.WblockCloneObjects(ids, targetSpaceId, idMap, DuplicateRecordCloning.Replace, false);
                                
                                IdPair idPair = idMap.Cast<IdPair>().FirstOrDefault();
                                if (idPair != null)
                                    ProfileId = idPair.Value;

                                targetT.Commit();
                            }
                        }
                    }
                }
            }
            catch(Exception ex)
            {
                curDoc.Editor.WriteMessage(ex.Message);
            }
        }

ClosedProfileWrapper is a .NET wrapper for my ClosedProfile entity.

 

Mike

Message 9 of 15
PSI_Tech
in reply to: PSI_Tech

Artc2,

 

I have attached a solution which illustrates my problem. It contains 3 projects: 

 

  1. Detailer.Entities which is the c++ dbx project
  2. Detailer.dotNet.Entities which implements the entity .NET wrapper objects
  3. and Detailer.dotNET which is the .NET arx application

Once compiled and "netloaded", the DET_MakeProfile command can be invoked which:

 

  • prompts the user to pick an entity
  • creates a new DetailerEntityWrapper object and sets the selected entity as its "Representation"
  • appends the DetailerEntityWrapper to the current working database
  • creates a circle for testing purposes at 0,0,0 with radius of 100 units
  • appends the circle to the current working database
  • wblocks the entity and circle out to a new drawing

As you will see, the Circle will be in the new drawing, my custom entity will as well, but the embedded entity selected is not fully serialized.

 

I hope someone can help me with this. It seems as though it should be so simple.

 

Regards,

 

Mike

Message 10 of 15
PSI_Tech
in reply to: PSI_Tech

Please, someone must have an idea. Feeling very discouraged at the moment. The issue is that I cannot copy the custom entity from one drawing to another. For some reason, the custom entity gets copied with the embedded entities, but the embedded entities are not copied correctly. This seems more like a bug in the ObjectArx or .NET WblockCloneObjects method. I am at wits end, I tried several approaches, all with the same outcome.

 

Anyone?

 

Mike

Message 11 of 15
owenwengerd
in reply to: PSI_Tech

If you are under time constraints, you might be better served to contract with Autodesk developer support or a private consultant for help with this sort of problem.

--
Owen Wengerd
ManuSoft
Message 12 of 15
artc2
in reply to: PSI_Tech

I'm sorry, but I don't have time right now to try and build and run your application.  If I can find some time, I'll try and take a look.

Message 13 of 15
PSI_Tech
in reply to: owenwengerd

Finally making some progress. It occured to me after several days of frustration to look at the FilerType in the dwgIn/OutFields methods. I seem to remember someone else having an issue and seeing the type kIdXlateFiler reminded me of it. I added a check to see if the filer is of this type before filing my embedded entities and skip the embedded entities if it is. Not sure if this is correct or not, but it seems to get me a little further. At least the embedded entities are showing up. Now having a problem with a crash when I click and drag my entity but that is a different problem, possibly a different post.

 

Anyway, my question to all you knowledgable out there, what is the kIdXlateFiler responsible for? I was assuming it is for mapping object handles to the object id (memory address), but not sure about that. Any documentation showing what theses filer types are for???

 

if(filer->filerType() != AcDb::kIdXlateFiler)
{
    Utilities::FilerUtilities::dwgOutFields(filer, mCurve);
}

 

Message 14 of 15
artc2
in reply to: PSI_Tech

The xlate filer deals with changing objectIds filed out by clone objects.  The clone object's dwgOutFIelds method is called to get the ids it files out. These would still be the same objectIds as in the original source object.  Then the idMap is used to find each of the ids and if an id is in the idMap, then the mapped value for it is used to replace it in the filer's data.  Once all of the ids are processed, then dwgInFields is called on the clone and since the xlate filer now has the mapped ids instead of the original ids, the clone's dwgInFields() will update the clone to use the mapped ids.

 

So, for an xlate filer, all that needs to be filed out/in is objectIds.  Any other data is ignored, so there's no need to file it.

Message 15 of 15
ChenX_7
in reply to: PSI_Tech

 
It is a pity.
I think we have the same problem
(The following English translation from Google).
 
I tried to use
 
(filer->filerType() == AcDb::kIdXlateFiler)
 
To solve the problem.

it is at CAD2007 ,Good running.
 
But when I move the code to a higher version of CAD.
 
use Ctrl+C.
 
It will prompt error
 
But it does not crash, still can operate normally.
 
But this makes me very prompt collapse
 

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

”Boost