2019-07-31 06:09:38 +00:00
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Windows system calls.
package windows
import (
errorspkg "errors"
"sync"
"syscall"
"time"
"unicode/utf16"
"unsafe"
)
type Handle uintptr
const (
InvalidHandle = ^ Handle ( 0 )
// Flags for DefineDosDevice.
DDD_EXACT_MATCH_ON_REMOVE = 0x00000004
DDD_NO_BROADCAST_SYSTEM = 0x00000008
DDD_RAW_TARGET_PATH = 0x00000001
DDD_REMOVE_DEFINITION = 0x00000002
// Return values for GetDriveType.
DRIVE_UNKNOWN = 0
DRIVE_NO_ROOT_DIR = 1
DRIVE_REMOVABLE = 2
DRIVE_FIXED = 3
DRIVE_REMOTE = 4
DRIVE_CDROM = 5
DRIVE_RAMDISK = 6
// File system flags from GetVolumeInformation and GetVolumeInformationByHandle.
FILE_CASE_SENSITIVE_SEARCH = 0x00000001
FILE_CASE_PRESERVED_NAMES = 0x00000002
FILE_FILE_COMPRESSION = 0x00000010
FILE_DAX_VOLUME = 0x20000000
FILE_NAMED_STREAMS = 0x00040000
FILE_PERSISTENT_ACLS = 0x00000008
FILE_READ_ONLY_VOLUME = 0x00080000
FILE_SEQUENTIAL_WRITE_ONCE = 0x00100000
FILE_SUPPORTS_ENCRYPTION = 0x00020000
FILE_SUPPORTS_EXTENDED_ATTRIBUTES = 0x00800000
FILE_SUPPORTS_HARD_LINKS = 0x00400000
FILE_SUPPORTS_OBJECT_IDS = 0x00010000
FILE_SUPPORTS_OPEN_BY_FILE_ID = 0x01000000
FILE_SUPPORTS_REPARSE_POINTS = 0x00000080
FILE_SUPPORTS_SPARSE_FILES = 0x00000040
FILE_SUPPORTS_TRANSACTIONS = 0x00200000
FILE_SUPPORTS_USN_JOURNAL = 0x02000000
FILE_UNICODE_ON_DISK = 0x00000004
FILE_VOLUME_IS_COMPRESSED = 0x00008000
FILE_VOLUME_QUOTAS = 0x00000020
2020-01-31 09:32:00 +00:00
// Flags for LockFileEx.
LOCKFILE_FAIL_IMMEDIATELY = 0x00000001
LOCKFILE_EXCLUSIVE_LOCK = 0x00000002
2019-07-31 06:09:38 +00:00
// Return values of SleepEx and other APC functions
STATUS_USER_APC = 0x000000C0
WAIT_IO_COMPLETION = STATUS_USER_APC
)
// StringToUTF16 is deprecated. Use UTF16FromString instead.
// If s contains a NUL byte this function panics instead of
// returning an error.
func StringToUTF16 ( s string ) [ ] uint16 {
a , err := UTF16FromString ( s )
if err != nil {
panic ( "windows: string with NUL passed to StringToUTF16" )
}
return a
}
// UTF16FromString returns the UTF-16 encoding of the UTF-8 string
// s, with a terminating NUL added. If s contains a NUL byte at any
// location, it returns (nil, syscall.EINVAL).
func UTF16FromString ( s string ) ( [ ] uint16 , error ) {
for i := 0 ; i < len ( s ) ; i ++ {
if s [ i ] == 0 {
return nil , syscall . EINVAL
}
}
return utf16 . Encode ( [ ] rune ( s + "\x00" ) ) , nil
}
// UTF16ToString returns the UTF-8 encoding of the UTF-16 sequence s,
// with a terminating NUL removed.
func UTF16ToString ( s [ ] uint16 ) string {
for i , v := range s {
if v == 0 {
s = s [ 0 : i ]
break
}
}
return string ( utf16 . Decode ( s ) )
}
// StringToUTF16Ptr is deprecated. Use UTF16PtrFromString instead.
// If s contains a NUL byte this function panics instead of
// returning an error.
func StringToUTF16Ptr ( s string ) * uint16 { return & StringToUTF16 ( s ) [ 0 ] }
// UTF16PtrFromString returns pointer to the UTF-16 encoding of
// the UTF-8 string s, with a terminating NUL added. If s
// contains a NUL byte at any location, it returns (nil, syscall.EINVAL).
func UTF16PtrFromString ( s string ) ( * uint16 , error ) {
a , err := UTF16FromString ( s )
if err != nil {
return nil , err
}
return & a [ 0 ] , nil
}
func Getpagesize ( ) int { return 4096 }
// NewCallback converts a Go function to a function pointer conforming to the stdcall calling convention.
// This is useful when interoperating with Windows code requiring callbacks.
// The argument is expected to be a function with with one uintptr-sized result. The function must not have arguments with size larger than the size of uintptr.
func NewCallback ( fn interface { } ) uintptr {
return syscall . NewCallback ( fn )
}
// NewCallbackCDecl converts a Go function to a function pointer conforming to the cdecl calling convention.
// This is useful when interoperating with Windows code requiring callbacks.
// The argument is expected to be a function with with one uintptr-sized result. The function must not have arguments with size larger than the size of uintptr.
func NewCallbackCDecl ( fn interface { } ) uintptr {
return syscall . NewCallbackCDecl ( fn )
}
// windows api calls
//sys GetLastError() (lasterr error)
//sys LoadLibrary(libname string) (handle Handle, err error) = LoadLibraryW
//sys LoadLibraryEx(libname string, zero Handle, flags uintptr) (handle Handle, err error) = LoadLibraryExW
//sys FreeLibrary(handle Handle) (err error)
//sys GetProcAddress(module Handle, procname string) (proc uintptr, err error)
2020-01-31 09:32:00 +00:00
//sys GetModuleFileName(module Handle, filename *uint16, size uint32) (n uint32, err error) = kernel32.GetModuleFileNameW
//sys GetModuleHandleEx(flags uint32, moduleName *uint16, module *Handle) (err error) = kernel32.GetModuleHandleExW
2019-07-31 06:09:38 +00:00
//sys GetVersion() (ver uint32, err error)
//sys FormatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) = FormatMessageW
//sys ExitProcess(exitcode uint32)
//sys IsWow64Process(handle Handle, isWow64 *bool) (err error) = IsWow64Process
//sys CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile Handle) (handle Handle, err error) [failretval==InvalidHandle] = CreateFileW
//sys ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error)
//sys WriteFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error)
//sys GetOverlappedResult(handle Handle, overlapped *Overlapped, done *uint32, wait bool) (err error)
//sys SetFilePointer(handle Handle, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, err error) [failretval==0xffffffff]
//sys CloseHandle(handle Handle) (err error)
//sys GetStdHandle(stdhandle uint32) (handle Handle, err error) [failretval==InvalidHandle]
//sys SetStdHandle(stdhandle uint32, handle Handle) (err error)
//sys findFirstFile1(name *uint16, data *win32finddata1) (handle Handle, err error) [failretval==InvalidHandle] = FindFirstFileW
//sys findNextFile1(handle Handle, data *win32finddata1) (err error) = FindNextFileW
//sys FindClose(handle Handle) (err error)
//sys GetFileInformationByHandle(handle Handle, data *ByHandleFileInformation) (err error)
//sys GetFileInformationByHandleEx(handle Handle, class uint32, outBuffer *byte, outBufferLen uint32) (err error)
//sys GetCurrentDirectory(buflen uint32, buf *uint16) (n uint32, err error) = GetCurrentDirectoryW
//sys SetCurrentDirectory(path *uint16) (err error) = SetCurrentDirectoryW
//sys CreateDirectory(path *uint16, sa *SecurityAttributes) (err error) = CreateDirectoryW
//sys RemoveDirectory(path *uint16) (err error) = RemoveDirectoryW
//sys DeleteFile(path *uint16) (err error) = DeleteFileW
//sys MoveFile(from *uint16, to *uint16) (err error) = MoveFileW
//sys MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) = MoveFileExW
2020-01-31 09:32:00 +00:00
//sys LockFileEx(file Handle, flags uint32, reserved uint32, bytesLow uint32, bytesHigh uint32, overlapped *Overlapped) (err error)
//sys UnlockFileEx(file Handle, reserved uint32, bytesLow uint32, bytesHigh uint32, overlapped *Overlapped) (err error)
2019-07-31 06:09:38 +00:00
//sys GetComputerName(buf *uint16, n *uint32) (err error) = GetComputerNameW
//sys GetComputerNameEx(nametype uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW
//sys SetEndOfFile(handle Handle) (err error)
//sys GetSystemTimeAsFileTime(time *Filetime)
//sys GetSystemTimePreciseAsFileTime(time *Filetime)
//sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) [failretval==0xffffffff]
//sys CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uint32, threadcnt uint32) (handle Handle, err error)
//sys GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (err error)
//sys PostQueuedCompletionStatus(cphandle Handle, qty uint32, key uint32, overlapped *Overlapped) (err error)
//sys CancelIo(s Handle) (err error)
//sys CancelIoEx(s Handle, o *Overlapped) (err error)
//sys CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) = CreateProcessW
//sys OpenProcess(desiredAccess uint32, inheritHandle bool, processId uint32) (handle Handle, err error)
2020-01-31 09:32:00 +00:00
//sys ShellExecute(hwnd Handle, verb *uint16, file *uint16, args *uint16, cwd *uint16, showCmd int32) (err error) [failretval<=32] = shell32.ShellExecuteW
2019-07-31 06:09:38 +00:00
//sys shGetKnownFolderPath(id *KNOWNFOLDERID, flags uint32, token Token, path **uint16) (ret error) = shell32.SHGetKnownFolderPath
//sys TerminateProcess(handle Handle, exitcode uint32) (err error)
//sys GetExitCodeProcess(handle Handle, exitcode *uint32) (err error)
//sys GetStartupInfo(startupInfo *StartupInfo) (err error) = GetStartupInfoW
//sys GetProcessTimes(handle Handle, creationTime *Filetime, exitTime *Filetime, kernelTime *Filetime, userTime *Filetime) (err error)
//sys DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (err error)
//sys WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, err error) [failretval==0xffffffff]
//sys waitForMultipleObjects(count uint32, handles uintptr, waitAll bool, waitMilliseconds uint32) (event uint32, err error) [failretval==0xffffffff] = WaitForMultipleObjects
//sys GetTempPath(buflen uint32, buf *uint16) (n uint32, err error) = GetTempPathW
//sys CreatePipe(readhandle *Handle, writehandle *Handle, sa *SecurityAttributes, size uint32) (err error)
//sys GetFileType(filehandle Handle) (n uint32, err error)
//sys CryptAcquireContext(provhandle *Handle, container *uint16, provider *uint16, provtype uint32, flags uint32) (err error) = advapi32.CryptAcquireContextW
//sys CryptReleaseContext(provhandle Handle, flags uint32) (err error) = advapi32.CryptReleaseContext
//sys CryptGenRandom(provhandle Handle, buflen uint32, buf *byte) (err error) = advapi32.CryptGenRandom
//sys GetEnvironmentStrings() (envs *uint16, err error) [failretval==nil] = kernel32.GetEnvironmentStringsW
//sys FreeEnvironmentStrings(envs *uint16) (err error) = kernel32.FreeEnvironmentStringsW
//sys GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, err error) = kernel32.GetEnvironmentVariableW
//sys SetEnvironmentVariable(name *uint16, value *uint16) (err error) = kernel32.SetEnvironmentVariableW
//sys CreateEnvironmentBlock(block **uint16, token Token, inheritExisting bool) (err error) = userenv.CreateEnvironmentBlock
//sys DestroyEnvironmentBlock(block *uint16) (err error) = userenv.DestroyEnvironmentBlock
//sys getTickCount64() (ms uint64) = kernel32.GetTickCount64
//sys SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (err error)
//sys GetFileAttributes(name *uint16) (attrs uint32, err error) [failretval==INVALID_FILE_ATTRIBUTES] = kernel32.GetFileAttributesW
//sys SetFileAttributes(name *uint16, attrs uint32) (err error) = kernel32.SetFileAttributesW
//sys GetFileAttributesEx(name *uint16, level uint32, info *byte) (err error) = kernel32.GetFileAttributesExW
//sys GetCommandLine() (cmd *uint16) = kernel32.GetCommandLineW
//sys CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, err error) [failretval==nil] = shell32.CommandLineToArgvW
//sys LocalFree(hmem Handle) (handle Handle, err error) [failretval!=0]
//sys SetHandleInformation(handle Handle, mask uint32, flags uint32) (err error)
//sys FlushFileBuffers(handle Handle) (err error)
//sys GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (n uint32, err error) = kernel32.GetFullPathNameW
//sys GetLongPathName(path *uint16, buf *uint16, buflen uint32) (n uint32, err error) = kernel32.GetLongPathNameW
//sys GetShortPathName(longpath *uint16, shortpath *uint16, buflen uint32) (n uint32, err error) = kernel32.GetShortPathNameW
//sys CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, err error) = kernel32.CreateFileMappingW
//sys MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow uint32, length uintptr) (addr uintptr, err error)
//sys UnmapViewOfFile(addr uintptr) (err error)
//sys FlushViewOfFile(addr uintptr, length uintptr) (err error)
//sys VirtualLock(addr uintptr, length uintptr) (err error)
//sys VirtualUnlock(addr uintptr, length uintptr) (err error)
//sys VirtualAlloc(address uintptr, size uintptr, alloctype uint32, protect uint32) (value uintptr, err error) = kernel32.VirtualAlloc
//sys VirtualFree(address uintptr, size uintptr, freetype uint32) (err error) = kernel32.VirtualFree
//sys VirtualProtect(address uintptr, size uintptr, newprotect uint32, oldprotect *uint32) (err error) = kernel32.VirtualProtect
//sys TransmitFile(s Handle, handle Handle, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (err error) = mswsock.TransmitFile
//sys ReadDirectoryChanges(handle Handle, buf *byte, buflen uint32, watchSubTree bool, mask uint32, retlen *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) = kernel32.ReadDirectoryChangesW
//sys CertOpenSystemStore(hprov Handle, name *uint16) (store Handle, err error) = crypt32.CertOpenSystemStoreW
//sys CertOpenStore(storeProvider uintptr, msgAndCertEncodingType uint32, cryptProv uintptr, flags uint32, para uintptr) (handle Handle, err error) [failretval==InvalidHandle] = crypt32.CertOpenStore
//sys CertEnumCertificatesInStore(store Handle, prevContext *CertContext) (context *CertContext, err error) [failretval==nil] = crypt32.CertEnumCertificatesInStore
//sys CertAddCertificateContextToStore(store Handle, certContext *CertContext, addDisposition uint32, storeContext **CertContext) (err error) = crypt32.CertAddCertificateContextToStore
//sys CertCloseStore(store Handle, flags uint32) (err error) = crypt32.CertCloseStore
//sys CertGetCertificateChain(engine Handle, leaf *CertContext, time *Filetime, additionalStore Handle, para *CertChainPara, flags uint32, reserved uintptr, chainCtx **CertChainContext) (err error) = crypt32.CertGetCertificateChain
//sys CertFreeCertificateChain(ctx *CertChainContext) = crypt32.CertFreeCertificateChain
//sys CertCreateCertificateContext(certEncodingType uint32, certEncoded *byte, encodedLen uint32) (context *CertContext, err error) [failretval==nil] = crypt32.CertCreateCertificateContext
//sys CertFreeCertificateContext(ctx *CertContext) (err error) = crypt32.CertFreeCertificateContext
//sys CertVerifyCertificateChainPolicy(policyOID uintptr, chain *CertChainContext, para *CertChainPolicyPara, status *CertChainPolicyStatus) (err error) = crypt32.CertVerifyCertificateChainPolicy
//sys RegOpenKeyEx(key Handle, subkey *uint16, options uint32, desiredAccess uint32, result *Handle) (regerrno error) = advapi32.RegOpenKeyExW
//sys RegCloseKey(key Handle) (regerrno error) = advapi32.RegCloseKey
//sys RegQueryInfoKey(key Handle, class *uint16, classLen *uint32, reserved *uint32, subkeysLen *uint32, maxSubkeyLen *uint32, maxClassLen *uint32, valuesLen *uint32, maxValueNameLen *uint32, maxValueLen *uint32, saLen *uint32, lastWriteTime *Filetime) (regerrno error) = advapi32.RegQueryInfoKeyW
//sys RegEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno error) = advapi32.RegEnumKeyExW
//sys RegQueryValueEx(key Handle, name *uint16, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) = advapi32.RegQueryValueExW
//sys GetCurrentProcessId() (pid uint32) = kernel32.GetCurrentProcessId
//sys GetConsoleMode(console Handle, mode *uint32) (err error) = kernel32.GetConsoleMode
//sys SetConsoleMode(console Handle, mode uint32) (err error) = kernel32.SetConsoleMode
//sys GetConsoleScreenBufferInfo(console Handle, info *ConsoleScreenBufferInfo) (err error) = kernel32.GetConsoleScreenBufferInfo
//sys WriteConsole(console Handle, buf *uint16, towrite uint32, written *uint32, reserved *byte) (err error) = kernel32.WriteConsoleW
//sys ReadConsole(console Handle, buf *uint16, toread uint32, read *uint32, inputControl *byte) (err error) = kernel32.ReadConsoleW
//sys CreateToolhelp32Snapshot(flags uint32, processId uint32) (handle Handle, err error) [failretval==InvalidHandle] = kernel32.CreateToolhelp32Snapshot
//sys Process32First(snapshot Handle, procEntry *ProcessEntry32) (err error) = kernel32.Process32FirstW
//sys Process32Next(snapshot Handle, procEntry *ProcessEntry32) (err error) = kernel32.Process32NextW
//sys Thread32First(snapshot Handle, threadEntry *ThreadEntry32) (err error)
//sys Thread32Next(snapshot Handle, threadEntry *ThreadEntry32) (err error)
//sys DeviceIoControl(handle Handle, ioControlCode uint32, inBuffer *byte, inBufferSize uint32, outBuffer *byte, outBufferSize uint32, bytesReturned *uint32, overlapped *Overlapped) (err error)
// This function returns 1 byte BOOLEAN rather than the 4 byte BOOL.
//sys CreateSymbolicLink(symlinkfilename *uint16, targetfilename *uint16, flags uint32) (err error) [failretval&0xff==0] = CreateSymbolicLinkW
//sys CreateHardLink(filename *uint16, existingfilename *uint16, reserved uintptr) (err error) [failretval&0xff==0] = CreateHardLinkW
//sys GetCurrentThreadId() (id uint32)
//sys CreateEvent(eventAttrs *SecurityAttributes, manualReset uint32, initialState uint32, name *uint16) (handle Handle, err error) = kernel32.CreateEventW
//sys CreateEventEx(eventAttrs *SecurityAttributes, name *uint16, flags uint32, desiredAccess uint32) (handle Handle, err error) = kernel32.CreateEventExW
//sys OpenEvent(desiredAccess uint32, inheritHandle bool, name *uint16) (handle Handle, err error) = kernel32.OpenEventW
//sys SetEvent(event Handle) (err error) = kernel32.SetEvent
//sys ResetEvent(event Handle) (err error) = kernel32.ResetEvent
//sys PulseEvent(event Handle) (err error) = kernel32.PulseEvent
2020-01-31 09:32:00 +00:00
//sys CreateMutex(mutexAttrs *SecurityAttributes, initialOwner bool, name *uint16) (handle Handle, err error) = kernel32.CreateMutexW
//sys CreateMutexEx(mutexAttrs *SecurityAttributes, name *uint16, flags uint32, desiredAccess uint32) (handle Handle, err error) = kernel32.CreateMutexExW
//sys OpenMutex(desiredAccess uint32, inheritHandle bool, name *uint16) (handle Handle, err error) = kernel32.OpenMutexW
//sys ReleaseMutex(mutex Handle) (err error) = kernel32.ReleaseMutex
2019-07-31 06:09:38 +00:00
//sys SleepEx(milliseconds uint32, alertable bool) (ret uint32) = kernel32.SleepEx
//sys CreateJobObject(jobAttr *SecurityAttributes, name *uint16) (handle Handle, err error) = kernel32.CreateJobObjectW
//sys AssignProcessToJobObject(job Handle, process Handle) (err error) = kernel32.AssignProcessToJobObject
//sys TerminateJobObject(job Handle, exitCode uint32) (err error) = kernel32.TerminateJobObject
//sys SetErrorMode(mode uint32) (ret uint32) = kernel32.SetErrorMode
//sys ResumeThread(thread Handle) (ret uint32, err error) [failretval==0xffffffff] = kernel32.ResumeThread
//sys SetPriorityClass(process Handle, priorityClass uint32) (err error) = kernel32.SetPriorityClass
//sys GetPriorityClass(process Handle) (ret uint32, err error) = kernel32.GetPriorityClass
//sys SetInformationJobObject(job Handle, JobObjectInformationClass uint32, JobObjectInformation uintptr, JobObjectInformationLength uint32) (ret int, err error)
//sys GenerateConsoleCtrlEvent(ctrlEvent uint32, processGroupID uint32) (err error)
//sys GetProcessId(process Handle) (id uint32, err error)
//sys OpenThread(desiredAccess uint32, inheritHandle bool, threadId uint32) (handle Handle, err error)
2020-01-31 09:32:00 +00:00
//sys SetProcessPriorityBoost(process Handle, disable bool) (err error) = kernel32.SetProcessPriorityBoost
2019-07-31 06:09:38 +00:00
// Volume Management Functions
//sys DefineDosDevice(flags uint32, deviceName *uint16, targetPath *uint16) (err error) = DefineDosDeviceW
//sys DeleteVolumeMountPoint(volumeMountPoint *uint16) (err error) = DeleteVolumeMountPointW
//sys FindFirstVolume(volumeName *uint16, bufferLength uint32) (handle Handle, err error) [failretval==InvalidHandle] = FindFirstVolumeW
//sys FindFirstVolumeMountPoint(rootPathName *uint16, volumeMountPoint *uint16, bufferLength uint32) (handle Handle, err error) [failretval==InvalidHandle] = FindFirstVolumeMountPointW
//sys FindNextVolume(findVolume Handle, volumeName *uint16, bufferLength uint32) (err error) = FindNextVolumeW
//sys FindNextVolumeMountPoint(findVolumeMountPoint Handle, volumeMountPoint *uint16, bufferLength uint32) (err error) = FindNextVolumeMountPointW
//sys FindVolumeClose(findVolume Handle) (err error)
//sys FindVolumeMountPointClose(findVolumeMountPoint Handle) (err error)
2020-01-31 09:32:00 +00:00
//sys GetDiskFreeSpaceEx(directoryName *uint16, freeBytesAvailableToCaller *uint64, totalNumberOfBytes *uint64, totalNumberOfFreeBytes *uint64) (err error) = GetDiskFreeSpaceExW
2019-07-31 06:09:38 +00:00
//sys GetDriveType(rootPathName *uint16) (driveType uint32) = GetDriveTypeW
//sys GetLogicalDrives() (drivesBitMask uint32, err error) [failretval==0]
//sys GetLogicalDriveStrings(bufferLength uint32, buffer *uint16) (n uint32, err error) [failretval==0] = GetLogicalDriveStringsW
//sys GetVolumeInformation(rootPathName *uint16, volumeNameBuffer *uint16, volumeNameSize uint32, volumeNameSerialNumber *uint32, maximumComponentLength *uint32, fileSystemFlags *uint32, fileSystemNameBuffer *uint16, fileSystemNameSize uint32) (err error) = GetVolumeInformationW
//sys GetVolumeInformationByHandle(file Handle, volumeNameBuffer *uint16, volumeNameSize uint32, volumeNameSerialNumber *uint32, maximumComponentLength *uint32, fileSystemFlags *uint32, fileSystemNameBuffer *uint16, fileSystemNameSize uint32) (err error) = GetVolumeInformationByHandleW
//sys GetVolumeNameForVolumeMountPoint(volumeMountPoint *uint16, volumeName *uint16, bufferlength uint32) (err error) = GetVolumeNameForVolumeMountPointW
//sys GetVolumePathName(fileName *uint16, volumePathName *uint16, bufferLength uint32) (err error) = GetVolumePathNameW
//sys GetVolumePathNamesForVolumeName(volumeName *uint16, volumePathNames *uint16, bufferLength uint32, returnLength *uint32) (err error) = GetVolumePathNamesForVolumeNameW
//sys QueryDosDevice(deviceName *uint16, targetPath *uint16, max uint32) (n uint32, err error) [failretval==0] = QueryDosDeviceW
//sys SetVolumeLabel(rootPathName *uint16, volumeName *uint16) (err error) = SetVolumeLabelW
//sys SetVolumeMountPoint(volumeMountPoint *uint16, volumeName *uint16) (err error) = SetVolumeMountPointW
//sys MessageBox(hwnd Handle, text *uint16, caption *uint16, boxtype uint32) (ret int32, err error) [failretval==0] = user32.MessageBoxW
2020-01-31 09:32:00 +00:00
//sys ExitWindowsEx(flags uint32, reason uint32) (err error) = user32.ExitWindowsEx
//sys InitiateSystemShutdownEx(machineName *uint16, message *uint16, timeout uint32, forceAppsClosed bool, rebootAfterShutdown bool, reason uint32) (err error) = advapi32.InitiateSystemShutdownExW
//sys SetProcessShutdownParameters(level uint32, flags uint32) (err error) = kernel32.SetProcessShutdownParameters
//sys GetProcessShutdownParameters(level *uint32, flags *uint32) (err error) = kernel32.GetProcessShutdownParameters
2019-07-31 06:09:38 +00:00
//sys clsidFromString(lpsz *uint16, pclsid *GUID) (ret error) = ole32.CLSIDFromString
//sys stringFromGUID2(rguid *GUID, lpsz *uint16, cchMax int32) (chars int32) = ole32.StringFromGUID2
//sys coCreateGuid(pguid *GUID) (ret error) = ole32.CoCreateGuid
//sys CoTaskMemFree(address unsafe.Pointer) = ole32.CoTaskMemFree
//sys rtlGetVersion(info *OsVersionInfoEx) (ret error) = ntdll.RtlGetVersion
2020-01-31 09:32:00 +00:00
//sys rtlGetNtVersionNumbers(majorVersion *uint32, minorVersion *uint32, buildNumber *uint32) = ntdll.RtlGetNtVersionNumbers
//sys getProcessPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint16, bufSize *uint32) (err error) = kernel32.GetProcessPreferredUILanguages
//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
// Process Status API (PSAPI)
//sys EnumProcesses(processIds []uint32, bytesReturned *uint32) (err error) = psapi.EnumProcesses
2019-07-31 06:09:38 +00:00
// syscall interface implementation for other packages
2020-01-31 09:32:00 +00:00
// GetCurrentProcess returns the handle for the current process.
// It is a pseudo handle that does not need to be closed.
// The returned error is always nil.
//
// Deprecated: use CurrentProcess for the same Handle without the nil
// error.
func GetCurrentProcess ( ) ( Handle , error ) {
return CurrentProcess ( ) , nil
}
// CurrentProcess returns the handle for the current process.
// It is a pseudo handle that does not need to be closed.
func CurrentProcess ( ) Handle { return Handle ( ^ uintptr ( 1 - 1 ) ) }
// GetCurrentThread returns the handle for the current thread.
// It is a pseudo handle that does not need to be closed.
// The returned error is always nil.
//
// Deprecated: use CurrentThread for the same Handle without the nil
// error.
func GetCurrentThread ( ) ( Handle , error ) {
return CurrentThread ( ) , nil
}
// CurrentThread returns the handle for the current thread.
// It is a pseudo handle that does not need to be closed.
func CurrentThread ( ) Handle { return Handle ( ^ uintptr ( 2 - 1 ) ) }
2019-07-31 06:09:38 +00:00
// GetProcAddressByOrdinal retrieves the address of the exported
// function from module by ordinal.
func GetProcAddressByOrdinal ( module Handle , ordinal uintptr ) ( proc uintptr , err error ) {
r0 , _ , e1 := syscall . Syscall ( procGetProcAddress . Addr ( ) , 2 , uintptr ( module ) , ordinal , 0 )
proc = uintptr ( r0 )
if proc == 0 {
if e1 != 0 {
err = errnoErr ( e1 )
} else {
err = syscall . EINVAL
}
}
return
}
func Exit ( code int ) { ExitProcess ( uint32 ( code ) ) }
func makeInheritSa ( ) * SecurityAttributes {
var sa SecurityAttributes
sa . Length = uint32 ( unsafe . Sizeof ( sa ) )
sa . InheritHandle = 1
return & sa
}
func Open ( path string , mode int , perm uint32 ) ( fd Handle , err error ) {
if len ( path ) == 0 {
return InvalidHandle , ERROR_FILE_NOT_FOUND
}
pathp , err := UTF16PtrFromString ( path )
if err != nil {
return InvalidHandle , err
}
var access uint32
switch mode & ( O_RDONLY | O_WRONLY | O_RDWR ) {
case O_RDONLY :
access = GENERIC_READ
case O_WRONLY :
access = GENERIC_WRITE
case O_RDWR :
access = GENERIC_READ | GENERIC_WRITE
}
if mode & O_CREAT != 0 {
access |= GENERIC_WRITE
}
if mode & O_APPEND != 0 {
access &^= GENERIC_WRITE
access |= FILE_APPEND_DATA
}
sharemode := uint32 ( FILE_SHARE_READ | FILE_SHARE_WRITE )
var sa * SecurityAttributes
if mode & O_CLOEXEC == 0 {
sa = makeInheritSa ( )
}
var createmode uint32
switch {
case mode & ( O_CREAT | O_EXCL ) == ( O_CREAT | O_EXCL ) :
createmode = CREATE_NEW
case mode & ( O_CREAT | O_TRUNC ) == ( O_CREAT | O_TRUNC ) :
createmode = CREATE_ALWAYS
case mode & O_CREAT == O_CREAT :
createmode = OPEN_ALWAYS
case mode & O_TRUNC == O_TRUNC :
createmode = TRUNCATE_EXISTING
default :
createmode = OPEN_EXISTING
}
2020-01-31 09:32:00 +00:00
var attrs uint32 = FILE_ATTRIBUTE_NORMAL
if perm & S_IWRITE == 0 {
attrs = FILE_ATTRIBUTE_READONLY
}
h , e := CreateFile ( pathp , access , sharemode , sa , createmode , attrs , 0 )
2019-07-31 06:09:38 +00:00
return h , e
}
func Read ( fd Handle , p [ ] byte ) ( n int , err error ) {
var done uint32
e := ReadFile ( fd , p , & done , nil )
if e != nil {
if e == ERROR_BROKEN_PIPE {
// NOTE(brainman): work around ERROR_BROKEN_PIPE is returned on reading EOF from stdin
return 0 , nil
}
return 0 , e
}
if raceenabled {
if done > 0 {
raceWriteRange ( unsafe . Pointer ( & p [ 0 ] ) , int ( done ) )
}
raceAcquire ( unsafe . Pointer ( & ioSync ) )
}
return int ( done ) , nil
}
func Write ( fd Handle , p [ ] byte ) ( n int , err error ) {
if raceenabled {
raceReleaseMerge ( unsafe . Pointer ( & ioSync ) )
}
var done uint32
e := WriteFile ( fd , p , & done , nil )
if e != nil {
return 0 , e
}
if raceenabled && done > 0 {
raceReadRange ( unsafe . Pointer ( & p [ 0 ] ) , int ( done ) )
}
return int ( done ) , nil
}
var ioSync int64
func Seek ( fd Handle , offset int64 , whence int ) ( newoffset int64 , err error ) {
var w uint32
switch whence {
case 0 :
w = FILE_BEGIN
case 1 :
w = FILE_CURRENT
case 2 :
w = FILE_END
}
hi := int32 ( offset >> 32 )
lo := int32 ( offset )
// use GetFileType to check pipe, pipe can't do seek
ft , _ := GetFileType ( fd )
if ft == FILE_TYPE_PIPE {
return 0 , syscall . EPIPE
}
rlo , e := SetFilePointer ( fd , lo , & hi , w )
if e != nil {
return 0 , e
}
return int64 ( hi ) << 32 + int64 ( rlo ) , nil
}
func Close ( fd Handle ) ( err error ) {
return CloseHandle ( fd )
}
var (
Stdin = getStdHandle ( STD_INPUT_HANDLE )
Stdout = getStdHandle ( STD_OUTPUT_HANDLE )
Stderr = getStdHandle ( STD_ERROR_HANDLE )
)
func getStdHandle ( stdhandle uint32 ) ( fd Handle ) {
r , _ := GetStdHandle ( stdhandle )
CloseOnExec ( r )
return r
}
const ImplementsGetwd = true
func Getwd ( ) ( wd string , err error ) {
b := make ( [ ] uint16 , 300 )
n , e := GetCurrentDirectory ( uint32 ( len ( b ) ) , & b [ 0 ] )
if e != nil {
return "" , e
}
return string ( utf16 . Decode ( b [ 0 : n ] ) ) , nil
}
func Chdir ( path string ) ( err error ) {
pathp , err := UTF16PtrFromString ( path )
if err != nil {
return err
}
return SetCurrentDirectory ( pathp )
}
func Mkdir ( path string , mode uint32 ) ( err error ) {
pathp , err := UTF16PtrFromString ( path )
if err != nil {
return err
}
return CreateDirectory ( pathp , nil )
}
func Rmdir ( path string ) ( err error ) {
pathp , err := UTF16PtrFromString ( path )
if err != nil {
return err
}
return RemoveDirectory ( pathp )
}
func Unlink ( path string ) ( err error ) {
pathp , err := UTF16PtrFromString ( path )
if err != nil {
return err
}
return DeleteFile ( pathp )
}
func Rename ( oldpath , newpath string ) ( err error ) {
from , err := UTF16PtrFromString ( oldpath )
if err != nil {
return err
}
to , err := UTF16PtrFromString ( newpath )
if err != nil {
return err
}
return MoveFileEx ( from , to , MOVEFILE_REPLACE_EXISTING )
}
func ComputerName ( ) ( name string , err error ) {
var n uint32 = MAX_COMPUTERNAME_LENGTH + 1
b := make ( [ ] uint16 , n )
e := GetComputerName ( & b [ 0 ] , & n )
if e != nil {
return "" , e
}
return string ( utf16 . Decode ( b [ 0 : n ] ) ) , nil
}
func DurationSinceBoot ( ) time . Duration {
return time . Duration ( getTickCount64 ( ) ) * time . Millisecond
}
func Ftruncate ( fd Handle , length int64 ) ( err error ) {
curoffset , e := Seek ( fd , 0 , 1 )
if e != nil {
return e
}
defer Seek ( fd , curoffset , 0 )
_ , e = Seek ( fd , length , 0 )
if e != nil {
return e
}
e = SetEndOfFile ( fd )
if e != nil {
return e
}
return nil
}
func Gettimeofday ( tv * Timeval ) ( err error ) {
var ft Filetime
GetSystemTimeAsFileTime ( & ft )
* tv = NsecToTimeval ( ft . Nanoseconds ( ) )
return nil
}
func Pipe ( p [ ] Handle ) ( err error ) {
if len ( p ) != 2 {
return syscall . EINVAL
}
var r , w Handle
e := CreatePipe ( & r , & w , makeInheritSa ( ) , 0 )
if e != nil {
return e
}
p [ 0 ] = r
p [ 1 ] = w
return nil
}
func Utimes ( path string , tv [ ] Timeval ) ( err error ) {
if len ( tv ) != 2 {
return syscall . EINVAL
}
pathp , e := UTF16PtrFromString ( path )
if e != nil {
return e
}
h , e := CreateFile ( pathp ,
FILE_WRITE_ATTRIBUTES , FILE_SHARE_WRITE , nil ,
OPEN_EXISTING , FILE_FLAG_BACKUP_SEMANTICS , 0 )
if e != nil {
return e
}
defer Close ( h )
a := NsecToFiletime ( tv [ 0 ] . Nanoseconds ( ) )
w := NsecToFiletime ( tv [ 1 ] . Nanoseconds ( ) )
return SetFileTime ( h , nil , & a , & w )
}
func UtimesNano ( path string , ts [ ] Timespec ) ( err error ) {
if len ( ts ) != 2 {
return syscall . EINVAL
}
pathp , e := UTF16PtrFromString ( path )
if e != nil {
return e
}
h , e := CreateFile ( pathp ,
FILE_WRITE_ATTRIBUTES , FILE_SHARE_WRITE , nil ,
OPEN_EXISTING , FILE_FLAG_BACKUP_SEMANTICS , 0 )
if e != nil {
return e
}
defer Close ( h )
a := NsecToFiletime ( TimespecToNsec ( ts [ 0 ] ) )
w := NsecToFiletime ( TimespecToNsec ( ts [ 1 ] ) )
return SetFileTime ( h , nil , & a , & w )
}
func Fsync ( fd Handle ) ( err error ) {
return FlushFileBuffers ( fd )
}
func Chmod ( path string , mode uint32 ) ( err error ) {
p , e := UTF16PtrFromString ( path )
if e != nil {
return e
}
attrs , e := GetFileAttributes ( p )
if e != nil {
return e
}
if mode & S_IWRITE != 0 {
attrs &^= FILE_ATTRIBUTE_READONLY
} else {
attrs |= FILE_ATTRIBUTE_READONLY
}
return SetFileAttributes ( p , attrs )
}
func LoadGetSystemTimePreciseAsFileTime ( ) error {
return procGetSystemTimePreciseAsFileTime . Find ( )
}
func LoadCancelIoEx ( ) error {
return procCancelIoEx . Find ( )
}
func LoadSetFileCompletionNotificationModes ( ) error {
return procSetFileCompletionNotificationModes . Find ( )
}
func WaitForMultipleObjects ( handles [ ] Handle , waitAll bool , waitMilliseconds uint32 ) ( event uint32 , err error ) {
// Every other win32 array API takes arguments as "pointer, count", except for this function. So we
// can't declare it as a usual [] type, because mksyscall will use the opposite order. We therefore
// trivially stub this ourselves.
var handlePtr * Handle
if len ( handles ) > 0 {
handlePtr = & handles [ 0 ]
}
return waitForMultipleObjects ( uint32 ( len ( handles ) ) , uintptr ( unsafe . Pointer ( handlePtr ) ) , waitAll , waitMilliseconds )
}
// net api calls
const socket_error = uintptr ( ^ uint32 ( 0 ) )
//sys WSAStartup(verreq uint32, data *WSAData) (sockerr error) = ws2_32.WSAStartup
//sys WSACleanup() (err error) [failretval==socket_error] = ws2_32.WSACleanup
//sys WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) [failretval==socket_error] = ws2_32.WSAIoctl
//sys socket(af int32, typ int32, protocol int32) (handle Handle, err error) [failretval==InvalidHandle] = ws2_32.socket
2020-01-31 09:32:00 +00:00
//sys sendto(s Handle, buf []byte, flags int32, to unsafe.Pointer, tolen int32) (err error) [failretval==socket_error] = ws2_32.sendto
//sys recvfrom(s Handle, buf []byte, flags int32, from *RawSockaddrAny, fromlen *int32) (n int32, err error) [failretval==-1] = ws2_32.recvfrom
2019-07-31 06:09:38 +00:00
//sys Setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (err error) [failretval==socket_error] = ws2_32.setsockopt
//sys Getsockopt(s Handle, level int32, optname int32, optval *byte, optlen *int32) (err error) [failretval==socket_error] = ws2_32.getsockopt
//sys bind(s Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socket_error] = ws2_32.bind
//sys connect(s Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socket_error] = ws2_32.connect
//sys getsockname(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) [failretval==socket_error] = ws2_32.getsockname
//sys getpeername(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) [failretval==socket_error] = ws2_32.getpeername
//sys listen(s Handle, backlog int32) (err error) [failretval==socket_error] = ws2_32.listen
//sys shutdown(s Handle, how int32) (err error) [failretval==socket_error] = ws2_32.shutdown
//sys Closesocket(s Handle) (err error) [failretval==socket_error] = ws2_32.closesocket
//sys AcceptEx(ls Handle, as Handle, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (err error) = mswsock.AcceptEx
//sys GetAcceptExSockaddrs(buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, lrsa **RawSockaddrAny, lrsalen *int32, rrsa **RawSockaddrAny, rrsalen *int32) = mswsock.GetAcceptExSockaddrs
//sys WSARecv(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSARecv
//sys WSASend(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSASend
//sys WSARecvFrom(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSARecvFrom
//sys WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSASendTo
//sys GetHostByName(name string) (h *Hostent, err error) [failretval==nil] = ws2_32.gethostbyname
//sys GetServByName(name string, proto string) (s *Servent, err error) [failretval==nil] = ws2_32.getservbyname
//sys Ntohs(netshort uint16) (u uint16) = ws2_32.ntohs
//sys GetProtoByName(name string) (p *Protoent, err error) [failretval==nil] = ws2_32.getprotobyname
//sys DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status error) = dnsapi.DnsQuery_W
//sys DnsRecordListFree(rl *DNSRecord, freetype uint32) = dnsapi.DnsRecordListFree
//sys DnsNameCompare(name1 *uint16, name2 *uint16) (same bool) = dnsapi.DnsNameCompare_W
//sys GetAddrInfoW(nodename *uint16, servicename *uint16, hints *AddrinfoW, result **AddrinfoW) (sockerr error) = ws2_32.GetAddrInfoW
//sys FreeAddrInfoW(addrinfo *AddrinfoW) = ws2_32.FreeAddrInfoW
//sys GetIfEntry(pIfRow *MibIfRow) (errcode error) = iphlpapi.GetIfEntry
//sys GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode error) = iphlpapi.GetAdaptersInfo
//sys SetFileCompletionNotificationModes(handle Handle, flags uint8) (err error) = kernel32.SetFileCompletionNotificationModes
//sys WSAEnumProtocols(protocols *int32, protocolBuffer *WSAProtocolInfo, bufferLength *uint32) (n int32, err error) [failretval==-1] = ws2_32.WSAEnumProtocolsW
//sys GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) = iphlpapi.GetAdaptersAddresses
//sys GetACP() (acp uint32) = kernel32.GetACP
//sys MultiByteToWideChar(codePage uint32, dwFlags uint32, str *byte, nstr int32, wchar *uint16, nwchar int32) (nwrite int32, err error) = kernel32.MultiByteToWideChar
// For testing: clients can set this flag to force
// creation of IPv6 sockets to return EAFNOSUPPORT.
var SocketDisableIPv6 bool
type RawSockaddrInet4 struct {
Family uint16
Port uint16
Addr [ 4 ] byte /* in_addr */
Zero [ 8 ] uint8
}
type RawSockaddrInet6 struct {
Family uint16
Port uint16
Flowinfo uint32
Addr [ 16 ] byte /* in6_addr */
Scope_id uint32
}
type RawSockaddr struct {
Family uint16
Data [ 14 ] int8
}
type RawSockaddrAny struct {
Addr RawSockaddr
Pad [ 100 ] int8
}
type Sockaddr interface {
sockaddr ( ) ( ptr unsafe . Pointer , len int32 , err error ) // lowercase; only we can define Sockaddrs
}
type SockaddrInet4 struct {
Port int
Addr [ 4 ] byte
raw RawSockaddrInet4
}
func ( sa * SockaddrInet4 ) sockaddr ( ) ( unsafe . Pointer , int32 , error ) {
if sa . Port < 0 || sa . Port > 0xFFFF {
return nil , 0 , syscall . EINVAL
}
sa . raw . Family = AF_INET
p := ( * [ 2 ] byte ) ( unsafe . Pointer ( & sa . raw . Port ) )
p [ 0 ] = byte ( sa . Port >> 8 )
p [ 1 ] = byte ( sa . Port )
for i := 0 ; i < len ( sa . Addr ) ; i ++ {
sa . raw . Addr [ i ] = sa . Addr [ i ]
}
return unsafe . Pointer ( & sa . raw ) , int32 ( unsafe . Sizeof ( sa . raw ) ) , nil
}
type SockaddrInet6 struct {
Port int
ZoneId uint32
Addr [ 16 ] byte
raw RawSockaddrInet6
}
func ( sa * SockaddrInet6 ) sockaddr ( ) ( unsafe . Pointer , int32 , error ) {
if sa . Port < 0 || sa . Port > 0xFFFF {
return nil , 0 , syscall . EINVAL
}
sa . raw . Family = AF_INET6
p := ( * [ 2 ] byte ) ( unsafe . Pointer ( & sa . raw . Port ) )
p [ 0 ] = byte ( sa . Port >> 8 )
p [ 1 ] = byte ( sa . Port )
sa . raw . Scope_id = sa . ZoneId
for i := 0 ; i < len ( sa . Addr ) ; i ++ {
sa . raw . Addr [ i ] = sa . Addr [ i ]
}
return unsafe . Pointer ( & sa . raw ) , int32 ( unsafe . Sizeof ( sa . raw ) ) , nil
}
type RawSockaddrUnix struct {
Family uint16
Path [ UNIX_PATH_MAX ] int8
}
type SockaddrUnix struct {
Name string
raw RawSockaddrUnix
}
func ( sa * SockaddrUnix ) sockaddr ( ) ( unsafe . Pointer , int32 , error ) {
name := sa . Name
n := len ( name )
if n > len ( sa . raw . Path ) {
return nil , 0 , syscall . EINVAL
}
if n == len ( sa . raw . Path ) && name [ 0 ] != '@' {
return nil , 0 , syscall . EINVAL
}
sa . raw . Family = AF_UNIX
for i := 0 ; i < n ; i ++ {
sa . raw . Path [ i ] = int8 ( name [ i ] )
}
// length is family (uint16), name, NUL.
sl := int32 ( 2 )
if n > 0 {
sl += int32 ( n ) + 1
}
if sa . raw . Path [ 0 ] == '@' {
sa . raw . Path [ 0 ] = 0
// Don't count trailing NUL for abstract address.
sl --
}
return unsafe . Pointer ( & sa . raw ) , sl , nil
}
func ( rsa * RawSockaddrAny ) Sockaddr ( ) ( Sockaddr , error ) {
switch rsa . Addr . Family {
case AF_UNIX :
pp := ( * RawSockaddrUnix ) ( unsafe . Pointer ( rsa ) )
sa := new ( SockaddrUnix )
if pp . Path [ 0 ] == 0 {
// "Abstract" Unix domain socket.
// Rewrite leading NUL as @ for textual display.
// (This is the standard convention.)
// Not friendly to overwrite in place,
// but the callers below don't care.
pp . Path [ 0 ] = '@'
}
// Assume path ends at NUL.
// This is not technically the Linux semantics for
// abstract Unix domain sockets--they are supposed
// to be uninterpreted fixed-size binary blobs--but
// everyone uses this convention.
n := 0
for n < len ( pp . Path ) && pp . Path [ n ] != 0 {
n ++
}
2020-01-31 09:32:00 +00:00
bytes := ( * [ len ( pp . Path ) ] byte ) ( unsafe . Pointer ( & pp . Path [ 0 ] ) ) [ 0 : n ]
2019-07-31 06:09:38 +00:00
sa . Name = string ( bytes )
return sa , nil
case AF_INET :
pp := ( * RawSockaddrInet4 ) ( unsafe . Pointer ( rsa ) )
sa := new ( SockaddrInet4 )
p := ( * [ 2 ] byte ) ( unsafe . Pointer ( & pp . Port ) )
sa . Port = int ( p [ 0 ] ) << 8 + int ( p [ 1 ] )
for i := 0 ; i < len ( sa . Addr ) ; i ++ {
sa . Addr [ i ] = pp . Addr [ i ]
}
return sa , nil
case AF_INET6 :
pp := ( * RawSockaddrInet6 ) ( unsafe . Pointer ( rsa ) )
sa := new ( SockaddrInet6 )
p := ( * [ 2 ] byte ) ( unsafe . Pointer ( & pp . Port ) )
sa . Port = int ( p [ 0 ] ) << 8 + int ( p [ 1 ] )
sa . ZoneId = pp . Scope_id
for i := 0 ; i < len ( sa . Addr ) ; i ++ {
sa . Addr [ i ] = pp . Addr [ i ]
}
return sa , nil
}
return nil , syscall . EAFNOSUPPORT
}
func Socket ( domain , typ , proto int ) ( fd Handle , err error ) {
if domain == AF_INET6 && SocketDisableIPv6 {
return InvalidHandle , syscall . EAFNOSUPPORT
}
return socket ( int32 ( domain ) , int32 ( typ ) , int32 ( proto ) )
}
func SetsockoptInt ( fd Handle , level , opt int , value int ) ( err error ) {
v := int32 ( value )
return Setsockopt ( fd , int32 ( level ) , int32 ( opt ) , ( * byte ) ( unsafe . Pointer ( & v ) ) , int32 ( unsafe . Sizeof ( v ) ) )
}
func Bind ( fd Handle , sa Sockaddr ) ( err error ) {
ptr , n , err := sa . sockaddr ( )
if err != nil {
return err
}
return bind ( fd , ptr , n )
}
func Connect ( fd Handle , sa Sockaddr ) ( err error ) {
ptr , n , err := sa . sockaddr ( )
if err != nil {
return err
}
return connect ( fd , ptr , n )
}
func Getsockname ( fd Handle ) ( sa Sockaddr , err error ) {
var rsa RawSockaddrAny
l := int32 ( unsafe . Sizeof ( rsa ) )
if err = getsockname ( fd , & rsa , & l ) ; err != nil {
return
}
return rsa . Sockaddr ( )
}
func Getpeername ( fd Handle ) ( sa Sockaddr , err error ) {
var rsa RawSockaddrAny
l := int32 ( unsafe . Sizeof ( rsa ) )
if err = getpeername ( fd , & rsa , & l ) ; err != nil {
return
}
return rsa . Sockaddr ( )
}
func Listen ( s Handle , n int ) ( err error ) {
return listen ( s , int32 ( n ) )
}
func Shutdown ( fd Handle , how int ) ( err error ) {
return shutdown ( fd , int32 ( how ) )
}
func WSASendto ( s Handle , bufs * WSABuf , bufcnt uint32 , sent * uint32 , flags uint32 , to Sockaddr , overlapped * Overlapped , croutine * byte ) ( err error ) {
rsa , l , err := to . sockaddr ( )
if err != nil {
return err
}
return WSASendTo ( s , bufs , bufcnt , sent , flags , ( * RawSockaddrAny ) ( unsafe . Pointer ( rsa ) ) , l , overlapped , croutine )
}
func LoadGetAddrInfo ( ) error {
return procGetAddrInfoW . Find ( )
}
var connectExFunc struct {
once sync . Once
addr uintptr
err error
}
func LoadConnectEx ( ) error {
connectExFunc . once . Do ( func ( ) {
var s Handle
s , connectExFunc . err = Socket ( AF_INET , SOCK_STREAM , IPPROTO_TCP )
if connectExFunc . err != nil {
return
}
defer CloseHandle ( s )
var n uint32
connectExFunc . err = WSAIoctl ( s ,
SIO_GET_EXTENSION_FUNCTION_POINTER ,
( * byte ) ( unsafe . Pointer ( & WSAID_CONNECTEX ) ) ,
uint32 ( unsafe . Sizeof ( WSAID_CONNECTEX ) ) ,
( * byte ) ( unsafe . Pointer ( & connectExFunc . addr ) ) ,
uint32 ( unsafe . Sizeof ( connectExFunc . addr ) ) ,
& n , nil , 0 )
} )
return connectExFunc . err
}
func connectEx ( s Handle , name unsafe . Pointer , namelen int32 , sendBuf * byte , sendDataLen uint32 , bytesSent * uint32 , overlapped * Overlapped ) ( err error ) {
r1 , _ , e1 := syscall . Syscall9 ( connectExFunc . addr , 7 , uintptr ( s ) , uintptr ( name ) , uintptr ( namelen ) , uintptr ( unsafe . Pointer ( sendBuf ) ) , uintptr ( sendDataLen ) , uintptr ( unsafe . Pointer ( bytesSent ) ) , uintptr ( unsafe . Pointer ( overlapped ) ) , 0 , 0 )
if r1 == 0 {
if e1 != 0 {
err = error ( e1 )
} else {
err = syscall . EINVAL
}
}
return
}
func ConnectEx ( fd Handle , sa Sockaddr , sendBuf * byte , sendDataLen uint32 , bytesSent * uint32 , overlapped * Overlapped ) error {
err := LoadConnectEx ( )
if err != nil {
return errorspkg . New ( "failed to find ConnectEx: " + err . Error ( ) )
}
ptr , n , err := sa . sockaddr ( )
if err != nil {
return err
}
return connectEx ( fd , ptr , n , sendBuf , sendDataLen , bytesSent , overlapped )
}
var sendRecvMsgFunc struct {
once sync . Once
sendAddr uintptr
recvAddr uintptr
err error
}
func loadWSASendRecvMsg ( ) error {
sendRecvMsgFunc . once . Do ( func ( ) {
var s Handle
s , sendRecvMsgFunc . err = Socket ( AF_INET , SOCK_DGRAM , IPPROTO_UDP )
if sendRecvMsgFunc . err != nil {
return
}
defer CloseHandle ( s )
var n uint32
sendRecvMsgFunc . err = WSAIoctl ( s ,
SIO_GET_EXTENSION_FUNCTION_POINTER ,
( * byte ) ( unsafe . Pointer ( & WSAID_WSARECVMSG ) ) ,
uint32 ( unsafe . Sizeof ( WSAID_WSARECVMSG ) ) ,
( * byte ) ( unsafe . Pointer ( & sendRecvMsgFunc . recvAddr ) ) ,
uint32 ( unsafe . Sizeof ( sendRecvMsgFunc . recvAddr ) ) ,
& n , nil , 0 )
if sendRecvMsgFunc . err != nil {
return
}
sendRecvMsgFunc . err = WSAIoctl ( s ,
SIO_GET_EXTENSION_FUNCTION_POINTER ,
( * byte ) ( unsafe . Pointer ( & WSAID_WSASENDMSG ) ) ,
uint32 ( unsafe . Sizeof ( WSAID_WSASENDMSG ) ) ,
( * byte ) ( unsafe . Pointer ( & sendRecvMsgFunc . sendAddr ) ) ,
uint32 ( unsafe . Sizeof ( sendRecvMsgFunc . sendAddr ) ) ,
& n , nil , 0 )
} )
return sendRecvMsgFunc . err
}
func WSASendMsg ( fd Handle , msg * WSAMsg , flags uint32 , bytesSent * uint32 , overlapped * Overlapped , croutine * byte ) error {
err := loadWSASendRecvMsg ( )
if err != nil {
return err
}
r1 , _ , e1 := syscall . Syscall6 ( sendRecvMsgFunc . sendAddr , 6 , uintptr ( fd ) , uintptr ( unsafe . Pointer ( msg ) ) , uintptr ( flags ) , uintptr ( unsafe . Pointer ( bytesSent ) ) , uintptr ( unsafe . Pointer ( overlapped ) ) , uintptr ( unsafe . Pointer ( croutine ) ) )
if r1 == socket_error {
if e1 != 0 {
err = errnoErr ( e1 )
} else {
err = syscall . EINVAL
}
}
return err
}
func WSARecvMsg ( fd Handle , msg * WSAMsg , bytesReceived * uint32 , overlapped * Overlapped , croutine * byte ) error {
err := loadWSASendRecvMsg ( )
if err != nil {
return err
}
r1 , _ , e1 := syscall . Syscall6 ( sendRecvMsgFunc . recvAddr , 5 , uintptr ( fd ) , uintptr ( unsafe . Pointer ( msg ) ) , uintptr ( unsafe . Pointer ( bytesReceived ) ) , uintptr ( unsafe . Pointer ( overlapped ) ) , uintptr ( unsafe . Pointer ( croutine ) ) , 0 )
if r1 == socket_error {
if e1 != 0 {
err = errnoErr ( e1 )
} else {
err = syscall . EINVAL
}
}
return err
}
// Invented structures to support what package os expects.
type Rusage struct {
CreationTime Filetime
ExitTime Filetime
KernelTime Filetime
UserTime Filetime
}
type WaitStatus struct {
ExitCode uint32
}
func ( w WaitStatus ) Exited ( ) bool { return true }
func ( w WaitStatus ) ExitStatus ( ) int { return int ( w . ExitCode ) }
func ( w WaitStatus ) Signal ( ) Signal { return - 1 }
func ( w WaitStatus ) CoreDump ( ) bool { return false }
func ( w WaitStatus ) Stopped ( ) bool { return false }
func ( w WaitStatus ) Continued ( ) bool { return false }
func ( w WaitStatus ) StopSignal ( ) Signal { return - 1 }
func ( w WaitStatus ) Signaled ( ) bool { return false }
func ( w WaitStatus ) TrapCause ( ) int { return - 1 }
// Timespec is an invented structure on Windows, but here for
// consistency with the corresponding package for other operating systems.
type Timespec struct {
Sec int64
Nsec int64
}
func TimespecToNsec ( ts Timespec ) int64 { return int64 ( ts . Sec ) * 1e9 + int64 ( ts . Nsec ) }
func NsecToTimespec ( nsec int64 ) ( ts Timespec ) {
ts . Sec = nsec / 1e9
ts . Nsec = nsec % 1e9
return
}
// TODO(brainman): fix all needed for net
func Accept ( fd Handle ) ( nfd Handle , sa Sockaddr , err error ) { return 0 , nil , syscall . EWINDOWS }
2020-01-31 09:32:00 +00:00
2019-07-31 06:09:38 +00:00
func Recvfrom ( fd Handle , p [ ] byte , flags int ) ( n int , from Sockaddr , err error ) {
2020-01-31 09:32:00 +00:00
var rsa RawSockaddrAny
l := int32 ( unsafe . Sizeof ( rsa ) )
n32 , err := recvfrom ( fd , p , int32 ( flags ) , & rsa , & l )
n = int ( n32 )
if err != nil {
return
}
from , err = rsa . Sockaddr ( )
return
2019-07-31 06:09:38 +00:00
}
2020-01-31 09:32:00 +00:00
func Sendto ( fd Handle , p [ ] byte , flags int , to Sockaddr ) ( err error ) {
ptr , l , err := to . sockaddr ( )
if err != nil {
return err
}
return sendto ( fd , p , int32 ( flags ) , ptr , l )
}
2019-07-31 06:09:38 +00:00
func SetsockoptTimeval ( fd Handle , level , opt int , tv * Timeval ) ( err error ) { return syscall . EWINDOWS }
// The Linger struct is wrong but we only noticed after Go 1.
// sysLinger is the real system call structure.
// BUG(brainman): The definition of Linger is not appropriate for direct use
// with Setsockopt and Getsockopt.
// Use SetsockoptLinger instead.
type Linger struct {
Onoff int32
Linger int32
}
type sysLinger struct {
Onoff uint16
Linger uint16
}
type IPMreq struct {
Multiaddr [ 4 ] byte /* in_addr */
Interface [ 4 ] byte /* in_addr */
}
type IPv6Mreq struct {
Multiaddr [ 16 ] byte /* in6_addr */
Interface uint32
}
func GetsockoptInt ( fd Handle , level , opt int ) ( int , error ) { return - 1 , syscall . EWINDOWS }
func SetsockoptLinger ( fd Handle , level , opt int , l * Linger ) ( err error ) {
sys := sysLinger { Onoff : uint16 ( l . Onoff ) , Linger : uint16 ( l . Linger ) }
return Setsockopt ( fd , int32 ( level ) , int32 ( opt ) , ( * byte ) ( unsafe . Pointer ( & sys ) ) , int32 ( unsafe . Sizeof ( sys ) ) )
}
func SetsockoptInet4Addr ( fd Handle , level , opt int , value [ 4 ] byte ) ( err error ) {
return Setsockopt ( fd , int32 ( level ) , int32 ( opt ) , ( * byte ) ( unsafe . Pointer ( & value [ 0 ] ) ) , 4 )
}
func SetsockoptIPMreq ( fd Handle , level , opt int , mreq * IPMreq ) ( err error ) {
return Setsockopt ( fd , int32 ( level ) , int32 ( opt ) , ( * byte ) ( unsafe . Pointer ( mreq ) ) , int32 ( unsafe . Sizeof ( * mreq ) ) )
}
func SetsockoptIPv6Mreq ( fd Handle , level , opt int , mreq * IPv6Mreq ) ( err error ) {
return syscall . EWINDOWS
}
func Getpid ( ) ( pid int ) { return int ( GetCurrentProcessId ( ) ) }
func FindFirstFile ( name * uint16 , data * Win32finddata ) ( handle Handle , err error ) {
// NOTE(rsc): The Win32finddata struct is wrong for the system call:
// the two paths are each one uint16 short. Use the correct struct,
// a win32finddata1, and then copy the results out.
// There is no loss of expressivity here, because the final
// uint16, if it is used, is supposed to be a NUL, and Go doesn't need that.
// For Go 1.1, we might avoid the allocation of win32finddata1 here
// by adding a final Bug [2]uint16 field to the struct and then
// adjusting the fields in the result directly.
var data1 win32finddata1
handle , err = findFirstFile1 ( name , & data1 )
if err == nil {
copyFindData ( data , & data1 )
}
return
}
func FindNextFile ( handle Handle , data * Win32finddata ) ( err error ) {
var data1 win32finddata1
err = findNextFile1 ( handle , & data1 )
if err == nil {
copyFindData ( data , & data1 )
}
return
}
func getProcessEntry ( pid int ) ( * ProcessEntry32 , error ) {
snapshot , err := CreateToolhelp32Snapshot ( TH32CS_SNAPPROCESS , 0 )
if err != nil {
return nil , err
}
defer CloseHandle ( snapshot )
var procEntry ProcessEntry32
procEntry . Size = uint32 ( unsafe . Sizeof ( procEntry ) )
if err = Process32First ( snapshot , & procEntry ) ; err != nil {
return nil , err
}
for {
if procEntry . ProcessID == uint32 ( pid ) {
return & procEntry , nil
}
err = Process32Next ( snapshot , & procEntry )
if err != nil {
return nil , err
}
}
}
func Getppid ( ) ( ppid int ) {
pe , err := getProcessEntry ( Getpid ( ) )
if err != nil {
return - 1
}
return int ( pe . ParentProcessID )
}
// TODO(brainman): fix all needed for os
func Fchdir ( fd Handle ) ( err error ) { return syscall . EWINDOWS }
func Link ( oldpath , newpath string ) ( err error ) { return syscall . EWINDOWS }
func Symlink ( path , link string ) ( err error ) { return syscall . EWINDOWS }
func Fchmod ( fd Handle , mode uint32 ) ( err error ) { return syscall . EWINDOWS }
func Chown ( path string , uid int , gid int ) ( err error ) { return syscall . EWINDOWS }
func Lchown ( path string , uid int , gid int ) ( err error ) { return syscall . EWINDOWS }
func Fchown ( fd Handle , uid int , gid int ) ( err error ) { return syscall . EWINDOWS }
func Getuid ( ) ( uid int ) { return - 1 }
func Geteuid ( ) ( euid int ) { return - 1 }
func Getgid ( ) ( gid int ) { return - 1 }
func Getegid ( ) ( egid int ) { return - 1 }
func Getgroups ( ) ( gids [ ] int , err error ) { return nil , syscall . EWINDOWS }
type Signal int
func ( s Signal ) Signal ( ) { }
func ( s Signal ) String ( ) string {
if 0 <= s && int ( s ) < len ( signals ) {
str := signals [ s ]
if str != "" {
return str
}
}
return "signal " + itoa ( int ( s ) )
}
func LoadCreateSymbolicLink ( ) error {
return procCreateSymbolicLinkW . Find ( )
}
// Readlink returns the destination of the named symbolic link.
func Readlink ( path string , buf [ ] byte ) ( n int , err error ) {
fd , err := CreateFile ( StringToUTF16Ptr ( path ) , GENERIC_READ , 0 , nil , OPEN_EXISTING ,
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS , 0 )
if err != nil {
return - 1 , err
}
defer CloseHandle ( fd )
rdbbuf := make ( [ ] byte , MAXIMUM_REPARSE_DATA_BUFFER_SIZE )
var bytesReturned uint32
err = DeviceIoControl ( fd , FSCTL_GET_REPARSE_POINT , nil , 0 , & rdbbuf [ 0 ] , uint32 ( len ( rdbbuf ) ) , & bytesReturned , nil )
if err != nil {
return - 1 , err
}
rdb := ( * reparseDataBuffer ) ( unsafe . Pointer ( & rdbbuf [ 0 ] ) )
var s string
switch rdb . ReparseTag {
case IO_REPARSE_TAG_SYMLINK :
data := ( * symbolicLinkReparseBuffer ) ( unsafe . Pointer ( & rdb . reparseBuffer ) )
p := ( * [ 0xffff ] uint16 ) ( unsafe . Pointer ( & data . PathBuffer [ 0 ] ) )
s = UTF16ToString ( p [ data . PrintNameOffset / 2 : ( data . PrintNameLength - data . PrintNameOffset ) / 2 ] )
case IO_REPARSE_TAG_MOUNT_POINT :
data := ( * mountPointReparseBuffer ) ( unsafe . Pointer ( & rdb . reparseBuffer ) )
p := ( * [ 0xffff ] uint16 ) ( unsafe . Pointer ( & data . PathBuffer [ 0 ] ) )
s = UTF16ToString ( p [ data . PrintNameOffset / 2 : ( data . PrintNameLength - data . PrintNameOffset ) / 2 ] )
default :
// the path is not a symlink or junction but another type of reparse
// point
return - 1 , syscall . ENOENT
}
n = copy ( buf , [ ] byte ( s ) )
return n , nil
}
// GUIDFromString parses a string in the form of
// "{XXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}" into a GUID.
func GUIDFromString ( str string ) ( GUID , error ) {
guid := GUID { }
str16 , err := syscall . UTF16PtrFromString ( str )
if err != nil {
return guid , err
}
err = clsidFromString ( str16 , & guid )
if err != nil {
return guid , err
}
return guid , nil
}
// GenerateGUID creates a new random GUID.
func GenerateGUID ( ) ( GUID , error ) {
guid := GUID { }
err := coCreateGuid ( & guid )
if err != nil {
return guid , err
}
return guid , nil
}
// String returns the canonical string form of the GUID,
// in the form of "{XXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}".
func ( guid GUID ) String ( ) string {
var str [ 100 ] uint16
chars := stringFromGUID2 ( & guid , & str [ 0 ] , int32 ( len ( str ) ) )
if chars <= 1 {
return ""
}
return string ( utf16 . Decode ( str [ : chars - 1 ] ) )
}
// KnownFolderPath returns a well-known folder path for the current user, specified by one of
// the FOLDERID_ constants, and chosen and optionally created based on a KF_ flag.
func KnownFolderPath ( folderID * KNOWNFOLDERID , flags uint32 ) ( string , error ) {
return Token ( 0 ) . KnownFolderPath ( folderID , flags )
}
// KnownFolderPath returns a well-known folder path for the user token, specified by one of
// the FOLDERID_ constants, and chosen and optionally created based on a KF_ flag.
func ( t Token ) KnownFolderPath ( folderID * KNOWNFOLDERID , flags uint32 ) ( string , error ) {
var p * uint16
err := shGetKnownFolderPath ( folderID , flags , t , & p )
if err != nil {
return "" , err
}
defer CoTaskMemFree ( unsafe . Pointer ( p ) )
return UTF16ToString ( ( * [ ( 1 << 30 ) - 1 ] uint16 ) ( unsafe . Pointer ( p ) ) [ : ] ) , nil
}
2020-01-31 09:32:00 +00:00
// RtlGetVersion returns the version of the underlying operating system, ignoring
// manifest semantics but is affected by the application compatibility layer.
2019-07-31 06:09:38 +00:00
func RtlGetVersion ( ) * OsVersionInfoEx {
info := & OsVersionInfoEx { }
info . osVersionInfoSize = uint32 ( unsafe . Sizeof ( * info ) )
// According to documentation, this function always succeeds.
// The function doesn't even check the validity of the
// osVersionInfoSize member. Disassembling ntdll.dll indicates
// that the documentation is indeed correct about that.
_ = rtlGetVersion ( info )
return info
}
2020-01-31 09:32:00 +00:00
// RtlGetNtVersionNumbers returns the version of the underlying operating system,
// ignoring manifest semantics and the application compatibility layer.
func RtlGetNtVersionNumbers ( ) ( majorVersion , minorVersion , buildNumber uint32 ) {
rtlGetNtVersionNumbers ( & majorVersion , & minorVersion , & buildNumber )
buildNumber &= 0xffff
return
}
// GetProcessPreferredUILanguages retrieves the process preferred UI languages.
func GetProcessPreferredUILanguages ( flags uint32 ) ( [ ] string , error ) {
return getUILanguages ( flags , getProcessPreferredUILanguages )
}
// GetThreadPreferredUILanguages retrieves the thread preferred UI languages for the current thread.
func GetThreadPreferredUILanguages ( flags uint32 ) ( [ ] string , error ) {
return getUILanguages ( flags , getThreadPreferredUILanguages )
}
// GetUserPreferredUILanguages retrieves information about the user preferred UI languages.
func GetUserPreferredUILanguages ( flags uint32 ) ( [ ] string , error ) {
return getUILanguages ( flags , getUserPreferredUILanguages )
}
// GetSystemPreferredUILanguages retrieves the system preferred UI languages.
func GetSystemPreferredUILanguages ( flags uint32 ) ( [ ] string , error ) {
return getUILanguages ( flags , getSystemPreferredUILanguages )
}
func getUILanguages ( flags uint32 , f func ( flags uint32 , numLanguages * uint32 , buf * uint16 , bufSize * uint32 ) error ) ( [ ] string , error ) {
size := uint32 ( 128 )
for {
var numLanguages uint32
buf := make ( [ ] uint16 , size )
err := f ( flags , & numLanguages , & buf [ 0 ] , & size )
if err == ERROR_INSUFFICIENT_BUFFER {
continue
}
if err != nil {
return nil , err
}
buf = buf [ : size ]
if numLanguages == 0 || len ( buf ) == 0 { // GetProcessPreferredUILanguages may return numLanguages==0 with "\0\0"
return [ ] string { } , nil
}
if buf [ len ( buf ) - 1 ] == 0 {
buf = buf [ : len ( buf ) - 1 ] // remove terminating null
}
languages := make ( [ ] string , 0 , numLanguages )
from := 0
for i , c := range buf {
if c == 0 {
languages = append ( languages , string ( utf16 . Decode ( buf [ from : i ] ) ) )
from = i + 1
}
}
return languages , nil
}
}