Hey all,
So I've been building an application that creates 6 files and dynamically xrefs them all to each other (i.e. test1.dwg will xref to test2.dwg test3.dwg test4.dwg test5.dwg and test6.dwg then test2 will xref test1, test3 etc....).
When I manually open one of the created files and run the command to do the xreffing it has no issue. However when I open the file from the application and try to create the xrefs dynamically it throws me an eFileAccessError.
I have tried letting the system sleep when it opens and moving the path for the files into AutoCAD's root directory, but the error still gets thrown. Does anyone have any idea why this would be happening?
___________________________________________________________________________________________________
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.EditorInput;
using System.Windows.Forms;
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
public class Commands
{
/// <summary>
/// Builds a file, draws on hardcoded lines then saves that file six times
/// </summary>
[CommandMethod("BuildSixXref", CommandFlags.Session)]
public static void BuildDrawSave()
{
Document acDoc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
string basepath = "C:\\Autodesk\\Autodesk-test";
if (basepath.EndsWith("\\")) { }
else
{
basepath = basepath + "\\";
}
string basename = "test";
// Loop 6 times to create 6 new files
for (int i = 1; i <= 6; i++)
{
//Dynamically generate filepath and name
string filename = basename + i.ToString();
string fullpath = basepath + filename;
SaveDrawing(fullpath);
}
acDoc.CloseAndDiscard();
DocumentCollection acDocMgr = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager;
// Loop 6 times decrementally to build the 6 xrefs
for (int i = 6; i >= 1; i--)
{
string filename = basename + i.ToString();
string fullpath = basepath + filename;
acDocMgr.Open(fullpath, false);
System.Threading.Thread.Sleep(1000);
BuildXref(fullpath);
acDoc.CloseAndSave(fullpath);
}
}
/// <summary>
/// Builds the xrefs between files
/// </summary>
public static void BuildXref(string path)
{
Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
HostApplicationServices hs = HostApplicationServices.Current;
// Split the path found into chunks
string[] splitpath = path.Split(System.IO.Path.DirectorySeparatorChar);
string basepath = "";
string filename = GetFileName(path);
// Isolate filename and add the other chunks back together
for (int i = 0; i < (splitpath.Length - 1); i++)
{
basepath += splitpath[i] + "\\";
}
//Finds all the files in the directory of the current file
string[] files = Directory.GetFiles(basepath);
//Sets up new list to hold the files which should be xreffed
List<string> xrefs = new List<string>();
//Parse through the files array and skip over any files containing the filename
//Since those will not be xreffed
foreach (string file in files)
{
if (file.Contains(filename)) { }
else
{
//Check if the file contains the basename specified when the files were built
//If not an xref to that file is not built
if (file.Contains(filename.Remove(filename.Length - 1)) && Path.GetExtension(file) == ".dwg")
{
//Adds file to the list "xrefs" for use by a transaction later
xrefs.Add(file);
doc.Editor.WriteMessage("\nFile: " + file);
}
}
}
//Build xrefs in currently opened file
//Get the current database and open transaction
Database acCurDb = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Database;
foreach (string xref in xrefs)
{
string overlayName = GetFileName(xref);
ObjectId xrefId = acCurDb.OverlayXref(xref, overlayName);
using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction())
{
BlockTable bt = acCurDb.BlockTableId.GetObject(OpenMode.ForRead) as BlockTable;
BlockTableRecord ms = bt[BlockTableRecord.ModelSpace].GetObject(OpenMode.ForWrite) as BlockTableRecord;
BlockReference bref = new BlockReference(Point3d.Origin, xrefId);
ms.AppendEntity(bref);
acTrans.AddNewlyCreatedDBObject(bref, true);
acTrans.Commit();
}
}
}
/// <summary>
/// Takes a path and returns the filename without extension
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public static string GetFileName(string path)
{
return path.Split(System.IO.Path.DirectorySeparatorChar).Last().Split(new char[] { '.' })[0];
}
/// <summary>
/// Saves the current file being worked on
/// </summary>
/// <param name="fullpath">Contains the full path to where a file should be saved to</param>
public static void SaveDrawing(string fullpath)
{
Document acDoc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
acDoc.Database.SaveAs(fullpath, true, DwgVersion.Current, acDoc.Database.SecurityParameters);
}
}
Solved! Go to Solution.
Solved by khoa.ho. Go to Solution.
I've tried your code and got the same error "eFileAccessError". However, your code does not look optimized for readable and performance. Then I came with my solution based on your requirements.
[CommandMethod("BuildDynamicXrefs")] public static void BuildDynamicXrefs() { Document doc = Application.DocumentManager.MdiActiveDocument; string basePath = "C:\\Temp\\Test"; string baseName = "Temp"; int count = 6; List<string> filePaths = new List<string>(); // Loop to create new files for (int i = 1; i <= count; i++) { // Dynamically generate file paths and names string fileName = baseName + i.ToString() + ".dwg"; string filePath = Path.Combine(basePath, fileName); Database db = new Database(); db.SaveAs(filePath, DwgVersion.Current); db.Dispose(); filePaths.Add(filePath); } // Xref all other drawings to the selected drawing for (int i = 0; i < count; i++) { string filePath = filePaths[i]; using (Database db = new Database()) { db.ReadDwgFile(filePath, System.IO.FileShare.ReadWrite, false, null); using (Transaction trans = db.TransactionManager.StartTransaction()) { var blockTable = (BlockTable)trans.GetObject(db.BlockTableId, OpenMode.ForRead); var modelSpace = (BlockTableRecord)trans.GetObject( blockTable[BlockTableRecord.ModelSpace], OpenMode.ForWrite); foreach (string xrefPath in filePaths) { // Skip the current drawing out of xref list if (xrefPath != filePath) { // Overlay (or Attach) xref to drawing ObjectId xrefObjId = db.OverlayXref(xrefPath, Path.GetFileNameWithoutExtension(xrefPath)); // Create a new block reference to hold the added xref var blockRef = new BlockReference(Point3d.Origin, xrefObjId); // Add new xref entity to model space modelSpace.AppendEntity(blockRef); modelSpace.DowngradeOpen(); // Update transaction for new added entity trans.AddNewlyCreatedDBObject(blockRef, true); } } trans.Commit(); } db.SaveAs(filePath, DwgVersion.Current); // Save xrefs list back to the drawing db.CloseInput(true); // Close file } } }
The code will create 6 drawings (Temp1.dwg to Temp6.dwg). Then for each drawing, xref all other drawings (except itself). I use db.ReadDwgFile which will work at backend without opening drawing in AutoCAD editor. Therefore, the performance is faster and get rid of all visible activities in AutoCAD.