Remco Koedoot Posted November 16, 2022 Share Posted November 16, 2022 I'm looking for a way through a lisp routine to search various folders drawings (.dwg files) to a specific layer name. The result in an excel list of the found dwg files where the specific layer is located. For example select folder and even subdirs. Look for given layer name: .... Seach and result, only the drawings that contains layer name ..... I have a lisp routine that will scan in a folder of drawings for all layer names. I want to specify it. It must be in a atnother solution. To specify to search various folders drawings (.dwg files) for a specific layer name. The result in an excel list of the found dwg files where the specific layer is located. You can read the current code in the topic. And that code works. I would like an extension to the existing module with function as described in the topic. What's your solution? (defun c:CheckLayers ( / *error* DBX DOCLST FILES FLAG LAYER_LIST ODOC OFILE OUTFILE SHELL ) (vl-load-com) (defun *error* (msg) (ObjRelease (list Shell dbx)) (and ofile (= (type ofile) 'FILE) (close ofile)) (or (wcmatch (strcase msg) "*BREAK,*CANCEL*,*EXIT*") (princ (strcat "\n** Error: " msg " **"))) (princ) ) (setq *acad (cond (*acad) ((vlax-get-acad-object))) *doc (cond (*doc ) ((vla-get-ActiveDocument *acad)))) (if (and (setq Files (GetAllFiles nil t "*.dwg")) (setq outfile (getfiled "Output File" "" "csv" 1))) (progn (vlax-for doc (vla-get-Documents *acad) (setq DocLst (cons (cons (strcase (vla-get-FullName doc)) doc) DocLst ) ) ) (setq dbx (ObjectDBXDocument)) (foreach dwg Files (cond ( (setq flag (and (setq oDoc (cdr (assoc (strcase dwg) DocLst)) ) ) ) ) (t (setq flag (not (vl-catch-all-error-p (vl-catch-all-apply (function vla-open) (list dbx dwg) ) ) ) ) (setq oDoc dbx) ) ) (setq Layer_List (if flag (cons (cons dwg (GetLayerProperties oDoc)) Layer_List) (cons (cons dwg '(("**Error Opening this Drawing **"))) Layer_List) ) ) ) (princ (strcat "\n<< " (itoa (length Files)) " Drawings Processed >>")) ) (princ "*Cancel*") ) (vlax-release-object dbx) (gc) (gc) (if (and Layer_List (setq ofile (open outfile "w"))) (progn (mapcar (function (lambda (x) (write-line (car x) ofile) (write-line (MakeString '("Name" "Colour" "LineType" "LineWeight") (chr 32)) ofile) (mapcar (function (lambda (y) (write-line (MakeString y (chr 32)) ofile ) ) ) (cdr x) ) (write-line "\n" ofile) ) ) Layer_List ) (close ofile) ) (princ "\n*Cancel*") ) (princ) ) (defun ObjectDBXDocument ( / acVer ) (setq *acad (cond (*acad) ((vlax-get-acad-object)))) (vla-GetInterfaceObject *acad (if (< (setq acVer (atoi (getvar "ACADVER"))) 16) "ObjectDBX.AxDbDocument" (strcat "ObjectDBX.AxDbDocument." (itoa acVer)) ) ) ) (defun GetAllFiles ( Dir Subs Filetype / GetSubFolders Shell Fold Dir ) (vl-load-com) (defun GetSubFolders ( folder / _f ) (mapcar (function (lambda ( f ) (setq _f (strcat folder "\\" f)) (cons _f (apply (function append) (GetSubFolders _f))) ) ) (cddr (vl-directory-files folder nil -1)) ) ) (cond ( (not (or (and Dir (vl-file-directory-p Dir)) (progn (setq Shell (vla-getInterfaceObject (setq acad (vlax-get-acad-object)) "Shell.Application") Fold (vlax-invoke-method Shell 'BrowseForFolder (vla-get-HWND acad) "Select Directory" 512)) (vlax-release-object Shell) (if Fold (progn (setq Dir (vlax-get-property (vlax-get-property Fold 'Self) 'Path)) (vlax-release-object Fold) (and (= "\\" (substr Dir (strlen Dir))) (setq Dir (substr Dir 1 (1- (strlen Dir))))) Dir ) ) ) ) ) ) ( (apply (function append) (vl-remove (quote nil) (mapcar (function (lambda (Filepath) (mapcar (function (lambda (Filename) (strcat Filepath "\\" Filename) ) ) (vl-directory-files Filepath Filetype 1) ) ) ) (append (list Dir) (apply (function append) (if subs (GetSubFolders Dir)) ) ) ) ) ) ) ) ) (defun GetLayerProperties ( doc / lst ) (vlax-for lay (vla-get-Layers doc) (setq lst (cons (mapcar (function (lambda ( property ) (vl-princ-to-string (vlax-get-property lay property) ) ) ) '(Name Color Linetype LineWeight) ) lst ) ) ) (vl-sort lst (function (lambda (a b) (< (car a) (car b))) ) ) ) (defun MakeString ( lst del / Pad str x i ) (setq i 10) (defun Pad ( Str Del Len ) (while (>= (strlen Str) Len) (setq Len (+ Len 5))) (while (< (strlen Str) Len) (setq Str (strcat Str Del)) ) Str ) (apply (function strcat) (reverse (cons (last lst) (mapcar (function (lambda ( $str ) (Pad $str del (setq i (abs (- 40 i)))) ) ) (cdr (reverse lst)) ) ) ) ) ) Quote Link to comment Share on other sites More sharing options...
BIGAL Posted November 17, 2022 Share Posted November 17, 2022 If you want just 1 layer look at your defun Getlayersproperties it can be shortened down to using a simple if, no need for sort etc Not tested. (defun GetLayerProperties ( doc / lst ) (vlax-for lay (vla-get-Layers doc) (If (= (vla-get-name lay) yourlayername) (write-line dwgname ofile) ) ) ) The way to go would be do a IF want "name,color,ltype" or "name" so call Getlayersproperties2 A bit of rewriting. Sorry have to many to do's at moment. Quote Link to comment Share on other sites More sharing options...
Dadgad Posted November 17, 2022 Share Posted November 17, 2022 Might Lees Mac's brilliant Batch Find & Replace lisp be able to do this? Using the SEARCH ONLY option? Thanks Lee! Quote Link to comment Share on other sites More sharing options...
Remco Koedoot Posted November 17, 2022 Author Share Posted November 17, 2022 (edited) 7 hours ago, Dadgad said: Might Lees Mac's brilliant Batch Find & Replace lisp be able to do this? Using the SEARCH ONLY option? Thanks Lee! This is not a option, it search not for layers. Better can use ObjectDBX to achieve this, ObjectDBX Wrapper function. Edited November 17, 2022 by Remco Koedoot Quote Link to comment Share on other sites More sharing options...
Remco Koedoot Posted November 17, 2022 Author Share Posted November 17, 2022 (edited) 8 hours ago, BIGAL said: If you want just 1 layer look at your defun Getlayersproperties it can be shortened down to using a simple if, no need for sort etc Not tested. (defun GetLayerProperties ( doc / lst ) (vlax-for lay (vla-get-Layers doc) (If (= (vla-get-name lay) yourlayername) (write-line dwgname ofile) ) ) ) The way to go would be do a IF want "name,color,ltype" or "name" so call Getlayersproperties2 A bit of rewriting. Sorry have to many to do's at moment. By running the lisp, how to wtite the input (layer name) in a shell-window and not by the routine? Edited November 17, 2022 by Remco Koedoot Quote Link to comment Share on other sites More sharing options...
BIGAL Posted November 18, 2022 Share Posted November 18, 2022 (edited) If using accoreconsole and a script calling a lisp (tblsearch "LAYER" yourlayer) will return true or nil, so write dwg name to file, use the "A" option when opening the file to append the answer. Look into Accoreconsole. https://through-the-interface.typepad.com/through_the_interface/2012/02/the-autocad-2013-core-console.html Edited November 18, 2022 by BIGAL 1 Quote Link to comment Share on other sites More sharing options...
Remco Koedoot Posted November 19, 2022 Author Share Posted November 19, 2022 On 11/18/2022 at 6:11 AM, BIGAL said: If using accoreconsole and a script calling a lisp (tblsearch "LAYER" yourlayer) will return true or nil, so write dwg name to file, use the "A" option when opening the file to append the answer. Look into Accoreconsole. https://through-the-interface.typepad.com/through_the_interface/2012/02/the-autocad-2013-core-console.html No in a lisp routine. Quote Link to comment Share on other sites More sharing options...
BIGAL Posted November 19, 2022 Share Posted November 19, 2022 No in a lisp routine. ??? Quote Link to comment Share on other sites More sharing options...
SLW210 Posted November 21, 2022 Share Posted November 21, 2022 I moved your thread to the AutoLISP, Visual LISP & DCL Forum. Please post in the appropriate forum. Quote Link to comment Share on other sites More sharing options...
StevJ Posted November 26, 2022 Share Posted November 26, 2022 (edited) I found this thread in a search. I'm trying to do the very thing as the OP, using Lee Mac's original version of the program, which outputs to a TEXT FILE. Only down side is my brain has trouble with the vl-/vla-/vlax- syntax used in the program. As originally written, The program lists all drawings in the chosen folder(and optionally, subs) and for each drawing, lists all layers alphabetically. What I'd like to change the program to do: List a drawing only if it contains the layer WATERMARK. This will leave a text file listing only those drawings containing that layer. Seemed simple enough. Just toss in a "If layer =" or some such, but as stated above, vl-/vla-/vlax- syntax is my enemy here and the programming style is, well, way beyond my abilities. The original program, as posted by @Lee Mac, is below for your viewing pleasure and to give credit to the author. ;; Posted by Lee Mac 15 Jan 2010 ;; https://www.cadtutor.net/forum/topic/17420-listing-layers-in-multiple-drawings/ ;; What changes are necessary to only list those DWGs that have layer "WATERMARK"? ;; GetLayers subroutine ?? (defun c:CheckLayers (/ *error* ObjRelease DirDialog Get_Subs ObjectDBXDocument GetLayers DBX DWLST FILE FOLDER LAYER_LIST PATH SHELL) (vl-load-com) ;; Lee Mac ~ 15.01.10 (defun *error* (msg) (ObjRelease (list Shell dbx)) (and ofile (= (type ofile) 'FILE) (close ofile)) (or (wcmatch (strcase msg) "*BREAK,*CANCEL*,*EXIT*") (princ (strcat "\n** Error: " msg " **"))) (princ)) (defun ObjRelease (lst) (mapcar (function (lambda (x) (if (and (eq (type x) 'VLA-OBJECT) (not (vlax-object-released-p x))) (vl-catch-all-apply (function vlax-release-object) (list x))))) lst)) (defun DirDialog (msg dir flag / Shell Fold Path) ;; Lee Mac ~ 07.06.09 (setq Shell (vla-getInterfaceObject *acad "Shell.Application") Fold (vlax-invoke-method Shell 'BrowseForFolder (vla-get-HWND *acad) msg flag dir)) (vlax-release-object Shell) (if Fold (progn (setq Path (vlax-get-property (vlax-get-property Fold 'Self) 'Path)) (vlax-release-object Fold) (and (= "\\" (substr Path (strlen Path))) (setq Path (substr Path 1 (1- (strlen Path))))))) Path) (defun Get_Subs (folder / file) ;; CAB (mapcar (function (lambda (x) (setq file (strcat folder "\\" x)) (cons file (apply (function append) (get_subs file))))) (cddr (vl-directory-files folder nil -1)))) (defun ObjectDBXDocument (/ acVer) (vla-GetInterfaceObject *acad (if (< (setq acVer (atoi (getvar "ACADVER"))) 16) "ObjectDBX.AxDbDocument" (strcat "ObjectDBX.AxDbDocument." (itoa acVer))))) (defun GetLayers (doc / lst) (vlax-for lay (vla-get-Layers doc) (setq lst (cons (vla-get-name lay) lst))) (acad_strlsort lst)) (setq *acad (cond (*acad) ((vlax-get-acad-object))) *doc (cond (*doc ) ((vla-get-ActiveDocument *acad)))) (or *def* (setq *def* "Yes")) (if (and (setq Path (DirDialog "Select Directory" nil 0)) (vl-file-directory-p Path) (setq outfile (getfiled "Output File" "" "txt" 1))) (progn (initget "Yes No") (setq *def* (cond ((getkword (strcat "\nProcess SubDirectories? <" *def* "> : "))) (*def*))) (princ "\n>> Processing...") (foreach dwg (setq dwLst (apply (function append) (vl-remove 'nil (mapcar (function (lambda (Path) (mapcar (function (lambda (File) (strcat Path "\\" File))) (vl-directory-files Path "*.dwg" 1)))) (append (list Path) (apply (function append) (if (= "YES" (strcase *def*)) (Get_Subs Path)))))))) (vlax-for doc (vla-get-Documents *acad) (and (eq (strcase (vla-get-fullname doc)) (strcase dwg)) (setq dbx doc))) (and (not dbx) (setq dbx (ObjectDBXDocument))) (if (not (vl-catch-all-error-p (vl-catch-all-apply (function vla-open) (list dbx dwg)))) (progn (princ (chr 46)) (setq Layer_List (cons (cons dwg (GetLayers dbx)) Layer_List)) ) ; Progn )) (princ (strcat "\n<< " (itoa (length dwLst)) " Drawings Processed >>"))) (princ "*Cancel*")) (ObjRelease (list Shell dbx)) (gc) (gc) (if (and Layer_List (setq ofile (open outfile "w"))) (progn (mapcar (function (lambda (x) (write-line (car x) ofile) (mapcar (function (lambda (y) (write-line y ofile))) (cdr x)) (write-line "\n" ofile))) Layer_List) (close ofile)) (princ "\n*Cancel*")) (princ)) Any helpful hints and ideas are appreciated. Thanks, Steve Edited November 26, 2022 by StevJ Quote Link to comment Share on other sites More sharing options...
Remco Koedoot Posted November 27, 2022 Author Share Posted November 27, 2022 15 hours ago, StevJ said: I found this thread in a search. I'm trying to do the very thing as the OP, using Lee Mac's original version of the program, which outputs to a TEXT FILE. Only down side is my brain has trouble with the vl-/vla-/vlax- syntax used in the program. As originally written, The program lists all drawings in the chosen folder(and optionally, subs) and for each drawing, lists all layers alphabetically. What I'd like to change the program to do: List a drawing only if it contains the layer WATERMARK. This will leave a text file listing only those drawings containing that layer. Seemed simple enough. Just toss in a "If layer =" or some such, but as stated above, vl-/vla-/vlax- syntax is my enemy here and the programming style is, well, way beyond my abilities. The original program, as posted by @Lee Mac, is below for your viewing pleasure and to give credit to the author. ;; Posted by Lee Mac 15 Jan 2010 ;; https://www.cadtutor.net/forum/topic/17420-listing-layers-in-multiple-drawings/ ;; What changes are necessary to only list those DWGs that have layer "WATERMARK"? ;; GetLayers subroutine ?? (defun c:CheckLayers (/ *error* ObjRelease DirDialog Get_Subs ObjectDBXDocument GetLayers DBX DWLST FILE FOLDER LAYER_LIST PATH SHELL) (vl-load-com) ;; Lee Mac ~ 15.01.10 (defun *error* (msg) (ObjRelease (list Shell dbx)) (and ofile (= (type ofile) 'FILE) (close ofile)) (or (wcmatch (strcase msg) "*BREAK,*CANCEL*,*EXIT*") (princ (strcat "\n** Error: " msg " **"))) (princ)) (defun ObjRelease (lst) (mapcar (function (lambda (x) (if (and (eq (type x) 'VLA-OBJECT) (not (vlax-object-released-p x))) (vl-catch-all-apply (function vlax-release-object) (list x))))) lst)) (defun DirDialog (msg dir flag / Shell Fold Path) ;; Lee Mac ~ 07.06.09 (setq Shell (vla-getInterfaceObject *acad "Shell.Application") Fold (vlax-invoke-method Shell 'BrowseForFolder (vla-get-HWND *acad) msg flag dir)) (vlax-release-object Shell) (if Fold (progn (setq Path (vlax-get-property (vlax-get-property Fold 'Self) 'Path)) (vlax-release-object Fold) (and (= "\\" (substr Path (strlen Path))) (setq Path (substr Path 1 (1- (strlen Path))))))) Path) (defun Get_Subs (folder / file) ;; CAB (mapcar (function (lambda (x) (setq file (strcat folder "\\" x)) (cons file (apply (function append) (get_subs file))))) (cddr (vl-directory-files folder nil -1)))) (defun ObjectDBXDocument (/ acVer) (vla-GetInterfaceObject *acad (if (< (setq acVer (atoi (getvar "ACADVER"))) 16) "ObjectDBX.AxDbDocument" (strcat "ObjectDBX.AxDbDocument." (itoa acVer))))) (defun GetLayers (doc / lst) (vlax-for lay (vla-get-Layers doc) (setq lst (cons (vla-get-name lay) lst))) (acad_strlsort lst)) (setq *acad (cond (*acad) ((vlax-get-acad-object))) *doc (cond (*doc ) ((vla-get-ActiveDocument *acad)))) (or *def* (setq *def* "Yes")) (if (and (setq Path (DirDialog "Select Directory" nil 0)) (vl-file-directory-p Path) (setq outfile (getfiled "Output File" "" "txt" 1))) (progn (initget "Yes No") (setq *def* (cond ((getkword (strcat "\nProcess SubDirectories? <" *def* "> : "))) (*def*))) (princ "\n>> Processing...") (foreach dwg (setq dwLst (apply (function append) (vl-remove 'nil (mapcar (function (lambda (Path) (mapcar (function (lambda (File) (strcat Path "\\" File))) (vl-directory-files Path "*.dwg" 1)))) (append (list Path) (apply (function append) (if (= "YES" (strcase *def*)) (Get_Subs Path)))))))) (vlax-for doc (vla-get-Documents *acad) (and (eq (strcase (vla-get-fullname doc)) (strcase dwg)) (setq dbx doc))) (and (not dbx) (setq dbx (ObjectDBXDocument))) (if (not (vl-catch-all-error-p (vl-catch-all-apply (function vla-open) (list dbx dwg)))) (progn (princ (chr 46)) (setq Layer_List (cons (cons dwg (GetLayers dbx)) Layer_List)) ) ; Progn )) (princ (strcat "\n<< " (itoa (length dwLst)) " Drawings Processed >>"))) (princ "*Cancel*")) (ObjRelease (list Shell dbx)) (gc) (gc) (if (and Layer_List (setq ofile (open outfile "w"))) (progn (mapcar (function (lambda (x) (write-line (car x) ofile) (mapcar (function (lambda (y) (write-line y ofile))) (cdr x)) (write-line "\n" ofile))) Layer_List) (close ofile)) (princ "\n*Cancel*")) (princ)) Any helpful hints and ideas are appreciated. Thanks, Steve I also assumed this code as the basis of Lee Mac. But I would like it different. I don't want to see all drawings as a result. As described in the topic. You should be able to enter the layer name search in a separate window, not by changing the lisp routine each time. And the result in Excel (.csv) of only those drawings that the layer contains. No more and no less. That's the challenge of changing Lee Mac's famous lisp routine Quote Link to comment Share on other sites More sharing options...
rlx Posted November 27, 2022 Share Posted November 27, 2022 (edited) had an idea (not necessarily a good one) but tried to add search for layers to a program I wrote a little while back My BFF. Have only tested it once though so hope for the best & plan for the worst... (1) Put Routine in layer mode , add names of layer(s) to search for. (2) Save the search list (3) select folder with drawings to scan (4) click on create (5) click on ok you should get new dialog with drawings containing layers you specified (if any). You can click on one item in list box and full path is displayed below the list box. You can then click on ok to open the drawing , or click on edit button to open notepad with list of all drawings found. You can also click on multiple lines in the listbox and click ok. Hope it works, if not , will try to fix later... RlxMyBFF.lsp Edited November 28, 2022 by rlx killed another bug 1 Quote Link to comment Share on other sites More sharing options...
StevJ Posted November 27, 2022 Share Posted November 27, 2022 31 minutes ago, rlx said: had an idea (not necessarily a good one) but tried to add search for layers to a program I wrote a little while back My BFF. Have only tested it once though so hope for the best & plan for the worst... (1) Put Routine in layer mode , add names of layer(s) to search for. (2) Save the search list (3) select folder with drawings to scan (4) click on create (5) click on ok you should get new dialog with drawings containing layers you specified (if any). You can click on one item in list box and full path is displayed below the list box. You can then click on ok to open the drawing , or click on edit button to open notepad with list of all drawings found. You can also click on multiple lines in the listbox and click ok. Hope it works, if not , will try to fix later... RlxMyBFF.lsp 53.58 kB · 0 downloads This is impressive, but unfortunately, at step 4, I get this error. My drawings do not have a title block. Steve Quote Link to comment Share on other sites More sharing options...
rlx Posted November 27, 2022 Share Posted November 27, 2022 ah yes , have'nt thought about that one. Just switch of layer mode , type in any string for blockname , same for attributes and switch back to layer mode, maybe this will work. I will fix this later. 1 Quote Link to comment Share on other sites More sharing options...
StevJ Posted November 28, 2022 Share Posted November 28, 2022 (edited) 7 hours ago, rlx said: ah yes , have'nt thought about that one. Just switch of layer mode , type in any string for blockname , same for attributes and switch back to layer mode, maybe this will work. I will fix this later. OK. That got the program to run - There are indeed 13 drawings in the folder. Some have HIDDEN layer. But when I selected OK button to see results, then, selecting OK on that message gives This last window was to give the user the results of the search for all drawings with , in this case, a HIDDEN layer? Also, the Folder Index List index file was never created. Steve Edited November 28, 2022 by StevJ spellin Quote Link to comment Share on other sites More sharing options...
rlx Posted November 28, 2022 Share Posted November 28, 2022 maybe try to use saveas index list and then use edit to see if list contains all your files. Sometimes its to do with IT and write permissions and sometimes just not enough safeguards built in. Not sure if you have to use 'Ignore case' too, else post a sample drawing so I can check if at least retrieving your layers is working as is intended. Its always a risk trying to change an existing routine that was originally meant to do something else. Quote Link to comment Share on other sites More sharing options...
rlx Posted November 28, 2022 Share Posted November 28, 2022 updated code above, hope it works now now back to work, I'm running behind planning Quote Link to comment Share on other sites More sharing options...
StevJ Posted November 28, 2022 Share Posted November 28, 2022 JACKPOT! Following your numbered steps, as posted above, now gives expected results. I have been volunteered to search thousands of drawings for a certain layer that is no longer part of our standards, then remove it and everything on it. Your program will shave many days off this task. Thank you for your programming time and effort. Cheers! Steve Quote Link to comment Share on other sites More sharing options...
Remco Koedoot Posted December 7, 2022 Author Share Posted December 7, 2022 Not found the right solution yet. Quote Link to comment Share on other sites More sharing options...
Tsuky Posted December 7, 2022 Share Posted December 7, 2022 (edited) With a script working with AcCoreConsole. Choose the folder where you want find layer in dwg You enter the name of the desired layer. If the wildcard "*" is used and at the beginning of the chain the XREF layers (if present), the layer names will also be returned. Elsewhere the affected layers will be returned. Example "Layer*" could return Layer1, Layer2, Layer3 etc... At the end of the execution of AcCoreConsole, the following line will return the result in the notepad. (startapp "notepad" (strcat (getvar "ROAMABLEROOTPREFIX") "support\\find_layer.txt")) find_layerbydwg.lsp Edited December 7, 2022 by Tsuky Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.