Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Will using MarshalAs(UnmanagedType.LPWStr) cleanup memory?

I'm trying to write a pinvoke for the ITaskTrigger::GetTriggerString method (defined at http://msdn.microsoft.com/en-us/library/windows/desktop/aa381866(v=vs.85).aspx). If you look at the page, it says that the caller of the method is responsible for freeing the memory (via CoTaskMemFree) of the LPWSTR referenced via the first argument. While I could do that manually in .NET or could write my custom marshaler using ICustomMarshaler, I was wondering if using the MarshalAs(UnmanagedType.LPWStr) attribute for that particular argument will free the memory appropriately.

Can anyone provide some insight?

like image 472
wwahammy Avatar asked Nov 20 '11 02:11

wwahammy


1 Answers

First things first: you're talking about COM Interop here (ITaskTrigger is a COM interface), not P/Invoke. There are different interop rules for the two, so it's important to keep them straight. For example, you'll need to define C# interop wrappers for the entire interface, not just the method you want. These should get you started: pinvoke.net

The short answer is, you're in luck, becase the CLR should take care of things properly for you.

The longer answer involves the different types of marshalling the COM interop code does, depending on the parameter types, directions, and what attributes you add to your interop signatures.

In this case, the parameter type you will get on the call is an "out string" parameter, with a MarshalAs(UnmanagedType.LPWSTR) attribute. When a COM server exposes a call that has an "out" parameter of LPWSTR string type, assuming the server is keeping up its end of the deal, it will allocate a memory buffer with CoTaskMemAlloc() and return it to you. (If it was a different string type, like a BSTR, the specific memory allocation call might be different, but the basic concept is the same.) At this point, you are responsible for cleaning up that memory when you no longer need it, using the matching CoTaskMemFree() call.

This is a special type of operation called a "reference change": the parameter you are sending in is already a reference parameter, but the COM server is going to replace it with a different reference. A good explanation for this process is found in the "Memory Ownership" section of this MSDN magazine article. As you can see from that article, when the CLR receives data back from an "out" parameter on a reference type, it recognizes that it is taking responsibility for freeing that memory. While marshaling that call back to managed code, it uses the MarshalAs attribute to determine that this is a LPWSTR string-type pointer in COM, and that it should therefore have been allocated using CoTaskMemAlloc(). After creating a managed string out of the data, it will call CoTaskMemFree() on the original buffer on your behalf. The data you get back will be fully managed and you won't have to deal with any ownership problems.

like image 70
Michael Edenfield Avatar answered Sep 28 '22 13:09

Michael Edenfield