Как вручную перенаправить BSTR из .NET в COM?
Я пытаюсь передать секрет, хранящийся в SecureString
, из моего приложения .NET в метод COM-объекта. Я хочу избежать преобразования SecureString
в String
, потому что вы не должны использовать SecureString
. Секрет тогда будет в открытом тексте в управляемой памяти и будет там висеть надолго. Вместо этого я пытаюсь сделать это Правильным способом & trade;: преобразовать его в BSTR в неуправляемой памяти, передать его методу COM, а затем очистить BSTR с помощью Marshal.ZeroFreeBSTR
, чтобы пароль был открыт только в течение ограниченного времени. .
Интерфейс .NET, который генерирует TblImp.exe для этого COM-объекта, ожидает, что секрет будет передан как String
, который затем маршалирует в BSTR. Это не то, что я хочу, так как это означает, что я должен поместить свой секрет в String
, поэтому, следуя этому Lean-методу для вызова COM , я создал свой собственный интерфейс, чтобы я мог настроить его и получить избавиться от String
. Вот с чего я начинаю:
[ComImport, Guid("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface ITheComObjectDispatcher
{ // +--- the naughty string
[return: MarshalAs(UnmanagedType.BStr)] // |
[DispId(1)] // V
string TheMethod([In, MarshalAs(UnmanagedType.BStr)] string secret);
}
[ComImport, Guid("YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY")]
public class TheComObject
{}
Это работает - но я должен преобразовать SecureString
в String
, чтобы использовать его, например, так:
private string UseTheMethod(SecureString secret)
{
var comObject = new TheComObject();
var comObjectDispatcher = (ITheComObjectDispatcher)comObject;
var secretAsString = NaughtilyConvertSecureStringToString(secret);
return comObjectDispatcher.TheMethod(secretAsString);
}
private static string NaughtilyConvertSecureStringToString(SecureString value)
{
var valuePtr = Marshal.SecureStringToGlobalAllocUnicode(value);
try
{
return Marshal.PtrToStringUni(valuePtr); // now the secret is in managed memory :(
}
finally
{
Marshal.ZeroFreeGlobalAllocUnicode(valuePtr);
}
}
Вместо этого я хочу использовать метод, подобный Marshal.SecureStringToBSTR
, и пропустить преобразование в String
. Я пробовал это ...
[return: MarshalAs(UnmanagedType.BStr)]
[DispId(1)]
string TheMethod([In, MarshalAs(UnmanagedType.BStr)] IntPtr secret);
... и это ...
[return: MarshalAs(UnmanagedType.BStr)]
[DispId(1)]
string TheMethod([In] IntPtr secret);
... с этим кодом вызова ...
private string UseTheMethod(SecureString secret)
{
var comObject = new TheComObject();
var comObjectDispatcher = (ITheComObjectDispatcher)comObject;
var secretPtr = Marshal.SecureStringToBSTR(secret);
try
{
return comObjectDispatcher.TheMethod(secretPtr);
}
finally
{
Marshal.ZeroFreeBSTR(secretPtr);
}
}
... но это не работает: неверное значение передается методу COM. Он не завершается с ошибкой - он просто дает другой результат.
Вопросы:
- Могу ли я передать BSTR напрямую как IntPtr, как это? Что я делаю не так?
- Есть ли способ отладки процесса маршалинга, чтобы увидеть, какое значение передается?