list printers - Scripting host example (OpenInsight 64-bit)
At 08 DEC 2020 01:21:45PM bob carten wrote:
I needed to enumerate the list of printers in OI10 without using OIPI. A WMI query is an easy way to get the collection of printers. WMI is an activex / COM interface. This proved to be a good example of using OpenInsight 10 embedded windows scripting host interface (RTI_AXSH). Read the RTI_AHSH_EQUATES for more information. Code example below.
function example_list_printers(printerList) /* * enumerate available printers using WMI plus rti activex scripting host interface (RTI_AXSH) * * printerList (out) = fm delinited list of available printers * * returns true on success * may affect set_status in non-eventcontext * * 12-08-20 rjc Created */ #pragma format_Indent_Comments Declare Function Get_Status, isEventContext Declare Subroutine Set_Status $Insert logical $Insert msg_equates $Insert rti_text_equates ; * defines crlf$ $insert rti_AXSH_Equates ; * methods for RTI_ASX ( rti active scripting host interface ) $Insert rti_ssp_equates ; * set_status / get_Status equates * Build a vbScript to enumerate the printers * See geekshangout.com/vbs-script-to-list-the-network-printers-a-user-is-connected-to/ script = 'Function getNetworkPrinters()' script := crlf$:'Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")' script := crlf$:'strPrinters = ""' script := crlf$: 'Set colPrinters = objWMIService.ExecQuery ("Select * From Win32_Printer")' script := crlf$:'If colPrinters.Count <> 0 Then' script := crlf$:' i = 0' script := crlf$:'' script := crlf$:' For Each objPrinterInstalled In colPrinters ' script := crlf$:' i = i+1' script := crlf$:'' script := crlf$:' If objPrinterInstalled.ServerName <> "" Then' script := crlf$:' strPrinters = strPrinters & objPrinterInstalled.ServerName & "\" & objPrinterInstalled.ShareName' script := crlf$:' else' script := crlf$:' strPrinters = strPrinters & objPrinterInstalled.Name' script := crlf$:' end if' script := crlf$:'' script := crlf$:' If i < colPrinters.Count Then' script := crlf$:' strPrinters = strPrinters & vbCrlf' script := crlf$:' end if' script := crlf$:'' script := crlf$:' Next' script := crlf$:'End if' script := crlf$:'' script := crlf$:'getNetworkPrinters = strPrinters' script := crlf$:'' script := crlf$:'End Function' isOk = true$ errorText = null$ printerList = null$ * Anything left over in get_status? * Assume it can be ignored - we should not have been called it there is already a real error hold_err = "" hold_status = Get_Status(hold_err) Set_Status(SETSTAT_OK$) * Create an instance of the scripting host, specify vbscript as the language createParam = "VBScript":@fm:"0":@FM:"":@FM:"-1" handle = rti_AXSH(REVAXSH_MTD_CREATE$, createParam) * Will set status on error If Get_Status(errorText) Then isOk = false$ end * Add the script If isOk Then * addcode will return true if script compiles, false on error If rti_axsh(REVAXSH_MTD_ADDCODE$, handle, script) Then rslt = rti_axsh(REVAXSH_MTD_RUNEX$, handle, 'getNetworkPrinters' ,'') End Else * retrieve error details using get_status isOk = false$ unused = Get_Status(errorText) end end * release the scripting host instance unused = rti_axsh(REVAXSH_MTD_DESTROY$, handle) If isOk Then Swap crlf$ With @fm In rslt transfer rslt To printerList End Else printerList = "" If isEventContext() Then Convert @fm To @vm In errorText def = '' def<mCaption$> = 'Error' def<mText$> = errorText def<mIcon$> = '!' Msg(@Window, def) Set_Status(setstat_Ok$) End end Return isOk
At 14 DEC 2020 08:40AM bob carten wrote:
BTW,
The above script is a nice example of using the embedded scripting host in OI10. However, unlike me, some developers are not captivated by puzzling out arcane details of the windows scripting host, WMI queries and so forth. If you just want the answer without worrying about how to get it, you might be interested in using a third party solution. For instance, the free SRPUtilities library will get you the same list if network printers. See
At 14 DEC 2020 10:00AM Donald Bakke wrote:
BTW,
The above script is a nice example of using the embedded scripting host in OI10. However, unlike me, some developers are not captivated by puzzling out arcane details of the windows scripting host, WMI queries and so forth. If you just want the answer without worrying about how to get it, you might be interested in using a third party solution. For instance, the free SRPUtilities library will get you the same list if network printers. See
Thanks for the shout-out, Bob. Just out of curiosity:
In broad strokes, what would it take to implement your solution in OI 9? ( I guess another way to put it is, "How does OI 10 differ from OI 9 when calling scripts?" ) For those who are interested in taking advantage of the Windows scripting host, where's a good place to learn this?
At 14 DEC 2020 02:16PM bob carten wrote:
what would it take to implement your solution in OI 9?Below is the same function in 9.
It uses the OLECreateInstance to instantiate the windows scripting host, then injects the script and runs it.
How does OI 10 differ from OI 9 when calling scripts?I think OI10 is a little cleaner. OI10 has a more structured interface, will manage the handles of the scripting host contexts for you. But the underlying capabilities are bounded by the scripting host itself, so 9 and 10 are similar.
For those who are interested in taking advantage of the Windows scripting host, where's a good place to learn this?There is a lot of information online.
https://www.codeproject.com/articles/1004/windows-script-host-chapter-7-built-in-wshand-vbsc
You can use VbScript or JavaScript in the thing. I tend to search on "do-something javascript", find an example on the web and translate it into a function in I can call from OI. Simple scripts translate directly into OI's OLE syntax, but complex scripts, or scripts involving deeply nested object references are easier to host in the scripting host. You can store the scripting host in a named common, inject a bunch of scripts and use it like a custom OLE dll. That is what I did for RTI_JSON and some of the DSBFS functionality.
Function Example_list_printers(void) Declare Subroutine Set_Status Declare Function Get_Status, IsEventContext $Insert msg_equates $Insert logical Equ crlf$ To \0D0A\ Equ setstat_ok$ To 0 script = 'Function getNetworkPrinters()' script := crlf$:'Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")' script := crlf$:'strPrinters = ""' script := crlf$: 'Set colPrinters = objWMIService.ExecQuery ("Select * From Win32_Printer")' script := crlf$:'If colPrinters.Count <> 0 Then' script := crlf$:' i = 0' script := crlf$:'' script := crlf$:' For Each objPrinterInstalled In colPrinters ' script := crlf$:' i = i+1' script := crlf$:'' script := crlf$:' If objPrinterInstalled.ServerName <> "" Then' script := crlf$:' strPrinters = strPrinters & objPrinterInstalled.ServerName & "\" & objPrinterInstalled.ShareName' script := crlf$:' else' script := crlf$:' strPrinters = strPrinters & objPrinterInstalled.Name' script := crlf$:' end if' script := crlf$:'' script := crlf$:' If i < colPrinters.Count Then' script := crlf$:' strPrinters = strPrinters & vbCrlf' script := crlf$:' end if' script := crlf$:'' script := crlf$:' Next' script := crlf$:'End if' script := crlf$:'' script := crlf$:'getNetworkPrinters = strPrinters' script := crlf$:'' script := crlf$:'End Function' isOk = true$ errorText = null$ printerList = null$ * Anything left over in get_status? * Assume it can be ignored - we should not have been called it there is already a real error hold_err = "" hold_status = Get_Status(hold_err) Set_Status(SETSTAT_OK$) /* ** 9.x version of scripting host below. ** I show the longhand and shorthand syntax for each step */ * Create an instance of the scripting host oScript = OLECreateInstance( 'MSScriptControl.ScriptControl') isOk = ( oleStatus() == 0 ) * specify vbscript as the language If isOk Then //OlePutProperty(oScript, 'Language', 'VBScript') oScript->Language = 'VBScript' isOk = ( oleStatus() == 0 ) end * Add the script * This is like using a <script> tag in a webpage * You can add entire libraries of scripts * Will set olestatus if there is an error in the script If isOk Then //x = OleCallMethod(oScript, 'AddCode', script) x = oScript->AddCode( script) isOk = ( olestatus() == 0 ) end * You can run scripts with the Eval method, but you must pass in an expression. * * myExpression = "Myfunction(":quote(myparam1):",":quote(myparam2)) * rslt = OleCallMethod(oscript, 'Eval', myExpression) * * In practice it is awkward to use Eval, for example to pass in text which contains quotes, or <idispatch> /* * Instead of Eval, get the handle to the codeObject. * This is like using scripts in the context of a web page. * It lets you use syntax like * rslt = ocode->myFunction(myparam1,myparam2) * which in turn allows you to pass parameters directly to the scripts. */ If isOk Then //oCode = oleGetProperty(oScript, 'CodeObject') oCode = oScript->CodeObject * Run the script //rslt = OleCallMethod(ocode, 'getNetworkPrinters') rslt = oCode->getNetworkPrinters() End If isOk Then Swap crlf$ With @fm In rslt transfer rslt To printerList End Else printerList = "" If isEventContext() Then Convert @fm To @vm In errorText def = '' def<mCaption$> = 'Error' def<mText$> = errorText def<mIcon$> = '!' Msg(@Window, def) Set_Status(setstat_Ok$) End End Return printerList
At 14 DEC 2020 02:22PM bshumsky wrote:
BTW,
The above script is a nice example of using the embedded scripting host in OI10. However, unlike me, some developers are not captivated by puzzling out arcane details of the windows scripting host, WMI queries and so forth. If you just want the answer without worrying about how to get it, you might be interested in using a third party solution. For instance, the free SRPUtilities library will get you the same list if network printers. See
Point of order - now that the Forum posts can be shown in descending order in a thread, your previous post is no longer necessarily "above".
Your annoyingly literal friend,
- Bryan Shumsky