У меня три структуры:
[StructLayout(LayoutKind.Sequential)]
internal struct COPYDATASTRUCT
{
public IntPtr dwData; // Specifies data to be passed
public int cbData; // Specifies the data size in bytes
public IntPtr lpData; // Pointer to data to be passed
}
public struct SHELLTRAYDATA
{
public UInt32 dwUnknown;
public UInt32 dwMessage;
public NID_XX nid;
}
public struct NID_XX
{
public UInt32 cbSize;
public IntPtr hWnd;
public uint uID;
public uint uFlags;
public uint uCallbackMessage;
public IntPtr hIcon;
}
В моем WndProc я делаю следующее:
case WM_COPYDATA:
{
COPYDATASTRUCT cp = (COPYDATASTRUCT)Marshal.PtrToStructure(lParam, typeof(COPYDATASTRUCT));
if(cp.dwData == SH_TRAY_DATA)
{
var shellTrayData = (SHELLTRAYDATA)Marshal.PtrToStructure(cp.lpData,typeof(SHELLTRAYDATA));
HandleNotification(shellTrayData);
}
}
Когда мое приложение работает на x86, оно отлично работает. Когда я запускаю его на x64, я не получаю hIcon и, кроме того, hWnd недействителен. Когда я нацеливаю приложение на x86 и запускаю его на x64, он работает нормально. Я знаю, что проблема кроется в Маршаллинге. Нужно ли вручную маршалировать структуру? Нужна помощь по этому поводу. Я бы предпочел иметь одну и ту же структуру для x64 и x86
РЕДАКТИРОВАТЬ:
Неуправляемые структуры:
typedef struct tagCOPYDATASTRUCT
{
ULONG_PTR dwData;
DWORD cbData;
_Field_size_bytes_(cbData) PVOID lpData;
} COPYDATASTRUCT, *PCOPYDATASTRUCT;
// data sent by shell via Shell_NotifyIcon
typedef struct _SHELLTRAYDATA
{
DWORD dwUnknown;
DWORD dwMessage;
NID_XX nid;
} *PSHELLTRAYDATA;
// sub structure common to all others
typedef struct
{
DWORD cbSize;
HWND hWnd;
UINT uID;
UINT uFlags;
UINT uCallbackMessage;
HICON hIcon;
} NID_XX, *PNID_XX;
typedef const NID_XX * PCNID_XX;
EDIT: Размеры структур следующие:
Неуправляемый:
Удалось:
То же самое и с обеих сторон.
Поскольку Ручки 64 бит на 64-битных сборках, а структура, которую мы получаем, по-прежнему содержит 32 бита. Изменение IntPtr на Uint32 для hIcon и hWnd сделало трюк. Теперь эта структура работает как на архитектуре x64, так и на x86. Я всегда знал, что сериализация в JSON определенно не соответствует моему требованию. Спасибо за помощь.
Эти структуры различаются для разных архитектур. Значения IntPtr
имеют ширину 32 бит или ширину 64 бит в зависимости от архитектуры. Это имеет очевидные последствия для размера членов и, возможно, менее очевидных последствий для выравнивания.
Нельзя использовать одну и ту же структуру независимо от архитектуры. Вы должны знать об архитектуре обоих процессов. Всякий раз, когда отправитель и получатель не имеют одинаковой архитектуры, у вас возникают проблемы.
Вы можете выбрать фиксированный макет, используя С# long
вместо IntPtr
. Такие типы, как HWND
и HICON
, всегда будут соответствовать long
С#. Хотя будьте осторожны с типами дескрипторов, которые имеют смысл только в конкретном процессе. Например, значения HICON
не будут иметь значения, как только вы отправите их в другой процесс.
Вместо использования фиксированной структуры компоновки, я думаю, я бы сериализовал. Сериализуйте данные, которые вы хотите отправить в JSON, например. Это может быть легко упаковано в строку и отправлено через WM_COPYDATA
.
IntPtr
на 32-битные целые, либо наоборот. Сравните определение этих структур в C и C # и определите правильные целочисленные размеры, используя таблицу в Типах данных Windows на MSDN . 2) Различия в выравнивании - еще одна потенциальная проблема, но она не должна влиять на ваш случай.