Reputation: 389
I am using Marshal.AllocHGlobal
c# method to allocate memory for a IntPtr and then copying the contain of a byte[]:
byte[] clientIpAddr = System.Text.Encoding.ASCII.GetBytes("127.0.0.1")
IntPtr client_ipAddr_p = IntPtr.Zero;
ipAddress_p = Marshal.AllocHGlobal(clientIpAddr.Length);
Marshal.Copy(clientIpAddr, 0, ipAddress_p, clientIpAddr.Length);
Then I pass the pointer to a C++ external library that receive my variable like this:
int open_socket(char *clientIpAddr_p)
{
<open a socket>
}
According to the definition of AllocHGlobal
it eventually could reserve more memory than expected (which I can assure because I am now suffering it). The problem is that I need my IntPtr
to have exactly the size I am requesting because I need the IP to be exact to open a socket afterwards.
Is there a better way to allocate external memory that assure the char *
to have my correct IP?
Upvotes: 2
Views: 1243
Reputation:
It is not a problem that Marshal.AllocHGlobal allocates more then the specified amount of memory. Your code suffers from a different and quite likely fatal problem.
open_socket(char *clientIpAddr_p)
expects a pointer to a C-style null-terminated string (also known as NUL-terminated string, zero-terminated string or ASCIIZ). However, your C# code creates a buffer and fills it with the string characters/bytes without terminating it with a null character. Quite possibly this will make the open_socket function crash or otherwisely misbehave when searching the memory (starting at the address given by the pointer) for the missing null character.
A possible fix would be rather simple: Allocate the buffer with a size of clientIpAddr.Length + 1
, accounting for the terminating null character. The zero-terminator (a null byte) has to be set explicitly, since Marshal.AllocHGlobal does not initialize/fill the allocated buffer with null bytes. Since we are dealing with an ASCII/ANSI string here the null character is simply a byte with a value of zero.
byte[] clientIpAddr = System.Text.Encoding.ASCII.GetBytes("127.0.0.1")
IntPtr client_ipAddr_p = Marshal.AllocHGlobal(clientIpAddr.Length + 1);
Marshal.Copy(clientIpAddr, 0, ipAddress_p, clientIpAddr.Length);
Marshal.WriteByte(client_ipAddr_p, clientIpAddr.Length, 0);
Okay, forget about the code i just wrote. ;-)
Why? Because there is an even simpler "one-stop" solution to the problem, saving you from the hassle of manually allocating and filling the buffer for the C-style null-terminated string: The Marshal.StringToHGlobalAnsi
method, which will convert your .NET string with the IP address directly into a corresponding C-style null-terminated ANSI string.
string ipAddress = "127.0.0.1";
IntPtr client_ipAddr_p = Marshal.StringToHGlobalAnsi(ipAddress);
(Unless the open_socket function requires the string buffer pointed at by clientIpAddr_p to continue existing after calling it, free the allocated buffer using the Marshal.FreeHGlobal
method after calling the native function, irregardless of whether the buffer has been allocated using Marshal.AllocHGlobal or Marshal.StringToHGlobalAnsi.)
Upvotes: 4