Tür hazırlama

Marshalling , yönetilen ve yerel kod arasında geçiş yapmak gerektiğinde türleri dönüştürme işlemidir.

Yönetilen ve yönetilmeyen koddaki türler farklı olduğundan, marshalling gereklidir. Örneğin yönetilen kodda, Stringyönetilmeyen dünya dizeleri Unicode ("geniş"), Unicode olmayan, null ile sonlandırılan, ASCII vb. olabilir. Varsayılan olarak, P/Invoke alt sistemi bu makalede açıklanan varsayılan davranışa göre doğru olanı yapmaya çalışır. Ancak, ek denetime ihtiyaç duyduğunuz durumlarda, yönetilmeyen tarafta beklenen türü belirtmek için MarshalAs özniteliğini kullanabilirsiniz. Örneğin, dizenin null olarak sonlandırılan bir ANSI dizesi olarak gönderilmesini istiyorsanız, bunu şu şekilde yapabilirsiniz:

[DllImport("somenativelibrary.dll")]
static extern int MethodA([MarshalAs(UnmanagedType.LPStr)] string parameter);

özniteliğini System.Runtime.CompilerServices.DisableRuntimeMarshallingAttribute derlemeye uygularsanız, aşağıdaki bölümdeki kurallar geçerli değildir. Bu öznitelik uygulandığında .NET değerlerinin yerel koda nasıl sunulduğu hakkında bilgi için bkz . devre dışı çalışma zamanı hazırlama.

Ortak türleri sıralamak için varsayılan kurallar

Genellikle çalışma zamanı, sizden en az iş gerektirecek şekilde hazırlama sırasında "doğru şeyi" yapmaya çalışır. Aşağıdaki tablolarda, bir parametre veya alanda kullanıldığında her türün varsayılan olarak nasıl sıralandığı açıklanmaktadır. C99/C++11 sabit genişlikli tamsayı ve karakter türleri, tüm platformlar için aşağıdaki tablonun doğru olduğundan emin olmak için kullanılır. Bu türle aynı hizalama ve boyut gereksinimlerine sahip herhangi bir yerel türü kullanabilirsiniz.

Bu ilk tabloda, hem P/Invoke hem de alan hazırlama için aynı olan çeşitli türler için eşlemeler açıklanmaktadır.

C# anahtar sözcüğü .NET Türü Yerel Tür
byte System.Byte uint8_t
sbyte System.SByte int8_t
short System.Int16 int16_t
ushort System.UInt16 uint16_t
int System.Int32 int32_t
uint System.UInt32 uint32_t
long System.Int64 int64_t
ulong System.UInt64 uint64_t
char System.Char P char /Invoke veya char16_t yapısına bağlı olarak veya bağlı olarak CharSet . Karakter kümesi belgelerine bakın.
System.Char P char* /Invoke veya char16_t* yapısına bağlı olarak veya bağlı olarak CharSet . Karakter kümesi belgelerine bakın.
nint System.IntPtr intptr_t
nuint System.UIntPtr uintptr_t
.NET İşaretçi türleri (örn. void*) void*
Türetilen tür System.Runtime.InteropServices.SafeHandle void*
Türetilen tür System.Runtime.InteropServices.CriticalHandle void*
bool System.Boolean Win32 BOOL türü
decimal System.Decimal COM DECIMAL yapısı
.NET Temsilcisi Yerel işlev işaretçisi
System.DateTime Win32 DATE türü
System.Guid Win32 GUID türü

Parametre veya yapı olarak sıralarsanız, birkaç sıralama kategorisi farklı varsayılan değerlere sahiptir.

.NET Türü Yerel Tür (Parametre) Yerel Tür (Alan)
.NET dizisi Dizi öğelerinin yerel gösterimleri dizisinin başlangıcına yönelik bir işaretçi. Öznitelik olmadan [MarshalAs] izin verilmez
veya içeren bir LayoutKindSequential sınıf Explicit Sınıfın yerel gösterimine bir işaretçi Sınıfın yerel gösterimi

Aşağıdaki tablo yalnızca Windows olan varsayılan sıralama kurallarını içerir. Windows olmayan platformlarda bu türleri sıralayamazsınız.

.NET Türü Yerel Tür (Parametre) Yerel Tür (Alan)
System.Object VARIANT IUnknown*
System.Array COM arabirimi Öznitelik olmadan [MarshalAs] izin verilmez
System.ArgIterator va_list İzin verilmiyor
System.Collections.IEnumerator IEnumVARIANT* İzin verilmiyor
System.Collections.IEnumerable IDispatch* İzin verilmiyor
System.DateTimeOffset int64_t 1 Ocak 1601'de gece yarısından bu yana kene sayısını temsil eden int64_t 1 Ocak 1601'de gece yarısından bu yana kene sayısını temsil eden

Bazı türler alan olarak değil yalnızca parametre olarak sıralanabilir. Bu türler aşağıdaki tabloda listelenmiştir:

.NET Türü Yerel Tür (Yalnızca Parametre)
System.Text.StringBuilder P char* /Invoke'un öğesine bağlı olarak veya char16_t* bağlı olarak CharSet . Karakter kümesi belgelerine bakın.
System.ArgIterator va_list (yalnızca Windows x86/x64/arm64 üzerinde)
System.Runtime.InteropServices.ArrayWithOffset void*
System.Runtime.InteropServices.HandleRef void*

Bu varsayılanlar tam olarak istediğiniz gibi değilse, parametrelerin nasıl hazırlanmasını özelleştirebilirsiniz. Parametre hazırlama makalesi, farklı parametre türlerinin nasıl sıraya eklendiğini özelleştirme konusunda size yol gösterir.

COM senaryolarında varsayılan sıralama

.NET'teki COM nesnelerinde yöntemleri çağırırken, .NET çalışma zamanı varsayılan sıralama kurallarını ortak COM semantiğiyle eşleşecek şekilde değiştirir. Aşağıdaki tabloda, .NET çalışma zamanlarının COM senaryolarında kullandığı kurallar listelanmaktadır:

.NET Türü Yerel Tür (COM yöntemi çağrıları)
System.Boolean VARIANT_BOOL
StringBuilder LPWSTR
System.String BSTR
Temsilci türleri _Delegate* .NET Framework'te. .NET Core ve .NET 5+ için izin verilmez.
System.Drawing.Color OLECOLOR
.NET dizisi SAFEARRAY
System.String[] SAFEARRAYs sayısı BSTR

Sınıflar ve yapılar için sıralama

Tür hazırlamanın bir diğer yönü de yapıyı yönetilmeyen bir yönteme geçirmedir. Örneğin, yönetilmeyen yöntemlerden bazıları parametre olarak bir yapı gerektirir. Bu gibi durumlarda, parametre olarak kullanmak için ilgili bir yapı veya dünyanın yönetilen bölümünde bir sınıf oluşturmanız gerekir. Ancak, yalnızca sınıfı tanımlamak yeterli değildir, ayrıca sınıf içindeki alanların yönetilmeyen yapıya nasıl eşlenmesi gerektiğini de belirtmelisiniz. StructLayout Burada öznitelik yararlı olur.

[DllImport("kernel32.dll")]
static extern void GetSystemTime(SystemTime systemTime);

[StructLayout(LayoutKind.Sequential)]
class SystemTime {
    public ushort Year;
    public ushort Month;
    public ushort DayOfWeek;
    public ushort Day;
    public ushort Hour;
    public ushort Minute;
    public ushort Second;
    public ushort Millisecond;
}

public static void Main(string[] args) {
    SystemTime st = new SystemTime();
    GetSystemTime(st);
    Console.WriteLine(st.Year);
}

Önceki kod işleve çağrı yapmanın basit bir örneğini GetSystemTime() gösterir. İlginç olan 4. satırda. özniteliği, sınıfın alanlarının diğer (yönetilmeyen) tarafındaki yapıya sıralı olarak eşlenmesi gerektiğini belirtir. Bu, aşağıdaki örnekte gösterilen yönetilmeyen yapıya karşılık gelmeleri gerektiğinden, alanların adlandırılmasının önemli olmadığı, yalnızca sıralarının önemli olduğu anlamına gelir:

typedef struct _SYSTEMTIME {
  WORD wYear;
  WORD wMonth;
  WORD wDayOfWeek;
  WORD wDay;
  WORD wHour;
  WORD wMinute;
  WORD wSecond;
  WORD wMilliseconds;
} SYSTEMTIME, *PSYSTEMTIME;

Bazen yapınız için varsayılan sıralama, ihtiyacınız olanı yapmaz. Yapıyı özelleştirme marshalling makalesi, yapınızın nasıl düzenlendiğini özelleştirmeyi öğretir.