|
|
@@ -21,6 +21,7 @@ var ( |
|
|
getWindowThreadProcessId = user32.NewProc("GetWindowThreadProcessId") |
|
|
getWindowThreadProcessId = user32.NewProc("GetWindowThreadProcessId") |
|
|
openProcess = kernel32.NewProc("OpenProcess") |
|
|
openProcess = kernel32.NewProc("OpenProcess") |
|
|
readProcessMemory = kernel32.NewProc("ReadProcessMemory") |
|
|
readProcessMemory = kernel32.NewProc("ReadProcessMemory") |
|
|
|
|
|
multiByteToWideChar = kernel32.NewProc("MultiByteToWideChar") |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
const ( |
|
|
const ( |
|
|
@@ -238,26 +239,58 @@ type TrackInfo struct { |
|
|
Title string `json:"title"` |
|
|
Title string `json:"title"` |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// readRemoteString reads a null-terminated ANSI string from another process. |
|
|
|
|
|
|
|
|
// readRemoteString reads a null-terminated ANSI string from another process |
|
|
|
|
|
// and converts it to UTF-8 via MultiByteToWideChar (CP_ACP = 0) so that |
|
|
|
|
|
// umlauts and other non-ASCII characters are handled correctly regardless of |
|
|
|
|
|
// the active Windows code page. |
|
|
func readRemoteString(proc syscall.Handle, ptr uintptr) string { |
|
|
func readRemoteString(proc syscall.Handle, ptr uintptr) string { |
|
|
if ptr == 0 { |
|
|
if ptr == 0 { |
|
|
return "" |
|
|
return "" |
|
|
} |
|
|
} |
|
|
buf := make([]byte, 512) |
|
|
buf := make([]byte, 512) |
|
|
var read uintptr |
|
|
var read uintptr |
|
|
readProcessMemory.Call( |
|
|
|
|
|
|
|
|
ok, _, _ := readProcessMemory.Call( |
|
|
uintptr(proc), |
|
|
uintptr(proc), |
|
|
ptr, |
|
|
ptr, |
|
|
uintptr(unsafe.Pointer(&buf[0])), |
|
|
uintptr(unsafe.Pointer(&buf[0])), |
|
|
uintptr(len(buf)), |
|
|
uintptr(len(buf)), |
|
|
uintptr(unsafe.Pointer(&read)), |
|
|
uintptr(unsafe.Pointer(&read)), |
|
|
) |
|
|
) |
|
|
for i, b := range buf { |
|
|
|
|
|
|
|
|
if ok == 0 || read == 0 { |
|
|
|
|
|
return "" |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Trim to null terminator. |
|
|
|
|
|
ansi := buf[:read] |
|
|
|
|
|
for i, b := range ansi { |
|
|
if b == 0 { |
|
|
if b == 0 { |
|
|
return string(buf[:i]) |
|
|
|
|
|
|
|
|
ansi = ansi[:i] |
|
|
|
|
|
break |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
return string(buf) |
|
|
|
|
|
|
|
|
if len(ansi) == 0 { |
|
|
|
|
|
return "" |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// First call: query required UTF-16 buffer size. |
|
|
|
|
|
const cpACP = 0 |
|
|
|
|
|
n, _, _ := multiByteToWideChar.Call( |
|
|
|
|
|
cpACP, 0, |
|
|
|
|
|
uintptr(unsafe.Pointer(&ansi[0])), uintptr(len(ansi)), |
|
|
|
|
|
0, 0, |
|
|
|
|
|
) |
|
|
|
|
|
if n == 0 { |
|
|
|
|
|
return string(ansi) // fallback: treat as latin-1 |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Second call: do the conversion. |
|
|
|
|
|
wide := make([]uint16, n) |
|
|
|
|
|
multiByteToWideChar.Call( |
|
|
|
|
|
cpACP, 0, |
|
|
|
|
|
uintptr(unsafe.Pointer(&ansi[0])), uintptr(len(ansi)), |
|
|
|
|
|
uintptr(unsafe.Pointer(&wide[0])), n, |
|
|
|
|
|
) |
|
|
|
|
|
return syscall.UTF16ToString(wide) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// GetPlaylist returns all titles in the current Winamp playlist. |
|
|
// GetPlaylist returns all titles in the current Winamp playlist. |
|
|
|