C# 获取特殊文件夹(如“我的电脑”和“库”)的图标

C# 获取特殊文件夹(如“我的电脑”和“库”)的图标,c#,winapi,icons,special-folders,C#,Winapi,Icons,Special Folders,我一直在尝试构造一个类来简单地获取特殊文件夹的当前图标,例如“我的电脑”、“计算机”、“库”,等等。我目前正在尝试使用SHGetFileInfo()API来实现这一点 Microsoft页面上的原始SHGetFileInfo函数 #1代码块 DWORD_PTR SHGetFileInfo( _In_ LPCTSTR pszPath, DWORD dwFileAttributes, _Inout_ SHFILEINFO *psfi, UINT cbFileInfo,

我一直在尝试构造一个类来简单地获取特殊文件夹的当前图标,例如“我的电脑”、“计算机”、“库”,等等。我目前正在尝试使用SHGetFileInfo()API来实现这一点

Microsoft页面上的原始SHGetFileInfo函数

#1代码块

DWORD_PTR SHGetFileInfo(
  _In_     LPCTSTR pszPath,
  DWORD dwFileAttributes,
  _Inout_  SHFILEINFO *psfi,
  UINT cbFileInfo,
  UINT uFlags
);
IntPtr pidl;
SHGetSpecialFolderLocation(0, CSIDL_DRIVES, pidl);
SHGetFileInfo(pidl, 0, shinfo, Marshal.SizeOf(shinfo), (SHGFI_PIDL | SHGFI_DISPLAYNAME | SHGFI_ICON | SHGFI_SMALLICON));
[DllImport("shell32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbFileInfo, uint uFlags);
[DllImport("Pdh.dll")]
static extern int PdhOpenQueryW(
    [MarshalAs(UnmanagedType.LPWStr)] string szDataSource, 
    UIntPtr dwUserData,
    out IntPtr phQuery);
[MarshalAs(UnmanagedType.LPWStr)] string
"_In_     LPCTSTR pszPath,"
(以上引用自:)

在另一个问题上,我发现这是一个例子

#2代码块

DWORD_PTR SHGetFileInfo(
  _In_     LPCTSTR pszPath,
  DWORD dwFileAttributes,
  _Inout_  SHFILEINFO *psfi,
  UINT cbFileInfo,
  UINT uFlags
);
IntPtr pidl;
SHGetSpecialFolderLocation(0, CSIDL_DRIVES, pidl);
SHGetFileInfo(pidl, 0, shinfo, Marshal.SizeOf(shinfo), (SHGFI_PIDL | SHGFI_DISPLAYNAME | SHGFI_ICON | SHGFI_SMALLICON));
[DllImport("shell32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbFileInfo, uint uFlags);
[DllImport("Pdh.dll")]
static extern int PdhOpenQueryW(
    [MarshalAs(UnmanagedType.LPWStr)] string szDataSource, 
    UIntPtr dwUserData,
    out IntPtr phQuery);
[MarshalAs(UnmanagedType.LPWStr)] string
"_In_     LPCTSTR pszPath,"
(以上引用自:)

它描述了以要求第一个参数为IntPtr的方式使用SHGetFileInfo。我的印象是,第一个参数必须是基于此的字符串

#3代码块

DWORD_PTR SHGetFileInfo(
  _In_     LPCTSTR pszPath,
  DWORD dwFileAttributes,
  _Inout_  SHFILEINFO *psfi,
  UINT cbFileInfo,
  UINT uFlags
);
IntPtr pidl;
SHGetSpecialFolderLocation(0, CSIDL_DRIVES, pidl);
SHGetFileInfo(pidl, 0, shinfo, Marshal.SizeOf(shinfo), (SHGFI_PIDL | SHGFI_DISPLAYNAME | SHGFI_ICON | SHGFI_SMALLICON));
[DllImport("shell32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbFileInfo, uint uFlags);
[DllImport("Pdh.dll")]
static extern int PdhOpenQueryW(
    [MarshalAs(UnmanagedType.LPWStr)] string szDataSource, 
    UIntPtr dwUserData,
    out IntPtr phQuery);
[MarshalAs(UnmanagedType.LPWStr)] string
"_In_     LPCTSTR pszPath,"
(以上引用自:)

此外,环顾四周,我也找到了这个答案

#4代码块

DWORD_PTR SHGetFileInfo(
  _In_     LPCTSTR pszPath,
  DWORD dwFileAttributes,
  _Inout_  SHFILEINFO *psfi,
  UINT cbFileInfo,
  UINT uFlags
);
IntPtr pidl;
SHGetSpecialFolderLocation(0, CSIDL_DRIVES, pidl);
SHGetFileInfo(pidl, 0, shinfo, Marshal.SizeOf(shinfo), (SHGFI_PIDL | SHGFI_DISPLAYNAME | SHGFI_ICON | SHGFI_SMALLICON));
[DllImport("shell32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbFileInfo, uint uFlags);
[DllImport("Pdh.dll")]
static extern int PdhOpenQueryW(
    [MarshalAs(UnmanagedType.LPWStr)] string szDataSource, 
    UIntPtr dwUserData,
    out IntPtr phQuery);
[MarshalAs(UnmanagedType.LPWStr)] string
"_In_     LPCTSTR pszPath,"
(以上引用自:)

在上面的回答中,用户告诉原始海报使用

#5代码块

DWORD_PTR SHGetFileInfo(
  _In_     LPCTSTR pszPath,
  DWORD dwFileAttributes,
  _Inout_  SHFILEINFO *psfi,
  UINT cbFileInfo,
  UINT uFlags
);
IntPtr pidl;
SHGetSpecialFolderLocation(0, CSIDL_DRIVES, pidl);
SHGetFileInfo(pidl, 0, shinfo, Marshal.SizeOf(shinfo), (SHGFI_PIDL | SHGFI_DISPLAYNAME | SHGFI_ICON | SHGFI_SMALLICON));
[DllImport("shell32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbFileInfo, uint uFlags);
[DllImport("Pdh.dll")]
static extern int PdhOpenQueryW(
    [MarshalAs(UnmanagedType.LPWStr)] string szDataSource, 
    UIntPtr dwUserData,
    out IntPtr phQuery);
[MarshalAs(UnmanagedType.LPWStr)] string
"_In_     LPCTSTR pszPath,"
映射到

#6代码块

DWORD_PTR SHGetFileInfo(
  _In_     LPCTSTR pszPath,
  DWORD dwFileAttributes,
  _Inout_  SHFILEINFO *psfi,
  UINT cbFileInfo,
  UINT uFlags
);
IntPtr pidl;
SHGetSpecialFolderLocation(0, CSIDL_DRIVES, pidl);
SHGetFileInfo(pidl, 0, shinfo, Marshal.SizeOf(shinfo), (SHGFI_PIDL | SHGFI_DISPLAYNAME | SHGFI_ICON | SHGFI_SMALLICON));
[DllImport("shell32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbFileInfo, uint uFlags);
[DllImport("Pdh.dll")]
static extern int PdhOpenQueryW(
    [MarshalAs(UnmanagedType.LPWStr)] string szDataSource, 
    UIntPtr dwUserData,
    out IntPtr phQuery);
[MarshalAs(UnmanagedType.LPWStr)] string
"_In_     LPCTSTR pszPath,"
帕拉姆。在顶部的MSDN C++构造函数中找到。这对我来说比任何一个都更有意义。但我无法理解的是上面的答案(#2代码块),当pinvoke.net网站说将IntPtr定义为字符串时,它告诉原始海报使用IntPtr

知道如何让SHGetFileInfo()工作以获得该图标吗?谢谢


更新

下面是我如何尝试使用它的一个例子

[DllImport("Shell32.dll")]
public static extern IntPtr SHGetFileInfo(
  string pszPath,
  uint dwFileAttributes,
  ref SHFILEINFO psfi,
  uint cbFileInfo,
  uint uFlags
);

SHGetFileInfo((IntPtr)oTarget, 0, ref shfi, (uint)Marshal.SizeOf(shfi), flags);
然后我得到两个错误

Error   1   The best overloaded method match for 'SHGetFileInfo(string, uint, ref SHFILEINFO, uint, uint)' has some invalid arguments   C:\FakePath\ImageWorker.cs  67  25  ImageWorker

Error   2   Argument 1: cannot convert from 'System.IntPtr' to 'string' C:\FakePath\ImageTool.cs    67  47  ImageWorker

如何获取图标示例:

 [DllImport("shell32.dll", CharSet = CharSet.Auto)]
 public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbFileInfo, uint uFlags);

 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
 public struct SHFILEINFO
 {
     public IntPtr hIcon;
     public int iIcon;
     public uint dwAttributes;
     public string szDisplayName;
     public string szTypeName;
 };

SHFILEINFO shinfo= new SHFILEINFO();
SHGetFileInfo(@"...", 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), 0x000000100); //SHGFI_ICON

Icon icon = (Icon)Icon.FromHandle(shinfo.hIcon);

//use the icon and finally destroy it with:

DestroyIcon(shinfo.hIcon); 

如何获取图标示例:

 [DllImport("shell32.dll", CharSet = CharSet.Auto)]
 public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbFileInfo, uint uFlags);

 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
 public struct SHFILEINFO
 {
     public IntPtr hIcon;
     public int iIcon;
     public uint dwAttributes;
     public string szDisplayName;
     public string szTypeName;
 };

SHFILEINFO shinfo= new SHFILEINFO();
SHGetFileInfo(@"...", 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), 0x000000100); //SHGFI_ICON

Icon icon = (Icon)Icon.FromHandle(shinfo.hIcon);

//use the icon and finally destroy it with:

DestroyIcon(shinfo.hIcon); 

SHGetFileInfo
相当时髦。第一个参数是指向以null结尾的字符数组的指针或PIDL。在非托管代码中,参数声明为以null结尾的字符数组。如果您希望通过PIDL,则需要执行强制转换


在p/invoke调用中,不能使用强制转换。因此,您需要声明两个重载的p/invoke导入。一个使用
string
作为第一个参数,另一个使用
IntPtr

SHGetFileInfo
相当时髦。第一个参数是指向以null结尾的字符数组的指针或PIDL。在非托管代码中,参数声明为以null结尾的字符数组。如果您希望通过PIDL,则需要执行强制转换



在p/invoke调用中,不能使用强制转换。因此,您需要声明两个重载的p/invoke导入。一个使用
string
作为第一个参数,另一个使用
IntPtr

SHGetFileInfo
根据是否设置了
SHGFI_PIDL
标志来获取字符串或PIDL。文档非常清楚。我看不到任何证据表明您确实试图调用该函数。@JonathanPotter,即使我设置了该标志,该函数的第一个参数需要一个字符串(我定义它的方式)。因此,如果我设置该标志,然后尝试调用该函数,我会得到我刚刚更新的示例(上面)中引用的错误。我是否应该以不同的方式定义DllImport?如果是,请提供建议。谢谢@DavidHeffernan:我真的不明白你的评论到底要说什么,但只是为了好玩,我用一个例子更新了我的问题,我试着使用它……所以,什么是
oTarget
SHGetFileInfo
根据是否设置了
SHGFI_-PIDL
标志来获取字符串或PIDL。文档非常清晰。我看不到任何证据表明您确实试图调用该函数。@JonathanPotter,即使我设置了该标志,该函数的第一个参数需要一个字符串(我定义它的方式)。因此,如果我设置该标志,然后尝试调用该函数,我会得到我刚刚更新的示例(上面)中引用的错误。我是否应该以不同的方式定义DllImport?如果是,请提供建议。谢谢@DavidHeffernan:我真的不明白你的评论到底想说什么,但只是为了好玩,我用了一个例子更新了我的问题,我试着使用它……那么,
oTarget
?我以为你想通过一个PIDLI考试,你的答案是100%正确的!:/我很难决定答案应该是什么。我只是想建议对另一个答案进行编辑,同时添加另一个DllImport。。。你能在你的答案中加上一个例子吗?;)所以你-1我的问题是我的错误,嗯不,不是我。我不确定我们还需要另一个p/invoke声明。你显然相当熟练,我认为你需要的不仅仅是高水平。我以为你想通过皮德利考试,你的答案是100%正确的!:/我很难决定答案应该是什么。我只是想建议对另一个答案进行编辑,同时添加另一个DllImport。。。你能在你的答案中加上一个例子吗?;)所以你-1我的问题是我的错误,嗯不,不是我。我不确定我们还需要另一个p/invoke声明。你显然相当精通,我认为你需要的不仅仅是高水平。我只是想接受这个作为例子的答案。我很难决定答案应该是什么。但是+1作为示例,只是没有按照我的要求使用正确的DLLImport。;)我将接受这一点作为答案,只是为了举例。我很难决定答案应该是什么。但是+1作为示例,只是没有按照我的要求使用正确的DLLImport。;)