Hi guys, I use this small VBA code to close my current DWG & open anther DWG.
Now that VBA is semi removed from Acad2010 (yes I know I can download it), I'd like to kill all my VBA code, if possible.
Does anyone have a way to open a DWG & close the calling DWG with VLisp?
Public Sub CloseCurrentOpenPath()
Dim ad As AcadDocument
Dim pth As String
Dim CloseFile As String
Dim Response As Integer
Set ad = ActiveDocument
pth = ad.GetVariable("users2")
If Not ad.GetVariable("DBMOD") = 0 Then
Response = MsgBox("Do you want to save changes to " & ad.FullName & "?", vbYesNoCancel + vbExclamation + vbDefaultButton1, "TMaCAD")
If Response = vbYes Then
If ad.GetVariable("WRITESTAT") = 1 Then
ad.Save
End If
ElseIf Response = vbCancel Then
Exit Sub
End If
End If
ad.Close False
If pth <> "" Then
Application.Documents.Open pth
End If
End Sub
Hm, have you ever thought about a .NET DLL with a LISP-function that would do that?
If you really want to solve this via LISP I can imagine to do it this way:
- Make sure that another drawing beside the current drawing is open (otherwise after closing the current drawing Lisp cannot be executed anymore).
- Show a modeless form. The modeless form has an active event OnDocActivated. In a label there is written: "Wait until reopening drawing has finished..." and below it there is a readonly textbox with the fullname of the drawing to reopen.
- Close the current drawing.
- The other drawing is going to get active. In this moment the event OnDocActivated is called. In the event function the name of the file to reopen can be read out from the textbox. And if this file can still be found (maybe a nervous colleague has deleted my file meanwhile) it will be opened.
- I think you are using a technology to load your app automatically to each newly opened drawing (via vl-load-all or similiar). In the end of your lisp there is a line which checks if the modeless form is active. In this case close it.
Hm, I feel it is worth to test it. ;)
Fred
Hi, it's a quarter to 3 in the night - at this time I have the best ideas!
Barry, I send you a small example. Note: load the lisp via (vl-load-all reopen.lsp").
Fred
WOW, Fred as always you da man. ;D
How do you come up with this stuff....
Ya I thought about .NET, but know you'd come through :)
Barry, I'm not very familiar with any language of MSVS .NET, unfortunately, indeed. I've already worked at a wrapper written in C# .NET which provides additional LISP functions to get access to a third party product which cannot be adressed by ActiveX. With this project in mind and the fact that Autodesk suggest developers using VBA in AutoCAD to migrate to VB .NET I thought about creating several lisp functions in a .NET-dll. But it depends on the number and content of your VBA-procedures you want to migrate.
QuoteHow do you come up with this stuff....
Very easy to tell: I remembered some of my palettes which are updating automatically after the current drawing is closed because OnDocActivated is being called. And on the other hand this modeless form is a good information what your command is currently going to do :)
But there is still a doubt towards .NET: I do not know if such a procedure in VB .NET called by a lisp-function would really work because if the current drawing is being closed, the lisp context of the current drawing has been gone, too. Will the rest of the .NET code still be executed? Lisp code won't be executed anymore cause the current execution depend on the current drawing. Does it also have the same effect in .NET? I do not know. I do know that a VBA skript can be executed between different drawings because it runs outside the drawing. But has a VB .NET skript the same behaviour? Especially if the procedure was called from Lisp? I do not know. And that's why I'd prefer the AutoLisp-way.
I have to look now to my kids what they're doing in their rooms - it sounds very strange there.
Fred
Hi Barry,
So, now I know much more. I created a C# project and I've found out that you cannot close the current drawing from the Lisp context even it is a Lisp function defined in C#. But if the same code runs in a command it works very well.
Here is the code. I also attached the whole C# project (MSVS 2005). For compiling anew the acmgd.dll and the acdbmdg.dll have to be linked anew before.
For those who want to test.
- Open AutoCAD and an existing drawing.
- call NETLOAD from command line and load ReOpen.dll from the source project
- call lisp function (reload). An exception will occur.
- call command reload from commandline. The drawing will be reloaded.
As you can see the lisp function and the command are doing the same.
[LispFunction("reload")]
public void fun_reload()
{
AcadClose();
}
[CommandMethod("reload", CommandFlags.Session)]
public void cmd_reload()
{
AcadClose();
}
That's the function for both:
private string AcadClose()
{
DocumentCollection oDocs = acadApp.DocumentManager;
Document oDoc = oDocs.MdiActiveDocument;
string strCurrentFile = oDoc.Name;
if (oDoc.IsReadOnly)
{
oDoc.CloseAndDiscard();
}
else
{
int isModified = System.Convert.ToInt32(acadApp.GetSystemVariable("DBMOD"));
// No need to save if not modified
if (isModified == 0)
{
oDoc.CloseAndDiscard();
}
else
{
int intReturn = System.Convert.ToInt32(MessageBox.Show("Do you want to save changes to " + strCurrentFile + "?", "Reopen current drawing", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1));
switch (intReturn)
{
case 6:
// this may save the drawing at strange places, espeacially if it wasn't saved before
// oDoc.Save(); // Does not work, not implemented yet (http://discussion.autodesk.com/forums/message.jspa?messageID=6110668)
oDoc.CloseAndSave(strCurrentFile);
break;
case 7:
oDoc.CloseAndDiscard();
break;
default:
strCurrentFile = "";
break;
}
}
}
if (strCurrentFile != "")
{
try
{
oDocs.Open(strCurrentFile,false);
}
catch (InvalidCastException e)
{
throw (e); // Rethrowing exception e
}
}
return strCurrentFile;
}
}
}
EDIT: copy the ReOpen.dll into the AutoCAD-InstallDir that it finds the correct acmgd.dll and acdbmgd.dll for the correct AutoCAD release. DO NOT COPY THE ACMGD.DLL and ACDBMGD.DLL OF THE SOURCE DIR INTO AUTOCAD INSTALLDIR (the compiler copied them to the output folder automatically)!
This it the advantage of .NET: this DLL works with AutoCAD 2008 as well as with AutoCAD 2010 (just testet).
So, I will cook some noodles now.
Fred
Fred,
cool, I'll have a play later.
Regarding the acmgd.dll and the acdbmdg.dll.
You should set the CopyLocal property for both to false, otherwise debugging issues may arise.
(http://sites.google.com/a/kdubpro.com/storage/Home/SetCopyLocalToFalse.png)
Thanks Kerry, good to know.
Fred
Thx for the help & the code Fred, I'll try to put it to good use.
Here's my modified version of Fred's code.
It asks you for the file name to open, open Read-Only, & if you want to close the current DWG or not (like SDI without SDI mode).
I doesn't have much error checking in it, since I do the error checking in Lisp before I run the RELOAD command.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Windows.Forms;
using System.IO;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
using acadApp = Autodesk.AutoCAD.ApplicationServices.Application;
namespace ReOpen
{
public class ReOpen
{
[CommandMethod("reload", CommandFlags.Session)]
public void cmd_reload()
{
Editor ed = acadApp.DocumentManager.MdiActiveDocument.Editor;
PromptStringOptions ops = new PromptStringOptions("\nDWG name: ");
ops.AllowSpaces = true;
PromptResult res = ed.GetString(ops);
PromptStringOptions ops2 = new PromptStringOptions("\nRead-Only Y/N: ");
PromptResult res2 = ed.GetString(ops2);
PromptStringOptions ops3 = new PromptStringOptions("\nClose current DWG Y/N: ");
PromptResult res3 = ed.GetString(ops3);
if (res.Status == PromptStatus.OK && res.StringResult != string.Empty)
{
//MessageBox.Show(res.StringResult);
AcadClose(res.StringResult, res2.StringResult, res3.StringResult);
}
}
private string AcadClose(string FileToOpen, string RO, string CloseCurrent)
{
DocumentCollection oDocs = acadApp.DocumentManager;
Document oDoc = oDocs.MdiActiveDocument;
string strCurrentFile = oDoc.Name;
if (CloseCurrent == "Y")
{
if (oDoc.IsReadOnly)
{
oDoc.CloseAndDiscard();
}
else
{
int isModified = System.Convert.ToInt32(acadApp.GetSystemVariable("DBMOD"));
// No need to save if not modified
if (isModified == 0)
{
oDoc.CloseAndDiscard();
}
else
{
int intReturn = System.Convert.ToInt32(MessageBox.Show("Do you want to save changes to " + strCurrentFile + "?", "TMaCAD", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1));
switch (intReturn)
{
case 6:
// this may save the drawing at strange places, espeacially if it wasn't saved before
// oDoc.Save(); // Does not work, not implemented yet (http://discussion.autodesk.com/forums/message.jspa?messageID=6110668)
oDoc.CloseAndSave(strCurrentFile);
break;
case 7:
oDoc.CloseAndDiscard();
break;
default:
FileToOpen = "";
break;
}
}
}
}
if (FileToOpen != "")
{
if (!File.Exists(FileToOpen))
{
throw new System.ArgumentException("Drawing does not exist", FileToOpen);
}
else
{
try
{
if (RO == "Y")
{
oDocs.Open(FileToOpen, true);
}
else
{
oDocs.Open(FileToOpen, false);
}
}
catch (InvalidCastException e)
{
throw (e); // Rethrowing exception e
}
}
}
return FileToOpen;
}
}
}