Skip to content

Add support for specifying credential dialog's dwAuthError parameter #60

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 20 additions & 12 deletions src/Ookii.Dialogs.WinForms/CredentialDialog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ namespace Ookii.Dialogs.WinForms
[DefaultProperty("MainInstruction"), DefaultEvent("UserNameChanged"), Description("Allows access to credential UI for generic credentials.")]
public partial class CredentialDialog : Component
{
/// <summary>
/// The logon attempt failed
/// </summary>
/// <remarks>A possible value for the authError parameter. Imported from WinError.h.</remarks>
public const int SEC_E_LOGON_DENIED = unchecked((int)0x8009030C);

private string _confirmTarget;
private NetworkCredential _credentials = new NetworkCredential();
private bool _isSaveChecked;
Expand Down Expand Up @@ -381,10 +387,10 @@ public string Content
/// </remarks>
public bool IsStoredCredential { get; private set; }


/// <summary>
/// Shows the credentials dialog as a modal dialog.
/// </summary>
/// <param name="authError">An optionally provided Windows error specifying why the credential dialog box is needed, for example <see cref="SEC_E_LOGON_DENIED"/>.</param>
/// <returns><see cref="DialogResult.OK" /> if the user clicked OK; otherwise, <see cref="DialogResult.Cancel" />.</returns>
/// <remarks>
/// <para>
Expand Down Expand Up @@ -417,15 +423,16 @@ public string Content
/// <exception cref="CredentialException">An error occurred while showing the credentials dialog.</exception>
/// <exception cref="InvalidOperationException"><see cref="Target"/> is an empty string ("").</exception>
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public DialogResult ShowDialog()
public DialogResult ShowDialog(int authError = 0)
{
return ShowDialog(null);
return ShowDialog(null, authError);
}

/// <summary>
/// Shows the credentials dialog as a modal dialog with the specified owner.
/// </summary>
/// <param name="owner">The <see cref="IntPtr"/> Win32 handle that owns the credentials dialog.</param>
/// <param name="authError">An optionally provided Windows error specifying why the credential dialog box is needed, for example <see cref="SEC_E_LOGON_DENIED"/>.</param>
/// <returns><see cref="DialogResult.OK" /> if the user clicked OK; otherwise, <see cref="DialogResult.Cancel" />.</returns>
/// <remarks>
/// <para>
Expand Down Expand Up @@ -458,7 +465,7 @@ public DialogResult ShowDialog()
/// <exception cref="CredentialException">An error occurred while showing the credentials dialog.</exception>
/// <exception cref="InvalidOperationException"><see cref="Target"/> is an empty string ("").</exception>
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public DialogResult ShowDialog(IntPtr owner)
public DialogResult ShowDialog(IntPtr owner, int authError = 0)
{
if( string.IsNullOrEmpty(_target) )
throw new InvalidOperationException(Properties.Resources.CredentialEmptyTargetError);
Expand Down Expand Up @@ -490,16 +497,17 @@ public DialogResult ShowDialog(IntPtr owner)
IntPtr ownerHandle = owner == IntPtr.Zero ? NativeMethods.GetActiveWindow() : owner;
bool result;
if( NativeMethods.IsWindowsVistaOrLater )
result = PromptForCredentialsCredUIWin(ownerHandle, storedCredentials);
result = PromptForCredentialsCredUIWin(ownerHandle, storedCredentials, authError);
else
result = PromptForCredentialsCredUI(ownerHandle, storedCredentials);
result = PromptForCredentialsCredUI(ownerHandle, storedCredentials, authError);
return result ? DialogResult.OK : DialogResult.Cancel;
}

/// <summary>
/// Shows the credentials dialog as a modal dialog with the specified owner.
/// </summary>
/// <param name="owner">The <see cref="IWin32Window"/> that owns the credentials dialog.</param>
/// <param name="authError">An optionally provided Windows error specifying why the credential dialog box is needed, for example <see cref="SEC_E_LOGON_DENIED"/>.</param>
/// <returns><see cref="DialogResult.OK" /> if the user clicked OK; otherwise, <see cref="DialogResult.Cancel" />.</returns>
/// <remarks>
/// <para>
Expand Down Expand Up @@ -532,14 +540,14 @@ public DialogResult ShowDialog(IntPtr owner)
/// <exception cref="CredentialException">An error occurred while showing the credentials dialog.</exception>
/// <exception cref="InvalidOperationException"><see cref="Target"/> is an empty string ("").</exception>
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public DialogResult ShowDialog(IWin32Window owner)
public DialogResult ShowDialog(IWin32Window owner, int authError = 0)
{
IntPtr ownerHandle;
if( owner == null )
ownerHandle = NativeMethods.GetActiveWindow();
else
ownerHandle = owner.Handle;
return ShowDialog(ownerHandle);
return ShowDialog(ownerHandle, authError);
}

/// <summary>
Expand Down Expand Up @@ -786,7 +794,7 @@ protected virtual void OnPasswordChanged(EventArgs e)
PasswordChanged(this, e);
}

private bool PromptForCredentialsCredUI(IntPtr owner, bool storedCredentials)
private bool PromptForCredentialsCredUI(IntPtr owner, bool storedCredentials, int authError)
{
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;
Expand All @@ -798,7 +806,7 @@ private bool PromptForCredentialsCredUI(IntPtr owner, bool storedCredentials)
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);
NativeMethods.CredUIReturnCodes result = NativeMethods.CredUIPromptForCredentials(ref info, Target, IntPtr.Zero, authError, user, NativeMethods.CREDUI_MAX_USERNAME_LENGTH, pw, NativeMethods.CREDUI_MAX_PASSWORD_LENGTH, ref _isSaveChecked, flags);
switch( result )
{
case NativeMethods.CredUIReturnCodes.NO_ERROR:
Expand All @@ -820,7 +828,7 @@ private bool PromptForCredentialsCredUI(IntPtr owner, bool storedCredentials)
}
}

private bool PromptForCredentialsCredUIWin(IntPtr owner, bool storedCredentials)
private bool PromptForCredentialsCredUIWin(IntPtr owner, bool storedCredentials, int authError)
{
NativeMethods.CREDUI_INFO info = CreateCredUIInfo(owner, false);
NativeMethods.CredUIWinFlags flags = NativeMethods.CredUIWinFlags.Generic;
Expand All @@ -845,7 +853,7 @@ private bool PromptForCredentialsCredUIWin(IntPtr owner, bool storedCredentials)

uint outBufferSize;
uint package = 0;
NativeMethods.CredUIReturnCodes result = NativeMethods.CredUIPromptForWindowsCredentials(ref info, 0, ref package, inBuffer, inBufferSize, out outBuffer, out outBufferSize, ref _isSaveChecked, flags);
NativeMethods.CredUIReturnCodes result = NativeMethods.CredUIPromptForWindowsCredentials(ref info, authError, ref package, inBuffer, inBufferSize, out outBuffer, out outBufferSize, ref _isSaveChecked, flags);
switch( result )
{
case NativeMethods.CredUIReturnCodes.NO_ERROR:
Expand Down