windows: add resource extraction functions

These functions make it possible to read executable resource information
at runtime.

Change-Id: I00f260199ecda8daeb3417eaa9c02198663063b7
Reviewed-on: https://go-review.googlesource.com/c/sys/+/298173
Trust: Jason A. Donenfeld <Jason@zx2c4.com>
Trust: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Jason A. Donenfeld <Jason@zx2c4.com>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
This commit is contained in:
Jason A. Donenfeld
2021-03-05 02:33:59 +00:00
parent 7b4935edff
commit f9bc61c02a
4 changed files with 163 additions and 0 deletions
+57
View File
@@ -9,6 +9,7 @@ package windows
import (
errorspkg "errors"
"fmt"
"runtime"
"sync"
"syscall"
"time"
@@ -384,6 +385,10 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys getThreadPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint16, bufSize *uint32) (err error) = kernel32.GetThreadPreferredUILanguages
//sys getUserPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint16, bufSize *uint32) (err error) = kernel32.GetUserPreferredUILanguages
//sys getSystemPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint16, bufSize *uint32) (err error) = kernel32.GetSystemPreferredUILanguages
//sys findResource(module Handle, name uintptr, resType uintptr) (resInfo Handle, err error) = kernel32.FindResourceW
//sys SizeofResource(module Handle, resInfo Handle) (size uint32, err error) = kernel32.SizeofResource
//sys LoadResource(module Handle, resInfo Handle) (resData Handle, err error) = kernel32.LoadResource
//sys LockResource(resData Handle) (addr uintptr, err error) = kernel32.LockResource
// Process Status API (PSAPI)
//sys EnumProcesses(processIds []uint32, bytesReturned *uint32) (err error) = psapi.EnumProcesses
@@ -1578,3 +1583,55 @@ func (s *UNICODE_STRING) Slice() []uint16 {
func (s *UNICODE_STRING) String() string {
return UTF16ToString(s.Slice())
}
// FindResource resolves a resource of the given name and resource type.
func FindResource(module Handle, name, resType ResourceIDOrString) (Handle, error) {
var namePtr, resTypePtr uintptr
var name16, resType16 *uint16
var err error
resolvePtr := func(i interface{}, keep **uint16) (uintptr, error) {
switch v := i.(type) {
case string:
*keep, err = UTF16PtrFromString(v)
if err != nil {
return 0, err
}
return uintptr(unsafe.Pointer(*keep)), nil
case ResourceID:
return uintptr(v), nil
}
return 0, errorspkg.New("parameter must be a ResourceID or a string")
}
namePtr, err = resolvePtr(name, &name16)
if err != nil {
return 0, err
}
resTypePtr, err = resolvePtr(resType, &resType16)
if err != nil {
return 0, err
}
resInfo, err := findResource(module, namePtr, resTypePtr)
runtime.KeepAlive(name16)
runtime.KeepAlive(resType16)
return resInfo, err
}
func LoadResourceData(module, resInfo Handle) (data []byte, err error) {
size, err := SizeofResource(module, resInfo)
if err != nil {
return
}
resData, err := LoadResource(module, resInfo)
if err != nil {
return
}
ptr, err := LockResource(resData)
if err != nil {
return
}
h := (*unsafeheader.Slice)(unsafe.Pointer(&data))
h.Data = unsafe.Pointer(ptr)
h.Len = int(size)
h.Cap = int(size)
return
}