0

I'm making a windows python application and I was trying to use windll and kernel32 to make underlined text in the console, however the text only becomes underlined post the program running.

I've cut out just the relevant part of code, but it may still seem long due to the constants that I define.

import os
import sys
import struct
from ctypes import windll, byref, sizeof, create_string_buffer, Structure
from ctypes import WINFUNCTYPE, c_char, c_wchar, c_int
from ctypes.wintypes import DWORD, HWND, HANDLE, _COORD, WORD, LONG, ULONG, SMALL_RECT, BOOL, MSG, RECT, POINT, UINT

COMMON_LVB_UNDERSCORE = 0x8000
COMMON_LVB_GRID_HORIZONTAL = 0x0400
COMMON_LVB_GRID_LVERTICAL = 0x0800
COMMON_LVB_GRID_RVERTICAL = 0x1000
COMMON_LVB_REVERSE_VIDEO = 0x4000

FOREGROUND_BLUE = 0x0001
FOREGROUND_GREEN = 0x0002
FOREGROUND_RED = 0x0004
FOREGROUND_INTENSITY = 0x0008
BACKGROUND_BLUE = 0x0010
BACKGROUND_GREEN = 0x0020
BACKGROUND_RED = 0x0040
BACKGROUND_INTENSITY =  0x0080

class CONSOLE_SCREEN_BUFFER_INFOEX(Structure):
    _fields_ = (
        ('cbSize', ULONG),
        ('dwSize', _COORD),
        ('dwCursorPosition', _COORD),
        ('wAttributes', WORD),
        ('srWindow', SMALL_RECT),
        ('dwMaximumWindowSize', _COORD),
        ('wPopupAttributes', WORD),
        ('bFullscreenSupported', BOOL),
        ('ColorTable', DWORD * 16))
    def __init__(self, *args, **kwds):
        super(CONSOLE_SCREEN_BUFFER_INFOEX, self).__init__(*args, **kwds)
        self.cbSize = sizeof(self)

# helper for color text
def rgb(r, g, b):
  return r + (g * 256) + (b * 256 * 256)

# Set colors
stdout =  windll.kernel32.GetStdHandle(-11)
csi = CONSOLE_SCREEN_BUFFER_INFOEX()
windll.kernel32.GetConsoleScreenBufferInfoEx(stdout, byref(csi))
csi.ColorTable[0] = rgb(0, 0, 0)
csi.ColorTable[1] = rgb(0, 0, 255)
csi.ColorTable[2] = rgb(0, 255, 0)
csi.ColorTable[3] = rgb(0, 200, 255)
csi.ColorTable[4] = rgb(255, 0, 0)
csi.ColorTable[5] = rgb(0, 100, 0)
csi.ColorTable[6] = rgb(0, 0, 100)
csi.ColorTable[7] = rgb(255, 255, 255)
csi.ColorTable[8] = rgb(0, 0, 100)
csi.ColorTable[9] = rgb(0, 100, 0)
csi.ColorTable[10] = rgb(100, 0, 0)
csi.ColorTable[11] = rgb(0, 100, 0)
csi.ColorTable[12] = rgb(0, 0, 100)
csi.ColorTable[13] = rgb(0, 100, 0)
csi.ColorTable[14] = rgb(100, 0, 0)
csi.ColorTable[15] = rgb(0, 100, 0)
windll.kernel32.SetConsoleScreenBufferInfoEx(stdout, byref(csi))

# Important section which causes problem
windll.kernel32.SetConsoleTextAttribute(stdout, DWORD(FOREGROUND_BLUE | COMMON_LVB_UNDERSCORE))
text = "This should be underlined."
windll.kernel32.WriteConsoleW(stdout, text, len(text), None, None)

# Loop to keep program running
while(True):
    pass

Blue text whilst running, but not underlined:

Blue text whilst running, but not underlined

After terminate, underline now works:

After terminate, underline now works

I saw this problem being mentioned here but the issue wasn't expanded upon.

EDIT: I should mention that this problem only happens in python, the equivalent code in C# or C both work as intended.

Dorian Turba
  • 3,260
  • 3
  • 23
  • 67
name
  • 181
  • 1
  • 12
  • Not the cause of your behavior, but check [\[SO\]: C function called from Python via ctypes returns incorrect value (@CristiFati's answer)](https://stackoverflow.com/a/58611011/4788546) for a common pitfall when working with *CTypes* (calling functions). – CristiFati Feb 07 '23 at 10:48

0 Answers0