“ref”的奇怪后果C# 到 COM 互操作中的关键字

发布于 2024-09-07 10:30:10 字数 2286 浏览 3 评论 0原文

考虑可以在此处找到的代码摘录:

namespace WinSearchFile
{
    public class Parser
    {
        [DllImport("query.dll", CharSet = CharSet.Unicode)] 
        private extern static int LoadIFilter (string pwcsPath, ref IUnknown pUnkOuter, ref IFilter ppIUnk); 

        [ComImport, Guid("00000000-0000-0000-C000-000000000046")] 
        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
        private interface IUnknown 
        { 
            [PreserveSig] 
            IntPtr QueryInterface( ref Guid riid, out IntPtr pVoid ); 
            [PreserveSig] 
            IntPtr AddRef(); 
            [PreserveSig] 
            IntPtr Release(); 
        } 

        private static IFilter loadIFilter(string filename)
        {
            IUnknown iunk = null; 
            IFilter filter = null;

            // Try to load the corresponding IFilter 
            int resultLoad = LoadIFilter( filename, ref iunk, ref filter ); 
            if (resultLoad != (int)IFilterReturnCodes.S_OK) 
            { 
                return null;
            } 
            return filter;
        }
  }

解析器:该代码中的 :loadIFilter() 基本上调用 LoadIFilter() 函数。后者查找注册表,找到与指定文件扩展名对应的类 id,实例化相应的 COM 类(调用 CoCreateInstance())并调用 IPersistFile::Load() 来自它。

现在的问题是 LoadIFilter() 的签名如下:

HRESULT __stdcall LoadIFilter( PCWSTR pwcsPath, __in IUnknown *pUnkOuter, __out void **ppIUnk );

因此第二个参数是聚合对象的 IUnknown* 。如果感兴趣的扩展的 COM 类不支持聚合并且传递的 IUnknown* 不为 null CoCreateInstance() 返回 CLASS_E_NOAGGREGATION 等等执行LoadIFilter()

如果我从声明中的 pUnkOuter 参数中删除 ref 关键字,并在 LoadIFilter() 调用处调用该函数,并使用 null <代码>IUnknown*。如果我保留 ref 关键字,则会使用非 null IUnknown* 调用该函数,并为不支持聚合的类返回 CLASS_E_NOAGGREGATION

我的问题是 - 为什么保留关键字时会传递非空 IUnknown*IUnknown iunk 局部变量被初始化为 null 那么非空 IUnknown* 在调用的非托管代码中来自哪里?

Consider an excerpt from code that can be found here:

namespace WinSearchFile
{
    public class Parser
    {
        [DllImport("query.dll", CharSet = CharSet.Unicode)] 
        private extern static int LoadIFilter (string pwcsPath, ref IUnknown pUnkOuter, ref IFilter ppIUnk); 

        [ComImport, Guid("00000000-0000-0000-C000-000000000046")] 
        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
        private interface IUnknown 
        { 
            [PreserveSig] 
            IntPtr QueryInterface( ref Guid riid, out IntPtr pVoid ); 
            [PreserveSig] 
            IntPtr AddRef(); 
            [PreserveSig] 
            IntPtr Release(); 
        } 

        private static IFilter loadIFilter(string filename)
        {
            IUnknown iunk = null; 
            IFilter filter = null;

            // Try to load the corresponding IFilter 
            int resultLoad = LoadIFilter( filename, ref iunk, ref filter ); 
            if (resultLoad != (int)IFilterReturnCodes.S_OK) 
            { 
                return null;
            } 
            return filter;
        }
  }

Parser::loadIFilter() in that code basically calls LoadIFilter() function. The latter looks up the registry, finds which class id corresponds to the specified file extension, instantiates a corresponding COM class (calls CoCreateInstance()) and calls IPersistFile::Load() from it.

Now the problem is that the signature for LoadIFilter() is the following:

HRESULT __stdcall LoadIFilter( PCWSTR pwcsPath, __in IUnknown *pUnkOuter, __out void **ppIUnk );

so the second parameter is IUnknown* of the aggregating object. If the COM class for the extension of interest doesn't support aggregation and the IUnknown* passed is not null CoCreateInstance() returns CLASS_E_NOAGGREGATION and so does LoadIFilter().

If I remove the ref keyword from the pUnkOuter parameter in the declaration and at the site of LoadIFilter() call the function is called with null IUnknown*. If I retain the ref keyword the function is called with non-null IUnknown* and returns CLASS_E_NOAGGREGATION for classes that don't support aggregation.

My question is - why is non-null IUnknown* passed when the keyword is retained? IUnknown iunk local variable is initialized to null so where does non-null IUnknown* come from in the invoked unmanaged code?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(3

二智少女 2024-09-14 10:30:11

使用 ref 是完全错误的,您的 IUnknown 已经作为指针传递,因为它是一个接口。传递 ref 相当于 IUnknown**

Using ref is simply wrong, your IUnknown is already passed as a pointer since it is an interface. Passing ref would be equivalent to IUnknown**

姐不稀罕 2024-09-14 10:30:11

非空位来自方法内部 - 它正在将一个对象实例化到您提供的引用上。在引用类型上使用 ref 关键字会将调用者引用传递给该对象,而不是创建对该对象的另一个引用(这就是通常通过引用传递时发生的情况)。试试这个:

static void Main()
{
    object foo = null;
    SetMyObject(ref foo);

    bool test = foo == null;
}

public static void SetMyObject(ref object foo)
{
    foo = new object();
}

变量测试将是错误的。

The non-null bit comes from inside the method - it is instantiating an object onto the reference you've provided. Using the ref keyword on a reference type will pass the callers reference to the object, not creating another reference to the object (which is what happens when you pass by reference normally). Try this:

static void Main()
{
    object foo = null;
    SetMyObject(ref foo);

    bool test = foo == null;
}

public static void SetMyObject(ref object foo)
{
    foo = new object();
}

The variable test will be false.

寄意 2024-09-14 10:30:10

当您使用 ref 时,您实际上并没有发送 null,而是发送对 null 存储位置的引用,但是当您在没有 ref 的情况下发送时,您将发送实际值,即 null

所以:

对于 ref 来说,它是对空指针的引用。

没有它,它只是一个空指针。

编辑:如果我正确理解你的问题,我不能百分百确定......

When you use the ref, you're not actually sending in the null, you're sending in a reference to where that null is stored, but when you're sending in without the ref you're sending in the actual value, which is null.

So:

With ref it's a reference to a null pointer.

Without it it's just a null pointer.

Edit: If I understand your question correctly, which I'm not 100% certain off...

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