考虑一下可以找到的代码摘录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()
基本上调用LoadIFilter()函数。后者查找注册表,查找哪个类id对应于指定的文件扩展名,实例化相应的COM类(调用CoCreateInstance()
)并从中调用IPersistFile::Load()
。
现在问题是LoadIFilter()
的签名如下:
HRESULT __stdcall LoadIFilter( PCWSTR pwcsPath, __in IUnknown *pUnkOuter, __out void **ppIUnk );
所以第二个参数是聚合对象的IUnknown*
。如果感兴趣的扩展的COM类不支持聚合并且传递的IUnknown*
不为空CoCreateInstance()
则返回CLASS_E_NOAGGREGATION
,LoadIFilter()
也是如此。
如果我从声明中的ref
参数和pUnkOuter
网站上删除了LoadIFilter()
关键字,则调用该函数为null IUnknown*
。如果我保留ref
关键字,则使用非空IUnknown*
调用该函数,并为不支持聚合的类返回CLASS_E_NOAGGREGATION
。
我的问题是 - 为什么在保留关键字时会传递非空IUnknown*
? IUnknown iunk
局部变量初始化为null
,因此非空IUnknown*
来自调用的非托管代码?
答案 0 :(得分:3)
当您使用ref
时,实际上并未发送null
,而是发送了null
存储位置的引用,但是当您使用ref
时在没有null
发送实际值的情况下发送,{{1}}。
所以:
使用ref它是对空指针的引用。
没有它,它只是一个空指针。
编辑:如果我理解你的问题,我不是100%肯定的......
答案 1 :(得分:2)
使用ref是完全错误的,你的IUnknown已经作为指针传递,因为它是一个接口。传递ref将等同于IUnknown **
答案 2 :(得分:1)
非null位来自方法内部 - 它将对象实例化到您提供的引用上。在引用类型上使用ref关键字会将调用者引用传递给该对象,而不是创建对该对象的另一个引用(这是通过引用正常传递时会发生的情况)。试试这个:
static void Main()
{
object foo = null;
SetMyObject(ref foo);
bool test = foo == null;
}
public static void SetMyObject(ref object foo)
{
foo = new object();
}
变量测试将为false。