windows – 在Go中调用SHGetImageList

前端之家收集整理的这篇文章主要介绍了windows – 在Go中调用SHGetImageList前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我试图在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,而不是它在内存中的位置.

猜你在找的Windows相关文章