我想显示标准系统对话框,要求用户输入帐户用户名和密码,以便使用此信息启动具有这些凭据的流程。
我一直指向显示该对话框的CredUIPromptForCredentials
函数。它以字符串形式返回用户名和密码。但ProcessStartInfo
结构需要密码为SecureString
。
据我所知,我现在可以将密码用作字符串,并按字符将其转换为SecureString
字符(没有单一功能) - 但它会完全打败SecureString
背后的想法
所以我想必须有一些方法可以直接从.NET中的CredUIPromptForCredentials
非托管调用中接受密码SecureString
。毕竟,我真的不需要以任何方式访问我的应用程序中的密码。它应该被用来启动另一个过程,然后可以尽快忘记。
那么CredUIPromptForCredentials
的P / Invoke声明如何与SecureString
一致? (我从pinvoke.net开始使用C#。)
更新:哦,如果有人在Windows Vista / 7中有新功能CredUIPromptForWindowsCredentials
的示例,那也很酷,因为我甚至无法弄清楚目前如何使用它。
答案 0 :(得分:2)
您可以将IntPtr
非托管字符串缓冲区强制转换为char*
并使用SecureString(char*, int)
构造函数。
// somehow, we come into posession of an IntPtr to a string
// obviously, this would be a foolish way to come into it in
// production, since stringOriginalContents is already in managed
// code, and the lifetime can therefore not be guaranteed...
var stringOriginalContents = "foobar";
IntPtr strPtr = Marshal.StringToHGlobalUni(stringOriginalContents);
int strLen = stringOriginalContents.Length;
int maxLen = 100;
// we copy the IntPtr to a SecureString, and zero out the old location
SecureString ssNew;
unsafe
{
char* strUPtr = (char*)strPtr;
// if we don't know the length, calculate
//for (strLen = 0; *(strUPtr + strLen) != '\0'
// // stop if the string is invalid
// && strLen < maxLen; strLen++)
// ;
ssNew = new SecureString((char*)strPtr, strLen);
// zero out the old memory and release, or use a Zero Free method
//for (int i = 0; i < strLen; i++)
// *(strUPtr + i) = '\0';
//Marshal.FreeHGlobal(strPtr);
// (only do one of these)
Marshal.ZeroFreeGlobalAllocUnicode(strPtr);
}
// now the securestring has the protected data, and the old memory has been
// zeroed, we can check that the securestring is correct. This, also should
// not be in production code.
string strInSecureString =
Marshal.PtrToStringUni(
Marshal.SecureStringToGlobalAllocUnicode(ssNew));
Assert.AreEqual(strInSecureString, stringOriginalContents);