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

SetXData extremely slow

19 REPLIES 19
Reply
Message 1 of 20
jramos
1203 Views, 19 Replies

SetXData extremely slow

I have this piece of code that runs fine in every drawing I tested.

/*acadNewBlock is of type Autodesk.AutoCAD.Interop.Common.AcadBlockReference and was created with acadApp.ActiveDocument.ModelSpace.InsertBlock(...)*/

short []dataType;
object []data;

dataType = new short[6];
data = new object[6];

dataType[0] = 1001; data[0] = "AppName_v1";
dataType[1] = 1000; data[1] = acadNewBlock.Handle;
dataType[2] = 1000; data[2] = "asdfasdf";
dataType[3] = 1000; data[3] = "xxacxas";
dataType[4] = 1000; data[4] = "asdfasdfadf";
dataType[5] = 1000; data[5] = "asdfasfasf assdfass";
acadNewBlock.SetXData(dataType, data);

But then I have a big drawing (a 2.7MB DWG) where the call acadNewBlock.SetXData(dataType, data) takes almost 2 minutes to complete! I've searched everywhere if I was doing something wrong and I'm running out of ideas. Can someone please help? (I'm using Visual Studio 2005 Express Edition with .NET and AutoCAD 2007)
19 REPLIES 19
Message 2 of 20
dgorsman
in reply to: jramos

Does the rest of the routine get *all* of the specified blocks, then add the XDATA to each of them?
----------------------------------
If you are going to fly by the seat of your pants, expect friction burns.
"I don't know" is the beginning of knowledge, not the end.


Message 3 of 20
jramos
in reply to: jramos

I don't know what you mean, but the routine ends there, the control is returned to AutoCAD after SetXData(...)
Message 4 of 20
dgorsman
in reply to: jramos

To rephrase: are you adding XDATA to all of the specified block refs objects in the drawing, or just one?
----------------------------------
If you are going to fly by the seat of your pants, expect friction burns.
"I don't know" is the beginning of knowledge, not the end.


Message 5 of 20
jramos
in reply to: jramos

I'm adding XData to all of the blocks that I create. I don't touch other blocks.
Essentially, my application consists of a toolbar where the user can select what blocks to add to the drawing. I then create an entity of the block type the user requested in the drawing and then call SetXData to save some internal information on it.
Message 6 of 20
Anonymous
in reply to: jramos

Is there a reason you’re not adding your XData using the managed wrappers?
Message 7 of 20
Anonymous
in reply to: jramos

This newsgroup is primarily focused on using the
managed .NET API, rather than the ActiveX API
from a .NET language (what your code uses).

I don't know what the problem is, but perhaps
someone in the VBA newsgroup might have come
across it as well.

Also, you haven't indicated whether this is an
in-process DLL or an out-of-process EXE. My
advice would be to post in the VBA newsgroup.

--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2008
Supporting AutoCAD 2000 through 2008
http://www.acadxtabs.com

wrote in message news:5746281@discussion.autodesk.com...
I'm adding XData to all of the blocks that I create. I don't touch other blocks.
Essentially, my application consists of a toolbar where the user can select what blocks to add to the drawing. I then create an entity of the block type the user requested in the drawing and then call SetXData to save some internal information on it.
Message 8 of 20
jramos
in reply to: jramos

My application should run on AutoCAD 2005, 2006, 2007 and 2008 (it is a DLL by the way, loaded with the command netload).
Because managed wrappers aren't available in AutoCAD 2005, I had to go with ActiveX so that the same code could be used in every version.
Message 9 of 20
Anonymous
in reply to: jramos

Ouch, I was going to try and steer you into using the wrappers, but it seems you have chosen the “eternal COM nightmare” ; )
Message 10 of 20
Anonymous
in reply to: jramos

If you use "NETLOAD" to load the DLL, it must be managed wrapper (.NET API),
it may or may not run on ALL version of Acad, depending on what your code
does.

You still did not indicating how many block references you are setting XData
to, one (that takse minites) or many. If it is many, is it possible the time
is caused by looping through each entity to find the block reference? If you
post bigger chunk of code, it may help to spot the problem.

Since you ARE using .NET API, why don't you use .NET API

DBObject.XData=[ResultBuffer]

instead of COM API in .NET API DLL?

I am not sure how it affect the speed, but think:

When use .NET API: Acad native ObjectARX code->.NET API
When use COM API in .NET API DLL: Acad native code->ActiveX API
Wrapper->.NET Wrapper

With COM API in .NET API DLL, you have to marshal data through at least one
extra layer. So, if you program with .NET API, try to use .NET API
objects/properties/methods first, only use COM API in .NET API DLL when
there is no .NET way to do it (there are quite a few missing in early .NET
API on Acad2005/6).

I used .NET API to set/retreive XData and did not notice obvious slowness
(not attaching XData to massive entities, though).

wrote in message news:5746491@discussion.autodesk.com...
My application should run on AutoCAD 2005, 2006, 2007 and 2008 (it is a DLL
by the way, loaded with the command netload).
Because managed wrappers aren't available in AutoCAD 2005, I had to go with
ActiveX so that the same code could be used in every version.
Message 11 of 20
jramos
in reply to: jramos

I'm setting XData in only one block reference, and that takes minutes.

The reason I'm using the COM API in my DLL is because that's the only thing I could come up with using the developer help that comes with AutoCAD 2005. I couldn't find out the proper DLLs to reference in my Visual Studio solution and ended up referencing the COMs that were available. I understand what you said about the extra layer since my code is .NET wrapped calling ActiveX APIs and I guess that is why my code may run slow.

Could you please help me? I don't know how to use .NET API with AutoCAD 2005. If I could at least call:

DBObject.XData=[ResultBuffer]

from the .NET API my problem would probably be solved...
Message 12 of 20
Anonymous
in reply to: jramos

Firstly, please make it clear:

Are you doing .NET API project, whcih pruduces a .NET DLL file and uses
"NETLOAD" command to load into Acad;
Or, you just do COM API programming by using VS2005 (stand alone app or
COM-able .NET DLL, which you call in VBA)?

If you do .NET API project (since you said your DLL is loaded by "NETLOAD"),
then you must already have necessary libraryies referenced (acdbmgd.dll and
acmgd.dll), in this case you do not need add reference to COM API.

Using .NET API to set XData is fairly simple:

1. get ObjectId from the targeting Entity
2. Start a transaction
3. create a ResultBuffer with needed data
4. Get the Entity from database according to its ObjectId
5. Entity.XData=theResultBuffer;
6. Commit the transaction


Also, if you do .NET API, Acad2005 would not be good platform to run, since
it is the very first version of Acad with .NET API available (buggy and
limited). Acad2006 would be the first usable .NET API version.

Not like LISP and VBA, ObjectARX and its .NET API may not that good to
targeting wide range of Acad versions, depending on what the program does.
You have to be aware its incompatibility between versions, especially
accross major version changes, such as 2000-2002, 2004-2006, 2007-2009(?).

As for the slowness of your code, I have no idea.


wrote in message news:5747514@discussion.autodesk.com...
I'm setting XData in only one block reference, and that takes minutes.

The reason I'm using the COM API in my DLL is because that's the only thing
I could come up with using the developer help that comes with AutoCAD 2005.
I couldn't find out the proper DLLs to reference in my Visual Studio
solution and ended up referencing the COMs that were available. I understand
what you said about the extra layer since my code is .NET wrapped calling
ActiveX APIs and I guess that is why my code may run slow.

Could you please help me? I don't know how to use .NET API with AutoCAD
2005. If I could at least call:

DBObject.XData=[ResultBuffer]

from the .NET API my problem would probably be solved...
Message 13 of 20
jramos
in reply to: jramos

Well, I changed the code to use .NET API and the same problem occurs. This is my code:

static public void XDataCreateBlock2 (Autodesk.AutoCAD.Interop.Common.AcadBlockReference acadBlock)
{
Database acadDB;
TransactionManager acadTManager;
RegAppTable regAppTable;

acadDB = Application.DocumentManager.MdiActiveDocument.Database;
acadTManager = acadDB.TransactionManager;
using(Transaction trans = acadTManager.StartTransaction())
{
regAppTable = (RegAppTable)trans.GetObject(acadDB.RegAppTableId, OpenMode.ForWrite);
if (regAppTable.Has("myAppName") == false)
{
RegAppTableRecord xdRec;
xdRec = new RegAppTableRecord();
xdRec.Name = "myAppName";

regAppTable.Add(xdRec); acadTManager.AddNewlyCreatedDBObject(xdRec, true);
}

trans.Commit();
}

try
{
using(Transaction trans = acadTManager.StartTransaction())
{
Entity entity;
ObjectId objID;
ResultBuffer resultBuffer;


objID = new ObjectId();
objID.OldId = acadBloco.ObjectID;
entity = (Entity)trans.GetObject(objID, OpenMode.ForWrite, false, true);

resultBuffer = new ResultBuffer();
resultBuffer.Add(new TypedValue(Convert.ToInt16(DxfCode.ExtendedDataRegAppName), "myAppName"));
resultBuffer.Add(new TypedValue(Convert.ToInt16(DxfCode.ExtendedDataAsciiString), "adsfasdfasdf"));
resultBuffer.Add(new TypedValue(Convert.ToInt16(DxfCode.ExtendedDataAsciiString), "asdfasdfasdf"));
resultBuffer.Add(new TypedValue(Convert.ToInt16(DxfCode.ExtendedDataAsciiString), "adfasdfasdf"));
resultBuffer.Add(new TypedValue(Convert.ToInt16(DxfCode.ExtendedDataAsciiString), "asfasdfasdfasdf"));
resultBuffer.Add(new TypedValue(Convert.ToInt16(DxfCode.ExtendedDataAsciiString), "asasdfasdfasdfasdf"));

entity.XData = resultBuffer;
trans.Commit();
}
}
catch(Exception exp)
{
}

The last call to "trans.Commit();" takes 2 minutes and 50 seconds to complete.
Message 14 of 20
Anonymous
in reply to: jramos

It became an interesting topic now.

You code looks OK to me. I have similar code (testing if an application name
is registered first, if not add one; then attach XData with taht application
name to an Entity.), it just work well with both Acad2006 and 2007 on
different computers.

So, you need to identify which line of the code is the reason. For example:

1. try use smaller ResultBuffer, say, only attach 1 piece data, rather than
5; or
2. try set the XData with different type, say, interger, instead of string;
or
3. try different BlockReference, or even different type of Entity; or
4. Not passing COM AcadBlockRefernece to the method, passing in an valid
DBObject's ObjectId directly instead; or...

These different test may or may not reveal the cause of slowness, but you
have to try. I believe you are not the first one who use .NET API to set
XData, I did not heard such a slowness until now. YOu may even try to run
the same code on other computer to eliminate possible hardware issue, or
write equivalent VBA code to set the same XData to the same BlockReference,
to see what happens.

Sorry for not being more help, but I'd like to hear the result of whatever
you tried.



wrote in message news:5747834@discussion.autodesk.com...
Well, I changed the code to use .NET API and the same problem occurs. This
is my code:

static public void XDataCreateBlock2
(Autodesk.AutoCAD.Interop.Common.AcadBlockReference acadBlock)
{
Database acadDB;
TransactionManager acadTManager;
RegAppTable regAppTable;

acadDB = Application.DocumentManager.MdiActiveDocument.Database;
acadTManager = acadDB.TransactionManager;
using(Transaction trans = acadTManager.StartTransaction())
{
regAppTable = (RegAppTable)trans.GetObject(acadDB.RegAppTableId,
OpenMode.ForWrite);
if (regAppTable.Has("myAppName") == false)
{
RegAppTableRecord xdRec;
xdRec = new RegAppTableRecord();
xdRec.Name = "myAppName";

regAppTable.Add(xdRec); acadTManager.AddNewlyCreatedDBObject(xdRec, true);
}

trans.Commit();
}

try
{
using(Transaction trans = acadTManager.StartTransaction())
{
Entity entity;
ObjectId objID;
ResultBuffer resultBuffer;


objID = new ObjectId();
objID.OldId = acadBloco.ObjectID;
entity = (Entity)trans.GetObject(objID, OpenMode.ForWrite, false, true);

resultBuffer = new ResultBuffer();
resultBuffer.Add(new
TypedValue(Convert.ToInt16(DxfCode.ExtendedDataRegAppName), "myAppName"));
resultBuffer.Add(new
TypedValue(Convert.ToInt16(DxfCode.ExtendedDataAsciiString),
"adsfasdfasdf"));
resultBuffer.Add(new
TypedValue(Convert.ToInt16(DxfCode.ExtendedDataAsciiString),
"asdfasdfasdf"));
resultBuffer.Add(new
TypedValue(Convert.ToInt16(DxfCode.ExtendedDataAsciiString),
"adfasdfasdf"));
resultBuffer.Add(new
TypedValue(Convert.ToInt16(DxfCode.ExtendedDataAsciiString),
"asfasdfasdfasdf"));
resultBuffer.Add(new
TypedValue(Convert.ToInt16(DxfCode.ExtendedDataAsciiString),
"asasdfasdfasdfasdf"));

entity.XData = resultBuffer;
trans.Commit();
}
}
catch(Exception exp)
{
}

The last call to "trans.Commit();" takes 2 minutes and 50 seconds to
complete.
Message 15 of 20
Anonymous
in reply to: jramos

Can you post (in a .zip file) the drawing that has the problem?

--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2008
Supporting AutoCAD 2000 through 2008
http://www.acadxtabs.com

wrote in message news:5747834@discussion.autodesk.com...
Well, I changed the code to use .NET API and the same problem occurs. This is my code:

static public void XDataCreateBlock2 (Autodesk.AutoCAD.Interop.Common.AcadBlockReference acadBlock)
{
Database acadDB;
TransactionManager acadTManager;
RegAppTable regAppTable;

acadDB = Application.DocumentManager.MdiActiveDocument.Database;
acadTManager = acadDB.TransactionManager;
using(Transaction trans = acadTManager.StartTransaction())
{
regAppTable = (RegAppTable)trans.GetObject(acadDB.RegAppTableId, OpenMode.ForWrite);
if (regAppTable.Has("myAppName") == false)
{
RegAppTableRecord xdRec;
xdRec = new RegAppTableRecord();
xdRec.Name = "myAppName";

regAppTable.Add(xdRec); acadTManager.AddNewlyCreatedDBObject(xdRec, true);
}

trans.Commit();
}

try
{
using(Transaction trans = acadTManager.StartTransaction())
{
Entity entity;
ObjectId objID;
ResultBuffer resultBuffer;


objID = new ObjectId();
objID.OldId = acadBloco.ObjectID;
entity = (Entity)trans.GetObject(objID, OpenMode.ForWrite, false, true);

resultBuffer = new ResultBuffer();
resultBuffer.Add(new TypedValue(Convert.ToInt16(DxfCode.ExtendedDataRegAppName), "myAppName"));
resultBuffer.Add(new TypedValue(Convert.ToInt16(DxfCode.ExtendedDataAsciiString), "adsfasdfasdf"));
resultBuffer.Add(new TypedValue(Convert.ToInt16(DxfCode.ExtendedDataAsciiString), "asdfasdfasdf"));
resultBuffer.Add(new TypedValue(Convert.ToInt16(DxfCode.ExtendedDataAsciiString), "adfasdfasdf"));
resultBuffer.Add(new TypedValue(Convert.ToInt16(DxfCode.ExtendedDataAsciiString), "asfasdfasdfasdf"));
resultBuffer.Add(new TypedValue(Convert.ToInt16(DxfCode.ExtendedDataAsciiString), "asasdfasdfasdfasdf"));

entity.XData = resultBuffer;
trans.Commit();
}
}
catch(Exception exp)
{
}

The last call to "trans.Commit();" takes 2 minutes and 50 seconds to complete.
Message 16 of 20
jramos
in reply to: jramos

Well, the problem kind of solved itself... Don't ask me how...
First, I did what Norman Yuan suggested: I used a smaller ResultBuffer, used different types, etc, but nothing worked. Then, since I was inserting the block reference with the COM API, I decided to insert the block reference with the .NET API but still nothing. Then I decided to take a break from it and I decided do finish reviewing my code. Later in that the day, I was checking a method that needed to move through all the objects in a drawing, and the main cycle looked like this:

for(int i=0; i less acadApp.ActiveDocument.ModelSpace.Count; i++)

then I decided to replace it with

foreach(Autodesk.AutoCAD.Interop.Common.AcadEntity acadEntity in acadApp.ActiveDocument.ModelSpace)

to make the code cleaner. Except that this change made the code run A LOT faster. I know that a foreach cycle is usually faster than a for(int i) one in .NET, but the difference using it with the AutoCAD COM API is huge! I mean real huge. After changing all of my cycles to foreach (obviously) I was doing some debugging and then decided to test with the drawings that where giving me the problem inserting the XData. To my surprise: problem solved!
Message 17 of 20
Anonymous
in reply to: jramos

The problem didn't solve itself. It was just unrelated to
setting xdata, and not in the code you posted.

Iterating over a block's contents that way is notoriously
slow, because of two main reasons:

The Count property of a block requires the implementation
code to iterate all the items in the block (skipping erased
objects) to produce its result, which means that it can take
a long time on a large block.

The indexer (e.g., ModelSpace.Items[index]), must do the
same thing as the Count property, to find a given element
having the specified index.

foreach() elminates that problem.

--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2008
Supporting AutoCAD 2000 through 2008
http://www.acadxtabs.com

wrote in message news:5749535@discussion.autodesk.com...
Well, the problem kind of solved itself... Don't ask me how...
First, I did what Norman Yuan suggested: I used a smaller ResultBuffer, used different types, etc, but nothing worked. Then, since I was inserting the block reference with the COM API, I decided to insert the block reference with the .NET API but still nothing. Then I decided to take a break from it and I decided do finish reviewing my code. Later in that the day, I was checking a method that needed to move through all the objects in a drawing, and the main cycle looked like this:

for(int i=0; i less acadApp.ActiveDocument.ModelSpace.Count; i++)

then I decided to replace it with

foreach(Autodesk.AutoCAD.Interop.Common.AcadEntity acadEntity in acadApp.ActiveDocument.ModelSpace)

to make the code cleaner. Except that this change made the code run A LOT faster. I know that a foreach cycle is usually faster than a for(int i) one in .NET, but the difference using it with the AutoCAD COM API is huge! I mean real huge. After changing all of my cycles to foreach (obviously) I was doing some debugging and then decided to test with the drawings that where giving me the problem inserting the XData. To my surprise: problem solved!
Message 18 of 20
jramos
in reply to: jramos

Well, I guess that is it then...
By the way, is there another way to get all the block references inside a drawing without having to interact all the entities in the drawing, like I am doing with:

foreach(Autodesk.AutoCAD.Interop.Common.AcadEntity acadEntity in acadApp.ActiveDocument.ModelSpace)
Message 19 of 20
Anonymous
in reply to: jramos

That is why I asked you many block references you need to set XData.

Looping throughentire model for certain type of entity is hardly a good way,
unless the model is very small. Even you use For Each...Next, not For i=0 To
ModelSpace.Count...Next, it is still not good enough if you have huge count
of entities in the model.

With COM API, you can use AcadSelectionSet.Selecct() , with .NET API, you
can use Editor.GetEntity()/Editor.SelectXXX(). You define filter in these
method call.


wrote in message news:5751301@discussion.autodesk.com...
Well, I guess that is it then...
By the way, is there another way to get all the block references inside a
drawing without having to interact all the entities in the drawing, like I
am doing with:

foreach(Autodesk.AutoCAD.Interop.Common.AcadEntity acadEntity in
acadApp.ActiveDocument.ModelSpace)
Message 20 of 20
Anonymous
in reply to: jramos

BlockTableRecord.GetBlockReferenceIds()

--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2008
Supporting AutoCAD 2000 through 2008
http://www.acadxtabs.com

wrote in message news:5751301@discussion.autodesk.com...
Well, I guess that is it then...
By the way, is there another way to get all the block references inside a drawing without having to interact all the entities in the drawing, like I am doing with:

foreach(Autodesk.AutoCAD.Interop.Common.AcadEntity acadEntity in acadApp.ActiveDocument.ModelSpace)

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

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost