;                             DDE.LSP
;
;  ________________________________________________________________________
;  
;  (C) Copyright 1990-1993 by Autodesk, Inc.
;    by Phil Ford
;
;  Permission to use, copy, modify, and distribute this software and its
;  documentation for any purpose and without fee is hereby granted.  
;
;  THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. 
;  ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF 
;  MERCHANTABILITY ARE HEREBY DISCLAIMED.                                
;  ________________________________________________________________________
;
; 
;  DDE.LSP data between AutoCAD and a concurrently running spreadsheet
;  program using the Dynamic Data Exchange feature of Windows.
;  This program relies on the ADS program, DDELISP.EXE, to call Windows.
;
;
;---------------------------
;

;  Main AutoLISP commands:
;       c:send - send tables and drawing to DDE app
;       c:get - read data back in and modify any changed entities
;       sendset - send a selection set
;
;  Main DDE functions (implemented with ADS functions in DdeLisp.exe):
;       ddeprompt - Open channel to default app, put up dialog if failure.
;                   The DDE dialog saves values in windows\ddelisp.ini.
;       setddeformat -  AutoCAD Entity filters and layout
;           0 = all data, use entity names
;           1 = all data, use handles and not names
;           2 = decimal handle, handle, tag1, attr1; dec handle, 
;                               handle, tag2, attr2; ...
;                       each block insert on one row 
;           3 = same as 2 but without tags
;       senddrawing - sends tables, 5 blank lines, rest of drawing
;       moddrawing - imports data from DDE program and modifies
;               any drawing entities that have changed
;       pokealltbl - sends drawing table data to remote app
;       pokeall - sends drawing entities
;       pokeset - sends selection set
;       advise - set up warm link on last item sent
;       reqmod - requests data and modifies drawing entities
;               with the data, using a specified range (speed opt)
;       ddefree  - call after the DDE request data function
;               "request", to free the shared data transferred from 
;               a remote application.
;       ddedone - terminate all DDE channels and free memory

;  Main global variables:
;       chnl - DDE channel number  (32 allowed)
;       topic - work file (spreadsheet name)
;       item - DDE item (cell range description)
;       row1, col1 - start of spreadsheet data
;       rowcnt - sum of rows used by last drawing
;               transmission



;       Send all the tables and entities to the remote
;       DDE program (app) on the channel created by ddestart
;       using "senddrawing" function
(defun c:send ()
  (chkdde)                              ;Check open chnl, prompt user if not
  (unadvise chnl "")                    ;Clear hot link on last item sent
  (sendheading)
  (princ "\nSending drawing data...\n")
  (setq rowcnt (senddrawing row1))
  (advise chnl "" linkcommand)          ;Set up warm link on last 
                                        ;  item sent ("").  When new data comes
                                        ;  in, interrupt AutoCAD and request
                                        ;  the moddrawing function
  (princ "\nNumber of rows used by drawing: ")
  (princ rowcnt)
  (princ "\n")
  (princ)
)



;       Request data and modify drawing
(defun c:get ()
  (chkdde)                              ;Check open chnl, prompt user if not
  (setq en (entnext))                   ;get first entity name
  (princ "Receiving data and modifying drawing...\n")
  (if (= rowcnt 0)(setq rowcnt 18000))  ;to read in spreadsheet data when
                                        ;  we wrote it in a previous
                                        ;  session, we don't
                                        ;  know the number of rows.  Just
                                        ;  set high limit on read, so  
                                        ;  "moddrawing" will continue until 
                                        ;  end of spreadsheet data.
  (setq modcnt (moddrawing row1 rowcnt))
)


;       Send all the tables and then the entities to the remote
;       DDE program (app) on the channel created by ddestart,
;       using "pokealltbl" and "pokeall"
(defun sendall ()
  (chkdde)                              ;Check open chnl, prompt user if not
  ;Send all the tables
  (setq tabrows (lenalltbl))            ;in case you need the length before
                                        ;  you send them
  (setq row row1)
  (setq tblrows (pokealltbl chnl row col1)) ;send all the tables
  (setq row (+ row tblrows))            ;set row to end of drawing data in
                                        ;  the spreadsheet
  (setq row (+ row 5))                  ;leave blank lines
  (princ "Rows used by the tables: ")
  (princ tblrows)
  (princ "\n")

                                ;TABLE Definitions
                                ;VPORT 0
                                ;LTYPE 1
                                ;LAYER 2
                                ;STYLE 3
                                ;VIEW  4
                                ;UCS   5
                                ;BLOCK 6
                                ;DIMSTYLE 7

  (setq blkrows (lentbl 6))     ;6=BLOCK
  (princ "\nNumber of rows in blocks: ")
  (princ blkrows)
  (princ "\n")

                        ;Send a table individually--this is just a
                        ;  test.  We already sent all the tables,
                        ;  including the BLOCK table.
; (setq item (cellstr row col1 rowcnt 4))  ;from row, col, rows sent
;                                       ;  previously  (4 cols)
;  (setq rowcnt (poketbl chnl item 6))  ;send BLOCK table (6)
;                                       ;  to spreadsheet with DDE
;  (setq row (+ row rowcnt))
;  (setq row (+ row 1))
;  (princ "Rows used by the blocks: ")
;  (princ rowcnt)
;  (princ "\n")


  (princ "\nSending drawing data...\n")
  (setq en (entnext))                   ;get first entity name
  (setq rowcnt (pokeall chnl en row col1)) ;send whole drawing to remote
                                        ;  spreadsheet with DDE
  (princ "\nNumber of rows used by entities: ")
  (princ rowcnt)
  (princ "\n")

  (princ)
)


;       Send a selection set to a remote application, using
;       "pokeset"
(defun sendset ()
  (chkdde)                              ;Check open chnl, prompt user if not
  (sendheading)
  (setq frmt (getddeformat))
  (if (< frmt 2)
    (setq sset (ssget))                 ;get a selection set of all codes
    (setq sset (ssget "X" (list (cons 0 "ATTRIB"))))
                                        ;just attributes
  )
  (unadvise chnl "")                    ;Clear hot link on last item sent
  (setq rowcnt (pokeset chnl sset row1 col1)) ;send set to remote
                                        ;  spreadsheet with DDE
  (advise chnl "" linkcommand)          ;Set up warm link on last 
                                        ;  item sent ("").  When new data comes
                                        ;  in, interrupt AutoCAD and request
                                        ;  the moddrawing function
  (setq sset nil)
  (princ "Rows: ")
  (princ rowcnt)
  (princ)
)




;       Read DDE data (from DDE remote app)
;       starting at a certain row, and modify any entities
;       that have changed.  Allows
;       column 1 values of less than -4 for comments in
;       spreadsheet.  -1 is normal entity group code in column 1.
;       Demonstrates "reqmod" function.
(defun mod ()
  (chkdde)                              ;Check open chnl, prompt user if not
  (setq mrow1 (getint "\nStart row: "))
  (setq nrows (getint "\nNumber of rows: "))
  (setq item (cellstr mrow1 col1 nrows 4))      ;from row, col, rows sent
                                        ;  previously  (4 cols)
  (setq mrowcnt (reqmod chnl item))     ;request range of data, modify
                                        ;  entities that have changed
  (setq entcnt (modcount))
  (ddefree chnl)                        ;free shared data from remote app
  (princ "\nEntities modified: ")
  (princ entcnt)
  (princ "\n")
  (princ "Rows: ")
  (princ mrowcnt)
  (princ)
)


;       
;       
;               Slower versions, transfer entities one at a time
;       
;       

;       Send all the entities in the drawing to the remote app
;       one at a time.  Demonstates DDE functions
;       "poke", "request", "execute", and entity transfer function
;       "entpokecell"
(defun sendall2 ()                      ;Dynamic Data Exchange Sample
                                        ;  Usage
  (chkdde)                              ;Check open chnl, prompt user if not
  (setq cell (cellstr 1 1 1 1))         ;cell item "R1C1", row 1 col 1,
                                        ;  1 number of rows, 1 ncols

                ;Test DDE functions; poke, request, and execute
  (poke chnl cell  
    "AutoCAD / Excel Demo .25...............40.................60.................80") 
                                        ;poke-send data for the cell, check
                                        ;  string length abilities of system
  (setq data (request chnl cell))       ;request-get data from a cell
  (ddefree chnl)                        ;free request data (shared data from
                                        ;  remote app)
  (princ "Data from Spreadsheet: \n")
  (princ data)
  (princ "\n")
  (setq cell (cellstr 1 3 1 1))         ;cell item "R1C1", row 1 col 3
  (setq execstr "[SELECT(\"R1C1\")][FORMULA(\"AutoCAD Graphics Data\")]")
  (execute chnl execstr)


                        ;Send entities one by one
  (setq en (entnext))                   ;get first entity name
  (setq row row1 col col1)              ;start spread sheet in row 2, col 1
  (setq rowcnt 0)
  (while (not (null en))
    (setq rows (entpokecell chnl en row col))
    (setq rowcnt (+ rowcnt rows))
                                        ;fill cells with entity data list.
                                        ;  rows is the number of items
                                        ;  in list
    (setq row (+ row rows))             ;move down to bottom of that entity
                                        ;  in spreadsheet
    (setq en (entnext en))              ;get next entity name
    (princ "\nNext Available Row ")
    (princ row)
    (princ)
  )
                                        ;just a test--not necessary:
  (setq cell (cellstr row 1 1 1))       ;  create cell string, such as
                                        ;  "R1C1:R2C2", row col nrows ncols
  (poke chnl cell "-99")                ;comment to flag end of sheet
  (princ)
)


;       Send a selection set to remote app, one by one.
;       Demonstates use of entpokecell.
(defun sendset2 ()
  (chkdde)                              ;Check open chnl, prompt user if not
  (setq sset (ssget))                   ;get a selection set
  (setq idx 0)
  (setq en (ssname sset idx))           ;set en to first entity
  (setq row row1 col col1)              ;starting spreadsheet cell
  (setq rowcnt 0)
  (while (not (null en))
    (setq rows (entpokecell chnl en row col))   ;fill cells with entity data
                                        ;  list. rows is the number of items
                                        ;  in list
    (setq row (+ row rows))             ;move down to bottom of that entity
                                        ;  in spreadsheet
    (setq rowcnt (+ rowcnt rows))       
    (setq idx (+ idx 1))
    (setq en (ssname sset idx))         ;set en to idx'th entity
    (princ "\nRow ")
    (princ row)
    (princ)
  )
  (setq sset nil)
)


;       Input data from remote app on all the entities in the drawing,
;       and update any that have changed, with entmod.  Entities
;       are transferred in sections 100 rows each.
;       Demonstrates DDE function "reqmod".
(defun mod2 ()                          ;Dynamic Data Exchange Sample
                                        ;  Usage
  (chkdde)                              ;Check open chnl, prompt user if not
  (setq row row1 rows 0 modtot 0)       ;start at top of spreadsheet
  (setq rowtot 0)
  (while (< rowtot rowcnt)              ;while there are more rows to check
                                        ;  based on how many were sent
    (setq item (cellstr row col1 100 4)) ;read in 100 rows at a time
    (princ item)
    (princ " ")
    (setq rows (reqmod chnl item))      ;get data from spreadsheet, and
                                        ;  convert to entities
    (princ rows)
    (princ " ")
    (setq modcnt (modcount))            ;(modcount) gets the last
                                        ;  count value
    (setq modtot (+ modtot modcnt))     ;update modified count.
    (setq row (+ row rows))             ;move down to bottom of that entity
                                        ;  in spreadsheet
    (setq rowtot (+ rowtot rows))
    (princ "Row: ")
    (princ row)
    (princ "\n")
  )
  (princ "\nEntities modified: ")
  (princ modtot)
  (princ)
)


;       Make sure we have a DDE channel.  Create one if not.
(defun chkdde ()
  (setq chnl (getddechnl))              ;Ask ddelisp.exe if we have a DDE
                                        ;  channel open
  (if (= 0 chnl) (progn
    (setq chnl (ddeprompt))             ;Try to load app, open channel.  If
                                        ;  fail, put up dialog for app, 
                                        ;  topic, and command line.
    (if (= 0 chnl) (progn
      (princ "No DDE conversation open\n")
;      (quit)
      ) 
      (setglobals) 
      )
    )
  )
)


;       Re-init AutoLISP globals for each new drawing.
(defun setglobals ()
  (setq row1 3 col1 1 rowcnt 0 ddeflag T)
  (fprecision 4 0.01)                   ;Set transfer floating point
                                        ;  precision and fuzz
                                        ;  factor for compares
  (setvar "cmdecho" 0)
  ;(command "_handles" "_on")
  (sethandles)                          ;ADS/DDE function that checks and
                                        ;  sets handles on if they're off.
  (setddeformat 1)                      ;Use handles, not ent names. 
  (setq linkcommand "(moddrawing 3 20000) ")
                                        ;When hot link data comes in, 
                                        ;request row 3 through 20000
                                        ;(or less if spreadsheet has less
                                        ;rows)
  (princ "DDE.LSP and DDELISP.EXE loaded\n")
  (princ)
)

;       Send a title to the spreadsheet
(defun sendheading ()
  (setq cell (cellstr 1 2 1 1))         ;cell item row 1 col 2, 1 row, 1 col
                ;Test DDE functions; poke, request, and execute
  (poke chnl cell "AutoCAD Drawing Data") 
)

;       To enable (quit) function, to emulate C "break" or "return"
;(defun *error*(msg)                    ;silent quit from function
;  (prin1)
;)

;       Initialize when loading dde.lsp.
(if (null initiate) (progn              ;DDELISP.EXE not loaded.
  (xload "ddelisp")                     ;ADS program that contains the DDE
                                        ;  AutoLISP functions.
  )
)

(setq chnl (getddechnl))                ;Ask ddelisp.exe if we have a DDE
                                        ;  channel open
(setq app (getddeapp) topic (getddetopic)) 
(setglobals)


;<end of file>
