比 Marshall.QueryInterface 更简洁的编码方式?

发布于 2024-09-25 10:13:19 字数 993 浏览 3 评论 0原文

我想知道是否有一种更干净的方法来编写下面的(工作)代码:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

哆兒滾 2024-10-02 10:13:19

哎呀,你正在以低级的方式攻击 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.

染年凉城似染瑾 2024-10-02 10:13:19

我开始编辑我的帖子以提供汉斯·帕桑特要求的信息,然后我顿悟并找出了问题所在。由于某种原因,前一个参与该项目的人创建的旧版本类型库和我的都有类似的问题,可能是因为我们都比我们应该信任的更信任 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文