gpt4 book ai didi

windows - 如何从剪贴板内存 (uintptr) 中检索图像数据缓冲区?

转载 作者:数据小太阳 更新时间:2023-10-29 03:14:24 31 4
gpt4 key购买 nike

我正在尝试将系统调用与 user32.dll 结合使用以获取剪贴板的内容。我希望它是来自打印屏幕的图像数据。

现在我得到了这个:

if opened := openClipboard(0); !opened {
fmt.Println("Failed to open Clipboard")
}

handle := getClipboardData(CF_BITMAP)

// get buffer

img, _, err := Decode(buffer)

我需要使用句柄将数据放入可读缓冲区。

我从 github 上的 AllenDang/w32 和 atotto/clipboard 获得了一些灵感。基于 atotto 的实现,以下内容适用于文本:

text := syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(handle))[:])

但是我怎样才能得到一个包含我可以解码的图像数据的缓冲区呢?

[更新]

按照@kostix 提供的解决方案,我拼凑了一个半工作示例:

image.RegisterFormat("bmp", "bmp", bmp.Decode, bmp.DecodeConfig)

if opened := w32.OpenClipboard(0); opened == false {
fmt.Println("Error: Failed to open Clipboard")
}

//fmt.Printf("Format: %d\n", w32.EnumClipboardFormats(w32.CF_BITMAP))
handle := w32.GetClipboardData(w32.CF_DIB)
size := globalSize(w32.HGLOBAL(handle))
if handle != 0 {
pData := w32.GlobalLock(w32.HGLOBAL(handle))
if pData != nil {
data := (*[1 << 25]byte)(pData)[:size]
// The data is either in DIB format and missing the BITMAPFILEHEADER
// or there are other issues since it can't be decoded at this point
buffer := bytes.NewBuffer(data)
img, _, err := image.Decode(buffer)
if err != nil {
fmt.Printf("Failed decoding: %s", err)
os.Exit(1)
}

fmt.Println(img.At(0, 0).RGBA())
}

w32.GlobalUnlock(w32.HGLOBAL(pData))
}
w32.CloseClipboard()

AllenDang/w32 包含大部分你需要的东西,但有时你需要自己实现一些东西,比如 globalSize():

var (
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
procGlobalSize = modkernel32.NewProc("GlobalSize")
)

func globalSize(hMem w32.HGLOBAL) uint {
ret, _, _ := procGlobalSize.Call(uintptr(hMem))

if ret == 0 {
panic("GlobalSize failed")
}

return uint(ret)
}

也许有人会想出一个解决方案来获取 BMP 数据。与此同时,我将采取不同的路线。

最佳答案

@JimB 是正确的:user32!GetClipboardData() 返回一个 HGLOBAL,以及一个注释示例 over there建议使用 kernel32!GlobalLock() 来 a) 全局锁定该句柄,以及 b) 产生一个指向它引用的内存的正确指针。

完成后,您将需要 kernel32!GlobalUnlock() 句柄。

至于将从 Win32 API 函数获得的指针转换为 Go 可读的东西,通常的技巧是将指针转换为一个非常大的 slice 。引用 "the Go wiki article on cgo" 的“将 C 数组转换为 Go slice ” :

To create a Go slice backed by a C array (without copying the original data), one needs to acquire this length at runtime and use a type conversion to a pointer to a very big array and then slice it to the length that you want (also remember to set the cap if you're using Go 1.2 > or later), for example (see http://play.golang.org/p/XuC0xqtAIC for a runnable example):

import "C"
import "unsafe"
...
var theCArray *C.YourType = C.getTheArray()
length := C.getTheArrayLength()
slice := (*[1 << 30]C.YourType)(unsafe.Pointer(theCArray))[:length:length]

It is important to keep in mind that the Go garbage collector will not interact with this data, and that if it is freed from the C side of things, the behavior of any Go code using the slice is nondeterministic.

在你的情况下它会更简单:

h := GlobalLock()
defer GlobalUnlock(h)
length := somehowGetLengthOfImageInTheClipboard()
slice := (*[1 << 30]byte)(unsafe.Pointer((uintptr(h)))[:length:length]

然后你需要实际读取位图。

这取决于可从剪贴板导出的设备无关位图 (DIB) 的格式。

参见 thisthis一开始。

通常,BITMAPINFOHEADER 等的定义很容易在 MSDN 站点在线获得。

关于windows - 如何从剪贴板内存 (uintptr) 中检索图像数据缓冲区?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41220587/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com