C#调用登录用户失败,带有SecureString

C#调用登录用户失败,带有SecureString,c#,security,winapi,C#,Security,Winapi,各位,我面临着LogonUser功能的问题 我只想知道是否可以通过以下签名将LogonUser函数导入C#: [DllImport("advapi32.dll", SetLastError = true)] internal static extern int LogonUser(string username, string domain, IntPtr password, int logonType, int logonProvider, ref IntPtr token); 因为我想保护

各位,我面临着
LogonUser
功能的问题

我只想知道是否可以通过以下签名将
LogonUser
函数导入C#:

[DllImport("advapi32.dll", SetLastError = true)]
internal static extern int LogonUser(string username, string domain, IntPtr password, int logonType, int logonProvider, ref IntPtr token);
因为我想保护我的密码,而不是使用字符串,而是
SecureString
类。随后,该函数将按如下方式使用:

var passwordPtr = Marshal.SecureStringToGlobalAllocUnicode(password);
var result = LogonUser(userName, domain, passwordPtr, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token);
我总是得到result=0,消息显示用户名和密码不正确。 但当我将签名更改为使用字符串密码时,一切都正常


请帮助我使用
SecureString
保护密码,这对我很重要。

正如Alex K所指出的,在中有一个使用
LogonUser
的示例。请注意,其中的P/Invoke声明有:

[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool LogonUser(String username, String domain, IntPtr password,
            int logonType, int logonProvider, ref IntPtr token);
并且指定了
CharSet=CharSet.Unicode
。不幸的是,由于历史原因,默认值是
Ansi
,因此您的P/Invoke尝试将使用该值

这对于
username
参数很好,因为p/Invoke基础结构将确保它适当地转换
字符串。但是它不适合于
password
参数,因为您已经执行了字符串转换,并且已经以Unicode的形式完成了转换,而P/Invoke现在看到的只是
IntPtr

我建议更新您的p/Invoke签名以匹配示例中给出的签名


另一种选择是切换到使用p/Invoke签名,而不使用p/Invoke签名。但这是一个严重的二流解决方案。不建议在2015年编写非Unicode代码


只要养成习惯,在您编写的任何p/Invoke签名中始终指定
CharSet.Unicode

这就是您应该做的。。
SecureStringToGlobalAllocUnicode
的MSDN页面有一个调用
LogonUser
的完整示例:一个明显的问题是,如果您的P/Invoke签名错误,并且试图将Unicode文本传递到Ansi版本的
LogonUser
,但我不能肯定,因为您没有显示P/Invoke签名。我刚刚更新了签名。感谢Damien_the_unsiver和Alex K。我尝试用字符集将签名更新为Unicode,现在工作正常。我只是没有意识到这个设置,并且在Alex K提到的文章中多次比较了函数签名:)