比 Marshall.QueryInterface 更简洁的编码方式?
我想知道是否有一种更干净的方法来编写下面的(工作)代码:
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);
当我尝试在 PSTORECLib 的 idl 文件中填充 IEnumPStoreTypes**
时(即当我使用 oleview 的初始 IDL 输出)调用 PStore.EnumTypes
,tlbimp 的 dll 输出告诉我传递对 CEnumTypes
的引用。该函数对此很满意(它返回了 S_OK),但它没有填充引用。当我将其更改为接受指向 long 的指针时,就会发生这种混乱的丑陋代码,并且是我为获取 CEnumTypes 实例来引用该指针所做的事情。整件事让我觉得有点混乱,尽管它确实有效。有没有更干净的方法来做到这一点?
请注意,PSTORECLib.CEnumTypes cen = new PSTORECLib.CEnumTypes();
行将抛出“Class Not Registered”COMException。
I am wondering if there is a cleaner way to write the (working) code below:
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);
When I tried stuffing IEnumPStoreTypes**
in the idl file of the PSTORECLib (i.e. when I used the initial IDL output by oleview) into the call to PStore.EnumTypes
, the dll output by tlbimp told me to pass in a reference to a CEnumTypes
. The function was happy with this (it returned S_OK), but it didn't populate the reference. This mess of ugly code is what happened when I changed it to accept a pointer to a long instead, and is what I did to get an instance of CEnumTypes to refer to the pointer. This whole thing strikes me as being a bit messy, though it does work. Is there a cleaner way to do this?
Note that the line PSTORECLib.CEnumTypes cen = new PSTORECLib.CEnumTypes();
will throw a "Class Not Registered" COMException.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
哎呀,你正在以低级的方式攻击 COM。大致上还可以,但是也有问题。它永远不会在 64 位模式下工作,uEnum 不能是 uint,它必须是指针。它也被泄露了,你没有为它调用 Release() 。你不能忽视这一点。
显然,您已经有了一个类型库并从中创建了一个互操作库,否则反射代码将无法工作。我只能猜测 IDL 有问题。 EnumTypes 的签名表明您忘记了最后一个参数的 [out,retval] 属性。至少发布 EnumTypes 的 IDL。
Ouch, you're hacking COM the low-level way. It is roughly okay, but there are problems. It will never work in 64-bit mode, uEnum can't be a uint, it has to be a pointer. It is also being leaked, you don't call Release() for it. You can't ignore that.
Clearly you've got a type library and created a interop library from it or else the reflection code wouldn't work. I can only guess that there's something wrong with the IDL. The signature of EnumTypes suggests that you forgot the [out,retval] attributes on the last argument. At least post the IDL for EnumTypes.
我开始编辑我的帖子以提供汉斯·帕桑特要求的信息,然后我顿悟并找出了问题所在。由于某种原因,前一个参与该项目的人创建的旧版本类型库和我的都有类似的问题,可能是因为我们都比我们应该信任的更信任 oleview。
特别是,参数之一是 [in] 参数而不是 [out] 参数。 VB6 并不关心,但 C# 非常关心。
I started to edit my post to provide the information Hans Passant asked for, then I had an epiphany and figured out the problem. For some reason, both the old version of the typelibrary created by a previous person working on this project and mine had a similar issue, likely because both of us trusted oleview more than we should have.
In particular, one of the parameters was an [in] parameter instead of an [out] parameter. VB6 didn't care, but C# cared a lot.