2016-11-01 6 views
0

Я изо всех сил пытался заставить его работать (вызов win32 API: SendMessage с WM_COPYDATA и COPYDATASTRUCT для хранения данных), и, поскольку он работает на моем компьютере с Windows 7, мне интересно, действительно ли мое сопоставление является хорошим и если нет побочного эффекта моего решения?JNA: Правильное отображение для COPYDATASTRUCT?

Вот мой код:

/** 
    * For usage with WM_COPYDATA 
    * cf : https://msdn.microsoft.com/en-us/library/windows/desktop/ms649010(v=vs.85).aspx 
    */ 
    long SendMessage(HWND hWnd, int msg, WPARAM wParam, COPYDATASTRUCT.ByReference lParam); 

    int WM_COPYDATA = 0x004A; 


//cf : https://msdn.microsoft.com/en-us/library/windows/desktop/ms649010(v=vs.85).aspx 
class COPYDATASTRUCT extends Structure { 

    public static class ByReference extends COPYDATASTRUCT implements Structure.ByReference { 
    } 

    public COPYDATASTRUCT() { 
     super(); 
    } 

    public int dwData; 
    public long cbData; 
    public Pointer lpData; 

    protected List<String> getFieldOrder() { 
     return Arrays.asList(new String[] { "dwData", "cbData", "lpData" }); 
    } 
} 

И код вызова с 2 примера:

User32Extension.COPYDATASTRUCT.ByReference dataStruct = new User32Extension.COPYDATASTRUCT.ByReference(); 
     String message = "Hello ! :-) !"; 
     Memory m = new Memory(message.length() + 1); 
     m.setString(0, message); 
     dataStruct.dwData = 10; 
     dataStruct.cbData = message.length() + 1; 
     dataStruct.lpData = m; 
     dataStruct.write(); // writes to native memory the structure. 
     result = user32.SendMessage(hwndTarget, // target hwnd. 
       User32Extension.WM_COPYDATA, // copy data message. 
       wparam, // current hwnd 
       dataStruct // data by reference here 
     ); 

     User32Extension.COPYDATASTRUCT.ByReference myDataStruct = new User32Extension.COPYDATASTRUCT.ByReference(); 
     User32Extension.TEST_STRUCT myStruct = new User32Extension.TEST_STRUCT(); 
     //simple C structure here with 4 fields of C types int, char, char and long. 
     myStruct.iNumber = 677; 
     myStruct.cCode = 'E'; 
     myStruct.cCode2 = 'T'; 
     myStruct.lLong1 = new NativeLong(123456789L); 
     myStruct.write(); 
     LOGGER.trace("myStruct (size=" + myStruct.size() + ")=" + myStruct.toString(true)); 

     myDataStruct.dwData = 11; 
     myDataStruct.cbData = myStruct.size(); 
     myDataStruct.lpData = myStruct.getPointer(); 
     myDataStruct.write(); // writes to native memory the structure. 
     result = user32.SendMessage(hwndTarget, // target hwnd. 
       User32Extension.WM_COPYDATA, // copy data message. 
       wparam, // current hwnd 
       myDataStruct // data 
     ); 

Главное, этот код по сравнению со всем, что я нашел в сети, является то, что COPYDATASTRUCT атрибут cbData имеет тип long. Если я настроен на int, это не сработает (данные неверно получены в WndProc унаследованного приложения C). Правильно ли отображать DWORD на длинный тип java? Было бы лучше с NativeLong?

Другое, что нужно отметить, это явный вызов Structure.write() для всех созданных объектов (myStruct и myDataStruct). Это необходимо, чтобы не иметь пустую память перед вызовом SendMessage api. Считаете ли вы, что это нормально? Или jna должен вызывать это автоматически перед вызовом SendMessage?

Заранее спасибо.

+0

JNA предоставляет определения для 'DWORD' и других типов окон. Любое использование собственного типа 'long' должно быть представлено типом' NativeLong' JNA. 'Structure.write()' вызывается JNA автоматически перед вызовом любой функции с аргументами структуры. – technomage

+0

@technomage, для записи я сделал еще один тест: это не обязательно для правильного поведения. Я добавил его для отладки с вызовом 'Structure.toString (true)'. Для типа DWORD, если я его использую, сообщение не поступает в C-называемую программу ... – cnico7

+0

Вот для информации, дампы памяти в трассировке (для теста со строкой Hello): дамп памяти с DWORD для cbData: [0a000000] [0e000000] [00c2d058] [00000000] дамп памяти с длиной для cbData: [0a000000] [00000000] [0e000000] [00000000] [306eda58] [00000000 ] – cnico7

ответ

0

Этот нативный код:

typedef struct tagCOPYDATASTRUCT { 
    ULONG_PTR dwData; 
    DWORD  cbData; 
    PVOID  lpData; 
} COPYDATASTRUCT, *PCOPYDATASTRUCT; 

карты к этому определению структуры ЮНА:

public class COPYDATASTRUCT extends Structure { 
    ULONG_PTR dwData; 
    DWORD  cbData; // or use "int" 
    Pointer lpData; 
} 

Первые и последние поля будут разного размера (и структура будет иметь различное выравнивание/отступы) в зависимости от того, используете ли вы 32- или 64-разрядную версию.

+0

Это кажется очевидным с ответом, и это то, что я испытал сначала, но не работал (нашел причину). К настоящему моменту, с моим текущим тестом, он работает, если моя JVM составляет 32 или 64 бит. И я подтверждаю, что dwData с длинным типом работает только в 64-битной JVM, но не в 32-битной JVM. Таким образом, тип ULONG_PTR имеет разный размер в зависимости от 32-битной или 64-разрядной JVM, которая использует JNA для отправки сообщения. Спасибо. – cnico7

+0

Я считаю, что технически 'ULONG_PTR' предназначен для беззнакового длинного, который достаточно велик, чтобы соответствовать указателю, поэтому имеет смысл, что он определяется по-разному на 32 против 64 бит. Определение типа JNA отражает этот факт, используя 'Pointer.SIZE', чтобы определить, насколько он большой. – technomage