Page 15 of 39
Posted: Fri Oct 10, 2008 8:18 pm
by srod
Little John wrote:Hello srod,
I've just finished reading the "COMate.chm" file. It's very well written, good understandable and instructive. And it actually answered all my million dollar questions.

So thanks again for so much good work!
Regards, Little John
Then that's a million dollars you owe me then!

Posted: Fri Oct 10, 2008 8:18 pm
by Xombie
Well, I
suppose I can forgive y'all this one time. Funny thing is, I tried that. I think it's because I was trying different combinations of things to see what the procedure would take and I don't think I had the chr(34) plus the enclosed ' at the same time.
Thanks! I will now happily motor on about my business

You may continue with whatever irrelevant thing y'all were doing before ~_~
Posted: Fri Oct 10, 2008 8:37 pm
by Little John
srod wrote:Then that's a million dollars you owe me then!

Got me!

It's a pity that I can't hold my tongue sometimes.
Regards, Little John
Posted: Thu Oct 16, 2008 8:51 pm
by Little John
I've got another WMI demo for COMate; it enumerates the printers on the system.
I just used the demo file "Demo_MonitorInfo.pb" as template, and combined it with information from a
post on the German PB forum by scholly. Although I don't know too much about COM and WMI, it seems that with good information from these sources I managed to create a new demo for COMate.

It works fine
here (Windows XP Pro SP3), it would be good if someone with appropriate knowledge checks the code, though:
Code: Select all
IncludePath "..\..\"
XIncludeFile "COMate.pbi"
Procedure Get_Printers()
Protected objWMIService.COMateObject, printer.COMateObject
Protected colPrinter.COMateEnumObject
strComputer.s = "."
Net_I_Index$ = Str(Interface_Index)
objWMIService = COMate_GetObject("winmgmts:\\" + strComputer + "\root\cimv2", "")
If objWMIService
colPrinter = objWMIService\CreateEnumeration("ExecQuery('Select * FROM Win32_Printer')")
If colPrinter
printer = colPrinter\GetNextObject()
While printer
Debug "Name = " + printer\GetStringProperty("Name")
Debug "Attributes = " + Str(printer\GetIntegerProperty("Attributes"))
Debug "----------------------------------------------------------------"
printer\Release()
printer = colPrinter\GetNextObject()
Wend
colPrinter\Release()
EndIf
objWMIService\Release()
EndIf
EndProcedure
Get_Printers()
I learned another interesting point from the post mentioned above: We can use this code to check whether a printer is online or offline. Just run the code above with your printers switched off, and save the attribute values. When the printers are on, their attribute values have changed.
For instance, the above code returns the following output on my system:
Name = EPSON Stylus DX4000 Series
Attributes = 3660
Then I can use the following code to check the status of this printer:
Code: Select all
IncludePath "..\..\"
XIncludeFile "COMate.pbi"
Procedure.i Check_Printer (name.s, attributes_off)
Protected objWMIService.COMateObject, printer.COMateObject
Protected colPrinter.COMateEnumObject
Protected ret = -1 ; return vcalue is undefined in the beginning
strComputer.s = "."
Net_I_Index$ = Str(Interface_Index)
objWMIService = COMate_GetObject("winmgmts:\\" + strComputer + "\root\cimv2", "")
If objWMIService
colPrinter = objWMIService\CreateEnumeration("ExecQuery('Select * FROM Win32_Printer')")
If colPrinter
printer = colPrinter\GetNextObject()
While printer
If printer\GetStringProperty("Name") = name
If printer\GetIntegerProperty("Attributes") = attributes_off
ret = 0 ; offline
Else
ret = 1 ; online
EndIf
printer\Release()
Break
EndIf
printer = colPrinter\GetNextObject()
Wend
colPrinter\Release()
EndIf
objWMIService\Release()
EndIf
ProcedureReturn ret
EndProcedure
Debug Check_Printer("EPSON Stylus DX4000 Series", 3660)
Regards, Little John
Posted: Thu Oct 16, 2008 9:17 pm
by srod
Demo added for the next update!

Thanks.
I'd be wary of the 'check online' procedure though because any number of factors could alter the attributes property which would fool your procedure into thinking the printer is online etc. Perhaps there is a single bit which you can mask out which will notify us of whether the printer is online etc?
Posted: Fri Oct 17, 2008 10:27 am
by srod
New demo.
Have extended Little John's list-printers demo to list all printers + their supported paper types. Uses safe arrays.
Code: Select all
;/////////////////////////////////////////////////////////////////////////////////
;***COMate*** COM automation through iDispatch.
;*===========
;*
;*WMI demo - list printers and supported paper types.
;/////////////////////////////////////////////////////////////////////////////////
IncludePath "..\..\"
XIncludeFile "COMate.pbi"
XIncludeFile "VariantHelper_Include.pb"
Procedure Get_Printers()
Protected objWMIService.COMateObject, printer.COMateObject
Protected colPrinter.COMateEnumObject
Protected *var.variant, *varPaper.VARIANT
Protected *sa.SafeArray, i
strComputer.s = "."
objWMIService = COMate_GetObject("winmgmts:\\" + strComputer + "\root\cimv2", "")
If objWMIService
colPrinter = objWMIService\CreateEnumeration("ExecQuery('Select * FROM Win32_Printer')")
If colPrinter
printer = colPrinter\GetNextObject()
While printer
Debug "Name = " + printer\GetStringProperty("Name")
Debug "==========================================="
Debug "Supported paper types :"
*var = printer\GetVariantProperty("PrinterPaperNames")
If *var
If *var\vt <> #VT_NULL
*sa = *var\parray
For i = saLBound(*sa) To saUBound(*sa)
*varPaper = SA_VARIANT(*sa, i)
If *varPaper\vt <> #VT_BSTR
VariantChangeType_(*varPaper, *varPaper, 0, #VT_BSTR)
EndIf
Debug " " + PeekS(*varPaper\bstrVal, -1, #PB_Unicode)
Next
saFreeSafeArray(*sa) ;This will clear all variants within the safe array.
EndIf
VariantClear_(*var)
FreeMemory(*var)
EndIf
Debug "==========================================="
printer\Release()
printer = colPrinter\GetNextObject()
Wend
colPrinter\Release()
EndIf
objWMIService\Release()
EndIf
EndProcedure
Get_Printers()
Posted: Fri Oct 17, 2008 3:29 pm
by Little John
Hello srod,
when I run the new demo program (using PB 4.20 and COMate 1.1.7), I get an IMA on line 1301
Code: Select all
result = iDisp\Invoke(dispID, ?IID_NULL, #LOCALE_USER_DEFAULT, invokeType, dp, *ret, excep, @uiArgErr)
in COMate.pbi.
I have some virtual printers installed on my system. Maybe the IMA occurs because the program tries to ask for supported paper types for virtual printers? The only real printer that I have installed is "EPSON Stylus DX4000 Series". When I only look for supported paper types for this printer, then I don't get an IMA:
Code: Select all
If printer\GetStringProperty("Name") = "EPSON Stylus DX4000 Series"
Debug "Supported paper types :"
*var = printer\GetVariantProperty("PrinterPaperNames")
If *var
If *var\vt <> #VT_NULL
*sa = *var\parray
For i = saLBound(*sa) To saUBound(*sa)
*varPaper = SA_VARIANT(*sa, i)
If *varPaper\vt <> #VT_BSTR
VariantChangeType_(*varPaper, *varPaper, 0, #VT_BSTR)
EndIf
Debug " " + PeekS(*varPaper\bstrVal, -1, #PB_Unicode)
Next
saFreeSafeArray(*sa) ;This will clear all variants within the safe array.
EndIf
VariantClear_(*var)
FreeMemory(*var)
EndIf
Debug "==========================================="
EndIf
A wish for the next COMate release: Maybe you can add a search tab to "COMate.chm"?
Regards, Little John
Posted: Fri Oct 17, 2008 5:07 pm
by Little John
srod wrote:I'd be wary of the 'check online' procedure though because any number of factors could alter the attributes property which would fool your procedure into thinking the printer is online etc. Perhaps there is a single bit which you can mask out which will notify us of whether the printer is online etc?
Now I've found some information on the internet. According to
http://search.cpan.org/~wasx/Win32-Prin ... er/Enum.pm we have to check for
$0400, which is in conformance with my tests. So this is my new demo code:
Code: Select all
IncludePath "..\.."
XIncludeFile "COMate.pbi"
Procedure Get_Printers()
Protected objWMIService.COMateObject, printer.COMateObject
Protected colPrinter.COMateEnumObject
Protected name.s
strComputer.s = "."
objWMIService = COMate_GetObject("winmgmts:\" + strComputer + "\root\cimv2", "")
If objWMIService
colPrinter = objWMIService\CreateEnumeration("ExecQuery('Select * FROM Win32_Printer')")
If colPrinter
Debug "Printers"
Debug "-----------"
printer = colPrinter\GetNextObject()
While printer
name = printer\GetStringProperty("Name")
If printer\GetIntegerProperty("Attributes") & $0400
Debug name + " is offline"
Else
Debug name + " is online"
EndIf
printer\Release()
printer = colPrinter\GetNextObject()
Wend
colPrinter\Release()
EndIf
objWMIService\Release()
EndIf
EndProcedure
Get_Printers()
Here is also some interesting code concerning WMI and printers.
Regards, Little John
Posted: Fri Oct 17, 2008 5:37 pm
by Little John
There is a minor glitch in the demo program "Demo_MonitorInfo.pb"":
The procedure
Monitor_Info() does not return any value. So instead of
Procedure.s
it should read
Procedure
//edit:
Also the following line isn't needed there, is it?
Code: Select all
Net_I_Index$ = Str(Interface_Index)
Regards, Little John
Posted: Fri Oct 17, 2008 9:34 pm
by Little John
I've now translated the code from the above mentioned page to PureBasic. IMHO this is currently the most interesing COMate demo code regarding printers.
Code: Select all
; Source: <http://www.computerperformance.co.uk/vbscript/wmi_printer.htm>
; translated to PureBasic and adapted by Little John
; Sample VBScript to interrogate Printer properties with WMI
; Author Guy Thomas http://computerperformance.co.uk/
; Version 2.3 - December 2005
EnableExplicit
IncludePath "..\..\"
XIncludeFile "COMate.pbi"
Define.COMateObject objWMIService, objItem
Define.COMateEnumObject colItems
Define.s strComputer, msg
Define intPrinters
strComputer = "."
intPrinters = 1
objWMIService = COMate_GetObject("winmgmts:\\" + strComputer + "\root\cimv2", "")
If objWMIService
colItems = objWMIService\CreateEnumeration("ExecQuery('Select * FROM Win32_Printer')")
If colItems
objItem = colItems\GetNextObject()
While objItem
msg = "Printer Number " + Str(intPrinters) + ": " + objItem\GetStringProperty("Name") + #CR$
msg + "====================================" + #CR$
msg + "Availability: " + objItem\GetStringProperty("Availability") + #CR$
msg + "Description: " + objItem\GetStringProperty("Description") + #CR$
msg + "Printer: " + objItem\GetStringProperty("DeviceID") + #CR$
msg + "Driver Name: " + objItem\GetStringProperty("DriverName") + #CR$
msg + "Port Name: " + objItem\GetStringProperty("PortName") + #CR$
msg + "Printer State: " + objItem\GetStringProperty("PrinterState") + #CR$
msg + "Printer Status: " + objItem\GetStringProperty("PrinterStatus") + #CR$
msg + "PrintJobDataType: " + objItem\GetStringProperty("PrintJobDataType") + #CR$
msg + "Print Processor: " + objItem\GetStringProperty("PrintProcessor") + #CR$
msg + "Spool Enabled: " + objItem\GetStringProperty("SpoolEnabled") + #CR$
msg + "Separator File: " + objItem\GetStringProperty("SeparatorFile") + #CR$
msg + "Queued: " + objItem\GetStringProperty("Queued") + #CR$
msg + "Status: " + objItem\GetStringProperty("Status") + #CR$
msg + "StatusInfo: " + objItem\GetStringProperty("StatusInfo") + #CR$
msg + "Published: " + objItem\GetStringProperty("Published") + #CR$
msg + "Shared: " + objItem\GetStringProperty("Shared") + #CR$
msg + "ShareName: " + objItem\GetStringProperty("ShareName") + #CR$
msg + "Direct: " + objItem\GetStringProperty("Direct") + #CR$
msg + "Location: " + objItem\GetStringProperty("Location") + #CR$
msg + "Priority: " + objItem\GetStringProperty("Priority") + #CR$
msg + "Work Offline: " + objItem\GetStringProperty("WorkOffline") + #CR$
msg + "Horizontal Res: " + objItem\GetStringProperty("HorizontalResolution") + #CR$
msg + "Vertical Res: " + objItem\GetStringProperty("VerticalResolution")
MessageRequester("", msg)
intPrinters + 1
objItem\Release()
objItem = colItems\GetNextObject()
Wend
colItems\Release()
EndIf
objWMIService\Release()
EndIf
Regards, Little John
Posted: Fri Oct 17, 2008 11:36 pm
by srod
I disagree!!!

That is just a list of many of the available properties whilst the listing paper types shows how to drill down into a safe-array returned from one of the properties! Many WMI properties return such arrays!

If you use the WMI tool which is included with the COMate download you will be able to pull up examples of using just about every kind of WMI object! Very useful!
Anyhow I have a virtual printer installed (pdf) and this is listed fine with the paper types example which crashes for you! I've tested with PB 4.2 and 4.3 and it all works fine. Afraid that I cannot explain the crash.
**EDIT : can you try the WMI tool which is part of the COMate package and see if it crashes? Select the Win32_Printer class and then click run etc. Amongst other things this will list the paper types for each printer it finds. Let us see if this crashes.
Posted: Fri Oct 17, 2008 11:59 pm
by srod
A wish for the next COMate release: Maybe you can add a search tab to "COMate.chm"?
Done.
Posted: Sat Oct 18, 2008 2:01 pm
by Little John
Hello srod!
srod wrote:A wish for the next COMate release: Maybe you can add a search tab to "COMate.chm"?
Done.
Thank you!
"ScriptomaticV2.hta" only runs with administrator privileges here (on XP), and running the code for Win32_Printer class worked fine. Then I tried running your demo program also with administrator privileges, but it crashed as before -- so missing privileges obviously weren't the cause of the problem.
After some more testing, I discovered something strange:
Asking for the supported paper types only for a
single printer (like I did in
this post) works fine for
each printer on my system!
But when I do
without a narrowing condition such as
Code: Select all
If printer\GetStringProperty("Name") = "FreePDF XP"
because I want to examine all installed printers, then I get that IMA!

(using PB 4.20)
Regards, Little John
Posted: Sat Oct 18, 2008 5:26 pm
by srod
Very strange indeed.
I am presuming that the GetVariantProperty() line is the one invoking the COM method which is causing the problems. I would suspect that one of these virtual printer drivers is playing silly buggers!
**EDIT : when you ran the scripting utility under xp did it list the virtual printers okay? And if so what does it report for the paper types?
Posted: Sat Oct 18, 2008 8:16 pm
by Little John
srod wrote:**EDIT : when you ran the scripting utility under xp did it list the virtual printers okay? And if so what does it report for the paper types?
As far as I can see, Scriptomatic2 listed everything OK. All entries related to paper are of the same form for all virtual printers and for the real one as well, e.g.:
Caption: SnagIt 7
CurrentPaperType:
DefaultPaperType:
PaperSizesSupported: 7,8,1,22,11,1,1,1,1
PaperTypesAvailable:
PrinterPaperNames: Letter,Legal,Executive,A4,Umschlag 10,Umschlag DL,Umschlag C5,Umschlag B5,Umschlag Monarch
In other words, the entries
CurrentPaperType:
DefaultPaperType:
PaperTypesAvailable:
are empty for all printers. Is this a problem?
I can send you the complete output, if you like (long!)
Regards, Little John