//go:build windows /* * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved. * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved. */ package w32 import ( "errors" "fmt" "syscall" "unsafe" ) type CSIDL uint32 const ( CSIDL_DESKTOP = 0x00 CSIDL_INTERNET = 0x01 CSIDL_PROGRAMS = 0x02 CSIDL_CONTROLS = 0x03 CSIDL_PRINTERS = 0x04 CSIDL_PERSONAL = 0x05 CSIDL_FAVORITES = 0x06 CSIDL_STARTUP = 0x07 CSIDL_RECENT = 0x08 CSIDL_SENDTO = 0x09 CSIDL_BITBUCKET = 0x0A CSIDL_STARTMENU = 0x0B CSIDL_MYDOCUMENTS = 0x0C CSIDL_MYMUSIC = 0x0D CSIDL_MYVIDEO = 0x0E CSIDL_DESKTOPDIRECTORY = 0x10 CSIDL_DRIVES = 0x11 CSIDL_NETWORK = 0x12 CSIDL_NETHOOD = 0x13 CSIDL_FONTS = 0x14 CSIDL_TEMPLATES = 0x15 CSIDL_COMMON_STARTMENU = 0x16 CSIDL_COMMON_PROGRAMS = 0x17 CSIDL_COMMON_STARTUP = 0x18 CSIDL_COMMON_DESKTOPDIRECTORY = 0x19 CSIDL_APPDATA = 0x1A CSIDL_PRINTHOOD = 0x1B CSIDL_LOCAL_APPDATA = 0x1C CSIDL_ALTSTARTUP = 0x1D CSIDL_COMMON_ALTSTARTUP = 0x1E CSIDL_COMMON_FAVORITES = 0x1F CSIDL_INTERNET_CACHE = 0x20 CSIDL_COOKIES = 0x21 CSIDL_HISTORY = 0x22 CSIDL_COMMON_APPDATA = 0x23 CSIDL_WINDOWS = 0x24 CSIDL_SYSTEM = 0x25 CSIDL_PROGRAM_FILES = 0x26 CSIDL_MYPICTURES = 0x27 CSIDL_PROFILE = 0x28 CSIDL_SYSTEMX86 = 0x29 CSIDL_PROGRAM_FILESX86 = 0x2A CSIDL_PROGRAM_FILES_COMMON = 0x2B CSIDL_PROGRAM_FILES_COMMONX86 = 0x2C CSIDL_COMMON_TEMPLATES = 0x2D CSIDL_COMMON_DOCUMENTS = 0x2E CSIDL_COMMON_ADMINTOOLS = 0x2F CSIDL_ADMINTOOLS = 0x30 CSIDL_CONNECTIONS = 0x31 CSIDL_COMMON_MUSIC = 0x35 CSIDL_COMMON_PICTURES = 0x36 CSIDL_COMMON_VIDEO = 0x37 CSIDL_RESOURCES = 0x38 CSIDL_RESOURCES_LOCALIZED = 0x39 CSIDL_COMMON_OEM_LINKS = 0x3A CSIDL_CDBURN_AREA = 0x3B CSIDL_COMPUTERSNEARME = 0x3D CSIDL_FLAG_CREATE = 0x8000 CSIDL_FLAG_DONT_VERIFY = 0x4000 CSIDL_FLAG_NO_ALIAS = 0x1000 CSIDL_FLAG_PER_USER_INIT = 0x8000 CSIDL_FLAG_MASK = 0xFF00 ) var ( modshell32 = syscall.NewLazyDLL("shell32.dll") procSHBrowseForFolder = modshell32.NewProc("SHBrowseForFolderW") procSHGetPathFromIDList = modshell32.NewProc("SHGetPathFromIDListW") procDragAcceptFiles = modshell32.NewProc("DragAcceptFiles") procDragQueryFile = modshell32.NewProc("DragQueryFileW") procDragQueryPoint = modshell32.NewProc("DragQueryPoint") procDragFinish = modshell32.NewProc("DragFinish") procShellExecute = modshell32.NewProc("ShellExecuteW") procExtractIcon = modshell32.NewProc("ExtractIconW") procGetSpecialFolderPath = modshell32.NewProc("SHGetSpecialFolderPathW") ) func SHBrowseForFolder(bi *BROWSEINFO) uintptr { ret, _, _ := procSHBrowseForFolder.Call(uintptr(unsafe.Pointer(bi))) return ret } func SHGetPathFromIDList(idl uintptr) string { buf := make([]uint16, 1024) procSHGetPathFromIDList.Call( idl, uintptr(unsafe.Pointer(&buf[0]))) return syscall.UTF16ToString(buf) } func DragAcceptFiles(hwnd HWND, accept bool) { procDragAcceptFiles.Call( uintptr(hwnd), uintptr(BoolToBOOL(accept))) } func DragQueryFile(hDrop HDROP, iFile uint) (fileName string, fileCount uint) { ret, _, _ := procDragQueryFile.Call( uintptr(hDrop), uintptr(iFile), 0, 0) fileCount = uint(ret) if iFile != 0xFFFFFFFF { buf := make([]uint16, fileCount+1) ret, _, _ := procDragQueryFile.Call( uintptr(hDrop), uintptr(iFile), uintptr(unsafe.Pointer(&buf[0])), uintptr(fileCount+1)) if ret == 0 { panic("Invoke DragQueryFile error.") } fileName = syscall.UTF16ToString(buf) } return } func DragQueryPoint(hDrop HDROP) (x, y int, isClientArea bool) { var pt POINT ret, _, _ := procDragQueryPoint.Call( uintptr(hDrop), uintptr(unsafe.Pointer(&pt))) return int(pt.X), int(pt.Y), (ret == 1) } func DragFinish(hDrop HDROP) { procDragFinish.Call(uintptr(hDrop)) } func ShellExecute(hwnd HWND, lpOperation, lpFile, lpParameters, lpDirectory string, nShowCmd int) error { var op, param, directory uintptr if len(lpOperation) != 0 { op = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpOperation))) } if len(lpParameters) != 0 { param = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpParameters))) } if len(lpDirectory) != 0 { directory = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpDirectory))) } ret, _, _ := procShellExecute.Call( uintptr(hwnd), op, uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpFile))), param, directory, uintptr(nShowCmd)) errorMsg := "" if ret != 0 && ret <= 32 { switch int(ret) { case ERROR_FILE_NOT_FOUND: errorMsg = "The specified file was not found." case ERROR_PATH_NOT_FOUND: errorMsg = "The specified path was not found." case ERROR_BAD_FORMAT: errorMsg = "The .exe file is invalid (non-Win32 .exe or error in .exe image)." case SE_ERR_ACCESSDENIED: errorMsg = "The operating system denied access to the specified file." case SE_ERR_ASSOCINCOMPLETE: errorMsg = "The file name association is incomplete or invalid." case SE_ERR_DDEBUSY: errorMsg = "The DDE transaction could not be completed because other DDE transactions were being processed." case SE_ERR_DDEFAIL: errorMsg = "The DDE transaction failed." case SE_ERR_DDETIMEOUT: errorMsg = "The DDE transaction could not be completed because the request timed out." case SE_ERR_DLLNOTFOUND: errorMsg = "The specified DLL was not found." case SE_ERR_NOASSOC: errorMsg = "There is no application associated with the given file name extension. This error will also be returned if you attempt to print a file that is not printable." case SE_ERR_OOM: errorMsg = "There was not enough memory to complete the operation." case SE_ERR_SHARE: errorMsg = "A sharing violation occurred." default: errorMsg = fmt.Sprintf("Unknown error occurred with error code %v", ret) } } else { return nil } return errors.New(errorMsg) } func ExtractIcon(lpszExeFileName string, nIconIndex int) HICON { ret, _, _ := procExtractIcon.Call( 0, uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpszExeFileName))), uintptr(nIconIndex)) return HICON(ret) } func SHGetSpecialFolderPath(hwndOwner HWND, lpszPath *uint16, csidl CSIDL, fCreate bool) bool { ret, _, _ := procGetSpecialFolderPath.Call( uintptr(hwndOwner), uintptr(unsafe.Pointer(lpszPath)), uintptr(csidl), uintptr(BoolToBOOL(fCreate)), 0, 0) return ret != 0 }