温故知新,CSharp遇见IntPtr,通过System.IntPtr来操作句柄(Handle)和指针

image

句柄(Handle)缘来

.NET提供了一个结构体System.IntPtr专门用来代表句柄或指针。

句柄是对象的标识符,当调用这些API创建对象时,它们并不直接返回指向对象的指针,而是会返回一个32位或64位的整数值,这个在进程或系统范围内唯一的整数值就是句柄(Handle),随后程序再次访问对象,或者删除对象,都将句柄作为Windows API的参数来间接对这些对象进行操作。

句柄指向就是指向文件开头,在windows系统所有的东西都是文件,对象也是文件。所以句柄和指针是一样的意思。句柄是面向对象的指针的称呼。

指针是对存储区域的引用,该区域包含您感兴趣的一些数据。指针是面向过程编程的称呼。

IntPtr类是IntPointer的缩写。

C#中用来取代指针,也可以说对指针进行封装,指向托管内存。

它也不常用,因为C#项目中指针都被弃用了,那指针的封装—句柄自然也被弃用了。

但总有特殊的地方会用到指针,比如调用C++动态库之类的;所以微软贴心的为我们做了个句柄,毕竟指针用起来太难受了。

句柄的定义

句柄是一个结构体,简单的来说,它是指针的一个封装,是C#中指针的替代者,下面我们看下句柄的定义。

image

namespace System
{
    //
    // 摘要:
    //     A platform-specific type that is used to represent a pointer or a handle.
    public readonly struct IntPtr : IComparable, IComparable<nint>, IEquatable<nint>, ISpanFormattable, IFormattable, ISerializable
    {
        //
        // 摘要:
        //     A read-only field that represents a pointer or handle that has been initialized
        //     to zero.
        public static readonly IntPtr Zero;

        //
        // 摘要:
        //     Initializes a new instance of System.IntPtr using the specified 32-bit pointer
        //     or handle.
        //
        // 参数:
        //   value:
        //     A pointer or handle contained in a 32-bit signed integer.
        public IntPtr(int value);
        //
        // 摘要:
        //     Initializes a new instance of System.IntPtr using the specified 64-bit pointer.
        //
        // 参数:
        //   value:
        //     A pointer or handle contained in a 64-bit signed integer.
        //
        // 异常:
        //   T:System.OverflowException:
        //     On a 32-bit platform, value is too large or too small to represent as an System.IntPtr.
        public IntPtr(long value);
        //
        // 摘要:
        //     Initializes a new instance of System.IntPtr using the specified pointer to an
        //     unspecified type.
        //
        // 参数:
        //   value:
        //     A pointer to an unspecified type.
        [CLSCompliant(false)]
        public IntPtr(void* value);

        //
        // 摘要:
        //     Represents the largest possible value of System.IntPtr.
        public static IntPtr MaxValue { get; }
        //
        // 摘要:
        //     Represents the smallest possible value of System.IntPtr.
        public static IntPtr MinValue { get; }
        //
        // 摘要:
        //     Gets the size of this instance.
        //
        // 返回结果:
        //     The size of a pointer or handle in this process, measured in bytes. The value
        //     of this property is 4 in a 32-bit process, and 8 in a 64-bit process. You can
        //     define the process type by setting the /platform switch when you compile your
        //     code with the C# and Visual Basic compilers.
        public static int Size { get; }

        //
        // 摘要:
        //     Adds an offset to the value of a pointer.
        //
        // 参数:
        //   pointer:
        //     The pointer to add the offset to.
        //
        //   offset:
        //     The offset to add.
        //
        // 返回结果:
        //     A new pointer that reflects the addition of offset to pointer.
        public static IntPtr Add(IntPtr pointer, int offset);
        //
        // 摘要:
        //     Converts the string representation of a number in a specified style and culture-specific
        //     format to its signed native integer equivalent.
        //
        // 参数:
        //   s:
        //     A string containing a number to convert.
        //
        //   style:
        //     A bitwise combination of the enumeration values that indicates the style elements
        //     that can be present in s.
        //
        //   provider:
        //     An object that supplies culture-specific formatting information about s.
        //
        // 返回结果:
        //     A signed native integer equivalent to the number contained in s.
        //
        // 异常:
        //   T:System.ArgumentNullException:
        //     s is null.
        //
        //   T:System.ArgumentException:
        //     style is not a System.Globalization.NumberStyles value or style is not a combination
        //     of System.Globalization.NumberStyles.AllowHexSpecifier and System.Globalization.NumberStyles.HexNumber
        //     values.
        //
        //   T:System.FormatException:
        //     s is not in the correct format.
        //
        //   T:System.OverflowException:
        //     s represents a number less than System.IntPtr.MinValue or greater than System.IntPtr.MaxValue.
        public static IntPtr Parse(string s, NumberStyles style, IFormatProvider? provider);
        //
        // 摘要:
        //     Converts the read-only span of characters representation of a number in a specified
        //     style and culture-specific format to its signed native integer equivalent.
        //
        // 参数:
        //   s:
        //     A read-only span of characters containing a number to convert.
        //
        //   style:
        //     A bitwise combination of the enumeration values that indicates the style elements
        //     that can be present in s.
        //
        //   provider:
        //     An object that supplies culture-specific formatting information about s.
        //
        // 返回结果:
        //     A signed native integer equivalent to the number contained in s.
        //
        // 异常:
        //   T:System.ArgumentException:
        //     style is not a System.Globalization.NumberStyles value or style is not a combination
        //     of System.Globalization.NumberStyles.AllowHexSpecifier and System.Globalization.NumberStyles.HexNumber
        //     values.
        //
        //   T:System.FormatException:
        //     s is not in the correct format.
        //
        //   T:System.OverflowException:
        //     s represents a number less than System.IntPtr.MinValue or greater than System.IntPtr.MaxValue.
        public static IntPtr Parse(ReadOnlySpan<char> s, NumberStyles style = NumberStyles.Integer, IFormatProvider? provider = null);
        //
        // 摘要:
        //     Converts the string representation of a number in a specified culture-specific
        //     format to its signed native integer equivalent.
        //
        // 参数:
        //   s:
        //     A string containing a number to convert.
        //
        //   provider:
        //     An object that supplies culture-specific formatting information about s.
        //
        // 返回结果:
        //     A signed native integer equivalent to the number contained in s.
        //
        // 异常:
        //   T:System.ArgumentNullException:
        //     s is null.
        //
        //   T:System.FormatException:
        //     s is not in the correct format.
        //
        //   T:System.OverflowException:
        //     s represents a number less than System.IntPtr.MinValue or greater than System.IntPtr.MaxValue.
        public static IntPtr Parse(string s, IFormatProvider? provider);
        //
        // 摘要:
        //     Converts the string representation of a number in a specified style to its signed
        //     native integer equivalent.
        //
        // 参数:
        //   s:
        //     A string containing a number to convert.
        //
        //   style:
        //     A bitwise combination of the enumeration values that indicates the style elements
        //     that can be present in s.
        //
        // 返回结果:
        //     A signed native integer equivalent to the number contained in s.
        //
        // 异常:
        //   T:System.ArgumentNullException:
        //     s is null.
        //
        //   T:System.ArgumentException:
        //     style is not a System.Globalization.NumberStyles value or style is not a combination
        //     of System.Globalization.NumberStyles.AllowHexSpecifier and System.Globalization.NumberStyles.HexNumber
        //     values.
        //
        //   T:System.FormatException:
        //     s is not in the correct format.
        //
        //   T:System.OverflowException:
        //     s represents a number less than System.IntPtr.MinValue or greater than System.IntPtr.MaxValue.
        public static IntPtr Parse(string s, NumberStyles style);
        //
        // 摘要:
        //     Converts the string representation of a number to its signed native integer equivalent.
        //
        // 参数:
        //   s:
        //     A string containing a number to convert.
        //
        // 返回结果:
        //     A signed native integer equivalent to the number contained in s.
        //
        // 异常:
        //   T:System.ArgumentNullException:
        //     s is null.
        //
        //   T:System.FormatException:
        //     s is not in the correct format.
        //
        //   T:System.OverflowException:
        //     s represents a number less than System.IntPtr.MinValue or greater than System.IntPtr.MaxValue.
        public static IntPtr Parse(string s);
        //
        // 摘要:
        //     Subtracts an offset from the value of a pointer.
        //
        // 参数:
        //   pointer:
        //     The pointer to subtract the offset from.
        //
        //   offset:
        //     The offset to subtract.
        //
        // 返回结果:
        //     A new pointer that reflects the subtraction of offset from pointer.
        public static IntPtr Subtract(IntPtr pointer, int offset);
        //
        // 摘要:
        //     Converts the read-only span of characters representation of a number in a specified
        //     style and culture-specific format to its signed native integer equivalent. A
        //     return value indicates whether the conversion succeeded.
        //
        // 参数:
        //   s:
        //     A read-only span of characters containing a number to convert. The string is
        //     interpreted using the style specified by style.
        //
        //   style:
        //     A bitwise combination of enumeration values that indicates the style elements
        //     that can be present in s.
        //
        //   provider:
        //     An object that supplies culture-specific formatting information about s.
        //
        //   result:
        //     When this method returns, contains the signed native integer value equivalent
        //     of the number contained in s, if the conversion succeeded, or zero if the conversion
        //     failed. The conversion fails if the s parameter is empty, is not of the correct
        //     format, or represents a number less than System.IntPtr.MinValue or greater than
        //     System.IntPtr.MaxValue. This parameter is passed uninitialized; any value originally
        //     supplied in result will be overwritten.
        //
        // 返回结果:
        //     true if s was converted successfully; otherwise, false.
        public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider? provider, out IntPtr result);
        //
        // 摘要:
        //     Converts the read-only span of characters representation of a number to its signed
        //     native integer equivalent. A return value indicates whether the conversion succeeded.
        //
        // 参数:
        //   s:
        //     A read-only span of characters containing a number to convert.
        //
        //   result:
        //     When this method returns, contains the signed native integer equivalent of the
        //     number contained in s, if the conversion succeeded, or zero if the conversion
        //     failed. The conversion fails if the s parameter is empty, is not of the correct
        //     format, or represents a number less than System.IntPtr.MinValue or greater than
        //     System.IntPtr.MaxValue. This parameter is passed uninitialized; any value originally
        //     supplied in result will be overwritten.
        //
        // 返回结果:
        //     true if s was converted successfully; otherwise, false.
        public static bool TryParse(ReadOnlySpan<char> s, out IntPtr result);
        //
        // 摘要:
        //     Converts the string representation of a number to its signed native integer equivalent.
        //     A return value indicates whether the conversion succeeded.
        //
        // 参数:
        //   s:
        //     A string containing a number to convert.
        //
        //   result:
        //     When this method returns, contains the signed native integer value equivalent
        //     of the number contained in s, if the conversion succeeded, or zero if the conversion
        //     failed. The conversion fails if the s parameter is null or empty, is not of the
        //     correct format, or represents a number less than System.IntPtr.MinValue or greater
        //     than System.IntPtr.MaxValue. This parameter is passed uninitialized; any value
        //     originally supplied in result will be overwritten.
        //
        // 返回结果:
        //     true if s was converted successfully; otherwise, false.
        public static bool TryParse([NotNullWhen(true)] string? s, out IntPtr result);
        //
        // 摘要:
        //     Converts the string representation of a number in a specified style and culture-specific
        //     format to its signed native integer equivalent. A return value indicates whether
        //     the conversion succeeded.
        //
        // 参数:
        //   s:
        //     A string containing a number to convert. The string is interpreted using the
        //     style specified by style.
        //
        //   style:
        //     A bitwise combination of enumeration values that indicates the style elements
        //     that can be present in s.
        //
        //   provider:
        //     An object that supplies culture-specific formatting information about s.
        //
        //   result:
        //     When this method returns, contains the signed native integer value equivalent
        //     of the number contained in s, if the conversion succeeded, or zero if the conversion
        //     failed. The conversion fails if the s parameter is null or empty, is not of the
        //     correct format, or represents a number less than System.IntPtr.MinValue or greater
        //     than System.IntPtr.MaxValue. This parameter is passed uninitialized; any value
        //     originally supplied in result will be overwritten.
        //
        // 返回结果:
        //     true if s was converted successfully; otherwise, false.
        public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out IntPtr result);
        //
        // 摘要:
        //     Compares the current instance with another object of the same type and returns
        //     an integer that indicates whether the current instance precedes, follows, or
        //     occurs in the same position in the sort order as the other object.
        //
        // 参数:
        //   value:
        //     An object to compare, or null.
        //
        // 返回结果:
        //     A value that indicates the relative order of the objects being compared. The
        //     return value has these meanings:
        //     Value – Meaning
        //     Less than zero – This instance precedes obj in the sort order.
        //     Zero – This instance occurs in the same position in the sort order as obj.
        //     Greater than zero – This instance follows obj in the sort order.
        public int CompareTo(object? value);
        //
        // 摘要:
        //     Compares the current instance with another object of the same type and returns
        //     an integer that indicates whether the current instance precedes, follows, or
        //     occurs in the same position in the sort order as the other object.
        //
        // 参数:
        //   value:
        //     A signed native integer to compare.
        //
        // 返回结果:
        //     A value that indicates the relative order of the objects being compared. The
        //     return value has these meanings:
        //     Value – Meaning
        //     Less than zero – This instance precedes other in the sort order.
        //     Zero – This instance occurs in the same position in the sort order as other.
        //     Greater than zero – This instance follows other in the sort order.
        public int CompareTo(IntPtr value);
        //
        // 摘要:
        //     Indicates whether the current object is equal to another object of the same type.
        //
        // 参数:
        //   other:
        //     An object to compare with this object.
        //
        // 返回结果:
        //     true if the current object is equal to other; otherwise, false.
        public bool Equals(IntPtr other);
        //
        // 摘要:
        //     Returns a value indicating whether this instance is equal to a specified object.
        //
        // 参数:
        //   obj:
        //     An object to compare with this instance or null.
        //
        // 返回结果:
        //     true if obj is an instance of System.IntPtr and equals the value of this instance;
        //     otherwise, false.
        public override bool Equals([NotNullWhen(true)] object? obj);
        //
        // 摘要:
        //     Returns the hash code for this instance.
        //
        // 返回结果:
        //     A 32-bit signed integer hash code.
        public override int GetHashCode();
        //
        // 摘要:
        //     Converts the value of this instance to a 32-bit signed integer.
        //
        // 返回结果:
        //     A 32-bit signed integer equal to the value of this instance.
        //
        // 异常:
        //   T:System.OverflowException:
        //     On a 64-bit platform, the value of this instance is too large or too small to
        //     represent as a 32-bit signed integer.
        public int ToInt32();
        //
        // 摘要:
        //     Converts the value of this instance to a 64-bit signed integer.
        //
        // 返回结果:
        //     A 64-bit signed integer equal to the value of this instance.
        public long ToInt64();
        //
        // 摘要:
        //     Converts the value of this instance to a pointer to an unspecified type.
        //
        // 返回结果:
        //     A pointer to System.Void; that is, a pointer to memory containing data of an
        //     unspecified type.
        [CLSCompliant(false)]
        public void* ToPointer();
        //
        // 摘要:
        //     Converts the numeric value of the current System.IntPtr object to its equivalent
        //     string representation.
        //
        // 返回结果:
        //     The string representation of the value of this instance.
        public override string ToString();
        //
        // 摘要:
        //     Formats the value of the current instance using the specified format.
        //
        // 参数:
        //   format:
        //     The format to use. -or- A null reference (Nothing in Visual Basic) to use the
        //     default format defined for the type of the System.IFormattable implementation.
        //
        //   provider:
        //     An object that supplies culture-specific formatting information.
        //
        // 返回结果:
        //     The value of the current instance in the specified format.
        public string ToString(string? format, IFormatProvider? provider);
        //
        // 摘要:
        //     Converts the numeric value of the current System.IntPtr object to its equivalent
        //     string representation.
        //
        // 参数:
        //   format:
        //     A format specification that governs how the current System.IntPtr object is converted.
        //
        // 返回结果:
        //     The string representation of the value of the current System.IntPtr object.
        //
        // 异常:
        //   T:System.FormatException:
        //     format is invalid or not supported.
        public string ToString(string? format);
        //
        // 摘要:
        //     Converts the numeric value of this instance to its equivalent string representation
        //     using the specified format and culture-specific format information.
        //
        // 参数:
        //   provider:
        //     An object that supplies culture-specific formatting information.
        //
        // 返回结果:
        //     The string representation of the value of this instance as specified by provider.
        public string ToString(IFormatProvider? provider);
        //
        // 摘要:
        //     Tries to format the value of the current instance into the provided span of characters.
        //
        // 参数:
        //   destination:
        //     The span where this instance's value formatted as a span of characters should
        //     be written.
        //
        //   charsWritten:
        //     When this method returns, contains the number of characters that were written
        //     in destination.
        //
        //   format:
        //     The characters that represent a standard or custom format string that defines
        //     the acceptable format for destination.
        //
        //   provider:
        //     An optional object that supplies culture-specific formatting information for
        //     destination.
        //
        // 返回结果:
        //     true if the formatting was successful; otherwise, false.
        public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider? provider = null);

        //
        // 摘要:
        //     Adds an offset to the value of a pointer.
        //
        // 参数:
        //   pointer:
        //     The pointer to add the offset to.
        //
        //   offset:
        //     The offset to add.
        //
        // 返回结果:
        //     A new pointer that reflects the addition of offset to pointer.
        public static IntPtr operator +(IntPtr pointer, int offset);
        //
        // 摘要:
        //     Subtracts an offset from the value of a pointer.
        //
        // 参数:
        //   pointer:
        //     The pointer to subtract the offset from.
        //
        //   offset:
        //     The offset to subtract.
        //
        // 返回结果:
        //     A new pointer that reflects the subtraction of offset from pointer.
        public static IntPtr operator -(IntPtr pointer, int offset);
        //
        // 摘要:
        //     Determines whether two specified instances of System.IntPtr are equal.
        //
        // 参数:
        //   value1:
        //     The first pointer or handle to compare.
        //
        //   value2:
        //     The second pointer or handle to compare.
        //
        // 返回结果:
        //     true if value1 equals value2; otherwise, false.
        public static bool operator ==(IntPtr value1, IntPtr value2);
        //
        // 摘要:
        //     Determines whether two specified instances of System.IntPtr are not equal.
        //
        // 参数:
        //   value1:
        //     The first pointer or handle to compare.
        //
        //   value2:
        //     The second pointer or handle to compare.
        //
        // 返回结果:
        //     true if value1 does not equal value2; otherwise, false.
        public static bool operator !=(IntPtr value1, IntPtr value2);

        //
        // 摘要:
        //     Converts the value of a 64-bit signed integer to an System.IntPtr.
        //
        // 参数:
        //   value:
        //     A 64-bit signed integer.
        //
        // 返回结果:
        //     A new instance of System.IntPtr initialized to value.
        //
        // 异常:
        //   T:System.OverflowException:
        //     On a 32-bit platform, value is too large to represent as an System.IntPtr.
        public static explicit operator IntPtr(long value);
        //
        // 摘要:
        //     Converts the value of the specified System.IntPtr to a 32-bit signed integer.
        //
        // 参数:
        //   value:
        //     The pointer or handle to convert.
        //
        // 返回结果:
        //     The contents of value.
        //
        // 异常:
        //   T:System.OverflowException:
        //     On a 64-bit platform, the value of value is too large to represent as a 32-bit
        //     signed integer.
        public static explicit operator int(IntPtr value);
        //
        // 摘要:
        //     Converts the value of the specified System.IntPtr to a 64-bit signed integer.
        //
        // 参数:
        //   value:
        //     The pointer or handle to convert.
        //
        // 返回结果:
        //     The contents of value.
        public static explicit operator long(IntPtr value);
        //
        // 摘要:
        //     Converts the value of a 32-bit signed integer to an System.IntPtr.
        //
        // 参数:
        //   value:
        //     A 32-bit signed integer.
        //
        // 返回结果:
        //     A new instance of System.IntPtr initialized to value.
        public static explicit operator IntPtr(int value);
        //
        // 摘要:
        //     Converts the value of the specified System.IntPtr to a pointer to an unspecified
        //     type. This API is not CLS-compliant.
        //
        // 参数:
        //   value:
        //     The pointer or handle to convert.
        //
        // 返回结果:
        //     The contents of value.
        [CLSCompliant(false)]
        public static explicit operator void*(IntPtr value);
        //
        // 摘要:
        //     Converts the specified pointer to an unspecified type to an System.IntPtr. This
        //     API is not CLS-compliant.
        //
        // 参数:
        //   value:
        //     A pointer to an unspecified type.
        //
        // 返回结果:
        //     A new instance of System.IntPtr initialized to value.
        [CLSCompliant(false)]
        public static explicit operator IntPtr(void* value);
    }
}

我们可以看到,句柄IntPtr里包含创建指针,获取指针长度,设置偏移量等等方法,并且为了编码方便还声明了些强制转换的方法。

看了句柄的结构体定义,相信稍微有点基础的人已经明白了,在C#中,微软是希望抛弃指针而改用更优秀的IntPtr代替它的

但我们还会发现,句柄里还提供一个方法是ToPointer(),它的返回类型是Void*,也就是说,我们还是可以从句柄里拿到C++中的指针,既然,微软期望在C#中不要使用指针,那为什么还要提供这样的方法呢?

这是因为,在项目开发中总是会有极特殊的情况,比如,你有一段C++写的非常复杂、完美的函数,而将这个函数转换成C#又及其耗时,那么最简单省力的方法就是直接在C#里启用指针进行移植。

也就是说,C#支持指针,其实是为了体现它的兼容性,并不是提倡大家去使用指针

使用要点

  • C#中的IntPtr类型被称之为"平台特定的整数类型",用于本机资源,例如窗口句柄。
  • 资源的大小取决于使用的硬件和操作系统,即此类型的实例在32位硬件和操作系统中将是32位,在64位硬件和操作系统中将是64位;但其大小总是足以包含系统的指针(因此也可以包含资源的名称)。
  • 在调用API函数时,类似含有窗口句柄参数(HANDLE)的原型函数,应显示地声明为IntPtr类型。
  • IntPtr类型对多线程操作是安全的。
  • IntIntPtr互转。

示例模型

struct ChatDemo
{
    public double X;

    public double Y;

    public ChatDemo(double x, double y)
    {
        X = x; 
        Y = y;
    }
}

Struct与IntPtr互相转换

public void ConvertStruct()
{
    var chatDemo = new ChatDemo(1, 10);
    // 通过使用指定的字节数,从进程的非托管内存中分配内存
    IntPtr intPtr = Marshal.AllocHGlobal
    (
        // 内存中的所需字节数
        cb: Marshal.SizeOf(typeof(ChatDemo))
    );
    // 将数据从托管对象封送到非托管内存块
    Marshal.StructureToPtr
    (
        // 包含要封送的数据的托管对象。该对象必须是格式化类的结构或实例
        structure: chatDemo,
        // 指向非托管内存块的指针,必须在调用此方法之前分配该指针
        ptr: intPtr,
        // 如果在此方法复制该数据前在DestroyStructure(IntPtr,Type)参数上调用ptr,则为true。该块必须包含有效的数据。请注意,在内存块已包含数据时传递false可能会导致内存泄漏。
        fDeleteOld: true
    );

    // 将数据从非托管内存块封送到托管对象
    var chatDemoRes = (ChatDemo)Marshal.PtrToStructure
    (
        // 指向非托管内存块的指针
        ptr: intPtr,
        // 要创建的对象的类型。此对象必须表示格式化类或结构
        structureType: typeof(ChatDemo)
    );
}

Struct对象数组与IntPtr互相转换

public void ConvertStructs()
{
    var chatDemos = new List<ChatDemo>() { new ChatDemo(1,3),  new ChatDemo(2,10), new ChatDemo(4,200)};
    // 将托管对象数组转成指针
    var intPtr = MarshalMangagedStruct2Array(chatDemos.ToArray());
    // 将指针转成托管对象数组
    MarshalUnmananagedArray2Struct(intPtr, chatDemos.Count, out ChatDemo[] chatDemoRes);
}

/// <summary>
/// 将指针转成托管对象数组
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="unmanagedArray">非托管指针</param>
/// <param name="length">数据长度</param>
/// <param name="mangagedArray">托管对象数组</param>
public void MarshalUnmananagedArray2Struct<T>(IntPtr unmanagedArray, int length, out T[] mangagedArray)
{
    if (length <= 0) throw new ArgumentException(nameof(length));

    // 获取对象的空间大小
    var size = Marshal.SizeOf(typeof(T));
    mangagedArray = new T[length];

    for (int i = 0; i < length; i++)
    {
        // 增加指针内存位置以便定位到下一个结构体
        IntPtr nextStructureMemBlock = new IntPtr(unmanagedArray.ToInt64() + i * size);
        mangagedArray[i] = Marshal.PtrToStructure<T>(nextStructureMemBlock);
    }
}

/// <summary>
/// 将托管对象数组转成指针
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="mangagedArray"></param>
/// <returns></returns>
public IntPtr MarshalMangagedStruct2Array<T>(T[] mangagedArray) where T : struct
{
    if (mangagedArray == null || mangagedArray.Length <= 0) throw new ArgumentException(nameof(mangagedArray));

    // 获取对象的空间大小
    int size = Marshal.SizeOf(typeof(T));
    // 得到非托管内存的总长度
    int allSize =  size * mangagedArray.Length;
    // 申请非托管内存空间
    IntPtr ptr = Marshal.AllocHGlobal(allSize);
    // 写入长度属性值
    Marshal.WriteInt32(ptr, mangagedArray.Length);
    // 写入数据
    for (int i = 0; i < mangagedArray.Length; i++)
    {
        // 根据指针+偏移量来写入指定序号的对象数据
        Marshal.StructureToPtr<T>(mangagedArray[i], ptr + (size * i), false);
    }
    return ptr;
}

C++与C#类型对照关系

C++ 数据类型 C# 数据类型
WORD ushort
DWORD uint
UCHAR int/byte
UCHAR* string/InPtr
unsigned char* [MarshalAs(UnmanagedType.LPArray)]byte[] / IntPtr
char* string
LPCTSTR string
LPTSTR [MarshalAs(UnmanagedType.LPTStr)] string
long int
ulong uint
Handle IntPtr
HWND IntPtr
void* IntPtr
int int
int* ref int
*int IntPtr
unsigned int uint
COLORREF uint

参考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章