2

谁能给出System.Security.Cryptography.RijndaelManaged使用 COM 从本机 Win32 使用的示例用法?


这是一个如何使用 .NET 的功能示例System.Security.Cryptography.SHA256Managed

注意:这是一个如何调用 SHA256Managed 的​​示例,而不是RijndaelManaged**。我展示这段代码是为了介绍一些使用早期和后期绑定调用 COM 对象的棘手概念,并展示使用 COM 可调用包装器调用 .NET 对象可能的。当听到我想混合 .NET 和 Win32 COM 时,有些人可能会举手。

注意:语言是 Delphi(这是我编写和测试的语言),但经过转码使其看起来更像 C# 或 Java,因此更广泛的受众更容易理解这个问题:

public static string HashStr256(String szPlaintext)
{
   OleVariant sha = CreateOleObject('System.Security.Cryptography.SHA256Managed');

   OleVariant inputBuffer = VarByteArrayOf(szPlaintext);

   Integer l = VarArrayLowBound(inputBuffer, 1);
   Integer h = VarArrayHighBound(inputBuffer, 1);

   ICryptoTransform crypto = IDispatch(sha) as ICryptoTransform;
   crypto.TransformFinalBlock(
         PSafeArray(TVarData(inputBuffer).VArray), //inputArray,
         l,  //input array offset
         h-l+1); //input array count

   OleVariant digest := sha.Hash;

   Result := ToBase64String(BytesOfVarByteArray(digest));
end;

使用辅助功能:

function VarByteArrayOf(const s: string): OleVariant;
var
    Data: Pointer;
begin
    //Create variant byte array to hold the bytes
    Result := VarArrayCreate([0, Length(s)-1], varByte);

    //Copy from Delphi array to Variant Array
    if Length(s) > 0 then
    begin
        Data := VarArrayLock(Result);
        try
            System.Move(s[1], Data^, Length(s));
        finally
            VarArrayUnlock(Result);
        end;
    end;
end;

我展示代码调用的真正原因SHA256Managed是为了展示我arrays在 Delphi 中传递给 COM 时遇到的困难。例如,如果您只是依赖IDispatch后期绑定:

sha: OleVariant;
inputBuffer: OleVariant;
...
sha.TransformFinalBlock(inputBuffer, i, count);

然后在运行时你得到参数不正确;关于IDispatch后期绑定的一些东西不支持传递一个OleVariant字节数组。

safearray这就是为什么我必须改为传递OleVariant. 众所周知,Variant只是一个联合结构,我们关心SAFEARRAY成员:

data: PSafeArray;

data := PSafeArray(TVarData(inputBuffer).VArray);
sha.TransformFinalBlock(data, i, count);

除了试图通过PSafeArray使用IDispatch后期绑定会导致 Delphi 抛出:

OLE 自动化调用中不允许的类型

这就是为什么我们被迫部分放弃IDispatch后期绑定以进行ICryptoTransform早期绑定的原因:

ICryptoTransform_Native = interface(IDispatch)
   ['{8ABAD867-F515-3CF6-BB62-5F0C88B3BB11}']
   ...
   function TransformFinalBlock(inputBuffer: PSafeArray; inputOffset: Integer; inputCount: Integer): PSafeArray; safecall;
   ...
end;

crypto: ICryptoTransform;
sha: OleVariant;
inputBuffer: OleVariant;

crypto = IDispatch(sha) as ICryptoTransform;
crypto.TransformFinalBlock(
         PSafeArray(TVarData(inputBuffer).VArray), //inputArray,
         i, n);

所以应该是这样吧?我们已经解决了如何将数组传递给 COM .NET 对象?我现在应该可以使用Rijndael了;使用早期绑定PSafeArray

这就是我们想用后期绑定来尝试的:

OleVariant aes := CreateOleObject('System.Security.Cryptography.RijndaelManaged');

OleVariant keyBytes = VarByteArrayOf(Key);
aes.Key := key;

由于上述相同的原因而失败 - 您不能将OleVariant数组传递给 COM 对象(参数不正确)。

所以我们应该只使用的早期绑定SymmetricAlgorithm.Key并将其Key作为 a传递PSafeArray

var
   symmetric: ISymmetricAlgorithm;
   aes: OleVariant;
   keyBytes: OleVariant;
begin
   aes := CreateOleObject('System.Security.Cryptography.RijndaelManaged');

   symmetric:= (IDispatch(aes) as ISymmetricAlgorithm;
   symmetric.Key := PSafeArray(TVarData(inputBuffer).VArray);
   ...
end;

除了没有ISymmetricAlgorithm接口;我编的。

如果从 导入类型库mscorelib.tlb,其中包含ICryptoTransform,则没有早期绑定ISymmetricAlgorithm。有一个后期 ISymmetricAlgorithm绑定:

IID__SymmetricAlgorithm: TGUID = '{05BC0E38-7136-3825-9E34-26C1CF2142C9}';
CLASS_SymmetricAlgorithm: TGUID = '{5B67EA6B-D85D-3F48-86D2-8581DB230C43}';
_SymmetricAlgorithm = interface;
SymmetricAlgorithm = _SymmetricAlgorithm;

_SymmetricAlgorithm = interface(IDispatch)
   ['{05BC0E38-7136-3825-9E34-26C1CF2142C9}']
end;
_SymmetricAlgorithmDisp = dispinterface
   ['{05BC0E38-7136-3825-9E34-26C1CF2142C9}']
end;

那么如何设置RijndaelManaged KeyIV本地 Win32 COM?我可以使用什么后期绑定语法?

如何从本机 COM 调用使用 .NET RijndaelManaged?

进一步的尝试

由于没有interface我可以使用的早期绑定,我必须专注于如何通过IDispatch. 秘密是Variant我传递给 COM 对象的内容。

由于使用了早期绑定版本safearrays,我将从它开始。首先,我将自己手动设置OleVariant结构。

对于以下每种尝试,以下情况都是正确的:

key: OleVariant;
data: PSafeArray;

data := PSafeArray(TVarData(keyBytes).VArray);

自己设置变量枚举

  • 尝试 1VT_ARRAY 一个 SAFEARRAY 指针。

    TVarData(key).VType := VT_ARRAY;
    TVarData(key).VArray := data;
    
  • 尝试 2VT_ARRAY 一个 SAFEARRAY 指针。

    TVarData(key).VType := VT_ARRAY or VT_I1;
    TVarData(key).VArray := data;
    
  • 尝试 3VT_SAFEARRAY 安全数组。在 VARIANT 中使用 VT_ARRAY。

    TVarData(key).VType := VT_SAFEARRAY or VT_I1;
    TVarData(key).VArray := data;
    
  • 尝试 4VT_SAFEARRAY 一个安全的数组。在 VARIANT 中使用 VT_ARRAY。

    TVarData(key).VType := VT_SAFEARRAY;
    TVarData(key).VArray := data;
    

The parameter is incorrect它们都因错误而失败。

让我感觉到VT_ARRAY(a safearray) 和VT_SAFEARRAY(a safearray) 并不是 COM 可调用包装器 IDispatch 接口准备接受的。也许它需要VT_CARRAY

或者可能不是。也许比我更聪明的人可以弄清楚。

奖金阅读

这本质上是对我 2008 年在 Borland 新闻组上提出的一个问题的重新表述

Delphi 编译器有内置的 COM SafeArrays 知识吗?

4

0 回答 0