【发布时间】:2019-02-12 22:05:13
【问题描述】:
如何手动将 BSTR 从 .NET 编组到 COM?
我试图将存储在SecureString 中的秘密从我的.NET 应用程序传递给COM 对象上的方法。我想避免将SecureString 转换为String,因为这不是您应该使用SecureString 的方式。然后,秘密将在托管内存中以明文形式存在并在那里徘徊很长时间。相反,我尝试以 Right Way™ 进行操作:将其转换为非托管内存中的 BSTR,将其传递给 COM 方法,然后使用 Marshal.ZeroFreeBSTR 清除 BSTR,以便密码仅在有限的时间内公开.
TblImp.exe 为该 COM 对象生成的 .NET 接口期望秘密作为 String 传递,然后将其编组到 BSTR。这不是我想要的,因为这意味着我必须将我的秘密放在String 中,所以按照这个Lean Method for Invoking 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 传递吗?我做错了什么?
- 有没有办法调试封送处理以查看正在传递的值?
【问题讨论】:
-
你确定 ITheComObjectDispatcher 是一个 IDispatch-only 接口吗?在这种情况下,您将无法轻松做到这一点。你有 ITheComObjectDispatcher 的原始 COM(idl 或 .h)定义吗?
-
@SimonMourier - 我有 IDL - 看起来它是“双重的”。
标签: .net com marshalling bstr securestring