Need to Free Memory after p/invoke?

M

Morgan Cheng

In http://www.pinvoke.net/default.aspx/urlmon.FindMimeFromData, it is
suggested to use FindMimeFromData in below way.
[DllImport("urlmon.dll", CharSet = CharSet.Unicode, ExactSpelling =
true, SetLastError = false)]
static extern int FindMimeFromData(IntPtr pBC,
[MarshalAs(UnmanagedType.LPWStr)] string pwzUrl,
[MarshalAs(UnmanagedType.LPArray,
ArraySubType=UnmanagedType.I1, SizeParamIndex=3)]
byte[] pBuffer,
int cbSize,
[MarshalAs(UnmanagedType.LPWStr)] string pwzMimeProposed,
int dwMimeFlags,
out IntPtr ppwzMimeOut,
int dwReserved);

I tried in another way by have output parameter ppwzMimeOut to be
StringBuilder. It also works.

If I have the function return a IntPtr. Then, I should free the
returned pointer with Marshal.FreeCoTaskMem, right? While, I have no
need to free a StringBuilder(actually I have no idea how to). It looks
like use StringBuilde is better. Is there any trick that original
author have the output parameter as IntPtr?
 
W

Willy Denoyette [MVP]

| In http://www.pinvoke.net/default.aspx/urlmon.FindMimeFromData, it is
| suggested to use FindMimeFromData in below way.
| [DllImport("urlmon.dll", CharSet = CharSet.Unicode, ExactSpelling =
| true, SetLastError = false)]
| static extern int FindMimeFromData(IntPtr pBC,
| [MarshalAs(UnmanagedType.LPWStr)] string pwzUrl,
| [MarshalAs(UnmanagedType.LPArray,
| ArraySubType=UnmanagedType.I1, SizeParamIndex=3)]
| byte[] pBuffer,
| int cbSize,
| [MarshalAs(UnmanagedType.LPWStr)] string pwzMimeProposed,
| int dwMimeFlags,
| out IntPtr ppwzMimeOut,
| int dwReserved);
|
| I tried in another way by have output parameter ppwzMimeOut to be
| StringBuilder. It also works.
|
| If I have the function return a IntPtr. Then, I should free the
| returned pointer with Marshal.FreeCoTaskMem, right? While, I have no
| need to free a StringBuilder(actually I have no idea how to). It looks
| like use StringBuilde is better. Is there any trick that original
| author have the output parameter as IntPtr?
|

The urlmon buffer (pointed to by ppwzMimeOut) is allocated using
CoTaskMemAlloc, so it must be freed using it's counterpart CoTaskMemFree.
If you pass a String, the buffer will automaically be freed by the CLR (the
interop layer free's all strings using CoTaskMemFree).
However, if you pass a pointer to an IntPtr, it's up to you to marshal the
buffer to the correct string representation AND to free the buffer by
calling the matching counter-part of the function used to allocate the
buffer (here, Marshal.FreeCoTaskMem).
So, in this case I would suggest you to use "out String" as argument and let
the CLR do the freeing.

Willy.
 
M

Morgan Cheng

Willy Denoyette [MVP] 写é“:
| In http://www.pinvoke.net/default.aspx/urlmon.FindMimeFromData, it is
| suggested to use FindMimeFromData in below way.
| [DllImport("urlmon.dll", CharSet = CharSet.Unicode, ExactSpelling =
| true, SetLastError = false)]
| static extern int FindMimeFromData(IntPtr pBC,
| [MarshalAs(UnmanagedType.LPWStr)] string pwzUrl,
| [MarshalAs(UnmanagedType.LPArray,
| ArraySubType=UnmanagedType.I1, SizeParamIndex=3)]
| byte[] pBuffer,
| int cbSize,
| [MarshalAs(UnmanagedType.LPWStr)] string pwzMimeProposed,
| int dwMimeFlags,
| out IntPtr ppwzMimeOut,
| int dwReserved);
|
| I tried in another way by have output parameter ppwzMimeOut to be
| StringBuilder. It also works.
|
| If I have the function return a IntPtr. Then, I should free the
| returned pointer with Marshal.FreeCoTaskMem, right? While, I have no
| need to free a StringBuilder(actually I have no idea how to). It looks
| like use StringBuilde is better. Is there any trick that original
| author have the output parameter as IntPtr?
|

The urlmon buffer (pointed to by ppwzMimeOut) is allocated using
CoTaskMemAlloc, so it must be freed using it's counterpart CoTaskMemFree.
If you pass a String, the buffer will automaically be freed by the CLR (the
interop layer free's all strings using CoTaskMemFree).
However, if you pass a pointer to an IntPtr, it's up to you to marshal the
buffer to the correct string representation AND to free the buffer by
calling the matching counter-part of the function used to allocate the
buffer (here, Marshal.FreeCoTaskMem).
So, in this case I would suggest you to use "out String" as argument and let
the CLR do the freeing.
I tried both with StringBuilder and IntPtr.
If StringBuilder is used. Sometimes, it will raise a exceptiion
"System.ArgumentOutOfRangeException:Capacity exceeds maximum
capacity.
Parameter name: capacity"
If IntPtr is used, no such exception is raised yet. I am not clear why
this happens.
 
W

Willy Denoyette [MVP]

Willy Denoyette [MVP] å?Té"ï¼s
| In http://www.pinvoke.net/default.aspx/urlmon.FindMimeFromData, it is
| suggested to use FindMimeFromData in below way.
| [DllImport("urlmon.dll", CharSet = CharSet.Unicode, ExactSpelling =
| true, SetLastError = false)]
| static extern int FindMimeFromData(IntPtr pBC,
| [MarshalAs(UnmanagedType.LPWStr)] string pwzUrl,
| [MarshalAs(UnmanagedType.LPArray,
| ArraySubType=UnmanagedType.I1, SizeParamIndex=3)]
| byte[] pBuffer,
| int cbSize,
| [MarshalAs(UnmanagedType.LPWStr)] string pwzMimeProposed,
| int dwMimeFlags,
| out IntPtr ppwzMimeOut,
| int dwReserved);
|
| I tried in another way by have output parameter ppwzMimeOut to be
| StringBuilder. It also works.
|
| If I have the function return a IntPtr. Then, I should free the
| returned pointer with Marshal.FreeCoTaskMem, right? While, I have no
| need to free a StringBuilder(actually I have no idea how to). It looks
| like use StringBuilde is better. Is there any trick that original
| author have the output parameter as IntPtr?
|

The urlmon buffer (pointed to by ppwzMimeOut) is allocated using
CoTaskMemAlloc, so it must be freed using it's counterpart CoTaskMemFree.
If you pass a String, the buffer will automaically be freed by the CLR
(the
interop layer free's all strings using CoTaskMemFree).
However, if you pass a pointer to an IntPtr, it's up to you to marshal the
buffer to the correct string representation AND to free the buffer by
calling the matching counter-part of the function used to allocate the
buffer (here, Marshal.FreeCoTaskMem).
So, in this case I would suggest you to use "out String" as argument and
let
the CLR do the freeing.
I tried both with StringBuilder and IntPtr.
If StringBuilder is used. Sometimes, it will raise a exceptiion
"System.ArgumentOutOfRangeException:Capacity exceeds maximum
capacity.
Parameter name: capacity"
If IntPtr is used, no such exception is raised yet. I am not clear why
this happens.



The problem with the StringBuilder usage is that YOU are responsible to
pre-allocate a buffer big enough to hold the return string. The default
StringBuilder (when no size is specified) is 16 characters, so, when the
unmanaged buffer contains more than 16 characters, your call will fail.

When using the IntPtr you will call the marshaler to copy the buffer
(holding a zero terminated wide string) and the marshaler is able to figure
out the required buffer size.
The same is tru when using:

String s;
FindMimeFromData(..., out s,...);
Here the marshaler creates string s buffer with the size obtained from the
unmanaged buffer contents.

Willy.
 
M

Morgan Cheng

Willy Denoyette [MVP] 写é“:
Willy Denoyette [MVP] Ã¥?TéÂ"ï¼s
| In http://www.pinvoke.net/default.aspx/urlmon.FindMimeFromData, it is
| suggested to use FindMimeFromData in below way.
| [DllImport("urlmon.dll", CharSet = CharSet.Unicode, ExactSpelling =
| true, SetLastError = false)]
| static extern int FindMimeFromData(IntPtr pBC,
| [MarshalAs(UnmanagedType.LPWStr)] string pwzUrl,
| [MarshalAs(UnmanagedType.LPArray,
| ArraySubType=UnmanagedType.I1, SizeParamIndex=3)]
| byte[] pBuffer,
| int cbSize,
| [MarshalAs(UnmanagedType.LPWStr)] string pwzMimeProposed,
| int dwMimeFlags,
| out IntPtr ppwzMimeOut,
| int dwReserved);
|
| I tried in another way by have output parameter ppwzMimeOut to be
| StringBuilder. It also works.
|
| If I have the function return a IntPtr. Then, I should free the
| returned pointer with Marshal.FreeCoTaskMem, right? While, I have no
| need to free a StringBuilder(actually I have no idea how to). It looks
| like use StringBuilde is better. Is there any trick that original
| author have the output parameter as IntPtr?
|

The urlmon buffer (pointed to by ppwzMimeOut) is allocated using
CoTaskMemAlloc, so it must be freed using it's counterpart CoTaskMemFree.
If you pass a String, the buffer will automaically be freed by the CLR
(the
interop layer free's all strings using CoTaskMemFree).
However, if you pass a pointer to an IntPtr, it's up to you to marshal the
buffer to the correct string representation AND to free the buffer by
calling the matching counter-part of the function used to allocate the
buffer (here, Marshal.FreeCoTaskMem).
So, in this case I would suggest you to use "out String" as argument and
let
the CLR do the freeing.
I tried both with StringBuilder and IntPtr.
If StringBuilder is used. Sometimes, it will raise a exceptiion
"System.ArgumentOutOfRangeException:Capacity exceeds maximum
capacity.
Parameter name: capacity"
If IntPtr is used, no such exception is raised yet. I am not clear why
this happens.



The problem with the StringBuilder usage is that YOU are responsible to
pre-allocate a buffer big enough to hold the return string. The default
StringBuilder (when no size is specified) is 16 characters, so, when the
unmanaged buffer contains more than 16 characters, your call will fail.

When using the IntPtr you will call the marshaler to copy the buffer
(holding a zero terminated wide string) and the marshaler is able to figure
out the required buffer size.
The same is tru when using:

String s;
FindMimeFromData(..., out s,...);
Here the marshaler creates string s buffer with the size obtained from the
unmanaged buffer contents.
Thanks for your clarification.
So, does it mean that String as output parameter is recommended instead
of StringBuilder?
 
W

Willy Denoyette [MVP]

Willy Denoyette [MVP] å?Té"ï¼s
Willy Denoyette [MVP] Ã¥?TéÂ"ï¼s
| In http://www.pinvoke.net/default.aspx/urlmon.FindMimeFromData, it is
| suggested to use FindMimeFromData in below way.
| [DllImport("urlmon.dll", CharSet = CharSet.Unicode, ExactSpelling =
| true, SetLastError = false)]
| static extern int FindMimeFromData(IntPtr pBC,
| [MarshalAs(UnmanagedType.LPWStr)] string pwzUrl,
| [MarshalAs(UnmanagedType.LPArray,
| ArraySubType=UnmanagedType.I1, SizeParamIndex=3)]
| byte[] pBuffer,
| int cbSize,
| [MarshalAs(UnmanagedType.LPWStr)] string pwzMimeProposed,
| int dwMimeFlags,
| out IntPtr ppwzMimeOut,
| int dwReserved);
|
| I tried in another way by have output parameter ppwzMimeOut to be
| StringBuilder. It also works.
|
| If I have the function return a IntPtr. Then, I should free the
| returned pointer with Marshal.FreeCoTaskMem, right? While, I have no
| need to free a StringBuilder(actually I have no idea how to). It looks
| like use StringBuilde is better. Is there any trick that original
| author have the output parameter as IntPtr?
|

The urlmon buffer (pointed to by ppwzMimeOut) is allocated using
CoTaskMemAlloc, so it must be freed using it's counterpart
CoTaskMemFree.
If you pass a String, the buffer will automaically be freed by the CLR
(the
interop layer free's all strings using CoTaskMemFree).
However, if you pass a pointer to an IntPtr, it's up to you to marshal
the
buffer to the correct string representation AND to free the buffer by
calling the matching counter-part of the function used to allocate the
buffer (here, Marshal.FreeCoTaskMem).
So, in this case I would suggest you to use "out String" as argument and
let
the CLR do the freeing.
I tried both with StringBuilder and IntPtr.
If StringBuilder is used. Sometimes, it will raise a exceptiion
"System.ArgumentOutOfRangeException:Capacity exceeds maximum
capacity.
Parameter name: capacity"
If IntPtr is used, no such exception is raised yet. I am not clear why
this happens.



The problem with the StringBuilder usage is that YOU are responsible to
pre-allocate a buffer big enough to hold the return string. The default
StringBuilder (when no size is specified) is 16 characters, so, when the
unmanaged buffer contains more than 16 characters, your call will fail.

When using the IntPtr you will call the marshaler to copy the buffer
(holding a zero terminated wide string) and the marshaler is able to
figure
out the required buffer size.
The same is tru when using:

String s;
FindMimeFromData(..., out s,...);
Here the marshaler creates string s buffer with the size obtained from the
unmanaged buffer contents.
Thanks for your clarification.
So, does it mean that String as output parameter is recommended instead
of StringBuilder?


Yep, in that case it's better to pass a String.


Willy.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top