Hi
I'm trying to do something similar in an out-of-process C# app, and AcadSelectionSet,AddItems() raises an exception.
//perform a WBLOCK on blockName to tempPath
AcadSelectionSet sset = null; sset = AcadDoc.SelectionSets.Add("BlSet"); sset.Clear(); AcadBlocks blocks = AcadDoc.Blocks; AcadBlock bl = null; bl = blocks.Item(blockName);//gets the block definition of input block name int i = bl.Count;//the number of entities in the block definition AcadEntity ent; Object[] objs = new Object[i]; AcadEntity[] ents = new AcadEntity[i]; int j = 0; for (j = 0; j < i; j++)//iterates thru the block definition { ent = bl.Item(j);//gets one entity //add it to the array objs[j] = ent.Copy();//OK } for (j = 0; j < i; j++) { ents[j] = (AcadEntity)objs[j]; } sset.AddItems(objs);//exception acApp.ActiveDocument.Wblock(tempPath, sset); sset.Delete();
I've tried a number of ways, with and without copying the array and/or the entities, but it never comes out right.
Even when in the debugger I see the entities were added to the selection set, then the Wblock() method raises an exception.
Any tips will be VERY welcome.
Thanks
alex
This one should work:
[CommandMethod("wblocks")] public static void WBlocking() { string tempPath = @"C:\Test\WPART.dwg"; AcadApplication acApp = new AcadApplicationClass(); acApp.Documents.Open(@"C:\Test\WorkingDrawing.dwg", Type.Missing, Type.Missing); AcadDocument AcadDoc = acApp.ActiveDocument; acApp.Visible = true; AcadSelectionSet sset = null; //perform a WBLOCK on blockName to tempPathAcadSelectionSet sset = null; sset = AcadDoc.SelectionSets.Add("BlSet"); List<AcadBlockReference> brefs = new List<AcadBlockReference>(); AcadBlocks blocks = AcadDoc.Blocks; AcadBlock bl = null; string blockName = "PART"; bl = blocks.Item(blockName);//gets the block definition of input block name AcadModelSpace AcSpace = AcadDoc.ModelSpace; //loop through the model space to fill the list of block references foreach (AcadEntity acEnt in AcSpace) { if (acEnt is AcadBlockReference) { AcadBlockReference AcBref = acEnt as AcadBlockReference; if (AcBref.EffectiveName == blockName) { brefs.Add(AcBref); } } } // convert list to array of objects Object[] objs = brefs.ToArray(); // cast array as single object Object pSelSet = (Object)objs; sset.AddItems(pSelSet);// select Additems, then click "Go to Definition" to see arguments acApp.ActiveDocument.Wblock(tempPath, sset); sset.Delete(); AcadDoc.Close(Type.Missing, Type.Missing); }
~'J'~
Hallex
Thank you for the response.
If I understand your code correctly, it writes to disk all instances of a particular block reference, which is not what I meant.
What I need is to write to disk just the block definition (as in WBLOCK blockName ...)
ANyway, I modified my code as per your suggestion, but I still get an exception on
sset.AddItems(pSelSet);//exception
The exception is:Error HRESULT E_FAIL has been returned from a call to a COM component.
Could you comment on that?
N.B. The code has to be compatible with ACAD 2004. Could this be the problem?
Thanks again
alex
To write on disk the block definitions you have use CloneObjects method instead,
see VBA help for more, if I can I will try to write an example about
~'J'~
Hallex
I can't seem to find a CloneObjects() method in Interop.
If you mean CopyObjects(), all I could find about it is some examples of its use for copying objects between databases and no documentation (also the examples are in VB, knowledge of which I have less than zero).
I understand that there is a problem copying entities from a block definition.
Maybe the (ugly) solution would be
[insert the block; explode it; add the exploded entities to the selection set; wblock the selection set; erase the exploded entities]
Could you help?
Thanks
alex
I can't test this code on A2004,
just tested them on my A2010, all is Ok here
Try again:
[CommandMethod("copydef")] public static void CopyBlockDefToDwg() { MessageBox.Show("Wait..."); // change file names to suit: string sourcePath = @"C:\Test\WorkingDrawing2.dwg"; string tempPath = @"C:\Test\atest.dwg"; AcadApplication acApp = new AcadApplicationClass(); //open for read only acApp.Documents.Open(sourcePath, Type.Missing, Type.Missing); AcadDocument AcadDoc = acApp.ActiveDocument; acApp.Visible = true; AcadBlocks blocks = AcadDoc.Blocks; // change block name to suit string blockName = "PART"; AcadBlock bl = blocks.Item(blockName);//gets the block definition of input block name // copy blockdefinition to array of AcadObject AcadObject[] copy = new AcadObject[1]; copy[0] = (AcadObject)bl; // convert array as single object object safe = copy as object; //open for read write acApp.Documents.Open(tempPath, false, Type.Missing); // set source document to be active AcadDocument newDoc = acApp.ActiveDocument; // prepare arguments for CoptObjects object IdPairs = new object(); // set all arguments as objects AcadDoc.CopyObjects(safe, newDoc.Blocks as object, ref IdPairs); // close and save destination document newDoc.SaveAs(tempPath, Type.Missing, Type.Missing); acApp.ActiveDocument = AcadDoc; newDoc.Close(); // close source document without changes AcadDoc.Close(Type.Missing, Type.Missing); acApp.Quit(); }
~'J'~
Hallex
The method you posted adds the block definition to the Blocks collection.
I needed it to work like the WBLOCK Autocad command, so I had to modify it a little for that (copy the block definition entityes to the new db model space).
There were some issues with parameters too (probably because the Acad 2004 compatibility requirement).
Anyway, your suggestion works great and Thank you.
Here is the final code:
private void createOutDwg(string tempPath, string blockToOutput) { AcadBlocks blocks = aCadDoc.Blocks; AcadBlock bl = blocks.Item(blockToOutput);//gets the block definition // copy block definition to array of AcadObject int i = bl.Count; AcadObject[] copy = new AcadObject[i]; for (int j = 0; j < i; j++)//iterates thru the block definition { copy[j] = (AcadObject)bl.Item(j); ;//gets one entity } // convert array as single object object safe = copy as object; //create new document acApp.Documents.Add(Type.Missing); //remember it AcadDocument newDoc = acApp.ActiveDocument; // prepare arguments for CopyObjects object IdPairs = new object(); // set all arguments as objects aCadDoc.CopyObjects(safe, newDoc.ModelSpace as object, ref IdPairs); //save and close destination document newDoc.SaveAs(tempPath, Type.Missing, Type.Missing); //make source document active before closing new doc acApp.ActiveDocument = aCadDoc; newDoc.Close(Type.Missing, Type.Missing); }
I still can't understand why we can't just add entities from the block definition to a selection set and the just Wblock() it. Maybe the Autocad people would like to comment on that.
Thank you again.
alex
Glad I could help,
Happy coding,
Cheers
~'J'~