[WinApi]Zaznaczalny Button

0

Witam, mam problem... Chce zrobić w WinAPI przycisk który można zazanaczyć i odznaczyć, jak naprzykład w Paincie. Mam taki kod:

.
.
onCreate:
.
.
invoke  CreateWindowEx,0,_btn,0,WS_CHILD+WS_VISIBLE, 1, 1, 25, 25, [hPanel], NULL, [hInstance],301      
.
.
onCommand:
cmp     [wparam], 301
jne     finish
invoke  SendMessage, [hPix], BM_GETCHECK, 0, 0
cmp     eax, BST_CHECKED
jne     uc
invoke  SendMessage, [hPix], BM_SETSTATE, 0, 0
uc:
invoke  SendMessage, [hPix], BM_SETSTATE, 1, 0     
finish:
.
.

I to nie chce działać. Czemu?

0

pozwolę sobie zacytować 'Win32 Programmers Reference':

Many developers create dialog boxes by using standalone tools, not requiring them to specify button styles. However, if an application creates a button by using the CreateWindow or CreateWindowEx function, the following table of constants can be used to define the button style.

Style Meaning
BS_3STATE Creates a button that is the same as a check box, except that the box can be grayed as well as checked or unchecked. Use the grayed state to show that the state of the check box is not determined.
BS_AUTO3STATE Creates a button that is the same as a three-state check box, except that the box changes its state when the user selects it. The state cycles through checked, grayed, and unchecked.
BS_AUTOCHECKBOX Creates a button that is the same as a check box, except that the check state automatically toggles between checked and unchecked each time the user selects the check box.
BS_AUTORADIOBUTTON Creates a button that is the same as a radio button, except that when the user selects it, Windows automatically sets the button's check state to checked and automatically sets the check state for all other buttons in the same group to unchecked.
BS_CHECKBOX Creates a small, empty check box with text. By default, the text is displayed to the right of the check box. To display the text to the left of the check box, combine this flag with the BS_LEFTTEXT style (or with the equivalent BS_RIGHTBUTTON style).
BS_DEFPUSHBUTTON Creates a push button that behaves like a BS_PUSHBUTTON style button, but also has a heavy black border. If the button is in a dialog box, the user can select the button by pressing the ENTER key, even when the button does not have the input focus. This style is useful for enabling the user to quickly select the most likely (default) option.
BS_GROUPBOX Creates a rectangle in which other controls can be grouped. Any text associated with this style is displayed in the rectangle's upper left corner.
BS_LEFTTEXT Places text on the left side of the radio button or check box when combined with a radio button or check box style. Same as the BS_RIGHTBUTTON style.
BS_OWNERDRAW Creates an owner-drawn button. The owner window receives a WM_MEASUREITEM message when the button is created and a WM_DRAWITEM message when a visual aspect of the button has changed. Do not combine the BS_OWNERDRAW style with any other button styles.
BS_PUSHBUTTON Creates a push button that posts a WM_COMMAND message to the owner window when the user selects the button.
BS_RADIOBUTTON Creates a small circle with text. By default, the text is displayed to the right of the circle. To display the text to the left of the circle, combine this flag with the BS_LEFTTEXT style (or with the equivalent BS_RIGHTBUTTON style). Use radio buttons for groups of related, but mutually exclusive choices.
BS_USERBUTTON Obsolete, but provided for compatibility with 16-bit versions of Windows. Win32-based applications should use BS_OWNERDRAW instead.
BS_BITMAP Specifies that the button displays a bitmap.
BS_BOTTOM Places text at the bottom of the button rectangle.
BS_CENTER Centers text horizontally in the button rectangle.
BS_ICON Specifies that the button displays an icon.
BS_LEFT Left-justifies the text in the button rectangle. However, if the button is a check box or radio button that does not have the BS_RIGHTBUTTON style, the text is left justified on the right side of the check box or radio button.
BS_MULTILINE Wraps the button text to multiple lines if the text string is too long to fit on a single line in the button rectangle.
BS_NOTIFY Enables a button to send BN_DBLCLK, BN_KILLFOCUS, and BN_SETFOCUS notification messages to its parent window. Note that buttons send the BN_CLICKED notification message regardless of whether it has this style.
BS_PUSHLIKE Makes a button (such as a check box, three-state check box, or radio button) look and act like a push button. The button looks raised when it isn't pushed or checked, and sunken when it is pushed or checked.
BS_RIGHT Right-justifies text in the button rectangle. However, if the button is a check box or radio button that does not have the BS_RIGHTBUTTON style, the text is right justified on the right side of the check box or radio button.
BS_RIGHTBUTTON Positions a radio button's circle or a check box's square on the right side of the button rectangle. Same as the BS_LEFTTEXT style.
BS_TEXT Specifies that the button displays text.
BS_TOP Places text at the top of the button rectangle.
BS_VCENTER Places text in the middle (vertically) of the button rectangle.

i chyba wszystko jasne - wystarczy odpowiedni styl...
nie chce mi się sprawdzać, ale chyba rozwiązaniem Twojego problemu będzie BS_AUTOCHECKBOX+BS_PUSHLIKE

0

Ale tu nie o to chodzi... Jakbym dał wysłanie komunikatu w onCreate to by zadziałało... OnCommand nie szwankuje bo exit działa... nie wiem o co chodzi :/

0

nie kapuję zbytnio /... może opisz dokładnie, ew. prześlij mi kod maila to coś wymyślę...

0

oto kod...

format PE GUI 4.0
entry start

include 'C:\Program Files\Flat Asembler\INCLUDE\win32a.inc'

IDM_NEW = 101
IDM_OPN = 102
IDM_SAV = 103
IDM_EXT = 104
IDM_ABT = 201

section '.data' data readable writeable

  _title db ' ',0
  _class db 'SREMain',0
  _btn   db 'BUTTON',0
  _stc   db 'STATIC',0

  hWnd      dd ?
  hInstance dd ?
  x         dd ?
  hPanel    dd ?
  hPix      dd ?

  rect RECT
  msg MSG
  wc  WNDCLASS

section '.code' code readable executable

  start:

        invoke  GetModuleHandle,0
        mov     [hInstance],EAX
        invoke  LoadIcon,0,IDI_APPLICATION
        mov     [wc.hIcon],EAX
        invoke  LoadCursor,0,IDC_ARROW
        mov     [wc.hCursor],EAX
        mov     [wc.style],0
        mov     [wc.lpfnWndProc],WindowProc
        mov     [wc.cbClsExtra],0
        mov     [wc.cbWndExtra],0
        mov     EAX,[hInstance]
        mov     [wc.hInstance],EAX
        mov     [wc.hbrBackground],COLOR_BTNFACE+1
        mov     [wc.lpszMenuName],0
        mov     [wc.lpszClassName],_class
        invoke  RegisterClass,wc

        invoke  LoadMenu, [hInstance], 1
        invoke  CreateWindowEx,0,_class,_title,WS_VISIBLE+WS_OVERLAPPEDWINDOW,0,0,800,550,NULL,eax,[hInstance],NULL
        mov     [hWnd],EAX

  msg_loop:
        invoke  GetMessage,msg,NULL,0,0
        or      EAX,EAX
        jz      end_loop
        invoke  TranslateMessage,msg
        invoke  DispatchMessage,msg
        jmp     msg_loop

  end_loop:
        invoke  ExitProcess,[msg.wParam]

proc WindowProc, hwnd,wmsg,wparam,lparam
        push    ebx esi edi
        cmp     [wmsg],WM_DESTROY
        je      onDestroy
  defwndproc:
        invoke  DefWindowProc,[hwnd],[wmsg],[wparam],[lparam]
        cmp     [wmsg],WM_CREATE
        je      onCreate
        cmp     [wmsg],WM_SIZE
        je      onResize
        cmp     [wmsg],WM_COMMAND
        je      onCommand
        jmp     finish
  onDestroy:
        invoke  PostQuitMessage,0
        xor     EAX,EAX
  onCreate:
        invoke  GetClientRect, [hwnd], rect
        invoke  CreateWindowEx,0, _stc, 0, WS_CHILD+WS_VISIBLE+WS_THICKFRAME, [rect.left],[rect.top],[rect.right],32 , [hwnd], NULL, [hInstance], NULL
        mov     [hPanel], eax
        invoke  CreateWindowEx,0, _btn, 0, WS_CHILD+WS_VISIBLE, 1, 1, 25, 25, [hPanel], NULL, [hInstance], 301
        mov     [hPix], eax
        jmp     finish
  onResize:
        invoke  GetClientRect, [hwnd], rect
        invoke  MoveWindow, [hPanel], [rect.left], [rect.top], [rect.right], 32, TRUE
        jmp     finish
  onCommand:
        cmp     [wparam], IDM_EXT
        je      onDestroy
        cmp     [wparam], 301
        jne     finish
        jmp     onDestroy
        invoke  SendMessage, [hPix], BM_GETCHECK, 0, 0
        cmp     eax, BST_CHECKED
        jne     uc
        invoke  SendMessage, [hPix], BM_SETSTATE, 0, 0
  uc:
        invoke  SendMessage, [hPix], BM_SETSTATE, 1, 0
  finish:
        pop     edi esi ebx
        return
endp

section '.idata' import data readable writeable

  library kernel,'KERNEL32.DLL',\
          user,'USER32.DLL'

  import kernel,\
         GetModuleHandle,'GetModuleHandleA',\
         ExitProcess,'ExitProcess'

  import user,\
         RegisterClass,'RegisterClassA',\
         CreateWindowEx,'CreateWindowExA',\
         DefWindowProc,'DefWindowProcA',\
         GetMessage,'GetMessageA',\
         TranslateMessage,'TranslateMessage',\
         DispatchMessage,'DispatchMessageA',\
         SendMessage,'SendMessageA',\
         LoadCursor,'LoadCursorA',\
         LoadIcon,'LoadIconA',\
         LoadMenu,'LoadMenuA',\
         GetClientRect,'GetClientRect',\
         MoveWindow, 'MoveWindow',\
         PostQuitMessage,'PostQuitMessage'

section '.rsrc' resource data readable

directory RT_MENU, menus

resource menus,\
         1,LANG_ENGLISH+SUBLANG_DEFAULT,mm

menu mm
     menuitem '&Plik',0,MFR_POPUP
              menuitem '&Nowy', IDM_NEW, 0
              menuitem '&Otwórz', IDM_OPN, 0
              menuitem '&Zapisz', IDM_SAV, 0
              menuseparator
              menuitem 'Z&amknij', IDM_EXT, MFR_END
     menuitem '&About', IDM_ABT, MFR_END

Nie wiem, czy to cokolwiek zmienia...

0

tu masz problem:

invoke  CreateWindowEx,0, _btn, 0, WS_CHILD+WS_VISIBLE, 1, 1, 25, 25, [hPanel], NULL, [hInstance], 301  

jak chcesz odbiewać wiadomości z okna głównego od kontolki, która nie jest bezpośrednio jego dzieckiem?
next błąd: identyfikator kontrolki powinien być podawany jako hmenu czyli ogółem powinno być:

invoke  CreateWindowEx,0, _btn, 0, WS_CHILD+WS_VISIBLE, 1, 1, 25, 25, [hwnd], 301, [hInstance], 0

i znów:

        jne     finish
        jmp     onDestroy ; tutaj
        invoke  SendMessage, [hPix], BM_GETCHECK, 0, 0   

ta linia powoduje, że reszta Twojego kodu dla przycisku jest omijana...
a ogólnie to stwórz przycisk ze stylem BS_AUTOCHECKBOX+BS_PUSHLIKE+WS_CHILD+WS_VISIBLE lub BS_CHECKBOX+BS_PUSHLIKE+WS_CHILD+WS_VISIBLE i wszystko będzie robione przez system, a Ty będziesz miał to co chcesz...
i jeszcze to:

  onDestroy:
        invoke  PostQuitMessage,0
        xor     EAX,EAX
  onCreate:     

i gdzie skok do finish ??

p.s. przykro mi to stwierdzić, ale masz paskudny styl kodowania pod asm... lepiej pisz w ansi C pod gcc z -o3 i ściągnij sobie starego helpa do winapi http://flatassembler.net/docs/win32hlp.zip
p.s.2 jak chcesz to mogę to twoje 'cudo' przepisać tak, aby działało i miało znośny kod...
//dopisane:
cóż, po skonsumowaniu obiadu stwerdziłem, że wypadałoby trochę odpocząć i przepisałem to 'coś' na wersję nieco bardziej optymalną i działającą chyba tak jak chcesz /tylko nie krzyczcie, że nieczytelne ;) /:

format PE GUI 4.0
entry start

include '%fasminc%\win32a.inc'

IMAGE_BASE              equ 0x400000

IDM_NEW = 101
IDM_OPN = 102
IDM_SAV = 103
IDM_EXT = 104
IDM_ABT = 201

;==========================================================================
section '.code' code executable readable

start:
        push    ebp
        push    ebx
        push    edi
        push    esi
        mov     ebp, esp

        xor     ebx, ebx

        sub     esp, sizeof.MSG ; zmienna lokalna /struktura MSG/

        lea     esi, [LoadIcon]

        push    esp

        lea     edi, [_wc]

        push    IDI_APPLICATION
        push    ebx
        call    dword [esi]     ; LoadIcon
        mov     [edi+WNDCLASSEX.hIcon], eax

        push    IDC_ARROW
        push    ebx
        call    dword [esi+4]   ; LoadCursor
        mov     [edi+WNDCLASSEX.hCursor], eax

        push    edi
        call    dword [esi+8]

        push    ebx
        push    IMAGE_BASE
        push    ebx
        push    ebx
        push    550
        push    800
        push    ebx
        push    ebx
        push    WS_VISIBLE+WS_OVERLAPPEDWINDOW
        push    _title
        push    _class
        push    ebx
        call    dword [esi+0x0c]; CreateWindowEx

        test    eax, eax
        jz      .ret

        pop     esi ; ptr do MSG
        lea     edi, [GetMessage]
.msg_loop:
        push    ebx
        push    ebx
        push    ebx
        push    esi
        call    dword [edi]     ; GetMessage
        test    eax, eax
        jz      @f

        push    esi
        call    dword [edi+4]   ; TranslateMessage
        push    esi
        call    dword [edi+8]   ; DispatchMessage
        jmp     .msg_loop
@@:
        mov     eax, [esi+MSG.wParam]
.ret:
        mov     esp, ebp
        pop     esi
        pop     edi
        pop     ebx
        pop     ebp
        ret
        align 0x10
WindowProc:
 .hwnd          equ ebp+8
 .msg           equ ebp+0x0c
 .wparam        equ ebp+0x10
 .lparam        equ ebp+0x14

        push    ebp
        mov     ebp, esp

        push    ebx
        push    edi
        push    esi

        xor     ebx, ebx

        mov     eax, [.msg]

        cmp     eax, WM_SIZE
        jz      .wm_size
        cmp     eax,WM_COMMAND
        jz      .wm_command
        cmp     eax, WM_CREATE
        jz      .wm_create
        cmp     eax, WM_DESTROY
        jz      .wm_destroy

        pop     esi
        pop     edi
        pop     ebx
        leave
        jmp     [DefWindowProc]
        align   0x10
.wm_create:
        lea     edi, [hPanel]
        mov     esi, [CreateWindowEx]

        push    ebx
        push    IMAGE_BASE
        push    ebx
        push    dword [.hwnd]
        push    ebx
        push    ebx
        push    ebx
        push    ebx
        push    WS_CHILD+WS_VISIBLE+WS_THICKFRAME
        push    ebx
        push    _stc
        push    ebx
        call    esi; CreateWindowEx

        test    eax, eax
        jz      .err

        mov     [edi], eax

        push    ebx
        push    IMAGE_BASE
        push    301
        push    dword [.hwnd]
        push    25
        push    25
        push    1
        push    1
        push    WS_CHILD+WS_VISIBLE+BS_AUTOCHECKBOX+BS_PUSHLIKE
        push    ebx
        push    _btn
        push    ebx
        call    esi; CreateWindowEx

        test    eax, eax
        jz      .err

        mov     [edi+4], eax
        jmp     .ret
        align   0x10
.err:
        or      ebx, -1
        jmp     .ret
        align   0x10
.wm_size:
        sub     esp, sizeof.RECT
        lea     edi, [esp]
        push    edi
        push    dword [.hwnd]
        call    [GetClientRect]

        push    1
        push    32
        push    dword [edi+RECT.right]
        push    dword [edi+RECT.top]
        push    dword [edi]; +RECT.left
        push    [hPanel]
        call    [MoveWindow]

        add     esp, sizeof.RECT
        jmp     .ret
        align 0x10
.wm_destroy:
        push    ebx
        call    [PostQuitMessage]
        jmp     .ret
        align 0x10
.wm_command:
        mov     eax, [.wparam]
        cmp     ax, IDM_EXT
        jz      .wm_destroy
        cmp     ax, 301
        jnz     .ret

        push    ebx
        push    ebx
        push    BM_GETCHECK
        push    [hPix]
        call    [SendMessage]

        push    ebx
        push    ebx
        push    dword [@F+eax*4]        ; BST_UNCHECKED     = 0 | BST_CHECKED       = 1
        push    dword [.hwnd]
        call    [MessageBox]
        jmp     .ret
        align   0x10
        @@:     dd  _wycisk, _wcisk
        align   0x10
.ret:
        mov     eax, ebx
        pop     esi
        pop     edi
        pop     ebx
        leave
        ret     0x10

;==========================================================================

section '.data' data readable writeable
;_wc WNDCLASSEX
_wc:
  .cbSize        dd sizeof.WNDCLASSEX
  .style         dd 0
  .lpfnWndProc   dd WindowProc
  .cbClsExtra    dd 0
  .cbWndExtra    dd 0
  .hInstance     dd IMAGE_BASE
  .hIcon         dd 0
  .hCursor       dd 0
  .hbrBackground dd COLOR_BTNFACE+1
  .lpszMenuName  dd 1
  .lpszClassName dd _class
  .hIconSm       dd 0




  _title        db ' ', 0
  _class        db 'SREMain', 0
  _btn          db 'BUTTON', 0
  _stc          db 'STATIC', 0
  _wcisk        db "Czuję się wciśnięty ;)", 0
  _wycisk       db 'ktoś dał mi wycisk :P', 0
  hPanel        dd ?
  hPix          dd ?
;==========================================================================

section '.import' import data readable

  dd 0, 0, 0, rva _user32, rva _user32_imports
  dd 0, 0, 0, 0, 0

_user32 db 'User32.dll', 0

align 0x10

_user32_imports:
LoadIcon                dd rva _LoadIcon
LoadCursor              dd rva _LoadCursor
RegisterClassEx         dd rva _RegisterClassEx
CreateWindowEx          dd rva _CreateWindowEx
GetMessage              dd rva _GetMessage
TranslateMessage        dd rva _TranslateMessage
DispatchMessage         dd rva _DispatchMessage
DefWindowProc           dd rva _DefWindowProc
SendMessage             dd rva _SendMessage
GetClientRect           dd rva _GetClientRect
MoveWindow              dd rva _MoveWindow
PostQuitMessage         dd rva _PostQuitMessage
MessageBox              dd rva _MessageBox
                        dd 0

_LoadIcon               dw 0
                        db 'LoadIconA'
_LoadCursor             dw 0
                        db 'LoadCursorA'
_RegisterClassEx        dw 0
                        db 'RegisterClassExA'
_CreateWindowEx         dw 0
                        db 'CreateWindowExA'
_GetMessage             dw 0
                        db 'GetMessageA'
_TranslateMessage       dw 0
                        db 'TranslateMessage'
_DispatchMessage        dw 0
                        db 'DispatchMessageA'
_DefWindowProc          dw 0
                        db 'DefWindowProcA'
_SendMessage            dw 0
                        db 'SendMessageA'
_GetClientRect          dw 0
                        db 'GetClientRect'
_MoveWindow             dw 0
                        db 'MoveWindow'
_PostQuitMessage        dw 0
                        db 'PostQuitMessage'
_MessageBox             dw 0
                        db 'MessageBoxA', 0

section '.rsrc' resource data readable

directory RT_MENU, menus

resource menus,\
         1,LANG_ENGLISH+SUBLANG_DEFAULT,mm
menu mm
     menuitem '&Plik',0,MFR_POPUP
              menuitem '&Nowy', IDM_NEW, 0
              menuitem '&Otwórz', IDM_OPN, 0
              menuitem '&Zapisz', IDM_SAV, 0
              menuseparator
              menuitem 'Z&amknij', IDM_EXT, MFR_END
     menuitem '&About', IDM_ABT, MFR_END

// coś chyba kolorowanie składni szaleje...

0

dzięki za pomoc.. Za C podziękuje, wole assemblera. Nie rozumiem poco obdarłeś mój kod ze wszelkich udogodnień, jakie daje mi FASM :/ W każdym razie dzięki

0

czemu wywaliłem udogodnienia? udogodnienia to jednocześnie ograniczenia - pełna kontrola nad kodem pozwala uzyskać lepsze efekty /szybszy i mniejszy kod/... ale każdy ma własny styl kodowania ;)

0

nie rozumiem, jak cię ogranicza invoke, ale masz prawo uważać, jak chcesz. Tyle że kod jest [i]troche[/i] mniej przejżysty :] ale za to jestem pod wrażeniem, bo po komplikacji jest mniejszy :] Znasz jakieś kursy w necie które uczą programować w taki sposób?

0

nie tylko mniejszy, ale i kilkukrotnie szybszy :D a tak poważnie to nie Ty pierwszy się o to pytasz, ale odpowiedź jest jedna - 'IA-32 Intel? Architecture Software Developer?s Manual' /do zdobycia na intel.com/. Chodzi przede wszystkim o opcode'y... no i dużo praktyki. Kilka sztuczek:
*uchwyt do mudułu /pobierany przez GetModuleHandle/ to adres pod który plik został załadowany - standardowo dla execa to 0x400000, ale można to smienić... w każdym razie zawsze jest to adres pierwszej sekcji - 0x1000 szyli w przedstawionej przeze mnie wersji Teojego kodu będzie to start-0x1000/odpada kod pobierający uchwyt oraz wpis w tablicy importów
*instrukcja 'lea' - raz, że szybka a dwa pozwala robić duużo ciekawych rzeczy/szegóły w manualach intela - dokładniej w 2a'
*kod inicjujący strukturę zwykle zajmuje więcej niż zainicjowana struktura - można zrobić tak, jak ja to zrobiłem z WNDCLASSEX
*rejestry ebx, esi, edi są zachowywane przy wywołaniach funkcji - trzymaj w nich adresy struktur, ew. 0 /zero/ - wrzucenie rejestru na stos jest szybsze niż stałej i w tym przypadku 2x mniejsze /push reg - 1 bajt, push signed_char -2 bajty/
*rób tablice adresów - paradoksalnie zmniejsza to i przyspiesza kod /tak jak przy wywołaniu messageboxa informującego o stanie przycisku
*odwołanie się do 16bitowej części rejestru zajmuje bajt więcej niż do całego 32bitowego rejestru /obecność przedrostka zmiany rozmiaru/
*jeśli jakąś stałą o zakresie od -127 do 127 chcesz wrzucić na stos conajmniej 3 razy mieść ją najpierw w rejestrze - szybciej i mniej
*operacje arytmetyczne wykonują się wolniej niż logiczne,
*grupuj dane w struktury i adresuj je przez rejestr - znacznie mniejszy i szybszy kod /tak jak w mojej przeróbce odwołania do części importów - zauważ, że adresowanie pośrednie stosowałem tylko, chciałem wywołać conajmniej 2,3 funkcje/,
*jeśli tylko możesz rób pętle zmierzające do zera...
*poprzeglądaj pliki nagłówkowe i definicje stałych /może się okazać, że jakaś stała to 0 a nie jest najlepszym pomysłem pisać mov eax, 0 lub mov [gdzieśtam], 0 - lepiej mieć w zapasie wyzerowany rejestr/
i wiele, wiele innych... chyba napiszę na ten temat arta i powieszę bo optymalizacja i kodowanie /nie mylić z programowaniem/ to naprawde rozległe i ciekawe zagadnienie...

0

tutaj czarną magią nie jest tyle, że naprzykład lea jest leprze od mov, bo o tym słyszałem, ale naprzykład sposób w jaki importuje się procki... Dzienx :] Poucze się trochę tego

1 użytkowników online, w tym zalogowanych: 0, gości: 1