NSE: Показывать виртуальный путь вместо пути файловой системы в диалоге SaveAs (IFileSaveDialog)
Это первый раз, когда я публикую что-то на Stackru. Я отчаянно ищу решение по не совсем задокументированной теме.
Мы разработали решение DMS (FileSystem / Cloud Services), интегрированное в Windows, как расширение пространства имен. Это решение отлично работает, NSE видна в IFileSaveDialog, и мы можем напрямую сохранять в нем файлы.
Моя проблема в том, что я хотел бы иметь возможность показывать виртуальный путь, а не путь файловой системы, при открытии диалога SaveAs в приложениях, таких как Word, Excel, Блокнот и т. Д. (Используемый файл ранее был открыт в Расширении пространства имен).
Я знаю, что мы можем передать IShellItem в качестве аргумента в IFilSaveDialog.SetSaveAsItem, но будет ли он иметь желаемый эффект (данный элемент имеет атрибут SFGAO_FILESYSTEM), а затем, более сложно, как я могу подключить его при использовании SaveAs в стандартном приложении Windows?
Возможно, я совершенно не прав, и есть очень секретный способ решения этой проблемы (я даже пытался симулировать перетаскивание в приложениях, таких как Winword.exe, поэтому я действительно застрял). Но я уверен (даже если это сложно), есть решение, так как Windows интегрирует виртуальные папки, такие как "Мои документы" в диалоге SaveAs.
Большое спасибо за вашу помощь.
2 ответа
Я никогда не отвечал здесь. Но в конце концов я нашел решение.
Денис Анисимов был прав, когда писал:
Если вы видите виртуальную папку в стандартном диалоговом окне "Сохранить как", это означает, что виртуальная папка имеет атрибут SFGAO_FILESYSANCESTOR. Windows показывает такую папку, но ожидает, что папка содержит объекты с атрибутом SFGAO_FILESYSTEM.
К сожалению, в Windows 10 папки должны иметь оба атрибута. Но это не главное.
Таким образом, ответы таковы: "пусть система думает, что ваш объект является объектом файловой системы, и управляйте процессом сохранения файла самостоятельно"
Поэтому вы не должны использовать путь файловой системы для отображаемого имени вашего объекта (в противном случае вы сделали это), а затем реализовать интерфейс IObjectWithSite в классах вашего виртуального объекта (спасибо ArielB за ваши сообщения!) И самостоятельно обрабатывать объекты, сохраняя действие - в моем случай загрузки файла во временную папку и запуска Файловой системы -.
Я разместил некоторые выдержки из кода. Вам также необходимо разработать собственную реализацию IFileDialogEvents.
public NativeMethods.HRESULT GetSite(ref Guid riid, out IntPtr ppvSite)
{
if (PUnkSite != IntPtr.Zero)
{
Marshal.QueryInterface(PUnkSite, ref riid, out ppvSite);
return NativeMethods.HRESULT.S_OK;
}
ppvSite = IntPtr.Zero;
return NativeMethods.HRESULT.S_FALSE;
}
public void SetSite(IntPtr pUnkSite)
{
if (PUnkSite != IntPtr.Zero)
{
Marshal.Release(PUnkSite);
if (FileSaveDialog != null)
{
FileSaveDialog.Unadvise(DwCookie);
Marshal.ReleaseComObject(FileSaveDialog);
FileSaveDialog = null;
DwCookie = 0;
}
else if (FileOpenDialog != null)
{
FileOpenDialog.Unadvise(DwCookie);
Marshal.ReleaseComObject(FileOpenDialog);
FileOpenDialog = null;
DwCookie = 0;
}
}
PUnkSite = pUnkSite;
if (PUnkSite == IntPtr.Zero) return;
Marshal.AddRef(PUnkSite);
Guid iFileSaveDialogGuid = typeof (NativeMethods.IFileSaveDialog).GUID;
IntPtr iFileSaveDialogPointer;
NativeMethods.IUnknown_QueryService(pUnkSite, ref NativeMethods.SID_SExplorerBrowserFrame, ref iFileSaveDialogGuid, out iFileSaveDialogPointer);
if (iFileSaveDialogPointer != IntPtr.Zero)
{
FileSaveDialog = (NativeMethods.IFileSaveDialog) Marshal.GetObjectForIUnknown(iFileSaveDialogPointer);
Marshal.Release(iFileSaveDialogPointer);
if (FileSaveDialog == null) return;
FileDialogEvents dialogEvents = new FileDialogEvents(ConnectorName, FileDialogEvents.FileSaveType,
ObjectMetadata.ObjectAddress, ObjectMetadata.ObjectClass);
FileSaveDialog.Advise(dialogEvents, out DwCookie);
return;
}
Guid iFileOpenDialogGuid = typeof(NativeMethods.IFileOpenDialog).GUID;
IntPtr iFileOpenDialogPointer;
NativeMethods.IUnknown_QueryService(pUnkSite, ref NativeMethods.SID_SExplorerBrowserFrame, ref iFileOpenDialogGuid, out iFileOpenDialogPointer);
if (iFileOpenDialogPointer == IntPtr.Zero) return;
FileOpenDialog = (NativeMethods.IFileOpenDialog)Marshal.GetObjectForIUnknown(iFileOpenDialogPointer);
Marshal.Release(iFileOpenDialogPointer);
if (FileOpenDialog == null) return;
FileDialogEvents dialogEventsOpen = new FileDialogEvents(ConnectorName, FileDialogEvents.FileOpenType,
ObjectMetadata.ObjectAddress, ObjectMetadata.ObjectClass);
FileOpenDialog.Advise(dialogEventsOpen, out DwCookie);
}
Также здесь COM-объекты (определенные в NativeMethods):
public static Guid SID_SExplorerBrowserFrame = new Guid("000214F1-0000-0000-C000-000000000046"); // SID_SExplorerBrowserFrame
[ComImport, Guid("FC4801A3-2BA9-11CF-A229-00AA003D7352"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IObjectWithSite
{
void SetSite([In] IntPtr pUnkSite);
HRESULT GetSite(ref Guid guid, out IntPtr ppvSite);
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)]
public struct COMDLG_FILTERSPEC
{
[MarshalAs(UnmanagedType.LPWStr)]
public string pszName;
[MarshalAs(UnmanagedType.LPWStr)]
public string pszSpec;
}
[Flags]
public enum FOS : uint
{
FOS_OVERWRITEPROMPT = 0x00000002,
FOS_STRICTFILETYPES = 0x00000004,
FOS_NOCHANGEDIR = 0x00000008,
FOS_PICKFOLDERS = 0x00000020,
FOS_FORCEFILESYSTEM = 0x00000040, // Ensure that items returned are filesystem items.
FOS_ALLNONSTORAGEITEMS = 0x00000080, // Allow choosing items that have no storage.
FOS_NOVALIDATE = 0x00000100,
FOS_ALLOWMULTISELECT = 0x00000200,
FOS_PATHMUSTEXIST = 0x00000800,
FOS_FILEMUSTEXIST = 0x00001000,
FOS_CREATEPROMPT = 0x00002000,
FOS_SHAREAWARE = 0x00004000,
FOS_NOREADONLYRETURN = 0x00008000,
FOS_NOTESTFILECREATE = 0x00010000,
FOS_HIDEMRUPLACES = 0x00020000,
FOS_HIDEPINNEDPLACES = 0x00040000,
FOS_NODEREFERENCELINKS = 0x00100000,
FOS_DONTADDTORECENT = 0x02000000,
FOS_FORCESHOWHIDDEN = 0x10000000,
FOS_DEFAULTNOMINIMODE = 0x20000000
}
[Flags]
public enum FDAP
{
FDAP_BOTTOM = 0,
FDAP_TOP = 1
}
[ComImport, Guid("B63EA76D-1F85-456F-A19C-48159EFA858B"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IShellItemArray
{
// Not supported: IBindCtx
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void BindToHandler([In, MarshalAs(UnmanagedType.Interface)] IntPtr pbc, [In] ref Guid rbhid,
[In] ref Guid riid, out IntPtr ppvOut);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetPropertyStore([In] int Flags, [In] ref Guid riid, out IntPtr ppv);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetPropertyDescriptionList([In] ref PROPERTYKEY keyType, [In] ref Guid riid, out IntPtr ppv);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetAttributes([In] SIATTRIBFLAGS dwAttribFlags, [In] uint sfgaoMask, out uint psfgaoAttribs);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetCount(out uint pdwNumItems);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetItemAt([In] uint dwIndex, [MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
// Not supported: IEnumShellItems (will use GetCount and GetItemAt instead)
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void EnumItems([MarshalAs(UnmanagedType.Interface)] out IntPtr ppenumShellItems);
}
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct PROPERTYKEY
{
public Guid fmtid;
public uint pid;
}
public enum SIATTRIBFLAGS
{
SIATTRIBFLAGS_AND = 1,
SIATTRIBFLAGS_APPCOMPAT = 3,
SIATTRIBFLAGS_OR = 2
}
[ComImport, Guid("d57c7288-d4ad-4768-be02-9d969532d960"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IFileOpenDialog : IFileDialog
{
// Defined on IModalWindow - repeated here due to requirements of COM interop layer
// --------------------------------------------------------------------------------
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), PreserveSig]
int Show([In] IntPtr parent);
// Defined on IFileDialog - repeated here due to requirements of COM interop layer
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetFileTypes([In] uint cFileTypes, [In] COMDLG_FILTERSPEC[] rgFilterSpec);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetFileTypeIndex([In] uint iFileType);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetFileTypeIndex(out uint piFileType);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void Advise([In, MarshalAs(UnmanagedType.Interface)] IFileDialogEvents pfde, out uint pdwCookie);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void Unadvise([In] uint dwCookie);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetOptions([In] FOS fos);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetOptions(out FOS pfos);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetDefaultFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetFolder([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetCurrentSelection([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetFileName([In, MarshalAs(UnmanagedType.LPWStr)] string pszName);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetTitle([In, MarshalAs(UnmanagedType.LPWStr)] string pszTitle);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetOkButtonLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszText);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetFileNameLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszLabel);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetResult([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void AddPlace([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, FDAP fdap);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetDefaultExtension([In, MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void Close([MarshalAs(UnmanagedType.Error)] int hr);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetClientGuid([In] ref Guid guid);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void ClearClientData();
// Not supported: IShellItemFilter is not defined, converting to IntPtr
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetFilter([MarshalAs(UnmanagedType.Interface)] IntPtr pFilter);
// Defined by IFileOpenDialog
// ---------------------------------------------------------------------------------
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetResults([MarshalAs(UnmanagedType.Interface)] out IShellItemArray ppenum);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetSelectedItems([MarshalAs(UnmanagedType.Interface)] out IShellItemArray ppsai);
}
[ComImport, Guid("84bccd23-5fde-4cdb-aea4-af64b83d78ab"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IFileSaveDialog : IFileDialog
{
// Defined on IModalWindow - repeated here due to requirements of COM interop layer
// --------------------------------------------------------------------------------
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), PreserveSig]
int Show([In] IntPtr parent);
// Defined on IFileDialog - repeated here due to requirements of COM interop layer
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetFileTypes([In] uint cFileTypes, [In] COMDLG_FILTERSPEC[] rgFilterSpec);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetFileTypeIndex([In] uint iFileType);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetFileTypeIndex(out uint piFileType);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void Advise([In, MarshalAs(UnmanagedType.Interface)] IFileDialogEvents pfde, out uint pdwCookie);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void Unadvise([In] uint dwCookie);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetOptions([In] FOS fos);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetOptions(out FOS pfos);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetDefaultFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetFolder([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetCurrentSelection([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetFileName([In, MarshalAs(UnmanagedType.LPWStr)] string pszName);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetTitle([In, MarshalAs(UnmanagedType.LPWStr)] string pszTitle);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetOkButtonLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszText);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetFileNameLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszLabel);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetResult([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void AddPlace([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, FDAP fdap);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetDefaultExtension([In, MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void Close([MarshalAs(UnmanagedType.Error)] int hr);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetClientGuid([In] ref Guid guid);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void ClearClientData();
// Not supported: IShellItemFilter is not defined, converting to IntPtr
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetFilter([MarshalAs(UnmanagedType.Interface)] IntPtr pFilter);
// Defined by IFileSaveDialog interface
// -----------------------------------------------------------------------------------
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetSaveAsItem([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi);
// Not currently supported: IPropertyStore
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetProperties([In, MarshalAs(UnmanagedType.Interface)] IntPtr pStore);
// Not currently supported: IPropertyDescriptionList
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetCollectedProperties([In, MarshalAs(UnmanagedType.Interface)] IntPtr pList, [In] int fAppendDefault);
// Not currently supported: IPropertyStore
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetProperties([MarshalAs(UnmanagedType.Interface)] out IntPtr ppStore);
// Not currently supported: IPropertyStore, IFileOperationProgressSink
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void ApplyProperties([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi,
[In, MarshalAs(UnmanagedType.Interface)] IntPtr pStore,
[In, ComAliasName("ShellObjects.wireHWND")] ref IntPtr hwnd,
[In, MarshalAs(UnmanagedType.Interface)] IntPtr pSink);
}
[ComImport, Guid("42f85136-db7e-439c-85f1-e4075d135fc8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IFileDialog : IModalWindow
{
// Defined on IModalWindow - repeated here due to requirements of COM interop layer
// --------------------------------------------------------------------------------
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), PreserveSig]
int Show([In] IntPtr parent);
// IFileDialog-Specific interface members
// --------------------------------------------------------------------------------
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetFileTypes([In] uint cFileTypes,
[In, MarshalAs(UnmanagedType.LPArray)] COMDLG_FILTERSPEC[] rgFilterSpec);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetFileTypeIndex([In] uint iFileType);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetFileTypeIndex(out uint piFileType);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void Advise([In, MarshalAs(UnmanagedType.Interface)] IFileDialogEvents pfde, out uint pdwCookie);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void Unadvise([In] uint dwCookie);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetOptions([In] FOS fos);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetOptions(out FOS pfos);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetDefaultFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetFolder([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetCurrentSelection([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetFileName([In, MarshalAs(UnmanagedType.LPWStr)] string pszName);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetTitle([In, MarshalAs(UnmanagedType.LPWStr)] string pszTitle);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetOkButtonLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszText);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetFileNameLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszLabel);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetResult([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void AddPlace([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, FDAP fdap);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetDefaultExtension([In, MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void Close([MarshalAs(UnmanagedType.Error)] int hr);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetClientGuid([In] ref Guid guid);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void ClearClientData();
// Not supported: IShellItemFilter is not defined, converting to IntPtr
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetFilter([MarshalAs(UnmanagedType.Interface)] IntPtr pFilter);
}
[ComImport, Guid("b4db1657-70d7-485e-8e3e-6fcb5a5c1802"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IModalWindow
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), PreserveSig]
int Show([In] IntPtr parent);
}
public enum HRESULT : long
{
S_FALSE = 0x0001,
S_OK = 0x0000,
E_INVALIDARG = 0x80070057,
E_OUTOFMEMORY = 0x8007000E,
STG_E_FILENOTFOUND = 0x80030002
}
public enum FDE_SHAREVIOLATION_RESPONSE
{
FDESVR_DEFAULT = 0x00000000,
FDESVR_ACCEPT = 0x00000001,
FDESVR_REFUSE = 0x00000002
}
public enum FDE_OVERWRITE_RESPONSE
{
FDEOR_DEFAULT = 0x00000000,
FDEOR_ACCEPT = 0x00000001,
FDEOR_REFUSE = 0x00000002
}
public enum Sigdn : uint
{
SigdnNormaldisplay = 0x00000000,
SigdnParentrelativeparsing = 0x80018001,
SigdnParentrelativeforaddressbar = 0x8001c001,
SigdnDesktopabsoluteparsing = 0x80028000,
SigdnParentrelativeediting = 0x80031001,
SigdnDesktopabsoluteediting = 0x8004c000,
SigdnFilesyspath = 0x80058000,
SigdnUrl = 0x80068000
}
[DllImport("shlwapi.dll")]
public static extern int IUnknown_QueryService(IntPtr pUnk, ref Guid guidService, ref Guid riid, out IntPtr ppvOut);
[ComImport, Guid("973510DB-7D7F-452B-8975-74A85828D354"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IFileDialogEvents
{
// NOTE: some of these callbacks are cancelable - returning S_FALSE means that
// the dialog should not proceed (e.g. with closing, changing folder); to
// support this, we need to use the PreserveSig attribute to enable us to return
// the proper HRESULT
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), PreserveSig]
HRESULT OnFileOk([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), PreserveSig]
HRESULT OnFolderChanging([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd,
[In, MarshalAs(UnmanagedType.Interface)] IShellItem psiFolder);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void OnFolderChange([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void OnSelectionChange([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void OnShareViolation([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd,
[In, MarshalAs(UnmanagedType.Interface)] IShellItem psi,
out FDE_SHAREVIOLATION_RESPONSE pResponse);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void OnTypeChange([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void OnOverwrite([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd,
[In, MarshalAs(UnmanagedType.Interface)] IShellItem psi,
out FDE_OVERWRITE_RESPONSE pResponse);
}
[DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern int SHCreateItemFromIDList(
/*PCIDLIST_ABSOLUTE*/ IntPtr pidl,
ref Guid riid,
[MarshalAs(UnmanagedType.Interface)] out IShellItem ppv);
Стандартное приложение для Windows было разработано для работы с реальными файлами с использованием такой функции, как CreateFile. Такие функции не могут работать с виртуальными файлами. Если вы видите виртуальную папку в стандартном диалоговом окне "Сохранить как", это означает, что виртуальная папка имеет атрибут SFGAO_FILESYSANCESTOR. Windows показывает такую папку, но ожидает, что папка содержит объекты с атрибутом SFGAO_FILESYSTEM. Поэтому я думаю, что нет никакого решения.