After using a struct from PInvoke, do I need to free memory?

I need to do something like this:

TEXTMETRIC tm;
bool isTrueType = false;
if (NativeMethods.GetTextMetrics(hDC, out tm))
{
    isTrueType = ((PitchAndFamily)tm.tmPitchAndFamily & PitchAndFamily.TMPF_TRUETYPE) == PitchAndFamily.TMPF_TRUETYPE;
    IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf<TEXTMETRIC>(tm));
    Marshal.StructureToPtr<TEXTMETRIC>(tm, ptr, true);
    Marshal.FreeHGlobal(ptr);
}

      

or will the cleared memory be automatically cleared after the function exits? I think (from what I've read) this is the last one, but I'm not sure!

Any clarification was appreciated!

+3


source to share


4 answers


Marshal.StructureToPtr<TEXTMETRIC>(tm, ptr, true);

      

Using true is very wrong here. The memory you allocated with AllocHGlobal () is not initialized and contains random bytes. It does not contain a previous version of the struct, which must be released before the method overwrites it.



This can lead to very difficult diagnostics of random failures, depending on the values ​​of the random bytes. You left with it because TEXTMETRIC contains no members to clean up. Calling FreeHGlobal () is sufficient, there is no need for Marshal.DestroyStructure (), you have to put it in a finally block to be exception safe. Which answers your question.

To complete, cleanup is required only if the structure contains a BSTR, SAFEARRAY, or COM interface pointer. Resources that have explicit release calls and require the [MarshalAs] attribute in the structure declaration. This is extremely rare when using pinvoke. Not uncommon when using COM interop, also uses StructureToPtr () under the hood, but the CLR does the call automatically.

+5


source


The function you are calling GetTextMetrics

expects the caller to allocate and free memory for the structure. If you allocate AllocHGlobal

, you must release it with FreeHGlobal

.

However, none of this is necessary. You highlight the structure when you declare tm

. Nothing else is needed there. Avoid having to call FreeHGlobal

without calling AllocHGlobal

.



TEXTMETRIC tm;
bool isTrueType = false;
if (NativeMethods.GetTextMetrics(hDC, out tm))
{
    isTrueType = ((PitchAndFamily)tm.tmPitchAndFamily & PitchAndFamily.TMPF_TRUETYPE) == PitchAndFamily.TMPF_TRUETYPE;
}

      

By avoiding manual allocation, you also avoid making a broken call, or even any call to StructureToPtr

that other answers are talking about.

+4


source


No, if you allocate memory with AllocHGlobal

, you must free it yourself. otherwise, a memory leak will occur.

Here is the relevant part of the documentation

Pointer to newly allocated memory. This memory must be released using the Marshal.FreeHGlobal method.

+2


source


If you manually allocate unmanaged memory (and you do), you need to manually free it. Add a block finally

so that the exception doesn't interfere with freeing memory.

You, for example, are not very smart, because you are copying tm

into a block of memory that you never use.

+1


source







All Articles