// Copyright 2010-2012 The W32 Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package w32 import ( "errors" "fmt" "syscall" "unsafe" ) 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") ) 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) }