From 7a2fe997fbf21661c331395658341a4d856f35c0 Mon Sep 17 00:00:00 2001 From: Starainrt Date: Tue, 26 Mar 2024 11:10:26 +0800 Subject: [PATCH] add clipboard func --- kernel32.go | 60 ++++++++++++++++++++++++ user32.go | 117 ++++++++++++++++++++++++++++++++++++++++++++++ user32_test.go | 65 ++++++++++++++++++++++++++ user32_typedef.go | 31 ++++++++++++ 4 files changed, 273 insertions(+) create mode 100644 user32_test.go diff --git a/kernel32.go b/kernel32.go index 7cfc44c..c354388 100644 --- a/kernel32.go +++ b/kernel32.go @@ -282,3 +282,63 @@ func DeviceIoControlPtr(hDevice HANDLE, dwIoControlCode DWORD, lpInBuffer uintpt } return true, nil } + +func GlobalLock(hMem HGLOBAL) (unsafe.Pointer, error) { + kernel32, err := syscall.LoadLibrary("kernel32.dll") + if err != nil { + return nil, err + } + defer syscall.FreeLibrary(kernel32) + gl, err := syscall.GetProcAddress(syscall.Handle(kernel32), "GlobalLock") + if err != nil { + return nil, err + } + r, _, errno := syscall.Syscall(gl, 1, uintptr(hMem), 0, 0) + if r == 0 { + if errno != 0 { + return nil, error(errno) + } + return nil, syscall.EINVAL + } + return unsafe.Pointer(r), nil +} + +func GlobalUnlock(hMem HGLOBAL) error { + kernel32, err := syscall.LoadLibrary("kernel32.dll") + if err != nil { + return err + } + defer syscall.FreeLibrary(kernel32) + gu, err := syscall.GetProcAddress(syscall.Handle(kernel32), "GlobalUnlock") + if err != nil { + return err + } + r, _, errno := syscall.Syscall(gu, 1, uintptr(hMem), 0, 0) + if r == 0 { + if errno != 0 { + return error(errno) + } + return syscall.EINVAL + } + return nil +} + +func GlobalSize(hMem HGLOBAL) (DWORD, error) { + kernel32, err := syscall.LoadLibrary("kernel32.dll") + if err != nil { + return 0, err + } + defer syscall.FreeLibrary(kernel32) + gs, err := syscall.GetProcAddress(syscall.Handle(kernel32), "GlobalSize") + if err != nil { + return 0, err + } + r, _, errno := syscall.Syscall(gs, 1, uintptr(hMem), 0, 0) + if r == 0 { + if errno != 0 { + return 0, error(errno) + } + return 0, syscall.EINVAL + } + return DWORD(r), nil +} diff --git a/user32.go b/user32.go index ecb1b83..d7fef9a 100644 --- a/user32.go +++ b/user32.go @@ -3,6 +3,7 @@ package win32api import ( "errors" "syscall" + "unsafe" ) func Keybd_event(keyname string, keydown bool) error { @@ -47,3 +48,119 @@ func Keybd_event_origin(key, keyenv, down, extra uintptr) error { syscall.Syscall6(keyevent, 4, key, keyenv, down, extra, 0, 0) return nil } + +func OpenClipboard(hWnd HWND) error { + user32, err := syscall.LoadLibrary("user32.dll") + if err != nil { + return errors.New("Can't Load User32 API") + } + defer syscall.FreeLibrary(user32) + oc, err := syscall.GetProcAddress(syscall.Handle(user32), "OpenClipboard") + if err != nil { + return errors.New("Can't Load OpenClipboard API") + } + if hWnd != 0 { + if r, _, errno := syscall.Syscall(oc, 1, uintptr(hWnd), 0, 0); r == 0 { + return error(errno) + } + return nil + } + if r, _, errno := syscall.Syscall(oc, 0, 0, 0, 0); r == 0 { + return error(errno) + } + return nil +} + +func CloseClipboard() error { + user32, err := syscall.LoadLibrary("user32.dll") + if err != nil { + return errors.New("Can't Load User32 API") + } + defer syscall.FreeLibrary(user32) + cc, err := syscall.GetProcAddress(syscall.Handle(user32), "CloseClipboard") + if err != nil { + return errors.New("Can't Load CloseClipboard API") + } + if r, _, errno := syscall.Syscall(cc, 0, 0, 0, 0); r == 0 { + return error(errno) + } + return nil +} + +func GetClipboardData(uFormat DWORD) (HGLOBAL, error) { + user32, err := syscall.LoadLibrary("user32.dll") + if err != nil { + return 0, errors.New("Can't Load User32 API") + } + defer syscall.FreeLibrary(user32) + gcd, err := syscall.GetProcAddress(syscall.Handle(user32), "GetClipboardData") + if err != nil { + return 0, errors.New("Can't Load GetClipboardData API") + } + r, _, errno := syscall.Syscall(gcd, 1, uintptr(uFormat), 0, 0) + if r == 0 { + return 0, error(errno) + } + return HGLOBAL(r), nil +} + +func EnumClipboardFormats(uFormat DWORD) (DWORD, error) { + user32, err := syscall.LoadLibrary("user32.dll") + if err != nil { + return 0, errors.New("Can't Load User32 API") + } + defer syscall.FreeLibrary(user32) + ecf, err := syscall.GetProcAddress(syscall.Handle(user32), "EnumClipboardFormats") + if err != nil { + return 0, errors.New("Can't Load EnumClipboardFormats API") + } + r, _, errno := syscall.Syscall(ecf, 1, uintptr(uFormat), 0, 0) + if r == 0 { + return 0, error(errno) + } + return DWORD(r), nil +} + +func EnumAllClipboardFormats() ([]DWORD, error) { + var formats []DWORD + for i := 0; ; i++ { + format, err := EnumClipboardFormats(DWORD(i)) + if err != nil { + break + } + formats = append(formats, format) + } + return formats, nil +} + +func GetClipboardFormatName(uFormat DWORD) (string, error) { + user32, err := syscall.LoadLibrary("user32.dll") + if err != nil { + return "", errors.New("Can't Load User32 API") + } + defer syscall.FreeLibrary(user32) + gcfn, err := syscall.GetProcAddress(syscall.Handle(user32), "GetClipboardFormatNameW") + if err != nil { + return "", errors.New("Can't Load GetClipboardFormatName API") + } + var buffer [256]uint16 + r, _, errno := syscall.Syscall6(gcfn, 3, uintptr(uFormat), uintptr(unsafe.Pointer(&buffer)), uintptr(len(buffer)), 0, 0, 0) + if r == 0 { + return "", error(errno) + } + return syscall.UTF16ToString(buffer[:]), nil +} + +func RegisterClipboardFormat(lpszFormat string) DWORD { + user32, err := syscall.LoadLibrary("user32.dll") + if err != nil { + return 0 + } + defer syscall.FreeLibrary(user32) + rcf, err := syscall.GetProcAddress(syscall.Handle(user32), "RegisterClipboardFormatW") + if err != nil { + return 0 + } + r, _, _ := syscall.Syscall(rcf, 1, uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpszFormat))), 0, 0) + return DWORD(r) +} diff --git a/user32_test.go b/user32_test.go new file mode 100644 index 0000000..362068e --- /dev/null +++ b/user32_test.go @@ -0,0 +1,65 @@ +package win32api + +import ( + "fmt" + "syscall" + "testing" + "unsafe" +) + +func TestClipboardReadText(t *testing.T) { + if err := OpenClipboard(0); err != nil { + t.Error(err) + } + formats, err := EnumAllClipboardFormats() + if err != nil { + t.Error(err) + } + tp := CF_UNICODETEXT + for _, f := range formats { + fmt.Println("Clipboard Format:", f) + d, e := GetClipboardFormatName(f) + fmt.Println("Clipboard Format Name:", d, e) + if d == "HTML Format" { + tp = RegisterClipboardFormat("HTML Format") + fmt.Println("HTML Format:", tp) + } + if d == "DataObject" { + tp = CF_HDROP + fmt.Println("DataObject:", tp) + } + } + + mem, err := GetClipboardData(tp) + if err != nil { + t.Error(err) + } + p, err := GlobalLock(mem) + if err != nil { + t.Error(err) + } + defer GlobalUnlock(mem) + //n := 0 + if tp == 13 { + var buf []uint16 + for ptr := unsafe.Pointer(p); *(*uint16)(ptr) != 0; ptr = unsafe.Pointer(uintptr(ptr) + unsafe.Sizeof(*((*uint16)(unsafe.Pointer(p))))) { + buf = append(buf, *(*uint16)(ptr)) + } + str := syscall.UTF16ToString(buf) + fmt.Println("\n\nClipboard Data:", str) + if err := CloseClipboard(); err != nil { + t.Error(err) + } + return + } + size, err := GlobalSize(mem) + if err != nil { + t.Error(err) + } + var buf []byte + for i := 0; i < int(size); i++ { + buf = append(buf, *(*byte)(unsafe.Pointer(uintptr(p) + uintptr(i)))) + } + fmt.Println("\n\nClipboard Data:", string(buf)) + fmt.Println("Clipboard Test Done") +} diff --git a/user32_typedef.go b/user32_typedef.go index a8e95e7..b7a931a 100644 --- a/user32_typedef.go +++ b/user32_typedef.go @@ -178,3 +178,34 @@ const ( VK_PA1 = 0xFD VK_OEM_CLEAR = 0xFE ) + +// 剪贴板标准格式 +const ( + CF_BITMAP DWORD = 2 + CF_DIB DWORD = 8 + CF_DIBV5 DWORD = 17 + CF_DIF DWORD = 5 + CF_DSPBITMAP DWORD = 130 + CF_DSPENHMETAFILE DWORD = 142 + CF_DSPMETAFILEPICT DWORD = 131 + CF_DSPTEXT DWORD = 129 + CF_ENHMETAFILE DWORD = 14 + CF_GDIOBJFIRST DWORD = 0x0300 + CF_GDIOBJLAST DWORD = 0x03FF + CF_HDROP DWORD = 15 + CF_LOCALE DWORD = 16 + CF_METAFILEPICT DWORD = 3 + CF_OEMTEXT DWORD = 7 + CF_OWNERDISPLAY DWORD = 0x0080 + CF_PALETTE DWORD = 9 + CF_PENDATA DWORD = 10 + CF_PRIVATEFIRST DWORD = 0x0200 + CF_PRIVATELAST DWORD = 0x02FF + CF_RIFF DWORD = 11 + CF_SYLK DWORD = 4 + CF_TEXT DWORD = 1 + CF_TIFF DWORD = 6 + CF_UNICODETEXT DWORD = 13 + CF_WAVE DWORD = 12 + CF_HENHMETAFILE DWORD = 14 +)