IntPtr и избегая небезопасного кода - PullRequest
4 голосов
/ 26 июля 2010

У меня есть внешняя библиотека, которая принимает IntPtr. Есть ли безопасный способ сделать это ...

int BytesWritten = 0;
Output.WriteBytes(buffer, new IntPtr(&BytesWritten));

... без использования «небезопасного» кода? Я не очень знаком с IntPtrs, но я бы хотел сделать что-то вроде этого:

fixed int BytesWritten = 0;
Output.WriteBytes(buffer, IntPtr.GetSafeIntPtr(ref BytesWritten));

... таким образом, что мне не нужно компилировать с /unsafe.

Я не могу изменить функцию WriteBytes, это внешняя функция.

Похоже, что между `ref int 'и IntPtr должно быть какое-то приведение, но мне не повезло найти его.

Ответы [ 3 ]

2 голосов
/ 26 июля 2010

Я предполагаю, что Output.WriteBytes - это метод [DllImport]. Вы можете опубликовать декларацию?

Вы сможете избежать указателя, объявив последний параметр как out int вместо IntPtr - пусть маршаллер P / Invoke сделает все остальное.

2 голосов
/ 26 июля 2010

Да, есть.Вы можете использовать P / Invoke для своего кода.Это создаст указатель для вас автоматически.Примерно так:

[DllImport("yourlib", SetLastError=true)]
static extern bool WriteBytes(
    [MarshalAs(UnmanagedType.LPArray)]
    byte [] buffer,
    ref int BytesWritten);

(я добавил массив в качестве бонуса) .Дополнительную информацию о P / Invoke, с примерами из gazillion, можно найти по адресу pinvoke.net .

Каждый параметр выше может принимать out, in и refПараметры out и ref переводятся как указатели, где параметр ref является двусторонним.

1 голос
/ 26 июля 2010

Вот класс, который предоставит вам безопасную реализацию IntPtr.Он происходит от класса SafeHandleZeroOrMinusOneIsInvalid, предоставляемого .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);
        }
    }
}
...