test
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
//go:build windows
|
||||
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var (
|
||||
ddUser32 = windows.NewLazySystemDLL("user32.dll")
|
||||
ddKernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
||||
ddFindWindowW = ddUser32.NewProc("FindWindowW")
|
||||
ddFindWindowExW = ddUser32.NewProc("FindWindowExW")
|
||||
ddSendMessageW = ddUser32.NewProc("SendMessageW")
|
||||
ddScreenToClient = ddUser32.NewProc("ScreenToClient")
|
||||
ddGetWindowThreadProcessID = ddUser32.NewProc("GetWindowThreadProcessId")
|
||||
ddOpenProcess = ddKernel32.NewProc("OpenProcess")
|
||||
ddVirtualAllocEx = ddKernel32.NewProc("VirtualAllocEx")
|
||||
ddVirtualFreeEx = ddKernel32.NewProc("VirtualFreeEx")
|
||||
ddWriteProcessMemory = ddKernel32.NewProc("WriteProcessMemory")
|
||||
ddReadProcessMemory = ddKernel32.NewProc("ReadProcessMemory")
|
||||
)
|
||||
|
||||
const (
|
||||
ddProcessVMOperation = 0x0008
|
||||
ddProcessVMRead = 0x0010
|
||||
ddProcessVMWrite = 0x0020
|
||||
ddProcessQueryInfo = 0x0400
|
||||
ddMemCommit = 0x1000
|
||||
ddMemReserve = 0x2000
|
||||
ddMemRelease = 0x8000
|
||||
ddPageReadWrite = 0x04
|
||||
ddLVMGetItemCount = 0x1004
|
||||
ddLVMSetItemPosition = 0x100f
|
||||
ddLVMGetItemTextW = 0x1073
|
||||
)
|
||||
|
||||
type desktopDropPoint struct{ X, Y int32 }
|
||||
|
||||
type desktopDropLVItem struct {
|
||||
Mask uint32
|
||||
IItem int32
|
||||
ISubItem int32
|
||||
State uint32
|
||||
StateMask uint32
|
||||
PszText uintptr
|
||||
CchTextMax int32
|
||||
IImage int32
|
||||
LParam uintptr
|
||||
}
|
||||
|
||||
func positionDesktopUpload(fileName string, x, y int32) {
|
||||
listView := desktopListView()
|
||||
if listView == 0 {
|
||||
return
|
||||
}
|
||||
point := desktopDropPoint{X: x, Y: y}
|
||||
ddScreenToClient.Call(listView, uintptr(unsafe.Pointer(&point)))
|
||||
|
||||
// Explorer may need a moment to observe the newly created file.
|
||||
for attempt := 0; attempt < 20; attempt++ {
|
||||
if index := desktopListViewItemIndex(listView, fileName); index >= 0 {
|
||||
packed := uintptr(uint32(uint16(point.X)) | uint32(uint16(point.Y))<<16)
|
||||
ddSendMessageW.Call(listView, ddLVMSetItemPosition, uintptr(index), packed)
|
||||
return
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
func desktopListView() uintptr {
|
||||
progman, _, _ := ddFindWindowW.Call(uintptr(unsafe.Pointer(mustUTF16Ptr("Progman"))), 0)
|
||||
if view := findShellDefView(progman); view != 0 {
|
||||
list, _, _ := ddFindWindowExW.Call(view, 0, uintptr(unsafe.Pointer(mustUTF16Ptr("SysListView32"))), 0)
|
||||
return list
|
||||
}
|
||||
var after uintptr
|
||||
for {
|
||||
worker, _, _ := ddFindWindowExW.Call(0, after, uintptr(unsafe.Pointer(mustUTF16Ptr("WorkerW"))), 0)
|
||||
if worker == 0 {
|
||||
return 0
|
||||
}
|
||||
if view := findShellDefView(worker); view != 0 {
|
||||
list, _, _ := ddFindWindowExW.Call(view, 0, uintptr(unsafe.Pointer(mustUTF16Ptr("SysListView32"))), 0)
|
||||
return list
|
||||
}
|
||||
after = worker
|
||||
}
|
||||
}
|
||||
|
||||
func findShellDefView(parent uintptr) uintptr {
|
||||
if parent == 0 {
|
||||
return 0
|
||||
}
|
||||
view, _, _ := ddFindWindowExW.Call(parent, 0, uintptr(unsafe.Pointer(mustUTF16Ptr("SHELLDLL_DefView"))), 0)
|
||||
return view
|
||||
}
|
||||
|
||||
func desktopListViewItemIndex(listView uintptr, fileName string) int32 {
|
||||
var pid uint32
|
||||
ddGetWindowThreadProcessID.Call(listView, uintptr(unsafe.Pointer(&pid)))
|
||||
process, _, _ := ddOpenProcess.Call(ddProcessVMOperation|ddProcessVMRead|ddProcessVMWrite|ddProcessQueryInfo, 0, uintptr(pid))
|
||||
if process == 0 {
|
||||
return -1
|
||||
}
|
||||
defer windows.CloseHandle(windows.Handle(process))
|
||||
|
||||
const textChars = 520
|
||||
itemSize := unsafe.Sizeof(desktopDropLVItem{})
|
||||
remote, _, _ := ddVirtualAllocEx.Call(process, 0, itemSize+textChars*2, ddMemCommit|ddMemReserve, ddPageReadWrite)
|
||||
if remote == 0 {
|
||||
return -1
|
||||
}
|
||||
defer ddVirtualFreeEx.Call(process, remote, 0, ddMemRelease)
|
||||
item := desktopDropLVItem{ISubItem: 0, PszText: remote + itemSize, CchTextMax: textChars}
|
||||
ddWriteProcessMemory.Call(process, remote, uintptr(unsafe.Pointer(&item)), itemSize, 0)
|
||||
|
||||
count, _, _ := ddSendMessageW.Call(listView, ddLVMGetItemCount, 0, 0)
|
||||
want := strings.EqualFold
|
||||
stem := strings.TrimSuffix(fileName, filepath.Ext(fileName))
|
||||
buf := make([]uint16, textChars)
|
||||
for index := int32(0); index < int32(count); index++ {
|
||||
ddSendMessageW.Call(listView, ddLVMGetItemTextW, uintptr(index), remote)
|
||||
ddReadProcessMemory.Call(process, remote+itemSize, uintptr(unsafe.Pointer(&buf[0])), textChars*2, 0)
|
||||
name := syscall.UTF16ToString(buf)
|
||||
if want(name, fileName) || (stem != "" && want(name, stem)) {
|
||||
return index
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func mustUTF16Ptr(value string) *uint16 {
|
||||
pointer, _ := windows.UTF16PtrFromString(value)
|
||||
return pointer
|
||||
}
|
||||
Reference in New Issue
Block a user