Ich habe eine Situation, wo ich spezielle Verarbeitung auf einigen Windows-Shell spezielle Ordner (die entsprechenden Werte in Die CSIDL-Enum.) (Meine Lösung muss WinXP-kompatibel sein.) Das Problem, das ich habe, ist, dass ich keine Möglichkeit finde, die IShellFolder mit ihrer CSIDL abzugleichen, wenn ich auf IShellFolders stoße.Erkennen Sie Windows Shell Special Folder (dh seine CSIDL) über seine pIDL (Jetzt bestimmen, ob pIDLs gleich C# sind)
Dies ist mein aktueller Ansatz:
initialisieren eine statische Eins-zu-Eins-Datenstruktur (csidlToFromFullPIdl
) alle CSIDLs ihrer pIDLs von SHGetSpecialFolderLocation
zurückgegeben.
foreach (CSIDL csidl in Enum.GetValues(typeof(CSIDL))
{
IntPtr fullPIdl = IntPtr.Zero;
int hResult = ShellApi.SHGetSpecialFolderLocation(IntPtr.Zero, csidl, ref fullPIdl);
if (hResult != 0)
Marshal.ThrowExceptionForHR(hResult);
csidlToFromFullPIdl.Add(csidl, fullPIdl);
}
die Hierarchie mit dem IShellFolder Desktop-Start:
int hResult = ShellApi.SHGetDesktopFolder(ref _shellFolder);
hResult = ShellApi.SHGetSpecialFolderLocation(IntPtr.Zero, CSIDL.CSIDL_DESKTOP, ref _fullPIdl);
Kinder Retrieve wie so:
hResult = _shellFolder.EnumObjects(IntPtr.Zero, SHCONTF.SHCONTF_FOLDERS, out pEnum);
// Then repeatedly call:
pEnum.Next(1, out childRelativePIdl, out numberGotten);
neue Konstrukt vollständig qualifizierte pIDLs für die Kinder wie so:
_fullPIdl = ShellApi.ILCombine(parentFullPIdl, childRelativePIdl);
(Schließlich rufen Sie die IShellFolder für das Kind :)
hResultUint = parentShellItem.ShellFolder.BindToObject(childRelativePIdl, IntPtr.Zero, ShellApi.IID_IShellFolder, out _shellFolder);
Das Problem ist, ich habe mit, dass weder der childRelativePIdl noch die _fullPIdl zu irgendwelchen pIDLs in csidlToFromFullPIdl
entsprechen.
TIA.
FYI auf Maschinen Vista die GUID corresponding to KNOWNFOLDERIDs kann eine Lösung (aber nicht für mich, wie ich WinXP kompatibel sein muss.) Sein
ich auch sagen soll, dass ich denke, die Pfade des speziellen Ordners mit (via SHGetSpecialFolderPath
) ist ungenügend, da einige der speziellen Ordner, an denen ich interessiert bin, keine Pfade haben. (Zum Beispiel CSIDL_DRIVES und CSIDL_NETWORK.)
Ich versuche, zwei Ansätze. Die erste ist SHGetDataFromIDList zu verwenden, um die Clsid abzurufen, die ich dann zu den bekannten CLSIDs vergleichen kann:
public static Guid GetClsidFromFullPIdl(IntPtr fullPIdl)
{
// Get both parent's IShellFolder and pIDL relative to parent from full pIDL
IntPtr pParentShellFolder;
IntPtr relativePIdl = IntPtr.Zero;
int hResultInt = ShellApi.SHBindToParent(fullPIdl, ShellGuids.IID_IShellFolder, out pParentShellFolder, ref relativePIdl);
if (hResultInt != (int)HRESULT.S_OK)
Marshal.ThrowExceptionForHR(hResultInt);
object parentShellFolderObj = System.Runtime.InteropServices.Marshal.GetTypedObjectForIUnknown(
pParentShellFolder, typeof(IShellFolder));
IShellFolder parentShellFolder = (IShellFolder)parentShellFolderObj;
SHDESCRIPTIONID descriptionId = new SHDESCRIPTIONID();
IntPtr pDescriptionId = MarshalToPointer(descriptionId);
// Next line returns hResult corresponding to NotImplementedException
hResultInt = ShellApi.SHGetDataFromIDList(parentShellFolder, ref relativePIdl, SHGDFIL.SHGDFIL_DESCRIPTIONID, pDescriptionId,
Marshal.SizeOf(typeof(SHDESCRIPTIONID)));
if (hResultInt != (int)HRESULT.S_OK)
Marshal.ThrowExceptionForHR(hResultInt);
if (parentShellFolder != null)
Marshal.ReleaseComObject(parentShellFolder);
return descriptionId.Clsid;
}
static IntPtr MarshalToPointer(object data)
{
IntPtr pData = Marshal.AllocHGlobal(Marshal.SizeOf(data));
Marshal.StructureToPtr(data, pData, false);
return pData;
}
Das Problem bei diesem Ansatz besteht darin, dass der Aufruf von SHGetDataFromIDList eine hResult zurückgibt, der zu werfen einen NotImplementedException entspricht. Bedeutet dies, dass SHGetDataFromIDList auf meinem System nicht verfügbar ist? (WinXP SP3.)
Mein zweiter Ansatz besteht darin, die Elementbezeichnerlisten, auf die durch zwei Zeiger verwiesen wird, mit Objektbezeichnerlisten zu vergleichen und festzustellen, ob sie gleich sind. Ich bin der Umsetzung einer Technik here in C codiert Dies ist, was ich bisher:
ITEMIDLISTs können äquivalent sein, ohne Byte für Byte identisch zu sein. Verwenden Sie IShellFolder :: CompareIDs, um die Äquivalenz zu testen. –
Danke @RaymondChen. –