OneSpace Modeling: Inquiring the Windows default printer
There are many ways to skin this cat. Here are two particularly interesting approaches
to inquire the default system printer on a Windows system.
Using Lisp and OneSpace Drafting macros
If you
know that the Annotation module is always running when you need the
name of the default printer, here's a clever combination of Lisp and Annotator/OneSpace Drafting
macro code which does the job:
(defun default-printer-name()
(oli:sd-execute-annotator-function :fnc
"INQ_ENV 22 (DOCU_WRITE_LINE_TO_SD (DOCU_CSTRING_TO_LSTRING (INQ 303)))"))
Just one function call in Lisp, but boy, there's a lot going on behind the
scenes when you run this code:
-
sd-execute-annotator-function
sends a command string in OneSpace Drafting macro
syntax to the Annotator process which was started when the user
activated the Annotation module.
- The Annotator process parses and executes the command.
DOCU_WRITE_LINE_TO_SD
opens a connection to OneSpace Modeling and sends the result back, this time in
Lisp syntax (DOCU_CSTRING_TO_LSTRING
does the conversion). We fill
this string with the results of magic OSDD-style inquiries which
happen to return the default printer name.
- OneSpace Modeling receives the result from Annotator, parses and
converts it into a Lisp string object - which happens to be pretty
adequate for a printer name
Using Lisp and VBscript
This approach uses the same technique as in
MacroEnumerateDrives to integrate Lisp
and VBscript code. The external VBscript code inquires the system
data, and the Lisp code reads its output.
Here is the VBscript code:
' GetDefaultPrinter
defaultPrinter = ""
Set wmi = GetObject("winmgmts:\\.\root\CIMV2")
For Each obj in wmi.ExecQuery("SELECT * FROM Win32_Printer")
if obj.Default then
defaultPrinter = obj.Name
end if
Next
WScript.Echo(defaultPrinter)
I'm using
Windows Management Instrumentation to query the system for all installed
printers. Among those printers, I choose the one which has the "Default"
flag set.
Let's save this code into a file called
inqprinter.vbs
. The Lisp part
of the solution relies on the name of the file, and also assumes that it is in the
current directory.
(defun inq-default-printer()
(with-open-file (s "| cscript /nologo inqprinter.vbs")
(remove #\Return (read-line s nil))))
For two reasons, I recommend this approach over the combination of Lisp and OSDD macros:
- It will work even if Annotation is not running yet.
- It can be used to find out about all kinds of interesting
system characteristics even if Drafting/Annotator does not
happen to have the magic
INQ_ENV
for it.
The downside of the approach is that two files are required to do
the job. But wait - we can do better than that:
;; -*-Lisp-*-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Description: Inquire the Windows default printer
;; Author: Claus Brod
;; Language: Lisp
;;
;; (C) Copyright 2006 Claus Brod, all rights reserved
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
(in-package :clausbrod.de)
(use-package :oli)
(defun inq-default-printer(s)
(format s "defaultPrinter=\"\"
Set wmi=GetObject(\"winmgmts:\\\\.\\root\\CIMV2\")
For Each obj in wmi.ExecQuery(\"SELECT * FROM Win32_Printer\")
If obj.Default Then
defaultPrinter = obj.Name
End If
Next
WScript.Echo(defaultPrinter)"))
(defun execute-vbscript(scriptfunction)
(let ((tmpfile (format nil "~A.vbs" (oli:sd-gen-unique-filename (oli:sd-inq-temp-dir)))))
;; write temporary script file
(with-open-file (s tmpfile :direction :output)
(funcall scriptfunction s))
;; execute script file
(prog1
(with-open-file (s (format nil "| cscript /nologo ~A" tmpfile))
(let (l)
(loop while (setf l (read-line s nil)) collecting (remove #\Return l))))
(delete-file tmpfile))))
(print (first (execute-vbscript 'inq-default-printer)))
execute-vbscript
creates a temporary file, then calls a
scriptfunction
(in this particular case,
inq-default-printer
) which fills the temporary
file with VBscript instructions.
The temporary file is then executed via
cscript
, just like in the original
approach, and then removed when we no longer need it. Voilà, two
languages in just one file!
--
ClausBrod - 09 Dec 2005, updated 4 Jan 2006
And to prove how flexible this polyglot technique of integrating VBScript
and Lisp is, here's another variation - this time we're listing all
installed printers instead of just the default printer.
The only significant change is that the VBScript code
loops over all printers and prints all their names. The code which
writes the temporary script file and executes it is left unchanged.
;; -*-Lisp-*-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Description: Inquire all installed Windows printers
;; Author: Claus Brod
;; Language: Lisp
;;
;; (C) Copyright 2006 Claus Brod, all rights reserved
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
(in-package :clausbrod.de)
(use-package :oli)
(defun inq-all-printers(s)
(format s "Set wmi=GetObject(\"winmgmts:\\\\.\\root\\CIMV2\")
For Each obj in wmi.ExecQuery(\"SELECT * FROM Win32_Printer\")
WScript.Echo(obj.Name)
Next"))
(defun execute-vbscript(scriptfunction)
(let ((tmpfile (format nil "~A.vbs" (oli:sd-gen-unique-filename (oli:sd-inq-temp-dir)))))
;; write temporary script file
(with-open-file (s tmpfile :direction :output)
(funcall scriptfunction s))
;; execute script file
(prog1
(with-open-file (s (format nil "| cscript /nologo ~A" tmpfile))
(let (l)
(loop while (setf l (read-line s nil)) collecting (remove #\Return l))))
(delete-file tmpfile))))
(print (execute-vbscript 'inq-all-printers))
--
ClausBrod - 05 Jan 2006