1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-21 01:18:02 +02:00

Merge branch 'master' of https://github.com/beefytech/Beef into FuzzyAutoComplete

This commit is contained in:
Simon Lübeß 2021-12-17 18:05:39 +01:00
parent c2c7431620
commit b70745ef1e
48 changed files with 2975 additions and 918 deletions

View file

@ -578,6 +578,43 @@ namespace System.Collections
return oldPtr;
}
private bool RemoveEntry(int32 hashCode, int_cosize index)
{
if (mBuckets != null)
{
int bucket = hashCode % (int_cosize)mAllocSize;
int lastIndex = -1;
for (int_cosize i = mBuckets[bucket]; i >= 0; lastIndex = i, i = mEntries[i].mNext)
{
if (i == index)
{
if (lastIndex < 0)
{
mBuckets[bucket] = mEntries[index].mNext;
}
else
{
mEntries[lastIndex].mNext = mEntries[index].mNext;
}
mEntries[index].mHashCode = -1;
mEntries[index].mNext = mFreeList;
#if BF_ENABLE_REALTIME_LEAK_CHECK
mEntries[index].mKey = default;
mEntries[index].mValue = default;
#endif
mFreeList = index;
mFreeCount++;
#if VERSION_DICTIONARY
mVersion++;
#endif
return true;
}
}
}
return false;
}
public bool Remove(TKey key)
{
if (mBuckets != null)
@ -901,7 +938,7 @@ namespace System.Collections
public void Remove() mut
{
int_cosize curIdx = mIndex - 1;
mDictionary.Remove(mDictionary.mEntries[curIdx].mKey);
mDictionary.RemoveEntry(mDictionary.mEntries[curIdx].mHashCode, curIdx);
#if VERSION_DICTIONARY
mVersion = mDictionary.mVersion;
#endif
@ -1052,7 +1089,7 @@ namespace System.Collections
public void Remove() mut
{
int_cosize curIdx = mIndex - 1;
mDictionary.Remove(mDictionary.mEntries[curIdx].mKey);
mDictionary.RemoveEntry(mDictionary.mEntries[curIdx].mHashCode, curIdx);
#if VERSION_DICTIONARY
mVersion = mDictionary.mVersion;
#endif
@ -1158,7 +1195,7 @@ namespace System.Collections
public void Remove() mut
{
int_cosize curIdx = mIndex - 1;
mDictionary.Remove(mDictionary.mEntries[curIdx].mKey);
mDictionary.RemoveEntry(mDictionary.mEntries[curIdx].mHashCode, curIdx);
#if VERSION_DICTIONARY
mVersion = mDictionary.mVersion;
#endif

View file

@ -1,8 +1,189 @@
using System.Reflection;
using System.Diagnostics;
using System.Collections;
using System.Security.Cryptography;
namespace System
{
static class Compiler
{
public abstract class Generator
{
public enum Flags
{
None = 0,
AllowRegenerate = 1
}
public String mCmdInfo = new String() ~ delete _;
public Dictionary<StringView, StringView> mParams = new .() ~ delete _;
public abstract String Name { get; }
public StringView ProjectName => mParams["ProjectName"];
public StringView ProjectDir => mParams["ProjectDir"];
public StringView FolderDir => mParams["FolderDir"];
public StringView Namespace => mParams["Namespace"];
public StringView DefaultNamespace => mParams["DefaultNamespace"];
public StringView WorkspaceName => mParams["WorkspaceName"];
public StringView WorkspaceDir => mParams["WorkspaceDir"];
public StringView DateTime => mParams["DateTime"];
public bool IsRegenerating => mParams.GetValueOrDefault("Regenerating") == "True";
public void Fail(StringView error)
{
mCmdInfo.AppendF("error\t");
error.QuoteString(mCmdInfo);
mCmdInfo.Append("\n");
}
public void AddEdit(StringView dataName, StringView label, StringView defaultValue)
{
mCmdInfo.AppendF($"addEdit\t");
dataName.QuoteString(mCmdInfo);
mCmdInfo.Append("\t");
label.QuoteString(mCmdInfo);
mCmdInfo.Append("\t");
defaultValue.QuoteString(mCmdInfo);
mCmdInfo.Append("\n");
}
public void AddCombo(StringView dataName, StringView label, StringView defaultValue, Span<StringView> values)
{
mCmdInfo.AppendF($"addCombo\t");
dataName.QuoteString(mCmdInfo);
mCmdInfo.Append("\t");
label.QuoteString(mCmdInfo);
mCmdInfo.Append("\t");
defaultValue.QuoteString(mCmdInfo);
for (var value in values)
{
mCmdInfo.Append("\t");
value.QuoteString(mCmdInfo);
}
mCmdInfo.Append("\n");
}
public void AddCheckbox(StringView dataName, StringView label, bool defaultValue)
{
mCmdInfo.AppendF($"addCheckbox\t");
dataName.QuoteString(mCmdInfo);
mCmdInfo.Append("\t");
label.QuoteString(mCmdInfo);
mCmdInfo.AppendF($"\t{defaultValue}\n");
}
public bool GetString(StringView key, String outVal)
{
if (mParams.TryGetAlt(key, var matchKey, var value))
{
outVal.Append(value);
return true;
}
return false;
}
public virtual void InitUI()
{
}
public virtual void Generate(String outFileName, String outText, ref Flags generateFlags)
{
}
static String GetName<T>() where T : Generator
{
T val = scope T();
String str = val.Name;
return str;
}
void HandleArgs(String args)
{
for (var line in args.Split('\n', .RemoveEmptyEntries))
{
int tabPos = line.IndexOf('\t');
var key = line.Substring(0, tabPos);
var value = line.Substring(tabPos + 1);
if (mParams.TryAdd(key, var keyPtr, var valuePtr))
{
*keyPtr = key;
*valuePtr = value;
}
}
}
static String InitUI<T>(String args) where T : Generator
{
T val = scope T();
val.HandleArgs(args);
val.InitUI();
return val.mCmdInfo;
}
static String Generate<T>(String args) where T : Generator
{
T val = scope T();
val.HandleArgs(args);
String fileName = scope .();
String outText = scope .();
Flags flags = .None;
val.Generate(fileName, outText, ref flags);
val.mCmdInfo.Append("fileName\t");
fileName.QuoteString(val.mCmdInfo);
val.mCmdInfo.Append("\n");
val.mCmdInfo.Append("data\n");
if (flags.HasFlag(.AllowRegenerate))
{
bool writeArg = false;
for (var line in args.Split('\n', .RemoveEmptyEntries))
{
int tabPos = line.IndexOf('\t');
var key = line.Substring(0, tabPos);
var value = line.Substring(tabPos + 1);
if (key == "Generator")
writeArg = true;
if (writeArg)
{
val.mCmdInfo.AppendF($"// {key}={value}\n");
}
}
var hash = MD5.Hash(.((.)outText.Ptr, outText.Length));
val.mCmdInfo.AppendF($"// GenHash={hash}\n\n");
}
val.mCmdInfo.Append(outText);
return val.mCmdInfo;
}
}
public class NewClassGenerator : Generator
{
public override String Name => "New Class";
public override void InitUI()
{
AddEdit("name", "Class Name", "");
}
public override void Generate(String outFileName, String outText, ref Flags generateFlags)
{
var name = mParams["name"];
if (name.EndsWith(".bf", .OrdinalIgnoreCase))
name.RemoveFromEnd(3);
outFileName.Append(name);
outText.AppendF(
$"""
namespace {Namespace}
{{
class {name}
{{
}}
}}
""");
}
}
public struct MethodBuilder
{
void* mNative;
@ -43,7 +224,7 @@ namespace System
public static extern String CallerProject;
[LinkName("#CallerExpression")]
public static extern String[0x0FFFFFFF] CallerExpression;
public static extern String[0x00FFFFFF] CallerExpression;
[LinkName("#ProjectName")]
public static extern String ProjectName;
@ -76,6 +257,7 @@ namespace System
static extern void* Comptime_MethodBuilder_EmitStr(void* native, StringView str);
static extern void* Comptime_CreateMethod(int32 typeId, StringView methodName, Type returnType, MethodFlags methodFlags);
static extern void Comptime_EmitTypeBody(int32 typeId, StringView text);
static extern void Comptime_EmitAddInterface(int32 typeId, int32 ifaceTypeId);
static extern void Comptime_EmitMethodEntry(int64 methodHandle, StringView text);
static extern void Comptime_EmitMethodExit(int64 methodHandle, StringView text);
static extern void Comptime_EmitMixin(StringView text);
@ -94,6 +276,12 @@ namespace System
Comptime_EmitTypeBody((.)owner.TypeId, text);
}
[Comptime(OnlyFromComptime=true)]
public static void EmitAddInterface(Type owner, Type iface)
{
Comptime_EmitAddInterface((.)owner.TypeId, (.)iface.TypeId);
}
[Comptime(OnlyFromComptime=true)]
public static void EmitMethodEntry(ComptimeMethodInfo methodHandle, StringView text)
{

View file

@ -21,8 +21,7 @@ namespace System
public const double NegativeInfinity = (double)(- 1.0 / (double)(0.0));
public const double PositiveInfinity = (double)1.0 / (double)(0.0);
public const double NaN = (double)0.0 / (double)0.0;
static double NegativeZero = BitConverter.Convert<int64, double>(0x8000000000000000UL);
public const double NegativeZero = -0.0;
public static int operator<=>(Double a, Double b)
{

View file

@ -163,7 +163,7 @@ namespace System
public static mixin Mark<T>(T val) where T : struct
{
#if BF_ENABLE_REALTIME_LEAK_CHECK
val.[Friend]GCMarkMembers();
val.[Friend, Unbound]GCMarkMembers();
#endif
}

View file

@ -19,7 +19,7 @@ namespace System.IO
set
{
mPos = Math.Min(value, Length);
mPos = value;
}
}
@ -43,20 +43,16 @@ namespace System.IO
public override Result<void> Seek(int64 pos, SeekKind seekKind = .Absolute)
{
int64 length = Length;
int64 newPos;
switch (seekKind)
{
case .Absolute:
mPos = Math.Min(pos, length);
if (pos > length)
return .Err;
mPos = pos;
case .FromEnd:
newPos = length - pos;
mPos = Length + pos;
case .Relative:
mPos = Math.Min(mPos + pos, length);
mPos = mPos + pos;
}
return .Ok;
}
@ -176,7 +172,12 @@ namespace System.IO
public override Result<void> Close()
{
return Flush();
let ret = Flush();
mPos = 0;
mBufferPos = -Int32.MinValue;
mBufferEnd = -Int32.MinValue;
return ret;
}
}
}

View file

@ -0,0 +1,580 @@
// 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<int, CommonDialog> sHookMap = new Dictionary<int, CommonDialog>() ~
{
Debug.Assert(sHookMap.Count == 0);
delete _;
};
public static Monitor sMonitor = new Monitor() ~ delete _;
public Result<DialogResult> 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<DialogResult> RunDialog(Windows.HWnd hWndOwner);
}
abstract class FileDialog : CommonDialog
{
protected abstract Result<DialogResult> RunFileDialog(ref Windows.OpenFileName ofn);
protected override Result<DialogResult> 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<void> 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<void> 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<DialogResult> 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
protected abstract Result<Windows.COM_IFileDialog*> CreateVistaDialog();
private Result<DialogResult> TryRunDialogVista(Windows.HWnd hWndOwner)
{
Windows.COM_IFileDialog* dialog;
if (!(CreateVistaDialog() case .Ok(out dialog)))
return .Err;
OnBeforeVistaDialog(dialog);
dialog.VT.Show(dialog, hWndOwner);
List<String> 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<String> files);
private Result<void> SetFileTypes(Windows.COM_IFileDialog* dialog)
{
List<Windows.COMDLG_FILTERSPEC> filterItems = scope .();
// Expected input types
// "Text files (*.txt)|*.txt|All files (*.*)|*.*"
// "Image Files(*.BMP;*.JPG;*.GIF)|*.BMP;*.JPG;*.GIF|All files (*.*)|*.*"
if (!String.IsNullOrEmpty(mFilter))
{
StringView[] tokens = mFilter.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 = tokens[i].ToScopedNativeWChar!::(); // This may be a semicolon delimited list of extensions (that's ok)
ext.pszName = tokens[i - 1].ToScopedNativeWChar!::();
filterItems.Add(ext);
}
}
}
if (filterItems.IsEmpty)
return .Ok;
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;
}
}
}
#endif

View file

@ -296,6 +296,15 @@ namespace System.IO
}
}
public override int64 Position
{
set
{
// Matches the behavior of Platform.BfpFile_Seek(mBfpFile, value, .Absolute);
mPos = Math.Max(value, 0);
}
}
public this()
{
@ -416,16 +425,37 @@ namespace System.IO
mFileAccess = access;
}
public override Result<void> Seek(int64 pos, SeekKind seekKind = .Absolute)
{
int64 newPos;
switch (seekKind)
{
case .Absolute:
newPos = pos;
case .FromEnd:
newPos = Length + pos;
case .Relative:
newPos = mPos + pos;
}
// Matches the behaviour of Platform.BfpFile_Seek(mBfpFile, value, .Absolute);
mPos = Math.Max(newPos, 0);
if (seekKind == .Absolute && newPos < 0)
return .Err;
return .Ok;
}
public override Result<void> Close()
{
var hadError = Flush() case .Err;
let ret = base.Close();
if (mBfpFile != null)
Platform.BfpFile_Release(mBfpFile);
mBfpFile = null;
mFileAccess = default;
if (hadError)
return .Err;
return .Ok;
mBfpFilePos = 0;
return ret;
}
protected override void UpdateLength()

View file

@ -57,7 +57,7 @@ namespace System.IO
ShowNewFolderButton = true;
}
protected Result<DialogResult> RunDialog_New(Windows.HWnd hWndOwner, FolderBrowserDialog.COM_IFileDialog* fileDialog)
protected Result<DialogResult> 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<DialogResult> 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

View file

@ -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<int, CommonDialog> sHookMap = new Dictionary<int, CommonDialog>() ~
{
Debug.Assert(sHookMap.Count == 0);
delete _;
};
public static Monitor sMonitor = new Monitor() ~ delete _;
public Result<DialogResult> 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<DialogResult> RunDialog(Windows.HWnd hWndOwner);
}
abstract class FileDialog : CommonDialog
{
protected abstract Result<DialogResult> RunFileDialog(ref Windows.OpenFileName ofn);
protected override Result<DialogResult> 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<void> 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<void> 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<DialogResult> 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,73 @@ namespace System.IO
return DialogResult.OK;
}
protected override void ProcessVistaFiles(Windows.COM_IFileDialog* dialog, List<String> 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)
{
Windows.COM_IShellItemArray* results = null;
openDialog.VT.GetResults(openDialog, out results);
if (results != null)
{
results.VT.GetCount(results, let count);
for (uint32 i < count)
{
Windows.COM_IShellItem* item = null;
results.VT.GetItemAt(results, i, out item);
if (item != null)
{
let filePath = GetFilePathFromShellItem!(item);
if (filePath != null)
files.Add(filePath);
}
}
results.VT.Release(results);
}
}
else
{
Windows.COM_IShellItem* shellItem = null;
openDialog.VT.GetResult(openDialog, out shellItem);
if (shellItem != null)
{
let filePath = GetFilePathFromShellItem!(shellItem);
if (filePath != null)
files.Add(filePath);
shellItem.VT.Release(shellItem);
}
}
}
protected override Result<Windows.COM_IFileDialog*> 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;
}
}
}

View file

@ -94,6 +94,48 @@ namespace System.IO
return DialogResult.OK;
}
protected override void ProcessVistaFiles(Windows.COM_IFileDialog* dialog, System.Collections.List<String> 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;
Windows.COM_IShellItem* shellItem = null;
saveDialog.VT.GetResult(saveDialog, out shellItem);
if (shellItem != null)
{
let filePath = GetFilePathFromShellItem!(shellItem);
if (filePath != null)
files.Add(filePath);
shellItem.VT.Release(shellItem);
}
}
protected override Result<Windows.COM_IFileDialog*> 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;
}
}
}

View file

@ -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);