Существует ли полное руководство по кроссплатформенным (x86 и x64) типам данных PInvoke и windows?
Я проверяю некоторый код для совместимости x64. Ранее я использовал PInvoke.net, но нашел несколько подозрительных объявлений в терминах x64. Итак, теперь я:
- Найдите ссылку на API, такую как MapViewOfFile.
- Посмотрите определение типа данных Windows
- Найдите соответствующий тип.NET.
Это шаг 3, где я хотел бы получить окончательную ссылку
В качестве примера:
LPVOID WINAPI MapViewOfFile(
__in HANDLE hFileMappingObject,
__in DWORD dwDesiredAccess,
__in DWORD dwFileOffsetHigh,
__in DWORD dwFileOffsetLow,
__in SIZE_T dwNumberOfBytesToMap
);
Возвращаемое значение - LPVOID, которое определяется как:
LPVOID
Указатель на любой тип.
Этот тип объявлен в WinDef.h следующим образом:
typedef void *LPVOID;
Хорошо... так что я думаю, что это IntPtr
или же UIntPtr
, В этой статье есть таблица и предлагается, чтобы LPVOID отображался в IntPtr или UIntPtr. ХОРОШО.
Далее РУЧКА.
СПРАВИТЬСЯ
Дескриптор объекта.
Этот тип объявлен в WinNT.h следующим образом:
typedef PVOID HANDLE;
ОК, РУЧКА - ПВОИД.
PVOID
Указатель на любой тип.
Этот тип объявлен в WinNT.h следующим образом:
typedef void * PVOID;
Хм, звучит как IntPtr
Далее DWORD
DWORD
32-разрядное целое число без знака. Диапазон составляет от 0 до 4294967295 десятичных.
Этот тип объявлен в WinDef.h следующим образом:
typedef unsigned long DWORD;
ОК, без знака длиной от 0 до 4294967295, так что это uint
и все же здесь это предлагает Int32 или UInt32. Int32 не сможет хранить значения более 2 147 483 648. Так что эта таблица очень подозрительна.
Наконец, у нас есть SIZE_T, который определяется как ULONG_PTR, длина которого может быть 32- или 64-битной со знаком в зависимости от платформы (определения приведены ниже). Эта статья (и продолжение) заключает, что вы должны использовать IntPtr, так как он будет обрабатывать переменные размеры.
SIZE_T
Максимальное количество байтов, на которое может указывать указатель. Используйте для счетчика, который должен охватывать весь диапазон указателя.
Этот тип объявлен в BaseTsd.h следующим образом:
typedef ULONG_PTR SIZE_T;
ULONG_PTR
Неподписанный LONG_PTR.
Этот тип объявлен в BaseTsd.h следующим образом:
#if defined(_WIN64) typedef unsigned __int64 ULONG_PTR; #else typedef unsigned long ULONG_PTR; #endif
ДОЛГО
32-разрядное целое число со знаком. Диапазон составляет от –2147483648 до 2147483647 десятичных.
Этот тип объявлен в WinNT.h следующим образом:
typedef long LONG;
INT64
64-разрядное целое число со знаком. Диапазон составляет от –9223372036854775808 до 9223372036854775807 десятичных.
Этот тип объявлен в BaseTsd.h следующим образом:
typedef signed __int64 INT64;
Поэтому, хотя я могу посмотреть определение каждого типа данных Windows, а затем найти соответствующий тип данных.NET с точки зрения размера, знака и того, работает ли он как на x86, так и на x64, это не идеально.
Есть ли точная ссылка (не pinvoke.net) с хорошей таблицей сопоставления, которая актуальна для x64?
2 ответа
При сопоставлении собственных типов данных с управляемыми типами все, что имеет значение, это размер и согласованность.
Выбор типов со знаком и без знака имеет значение только при интерпретации управляемого значения.
Они оба маршалированы как необработанные биты.
В большинстве случаев вы просто будете передавать значения из одного метода API в другой; в этих случаях не имеет значения, является ли тип подписанным или беззнаковым, если это правильный размер.
Следовательно, общее правило заключается в том, что любое значение размером с указатель становится IntPtr
, а также DWORD
а также QWORD
становиться U?Int32
а также U?Int64
соответственно.
Кроме того, если он 32-битный на 32-битных машинах и 64-битный на 64-битных машинах (например, ptrdiff_t), вы должны использовать IntPtr.