How to get COM/Automation running under LispWorks
Well I spend quite a bunch of time with trying to understand how things have to work. I found quite a few bugs on my way which the excellent support of Xanalys fixed immediatly. So before anything else thanks (especially to Dave) for helping me so much. Before you start to get things going you may Before we can start our journey I suggest asking Xanalys for the sended patches. CL-USER 29 : 2 > (directory "*.fsl") (#P"p:/LispWorks/lib/4-2-0-0/private-patches/type-library-handle-parent-inte rfaces.fsl" #P"p:/LispWorks/lib/4-2-0-0/private-patches/find-dispatch-method-or-property -in-interface.fsl" #P"p:/LispWorks/lib/4-2-0-0/private-patches/com-handle-parent-interfaces.fsl " #P"p:/LispWorks/lib/4-2-0-0/private-patches/autoload-com-tools.fsl") This is the needed load.lisp file to get all this patches applied (let ((location (pathname-location *load-pathname*))) (flet ((load-one-private-patch (path sequence) (scm:require-private-patch (merge-pathnames path location) sequence))) ;; Example form to load a :system sequence patch from the file my-patch. ;; (load-one-private-patch "my-patch" :system) (load-one-private-patch "com-handle-parent-interfaces" :COM) (load-one-private-patch "type-library-handle-parent-interfaces" :AUTOMATION) (LOAD-ONE-PRIVATE-PATCH "find-dispatch-method-or-property-in-interface" :AUTOMATION) (LOAD-ONE-PRIVATE-PATCH "autoload-com-tools" :full) )) Now what I was going to do depended on the Scripting.FileSystemObject from the Windows Scripting Host an example using this look like this in VB or VBScript Private Sub Fun_1() Set fso = CreateObject("Scripting.FileSystemObject") Set Drive = fso.GetDrive("C:") MsgBox "On C: are " & Drive.FreeSpace / (1024# * 1024#) & " MB left" End Sub Or something else along this lines. This are the steps it took to get things going: - Search for the library which provided the needed functionality. (I have used ScriptingSpy and after applying the patch "autoload-com-tools" the Tools provided with LispWorks (See manual COM chapter 5)) - the needed functinality can be found in scrrun.dll - I copied this file to the working directory. than you have to rename it to scrrun.tlb (just informing that it should be treated as a :midl-type-library-file does not work) - Then I set-up a defsys-lisp file (in-package :cl-user) (require "com") (require "automation") (defsystem com-example () :members (("scrrun.tlb" :type :midl-type-library-file) "foo.lisp")) - you know can compile/load the system - I wrote some (not so useful ;-) Scripts (defvar *fso-object* nil) (defun initialize () (com:co-initialize) ; prior to any use (setf *fso-object* (com:create-object :progid "Scripting.FileSystemObject"))) (initialize) (defun com-test-1 () (let ((folder (com:call-dispatch-method (*fso-object* i-file-system get-folder) "c:\\"))) (capi:display-message "~A~%" (com:call-dispatch-method (folder i-folder type))))) (defun com-test-3 () (let ((folder (com:call-dispatch-method (*fso-object* file-system-object get-folder) "c:\\"))) (capi:display-message "~A~%" (com:call-dispatch-method (folder folder type))))) (defun com-test-2 () (let* ((file-name (capi:prompt-for-string "Give me a file name please"))) (capi:display-message "~A" (com:call-dispatch-method (*fso-object* i-file-system get-absolute-path-name) file-name)))) (defun com-test-4 () (let ((drive-list (com:call-dispatch-get-property (*fso-object* i-file-system drives)))) (flet ((disp-info (drive-letter free-space) (capi:display-message "~A has ~A GB free space left" drive-letter free-space))) (com:do-collection-items (drive drive-list) (when (com:call-dispatch-get-property (drive drive is-ready)) (disp-info (com:call-dispatch-get-property (drive i-drive drive-letter)) (float (/ (com:call-dispatch-get-property (drive i-drive free-space)) (* 1024 1024 1024))))))))) com-test-1 is how things have to be handeled without the patches com-test-3 shows how it got a bit easier with the patches applied. Remarks: This are my impressions about the COM stuff. - it seems to me as if I had to provide too much information on my own and the different com:call-dispatch functions make things not easier. As I understand the created COM Object does have all this information availabel (what interface it implements etc, nevertheless do I have to re-write it by myself. - The com:call-dispatch-stuff is IMHO too long winded. - the naming conventions differ between COM and Automation. If you use the tools provided with LispWorks you find the COM convention. which looks like this (com:define-com-method (i-drive get-drive-letter) ((this com::c-generic-class-factory) (pbstr-letter :out)) ;; Insert implementation here com:s_ok) You see get-drive-letter. If you are using the Automation stuff you do not have to use this name but the name without the get see e.g com-test-4 - the com:call-dispatch stuff reminds me of the send syntax from LispMachines. It's IMHO not very Lisp-ish the :send syntax was superseeded by the CLOS accessor functions which I think are much easier to understand. Suggestion (for discussion) - Wouldn't it make sense to handle COM or Automation Objects like CLOS Objects? - things would be much easier to write, read and understand e.g (defun com-test-1 () (let ((folder (com:call-dispatch-method (*fso-object* i-file-system get-folder) "c:\\"))) (capi:display-message "~A~%" (com:call-dispatch-method (folder i-folder type))))) would get (defun com-test-1-fictious() (let ((folder (get-folder *fso-object* "c:\\"))) (capi:display-message "~A~%" (type folder))))) Even in that simple example think the advantages are obvious, IMHO. I hope this mail will help someone else trying to get things going. Conclusion: Having the possibility to use COM Objects enhances the usefullness of LispWorks massively. It's was the "right" more IMHO. The easier the briding to the "outer-world" the better for people using Lisp. I do feel nevertheless that the API should been improved, that it's easier to use the available facilities. Again many thanks to the Xanalys Support Team. You have done a remarkable job. Regards Friedrich