溫故知新,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

參考

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