diff --git a/src/Ookii.Dialogs.Wpf/AnimationResource.cs b/src/Ookii.Dialogs.Wpf/AnimationResource.cs index dca07f0..7a3bb07 100644 --- a/src/Ookii.Dialogs.Wpf/AnimationResource.cs +++ b/src/Ookii.Dialogs.Wpf/AnimationResource.cs @@ -74,9 +74,9 @@ public static AnimationResource GetShellAnimation(ShellAnimation animation) return new AnimationResource("shell32.dll", (int)animation); } - internal SafeModuleHandle LoadLibrary() + internal FreeLibrarySafeHandle LoadLibrary() { - SafeModuleHandle handle = NativeMethods.LoadLibraryEx(ResourceFile, IntPtr.Zero, NativeMethods.LoadLibraryExFlags.LoadLibraryAsDatafile); + var handle = NativeMethods.LoadLibraryEx(ResourceFile, default, Windows.Win32.System.LibraryLoader.LOAD_LIBRARY_FLAGS.LOAD_LIBRARY_AS_DATAFILE); if( handle.IsInvalid ) { int error = System.Runtime.InteropServices.Marshal.GetLastWin32Error(); diff --git a/src/Ookii.Dialogs.Wpf/ComCtlv6ActivationContext.cs b/src/Ookii.Dialogs.Wpf/ComCtlv6ActivationContext.cs index 05c23be..cc3e8ca 100644 --- a/src/Ookii.Dialogs.Wpf/ComCtlv6ActivationContext.cs +++ b/src/Ookii.Dialogs.Wpf/ComCtlv6ActivationContext.cs @@ -23,9 +23,9 @@ namespace Ookii.Dialogs.Wpf sealed class ComCtlv6ActivationContext : IDisposable { // Private data - private IntPtr _cookie; - private static NativeMethods.ACTCTX _enableThemingActivationContext; - private static ActivationContextSafeHandle _activationContext; + private nuint _cookie; + private static ACTCTXW _enableThemingActivationContext; + private static SafeFileHandle _activationContext; private static bool _contextCreationSucceeded; private static readonly object _contextCreationLock = new object(); @@ -38,7 +38,7 @@ public ComCtlv6ActivationContext(bool enable) if( !NativeMethods.ActivateActCtx(_activationContext, out _cookie) ) { // Be sure cookie always zero if activation failed - _cookie = IntPtr.Zero; + _cookie = 0; } } } @@ -57,12 +57,12 @@ public void Dispose() private void Dispose(bool disposing) { - if( _cookie != IntPtr.Zero ) + if( _cookie != 0 ) { if( NativeMethods.DeactivateActCtx(0, _cookie) ) { // deactivation succeeded... - _cookie = IntPtr.Zero; + _cookie = 0; } } } @@ -95,15 +95,21 @@ private static bool EnsureActivateContextCreated() } } - _enableThemingActivationContext = new NativeMethods.ACTCTX + unsafe { - cbSize = Marshal.SizeOf(typeof(NativeMethods.ACTCTX)), - lpSource = manifestTempFilePath, - }; + fixed (char* szManifestTempFilePath = manifestTempFilePath) + { + _enableThemingActivationContext = new ACTCTXW + { + cbSize = (uint)Marshal.SizeOf(typeof(ACTCTXW)), + lpSource = szManifestTempFilePath, + }; + } + } // Note this will fail gracefully if file specified // by manifestFilePath doesn't exist. - _activationContext = NativeMethods.CreateActCtx(ref _enableThemingActivationContext); + _activationContext = NativeMethods.CreateActCtx(_enableThemingActivationContext); _contextCreationSucceeded = !_activationContext.IsInvalid; try diff --git a/src/Ookii.Dialogs.Wpf/CredentialDialog.cs b/src/Ookii.Dialogs.Wpf/CredentialDialog.cs index 8e94c76..5fcefcb 100644 --- a/src/Ookii.Dialogs.Wpf/CredentialDialog.cs +++ b/src/Ookii.Dialogs.Wpf/CredentialDialog.cs @@ -24,6 +24,7 @@ using System.Windows; using System.Windows.Interop; using System.ComponentModel; +using System.Runtime.CompilerServices; namespace Ookii.Dialogs.Wpf { @@ -53,7 +54,7 @@ public partial class CredentialDialog : Component private string _confirmTarget; private NetworkCredential _credentials = new NetworkCredential(); private byte[] _additionalEntropy; - private bool _isSaveChecked; + private BOOL _isSaveChecked; private string _target; private static readonly Dictionary _applicationInstanceCredentialCache = new Dictionary(); @@ -86,7 +87,7 @@ public CredentialDialog() /// The to add the component to. public CredentialDialog(IContainer container) { - if( container != null ) + if (container != null) container.Add(this); InitializeComponent(); @@ -123,7 +124,7 @@ public CredentialDialog(IContainer container) /// [Category("Behavior"), Description("Indicates whether to use the application instance credential cache."), DefaultValue(false)] public bool UseApplicationInstanceCredentialCache { get; set; } - + /// /// Gets or sets whether the "save password" checkbox is checked. /// @@ -231,8 +232,8 @@ private set public string Target { get { return _target ?? string.Empty; } - set - { + set + { _target = value; _confirmTarget = null; } @@ -460,16 +461,16 @@ public bool ShowDialog() [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] public bool ShowDialog(IntPtr owner) { - if( string.IsNullOrEmpty(_target) ) + if (string.IsNullOrEmpty(_target)) throw new InvalidOperationException(Properties.Resources.CredentialEmptyTargetError); - IntPtr ownerHandle = owner == default(IntPtr) ? NativeMethods.GetActiveWindow() : owner; + HWND ownerHandle = owner == default ? NativeMethods.GetActiveWindow() : (HWND)owner; UserName = ""; Password = ""; IsStoredCredential = false; - if( RetrieveCredentialsFromApplicationInstanceCache() ) + if (RetrieveCredentialsFromApplicationInstanceCache()) { IsStoredCredential = true; _confirmTarget = Target; @@ -477,10 +478,10 @@ public bool ShowDialog(IntPtr owner) } bool storedCredentials = false; - if( ShowSaveCheckBox && RetrieveCredentials() ) + if (ShowSaveCheckBox && RetrieveCredentials()) { IsSaveChecked = true; - if( !ShowUIForSavedCredentials ) + if (!ShowUIForSavedCredentials) { IsStoredCredential = true; _confirmTarget = Target; @@ -490,7 +491,7 @@ public bool ShowDialog(IntPtr owner) } bool result; - if( NativeMethods.IsWindowsVistaOrLater ) + if (NativeMethods.IsWindowsVistaOrLater) result = PromptForCredentialsCredUIWin(ownerHandle, storedCredentials); else result = PromptForCredentialsCredUI(ownerHandle, storedCredentials); @@ -536,7 +537,7 @@ public bool ShowDialog(IntPtr owner) public bool ShowDialog(Window owner) { IntPtr ownerHandle; - if( owner == null ) + if (owner == null) ownerHandle = NativeMethods.GetActiveWindow(); else ownerHandle = new WindowInteropHelper(owner).Handle; @@ -558,16 +559,16 @@ public bool ShowDialog(Window owner) /// There was an error saving the credentials. public void ConfirmCredentials(bool confirm) { - if( _confirmTarget == null || _confirmTarget != Target ) + if (_confirmTarget == null || _confirmTarget != Target) throw new InvalidOperationException(Properties.Resources.CredentialPromptNotCalled); _confirmTarget = null; - if( IsSaveChecked && confirm ) + if (IsSaveChecked && confirm) { - if( UseApplicationInstanceCredentialCache ) + if (UseApplicationInstanceCredentialCache) { - lock( _applicationInstanceCredentialCache ) + lock (_applicationInstanceCredentialCache) { _applicationInstanceCredentialCache[Target] = new System.Net.NetworkCredential(UserName, Password); } @@ -608,32 +609,38 @@ public void ConfirmCredentials(bool confirm) /// form "Company_ApplicationName_www.example.com". /// /// - public static void StoreCredential(string target, NetworkCredential credential, byte[] additionalEntropy = null) + public unsafe static void StoreCredential(string target, NetworkCredential credential, byte[] additionalEntropy = null) { - if( target == null ) + if (target == null) throw new ArgumentNullException("target"); - if( target.Length == 0 ) + if (target.Length == 0) throw new ArgumentException(Properties.Resources.CredentialEmptyTargetError, "target"); - if( credential == null ) + if (credential == null) throw new ArgumentNullException("credential"); - NativeMethods.CREDENTIAL c = new NativeMethods.CREDENTIAL(); - c.UserName = credential.UserName; - c.TargetName = target; - c.Persist = NativeMethods.CredPersist.Enterprise; - byte[] encryptedPassword = EncryptPassword(credential.Password, additionalEntropy); - c.CredentialBlob = System.Runtime.InteropServices.Marshal.AllocHGlobal(encryptedPassword.Length); - try + fixed (char* userNamePtr = credential.UserName) + fixed (char* targetPtr = target) { - System.Runtime.InteropServices.Marshal.Copy(encryptedPassword, 0, c.CredentialBlob, encryptedPassword.Length); - c.CredentialBlobSize = (uint)encryptedPassword.Length; - c.Type = NativeMethods.CredTypes.CRED_TYPE_GENERIC; - if( !NativeMethods.CredWrite(ref c, 0) ) - throw new CredentialException(System.Runtime.InteropServices.Marshal.GetLastWin32Error()); - } - finally - { - System.Runtime.InteropServices.Marshal.FreeCoTaskMem(c.CredentialBlob); + var c = new CREDENTIALW + { + UserName = userNamePtr, + TargetName = targetPtr, + Persist = CRED_PERSIST.CRED_PERSIST_ENTERPRISE + }; + byte[] encryptedPassword = EncryptPassword(credential.Password, additionalEntropy); + c.CredentialBlob = (byte*)System.Runtime.InteropServices.Marshal.AllocHGlobal(encryptedPassword.Length); + try + { + System.Runtime.InteropServices.Marshal.Copy(encryptedPassword, 0, (IntPtr)c.CredentialBlob, encryptedPassword.Length); + c.CredentialBlobSize = (uint)encryptedPassword.Length; + c.Type = CRED_TYPE.CRED_TYPE_GENERIC; + if (!NativeMethods.CredWrite(c, 0)) + throw new CredentialException(System.Runtime.InteropServices.Marshal.GetLastWin32Error()); + } + finally + { + System.Runtime.InteropServices.Marshal.FreeCoTaskMem((IntPtr)c.CredentialBlob); + } } } @@ -656,28 +663,27 @@ public static void StoreCredential(string target, NetworkCredential credential, /// is . /// is an empty string (""). /// An error occurred retrieving the credentials. - public static NetworkCredential RetrieveCredential(string target, byte[] additionalEntropy = null) + public unsafe static NetworkCredential RetrieveCredential(string target, byte[] additionalEntropy = null) { - if( target == null ) + if (target == null) throw new ArgumentNullException("target"); - if( target.Length == 0 ) + if (target.Length == 0) throw new ArgumentException(Properties.Resources.CredentialEmptyTargetError, "target"); NetworkCredential cred = RetrieveCredentialFromApplicationInstanceCache(target); - if( cred != null ) + if (cred != null) return cred; - IntPtr credential; - bool result = NativeMethods.CredRead(target, NativeMethods.CredTypes.CRED_TYPE_GENERIC, 0, out credential); + var result = NativeMethods.CredRead(target, (uint)CRED_TYPE.CRED_TYPE_GENERIC, 0, out var credential); int error = System.Runtime.InteropServices.Marshal.GetLastWin32Error(); - if( result ) + if (result) { try { - NativeMethods.CREDENTIAL c = (NativeMethods.CREDENTIAL)System.Runtime.InteropServices.Marshal.PtrToStructure(credential, typeof(NativeMethods.CREDENTIAL)); + CREDENTIALW c = (CREDENTIALW)System.Runtime.InteropServices.Marshal.PtrToStructure(new IntPtr(credential), typeof(CREDENTIALW)); byte[] encryptedPassword = new byte[c.CredentialBlobSize]; - System.Runtime.InteropServices.Marshal.Copy(c.CredentialBlob, encryptedPassword, 0, encryptedPassword.Length); - cred = new NetworkCredential(c.UserName, DecryptPassword(encryptedPassword, additionalEntropy)); + System.Runtime.InteropServices.Marshal.Copy((IntPtr)c.CredentialBlob, encryptedPassword, 0, encryptedPassword.Length); + cred = new NetworkCredential(c.UserName.ToString(), DecryptPassword(encryptedPassword, additionalEntropy)); } finally { @@ -687,7 +693,7 @@ public static NetworkCredential RetrieveCredential(string target, byte[] additio } else { - if( error == (int)NativeMethods.CredUIReturnCodes.ERROR_NOT_FOUND ) + if (error == (int)WIN32_ERROR.ERROR_NOT_FOUND) return null; else throw new CredentialException(error); @@ -709,15 +715,14 @@ public static NetworkCredential RetrieveCredential(string target, byte[] additio /// is an empty string (""). public static NetworkCredential RetrieveCredentialFromApplicationInstanceCache(string target) { - if( target == null ) + if (target == null) throw new ArgumentNullException("target"); - if( target.Length == 0 ) + if (target.Length == 0) throw new ArgumentException(Properties.Resources.CredentialEmptyTargetError, "target"); - lock( _applicationInstanceCredentialCache ) + lock (_applicationInstanceCredentialCache) { - System.Net.NetworkCredential cred; - if( _applicationInstanceCredentialCache.TryGetValue(target, out cred) ) + if (_applicationInstanceCredentialCache.TryGetValue(target, out NetworkCredential cred)) { return cred; } @@ -743,25 +748,25 @@ public static NetworkCredential RetrieveCredentialFromApplicationInstanceCache(s /// An error occurred deleting the credentials from the operating system's credential store. public static bool DeleteCredential(string target) { - if( target == null ) + if (target == null) throw new ArgumentNullException("target"); - if( target.Length == 0 ) + if (target.Length == 0) throw new ArgumentException(Properties.Resources.CredentialEmptyTargetError, "target"); bool found = false; - lock( _applicationInstanceCredentialCache ) + lock (_applicationInstanceCredentialCache) { found = _applicationInstanceCredentialCache.Remove(target); } - if( NativeMethods.CredDelete(target, NativeMethods.CredTypes.CRED_TYPE_GENERIC, 0) ) + if (NativeMethods.CredDelete(target, (uint)CRED_TYPE.CRED_TYPE_GENERIC, 0)) { found = true; } else { int error = Marshal.GetLastWin32Error(); - if( error != (int)NativeMethods.CredUIReturnCodes.ERROR_NOT_FOUND ) + if (error != (int)WIN32_ERROR.ERROR_NOT_FOUND) throw new CredentialException(error); } return found; @@ -773,7 +778,7 @@ public static bool DeleteCredential(string target) /// The containing data for the event. protected virtual void OnUserNameChanged(EventArgs e) { - if( UserNameChanged != null ) + if (UserNameChanged != null) UserNameChanged(this, e); } @@ -783,137 +788,176 @@ protected virtual void OnUserNameChanged(EventArgs e) /// The containing data for the event. protected virtual void OnPasswordChanged(EventArgs e) { - if( PasswordChanged != null ) + if (PasswordChanged != null) PasswordChanged(this, e); } - private bool PromptForCredentialsCredUI(IntPtr owner, bool storedCredentials) + private unsafe bool PromptForCredentialsCredUI(HWND owner, bool storedCredentials) { - NativeMethods.CREDUI_INFO info = CreateCredUIInfo(owner, true); - NativeMethods.CREDUI_FLAGS flags = NativeMethods.CREDUI_FLAGS.GENERIC_CREDENTIALS | NativeMethods.CREDUI_FLAGS.DO_NOT_PERSIST | NativeMethods.CREDUI_FLAGS.ALWAYS_SHOW_UI; - if( ShowSaveCheckBox ) - flags |= NativeMethods.CREDUI_FLAGS.SHOW_SAVE_CHECK_BOX; - - StringBuilder user = new StringBuilder(NativeMethods.CREDUI_MAX_USERNAME_LENGTH); - user.Append(UserName); - StringBuilder pw = new StringBuilder(NativeMethods.CREDUI_MAX_PASSWORD_LENGTH); - pw.Append(Password); - - NativeMethods.CredUIReturnCodes result = NativeMethods.CredUIPromptForCredentials(ref info, Target, IntPtr.Zero, 0, user, NativeMethods.CREDUI_MAX_USERNAME_LENGTH, pw, NativeMethods.CREDUI_MAX_PASSWORD_LENGTH, ref _isSaveChecked, flags); - switch( result ) + CREDUI_INFOW info = CreateCredUIInfo(owner, true); + CREDUI_FLAGS flags = CREDUI_FLAGS.CREDUI_FLAGS_GENERIC_CREDENTIALS | CREDUI_FLAGS.CREDUI_FLAGS_DO_NOT_PERSIST | CREDUI_FLAGS.CREDUI_FLAGS_ALWAYS_SHOW_UI; + if (ShowSaveCheckBox) + flags |= CREDUI_FLAGS.CREDUI_FLAGS_SHOW_SAVE_CHECK_BOX; + + Span userSpan = stackalloc char[(int)NativeMethods.CREDUI_MAX_USERNAME_LENGTH]; + UserName.AsSpan().CopyTo(userSpan); + Span pwSpan = stackalloc char[NativeMethods.CREDUI_MAX_PASSWORD_LENGTH]; + Password.AsSpan().CopyTo(pwSpan); + WIN32_ERROR result; + fixed (BOOL* b = &_isSaveChecked) + result = (WIN32_ERROR)NativeMethods.CredUIPromptForCredentials(info, Target, ref Unsafe.AsRef((void*)0), 0, ref userSpan, NativeMethods.CREDUI_MAX_USERNAME_LENGTH, ref pwSpan, NativeMethods.CREDUI_MAX_PASSWORD_LENGTH, b, flags); + + switch (result) { - case NativeMethods.CredUIReturnCodes.NO_ERROR: - UserName = user.ToString(); - Password = pw.ToString(); - if( ShowSaveCheckBox ) + case WIN32_ERROR.NO_ERROR: + UserName = userSpan.ToCleanString(); + Password = pwSpan.ToCleanString(); + if (ShowSaveCheckBox) { _confirmTarget = Target; // If the credential was stored previously but the user has now cleared the save checkbox, // we want to delete the credential. - if( storedCredentials && !IsSaveChecked ) + if (storedCredentials && !IsSaveChecked) DeleteCredential(Target); } return true; - case NativeMethods.CredUIReturnCodes.ERROR_CANCELLED: + case WIN32_ERROR.ERROR_CANCELLED: return false; default: throw new CredentialException((int)result); } } - private bool PromptForCredentialsCredUIWin(IntPtr owner, bool storedCredentials) + private unsafe bool PromptForCredentialsCredUIWin(HWND owner, bool storedCredentials) { - NativeMethods.CREDUI_INFO info = CreateCredUIInfo(owner, false); - NativeMethods.CredUIWinFlags flags = NativeMethods.CredUIWinFlags.Generic; - if( ShowSaveCheckBox ) - flags |= NativeMethods.CredUIWinFlags.Checkbox; + CREDUI_INFOW info = CreateCredUIInfo(owner, false); + CREDUIWIN_FLAGS flags = CREDUIWIN_FLAGS.CREDUIWIN_GENERIC; + if (ShowSaveCheckBox) + flags |= CREDUIWIN_FLAGS.CREDUIWIN_CHECKBOX; IntPtr inBuffer = IntPtr.Zero; IntPtr outBuffer = IntPtr.Zero; try { uint inBufferSize = 0; - if( UserName.Length > 0 ) + if (UserName.Length > 0) { - NativeMethods.CredPackAuthenticationBuffer(0, UserName, Password, IntPtr.Zero, ref inBufferSize); - if( inBufferSize > 0 ) + Span userSpan = stackalloc char[(int)NativeMethods.CREDUI_MAX_USERNAME_LENGTH]; + UserName.AsSpan().CopyTo(userSpan); + Span pwSpan = stackalloc char[NativeMethods.CREDUI_MAX_PASSWORD_LENGTH]; + Password.AsSpan().CopyTo(pwSpan); + fixed (char* user = userSpan) + fixed (char* pw = pwSpan) + fixed (BOOL* b = &_isSaveChecked) { - inBuffer = Marshal.AllocCoTaskMem((int)inBufferSize); - if( !NativeMethods.CredPackAuthenticationBuffer(0, UserName, Password, inBuffer, ref inBufferSize) ) - throw new CredentialException(Marshal.GetLastWin32Error()); + + NativeMethods.CredPackAuthenticationBuffer(0, user, pw, (byte*)0, ref inBufferSize); + if (inBufferSize > 0) + { + inBuffer = Marshal.AllocCoTaskMem((int)inBufferSize); + if (!NativeMethods.CredPackAuthenticationBuffer(0, user, pw, (byte*)inBuffer, ref inBufferSize)) + throw new CredentialException(Marshal.GetLastWin32Error()); + } } } uint outBufferSize; uint package = 0; - NativeMethods.CredUIReturnCodes result = NativeMethods.CredUIPromptForWindowsCredentials(ref info, 0, ref package, inBuffer, inBufferSize, out outBuffer, out outBufferSize, ref _isSaveChecked, flags); - switch( result ) + WIN32_ERROR result; + fixed (BOOL* b = &_isSaveChecked) { - case NativeMethods.CredUIReturnCodes.NO_ERROR: - StringBuilder userName = new StringBuilder(NativeMethods.CREDUI_MAX_USERNAME_LENGTH); - StringBuilder password = new StringBuilder(NativeMethods.CREDUI_MAX_PASSWORD_LENGTH); - uint userNameSize = (uint)userName.Capacity; - uint passwordSize = (uint)password.Capacity; - uint domainSize = 0; - if( !NativeMethods.CredUnPackAuthenticationBuffer(0, outBuffer, outBufferSize, userName, ref userNameSize, null, ref domainSize, password, ref passwordSize) ) - throw new CredentialException(Marshal.GetLastWin32Error()); - UserName = userName.ToString(); - Password = password.ToString(); - if( ShowSaveCheckBox ) - { - _confirmTarget = Target; - // If the credential was stored previously but the user has now cleared the save checkbox, - // we want to delete the credential. - if( storedCredentials && !IsSaveChecked ) - DeleteCredential(Target); - } - return true; - case NativeMethods.CredUIReturnCodes.ERROR_CANCELLED: - return false; - default: - throw new CredentialException((int)result); + result = (WIN32_ERROR)NativeMethods.CredUIPromptForWindowsCredentials(info, 0, ref package, (void*)inBuffer, inBufferSize, out var poutBuffer, out outBufferSize, b, flags); + outBuffer = (IntPtr)poutBuffer; + } + + switch (result) + { + case WIN32_ERROR.NO_ERROR: + Span userSpan = stackalloc char[(int)NativeMethods.CREDUI_MAX_USERNAME_LENGTH]; + UserName.AsSpan().CopyTo(userSpan); + Span pwSpan = stackalloc char[NativeMethods.CREDUI_MAX_PASSWORD_LENGTH]; + Password.AsSpan().CopyTo(pwSpan); + uint userNameSize = (uint)userSpan.Length; + uint passwordSize = (uint)pwSpan.Length; + uint domainSize = 0; + BOOL res; + + fixed (char* user = userSpan) + fixed (char* pw = pwSpan) + res = NativeMethods.CredUnPackAuthenticationBuffer(0, (void*)outBuffer, outBufferSize, user, ref userNameSize, null, &domainSize, pw, ref passwordSize); + + if (!res) + throw new CredentialException(Marshal.GetLastWin32Error()); + UserName = userSpan.ToCleanString(); + Password = pwSpan.ToCleanString(); + if (ShowSaveCheckBox) + { + _confirmTarget = Target; + // If the credential was stored previously but the user has now cleared the save checkbox, + // we want to delete the credential. + if (storedCredentials && !IsSaveChecked) + DeleteCredential(Target); + } + return true; + case WIN32_ERROR.ERROR_CANCELLED: + return false; + default: + throw new CredentialException((int)result); } } finally { - if( inBuffer != IntPtr.Zero ) + if (inBuffer != IntPtr.Zero) Marshal.FreeCoTaskMem(inBuffer); - if( outBuffer != IntPtr.Zero ) + if (outBuffer != IntPtr.Zero) Marshal.FreeCoTaskMem(outBuffer); } } - private NativeMethods.CREDUI_INFO CreateCredUIInfo(IntPtr owner, bool downlevelText) + private unsafe CREDUI_INFOW CreateCredUIInfo(HWND owner, bool downlevelText) { - NativeMethods.CREDUI_INFO info = new NativeMethods.CREDUI_INFO(); - info.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(info); - info.hwndParent = owner; - if( downlevelText ) + var info = new CREDUI_INFOW + { + hwndParent = owner + }; + info.cbSize = (uint)System.Runtime.InteropServices.Marshal.SizeOf(info); + if (downlevelText) { - info.pszCaptionText = WindowTitle; - switch( DownlevelTextMode ) + fixed (char* pWindowTitle = WindowTitle) + info.pszCaptionText = pWindowTitle; + switch (DownlevelTextMode) { - case DownlevelTextMode.MainInstructionAndContent: - if( MainInstruction.Length == 0 ) - info.pszMessageText = Content; - else if( Content.Length == 0 ) - info.pszMessageText = MainInstruction; - else - info.pszMessageText = MainInstruction + Environment.NewLine + Environment.NewLine + Content; - break; - case DownlevelTextMode.MainInstructionOnly: - info.pszMessageText = MainInstruction; - break; - case DownlevelTextMode.ContentOnly: - info.pszMessageText = Content; - break; + case DownlevelTextMode.MainInstructionAndContent: + string text; + if (MainInstruction.Length == 0) + text = Content; + else if (Content.Length == 0) + text = MainInstruction; + else + text = MainInstruction + Environment.NewLine + Environment.NewLine + Content; + + fixed (char* pText = text) + info.pszMessageText = pText; + break; + case DownlevelTextMode.MainInstructionOnly: + fixed (char* pMainInstruction = MainInstruction) + info.pszMessageText = pMainInstruction; + break; + case DownlevelTextMode.ContentOnly: + fixed (char* pContent = Content) + info.pszMessageText = pContent; + break; } } else { // Vista and later don't use the window title. - info.pszMessageText = Content; - info.pszCaptionText = MainInstruction; + fixed (char* pContent = Content) + fixed (char* pMainInstruction = MainInstruction) + { + info.pszMessageText = pContent; + info.pszCaptionText = pMainInstruction; + } } return info; } @@ -921,7 +965,7 @@ private NativeMethods.CREDUI_INFO CreateCredUIInfo(IntPtr owner, bool downlevelT private bool RetrieveCredentials() { NetworkCredential credential = RetrieveCredential(Target, AdditionalEntropy); - if( credential != null ) + if (credential != null) { UserName = credential.UserName; Password = credential.Password; @@ -942,7 +986,7 @@ private static string DecryptPassword(byte[] encrypted, byte[] additionalEntropy { return Encoding.UTF8.GetString(System.Security.Cryptography.ProtectedData.Unprotect(encrypted, additionalEntropy, System.Security.Cryptography.DataProtectionScope.CurrentUser)); } - catch( System.Security.Cryptography.CryptographicException ) + catch (System.Security.Cryptography.CryptographicException) { return string.Empty; } @@ -950,10 +994,10 @@ private static string DecryptPassword(byte[] encrypted, byte[] additionalEntropy private bool RetrieveCredentialsFromApplicationInstanceCache() { - if( UseApplicationInstanceCredentialCache ) + if (UseApplicationInstanceCredentialCache) { NetworkCredential credential = RetrieveCredentialFromApplicationInstanceCache(Target); - if( credential != null ) + if (credential != null) { UserName = credential.UserName; Password = credential.Password; diff --git a/src/Ookii.Dialogs.Wpf/Interop/COMGuids.cs b/src/Ookii.Dialogs.Wpf/Interop/COMGuids.cs index fff3e36..cd7893d 100644 --- a/src/Ookii.Dialogs.Wpf/Interop/COMGuids.cs +++ b/src/Ookii.Dialogs.Wpf/Interop/COMGuids.cs @@ -14,28 +14,13 @@ // #endregion -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Runtime.InteropServices; - namespace Ookii.Dialogs.Wpf.Interop { internal static class IIDGuid { - internal const string IModalWindow = "b4db1657-70d7-485e-8e3e-6fcb5a5c1802"; - internal const string IFileDialog = "42f85136-db7e-439c-85f1-e4075d135fc8"; internal const string IFileOpenDialog = "d57c7288-d4ad-4768-be02-9d969532d960"; internal const string IFileSaveDialog = "84bccd23-5fde-4cdb-aea4-af64b83d78ab"; - internal const string IFileDialogEvents = "973510DB-7D7F-452B-8975-74A85828D354"; - internal const string IFileDialogControlEvents = "36116642-D713-4b97-9B83-7484A9D00433"; - internal const string IFileDialogCustomize = "e6fdd21a-163f-4975-9c8c-a69f1ba37034"; - internal const string IShellItem = "43826D1E-E718-42EE-BC55-A1E261C37BFE"; - internal const string IShellItemArray = "B63EA76D-1F85-456F-A19C-48159EFA858B"; - internal const string IKnownFolder = "38521333-6A87-46A7-AE10-0F16706816C3"; internal const string IKnownFolderManager = "44BEAAEC-24F4-4E90-B3F0-23D258FBB146"; - internal const string IPropertyStore = "886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99"; internal const string IProgressDialog = "EBBC7C04-315E-11d2-B62F-006097DF5BD4"; } @@ -46,12 +31,4 @@ internal static class CLSIDGuid internal const string KnownFolderManager = "4df0c730-df9d-4ae3-9153-aa6b82e9795a"; internal const string ProgressDialog = "F8383852-FCD3-11d1-A6B9-006097DF5BD4"; } - - internal static class KFIDGuid - { - internal const string ComputerFolder = "0AC0837C-BBF8-452A-850D-79D08E667CA7"; - internal const string Favorites = "1777F761-68AD-4D8A-87BD-30B759FA33DD"; - internal const string Documents = "FDD39AD0-238F-46AF-ADB4-6C85480369C7"; - internal const string Profile = "5E6C858F-0E22-4760-9AFE-EA3317B67173"; - } } diff --git a/src/Ookii.Dialogs.Wpf/Interop/ComDlgResources.cs b/src/Ookii.Dialogs.Wpf/Interop/ComDlgResources.cs index c6d2623..8287bc2 100644 --- a/src/Ookii.Dialogs.Wpf/Interop/ComDlgResources.cs +++ b/src/Ookii.Dialogs.Wpf/Interop/ComDlgResources.cs @@ -14,10 +14,6 @@ // #endregion -using System; -using System.Collections.Generic; -using System.Text; - namespace Ookii.Dialogs.Wpf.Interop { static class ComDlgResources diff --git a/src/Ookii.Dialogs.Wpf/Interop/ErrorHelper.cs b/src/Ookii.Dialogs.Wpf/Interop/ErrorHelper.cs deleted file mode 100644 index e8410fa..0000000 --- a/src/Ookii.Dialogs.Wpf/Interop/ErrorHelper.cs +++ /dev/null @@ -1,31 +0,0 @@ -#region Copyright 2009-2021 Ookii Dialogs Contributors -// -// Licensed under the BSD 3-Clause License (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://opensource.org/licenses/BSD-3-Clause -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -#endregion - -using System; -using System.Collections.Generic; -using System.Text; - -namespace Ookii.Dialogs.Wpf.Interop -{ - internal enum HRESULT : long - { - S_FALSE = 0x0001, - S_OK = 0x0000, - E_INVALIDARG = 0x80070057, - E_OUTOFMEMORY = 0x8007000E, - ERROR_CANCELLED = 0x800704C7 - } -} diff --git a/src/Ookii.Dialogs.Wpf/Interop/IProgressDialog.cs b/src/Ookii.Dialogs.Wpf/Interop/IProgressDialog.cs index 7985cc7..b3f48e8 100644 --- a/src/Ookii.Dialogs.Wpf/Interop/IProgressDialog.cs +++ b/src/Ookii.Dialogs.Wpf/Interop/IProgressDialog.cs @@ -31,94 +31,4 @@ internal class ProgressDialogRCW internal interface ProgressDialog : IProgressDialog { } - - [Flags] - internal enum ProgressDialogFlags : uint - { - Normal = 0x00000000, - Modal = 0x00000001, - AutoTime = 0x00000002, - NoTime = 0x00000004, - NoMinimize = 0x00000008, - NoProgressBar = 0x00000010, - MarqueeProgress = 0x00000020, - NoCancel = 0x00000040, - } - - [Flags] - internal enum ProgressDialogTimerAction : uint - { - Reset = 0x00000001, - Pause = 0x00000002, - Resume = 0x00000003, - } - - [ComImport] - [Guid(IIDGuid.IProgressDialog)] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - internal interface IProgressDialog - { - - [PreserveSig] - void StartProgressDialog( - IntPtr hwndParent, - [MarshalAs(UnmanagedType.IUnknown)] - object punkEnableModless, - ProgressDialogFlags dwFlags, - IntPtr pvResevered - ); - - [PreserveSig] - void StopProgressDialog(); - - [PreserveSig] - void SetTitle( - [MarshalAs(UnmanagedType.LPWStr)] - string pwzTitle - ); - - [PreserveSig] - void SetAnimation( - SafeModuleHandle hInstAnimation, - ushort idAnimation - ); - - [PreserveSig] - [return: MarshalAs(UnmanagedType.Bool)] - bool HasUserCancelled(); - - [PreserveSig] - void SetProgress( - uint dwCompleted, - uint dwTotal - ); - [PreserveSig] - void SetProgress64( - ulong ullCompleted, - ulong ullTotal - ); - - [PreserveSig] - void SetLine( - uint dwLineNum, - [MarshalAs(UnmanagedType.LPWStr)] - string pwzString, - [MarshalAs(UnmanagedType.VariantBool)] - bool fCompactPath, - IntPtr pvResevered - ); - - [PreserveSig] - void SetCancelMsg( - [MarshalAs(UnmanagedType.LPWStr)] - string pwzCancelMsg, - object pvResevered - ); - - [PreserveSig] - void Timer( - ProgressDialogTimerAction dwTimerAction, - object pvReserved - ); - } } diff --git a/src/Ookii.Dialogs.Wpf/Interop/ShellComInterfaces.cs b/src/Ookii.Dialogs.Wpf/Interop/ShellComInterfaces.cs deleted file mode 100644 index e4350b8..0000000 --- a/src/Ookii.Dialogs.Wpf/Interop/ShellComInterfaces.cs +++ /dev/null @@ -1,622 +0,0 @@ -#region Copyright 2009-2021 Ookii Dialogs Contributors -// -// Licensed under the BSD 3-Clause License (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://opensource.org/licenses/BSD-3-Clause -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -#endregion - -using System; -using System.Collections.Generic; -using System.Text; -using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; - -// Disable warning CS0108: 'x' hides inherited member 'y'. Use the new keyword if hiding was intended. -#pragma warning disable 0108 - -namespace Ookii.Dialogs.Wpf.Interop -{ - [ComImport(), - Guid(IIDGuid.IModalWindow), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - internal interface IModalWindow - { - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), - PreserveSig] - int Show([In] IntPtr parent); - } - - [ComImport(), - Guid(IIDGuid.IFileDialog), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - internal interface IFileDialog : IModalWindow - { - // Defined on IModalWindow - repeated here due to requirements of COM interop layer - // -------------------------------------------------------------------------------- - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), - PreserveSig] - int Show([In] IntPtr parent); - - // IFileDialog-Specific interface members - // -------------------------------------------------------------------------------- - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetFileTypes([In] uint cFileTypes, [In, MarshalAs(UnmanagedType.LPArray)] NativeMethods.COMDLG_FILTERSPEC[] rgFilterSpec); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetFileTypeIndex([In] uint iFileType); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetFileTypeIndex(out uint piFileType); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void Advise([In, MarshalAs(UnmanagedType.Interface)] IFileDialogEvents pfde, out uint pdwCookie); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void Unadvise([In] uint dwCookie); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetOptions([In] NativeMethods.FOS fos); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetOptions(out NativeMethods.FOS pfos); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetDefaultFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetFolder([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetCurrentSelection([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetFileName([In, MarshalAs(UnmanagedType.LPWStr)] string pszName); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetTitle([In, MarshalAs(UnmanagedType.LPWStr)] string pszTitle); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetOkButtonLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszText); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetFileNameLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszLabel); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetResult([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void AddPlace([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, NativeMethods.FDAP fdap); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetDefaultExtension([In, MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void Close([MarshalAs(UnmanagedType.Error)] int hr); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetClientGuid([In] ref Guid guid); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void ClearClientData(); - - // Not supported: IShellItemFilter is not defined, converting to IntPtr - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetFilter([MarshalAs(UnmanagedType.Interface)] IntPtr pFilter); - } - - [ComImport(), - Guid(IIDGuid.IFileOpenDialog), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - internal interface IFileOpenDialog : IFileDialog - { - // Defined on IModalWindow - repeated here due to requirements of COM interop layer - // -------------------------------------------------------------------------------- - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), - PreserveSig] - int Show([In] IntPtr parent); - - // Defined on IFileDialog - repeated here due to requirements of COM interop layer - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetFileTypes([In] uint cFileTypes, [In] ref NativeMethods.COMDLG_FILTERSPEC rgFilterSpec); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetFileTypeIndex([In] uint iFileType); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetFileTypeIndex(out uint piFileType); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void Advise([In, MarshalAs(UnmanagedType.Interface)] IFileDialogEvents pfde, out uint pdwCookie); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void Unadvise([In] uint dwCookie); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetOptions([In] NativeMethods.FOS fos); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetOptions(out NativeMethods.FOS pfos); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetDefaultFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetFolder([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetCurrentSelection([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetFileName([In, MarshalAs(UnmanagedType.LPWStr)] string pszName); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetTitle([In, MarshalAs(UnmanagedType.LPWStr)] string pszTitle); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetOkButtonLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszText); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetFileNameLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszLabel); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetResult([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void AddPlace([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, NativeMethods.FDAP fdap); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetDefaultExtension([In, MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void Close([MarshalAs(UnmanagedType.Error)] int hr); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetClientGuid([In] ref Guid guid); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void ClearClientData(); - - // Not supported: IShellItemFilter is not defined, converting to IntPtr - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetFilter([MarshalAs(UnmanagedType.Interface)] IntPtr pFilter); - - // Defined by IFileOpenDialog - // --------------------------------------------------------------------------------- - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetResults([MarshalAs(UnmanagedType.Interface)] out IShellItemArray ppenum); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetSelectedItems([MarshalAs(UnmanagedType.Interface)] out IShellItemArray ppsai); - } - - [ComImport(), - Guid(IIDGuid.IFileSaveDialog), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - internal interface IFileSaveDialog : IFileDialog - { - // Defined on IModalWindow - repeated here due to requirements of COM interop layer - // -------------------------------------------------------------------------------- - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), - PreserveSig] - int Show([In] IntPtr parent); - - // Defined on IFileDialog - repeated here due to requirements of COM interop layer - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetFileTypes([In] uint cFileTypes, [In] ref NativeMethods.COMDLG_FILTERSPEC rgFilterSpec); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetFileTypeIndex([In] uint iFileType); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetFileTypeIndex(out uint piFileType); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void Advise([In, MarshalAs(UnmanagedType.Interface)] IFileDialogEvents pfde, out uint pdwCookie); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void Unadvise([In] uint dwCookie); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetOptions([In] NativeMethods.FOS fos); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetOptions(out NativeMethods.FOS pfos); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetDefaultFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetFolder([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetCurrentSelection([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetFileName([In, MarshalAs(UnmanagedType.LPWStr)] string pszName); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetTitle([In, MarshalAs(UnmanagedType.LPWStr)] string pszTitle); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetOkButtonLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszText); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetFileNameLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszLabel); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetResult([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void AddPlace([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, NativeMethods.FDAP fdap); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetDefaultExtension([In, MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void Close([MarshalAs(UnmanagedType.Error)] int hr); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetClientGuid([In] ref Guid guid); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void ClearClientData(); - - // Not supported: IShellItemFilter is not defined, converting to IntPtr - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetFilter([MarshalAs(UnmanagedType.Interface)] IntPtr pFilter); - - // Defined by IFileSaveDialog interface - // ----------------------------------------------------------------------------------- - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetSaveAsItem([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi); - - // Not currently supported: IPropertyStore - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetProperties([In, MarshalAs(UnmanagedType.Interface)] IntPtr pStore); - - // Not currently supported: IPropertyDescriptionList - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetCollectedProperties([In, MarshalAs(UnmanagedType.Interface)] IntPtr pList, [In] int fAppendDefault); - - // Not currently supported: IPropertyStore - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetProperties([MarshalAs(UnmanagedType.Interface)] out IntPtr ppStore); - - // Not currently supported: IPropertyStore, IFileOperationProgressSink - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void ApplyProperties([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, [In, MarshalAs(UnmanagedType.Interface)] IntPtr pStore, [In, ComAliasName("Interop.wireHWND")] ref IntPtr hwnd, [In, MarshalAs(UnmanagedType.Interface)] IntPtr pSink); - } - - [ComImport, - Guid(IIDGuid.IFileDialogEvents), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - internal interface IFileDialogEvents - { - // NOTE: some of these callbacks are cancelable - returning S_FALSE means that - // the dialog should not proceed (e.g. with closing, changing folder); to - // support this, we need to use the PreserveSig attribute to enable us to return - // the proper HRESULT - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), - PreserveSig] - HRESULT OnFileOk([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), - PreserveSig] - HRESULT OnFolderChanging([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd, [In, MarshalAs(UnmanagedType.Interface)] IShellItem psiFolder); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void OnFolderChange([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void OnSelectionChange([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void OnShareViolation([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd, [In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, out NativeMethods.FDE_SHAREVIOLATION_RESPONSE pResponse); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void OnTypeChange([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void OnOverwrite([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd, [In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, out NativeMethods.FDE_OVERWRITE_RESPONSE pResponse); - } - - [ComImport, - Guid(IIDGuid.IShellItem), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - internal interface IShellItem - { - // Not supported: IBindCtx - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void BindToHandler([In, MarshalAs(UnmanagedType.Interface)] IntPtr pbc, [In] ref Guid bhid, [In] ref Guid riid, out IntPtr ppv); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetParent([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetDisplayName([In] NativeMethods.SIGDN sigdnName, [MarshalAs(UnmanagedType.LPWStr)] out string ppszName); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetAttributes([In] uint sfgaoMask, out uint psfgaoAttribs); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void Compare([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, [In] uint hint, out int piOrder); - } - - [ComImport, - Guid(IIDGuid.IShellItemArray), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - internal interface IShellItemArray - { - // Not supported: IBindCtx - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void BindToHandler([In, MarshalAs(UnmanagedType.Interface)] IntPtr pbc, [In] ref Guid rbhid, [In] ref Guid riid, out IntPtr ppvOut); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetPropertyStore([In] int Flags, [In] ref Guid riid, out IntPtr ppv); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetPropertyDescriptionList([In] ref NativeMethods.PROPERTYKEY keyType, [In] ref Guid riid, out IntPtr ppv); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetAttributes([In] NativeMethods.SIATTRIBFLAGS dwAttribFlags, [In] uint sfgaoMask, out uint psfgaoAttribs); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetCount(out uint pdwNumItems); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetItemAt([In] uint dwIndex, [MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); - - // Not supported: IEnumShellItems (will use GetCount and GetItemAt instead) - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void EnumItems([MarshalAs(UnmanagedType.Interface)] out IntPtr ppenumShellItems); - } - - [ComImport, - Guid(IIDGuid.IKnownFolder), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - internal interface IKnownFolder - { - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetId(out Guid pkfid); - - // Not yet supported - adding to fill slot in vtable - void spacer1(); - //[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - //void GetCategory(out mbtagKF_CATEGORY pCategory); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetShellItem([In] uint dwFlags, ref Guid riid, out IShellItem ppv); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetPath([In] uint dwFlags, [MarshalAs(UnmanagedType.LPWStr)] out string ppszPath); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetPath([In] uint dwFlags, [In, MarshalAs(UnmanagedType.LPWStr)] string pszPath); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetLocation([In] uint dwFlags, [Out, ComAliasName("Interop.wirePIDL")] IntPtr ppidl); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetFolderType(out Guid pftid); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetRedirectionCapabilities(out uint pCapabilities); - - // Not yet supported - adding to fill slot in vtable - void spacer2(); - //[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - //void GetFolderDefinition(out tagKNOWNFOLDER_DEFINITION pKFD); - } - - - [ComImport, - Guid(IIDGuid.IKnownFolderManager), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - internal interface IKnownFolderManager - { - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void FolderIdFromCsidl([In] int nCsidl, out Guid pfid); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void FolderIdToCsidl([In] ref Guid rfid, out int pnCsidl); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetFolderIds([Out] IntPtr ppKFId, [In, Out] ref uint pCount); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetFolder([In] ref Guid rfid, [MarshalAs(UnmanagedType.Interface)] out IKnownFolder ppkf); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetFolderByName([In, MarshalAs(UnmanagedType.LPWStr)] string pszCanonicalName, [MarshalAs(UnmanagedType.Interface)] out IKnownFolder ppkf); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void RegisterFolder([In] ref Guid rfid, [In] ref NativeMethods.KNOWNFOLDER_DEFINITION pKFD); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void UnregisterFolder([In] ref Guid rfid); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void FindFolderFromPath([In, MarshalAs(UnmanagedType.LPWStr)] string pszPath, [In] NativeMethods.FFFP_MODE mode, [MarshalAs(UnmanagedType.Interface)] out IKnownFolder ppkf); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void FindFolderFromIDList([In] IntPtr pidl, [MarshalAs(UnmanagedType.Interface)] out IKnownFolder ppkf); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void Redirect([In] ref Guid rfid, [In] IntPtr hwnd, [In] uint Flags, [In, MarshalAs(UnmanagedType.LPWStr)] string pszTargetPath, [In] uint cFolders, [In] ref Guid pExclusion, [MarshalAs(UnmanagedType.LPWStr)] out string ppszError); - } - - [ComImport, - Guid(IIDGuid.IFileDialogCustomize), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - internal interface IFileDialogCustomize - { - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void EnableOpenDropDown([In] int dwIDCtl); - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void AddMenu([In] int dwIDCtl, [In, MarshalAs(UnmanagedType.LPWStr)] string pszLabel); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void AddPushButton([In] int dwIDCtl, [In, MarshalAs(UnmanagedType.LPWStr)] string pszLabel); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void AddComboBox([In] int dwIDCtl); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void AddRadioButtonList([In] int dwIDCtl); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void AddCheckButton([In] int dwIDCtl, [In, MarshalAs(UnmanagedType.LPWStr)] string pszLabel, [In] bool bChecked); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void AddEditBox([In] int dwIDCtl, [In, MarshalAs(UnmanagedType.LPWStr)] string pszText); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void AddSeparator([In] int dwIDCtl); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void AddText([In] int dwIDCtl, [In, MarshalAs(UnmanagedType.LPWStr)] string pszText); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetControlLabel([In] int dwIDCtl, [In, MarshalAs(UnmanagedType.LPWStr)] string pszLabel); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetControlState([In] int dwIDCtl, [Out] out NativeMethods.CDCONTROLSTATE pdwState); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetControlState([In] int dwIDCtl, [In] NativeMethods.CDCONTROLSTATE dwState); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetEditBoxText([In] int dwIDCtl, [Out] IntPtr ppszText); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetEditBoxText([In] int dwIDCtl, [In, MarshalAs(UnmanagedType.LPWStr)] string pszText); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetCheckButtonState([In] int dwIDCtl, [Out] out bool pbChecked); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetCheckButtonState([In] int dwIDCtl, [In] bool bChecked); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void AddControlItem([In] int dwIDCtl, [In] int dwIDItem, [In, MarshalAs(UnmanagedType.LPWStr)] string pszLabel); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void RemoveControlItem([In] int dwIDCtl, [In] int dwIDItem); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void RemoveAllControlItems([In] int dwIDCtl); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetControlItemState([In] int dwIDCtl, [In] int dwIDItem, [Out] out NativeMethods.CDCONTROLSTATE pdwState); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetControlItemState([In] int dwIDCtl, [In] int dwIDItem, [In] NativeMethods.CDCONTROLSTATE dwState); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetSelectedControlItem([In] int dwIDCtl, [Out] out int pdwIDItem); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetSelectedControlItem([In] int dwIDCtl, [In] int dwIDItem); // Not valid for OpenDropDown - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void StartVisualGroup([In] int dwIDCtl, [In, MarshalAs(UnmanagedType.LPWStr)] string pszLabel); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void EndVisualGroup(); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void MakeProminent([In] int dwIDCtl); - } - - [ComImport, - Guid(IIDGuid.IFileDialogControlEvents), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - internal interface IFileDialogControlEvents - { - - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void OnItemSelected([In, MarshalAs(UnmanagedType.Interface)] IFileDialogCustomize pfdc, [In] int dwIDCtl, [In] int dwIDItem); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void OnButtonClicked([In, MarshalAs(UnmanagedType.Interface)] IFileDialogCustomize pfdc, [In] int dwIDCtl); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void OnCheckButtonToggled([In, MarshalAs(UnmanagedType.Interface)] IFileDialogCustomize pfdc, [In] int dwIDCtl, [In] bool bChecked); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void OnControlActivating([In, MarshalAs(UnmanagedType.Interface)] IFileDialogCustomize pfdc, [In] int dwIDCtl); - } - - [ComImport, - Guid(IIDGuid.IPropertyStore), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - internal interface IPropertyStore - { - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetCount([Out] out uint cProps); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetAt([In] uint iProp, out NativeMethods.PROPERTYKEY pkey); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void GetValue([In] ref NativeMethods.PROPERTYKEY key, out object pv); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void SetValue([In] ref NativeMethods.PROPERTYKEY key, [In] ref object pv); - [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - void Commit(); - } - - /// - /// C# definition of the IMalloc interface. - /// - [ComImport] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - [Guid("00000002-0000-0000-C000-000000000046")] - internal interface IMalloc - { - /// - /// Allocate a block of memory - /// - /// Size, in bytes, of the memory block to be allocated. - /// a pointer to the allocated memory block. - [PreserveSig] - IntPtr Alloc( - [In] UInt32 cb); - - /// - /// Changes the size of a previously allocated memory block. - /// - /// Pointer to the memory block to be reallocated - /// Size of the memory block, in bytes, to be reallocated. - /// reallocated memory block - [PreserveSig] - IntPtr Realloc( - [In] IntPtr pv, - [In] UInt32 cb); - - /// - /// Free a previously allocated block of memory. - /// - /// Pointer to the memory block to be freed. - [PreserveSig] - void Free( - [In] IntPtr pv); - - - - /// - /// This method returns the size, in bytes, of a memory block previously allocated with IMalloc::Alloc or IMalloc::Realloc. - /// - /// Pointer to the memory block for which the size is requested - /// The size of the allocated memory block in bytes. - [PreserveSig] - UInt32 GetSize( - [In] IntPtr pv); - - /// - /// This method determines whether this allocator was used to allocate the specified block of memory. - /// - /// Pointer to the memory block - /// - /// 1 - allocated - /// 0 - not allocated by this IMalloc Instance. - /// -1 if DidAlloc is unable to determine whether or not it allocated the memory block. - /// - [PreserveSig] - Int16 DidAlloc( - [In] IntPtr pv); - - /// - /// Minimizes the heap by releasing unused memory to the operating system. - /// - [PreserveSig] - void HeapMinimize(); - } -} diff --git a/src/Ookii.Dialogs.Wpf/Interop/Win32Resources.cs b/src/Ookii.Dialogs.Wpf/Interop/Win32Resources.cs index c6bfcc5..d954c63 100644 --- a/src/Ookii.Dialogs.Wpf/Interop/Win32Resources.cs +++ b/src/Ookii.Dialogs.Wpf/Interop/Win32Resources.cs @@ -16,69 +16,80 @@ using System; using System.Collections.Generic; +using System.Runtime.InteropServices; using System.Text; +using Windows.Win32; +using Windows.Win32.System.Diagnostics.Debug; +using Windows.Win32.System.LibraryLoader; +using System.Runtime.CompilerServices; namespace Ookii.Dialogs.Wpf.Interop { class Win32Resources : IDisposable { - private SafeModuleHandle _moduleHandle; + private SafeHandle _moduleHandle; private const int _bufferSize = 500; public Win32Resources(string module) { - _moduleHandle = NativeMethods.LoadLibraryEx(module, IntPtr.Zero, NativeMethods.LoadLibraryExFlags.LoadLibraryAsDatafile); - if( _moduleHandle.IsInvalid ) + _moduleHandle = NativeMethods.LoadLibraryEx(module, default, LOAD_LIBRARY_FLAGS.LOAD_LIBRARY_AS_DATAFILE); + if (_moduleHandle.IsInvalid) throw new System.ComponentModel.Win32Exception(System.Runtime.InteropServices.Marshal.GetLastWin32Error()); } - public string LoadString(uint id) + public unsafe string LoadString(uint id) { CheckDisposed(); - StringBuilder buffer = new StringBuilder(_bufferSize); - if( NativeMethods.LoadString(_moduleHandle, id, buffer, buffer.Capacity + 1) == 0 ) - throw new System.ComponentModel.Win32Exception(System.Runtime.InteropServices.Marshal.GetLastWin32Error()); + Span buffer = stackalloc char[_bufferSize]; + fixed (char* pBuffer = buffer) + { + if (NativeMethods.LoadString(_moduleHandle, id, pBuffer, _bufferSize + 1) == 0) + throw new System.ComponentModel.Win32Exception(System.Runtime.InteropServices.Marshal.GetLastWin32Error()); + } return buffer.ToString(); } - public string FormatString(uint id, params string[] args) + public unsafe string FormatString(uint id, params string[] args) { CheckDisposed(); - IntPtr buffer = IntPtr.Zero; + PWSTR buffer = new(); string source = LoadString(id); // For some reason FORMAT_MESSAGE_FROM_HMODULE doesn't work so we use this way. - NativeMethods.FormatMessageFlags flags = NativeMethods.FormatMessageFlags.FORMAT_MESSAGE_ALLOCATE_BUFFER | NativeMethods.FormatMessageFlags.FORMAT_MESSAGE_ARGUMENT_ARRAY | NativeMethods.FormatMessageFlags.FORMAT_MESSAGE_FROM_STRING; + FORMAT_MESSAGE_OPTIONS flags = FORMAT_MESSAGE_OPTIONS.FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_OPTIONS.FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_OPTIONS.FORMAT_MESSAGE_FROM_STRING; IntPtr sourcePtr = System.Runtime.InteropServices.Marshal.StringToHGlobalAuto(source); try { - if( NativeMethods.FormatMessage(flags, sourcePtr, id, 0, ref buffer, 0, args) == 0 ) - throw new System.ComponentModel.Win32Exception(System.Runtime.InteropServices.Marshal.GetLastWin32Error()); + fixed (char* pargs = args[0]) + { + if (NativeMethods.FormatMessage(flags, (void*)sourcePtr, id, 0, (PWSTR)Unsafe.AsPointer(ref buffer), 0, (sbyte**)&pargs) == 0) + throw new System.ComponentModel.Win32Exception(System.Runtime.InteropServices.Marshal.GetLastWin32Error()); + } } finally { System.Runtime.InteropServices.Marshal.FreeHGlobal(sourcePtr); } - string result = System.Runtime.InteropServices.Marshal.PtrToStringAuto(buffer); + string result = buffer.ToString(); // FreeHGlobal calls LocalFree - System.Runtime.InteropServices.Marshal.FreeHGlobal(buffer); + System.Runtime.InteropServices.Marshal.FreeHGlobal((IntPtr)Unsafe.AsPointer(ref buffer)); return result; } protected virtual void Dispose(bool disposing) { - if( disposing ) + if (disposing) _moduleHandle.Dispose(); } private void CheckDisposed() { - if( _moduleHandle.IsClosed ) + if (_moduleHandle.IsClosed) { throw new ObjectDisposedException("Win32Resources"); } @@ -92,6 +103,6 @@ public void Dispose() GC.SuppressFinalize(this); } - #endregion + #endregion } } diff --git a/src/Ookii.Dialogs.Wpf/NativeMethods.cs b/src/Ookii.Dialogs.Wpf/NativeMethods.cs index 6d88788..4258db0 100644 --- a/src/Ookii.Dialogs.Wpf/NativeMethods.cs +++ b/src/Ookii.Dialogs.Wpf/NativeMethods.cs @@ -15,16 +15,12 @@ #endregion using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Runtime.InteropServices; -using System.Runtime.ConstrainedExecution; -using Ookii.Dialogs.Wpf.Interop; +using System.Runtime.CompilerServices; -namespace Ookii.Dialogs.Wpf +namespace Windows.Win32 { - static class NativeMethods + static partial class NativeMethods { public const int ErrorFileNotFound = 2; @@ -44,626 +40,18 @@ public static bool IsWindowsXPOrLater } } - #region LoadLibrary - - [DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern Ookii.Dialogs.Wpf.SafeModuleHandle LoadLibraryEx( - string lpFileName, - IntPtr hFile, - LoadLibraryExFlags dwFlags - ); - - [DllImport("kernel32", SetLastError = true), - ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool FreeLibrary(IntPtr hModule); - - [Flags] - public enum LoadLibraryExFlags : uint - { - DontResolveDllReferences = 0x00000001, - LoadLibraryAsDatafile = 0x00000002, - LoadWithAlteredSearchPath = 0x00000008, - LoadIgnoreCodeAuthzLevel = 0x00000010 - } - - #endregion - - #region Task Dialogs - - [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] - public static extern IntPtr GetActiveWindow(); - - [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] - public static extern bool EnableWindow(IntPtr hwnd, bool bEnable); - - [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] - public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId); - - [DllImport("kernel32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] - public static extern int GetCurrentThreadId(); - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Interoperability", "CA1400:PInvokeEntryPointsShouldExist"), DllImport("comctl32.dll", PreserveSig = false)] - public static extern void TaskDialogIndirect([In] ref TASKDIALOGCONFIG pTaskConfig, out int pnButton, out int pnRadioButton, [MarshalAs(UnmanagedType.Bool)] out bool pfVerificationFlagChecked); - - - public delegate uint TaskDialogCallback(IntPtr hwnd, uint uNotification, IntPtr wParam, IntPtr lParam, IntPtr dwRefData); - - - public const int WM_USER = 0x400; - public const int WM_GETICON = 0x007F; - public const int WM_SETICON = 0x0080; - public const int ICON_SMALL = 0; - - public enum TaskDialogNotifications - { - Created = 0, - Navigated = 1, - ButtonClicked = 2, // wParam = Button ID - HyperlinkClicked = 3, // lParam = (LPCWSTR)pszHREF - Timer = 4, // wParam = Milliseconds since dialog created or timer reset - Destroyed = 5, - RadioButtonClicked = 6, // wParam = Radio Button ID - DialogConstructed = 7, - VerificationClicked = 8, // wParam = 1 if checkbox checked, 0 if not, lParam is unused and always 0 - Help = 9, - ExpandoButtonClicked = 10 // wParam = 0 (dialog is now collapsed), wParam != 0 (dialog is now expanded) - } - - [Flags] - public enum TaskDialogCommonButtonFlags - { - OkButton = 0x0001, // selected control return value IDOK - YesButton = 0x0002, // selected control return value IDYES - NoButton = 0x0004, // selected control return value IDNO - CancelButton = 0x0008, // selected control return value IDCANCEL - RetryButton = 0x0010, // selected control return value IDRETRY - CloseButton = 0x0020 // selected control return value IDCLOSE - }; - - [Flags] - public enum TaskDialogFlags - { - EnableHyperLinks = 0x0001, - UseHIconMain = 0x0002, - UseHIconFooter = 0x0004, - AllowDialogCancellation = 0x0008, - UseCommandLinks = 0x0010, - UseCommandLinksNoIcon = 0x0020, - ExpandFooterArea = 0x0040, - ExpandedByDefault = 0x0080, - VerificationFlagChecked = 0x0100, - ShowProgressBar = 0x0200, - ShowMarqueeProgressBar = 0x0400, - CallbackTimer = 0x0800, - PositionRelativeToWindow = 0x1000, - RtlLayout = 0x2000, - NoDefaultRadioButton = 0x4000, - CanBeMinimized = 0x8000 - }; - - public enum TaskDialogMessages - { - NavigatePage = WM_USER + 101, - ClickButton = WM_USER + 102, // wParam = Button ID - SetMarqueeProgressBar = WM_USER + 103, // wParam = 0 (nonMarque) wParam != 0 (Marquee) - SetProgressBarState = WM_USER + 104, // wParam = new progress state - SetProgressBarRange = WM_USER + 105, // lParam = MAKELPARAM(nMinRange, nMaxRange) - SetProgressBarPos = WM_USER + 106, // wParam = new position - SetProgressBarMarquee = WM_USER + 107, // wParam = 0 (stop marquee), wParam != 0 (start marquee), lparam = speed (milliseconds between repaints) - SetElementText = WM_USER + 108, // wParam = element (TASKDIALOG_ELEMENTS), lParam = new element text (LPCWSTR) - ClickRadioButton = WM_USER + 110, // wParam = Radio Button ID - EnableButton = WM_USER + 111, // lParam = 0 (disable), lParam != 0 (enable), wParam = Button ID - EnableRadioButton = WM_USER + 112, // lParam = 0 (disable), lParam != 0 (enable), wParam = Radio Button ID - ClickVerification = WM_USER + 113, // wParam = 0 (unchecked), 1 (checked), lParam = 1 (set key focus) - UpdateElementText = WM_USER + 114, // wParam = element (TASKDIALOG_ELEMENTS), lParam = new element text (LPCWSTR) - SetButtonElevationRequiredState = WM_USER + 115, // wParam = Button ID, lParam = 0 (elevation not required), lParam != 0 (elevation required) - UpdateIcon = WM_USER + 116 // wParam = icon element (TASKDIALOG_ICON_ELEMENTS), lParam = new icon (hIcon if TDF_USE_HICON_* was set, PCWSTR otherwise) - } - - public enum TaskDialogElements - { - Content, - ExpandedInformation, - Footer, - MainInstruction - } - - [StructLayout(LayoutKind.Sequential, Pack = 4)] - public struct TASKDIALOG_BUTTON - { - public int nButtonID; - [MarshalAs(UnmanagedType.LPWStr)] - public string pszButtonText; - } - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1049:TypesThatOwnNativeResourcesShouldBeDisposable"), StructLayout(LayoutKind.Sequential, Pack = 4)] - public struct TASKDIALOGCONFIG - { - public uint cbSize; - public IntPtr hwndParent; - public IntPtr hInstance; - public TaskDialogFlags dwFlags; - public TaskDialogCommonButtonFlags dwCommonButtons; - [MarshalAs(UnmanagedType.LPWStr)] - public string pszWindowTitle; - public IntPtr hMainIcon; - [MarshalAs(UnmanagedType.LPWStr)] - public string pszMainInstruction; - [MarshalAs(UnmanagedType.LPWStr)] - public string pszContent; - public uint cButtons; - //[MarshalAs(UnmanagedType.LPArray)] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] - public IntPtr pButtons; - public int nDefaultButton; - public uint cRadioButtons; - //[MarshalAs(UnmanagedType.LPArray)] - public IntPtr pRadioButtons; - public int nDefaultRadioButton; - [MarshalAs(UnmanagedType.LPWStr)] - public string pszVerificationText; - [MarshalAs(UnmanagedType.LPWStr)] - public string pszExpandedInformation; - [MarshalAs(UnmanagedType.LPWStr)] - public string pszExpandedControlText; - [MarshalAs(UnmanagedType.LPWStr)] - public string pszCollapsedControlText; - public IntPtr hFooterIcon; - [MarshalAs(UnmanagedType.LPWStr)] - public string pszFooterText; - [MarshalAs(UnmanagedType.FunctionPtr)] - public TaskDialogCallback pfCallback; - public IntPtr lpCallbackData; - public uint cxWidth; - } - - [DllImport("user32.dll", CharSet = CharSet.Auto)] - public static extern IntPtr SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam); - - #endregion - - #region Activation Context - - [DllImport("Kernel32.dll", SetLastError = true)] - public extern static ActivationContextSafeHandle CreateActCtx(ref ACTCTX actctx); - [DllImport("kernel32.dll"), ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] - public extern static void ReleaseActCtx(IntPtr hActCtx); - [DllImport("Kernel32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public extern static bool ActivateActCtx(ActivationContextSafeHandle hActCtx, out IntPtr lpCookie); - [DllImport("Kernel32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public extern static bool DeactivateActCtx(uint dwFlags, IntPtr lpCookie); - - public const int ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID = 0x004; - - public struct ACTCTX - { - public int cbSize; - public uint dwFlags; - public string lpSource; - public ushort wProcessorArchitecture; - public ushort wLangId; - public string lpAssemblyDirectory; - public string lpResourceName; - public string lpApplicationName; - } - - - #endregion - - #region File Operations Definitions - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)] - internal struct COMDLG_FILTERSPEC - { - [MarshalAs(UnmanagedType.LPWStr)] - internal string pszName; - [MarshalAs(UnmanagedType.LPWStr)] - internal string pszSpec; - } - - internal enum FDAP - { - FDAP_BOTTOM = 0x00000000, - FDAP_TOP = 0x00000001, - } - - internal enum FDE_SHAREVIOLATION_RESPONSE - { - FDESVR_DEFAULT = 0x00000000, - FDESVR_ACCEPT = 0x00000001, - FDESVR_REFUSE = 0x00000002 - } - - internal enum FDE_OVERWRITE_RESPONSE - { - FDEOR_DEFAULT = 0x00000000, - FDEOR_ACCEPT = 0x00000001, - FDEOR_REFUSE = 0x00000002 - } - - internal enum SIATTRIBFLAGS - { - SIATTRIBFLAGS_AND = 0x00000001, // if multiple items and the attirbutes together. - SIATTRIBFLAGS_OR = 0x00000002, // if multiple items or the attributes together. - SIATTRIBFLAGS_APPCOMPAT = 0x00000003, // Call GetAttributes directly on the ShellFolder for multiple attributes - } - - internal enum SIGDN : uint - { - SIGDN_NORMALDISPLAY = 0x00000000, // SHGDN_NORMAL - SIGDN_PARENTRELATIVEPARSING = 0x80018001, // SHGDN_INFOLDER | SHGDN_FORPARSING - SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000, // SHGDN_FORPARSING - SIGDN_PARENTRELATIVEEDITING = 0x80031001, // SHGDN_INFOLDER | SHGDN_FOREDITING - SIGDN_DESKTOPABSOLUTEEDITING = 0x8004c000, // SHGDN_FORPARSING | SHGDN_FORADDRESSBAR - SIGDN_FILESYSPATH = 0x80058000, // SHGDN_FORPARSING - SIGDN_URL = 0x80068000, // SHGDN_FORPARSING - SIGDN_PARENTRELATIVEFORADDRESSBAR = 0x8007c001, // SHGDN_INFOLDER | SHGDN_FORPARSING | SHGDN_FORADDRESSBAR - SIGDN_PARENTRELATIVE = 0x80080001 // SHGDN_INFOLDER - } - - [Flags] - internal enum FOS : uint - { - FOS_OVERWRITEPROMPT = 0x00000002, - FOS_STRICTFILETYPES = 0x00000004, - FOS_NOCHANGEDIR = 0x00000008, - FOS_PICKFOLDERS = 0x00000020, - FOS_FORCEFILESYSTEM = 0x00000040, // Ensure that items returned are filesystem items. - FOS_ALLNONSTORAGEITEMS = 0x00000080, // Allow choosing items that have no storage. - FOS_NOVALIDATE = 0x00000100, - FOS_ALLOWMULTISELECT = 0x00000200, - FOS_PATHMUSTEXIST = 0x00000800, - FOS_FILEMUSTEXIST = 0x00001000, - FOS_CREATEPROMPT = 0x00002000, - FOS_SHAREAWARE = 0x00004000, - FOS_NOREADONLYRETURN = 0x00008000, - FOS_NOTESTFILECREATE = 0x00010000, - FOS_HIDEMRUPLACES = 0x00020000, - FOS_HIDEPINNEDPLACES = 0x00040000, - FOS_NODEREFERENCELINKS = 0x00100000, - FOS_DONTADDTORECENT = 0x02000000, - FOS_FORCESHOWHIDDEN = 0x10000000, - FOS_DEFAULTNOMINIMODE = 0x20000000 - } - - internal enum CDCONTROLSTATE - { - CDCS_INACTIVE = 0x00000000, - CDCS_ENABLED = 0x00000001, - CDCS_VISIBLE = 0x00000002 - } - - #endregion - - #region KnownFolder Definitions - - internal enum FFFP_MODE - { - FFFP_EXACTMATCH, - FFFP_NEARESTPARENTMATCH - } - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)] - internal struct KNOWNFOLDER_DEFINITION - { - internal NativeMethods.KF_CATEGORY category; - [MarshalAs(UnmanagedType.LPWStr)] - internal string pszName; - [MarshalAs(UnmanagedType.LPWStr)] - internal string pszCreator; - [MarshalAs(UnmanagedType.LPWStr)] - internal string pszDescription; - internal Guid fidParent; - [MarshalAs(UnmanagedType.LPWStr)] - internal string pszRelativePath; - [MarshalAs(UnmanagedType.LPWStr)] - internal string pszParsingName; - [MarshalAs(UnmanagedType.LPWStr)] - internal string pszToolTip; - [MarshalAs(UnmanagedType.LPWStr)] - internal string pszLocalizedName; - [MarshalAs(UnmanagedType.LPWStr)] - internal string pszIcon; - [MarshalAs(UnmanagedType.LPWStr)] - internal string pszSecurity; - internal uint dwAttributes; - internal NativeMethods.KF_DEFINITION_FLAGS kfdFlags; - internal Guid ftidType; - } - - internal enum KF_CATEGORY - { - KF_CATEGORY_VIRTUAL = 0x00000001, - KF_CATEGORY_FIXED = 0x00000002, - KF_CATEGORY_COMMON = 0x00000003, - KF_CATEGORY_PERUSER = 0x00000004 - } - - [Flags] - internal enum KF_DEFINITION_FLAGS - { - KFDF_PERSONALIZE = 0x00000001, - KFDF_LOCAL_REDIRECT_ONLY = 0x00000002, - KFDF_ROAMABLE = 0x00000004, - } - - - // Property System structs and consts - [StructLayout(LayoutKind.Sequential, Pack = 4)] - internal struct PROPERTYKEY - { - internal Guid fmtid; - internal uint pid; - } - - #endregion - - #region Shell Parsing Names - - [DllImport("shell32.dll", CharSet = CharSet.Unicode)] - public static extern int SHCreateItemFromParsingName([MarshalAs(UnmanagedType.LPWStr)] string pszPath, IntPtr pbc, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out object ppv); - - public static Interop.IShellItem CreateItemFromParsingName(string path) + public static IShellItem CreateItemFromParsingName(string path) { - object item; - Guid guid = new Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe"); // IID_IShellItem - int hr = NativeMethods.SHCreateItemFromParsingName(path, IntPtr.Zero, ref guid, out item); - if( hr != 0 ) - throw new System.ComponentModel.Win32Exception(hr); - return (Interop.IShellItem)item; - } - - #endregion - - #region String Resources + // https://github.com/microsoft/CsWin32/issues/434#issuecomment-956966139 + var guid = new Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe"); // IID_IShellItem + var hr = SHCreateItemFromParsingName(path, default, guid/*typeof(IShellItem).GUID*/, out var o); + if (hr != 0) + throw new global::System.ComponentModel.Win32Exception(hr); - [Flags()] - public enum FormatMessageFlags - { - FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100, - FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200, - FORMAT_MESSAGE_FROM_STRING = 0x00000400, - FORMAT_MESSAGE_FROM_HMODULE = 0x00000800, - FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000, - FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000 + IShellItem shellItem = (IShellItem)o; + return shellItem; } - - [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto, BestFitMapping = false, ThrowOnUnmappableChar = true)] - public static extern int LoadString(SafeModuleHandle hInstance, uint uID, StringBuilder lpBuffer, int nBufferMax); - - [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] - public static extern uint FormatMessage([MarshalAs(UnmanagedType.U4)] FormatMessageFlags dwFlags, IntPtr lpSource, - uint dwMessageId, uint dwLanguageId, ref IntPtr lpBuffer, - uint nSize, string[] Arguments); - - #endregion - - #region Credentials - internal const int CREDUI_MAX_USERNAME_LENGTH = 256 + 1 + 256; internal const int CREDUI_MAX_PASSWORD_LENGTH = 256; - - [Flags] - public enum CREDUI_FLAGS - { - INCORRECT_PASSWORD = 0x1, - DO_NOT_PERSIST = 0x2, - REQUEST_ADMINISTRATOR = 0x4, - EXCLUDE_CERTIFICATES = 0x8, - REQUIRE_CERTIFICATE = 0x10, - SHOW_SAVE_CHECK_BOX = 0x40, - ALWAYS_SHOW_UI = 0x80, - REQUIRE_SMARTCARD = 0x100, - PASSWORD_ONLY_OK = 0x200, - VALIDATE_USERNAME = 0x400, - COMPLETE_USERNAME = 0x800, - PERSIST = 0x1000, - SERVER_CREDENTIAL = 0x4000, - EXPECT_CONFIRMATION = 0x20000, - GENERIC_CREDENTIALS = 0x40000, - USERNAME_TARGET_CREDENTIALS = 0x80000, - KEEP_USERNAME = 0x100000 - } - - [Flags] - public enum CredUIWinFlags - { - Generic = 0x1, - Checkbox = 0x2, - AutoPackageOnly = 0x10, - InCredOnly = 0x20, - EnumerateAdmins = 0x100, - EnumerateCurrentUser = 0x200, - SecurePrompt = 0x1000, - Pack32Wow = 0x10000000 - } - - internal enum CredUIReturnCodes - { - NO_ERROR = 0, - ERROR_CANCELLED = 1223, - ERROR_NO_SUCH_LOGON_SESSION = 1312, - ERROR_NOT_FOUND = 1168, - ERROR_INVALID_ACCOUNT_NAME = 1315, - ERROR_INSUFFICIENT_BUFFER = 122, - ERROR_INVALID_PARAMETER = 87, - ERROR_INVALID_FLAGS = 1004 - } - - internal enum CredTypes - { - CRED_TYPE_GENERIC = 1, - CRED_TYPE_DOMAIN_PASSWORD = 2, - CRED_TYPE_DOMAIN_CERTIFICATE = 3, - CRED_TYPE_DOMAIN_VISIBLE_PASSWORD = 4 - } - - internal enum CredPersist - { - Session = 1, - LocalMachine = 2, - Enterprise = 3 - } - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1049:TypesThatOwnNativeResourcesShouldBeDisposable")] - internal struct CREDUI_INFO - { - public int cbSize; - public IntPtr hwndParent; - [MarshalAs(UnmanagedType.LPWStr)] - public string pszMessageText; - [MarshalAs(UnmanagedType.LPWStr)] - public string pszCaptionText; - public IntPtr hbmBanner; - } - - [DllImport("credui.dll", CharSet = CharSet.Unicode)] - extern static internal CredUIReturnCodes CredUIPromptForCredentials( - ref CREDUI_INFO pUiInfo, - string targetName, - IntPtr Reserved, - int dwAuthError, - StringBuilder pszUserName, - uint ulUserNameMaxChars, - StringBuilder pszPassword, - uint ulPaswordMaxChars, - [MarshalAs(UnmanagedType.Bool), In(), Out()] ref bool pfSave, - CREDUI_FLAGS dwFlags); - - [DllImport("credui.dll", CharSet = CharSet.Unicode)] - public static extern CredUIReturnCodes CredUIPromptForWindowsCredentials( - ref CREDUI_INFO pUiInfo, - uint dwAuthError, - ref uint pulAuthPackage, - IntPtr pvInAuthBuffer, - uint ulInAuthBufferSize, - out IntPtr ppvOutAuthBuffer, - out uint pulOutAuthBufferSize, - [MarshalAs(UnmanagedType.Bool)]ref bool pfSave, - CredUIWinFlags dwFlags); - - [DllImport("advapi32.dll", CharSet = CharSet.Unicode, EntryPoint = "CredReadW", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - extern static internal bool CredRead(string TargetName, CredTypes Type, int Flags, out IntPtr Credential); - - [DllImport("advapi32.dll"), ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] - extern static internal void CredFree(IntPtr Buffer); - - [DllImport("advapi32.dll", CharSet = CharSet.Unicode, EntryPoint = "CredDeleteW", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - extern static internal bool CredDelete(string TargetName, CredTypes Type, int Flags); - - [DllImport("advapi32.dll", CharSet = CharSet.Unicode, EntryPoint = "CredWriteW", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - extern static internal bool CredWrite(ref CREDENTIAL Credential, int Flags); - - [DllImport("credui.dll", CharSet = CharSet.Unicode, SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool CredPackAuthenticationBuffer(uint dwFlags, string pszUserName, string pszPassword, IntPtr pPackedCredentials, ref uint pcbPackedCredentials); - - [DllImport("credui.dll", CharSet = CharSet.Unicode, SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool CredUnPackAuthenticationBuffer(uint dwFlags, IntPtr pAuthBuffer, uint cbAuthBuffer, StringBuilder pszUserName, ref uint pcchMaxUserName, StringBuilder pszDomainName, ref uint pcchMaxDomainName, StringBuilder pszPassword, ref uint pcchMaxPassword); - - // Disable the "Internal field is never assigned to" warning. -#pragma warning disable 649 - // This type does not own the IntPtr native resource; when CredRead is used, CredFree must be called on the - // IntPtr that the struct was marshalled from to release all resources including the CredentialBlob IntPtr, - // When allocating the struct manually for CredWrite you should also manually deallocate the CredentialBlob. - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1049:TypesThatOwnNativeResourcesShouldBeDisposable")] - public struct CREDENTIAL - { - public int Flags; - public CredTypes Type; - [MarshalAs(UnmanagedType.LPWStr)] - public string TargetName; - [MarshalAs(UnmanagedType.LPWStr)] - public string Comment; - public long LastWritten; - public uint CredentialBlobSize; - // Since the resource pointed to must be either released manually or by CredFree, SafeHandle is not appropriate here - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] - public IntPtr CredentialBlob; - [MarshalAs(UnmanagedType.U4)] - public CredPersist Persist; - public int AttributeCount; - public IntPtr Attributes; - [MarshalAs(UnmanagedType.LPWStr)] - public string TargetAlias; - [MarshalAs(UnmanagedType.LPWStr)] - public string UserName; - } -#pragma warning restore 649 - - #endregion - - #region Downlevel folder browser dialog - - public enum FolderBrowserDialogMessage - { - Initialized = 1, - SelChanged = 2, - ValidateFailedA = 3, - ValidateFailedW = 4, - EnableOk = 0x465, - SetSelection = 0x467 - } - - public delegate int BrowseCallbackProc(IntPtr hwnd, FolderBrowserDialogMessage msg, IntPtr lParam, IntPtr wParam); - - [Flags] - public enum BrowseInfoFlags - { - ReturnOnlyFsDirs = 0x00000001, - DontGoBelowDomain = 0x00000002, - StatusText = 0x00000004, - ReturnFsAncestors = 0x00000008, - EditBox = 0x00000010, - Validate = 0x00000020, - NewDialogStyle = 0x00000040, - UseNewUI = NewDialogStyle | EditBox, - BrowseIncludeUrls = 0x00000080, - UaHint = 0x00000100, - NoNewFolderButton = 0x00000200, - NoTranslateTargets = 0x00000400, - BrowseForComputer = 0x00001000, - BrowseForPrinter = 0x00002000, - BrowseIncludeFiles = 0x00004000, - Shareable = 0x00008000, - BrowseFileJunctions = 0x00010000 - } - - public struct BROWSEINFO - { - public IntPtr hwndOwner; - public IntPtr pidlRoot; - public string pszDisplayName; - public string lpszTitle; - public BrowseInfoFlags ulFlags; - public BrowseCallbackProc lpfn; - public IntPtr lParam; - public int iImage; - } - - [DllImport("shell32.dll", CharSet = CharSet.Unicode)] - public static extern IntPtr SHBrowseForFolder(ref BROWSEINFO lpbi); - [DllImport("shell32.dll", SetLastError = true)] - public static extern int SHGetSpecialFolderLocation(IntPtr hwndOwner, Environment.SpecialFolder nFolder, ref IntPtr ppidl); - [DllImport("shell32.dll", PreserveSig = false)] - public static extern IMalloc SHGetMalloc(); - [DllImport("shell32.dll", CharSet = CharSet.Unicode)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool SHGetPathFromIDList(IntPtr pidl, StringBuilder pszPath); - [DllImport("user32.dll", CharSet = CharSet.Unicode)] - public static extern IntPtr SendMessage(IntPtr hWnd, FolderBrowserDialogMessage msg, IntPtr wParam, string lParam); - [DllImport("user32.dll")] - public static extern IntPtr SendMessage(IntPtr hWnd, FolderBrowserDialogMessage msg, IntPtr wParam, IntPtr lParam); - - - #endregion - } } diff --git a/src/Ookii.Dialogs.Wpf/NativeMethods.json b/src/Ookii.Dialogs.Wpf/NativeMethods.json new file mode 100644 index 0000000..019bb05 --- /dev/null +++ b/src/Ookii.Dialogs.Wpf/NativeMethods.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://aka.ms/CsWin32.schema.json", + "emitSingleFile": false, + "className": "NativeMethods", + "comInterop": { + "preserveSigMethods": [ + "IFileDialog.Show", + "IFileDialogEvents.OnFileOk", + "IFileDialogEvents.OnFolderChanging" + ] + } +} diff --git a/src/Ookii.Dialogs.Wpf/NativeMethods.txt b/src/Ookii.Dialogs.Wpf/NativeMethods.txt new file mode 100644 index 0000000..cfefc41 --- /dev/null +++ b/src/Ookii.Dialogs.Wpf/NativeMethods.txt @@ -0,0 +1,72 @@ +ACTCTXW +ActivateActCtx +BFFM_ENABLEOK +BFFM_INITIALIZED +BFFM_IUNKNOWN +BFFM_SELCHANGED +BFFM_SETSELECTION +BFFM_VALIDATEFAILED +BIF_NEWDIALOGSTYLE +BIF_NONEWFOLDERBUTTON +BIF_RETURNONLYFSDIRS +COMDLG_FILTERSPEC +CreateActCtx +CredDelete +CredFree +CredPackAuthenticationBuffer +CredRead +CREDUI_FLAGS +CREDUI_INFOW +CREDUI_MAX_USERNAME_LENGTH +CredUIPromptForCredentials +CredUIPromptForWindowsCredentials +CredUnPackAuthenticationBuffer +CredWrite +DeactivateActCtx +EnableWindow +FDE_SHAREVIOLATION_RESPONSE +FILEOPENDIALOGOPTIONS +FormatMessage +GetActiveWindow +GetCurrentThreadId +GetWindowThreadProcessId +HRESULT_FROM_WIN32 +ICON_SMALL +IFileDialogControlEvents +IFileOpenDialog +IFileSaveDialog +IKnownFolderManager +IMalloc +IProgressDialog +IShellItem +LoadLibraryEx +LoadString +MAX_PATH +PathParseIconLocation +PDTIMER_RESUME +PROGDLG_AUTOTIME +PROGDLG_MARQUEEPROGRESS +PROGDLG_MODAL +PROGDLG_NOCANCEL +PROGDLG_NOMINIMIZE +PROGDLG_NOPROGRESSBAR +PROGDLG_NORMAL +PROGDLG_NOTIME +ReleaseActCtx +S_FALSE +S_OK +SendMessage +SHBrowseForFolder +SHCreateItemFromParsingName +SHGetMalloc +SHGetPathFromIDList +SHGetSpecialFolderLocation +SIGDN +TASKDIALOG_BUTTON +TASKDIALOG_ELEMENTS +TASKDIALOG_MESSAGES +TASKDIALOG_NOTIFICATIONS +TaskDialogIndirect +WIN32_ERROR +WM_GETICON +WM_SETICON diff --git a/src/Ookii.Dialogs.Wpf/Ookii.Dialogs.Wpf.csproj b/src/Ookii.Dialogs.Wpf/Ookii.Dialogs.Wpf.csproj index 5ae9949..8ed02b1 100644 --- a/src/Ookii.Dialogs.Wpf/Ookii.Dialogs.Wpf.csproj +++ b/src/Ookii.Dialogs.Wpf/Ookii.Dialogs.Wpf.csproj @@ -30,6 +30,7 @@ true true true + 10 @@ -67,6 +68,8 @@ + + @@ -80,6 +83,19 @@ + + + + + + + + + + + + + diff --git a/src/Ookii.Dialogs.Wpf/ProgressDialog.cs b/src/Ookii.Dialogs.Wpf/ProgressDialog.cs index 54c7bdb..7a4ff2e 100644 --- a/src/Ookii.Dialogs.Wpf/ProgressDialog.cs +++ b/src/Ookii.Dialogs.Wpf/ProgressDialog.cs @@ -48,11 +48,11 @@ private class ProgressChangedData private string _windowTitle; private string _text; private string _description; - private Interop.IProgressDialog _dialog; + private IProgressDialog _dialog; private string _cancellationText; private bool _useCompactPathsForText; private bool _useCompactPathsForDescription; - private SafeModuleHandle _currentAnimationModuleHandle; + private FreeLibrarySafeHandle _currentAnimationModuleHandle; private volatile bool _cancellationPending; private CancellationTokenSource _cancellationTokenSource; private int _percentProgress; @@ -146,8 +146,11 @@ public string Text set { _text = value; - if( _dialog != null ) - _dialog.SetLine(1, Text, UseCompactPathsForText, IntPtr.Zero); + unsafe + { + if (_dialog != null) + _dialog.SetLine(1, Text, UseCompactPathsForText, default); + } } } @@ -175,8 +178,11 @@ public bool UseCompactPathsForText set { _useCompactPathsForText = value; - if( _dialog != null ) - _dialog.SetLine(1, Text, UseCompactPathsForText, IntPtr.Zero); + unsafe + { + if ( _dialog != null ) + _dialog.SetLine(1, Text, UseCompactPathsForText, default); + } } } @@ -203,8 +209,11 @@ public string Description set { _description = value; - if( _dialog != null ) - _dialog.SetLine(2, Description, UseCompactPathsForDescription, IntPtr.Zero); + unsafe + { + if (_dialog != null) + _dialog.SetLine(2, Description, UseCompactPathsForDescription, default); + } } } @@ -232,8 +241,11 @@ public bool UseCompactPathsForDescription set { _useCompactPathsForDescription = value; - if( _dialog != null ) - _dialog.SetLine(2, Description, UseCompactPathsForDescription, IntPtr.Zero); + unsafe + { + if (_dialog != null) + _dialog.SetLine(2, Description, UseCompactPathsForDescription, default); + } } } @@ -728,7 +740,7 @@ protected virtual void OnProgressChanged(ProgressChangedEventArgs e) handler(this, e); } - private void RunProgressDialog(IntPtr owner, object argument, CancellationToken cancellationToken) + private unsafe void RunProgressDialog(IntPtr owner, object argument, CancellationToken cancellationToken) { if (_backgroundWorker.IsBusy || !(_cancellationTokenSource is null)) { @@ -761,34 +773,34 @@ private void RunProgressDialog(IntPtr owner, object argument, CancellationToken if( CancellationText.Length > 0 ) _dialog.SetCancelMsg(CancellationText, null); - _dialog.SetLine(1, Text, UseCompactPathsForText, IntPtr.Zero); - _dialog.SetLine(2, Description, UseCompactPathsForDescription, IntPtr.Zero); + _dialog.SetLine(1, Text, UseCompactPathsForText, default); + _dialog.SetLine(2, Description, UseCompactPathsForDescription, default); - Interop.ProgressDialogFlags flags = Ookii.Dialogs.Wpf.Interop.ProgressDialogFlags.Normal; + uint flags = NativeMethods.PROGDLG_NORMAL; if( owner != IntPtr.Zero ) - flags |= Ookii.Dialogs.Wpf.Interop.ProgressDialogFlags.Modal; + flags |= NativeMethods.PROGDLG_MODAL; switch( ProgressBarStyle ) { case ProgressBarStyle.None: - flags |= Ookii.Dialogs.Wpf.Interop.ProgressDialogFlags.NoProgressBar; + flags |= NativeMethods.PROGDLG_NOPROGRESSBAR; break; case ProgressBarStyle.MarqueeProgressBar: if( NativeMethods.IsWindowsVistaOrLater ) - flags |= Ookii.Dialogs.Wpf.Interop.ProgressDialogFlags.MarqueeProgress; + flags |= NativeMethods.PROGDLG_MARQUEEPROGRESS; else - flags |= Ookii.Dialogs.Wpf.Interop.ProgressDialogFlags.NoProgressBar; // Older than Vista doesn't support marquee. + flags |= NativeMethods.PROGDLG_NOPROGRESSBAR; // Older than Vista doesn't support marquee. break; } if( ShowTimeRemaining ) - flags |= Ookii.Dialogs.Wpf.Interop.ProgressDialogFlags.AutoTime; + flags |= NativeMethods.PROGDLG_AUTOTIME; if( !ShowCancelButton ) - flags |= Ookii.Dialogs.Wpf.Interop.ProgressDialogFlags.NoCancel; + flags |= NativeMethods.PROGDLG_NOCANCEL; if( !MinimizeBox ) - flags |= Ookii.Dialogs.Wpf.Interop.ProgressDialogFlags.NoMinimize; + flags |= NativeMethods.PROGDLG_NOMINIMIZE; _ownerHandle = owner; - _dialog.StartProgressDialog(owner, null, flags, IntPtr.Zero); + _dialog.StartProgressDialog((HWND)owner, null, flags, default); _backgroundWorker.RunWorkerAsync(argument); } @@ -820,7 +832,7 @@ private void _backgroundWorker_RunWorkerCompleted(object sender, RunWorkerComple } if (_ownerHandle != IntPtr.Zero) - NativeMethods.EnableWindow(_ownerHandle, true); + NativeMethods.EnableWindow((HWND)_ownerHandle, true); var cancellationTokenSource = _cancellationTokenSource; if (!(cancellationTokenSource is null)) diff --git a/src/Ookii.Dialogs.Wpf/SafeHandles.cs b/src/Ookii.Dialogs.Wpf/SafeHandles.cs deleted file mode 100644 index 886d6d1..0000000 --- a/src/Ookii.Dialogs.Wpf/SafeHandles.cs +++ /dev/null @@ -1,60 +0,0 @@ -#region Copyright 2009-2021 Ookii Dialogs Contributors -// -// Licensed under the BSD 3-Clause License (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://opensource.org/licenses/BSD-3-Clause -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -#endregion - -using Microsoft.Win32.SafeHandles; -using System.Security.Permissions; -using System; -using System.Runtime.InteropServices; -using System.Runtime.ConstrainedExecution; - -namespace Ookii.Dialogs.Wpf -{ - [SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)] - class SafeModuleHandle : SafeHandle - { - public SafeModuleHandle() - : base(IntPtr.Zero, true) - { - } - - public override bool IsInvalid - { - get { return handle == IntPtr.Zero; } - } - - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] - protected override bool ReleaseHandle() - { - return NativeMethods.FreeLibrary(handle); - } - } - - [SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)] - class ActivationContextSafeHandle : SafeHandleZeroOrMinusOneIsInvalid - { - public ActivationContextSafeHandle() - : base(true) - { - } - - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] - protected override bool ReleaseHandle() - { - NativeMethods.ReleaseActCtx(handle); - return true; - } - } -} diff --git a/src/Ookii.Dialogs.Wpf/SpanExtensions.cs b/src/Ookii.Dialogs.Wpf/SpanExtensions.cs new file mode 100644 index 0000000..354f26b --- /dev/null +++ b/src/Ookii.Dialogs.Wpf/SpanExtensions.cs @@ -0,0 +1,14 @@ +using System; + +namespace Ookii.Dialogs.Wpf +{ + internal static class SpanExtensions + { + /// + /// Drops '\0' character padding before converting to string. + /// + /// Span to convert to string. + /// Resulting string. + public static string ToCleanString(this Span span) => span.Slice(0, span.IndexOf('\0')).ToString(); + } +} diff --git a/src/Ookii.Dialogs.Wpf/TaskDialog.cs b/src/Ookii.Dialogs.Wpf/TaskDialog.cs index 17fa4e6..f699fb4 100644 --- a/src/Ookii.Dialogs.Wpf/TaskDialog.cs +++ b/src/Ookii.Dialogs.Wpf/TaskDialog.cs @@ -40,7 +40,7 @@ namespace Ookii.Dialogs.Wpf /// /// [DefaultProperty("MainInstruction"), DefaultEvent("ButtonClicked"), Description("Displays a task dialog."), Designer(typeof(TaskDialogDesigner))] - public partial class TaskDialog : Component, IWin32Window + public partial class TaskDialog : Component, System.Windows.Interop.IWin32Window { #region Events @@ -124,7 +124,7 @@ public partial class TaskDialog : Component, IWin32Window private TaskDialogItemCollection _buttons; private TaskDialogItemCollection _radioButtons; - private NativeMethods.TASKDIALOGCONFIG _config = new NativeMethods.TASKDIALOGCONFIG(); + private TASKDIALOGCONFIG _config = new TASKDIALOGCONFIG(); private TaskDialogIcon _mainIcon; private System.Drawing.Icon _customMainIcon; private System.Drawing.Icon _customFooterIcon; @@ -154,7 +154,7 @@ public TaskDialog() InitializeComponent(); _config.cbSize = (uint)Marshal.SizeOf(_config); - _config.pfCallback = new NativeMethods.TaskDialogCallback(TaskDialogCallback); + _config.pfCallback = new PFTASKDIALOGCALLBACK(TaskDialogCallback); } /// @@ -169,7 +169,7 @@ public TaskDialog(IContainer container) InitializeComponent(); _config.cbSize = (uint)Marshal.SizeOf(_config); - _config.pfCallback = new NativeMethods.TaskDialogCallback(TaskDialogCallback); + _config.pfCallback = new PFTASKDIALOGCALLBACK(TaskDialogCallback); } #endregion @@ -230,11 +230,15 @@ public string WindowTitle { get { - return _config.pszWindowTitle ?? string.Empty; + return _config.pszWindowTitle.ToString(); } set { - _config.pszWindowTitle = string.IsNullOrEmpty(value) ? null : value; + unsafe + { + fixed (char* pvalue = string.IsNullOrEmpty(value) ? null : value) + _config.pszWindowTitle = pvalue; + } UpdateDialog(); } } @@ -252,11 +256,15 @@ public string WindowTitle [Localizable(true), Category("Appearance"), Description("The dialog's main instruction."), DefaultValue(""), Editor(typeof(System.ComponentModel.Design.MultilineStringEditor), typeof(UITypeEditor))] public string MainInstruction { - get { return _config.pszMainInstruction ?? string.Empty; } + get { return _config.pszMainInstruction.ToString(); } set - { - _config.pszMainInstruction = string.IsNullOrEmpty(value) ? null : value; - SetElementText(NativeMethods.TaskDialogElements.MainInstruction, MainInstruction); + { + unsafe + { + fixed (char* pMainInstruction = string.IsNullOrEmpty(value) ? null : value) + _config.pszMainInstruction = pMainInstruction; + } + SetElementText(TASKDIALOG_ELEMENTS.TDE_MAIN_INSTRUCTION, MainInstruction); } } @@ -269,11 +277,15 @@ public string MainInstruction [Localizable(true), Category("Appearance"), Description("The dialog's primary content."), DefaultValue(""), Editor(typeof(System.ComponentModel.Design.MultilineStringEditor), typeof(UITypeEditor))] public string Content { - get { return _config.pszContent ?? string.Empty; } + get { return _config.pszContent.ToString(); } set - { - _config.pszContent = string.IsNullOrEmpty(value) ? null : value; - SetElementText(NativeMethods.TaskDialogElements.Content, Content); + { + unsafe + { + fixed (char* pContent = string.IsNullOrEmpty(value) ? null : value) + _config.pszContent = pContent; + } + SetElementText(TASKDIALOG_ELEMENTS.TDE_CONTENT, Content); } } @@ -294,7 +306,7 @@ public System.Drawing.Icon WindowIcon { if( IsDialogRunning ) { - IntPtr icon = NativeMethods.SendMessage(Handle, NativeMethods.WM_GETICON, new IntPtr(NativeMethods.ICON_SMALL), IntPtr.Zero); + IntPtr icon = NativeMethods.SendMessage((HWND)Handle, NativeMethods.WM_GETICON, (nuint)NativeMethods.ICON_SMALL, IntPtr.Zero); return System.Drawing.Icon.FromHandle(icon); } return _windowIcon; @@ -435,14 +447,14 @@ public TaskDialogButtonStyle ButtonStyle { get { - return GetFlag(NativeMethods.TaskDialogFlags.UseCommandLinksNoIcon) ? TaskDialogButtonStyle.CommandLinksNoIcon : - GetFlag(NativeMethods.TaskDialogFlags.UseCommandLinks) ? TaskDialogButtonStyle.CommandLinks : + return GetFlag(TASKDIALOG_FLAGS.TDF_USE_COMMAND_LINKS_NO_ICON) ? TaskDialogButtonStyle.CommandLinksNoIcon : + GetFlag(TASKDIALOG_FLAGS.TDF_USE_COMMAND_LINKS) ? TaskDialogButtonStyle.CommandLinks : TaskDialogButtonStyle.Standard; } set { - SetFlag(NativeMethods.TaskDialogFlags.UseCommandLinks, value == TaskDialogButtonStyle.CommandLinks); - SetFlag(NativeMethods.TaskDialogFlags.UseCommandLinksNoIcon, value == TaskDialogButtonStyle.CommandLinksNoIcon); + SetFlag(TASKDIALOG_FLAGS.TDF_USE_COMMAND_LINKS, value == TaskDialogButtonStyle.CommandLinks); + SetFlag(TASKDIALOG_FLAGS.TDF_USE_COMMAND_LINKS_NO_ICON, value == TaskDialogButtonStyle.CommandLinksNoIcon); UpdateDialog(); } } @@ -460,13 +472,17 @@ public TaskDialogButtonStyle ButtonStyle [Localizable(true), Category("Appearance"), Description("The label for the verification checkbox."), DefaultValue("")] public string VerificationText { - get { return _config.pszVerificationText ?? string.Empty; } + get { return _config.pszVerificationText.ToString() ?? string.Empty; } set { string realValue = string.IsNullOrEmpty(value) ? null : value; - if( _config.pszVerificationText != realValue ) + if( _config.pszVerificationText.ToString() != realValue ) { - _config.pszVerificationText = realValue; + unsafe + { + fixed (char* prealValue = realValue) + _config.pszVerificationText = prealValue; + } UpdateDialog(); } } @@ -491,12 +507,12 @@ public string VerificationText [Category("Behavior"), Description("Indicates whether the verification checkbox is checked ot not."), DefaultValue(false)] public bool IsVerificationChecked { - get { return GetFlag(NativeMethods.TaskDialogFlags.VerificationFlagChecked); } + get { return GetFlag(TASKDIALOG_FLAGS.TDF_VERIFICATION_FLAG_CHECKED); } set { if( value != IsVerificationChecked ) { - SetFlag(NativeMethods.TaskDialogFlags.VerificationFlagChecked, value); + SetFlag(TASKDIALOG_FLAGS.TDF_VERIFICATION_FLAG_CHECKED, value); if( IsDialogRunning ) ClickVerification(value, false); } @@ -525,11 +541,15 @@ public bool IsVerificationChecked [Localizable(true), Category("Appearance"), Description("Additional information to be displayed on the dialog."), DefaultValue(""), Editor(typeof(System.ComponentModel.Design.MultilineStringEditor), typeof(UITypeEditor))] public string ExpandedInformation { - get { return _config.pszExpandedInformation ?? string.Empty; } + get { return _config.pszExpandedInformation.ToString() ?? string.Empty; } set { - _config.pszExpandedInformation = string.IsNullOrEmpty(value) ? null : value; - SetElementText(NativeMethods.TaskDialogElements.ExpandedInformation, ExpandedInformation); + unsafe + { + fixed (char* pExpandedInformation = string.IsNullOrEmpty(value) ? null : value) + _config.pszExpandedInformation = pExpandedInformation; + } + SetElementText(TASKDIALOG_ELEMENTS.TDE_EXPANDED_INFORMATION, ExpandedInformation); } } @@ -553,13 +573,17 @@ public string ExpandedInformation [Localizable(true), Category("Appearance"), Description("The text to use for the control for collapsing the expandable information."), DefaultValue("")] public string ExpandedControlText { - get { return _config.pszExpandedControlText ?? string.Empty; } + get { return _config.pszExpandedControlText.ToString() ?? string.Empty; } set { string realValue = string.IsNullOrEmpty(value) ? null : value; - if( _config.pszExpandedControlText != realValue ) + if (_config.pszExpandedControlText.ToString() != realValue) { - _config.pszExpandedControlText = realValue; + unsafe + { + fixed (char* prealValue = realValue) + _config.pszExpandedControlText = prealValue; + } UpdateDialog(); } } @@ -585,13 +609,17 @@ public string ExpandedControlText [Localizable(true), Category("Appearance"), Description("The text to use for the control for expanding the expandable information."), DefaultValue("")] public string CollapsedControlText { - get { return _config.pszCollapsedControlText ?? string.Empty; } + get { return _config.pszCollapsedControlText.ToString() ?? string.Empty; } set { string realValue = string.IsNullOrEmpty(value) ? null : value; - if( _config.pszCollapsedControlText != realValue ) + if( _config.pszCollapsedControlText.ToString() != realValue ) { - _config.pszCollapsedControlText = string.IsNullOrEmpty(value) ? null : value; + unsafe + { + fixed (char* prealValue = realValue) + _config.pszCollapsedControlText = prealValue; + } UpdateDialog(); } } @@ -607,11 +635,15 @@ public string CollapsedControlText [Localizable(true), Category("Appearance"), Description("The text to be used in the footer area of the task dialog."), DefaultValue(""), Editor(typeof(System.ComponentModel.Design.MultilineStringEditor), typeof(UITypeEditor))] public string Footer { - get { return _config.pszFooterText ?? string.Empty; } + get { return _config.pszFooter.ToString() ?? string.Empty; } set - { - _config.pszFooterText = string.IsNullOrEmpty(value) ? null : value; - SetElementText(NativeMethods.TaskDialogElements.Footer, Footer); + { + unsafe + { + fixed (char* pvalue = string.IsNullOrEmpty(value) ? null : value) + _config.pszFooter = pvalue; + } + SetElementText(TASKDIALOG_ELEMENTS.TDE_FOOTER, Footer); } } @@ -660,12 +692,12 @@ public int Width [Category("Behavior"), Description("Indicates whether hyperlinks are allowed for the Content, ExpandedInformation and Footer properties."), DefaultValue(false)] public bool EnableHyperlinks { - get { return GetFlag(NativeMethods.TaskDialogFlags.EnableHyperLinks); } + get { return GetFlag(TASKDIALOG_FLAGS.TDF_ENABLE_HYPERLINKS); } set { if( EnableHyperlinks != value ) { - SetFlag(NativeMethods.TaskDialogFlags.EnableHyperLinks, value); + SetFlag(TASKDIALOG_FLAGS.TDF_ENABLE_HYPERLINKS, value); UpdateDialog(); } } @@ -683,12 +715,12 @@ public bool EnableHyperlinks [Category("Behavior"), Description("Indicates that the dialog should be able to be closed using Alt-F4, Escape and the title bar's close button even if no cancel button is specified."), DefaultValue(false)] public bool AllowDialogCancellation { - get { return GetFlag(NativeMethods.TaskDialogFlags.AllowDialogCancellation); } + get { return GetFlag(TASKDIALOG_FLAGS.TDF_ALLOW_DIALOG_CANCELLATION); } set { if( AllowDialogCancellation != value ) { - SetFlag(NativeMethods.TaskDialogFlags.AllowDialogCancellation, value); + SetFlag(TASKDIALOG_FLAGS.TDF_ALLOW_DIALOG_CANCELLATION, value); UpdateDialog(); } } @@ -706,12 +738,12 @@ public bool AllowDialogCancellation [Category("Behavior"), Description("Indicates that the string specified by the ExpandedInformation property should be displayed at the bottom of the dialog's footer area instead of immediately after the dialog's content."), DefaultValue(false)] public bool ExpandFooterArea { - get { return GetFlag(NativeMethods.TaskDialogFlags.ExpandFooterArea); } + get { return GetFlag(TASKDIALOG_FLAGS.TDF_EXPAND_FOOTER_AREA); } set { if( ExpandFooterArea != value ) { - SetFlag(NativeMethods.TaskDialogFlags.ExpandFooterArea, value); + SetFlag(TASKDIALOG_FLAGS.TDF_EXPAND_FOOTER_AREA, value); UpdateDialog(); } } @@ -729,12 +761,12 @@ public bool ExpandFooterArea [Category("Behavior"), Description("Indicates that the string specified by the ExpandedInformation property should be displayed by default."), DefaultValue(false)] public bool ExpandedByDefault { - get { return GetFlag(NativeMethods.TaskDialogFlags.ExpandedByDefault); } + get { return GetFlag(TASKDIALOG_FLAGS.TDF_EXPANDED_BY_DEFAULT); } set { if( ExpandedByDefault != value ) { - SetFlag(NativeMethods.TaskDialogFlags.ExpandedByDefault, value); + SetFlag(TASKDIALOG_FLAGS.TDF_EXPANDED_BY_DEFAULT, value); UpdateDialog(); } } @@ -754,12 +786,12 @@ public bool ExpandedByDefault [Category("Behavior"), Description("Indicates whether the Timer event is raised periodically while the dialog is visible."), DefaultValue(false)] public bool RaiseTimerEvent { - get { return GetFlag(NativeMethods.TaskDialogFlags.CallbackTimer); } + get { return GetFlag(TASKDIALOG_FLAGS.TDF_CALLBACK_TIMER); } set { if( RaiseTimerEvent != value ) { - SetFlag(NativeMethods.TaskDialogFlags.CallbackTimer, value); + SetFlag(TASKDIALOG_FLAGS.TDF_CALLBACK_TIMER, value); UpdateDialog(); } } @@ -775,12 +807,12 @@ public bool RaiseTimerEvent [Category("Layout"), Description("Indicates whether the dialog is centered in the parent window instead of the screen."), DefaultValue(false)] public bool CenterParent { - get { return GetFlag(NativeMethods.TaskDialogFlags.PositionRelativeToWindow); } + get { return GetFlag(TASKDIALOG_FLAGS.TDF_POSITION_RELATIVE_TO_WINDOW); } set { if( CenterParent != value ) { - SetFlag(NativeMethods.TaskDialogFlags.PositionRelativeToWindow, value); + SetFlag(TASKDIALOG_FLAGS.TDF_POSITION_RELATIVE_TO_WINDOW, value); UpdateDialog(); } } @@ -796,12 +828,12 @@ public bool CenterParent [Localizable(true), Category("Appearance"), Description("Indicates whether text is displayed right to left."), DefaultValue(false)] public bool RightToLeft { - get { return GetFlag(NativeMethods.TaskDialogFlags.RtlLayout); } + get { return GetFlag(TASKDIALOG_FLAGS.TDF_RTL_LAYOUT); } set { if( RightToLeft != value ) { - SetFlag(NativeMethods.TaskDialogFlags.RtlLayout, value); + SetFlag(TASKDIALOG_FLAGS.TDF_RTL_LAYOUT, value); UpdateDialog(); } } @@ -821,12 +853,12 @@ public bool RightToLeft [Category("Window Style"), Description("Indicates whether the dialog has a minimize box on its caption bar."), DefaultValue(false)] public bool MinimizeBox { - get { return GetFlag(NativeMethods.TaskDialogFlags.CanBeMinimized); } + get { return GetFlag(TASKDIALOG_FLAGS.TDF_CAN_BE_MINIMIZED); } set { if( MinimizeBox != value ) { - SetFlag(NativeMethods.TaskDialogFlags.CanBeMinimized, value); + SetFlag(TASKDIALOG_FLAGS.TDF_CAN_BE_MINIMIZED, value); UpdateDialog(); } } @@ -858,17 +890,17 @@ public ProgressBarStyle ProgressBarStyle { get { - if( GetFlag(NativeMethods.TaskDialogFlags.ShowMarqueeProgressBar) ) + if( GetFlag(TASKDIALOG_FLAGS.TDF_SHOW_MARQUEE_PROGRESS_BAR) ) return ProgressBarStyle.MarqueeProgressBar; - else if( GetFlag(NativeMethods.TaskDialogFlags.ShowProgressBar) ) + else if( GetFlag(TASKDIALOG_FLAGS.TDF_SHOW_PROGRESS_BAR) ) return ProgressBarStyle.ProgressBar; else return ProgressBarStyle.None; } set { - SetFlag(NativeMethods.TaskDialogFlags.ShowMarqueeProgressBar, value == ProgressBarStyle.MarqueeProgressBar); - SetFlag(NativeMethods.TaskDialogFlags.ShowProgressBar, value == ProgressBarStyle.ProgressBar); + SetFlag(TASKDIALOG_FLAGS.TDF_SHOW_MARQUEE_PROGRESS_BAR, value == ProgressBarStyle.MarqueeProgressBar); + SetFlag(TASKDIALOG_FLAGS.TDF_SHOW_PROGRESS_BAR, value == ProgressBarStyle.ProgressBar); UpdateProgressBarStyle(); } } @@ -1115,7 +1147,7 @@ public TaskDialogButton ShowDialog(Window owner) /// Task dialogs are not supported on the current operating system. /// Thrown if task dialog is already being displayed. /// Thrown if no buttons are present. - public TaskDialogButton ShowDialog(IntPtr owner) + public unsafe TaskDialogButton ShowDialog(IntPtr owner) { if( !OSSupportsTaskDialogs ) throw new NotSupportedException(Properties.Resources.TaskDialogsNotSupportedError); @@ -1126,42 +1158,44 @@ public TaskDialogButton ShowDialog(IntPtr owner) if (_buttons is null || _buttons.Count == 0) throw new InvalidOperationException(Properties.Resources.TaskDialogNoButtonsError); - _config.hwndParent = owner; + _config.hwndParent = (HWND)owner; _config.dwCommonButtons = 0; - _config.pButtons = IntPtr.Zero; + _config.pButtons = default; _config.cButtons = 0; - List buttons = SetupButtons(); - List radioButtons = SetupRadioButtons(); + List buttons = SetupButtons(); + List radioButtons = SetupRadioButtons(); SetupIcon(); try { - MarshalButtons(buttons, out _config.pButtons, out _config.cButtons); - MarshalButtons(radioButtons, out _config.pRadioButtons, out _config.cRadioButtons); + MarshalButtons(buttons, out var pButtons, out _config.cButtons); + _config.pButtons = (TASKDIALOG_BUTTON*)pButtons; + MarshalButtons(radioButtons, out var pRadioButtons, out _config.cRadioButtons); + _config.pRadioButtons = (TASKDIALOG_BUTTON*)pRadioButtons; int buttonId; int radioButton; - bool verificationFlagChecked; + BOOL verificationFlagChecked; using( new ComCtlv6ActivationContext(true) ) { - NativeMethods.TaskDialogIndirect(ref _config, out buttonId, out radioButton, out verificationFlagChecked); + NativeMethods.TaskDialogIndirect(_config, &buttonId, &radioButton, &verificationFlagChecked); } IsVerificationChecked = verificationFlagChecked; - TaskDialogRadioButton selectedRadioButton; - if( _radioButtonsById.TryGetValue(radioButton, out selectedRadioButton) ) + if (_radioButtonsById.TryGetValue(radioButton, out TaskDialogRadioButton selectedRadioButton)) selectedRadioButton.Checked = true; - TaskDialogButton selectedButton; - if( _buttonsById.TryGetValue(buttonId, out selectedButton) ) + if (_buttonsById.TryGetValue(buttonId, out TaskDialogButton selectedButton)) return selectedButton; else return null; } finally { - CleanUpButtons(ref _config.pButtons, ref _config.cButtons); - CleanUpButtons(ref _config.pRadioButtons, ref _config.cRadioButtons); + var pButtons = (IntPtr)_config.pButtons; + var pRadioButtons = (IntPtr)_config.pRadioButtons; + CleanUpButtons(ref pButtons, ref _config.cButtons); + CleanUpButtons(ref pRadioButtons, ref _config.cRadioButtons); } } @@ -1176,7 +1210,7 @@ public void ClickVerification(bool checkState, bool setFocus) if( !IsDialogRunning ) throw new InvalidOperationException(Properties.Resources.TaskDialogNotRunningError); - NativeMethods.SendMessage(Handle, (int)NativeMethods.TaskDialogMessages.ClickVerification, new IntPtr(checkState ? 1 : 0), new IntPtr(setFocus ? 1 : 0)); + NativeMethods.SendMessage((HWND)Handle, (int)TASKDIALOG_MESSAGES.TDM_CLICK_VERIFICATION, (nuint)(checkState ? 1 : 0), new IntPtr(setFocus ? 1 : 0)); } #endregion @@ -1281,7 +1315,7 @@ internal void SetItemEnabled(TaskDialogItem item) { if( IsDialogRunning ) { - NativeMethods.SendMessage(Handle, (int)(item is TaskDialogButton ? NativeMethods.TaskDialogMessages.EnableButton : NativeMethods.TaskDialogMessages.EnableRadioButton), new IntPtr(item.Id), new IntPtr(item.Enabled ? 1 : 0)); + NativeMethods.SendMessage((HWND)Handle, item is TaskDialogButton ? (uint)TASKDIALOG_MESSAGES.TDM_ENABLE_BUTTON : (uint)TASKDIALOG_MESSAGES.TDM_ENABLE_RADIO_BUTTON, (nuint)item.Id, (nint)(item.Enabled ? 1 : 0)); } } @@ -1289,7 +1323,7 @@ internal void SetButtonElevationRequired(TaskDialogButton button) { if( IsDialogRunning ) { - NativeMethods.SendMessage(Handle, (int)NativeMethods.TaskDialogMessages.SetButtonElevationRequiredState, new IntPtr(button.Id), new IntPtr(button.ElevationRequired ? 1 : 0)); + NativeMethods.SendMessage((HWND)Handle, (int)TASKDIALOG_MESSAGES.TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, (nuint)button.Id, new IntPtr(button.ElevationRequired ? 1 : 0)); } } @@ -1298,14 +1332,14 @@ internal void ClickItem(TaskDialogItem item) if( !IsDialogRunning ) throw new InvalidOperationException(Properties.Resources.TaskDialogNotRunningError); - NativeMethods.SendMessage(Handle, (int)(item is TaskDialogButton ? NativeMethods.TaskDialogMessages.ClickButton : NativeMethods.TaskDialogMessages.ClickRadioButton), new IntPtr(item.Id), IntPtr.Zero); + NativeMethods.SendMessage((HWND)Handle, (uint)(item is TaskDialogButton ? TASKDIALOG_MESSAGES.TDM_CLICK_BUTTON : TASKDIALOG_MESSAGES.TDM_CLICK_RADIO_BUTTON), (nuint)item.Id, IntPtr.Zero); } #endregion #region Private members - internal void UpdateDialog() + internal unsafe void UpdateDialog() { if( IsDialogRunning ) { @@ -1318,28 +1352,32 @@ internal void UpdateDialog() else { _updatePending = false; - CleanUpButtons(ref _config.pButtons, ref _config.cButtons); - CleanUpButtons(ref _config.pRadioButtons, ref _config.cRadioButtons); + var pButtons = (IntPtr)_config.pButtons; + var pRadioButtons = (IntPtr)_config.pRadioButtons; + CleanUpButtons(ref pButtons, ref _config.cButtons); + CleanUpButtons(ref pRadioButtons, ref _config.cRadioButtons); _config.dwCommonButtons = 0; - List buttons = SetupButtons(); - List radioButtons = SetupRadioButtons(); + List buttons = SetupButtons(); + List radioButtons = SetupRadioButtons(); SetupIcon(); - MarshalButtons(buttons, out _config.pButtons, out _config.cButtons); - MarshalButtons(radioButtons, out _config.pRadioButtons, out _config.cRadioButtons); + MarshalButtons(buttons, out pButtons, out _config.cButtons); + _config.pButtons = (TASKDIALOG_BUTTON*)pButtons; + MarshalButtons(radioButtons, out pRadioButtons, out _config.cRadioButtons); + _config.pRadioButtons = (TASKDIALOG_BUTTON*)pRadioButtons; int size = Marshal.SizeOf(_config); IntPtr memory = Marshal.AllocHGlobal(size); try { Marshal.StructureToPtr(_config, memory, false); - NativeMethods.SendMessage(Handle, (int)NativeMethods.TaskDialogMessages.NavigatePage, IntPtr.Zero, memory); + NativeMethods.SendMessage((HWND)Handle, (int)TASKDIALOG_MESSAGES.TDM_NAVIGATE_PAGE, 0, memory); } finally { - Marshal.DestroyStructure(memory, typeof(NativeMethods.TASKDIALOGCONFIG)); + Marshal.DestroyStructure(memory, typeof(TASKDIALOGCONFIG)); Marshal.FreeHGlobal(memory); } } @@ -1355,14 +1393,14 @@ private bool IsDialogRunning } } - private void SetElementText(NativeMethods.TaskDialogElements element, string text) + private void SetElementText(TASKDIALOG_ELEMENTS element, string text) { if( IsDialogRunning ) { IntPtr newTextPtr = Marshal.StringToHGlobalUni(text); try { - IntPtr result = NativeMethods.SendMessage(Handle, (int)NativeMethods.TaskDialogMessages.SetElementText, new IntPtr((int)element), newTextPtr); + IntPtr result = NativeMethods.SendMessage((HWND)Handle, (int)TASKDIALOG_MESSAGES.TDM_SET_ELEMENT_TEXT, (nuint)element, newTextPtr); } finally { @@ -1374,11 +1412,11 @@ private void SetElementText(NativeMethods.TaskDialogElements element, string tex private void SetupIcon() { - SetupIcon(MainIcon, CustomMainIcon, NativeMethods.TaskDialogFlags.UseHIconMain); - SetupIcon(FooterIcon, CustomFooterIcon, NativeMethods.TaskDialogFlags.UseHIconFooter); + SetupIcon(MainIcon, CustomMainIcon, TASKDIALOG_FLAGS.TDF_USE_HICON_MAIN); + SetupIcon(FooterIcon, CustomFooterIcon, TASKDIALOG_FLAGS.TDF_USE_HICON_FOOTER); } - private void SetupIcon(TaskDialogIcon icon, System.Drawing.Icon customIcon, NativeMethods.TaskDialogFlags flag) + private void SetupIcon(TaskDialogIcon icon, System.Drawing.Icon customIcon, TASKDIALOG_FLAGS flag) { SetFlag(flag, false); if( icon == TaskDialogIcon.Custom ) @@ -1386,18 +1424,18 @@ private void SetupIcon(TaskDialogIcon icon, System.Drawing.Icon customIcon, Nati if( customIcon != null ) { SetFlag(flag, true); - if( flag == NativeMethods.TaskDialogFlags.UseHIconMain ) - _config.hMainIcon = customIcon.Handle; + if( flag == TASKDIALOG_FLAGS.TDF_USE_HICON_MAIN ) + _config.Anonymous1.hMainIcon = (HICON)customIcon.Handle; else - _config.hFooterIcon = customIcon.Handle; + _config.Anonymous2.hFooterIcon = (HICON)customIcon.Handle; } } else { - if( flag == NativeMethods.TaskDialogFlags.UseHIconMain ) - _config.hMainIcon = new IntPtr((int)icon); + if( flag == TASKDIALOG_FLAGS.TDF_USE_HICON_MAIN ) + _config.Anonymous1.hMainIcon = (HICON)new IntPtr((int)icon); else - _config.hFooterIcon = new IntPtr((int)icon); + _config.Anonymous2.hFooterIcon = (HICON)new IntPtr((int)icon); } } @@ -1405,13 +1443,13 @@ private static void CleanUpButtons(ref IntPtr buttons, ref uint count) { if( buttons != IntPtr.Zero ) { - int elementSize = Marshal.SizeOf(typeof(NativeMethods.TASKDIALOG_BUTTON)); + int elementSize = Marshal.SizeOf(typeof(TASKDIALOG_BUTTON)); for( int x = 0; x < count; ++x ) { // This'll be safe until they introduce 128 bit machines. :) // It's the only way to do it without unsafe code. IntPtr offset = new IntPtr(buttons.ToInt64() + x * elementSize); - Marshal.DestroyStructure(offset, typeof(NativeMethods.TASKDIALOG_BUTTON)); + Marshal.DestroyStructure(offset, typeof(TASKDIALOG_BUTTON)); } Marshal.FreeHGlobal(buttons); buttons = IntPtr.Zero; @@ -1419,13 +1457,13 @@ private static void CleanUpButtons(ref IntPtr buttons, ref uint count) } } - private static void MarshalButtons(List buttons, out IntPtr buttonsPtr, out uint count) + private static void MarshalButtons(List buttons, out IntPtr buttonsPtr, out uint count) { buttonsPtr = IntPtr.Zero; count = 0; if( buttons.Count > 0 ) { - int elementSize = Marshal.SizeOf(typeof(NativeMethods.TASKDIALOG_BUTTON)); + int elementSize = Marshal.SizeOf(typeof(TASKDIALOG_BUTTON)); buttonsPtr = Marshal.AllocHGlobal(elementSize * buttons.Count); for( int x = 0; x < buttons.Count; ++x ) { @@ -1438,10 +1476,10 @@ private static void MarshalButtons(List buttons } } - private List SetupButtons() + private unsafe List SetupButtons() { _buttonsById = new Dictionary(); - List buttons = new List(); + List buttons = new List(); _config.nDefaultButton = 0; foreach( TaskDialogButton button in Buttons ) { @@ -1454,11 +1492,20 @@ private static void MarshalButtons(List buttons { if( string.IsNullOrEmpty(button.Text) ) throw new InvalidOperationException(Properties.Resources.TaskDialogEmptyButtonLabelError); - NativeMethods.TASKDIALOG_BUTTON taskDialogButton = new NativeMethods.TASKDIALOG_BUTTON(); - taskDialogButton.nButtonID = button.Id; - taskDialogButton.pszButtonText = button.Text; - if( ButtonStyle == TaskDialogButtonStyle.CommandLinks || ButtonStyle == TaskDialogButtonStyle.CommandLinksNoIcon && !string.IsNullOrEmpty(button.CommandLinkNote) ) - taskDialogButton.pszButtonText += "\n" + button.CommandLinkNote; + + TASKDIALOG_BUTTON taskDialogButton; + var text = button.Text; + if (ButtonStyle == TaskDialogButtonStyle.CommandLinks || ButtonStyle == TaskDialogButtonStyle.CommandLinksNoIcon && !string.IsNullOrEmpty(button.CommandLinkNote)) + text += "\n" + button.CommandLinkNote; + + fixed (char* pText = text) + { + taskDialogButton = new TASKDIALOG_BUTTON + { + nButtonID = button.Id, + pszButtonText = pText + }; + } buttons.Add(taskDialogButton); } else @@ -1469,10 +1516,10 @@ private static void MarshalButtons(List buttons return buttons; } - private List SetupRadioButtons() + private unsafe List SetupRadioButtons() { _radioButtonsById = new Dictionary(); - List radioButtons = new List(); + List radioButtons = new List(); _config.nDefaultRadioButton = 0; foreach( TaskDialogRadioButton radioButton in RadioButtons ) { @@ -1483,16 +1530,19 @@ private static void MarshalButtons(List buttons _radioButtonsById.Add(radioButton.Id, radioButton); if( radioButton.Checked ) _config.nDefaultRadioButton = radioButton.Id; - NativeMethods.TASKDIALOG_BUTTON taskDialogButton = new NativeMethods.TASKDIALOG_BUTTON(); + TASKDIALOG_BUTTON taskDialogButton = new TASKDIALOG_BUTTON(); taskDialogButton.nButtonID = radioButton.Id; - taskDialogButton.pszButtonText = radioButton.Text; + fixed (char* pText = radioButton.Text) + { + taskDialogButton.pszButtonText = pText; + } radioButtons.Add(taskDialogButton); } - SetFlag(NativeMethods.TaskDialogFlags.NoDefaultRadioButton, _config.nDefaultRadioButton == 0); + SetFlag(TASKDIALOG_FLAGS.TDF_NO_DEFAULT_RADIO_BUTTON, _config.nDefaultRadioButton == 0); return radioButtons; } - private void SetFlag(NativeMethods.TaskDialogFlags flag, bool value) + private void SetFlag(TASKDIALOG_FLAGS flag, bool value) { if( value ) _config.dwFlags |= flag; @@ -1500,69 +1550,69 @@ private void SetFlag(NativeMethods.TaskDialogFlags flag, bool value) _config.dwFlags &= ~flag; } - private bool GetFlag(NativeMethods.TaskDialogFlags flag) + private bool GetFlag(TASKDIALOG_FLAGS flag) { return (_config.dwFlags & flag) != 0; } - private uint TaskDialogCallback(IntPtr hwnd, uint uNotification, IntPtr wParam, IntPtr lParam, IntPtr dwRefData) + private HRESULT TaskDialogCallback(HWND hwnd, uint uNotification, WPARAM wParam, LPARAM lParam, nint dwRefData) { Interlocked.Increment(ref _inEventHandler); try { - switch( (NativeMethods.TaskDialogNotifications)uNotification ) + switch( (TASKDIALOG_NOTIFICATIONS)uNotification ) { - case NativeMethods.TaskDialogNotifications.Created: + case TASKDIALOG_NOTIFICATIONS.TDN_CREATED: _handle = hwnd; DialogCreated(); OnCreated(EventArgs.Empty); break; - case NativeMethods.TaskDialogNotifications.Destroyed: + case TASKDIALOG_NOTIFICATIONS.TDN_DESTROYED: _handle = IntPtr.Zero; OnDestroyed(EventArgs.Empty); break; - case NativeMethods.TaskDialogNotifications.Navigated: + case TASKDIALOG_NOTIFICATIONS.TDN_NAVIGATED: DialogCreated(); break; - case NativeMethods.TaskDialogNotifications.HyperlinkClicked: + case TASKDIALOG_NOTIFICATIONS.TDN_HYPERLINK_CLICKED: string url = Marshal.PtrToStringUni(lParam); OnHyperlinkClicked(new HyperlinkClickedEventArgs(url)); break; - case NativeMethods.TaskDialogNotifications.ButtonClicked: + case TASKDIALOG_NOTIFICATIONS.TDN_BUTTON_CLICKED: TaskDialogButton button; - if( _buttonsById.TryGetValue((int)wParam, out button) ) + if( _buttonsById.TryGetValue((int)(nuint)wParam, out button) ) { TaskDialogItemClickedEventArgs e = new TaskDialogItemClickedEventArgs(button); OnButtonClicked(e); if( e.Cancel ) - return 1; + return HRESULT.S_FALSE; } break; - case NativeMethods.TaskDialogNotifications.VerificationClicked: - IsVerificationChecked = ((int)wParam) == 1; + case TASKDIALOG_NOTIFICATIONS.TDN_VERIFICATION_CLICKED: + IsVerificationChecked = ((int)(nuint)wParam) == 1; OnVerificationClicked(EventArgs.Empty); break; - case NativeMethods.TaskDialogNotifications.RadioButtonClicked: + case TASKDIALOG_NOTIFICATIONS.TDN_RADIO_BUTTON_CLICKED: TaskDialogRadioButton radioButton; - if( _radioButtonsById.TryGetValue((int)wParam, out radioButton) ) + if( _radioButtonsById.TryGetValue((int)(nuint)wParam, out radioButton) ) { radioButton.Checked = true; // there's no way to click a radio button without checking it, is there? TaskDialogItemClickedEventArgs e = new TaskDialogItemClickedEventArgs(radioButton); OnRadioButtonClicked(e); } break; - case NativeMethods.TaskDialogNotifications.Timer: - TimerEventArgs timerEventArgs = new TimerEventArgs(wParam.ToInt32()); + case TASKDIALOG_NOTIFICATIONS.TDN_TIMER: + TimerEventArgs timerEventArgs = new TimerEventArgs((int)(nuint)wParam); OnTimer(timerEventArgs); - return (uint)(timerEventArgs.ResetTickCount ? 1 : 0); - case NativeMethods.TaskDialogNotifications.ExpandoButtonClicked: - OnExpandButtonClicked(new ExpandButtonClickedEventArgs(wParam.ToInt32() != 0)); + return timerEventArgs.ResetTickCount ? HRESULT.S_FALSE : HRESULT.S_OK; + case TASKDIALOG_NOTIFICATIONS.TDN_EXPANDO_BUTTON_CLICKED: + OnExpandButtonClicked(new ExpandButtonClickedEventArgs((int)(nuint)wParam != 0)); break; - case NativeMethods.TaskDialogNotifications.Help: + case TASKDIALOG_NOTIFICATIONS.TDN_HELP: OnHelpRequested(EventArgs.Empty); break; } - return 0; + return HRESULT.S_OK; } finally { @@ -1576,7 +1626,7 @@ private void DialogCreated() { if( _config.hwndParent == IntPtr.Zero && _windowIcon != null ) { - NativeMethods.SendMessage(Handle, NativeMethods.WM_SETICON, new IntPtr(NativeMethods.ICON_SMALL), _windowIcon.Handle); + NativeMethods.SendMessage((HWND)Handle, NativeMethods.WM_SETICON, (nuint)NativeMethods.ICON_SMALL, _windowIcon.Handle); } foreach( TaskDialogButton button in Buttons ) @@ -1597,7 +1647,7 @@ private void UpdateProgressBarStyle() { if( IsDialogRunning ) { - NativeMethods.SendMessage(Handle, (int)NativeMethods.TaskDialogMessages.SetMarqueeProgressBar, new IntPtr(ProgressBarStyle == ProgressBarStyle.MarqueeProgressBar ? 1 : 0), IntPtr.Zero); + NativeMethods.SendMessage((HWND)Handle, (int)TASKDIALOG_MESSAGES.TDM_SET_MARQUEE_PROGRESS_BAR, (nuint)(ProgressBarStyle == ProgressBarStyle.MarqueeProgressBar ? 1 : 0), IntPtr.Zero); } } @@ -1605,7 +1655,7 @@ private void UpdateProgressBarMarqueeSpeed() { if( IsDialogRunning ) { - NativeMethods.SendMessage(Handle, (int)NativeMethods.TaskDialogMessages.SetProgressBarMarquee, new IntPtr(ProgressBarMarqueeAnimationSpeed > 0 ? 1 : 0), new IntPtr(ProgressBarMarqueeAnimationSpeed)); + NativeMethods.SendMessage((HWND)Handle, (int)TASKDIALOG_MESSAGES.TDM_SET_PROGRESS_BAR_MARQUEE, (nuint)(ProgressBarMarqueeAnimationSpeed > 0 ? 1 : 0), (nint)ProgressBarMarqueeAnimationSpeed); } } @@ -1613,7 +1663,7 @@ private void UpdateProgressBarRange() { if( IsDialogRunning ) { - NativeMethods.SendMessage(Handle, (int)NativeMethods.TaskDialogMessages.SetProgressBarRange, IntPtr.Zero, new IntPtr(ProgressBarMaximum << 16 | ProgressBarMinimum)); + NativeMethods.SendMessage((HWND)Handle, (int)TASKDIALOG_MESSAGES.TDM_SET_PROGRESS_BAR_RANGE, 0, new IntPtr(ProgressBarMaximum << 16 | ProgressBarMinimum)); } if( ProgressBarValue < ProgressBarMinimum ) ProgressBarValue = ProgressBarMinimum; @@ -1625,7 +1675,7 @@ private void UpdateProgressBarValue() { if( IsDialogRunning ) { - NativeMethods.SendMessage(Handle, (int)NativeMethods.TaskDialogMessages.SetProgressBarPos, new IntPtr(ProgressBarValue), IntPtr.Zero); + NativeMethods.SendMessage((HWND)Handle, (int)TASKDIALOG_MESSAGES.TDM_SET_PROGRESS_BAR_POS, (nuint)ProgressBarValue, IntPtr.Zero); } } @@ -1633,19 +1683,19 @@ private void UpdateProgressBarState() { if( IsDialogRunning ) { - NativeMethods.SendMessage(Handle, (int)NativeMethods.TaskDialogMessages.SetProgressBarState, new IntPtr((int)ProgressBarState + 1), IntPtr.Zero); + NativeMethods.SendMessage((HWND)Handle, (int)TASKDIALOG_MESSAGES.TDM_SET_PROGRESS_BAR_STATE, (nuint)ProgressBarState + 1, IntPtr.Zero); } } - private void CheckCrossThreadCall() + private unsafe void CheckCrossThreadCall() { IntPtr handle = _handle; if( handle != IntPtr.Zero ) { - int processId; - int windowThreadId = NativeMethods.GetWindowThreadProcessId(handle, out processId); - int threadId = NativeMethods.GetCurrentThreadId(); - if( windowThreadId != threadId ) + uint processId; + var windowThreadId = NativeMethods.GetWindowThreadProcessId((HWND)handle, &processId); + var threadId = NativeMethods.GetCurrentThreadId(); + if (windowThreadId != threadId) throw new InvalidOperationException(Properties.Resources.TaskDialogIllegalCrossThreadCallError); } } diff --git a/src/Ookii.Dialogs.Wpf/TaskDialogButton.cs b/src/Ookii.Dialogs.Wpf/TaskDialogButton.cs index 3949782..44a65a3 100644 --- a/src/Ookii.Dialogs.Wpf/TaskDialogButton.cs +++ b/src/Ookii.Dialogs.Wpf/TaskDialogButton.cs @@ -206,24 +206,24 @@ internal override void CheckDuplicate(TaskDialogItem itemToExclude) base.CheckDuplicate(itemToExclude); } - internal NativeMethods.TaskDialogCommonButtonFlags ButtonFlag + internal TASKDIALOG_COMMON_BUTTON_FLAGS ButtonFlag { get { switch( _type ) { case ButtonType.Ok: - return NativeMethods.TaskDialogCommonButtonFlags.OkButton; + return TASKDIALOG_COMMON_BUTTON_FLAGS.TDCBF_OK_BUTTON; case ButtonType.Yes: - return NativeMethods.TaskDialogCommonButtonFlags.YesButton; + return TASKDIALOG_COMMON_BUTTON_FLAGS.TDCBF_YES_BUTTON; case ButtonType.No: - return NativeMethods.TaskDialogCommonButtonFlags.NoButton; + return TASKDIALOG_COMMON_BUTTON_FLAGS.TDCBF_NO_BUTTON; case ButtonType.Cancel: - return NativeMethods.TaskDialogCommonButtonFlags.CancelButton; + return TASKDIALOG_COMMON_BUTTON_FLAGS.TDCBF_CANCEL_BUTTON; case ButtonType.Retry: - return NativeMethods.TaskDialogCommonButtonFlags.RetryButton; + return TASKDIALOG_COMMON_BUTTON_FLAGS.TDCBF_RETRY_BUTTON; case ButtonType.Close: - return NativeMethods.TaskDialogCommonButtonFlags.CloseButton; + return TASKDIALOG_COMMON_BUTTON_FLAGS.TDCBF_CLOSE_BUTTON; default: return 0; } diff --git a/src/Ookii.Dialogs.Wpf/VistaFileDialog.cs b/src/Ookii.Dialogs.Wpf/VistaFileDialog.cs index d72a137..6fef7e0 100644 --- a/src/Ookii.Dialogs.Wpf/VistaFileDialog.cs +++ b/src/Ookii.Dialogs.Wpf/VistaFileDialog.cs @@ -54,7 +54,7 @@ public abstract class VistaFileDialog internal const int HelpButtonId = 0x4001; private FileDialog _downlevelDialog; - private NativeMethods.FOS _options; + private FILEOPENDIALOGOPTIONS _options; private string _filter; private int _filterIndex ; private string[] _fileNames; @@ -144,14 +144,14 @@ public virtual bool CheckFileExists { if( DownlevelDialog != null ) return DownlevelDialog.CheckFileExists; - return GetOption(NativeMethods.FOS.FOS_FILEMUSTEXIST); + return GetOption(FILEOPENDIALOGOPTIONS.FOS_FILEMUSTEXIST); } set { if( DownlevelDialog != null ) DownlevelDialog.CheckFileExists = value; else - SetOption(NativeMethods.FOS.FOS_FILEMUSTEXIST, value); + SetOption(FILEOPENDIALOGOPTIONS.FOS_FILEMUSTEXIST, value); } } @@ -169,14 +169,14 @@ public bool CheckPathExists { if( DownlevelDialog != null ) return DownlevelDialog.CheckPathExists; - return GetOption(NativeMethods.FOS.FOS_PATHMUSTEXIST); + return GetOption(FILEOPENDIALOGOPTIONS.FOS_PATHMUSTEXIST); } set { if( DownlevelDialog != null ) DownlevelDialog.CheckPathExists = value; else - SetOption(NativeMethods.FOS.FOS_PATHMUSTEXIST, value); + SetOption(FILEOPENDIALOGOPTIONS.FOS_PATHMUSTEXIST, value); } } @@ -229,14 +229,14 @@ public bool DereferenceLinks { if( DownlevelDialog != null ) return DownlevelDialog.DereferenceLinks; - return !GetOption(NativeMethods.FOS.FOS_NODEREFERENCELINKS); + return !GetOption(FILEOPENDIALOGOPTIONS.FOS_NODEREFERENCELINKS); } set { if( DownlevelDialog != null ) DownlevelDialog.DereferenceLinks = value; else - SetOption(NativeMethods.FOS.FOS_NODEREFERENCELINKS, !value); + SetOption(FILEOPENDIALOGOPTIONS.FOS_NODEREFERENCELINKS, !value); } } @@ -393,14 +393,14 @@ public bool RestoreDirectory { if( DownlevelDialog != null ) return DownlevelDialog.RestoreDirectory; - return GetOption(NativeMethods.FOS.FOS_NOCHANGEDIR); + return GetOption(FILEOPENDIALOGOPTIONS.FOS_NOCHANGEDIR); } set { if( DownlevelDialog != null ) DownlevelDialog.RestoreDirectory = value; else - SetOption(NativeMethods.FOS.FOS_NOCHANGEDIR, value); + SetOption(FILEOPENDIALOGOPTIONS.FOS_NOCHANGEDIR, value); } } @@ -445,14 +445,14 @@ public bool ValidateNames { if( DownlevelDialog != null ) return DownlevelDialog.ValidateNames; - return !GetOption(NativeMethods.FOS.FOS_NOVALIDATE); + return !GetOption(FILEOPENDIALOGOPTIONS.FOS_NOVALIDATE); } set { if( DownlevelDialog != null ) DownlevelDialog.ValidateNames = value; else - SetOption(NativeMethods.FOS.FOS_NOVALIDATE, !value); + SetOption(FILEOPENDIALOGOPTIONS.FOS_NOVALIDATE, !value); } } @@ -575,7 +575,7 @@ public virtual void Reset() #region Protected Methods - internal void SetOption(NativeMethods.FOS option, bool value) + internal void SetOption(FILEOPENDIALOGOPTIONS option, bool value) { if( value ) _options |= option; @@ -583,19 +583,19 @@ internal void SetOption(NativeMethods.FOS option, bool value) _options &= ~option; } - internal bool GetOption(NativeMethods.FOS option) + internal bool GetOption(FILEOPENDIALOGOPTIONS option) { return (_options & option) != 0; } - internal virtual void GetResult(Ookii.Dialogs.Wpf.Interop.IFileDialog dialog) + internal virtual void GetResult(IFileDialog dialog) { - if( !GetOption(NativeMethods.FOS.FOS_ALLOWMULTISELECT) ) + if( !GetOption(FILEOPENDIALOGOPTIONS.FOS_ALLOWMULTISELECT) ) { _fileNames = new string[1]; - Ookii.Dialogs.Wpf.Interop.IShellItem result; - dialog.GetResult(out result); - result.GetDisplayName(NativeMethods.SIGDN.SIGDN_FILESYSPATH, out _fileNames[0]); + dialog.GetResult(out var result); + result.GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out var str); + _fileNames[0] = str.ToString(); } } @@ -625,13 +625,12 @@ internal bool PromptUser(string text, MessageBoxButton buttons, MessageBoxImage return MessageBox.Show(_owner, text, caption, buttons, icon, defaultResult, options) == MessageBoxResult.Yes; } - internal virtual void SetDialogProperties(Ookii.Dialogs.Wpf.Interop.IFileDialog dialog) + internal unsafe virtual void SetDialogProperties(IFileDialog dialog) { - uint cookie; - dialog.Advise(new VistaFileDialogEvents(this), out cookie); + dialog.Advise(new VistaFileDialogEvents(this), out uint cookie); // Set the default file name - if( !(_fileNames == null || _fileNames.Length == 0 || string.IsNullOrEmpty(_fileNames[0])) ) + if ( !(_fileNames == null || _fileNames.Length == 0 || string.IsNullOrEmpty(_fileNames[0])) ) { string parent = Path.GetDirectoryName(_fileNames[0]); if( parent == null || !Directory.Exists(parent) ) @@ -645,18 +644,23 @@ internal virtual void SetDialogProperties(Ookii.Dialogs.Wpf.Interop.IFileDialog dialog.SetFileName(folder); } } - + // Set the filter - if( !string.IsNullOrEmpty(_filter) ) + if ( !string.IsNullOrEmpty(_filter) ) { string[] filterElements = _filter.Split(new char[] { '|' }); - NativeMethods.COMDLG_FILTERSPEC[] filter = new NativeMethods.COMDLG_FILTERSPEC[filterElements.Length / 2]; - for( int x = 0; x < filterElements.Length; x += 2 ) + COMDLG_FILTERSPEC[] filter = new COMDLG_FILTERSPEC[filterElements.Length / 2]; + for (int x = 0; x < filterElements.Length; x += 2) { - filter[x / 2].pszName = filterElements[x]; - filter[x / 2].pszSpec = filterElements[x + 1]; + fixed (char* pszName = filterElements[x]) + fixed (char* pszSpec = filterElements[x+1]) + { + filter[x / 2].pszName = pszName; + filter[x / 2].pszSpec = pszSpec; + } } - dialog.SetFileTypes((uint)filter.Length, filter); + fixed (COMDLG_FILTERSPEC* pfilter = filter) + dialog.SetFileTypes((uint)filter.Length, pfilter); if( _filterIndex > 0 && _filterIndex <= filter.Length ) dialog.SetFileTypeIndex((uint)_filterIndex); @@ -671,7 +675,7 @@ internal virtual void SetDialogProperties(Ookii.Dialogs.Wpf.Interop.IFileDialog // Initial directory if( !string.IsNullOrEmpty(_initialDirectory) ) { - Ookii.Dialogs.Wpf.Interop.IShellItem item = NativeMethods.CreateItemFromParsingName(_initialDirectory); + IShellItem item = NativeMethods.CreateItemFromParsingName(_initialDirectory); dialog.SetDefaultFolder(item); } @@ -680,12 +684,12 @@ internal virtual void SetDialogProperties(Ookii.Dialogs.Wpf.Interop.IFileDialog dialog.SetTitle(_title); } - dialog.SetOptions((_options | NativeMethods.FOS.FOS_FORCEFILESYSTEM)); + dialog.SetOptions(_options | FILEOPENDIALOGOPTIONS.FOS_FORCEFILESYSTEM); } - internal abstract Ookii.Dialogs.Wpf.Interop.IFileDialog CreateFileDialog(); + internal abstract IFileDialog CreateFileDialog(); - internal bool DoFileOk(Ookii.Dialogs.Wpf.Interop.IFileDialog dialog) + internal bool DoFileOk(IFileDialog dialog) { GetResult(dialog); @@ -700,15 +704,15 @@ internal bool DoFileOk(Ookii.Dialogs.Wpf.Interop.IFileDialog dialog) private bool RunFileDialog(IntPtr hwndOwner) { - Ookii.Dialogs.Wpf.Interop.IFileDialog dialog = null; + IFileDialog dialog = null; try { dialog = CreateFileDialog(); SetDialogProperties(dialog); - int result = dialog.Show(hwndOwner); + var result = dialog.Show((HWND)hwndOwner); if( result < 0 ) { - if( (uint)result == (uint)HRESULT.ERROR_CANCELLED ) + if( (uint)result == (uint)NativeMethods.HRESULT_FROM_WIN32(WIN32_ERROR.ERROR_CANCELLED) ) return false; else throw System.Runtime.InteropServices.Marshal.GetExceptionForHR(result); diff --git a/src/Ookii.Dialogs.Wpf/VistaFileDialogEvents.cs b/src/Ookii.Dialogs.Wpf/VistaFileDialogEvents.cs index aed5e57..dbc30ab 100644 --- a/src/Ookii.Dialogs.Wpf/VistaFileDialogEvents.cs +++ b/src/Ookii.Dialogs.Wpf/VistaFileDialogEvents.cs @@ -15,86 +15,72 @@ #endregion using System; -using System.Collections.Generic; -using System.Text; namespace Ookii.Dialogs.Wpf { - class VistaFileDialogEvents : Ookii.Dialogs.Wpf.Interop.IFileDialogEvents, Ookii.Dialogs.Wpf.Interop.IFileDialogControlEvents + class VistaFileDialogEvents : IFileDialogEvents, IFileDialogControlEvents { - const uint S_OK = 0; - const uint S_FALSE = 1; - const uint E_NOTIMPL = 0x80004001; - private VistaFileDialog _dialog; public VistaFileDialogEvents(VistaFileDialog dialog) { - if( dialog == null ) - throw new ArgumentNullException("dialog"); - - _dialog = dialog; + _dialog = dialog ?? throw new ArgumentNullException("dialog"); } #region IFileDialogEvents Members - public Ookii.Dialogs.Wpf.Interop.HRESULT OnFileOk(Ookii.Dialogs.Wpf.Interop.IFileDialog pfd) + HRESULT IFileDialogEvents.OnFileOk(IFileDialog pfd) { - if( _dialog.DoFileOk(pfd) ) - return Ookii.Dialogs.Wpf.Interop.HRESULT.S_OK; + if (_dialog.DoFileOk(pfd)) + return HRESULT.S_OK; else - return Ookii.Dialogs.Wpf.Interop.HRESULT.S_FALSE; + return HRESULT.S_FALSE; } - public Ookii.Dialogs.Wpf.Interop.HRESULT OnFolderChanging(Ookii.Dialogs.Wpf.Interop.IFileDialog pfd, Ookii.Dialogs.Wpf.Interop.IShellItem psiFolder) - { - return Ookii.Dialogs.Wpf.Interop.HRESULT.S_OK; - } + HRESULT IFileDialogEvents.OnFolderChanging(IFileDialog pfd, IShellItem psiFolder) => HRESULT.S_OK; - public void OnFolderChange(Ookii.Dialogs.Wpf.Interop.IFileDialog pfd) + public void OnFolderChange(IFileDialog pfd) { } - public void OnSelectionChange(Ookii.Dialogs.Wpf.Interop.IFileDialog pfd) + public void OnSelectionChange(IFileDialog pfd) { } - public void OnShareViolation(Ookii.Dialogs.Wpf.Interop.IFileDialog pfd, Ookii.Dialogs.Wpf.Interop.IShellItem psi, out NativeMethods.FDE_SHAREVIOLATION_RESPONSE pResponse) + public unsafe void OnShareViolation(IFileDialog pfd, IShellItem psi, FDE_SHAREVIOLATION_RESPONSE* pResponse) { - pResponse = NativeMethods.FDE_SHAREVIOLATION_RESPONSE.FDESVR_DEFAULT; + *pResponse = FDE_SHAREVIOLATION_RESPONSE.FDESVR_DEFAULT; } - public void OnTypeChange(Ookii.Dialogs.Wpf.Interop.IFileDialog pfd) + public void OnTypeChange(IFileDialog pfd) { } - public void OnOverwrite(Ookii.Dialogs.Wpf.Interop.IFileDialog pfd, Ookii.Dialogs.Wpf.Interop.IShellItem psi, out NativeMethods.FDE_OVERWRITE_RESPONSE pResponse) + public unsafe void OnOverwrite(IFileDialog pfd, IShellItem psi, FDE_OVERWRITE_RESPONSE* pResponse) { - pResponse = NativeMethods.FDE_OVERWRITE_RESPONSE.FDEOR_DEFAULT; + *pResponse = FDE_OVERWRITE_RESPONSE.FDEOR_DEFAULT; } #endregion #region IFileDialogControlEvents Members - public void OnItemSelected(Ookii.Dialogs.Wpf.Interop.IFileDialogCustomize pfdc, int dwIDCtl, int dwIDItem) + public void OnItemSelected(IFileDialogCustomize pfdc, uint dwIDCtl, uint dwIDItem) { } - public void OnButtonClicked(Ookii.Dialogs.Wpf.Interop.IFileDialogCustomize pfdc, int dwIDCtl) + public void OnButtonClicked(IFileDialogCustomize pfdc, uint dwIDCtl) { } - public void OnCheckButtonToggled(Ookii.Dialogs.Wpf.Interop.IFileDialogCustomize pfdc, int dwIDCtl, bool bChecked) + public void OnCheckButtonToggled(IFileDialogCustomize pfdc, uint dwIDCtl, BOOL bChecked) { } - public void OnControlActivating(Ookii.Dialogs.Wpf.Interop.IFileDialogCustomize pfdc, int dwIDCtl) + public void OnControlActivating(IFileDialogCustomize pfdc, uint dwIDCtl) { } #endregion - - } } diff --git a/src/Ookii.Dialogs.Wpf/VistaFolderBrowserDialog.cs b/src/Ookii.Dialogs.Wpf/VistaFolderBrowserDialog.cs index 314f3a8..886d29f 100644 --- a/src/Ookii.Dialogs.Wpf/VistaFolderBrowserDialog.cs +++ b/src/Ookii.Dialogs.Wpf/VistaFolderBrowserDialog.cs @@ -41,7 +41,7 @@ public sealed class VistaFolderBrowserDialog { private string _description; private string _selectedPath; - private NativeMethods.FOS _options; + private FILEOPENDIALOGOPTIONS _options; private string[] _selectedPaths; /// @@ -99,7 +99,7 @@ public string Description /// The value assigned is not one of the values. [Localizable(false), Description("The root folder where the browsing starts from. This property has no effect if the Vista style dialog is used."), Category("Folder Browsing"), Browsable(true), DefaultValue(typeof(System.Environment.SpecialFolder), "Desktop")] public System.Environment.SpecialFolder RootFolder { get; set; } - + /// /// Gets or sets the path selected by the user. /// @@ -133,7 +133,7 @@ public string SelectedPath /// if the New Folder button is shown in the dialog box; otherwise, . The default is . /// [Browsable(true), Localizable(false), Description("A value indicating whether the New Folder button appears in the folder browser dialog box. This property has no effect if the Vista style dialog is used; in that case, the New Folder button is always shown."), DefaultValue(true), Category("Folder Browsing")] - public bool ShowNewFolderButton { get; set; } + public bool ShowNewFolderButton { get; set; } /// /// Gets or sets a value that indicates whether to use the value of the property @@ -156,12 +156,12 @@ public bool Multiselect { get { - return HasOption(NativeMethods.FOS.FOS_ALLOWMULTISELECT); + return HasOption(FILEOPENDIALOGOPTIONS.FOS_ALLOWMULTISELECT); } set { - SetOption(NativeMethods.FOS.FOS_ALLOWMULTISELECT, value); + SetOption(FILEOPENDIALOGOPTIONS.FOS_ALLOWMULTISELECT, value); } } @@ -247,14 +247,14 @@ public void Reset() public bool? ShowDialog(IntPtr owner) { IntPtr ownerHandle = owner == default(IntPtr) ? NativeMethods.GetActiveWindow() : owner; - return new bool?(IsVistaFolderDialogSupported ? RunDialog(ownerHandle) : RunDialogDownlevel(ownerHandle)); + return new bool?(IsVistaFolderDialogSupported ? RunDialog((HWND)ownerHandle) : RunDialogDownlevel((HWND)ownerHandle)); } #endregion #region Internal Methods - internal void SetOption(NativeMethods.FOS option, bool value) + internal void SetOption(FILEOPENDIALOGOPTIONS option, bool value) { if (value) { @@ -266,7 +266,7 @@ internal void SetOption(NativeMethods.FOS option, bool value) } } - internal bool HasOption(NativeMethods.FOS option) + internal bool HasOption(FILEOPENDIALOGOPTIONS option) { return (_options & option) != 0; } @@ -275,59 +275,67 @@ internal bool HasOption(NativeMethods.FOS option) #region Private Methods - private bool RunDialog(IntPtr owner) + private bool RunDialog(HWND owner) { - Ookii.Dialogs.Wpf.Interop.IFileDialog dialog = null; + IFileDialog dialog = null; try { - dialog = new Ookii.Dialogs.Wpf.Interop.NativeFileOpenDialog(); + dialog = new NativeFileOpenDialog(); SetDialogProperties(dialog); int result = dialog.Show(owner); - if( result < 0 ) + if (result < 0) { - if( (uint)result == (uint)HRESULT.ERROR_CANCELLED ) + if ((uint)result == (uint)NativeMethods.HRESULT_FROM_WIN32(WIN32_ERROR.ERROR_CANCELLED)) return false; else throw System.Runtime.InteropServices.Marshal.GetExceptionForHR(result); - } + } GetResult(dialog); return true; } finally { - if( dialog != null ) + if (dialog != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(dialog); } } - private bool RunDialogDownlevel(IntPtr owner) + private unsafe bool RunDialogDownlevel(HWND owner) { - IntPtr rootItemIdList = IntPtr.Zero; IntPtr resultItemIdList = IntPtr.Zero; - if( NativeMethods.SHGetSpecialFolderLocation(owner, RootFolder, ref rootItemIdList) != 0 ) + if (NativeMethods.SHGetSpecialFolderLocation(owner, (int)RootFolder, out ITEMIDLIST* rootItemIdList) != HRESULT.S_OK) { - if( NativeMethods.SHGetSpecialFolderLocation(owner, 0, ref rootItemIdList) != 0 ) + if (NativeMethods.SHGetSpecialFolderLocation(owner, 0, out rootItemIdList) != 0) { throw new InvalidOperationException(Properties.Resources.FolderBrowserDialogNoRootFolder); } } try { - NativeMethods.BROWSEINFO info = new NativeMethods.BROWSEINFO(); - info.hwndOwner = owner; - info.lpfn = new NativeMethods.BrowseCallbackProc(BrowseCallbackProc); - info.lpszTitle = Description; - info.pidlRoot = rootItemIdList; - info.pszDisplayName = new string('\0', 260); - info.ulFlags = NativeMethods.BrowseInfoFlags.NewDialogStyle | NativeMethods.BrowseInfoFlags.ReturnOnlyFsDirs; - if( !ShowNewFolderButton ) - info.ulFlags |= NativeMethods.BrowseInfoFlags.NoNewFolderButton; - resultItemIdList = NativeMethods.SHBrowseForFolder(ref info); - if( resultItemIdList != IntPtr.Zero ) + BROWSEINFOW info; + Span spanDisplayName = stackalloc char[(int)NativeMethods.MAX_PATH]; + fixed (char* pszDisplayName = spanDisplayName) + fixed (char* pDescription = Description) + { + info = new BROWSEINFOW + { + hwndOwner = owner, + lpfn = BrowseCallbackProc, + lpszTitle = pDescription, + pidlRoot = rootItemIdList, + pszDisplayName = pszDisplayName, + ulFlags = NativeMethods.BIF_NEWDIALOGSTYLE | NativeMethods.BIF_RETURNONLYFSDIRS + }; + if (!ShowNewFolderButton) + info.ulFlags |= NativeMethods.BIF_NONEWFOLDERBUTTON; + } + resultItemIdList = (IntPtr)NativeMethods.SHBrowseForFolder(info); + if (resultItemIdList != IntPtr.Zero) { - StringBuilder path = new StringBuilder(260); - NativeMethods.SHGetPathFromIDList(resultItemIdList, path); - SelectedPath = path.ToString(); + Span path = stackalloc char[(int)NativeMethods.MAX_PATH]; + fixed (char* ppath = path) + NativeMethods.SHGetPathFromIDList((ITEMIDLIST*)resultItemIdList, ppath); + SelectedPath = path.ToCleanString(); return true; } else @@ -335,41 +343,41 @@ private bool RunDialogDownlevel(IntPtr owner) } finally { - if( rootItemIdList != IntPtr.Zero ) + if (rootItemIdList != default) { - IMalloc malloc = NativeMethods.SHGetMalloc(); + NativeMethods.SHGetMalloc(out var malloc); malloc.Free(rootItemIdList); Marshal.ReleaseComObject(malloc); } - if( resultItemIdList != IntPtr.Zero ) + if (resultItemIdList != IntPtr.Zero) { Marshal.FreeCoTaskMem(resultItemIdList); } } } - private void SetDialogProperties(Ookii.Dialogs.Wpf.Interop.IFileDialog dialog) + private void SetDialogProperties(IFileDialog dialog) { // Description - if( !string.IsNullOrEmpty(_description) ) + if (!string.IsNullOrEmpty(_description)) { - if( UseDescriptionForTitle ) + if (UseDescriptionForTitle) { dialog.SetTitle(_description); } else { - Ookii.Dialogs.Wpf.Interop.IFileDialogCustomize customize = (Ookii.Dialogs.Wpf.Interop.IFileDialogCustomize)dialog; + IFileDialogCustomize customize = (IFileDialogCustomize)dialog; customize.AddText(0, _description); } } - dialog.SetOptions(NativeMethods.FOS.FOS_PICKFOLDERS | NativeMethods.FOS.FOS_FORCEFILESYSTEM | NativeMethods.FOS.FOS_FILEMUSTEXIST | _options); + dialog.SetOptions(FILEOPENDIALOGOPTIONS.FOS_PICKFOLDERS | FILEOPENDIALOGOPTIONS.FOS_FORCEFILESYSTEM | FILEOPENDIALOGOPTIONS.FOS_FILEMUSTEXIST | _options); - if ( !string.IsNullOrEmpty(_selectedPath) ) + if (!string.IsNullOrEmpty(_selectedPath)) { string parent = Path.GetDirectoryName(_selectedPath); - if( parent == null || !Directory.Exists(parent) ) + if (parent == null || !Directory.Exists(parent)) { dialog.SetFileName(_selectedPath); } @@ -394,9 +402,9 @@ private void GetResult(IFileDialog dialog) for (uint x = 0; x < count; ++x) { results.GetItemAt(x, out IShellItem item); - item.GetDisplayName(NativeMethods.SIGDN.SIGDN_FILESYSPATH, out string name); + item.GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out var name); - folderPaths[x] = name; + folderPaths[x] = name.ToString(); } SelectedPaths = folderPaths; @@ -404,26 +412,32 @@ private void GetResult(IFileDialog dialog) else { dialog.GetResult(out IShellItem item); - item.GetDisplayName(NativeMethods.SIGDN.SIGDN_FILESYSPATH, out _selectedPath); + item.GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out var s); + _selectedPath = s.ToString(); } } - private int BrowseCallbackProc(IntPtr hwnd, NativeMethods.FolderBrowserDialogMessage msg, IntPtr lParam, IntPtr wParam) + private unsafe int BrowseCallbackProc(HWND hwnd, uint msg, LPARAM lParam, LPARAM lpData) { - switch( msg ) + switch (msg) { - case NativeMethods.FolderBrowserDialogMessage.Initialized: - if( SelectedPath.Length != 0 ) - NativeMethods.SendMessage(hwnd, NativeMethods.FolderBrowserDialogMessage.SetSelection, new IntPtr(1), SelectedPath); - break; - case NativeMethods.FolderBrowserDialogMessage.SelChanged: - if( lParam != IntPtr.Zero ) - { - StringBuilder path = new StringBuilder(260); - bool validPath = NativeMethods.SHGetPathFromIDList(lParam, path); - NativeMethods.SendMessage(hwnd, NativeMethods.FolderBrowserDialogMessage.EnableOk, IntPtr.Zero, validPath ? new IntPtr(1) : IntPtr.Zero); - } - break; + case NativeMethods.BFFM_INITIALIZED: + if (SelectedPath.Length != 0) + { + fixed (char* pSelectedPath = SelectedPath) + NativeMethods.SendMessage(hwnd, NativeMethods.BFFM_SETSELECTION, 1, (IntPtr)pSelectedPath); + } + break; + case NativeMethods.BFFM_SELCHANGED: + if (lParam != default) + { + bool validPath; + Span span = stackalloc char[(int)NativeMethods.MAX_PATH]; + fixed (char* pspan = span) + validPath = NativeMethods.SHGetPathFromIDList((ITEMIDLIST*)(IntPtr)lParam, pspan); + NativeMethods.SendMessage(hwnd, NativeMethods.BFFM_ENABLEOK, 0, (nint)(validPath ? 1 : 0)); + } + break; } return 0; } diff --git a/src/Ookii.Dialogs.Wpf/VistaOpenFileDialog.cs b/src/Ookii.Dialogs.Wpf/VistaOpenFileDialog.cs index 0712b4d..9a44fa6 100644 --- a/src/Ookii.Dialogs.Wpf/VistaOpenFileDialog.cs +++ b/src/Ookii.Dialogs.Wpf/VistaOpenFileDialog.cs @@ -98,14 +98,14 @@ public bool Multiselect { if( DownlevelDialog != null ) return ((OpenFileDialog)DownlevelDialog).Multiselect; - return GetOption(NativeMethods.FOS.FOS_ALLOWMULTISELECT); + return GetOption(FILEOPENDIALOGOPTIONS.FOS_ALLOWMULTISELECT); } set { if( DownlevelDialog != null ) ((OpenFileDialog)DownlevelDialog).Multiselect = value; - SetOption(NativeMethods.FOS.FOS_ALLOWMULTISELECT, value); + SetOption(FILEOPENDIALOGOPTIONS.FOS_ALLOWMULTISELECT, value); } } @@ -199,39 +199,35 @@ public System.IO.Stream OpenFile() #region Internal Methods - internal override Ookii.Dialogs.Wpf.Interop.IFileDialog CreateFileDialog() + internal override IFileDialog CreateFileDialog() { - return new Ookii.Dialogs.Wpf.Interop.NativeFileOpenDialog(); + return new NativeFileOpenDialog(); } - internal override void SetDialogProperties(Ookii.Dialogs.Wpf.Interop.IFileDialog dialog) + internal override void SetDialogProperties(IFileDialog dialog) { base.SetDialogProperties(dialog); if( _showReadOnly ) { - Ookii.Dialogs.Wpf.Interop.IFileDialogCustomize customize = (Ookii.Dialogs.Wpf.Interop.IFileDialogCustomize)dialog; + IFileDialogCustomize customize = (IFileDialogCustomize)dialog; customize.EnableOpenDropDown(_openDropDownId); customize.AddControlItem(_openDropDownId, _openItemId, ComDlgResources.LoadString(ComDlgResources.ComDlgResourceId.OpenButton)); customize.AddControlItem(_openDropDownId, _readOnlyItemId, ComDlgResources.LoadString(ComDlgResources.ComDlgResourceId.ReadOnly)); } } - internal override void GetResult(Ookii.Dialogs.Wpf.Interop.IFileDialog dialog) + internal unsafe override void GetResult(IFileDialog dialog) { if( Multiselect ) { - Ookii.Dialogs.Wpf.Interop.IShellItemArray results; - ((Ookii.Dialogs.Wpf.Interop.IFileOpenDialog)dialog).GetResults(out results); - uint count; - results.GetCount(out count); + ((IFileOpenDialog)dialog).GetResults(out var results); + results.GetCount(out uint count); string[] fileNames = new string[count]; for( uint x = 0; x < count; ++x ) { - Ookii.Dialogs.Wpf.Interop.IShellItem item; - results.GetItemAt(x, out item); - string name; - item.GetDisplayName(NativeMethods.SIGDN.SIGDN_FILESYSPATH, out name); - fileNames[x] = name; + results.GetItemAt(x, out IShellItem item); + item.GetDisplayName(SIGDN.SIGDN_FILESYSPATH,out var ptr); + fileNames[x] = ptr.ToString(); } FileNamesInternal = fileNames; @@ -241,9 +237,9 @@ internal override void GetResult(Ookii.Dialogs.Wpf.Interop.IFileDialog dialog) if( ShowReadOnly ) { - Ookii.Dialogs.Wpf.Interop.IFileDialogCustomize customize = (Ookii.Dialogs.Wpf.Interop.IFileDialogCustomize)dialog; - int selected; - customize.GetSelectedControlItem(_openDropDownId, out selected); + IFileDialogCustomize customize = (IFileDialogCustomize)dialog; + uint selected; + customize.GetSelectedControlItem(_openDropDownId, &selected); _readOnlyChecked = (selected == _readOnlyItemId); } diff --git a/src/Ookii.Dialogs.Wpf/VistaSaveFileDialog.cs b/src/Ookii.Dialogs.Wpf/VistaSaveFileDialog.cs index 50991e5..a6ddac3 100644 --- a/src/Ookii.Dialogs.Wpf/VistaSaveFileDialog.cs +++ b/src/Ookii.Dialogs.Wpf/VistaSaveFileDialog.cs @@ -80,14 +80,14 @@ public bool CreatePrompt { if( DownlevelDialog != null ) return ((SaveFileDialog)DownlevelDialog).CreatePrompt; - return GetOption(NativeMethods.FOS.FOS_CREATEPROMPT); + return GetOption(FILEOPENDIALOGOPTIONS.FOS_CREATEPROMPT); } set { if( DownlevelDialog != null ) ((SaveFileDialog)DownlevelDialog).CreatePrompt = value; else - SetOption(NativeMethods.FOS.FOS_CREATEPROMPT, value); + SetOption(FILEOPENDIALOGOPTIONS.FOS_CREATEPROMPT, value); } } @@ -107,14 +107,14 @@ public bool OverwritePrompt { if( DownlevelDialog != null ) return ((SaveFileDialog)DownlevelDialog).OverwritePrompt; - return GetOption(NativeMethods.FOS.FOS_OVERWRITEPROMPT); + return GetOption(FILEOPENDIALOGOPTIONS.FOS_OVERWRITEPROMPT); } set { if( DownlevelDialog != null ) ((SaveFileDialog)DownlevelDialog).OverwritePrompt = value; else - SetOption(NativeMethods.FOS.FOS_OVERWRITEPROMPT, value); + SetOption(FILEOPENDIALOGOPTIONS.FOS_OVERWRITEPROMPT, value); } } @@ -188,9 +188,9 @@ protected override void OnFileOk(CancelEventArgs e) #region Internal Methods - internal override Ookii.Dialogs.Wpf.Interop.IFileDialog CreateFileDialog() + internal override IFileDialog CreateFileDialog() { - return new Ookii.Dialogs.Wpf.Interop.NativeFileSaveDialog(); + return new NativeFileSaveDialog(); } #endregion