Folder Browser Dialog for LISP
Hey Group,
One function that is exposed in the shell.application is browseforfolder.
Code:
; LISP syntax (browseforfolder "Select Folder" "C:\\acad")
(defun BrowseForFolder (strMessage
strRootFolder
/
lstObjects
objShellApp
objFolder
objParentFolder
strPath
)
(and
(setq objShellApp (vla-getInterfaceObject
(vlax-get-acad-object)
"Shell.Application"
)
)
(setq lstObjects (list objShellApp))
(setq objFolder (vlax-invoke objShellApp
'BrowseForFolder
0
strMessage
0
strRootFolder
)
)
(setq lstObjects (cons objFolder lstObjects))
(setq strTitle (vlax-get objFolder "Title"))
(setq objParentFolder (vlax-get objFolder 'ParentFolder))
(setq lstObjects (cons objParentFolder lstObjects))
(setq strPath (vlax-get (vlax-invoke objParentFolder "Parsename" strTitle) "Path"))
)
(mapcar 'vlax-release-object lstObjects)
strPath
)
But it does not allow you to pre select a selectedfolder.
.NET has a browsefolderdialog that gives you more options including the ability to selectfolder.
See next post.
Re: Folder Browser Dialog for LISP
This is the code.
It has several options for the lisp function and you may want to modify it to add maybe the root folder etc...
You can view its functionality on Youtube to see if is something you like.
http://www.youtube.com/watch?v=Ug0k5...ature=youtu.be
Code:
Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.DatabaseServices
Imports System.Windows.Forms
''' <summary>
''' Folder Class to create a LISP Function to display the Folder Browser Dialog
''' In the System.Windows.Forms Class
''' </summary>
Public Class FolderClass
''' <summary>
''' LISP Function to display the Folder Browser Dialog
''' </summary>
''' <param name="rbfArguments"></param>
'''
''' <remarks>LISP Syntax
''' (folder) Default Selected Path is C:\\
''' (folder "C:\\") Sets the Selected Path to C:\\
''' (folder "C:\\" "Select Folder") Sets Description to "Select Folder"
''' (folder "C:\\" "Select Folder" T) Displays New Folder Button
''' </remarks>
<LispFunction("Folder")> _
Public Function Folder(ByVal rbfArguments As ResultBuffer)
Try
If rbfArguments Is Nothing Then Return Folder("C:\")
Dim arrArguments As TypedValue() = rbfArguments.AsArray()
Select Case arrArguments.Length
Case 0
Return Folder("C:\")
Case 1
Return Folder(arrArguments(0).Value.ToString)
Case 2
Return Folder(arrArguments(0).Value.ToString, arrArguments(1).Value.ToString)
Case 3
Return Folder(arrArguments(0).Value.ToString, arrArguments(1).Value.ToString, True)
End Select
Catch ex As System.Exception
End Try
Return Nothing
End Function
''' <summary>
''' .NET Function to display Folder Browser Dialog
''' </summary>
''' <param name="strSelectedPath"></param>
''' <param name="strDescription"></param>
''' <param name="blnNewFolderShow"></param>
''' <returns>Selected folder as string</returns>
Public Function Folder(Optional ByVal strSelectedPath As String = "", _
Optional ByVal strDescription As String = "", _
Optional ByVal blnNewFolderShow As Boolean = False)
Try
If strSelectedPath IsNot Nothing Then
Dim folderBrowserDialog As New FolderBrowserDialog
folderBrowserDialog.RootFolder = Environment.SpecialFolder.MyComputer
folderBrowserDialog.SelectedPath = strSelectedPath
folderBrowserDialog.Description = strDescription
folderBrowserDialog.ShowNewFolderButton = blnNewFolderShow
folderBrowserDialog.ShowDialog()
Return folderBrowserDialog.SelectedPath
End If
Catch ex As System.Exception
End Try
Return Nothing
End Function
End Class
Re: Folder Browser Dialog for LISP
Quote:
Originally Posted by
peter
Hey Group,
One function that is exposed in the shell.application is browseforfolder.
Very nice. Thanks.
Re: Folder Browser Dialog for LISP
Quote:
Originally Posted by
peter
Hey Group,
One function that is exposed in the shell.application is browseforfolder.
I too am a fan of BrowseForFolder... My old BatchFindSurface routine for Civil 3D comes to mind for this specific topic, and includes some other goodies.
Cheers
Re: Folder Browser Dialog for LISP
BTW, Shell.Application (an external object) is never released.
Re: Folder Browser Dialog for LISP
Here's a slightly different adaptation of the LISP code posted above that may prove useful... Please note the allowed parameter combinations shown in the commented examples:
Code:
(vl-load-com)
(defun _BrowseForFolder (msg path / *error* acApp oShell oFolder)
;; Examples:
;; (_BrowseForFolder "Select a Folder" nil)
;; (_BrowseForFolder nil nil)
;; (_BrowseForFolder nil "C:\\users")
(defun *error* (msg)
(if oShell (vlax-release-object oShell))
(cond ((not msg)) ; Normal exit
((member msg '("Function cancelled" "quit / exit abort"))) ; <esc> or (quit)
((princ (strcat "\n** Error: " msg " ** "))) ; Fatal error, display it
)
(if oFolder path nil)
)
(and
(or
(and (= 'STR (type path)) (findfile path))
(setq path (+ 1 64 256))
)
(or (= 'STR (type msg)) (setq msg "Select a Folder to Search"))
(setq acApp (vlax-get-acad-object))
(setq oShell (vla-getinterfaceobject acApp "Shell.Application"))
(setq oFolder
(vlax-invoke
oShell
'BrowseForFolder
(vla-get-hwnd acApp)
msg
0
path
)
)
(setq path (vlax-get-property
(vlax-get-property oFolder 'Self)
'Path
)
)
)
(*error* nil)
)
Re: Folder Browser Dialog for LISP
Quote:
Originally Posted by
BlackBox
BTW, Shell.Application (an external object) is never released.
I have thought about that, in my original code I had the release expressions, but when I checked, because of the localized variable, LISP releases it automatically.
I could never find any documentation on whether the release statement is or is not required for a localized variable.
Do you know of any?
Peter
Re: Folder Browser Dialog for LISP
Quote:
Originally Posted by
peter
I have thought about that, in my original code I had the release expressions, but when I checked, because of the localized variable, LISP releases it automatically.
As I understand it.... While localisation clears the variable (symbol) value from being accessed once the Defun's scope has ended, this unfortunately does not account for releasing the object instance itself, which could result in multiple instances lingering for repeated code, and can cause other application, or even OS issues down the line.
This principle applies to any external object, be it an AutoCAD-based object like the legacy Land Desktop (external) Database, today's Civil 3D COM Objects, or Shell.Application Object, Scripting.FileSystemObject Object, and ADsSecurityUtility Object, etc. as some other examples.
Quote:
Originally Posted by
peter
I could never find any documentation on whether the release statement is or is not required for a localized variable.
Do you know of any?
Especially if you're using 2012-2013 the ActiveX documentation is a bit cumbersome to use, IMO. 2014 is a little better, but you may want to install the offline help depending on bandwidth limitation, etc.
Straight from the ActiveX Developer Documentation within VLIDE:
Quote:
vlax-Release-Object
When an AutoLISP routine no longer uses an object outside AutoCAD, such as a Microsoft Excel object, call the (vlax-release-object) function to make sure that the associated application closes properly. Objects released with (vlax-release-object...) may not be released immediately. The actual release may not happen until the next automatic garbage collection occurs.
...
HTH :beer:
Re: Folder Browser Dialog for LISP
I added them back into the example at the top.
Although the thread was more about how to do that with .net and not with the shell application.
p=
Re: Folder Browser Dialog for LISP
Quote:
Originally Posted by
peter
I added them back into the example at the top.
What happens in the event of an error? :wink:
Quote:
Originally Posted by
peter
Although the thread was more about how to do that with .net and not with the shell application.
Fair enough; here's an alternative that provides some native 'invalid argument' handling:
Code:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using acApp = Autodesk.AutoCAD.ApplicationServices.Application;
using System;
using System.IO;
using System.Windows.Forms;
[assembly: CommandClass(typeof(BlackBox.AutoCAD.FolderBrowser.Commands))]
namespace BlackBox.AutoCAD.FolderBrowser
{
public class Commands
{
private bool showNewFolderButton;
private DocumentCollection acDocs = acApp.DocumentManager;
private string selectedPath;
private string description;
private object Browse()
{
FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog();
folderBrowserDialog.Description = description;
folderBrowserDialog.RootFolder = Environment.SpecialFolder.MyComputer;
folderBrowserDialog.SelectedPath = selectedPath;
folderBrowserDialog.ShowNewFolderButton = showNewFolderButton;
if (folderBrowserDialog.ShowDialog() != DialogResult.OK)
return null;
return folderBrowserDialog.SelectedPath;
}
[LispFunction("FolderBrowser")]
public object FolderBrowser(ResultBuffer resbuf)
{
showNewFolderButton = false;
selectedPath = "C:\\";
description = "";
try
{
if (resbuf == null)
return Browse();
TypedValue[] args = resbuf.AsArray();
int i = args.Length;
if (args[0].TypeCode != (int)LispDataType.Text)
throw new ArgumentTypeException("stringp", args[0]);
selectedPath = (string)args[0].Value;
if (!Directory.Exists(selectedPath))
throw new DirectoryDoesNotExistException();
if (i >= 2)
{
if (args[1].TypeCode != (int)LispDataType.Text)
throw new ArgumentTypeException("stringp", args[1]);
description = (string)args[1].Value;
}
if (i == 3 && args[2].TypeCode != (int)LispDataType.Nil)
showNewFolderButton = true;
return Browse();
}
catch (LispException ex)
{
acDocs.MdiActiveDocument.Editor.WriteMessage(
"\n; error: LispException: " + ex.Message + "\n");
return null;
}
catch (System.Exception ex)
{
acDocs.MdiActiveDocument.Editor.WriteMessage(
"\n; error: System.Exception: " + ex.Message + "\n");
return null;
}
}
}
/// <summary>
/// Special thanks to Gile for his LispException classes:
/// </summary>
class LispException : System.Exception
{
public LispException(string msg) : base(msg) { }
}
class TooFewArgsException : LispException
{
public TooFewArgsException() : base("too few arguments") { }
}
class TooManyArgsException : LispException
{
public TooManyArgsException() : base("too many arguments") { }
}
class ArgumentTypeException : LispException
{
public ArgumentTypeException(string s, TypedValue tv)
: base(string.Format(
"invalid argument type: {0}: {1}",
s, tv.TypeCode == (int)LispDataType.Nil ? "nil" : tv.Value))
{ }
}
// Added by BlackBox
class DirectoryDoesNotExistException : LispException
{
public DirectoryDoesNotExistException() : base("directory does not exist") { }
}
}
Cheers :beer: