github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/kbfs/libdokan/new_folder_name.go (about) 1 // Copyright 2016 Keybase Inc. All rights reserved. 2 // Use of this source code is governed by a BSD 3 // license that can be found in the LICENSE file. 4 5 //go:build windows 6 // +build windows 7 8 package libdokan 9 10 import ( 11 "reflect" 12 "strings" 13 "syscall" 14 "unicode/utf16" 15 "unicode/utf8" 16 "unsafe" 17 18 "golang.org/x/sys/windows" 19 ) 20 21 func isNewFolderName(name string) bool { 22 return name == newFolderName || name == newFolderAltName 23 } 24 25 var newFolderName, newFolderNameErr = getNewFolderName() 26 var newFolderAltName = altCase(newFolderName) 27 28 func altCase(s string) string { 29 _, idx := utf8.DecodeRuneInString(s) 30 return s[:idx] + strings.ToLower(s[idx:]) 31 } 32 33 // The resourse IDs are not considered stable by Microsoft. 34 // Luckily for us this happens to be the same for our 35 // targeted Windows versions where kbfsdokan works. 36 // Tested for Windows 7, 8, 8.1 and 10. 37 // TODO test this for new Windows versions! 38 const newFolderWindws7to10ResourceID = 16888 39 40 func getNewFolderName() (string, error) { 41 var u16ptr *uint16 42 // The following id is valid for at least Windows 7, 8.1 and 10. 43 res, _, err := syscall.Syscall6(procLoadStringW.Addr(), 4, shell32DLL.Handle(), 44 newFolderWindws7to10ResourceID, uintptr(unsafe.Pointer(&u16ptr)), 0, 0, 0) 45 if res == 0 { 46 return "New Folder", err 47 } 48 return lpcwstrToString(u16ptr), nil 49 } 50 51 var ( 52 shell32DLL = windows.NewLazySystemDLL("shell32.dll") 53 user32DLL = windows.NewLazySystemDLL("user32.dll") 54 procLoadStringW = user32DLL.NewProc("LoadStringW") 55 ) 56 57 // lpcwstrToString converts a nul-terminated Windows wide string to a Go string, 58 func lpcwstrToString(ptr *uint16) string { 59 if ptr == nil { 60 return "" 61 } 62 var len = 0 63 for tmp := ptr; *tmp != 0; tmp = (*uint16)(unsafe.Pointer((uintptr(unsafe.Pointer(tmp)) + 2))) { 64 len++ 65 } 66 raw := ptrUcs2Slice(ptr, len) 67 return string(utf16.Decode(raw)) 68 } 69 70 // ptrUcs2Slice takes a C Windows wide string and length in UCS2 71 // and returns it aliased as a uint16 slice. 72 func ptrUcs2Slice(ptr *uint16, lenUcs2 int) []uint16 { 73 return *(*[]uint16)(unsafe.Pointer(&reflect.SliceHeader{ 74 Data: uintptr(unsafe.Pointer(ptr)), 75 Len: lenUcs2, 76 Cap: lenUcs2})) 77 }