Ticket UUID: | bb5c3d0ecc034be3c99c887a62edef2618e21a80 | |||
Title: | tk print command fails with text widget on windows | |||
Type: | Bug | Version: | trunk | |
Submitter: | emiliano | Created on: | 2025-04-23 13:35:09 | |
Subsystem: | -- New Commands | Assigned To: | fvogel | |
Priority: | 5 Medium | Severity: | Important | |
Status: | Closed | Last Modified: | 2025-04-26 11:48:23 | |
Resolution: | Fixed | Closed By: | fvogel | |
Closed on: | 2025-04-26 11:48:23 | |||
Description: |
Trying to print a simple text on windows fails with % text .t % pack .t % .t insert end "This is a test" % tk print .t can't read "printargs(hDC)": no such element in array Same error in both Win7, 32bits % parray tcl_platform tcl_platform(byteOrder) = littleEndian tcl_platform(engine) = Tcl tcl_platform(machine) = intel tcl_platform(os) = Windows NT tcl_platform(osVersion) = 6.1 tcl_platform(pathSeparator) = ; tcl_platform(platform) = windows tcl_platform(pointerSize) = 4 tcl_platform(user) = Emiliano tcl_platform(wordSize) = 4 % info patchlevel 9.1a0 and with Win11, 64bits % parray tcl_platform tcl_platform(byteOrder) = littleEndian tcl_platform(engine) = Tcl tcl_platform(machine) = amd64 tcl_platform(os) = Windows NT tcl_platform(osVersion) = 11.0 tcl_platform(pathSeparator) = ; tcl_platform(platform) = windows tcl_platform(pointerSize) = 8 tcl_platform(user) = Usuario tcl_platform(wordSize) = 4 % info patchlevel 9.1a0 Both versions compiled with mingw-w64 | |||
User Comments: |
fvogel added on 2025-04-26 11:48:23:
Now merged. Closing. fvogel added on 2025-04-25 19:16:05: Thanks! Patch added to the bugfix branch. emiliano added on 2025-04-25 14:34:21: Two more fine points to nail this down: * While a 100 bytes buffer to hold the printer name seems more than enough, a more "correct" way would be to ckalloc() a buffer with space_needed bytes as returned by the first call to WideCharToMultiByte() and ckfree() it at the end. * In the case where PrintDlg() returns 0, there's no distinction between an error in the dialog itself or the user cancelling the operation. The distinction can be made by calling CommDlgExtendedError() and checking its return value: zero for user action, nonzero for any error. In the last case, I think returning the error to the user is better than "do nothing gracefully". The attached patch, to be applied over the last one, addresses both points. Feel free to apply, modify or discard it. jan.nijtmans added on 2025-04-25 07:43:24: Well done! +1 fvogel added on 2025-04-25 06:15:35: Thanks! Your complementary patch indeed fixes the issues you describe. Now put in the bugfix branch. emiliano added on 2025-04-24 23:37:17: As mentioned in the chat, there is a leak in this code, as there are ckalloc's without corresponding ckfree's. So, based on Francois patch, I crafted the attached patch. Since the Tcl code immediately after the call to _selectprinter checks whether the variable ::tk::print::printer_name exists to determine if a valid printer was selected, I think is better to set/unset the variable based on the return value of PrintDlgW. This is also contemplated in the patch, since there are further errors if the user first select a valid printer (and prints) but cancels a subsequent call to [tk print], given that the variable still exists. fvogel added on 2025-04-24 21:12:10: The fix is [8fd0f283] IMO. Explanation: For some reason I could observe the problem when trying again. This allowed to see that in PrintSelectPrinter() in tkWinGDI.c everything is fine until the call to WideCharToMultiByte(). When the error message can't read "printargs(hDC)" is obtained, the varlink1 is "", which is catched by the code checking printer_name in print.tcl When there is no error (the cases that lead me to state I can't reproduce), the varlink1 there contains garbage. This means that this code never worked. It's just that in this case since printer_name is not empty the rest of print.tcl is happy and triggers no error. But in all cases printer_name never got the right value from localPrinterName through WideCharToMultiByte(). It worked by pure chance so far (and not always, it depends on whether the allocated memory happens to start by a zero or not!). [8fd0f283] fixes this by first requesting the output buffer size from WideCharToMultiByte() before actually making the conversion through a second call to WideCharToMultiByte(). The printer-name now contains the correct string value from localPrinterName. emiliano added on 2025-04-24 16:34:55: No change with the proposed patch applied; it still fails. Also confirmed that there's no change calling [tk print] several times, as shown in both https://imgur.com/a/tk-print-error-xotEMVz and https://imgur.com/a/tk-print-error-win11-64-bits-UixEwGH . fvogel added on 2025-04-24 06:03:35: Definitely I don't manage to reproduce (Win11, Tcl and Tk trunks). Since you can reproduce everytime, can you try the following wild guess perhaps? Index: library/print.tcl ================================================================== --- library/print.tcl +++ library/print.tcl @@ -103,11 +103,11 @@ variable printargs variable printer_name _set_dc - if {![info exists printer_name]} { + if {![info exists printer_name] || $printer_name eq ""} { return } if {$font eq ""} { _gdi characters $printargs(hDC) -array printcharwid @@ -260,11 +260,11 @@ variable printargs variable printer_name _set_dc - if {![info exists printer_name]} { + if {![info exists printer_name] || $printer_name eq ""} { return } _opendoc _openpage fvogel added on 2025-04-23 21:45:51: This problem seems to happen once only. At least I could only get it once only. After the first time, when the problem does no longer happen the correct functioning survives kill and restart of tclsh, and even survives the switch of / switch on of the printer. Interesting. This problem is the same as the second issue described in [d2eac285d9]. |
