更清洁的代码方式而不是Marshall.QueryInterface?

时间:2010-09-28 16:16:33

标签: c# .net pinvoke

我想知道是否有更简洁的方法来编写下面的(工作)代码:

uint uEnum = 0;
PStore.EnumTypes(0, 0, ref uEnum);
System.Reflection.MemberInfo inf = typeof(PSTORECLib.CEnumTypes);
GuidAttribute CEnumGuid = 
    (GuidAttribute)inf.GetCustomAttributes(typeof(GuidAttribute), false)[0];
Guid tmp = new Guid(CEnumGuid.Value);
IntPtr ppv;
Marshal.QueryInterface((IntPtr)uEnum, ref tmp, out ppv);
PSTORECLib.CEnumTypes EnumPStoreTypes = 
    (PSTORECLib.CEnumTypes)Marshal.GetObjectForIUnknown(ppv);

//Later
Marshal.Release(ppv);

当我尝试将IEnumPStoreTypes**填充到PSTORECLib的idl文件中(即当我使用oleview的初始IDL输出时)到PStore.EnumTypes的调用中时,tlbimp输出的dll告诉我通过在引用CEnumTypes时。函数很满意(它返回了S_OK),但它没有填充引用。这个丑陋的代码就是当我改变它以接受指向long的指针时发生的事情,而我正在做的是获取CEnumTypes的实例来引用指针。虽然确实工作,但整件事情让我觉得有些混乱。有更清洁的方法吗?

请注意,行PSTORECLib.CEnumTypes cen = new PSTORECLib.CEnumTypes();将抛出“未注册的类”COMException。

2 个答案:

答案 0 :(得分:4)

哎呀,你是以低级别的方式攻击COM。这大致没问题,但有问题。它永远不会在64位模式下工作,uEnum不能是一个uint,它必须是一个指针。它也被泄露了,你不要为它调用Release()。你不能忽视这一点。

显然,你有一个类型库,并从中创建了一个互操作库,否则反射代码将无效。我只能猜测IDL有问题。 EnumTypes的签名表明您忘记了最后一个参数的[out,retval]属性。至少发布EnumTypes的IDL。

答案 1 :(得分:0)

我开始编辑我的帖子以提供Hans Passant要求的信息,然后我有一个顿悟并找出了问题。出于某种原因,前一个在这个项目上工作的人和我的类型库创建的旧版本都有类似的问题,可能是因为我们都比我们应该更多地信任oleview。

特别是,其中一个参数是[in]参数而不是[out]参数。 VB6并不关心,但C#很关心。