Hi,
Try this way:
public static void ImportBlocks(Database destDb, string filename)
{
var ids = new ObjectIdCollection();
using (var sourceDb = new Database(false, true))
{
sourceDb.ReadDwgFile(filename, FileOpenMode.OpenForReadAndReadShare, false, null);
using (var tr = sourceDb.TransactionManager.StartTransaction())
{
var bt = (BlockTable)tr.GetObject(sourceDb.BlockTableId, OpenMode.ForRead);
foreach (ObjectId id in bt)
{
var btr = (BlockTableRecord)tr.GetObject(id, OpenMode.ForRead);
if (!btr.IsAnonymous && !btr.IsLayout)
ids.Add(id);
}
tr.Commit();
}
var mapping = new IdMapping();
destDb.WblockCloneObjects(ids, destDb.BlockTableId, mapping, DuplicateRecordCloning.Replace, false);
}
}
your code doesn't work。
private void button8_Click(object sender, EventArgs e)
{
Document doc = CADAPP.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
using (doc.LockDocument())
{
ImportABC();
}
}
// Error: ePermanentlyErased。
targetDb.WblockCloneObjects(ids, targetDb.BlockTableId, mapping, DuplicateRecordCloning.Replace, false);
your code doesn't work.
I try it twice .
first time :
Unhandled Access Violation Reading 0x0170 Exception at CC3F58BFh
second time:
Unhandled Access Violation Reading 0x0128 Exception at CC3F58BFh
private void button10_Click(object sender, EventArgs e)
{
Document doc = CADAPP.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
using (doc.LockDocument())
{
ImportBlocks_gile(db, @"d:\abclqh.dwg");
}
}
----- following is your code -----
public void ImportBlocks_gile (Database destDb, string filename)
{
var ids = new ObjectIdCollection();
using (var sourceDb = new Database(false, true))
{
sourceDb.ReadDwgFile(filename, FileOpenMode.OpenForReadAndReadShare, false, null);
using (var tr = sourceDb.TransactionManager.StartTransaction())
{
var bt = (BlockTable)tr.GetObject(sourceDb.BlockTableId, OpenMode.ForRead);
foreach (ObjectId id in bt)
{
var btr = (BlockTableRecord)tr.GetObject(id, OpenMode.ForRead);
if (!btr.IsAnonymous && !btr.IsLayout)
ids.Add(id);
}
tr.Commit();
}
var mapping = new IdMapping();
destDb.WblockCloneObjects(ids, destDb.BlockTableId, mapping, DuplicateRecordCloning.Replace, false);
}
}
I tried with your "abclqh.dwg" file and the 3 following commands (simple command, modal dialog, modeless dialog) an they all worked.
It looks like you have a problem with the access to your "abclqh.dwg" file on your computer.
Commands class:
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using System;
using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;
namespace ImportBlocksSample
{
public class Commands
{
[CommandMethod("IMPORTBLOCKS")]
public static void ImportBlocksCommand()
{
var doc = AcAp.DocumentManager.MdiActiveDocument;
var db = doc.Database;
ImportBlocks(db, @"D:\abclqh.dwg");
}
[CommandMethod("IMPORTBLOCKSMODALDIALOG")]
public static void ImportBlocksModalDialog()
{
using (var modalDialog = new ImportBlocksDialog())
{
AcAp.ShowModalDialog(modalDialog);
}
}
static ImportBlocksDialog modelessDialog;
[CommandMethod("IMPORTBLOCKSMODELESSDIALOG")]
public static void ImportBlocksModelessDialog()
{
if (modelessDialog == null)
modelessDialog = new ImportBlocksDialog();
AcAp.ShowModelessDialog(modelessDialog);
}
public static void ImportBlocks(Database destDb, string filename)
{
try
{
var ids = new ObjectIdCollection();
using (var sourceDb = new Database(false, true))
{
sourceDb.ReadDwgFile(filename, FileOpenMode.OpenForReadAndAllShare, false, null);
using (var tr = sourceDb.TransactionManager.StartTransaction())
{
var bt = (BlockTable)tr.GetObject(sourceDb.BlockTableId, OpenMode.ForRead);
foreach (ObjectId id in bt)
{
var btr = (BlockTableRecord)tr.GetObject(id, OpenMode.ForRead);
if (!btr.IsAnonymous && !btr.IsLayout)
ids.Add(id);
}
tr.Commit();
}
var mapping = new IdMapping();
destDb.WblockCloneObjects(ids, destDb.BlockTableId, mapping, DuplicateRecordCloning.Replace, false);
}
AcAp.ShowAlertDialog("Blocks importation succeeded");
}
catch(System.Exception ex)
{
AcAp.ShowAlertDialog(ex.Message);
}
}
}
}
ImportBlocksDialog class:
using System;
using System.Windows.Forms;
using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;
namespace ImportBlocksSample
{
public partial class ImportBlocksDialog : Form
{
public ImportBlocksDialog()
{
InitializeComponent();
}
private void ImportButton_Click(object sender, EventArgs e)
{
var doc = AcAp.DocumentManager.MdiActiveDocument;
var db = doc.Database;
using (doc.LockDocument())
{
Commands.ImportBlocks(db, @"D:\abclqh.dwg");
}
DialogResult = DialogResult.OK; // <- this is to close the form if shown as modal dialog
}
}
}
Note that in case of a modeless dialog it would be safer to directly call the IMPORTBLOCKS command wirh SendStringToExecute (to let AutoCAD take care of locking the document).
private void ImportButton_Click(object sender, EventArgs e)
{
var doc = AcAp.DocumentManager.MdiActiveDocument;
doc.SendStringToExecute("IMPORTBLOCKS\n", false, false, false);
DialogResult = DialogResult.OK; // <- this is to close the form if shown as modal dialog
}
var testForm = new TestForm();
testForm.ShowInTaskbar = true;
testForm.Show();
You should not use;
testForm.Show();
to display your dialogs you should use:
Application.ShowModelessDialog(testForm);
See this old but still relevant topic from Kean Walmsley's blog and this other one from the developper's documentation.
That said, according you want to use as modeless form, as said upper, you should define a simple command (as the upper IMPORTBLOCKS) and call this method with SendStringToExecute from the button event handler.
I need modalless winform.
static ImportBlocksDialog modelessDialog;
[CommandMethod("IMPORTBLOCKSMODELESSDIALOG")]
public static void ImportBlocksModelessDialog()
{
if (modelessDialog == null)
modelessDialog = new ImportBlocksDialog();
AcAp.ShowModelessDialog(modelessDialog);
}
So I test your code .
start AutoCAD 2019
in cad , i netload Commands.dll.
in editor, i Enter command:"IMPORTBLOCKSMODELESSDIALOG",
then the ImportBlocksDialog show as modelessDialog.
then click button .
first time ,it is ok.
then i Create a new file ,click the button, it's ok.
then i Create a new file again,click the button, it's ok.
then i Create a new file again,click the button, it's ok.
....after some times....
then i Create a new file again,click the button, CAD crush.
unhandled access violation reading 0x0108 exception at C9775B8FH
i test the most safer method:
[CommandMethod("IMPORTBLOCKS")]
public static void ImportBlocksCommand()
{
var doc = AcAp.DocumentManager.MdiActiveDocument;
var db = doc.Database;
ImportBlocks(db, @"D:\abclqh.dwg");
}
i test 30 times.----create 30 new dwg files.
all is ok.
CAD does not crush.
But I need modaless winform.
i test the method:
doc.SendStringToExecute("IMPORTBLOCKS\n", false, false, false);
using System;
using System.Windows.Forms;
using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;
namespace ImportBlocksSample
{
public partial class ImportBlocksDialog : Form
{
public ImportBlocksDialog()
{
InitializeComponent();
}
private void ImportButton_Click(object sender, EventArgs e)
{
var doc = AcAp.DocumentManager.MdiActiveDocument;
doc.SendStringToExecute("IMPORTBLOCKS\n", false, false, false);
DialogResult = DialogResult.OK; // <- this is to close the form if shown as modal dialog
}
}
}
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;
namespace ImportBlocksSample
{
public class Commands
{
static ImportBlocksDialog modelessDialog;
[CommandMethod("IMPORTBLOCKSMODELESSDIALOG")]
public static void ImportBlocksModelessDialog()
{
if (modelessDialog == null)
modelessDialog = new ImportBlocksDialog();
AcAp.ShowModelessDialog(modelessDialog);
}
public static void ImportBlocks(Database destDb, string filename)
{
try
{
var ids = new ObjectIdCollection();
using (var sourceDb = new Database(false, true))
{
sourceDb.ReadDwgFile(filename, FileOpenMode.OpenForReadAndAllShare, false, null);
using (var tr = sourceDb.TransactionManager.StartTransaction())
{
var bt = (BlockTable)tr.GetObject(sourceDb.BlockTableId, OpenMode.ForRead);
foreach (ObjectId id in bt)
{
var btr = (BlockTableRecord)tr.GetObject(id, OpenMode.ForRead);
if (!btr.IsAnonymous && !btr.IsLayout)
ids.Add(id);
}
tr.Commit();
}
var mapping = new IdMapping();
destDb.WblockCloneObjects(ids, destDb.BlockTableId, mapping, DuplicateRecordCloning.Replace, false);
}
AcAp.ShowAlertDialog("Blocks importation succeeded");
}
catch (System.Exception ex)
{
AcAp.ShowAlertDialog(ex.Message);
}
}
}
}
first time ,it is ok
second time ,create a new dwg file ,click the button ,it is ok
after several time ---- about 10 times
CAD crush
unhandled access violation reading 0x0100 exception at C9775B8FH
Difficult to diagnose.
Perhaps you read the source DWG many times too quickly.
Try to force a garbage collection after the newly created Database is disposed.
public static void ImportBlocks(Database destDb, string filename)
{
try
{
var ids = new ObjectIdCollection();
using (var sourceDb = new Database(false, true))
{
sourceDb.ReadDwgFile(filename, FileOpenMode.OpenForReadAndAllShare, false, null);
using (var tr = sourceDb.TransactionManager.StartTransaction())
{
var bt = (BlockTable)tr.GetObject(sourceDb.BlockTableId, OpenMode.ForRead);
foreach (ObjectId id in bt)
{
var btr = (BlockTableRecord)tr.GetObject(id, OpenMode.ForRead);
if (!btr.IsAnonymous && !btr.IsLayout)
ids.Add(id);
}
tr.Commit();
}
var mapping = new IdMapping();
destDb.WblockCloneObjects(ids, destDb.BlockTableId, mapping, DuplicateRecordCloning.Replace, false);
}
GC.Collect(); // <- forces a garbage collection
AcAp.ShowAlertDialog("Blocks importation succeeded");
}
catch(System.Exception ex)
{
AcAp.ShowAlertDialog(ex.Message);
}
}
I try the following code .
private void ImportButton_Click(object sender, EventArgs e)
{
rtx1.Clear();
var doc = AcAp.DocumentManager.MdiActiveDocument;
var db = doc.Database;
var listname = Commands.ImportBlocks_listname(@"D:\abclqh.dwg");
foreach (var item in listname)
{
rtx1.AppendText(item + hh);
}
rtx1.AppendText("---" + hh);
foreach (var name in listname)
{
rtx1.AppendText("-- read --" + name + hh);
using (doc.LockDocument())
{
Commands.only_sourceDb_ReadDwgFile( @"D:\abclqh.dwg" );
}
}
rtx1.AppendText("----all ok-----" + hh);
}
public static List<string> ImportBlocks_listname(string filename)
{
List<string> listName = new List<string>();
try
{
var ids = new ObjectIdCollection();
using (var sourceDb = new Database(false, true))
{
sourceDb.ReadDwgFile(filename, FileOpenMode.OpenForReadAndAllShare, false, null);
using (var tr = sourceDb.TransactionManager.StartTransaction())
{
var bt = (BlockTable)tr.GetObject(sourceDb.BlockTableId, OpenMode.ForRead);
foreach (ObjectId id in bt)
{
var btr = (BlockTableRecord)tr.GetObject(id, OpenMode.ForRead);
if (!btr.IsAnonymous && !btr.IsLayout)
{
listName.Add(btr.Name);
}
}
tr.Commit();
}
}
AcAp.ShowAlertDialog("get List name OK");
}
catch (System.Exception ex)
{
AcAp.ShowAlertDialog(ex.Message);
}
return listName;
}
public static void only_sourceDb_ReadDwgFile(string filename )
{
try
{
using (var sourceDb = new Database(false, true))
{
sourceDb.ReadDwgFile(filename, FileOpenMode.OpenForReadAndAllShare, false, null);
using (var tr = sourceDb.TransactionManager.StartTransaction())
{
var bt = (BlockTable)tr.GetObject(sourceDb.BlockTableId, OpenMode.ForRead);
tr.Commit();
}
}
}
catch (System.Exception ex)
{
AcAp.ShowAlertDialog(ex.Message);
}
}
1、 first dwg , it is ok .
2 、create a new dwg file ,and click the button . it's ok
3 、create a new dwg file ,and click the button . windows 10 crush, pop up a window : not enough memory.
i restart my computer.Try again.
my computer memory is 16GB.
1、 first dwg , it is ok .
but i find that ,in the windows 10 Task Manager, the 16GB is nearly full
2. second time ,CAD Crush.
so , i think , using (var sourceDb = new Database(false, true)) don't really dispose the sourceDb , don't realy release the memory.
@wokeyiyognshenme a écrit :
so , i think , using (var sourceDb = new Database(false, true)) don't really dispose the sourceDb , don't realy release the memory.
Look at my last reply about garbage collection.
first dwg ,it is ok, but computer memory still quickly become full. gc.collect() doesn't work.
then create a new dwg , click the buton , after a few seconds , CAD crush.
public static void only_sourceDb_ReadDwgFile(string filename )
{
try
{
using (var sourceDb = new Database(false, true))
{
sourceDb.ReadDwgFile(filename, FileOpenMode.OpenForReadAndAllShare, false, null);
sourceDb.CloseInput(true);
using (var tr = sourceDb.TransactionManager.StartTransaction())
{
var bt = (BlockTable)tr.GetObject(sourceDb.BlockTableId, OpenMode.ForRead);
tr.Commit();
}
}
GC.Collect(); // <- forces a garbage collection
}
catch (System.Exception ex)
{
AcAp.ShowAlertDialog(ex.Message);
}
}
sourceDb.CloseInput(true);// try it
GC.Collect(); // <- forces a garbage collection
both doesn't work.
public static void only_sourceDb_ReadDwgFile(string filename )
{
try
{
using (var sourceDb = new Database(false, true))
{
sourceDb.ReadDwgFile(filename, FileOpenMode.OpenForReadAndAllShare, false, null);
sourceDb.CloseInput(true);// try it
using (var tr = sourceDb.TransactionManager.StartTransaction())
{
var bt = (BlockTable)tr.GetObject(sourceDb.BlockTableId, OpenMode.ForRead);
tr.Commit();
}
}
GC.Collect(); // <- forces a garbage collection
}
catch (System.Exception ex)
{
AcAp.ShowAlertDialog(ex.Message);
}
}
private void ImportButton_Click(object sender, EventArgs e)
{
rtx1.Clear();
var doc = AcAp.DocumentManager.MdiActiveDocument;
for (int i = 0; i < 60; i++)
{
rtx1.AppendText("-- i --" + i + hh);
using (doc.LockDocument())
{
Commands.only_sourceDb_ReadDwgFile(@"D:\abclqh.dwg");
}
}
rtx1.AppendText("----all ok-----" + hh);
}
Can't find what you're looking for? Ask the community or share your knowledge.