Я никогда не получал ответ на вопрос в заголовке, поэтому я до сих пор не знаю, что SecureString направляется в неуправляемый код.
Однако мой код заработал, используя рекомендации из некоторых других ответов. Я предоставил код ниже.
internal static class NativeService
{
...
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ChangeServiceConfig(IntPtr hService, uint nServiceType, uint nStartType, uint nErrorControl, string lpBinaryPathName, string lpLoadOrderGroup, IntPtr lpdwTagId, [In] char[] lpDependencies, string lpServiceStartName, IntPtr lpPassword, string lpDisplayName);
...
public const uint SERVICE_NO_CHANGE = 0xffffffff;
}
internal class ClassThatConfiguresService
{
...
public void ConfigureStartupAccount(IntPtr service, string userName, SecureString password)
{
passwordPointer = Marshal.SecureStringToGlobalAllocUnicode(password);
try
{
if(!NativeService.ChangeServiceConfig(service, NativeService.SERVICE_NO_CHANGE, NativeService.SERVICE_NO_CHANGE, NativeService.SERVICE_NO_CHANGE, null, null, IntPtr.Zero, null, userName, passwordPointer, null))
throw new Win32Exception(Marshal.GetLastWin32Error());
}
finally
{
Marshal.ZeroFreeGlobalAllocUnicode(passwordPointer);
}
}
...
}
Вместо Marshal.SecureStringToBSTR я использовал Marshal.SecureStringToGlobalAllocUnicode, потому что это то, что ожидает неуправляемая функция, но в остальном она обрабатывает удовольствие.
Надеюсь, кто-то еще найдет это полезным.
Кеп.