Golang中StretchDIBits在Windows 10上无法工作的问题
Golang中StretchDIBits在Windows 10上无法工作的问题 你好,
我一直在开发一个Windows应用程序,它使用Windows gdi32.dll中的StretchDIBits函数在屏幕上绘制图像。我成功地在Windows 11上使其正常工作。
但是,当我在Windows 10上运行它时,StretchDIBits返回0,我完全不清楚是什么导致了这个问题。请注意,我在C++中测试了相同的代码,它在Windows 11和Windows 10上都能运行。
你可以在以下链接找到重现此问题的最小代码:buggy_stretchdibits.go · GitHub
谢谢,
更多关于Golang中StretchDIBits在Windows 10上无法工作的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html
面向对象,太酷了,我们可以像这样在Go中调用Windows的DLL API,你真的需要这样做吗?
更多关于Golang中StretchDIBits在Windows 10上无法工作的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
嗯,除了使用cgo,还有其他调用Windows的StretchDIBits的方法吗?我的意思是,因为cgo的效果也不理想。
这是一个已知的Golang在Windows 10上的特定问题,主要与BITMAPINFOHEADER结构的内存对齐方式有关。Windows 10对结构对齐的要求比Windows 11更严格。
问题出在BITMAPINFOHEADER结构定义上。在您的代码中,结构字段使用了Go的默认对齐方式,但在Windows 10上需要显式指定Windows的1字节对齐。
以下是修复后的代码:
package main
import (
"fmt"
"syscall"
"unsafe"
)
// 使用1字节对齐的BITMAPINFOHEADER结构
type BITMAPINFOHEADER struct {
BiSize uint32
BiWidth int32
BiHeight int32
BiPlanes uint16
BiBitCount uint16
BiCompression uint32
BiSizeImage uint32
BiXPelsPerMeter int32
BiYPelsPerMeter int32
BiClrUsed uint32
BiClrImportant uint32
}
// 使用1字节对齐的BITMAPINFO结构
type BITMAPINFO struct {
BmiHeader BITMAPINFOHEADER
BmiColors *RGBQUAD
}
type RGBQUAD struct {
RgbBlue byte
RgbGreen byte
RgbRed byte
RgbReserved byte
}
func main() {
// 加载必要的DLL
user32 := syscall.NewLazyDLL("user32.dll")
gdi32 := syscall.NewLazyDLL("gdi32.dll")
getDC := user32.NewProc("GetDC")
releaseDC := user32.NewProc("ReleaseDC")
stretchDIBits := gdi32.NewProc("StretchDIBits")
// 获取屏幕DC
hwnd := uintptr(0)
hdc, _, _ := getDC.Call(hwnd)
defer releaseDC.Call(hwnd, hdc)
// 创建测试图像数据
width := 100
height := 100
pixelData := make([]byte, width*height*4)
// 填充测试数据(红色)
for i := 0; i < len(pixelData); i += 4 {
pixelData[i] = 0 // B
pixelData[i+1] = 0 // G
pixelData[i+2] = 255 // R
pixelData[i+3] = 0 // Reserved
}
// 设置BITMAPINFO结构
var bmi BITMAPINFO
bmi.BmiHeader.BiSize = uint32(unsafe.Sizeof(bmi.BmiHeader))
bmi.BmiHeader.BiWidth = int32(width)
bmi.BmiHeader.BiHeight = int32(-height) // 负值表示从上到下的DIB
bmi.BmiHeader.BiPlanes = 1
bmi.BmiHeader.BiBitCount = 32
bmi.BmiHeader.BiCompression = 0 // BI_RGB
bmi.BmiHeader.BiSizeImage = uint32(len(pixelData))
// 调用StretchDIBits
ret, _, err := stretchDIBits.Call(
hdc, // hdc
0, // xDest
0, // yDest
uintptr(width), // wDest
uintptr(height), // hDest
0, // xSrc
0, // ySrc
uintptr(width), // wSrc
uintptr(height), // hSrc
uintptr(unsafe.Pointer(&pixelData[0])), // lpBits
uintptr(unsafe.Pointer(&bmi)), // lpBitsInfo
0, // iUsage (DIB_RGB_COLORS)
0x00CC0020, // rop (SRCCOPY)
)
if ret == 0 {
fmt.Printf("StretchDIBits failed with error: %v\n", err)
} else {
fmt.Printf("StretchDIBits succeeded, returned: %d\n", ret)
}
}
关键修复是确保结构体使用正确的对齐方式。如果您需要更精确的控制,可以使用//go:packed指令或使用字节数组手动构建结构:
// 替代方案:使用字节数组手动构建BITMAPINFOHEADER
func createBitmapInfoHeader(width, height int) []byte {
header := make([]byte, 40) // BITMAPINFOHEADER大小为40字节
// BiSize
binary.LittleEndian.PutUint32(header[0:4], 40)
// BiWidth
binary.LittleEndian.PutUint32(header[4:8], uint32(width))
// BiHeight
binary.LittleEndian.PutUint32(header[8:12], uint32(-height))
// BiPlanes
binary.LittleEndian.PutUint16(header[12:14], 1)
// BiBitCount
binary.LittleEndian.PutUint16(header[14:16], 32)
// 其余字段保持为0
return header
}
这个修复确保了结构在内存中的布局与Windows 10期望的完全一致,从而解决了StretchDIBits返回0的问题。

