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?