首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >编组CTL_USAGE

编组CTL_USAGE
EN

Stack Overflow用户
提问于 2013-05-08 22:18:53
回答 1查看 249关注 0票数 0

我正在做一个使用证书的项目,我需要将CTL_USAGE结构转换为C#。原始结构如下:

代码语言:javascript
复制
typedef struct _CTL_USAGE {
  DWORD cUsageIdentifier;
  LPSTR *rgpszUsageIdentifier;
} CTL_USAGE, *PCTL_USAGE, CERT_ENHKEY_USAGE, *PCERT_ENHKEY_USAGE;

根据P/Invoke网站,C#结构应该是这样的:

代码语言:javascript
复制
[StructLayout(LayoutKind.Sequential)]
public struct CTL_USAGE
{
    public int cUsageIdentifier;
    public IntPtr rgpszUsageIdentifier;
}

要使用此代码,我使用Encoding.ASCII.GetBytes()将要添加到结构中的每个字符串转换为字节数组。然后,我使用GCHandle.Alloc(byteArray,GCHandleType.Pinned)将该字节数组转换为GCHandle。我将该值添加到IntPtrs数组中,然后为IntPtr数组创建一个GCHandle并将其分配给rgpszUsageIdentifier。对CryptEncodeObjectEx的调用不会抛出错误,但是生成的数据是垃圾数据,不能使用CryptDecodeObject进行解密。我的编码如下:

代码语言:javascript
复制
//EnhancedUsage is a List<String> containing the Enhanced Usage OIDs
CTL_USAGE usage = new CTL_USAGE()
{
    cUsageIdentifier = EnhancedUsage.Count,
};

List<IntPtr> usageList = new List<IntPtr>();

foreach (string s in EnhancedUsage)
    usageList.Add(new PinnedHandle(Encoding.ASCII.GetBytes(s)));

usage.rgpszUsageIdentifier = new PinnedHandle(usageList.ToArray());

IntPtr data = Marshal.AllocHGlobal(Marshal.SizeOf(usage));
Marshal.StructureToPtr(usage, data, false);

int encodedSize = 0;

if (!Crypt32.CryptEncodeObjectEx((int)CertEncoding.X509Asn, CertOid.szOID_ENHANCED_KEY_USAGE, data, 0, IntPtr.Zero, null, ref encodedSize))
    throw new Win32Exception();

byte[] buffer = new byte[encodedSize];

if (!Crypt32.CryptEncodeObjectEx((int)CertEncoding.X509Asn, CertOid.szOID_ENHANCED_KEY_USAGE, data, 0, IntPtr.Zero, buffer, ref encodedSize))
    throw new Win32Exception();

PinnedHandle类是GCHandle的包装器。它看起来是这样的:

代码语言:javascript
复制
public class PinnedHandle : IDisposable
{
    private GCHandle handle;

    public PinnedHandle(object value)
    {
        handle = GCHandle.Alloc(value, GCHandleType.Pinned);
    }

    public static implicit operator IntPtr(PinnedHandle value)
    {
        return value.handle.AddrOfPinnedObject();
    }

    public void Dispose()
    {
        try
        {
            handle.Free();
        }
        catch
        {

        }
    }
}

我认为它在这里不会造成任何问题,因为我在其他类似的情况下使用过它,它们工作正常。你知道如何让它正确工作吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-05-12 13:15:41

使用AllocHGLobal分配非托管内存块,将usageList中的所有IntPtr实例复制到其中,并将此块句柄传递给非托管函数。为此,请使用Marshal.WriteIntPtr Method (IntPtr, Int32, IntPtr)

http://msdn.microsoft.com/en-us/library/ms146679.aspx

在我的互操作性代码中,我避免固定托管对象,而更喜欢使用不同的封送方法来构建本机内存区域。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16443110

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档