Author Topic: HostApplicationServices.WorkingDatabase  (Read 6170 times)

0 Members and 1 Guest are viewing this topic.

WILL HATCH

  • Bull Frog
  • Posts: 450
HostApplicationServices.WorkingDatabase
« on: January 10, 2013, 11:41:26 AM »
I came across a confusing issue recently while working on a tool to migrate old title blocks to new ones. First there is a program which will interact with the user to generate a sort of mapping from the old block(name, attributes, scale) to the new one.  Then there is a separate on which will read that mapping, prompt for a selection of file, then go through each of them replacing the block.  The problem that has come up is some computers were crashing AFTER the command had finished leaving no useful debugging info.  The new files were still being created properly with the blocks replaced, upon audit they were fine.  Shortened code below:

Code - C#: [Select]
  1. [CommandMethod("SWAPBLOCKS", CommandFlags.Session)]
  2.         public void SwapBlocks()
  3.         {
  4.             //prompt config file
  5.  
  6.            
  7.                 using (Database srcdb = new Database(false, false))
  8.                 {
  9.                     //get file containing new block as defined in config file, or guide user through finding it
  10.  
  11.                     //build up dictionary to link old attribute names to new ones
  12.  
  13.                     //get selection of files to operate on
  14.                     string[] names = ofd.GetFilenames();
  15.  
  16.                     foreach (string name in names)
  17.                     {
  18.                         try
  19.                         {
  20.                             //read dgw into side database, if the block table has our old block then go through each record looking for instances of it
  21.                                 foreach (ObjectId id in bt)
  22.                                 {
  23.                                     BlockTableRecord btr = (BlockTableRecord)tr.GetObject(id, OpenMode.ForWrite);
  24.                                     IEnumerable<BlockReference> blocks = AcDbExtensions.GetObjects<BlockReference>(btr, OpenMode.ForWrite, false, true).Where(BlockReference => BlockReference.Name == configData[2, 2].ToString());
  25.                                     foreach (BlockReference block in blocks)
  26.                                     {
  27.                                         //collect location, scale, layer, containing blocktablerecord, attributes, then erase
  28.                                     }
  29.                                 }
  30.                                 //erase old block definition
  31.                                 //clone new block def into dwg
  32.                                 //create new block ref where each old block ref was, mapping scales, attributes
  33.                                 destdb.Clayer = StartLayer;
  34.                                 tr.Commit();
  35.  
  36.                             }
  37.                             doclock.Dispose();
  38.                             HostApplicationServices.WorkingDatabase = db;//  <--- working database must be restored here to prevent some computers from crashing
  39.                             destdb.SaveAs(name.Substring(0, name.Length - 4) + "_updated.dwg", DwgVersion.Current);
  40.                             destdb.SaveAs(name.Substring(0, name.Length - 4) + "_updated.BAK", DwgVersion.Current);
  41.                             destdb.Dispose();
  42.                         }
  43.                         catch (System.Exception e)
  44.                         {
  45.                             System.Windows.MessageBox.Show(e.ToString(), "Error");
  46.                             throw;
  47.                         }
  48.                     }
  49.                     //HostApplicationServices.WorkingDatabase = db;//  <---- if I restore working database here, the program crashes autocad on some of the computers here
  50.                 }
  51.         }
  52.  

I'm concerned that resetting inside the try catch statement may result in a fatal error if there is an error in the try and the working database is not restored before returning control to autocad.

Anybody know what's causing the error here?  Should I leave the last line in the program to restore the working database in case the try fails?  Why does it fail on one machine but work on another when they're all the same hardware/os/ACAD 2012?!?!?

Thanks!

fixo

  • Guest
Re: HostApplicationServices.WorkingDatabase
« Reply #1 on: January 10, 2013, 03:39:17 PM »
The reason of in this line of code:
destdb.Dispose();
Hey, after disposing database you want to use it again,
that's not good idea :)
and also this code line:
doclock.Dispose(); is smells the same
if you're use:
using (Object someobject=ParentObject.SomeProperty)
{

}// here someobject is disposed

then after the last curled bracket your object
should be disposed comletely, thus you don't need to
add someobject.Dispose(); after

Cheers :)

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: HostApplicationServices.WorkingDatabase
« Reply #2 on: January 11, 2013, 01:16:59 AM »
Hi,

It's difficult to see what is (are) wrong in your code because the extract you posted hide some important things as instantiations of db, tr, doclock...

Anyway, it seems to mee this code is build from snippets found here and there that you do not realy understand (using statement, extension methods...)

IMO you're wrong in the way you nest statements and loops (creating a single new Database and using it to read each file).

Pseudo code:
Code: [Select]
Document doc = Application.DocumentManager.MdiActiveDocument
Database db = doc.Database;

foreach (string name in names)
{
    using(Database srcdb = new Database(false, false))
    {
        srcdb.ReadDwgFile(...)
using(Transaction tr = srcdb.TransactionManager.StartTransaction())
{
    // do your stuff for each file database here
} // <- the transaction is diposed here
    } // <- the side database is disposed here
}
Speaking English as a French Frog

TheMaster

  • Guest
Re: HostApplicationServices.WorkingDatabase
« Reply #3 on: January 11, 2013, 09:04:09 AM »
I think you're leaving a few too many pieces out of the puzzle.

You show variables that are being dispsosed but don't show the code where they're initialized or assigned.

Given that, you're basically asking us to guess what the code you don't show is doing.

What I can tell you is that there is no reason to change the current working database when working with Databases for files that aren't open in the Editror, so I'm just wondering why you think you need to do that.

WILL HATCH

  • Bull Frog
  • Posts: 450
Re: HostApplicationServices.WorkingDatabase
« Reply #4 on: January 11, 2013, 12:32:45 PM »
Complete code:

Code - C#: [Select]
  1.     class BlkRef
  2.     {
  3.         public Point3d Insert { get; set; }
  4.         public Scale3d Scale { get; set; }
  5.         public ObjectId layerID { get; set; }
  6.         public Dictionary<string, string> Attributes { get; set; }
  7.         public BlockTableRecord Space { get; set; }
  8.  
  9.     }
  10.         [CommandMethod("SWAPBLOCKS", CommandFlags.Session)]
  11.         public void SwapBlocks()
  12.         {
  13.             Document doc = Application.DocumentManager.MdiActiveDocument;
  14.             Editor ed = doc.Editor;
  15.             Database db = doc.Database;
  16.             //get config data
  17.             OpenFileDialog ofd = new OpenFileDialog(
  18.                 "Select Config File",
  19.                 Directory.GetParent(db.Filename).ToString(),
  20.                 "xlsx;xls",
  21.                 "ConfigFile",
  22.                 OpenFileDialog.OpenFileDialogFlags.SearchPath
  23.                 );
  24.             System.Windows.Forms.DialogResult dr = ofd.ShowDialog();
  25.             if (dr != System.Windows.Forms.DialogResult.OK)
  26.                 return;
  27.             string[] configFile = ofd.GetFilenames();
  28.             object[,] configData = ExcelFunctions.ExtractSheetData(configFile[0], 1);
  29.  
  30.  
  31.             using (Database srcdb = new Database(false, false))
  32.             {
  33.                 BlockTable srcbt;
  34.                 BlockTableRecord srcbtr;
  35.                 try
  36.                 {
  37.                     List<object> srcData = new List<object>();
  38.                     string sourcePath = configData[1, 1].ToString();
  39.                     //if original source block dwg doesnt exist, get a dwg which contains it
  40.                     if (!File.Exists(sourcePath))
  41.                     {
  42.                         ed.WriteMessage("\n{0} does not exist!", configData[1, 1]);
  43.                         srcData = GetBlockReference("Replacement");
  44.                         sourcePath = srcData[0].ToString();
  45.  
  46.                     }
  47.                    
  48.                    
  49.                     //get dwg with source block table record to clone into destination databases
  50.                     while (true) //here we make sure we have the source block defined in the mapping file
  51.                     {
  52.                         //we skip this section if the config data pointed to an existing file
  53.                         if (srcData.Count != 0)
  54.                         {
  55.                             sourcePath = srcData[0].ToString();
  56.                             if (sourcePath == "fail") //if GetBlockReference failed operation failed
  57.                             {
  58.                                 ed.WriteMessage("\nFailed to get a replacement block");
  59.                                 return;
  60.                             }
  61.                             if (srcData[1].ToString() != configData[2, 1].ToString()) //check we have the same block the mapping is set up for
  62.                             {
  63.                                 ed.WriteMessage("\nBlock ({0}) does not match replacement from config file ({1})", srcData[1], configData[2, 1]);
  64.                                 srcData = GetBlockReference("Replacement");
  65.                                 continue;
  66.                             }
  67.                         }
  68.                         using (DocumentLock locking = doc.LockDocument())
  69.                         {
  70.                             srcdb.ReadDwgFile(sourcePath, FileOpenMode.OpenForReadAndAllShare, true, "");
  71.                             srcdb.CloseInput(true);
  72.  
  73.  
  74.                             using (Transaction tr = srcdb.TransactionManager.StartTransaction())
  75.                             {
  76.                                 srcbt = (BlockTable)tr.GetObject(srcdb.BlockTableId, OpenMode.ForRead);
  77.  
  78.                                 if (srcbt.Has(configData[2, 1].ToString())) //check dwg has source block
  79.                                 {
  80.                                     srcbtr = (BlockTableRecord)tr.GetObject(srcbt[configData[2, 1].ToString()], OpenMode.ForRead);
  81.                                     break; //if so break from this while loop
  82.                                 }
  83.                                 tr.Commit();
  84.                             }
  85.                             if (!srcbt.Has(configData[2, 1].ToString()))
  86.                             {
  87.                                 ed.WriteMessage("\n{0} does not have {1} block", sourcePath, configData[2, 1]);
  88.                                 srcData = GetBlockReference("Replacement");
  89.                             }
  90.                         }
  91.                     }
  92.  
  93.                 }
  94.                 catch (System.Exception)
  95.                 {
  96.  
  97.                     throw;
  98.                 }
  99.                 // build dictionary to map attributes
  100.                 Dictionary<string, string> AttMap = new Dictionary<string, string>();
  101.                 for (int i = 4; i <= configData.GetUpperBound(0); i++)
  102.                 {
  103.                     if ((configData[i, 1] != null) && (configData[i, 2] != null))
  104.                     {
  105.                         AttMap.Add((string)configData[i, 1], (string)configData[i, 2]);
  106.                         ed.WriteMessage("\n{0},{1}", configData[i, 2], (string)configData[i, 1]);
  107.                     }
  108.                 }
  109.                 //get drawings to process
  110.                 ofd =
  111.                        new OpenFileDialog(
  112.                            "Select DWGs to change block",
  113.                            null,
  114.                            "dwg",
  115.                            "DWGsToChange",
  116.                            OpenFileDialog.OpenFileDialogFlags.AllowMultiple
  117.                            );
  118.                 dr = ofd.ShowDialog();
  119.                 if (dr != System.Windows.Forms.DialogResult.OK)
  120.                 {
  121.                     srcdb.Dispose();
  122.                     return;
  123.                 }
  124.                 string[] names = ofd.GetFilenames();
  125.                 //calculate scale difference from config data
  126.                 Scale3d[] scales = new Scale3d[2];
  127.                 for (int i = 1; i <= 2; i++)
  128.                 {
  129.                     string curscale = (string)configData[3, i];
  130.                     curscale = curscale.Replace("(", "").Replace(")", "");
  131.                     string[] scalevals = curscale.Split(',');
  132.                     ed.WriteMessage("\n{0},{1},{2}", scalevals[0], scalevals[1], scalevals[2]);
  133.                     double scaX = Convert.ToDouble(scalevals[0]);
  134.                     double scaY = Convert.ToDouble(scalevals[1]);
  135.                     double scaZ = Convert.ToDouble(scalevals[2]);
  136.  
  137.                     scales[i - 1] = new Scale3d(scaX, scaY, scaZ);
  138.                 }
  139.                 //replace block in each drawing
  140.                 foreach (string name in names)
  141.                 {
  142.                     try
  143.                     {
  144.                         Database destdb = new Database(false, true);
  145.                         destdb.ReadDwgFile(name, FileOpenMode.OpenForReadAndAllShare, false, "");
  146.                         destdb.CloseInput(true);
  147.                         HostApplicationServices.WorkingDatabase = destdb;
  148.                         DocumentLock doclock = doc.LockDocument();
  149.                         //get old blocks in this drawing
  150.                         List<BlkRef> BlocksInDwg = new List<BlkRef>();
  151.                         using (Transaction tr = destdb.TransactionManager.StartTransaction())
  152.                         {
  153.  
  154.                             BlockTable bt = (BlockTable)tr.GetObject(destdb.BlockTableId, OpenMode.ForWrite);
  155.                             if (!bt.Has((string)configData[2, 2]))//dont waste time if dwg doesn't have the block
  156.                             {
  157.                                 ed.WriteMessage("Block: {0} was not found processing {1}", (string)configData[2, 2], destdb.Filename);
  158.                                 continue;
  159.                             }
  160.                             //check each container in the database for old block
  161.                             foreach (ObjectId id in bt)
  162.                             {
  163.                                 BlockTableRecord btr = (BlockTableRecord)tr.GetObject(id, OpenMode.ForWrite);
  164.                                 IEnumerable<BlockReference> blocks = AcDbExtensions.GetObjects<BlockReference>(btr, OpenMode.ForWrite, false, true).Where(BlockReference => BlockReference.Name == configData[2, 2].ToString());
  165.                                 foreach (BlockReference block in blocks)//extract block data to our list before erasing old blocks
  166.                                 {
  167.                                     BlkRef ThisBlock = new BlkRef();
  168.                                     ThisBlock.Insert = block.Position;
  169.                                     //calculate scale for new block
  170.                                     Scale3d scale = new Scale3d(
  171.                                         block.ScaleFactors.X * scales[1].X / scales[0].X,
  172.                                         block.ScaleFactors.Y * scales[1].Y / scales[0].Y,
  173.                                         block.ScaleFactors.Z * scales[1].Z / scales[0].Z
  174.                                         );
  175.                                     ThisBlock.Scale = scale;
  176.                                     ThisBlock.layerID = block.LayerId;
  177.                                     Dictionary<string, string> Attributes = new Dictionary<string, string>();
  178.                                     foreach (ObjectId arID in block.AttributeCollection)
  179.                                     {
  180.                                         AttributeReference ar = (AttributeReference)tr.GetObject(arID, OpenMode.ForWrite);
  181.                                         Attributes.Add(ar.Tag, ar.TextString);
  182.                                         ar.Erase();
  183.                                     }
  184.                                     ThisBlock.Attributes = Attributes;
  185.                                     ThisBlock.Space = btr;
  186.                                     block.Erase();
  187.                                     BlocksInDwg.Add(ThisBlock);
  188.                                 }
  189.                             }
  190.                             //erase old block def
  191.                             BlockTableRecord destbtr = (BlockTableRecord)tr.GetObject(bt[(string)configData[2, 2]], OpenMode.ForWrite);
  192.                             destbtr.Erase();
  193.                             //clone new block def
  194.                             ObjectIdCollection ids = new ObjectIdCollection();
  195.                             ids.Add(srcbtr.ObjectId);
  196.                             IdMapping mapping = new IdMapping();
  197.                             srcdb.WblockCloneObjects(ids, destdb.BlockTableId, mapping, DuplicateRecordCloning.Replace, false);
  198.                             BlockTableRecord newbtr = (BlockTableRecord)tr.GetObject(bt[(string)configData[2, 1]], OpenMode.ForRead);
  199.                             ObjectId StartLayer = destdb.Clayer;
  200.                             //insert new blocks from list
  201.                             foreach (BlkRef blk in BlocksInDwg)
  202.                             {
  203.  
  204.                                 destdb.Clayer = blk.layerID;
  205.                                 BlockReference br = new BlockReference(blk.Insert, newbtr.ObjectId);
  206.                                 BlockTableRecord btr = (BlockTableRecord)tr.GetObject(blk.Space.ObjectId, OpenMode.ForWrite);
  207.                                 btr.AppendEntity(br);
  208.                                 tr.AddNewlyCreatedDBObject(br, true);
  209.                                 br.ScaleFactors = blk.Scale;
  210.                                 IEnumerable<AttributeDefinition> attributes = AcDbExtensions.GetObjects<AttributeDefinition>(newbtr);
  211.  
  212.                                 foreach (AttributeDefinition ad in attributes)
  213.                                 {
  214.                                     if (ad == null || ad.Constant) continue;
  215.                                     AttributeReference ar = new AttributeReference();
  216.                                     ar.SetDatabaseDefaults(destdb);
  217.                                     ar.SetAttributeFromBlock(ad, br.BlockTransform);
  218.                                     ar.Position = ad.Position.TransformBy(br.BlockTransform);
  219.                                     if (AttMap.ContainsKey(ad.Tag))
  220.                                     {
  221.                                         ar.TextString = blk.Attributes[AttMap[ad.Tag]];
  222.                                         ed.WriteMessage("{0},{1}", AttMap[ad.Tag], blk.Attributes[AttMap[ad.Tag]]);
  223.                                     }
  224.                                     else
  225.                                         ar.TextString = "";
  226.                                     br.AttributeCollection.AppendAttribute(ar);
  227.                                     tr.AddNewlyCreatedDBObject(ar, true);
  228.                                     try
  229.                                     {
  230.                                         ar.AlignmentPoint = ad.AlignmentPoint.TransformBy(br.BlockTransform);
  231.                                     }
  232.                                     catch
  233.                                     {
  234.                                         ed.WriteMessage("\n{0},{1},{2}", ar.Tag, ar.Justify, ar.TextString);
  235.                                     }
  236.                                     if (ar.IsMTextAttribute)
  237.                                     {
  238.                                         ar.UpdateMTextAttribute();
  239.                                     }
  240.                                 }
  241.                             }
  242.                             destdb.Clayer = StartLayer;
  243.                             tr.Commit();
  244.                         }
  245.                         doclock.Dispose();
  246.                         HostApplicationServices.WorkingDatabase = db;
  247.                         destdb.SaveAs(name.Substring(0, name.Length - 4) + "_updated.dwg", DwgVersion.Current);
  248.                         destdb.Dispose();
  249.  
  250.                     }
  251.                     catch (System.Exception e)
  252.                     {
  253.                         System.Windows.MessageBox.Show(e.ToString(), "Error");
  254.                         throw;
  255.                     }
  256.                 }
  257.                 //HostApplicationServices.WorkingDatabase = db;
  258.             }
  259.         }
  260.  
  261.  
  262.         public List<object> GetBlockReference(string mode)
  263.         {
  264.             Document doc = Application.DocumentManager.MdiActiveDocument;
  265.             Database db = doc.Database;
  266.             Editor ed = doc.Editor;
  267.            
  268.             PromptEntityOptions peo = new PromptEntityOptions("\nSelect " + mode + " Block To Export or");
  269.             peo.AppendKeywordsToMessage = true;
  270.             peo.Keywords.Add("Open");
  271.             peo.Keywords.Add("Toggle");
  272.             peo.SetRejectMessage("\nNot a block reference!!!\n");
  273.             peo.AddAllowedClass(typeof(BlockReference), false);
  274.  
  275.            
  276.            
  277.             PromptEntityResult per = ed.GetEntity(peo);
  278.             if (per.StringResult == "Open")
  279.             {
  280.                 OpenFileDialog ofd = new OpenFileDialog(
  281.                     "Select DWG",
  282.                     Directory.GetParent(db.Filename).ToString(),
  283.                     "dwg",
  284.                     "DWG with block",
  285.                     OpenFileDialog.OpenFileDialogFlags.SearchPath
  286.                     );
  287.                 System.Windows.Forms.DialogResult dr = ofd.ShowDialog();
  288.                 if (dr == System.Windows.Forms.DialogResult.Cancel)
  289.                 {
  290.                     return GetBlockReference(mode);
  291.                 }
  292.                 else if (dr != System.Windows.Forms.DialogResult.OK)
  293.                 {
  294.                     List<object> badresults = new List<object>();
  295.                     badresults.Add("fail");
  296.                     return badresults;
  297.                 }
  298.                
  299.                 string[] names = ofd.GetFilenames();
  300.                 Document newFile = Application.DocumentManager.Open(names[0], true, "");
  301.                 List<object> results = GetBlockReference(mode);
  302.                 newFile.CloseAndDiscard();
  303.                 return results;
  304.                
  305.             }
  306.             else if (per.StringResult == "Toggle")
  307.             {
  308.                 ToggleSpace();
  309.                 List<object> results = GetBlockReference(mode);
  310.                 return results;
  311.             }
  312.             else
  313.             {
  314.                 List<object> results=new List<object>();
  315.  
  316.                 if (per.Status != PromptStatus.OK)
  317.                 {
  318.                    
  319.                     results.Add("fail");
  320.                     return results;
  321.                 }
  322.                 using (Transaction tr = doc.TransactionManager.StartTransaction())
  323.                 {
  324.                     BlockReference br = (BlockReference)tr.GetObject(per.ObjectId, OpenMode.ForRead);
  325.  
  326.                     BlockTableRecord btr = (BlockTableRecord)tr.GetObject(br.BlockTableRecord, OpenMode.ForRead);
  327.                     results.Add(db.Filename);
  328.                     results.Add(br.Name);
  329.                     Scale3d scale = new Scale3d(
  330.                         (br.GeometricExtents.MaxPoint.X-br.GeometricExtents.MinPoint.X)/br.ScaleFactors.X,
  331.                         (br.GeometricExtents.MaxPoint.Y-br.GeometricExtents.MinPoint.Y)/br.ScaleFactors.Y,
  332.                         (br.GeometricExtents.MaxPoint.Z-br.GeometricExtents.MinPoint.Z)/br.ScaleFactors.Z
  333.                         );
  334.                     results.Add(scale);
  335.                     foreach (ObjectId id in br.AttributeCollection)
  336.                     {
  337.                         AttributeReference ar = (AttributeReference)tr.GetObject(id, OpenMode.ForRead);
  338.                         results.Add(ar.Tag);
  339.                     }
  340.                 }
  341.                
  342.             return results;
  343.             }
  344.            
  345.         }
  346.  
  347.         public static void ToggleSpace()
  348.         {
  349.             Document doc = Application.DocumentManager.MdiActiveDocument;
  350.             Editor ed = doc.Editor;
  351.             short tilemode = (short)Application.GetSystemVariable("TILEMODE");
  352.             using (DocumentLock docLock = doc.LockDocument())
  353.             {
  354.                 if (tilemode == 1)
  355.                     Application.SetSystemVariable("TILEMODE", 0);
  356.                 else if ((short)Application.GetSystemVariable("CVPORT") != 1)
  357.                     ed.SwitchToPaperSpace();
  358.                 else
  359.                 {
  360.                     Application.SetSystemVariable("TILEMODE", 1);
  361.                 }
  362.             }
  363.         }
  364.  

WILL HATCH

  • Bull Frog
  • Posts: 450
Re: HostApplicationServices.WorkingDatabase
« Reply #5 on: January 11, 2013, 12:41:47 PM »
Perhaps also useful to see is the program I use to create config data:

Code - C#: [Select]
  1.         [CommandMethod("SWAPBLOCKSCONFIG", CommandFlags.Session)]
  2.         public void SwapBlocksConfig()
  3.         {
  4.             Document doc = Application.DocumentManager.MdiActiveDocument;
  5.             Editor ed = doc.Editor;
  6.             List<object> SourceBlock = GetBlockReference("Replacement");
  7.             if ((string)SourceBlock[0] == "fail")
  8.             {
  9.                 ed.WriteMessage("\nFailed getting replacement block");
  10.                 return;
  11.             }
  12.             int k = 0;
  13.             foreach (object line in SourceBlock)
  14.             {
  15.                 ed.WriteMessage("\n{0}, {1}",k++, line);
  16.             }
  17.             List<object> DestBlock = GetBlockReference("Obsolete");
  18.             if ((string)DestBlock[0] == "fail")
  19.             {
  20.                 ed.WriteMessage("\nFailed getting obsolete block");
  21.                 return;
  22.             }
  23.             object[,] Output = new object[(Math.Max(SourceBlock.Count, DestBlock.Count) + 1), 3];
  24.             for (int i = 0; i < 4; i++)
  25.             {
  26.                 Output[i, 0] = SourceBlock[0].ToString();
  27.                 Output[i, 1] = DestBlock[0].ToString();
  28.                 SourceBlock.Remove(SourceBlock[0]);
  29.                 DestBlock.Remove(DestBlock[0]);
  30.            
  31.            
  32.             }
  33.             int count = 3;
  34.             for (int i = SourceBlock.Count-1; i >= 0; i--)
  35.             {
  36.                 string AttTag = SourceBlock[i].ToString();
  37.                 for (int j = DestBlock.Count-1; j >= 0; j--)
  38.                 {
  39.                     if (DestBlock[j].ToString()==AttTag)
  40.                     {
  41.                         Output[count,0] = AttTag;
  42.                         Output[count,1] = DestBlock[j].ToString();
  43.                         SourceBlock.Remove(SourceBlock[i]);
  44.                         DestBlock.Remove(DestBlock[j]);
  45.                         count++;
  46.                         break;
  47.                     }
  48.                 }
  49.             }
  50.             for (int i = SourceBlock.Count-1; i >= 0; i--)
  51.             {
  52.                 Output[count + i,0] = SourceBlock[i].ToString();
  53.             }
  54.             for (int j = DestBlock.Count-1; j >= 0; j--)
  55.             {
  56.                 Output[ count + j,1] = DestBlock[j].ToString();
  57.             }
  58.             ExcelFunctions.WriteSheetData(Output);
  59.  
  60.         }
  61.  

and a sample of config data:


C:\Users\whatch\Desktop\New folder\TitleBlock\GTISTD-S001.dwg
C1
(215.9,279.4,25.4)
REV3
REV2
REV1
PROJECT_NAME
TITLE_LINE_1_OF_3
TITLE_LINE_2_OF_3
TITLE_LINE_3_OF_3
TITLE_1_OF_2
TITLE_2_OF_2
DWG_NO
REV_NO
DRN_BY
DWG_SCALE
DATE_DRAWN
CHK_BY
DATE_CHECKED
APP_BY
DATE_APPROVED
DATE1
BY1
D_CHK1
REV1_ISSUED
DATE2
BY2
D_CHK2
REV2_ISSUED
DATE3
BY3
D_CHK3
REV3_ISSUED
FILE_NO





C:\Users\whatch\Desktop\New folder\SwapBlock Test\GTISTD-E000-master -CURRENT.dwg
GTI-TBLK_A_SyD
(8.5,11,1)
REV2
REV1
REV0
CLIENT_FACILITY_NAME
LINE_1
LINE_2
LINE_3




DRAWN_BY
SCALE
DATE




REV_DATE_0
REV_0_BY
REV_0_CKD
REV0_DESC
REV_DATE_1
REV_1_BY
REV_1_CKD
REV1_DESC
REV_DATE_2
REV_2_BY
REV_2_CKD
REV2_DESC

PROJECT
REV_DATE_3
REV_3_BY
REV_3_CKD
REV3_DESC



let me know if you need to excel or AcDbExtensions.GetObjects  functions that I reference here to build the program for yourself

WILL HATCH

  • Bull Frog
  • Posts: 450
Re: HostApplicationServices.WorkingDatabase
« Reply #6 on: January 11, 2013, 12:53:23 PM »
Thank you for the feedback! It's very appreciated.  I hope that you can provide more now that I've given you some additional info.  I'm quite pleased with the function this program provides and especially like the way my GetBlockReference() function works allowing the user to dig through multiple drawings until they find the block they are looking for.

fixo:
thanks for showing a best practice that I don't always follow.  Would following it help me out in the event something fails inside a try catch block and my object.Dispose() code is not reached?  Understanding why best practices are such is important to me, my background is primarily embedded systems programming in assembly where it is very obvious what each function is doing in the background so it was quite easy to optimize functions.  I find it much more difficult working with a very abstract high level language since I no longer can see how the processor is crunching each instruction.

Gile:
I think you've mixed up srcdb and destdb, srcdb sits outside the foreach(name in names) loop because I am cloning the block from it into each destdb

TT:
I found that I needed to change the working database to insure that attribute alignment was properly set.  Initially without that addition to my code the center justified attributes would come out with the same bottom left corner as the attribute definition even though the length of the attribute value was different.  Is there a better way to solve that problem?

Jeff H

  • Needs a day job
  • Posts: 6144
Re: HostApplicationServices.WorkingDatabase
« Reply #7 on: January 11, 2013, 01:03:33 PM »
Code - C#: [Select]
  1.   using (Transaction tr = srcdb.TransactionManager.StartTransaction())
  2.                             {
  3.                                 srcbt = (BlockTable)tr.GetObject(srcdb.BlockTableId, OpenMode.ForRead);
  4.  
  5.                                 if (srcbt.Has(configData[2, 1].ToString())) //check dwg has source block
  6.                                 {
  7.                                     srcbtr = (BlockTableRecord)tr.GetObject(srcbt[configData[2, 1].ToString()], OpenMode.ForRead);
  8.                                     break; //if so break from this while loop
  9.                                 }
  10.                                 tr.Commit();
  11.                             }
  12.                             if (!srcbt.Has(configData[2, 1].ToString()))
  13.                             {
  14.                                 ed.WriteMessage("\n{0} does not have {1} block", sourcePath, configData[2, 1]);
  15.                                 srcData = GetBlockReference("Replacement");
  16.                             }
  17.                         }
  18.  


Just scanning  it quickly,
If your configData Has the block and 'break' is called does your transaction get committed ?
Then accessing srcbt outside the non-commited transaction.
If I remember correctly if you commit a transaction it will pass up the objects to the containing transaction, but never counted on that.



WILL HATCH

  • Bull Frog
  • Posts: 450
Re: HostApplicationServices.WorkingDatabase
« Reply #8 on: January 11, 2013, 01:13:26 PM »
nice catch Jeff! I think that this will cause a minor performance decrease in that the transaction will be aborted as it exits the scope of the using statement, but since I'm not actually changing anything in the transaction I still have the BlockTableRecord for use in cloning later.  I've tested the code here and it works, can anybody correct my assumption here?

Thanks

WILL HATCH

  • Bull Frog
  • Posts: 450
Re: HostApplicationServices.WorkingDatabase
« Reply #9 on: January 14, 2013, 04:40:06 PM »
@Jeff H:
I did some thinking about your point and wanted to learn a bit more about what is really happening here.  I wrote the following code to generate a comparison of commit() vs abort()

Code - C#: [Select]
  1. [CommandMethod("testtx")]
  2.         public void TestTransaction()
  3.         {
  4.            
  5.             Document doc = Application.DocumentManager.MdiActiveDocument;
  6.             Editor ed = doc.Editor;
  7.             Database db = doc.Database;
  8.             PromptEntityOptions peo = new PromptEntityOptions("\nSelect block");
  9.             peo.SetRejectMessage("\nNot a block reference... try again!");
  10.             peo.AddAllowedClass(typeof(BlockReference), true);
  11.             PromptEntityResult per = ed.GetEntity(peo);
  12.             if (per.Status != PromptStatus.OK)
  13.             {
  14.                 ed.WriteMessage("\nOperation Failed!");
  15.                 return;
  16.             }
  17.             ObjectId sourceBTR;
  18.             using (Transaction tr = db.TransactionManager.StartTransaction())
  19.             {
  20.                 BlockReference br = (BlockReference)tr.GetObject(per.ObjectId, OpenMode.ForRead);
  21.                 sourceBTR = br.BlockTableRecord;
  22.                 tr.Commit();
  23.             }
  24.             Stopwatch timer = new Stopwatch();
  25.             //check time with aborting tr:
  26.             BlockTable bt = null;
  27.             BlockTableRecord btr = null;
  28.             for (int i = 0; i < 2; i++)
  29.             {
  30.                 using (Transaction tr = db.TransactionManager.StartTransaction())
  31.                 {
  32.                     bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
  33.                     btr = (BlockTableRecord)tr.GetObject(sourceBTR, OpenMode.ForRead);
  34.                     timer.Start();
  35.                     tr.Abort();
  36.                     timer.Stop();
  37.                 }
  38.                 ed.WriteMessage("\nRun {0} without commit took {1} ({3} ticks) to get {2}", i + 1, timer.Elapsed, btr.Name,timer.ElapsedTicks);
  39.                 timer.Reset();
  40.             }
  41.  
  42.  
  43.             //check time with committing tr:
  44.             bt = null;
  45.             btr = null;
  46.             for (int i = 0; i < 2; i++)
  47.             {
  48.                 using (Transaction tr = db.TransactionManager.StartTransaction())
  49.                 {
  50.                     bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
  51.                     btr = (BlockTableRecord)tr.GetObject(sourceBTR, OpenMode.ForRead);
  52.                     timer.Start();
  53.                     tr.Commit();
  54.                     timer.Stop();
  55.                 }
  56.                 ed.WriteMessage("\nRun {0} with commit took    {1} ({3} ticks) to get {2}", i + 1, timer.Elapsed, btr.Name,timer.ElapsedTicks);
  57.                 timer.Reset();
  58.             }
  59.         }
  60.  

Just out of curiosity, I compare the situations where we are initializing a null variable in run 1 and overwriting a variable in run 2.  Also, I query the BlockTableRecord in both cases to determine if it is still returned by the aborted transaction
As shown in the results below, the block is properly returned.  The interesting thing to note is that it takes a different amount of time to commit or abort a transaction depending on if our variables were initially null.  Can anybody who knows more about these methods comment?

Command: TESTTX
Select block:
Run 1 without commit took 00:00:00.0027396 (8581 ticks) to get C1
Run 2 without commit took 00:00:00.0001803 (565 ticks) to get C1
Run 1 with commit took    00:00:00.0000092 (29 ticks) to get C1
Run 2 with commit took    00:00:00.0000086 (27 ticks) to get C1
Command:  TESTTX
Select block:
Run 1 without commit took 00:00:00.0002404 (753 ticks) to get C1
Run 2 without commit took 00:00:00.0001794 (562 ticks) to get C1
Run 1 with commit took    00:00:00.0000089 (28 ticks) to get C1
Run 2 with commit took    00:00:00.0000089 (28 ticks) to get C1
Command:  TESTTX
Select block:
Run 1 without commit took 00:00:00.0002391 (749 ticks) to get C1
Run 2 without commit took 00:00:00.0001787 (560 ticks) to get C1
Run 1 with commit took    00:00:00.0000092 (29 ticks) to get C1
Run 2 with commit took    00:00:00.0000089 (28 ticks) to get C1
Command:  TESTTX
Select block:
Run 1 without commit took 00:00:00.0002337 (732 ticks) to get C1
Run 2 without commit took 00:00:00.0001791 (561 ticks) to get C1
Run 1 with commit took    00:00:00.0000095 (30 ticks) to get C1
Run 2 with commit took    00:00:00.0000089 (28 ticks) to get C1
Command:  TESTTX
Select block:
Run 1 without commit took 00:00:00.0002359 (739 ticks) to get C1
Run 2 without commit took 00:00:00.0001784 (559 ticks) to get C1
Run 1 with commit took    00:00:00.0000092 (29 ticks) to get C1
Run 2 with commit took    00:00:00.0000086 (27 ticks) to get C1
Command:  TESTTX
Select block:
Run 1 without commit took 00:00:00.0002333 (731 ticks) to get C1
Run 2 without commit took 00:00:00.0001794 (562 ticks) to get C1
Run 1 with commit took    00:00:00.0000092 (29 ticks) to get C1
Run 2 with commit took    00:00:00.0000089 (28 ticks) to get C1
Command:  TESTTX
Select block:
Run 1 without commit took 00:00:00.0002372 (743 ticks) to get C1
Run 2 without commit took 00:00:00.0001794 (562 ticks) to get C1
Run 1 with commit took    00:00:00.0000092 (29 ticks) to get C1
Run 2 with commit took    00:00:00.0000089 (28 ticks) to get C1
Command:  TESTTX
Select block:
Run 1 without commit took 00:00:00.0002324 (728 ticks) to get C1
Run 2 without commit took 00:00:00.0001781 (558 ticks) to get C1
Run 1 with commit took    00:00:00.0000092 (29 ticks) to get C1
Run 2 with commit took    00:00:00.0000086 (27 ticks) to get C1
Command:  TESTTX
Select block:
Run 1 without commit took 00:00:00.0002327 (729 ticks) to get C1
Run 2 without commit took 00:00:00.0001797 (563 ticks) to get C1
Run 1 with commit took    00:00:00.0000092 (29 ticks) to get C1
Run 2 with commit took    00:00:00.0000086 (27 ticks) to get C1
Command:  TESTTX
Select block:
Run 1 without commit took 00:00:00.0002365 (741 ticks) to get C1
Run 2 without commit took 00:00:00.0001791 (561 ticks) to get C1
Run 1 with commit took    00:00:00.0000089 (28 ticks) to get C1
Run 2 with commit took    00:00:00.0000086 (27 ticks) to get C1

Jeff H

  • Needs a day job
  • Posts: 6144
Re: HostApplicationServices.WorkingDatabase
« Reply #10 on: January 15, 2013, 04:23:09 PM »

Not sure but off the top of my head,bt & btr are reference types so the memory slot they point to can contain either null or the address were the object lives. I can not see writing the address in the memory slot for bt or btr causing much difference. 


Not sure if AutoCAD cache's the value somehow but without looking or testing I would think the unmanaged object  would be closed when a transaction is aborted or commited and unless the managed wrapper stores the name in a field instead of getting the value from the unmanaged object seems that would fail.



Still just guessing and have not looked in reflector or debugged.