“ref”的奇怪后果C# 到 COM 互操作中的关键字
考虑可以在此处找到的代码摘录:
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
使用 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**
非空位来自方法内部 - 它正在将一个对象实例化到您提供的引用上。在引用类型上使用 ref 关键字会将调用者引用传递给该对象,而不是创建对该对象的另一个引用(这就是通常通过引用传递时发生的情况)。试试这个:
变量测试将是错误的。
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:
The variable test will be false.
当您使用
ref
时,您实际上并没有发送null
,而是发送对null
存储位置的引用,但是当您在没有ref
的情况下发送时,您将发送实际值,即null
。所以:
对于 ref 来说,它是对空指针的引用。
没有它,它只是一个空指针。
编辑:如果我正确理解你的问题,我不能百分百确定......
When you use the
ref
, you're not actually sending in thenull
, you're sending in a reference to where thatnull
is stored, but when you're sending in without theref
you're sending in the actual value, which isnull
.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...