我试图在Go中调用SHGet
ImageList,以便从.EXE文件中提取图标.问题是我不知道如何在Go中创建/传递“IImageList2接口”,这是SHGetImageList所需要的.
我已经尝试了几个小时的杂项,但这都导致了同样的E_NOINTERFACE错误.基本上它们都是“黑暗中的镜头”([]字节数组,看看我是否可以接收任何“数据”,Go中的实际接口{}包含与MSDN定义的IImagelist2接口相同的功能,等等) .如果它有任何相关性,我在C#中使用http://www.pinvoke.net/default.aspx/shell32.shgetimagelist这样的东西确实有一个这样的工作版本,但我根本没有关于如何“转换”到Go的真正线索.任何帮助将非常感激.
示例转到下面的代码,其中包含一些信息以及评论中指向MSDN的链接.
package main import ( "fmt" "syscall" "unsafe" ) var ( shell32 = syscall.MustLoadDLL("shell32.dll") // https://msdn.microsoft.com/en-us/library/windows/desktop/bb762179(v=vs.85).aspx procSHGetFileInfo = shell32.MustFindProc("SHGetFileInfoW") //https://msdn.microsoft.com/en-us/library/windows/desktop/bb762185(v=vs.85).aspx procSHGetImageList = shell32.MustFindProc("SHGetImageList") ) func main() { someExeFile := `c:\windows\explorer.exe` iconIndex := GetIconIndex(someExeFile) // The problem: HRESULT,_,_ := procSHGetImageList.Call( uintptr(SHIL_JUMBO),uintptr(unsafe.Pointer(&IID_IImageList2)),// I don't know how pass/create an "IImageList interface" in Go,// or if it's even possible without relying on CGO. // IImageList interface: // https://msdn.microsoft.com/en-us/library/windows/desktop/bb761419(v=vs.85).aspx // Currently there's just a pointer to an empty []byte so that the code will compile. // HRESULT naturally contains the error code E_NOINTERFACE (2147500034),// which makes sense seeing as I'm not passing a valid interface. uintptr(unsafe.Pointer(&[]byte{})),) fmt.Println(iconIndex,HRESULT) } const SHIL_JUMBO = 0x4 const shGetFileInfoLen = 3 const shGetFileInfoFlags = 16400 //(SysIconIndex|LargeIcon|UseFileAttributes) // use SHGetFileInfo to get the icon index (only value we care about) func GetIconIndex(fileName string) int { buf := make([]uint16,shGetFileInfoLen) ret,_ := procSHGetFileInfo.Call( uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(fileName))),uintptr(unsafe.Pointer(&buf[0])),shGetFileInfoLen,shGetFileInfoFlags,) if ret != 0 && buf[2] > 0 { return int(buf[2]) } return 0 } // From: "192B9D83-50FC-457B-90A0-2B82A8B5DAE1" var IID_IImageList2 = &GUID{0x192b9d83,0x50fc,0x457b,[8]byte{0x90,0xa0,0x2b,0x82,0xa8,0xb5,0xda,0xe1}} // http://msdn.microsoft.com/en-us/library/windows/desktop/aa373931.aspx type GUID struct { Data1 uint32 Data2 uint16 Data3 uint16 Data4 [8]byte }
UPDATE
现在的问题是,当调用Syscall获取实际的图标指针时,它会以错误(0xC0000005)退出.
package main import ( "fmt" "syscall" "unsafe" ) var ( shell32 = syscall.MustLoadDLL("shell32.dll") // https://msdn.microsoft.com/en-us/library/windows/desktop/bb762179(v=vs.85).aspx procSHGetFileInfo = shell32.MustFindProc("SHGetFileInfoW") //https://msdn.microsoft.com/en-us/library/windows/desktop/bb762185(v=vs.85).aspx procSHGetImageList = shell32.MustFindProc("SHGetImageList") ole32 = syscall.MustLoadDLL("ole32.dll") procCoInitialize = ole32.MustFindProc("CoInitialize") ) func main() { someExeFile := `c:\windows\explorer.exe` procCoInitialize.Call() iconIndex := GetIconIndex(someExeFile) var imglist *IImageList hr,uintptr(unsafe.Pointer(&IID_IImageList)),uintptr(unsafe.Pointer(&imglist)),) // These look OK fmt.Println(iconIndex,hr,imglist.Vtbl.GetIcon) var hIcon uintptr // GetIcon: https://msdn.microsoft.com/en-us/library/windows/desktop/bb761463(v=vs.85).aspx hr,_ = syscall.Syscall(imglist.Vtbl.GetIcon,uintptr(unsafe.Pointer(imglist)),uintptr(iconIndex),getIconFlags,uintptr(unsafe.Pointer(&hIcon)),) // Errors: "Process finished with exit code -1073741819 (0xC0000005)" fmt.Println("hIcon:",hIcon) // Never reaches this } // ILD_TRANSPARENT | ILD_IMAGE const getIconFlags = 0x00000001 | 0x00000020 const SHIL_JUMBO = 0x4 const shGetFileInfoLen = 3 const shGetFileInfoFlags = 16400 //(SysIconIndex|LargeIcon|UseFileAttributes) // use SHGetFileInfo to get the icon index (only value we care about) func GetIconIndex(fileName string) int { buf := make([]uint16,) if ret != 0 && buf[2] > 0 { return int(buf[2]) } return 0 } // From: "46EB5926-582E-4017-9FDF-E8998DAA0950" var IID_IImageList = GUID{0x46eb5926,0x582e,0x4017,[8]byte{0x9f,0xdf,0xe8,0x99,0x8d,0xaa,0x09,0x50}} // http://msdn.microsoft.com/en-us/library/windows/desktop/aa373931.aspx type GUID struct { Data1 uint32 Data2 uint16 Data3 uint16 Data4 [8]byte } type IImageList struct { Vtbl *IImageListVtbl } type IImageListVtbl struct { Add uintptr ReplaceIcon uintptr SetOverlayImage uintptr Replace uintptr AddMasked uintptr Draw uintptr Remove uintptr GetIcon uintptr GetImageInfo uintptr Copy uintptr Merge uintptr Clone uintptr GetImageRect uintptr GetIconSize uintptr SetIconSize uintptr GetImageCount uintptr SetImageCount uintptr SetBkColor uintptr GetBkColor uintptr BeginDrag uintptr EndDrag uintptr DragEnter uintptr DragLeave uintptr DragMove uintptr SetDragCursorImage uintptr DragShowNolock uintptr GetDragImage uintptr GetItemFlags uintptr GetOverlayImage uintptr }
解决方法
哦,我现在看到了实际的问题.
uintptr(unsafe.Pointer(&IID_IImageList2)),... var IID_IImageList2 = &GUID{0x192b9d83,0xe1}}
你的IID_IImageList2已经是一个指针.在您的调用中,您将获取指向该指针的指针,这意味着该地址将用作GUID.你应该这样做
uintptr(unsafe.Pointer(&IID_IImageList2)),... var IID_IImageList2 = GUID{0x192b9d83,0xe1}}
要么
uintptr(unsafe.Pointer(IID_IImageList2)),0xe1}}
这样,GUID本身用作GUID,而不是它在内存中的位置.