diff --git a/BeefLibs/corlib/src/IO/FileDialog.Vista.bf b/BeefLibs/corlib/src/IO/FileDialog.Vista.bf new file mode 100644 index 00000000..994a2382 --- /dev/null +++ b/BeefLibs/corlib/src/IO/FileDialog.Vista.bf @@ -0,0 +1,159 @@ +// This file contains portions of code released by Microsoft under the MIT license as part +// of an open-sourcing initiative in 2014 of the C# core libraries. +// The original source was submitted to https://github.com/Microsoft/referencesource + +using System.Diagnostics; +using System.Collections; + +#if BF_PLATFORM_WINDOWS +namespace System.IO +{ + extension FileDialog + { + protected abstract Result CreateVistaDialog(); + + private Result TryRunDialogVista(Windows.HWnd hWndOwner) + { + Windows.COM_IFileDialog* dialog; + if (!(CreateVistaDialog() case .Ok(out dialog))) + return .Err; + + OnBeforeVistaDialog(dialog); + dialog.VT.Show(dialog, hWndOwner); + + List files = scope .(); + ProcessVistaFiles(dialog, files); + + DeleteContainerAndItems!(mFileNames); + mFileNames = new String[files.Count]; + files.CopyTo(mFileNames); + + dialog.VT.Release(dialog); + + return .Ok(files.IsEmpty ? .Cancel : .OK); + } + + private void OnBeforeVistaDialog(Windows.COM_IFileDialog* dialog) + { + dialog.VT.SetDefaultExtension(dialog, DefaultExt.ToScopedNativeWChar!()); + + if (mFileNames != null && !mFileNames.IsEmpty) + dialog.VT.SetFileName(dialog, mFileNames[0].ToScopedNativeWChar!()); + + if (!String.IsNullOrEmpty(mInitialDir)) + { + Windows.COM_IShellItem* folderShellItem = null; + Windows.SHCreateItemFromParsingName(mInitialDir.ToScopedNativeWChar!(), null, Windows.COM_IShellItem.sIID, (void**)&folderShellItem); + if (folderShellItem != null) + { + dialog.VT.SetDefaultFolder(dialog, folderShellItem); + dialog.VT.SetFolder(dialog, folderShellItem); + folderShellItem.VT.Release(folderShellItem); + } + } + + dialog.VT.SetTitle(dialog, mTitle.ToScopedNativeWChar!()); + dialog.VT.SetOptions(dialog, GetOptions()); + SetFileTypes(dialog); + } + + private Windows.COM_IFileDialog.FOS GetOptions() + { + const Windows.COM_IFileDialog.FOS BlittableOptions = + Windows.COM_IFileDialog.FOS.OVERWRITEPROMPT + | Windows.COM_IFileDialog.FOS.NOCHANGEDIR + | Windows.COM_IFileDialog.FOS.NOVALIDATE + | Windows.COM_IFileDialog.FOS.ALLOWMULTISELECT + | Windows.COM_IFileDialog.FOS.PATHMUSTEXIST + | Windows.COM_IFileDialog.FOS.FILEMUSTEXIST + | Windows.COM_IFileDialog.FOS.CREATEPROMPT + | Windows.COM_IFileDialog.FOS.NODEREFERENCELINKS; + + const int32 UnexpectedOptions = + (int32)(Windows.OFN_SHOWHELP // If ShowHelp is true, we don't use the Vista Dialog + | Windows.OFN_ENABLEHOOK // These shouldn't be set in options (only set in the flags for the legacy dialog) + | Windows.OFN_ENABLESIZING // These shouldn't be set in options (only set in the flags for the legacy dialog) + | Windows.OFN_EXPLORER); // These shouldn't be set in options (only set in the flags for the legacy dialog) + + Debug.Assert((UnexpectedOptions & mOptions) == 0, "Unexpected FileDialog options"); + + Windows.COM_IFileDialog.FOS ret = (Windows.COM_IFileDialog.FOS)mOptions & BlittableOptions; + + // Force no mini mode for the SaveFileDialog + ret |= Windows.COM_IFileDialog.FOS.DEFAULTNOMINIMODE; + + // Make sure that the Open dialog allows the user to specify + // non-file system locations. This flag will cause the dialog to copy the resource + // to a local cache (Temporary Internet Files), and return that path instead. This + // also affects the Save dialog by disallowing navigation to these areas. + // An example of a non-file system location is a URL (http://), or a file stored on + // a digital camera that is not mapped to a drive letter. + // This reproduces the behavior of the "classic" Open and Save dialogs. + ret |= Windows.COM_IFileDialog.FOS.FORCEFILESYSTEM; + + return ret; + } + + protected abstract void ProcessVistaFiles(Windows.COM_IFileDialog* dialog, List files); + + private Result SetFileTypes(Windows.COM_IFileDialog* dialog) + { + List filterItems = scope .(); + GetFilterItems(filterItems, mFilter); + + if (filterItems.Count == 0) + return .Ok; + + defer + { + for (var filter in filterItems) + { + delete filter.pszName; + delete filter.pszSpec; + } + } + + Windows.COM_IUnknown.HResult hr = dialog.VT.SetFileTypes(dialog, (uint32)filterItems.Count, filterItems.Ptr); + if (hr.Failed) + return .Err; + + hr = dialog.VT.SetFileTypeIndex(dialog, (uint32)mFilterIndex); + if (hr.Failed) + return .Err; + + return .Ok; + } + + private static void GetFilterItems(List list, String filter) + { + mixin ToHeapWChar(var str) + { + int encodedLen = System.Text.UTF16.GetEncodedLen(str); + char16* buf = new char16[encodedLen]* ( ? ); + System.Text.UTF16.Encode(str, buf, encodedLen); + buf + } + + // Expected input types + // "Text files (*.txt)|*.txt|All files (*.*)|*.*" + // "Image Files(*.BMP;*.JPG;*.GIF)|*.BMP;*.JPG;*.GIF|All files (*.*)|*.*" + if (!String.IsNullOrEmpty(filter)) + { + StringView[] tokens = filter.Split!('|'); + if (0 == tokens.Count % 2) + { + // All even numbered tokens should be labels + // Odd numbered tokens are the associated extensions + for (int i = 1; i < tokens.Count; i += 2) + { + Windows.COMDLG_FILTERSPEC ext; + ext.pszSpec = ToHeapWChar!(tokens[i]); // This may be a semicolon delimited list of extensions (that's ok) + ext.pszName = ToHeapWChar!(tokens[i - 1]); + list.Add(ext); + } + } + } + } + } +} +#endif \ No newline at end of file diff --git a/BeefLibs/corlib/src/IO/FileDialog.bf b/BeefLibs/corlib/src/IO/FileDialog.bf new file mode 100644 index 00000000..0ca13890 --- /dev/null +++ b/BeefLibs/corlib/src/IO/FileDialog.bf @@ -0,0 +1,456 @@ +// This file contains portions of code released by Microsoft under the MIT license as part +// of an open-sourcing initiative in 2014 of the C# core libraries. +// The original source was submitted to https://github.com/Microsoft/referencesource + +using System.Text; +using System.Collections; +using System.Threading; +using System.Diagnostics; + +#if BF_PLATFORM_WINDOWS +namespace System.IO +{ + enum DialogResult + { + None = 0, + OK = 1, + Cancel = 2 + } + + abstract class CommonDialog + { + public Windows.HWnd mHWnd; + public Windows.HWnd mDefaultControlHwnd; + public int mDefWndProc; + + private const int32 CDM_SETDEFAULTFOCUS = Windows.WM_USER + 0x51; + + public static Dictionary sHookMap = new Dictionary() ~ + { + Debug.Assert(sHookMap.Count == 0); + delete _; + }; + public static Monitor sMonitor = new Monitor() ~ delete _; + + public Result ShowDialog(INativeWindow owner = null) + { + Windows.HWnd hwndOwner = 0; + if (owner != null) + hwndOwner = (.)owner.Handle; + //Native.WndProc wndProc = scope => OwnerWndProc; + + //mDefWndProc = Native.SetWindowLong(mHWnd, Native.GWL_WNDPROC, (intptr)wndProc.GetFuncPtr().Value); + + var result = RunDialog(hwndOwner); + return result; + } + + public virtual int OwnerWndProc(Windows.HWnd hWnd, int32 msg, int wParam, int lParam) + { + return Windows.CallWindowProcW(mDefWndProc, hWnd, msg, wParam, lParam); + } + + protected virtual int HookProc(Windows.HWnd hWnd, int32 msg, int wParam, int lparam) + { + if (msg == Windows.WM_INITDIALOG) + { + //TODO: MoveToScreenCenter(hWnd); + // Under some circumstances, the dialog + // does not initially focus on any control. We fix that by explicitly + // setting focus ourselves. See ASURT 39435. + // + mDefaultControlHwnd = (Windows.HWnd)wParam; + if (mDefaultControlHwnd != 0) + Windows.SetFocus(mDefaultControlHwnd); + } + else if (msg == Windows.WM_SETFOCUS) + { + Windows.PostMessageW(hWnd, CDM_SETDEFAULTFOCUS, 0, 0); + } + else if (msg == CDM_SETDEFAULTFOCUS) + { + // If the dialog box gets focus, bounce it to the default control. + // so we post a message back to ourselves to wait for the focus change then push it to the default + // control. See ASURT 84016. + // + if (mDefaultControlHwnd != 0) + Windows.SetFocus(mDefaultControlHwnd); + } + return 0; + } + + protected abstract Result RunDialog(Windows.HWnd hWndOwner); + } + + abstract class FileDialog : CommonDialog + { + protected abstract Result RunFileDialog(ref Windows.OpenFileName ofn); + + protected override Result RunDialog(Windows.HWnd hWndOwner) + { + if (TryRunDialogVista(hWndOwner) case .Ok(let result)) + return .Ok(result); + + return RunDialogOld(hWndOwner); + } + + private const int32 FILEBUFSIZE = 8192; + protected const int32 OPTION_ADDEXTENSION = (int32)0x80000000; + + protected int32 mOptions; + private String mTitle ~ delete _; + private String mInitialDir ~ delete _; + private String mDefaultExt ~ delete _; + protected String[] mFileNames ~ DeleteContainerAndItems!(_); + private bool mSecurityCheckFileNames; + private String mFilter ~ delete _; + private String mFilterBuffer = new String() ~ delete _; + private int32 mFilterIndex; + private bool mSupportMultiDottedExtensions; + private bool mIgnoreSecondFileOkNotification; // Used for VS Whidbey 95342 + private int32 mOKNotificationCount; // Same + //private String char8Buffer = new String(FILEBUFSIZE) ~ delete _; + + public this() + { + Reset(); + } + + public virtual void Reset() + { + DeleteAndNullify!(mTitle); + DeleteAndNullify!(mInitialDir); + DeleteAndNullify!(mDefaultExt); + DeleteContainerAndItems!(mFileNames); + mFileNames = null; + DeleteAndNullify!(mFilter); + mFilterIndex = 1; + mSupportMultiDottedExtensions = false; + mOptions = Windows.OFN_HIDEREADONLY | Windows.OFN_PATHMUSTEXIST | + OPTION_ADDEXTENSION; + } + + + + protected int32 Options + { + get + { + return mOptions & ( + Windows.OFN_READONLY | + Windows.OFN_HIDEREADONLY | + Windows.OFN_NOCHANGEDIR | + Windows.OFN_SHOWHELP | + Windows.OFN_NOVALIDATE | + Windows.OFN_ALLOWMULTISELECT | + Windows.OFN_PATHMUSTEXIST | + Windows.OFN_FILEMUSTEXIST | + Windows.OFN_NODEREFERENCELINKS | + Windows.OFN_OVERWRITEPROMPT); + //return mOptions; + } + } + + public StringView Title + { + set + { + String.NewOrSet!(mTitle, value); + } + + get + { + return mTitle; + } + } + + public StringView InitialDirectory + { + set + { + String.NewOrSet!(mInitialDir, value); + } + + get + { + return mInitialDir; + } + } + + public String[] FileNames + { + get + { + return mFileNames; + } + } + + public StringView FileName + { + set + { + if (mFileNames == null) + { + mFileNames = new String[](new String(value)); + } + } + } + + public bool AddExtension + { + get + { + return GetOption(OPTION_ADDEXTENSION); + } + + set + { + SetOption(OPTION_ADDEXTENSION, value); + } + } + + public virtual bool CheckFileExists + { + get + { + return GetOption(Windows.OFN_FILEMUSTEXIST); + } + + set + { + SetOption(Windows.OFN_FILEMUSTEXIST, value); + } + } + + public bool DereferenceLinks + { + get + { + return !GetOption(Windows.OFN_NODEREFERENCELINKS); + } + set + { + SetOption(Windows.OFN_NODEREFERENCELINKS, !value); + } + } + + public bool CheckPathExists + { + get + { + return GetOption(Windows.OFN_PATHMUSTEXIST); + } + + set + { + SetOption(Windows.OFN_PATHMUSTEXIST, value); + } + } + + public bool Multiselect + { + get + { + return GetOption(Windows.OFN_ALLOWMULTISELECT); + } + + set + { + SetOption(Windows.OFN_ALLOWMULTISELECT, value); + } + } + + public bool ValidateNames + { + get + { + return !GetOption(Windows.OFN_NOVALIDATE); + } + + set + { + SetOption(Windows.OFN_NOVALIDATE, !value); + } + } + + public StringView DefaultExt + { + get + { + return mDefaultExt == null ? "" : mDefaultExt; + } + + set + { + delete mDefaultExt; + mDefaultExt = null; + + //if (!String.IsNullOrEmpty(value)) + if (value.Length > 0) + { + mDefaultExt = new String(value); + if (mDefaultExt.StartsWith(".")) + mDefaultExt.Remove(0, 1); + } + } + } + + public void GetFilter(String outFilter) + { + if (mFilter != null) + outFilter.Append(mFilter); + } + + public Result SetFilter(StringView value) + { + String useValue = scope String(value); + if (useValue != null && useValue.Length > 0) + { + var formats = String.StackSplit!(useValue, '|'); + if (formats == null || formats.Count % 2 != 0) + { + return .Err; + } + /// + /*String[] formats = value.Split('|'); + if (formats == null || formats.Length % 2 != 0) + { + throw new ArgumentException(SR.GetString(SR.FileDialogInvalidFilter)); + }*/ + String.NewOrSet!(mFilter, useValue); + } + else + { + useValue = null; + DeleteAndNullify!(mFilter); + } + + return .Ok; + } + + protected bool GetOption(int32 option) + { + return (mOptions & option) != 0; + } + + protected void SetOption(int32 option, bool value) + { + if (value) + { + mOptions |= option; + } + else + { + mOptions &= ~option; + } + } + + private static Result MakeFilterString(String s, bool dereferenceLinks, String filterBuffer) + { + String useStr = s; + if (useStr == null || useStr.Length == 0) + { + // Workaround for Whidbey bug #5165 + // Apply the workaround only when DereferenceLinks is true and OS is at least WinXP. + if (dereferenceLinks && System.Environment.OSVersion.Version.Major >= 5) + { + useStr = " |*.*"; + } + else if (useStr == null) + { + return .Err; + } + } + + filterBuffer.Set(s); + for (int32 i = 0; i < filterBuffer.Length; i++) + if (filterBuffer[i] == '|') + filterBuffer[i] = (char8)0; + filterBuffer.Append((char8)0); + return .Ok; + } + + private Result RunDialogOld(Windows.HWnd hWndOwner) + { + //RunDialogTest(hWndOwner); + + Windows.WndProc hookProcPtr = => StaticHookProc; + Windows.OpenFileName ofn = Windows.OpenFileName(); + + char16[FILEBUFSIZE] char16Buffer = .(0, ?); + + if (mFileNames != null && !mFileNames.IsEmpty) + { + //int len = UTF16.GetEncodedLen(fileNames[0]); + //char16Buffer = scope:: char16[len + 1]*; + UTF16.Encode(mFileNames[0], (char16*)&char16Buffer, FILEBUFSIZE); + } + // Degrade to the older style dialog if we're not on Win2K. + // We do this by setting the struct size to a different value + // + + if (Environment.OSVersion.Platform != System.PlatformID.Win32NT || + Environment.OSVersion.Version.Major < 5) { + ofn.mStructSize = 0x4C; + } + ofn.mHwndOwner = hWndOwner; + ofn.mHInstance = (Windows.HInstance)Windows.GetModuleHandleW(null); + + if (mFilter != null) + { + Try!(MakeFilterString(mFilter, this.DereferenceLinks, mFilterBuffer)); + ofn.mFilter = mFilterBuffer.ToScopedNativeWChar!::(); + } + ofn.nFilterIndex = mFilterIndex; + ofn.mFile = (char16*)&char16Buffer; + ofn.nMaxFile = FILEBUFSIZE; + if (mInitialDir != null) + ofn.mInitialDir = mInitialDir.ToScopedNativeWChar!::(); + if (mTitle != null) + ofn.mTitle = mTitle.ToScopedNativeWChar!::(); + ofn.mFlags = Options | (Windows.OFN_EXPLORER | Windows.OFN_ENABLEHOOK | Windows.OFN_ENABLESIZING); + ofn.mHook = hookProcPtr; + ofn.mCustData = (int)Internal.UnsafeCastToPtr(this); + ofn.mFlagsEx = Windows.OFN_USESHELLITEM; + if (mDefaultExt != null && AddExtension) + ofn.mDefExt = mDefaultExt.ToScopedNativeWChar!::(); + + DeleteContainerAndItems!(mFileNames); + mFileNames = null; + //Security checks happen here + return RunFileDialog(ref ofn); + } + + static int StaticHookProc(Windows.HWnd hWnd, int32 msg, int wParam, int lparam) + { + if (msg == Windows.WM_INITDIALOG) + { + using (sMonitor.Enter()) + { + var ofn = (Windows.OpenFileName*)(void*)lparam; + sHookMap[(int)hWnd] = (CommonDialog)Internal.UnsafeCastToObject((void*)ofn.mCustData); + } + } + + CommonDialog dlg; + using (sMonitor.Enter()) + { + sHookMap.TryGetValue((int)hWnd, out dlg); + } + if (dlg == null) + return 0; + + dlg.[Friend]HookProc(hWnd, msg, wParam, lparam); + if (msg == Windows.WM_DESTROY) + { + using (sMonitor.Enter()) + { + sHookMap.Remove((int)hWnd); + } + } + return 0; + } + //TODO: Add ProcessFileNames for validation + } +} +#endif \ No newline at end of file diff --git a/BeefLibs/corlib/src/IO/FolderBrowserDialog.bf b/BeefLibs/corlib/src/IO/FolderBrowserDialog.bf index 91844228..420757ac 100644 --- a/BeefLibs/corlib/src/IO/FolderBrowserDialog.bf +++ b/BeefLibs/corlib/src/IO/FolderBrowserDialog.bf @@ -57,7 +57,7 @@ namespace System.IO ShowNewFolderButton = true; } - protected Result RunDialog_New(Windows.HWnd hWndOwner, FolderBrowserDialog.COM_IFileDialog* fileDialog) + protected Result RunDialog_New(Windows.HWnd hWndOwner, Windows.COM_IFileDialog* fileDialog) { //COM_IFileDialogEvents evts; /*COM_IFileDialogEvents.VTable funcs; @@ -106,8 +106,8 @@ namespace System.IO if (!mSelectedPath.IsEmpty) { - COM_IShellItem* folderShellItem = null; - Windows.SHCreateItemFromParsingName(mSelectedPath.ToScopedNativeWChar!(), null, COM_IShellItem.sIID, (void**)&folderShellItem); + Windows.COM_IShellItem* folderShellItem = null; + Windows.SHCreateItemFromParsingName(mSelectedPath.ToScopedNativeWChar!(), null, Windows.COM_IShellItem.sIID, (void**)&folderShellItem); if (folderShellItem != null) { fileDialog.VT.SetDefaultFolder(fileDialog, folderShellItem); @@ -121,7 +121,7 @@ namespace System.IO DialogResult result = .Cancel; mSelectedPath.Clear(); - COM_IShellItem* shellItem = null; + Windows.COM_IShellItem* shellItem = null; fileDialog.VT.GetResult(fileDialog, out shellItem); if (shellItem != null) { @@ -142,10 +142,10 @@ namespace System.IO protected override Result RunDialog(Windows.HWnd hWndOwner) { - FolderBrowserDialog.COM_IFileDialog* fileDialog = null; + Windows.COM_IFileDialog* fileDialog = null; Windows.COM_IUnknown.HResult hr; //if (mFolderKind == .Open) - hr = Windows.COM_IUnknown.CoCreateInstance(ref FolderBrowserDialog.COM_IFileDialog.sCLSID, null, .INPROC_SERVER, ref FolderBrowserDialog.COM_IFileDialog.sIID, (void**)&fileDialog); + hr = Windows.COM_IUnknown.CoCreateInstance(ref Windows.COM_IFileDialog.sCLSID, null, .INPROC_SERVER, ref Windows.COM_IFileDialog.sIID, (void**)&fileDialog); //else //hr = Windows.COM_IUnknown.CoCreateInstance(ref FolderBrowserDialog.COM_FileSaveDialog.sCLSID, null, .INPROC_SERVER, ref FolderBrowserDialog.COM_FileSaveDialog.sIID, (void**)&fileDialog); if (hr == 0) @@ -219,143 +219,6 @@ namespace System.IO } return 0; } - - struct FDE_SHAREVIOLATION_RESPONSE; - struct FDE_OVERWRITE_RESPONSE; - - struct COM_IFileDialogEvents : Windows.COM_IUnknown - { - public struct VTable : Windows.COM_IUnknown.VTable - { - public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog) OnFileOk; - public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog, COM_IShellItem* psiFolder) OnFolderChanging; - public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog) OnFolderChange; - public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog) OnSelectionChange; - public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog, FDE_SHAREVIOLATION_RESPONSE* pResponse) OnShareViolation; - public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog) OnTypeChange; - public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog, COM_IShellItem* shellItem, FDE_OVERWRITE_RESPONSE* response) OnOverwrite; - - } - } - - struct COM_IShellItem : Windows.COM_IUnknown - { - public static Guid sIID = .(0x43826d1e, 0xe718, 0x42ee, 0xbc, 0x55, 0xa1, 0xe2, 0x61, 0xc3, 0x7b, 0xfe); - - public enum SIGDN : uint32 - { - NORMALDISPLAY = 0x00000000, // SHGDN_NORMAL - PARENTRELATIVEPARSING = 0x80018001, // SHGDN_INFOLDER | SHGDN_FORPARSING - DESKTOPABSOLUTEPARSING = 0x80028000, // SHGDN_FORPARSING - PARENTRELATIVEEDITING = 0x80031001, // SHGDN_INFOLDER | SHGDN_FOREDITING - DESKTOPABSOLUTEEDITING = 0x8004c000, // SHGDN_FORPARSING | SHGDN_FORADDRESSBAR - FILESYSPATH = 0x80058000, // SHGDN_FORPARSING - URL = 0x80068000, // SHGDN_FORPARSING - PARENTRELATIVEFORADDRESSBAR = 0x8007c001, // SHGDN_INFOLDER | SHGDN_FORPARSING | SHGDN_FORADDRESSBAR - PARENTRELATIVE = 0x80080001 // SHGDN_INFOLDER - } - - public struct VTable : Windows.COM_IUnknown.VTable - { - public function HResult(COM_IShellItem* self, void* pbc, ref Guid bhid, ref Guid riid, void** ppv) BindToHandler; - public function HResult(COM_IShellItem* self, out COM_IShellItem* ppsi) GetParent; - public function HResult(COM_IShellItem* self, SIGDN sigdnName, out char16* ppszName) GetDisplayName; - public function HResult(COM_IShellItem* self, uint sfgaoMask, out uint psfgaoAttribs) GetAttributes; - public function HResult(COM_IShellItem* self, COM_IShellItem* psi, uint32 hint, out int32 piOrder) Compare; - - } - public new VTable* VT - { - get - { - return (.)mVT; - } - } - } - - struct COMDLG_FILTERSPEC - { - public char16* pszName; - public char16* pszSpec; - } - - enum FDAP : uint32 - { - FDAP_BOTTOM = 0x00000000, - FDAP_TOP = 0x00000001, - } - - public struct COM_IFileDialog : Windows.COM_IUnknown - { - public static Guid sIID = .(0x42f85136, 0xdb7e, 0x439c, 0x85, 0xf1, 0xe4, 0x07, 0x5d, 0x13, 0x5f, 0xc8); - public static Guid sCLSID = .(0xdc1c5a9c, 0xe88a, 0x4dde, 0xa5, 0xa1, 0x60, 0xf8, 0x2a, 0x20, 0xae, 0xf7); - - ///s - public enum FOS : uint32 - { - OVERWRITEPROMPT = 0x00000002, - STRICTFILETYPES = 0x00000004, - NOCHANGEDIR = 0x00000008, - PICKFOLDERS = 0x00000020, - FORCEFILESYSTEM = 0x00000040, - ALLNONSTORAGEITEMS = 0x00000080, - NOVALIDATE = 0x00000100, - ALLOWMULTISELECT = 0x00000200, - PATHMUSTEXIST = 0x00000800, - FILEMUSTEXIST = 0x00001000, - CREATEPROMPT = 0x00002000, - SHAREAWARE = 0x00004000, - NOREADONLYRETURN = 0x00008000, - NOTESTFILECREATE = 0x00010000, - HIDEMRUPLACES = 0x00020000, - HIDEPINNEDPLACES = 0x00040000, - NODEREFERENCELINKS = 0x00100000, - DONTADDTORECENT = 0x02000000, - FORCESHOWHIDDEN = 0x10000000, - DEFAULTNOMINIMODE = 0x20000000 - } - - public struct VTable : Windows.COM_IUnknown.VTable - { - public function HResult(COM_IFileDialog* self, Windows.HWnd parent) Show; - public function HResult(COM_IFileDialog* self, uint cFileTypes, COMDLG_FILTERSPEC* rgFilterSpec) SetFileTypes; - public function HResult(COM_IFileDialog* self, uint iFileType) SetFileTypeIndex; - public function HResult(COM_IFileDialog* self, out uint piFileType) GetFileTypeIndex; - public function HResult(COM_IFileDialog* self, COM_IFileDialogEvents* pfde, out uint pdwCookie) Advise; - public function HResult(COM_IFileDialog* self, uint dwCookie) Unadvise; - public function HResult(COM_IFileDialog* self, FOS fos) SetOptions; - public function HResult(COM_IFileDialog* self, out FOS pfos) GetOptions; - public function HResult(COM_IFileDialog* self, COM_IShellItem* psi) SetDefaultFolder; - public function HResult(COM_IFileDialog* self, COM_IShellItem* psi) SetFolder; - public function HResult(COM_IFileDialog* self, out COM_IShellItem* ppsi) GetFolder; - public function HResult(COM_IFileDialog* self, out COM_IShellItem* ppsi) GetCurrentSelection; - public function HResult(COM_IFileDialog* self, char16* pszName) SetFileName; - public function HResult(COM_IFileDialog* self, out char16* pszName) GetFileName; - public function HResult(COM_IFileDialog* self, char16* pszTitle) SetTitle; - public function HResult(COM_IFileDialog* self, char16* pszText) SetOkButtonLabel; - public function HResult(COM_IFileDialog* self, char16* pszLabel) SetFileNameLabel; - public function HResult(COM_IFileDialog* self, out COM_IShellItem* ppsi) GetResult; - public function HResult(COM_IFileDialog* self, COM_IShellItem* psi, FDAP fdap) AddPlace; - public function HResult(COM_IFileDialog* self, char16* pszDefaultExtension) SetDefaultExtension; - public function HResult(COM_IFileDialog* self, int hr) Close; - public function HResult(COM_IFileDialog* self, ref Guid guid) SetClientGuid; - public function HResult(COM_IFileDialog* self) ClearClientData; - public function HResult(COM_IFileDialog* self, void* pFilter) SetFilter; - } - public new VTable* VT - { - get - { - return (.)mVT; - } - } - } - - public struct COM_FileSaveDialog : COM_IFileDialog - { - public static new Guid sIID = .(0x84bccd23, 0x5fde, 0x4cdb, 0xae, 0xa4, 0xaf, 0x64, 0xb8, 0x3d, 0x78, 0xab); - public static new Guid sCLSID = .(0xC0B4E2F3, 0xBA21, 0x4773, 0x8D, 0xBA, 0x33, 0x5E, 0xC9, 0x46, 0xEB, 0x8B); - } } } #endif \ No newline at end of file diff --git a/BeefLibs/corlib/src/IO/OpenFileDialog.bf b/BeefLibs/corlib/src/IO/OpenFileDialog.bf index 3697c1c5..6523c097 100644 --- a/BeefLibs/corlib/src/IO/OpenFileDialog.bf +++ b/BeefLibs/corlib/src/IO/OpenFileDialog.bf @@ -11,460 +11,6 @@ using System.Text; namespace System.IO { - enum DialogResult - { - None = 0, - OK = 1, - Cancel = 2 - } - - abstract class CommonDialog - { - public Windows.HWnd mHWnd; - public Windows.HWnd mDefaultControlHwnd; - public int mDefWndProc; - - private const int32 CDM_SETDEFAULTFOCUS = Windows.WM_USER + 0x51; - - public static Dictionary sHookMap = new Dictionary() ~ - { - Debug.Assert(sHookMap.Count == 0); - delete _; - }; - public static Monitor sMonitor = new Monitor() ~ delete _; - - public Result ShowDialog(INativeWindow owner = null) - { - Windows.HWnd hwndOwner = 0; - if (owner != null) - hwndOwner = (.)owner.Handle; - //Native.WndProc wndProc = scope => OwnerWndProc; - - //mDefWndProc = Native.SetWindowLong(mHWnd, Native.GWL_WNDPROC, (intptr)wndProc.GetFuncPtr().Value); - - var result = RunDialog(hwndOwner); - return result; - } - - public virtual int OwnerWndProc(Windows.HWnd hWnd, int32 msg, int wParam, int lParam) - { - return Windows.CallWindowProcW(mDefWndProc, hWnd, msg, wParam, lParam); - } - - protected virtual int HookProc(Windows.HWnd hWnd, int32 msg, int wParam, int lparam) - { - if (msg == Windows.WM_INITDIALOG) - { - //TODO: MoveToScreenCenter(hWnd); - // Under some circumstances, the dialog - // does not initially focus on any control. We fix that by explicitly - // setting focus ourselves. See ASURT 39435. - // - mDefaultControlHwnd = (Windows.HWnd)wParam; - if (mDefaultControlHwnd != 0) - Windows.SetFocus(mDefaultControlHwnd); - } - else if (msg == Windows.WM_SETFOCUS) - { - Windows.PostMessageW(hWnd, CDM_SETDEFAULTFOCUS, 0, 0); - } - else if (msg == CDM_SETDEFAULTFOCUS) - { - // If the dialog box gets focus, bounce it to the default control. - // so we post a message back to ourselves to wait for the focus change then push it to the default - // control. See ASURT 84016. - // - if (mDefaultControlHwnd != 0) - Windows.SetFocus(mDefaultControlHwnd); - } - return 0; - } - - protected abstract Result RunDialog(Windows.HWnd hWndOwner); - } - - abstract class FileDialog : CommonDialog - { - protected abstract Result RunFileDialog(ref Windows.OpenFileName ofn); - - protected override Result RunDialog(Windows.HWnd hWndOwner) - { - return RunDialogOld(hWndOwner); - } - - private const int32 FILEBUFSIZE = 8192; - protected const int32 OPTION_ADDEXTENSION = (int32)0x80000000; - - protected int32 mOptions; - private String mTitle ~ delete _; - private String mInitialDir ~ delete _; - private String mDefaultExt ~ delete _; - protected String[] mFileNames ~ DeleteContainerAndItems!(_); - private bool mSecurityCheckFileNames; - private String mFilter ~ delete _; - private String mFilterBuffer = new String() ~ delete _; - private int32 mFilterIndex; - private bool mSupportMultiDottedExtensions; - private bool mIgnoreSecondFileOkNotification; // Used for VS Whidbey 95342 - private int32 mOKNotificationCount; // Same - //private String char8Buffer = new String(FILEBUFSIZE) ~ delete _; - - public this() - { - Reset(); - } - - public virtual void Reset() - { - DeleteAndNullify!(mTitle); - DeleteAndNullify!(mInitialDir); - DeleteAndNullify!(mDefaultExt); - DeleteContainerAndItems!(mFileNames); - mFileNames = null; - DeleteAndNullify!(mFilter); - mFilterIndex = 1; - mSupportMultiDottedExtensions = false; - mOptions = Windows.OFN_HIDEREADONLY | Windows.OFN_PATHMUSTEXIST | - OPTION_ADDEXTENSION; - } - - protected int32 Options - { - get - { - return mOptions & ( - Windows.OFN_READONLY | - Windows.OFN_HIDEREADONLY | - Windows.OFN_NOCHANGEDIR | - Windows.OFN_SHOWHELP | - Windows.OFN_NOVALIDATE | - Windows.OFN_ALLOWMULTISELECT | - Windows.OFN_PATHMUSTEXIST | - Windows.OFN_FILEMUSTEXIST | - Windows.OFN_NODEREFERENCELINKS | - Windows.OFN_OVERWRITEPROMPT); - //return mOptions; - } - } - - public StringView Title - { - set - { - String.NewOrSet!(mTitle, value); - } - - get - { - return mTitle; - } - } - - public StringView InitialDirectory - { - set - { - String.NewOrSet!(mInitialDir, value); - } - - get - { - return mInitialDir; - } - } - - public String[] FileNames - { - get - { - return mFileNames; - } - } - - public StringView FileName - { - set - { - if (mFileNames == null) - { - mFileNames = new String[](new String(value)); - } - } - } - - public bool AddExtension - { - get - { - return GetOption(OPTION_ADDEXTENSION); - } - - set - { - SetOption(OPTION_ADDEXTENSION, value); - } - } - - public virtual bool CheckFileExists - { - get - { - return GetOption(Windows.OFN_FILEMUSTEXIST); - } - - set - { - SetOption(Windows.OFN_FILEMUSTEXIST, value); - } - } - - public bool DereferenceLinks - { - get - { - return !GetOption(Windows.OFN_NODEREFERENCELINKS); - } - set - { - SetOption(Windows.OFN_NODEREFERENCELINKS, !value); - } - } - - public bool CheckPathExists - { - get - { - return GetOption(Windows.OFN_PATHMUSTEXIST); - } - - set - { - SetOption(Windows.OFN_PATHMUSTEXIST, value); - } - } - - public bool Multiselect - { - get - { - return GetOption(Windows.OFN_ALLOWMULTISELECT); - } - - set - { - SetOption(Windows.OFN_ALLOWMULTISELECT, value); - } - } - - public bool ValidateNames - { - get - { - return !GetOption(Windows.OFN_NOVALIDATE); - } - - set - { - SetOption(Windows.OFN_NOVALIDATE, !value); - } - } - - public StringView DefaultExt - { - get - { - return mDefaultExt == null ? "" : mDefaultExt; - } - - set - { - delete mDefaultExt; - mDefaultExt = null; - - //if (!String.IsNullOrEmpty(value)) - if (value.Length > 0) - { - mDefaultExt = new String(value); - if (mDefaultExt.StartsWith(".")) - mDefaultExt.Remove(0, 1); - } - } - } - - public void GetFilter(String outFilter) - { - if (mFilter != null) - outFilter.Append(mFilter); - } - - public Result SetFilter(StringView value) - { - String useValue = scope String(value); - if (useValue != null && useValue.Length > 0) - { - var formats = String.StackSplit!(useValue, '|'); - if (formats == null || formats.Count % 2 != 0) - { - return .Err; - } - /// - /*String[] formats = value.Split('|'); - if (formats == null || formats.Length % 2 != 0) - { - throw new ArgumentException(SR.GetString(SR.FileDialogInvalidFilter)); - }*/ - String.NewOrSet!(mFilter, useValue); - } - else - { - useValue = null; - DeleteAndNullify!(mFilter); - } - - return .Ok; - } - - protected bool GetOption(int32 option) - { - return (mOptions & option) != 0; - } - - protected void SetOption(int32 option, bool value) - { - if (value) - { - mOptions |= option; - } - else - { - mOptions &= ~option; - } - } - - private static Result MakeFilterString(String s, bool dereferenceLinks, String filterBuffer) - { - String useStr = s; - if (useStr == null || useStr.Length == 0) - { - // Workaround for Whidbey bug #5165 - // Apply the workaround only when DereferenceLinks is true and OS is at least WinXP. - if (dereferenceLinks && System.Environment.OSVersion.Version.Major >= 5) - { - useStr = " |*.*"; - } - else if (useStr == null) - { - return .Err; - } - } - - filterBuffer.Set(s); - for (int32 i = 0; i < filterBuffer.Length; i++) - if (filterBuffer[i] == '|') - filterBuffer[i] = (char8)0; - filterBuffer.Append((char8)0); - return .Ok; - } - - public static mixin Testie() - { - int a = 123; - char16* buf; - if (a == 0) - { - buf = null; - } - else - { - buf = new char16[123]* ( ? ); - defer:mixin delete buf; - } - buf - } - - private Result RunDialogOld(Windows.HWnd hWndOwner) - { - //RunDialogTest(hWndOwner); - - Windows.WndProc hookProcPtr = => StaticHookProc; - Windows.OpenFileName ofn = Windows.OpenFileName(); - - char16[FILEBUFSIZE] char16Buffer = .(0, ?); - - if (mFileNames != null) - { - //int len = UTF16.GetEncodedLen(fileNames[0]); - //char16Buffer = scope:: char16[len + 1]*; - UTF16.Encode(mFileNames[0], (char16*)&char16Buffer, FILEBUFSIZE); - } - // Degrade to the older style dialog if we're not on Win2K. - // We do this by setting the struct size to a different value - // - - if (Environment.OSVersion.Platform != System.PlatformID.Win32NT || - Environment.OSVersion.Version.Major < 5) { - ofn.mStructSize = 0x4C; - } - ofn.mHwndOwner = hWndOwner; - ofn.mHInstance = (Windows.HInstance)Windows.GetModuleHandleW(null); - - if (mFilter != null) - { - Try!(MakeFilterString(mFilter, this.DereferenceLinks, mFilterBuffer)); - ofn.mFilter = mFilterBuffer.ToScopedNativeWChar!::(); - } - ofn.nFilterIndex = mFilterIndex; - ofn.mFile = (char16*)&char16Buffer; - ofn.nMaxFile = FILEBUFSIZE; - if (mInitialDir != null) - ofn.mInitialDir = mInitialDir.ToScopedNativeWChar!::(); - if (mTitle != null) - ofn.mTitle = mTitle.ToScopedNativeWChar!::(); - ofn.mFlags = Options | (Windows.OFN_EXPLORER | Windows.OFN_ENABLEHOOK | Windows.OFN_ENABLESIZING); - ofn.mHook = hookProcPtr; - ofn.mCustData = (int)Internal.UnsafeCastToPtr(this); - ofn.mFlagsEx = Windows.OFN_USESHELLITEM; - if (mDefaultExt != null && AddExtension) - ofn.mDefExt = mDefaultExt.ToScopedNativeWChar!::(); - - DeleteContainerAndItems!(mFileNames); - mFileNames = null; - //Security checks happen here - return RunFileDialog(ref ofn); - } - - static int StaticHookProc(Windows.HWnd hWnd, int32 msg, int wParam, int lparam) - { - if (msg == Windows.WM_INITDIALOG) - { - using (sMonitor.Enter()) - { - var ofn = (Windows.OpenFileName*)(void*)lparam; - sHookMap[(int)hWnd] = (CommonDialog)Internal.UnsafeCastToObject((void*)ofn.mCustData); - } - } - - CommonDialog dlg; - using (sMonitor.Enter()) - { - sHookMap.TryGetValue((int)hWnd, out dlg); - } - if (dlg == null) - return 0; - - dlg.[Friend]HookProc(hWnd, msg, wParam, lparam); - if (msg == Windows.WM_DESTROY) - { - using (sMonitor.Enter()) - { - sHookMap.Remove((int)hWnd); - } - } - return 0; - } - //TODO: Add ProcessFileNames for validation - } - class OpenFileDialog : FileDialog { public override void Reset() @@ -557,6 +103,70 @@ namespace System.IO return DialogResult.OK; } + + protected override void ProcessVistaFiles(Windows.COM_IFileDialog* dialog, List files) + { + mixin GetFilePathFromShellItem(Windows.COM_IShellItem* shellItem) + { + String str = null; + if (shellItem.VT.GetDisplayName(shellItem, .FILESYSPATH, let cStr) == .OK) + { + str = new String()..Append(cStr); + Windows.COM_IUnknown.CoTaskMemFree(cStr); + } + str + } + + Windows.COM_IFileOpenDialog* openDialog = (.)dialog; + if (Multiselect) + { + openDialog.VT.GetResults(openDialog, let results); + + if (results != null) + { + results.VT.GetCount(results, let count); + for (uint32 i < count) + { + results.VT.GetItemAt(results, i, let item); + if (item != null) + { + let filePath = GetFilePathFromShellItem!(item); + if (filePath != null) + files.Add(filePath); + } + } + results.VT.Release(results); + } + } + else + { + openDialog.VT.GetResult(openDialog, let shellItem); + + if (shellItem != null) + { + let filePath = GetFilePathFromShellItem!(shellItem); + if (filePath != null) + files.Add(filePath); + shellItem.VT.Release(shellItem); + } + } + } + + protected override Result CreateVistaDialog() + { + Windows.COM_IFileDialog* fileDialog = null; + + Windows.COM_IUnknown.HResult hr = (Windows.COM_IUnknown.CoCreateInstance( + ref Windows.COM_IFileDialog.sCLSID, + null, + .INPROC_SERVER | .LOCAL_SERVER | .REMOTE_SERVER, + ref Windows.COM_IFileOpenDialog.sIID, + (void**)&fileDialog)); + if (hr.Failed) + return .Err; + + return fileDialog; + } } } diff --git a/BeefLibs/corlib/src/IO/SaveFileDialog.bf b/BeefLibs/corlib/src/IO/SaveFileDialog.bf index 89585e2d..19064fbc 100644 --- a/BeefLibs/corlib/src/IO/SaveFileDialog.bf +++ b/BeefLibs/corlib/src/IO/SaveFileDialog.bf @@ -94,6 +94,47 @@ namespace System.IO return DialogResult.OK; } + + protected override void ProcessVistaFiles(Windows.COM_IFileDialog* dialog, System.Collections.List files) + { + mixin GetFilePathFromShellItem(Windows.COM_IShellItem* shellItem) + { + String str = null; + if (shellItem.VT.GetDisplayName(shellItem, .FILESYSPATH, let cStr) == .OK) + { + str = new String()..Append(cStr); + Windows.COM_IUnknown.CoTaskMemFree(cStr); + } + str + } + + Windows.COM_IFileSaveDialog* saveDialog = (.)dialog; + saveDialog.VT.GetResult(saveDialog, let shellItem); + + if (shellItem != null) + { + let filePath = GetFilePathFromShellItem!(shellItem); + if (filePath != null) + files.Add(filePath); + shellItem.VT.Release(shellItem); + } + } + + protected override Result CreateVistaDialog() + { + Windows.COM_IFileDialog* fileDialog = null; + + Windows.COM_IUnknown.HResult hr = (Windows.COM_IUnknown.CoCreateInstance( + ref Windows.COM_IFileSaveDialog.sCLSID, + null, + .INPROC_SERVER | .LOCAL_SERVER | .REMOTE_SERVER, + ref Windows.COM_IFileSaveDialog.sIID, + (void**)&fileDialog)); + if (hr.Failed) + return .Err; + + return fileDialog; + } } } diff --git a/BeefLibs/corlib/src/Windows.bf b/BeefLibs/corlib/src/Windows.bf index e1d1848c..78be9cb8 100644 --- a/BeefLibs/corlib/src/Windows.bf +++ b/BeefLibs/corlib/src/Windows.bf @@ -1117,6 +1117,215 @@ namespace System TRUSTEE_W Trustee; } + struct COM_IFileDialogEvents : Windows.COM_IUnknown + { + struct FDE_SHAREVIOLATION_RESPONSE; + struct FDE_OVERWRITE_RESPONSE; + + public struct VTable : Windows.COM_IUnknown.VTable + { + public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog) OnFileOk; + public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog, COM_IShellItem* psiFolder) OnFolderChanging; + public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog) OnFolderChange; + public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog) OnSelectionChange; + public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog, FDE_SHAREVIOLATION_RESPONSE* pResponse) OnShareViolation; + public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog) OnTypeChange; + public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog, COM_IShellItem* shellItem, FDE_OVERWRITE_RESPONSE* response) OnOverwrite; + + } + } + + public struct COM_IShellItem : Windows.COM_IUnknown + { + public static Guid sIID = .(0x43826d1e, 0xe718, 0x42ee, 0xbc, 0x55, 0xa1, 0xe2, 0x61, 0xc3, 0x7b, 0xfe); + + public enum SIGDN : uint32 + { + NORMALDISPLAY = 0x00000000, // SHGDN_NORMAL + PARENTRELATIVEPARSING = 0x80018001, // SHGDN_INFOLDER | SHGDN_FORPARSING + DESKTOPABSOLUTEPARSING = 0x80028000, // SHGDN_FORPARSING + PARENTRELATIVEEDITING = 0x80031001, // SHGDN_INFOLDER | SHGDN_FOREDITING + DESKTOPABSOLUTEEDITING = 0x8004c000, // SHGDN_FORPARSING | SHGDN_FORADDRESSBAR + FILESYSPATH = 0x80058000, // SHGDN_FORPARSING + URL = 0x80068000, // SHGDN_FORPARSING + PARENTRELATIVEFORADDRESSBAR = 0x8007c001, // SHGDN_INFOLDER | SHGDN_FORPARSING | SHGDN_FORADDRESSBAR + PARENTRELATIVE = 0x80080001 // SHGDN_INFOLDER + } + + public struct VTable : Windows.COM_IUnknown.VTable + { + public function HResult(COM_IShellItem* self, void* pbc, ref Guid bhid, ref Guid riid, void** ppv) BindToHandler; + public function HResult(COM_IShellItem* self, out COM_IShellItem* ppsi) GetParent; + public function HResult(COM_IShellItem* self, SIGDN sigdnName, out char16* ppszName) GetDisplayName; + public function HResult(COM_IShellItem* self, uint sfgaoMask, out uint psfgaoAttribs) GetAttributes; + public function HResult(COM_IShellItem* self, COM_IShellItem* psi, uint32 hint, out int32 piOrder) Compare; + + } + public new VTable* VT + { + get + { + return (.)mVT; + } + } + } + + public struct COM_IShellItemArray : Windows.COM_IUnknown + { + public enum GETPROPERTYSTOREFLAGS : uint + { + DEFAULT = 0x00000000, + HANDLERPROPERTIESONLY = 0x00000001, + READWRITE = 0x00000002, + TEMPORARY = 0x00000004, + FASTPROPERTIESONLY = 0x00000008, + OPENSLOWITEM = 0x00000010, + DELAYCREATION = 0x00000020, + BESTEFFORT = 0x00000040, + NO_OPLOCK = 0x00000080, + PREFERQUERYPROPERTIES = 0x00000100, + EXTRINSICPROPERTIES = 0x00000200, + EXTRINSICPROPERTIESONLY = 0x00000400, + VOLATILEPROPERTIES = 0x00000800, + VOLATILEPROPERTIESONLY = 0x00001000, + MASK_VALID = 0x00001FFF + } + + [AllowDuplicates] + public enum SIATTRIBFLAGS : uint + { + AND = 0x1, + OR = 0x2, + APPCOMPAT = 0x3, + MASK = 0x3, + ALLITEMS = 0x4000 + } + + public struct PROPERTYKEY; + + public static Guid sIID = .(0xB63EA76D, 0x1F85, 0x456F, 0xA1, 0x9C, 0x48, 0x15, 0x9E, 0xFA, 0x85, 0x8B); + + public struct VTable : Windows.COM_IUnknown.VTable + { + public function HResult(COM_IShellItemArray* self, void* pbc, ref Guid rbhid, ref Guid riid, out void* ppvOut) BindToHandler; + public function HResult(COM_IShellItemArray* self, GETPROPERTYSTOREFLAGS flags, ref Guid riid, out void* ppv) GetPropertyStore; + public function HResult(COM_IShellItemArray* self, ref PROPERTYKEY keyType, ref Guid riid, out void* ppv) GetPropertyDescriptionList; + public function HResult(COM_IShellItemArray* self, SIATTRIBFLAGS dwAttribFlags, uint32 sfgaoMask, out uint32 psfgaoAttribs) GetAttributes; + public function HResult(COM_IShellItemArray* self, out uint32 pdwNumItems) GetCount; + public function HResult(COM_IShellItemArray* self, uint32 dwIndex, out COM_IShellItem* ppsi) GetItemAt; + public function HResult(COM_IShellItemArray* self, out void* ppenumShellItems) EnumItems; + } + public new VTable* VT + { + get + { + return (.)mVT; + } + } + } + + public struct COMDLG_FILTERSPEC + { + public char16* pszName; + public char16* pszSpec; + } + + enum FDAP : uint32 + { + FDAP_BOTTOM = 0x00000000, + FDAP_TOP = 0x00000001, + } + + public struct COM_IFileDialog : Windows.COM_IUnknown + { + public static Guid sIID = .(0x42f85136, 0xdb7e, 0x439c, 0x85, 0xf1, 0xe4, 0x07, 0x5d, 0x13, 0x5f, 0xc8); + public static Guid sCLSID = .(0xdc1c5a9c, 0xe88a, 0x4dde, 0xa5, 0xa1, 0x60, 0xf8, 0x2a, 0x20, 0xae, 0xf7); + + ///s + public enum FOS : uint32 + { + OVERWRITEPROMPT = 0x00000002, + STRICTFILETYPES = 0x00000004, + NOCHANGEDIR = 0x00000008, + PICKFOLDERS = 0x00000020, + FORCEFILESYSTEM = 0x00000040, + ALLNONSTORAGEITEMS = 0x00000080, + NOVALIDATE = 0x00000100, + ALLOWMULTISELECT = 0x00000200, + PATHMUSTEXIST = 0x00000800, + FILEMUSTEXIST = 0x00001000, + CREATEPROMPT = 0x00002000, + SHAREAWARE = 0x00004000, + NOREADONLYRETURN = 0x00008000, + NOTESTFILECREATE = 0x00010000, + HIDEMRUPLACES = 0x00020000, + HIDEPINNEDPLACES = 0x00040000, + NODEREFERENCELINKS = 0x00100000, + DONTADDTORECENT = 0x02000000, + FORCESHOWHIDDEN = 0x10000000, + DEFAULTNOMINIMODE = 0x20000000 + } + + public struct VTable : Windows.COM_IUnknown.VTable + { + public function HResult(COM_IFileDialog* self, Windows.HWnd parent) Show; + public function HResult(COM_IFileDialog* self, uint cFileTypes, COMDLG_FILTERSPEC* rgFilterSpec) SetFileTypes; + public function HResult(COM_IFileDialog* self, uint iFileType) SetFileTypeIndex; + public function HResult(COM_IFileDialog* self, out uint piFileType) GetFileTypeIndex; + public function HResult(COM_IFileDialog* self, COM_IFileDialogEvents* pfde, out uint pdwCookie) Advise; + public function HResult(COM_IFileDialog* self, uint dwCookie) Unadvise; + public function HResult(COM_IFileDialog* self, FOS fos) SetOptions; + public function HResult(COM_IFileDialog* self, out FOS pfos) GetOptions; + public function HResult(COM_IFileDialog* self, COM_IShellItem* psi) SetDefaultFolder; + public function HResult(COM_IFileDialog* self, COM_IShellItem* psi) SetFolder; + public function HResult(COM_IFileDialog* self, out COM_IShellItem* ppsi) GetFolder; + public function HResult(COM_IFileDialog* self, out COM_IShellItem* ppsi) GetCurrentSelection; + public function HResult(COM_IFileDialog* self, char16* pszName) SetFileName; + public function HResult(COM_IFileDialog* self, out char16* pszName) GetFileName; + public function HResult(COM_IFileDialog* self, char16* pszTitle) SetTitle; + public function HResult(COM_IFileDialog* self, char16* pszText) SetOkButtonLabel; + public function HResult(COM_IFileDialog* self, char16* pszLabel) SetFileNameLabel; + public function HResult(COM_IFileDialog* self, out COM_IShellItem* ppsi) GetResult; + public function HResult(COM_IFileDialog* self, COM_IShellItem* psi, FDAP fdap) AddPlace; + public function HResult(COM_IFileDialog* self, char16* pszDefaultExtension) SetDefaultExtension; + public function HResult(COM_IFileDialog* self, int hr) Close; + public function HResult(COM_IFileDialog* self, ref Guid guid) SetClientGuid; + public function HResult(COM_IFileDialog* self) ClearClientData; + public function HResult(COM_IFileDialog* self, void* pFilter) SetFilter; + } + public new VTable* VT + { + get + { + return (.)mVT; + } + } + } + + public struct COM_IFileSaveDialog : COM_IFileDialog + { + public static new Guid sIID = .(0x84BCCD23, 0x5FDE, 0x4CDB, 0xAE, 0xA4, 0xAF, 0x64, 0xB8, 0x3D, 0x78, 0xAB); + public static new Guid sCLSID = .(0xC0B4E2F3, 0xBA21, 0x4773, 0x8D, 0xBA, 0x33, 0x5E, 0xC9, 0x46, 0xEB, 0x8B); + } + + public struct COM_IFileOpenDialog : COM_IFileDialog + { + public static new Guid sIID = .(0xD57C7288, 0xD4AD, 0x4768, 0xBE, 0x02, 0x9D, 0x96, 0x95, 0x32, 0xD9, 0x60); + + public struct VTable : COM_IFileDialog.VTable + { + public function HResult(COM_IFileOpenDialog* self, out COM_IShellItemArray* ppenum) GetResults; + public function HResult(COM_IFileOpenDialog* self, out COM_IShellItemArray* ppsai) GetSelectedItems; + } + public new VTable* VT + { + get + { + return (.)mVT; + } + } + } + [Import("version.lib"), CLink, CallingConvention(.Stdcall)] public static extern IntBool GetFileVersionInfoW(char16* lptstrFilename, uint32 dwHandle, uint32 dwLen, void* lpData);