Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to marshal unmanaged memory for IQueryInfo

85 views
Skip to first unread message

Alan Bahm

unread,
Oct 20, 2004, 6:03:37 PM10/20/04
to
Hi all,

I'm trying to write an InfoTip extension for my filetype in explorer
(running on WinXP & W2K). The interface IQueryInfo supports this
feature (with some help from IPersistFile), through the function call
GetInfoTip. GetInfoTip requires that you return a string for the
InfoTip that is allocated off of CoTaskMem, so that the calling
process (Explorer) can deallocate it.

I'm running into some conceptual trouble with implementing this in the
managed world.

I've used the following interface definition:


[ComImport(),
Guid("00021500-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IQueryInfo
{
int GetInfoTip(
[In] int dwFlags,
[Out, MarshalAs(UnmanagedType.BStr)] out string ppwszTip);
int GetInfoFlags([Out] int pdwFlags);
}


I started by naively returning a string directly:


public int GetInfoTip(int dwFlags, out string ppwszTip)
{
Debug.WriteLine("ShellSupport.GetInfoTip(" + dwFlags + ")");
ppwszTip = "Hello world.";
return 0;
}


and while the infotip shows up briefly, the Explorer promptly crashes
(I assume because it is trying to de-allocate the string.)
So I _read_ the documentation and realized I probably should be doing
this instead:


public int GetInfoTip(int dwFlags, out string ppwszTip)
{
Debug.WriteLine("ShellSupport.GetInfoTip(" + dwFlags + ")");
ppwszTip = Marshal.StringToCoTaskMemAuto("Hello world.");
return 0;
}


but of course, ppwszTip is a *string*, not an *IntPtr*, so this won't
compile. If I change the second argument in the interface to


[Out, MarshalAs(UnmanagedType.BStr)] out IntPtr ppwszTip


then my function isn't entered at all (the COM signature is too
different?)

All told, I'm conceptually stuck, trying to figure out how to return a
.NET System.String that points to unmanaged memory. I don't think
that can be done, but I'm certain that a C# info tip _can_ be written.
What am I missing?

Any help appreciated,
Alan Bahm
ab...@feico.com

Mattias Sjögren

unread,
Oct 20, 2004, 6:22:51 PM10/20/04
to
Alan,

> int GetInfoTip(
> [In] int dwFlags,
> [Out, MarshalAs(UnmanagedType.BStr)] out string ppwszTip);
> int GetInfoFlags([Out] int pdwFlags);
> }

The return types should be void, unless you really want to explicitly
return the HRESULT, in which case you should add the [PreserveSig]
attribute to the methods.

The string parameter should be an LPWSTR, not a BSTR, so use
UnmanagedType.LPWStr instead.

pdwFlags should be an out parameter. Note that out == [Out] ref, so
using only the [Out] attribute isn't enough.


>and while the infotip shows up briefly, the Explorer promptly crashes
>(I assume because it is trying to de-allocate the string.)

More likely because your method signatures are incorrect.


>If I change the second argument in the interface to
>
>
> [Out, MarshalAs(UnmanagedType.BStr)] out IntPtr ppwszTip
>
>
>then my function isn't entered at all (the COM signature is too
>different?)

That should work too if you remove the MarshalAs attribute. But the
runtime returns out strings in CoTaskMemAlloc'ed memory by default so
using a string should be easier.

Mattias

--
Mattias Sjögren [MVP] mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Please reply only to the newsgroup.

Alan Bahm

unread,
Oct 21, 2004, 4:36:02 PM10/21/04
to
Mattias,

Thank you very much! I didn't realize that the interop takes care of
the string allocation.
You were right - I went back over the signatures, and I got it working
after changing the int return value to void.

Best regards,
Alan

0 new messages