Доброго времени суток.
Имею дело с windows-only приложением на c#/.net 4.0. Успешно интегрировал IExplorerBrowser в приложение (благо WindowsAPICodecPack есть, хоть и доработать пришлось немного).
Теперь есть задача сделать так, чтобы этим-же IExplorerBrowser можно было ходить по FTP.
Кто хочет сразу прочитать суть вопроса — прошу пропустить следующий код.
Вот что я сделал изначально для решения этой задачи (код пока сваливал почти в кучу ибо долго в этом всем разбирался).
... // OnCreateControl
explorerBrowserControl = new ExplorerBrowserClass();
ExplorerBrowserNativeMethods.IUnknown_SetSite(explorerBrowserControl, this);
explorerBrowserControl.Advise(
Marshal.GetComInterfaceForObject(this, typeof(IExplorerBrowserEvents)),
out eventsCookie);
viewEvents = new ExplorerBrowserViewEvents(this);
NativeRect rect = new NativeRect();
rect.Top = ClientRectangle.Top;
rect.Left = ClientRectangle.Left;
rect.Right = ClientRectangle.Right;
rect.Bottom = ClientRectangle.Bottom;
FolderSettings fs = new FolderSettings();
fs.ViewMode = FolderViewMode.Details;
fs.Options = FolderOptions.AutoArrange | FolderOptions.NoWebView;
explorerBrowserControl.Initialize(this.Handle, ref rect, null);
explorerBrowserControl.SetOptions(ExplorerBrowserOptions.AlwaysNavigate);
explorerBrowserControl.FillFromObject(IntPtr.Zero, 0x00); // HERE
... //
[ComVisible(true)]
[Guid("618C54EC-1C73-4CF1-878F-89F46589C5DA")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("Microsoft.WindowsAPICodePack.Shell.Custom.FtpSourceShellItem")]
[ComSourceInterfaces(typeof(IShellItem2))]
public class FtpSourceShellItem : IShellItem2
... // При создании айтема ftpSource.
Type shellType = Type.GetTypeFromCLSID(new Guid("618C54EC-1C73-4CF1-878F-89F46589C5DA"), true);
object shel = Activator.CreateInstance(shellType);
newItem = shell as IShellItem2;
if (hr != HResult.Ok)
{
throw new ShellException("Could not create ftp shell item", hr);
}
ftpSource.nativeShellItem = newItem;
... // Метод Navigate, в тестовых целях вызывается раз.
explorerBrowserControl.SetOptions(ExplorerBrowserOptions.NavigateOnce);
IntPtr temp;
Guid iid = new Guid(ExplorerBrowserIIDGuid.IFolderView2);
HResult result = explorerBrowserControl.GetCurrentView(ref iid, out temp);
if (result != HResult.Ok)
{
throw new ShellException("Failed calling IExplorerBrowser.GetCurrentView(ref Guid, out IFolderView2)", result);
}
IFolderView2 ifv2 = (IFolderView2)Marshal.GetObjectForIUnknown(temp);
IResultsFolder prf;
object temp2;
iid = new Guid(ExplorerBrowserIIDGuid.IResultsFolder);
result = ifv2.GetFolder(ref iid, out prf);
if (result != HResult.Ok)
{
throw new ShellException("Failed calling IFolderView2.GetFolder(ref Guid, out IResultsFolder)", result);
}
prf.AddItem(ftpSource.nativeShellItem);
Но таким способом нельзя описывать сам item, и методы его не вызываются вовсе. Может как-то и можно его описать и не городить то, что приведено ниже.
Решил реализовать IDataObject для метода IExplorerBrowser.FillFromObject, чтобы информация про айтемы бралась оттуда.
[ComVisible(true)]
[Guid("1BE34910-108C-4A61-B4CA-9B6F87815607")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("Microsoft.WindowsAPICodePack.Shell.Custom.DataSource")]
[ComSourceInterfaces(typeof(IDataObject))]
public class DataObject : IDataObject
{
public void GetData(ref FORMATETC format, out STGMEDIUM medium)
{
Console.WriteLine("GetData");
Console.WriteLine(
"format.cfFormat: " + format.cfFormat +
" format.dwAspect:" + format.dwAspect +
" format.lindex:" + format.lindex +
" format.ptd:" + format.ptd +
" format.tymed:" + format.tymed
);
medium = new STGMEDIUM();
medium.tymed = TYMED.TYMED_HGLOBAL;
}
... // Далее примерно так же
}
... //OnCreateControl
...
Type shellType = Type.GetTypeFromCLSID(new Guid("1BE34910-108C-4A61-B4CA-9B6F87815607"), true);
object shell = Activator.CreateInstance(shellType);
HResult result = explorerBrowserControl.FillFromObject(shell, 0x00);
После вызова FillFromObject вызывается только метод GetData, три раза со следующими параметрами:
— format.cfFormat=-16147, format.dwAspect=DVASPECT_CONTENT, format.lindex=-1, format.ptd=0, format.tymed=TYMED_HGLOBAL
— format.cfFormat=-16244, format.dwAspect=DVASPECT_CONTENT, format.lindex=-1, format.ptd=0, format.tymed=TYMED_HGLOBAL
— format.cfFormat=15, format.dwAspect=DVASPECT_CONTENT, format.lindex=-1, format.ptd=0, format.tymed=TYMED_HGLOBAL
Иногда появляется зелёный иероглиф возле иконки пустого файла.
Собственно основной вопрос здесь — куда дальше двигаться?
15 это, согласно документации — CF_HDROP, что не имеет, как по мне, смысла.
По остальным значениям ничего в интернете нет.
Если искать их с учётом того что это скорее всего выход за пределы ushort.MaxValue — гугл выдаёт авиабазы и сайты на китайском от безысходности.
Re: Заголовок должен быть: Custom Items для IExplorerBrowser
Здравствуйте, M3fN, Вы писали:
MN>Теперь GetClipboardFormatName выдаёт "Autoplay Enumerated IDlist array" и "Shell IDlist array". MN>Где можно почитать по этим форматам?
Здравствуйте, M3fN, Вы писали:
MN>Здравствуйте, Aniskin, Вы писали:
A>>Я бы использовал иную математику
A>>-16147 = C0ED = 49389 A>>-16244 = C08C = 49292
MN>Спасибо. Теперь GetClipboardFormatName выдаёт "Autoplay Enumerated IDlist array" и "Shell IDlist array". MN>Где можно почитать по этим форматам?
Для отладки вынес функционал в другой класс.
Сейчас делаю так:
public static class Util
{
public static uint OverflowShortToUInt(short s)
{
return (uint)(s >= 0 ? s : Math.Abs((-s) + Int16.MinValue) + Int16.MaxValue + 1);
}
}
unsafe public class DataObjectS
{
public static DataObject.CIDA cida;
public static IntPtr ciPtr;
[DllImport("ntdll.dll")]
public static extern int memcpy(int dst, int src, int count);
static DataObjectS()
{
IntPtr idList = ShellNativeMethods.SHSimpleIDListFromPath("ftp://smth.com");
IntPtr idListFile = ShellNativeMethods.SHSimpleIDListFromPath("ftp://smth.com/hi");
DataObject.ITEMIDLIST idListS = (DataObject.ITEMIDLIST)Marshal.PtrToStructure(idList, typeof(DataObject.ITEMIDLIST));
DataObject.ITEMIDLIST idListFileS = (DataObject.ITEMIDLIST)Marshal.PtrToStructure(idListFile, typeof(DataObject.ITEMIDLIST));
int itemDListSize = idListFileS.mkid.cb; //both item`s size is equal
// CIDA size + second element of uint[] + 2 ITEMIDLIST
ciPtr = Marshal.AllocHGlobal(sizeof(DataObject.CIDA) + sizeof(uint) + itemDListSize * 2);
cida = (DataObject.CIDA)Marshal.PtrToStructure(ciPtr, typeof(DataObject.CIDA));
cida.cidl = 2;
fixed (uint* cidaAOffs = cida.aoffset)
{
cidaAOffs[0] = (uint)(sizeof(DataObject.CIDA) + sizeof(uint));
cidaAOffs[1] = (uint)(sizeof(DataObject.CIDA) + sizeof(uint) + itemDListSize);
memcpy((int) (ciPtr.ToInt32() + cidaAOffs[0]), idList.ToInt32(), itemDListSize);
memcpy((int) (ciPtr.ToInt32() + cidaAOffs[1]), idListFile.ToInt32(), itemDListSize);
// Check on debug.
IntPtr ptr = new IntPtr(ciPtr.ToInt32() + cidaAOffs[1]);
// Тут не сходится
DataObject.ITEMIDLIST idListFileSCheck = (DataObject.ITEMIDLIST)Marshal.PtrToStructure(ptr, typeof(DataObject.ITEMIDLIST));
}
}
// Вызывается перед всем остальнымpublic static void ChopChop() // COM-object cannot be debugged and does not call static constructor
{
}
}
[ComVisible(true)]
[Guid("1BE34910-108C-4A61-B4CA-9B6F87815607")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("Microsoft.WindowsAPICodePack.Shell.Custom.DataSource")]
[ComSourceInterfaces(typeof(IDataObject))]
unsafe public class DataObject : IDataObject
{
enum CFormat
{
CF_TEXT = 1,
CF_BITMAP = 2,
CF_METAFILEPICT = 3,
CF_SYLK = 4,
CF_DIF = 5,
CF_TIFF = 6,
CF_OEMTEXT = 7,
CF_DIB = 8,
CF_PALETTE = 9,
CF_PENDATA = 10,
CF_RIFF = 11,
CF_WAVE = 12,
CF_UNICODETEXT = 13,
CF_ENHMETAFILE = 14,
// For windows XP+
CF_HDROP = 15,
CF_LOCALE = 16,
CF_DIBV5 = 17,
CF_MAX = 18,
CF_OWNERDISPLAY = 0x0080,
CF_DSPTEXT = 0x0081,
CF_DSPBITMAP = 0x0082,
CF_DSPMETAFILEPICT = 0x0083,
CF_DSPENHMETAFILE = 0x008E,
/*
* "Private" formats don't get GlobalFree()'d
*/
CF_PRIVATEFIRST = 0x0200,
CF_PRIVATELAST = 0x02FF,
/*
* "GDIOBJ" formats do get DeleteObject()'d
*/
CF_GDIOBJFIRST = 0x0300,
CF_GDIOBJLAST = 0x03FF,
/*
* Situatuion-related
*/
FC_AutoplayEnumIDListArray = 0xC0ED,
FC_ShellIDListArray = 0xC08C
}
[StructLayout(LayoutKind.Sequential)]
public struct CIDA
{
public uint cidl;
public fixed uint aoffset[1]; // list of ITEMIDLIST
};
[StructLayout(LayoutKind.Sequential)]
public struct ITEMIDLIST
{
public SHITEMID mkid;
};
[StructLayout(LayoutKind.Sequential)]
public struct SHITEMID
{
public ushort cb;
public byte[1] abID; // list of ?
};
public void GetData(ref FORMATETC format, out STGMEDIUM medium)
{
Console.WriteLine("GetData");
Console.WriteLine(
"format.cfFormat: " + format.cfFormat +
" format.dwAspect:" + format.dwAspect +
" format.lindex:" + format.lindex +
" format.ptd:" + format.ptd +
" format.tymed:" + format.tymed
);
uint cFormat = Util.OverflowShortToUInt(format.cfFormat);
Console.WriteLine(cFormat);
/*StringBuilder cName = new StringBuilder(255);
if (GetClipboardFormatName(bits, cName, 255) == 0)
{
Console.WriteLine("FmtName returned zeo");
}
Console.WriteLine(cName.ToString());*/
medium = new STGMEDIUM();
if ((CFormat)cFormat == CFormat.FC_ShellIDListArray)
{
medium.unionmember = DataObjectS.ciPtr;
}
}
.......
Если я правильно понимаю — если я хочу всё сделать сплошным куском (все offsets рядом) — для двух айтемов нужно выделить sizeof(DataObject.CIDA) + (sizeof(uint)*(2-1)) + размер ITEMIDLIST * (2)
Так как CIDA содержит массив с 1 элементом, а нужно 2 — выделяем ещё плюс sizeof(uint), и плюс 2 объекта ITEMIDLIST.
В вышеприведённом коде в методе DataObjectS() почему-то не сходятся значения структур (обычно отличаются на 1-2 последних цифры).
Сейчас код падает с ошибкой Access violation reading location, с адресом, никак не связаным ни с CIDA, ни с содержимым ITEMIDLIST (а там тоже невалидная ссылка) полученным через SHSimpleIDListFromPath с несуществующим адресом.
Тяжело однако.
Re[7]: Подмена отдельного класса \ методав чужой не обфусцированной сборке
Здравствуйте, Aniskin, Вы писали:
A>Здравствуйте, M3fN, Вы писали:
MN>>Пока копаю дальше, в этот COM.
A>Предполагаю, что придется тебе писать namespace shell extension, а уже его отображать в IExplorerBrowser.
Через реализацию IDataObject это вообще можно сделать? А то я просто копаю, не знаю куда. Если да, то как будет легче и быстрее?
Уже уйму времени потратил с начала недели. Такое ощущение что в COM всё сделано максимально сложно.
Re[7]: Подмена отдельного класса \ методав чужой не обфусцированной сборке
В код не вникал, поскольку не знакомый мне ЯП.
MN> FC_AutoplayEnumIDListArray = 0xC0ED, MN> FC_ShellIDListArray = 0xC08C
Эти величины должны получаться путем вызова RegisterClipboardFormat с "Autoplay Enumerated IDlist array" и "Shell IDlist array" соответственно.
MN>Если я правильно понимаю — если я хочу всё сделать сплошным куском (все offsets рядом) — для двух айтемов нужно выделить sizeof(DataObject.CIDA) + (sizeof(uint)*(2-1)) + размер ITEMIDLIST * (2) MN>Так как CIDA содержит массив с 1 элементом, а нужно 2 — выделяем ещё плюс sizeof(uint), и плюс 2 объекта ITEMIDLIST.
Для N элементов нужно выделить sizeof(UINT {CIDA.cidl}) + sizeof(UINT) * (N + 1) + sizeof(ITEMIDLIST) * (N + 1) байт.
MN>Сейчас код падает с ошибкой Access violation reading location, с адресом, никак не связаным ни с CIDA, ни с содержимым ITEMIDLIST (а там тоже невалидная ссылка) полученным через SHSimpleIDListFromPath с несуществующим адресом.
Я думаю проблема в том, что после получения твоих структур IExplorerBrowser начинает вызывать различные функции для работы с ITEMIDLIST, и при этом подразумевается, что твои ITEMIDLIST-ты ссылаются на какие-либо реально существующие объекты реальной или виртуальной файловой системы. А поскольку их нет, то и возникают AV. Поэтому я и написал, что нужно писать namespace shell extension, тогда у shell32.dll к тебе претензий в виде AV не будет.
Re[8]: Подмена отдельного класса \ методав чужой не обфусцированной сборке
Здравствуйте, M3fN, Вы писали:
A>>Предполагаю, что придется тебе писать namespace shell extension, а уже его отображать в IExplorerBrowser.
MN>Через реализацию IDataObject это вообще можно сделать?
Нет. Namespace shell extension — это отдельная dll, регистрируемая в системе. Подробнее.
MN>А то я просто копаю, не знаю куда. Если да, то как будет легче и быстрее?
Если стоит задача отображать в IExplorerBrowser произвольные данные, то imho он для этого не предназначен. Поэтому нужно/можно использовать обходной путь в виде namespace shell extension. Конечно, возможно, что я и ошибаюсь.
MN>Такое ощущение что в COM всё сделано максимально сложно.
Я тоже по началу так думал. С тех под прошло много лет. И мое мнение совершенно не изменилось
Re[8]: Подмена отдельного класса \ методав чужой не обфусцированной сборке
Здравствуйте, Aniskin, Вы писали:
A>Я думаю проблема в том, что после получения твоих структур IExplorerBrowser начинает вызывать различные функции для работы с ITEMIDLIST, и при этом подразумевается, что твои ITEMIDLIST-ты ссылаются на какие-либо реально существующие объекты реальной или виртуальной файловой системы. А поскольку их нет, то и возникают AV. Поэтому я и написал, что нужно писать namespace shell extension, тогда у shell32.dll к тебе претензий в виде AV не будет.
ITEMIDLIST может быть "провайдером" только для объектов виртуальной или реальной файловой системы? Ничего кастомного туда нельзя запихнуть?
Например, реализовать IShellItem2 и каким-то образом сказать ITEMIDLIST ссылаться на него?
Re[9]: Подмена отдельного класса \ методав чужой не обфусцированной сборке
Здравствуйте, M3fN, Вы писали:
MN>ITEMIDLIST может быть "провайдером" только для объектов виртуальной или реальной файловой системы?
Imho, да.
Ничего кастомного туда нельзя запихнуть?
Imho, нельзя.
MN>Например, реализовать IShellItem2 и каким-то образом сказать ITEMIDLIST ссылаться на него?
Я такого пути не знаю.
ITEMIDLIST — это просто набор байтов, о сути которых знает только та сущность, что их создала. Shell оперирует этими ITEMIDLIST без понимания, что в них находятся. Если нужно получить имя объекта, то shell просто обращается к IShellFolder2, который реализует расширение оболочки.
Re[7]: Подмена отдельного класса \ методав чужой не обфусцированной сборке
Здравствуйте, Aniskin, Вы писали:
A>Здравствуйте, M3fN, Вы писали:
MN>>Пока копаю дальше, в этот COM.
A>Предполагаю, что придется тебе писать namespace shell extension, а уже его отображать в IExplorerBrowser.
Здравствуйте, M3fN, Вы писали:
MN>но так и не понял как теперь это использовать. Как? В IExplorerBrowser желательно.
В namespace extension реализуется логика получения имен файлов, которые нужно отображать в IExplorerBrowser, т.е. реализуется виртуальные файлы. А затем в IExplorerBrowser через IDataObject передаются ссылки на эти виртуальные файлы. После чего IExplorerBrowser спокойно отображает эти самые виртуальные файлы. Как-то так.
Re[9]: Подмена отдельного класса \ методав чужой не обфусцированной сборке
Здравствуйте, Aniskin, Вы писали:
A>Здравствуйте, M3fN, Вы писали:
MN>>но так и не понял как теперь это использовать. Как? В IExplorerBrowser желательно.
A>В namespace extension реализуется логика получения имен файлов, которые нужно отображать в IExplorerBrowser, т.е. реализуется виртуальные файлы. А затем в IExplorerBrowser через IDataObject передаются ссылки на эти виртуальные файлы. После чего IExplorerBrowser спокойно отображает эти самые виртуальные файлы. Как-то так.
Есть зарегистрированные классы:
class ATL_NO_VTABLE CShellViewImpl :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CShellViewImpl, &CLSID_ShellViewImpl>,
public IShellView,
public IOleCommandTarget,
public CWindowImpl<CShellViewImpl>
class ATL_NO_VTABLE CShellFolderImpl :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CShellFolderImpl, &CLSID_ShellFolderImpl>,
public IShellFolder,
public IPersistFolder
Как их теперь использовать для получения виртуальных id? Google "Using namespace shell extension" выдаёт ничего.
Re[10]: Подмена отдельного класса \ методав чужой не обфусцированной сборке
Здравствуйте, M3fN, Вы писали:
MN>Как их теперь использовать для получения виртуальных id? Google "Using namespace shell extension" выдаёт ничего.
Я думаю, что стоит начать с того, что бы твоя виртуальная папка с твоими виртуальными файлами отображалась в простом проводнике. А как все заработает, то ее можно будет скрыть, и уже получать IDLIST через IShellFolder2.
Re[11]: Подмена отдельного класса \ методав чужой не обфусцированной сборке
Здравствуйте, Aniskin, Вы писали:
A>Здравствуйте, M3fN, Вы писали:
MN>>Как их теперь использовать для получения виртуальных id? Google "Using namespace shell extension" выдаёт ничего.
A>Я думаю, что стоит начать с того, что бы твоя виртуальная папка с твоими виртуальными файлами отображалась в простом проводнике. А как все заработает, то ее можно будет скрыть, и уже получать IDLIST через IShellFolder2.
Здравствуйте, M3fN, Вы писали:
MN>не могу найти там где же всё-таки его хоть как-то использовать, хоть где-то, проект — две библиотеки.
Поскольку вопрос задается второй раз, то соответственно на первый я отвел не то, что ты хотел услышать. Произошло это, вероятно, по той причине, что я не правильно понял вопрос. Соответственно, перефразируй или задай менее общий вопрос.
Re[13]: Подмена отдельного класса \ методав чужой не обфусцированной сборке
Здравствуйте, Aniskin, Вы писали:
A>Здравствуйте, M3fN, Вы писали:
MN>>не могу найти там где же всё-таки его хоть как-то использовать, хоть где-то, проект — две библиотеки.
A>Поскольку вопрос задается второй раз, то соответственно на первый я отвел не то, что ты хотел услышать. Произошло это, вероятно, по той причине, что я не правильно понял вопрос. Соответственно, перефразируй или задай менее общий вопрос.
Я не представляю как вообще можно использовать собственный shell namespace extension, ведь это просто набор com-классов, как к ним обращаться, будь то встраивание в IExplorerBrowser или использование в простом проводнике.
Вы написали чтобы я попробовал создать виртуальную папку и использовать в простом проводнике, как я понял её можно создать реализуя shell namespace(extension) или, как я нагуглил, что-то там настраивать в IIS (возможно это разные понятия под одним названием?).
Re[14]: Подмена отдельного класса \ методав чужой не обфусцированной сборке
Здравствуйте, M3fN, Вы писали:
MN>Я не представляю как вообще можно использовать собственный shell namespace extension, ведь это просто набор com-классов, как к ним обращаться, будь то встраивание в IExplorerBrowser или использование в простом проводнике.
Ок. Имеется некое shell namespace extension. В общем случае корневая папка твоего расширения будет иметь виртуальный путь типа такого (GUID-ы взяты наугад) "::{ED228FDF-9EA8-4870-83B1-96B02CFE0D52}\{6C815596-821F-40B3-8A84-643B73A8EB16}" Для того, что бы обратиться к твоим объектам, нужно будет получить интерфейс IShellFolder твоей папки. Это делается примерно следующими вызовами (пишу по памяти):
Что бы перечислить объекты, нужно вызвать IShellFolder::EnumObjects, что бы получить имя каждого из объектов, нужно вызвать IShellFolder.GetDisplayNameOf и т.д.
Соответственно, полученный ItemIDList можно передать в IExplorerBrowser через IDataObject. И IExplorerBrowser будет отображать твою папку, используя эти же самые вызовы из IShellFolder. Но, наверное, будет проще использовать IExplorerBrowser.BrowseToIDList или IExplorerBrowser.BrowseToObject вместо гемора с IDataObject.
MN>Вы написали чтобы я попробовал создать виртуальную папку и использовать в простом проводнике, как я понял её можно создать реализуя shell namespace(extension)
Ты правильно понял.
MN>или, как я нагуглил, что-то там настраивать в IIS (возможно это разные понятия под одним названием?).
Не знаком с этий аббревиатурой.
Re[15]: Подмена отдельного класса \ методав чужой не обфусцированной сборке
Здравствуйте, Aniskin, Вы писали:
A>Здравствуйте, M3fN, Вы писали:
MN>>Я не представляю как вообще можно использовать собственный shell namespace extension, ведь это просто набор com-классов, как к ним обращаться, будь то встраивание в IExplorerBrowser или использование в простом проводнике.
A>Ок. Имеется некое shell namespace extension. В общем случае корневая папка твоего расширения будет иметь виртуальный путь типа такого (GUID-ы взяты наугад) "::{ED228FDF-9EA8-4870-83B1-96B02CFE0D52}\{6C815596-821F-40B3-8A84-643B73A8EB16}" Для того, что бы обратиться к твоим объектам, нужно будет получить интерфейс IShellFolder твоей папки. Это делается примерно следующими вызовами (пишу по памяти):
A>SHGetDesktopFolder(DesktopFolder) A>DesktopFolder.ParseDisplayName(0, nil, '::{ED228FDF-9EA8-4870-83B1-96B02CFE0D52}\{6C815596-821F-40B3-8A84-643B73A8EB16}', Eaten, ItemIDList, Attributes)) A>DesktopFolder.BindToObject(ItemIDList, nil, IID_IShellFolder, ShellFolder)
A>Что бы перечислить объекты, нужно вызвать IShellFolder::EnumObjects, что бы получить имя каждого из объектов, нужно вызвать IShellFolder.GetDisplayNameOf и т.д.
A>Соответственно, полученный ItemIDList можно передать в IExplorerBrowser через IDataObject. И IExplorerBrowser будет отображать твою папку, используя эти же самые вызовы из IShellFolder. Но, наверное, будет проще использовать IExplorerBrowser.BrowseToIDList или IExplorerBrowser.BrowseToObject вместо гемора с IDataObject.
MN>>Вы написали чтобы я попробовал создать виртуальную папку и использовать в простом проводнике, как я понял её можно создать реализуя shell namespace(extension)
A>Ты правильно понял.
MN>>или, как я нагуглил, что-то там настраивать в IIS (возможно это разные понятия под одним названием?).
A>Не знаком с этий аббревиатурой.
Спасибо большое. Буду копать, хотя твой пост пока выглядит так, что всё вроде-бы выкопано.