Golang使用win32 API修改cmd字体失败的问题

Golang使用win32 API修改cmd字体失败的问题 大家好, 我想通过win32 API获取控制台字体,但未能成功。 以下是我的代码:

func KernelGetConsoleHandle() (e syscall.Handle) {
	hwnd, _, _ := procGetConsoleWindow.Call()
	return syscall.Handle(hwnd)
}

func KernelGetConsoleFont(maximumWindows bool) *CONSOLE_FONT_INFOEX {
	in, err := syscall.GetStdHandle(syscall.STD_OUTPUT_HANDLE)
	if err != nil {
		fmt.Println("Could not get std handle")
		return nil
	}
	fmt.Println(in)

	var cfi CONSOLE_FONT_INFOEX
	cfi.Size = uint64(unsafe.Sizeof(cfi))

	mWindows := 0
	if maximumWindows {
		mWindows = 1
	}

	console, _, _ := procGetCurrentConsoleFontEx.Call(uintptr(in), uintptr(mWindows), uintptr(unsafe.Pointer(&cfi)))
	fmt.Println("cfi", cfi)
	if console == 0 {
		fmt.Println(syscall.Errno(GetLastError()))
	}
	fmt.Println("console", console)

	return &cfi
}
type CONSOLE_FONT_INFOEX struct {
	Size       uint64
	Font       uint32
	FontSize   COORD
	FontFamily uint64
	FontWeight uint64
	FaceName   [64]byte
}

type COORD struct {
	X int16
	Y int16
}
cfi := *win32.KernelGetConsoleFont(false)

KernelGetConsoleFont函数中,我无法获取到填充了数据的cfi结构体。我也不确定这个CONSOLE_FONT_INFOEX结构体定义是否正确。 我该如何解决这个问题?


更多关于Golang使用win32 API修改cmd字体失败的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang使用win32 API修改cmd字体失败的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


问题出在CONSOLE_FONT_INFOEX结构体的定义上。Windows API要求结构体字段顺序和类型必须完全匹配,你的定义有几个问题:

  1. Size字段应该是ULONG(32位),不是uint64
  2. FontFamily应该是UINT(32位),不是uint64
  3. FontWeight应该是UINT(32位),不是uint64

以下是正确的结构体定义和修复后的函数:

package main

import (
    "fmt"
    "syscall"
    "unsafe"
)

// 正确的CONSOLE_FONT_INFOEX结构体定义
type CONSOLE_FONT_INFOEX struct {
    Size       uint32 // ULONG
    Font       uint32 // DWORD
    FontSize   COORD
    FontFamily uint32 // UINT
    FontWeight uint32 // UINT
    FaceName   [LF_FACESIZE]uint16 // WCHAR数组
}

type COORD struct {
    X int16
    Y int16
}

const (
    LF_FACESIZE = 32
    STD_OUTPUT_HANDLE = uint32(0xFFFFFFF5)
)

var (
    kernel32 = syscall.NewLazyDLL("kernel32.dll")
    procGetCurrentConsoleFontEx = kernel32.NewProc("GetCurrentConsoleFontEx")
    procGetStdHandle = kernel32.NewProc("GetStdHandle")
)

func GetConsoleFontInfoEx() (*CONSOLE_FONT_INFOEX, error) {
    // 获取标准输出句柄
    hConsole, _, err := procGetStdHandle.Call(uintptr(STD_OUTPUT_HANDLE))
    if hConsole == 0 {
        return nil, fmt.Errorf("GetStdHandle failed: %v", err)
    }
    
    // 初始化结构体
    cfi := &CONSOLE_FONT_INFOEX{}
    cfi.Size = uint32(unsafe.Sizeof(*cfi))
    
    // 调用API
    success, _, err := procGetCurrentConsoleFontEx.Call(
        hConsole,
        uintptr(0), // maximumWindow设为false
        uintptr(unsafe.Pointer(cfi)),
    )
    
    if success == 0 {
        return nil, fmt.Errorf("GetCurrentConsoleFontEx failed: %v", err)
    }
    
    return cfi, nil
}

func main() {
    cfi, err := GetConsoleFontInfoEx()
    if err != nil {
        fmt.Printf("Error: %v\n", err)
        return
    }
    
    // 将WCHAR数组转换为Go字符串
    faceName := syscall.UTF16ToString(cfi.FaceName[:])
    
    fmt.Printf("Font Index: %d\n", cfi.Font)
    fmt.Printf("Font Size: %dx%d\n", cfi.FontSize.X, cfi.FontSize.Y)
    fmt.Printf("Font Family: 0x%X\n", cfi.FontFamily)
    fmt.Printf("Font Weight: %d\n", cfi.FontWeight)
    fmt.Printf("Font Name: %s\n", faceName)
}

如果需要修改控制台字体,可以使用SetCurrentConsoleFontEx函数:

var (
    procSetCurrentConsoleFontEx = kernel32.NewProc("SetCurrentConsoleFontEx")
)

func SetConsoleFontInfoEx(cfi *CONSOLE_FONT_INFOEX) error {
    hConsole, _, err := procGetStdHandle.Call(uintptr(STD_OUTPUT_HANDLE))
    if hConsole == 0 {
        return fmt.Errorf("GetStdHandle failed: %v", err)
    }
    
    success, _, err := procSetCurrentConsoleFontEx.Call(
        hConsole,
        uintptr(0), // maximumWindow设为false
        uintptr(unsafe.Pointer(cfi)),
    )
    
    if success == 0 {
        return fmt.Errorf("SetCurrentConsoleFontEx failed: %v", err)
    }
    
    return nil
}

// 修改字体示例
func ChangeConsoleFont() {
    cfi, err := GetConsoleFontInfoEx()
    if err != nil {
        fmt.Printf("Error getting font: %v\n", err)
        return
    }
    
    // 修改字体大小
    cfi.FontSize.X = 8
    cfi.FontSize.Y = 16
    
    // 修改字体名称(使用WCHAR字符串)
    newFontName := "Consolas"
    utf16Name := syscall.StringToUTF16(newFontName)
    copy(cfi.FaceName[:], utf16Name)
    
    // 应用修改
    err = SetConsoleFontInfoEx(cfi)
    if err != nil {
        fmt.Printf("Error setting font: %v\n", err)
        return
    }
    
    fmt.Println("Console font changed successfully")
}

关键点:

  1. 结构体字段类型必须与Windows API完全匹配
  2. FaceName字段应该是WCHAR数组(uint16数组),不是byte数组
  3. 使用syscall.UTF16ToStringsyscall.StringToUTF16进行字符串转换
  4. 确保Size字段正确设置为结构体大小
回到顶部