SHOpenFolderAndSelectItems Win32 API 不适用于 Go,但适用于 C#

问题描述 投票:0回答:1

我正在尝试打开一个 Windows 资源管理器窗口,其中选择了特定文件夹中的指定项目。

我尝试使用 SHOpenFolderAndSelectItems Win32 API 和 C# 来实现该程序。按照此处的答案:https://stackoverflow.com/a/12262552

using System.Runtime.InteropServices;

SelectInFileExplorer("C:\\Users");

void SelectInFileExplorer(string fullPath)
{
    if (string.IsNullOrEmpty(fullPath))
        throw new ArgumentNullException("fullPath");

    fullPath = Path.GetFullPath(fullPath);

    IntPtr pidlList = NativeMethods.ILCreateFromPathW(fullPath);
    if (pidlList != IntPtr.Zero)
        try
        {
            // Open parent folder and select item
            Marshal.ThrowExceptionForHR(NativeMethods.SHOpenFolderAndSelectItems(pidlList, 0, IntPtr.Zero, 0));
        }
        finally
        {
            NativeMethods.ILFree(pidlList);
        }
}

static class NativeMethods
{

    [DllImport("shell32.dll", ExactSpelling = true)]
    public static extern void ILFree(IntPtr pidlList);

    [DllImport("shell32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
    public static extern IntPtr ILCreateFromPathW(string pszPath);

    [DllImport("shell32.dll", ExactSpelling = true)]
    public static extern int SHOpenFolderAndSelectItems(IntPtr pidlList, uint cild, IntPtr children, uint dwFlags);
}

它有效,但现在我想使用 Go 实现同样的事情。

这是我的代码:

package main

import (
    "fmt"
    "path/filepath"
    "syscall"
    "unsafe"
)

func main() {
    SelectInFileExplorer("C:\\Users")
    fmt.Println("Hello, World!")
}

func SelectInFileExplorer(fullPath string) {
    if fullPath == "" {
        panic("fullPath cannot be empty")
    }

    fullPath, _ = filepath.Abs(fullPath)

    pidlList, err := ILCreateFromPathW(fullPath)
    if err != nil {
        panic(err)
    }
    defer ILFree(pidlList)

    // Open parent folder and select item
    err = SHOpenFolderAndSelectItems(pidlList, 0, 0)
    if err != nil {
        panic(err)
    }
}

func ILFree(pidlList uintptr) {
    shell32 := syscall.NewLazyDLL("shell32.dll")
    proc := shell32.NewProc("ILFree")
    proc.Call(pidlList)
}

func ILCreateFromPathW(pszPath string) (uintptr, error) {
    shell32 := syscall.NewLazyDLL("shell32.dll")
    proc := shell32.NewProc("ILCreateFromPathW")

    pszPathPtr, err := syscall.UTF16PtrFromString(pszPath)
    if err != nil {
        return 0, err
    }

    ret, _, err := proc.Call(uintptr(unsafe.Pointer(pszPathPtr)))
    if ret == 0 {
        return 0, err
    }
    return ret, nil
}

func SHOpenFolderAndSelectItems(pidlList uintptr, cild uint32, children uintptr) error {
    shell32 := syscall.NewLazyDLL("shell32.dll")
    proc := shell32.NewProc("SHOpenFolderAndSelectItems")

    ret, _, err := proc.Call(pidlList, uintptr(cild), children, 0)
    if ret != 0 && err.Error() != "The operation completed successfully." {
        return err
    }
    return nil
}

它不起作用,因为我执行代码后没有任何反应。探索者没有出现。

我阅读了一些有关API使用的文档:https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shopenfolderandselectitems

还是不知道发生了什么。也许不是因为编程语言本身。我认为在 GO 中调用 DLL 函数有点复杂,而且我可能在函数调用方面做错了什么。

c# go winapi windows-shell
1个回答
0
投票

如官方

SHOpenFolderAndSelectItems
文档中所述备注

使用前必须调用

CoInitializeCoInitializeEx SHOpenFolderAndSelectItems。不这样做会导致 SHOpenFolderAndSelectItems 失败。

因此,您必须在 main 中添加类似的内容,例如:

ole32 := syscall.NewLazyDLL("ole32.dll")
proc := ole32.NewProc("CoInitialize")
proc.Call(0)

它可以在 .NET 中工作,因为 .NET 自动执行此操作

© www.soinside.com 2019 - 2024. All rights reserved.