Now that it's done (good job Tim, and no surprise) let me illuminate a little on the ProjectName variable with regards to some bulk xref repathing I had to do a couple years back.
I worked on a project that had in excess of 5000 (it may have been 11000, that number seems to be familiar) production drawings that referenced some 500 or so different models (xreferences). Each xref would reside in a directory like:
drive\project\discipline\plant\model.dwge.g.
X:\999\elec\21\21-E-0001.dwg
X:\999\elec\21\21-E-0002.dwg
X:\999\elec\21\21-E-0003.dwg
X:\999\elec\37\37-E-0001.dwg
X:\999\elec\42\42-E-0001.dwg
X:\999\elec\63\63-E-0001.dwg
etc. for the civil, piping, inst ... disciplinesFor reasons I won't detail all xrefs were copied to a different drive and folder structure for another need (read "relative xref paths" wouldn't be a quick fix).
e.g.
z:\client\models\elec\21-E-0001.dwg
z:\client\models\elec\21-E-0002.dwg
z:\client\models\elec\21-E-0003.dwg
z:\client\models\elec\37-E-0001.dwg
z:\client\models\elec\42-E-0001.dwg
z:\client\models\elec\63-E-0001.dwg
etc. for the civil, piping, inst ... disciplinesSo --
I wrote a routine to repath the xrefs based on the paths associated with the current ProjectName, as said variable will host multiple paths, not just one.
e.g. ProjectName "Repath999" might have had these paths --
z:\client\models\elec
z:\client\models\civil
z:\client\models\piping
z:\client\models\instStored in the registry as --
"z:\client\models\elec;z:\client\models\civil;z:\client\models\piping;z:\client\models\inst"I could have done it differently, but it served other repathing needs that emerged about the same time that could also exploit the ProjectName variable, i.e. have the user select a ProjectName value from a list (i.e. read the resistry and display all the valid ProjectName values) and then repath all xrefs accordingly.
Anyway --
As the code was written for a client I just bashed this all out anew to demonstrate (hopefully no bugs). First the core code which knows nothing of the ProjectName variable, it just blithely repaths each xref in the supplied document (read objectDbx compatible) to the first path that resolves and repaths without error in a list of alternate paths.
(defun _RepathXrefs ( document paths / _GetXrefNames _RepathXref _Main )
;; repath each xref in the document to the first path
;; in the list of supplied paths that resolves and repaths
;; without error
(defun _GetXrefNames ( document / result )
;; get the document's xref names
(vlax-for block (vla-get-blocks document)
(if (eq :vlax-true (vla-get-isxref block))
(setq result
(cons (vla-get-name block)
result
)
)
)
result
)
)
(defun _RepathXref ( xref paths )
;; attempt to repath the xref to the first path in
;; the supplied alternate paths that hosts the xref's
;; filename AND can be remapped to w/out error
;;
;; note, each path in the paths argument is expected
;; to be valid and clean, no terminating back or forward
;; slashes
( (lambda ( filename )
(vl-some
'(lambda ( candidatePath / tryPath result )
(cond
( (findfile
(setq tryPath
(strcat
candidatePath
"\\"
filename
)
)
)
(vl-catch-all-apply
'(lambda ( )
(vla-put-path xref tryPath)
(setq result t)
)
)
result
)
)
)
paths
)
)
(strcat (vl-filename-base (vla-get-path xref)) ".dwg")
)
)
(defun _Main ( document paths / xrefNames )
;; get the document's xref names
(setq xrefNames (_GetXrefNames document))
;; iterate the xrefs in the document, trying to
;; remap 'em to the first valid path found in the
;; supplied paths
(vlax-for layout (vla-get-layouts document)
(vlax-for object (vla-get-block layout)
(if (eq "AcDbBlockReference" (vla-get-objectname object))
(if (member (vla-get-name object) xrefNames)
(_RepathXref object paths)
)
)
)
)
)
(_Main document paths)
)
Now an example program that repaths xrefs in the current document to the first valid path in the paths associated with the ProjectName's current value.
(defun c:Example ( / _GetProjectPath _SearchPathToList _Main *debug* )
;; use the paths associated with the projectname
;; variable as an alternate path for each xref
;; in the current document
(defun _GetProjectPath ( name )
;; get the paths associate with the project
;; name (note: result if non nil will be semi
;; colon delimited string)
(vl-registry-read
(strcat "HKEY_CURRENT_USER\\"
(vlax-product-key)
"\\Profiles\\"
(getvar "cprofile")
"\\Project Settings\\"
Name
)
"RefSearchPath"
)
)
(defun _SearchPathToList ( searchPath / path result )
(foreach code (reverse (vl-string->list searchPath))
(if (eq 59 code) ;; ascii ";" = 59
(if path
(setq
result (cons path result)
path nil
)
)
(setq path (cons code path))
)
)
(mapcar
'(lambda (lst) (vl-string-right-trim "/\\" (vl-list->string lst)))
(if path (cons path result) result)
)
)
(defun _Main ( document / paths )
;; if there are paths associated with
;; the current projectname ...
(cond
(
(setq paths
(_GetProjectPath
(vlax-invoke
document
'GetVariable
"projectname"
)
)
)
;; do it
(_RepathXrefs
document
(_SearchPathToList paths)
)
;; reload all xrefs
(vlax-for block (vla-get-blocks document)
(if (eq :vlax-true (vla-get-isxref block))
(vla-reload block)
)
)
;; force a regen
(vla-regen
document
acAllViewports
)
)
)
(princ)
)
(_Main
(vla-get-activedocument
(vlax-get-acad-object)
)
)
)
Hope it makes sense.