go-toast

Send toast notifications in Windows
Log | Files | Refs | README | LICENSE

kernel32.go (2137B)


      1 //go:build windows
      2 
      3 package kernel32
      4 
      5 import (
      6 	"sync/atomic"
      7 	"syscall"
      8 	"unsafe"
      9 
     10 	"golang.org/x/sys/windows"
     11 )
     12 
     13 type (
     14 	heapHandle = uintptr
     15 	win32Error uint32
     16 	heapFlags  uint32
     17 )
     18 
     19 const (
     20 	heapNone       heapFlags = 0
     21 	heapZeroMemory heapFlags = 8 // The allocated memory will be initialized to zero.
     22 )
     23 
     24 var (
     25 	libKernel32 = windows.NewLazySystemDLL("kernel32.dll")
     26 
     27 	pHeapFree       uintptr
     28 	pHeapAlloc      uintptr
     29 	pGetProcessHeap uintptr
     30 
     31 	hHeap heapHandle
     32 )
     33 
     34 func init() {
     35 	hHeap, _ = getProcessHeap()
     36 }
     37 
     38 // Malloc allocates the given amount of bytes in the heap
     39 func Malloc(size uintptr) unsafe.Pointer {
     40 	return heapAlloc(hHeap, heapZeroMemory, size)
     41 }
     42 
     43 // Free releases the given unsafe pointer from the heap
     44 func Free(inst unsafe.Pointer) {
     45 	_, _ = heapFree(hHeap, heapNone, inst)
     46 }
     47 
     48 // https://docs.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heapalloc
     49 func heapAlloc(hHeap heapHandle, dwFlags heapFlags, dwBytes uintptr) unsafe.Pointer {
     50 	addr := getProcAddr(&pHeapAlloc, libKernel32, "HeapAlloc")
     51 	allocatedPtr, _, _ := syscall.SyscallN(addr, hHeap, uintptr(dwFlags), dwBytes)
     52 	// Since this pointer is allocated in the heap by Windows, it will never be
     53 	// GCd by Go, so this is a safe operation.
     54 	// But linter thinks it is not (probably because we are not using CGO) and fails.
     55 	return unsafe.Pointer(allocatedPtr) //nolint:gosec,govet
     56 }
     57 
     58 // https://docs.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heapfree
     59 func heapFree(hHeap heapHandle, dwFlags heapFlags, lpMem unsafe.Pointer) (bool, win32Error) {
     60 	addr := getProcAddr(&pHeapFree, libKernel32, "HeapFree")
     61 	ret, _, err := syscall.SyscallN(addr, hHeap, uintptr(dwFlags), uintptr(lpMem))
     62 	return ret == 0, win32Error(err)
     63 }
     64 
     65 func getProcessHeap() (heapHandle, win32Error) {
     66 	addr := getProcAddr(&pGetProcessHeap, libKernel32, "GetProcessHeap")
     67 	ret, _, err := syscall.SyscallN(addr)
     68 	return ret, win32Error(err)
     69 }
     70 
     71 func getProcAddr(pAddr *uintptr, lib *windows.LazyDLL, procName string) uintptr {
     72 	addr := atomic.LoadUintptr(pAddr)
     73 	if addr == 0 {
     74 		addr = lib.NewProc(procName).Addr()
     75 		atomic.StoreUintptr(pAddr, addr)
     76 	}
     77 	return addr
     78 }