IntPtr and avoiding unsafe code
I have an external library that takes an IntPtr. Is there any safe way to do this...
int BytesWritten = 0;
Output.WriteBytes(buffer, new IntPtr(&BytesWritten));
...without having to use 'unsafe' code? I'm not that familiar with IntPtrs, but I'd like to do something like this:
fixed int BytesWritten = 0;
Output.WriteBytes(buffer, IntPtr.GetSafeIntPtr(ref BytesWritten));
...in such a way that I don't need to compile with /unsafe.
I can't change the WriteBytes function, it'开发者_StackOverflow社区s an external function.
It seems like there should be some sort of cast between 'ref int' and IntPtr, but I have not had luck finding it.
I assume that Output.WriteBytes
is a [DllImport]
method. Can you post the declaration?
You should be able to avoid the pointer by declaring the last parameter as out int
instead of IntPtr
-- let the P/Invoke marshaller do the rest.
Yes, there is. You can use P/Invoke for your code. It will create the pointer for you automagically. Something like this:
[DllImport("yourlib", SetLastError=true)]
static extern bool WriteBytes(
[MarshalAs(UnmanagedType.LPArray)]
byte [] buffer,
ref int BytesWritten);
(I added the array as a bonus). More info on P/Invoke can be found, with gazillion examples, at pinvoke.net.
Each parameter above can take out
, in
and ref
. Out and ref parameters are translated as pointers, where an ref-parameter is two-way.
Here is a class that will provide you with a safe IntPtr implementation. It derives from the SafeHandleZeroOrMinusOneIsInvalid class, provided by the .NET framework.
/// <summary>
/// IntPtr wrapper which can be used as result of
/// Marshal.AllocHGlobal operation.
/// Call Marshal.FreeHGlobal when disposed or finalized.
/// </summary>
class HGlobalSafeHandle : SafeHandleZeroOrMinusOneIsInvalid
{
/// <summary>
/// Creates new instance with given IntPtr value
/// </summary>
public HGlobalSafeHandle(IntPtr ptr) : base(ptr, true)
{
}
/// <summary>
/// Creates new instance with zero IntPtr
/// </summary>
public HGlobalSafeHandle() : base(IntPtr.Zero, true)
{
}
/// <summary>
/// Creates new instance which allocates unmanaged memory of given size
/// Can throw OutOfMemoryException
/// </summary>
public HGlobalSafeHandle(int size) :
base(Marshal.AllocHGlobal(size), true)
{
}
/// <summary>
/// Allows to assign IntPtr to HGlobalSafeHandle
/// </summary>
public static implicit operator HGlobalSafeHandle(IntPtr ptr)
{
return new HGlobalSafeHandle(ptr);
}
/// <summary>
/// Allows to use HGlobalSafeHandle as IntPtr
/// </summary>
public static implicit operator IntPtr(HGlobalSafeHandle h)
{
return h.handle;
}
/// <summary>
/// Called when object is disposed or finalized.
/// </summary>
override protected bool ReleaseHandle()
{
Marshal.FreeHGlobal(handle);
return true;
}
/// <summary>
/// Defines invalid (null) handle value.
/// </summary>
public override bool IsInvalid
{
get
{
return (handle == IntPtr.Zero);
}
}
}
精彩评论