Menu, Создание динамического меню.

Тема в разделе "WASM.WIN32", создана пользователем Andrey_59, 25 май 2023.

  1. Andrey_59

    Andrey_59 Member

    Публикаций:
    0
    Регистрация:
    20 фев 2021
    Сообщения:
    81
    Ещё раз здравствуйте! Вопрос назрел следующий, если я хочу создать меню динамически, как создавал окна диалоговых панелей, только здесь структуры MENUEX_TEMPLATE_HEADER, MENUEX_TEMPLATE_ITEM, думал делать по аналогии с диалоговыми окнами, не получается, Вызов функции создания меню LoadMenuIndirect() завершается с ошибкой 13. Я думаю, что заполняю структуры не верно, хотелось бы получить дельный совет...
    Вот как я пытаюсь реализовать создание меню.
    Код (C++):
    1. HMENU CreateMenu()
    2. {
    3.     BYTE* p, * pmenuTempl;
    4.     p = pmenuTempl = (BYTE*)LocalAlloc(LPTR, 512);
    5.     if (!p)
    6.     {
    7.         MessageBox(NULL, TEXT("Can't memory allocated"),
    8.             TEXT("Error"), MB_OK);
    9.         return (HMENU)NULL;
    10.     }
    11.  
    12.     MENUEX_TEMPLATE_HEADER* lpmth;
    13.     MENUEX_TEMPLATE_ITEM* lpmti;
    14.  
    15.     lpmth = (MENUEX_TEMPLATE_HEADER*)p;
    16.     lpmth->wVersion = 1;
    17.     lpmth->wOffset = 4;
    18.     lpmth->dwHelpId = 0;
    19.  
    20.     p = (BYTE*)(lpmth + 1);
    21.     LPWSTR szDst;
    22.     ULONG_PTR ui = 0;
    23.     //lpmti = (MENUEX_TEMPLATE_ITEM*)p;
    24.     //lpmti->dwHelpId = 0;
    25.     //lpmti->dwType = MFT_STRING;
    26.     //lpmti->dwState = MFS_ENABLED;
    27.     //lpmti->menuId = CM_FILE_OPEN;
    28.     //lpmti->bResInfo = 0;
    29.     //LPWSTR szDst = (LPWSTR)&lpmti->szText;
    30.     ////p = (BYTE*)(lpmti + 1);
    31.     ////LPWSTR szDst = (LPWSTR)p;
    32.     //wmemcpy_s(szDst, 512, TEXT("Open"), 5);
    33.     //p = (BYTE*)(szDst + _tcslen(TEXT("Open")));
    34.  
    35.     //ULONG_PTR ui = (ULONG_PTR)p;
    36.     //ui += 3;
    37.     //ui >>= 2;
    38.     //ui <<= 2;
    39.     //p = (BYTE*)ui;
    40.  
    41.     ////2
    42.     //lpmti = (MENUEX_TEMPLATE_ITEM*)p;
    43.     //lpmti->dwHelpId = 0;
    44.     //lpmti->dwType = MFT_STRING;
    45.     //lpmti->dwState = MFS_ENABLED;
    46.     //lpmti->menuId = CM_FILE_CREATE;
    47.     //lpmti->bResInfo = 0;
    48.     //szDst = (LPWSTR)&lpmti->szText;
    49.  
    50.     //wmemcpy_s(szDst, 512, TEXT("Create"), 7);
    51.     //p = (BYTE*)(szDst + _tcslen(TEXT("Create")));
    52.     //ui = (ULONG_PTR)p;
    53.     //ui += 3;
    54.     //ui >>= 2;
    55.     //ui <<= 2;
    56.     //p = (BYTE*)ui;
    57.  
    58.     ////3
    59.     //lpmti = (MENUEX_TEMPLATE_ITEM*)p;
    60.     //lpmti->dwHelpId = 0;
    61.     //lpmti->dwType = MFT_STRING;
    62.     //lpmti->dwState = MFS_ENABLED;
    63.     //lpmti->menuId = CM_FILE_SAVE;
    64.     //lpmti->bResInfo = 0;
    65.     //szDst = (LPWSTR)&lpmti->szText;
    66.     //wmemcpy_s(szDst, 512, TEXT("Save"), 5);
    67.     //p = (BYTE*)(szDst + _tcslen(TEXT("Save")));
    68.     //
    69.  
    70.     //ui = (ULONG_PTR)p;
    71.     //ui += 3;
    72.     //ui >>= 2;
    73.     //ui <<= 2;
    74.     //p = (BYTE*)ui;
    75.  
    76.     //4
    77.     lpmti = (MENUEX_TEMPLATE_ITEM*)p;
    78.     lpmti->dwHelpId = 0;
    79.     lpmti->dwType = MFT_STRING;
    80.     lpmti->dwState = MFS_ENABLED;
    81.     lpmti->menuId = CM_FILE_QUIT;
    82.     lpmti->bResInfo = 0x80;
    83.     szDst = (LPWSTR)&lpmti->szText;
    84.     wmemcpy_s(szDst, 512, TEXT("Exit"), 5);
    85.     p = (BYTE*)(szDst + _tcslen(TEXT("Exit")));
    86.  
    87.     ui = (ULONG_PTR)p;
    88.     ui += 3;
    89.     ui >>= 2;
    90.     ui <<= 2;
    91.     p = (BYTE*)ui;
    92.  
    93.  
    94.     HMENU hMenu = LoadMenuIndirect((MENUTEMPLATEW*)(MENUEX_TEMPLATE_HEADER*)pmenuTempl);
    95.  
    96.     if (!hMenu)
    97.     {
    98.         DWORD er = GetLastError();
    99.     }
    100.     LocalFree(LocalHandle(pmenuTempl));
    101.  
    102.     return hMenu;
    103. }
     
  2. Andrey_59

    Andrey_59 Member

    Публикаций:
    0
    Регистрация:
    20 фев 2021
    Сообщения:
    81
    Если никому не интересно, то хотя бы скажите. стоит ли вообще выделять память для построения меню с помощью вышеозначенных структур?
     
  3. MaKsIm

    MaKsIm Member

    Публикаций:
    0
    Регистрация:
    11 фев 2008
    Сообщения:
    94
    Больше сил потратишь на разыменовывание указателей. Куда проще сделать CreateMenu, а потом по его хэндлу InsertMenu/AppendMenu
     
  4. mantissa

    mantissa Мембер Команда форума

    Публикаций:
    0
    Регистрация:
    9 сен 2022
    Сообщения:
    155
    если ты будешь всегда это делать вручную, то нет. Если напишешь оболочку, то без разницы как
     
  5. M0rg0t

    M0rg0t Well-Known Member

    Публикаций:
    0
    Регистрация:
    18 окт 2010
    Сообщения:
    1.576
    Andrey_59, можно либо нарисовать в редакторе ресурсов, либо создавать динамически.

    1. Создаете ресурс, верхний элемент (допустим, как "File" делаете пустым или каким угодно, далее его подэлементы и будут элементы меню).
    Код (Text):
    1. hMenu = LoadMenu(NULL, MAKEINTRESOURCE(MAIN_MENU));
    2.         hSubMenu = GetSubMenu(hMenu, 0);
    3. TrackPopupMenuEx(GetSubMenu....)[
    4.  
    2.
    Код (Text):
    1. hMenu = CreatePopupMenu();
    2. AppendMenu(hMenu, MF_STRING, 1, L"Open");
    3. AppendMenu(hMenu, MF_STRING, 2, L"Upload");
    4. ...
    5. TrackPopupMenuEx(hMenu....)
     
    Thetrik нравится это.
  6. Andrey_59

    Andrey_59 Member

    Публикаций:
    0
    Регистрация:
    20 фев 2021
    Сообщения:
    81
    Вроде бы понятно по вопросу, что именно меня интересует, СОЗДАВАТЬ ДИНАМИЧЕСКИ. Я знаю про CreateMenu, CreatePopupMenu, SetMenu... , значит меня интересует что-то другое, а что именно, ну, вы не поверите, создание меню динамически с помощью MENUEX_TEMPLATE_HEADER, MENUEX_TEMPLATE_ITEM.
     
  7. MaKsIm

    MaKsIm Member

    Публикаций:
    0
    Регистрация:
    11 фев 2008
    Сообщения:
    94
    Если вам так хочется извращаться на C++, то это ваше дело. Но вот вам на FASM использование этой же функции. Все прекрасно работает.
    Проверил 4 варианта: статический буфер в секции данных, 3 способа динамического выделения памяти (HeapAlloc, GlobalAlloc, LocalAlloc).
    Код (ASM):
    1. format   PE64 GUI 6.0
    2. struc   String text& { rb RVA $ and 1
    3.   . du text
    4.   label .Length   at (( $ - . ) shr 1 )
    5.   dw NULL
    6.   label .Bytes   at  ( $ - . )
    7. }
    8. include 'WIN64A.INC'
    9. section '.idata' import data readable writeable
    10. library   kernel32,     "kernel32.dll",\
    11.    user32,       "user32.dll"
    12. include 'API\KERNEL32.INC'
    13. include 'API\USER32.INC'
    14. section '.text' code readable executable
    15. entry   $
    16.    push   rax
    17.    mov   [wce.cbSize], wce.Length
    18.    lea   rdx, [main]
    19.    mov   [wce.style], CS_HREDRAW or CS_VREDRAW or CS_GLOBALCLASS
    20.    mov   [wce.lpfnWndProc], rdx
    21.    mov   [wce.cbClsExtra], 0
    22.    mov   [wce.cbWndExtra], 0
    23.    invoke   GetModuleHandleW, NULL
    24.    mov   [wce.hInstance], rax
    25.    invoke   LoadIconW, NULL, IDI_APPLICATION
    26.    mov   [wce.hIcon], rax
    27.    invoke   LoadCursorW, NULL, IDC_ARROW
    28.    mov   rdx, COLOR_WINDOW + 1
    29.    mov   [wce.hCursor], rax
    30.    lea   rcx, [main.szClass]
    31.    mov   [wce.hbrBackground], rdx
    32.    and   [wce.lpszMenuName], 0
    33.    mov   [wce.lpszClassName], rcx
    34.    invoke   LoadIconW, NULL, IDI_APPLICATION
    35.    mov   [wce.hIconSm], rax
    36.    invoke   RegisterClassExW, addr wce
    37.    mov   rdx, rax
    38.    invoke   CreateWindowExW, WS_EX_OVERLAPPEDWINDOW, rdx,\
    39.           addr main.szTitle, WS_OVERLAPPEDWINDOW,\
    40.           100, 100, 800, 600, HWND_DESKTOP,\
    41.           NULL, [wce.hInstance], NULL
    42.    pop   rax
    43.    call   MessageLoop
    44.    push   rax
    45.    invoke   ExitProcess, rax
    46.  
    47.   @@:
    48.    invoke   TranslateMessage, addr msg
    49.    invoke   DispatchMessageW, addr msg
    50.  
    51. MessageLoop:
    52.    invoke   GetMessageW, addr msg, NULL, NULL, NULL
    53.    inc   eax
    54.    jz   @f
    55.    dec   eax
    56.    jnz   @b
    57.    mov   rax, [msg.wParam]
    58.    retn
    59.  
    60.   @@:
    61.    invoke   GetLastError
    62.    retn
    63.  
    64. CM_FILE_QUIT = 1000
    65.  
    66. align 64
    67. main:
    68.    push   rdi
    69.    mov   eax, edx
    70.    mov   rdx, rcx
    71.    mov   rcx, .jumps.count
    72.    lea   rdi, [.jumps]
    73.   repne   scas   dword [rdi]
    74.    xchg   rax, rcx
    75.    xchg   rdx, rcx
    76.    pop   rdi
    77.    jne   @f
    78.    neg   rax
    79.    movzx   rax, word [.jumps + .jumps.count * 6 + rax * 2 - 2]
    80.    lea   rax, [main + rax]
    81.    jmp   rax
    82.  
    83.   @@:
    84.    jmp   [DefWindowProcW]
    85.   .szClass   String "TForm1"
    86.   .szTitle   String "Form1"
    87. align 4
    88.   .jumps   dd WM_CREATE, WM_DESTROY, WM_COMMAND
    89.   label .jumps.count at (( $ - .jumps ) shr 2 )
    90.      dw .Form1Create - main
    91.      dw .Form1Destroy - main
    92.      dw .Form1Command - main
    93.  
    94. label .hWnd qword at ( rbp + 16 )
    95. label .uMsg qword at ( rbp + 24 )
    96. label .wPar qword at ( rbp + 32 )
    97. label .lPar qword at ( rbp + 40 )
    98.  
    99. .Form1Create:
    100.    enter   0, 0
    101.    mov   [.hWnd], rcx
    102. ;   call   newMenu0 ; LoadMenuIndirect из структур в секции .data
    103. ;   call   newMenu1 ; LoadMenuIndirect при выделении памяти через HeapAlloc
    104. ;   call   newMenu2 ; LoadMenuIndirect при выделении памяти через GlobalAlloc
    105.    call   newMenu3 ; LoadMenuIndirect при выделении памяти через LocalAlloc
    106.    invoke   SetMenu, [.hWnd], rax
    107.    invoke   IsWindowVisible, [.hWnd]
    108.    test   al, al
    109.    jnz   @f
    110.    invoke   ShowWindow, [.hWnd], SW_SHOWNORMAL
    111.    invoke   UpdateWindow, [.hWnd]
    112.  
    113.   @@:
    114.    xor   rax, rax
    115.    leave
    116.    retn
    117.  
    118. .Form1Destroy:
    119.    enter   0, 0
    120.    invoke   PostQuitMessage, NULL
    121.    xor   rax, rax
    122.    leave
    123.    retn
    124.  
    125. .Form1Command:
    126.    enter   0, 0
    127.    cmp   r8d, CM_FILE_QUIT
    128.    jnz   .done
    129.    invoke   DestroyWindow, rcx
    130.    jmp   .done
    131.  
    132.   .done:
    133.    xor   rax, rax
    134.    leave
    135.    retn
    136.  
    137. newMenu0:
    138.    push   rcx
    139.    invoke   LoadMenuIndirect, addr main.mainMenu
    140.    pop   rcx
    141.    retn
    142.  
    143. newMenu1:
    144.    push   rdi
    145.    push   rdx
    146.    push   rax
    147.    invoke   GetProcessHeap
    148.    invoke   HeapAlloc, rax, HEAP_ZERO_MEMORY, 512
    149.    mov   rdi, rax
    150.    call   fillMenu
    151.    invoke   LoadMenuIndirect, rdi
    152.    mov   [rsp], rax
    153.    invoke   GetProcessHeap
    154.    invoke   HeapFree, rax, HEAP_NO_SERIALIZE, rdi
    155.    pop   rax
    156.    pop   rdx
    157.    pop   rdi
    158.    retn
    159.  
    160. newMenu2:
    161.    push   rdi
    162.    push   rdx
    163.    push   rax
    164.    invoke   GlobalAlloc, GPTR, 512
    165.    mov   rdi, rax
    166.    call   fillMenu
    167.    invoke   LoadMenuIndirect, rdi
    168.    mov   [rsp], rax
    169.    invoke   GlobalFree, rdi
    170.    pop   rax
    171.    pop   rdx
    172.    pop   rdi
    173.    retn
    174.  
    175. newMenu3:
    176.    push   rdi
    177.    push   rdx
    178.    push   rax
    179.    invoke   LocalAlloc, LPTR, 512
    180.    mov   rdi, rax
    181.    call   fillMenu
    182.    invoke   LoadMenuIndirect, rdi
    183.    mov   [rsp], rax
    184.    invoke   LocalFree, rdi
    185.    pop   rax
    186.    pop   rdx
    187.    pop   rdi
    188.    retn
    189.  
    190. fillMenu:
    191.   virtual at 0
    192.      du 'Exit'
    193.   load .a qword from 0
    194.   end virtual
    195.    push   rdx
    196.    mov   rdx, .a
    197.    mov   qword [rdi +  0], 0x0000000000040001 ; MENUEX_TEMPLATE_HEADER(wVersion = 1, wOffset = 4, dwHelpId = 0)
    198.    mov   dword [rdi +  8], MFT_STRING    ; MENUEX_TEMPLATE_ITEM
    199.    mov   dword [rdi + 12], MFS_ENABLED
    200.    mov   dword [rdi + 16], CM_FILE_QUIT
    201.    mov    word [rdi + 20], 0x80
    202.    mov   qword [rdi + 22], rdx
    203.    mov    word [rdi + 30], NULL
    204.    pop   rdx
    205.    retn
    206.  
    207. section '.data' data readable writeable
    208. msg     MSG
    209. wce     WNDCLASSEX
    210. wce.Length = $ - wce
    211. align   8
    212. main.mainMenu   dw 1, 4    ; MENUEX_TEMPLATE_HEADER
    213.      dd 0
    214.      dd MFT_STRING   ; MENUEX_TEMPLATE_ITEM
    215.      dd MFS_ENABLED
    216.      dd CM_FILE_QUIT
    217.      dw 0x80
    218.      du "Exit", 0
     
  8. Andrey_59

    Andrey_59 Member

    Публикаций:
    0
    Регистрация:
    20 фев 2021
    Сообщения:
    81
    Вам же хочется извращаться на ассемблере почему бы этого не делать на другом языке программирования... и в чём здесь извращение? В том, что хочу понять, как это работает?!
    По теме:
    У меня ничего не получается, не знаю почему... Возможно ли с помощью данных структур создать не только пункты меню, которые ещё нужно как-то подключить к главному меню, но и главное меню? Что я имею ввиду: CreateMenu(), создаётся главное меню к которому подключаются меню созданные с помощью CreatePopupMenu(), я так понимаю, что с помощью данных структур можно создавать только пункты меню, которые затем подключаются к главному меню. Или я не прав.
     
  9. MaKsIm

    MaKsIm Member

    Публикаций:
    0
    Регистрация:
    11 фев 2008
    Сообщения:
    94
    Нет. Можно создать полноценное меню. Возьмите мой пример и попробуйте. Его надо просто скормить fasmw. Потом можете скопировать строки со 198 по 203 и изменить данные пунктов меню прибавляя смещение. Так вы создадите и другие элементы меню. А если посмотрите на 106 строку, то увидите как это меню цепляется к окну в качестве MainMenu
    --- Сообщение объединено, 28 май 2023 ---
    Вот так у меня выглядит структура в секции данных для создания меню следующего вида (см. скриншот) через LoadMenuIndirect
    Код (ASM):
    1. main.mainMenu  dw 1, 4  ; MENUEX_TEMPLATE_HEADER
    2.   dd 0
    3.  
    4.   dd MFT_STRING  ; MENUEX_TEMPLATE_ITEM
    5.   dd MFS_ENABLED
    6.   dd 0
    7.   dw 0x01
    8.   du "File", 0
    9.   dd 0
    10.  
    11.   dd MFT_STRING  ; MENUEX_TEMPLATE_ITEM
    12.   dd MFS_ENABLED
    13.   dd CM_FILE_NEW
    14.   dw 0x00
    15.   du "New", 0, 0
    16.  
    17.   dd MFT_STRING  ; MENUEX_TEMPLATE_ITEM
    18.   dd MFS_ENABLED
    19.   dd CM_FILE_QUIT
    20.   dw 0x80
    21.   du "Exit", 0
    22.  
    23.   dd MFT_STRING  ; MENUEX_TEMPLATE_ITEM
    24.   dd MFS_ENABLED
    25.   dd CM_FILE_HELP
    26.   dw 0x80
    27.   du "Help", 0
    Screenshot_20230528_033613.png
     
  10. Andrey_59

    Andrey_59 Member

    Публикаций:
    0
    Регистрация:
    20 фев 2021
    Сообщения:
    81
    Хз. Я так же делаю, что не так то, у меня вылетает ошибка.
     
  11. MaKsIm

    MaKsIm Member

    Публикаций:
    0
    Регистрация:
    11 фев 2008
    Сообщения:
    94
    Ну у меня тоже вылетала пока я после File не добавил dd 0. Это странно, т.к. File уже выровнена на 4 байта и без dd.
    Код (ASM):
    1.   dd MFT_STRING  ; MENUEX_TEMPLATE_ITEM
    2.   dd MFS_ENABLED
    3.   dd 0
    4.   dw 0x01
    5.   du "File", 0
    6.   dd 0 ; <<< Вот этот ноль тут лишний. Он даже до 8 не выравнивает т.к. это смещение 24 от начала структуры и 32 от начала заголовка. С этим 0 получается 28 и 36 соответственно, но без него вылезает ошибка. Т.е. он не видит следующую структуру и считывает поля не из тех мест. При этом после Exit такой же фигни нету, хотя она по длине эквивалентна File.
    7.  
    8.   dd MFT_STRING  ; MENUEX_TEMPLATE_ITEM
    9. ...
     
  12. Andrey_59

    Andrey_59 Member

    Публикаций:
    0
    Регистрация:
    20 фев 2021
    Сообщения:
    81
    У меня такая вот структура, выравнивать, я выравниваю
    Код (Text):
    1. typedef struct {
    2.     //DWORD  dwHelpId;
    3.     DWORD  dwType;
    4.     DWORD  dwState;
    5.     DWORD  menuId;
    6.     WORD  bResInfo;
    7.     WCHAR  szText[1];
    8.     DWORD  dwHelpId;
    9.  
    10. } MENUEX_TEMPLATE_ITEM;
    Куда что добавлять мне, как по мне всё правильно, но всё равно ошибка 13(Недопустимые данные), хоть ты тресни.
    Код (C++):
    1. lpmti = (MENUEX_TEMPLATE_ITEM*)(lpmth+1);
    2.     //lpmti->dwHelpId = 0;
    3.     lpmti->dwType = MFT_STRING;
    4.     lpmti->dwState = MFS_ENABLED;
    5.     lpmti->menuId = 0;
    6.     lpmti->bResInfo = 0x01;
    7.     szDst = (LPWSTR)(lpmti->szText);
    8.     szSrc = TEXT("FILE");
    9.     for (; *szDst++ = *szSrc++;)
    10.         ;
    11.     lpmti = (MENUEX_TEMPLATE_ITEM*)szDst;
    12.     lpmti->dwHelpId = 0;
    13.     p = (BYTE*)lpmti;
     
  13. MaKsIm

    MaKsIm Member

    Публикаций:
    0
    Регистрация:
    11 фев 2008
    Сообщения:
    94
    Код (C++):
    1.    szDst = (LPWSTR)(lpmti->szText);
    2. ...
    3.     lpmti = (MENUEX_TEMPLATE_ITEM*)szDst;
    4.     lpmti->dwHelpId = 0;
    Так получается вы обратились к
    Смещение lpmti->szText = 14
    Смещение length(TEXT(L"FILE")) + 1 символ = 10 байт т.к. строка должна быть всегда WideChar
    Смещение lpmti->dwHelpId = 16
    Итого от исходного заголовка вы dwHelpId записали по смещению 40, а надо было записать его по смещению 24
    Код (C++):
    1. (DWORD*)szDst = 0;
    Вот так
     
    Последнее редактирование: 29 май 2023
  14. Andrey_59

    Andrey_59 Member

    Публикаций:
    0
    Регистрация:
    20 фев 2021
    Сообщения:
    81
    Тут ещё такая тема, что в одних структурах поле lpmti->dwHelpId есть, а в других нет., нужен ли этот член в структуре MENUEX_TEMPLATE_ITEM?
    Не знаю, смотрел в отладчике и, вроде бы, со смещениями всё в порядке. Хотя делал я это без поля dwHelpId.
    --- Сообщение объединено, 30 май 2023 ---
    В смысле вместо
    Код (C++):
    1. lpmti = (MENUEX_TEMPLATE_ITEM*)szDst;
    вставить
    Код (C++):
    1. lpmti = (DWORD*)szDst;
    - НО ЭТО ерунда какая то.
     
  15. MaKsIm

    MaKsIm Member

    Публикаций:
    0
    Регистрация:
    11 фев 2008
    Сообщения:
    94
    Вот именно. У вас ерунда. Я сказал, что вы присваиваете вот тут
    Код (C++):
    1. lpmti = (MENUEX_TEMPLATE_ITEM*)szDst;
    адрес конца строки как начало новой структуры
    MENUEX_TEMPLATE_ITEM и затем заполняете поле
    Код (C++):
    1. lpmti->dwHelpId = 0;
    Это, по вашему же описанию структуры, поле находится здесь
    Код (C++):
    1. typedef struct {
    2.     //DWORD  dwHelpId;
    3.     DWORD  dwType; // +0
    4.     DWORD  dwState; // +4
    5.     DWORD  menuId; // +8
    6.     WORD  bResInfo; // +12
    7.     WCHAR  szText[1]; // +14
    8.     DWORD  dwHelpId; // +16 <<<
    9.  
    10. } MENUEX_TEMPLATE_ITEM;
    Значит строка
    Код (C++):
    1. lpmti->dwHelpId = 0;
    эквивалентна записи (DWORD)0 по смещению 16 от начала структуры.

    Далее рассматриваем значение указателя szDst. По этому указателю в цикле
    Код (C++):
    1. for (; *szDst++ = *szSrc++;); // строка "File", \0 состоит из 5 символов и каждый по 2 байта
    было сделано 5 инкрементов (по 2 байта). Путём не хитрых математических вычислений получается что к
    szDst прибавили 10. Но изначально к нему был присвоен адрес со смещением +14 от начала структуры
    Код (C++):
    1. szDst = (LPWSTR)(lpmti->szText);
    Итого: 14 + 5*2 + 16 = 40, но должно быть так
    Код (C++):
    1. typedef struct {
    2.     //DWORD  dwHelpId;
    3.     DWORD  dwType; // +0
    4.     DWORD  dwState; // +4
    5.     DWORD  menuId; // +8
    6.     WORD  bResInfo;  // +12
    7.     WCHAR  szText[5]; // +14
    8.     DWORD  dwHelpId; // +24
    9. } MENUEX_TEMPLATE_ITEM;
    конкретно для строки File из 4 символов.
     
    Последнее редактирование: 30 май 2023
  16. Andrey_59

    Andrey_59 Member

    Публикаций:
    0
    Регистрация:
    20 фев 2021
    Сообщения:
    81
    Я это поле убрал. Только ситуация не меняется.
    Ну хорошо сделал так как написано, но та же ошибка.
    Код (C++):
    1. lpmti = (MENUEX_TEMPLATE_ITEM*)(lpmth+1);
    2.     //lpmti->dwHelpId = 0;
    3.     lpmti->dwType = MFT_STRING;
    4.     lpmti->dwState = MFS_ENABLED;
    5.     lpmti->menuId = 0;
    6.     lpmti->bResInfo = 0x01;
    7.     szDst = (LPWSTR)(lpmti->szText);
    8.     szSrc = TEXT("FILE");
    9.     for (; *szDst++ = *szSrc++;)
    10.         ;
    11.  
    12.     DWORD* pdwVal = (DWORD*)szDst;
    13.     *pdwVal++ = 0;
    14.  
    15.     //----------------------------------------
    16.  
    17.     lpmti = (MENUEX_TEMPLATE_ITEM*)(BYTE*)pdwVal;
    18.     lpmti->dwType = MFT_STRING;
    19.     lpmti->dwState = MFS_ENABLED;
    20.     lpmti->menuId = CM_FILE_QUIT;
    21.     lpmti->bResInfo = MF_END;
    22.     szDst = (LPWSTR)(lpmti->szText);
    23.     szSrc = TEXT("Exit");
    24.     for (; *szDst++ = *szSrc++;)
    25.         ;
    26.  
    27.     *(DWORD*)szDst = 0;
     
  17. MaKsIm

    MaKsIm Member

    Публикаций:
    0
    Регистрация:
    11 фев 2008
    Сообщения:
    94
    Код (C++):
    1. #include <windows.h>
    2. #include <stdio.h>
    3.  
    4. #define MM_NEW_ITEM 1000
    5. #define MM_EXIT_ITEM 1001
    6. #define MM_HELP_ITEM 1002
    7.  
    8. char menuTemplate[1024];
    9. HINSTANCE hInstance = nullptr;
    10.  
    11. struct MENUEX_TEMPLATE_HEADER {
    12.    WORD wVersion, wOffset;
    13.    DWORD dwHelpId;
    14. };
    15.  
    16. struct MENUEX_TEMPLATE_ITEM {
    17.    DWORD dwType, dwState, uId;
    18.    WORD wFlags;
    19.    WCHAR szText[1];
    20. };
    21.  
    22. MENUEX_TEMPLATE_ITEM *FillMenuItemTemplate(MENUEX_TEMPLATE_ITEM *lpmti,
    23.                       DWORD aType, DWORD aState,
    24.                       DWORD aID,  WORD aFlags,
    25.                       LPCWSTR szText) {
    26.    int flag  = 0;
    27.    lpmti->dwType  = aType;
    28.    lpmti->dwState  = aState;
    29.    lpmti->uId  = aID;
    30.    lpmti->wFlags  = aFlags;
    31.    WCHAR *szDst  = &lpmti->szText[0];
    32.    const WCHAR *szSrc = szText;
    33.    for (; *szDst++  = *szSrc++; flag ^= 2);
    34.    return (MENUEX_TEMPLATE_ITEM *)(((BYTE *)szDst) + flag);
    35. }
    36.  
    37. void FillMenuBuffer(MENUEX_TEMPLATE_HEADER *lpmth) {
    38.    lpmth->wVersion = 1;
    39.    lpmth->wOffset  = 4;
    40.    lpmth->dwHelpId = 0;
    41.    MENUEX_TEMPLATE_ITEM *lpmti = (MENUEX_TEMPLATE_ITEM *)((void *)(lpmth + 1));
    42.    lpmti = FillMenuItemTemplate(lpmti, MFT_STRING, MFS_ENABLED, 0, 0x01, L"File");
    43.  
    44. // Эта штука нужна только после пункта File
    45.    *(DWORD *)lpmti = 0;
    46.    lpmti = (MENUEX_TEMPLATE_ITEM *)((DWORD *)(lpmti) + 1);
    47.  
    48.    lpmti = FillMenuItemTemplate(lpmti, MFT_STRING, MFS_ENABLED, MM_NEW_ITEM,  0x00, L"New");
    49.    lpmti = FillMenuItemTemplate(lpmti, MFT_STRING, MFS_ENABLED, MM_EXIT_ITEM, 0x80, L"Exit");
    50.    lpmti = FillMenuItemTemplate(lpmti, MFT_STRING, MFS_ENABLED, MM_HELP_ITEM, 0x80, L"Help");
    51. }
    52.  
    53. HMENU LoadMenuTemplate0() {
    54.    FillMenuBuffer((MENUEX_TEMPLATE_HEADER *)&menuTemplate);
    55.    return LoadMenuIndirectA((MENUEX_TEMPLATE_HEADER *)&menuTemplate);
    56. }
    57.  
    58. HMENU LoadMenuTemplate1() {
    59.    MENUEX_TEMPLATE_HEADER *lpmth = (MENUEX_TEMPLATE_HEADER *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 1024);
    60.    FillMenuBuffer(lpmth);
    61.    HMENU hMenu = LoadMenuIndirectA(lpmth);
    62.    HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, (void *)lpmth);
    63.    return hMenu;
    64. }
    65.  
    66. HMENU LoadMenuTemplate2() {
    67.    MENUEX_TEMPLATE_HEADER *lpmth = (MENUEX_TEMPLATE_HEADER *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 1024);
    68.    FillMenuBuffer(lpmth);
    69.    HMENU hMenu = LoadMenuIndirectW(lpmth);
    70.    HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, (void *)lpmth);
    71.    return hMenu;
    72. }
    73.  
    74. ATOM RegisterMainClass(HINSTANCE hInst, LPCWSTR szClass, void *fnProc) {
    75.    WNDCLASSEXW wce;
    76.    wce.cbSize  = sizeof(wce);
    77.    wce.style  = CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS;
    78.    wce.lpfnWndProc  = (WNDPROC)fnProc;
    79.    wce.cbClsExtra  = 0;
    80.    wce.cbWndExtra  = 0;
    81.    wce.hInstance  = hInst;
    82.    wce.hIcon  = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
    83.    wce.hCursor  = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
    84.    wce.hbrBackground = (HBRUSH)COLOR_WINDOW + 1;
    85.    wce.lpszMenuName  = nullptr;
    86.    wce.lpszClassName = szClass;
    87.    wce.hIconSm  = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
    88.    return RegisterClassExW(&wce);
    89. }
    90.  
    91. LRESULT Form1_wndProc(HWND hWnd, UINT uMsg, WPARAM wPar, LPARAM lPar) {
    92.    switch (uMsg) {
    93.      case WM_DESTROY: PostQuitMessage(0);
    94.        return 0;
    95.      case WM_CREATE: SetMenu(hWnd, LoadMenuTemplate1());
    96.        if (!IsWindowVisible(hWnd)) {
    97.          ShowWindow(hWnd, SW_SHOWNORMAL);
    98.          UpdateWindow(hWnd);
    99.        }
    100.        return 0;
    101.      case WM_COMMAND:
    102.        switch (wPar) {
    103.          case MM_NEW_ITEM: break;
    104.          case MM_EXIT_ITEM: DestroyWindow(hWnd);
    105.            return 0;
    106.          case MM_HELP_ITEM: break;
    107.          default: break;
    108.        }
    109.        break;
    110.      default: break;
    111.    }
    112.    return DefWindowProcW(hWnd, uMsg, wPar, lPar);
    113. }
    114.  
    115. int main(int argc, char *argv[]) {
    116.    hInstance  = GetModuleHandleW(NULL);
    117.    if (!hInstance) {
    118.      printf("Error! Can't GetModuleHandle. . .");
    119.      return 1;
    120.    }
    121.    ATOM aClass  = RegisterMainClass(hInstance, L"TForm1", (void *)Form1_wndProc);
    122.    if (!aClass) {
    123.      printf("Error! Can't RegisterMainClass. . .");
    124.      return 1;
    125.    }
    126.    HWND aWindow = CreateWindowExW(WS_EX_OVERLAPPEDWINDOW,
    127.                   (LPCWSTR)((unsigned)aClass), L"Form1",
    128.                   WS_OVERLAPPEDWINDOW,
    129.                   100, 100, 800, 600,
    130.                   HWND_DESKTOP, nullptr,
    131.                   hInstance, nullptr);
    132.    if (!aWindow) {
    133.      printf("Error! Can't CreateWindowEx. . .");
    134.      return 1;
    135.    }
    136.    MSG aMsg;
    137.    while (int state = GetMessageW(&aMsg, 0, 0, 0)) {
    138.      if (state == -1) {
    139.        aMsg.wParam = GetLastError();
    140.        break;
    141.      }
    142.      TranslateMessage(&aMsg);
    143.      DispatchMessageW(&aMsg);
    144.    }
    145.    return aMsg.wParam;
    146. }
    Вот я вам на С++ набросал пример, который ранее показывал на FASM. Там есть меню из 4 пунктов (см. мой предыдущий скриншот).
     
  18. Andrey_59

    Andrey_59 Member

    Публикаций:
    0
    Регистрация:
    20 фев 2021
    Сообщения:
    81
    Это что за ... зачем, для чего...
    Мне не код нужен я не понимаю почему у меня не работает, я понять хочу, как с этим работать, а код я и сам напишу.
     
  19. MaKsIm

    MaKsIm Member

    Публикаций:
    0
    Регистрация:
    11 фев 2008
    Сообщения:
    94
    Это выравнивание.
    Ну так возьмите пример. Соберите, изучите и пишите сами что-то подобное.
     
  20. MaKsIm

    MaKsIm Member

    Публикаций:
    0
    Регистрация:
    11 фев 2008
    Сообщения:
    94
    Например вот так выглядит структура для создания меню изображённого ниже на скриншотах
    Поясняю. После каждого пункта меню первого уровня (File, Edit, ? и Help) есть дополнительное поле 4-батовое (этот поле появляется у каждого вложенного подменю wFlags & 1 != 0). Все остальные (New, Exit, Redo, итд) вложенные пункты меню идут без этого поля.
    Код (ASM):
    1.  
    2. main.mainMenu  dw 1, 4  ; MENUEX_TEMPLATE_HEADER
    3.   dd 0
    4.  
    5.   dd MFT_STRING  ; MENUEX_TEMPLATE_ITEM
    6.   dd MFS_ENABLED
    7.   dd 0
    8.   dw 0x01
    9.   du "File", 0
    10.   dd 0 ; <<< Дополнительное поле
    11.  
    12.   dd MFT_STRING  ; MENUEX_TEMPLATE_ITEM
    13.   dd MFS_ENABLED
    14.   dd CM_FILE_NEW
    15.   dw 0x00
    16.   du "New", 0, 0
    17.  
    18.   dd MFT_STRING  ; MENUEX_TEMPLATE_ITEM
    19.   dd MFS_ENABLED
    20.   dd CM_FILE_NEW
    21.   dw 0x00
    22.   du "Open...", 0, 0
    23.  
    24.   dd MFT_STRING  ; MENUEX_TEMPLATE_ITEM
    25.   dd MFS_ENABLED
    26.   dd CM_FILE_NEW
    27.   dw 0x00
    28.   du "Save...", 0, 0
    29.  
    30.   dd MFT_STRING  ; MENUEX_TEMPLATE_ITEM
    31.   dd MFS_ENABLED
    32.   dd CM_FILE_NEW
    33.   dw 0x00
    34.   du "Save as...", 0
    35.  
    36.   dd MFT_STRING  ; MENUEX_TEMPLATE_ITEM
    37.   dd MFS_ENABLED
    38.   dd CM_FILE_QUIT
    39.   dw 0x80
    40.   du "Exit", 0
    41.  
    42.   dd MFT_STRING  ; MENUEX_TEMPLATE_ITEM
    43.   dd MFS_ENABLED
    44.   dd CM_FILE_HELP
    45.   dw 0x01
    46.   du "Edit", 0
    47.   dd 0 ; <<< Дополнительное поле
    48.  
    49.   dd MFT_STRING  ; MENUEX_TEMPLATE_ITEM
    50.   dd MFS_ENABLED
    51.   dd CM_FILE_HELP
    52.   dw 0x00
    53.   du "Redo", 0
    54.  
    55.   dd MFT_STRING  ; MENUEX_TEMPLATE_ITEM
    56.   dd MFS_ENABLED
    57.   dd CM_FILE_HELP
    58.   dw 0x00
    59.   du "Undo", 0
    60.  
    61.   dd MFT_STRING  ; MENUEX_TEMPLATE_ITEM
    62.   dd MFS_ENABLED
    63.   dd CM_FILE_HELP
    64.   dw 0x00
    65.   du "Cut", 0, 0
    66.  
    67.   dd MFT_STRING  ; MENUEX_TEMPLATE_ITEM
    68.   dd MFS_ENABLED
    69.   dd CM_FILE_HELP
    70.   dw 0x00
    71.   du "Copy", 0
    72.  
    73.   dd MFT_STRING  ; MENUEX_TEMPLATE_ITEM
    74.   dd MFS_ENABLED
    75.   dd CM_FILE_HELP
    76.   dw 0x00
    77.   du "Paste", 0, 0
    78.  
    79.   dd MFT_STRING  ; MENUEX_TEMPLATE_ITEM
    80.   dd MFS_ENABLED
    81.   dd CM_FILE_HELP
    82.   dw 0x00
    83.   du "Remove", 0
    84.  
    85.   dd MFT_STRING  ; MENUEX_TEMPLATE_ITEM
    86.   dd MFS_ENABLED
    87.   dd CM_FILE_HELP
    88.   dw 0x80
    89.   du "Select all", 0
    90.  
    91.   dd MFT_STRING  ; MENUEX_TEMPLATE_ITEM
    92.   dd MFS_ENABLED
    93.   dd CM_FILE_HELP
    94.   dw 0x81
    95.   du "?", 0, 0
    96.   dd 0 ; <<< Дополнительное поле
    97.  
    98.   dd MFT_STRING  ; MENUEX_TEMPLATE_ITEM
    99.   dd MFS_ENABLED
    100.   dd CM_FILE_HELP
    101.   dw 0x01
    102.   du "Help", 0
    103.   dd 0 ; <<< Дополнительное поле
    104.  
    105.   dd MFT_STRING  ; MENUEX_TEMPLATE_ITEM
    106.   dd MFS_ENABLED
    107.   dd CM_FILE_HELP
    108.   dw 0x00
    109.   du "Test1", 0, 0
    110.  
    111.   dd MFT_STRING  ; MENUEX_TEMPLATE_ITEM
    112.   dd MFS_ENABLED
    113.   dd CM_FILE_HELP
    114.   dw 0x00
    115.   du "Test2", 0, 0
    116.  
    117.   dd MFT_STRING  ; MENUEX_TEMPLATE_ITEM
    118.   dd MFS_ENABLED
    119.   dd CM_FILE_HELP
    120.   dw 0x80
    121.   du "Test3", 0, 0
    122.  
    123.   dd MFT_STRING  ; MENUEX_TEMPLATE_ITEM
    124.   dd MFS_ENABLED
    125.   dd CM_FILE_HELP
    126.   dw 0x80
    127.   du "About", 0, 0
    128.  
    Screenshot_20230531_154900.png Screenshot_20230531_154917.png Screenshot_20230531_154926.png
    --- Сообщение объединено, 31 май 2023 ---
    А вот и на С++ тоже самое
    Код (C++):
    1. #include <windows.h>
    2. #include <stdio.h>
    3.  
    4. #define MM_NEW_ITEM 1000
    5. #define MM_EXIT_ITEM 1001
    6. #define MM_HELP_ITEM 1002
    7.  
    8. char menuTemplate[1024];
    9. HINSTANCE hInstance = nullptr;
    10.  
    11. struct MENUEX_TEMPLATE_HEADER {
    12.   WORD wVersion, wOffset;
    13.   DWORD dwHelpId;
    14. };
    15.  
    16. struct MENUEX_TEMPLATE_ITEM {
    17.   DWORD dwType, dwState, uId;
    18.   WORD wFlags;
    19.   WCHAR szText[1];
    20. };
    21.  
    22. MENUEX_TEMPLATE_ITEM *FillMenuItemTemplate(MENUEX_TEMPLATE_ITEM *lpmti,
    23.   DWORD aType, DWORD aState,
    24.   DWORD aID,  WORD aFlags,
    25.   LPCWSTR szText) {
    26.   int flag  = (aFlags & 1) ? 4 : 0;
    27.   lpmti->dwType  = aType;
    28.   lpmti->dwState  = aState;
    29.   lpmti->uId  = aID;
    30.   lpmti->wFlags  = aFlags;
    31.   WCHAR *szDst  = &lpmti->szText[0];
    32.   const WCHAR *szSrc = szText;
    33.   for (; *szDst++  = *szSrc++; flag ^= 2);
    34.   if (aFlags & 1) *(DWORD *)szDst = 0;
    35.   return (MENUEX_TEMPLATE_ITEM *)(((BYTE *)szDst) + flag);
    36. }
    37.  
    38. void FillMenuBuffer(MENUEX_TEMPLATE_HEADER *lpmth) {
    39.   lpmth->wVersion = 1;
    40.   lpmth->wOffset  = 4;
    41.   lpmth->dwHelpId = 0;
    42.   MENUEX_TEMPLATE_ITEM *lpmti = (MENUEX_TEMPLATE_ITEM *)((void *)(lpmth + 1));
    43.   lpmti = FillMenuItemTemplate(lpmti, MFT_STRING, MFS_ENABLED, 0, 0x01, L"File");
    44.   lpmti = FillMenuItemTemplate(lpmti, MFT_STRING, MFS_ENABLED, MM_NEW_ITEM,  0x00, L"New");
    45.   lpmti = FillMenuItemTemplate(lpmti, MFT_STRING, MFS_ENABLED, MM_NEW_ITEM,  0x00, L"Open...");
    46.   lpmti = FillMenuItemTemplate(lpmti, MFT_STRING, MFS_ENABLED, MM_NEW_ITEM,  0x01, L"Reopen");
    47.   lpmti = FillMenuItemTemplate(lpmti, MFT_STRING, MFS_ENABLED, MM_NEW_ITEM,  0x00, L"Reopen file 1");
    48.   lpmti = FillMenuItemTemplate(lpmti, MFT_STRING, MFS_ENABLED, MM_NEW_ITEM,  0x00, L"Reopen file 2");
    49.   lpmti = FillMenuItemTemplate(lpmti, MFT_STRING, MFS_ENABLED, MM_NEW_ITEM,  0x00, L"Reopen file 3");
    50.   lpmti = FillMenuItemTemplate(lpmti, MFT_STRING, MFS_ENABLED, MM_NEW_ITEM,  0x00, L"Reopen file 4");
    51.   lpmti = FillMenuItemTemplate(lpmti, MFT_STRING, MFS_ENABLED, MM_NEW_ITEM,  0x80, L"Reopen file 5");
    52.   lpmti = FillMenuItemTemplate(lpmti, MFT_STRING, MFS_ENABLED, MM_NEW_ITEM,  0x00, L"Save...");
    53.   lpmti = FillMenuItemTemplate(lpmti, MFT_STRING, MFS_ENABLED, MM_NEW_ITEM,  0x00, L"Save as...");
    54.   lpmti = FillMenuItemTemplate(lpmti, MFT_STRING, MFS_ENABLED, MM_EXIT_ITEM, 0x80, L"Exit");
    55.   lpmti = FillMenuItemTemplate(lpmti, MFT_STRING, MFS_ENABLED, MM_EXIT_ITEM, 0x01, L"Edit");
    56.   lpmti = FillMenuItemTemplate(lpmti, MFT_STRING, MFS_ENABLED, MM_EXIT_ITEM, 0x00, L"Redo");
    57.   lpmti = FillMenuItemTemplate(lpmti, MFT_STRING, MFS_ENABLED, MM_EXIT_ITEM, 0x00, L"Undo");
    58.   lpmti = FillMenuItemTemplate(lpmti, MFT_STRING, MFS_ENABLED, MM_EXIT_ITEM, 0x00, L"Cut");
    59.   lpmti = FillMenuItemTemplate(lpmti, MFT_STRING, MFS_ENABLED, MM_EXIT_ITEM, 0x00, L"Copy");
    60.   lpmti = FillMenuItemTemplate(lpmti, MFT_STRING, MFS_ENABLED, MM_EXIT_ITEM, 0x00, L"Paste");
    61.   lpmti = FillMenuItemTemplate(lpmti, MFT_STRING, MFS_ENABLED, MM_EXIT_ITEM, 0x00, L"Remove");
    62.   lpmti = FillMenuItemTemplate(lpmti, MFT_STRING, MFS_ENABLED, MM_EXIT_ITEM, 0x80, L"Select all");
    63.   lpmti = FillMenuItemTemplate(lpmti, MFT_STRING, MFS_ENABLED, MM_HELP_ITEM, 0x81, L"?");
    64.   lpmti = FillMenuItemTemplate(lpmti, MFT_STRING, MFS_ENABLED, MM_HELP_ITEM, 0x01, L"Help");
    65.   lpmti = FillMenuItemTemplate(lpmti, MFT_STRING, MFS_ENABLED, MM_HELP_ITEM, 0x00, L"Test 1");
    66.   lpmti = FillMenuItemTemplate(lpmti, MFT_STRING, MFS_ENABLED, MM_HELP_ITEM, 0x00, L"Test 2");
    67.   lpmti = FillMenuItemTemplate(lpmti, MFT_STRING, MFS_ENABLED, MM_HELP_ITEM, 0x00, L"Test 3");
    68.   lpmti = FillMenuItemTemplate(lpmti, MFT_STRING, MFS_ENABLED, MM_HELP_ITEM, 0x00, L"Test 4");
    69.   lpmti = FillMenuItemTemplate(lpmti, MFT_STRING, MFS_ENABLED, MM_HELP_ITEM, 0x80, L"Test 5");
    70.   lpmti = FillMenuItemTemplate(lpmti, MFT_STRING, MFS_ENABLED, MM_HELP_ITEM, 0x80, L"About");
    71. }
    72.  
    73. HMENU LoadMenuTemplate0() {
    74.   FillMenuBuffer((MENUEX_TEMPLATE_HEADER *)&menuTemplate);
    75.   return LoadMenuIndirectA((MENUEX_TEMPLATE_HEADER *)&menuTemplate);
    76. }
    77.  
    78. HMENU LoadMenuTemplate1() {
    79.   MENUEX_TEMPLATE_HEADER *lpmth = (MENUEX_TEMPLATE_HEADER *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 1024);
    80.   FillMenuBuffer(lpmth);
    81.   HMENU hMenu = LoadMenuIndirectA(lpmth);
    82.   HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, (void *)lpmth);
    83.   return hMenu;
    84. }
    85.  
    86. HMENU LoadMenuTemplate2() {
    87.   MENUEX_TEMPLATE_HEADER *lpmth = (MENUEX_TEMPLATE_HEADER *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 1024);
    88.   FillMenuBuffer(lpmth);
    89.   HMENU hMenu = LoadMenuIndirectW(lpmth);
    90.   HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, (void *)lpmth);
    91.   return hMenu;
    92. }
    93.  
    94. ATOM RegisterMainClass(HINSTANCE hInst, LPCWSTR szClass, void *fnProc) {
    95.   WNDCLASSEXW wce;
    96.   wce.cbSize  = sizeof(wce);
    97.   wce.style  = CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS;
    98.   wce.lpfnWndProc  = (WNDPROC)fnProc;
    99.   wce.cbClsExtra  = 0;
    100.   wce.cbWndExtra  = 0;
    101.   wce.hInstance  = hInst;
    102.   wce.hIcon  = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
    103.   wce.hCursor  = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
    104.   wce.hbrBackground = (HBRUSH)COLOR_WINDOW + 1;
    105.   wce.lpszMenuName  = nullptr;
    106.   wce.lpszClassName = szClass;
    107.   wce.hIconSm  = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
    108.   return RegisterClassExW(&wce);
    109. }
    110.  
    111. LRESULT Form1_wndProc(HWND hWnd, UINT uMsg, WPARAM wPar, LPARAM lPar) {
    112.   switch (uMsg) {
    113.   case WM_DESTROY: PostQuitMessage(0);
    114.   return 0;
    115.   case WM_CREATE: SetMenu(hWnd, LoadMenuTemplate1());
    116.   if (!IsWindowVisible(hWnd)) {
    117.   ShowWindow(hWnd, SW_SHOWNORMAL);
    118.   UpdateWindow(hWnd);
    119.   }
    120.   return 0;
    121.   case WM_COMMAND:
    122.   switch (wPar) {
    123.   case MM_NEW_ITEM: break;
    124.   case MM_EXIT_ITEM: DestroyWindow(hWnd);
    125.   return 0;
    126.   case MM_HELP_ITEM: break;
    127.   default: break;
    128.   }
    129.   break;
    130.   default: break;
    131.   }
    132.   return DefWindowProcW(hWnd, uMsg, wPar, lPar);
    133. }
    134.  
    135. int main(int argc, char *argv[]) {
    136.   hInstance  = GetModuleHandleW(NULL);
    137.   if (!hInstance) {
    138.   printf("Error! Can't GetModuleHandle. . .");
    139.   return 1;
    140.   }
    141.   ATOM aClass  = RegisterMainClass(hInstance, L"TForm1", (void *)Form1_wndProc);
    142.   if (!aClass) {
    143.   printf("Error! Can't RegisterMainClass. . .");
    144.   return 1;
    145.   }
    146.   HWND aWindow = CreateWindowExW(WS_EX_OVERLAPPEDWINDOW,
    147.   (LPCWSTR)((unsigned)aClass), L"Form1",
    148.   WS_OVERLAPPEDWINDOW,
    149.   100, 100, 800, 600,
    150.   HWND_DESKTOP, nullptr,
    151.   hInstance, nullptr);
    152.   if (!aWindow) {
    153.   printf("Error! Can't CreateWindowEx. . .");
    154.   return 1;
    155.   }
    156.   MSG aMsg;
    157.   while (int state = GetMessageW(&aMsg, 0, 0, 0)) {
    158.   if (state == -1) {
    159.   aMsg.wParam = GetLastError();
    160.   break;
    161.   }
    162.   TranslateMessage(&aMsg);
    163.   DispatchMessageW(&aMsg);
    164.   }
    165.   return aMsg.wParam;
    166. }
     
    Последнее редактирование: 31 май 2023