VA 8 beta 1 -> Win2k -> No printer available

VA Smalltalk is a "100% VisualAge compatible" IDE that includes the original VisualAge technology and the popular VA Assist and WidgetKit add-ons.

Moderators: Eric Clayberg, wembley, tc, Diane Engles, solveig

VA 8 beta 1 -> Win2k -> No printer available

Postby klaus » Mon Dec 08, 2008 7:13 am

Hello,

our application runs with Windows 2000 service pack 4 and we need to get all installed printer names. With VA 7 it works fine, but VA8 does not find any installed printer. The change - maybe since VA 7.5 - is in #CgWinPrinterServer class -> #allPrinterScreenInfos. If I use the old VA 7 method, #allPrinterScreenInfos returns all installed printers. But works this old method with Windows XP and Vista?

Regards

Klaus
Klaus Breker
Currently working for clearstream (Deutsche Börse Group)
klaus
 
Posts: 38
Joined: Fri Nov 28, 2008 1:16 am
Location: Bonn

Re: VA 8 beta 1 -> Win2k -> No printer available

Postby tc » Tue Dec 09, 2008 12:36 pm

Can you post the method that works? The reason I ask is I went back through our cases and there was a change made in the 7.5/7.5.2 time period to handle the situation where the method would hang when looking for printers.

Thanks.

--tc
tc
Moderator
 
Posts: 304
Joined: Tue Oct 17, 2006 7:40 am
Location: Raleigh, NC

Re: VA 8 beta 1 -> Win2k -> No printer available

Postby klaus » Wed Dec 10, 2008 1:28 am

Hello tc,

I tested #CgWinPrinterServer class -> #allPrinterScreenInfos with Windows XP, Service Pack 3 and it didn't works too. #CgDisplay class -> #defaultPrinterDisplayName returns also no printer; not with Win2000 nor Win XP. What went wrong?

The working methods are from VA 7:
---------------
CgWinPrinterServer class -> #allPrinterScreenInfos
allPrinterScreenInfos
"Private - Answer a dictionary whose keys are the names of all available
print servers, and whose values are instance of CgPrinterScreenInfo."

| buf n deviceNames driverName currentPrinters updatedPrinters |

buf := String new: 8192. "Windows gives no indication if this buffer is too small to hold the query results, so make it big!"
n := OS
getProfileString: 'PrinterPorts' "$NON-NLS$"
lpszEntry: nil
lpszDefault: '' "$NON-NLS$"
lpszReturnBuffer: buf
cbReturnBuffer: buf size.
n = 0
ifTrue: [^Dictionary new].
deviceNames := (buf copyFrom: 1 to: n - 1) subStrings: 0 asCharacter.
currentPrinters := self printerScreenInfo.

updatedPrinters := Dictionary new.
deviceNames do: [:deviceName | | fields nameHeader |
n := OS
getProfileString: 'PrinterPorts' "$NON-NLS$"
lpszEntry: deviceName
lpszDefault: '' "$NON-NLS$"
lpszReturnBuffer: buf
cbReturnBuffer: buf size.
fields := (buf copyFrom: 1 to: n) subStrings: $,.
driverName := fields at: 1.
2 to: fields size by: 3 do: [:i|
| medium longName separator1Index separator2Index info |
medium := fields at: i.
longName := String new: deviceName size + driverName size + medium size + 2.
separator1Index := deviceName size + 1.
separator2Index := deviceName size + driverName size + 2.
longName
replaceFrom: 1 to: deviceName size with: deviceName;
at: separator1Index put: $,;
replaceFrom: separator1Index + 1 to: separator1Index + driverName size with: driverName;
at: separator2Index put: $,;
replaceFrom: separator2Index + 1 to: separator2Index + medium size with: medium.
info := currentPrinters at: longName ifAbsent: [
CgPrinterScreenInfo
driverName: driverName
deviceName: deviceName
outputMedium: medium
].
info notNil ifTrue: [updatedPrinters at: longName put: info]
]
].

self printerScreenInfo: updatedPrinters.

^updatedPrinters
-----------------------------------------------------------------------------
#CgDisplay class -> #defaultPrinterDisplayName
defaultPrinterDisplayName
"Answer a string specifying the name of the default print server.
A print server's name is passed to CwAppContext>>openDisplay:... to establish
a connection with that server.
Answer nil if there is no default print server."

| buf n fields |
buf := String new: 256.
n := OSCall new
getProfileString: 'Windows' "$NON-NLS$"
lpszEntry: 'device' "$NON-NLS$"
lpszDefault: '' "$NON-NLS$"
lpszReturnBuffer: buf
cbReturnBuffer: buf size.
n <= 0
ifTrue: [^nil].
(buf occurrencesOf: $,) < 2
ifTrue: [^nil].

^buf copyFrom: 1 to: n
---------------------------------------------------------------------------

Regards

Klaus
Klaus Breker
Currently working for clearstream (Deutsche Börse Group)
klaus
 
Posts: 38
Joined: Fri Nov 28, 2008 1:16 am
Location: Bonn

Re: VA 8 beta 1 -> Win2k -> No printer available

Postby marten » Wed Dec 10, 2008 4:03 am

klaus wrote:Hello tc,

I tested #CgWinPrinterServer class -> #allPrinterScreenInfos with Windows XP, Service Pack 3 and it didn't works too. #CgDisplay class -> #defaultPrinterDisplayName returns also no printer; not with Win2000 nor Win XP. What went wrong?



Some errors are in the V8 code. Exchange the start of the method "CgDisplay>>defaultPrinterDisplayName" with:

defaultPrinterDisplayName

Code: Select all
      rc := OS
            getDefaultPrinter: (pszBuffer := OSStringZ new: 256)
            pcchBuffer: ((pcchBuffer := OSUInt32 new) uint32At: 0 put: 256 ; yourself ).
               ....
      rc ifFalse: [^nil].
               ....



The problem with the original code is, that

((pcchBuffer := OSUInt32 new) uint32At: 0 put: pszBuffer size)

returns NOT pcchBuffer, but the result of pszBuffer size - which is 0 and therefore a NULL pointer is given to the API call. pszBuffer size is 0 because the instance of OSStringZ contains an empty string before the API call.

Marten
Marten Feldtmann, Principal Smalltalk User, Private
SkypeMe callto://marten.feldtmann
marten
[|]
 
Posts: 641
Joined: Sat Oct 14, 2006 7:10 am
Location: Hamburg - Germany

Re: VA 8 beta 1 -> Win2k -> No printer available

Postby klaus » Wed Dec 10, 2008 5:27 am

Hello Marten,

thanks for your reply, I'm one step further in this method. Only one step, because

Code: Select all
      result := OS
               getPrinter: (OSHandle immediate: (hnd uint32At: 0))
               level: 2
               pPrinter: Null
               cbBuf: 0      "Get the buffer size needed"
               pcbNeeded: (bufNeeded := ByteArray new: 4).
      (result == false and: [OSCall new getLastError == 122])
         ifTrue: [bufSize := bufNeeded int32At: 0]
         ifFalse: [^nil].


results to false and
Code: Select all
OSCall new getLastError
is 0.

Code: Select all
   OS
         getPrinter: [b]prHandle[/b]
         level: 2
         pPrinter: (buf := ByteArray new: bufSize)
         cbBuf: bufSize
         pcbNeeded: bufNeeded.
      printerInfo := OSPrinterInfo2 reference: buf.

And the variable prHandle? It is always nil and will cause a Primitive failed error.

The intention of this method should be to return only the name of the default printer and not to open and close this? Am I wrong?

The correct implementation of this method should be:
Code: Select all
defaultPrinterDisplayName

      | rc pszBuffer pcchBuffer defaultPrinterName hnd prHandle bufSize bufNeeded result buf printerInfo |

      rc := OS
         getDefaultPrinter: (pszBuffer := OSStringZ new: 256)
         pcchBuffer: ((pcchBuffer := OSUInt32 new) uint32At: 0 put: 256 ; yourself ).

      defaultPrinterName := pszBuffer asString.
      pszBuffer free.
      pcchBuffer free.
      ^(rc == false or: [defaultPrinterName isEmpty])
                ifTrue: [nil]
                ifFalse: [defaultPrinterName ]


The rest of the code has to be for other tasks.

Regards

Klaus
Klaus Breker
Currently working for clearstream (Deutsche Börse Group)
klaus
 
Posts: 38
Joined: Fri Nov 28, 2008 1:16 am
Location: Bonn

Re: VA 8 beta 1 -> Win2k -> No printer available

Postby marten » Wed Dec 10, 2008 7:13 am

Ok, here is my modified version of this code:

Code: Select all
defaultPrinterDisplayName
   "CgDisplay defaultPrinterDisplayName"
   
      | rc pszBuffer pcchBuffer defaultPrinterName hnd prHandle bufSize bufNeeded result buf printerInfo errorCode |

      "gets the name of the default printer"
      rc := OS
            getDefaultPrinter: (pszBuffer := OSStringZ new: 256)
            pcchBuffer: ((pcchBuffer := OSUInt32 new) uint32At: 0 put: 256 ; yourself ).
      defaultPrinterName := pszBuffer asString.
      pszBuffer free.
      pcchBuffer free.
      
      "error case getting default printer"
      rc ifFalse: [^nil].
      defaultPrinterName isEmpty ifTrue: [^nil].
      
      "opening the printer shows us, that the printer is valid"
      hnd := OSUInt32 new.      
      (OS
         openPrinter: defaultPrinterName
         phPrinter: hnd
         pDefault: Null) ifFalse: [^nil].
            
      prHandle := OSHandle immediate: (hnd uint32At: 0).
      
      "
         retrieve the size of memory we need to store the printer info inclusive all strings
         referenced by the structure OSPrinterInfo2
      "
      bufNeeded := OSInt32 new.
      result :=
         OS
            getPrinter: prHandle
            level: 2
            pPrinter: nil
            cbBuf:  0
            pcbNeeded: bufNeeded.
      "error 122 == ERROR_INSUFFICIENT_BUFFER - this behaviour was defined in
         an MS article according Windows 98 and windows NT 3.5.1 - but actually MSDN
         say nothing about this. It does not seem to work under newer systems ?
      "
      "errorCode := OS getLastError.
      (result == false and: [ errorCode == 122])
         ifTrue: [bufSize := bufNeeded int32At: 0]
         ifFalse: [ OS closePrinter: prHandle. ^nil]."

      bufSize := bufNeeded uint32At: 0.
      buf := ByteArray new:  bufSize.
            
      "retrieve the printer information"
      (OS
         getPrinter: prHandle
         level: 2
         pPrinter: buf
         cbBuf: buf size
         pcbNeeded: bufNeeded) ifFalse:[ OS closePrinter: prHandle. ^nil ].

      printerInfo := OSPrinterInfo2 reference: buf.
      defaultPrinterName := printerInfo pPrinterName asString, ',winspool,', printerInfo pPortName asString.   "$NON-NLS$"
      OS closePrinter: prHandle.
      ^defaultPrinterName

Last edited by marten on Wed Dec 10, 2008 1:40 pm, edited 1 time in total.
Marten Feldtmann, Principal Smalltalk User, Private
SkypeMe callto://marten.feldtmann
marten
[|]
 
Posts: 641
Joined: Sat Oct 14, 2006 7:10 am
Location: Hamburg - Germany

Re: VA 8 beta 1 -> Win2k -> No printer available

Postby klaus » Wed Dec 10, 2008 8:45 am

Hi Marten,

your code works fine and for #CgWinPrinterServer class -> #allPrinterScreenInfos I found the following solution:
Code: Select all
allPrinterScreenInfos
   "Answer a dictionary whose keys are the names of all available
    print servers, and whose values are instance of CgPrinterScreenInfo."

   | buf resultSize numBuffers res bufSize numberPrinters printerInfo updatedPrinters |

   updatedPrinters := Dictionary new.

   res := EnumPrinters
         callWith: PrinterEnumLocal | PrinterEnumConnections
         with: Null
         with: 2
         with: Null
         with: 0      "Call to get the buffer size"
         with: (resultSize := ByteArray new: 4)
         with: (numBuffers := ByteArray new: 4).

   res == false
      ifTrue: [bufSize := resultSize int32At: 0]
      ifFalse: [^updatedPrinters].

   res := EnumPrinters
         callWith: PrinterEnumLocal  | PrinterEnumConnections
         with: Null
         with: 2
         with: (buf := ByteArray new: bufSize)
         with: bufSize
         with: resultSize
         with: numBuffers.

   res ifFalse: [^updatedPrinters].

   numberPrinters := numBuffers int32At: 0.
   printerInfo := OSPrinterInfo2 reference: buf.

   1 to: numberPrinters do: [:indx |
      (CgPrinterScreenInfo
         driverName: 'winspool'   "$NON-NLS$"
         deviceName: printerInfo pPrinterName asString
         outputMedium: printerInfo pPortName asString)
            ifNotNil: [:printerScreenInfo |
               updatedPrinters
                  at: (printerScreenInfo deviceName, ',winspool,', printerScreenInfo outputMedium)   "$NON-NLS$"
                  put: printerScreenInfo].
      printerInfo increment].

   self printerScreenInfo: updatedPrinters.

   ^updatedPrinters


Important is PrinterEnumConnections (otherwise there are no network printer available) and I deleted "and: [OS getLastError == 122])" which seems to be a copy and paste implementation error.

Regards

Klaus
Klaus Breker
Currently working for clearstream (Deutsche Börse Group)
klaus
 
Posts: 38
Joined: Fri Nov 28, 2008 1:16 am
Location: Bonn

Re: VA 8 beta 1 -> Win2k -> No printer available

Postby tc » Fri Dec 12, 2008 10:10 am

Hello,

I opened a case on this, #38329 -- fixed in V8.0.0.

Thanks.

--tc
tc
Moderator
 
Posts: 304
Joined: Tue Oct 17, 2006 7:40 am
Location: Raleigh, NC


Return to VA Smalltalk 7.0, 7.5 & 8.0

Who is online

Users browsing this forum: Yahoo [Bot] and 1 guest