duanshan1856 2016-12-19 10:31
浏览 28
已采纳

如何从剪贴板存储器(uintptr)检索图像数据缓冲区?

I'm trying to use syscall with user32.dll to get the contents of the clipboard. I expect it to be image data from a Print Screen.

Right now I've got this:

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

handle := getClipboardData(CF_BITMAP)

// get buffer

img, _, err := Decode(buffer)

I need to get the data into a readable buffer using the handle.

I've had some inspiration from AllenDang/w32 and atotto/clipboard on github. The following would work for text, based on atotto's implementation:

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

But how can I get a buffer containing image data I can decode?

[Update]

Going by the solution @kostix provided, I hacked together a half working example:

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
", 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 contains most of what you'd need, but sometimes you need to implement something yourself, like 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)
}

Maybe someone will come up with a solution to get the BMP data. In the meantime I'll be taking a different route.

  • 写回答

1条回答 默认 最新

  • dongxian1921 2016-12-20 06:11
    关注

    @JimB is correct: user32!GetClipboardData() returns a HGLOBAL, and a comment example over there suggests using kernel32!GlobalLock() to a) globally lock that handle, and b) yield a proper pointer to the memory referred to by it.

    You will need to kernel32!GlobalUnlock() the handle after you're done with it.

    As to converting pointers obtained from Win32 API functions to something readable by Go, the usual trick is casting the pointer to an insanely large slice. To cite the "Turning C arrays into Go slices" of "the Go wiki article on cgo":

    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.

    In your case it will be simpler:

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

    Then you need to actually read the bitmap.

    This depends on the format of the Device-Independent Bitmap (DIB) available for export from the clipboard.

    See this and this for a start.

    As usually, definitions of BITMAPINFOHEADER etc are easily available online in the MSDN site.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 关于#matlab#的问题:在模糊控制器中选出线路信息,在simulink中根据线路信息生成速度时间目标曲线(初速度为20m/s,15秒后减为0的速度时间图像)我想问线路信息是什么
  • ¥15 banner广告展示设置多少时间不怎么会消耗用户价值
  • ¥16 mybatis的代理对象无法通过@Autowired装填
  • ¥15 可见光定位matlab仿真
  • ¥15 arduino 四自由度机械臂
  • ¥15 wordpress 产品图片 GIF 没法显示
  • ¥15 求三国群英传pl国战时间的修改方法
  • ¥15 matlab代码代写,需写出详细代码,代价私
  • ¥15 ROS系统搭建请教(跨境电商用途)
  • ¥15 AIC3204的示例代码有吗,想用AIC3204测量血氧,找不到相关的代码。