Author Topic: eFileAccessErr exception with Database.SaveAs  (Read 7108 times)

0 Members and 1 Guest are viewing this topic.

gile

  • Gator
  • Posts: 2520
  • Marseille, France
eFileAccessErr exception with Database.SaveAs
« on: November 19, 2009, 02:17:59 PM »
Hi,

I'm trying to make a batch process and I want to trap any possible situation:
- the file is the active document
- the file is opened but not active
- the file is closed
It works fine excepted if the document is opened in another AutoCAD session than the one from where the process is launched: the document doesn't owns to the DocumentCollection so it's dealed as a closed one and I got an eFileAccessErr exception when trying to invoke Database.SaveAs.

Here's what I wrote:

Code: [Select]
        private void ProcessDatabase(string filename)
        {
            DocumentCollection docMan = acadApp.DocumentManager;
            Database db = null;

            if (docMan.MdiActiveDocument.Name == filename)
            {
                db = docMan.MdiActiveDocument.Database;
                DoIt(db);
                db.SaveAs(filename, DwgVersion.Current);
            }

            else
            {
                foreach (Document doc in docMan)
                {
                    if (doc.Name == filename)
                    {
                        using (DocumentLock docLock = doc.LockDocument())
                        {
                            db = doc.Database;
                            DoIt(db);
                        }
                        doc.CloseAndSave(filename);
                    }
                }

                if (db == null)
                {
                    using (db = new Database(false, true))
                    {
                        db.ReadDwgFile(filename, System.IO.FileShare.ReadWrite, true, string.Empty);
                        DoIt(db);
                        db.SaveAs(filename, DwgVersion.Current);
                    }
                }
            }
        }
Speaking English as a French Frog

T.Willey

  • Needs a day job
  • Posts: 5251
Re: eFileAccessErr exception with Database.SaveAs
« Reply #1 on: November 19, 2009, 03:26:49 PM »
Maybe this will shed some light for you Gile.

(File.GetAttributes (Str) & FileAttributes.ReadOnly) == 0)

Str = valid file name.  I used this check to make sure I could open a drawing.  I don't remember all that is used, but I know I got the information from MSDN, and maybe even some help here.

Here is a thread where I tried to make a sub that will let one know if a drawing can be open.

[ http://www.theswamp.org/index.php?topic=12257.0 ]
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

gile

  • Gator
  • Posts: 2520
  • Marseille, France
Re: eFileAccessErr exception with Database.SaveAs
« Reply #2 on: November 20, 2009, 12:05:04 PM »
Thanks Tim,

But this doesn't solve my problem.
On a file opened in anther AutoCAD session, (File.GetAttributes (Str) & FileAttributes.ReadOnly) == 0) returns true and the file is processed as a closed file because it doesn't own the current DocumentCollection.
Speaking English as a French Frog

T.Willey

  • Needs a day job
  • Posts: 5251
Re: eFileAccessErr exception with Database.SaveAs
« Reply #3 on: November 20, 2009, 12:52:02 PM »
It should return true, since the file is attributed as being ' ReadOnly ' ( you can't save back to the same file name ).  With it being read only, it is different than being closed, so the code should know what to do with it being read only.

Edit:  If it is read only, then I think you should show that some way, and move on to the next drawing, since what you want to do will be saved to the drawing.  If you are just gathering info from then drawing, then I think there is no problem.
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

gile

  • Gator
  • Posts: 2520
  • Marseille, France
Re: eFileAccessErr exception with Database.SaveAs
« Reply #4 on: November 20, 2009, 01:26:41 PM »
Thanks again Tim.

I certainly should check hte 'ReadOnly' attribute but this is not the problem I'm on.
It's quite difficult for me to explain it in good English.

I need to make some changes in the file databases so I need to save them.

If the file is opened, the SaveAs method works for the the active drawing, but for others I need to LockDocument the document and use CloseAndSave. I can get this work for the DocumentCollection documents.

If the file is closed, I can access to its database using ReadDwgFile and save it with SaveAs.

My problem are files opened in another session: I think I may deal with them as with those which own to the current DocumentCollection but I don't know how to cath them.

IOW, how to know if a fil is opened knowing its filename and possibly its database (using ReadDwgFile) ?
Speaking English as a French Frog

T.Willey

  • Needs a day job
  • Posts: 5251
Re: eFileAccessErr exception with Database.SaveAs
« Reply #5 on: November 20, 2009, 02:43:15 PM »
The read only attribute will let you know if you can save the file ( before you even open it ), and you can find that out with the file name.  If the file is open by someone else, or another session, then You will only be able to open it as read only, and you will not be able to save it, and it will throw the error if you do try.  I think I'm understanding your issue.
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

gile

  • Gator
  • Posts: 2520
  • Marseille, France
Re: eFileAccessErr exception with Database.SaveAs
« Reply #6 on: November 21, 2009, 04:46:21 PM »
According to the tests I made, an opened dwg (in the current session or another) has an Archive attribute.

So, I rewrote my batch method to work only with the active document or closed files and I try to cath exceptions as GlennR shows here (thanks to him).

Here's where I am now. I tried to make a more 'generic' method using a delegate.

Code: [Select]
using System.IO;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using acadApp = Autodesk.AutoCAD.ApplicationServices.Application;

namespace BatchProcess
{
    public class Process
    {
        public delegate void ProcessDatabase(Database db);

        public static void ProcessFiles(string[] filenames, ProcessDatabase DoIt)
        {
            Document doc = acadApp.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            foreach (string filename in filenames)
            {
                if ((File.GetAttributes(filename) & FileAttributes.ReadOnly) == 0)
                {
                    try
                    {
                        if (filename == doc.Name)
                            using (Database db = doc.Database)
                            {
                                DoIt.Invoke(db);
                                db.SaveAs(filename, DwgVersion.Current);
                            }
                        else
                        {
                            using (Database db = new Database(false, true))
                            {
                                db.ReadDwgFile(filename, FileShare.ReadWrite, true, string.Empty);
                                DoIt.Invoke(db);
                                db.SaveAs(filename, DwgVersion.Current);
                            }
                        }
                    }
                    catch (Autodesk.AutoCAD.Runtime.Exception aex)
                    {
                        if ((aex.ErrorStatus == ErrorStatus.FileSharingViolation) || (aex.ErrorStatus == ErrorStatus.FileAccessErr))
                            ed.WriteMessage("\n \"{0}\" is already opened", filename);
                        else if (aex.ErrorStatus == ErrorStatus.DwgNeedsRecovery)
                            ed.WriteMessage("\n\"{0}\" needs a recovery", filename);
                        else if (aex.ErrorStatus == ErrorStatus.BadDwgHeader)
                            ed.WriteMessage("\n\"{0}\" has a bad header", filename);
                        else
                            ed.WriteMessage("\n\"{0}\" AutoCAD error: {1}", filename, aex.Message);
                    }
                    catch (System.Exception ex)
                    {
                        ed.WriteMessage("\n\"{0}\" System error: {1}", filename, ex.Message);
                    }
                }
                else
                    ed.WriteMessage("\n\"{0}\" is read only", filename);
            }
        }
    }
}

Using examples:

Code: [Select]
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Windows;
using BatchProcess;

namespace BatchCommands
{
    public class Commands
    {
        [CommandMethod("TEST1")]
        public void test1()
        {
            OpenFileDialog.OpenFileDialogFlags flag = OpenFileDialog.OpenFileDialogFlags.AllowMultiple;
            OpenFileDialog ofd = new OpenFileDialog("Select files", "", "dwg", "", flag);
            Process.ProcessDatabase DoIt = AddCircle;
            if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                Process.ProcessFiles(ofd.GetFilenames(), DoIt);
            }
        }

        private void AddCircle(Database db)
        {
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
                Circle c = new Circle(new Point3d(0.0, 0.0, 0.0), new Vector3d(0.0, 0.0, 1.0), 10.0);
                btr.AppendEntity(c);
                tr.AddNewlyCreatedDBObject(c, true);
                tr.Commit();
            }
        }

        [CommandMethod("TEST2")]
        public void test2()
        {
            OpenFileDialog.OpenFileDialogFlags flag = OpenFileDialog.OpenFileDialogFlags.AllowMultiple;
            OpenFileDialog ofd = new OpenFileDialog("Select files", "", "dwg", "", flag);
            Process.ProcessDatabase DoIt = EraseCircle;
            if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                Process.ProcessFiles(ofd.GetFilenames(), DoIt);
            }
        }

        private void EraseCircle(Database db)
        {
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
                foreach (ObjectId id in btr)
                {
                    Circle c = tr.GetObject(id, OpenMode.ForRead, false) as Circle;
                    if ((c != null) && (c.Center == new Point3d(0.0, 0.0, 0.0)) && (c.Radius == 10.0))
                    {
                        c.UpgradeOpen();
                        c.Erase();
                    }
                }
                tr.Commit();
            }
        }
    }
}

« Last Edit: November 21, 2009, 04:57:35 PM by gile »
Speaking English as a French Frog