public static System.Data.DataTable PasteUserSelectedData(string strAtts, string strDynAtts) { #region Variable Declaration System.Data.DataTable dtRetVal = new System.Data.DataTable(); Editor ed; AcadDataServ.Database db; AcadDataServ.Transaction tr, trCopyFrom; PromptPointOptions ppoOpts; AcadDataServ.DynamicBlockReferencePropertyCollection dbrpcDynamicProps; AcadDataServ.BlockReference brBlkRef; Autodesk.AutoCAD.DatabaseServices.AttributeCollection acAttCol; AcadDataServ.AttributeReference arAttRef = new AttributeReference(); AcadDataServ.ObjectId[] oiIdArray; System.IntPtr hwnd; PromptPointResult res; BlockTable btCopyTo = null; BlockTableRecord btrCopyTo = null; ObjectIdCollection oicCopyFrom, oicCopyFromOther = null; IdMapping idmCopyTo = null; Entity entCurrent = null; char[] charArr = new char[1]; string[] strAttsArr, strDynAttsArr; int j = 0; string strTemp = ""; System.IO.StreamWriter stw = new System.IO.StreamWriter("C:\\Users\\controls\\errors.txt", true); #endregion End Of Variable Declaration //get the names of all the attributes and dynamic attributes that the user wants from the block attributes charArr[0] = ','; if ((strAtts == "") || (strAtts == null)) { strAttsArr = new string[0]; } else { strAttsArr = strAtts.Split(charArr); } if ((strDynAtts == "") || (strDynAtts == null)) { strDynAttsArr = new string[0]; } else { strDynAttsArr = strDynAtts.Split(charArr); } //add all of the columns that are needed into the data table that will be returned to the user //to do this in one for loop a simple if else statement is required which just goes the length of both arrays for (int i = 0; i < strAttsArr.Length + strDynAttsArr.Length; i++) { //check to see if the column that is being added should come from the regular attributes or dynamic attributes if (i < strAttsArr.Length) { //add the column from the regular attributes dtRetVal.Columns.Add(strAttsArr[i], typeof(string)); }//otherwise the column that should be added comes from the dynamic attributes array else { //add the column from the dynamic attributes dtRetVal.Columns.Add(strDynAttsArr[i - strAttsArr.Length], typeof(string)); } } dtRetVal.Columns.Add("FILEFROM", typeof(string)); dtRetVal.Columns.Add("FILETO", typeof(string)); ed = AcadAppServ.Application.DocumentManager.MdiActiveDocument.Editor; db = AcadDataServ.HostApplicationServices.WorkingDatabase; tr = db.TransactionManager.StartTransaction(); //prompt the user to select blocks and then see if the blocks contain the attributes specified using (AcadAppServ.DocumentLock docLock = AcadAppServ.Application.DocumentManager.MdiActiveDocument.LockDocument()) { // The following two lines are useful to set the focus on the AutoCAD editor from a modeless form hwnd = adsw_acadDocWnd(); SetFocus(hwnd); // Start the transaction try { // Build a filter list so that any point can be selected ppoOpts = new PromptPointOptions(""); ppoOpts.Message = "\nSPECIFY A POINT TO PASTE THE OBJECTS:"; res = ed.GetPoint(ppoOpts); // Do nothing if selection is unsuccessful just prompt user that selection failed if (res.Status != PromptStatus.OK) { ed.WriteMessage("USER PASTE CANCELLED"); }//otherwise the user has selected something that should be handled and checked for the appropriate attributes else { //Open the block table records for writing so that the program can copy all of the autocad data btCopyTo = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead); btrCopyTo = (BlockTableRecord)tr.GetObject(btCopyTo[BlockTableRecord.ModelSpace], OpenMode.ForWrite); //check to see if the file to copy from is the same as the file to copy to because a different method to copy all of the data is needed //when copying to the same drawing can use DeepCloneObjects, but when copying to different drawings need to use WblockCloneObjects if (AcadAppServ.Application.DocumentManager.GetDocument(db).Name == AcadAppServ.Application.DocumentManager.GetDocument(dbCopyFrom).Name) { //copy all of the objects idmCopyTo = new IdMapping(); oiIdArray = ssCopyFrom.GetObjectIds(); oicCopyFrom = new ObjectIdCollection(oiIdArray); db.DeepCloneObjects(oicCopyFrom, btrCopyTo.Id, idmCopyTo, false); } else { //otherwise need to start another transaction on the copy from database trCopyFrom = dbCopyFrom.TransactionManager.StartTransaction(); using (AcadAppServ.DocumentLock docLockFrom = AcadAppServ.Application.DocumentManager.GetDocument(dbCopyFrom).LockDocument()) { try { //attempt to copy all of the data idmCopyTo = new IdMapping(); oiIdArray = ssCopyFrom.GetObjectIds(); oicCopyFromOther = new ObjectIdCollection(oiIdArray); db.WblockCloneObjects(oicCopyFromOther, btrCopyTo.Id, idmCopyTo, DuplicateRecordCloning.Ignore, false); trCopyFrom.Commit(); }//catch any errors that occur when interacting with the acad database and inform the user of the error catch (Exception exc) { ed.WriteMessage("Exception: " + exc.ToString()); } finally { //garbage collection on the transaction if problems occur trCopyFrom.Dispose(); } trCopyFrom.Dispose(); } } stw.WriteLine("Copy succeeded, onto transform."); idPairsCopyTo = new IdPair[0]; //go through all of the objects that were pasted and move them by the specified offset between the two points selected by the user foreach (IdPair idp in idmCopyTo) { //this if statement is to try and eliminate the casting of the object to an entity failure because these objects don't cast to entities if (!((idp.Key.ObjectClass.DxfName.ToUpper().Contains("DICTIONARY")) || (idp.Key.ObjectClass.DxfName.ToUpper().Contains("XRECORD")) || (idp.Key.ObjectClass.DxfName.ToUpper().Contains("SEQEND")) || (idp.Key.ObjectClass.DxfName.ToUpper().Contains("ACDB")) || (idp.Key.ObjectClass.DxfName.ToUpper().Contains("FIELD")) || (idp.Key.ObjectClass.DxfName.ToUpper().Contains("ACTION")) || (idp.Key.ObjectClass.DxfName.ToUpper().Contains("GRIP")) || (idp.Key.ObjectClass.DxfName.ToUpper().Contains("PARAMETER")) || (idp.Key.ObjectClass.DxfName.ToUpper().Contains("BLOCK_RECORD")) || (idp.Key.ObjectClass.DxfName.ToUpper().Contains("LAYER")) || (idp.Key.ObjectClass.DxfName.ToUpper().Contains("LTYPE")) || (idp.Key.ObjectClass.DxfName.ToUpper().Contains("VERTEX")) || (idp.Key.ObjectClass.DxfName.ToUpper().Contains("TABLE")) || (idp.Key.ObjectClass.DxfName.ToUpper().Contains("STYLE")) || (idp.Key.ObjectClass.DxfName.ToUpper().Contains("MATERIAL")) || (idp.Key.ObjectClass.DxfName.ToUpper().Contains("APPID")) || (idp.Key.ObjectClass.DxfName.ToUpper().Contains("ACAD_EVALUATION")))) { try { stw.WriteLine(idp.Key.ObjectClass.DxfName.ToUpper()); //try to get the object if it is an entity, could be a database which we can't move, then try to move the object based upon the points selected entCurrent = (Entity)tr.GetObject(idp.Value, OpenMode.ForRead); stw.WriteLine(entCurrent.ToString()); //check to make sure this in not an attribute reference because attributes are part of blocks and blocks will be moved along with the attributes that are //contained within them, the check for MODEL is to make sure that this is not a child of some other block or object if ((entCurrent.BlockName.ToUpper().Contains("MODEL")) && (entCurrent.GetType() != arAttRef.GetType())) { //since this is an object that needs to be moved upgrade the status of the transaction for this object so that it can be written to for the changes entCurrent.UpgradeOpen(); //move the object based upon the point selected for the copy and the point selected for the paste entCurrent.TransformBy(Matrix3d.Displacement(p3dCopyFrom.GetVectorTo(res.Value))); //now downgrade the status of the transaction for read only because the object doesn't need to be manipulated anymore entCurrent.DowngradeOpen(); try { //check to see if the entity is a block so that its attributes can be saved in a data table for use later if (idp.Key.ObjectClass.DxfName.ToUpper().Contains("INSERT")) { //save the id pairs so that attributes of that id pair can updated if needed later after the paste has occurred Array.Resize(ref idPairsCopyTo, idPairsCopyTo.Length + 1); idPairsCopyTo[j] = new IdPair(idp.Key,idp.Value, idp.IsCloned, idp.IsPrimary, idp.IsOwnerTranslated); //get the block reference for the current object id from the database of blocks brBlkRef = (AcadDataServ.BlockReference)entCurrent; //add a new row to the data table for each block that was selected dtRetVal.Rows.Add(); //put the name of the file for each block for the file it came from as well as the file it is going to strTemp = AcadAppServ.Application.DocumentManager.GetDocument(db).Name; strTemp = strTemp.Substring(strTemp.LastIndexOf("\\") + 1); dtRetVal.Rows[j]["FILETO"] = strTemp; strTemp = AcadAppServ.Application.DocumentManager.GetDocument(dbCopyFrom).Name; strTemp = strTemp.Substring(strTemp.LastIndexOf("\\") + 1); dtRetVal.Rows[j]["FILEFROM"] = strTemp; //check to see if the block has any dynamic properties and that we need to get dynamic properties //because if the calling function isn't looking for dynamic properties, then ignore this section if ((strDynAttsArr.Length > 0) && (brBlkRef.IsDynamicBlock == true)) { //get the appropriate dynamic properties for this block reference dbrpcDynamicProps = brBlkRef.DynamicBlockReferencePropertyCollection; //go through all of the dynamic properties and search for one of the list of dynamic properties for which the program wants a value foreach (AcadDataServ.DynamicBlockReferenceProperty dbrpDynamicProp in dbrpcDynamicProps) { //go through all dynamic attributes for which the program is searching and see if this dynamic attribute matches for (int i = 0; i < strDynAttsArr.Length; i++) { //if the dynamic attribute is this one then save the value to the data table in the current row and then exit this loop gracefully if (dbrpDynamicProp.PropertyName == strDynAttsArr[i]) { //save the value to the data table dtRetVal.Rows[j][strDynAttsArr[i]] = dbrpDynamicProp.Value.ToString(); i += strDynAttsArr.Length; } } } } //once the dynamic attribute search is complete, then search for the regular attributes of this block acAttCol = brBlkRef.AttributeCollection; //go through the collection of attributes and see if this one is in the list of attributes for which the program is searching foreach (AcadDataServ.ObjectId oiAttId in acAttCol) { //get the current attribute and check that one against the list of attributes arAttRef = (AcadDataServ.AttributeReference)tr.GetObject(oiAttId, AcadDataServ.OpenMode.ForRead); //check all attributes against the list of attributes for which the program is searching for (int i = 0; i < strAttsArr.Length; i++) { //is this attribute the one the program needs to find if (arAttRef.Tag == strAttsArr[i]) { //store the value into the data table and then exit the loop gracefully dtRetVal.Rows[j][strAttsArr[i]] = arAttRef.TextString; i += strAttsArr.Length; } } } j++; } } catch { } } entCurrent.Dispose(); } catch { } } } //commit all transactions in the acad databases tr.Commit(); } }//catch any errors that occur when interacting with the acad database and inform the user of the error catch (Autodesk.AutoCAD.Runtime.Exception ex) { ed.WriteMessage(("Exception: " + ex.Message)); } finally { //garbage collection on the transaction if problems occur tr.Dispose(); } tr.Dispose(); } AcadAppServ.Application.DocumentManager.MdiActiveDocument.Editor.Regen(); return dtRetVal; }