From CSV to XLS

From CSV to XLS

DGRL
Advisor Advisor
3,449 Views
13 Replies
Message 1 of 14

From CSV to XLS

DGRL
Advisor
Advisor

Dear forum members,

 

I am using the code from Lee Mac to read from CSV and fill in Attributes in dwg.
It works but I need it to read from XLS instead of CSV

 

Just changing the 2 entry's in de lsp file from csv to xls is not working.
Does any of you or Lee Mac himself how to make this code to work with XLS?

 

I attached also the 2 sample files ( they are working with CSV now )

 

ORG code below

 

;;-----------------------=={ Update Attributes }==----------------------;;
;;                                                                      ;;
;;  Reads a CSV file containing attribute data, and, should the drawing ;;
;;  name of the current drawing appear in the first column of the CSV   ;;
;;  Drawing List, the program will proceed to update block attributes.  ;;
;;                                                                      ;;
;;  The attributes updated will be those with tags corresponding to the ;;
;;  CSV column headings. These will be updated with values from the     ;;
;;  row in which the drawing file is listed.                            ;;
;;                                                                      ;;
;;  -------------------------------------                               ;;
;;  Example of CSV format:                                              ;;
;;  -------------------------------------                               ;;
;;                                                                      ;;
;;  +------------+-----------+-----------+----------+-----+----------+  ;;
;;  |    DWG     |  Layout*  |   Block*  |   TAG1   | ... |   TAGN   |  ;;
;;  +------------+-----------+-----------+----------+-----+----------+  ;;
;;  |  Drawing1  |  Layout1  |   Block1  |  Value1  | ... |  ValueN  |  ;;
;;  +------------+-----------+-----------+----------+-----+----------+  ;;
;;  |  Drawing1  |  Layout2  |   Block1  |  Value1  | ... |  ValueN  |  ;;
;;  +------------+-----------+-----------+----------+-----+----------+  ;;
;;  |  Drawing2  |  Layout1  |   Block2  |  Value1  | ... |  ValueN  |  ;;
;;  +------------+-----------+-----------+----------+-----+----------+  ;;
;;  |    ...     |    ...    |    ...    |    ...   | ... |    ...   |  ;;
;;  +------------+-----------+-----------+----------+-----+----------+  ;;
;;                                                                      ;;
;;  *Layout & Block Name columns are optional.                          ;;
;;                                                                      ;;
;;  -------------------------------------                               ;;
;;  Possible Warnings:                                                  ;;
;;  -------------------------------------                               ;;
;;  -  Without a block filter or block name column the code will        ;;
;;     update ALL attributed blocks with tags listed in the CSV         ;;
;;     headings.                                                        ;;
;;                                                                      ;;
;;  -  Currently designed to run on startup - add to either             ;;
;;     Startup-Suite or ACADDOC.lsp to update blocks when drawing is    ;;
;;     opened. To disable code running when loaded, remove (c:utb)      ;;
;;     from the bottom of the code.                                     ;;
;;                                                                      ;;
;;----------------------------------------------------------------------;;
;;  Author:  Lee Mac, Copyright © 2011  -  www.lee-mac.com              ;;
;;----------------------------------------------------------------------;;
;;  Version 1.0    -    2011-01-12                                      ;;
;;                                                                      ;;
;;  - First release.                                                    ;;
;;----------------------------------------------------------------------;;
;;  Version 1.1    -    2011-01-13                                      ;;
;;                                                                      ;;
;;  - Added optional 'Layout' column (next to DWG Column) to allow      ;;
;;    multiple titleblocks to be updated with different information     ;;
;;    within a single drawing.                                          ;;
;;----------------------------------------------------------------------;;
;;  Version 1.2    -    2011-08-28                                      ;;
;;                                                                      ;;
;;  - Removed case-sensitivity of drawing file column in CSV.           ;;
;;----------------------------------------------------------------------;;
;;  Version 1.3    -    2011-12-27                                      ;;
;;                                                                      ;;
;;  - Revised the code to correctly process CSV files generated using   ;;
;;    OpenOffice software.                                              ;;
;;----------------------------------------------------------------------;;
;;  Version 1.4    -    2012-01-16                                      ;;
;;                                                                      ;;
;;  - Updated the 'ReadCSV' local function to correctly read CSV cells  ;;
;;    containing commas and quotes.                                     ;;
;;----------------------------------------------------------------------;;
;;  Version 1.5    -    2012-09-19                                      ;;
;;                                                                      ;;
;;  - Updated CSV file parser function to account for the use of        ;;
;;    alternative cell delimiter characters in CSV file (such as a      ;;
;;    semi-colon).                                                      ;;
;;----------------------------------------------------------------------;;
;;  Version 1.6    -    2013-05-22                                      ;;
;;                                                                      ;;
;;  - Removed the need for file extension in first column of CSV file.  ;;
;;  - Updated CSV file parser function to correct bug.                  ;;
;;----------------------------------------------------------------------;;
;;  Version 1.7    -    2014-11-01                                      ;;
;;                                                                      ;;
;;  - Fixed bug causing filenames containing ASCII character 46 (point) ;;
;;    to not be found in the first column of the CSV file.              ;;
;;----------------------------------------------------------------------;;
;;  Version 1.8    -    2015-04-13                                      ;;
;;                                                                      ;;
;;  - Added support for duplicate attribute tags.                       ;;
;;  - Added support for optional 'Block Name' column in CSV file.       ;;
;;  - Added inclusion of anonymous block names to optional block name   ;;
;;    filter to enable dynamic block support.                           ;;
;;----------------------------------------------------------------------;;
;;  Version 1.9    -    2016-09-18                                      ;;
;;                                                                      ;;
;;  - Fixed implementation of block filter when processing attributed   ;;
;;    dynamic blocks.                                                   ;;
;;----------------------------------------------------------------------;;

(defun c:utb

    (
        /
        *error*
        ano
        bln bno
        csv
        ent
        flg fnb:fun
        inc
        lst
        sel str
        tag
        utb:blk utb:csv utb:ftr utb:lay
        val
    )

;;----------------------------------------------------------------------;;
;; Location of CSV Drawing List (set to nil for prompt)                 ;;
;;                                                                      ;;
;; If the CSV file resides in the same directory as the drawing, omit   ;;
;; the filepath from the location of the CSV file, and only include     ;;
;; the filename, e.g. "myfile.csv"                                      ;;
;;                                                                      ;;
;; If only a filename is specified, AutoCAD will first search the       ;;
;; working directory for this file before searching the Support Paths.  ;;
;;----------------------------------------------------------------------;;
 
    (setq utb:csv nil) ;; e.g. (setq utb:csv "C:/myfolder/myfile.csv")

;;----------------------------------------------------------------------;;
;; Block Filter (may use wildcards and may be nil)                      ;;
;;----------------------------------------------------------------------;;

    (setq utb:ftr nil)  ;; e.g. (setq utb:ftr "*BORDER")

;;----------------------------------------------------------------------;;
;; Layout Column (t or nil)                                             ;;
;;----------------------------------------------------------------------;;

    (setq utb:lay t)    ;; set to t if CSV file contains Layout Column

;;----------------------------------------------------------------------;;
;; Block Name Column (t or nil)                                         ;;
;;----------------------------------------------------------------------;;

    (setq utb:blk nil)  ;; set to t if CSV file contains Block Name Column

;;----------------------------------------------------------------------;;

    (defun *error* ( msg )
        (LM:endundo (LM:acdoc))
        (if (not (wcmatch (strcase msg t) "*break,*cancel*,*exit*"))
            (princ (strcat "\nError: " msg))
        )
        (princ)
    )

    (setq fnb:fun
        (lambda ( s )
            (if (wcmatch (strcase s t) "*.dwg,*.dxf,*.dwt,*.dws")
                (vl-filename-base s) s
            )
        )
    )
    (cond
        (   (not (setq sel (ssget "_X" (vl-list* '(0 . "INSERT") '(66 . 1) (if utb:ftr (list (cons 2 (strcat "`*U*," utb:ftr))))))))
            (princ "\nNo Attributed Blocks found in drawing.")
        )
        (   (and utb:csv (not (setq csv (findfile utb:csv))))
            (princ
                (strcat
                    "\n"
                    (vl-filename-base utb:csv)
                    (vl-filename-extension utb:csv)
                    " not found."
                )
            )
        )
        (   (and csv (/= ".CSV" (strcase (vl-filename-extension csv))))
            (princ "\nAttribute data file must be in CSV format.")
        )
        (   (not (or csv (setq csv (getfiled "Select CSV File" "" "csv" 16))))
            (princ "\n*Cancel*")
        )
        (   (not (setq lst (mapcar '(lambda ( x ) (cons (strcase (fnb:fun (car x))) (cdr x))) (LM:readcsv csv))))
            (princ
                (strcat
                    "\nNo data found in "
                    (vl-filename-base csv)
                    ".csv file."
                )
            )
        )
        (   (not
                (setq tag (mapcar 'strcase (cdar lst))
                      lst (LM:massoc (strcase (fnb:fun (getvar 'dwgname))) lst)
                )
            )
            (princ (strcat "\n" (fnb:fun (getvar 'dwgname)) " not found in first column of CSV file."))
        )
        (   t
            (setq lst (mapcar '(lambda ( x ) (mapcar 'cons tag x)) lst)
                  ano 0
                  bno 0
            )
            (LM:startundo (LM:acdoc))
            (repeat (setq inc (sslength sel))
                (setq ent (ssname sel (setq inc (1- inc)))
                      bln (strcase (LM:al-effectivename ent))
                      val lst
                      flg nil
                )
                (if (or (null utb:ftr) (wcmatch bln (strcase utb:ftr)))
                    (progn
                        (if utb:lay
                            (setq val (mapcar '(lambda ( x ) (cons (strcase (cdar x)) (cdr x))) val)
                                  val (LM:massoc (strcase (cdr (assoc 410 (entget ent)))) val)
                            )
                        )
                        (if utb:blk
                            (setq val (mapcar '(lambda ( x ) (cons (strcase (cdar x)) (cdr x))) val)
                                  val (cdr (assoc bln val))
                            )
                            (setq val (car val))
                        )
                        (if val
                            (foreach att (vlax-invoke (vlax-ename->vla-object ent) 'getattributes)
                                (if
                                    (and
                                        (setq str (assoc (strcase (vla-get-tagstring att)) val))
                                        (progn
                                            (setq val (LM:remove1st str val))
                                            (/= (vla-get-textstring att) (cdr str))
                                        )
                                    )
                                    (progn
                                        (vla-put-textstring att (cdr str))
                                        (setq flg t
                                              ano (1+ ano)
                                        )
                                    )
                                )
                            )
                        )
                        (if flg (setq bno (1+ bno)))
                    )
                )
            )
            (if (zerop ano)
                (princ "\nAll attributes are up-to-date.")
                (princ
                    (strcat
                        "\n"           (itoa ano) " attribute" (if (= 1 ano) "" "s")
                        " updated in " (itoa bno) " block"     (if (= 1 bno) "" "s") "."
                    )
                )
            )
            (LM:endundo (LM:acdoc))
        )
    )
    (princ)
)

;; Effective Block Name  -  Lee Mac
;; ent - [ent] Block Reference entity

(defun LM:al-effectivename ( ent / blk rep )
    (if (wcmatch (setq blk (cdr (assoc 2 (entget ent)))) "`**")
        (if
            (and
                (setq rep
                    (cdadr
                        (assoc -3
                            (entget
                                (cdr
                                    (assoc 330
                                        (entget
                                            (tblobjname "block" blk)
                                        )
                                    )
                                )
                               '("AcDbBlockRepBTag")
                            )
                        )
                    )
                )
                (setq rep (handent (cdr (assoc 1005 rep))))
            )
            (setq blk (cdr (assoc 2 (entget rep))))
        )
    )
    blk
)

;; Read CSV  -  Lee Mac
;; Parses a CSV file into a matrix list of cell values.
;; csv - [str] filename of CSV file to read
 
(defun LM:readcsv ( csv / des lst sep str )
    (if (setq des (open csv "r"))
        (progn
            (setq sep (cond ((vl-registry-read "HKEY_CURRENT_USER\\Control Panel\\International" "sList")) (",")))
            (while (setq str (read-line des))
                (setq lst (cons (LM:csv->lst str sep 0) lst))
            )
            (close des)
        )
    )
    (reverse lst)
)

;; CSV -> List  -  Lee Mac
;; Parses a line from a CSV file into a list of cell values.
;; str - [str] string read from CSV file
;; sep - [str] CSV separator token
;; pos - [int] initial position index (always zero)
 
(defun LM:csv->lst ( str sep pos / s )
    (cond
        (   (not (setq pos (vl-string-search sep str pos)))
            (if (wcmatch str "\"*\"")
                (list (LM:csv-replacequotes (substr str 2 (- (strlen str) 2))))
                (list str)
            )
        )
        (   (or (wcmatch (setq s (substr str 1 pos)) "\"*[~\"]")
                (and (wcmatch s "~*[~\"]*") (= 1 (logand 1 pos)))
            )
            (LM:csv->lst str sep (+ pos 2))
        )
        (   (wcmatch s "\"*\"")
            (cons
                (LM:csv-replacequotes (substr str 2 (- pos 2)))
                (LM:csv->lst (substr str (+ pos 2)) sep 0)
            )
        )
        (   (cons s (LM:csv->lst (substr str (+ pos 2)) sep 0)))
    )
)

(defun LM:csv-replacequotes ( str / pos )
    (setq pos 0)
    (while (setq pos (vl-string-search  "\"\"" str pos))
        (setq str (vl-string-subst "\"" "\"\"" str pos)
              pos (1+ pos)
        )
    )
    str
)

;; MAssoc  -  Lee Mac
;; Returns all associations of a key in an association list

(defun LM:massoc ( key lst / item )
    (if (setq item (assoc key lst))
        (cons (cdr item) (LM:massoc key (cdr (member item lst))))
    )
)

;; Remove 1st  -  Lee Mac
;; Removes the first occurrence of an item from a list

(defun LM:remove1st ( itm lst / f )
    (setq f equal)
    (vl-remove-if '(lambda ( a ) (if (f a itm) (setq f (lambda ( a b ) nil)))) lst)
)

;; Start Undo  -  Lee Mac
;; Opens an Undo Group.

(defun LM:startundo ( doc )
    (LM:endundo doc)
    (vla-startundomark doc)
)

;; End Undo  -  Lee Mac
;; Closes an Undo Group.

(defun LM:endundo ( doc )
    (while (= 8 (logand 8 (getvar 'undoctl)))
        (vla-endundomark doc)
    )
)

;; Active Document  -  Lee Mac
;; Returns the VLA Active Document Object

(defun LM:acdoc nil
    (eval (list 'defun 'LM:acdoc 'nil (vla-get-activedocument (vlax-get-acad-object))))
    (LM:acdoc)
)

;;----------------------------------------------------------------------;;

(vl-load-com)
(princ
    (strcat
        "\n:: UpdateTitleblock.lsp | Version 1.9 | \\U+00A9 Lee Mac "
        (menucmd "m=$(edtime,0,yyyy)")
        " www.lee-mac.com ::"
        "\n:: Type \"utb\" to run manually ::\n"
    )
)
(princ)

;;----------------------------------------------------------------------;;

(c:utb) ;; Remove or comment this line to disable autorun

;;----------------------------------------------------------------------;;
;;                             End of File                              ;;
;;----------------------------------------------------------------------;;

If this was of any help please kudo and/or Accept as Solution
Kind Regards
0 Likes
Accepted solutions (2)
3,450 Views
13 Replies
Replies (13)
Message 2 of 14

paullimapa
Mentor
Mentor

CSV is a text file that can be read by any text editing programming including Lisp.  But XLS is especially formatted with Excel program codes.  This can only be read by Excel.  Is there a reason why you don't use Excel to save the file as CSV first and then use the Lisp function?

 

Area Object Link | Attribute Modifier | Dwg Setup | Feet-Inch Calculator
Layer Apps | List on Steroids | VP Zoom Scales | Exchange App Store


Paul Li
IT Specialist
@The Office
Apps & Publications | Video Demos
0 Likes
Message 3 of 14

DGRL
Advisor
Advisor

HI @paullimapa

 

Thanks for the reply

The reason why I want to read from XLS is because I use LDT setup when generating Isometrics.

I want to use the same file to insert the correct info for the layouts and P&ID's

 

 

If this was of any help please kudo and/or Accept as Solution
Kind Regards
0 Likes
Message 4 of 14

paullimapa
Mentor
Mentor

Since XLS is a proprietary Microsoft Excel format, you'll need a program like Excel or that has a license to read/view this kind of formatted file.

 

Area Object Link | Attribute Modifier | Dwg Setup | Feet-Inch Calculator
Layer Apps | List on Steroids | VP Zoom Scales | Exchange App Store


Paul Li
IT Specialist
@The Office
Apps & Publications | Video Demos
0 Likes
Message 5 of 14

lando7189
Advocate
Advocate

Could you upload an actual excel file you are using as well as a CSV text file that did work in the past?  I'm not sure if what i see in the Excel file from your initial post is reflective of what you are trying to accomplish.

 

There is a 'Get_Excel.lsp' file that i came across a couple of years ago that has a whole array of library functions... (included below for reference) ... its just a matter of incorporating these into your code.  Note:  You must have Microsoft Office's Excel installed for it to work.

 

 ;======================================================================================
 ; Get_Excel.lsp									
 ;======================================================================================
 ;  Rev.2013.01 - 01/30/13 Initial code written from program by Oleg Fattev		
 ;======================================================================================

 ; subroutine to read Excel Spreadsheet book and store in List_Excel			
 ;   reads each sheet and stores all data in whole_data variable			
 ; (FSC_Get_Excel FileName)								
 ; 	example - (XL_Get_App "My_Equipment.xls")					
 
(vl-load-com)

;; = MAIN Program to get excel data = ;;
(defun FSC_Get_Excel (XLfile / item path xlapp xlbook xlbooks xlcell xlrange xlsheet xlsheets)
  (setq whole_data nil)
  (setq xlapp (xlgetapp))
  (_set xlapp 'visible :vlax-false)
  (_set xlapp 'screenupdating :vlax-true)
  (_invoke xlapp (list 'volatile))
  ;|check if no Excel documents were open|;
  (if (xlhasbooks xlapp)
    ;| if one or more open then get active document|;
    (setq xlbook (xlgetactivebook xlapp))
    (progn
      ;| set path to file|;
      (setq Path (findfile XLfile))
      ;| get Workbooks collection|;
      (setq xlbooks (xlgetbooks xlapp))
      ;| open selected document|;
      (setq xlbook (xlopenbook xlbooks path))
      ;| activate this document (optional)|;
      (setq xlbook (xlgetactivebook xlapp))
    )
  )
  (_set xlapp 'screenupdating :vlax-true)
   ;| get Worksheets collection|;
  (setq xlsheets (xlgetsheets xlbook))
  ;| iterate through Worksheet objects and get used range value of|;
  ;(setq xlsheets (_get xlbook 'worksheets))
  ;;----------------------------------------------------------------------
  (vlax-for  xlsheet xlsheets
    ;|activate worksheet by selction|;
    (_invoke xlsheet (list 'select ))
    ;|activate worksheet to be sure|;
    (setq xlsheet (xlactivate xlsheet))
    ;|get used range of worksheet|;
    (setq xlrange (xlgetusedrange xlsheet))
    ;|add used range to common data list|;
    (setq whole_data (cons (cons (_get xlsheet 'name)(xlreadrange xlapp (xladdressof xlrange) nil nil nil)) whole_data))
  );;;
  (setq whole_data (reverse whole_data))
  ;| clean up and close Excel |;
  (xlshout xlapp :vlax-true)
  ;|we don't need to save document, so we can close it without saving|;
  (xlbookclose xlbook nil)
  ;|quit Excel application|;
  (xlquit xlapp)
  ;| clean up memory and relese objects we're using|;
  (xlcleanup  (list xlcell xlrange xlsheet xlsheets xlbook xlapp))
  (setq xlapp nil)
  whole_data
)

;; = Get major Excel version number from registry = ;;
(defun xlvernum  (/ childs root)
  (setq root "HKEY_CURRENT_USER\\Software\\Microsoft\\Office")
  (itoa (fix (apply 'max (mapcar 'atof (vl-registry-descendents root)))))
)

;; = Get major Excel version from registry = ;;
(defun xlver (/ childs root)
  (setq root "HKEY_CURRENT_USER\\Software\\Microsoft\\Office")
  (setq childs (vl-registry-descendents root))
  (strcat (strcat "excel.application." (itoa (fix (apply 'max (mapcar 'atof childs))))))
)

;; = Get Excel application object = ;;
(defun xlgetapp (/ xlapp)
  (cond
    (xlapp)
    ((setq xlapp (vlax-get-or-create-object (xlver))))
  )
)

;; = Check if Excel has open WorkBooks = ;;
(defun xlhasbooks (xlapp / winds)
  (and (not (vl-catch-all-error-p (setq winds (vl-catch-all-apply 'vlax-get-property (list xlapp 'windows)))))
       (> (vl-catch-all-apply 'vlax-get-property (list winds 'count)) 0)
  )
)

;; = Get Excel Workbooks object = ;;
(defun xlgetbooks (xlapp / xlbooks)
  (cond
    (xlbooks)
    ((setq xlbooks (vl-catch-all-apply 'vlax-get-property (list xlapp 'workBooks))))
  )
)

;; = open Excel document and return Workbook object = ;;
;;  if argument 'path' is ommited then open new Document
(defun xlopenbook (xlbooks path / xlbook)
  (cond
    (xlbook)
    ((if path
       (setq xlbook (vl-catch-all-apply 'vla-open (list xlbooks path)))
       (setq xlbook (vl-catch-all-apply 'vla-add  (list xlbooks))))
    )
  )
)

;; = Get Excel document and return Workbook object = ;;
(defun xlgetactivebook (xlapp / xlbook)
  (cond
    ((not (vl-catch-all-error-p (setq xlbook (vl-catch-all-apply 'vlax-get-property (list xlapp 'activeworkbook))))) xlbook)
    (nil)
  )
)

;; = Get Excel ActiveWorkbook object = ;;
(defun xlactivebook (xlapp / xlbook)
  (cond
    (xlbook)
    ((setq xlbook (vl-catch-all-apply 'vlax-get-property (list xlapp 'ActiveWorkbook))))
  )
)

;; = Add new Excel document and return Workbook object = ;;
(defun xladdbook (xlapp / xlbook)
  (cond
    (xlbook)
    ((setq xlbook (vl-catch-all-apply 'vlax-invoke-method (list (xlgetbooks xlapp) 'add))))
  )
)

;; = Get Excel Worksheets collection = ;;
(defun xlgetsheets (xlbook / xlsheets)
  (cond
    (xlsheets)
    ((setq xlsheets (vl-catch-all-apply 'vlax-get-property (list xlbook 'sheets))))
  )
)

;; = Get Workbook sheet names = ;;
(defun xlsheetnames (xlbook / sheetnames)
  (vlax-for xlsheet (xlgetsheets xlbook)
    (setq sheetnames (cons (_get xlsheet 'name) sheetnames))
  )
  (reverse sheetnames)
)

;; = Get Excel Worksheet object by index or name= ;;
(defun xlgetsheet (xlsheets indexorname / xlsheet)
  (cond
    (xlsheet)
    ((setq xlsheet (vl-catch-all-apply 'vlax-get-property (list xlsheets 'item indexorname))))
  )
)

;; = Get Excel Worksheets collection = ;;
(defun xlgetsheets (xlbook / xlsheets)
  (cond
    (xlsheets)
    ((setq xlsheets (vl-catch-all-apply 'vlax-get-property (list xlbook 'sheets))))
  )
)

;; = Add Excel Worksheet object = ;;
(defun xladdsheet (xlbook sheetname / xlsheet)
  (cond
    (xlsheet)
    ((setq xlsheet (vl-catch-all-apply 'vlax-invoke-method (list (xlgetsheets xlbook) 'add))))
  )
  (if sheetname
    (vl-catch-all-apply 'vlax-put-property (list xlsheet 'name sheetname))
  )
  xlsheet
)

;; = Get Columns collection = ;;
(defun xlgetcolumns (xlobj)
  (vl-catch-all-apply 'vlax-get-property (list xlobj 'columns))
)

;; = Get Rows collection = ;;
(defun xlgetrows (xlobj)
  (vl-catch-all-apply 'vlax-get-property (list xlobj 'rows))
)

;; = Get Cells collection = ;;
(defun xlgetcells (xlobj)
  (vl-catch-all-apply 'vlax-get-property (list xlobj 'cells))
)

;; = Save Excel document as = ;;
(defun xlbooksaveas (xlbook path)
  (vl-catch-all-apply 'vlax-invoke-method (list xlbook 'SaveAs path nil nil nil :vlax-false :vlax-false 1 2))
)

;; = Save Excel document  = ;;
(defun xlbooksave (xlbook )
  (vl-catch-all-apply 'vlax-invoke-method (list xlbook 'save))
)

;; = Close Excel document = ;;
(defun xlbookclose (xlbook save)
  (vl-catch-all-apply 'vlax-invoke-method (list xlbook 'close (if save :vlax-true)))
)

;; = Quit Excel = ;;
(defun xlquit (xlapp / )
  (gc)
  (vl-catch-all-apply 'vlax-invoke-method (list xlapp 'quit))
)

;; = Release objects and clean up memory usage = ;;
(defun xlcleanup( lstobjects)
  (and (mapcar '(lambda (x) (vl-catch-all-apply '(lambda () (vlax-release-object x)))) lstobjects)
       (repeat 3 (gc))
  )
)
;; = Select Excel range and return Selection object = ;;
(defun xlsetselection (xlapp xlrange / selrange)
  (and (vl-catch-all-apply 'vlax-invoke-method (list xlrange 'select))
       (setq selrange (vl-catch-all-apply 'vlax-get-property (list xlapp 'selection)))
  )
  selrange
)

;; = Get Excel Range object = ;;
(defun xlgetrange  (xlsheet address / xlrange)
  (cond
    (xlrange)
    ((setq xlrange (vl-catch-all-apply 'vlax-get-property (list (vl-catch-all-apply 'vlax-get-property (list xlsheet 'cells)) 'range (getaddress address)))))
  )
)

;; = Get Cell Range (overriden) = ;;
(defun xlsetcellrange (xlapp r1 c1 r2 c2 / xlrange)
  (cond
    (xlrange)
    ((setq xlrange (vlax-get-property xlapp 'range (vlax-get-property (vlax-get-property (vlax-get-property xlapp 'activesheet) 'cells) 'item (vlax-make-variant r1) (vlax-make-variant c1))
                   (vlax-get-property (vlax-get-property (vlax-get-property xlapp 'activesheet) 'cells) 'item (vlax-make-variant r2) (vlax-make-variant c2)))))
  )
)

;; = Detect if Range is a single column = ;;
(defun xliscolumn  (xlrange / cols rows)
  (and
    (and (not (vl-catch-all-error-p (setq cols (vl-catch-all-apply 'vlax-get-property (list xlrange 'columns)))))
         (= (vl-catch-all-apply 'vlax-get-property (list cols 'count)) 1)
    )
    (and (not (vl-catch-all-error-p (setq rows (vl-catch-all-apply 'vlax-get-property (list xlrange 'rows)))))
         (> (vl-catch-all-apply 'vlax-get-property (list rows 'count)) 1)
    )
  )
)

;; = Detect if Range is a single row = ;;
(defun xlisrow  (xlrange / rowcol cols)
  (and
    (and (not (vl-catch-all-error-p (setq rowcol (vl-catch-all-apply 'vlax-get-property (list xlrange 'rows)))))
         (= (vl-catch-all-apply 'vlax-get-property (list rowcol 'count)) 1)
    )
    (and (not (vl-catch-all-error-p (setq cols (vl-catch-all-apply 'vlax-get-property (list xlrange 'columns)))))
         (> (vl-catch-all-apply 'vlax-get-property (list cols 'count)) 1)
    )
  )
)

;; = Detect if Range is a union range = ;;
(defun xlisunion (xlrange / cols rowcol)
  (and
    (and (not (vl-catch-all-error-p (setq rowcol (vl-catch-all-apply 'vlax-get-property (list xlrange 'rows)))))
         (= (vl-catch-all-apply 'vlax-get-property (list rowcol 'count)) 1)
    )
    (and (not (vl-catch-all-error-p (setq cols (vl-catch-all-apply 'vlax-get-property (list xlrange 'columns)))))
         (= (vl-catch-all-apply 'vlax-get-property (list cols 'count)) 1)
    )
    (> (vl-catch-all-apply 'vlax-get-property (list xlrange 'count)) 1)
  )
)

;; = Detect if Range is a single cell = ;;
(defun xliscell (xlrange / )
  (and (xlisrow xlrange) (xliscolumn xlrange))
)

;; = Get UsedRange object = ;;
(defun xlgetusedrange (xlsheet / xlrange)
  (cond
    (xlrange)
    ((setq xlrange(vl-catch-all-apply 'vlax-get-property (list xlsheet 'usedrange))))
  )
)

;; = Get Item property = ;;
(defun xlitem (xlobj idx)
  (vlax-variant-value (vl-catch-all-apply 'vlax-get-property (list xlobj 'item idx)))
)

;; = Get Excel cell = ;;
(defun xlgetcell (xlrange row col)
  (vlax-variant-value (vl-catch-all-apply 'vlax-get-property (list (vl-catch-all-apply 'vlax-get-property (list xlrange 'cells)) 'item (vlax-make-variant row vlax-vblong) (vlax-make-variant col vlax-vblong))))
)

;; = Get Excel cell range by address= ;;    
;;  arguments:       
;;   xlsheet = active sheet     
;;   listRC = list sort of: (list 1 1); this means "A1" 
;;    or (list 1 1 1 1); this means "A1:A1")  
;;    or (list "A1" "A1"); this means "A1:A1") 
;;  NOTE: use this function for the single cell only  
(defun xlgetcellrange (xlsheet listRC)
  (cond
    (xlcell)
    ((setq cell(vl-catch-all-apply 'vlax-get-property (list (vl-catch-all-apply 'vlax-get-property (list xlsheet 'cells)) 'range (vlax-make-variant (getaddress listRC))))))
  )
)

;; = Get Excel cell by address= ;;
(defun xlgetcellbyref (xlrange address)
  (vlax-variant-value (vl-catch-all-apply 'vlax-get-property (list (vl-catch-all-apply 'vlax-get-property (list xlrange 'cells)) 'item (vlax-make-variant address))))
)

;; = Get Excel cell (slow method) = ;;
(defun xlevalcell (xlapp row col / cell cellref)
  (setq cellref
         (cond
           ((not row) nil)
           ((and row col) (getaddress (list row col)))
           ((and row (not col))(getaddress (list row)))
         )
  )
  (if (not cellref)
    nil
    (vlax-variant-value (vl-catch-all-apply 'vlax-invoke-method (list xlapp 'Evaluate cellref)))
  )
)

;; = Get Excel cell address = ;;
(defun xlgetcelladdress (xlcell)
  (list (vl-catch-all-apply 'vlax-get-property (list xlcell 'row))
        (vl-catch-all-apply 'vlax-get-property (list xlcell 'column))
  )
)

;; = Set Excel cell value = ;;
(defun xlsetcellvalue (xlcell xlval)
  (vl-catch-all-apply 'vlax-put-property (list xlcell 'value2 (vlax-make-variant xlval)))
)

;; = Get Excel cell value = ;;
(defun xlgetcellvalue (xlcell / xlval)
  (if (eq 'variant (type (setq xlval (vl-catch-all-apply 'vlax-get-property (list xlcell 'value2)))))
    (vlax-variant-value xlval)
    xlval
  )
)

;; = Set Excel cell text = ;;
(defun xlsetcelltext (xlcells row column text)
  (vl-catch-all-apply 'vlax-put-property (list xlcells 'Item row column (vlax-make-variant (vl-princ-to-string text) vlax-vbstring)))
)

;; = Get Excel range value = ;;
;;  simplified version      
;;  example usage:       
;;   (setq rng (xlreadrangebyref xlapp "A1:D200" nil) 
;;   or:       
;;   (setq rng (xlreadrangebyref xlapp "A1" "D200")  
;;   or:       
;;   (setq rng (xlreadrangebyref xlapp 1 1 4 200)  
(defun xlreadrangebyref (xlapp r1 c1  / vardata xlrange)
  (setq xlrange
         (cond
           ((and (not r1)(not c1))nil)
           ((not c1)(vlax-get-property xlapp 'range (vlax-make-variant r1)))
           (T (vlax-get-property xlapp 'range (vlax-make-variant r1) (vlax-make-variant c1)))
         )
  )
  (xlreadrange xlapp (xladdressof xlrange) nil nil nil)
)

;; = Get Excel range value = ;;
;;  extended version      
;; example usage:       
;;   (setq rng (xlreadrange xlapp "A1:D200" nil nil nil)) 
;;   or:       
;;   (setq rng (xlreadrange xlapp "A1" "D20" nil nil)) 
(defun xlreadrange (xlapp r1 c1 r2 c2 / cellrange rangevalue typval vardata xlrange)
  (setq xlrange
         (cond
           ((vl-every 'numberp (list r1 c1 r2 c2))
             (vlax-get-property xlapp 'range
               (vlax-get-property (vlax-get-property (vlax-get-property xlapp 'activesheet) 'cells) 'item (vlax-make-variant r1) (vlax-make-variant c1))
               (vlax-get-property (vlax-get-property (vlax-get-property xlapp 'activesheet) 'cells) 'item (vlax-make-variant r2) (vlax-make-variant c2))
             )
           )
           ((and r1 (not c1) (not r2) (not c2))
             (vlax-get-property xlapp 'range (vlax-make-variant r1))
           )
    ((and r1 c1 (not r2) (not c2))
             (vlax-get-property  xlapp 'range (vlax-make-variant r1) (vlax-make-variant c1))
           )
    (T nil)
  )
  )
  (if xlrange
    (setq rangevalue (vlax-variant-value (vlax-get-property xlrange 'value2)))
    (setq rangevalue nil)
  )
  (cond
    ((not rangevalue) (setq vardata nil))
    ((and rangevalue (not (xlisunion xlrange))(not (xliscolumn xlrange))(not (xliscell xlrange)))
      (setq typval (type rangevalue))
      (setq vardata
             (cond
               ((not rangevalue) nil)
               ((or (eq 'str typval)(eq 'real typval)(eq 'int typval)) rangevalue)
               ((eq 'variant  typval)(vlax-variant-value rangevalue))
               ((eq 'safearray typval)
                 (mapcar (function (lambda (x) (mapcar 'vlax-variant-value x))) (vlax-safearray->list rangevalue)))
             )
      )
    )
    ((or (xlisunion xlrange) (xliscolumn xlrange))
      (setq cellrange (_get xlrange 'cells))
      (vlax-for item xlrange
        (setq vardata (cons (xlreadrange xlapp (xladdressof item) nil nil nil) vardata))    ;for union range not sorted by order
      )
      (setq vardata (reverse vardata))
    )
    ((xliscell xlrange)
      (setq vardata (xlgetcellvalue xlrange))
    )
    (T (setq vardata nil))
  )  
  vardata
)
 
;; = Set Excel range value = ;;
;;;    optional:
;;;    (setq xlrange   (xlactivate xlrange))
;;;    (setq xlrange   (xlsetselection xlapp xlrange))
(defun xlsetrangevalue (xlrange valuelist / i n)
  (cond
    ((or (xliscolumn xlrange) (xlisunion xlrange))
      (setq i 0 n (length valuelist))
      (vlax-for item (vlax-get-property xlrange'cells)
        (vlax-put-property item 'value2 (vlax-make-variant (nth i valuelist)))
        (setq i (1+ i))
      )
    )
    ((xliscell xlrange)
      (_set xlrange 'wraptext :vlax-true)
      (xlsetcellvalue xlrange (xlwraptext valuelist))
    )
    (T
      (vl-catch-all-apply 'vlax-put-property (list xlrange 'value2 (listtovariant valuelist)))
    )
  )
)

;; = Get last cell in WorkSheet = ;;
(defun xlsheetlastcell (xlapp xlsheet / findrange lastcell lastrow rownum)
  (vl-catch-all-apply 'vlax-invoke-method (list xlapp 'volatile))
  (setq xlsheet (xlactivate xlsheet))
  (setq findrange (xlgetusedrange xlsheet))
  (setq rownum (vlax-get-property (vlax-get-property findrange 'rows) 'count))
  (setq lastrow (vlax-variant-value (vlax-get-property (vlax-get-property findrange 'rows) 'item rownum)))
  (setq lastcell (vlax-get-property lastRow 'end 2))
  lastcell
)

;; = Get last cell in any Range = ;;
(defun xlanylastcell (obj / lastcell)
  (cond
    (lastcell)
    ((setq lastcell (xlitem obj (vl-catch-all-apply 'vlax-get-property (list (vl-catch-all-apply 'vlax-get-property (list obj 'cells)) 'count)))))
  )
)

;; = Get last cell in the column range = ;;
(defun xlcolumnlastcell(xlapp colrange / colcells colnum lastcell rowcount)
  (vl-catch-all-apply 'vlax-invoke-method (list xlapp 'volatile))
  (setq rowcount (vl-catch-all-apply 'vlax-get-property (list (vlax-get-property colrange 'rows) 'count)))  
  (setq colcells (vl-catch-all-apply 'vlax-get-property (list (vlax-get-property colrange 'parent) 'cells)))
  (setq colnum   (vl-catch-all-apply 'vlax-get-property (list colrange 'column)))
  (setq lastcell (vlax-get-property (vlax-variant-value (vlax-get-property colcells 'item (vlax-make-variant rowcount 3) (vlax-make-variant colnum 3))) 'end (vlax-make-variant -4162 3))) ;<-- (-4162) xlUp
)

;; = Get first cell in the column range = ;;
(defun xlcolumnfirstcell (xlapp colrange / colcells colnum firstcell startcell)
  (vl-catch-all-apply 'vlax-invoke-method (list xlapp 'volatile))
  (setq colcells (vl-catch-all-apply 'vlax-get-property (list (vlax-get-property colrange 'parent) 'cells)))
  (setq colnum   (vl-catch-all-apply 'vlax-get-property (list colrange 'column)))\
  (setq startcell (vlax-variant-value (vlax-get-property colcells 'item (vlax-make-variant 1 3) (vlax-make-variant colnum 3))))
  (if (not (eq "" (vlax-variant-value (vl-catch-all-apply 'vlax-get-property (list startcell 'value2)))))
    (setq firstcell startcell)
    (setq firstcell (vl-catch-all-apply 'vlax-get-property (list startcell 'end (vlax-make-variant -4121 3))))  ;<-- (-4121) xlDown 
  )
  firstcell
)

;; = Get last cell in the row range = ;;
(defun xlrowlastcell (xlapp rowrange / colcount lastcell rowcells rownum)
  (vl-catch-all-apply 'vlax-invoke-method (list xlapp 'volatile))
  (setq colcount (vl-catch-all-apply 'vlax-get-property (list (vlax-get-property rowrange 'columns) 'count)))
  (setq rowcells (vl-catch-all-apply 'vlax-get-property (list (vlax-get-property rowrange 'parent) 'cells)))
  (setq rownum   (vl-catch-all-apply 'vlax-get-property (list rowrange 'row)))
  (setq lastcell (vlax-get-property (vlax-variant-value (vlax-get-property rowcells 'item (vlax-make-variant rownum 3) (vlax-make-variant colcount 3))) 'end (vlax-make-variant -4159 3))) ;<-- (-4159) xlLeft 
)

;; = Get first cell in the row range = ;;
(defun xlrowfirstcell(xlapp xlrowrange / rowcells rownum firstcell startcell)
  (vl-catch-all-apply 'vlax-invoke-method (list xlapp 'volatile))
  (setq rowcells (vl-catch-all-apply 'vlax-get-property (list (vlax-get-property xlrowrange 'parent) 'cells)))
  (setq rownum   (vl-catch-all-apply 'vlax-get-property (list xlrowrange 'row)))
  (setq startcell (vlax-variant-value (vlax-get-property rowcells 'item (vlax-make-variant rownum 3) (vlax-make-variant 1 3))))
  (if (not (eq "" (vlax-variant-value (vl-catch-all-apply 'vlax-get-property (list startcell 'value2)))))
    (setq firstcell startcell)
    (setq firstcell (vl-catch-all-apply 'vlax-get-property (list startcell 'end (vlax-make-variant -4159 3))))  ;<-- (-4152) xlRight 
  )
  firstcell
)

;; = Allow or discard Excel alert messages = ;;
(defun xlshout (xlapp bool)
  (vl-catch-all-apply 'vlax-put-property (list xlapp 'displayalerts bool))
)

;; = Activate then return active object = ;;
(defun xlactivate (xlobj)
  (if (vlax-method-applicable-p xlobj 'activate)
    (vl-catch-all-apply 'vlax-invoke-method (list xlobj 'activate))
    xlobj
  )
)

;; = Apply grid lines to Range borders = ;;
(defun xlsetgridlines  (xlrange)
  (vl-catch-all-apply 'vlax-put-property (list (vl-catch-all-apply 'vlax-get-property (list xlrange 'borders)) 'lineStyle (vlax-make-variant 1 3)))
)

;; = Set Range NumberFormat = ;;
;;  see allowed formats in the Excel document, most used "general", "@","#","#0.01","#0.001" etc...
(defun xlsetrangeformat (xlrange format)
  (if (vl-catch-all-error-p (vl-catch-all-apply 'vlax-put-property (list xlrange 'NumberFormat (vlax-make-variant (vl-princ-to-string format) 8))))
    (vl-catch-all-apply 'vlax-put-property (list xlrange 'NumberFormat (vlax-make-variant "@" 8)))  ;<-- on error set text format
  )
)

;; = Set Range Alignment = ;;
(defun xlsetalignment(xlrange ha va)
  (if (not (vl-position va (list -4107 -4108 -4117 -4130 -4160))) ; allowed values
    (setq va -4108)
  )
  (if (not (vl-position ha (list -4108 7 -4117 5 1 -4130 -4131 -4152)))	; allowed values
    (setq ha -4108)
  )
  (vl-catch-all-apply 'vlax-put-property (list xlrange 'horizontalalignment (vlax-make-variant ha 3)))
  (vl-catch-all-apply 'vlax-put-property (list xlrange 'verticalAlignment (vlax-make-variant va 3)))
)

;; = Set Range Font properties = ;;
;;  see about colors for more (56 Excel Colors):
;;  http://dmcritchie.mvps.org/excel/colors.htm
(defun xlsetrangefont (xlapp xlrange fontname fontsize fontcolor isbold isitalic / xlfont)
  (setq xlrange (xlactivate xlrange))
  (setq xlrange (xlsetselection xlapp xlrange))
  (setq xlfont (vl-catch-all-apply 'vlax-get-property(list xlrange 'font)))
  (vl-catch-all-apply 'vlax-put-property (list xlfont 'name (vlax-make-variant fontname)))
  (vl-catch-all-apply 'vlax-put-property (list xlfont 'size (vlax-make-variant fontsize)))
  (vl-catch-all-apply 'vlax-put-property (list xlfont 'bold (vlax-make-variant isbold 11)))
  (vl-catch-all-apply 'vlax-put-property (list xlfont 'iItalic (vlax-make-variant isitalic 11)))
  (if (or (<= 0 fontcolor 56))
    (vl-catch-all-apply 'vlax-put-property (list xlfont 'colorindex (vlax-make-variant fontcolor)))
  )
)

;; = Set Range Background color = ;;
;; see about colors for more (56 Excel Colors):
;; http://dmcritchie.mvps.org/excel/colors.htm
(defun xlsetrangebgcolor (xlapp xlrange bgcolor / xlinter )
  (setq xlrange (xlactivate xlrange))
  (setq xlrange (xlsetselection xlapp xlrange))
  (setq xlinter (vl-catch-all-apply 'vlax-get-property(list xlrange 'interior)))
  (if (or (<= 0 bgcolor 56))
    (vl-catch-all-apply 'vlax-put-property (list xlinter 'colorindex (vlax-make-variant bgcolor)))
  )
)

;; = Write data to column by specifying the first cell = ;;
(defun xlwritecolumnfrom  (xlsheet xlcell valuelist / r1 c1 r2 c2 xlrange)
  (setq r1 (_get xlcell 'row)
        c1 (_get xlcell 'column)
        r2 (+ r1 (1- (length valuelist)))
        c2 c1
  )
  (setq xlrange (xlgetrange xlsheet (list r1 c1 r2 c2)))
  (xlsetrangevalue xlrange valuelist)
  xlrange
)
       
;; = Write data to row by specifying the first cell = ;;
(defun xlwriterowfrom  (xlsheet xlcell valuelist / r1 c1 r2 c2 xlrange)
  (setq r1 (_get xlcell 'row)
        c1 (_get xlcell 'column)
        r2 r1
        c2 (+ c1 (1- (length valuelist)))
  )
  (setq xlrange (xlgetrange xlsheet (list r1 c1 r2 c2)))
  (xlsetrangevalue xlrange valuelist)
  xlrange
)

;; = Write data to a cell range by specifying the first cell = ;;
(defun xlwriterangefrom  (xlsheet xlcell valuelist / r1 c1 r2 c2 xlrange)
  (setq r1 (_get xlcell 'row)
        c1 (_get xlcell 'column)
        r2 (+ r1 (1- (length valuelist)))
        c2 (+ c1 (1- (length (car valuelist))))
  )
  (setq xlrange (xlgetrange xlsheet (list r1 c1 r2 c2)))
  (xlsetrangevalue xlrange valuelist)
  xlrange
)

;;=====================================auxiliary functions==============================================;;

;; = Get any object property = ;;
;;   without error trapping especially
;;;   arguments:
;;;    obj - any Excel object
;;;    pname - quoted property name
(defun _get(obj pname)
  (vl-catch-all-apply 'vlax-get-property (list obj pname))
)

;; = Set property value of any object = ;;
;;   without error trapping especially
;;;   arguments:
;;;    obj - any Excel object
;;;    pname is quoted property name
;;;   pvalue - value to set to
(defun _set(obj pname pvalue)
  (vl-catch-all-apply 'vlax-put-property (list obj pname (vlax-make-variant pvalue)))
)

;; = Invoke any methods = ;;
;; without error trapping especially for easy debug 
;;  arguments:
;;   params: list of parameters, eg: (list 'close :vlax-true) or (list 'select)
;;   usage, i.e.: (_invoke xlapp (list 'volatile))
(defun _invoke (obj params)
  (vl-catch-all-apply 'vlax-invoke-method (append (list obj )params))
)

;; = Convert list of string to multiline string = ;;
;;  use it just for Excel or Word documents
(defun xlwraptext (strlst / txtvalue)
  (setq txtvalue "")
  (while (cadr strlst)
    (setq txtvalue (strcat txtvalue (strcat (vl-princ-to-string (car strlst)) (chr 10) (chr 13))))
    (setq strlst (cdr strlst))
  )
  (setq txtvalue (strcat txtvalue (last strlst)))
  txtvalue
)

;; = Merge Cells then write multiline string from list = ;;
(defun xlmergecolumn (xapp xlrange txt_list / selrange )
  (setq txt_list (xlwraptext txt_list))
  (vl-catch-all-apply 'vlax-invoke-method (list xlrange 'Select))
  (setq selrange (vl-catch-all-apply 'vlax-get-property (list xapp 'Selection)))
  (mapcar '(lambda (prop value) (vl-catch-all-apply 'vlax-put-property (list selrange prop value)))
           (list 'HorizontalAlignment 'VerticalAlignment 'WrapText 'Orientation 'AddIndent 'IndentLevel 'ShrinkToFit 'ReadingOrder 'MergeCells 'Value2)
           (list -4143 -4108 :vlax-true 0 :vlax-false 0 :vlax-false -5102 :vlax-true txt_list)
  )
  selrange
)

;; = Merge Cells in row then write value = ;;
(defun xlmergerow (xapp xlrange txt /  selrange )
  (vl-catch-all-apply 'vlax-invoke-method (list xlrange 'Select))
  (setq selrange (vl-catch-all-apply 'vlax-get-property (list xapp 'Selection)))
  (mapcar '(lambda (prop value) (vl-catch-all-apply 'vlax-put-property (list selrange prop value)))
           (list 'HorizontalAlignment 'VerticalAlignment 'WrapText
  'Orientation 'AddIndent 'IndentLevel 'ShrinkToFit 'ReadingOrder
  'MergeCells 'Value2
        )

   (list -4108 -4108 :vlax-false 0 :vlax-false 0 :vlax-false -5102 :vlax-true txt)
  )
  selrange
)

;; = Merge Cells in the Range = ;;
(defun xlmergecells (xapp xlrange  /  selrange )
  (vl-catch-all-apply 'vlax-invoke-method (list xlrange 'Select))
  (setq selrange (vl-catch-all-apply 'vlax-get-property (list xapp 'Selection)))
  (vl-catch-all-apply 'vlax-put-property (list selrange 'MergeCells :vlax-true))
  selrange
)

;; = Perform Union method from list of row/column values = ;;
;; 	create then return complex range 
;; 	arguments: 
;; 		union_list = list like: (list '(1 2) '(2 3) '(3 4) '(4 5))etc.. 
;; 		support just less then 31 items in the list 
;; 		app = application
(defun xlapplyunion (app union_list / i rangelist  xlrange)
  (setq union_list (mapcar '(lambda (i) (getaddress i)) union_list))
  (setq rangelist (mapcar '(lambda (i) (xlgetrange app i)) union_list))
  (_set app 'screenupdating :vlax-true)
  (setq xlrange (vlax-invoke app 'union (car rangelist) (cadr rangelist)))
  (setq rangelist (cddr rangelist))
  (while rangelist
    (setq xlrange (vlax-invoke app 'union xlrange (car rangelist)))
    (setq rangelist (cdr rangelist))
  )
  xlrange
)

;; = Get combined Range from list of addresses = ;;
;; 	create then return combined range 
;; 	arguments: 
;; 		address_list = list like: (list '(1 2) '(2 3) '(3 4) '(4 5))
;; 		or (list "A5" B6 "E8" "F9:H20")..etc.
;; 		support just less then 31 items in the list 
;; 	xlsheet = active worksheet
(defun xlapplycombined (xlsheet address_list / address i xlrange)
  (setq address_list (mapcar '(lambda (i) (getaddress i)) address_list) address (lst2str address_list ";"))
  (setq xlrange (vl-catch-all-apply 'vlax-get-property (list (vl-catch-all-apply 'vlax-get-property (list  xlsheet 'cells)) 'range address)))
  xlrange
)

;; = Select Range on screen and return Range object = ;;
(defun xlgetreference (xlapp msg title / address c1 c2 r1 r2  xlrange)
  (vlax-put-property xlapp 'visible :vlax-true)
  (vlax-put-property xlapp 'screenupdating :vlax-true)
  (vlax-put-property xlapp 'displayalerts :vlax-false)
  (if (not (vl-catch-all-error-p (setq xlrange (vl-catch-all-apply (function (lambda () (vlax-variant-value (vlax-invoke-method (vlax-get-property (xlgetactivebook xlapp) 'application) 'Inputbox msg title nil nil nil nil nil 8))))))))
    (progn
      (vlax-put-property xlapp 'displayalerts :vlax-true)
      (setq r1 (vlax-get-property xlrange 'row))
      (setq c1 (vlax-get-property xlrange 'column))
      (setq r2 (vlax-get-property (vlax-get-property xlrange 'rows) 'count))
      (setq c2 (vlax-get-property (vlax-get-property xlrange 'columns) 'count))
      (setq address (strcat (chr (+ 64 c1)) (itoa r1) ":" (chr (+ (ascii (chr (+ 64 c1))) (1- c2))) (itoa (+ r1 (1- r2)))))
      (setq xlrange (vlax-get-property (_get xlapp 'activesheet) 'range address))
      (vlax-invoke xlrange 'select)
      (vlax-put-property xlapp 'displayalerts :vlax-false)
    )
  )
  (list xlrange address)
)

;; = Get range address in format R1C1 = ;;
(defun xladdressof (xlrange)
  ((lambda() T (vlax-get xlrange 'address)
  (vlax-get-property xlrange 'address nil nil 1)))
)

;; = Parse address to most Excel useable = ;;
;; 	arguments:                ;;
;; 	address - string (like "A1" or "A1:D10") or
;; 	list of two numbers like '(1 3)- return string "C1"
;; 	or like a list of four numbers '(13 14 15 16)- return string "N13:P15"
(defun getaddress (address / c1 c2 r1 r2)
  (cond
    ((listp address)
      (cond
        ((= 4 (length address))
          (setq r1 (nth 0 address) c1 (nth 1 address) r2 (nth 2 address) c2 (nth 3 address))
          (setq address (strcat (columnchar c1)(itoa r1)":"(columnchar c2)(itoa r2)))
        )
        ((= 2 (length address))
          (setq r1 (nth 0 address) c1 (nth 1 address))
          (setq address (strcat (columnchar c1)(itoa r1)))
        )
      )
    )
    ((or (wcmatch address "*@#*:*@#*") (wcmatch address "*@#*"))
      (setq address (strcase address))
    )
  )
)

;; = Parse address to most Excel useable = ;;
;;	usage:						
;;		(setq RC (xlgetRC "$A$1:$AO$141")	
;;;      	         firstCell (car RC)		
;;;      		 secondCell (cadr RC))		
(defun xlgetRC (address /)
  (list (substr ad 1 (vl-string-position (ascii ":") ad)) (substr ad (+ 2 (vl-string-position (ascii ":") ad))))
)

;; = return column name by given number = ;;
;; 	author VK (Vladimir Kleshev)
(defun columnchar (col / fst snd)
  (cond
    ((or (minusp col) (> col 256))
      nil
    )
    ((<= col 26)
      (chr (+ col 64))
    )
    (T
      (setq fst (rem col 26)
            snd (fix (/ col 26))
      )
      (if (zerop fst)
        (progn
          (setq fst 26
                snd (1- snd)
          )
        )
      )
      (strcat (chr (+ snd 64)) (chr (+ fst 64)))
    )
  )
)

;; = convert list to variant = ;;
;; 	extended version
;; 	agument lst = single list or list of lists like: 
;; 		("a" "b" "c" "d" "e" "f")
;; 		 or (("a" "b") ("c" "d") ("e" "f"))
;; 		 or ((1 2) (1.0 2.0) ("a" "b"))
(defun listtovariant (lst / sfar varvalue)
  (cond
    ((not (listp lst))( setq varvalue nil))
    ((and (listp lst)(not (listp (car lst))))
      (setq sfar (vlax-safearray-fill (vlax-make-safearray vlax-vbvariant (cons 0 (1- (length lst)))) lst))
      (setq varvalue (vlax-make-variant sfar))
    )
    ((and (listp lst)(listp (car lst)))
      (setq sfar (vlax-safearray-fill (vlax-make-safearray vlax-vbvariant (cons 0 (1- (length lst))) (cons 1 (length (car lst)))) lst))
      (setq varvalue (vlax-make-variant sfar))
    )
  )
  varvalue
)

;; = Convert delimited string to list = ;;
;;	usage: (str2lst "A1:A3;B1:B3;C1:C3" ";"); return '("A1:A3" "B1:B3" "C1:C3")
(defun str2lst (str sep / pos)
  (if (setq pos (vl-string-search sep str))
    (cons (substr str 1 pos) (str2lst (substr str (+ (strlen sep) pos 1)) sep))
    (list str)
  )
)

;; = Convert list to delimted string = ;;
;;;	usage: (lst2str (list "A1:A3" "B1:B3" "C1:C3") ";"); return "A1:A3;B1:B3;C1:C3"
(defun lst2str (lst sep)
  (if (cadr lst)
    (strcat (vl-princ-to-string (car lst)) sep (lst2str (cdr lst) sep))
    (vl-princ-to-string (car lst))
  )
)


;===============================================
; Here are some Excel constants: 		
;===============================================
; Alignment Constants        			
;===============================================
; Lisp     |   VBA       			
;===============================================
;  Vertical Alignment:       			
;===============================================
; -4107    | XlVAlignBottom			
; -4108    | XlVAlignCenter			
; -4117    | XlVAlignDistributed		
; -4130    | XlVAlignJustify			
; -4160    | XlVAlignTop			
;===============================================
;  Horizontal Alignment:			
;===============================================
; -4108    | XlHAlignCenter			
;     7    | XlHAlignCenterAcrossSelection	
; -4117    | XlHAlignDistributed		
;     5    | XlHAlignFill			
;     1    | XlHAlignGeneral			
; -4130    | XlHAlignJustify			
; -4131    | XlHAlignLeft			
; -4152    | XlHAlignRight			
;===============================================
; Excel Sort Constants				
;===============================================
; 1        | xlAscending (Order)		
; 2        | xlDescending (Order)		
; 1        | xlSortValues (Type)		
; 2        | xlSortLabels (Type)		
; 0        | xlGuess (Header)			
; 1        | xlYes (Header)			
; 2        | xlNo (Header)			
; 1        | xlSortColumns (Orientation)	
; 2        | xlSortRows (Orientation)		
; 1        | xlTopToBottom (OrderCustom)	
; 1        | xlPinYin (SortMethod)		
; 2        | xlStroke (SortMethod)		
; 0        | xlSortNormal (DataOption)		
; 1        | xlSortTextAsNumbers (DataOption)	
;===============================================


0 Likes
Message 6 of 14

DGRL
Advisor
Advisor

Hi @lando7189

 

Thanks for the reply and the code

The csv file I uploaded can be saved as xls and you have the file you need 🙂
|I will check the code to see if I can use it the way I want

 

Best regards,

 

If this was of any help please kudo and/or Accept as Solution
Kind Regards
0 Likes
Message 7 of 14

lando7189
Advocate
Advocate

Ah... my bad... i opened the CSV file in Excel (which put each line of text into the cells of the first column) as opposed to importing it (which separates the semi-colon values into separate columns).  The file is actually 'semi-colon' delimited so Excel didn't do the default operation of separating the values.

 

If you are familiar with AutoLISP, it should be pretty easy to adapt it to your code.  I won't have time over the next several days to try and work with it, but can have a go at it next week if needed. 

 

- Lanny

0 Likes
Message 8 of 14

DGRL
Advisor
Advisor

Hi @lando7189

 

My bad also i thought it was a correct file

See uploaded file to be the xls i want to work with

It is pretty straight forward to be honest

 

Sadly enough is my knowledge about xls and lisp to low to do the job.

 

If this was of any help please kudo and/or Accept as Solution
Kind Regards
0 Likes
Message 9 of 14

lando7189
Advocate
Advocate
Accepted solution

I found a bit of time to look at this... easier than i thought.  Attached are the 2 files -- the modified UTB command (UTB.lsp), as well as the Get_Excel.lsp.  I decided to keep the 'get_excel' utilities separate as its own file.

 

Download and load both files -- the UTB command will no longer have a 'CSV' file filter on it when prompted to select a file.  The command will allow CSV, XLS, and XLSX files.

 

Cheers!  - Lanny

Message 10 of 14

DGRL
Advisor
Advisor

Dear @lando7189

 

Thanks for this lisp

So far it seems to work the way I want

There is only 1 thing that I noticed


The date that is written in the xls ( 23-10-2017) is written in days (43031) in my template

Do you know What to change in order for the date to be written how it should?

 

Thanks for all the help 🙂
best regards,

 

 

If this was of any help please kudo and/or Accept as Solution
Kind Regards
Message 11 of 14

Edwin.Saez
Advisor
Advisor
Accepted solution

WRITE THE DATE OF THIS FORM  '23-10-2017

Edwin Saez


LinkedIn / AutoCAD Certified Professional


EESignature


 


Si mi respuesta fue una solución para usted, por favor seleccione "Aceptar Solución", para que también sirva a otro usuarios.

Message 12 of 14

lando7189
Advocate
Advocate

I modified the 'Get_Excel.lsp' file and added a "global switch":

 

(setq xl:UseTextOnGet T)

 

This switch when set to true (T), will use the read-only 'text' property instead of the 'value2' property.  This will use the 'formatted' value as shown in Excel instead of the 'behind the scenes' value.

 

The modified lisp file is attached.

0 Likes
Message 13 of 14

lando7189
Advocate
Advocate

Disregard my previous message... the 'text' property appears to only work from within Excel to display the contents as how they are currently shown.

0 Likes
Message 14 of 14

DGRL
Advisor
Advisor

@lando7189 

 

Back in 2017 you changed a lisp for me to read XLS and XLSX files. in the 2016 version of Autocad it worked. I recently changed to 2021 and office 2019 and now the lisp is giving me this error

 

"Error: bad argument type: stringp nil" 

 

Would you mind helping me to fix this? I spend already few hours debugging this but cant find the reason

Regards and thanks in advance

 

 

If this was of any help please kudo and/or Accept as Solution
Kind Regards
0 Likes