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. :D
So thanks again for so much good work!

Regards, Little John
:D

Then that's a million dollars you owe me then! :wink:

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! :wink:
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! :wink: 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! :wink: 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