CoCreate 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 CoCreate 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/CoCreate 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 CoCreate 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 CoCreate 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.
  • CoCreate 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 smile

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


When asked for a TWiki account, use your own or the default TWikiGuest account.

Revision: r1.11 - 24 Jul 2009 - 19:53 - ClausBrod
CoCreateModeling > OsdmMacros > MacroDefaultPrinter
Copyright © 1999-2024 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback