Announcement

Collapse
No announcement yet.

Palette Laboratory

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Aldo Cavini
    replied
    Semen,
    there is a wish to include it's registration and WndProc into separate "INC" and to "forget".
    If the problem is not to forget the palette messages inside the main dialog callback function, a solution can be to add a few "debug" lines of code. The situation is as follows:
    • There is a registered custon control
    • The control has its own callback function, which doesn't receives the palette messages.
    • To correctly respond to the palette messages, and to redraw the controls after each message, there should be a main dialog callback function. But you risk to forget to include it.

    The solution could be to include a little code to check for the main dialog callback function. Assume the control callback includes the following code:
    Code:
    LOCAL a AS LONG
      a = 0
      SendMessage CBHNDL, %WM_USER + 123, VARPTR( a ), 123
      IF a <> 123 THEN
        MSGBOX "ERROR: CUSTOM CONTROL......."
      END IF
    The main callback function should include the palette messages actions, and the following rows:
    Code:
    LOCAL a AS LONG PTR
      IF CBMSG = %WM_USER + 123 THEN
        a = CBWPARAM
        @a = CBLPARAM
      END IF
    The value for 'a' after SendMessage will be set to 123 only if is there a main dialog callback function. Otherwise you will have an error message.

    Your separate "INC" should contain the custom control code and a standard palette messages handler function. This function will be declared as a callback function for the dialogs - if you forget to decalre it, you'll get an error message. Very little and fast code.

    Aldo

    ------------------

    Leave a comment:


  • Aldo Cavini
    replied
    To avoid creating an infinite loop, a window that receives this message must not realize its palette, unless it determines that wParam does not contain its own window handle.
    Borje, I tried avoiding the wParam check you mentioned, and never got this infinite loop... Windows misteries.

    I looked at your forum lately (it was from there I had the idea to write my laboratory ). I think you should call RedrawWindow also on WM_QUERYNEWPALETTE, otherwise when your window gets the focus it won't refresh its own colors. The problem is, if another program changes all the colors inside the palette (I mean, it makes your program doesn't find the exact color match when it is background) the control color won't be restored when your window becomes foreground.

    ------------------

    Leave a comment:


  • Semen Matusovski
    replied
    What about additional (invisible) TOOLWINDOW per class ?
    I mean to register it together with custom control

    ------------------
    E-MAIL: [email protected]

    Leave a comment:


  • Borje Hagsten
    replied
    Has been one of my main problems lately. Found a clumsy solution by
    including the following in main dialog:
    Code:
         CASE %WM_PALETTECHANGED
            IF CBWPARAM <> CBHNDL THEN
               RedrawWindow CBHNDL, ByVal 0, ByVal 0, %RDW_INVALIDATE OR %RDW_UPDATENOW
            END IF
    This redraws entire window when palette is changed, so all controls become
    updated. Works, but not pretty code. Maybe don't have to check wParam there,
    don't know, but it felt good to do it, so..


    ------------------

    Leave a comment:


  • Aldo Cavini
    replied
    The WM_PALETTECHANGED message is sent to all top-level and overlapped windows
    Intercepting the palette messages inside each top window, and using RedrawWindow with %RDW_ALLCHILDREN, should solve the problem. Top-level dialog callbacks do receive the palette messages. Absolutely no way to intercept the palette messages if you create a top-level dialog and don't declare a callback function for that dialog (hence, no way to repaint the controls).

    ------------------

    Leave a comment:


  • Semen Matusovski
    replied
    Aldo --
    In child control you can't receive (by "normal way") WM_QUERYNEWPALETTE, WM_PALETTECHANGED, WM_DISPLAYCHANGE.
    Meanwhile, if you do custom control, let's say "Picture", there is a wish to include it's registration and WndProc into separate "INC" and to "forget".
    In main program to do o RegisterCustomControl; Control Add "..." only.



    ------------------
    E-MAIL: [email protected]

    Leave a comment:


  • Aldo Cavini
    replied
    Semen,

    I also suspect the SelectPalette function can be called without testing for GetDeviceCaps. Anyway, better to be prudent...
    custom controls (setting pallete without assist of main dialog).
    Sorry Semen, I don't understand what does it mean a control without a main dialog. If the program shows a control, it should have always a message queue will receive the palette messages. Am I wrong?

    I never used custom colors inside controls. But I used them inside menu bars (ownerdraw). Once the palette has been realized (WM_QUERYNEWPALETTE and other messages), you simply need to select the palette into the device context for drawing the menu item. Does it work bad with custom controls? In case, post a little code sample with a coloured custom control - I'll try it.




    ------------------

    Leave a comment:


  • Semen Matusovski
    replied
    With dialogs more or less clear - if to use SelectPalette .. %false in WM_PAINT, performance is enough good.
    BTW, not sure that it's necessary to test GetDeviceCaps (as I understand, all OSes simply ignore "incorrect" SelectPalette).
    Main "unsolved" problem - custom controls (setting pallete without assist of main dialog).



    ------------------
    E-MAIL: [email protected]

    Leave a comment:


  • Aldo Cavini
    replied
    Borje, I'm glad you liked it. Effectively, it's almost impossible to understand how to use palettes with Windows. I worked on it thoroughly in the past. For the moment I'm waiting for comments in this forum - at the end I'll publish an article with all I think (?) to know on the argument.

    ------------------

    Leave a comment:


  • Borje Hagsten
    replied
    Nice and useful piece of work, Aldo - thanks! After having drowned
    in a black pallette info hole myself a couple of times, I can only
    say - the palette handling in Windows must have been written by
    someone who really hated Microsoft..

    How does Windows search for nearest color? Found that even if a color
    is in own palette, one cannot be sure it is used. Switching between
    Netscape, MSIE and own palette in 256 color mode is a real adventure,
    with no sure outcome. Probably caused by my own ignorance, but where
    to learn? Even MSDN says many different things..

    Will look at your code more closely later - looks real interesting Aldo.


    ------------------

    Leave a comment:


  • Aldo Cavini
    started a topic Palette Laboratory

    Palette Laboratory

    During the last weekend I wrote a Palette laboratory program (works both with PB/CC and PB/DLL). It helps to test all the possible strategies in implementing a palette driven program, when the screen is 256 colors. In the past I had some discussions on this topic (mostly with Semen) - The result was there are two main methods to work with palattes:
    • To realize the palette inside the Windows specific messages (my own method)
    • To realize the palette inside the WM_PAINT message (Semen's method - hope I haven't misunderstood his thought)

    The code I wrote uses some Windows messages (the quotation marks identify Win32Api.hlp extracts):
    • WM_QUERYNEWPALETTE - "This message informs a window that it is about to receive the keyboard focus, giving the window the opportunity to realize its logical palette when it receives the focus"
    • WM_PALETTEISCHANGING - I couldn't understand this message usage, so I didn't include it into the laboratory
    • WM_PALETTECHANGED - "This message is sent to all top-level and overlapped windows after the window with the keyboard focus has realized its logical palette, thereby changing the system palette"
    • WM_DISPLAYCHANGE - "This message is sent to all windows when the display resolution has changed" (also it is sent when the bit-per-pixel has changed)
    • USER_palettechange - This message is posted by the program itself when it changes the palette colors
    • WM_PAINT - Well, we all know how this message works

    My code also uses some API calls:
    • CreatePalette - "This function creates a logical color palette".
    • SelectPalette - "This function selects the specified logical palette into a device context". It requires the bForceBackground parameter, which can be %true or %false. I didn't understand which case requires the %true value.
    • UnrealizeObject - "This function resets a logical palette". This function seems to be ininfluent to the program, but sometimes its use make the program behaves bad (see later).
    • RealizePalette - "This function maps palette entries from the current logical palette to the system palette"
    • RedrawWindow - "This function updates the specified rectangle or region in a window's client area"

    My laboratory program must be used on a 256 colors screen. It shows a grid with 128 rectangles, painted each with a different color. The colors are 128 values of red, green, blue or gray, depending on a listbox selection. If you run two (or more) instances of the program, each showing different colors, of course only the instance which has the focus will show all the correct colors. The other instances will show some incorrect colors - they will be highlighted via a cyan cross.

    There are three checkbox groups: the first enables the specific Windows messages process; the second enables the API functions to be called inside each message processing; the third enables the APIs to be called inside the WM_PAINT message.

    Two buttons reset all the checkboxes to the needed values for the two methods I mentioned: Full Messages Defaults (my method) and Simple Paint Defaults (Semen's method).

    To fully test the methods, you must try (at least) the following:
    • Run more than one instance of the program, showing different colors, and show another palette driver window (i.e. MsPaint).
    • Change the screen resolution (8 bit to 24, 24 bit to 8). This test demonstrates why it is needed to process the WM_DISPLAYCHANGE message on my method.
    • Maximize a window (i.e. explorer), and put all the laboratory program windows on the top; then minimize the explorer window: the laboratory windows will be hidden and painted again on the same time. You will see the program sometimes behaves wrong if the UnrealizeObject call is enabled (bad colors on the non-foreground windows).


    You will see both the methods are ok. The following is an abstract of my method:
    Code:
      CASE %WM_QUERYNEWPALETTE, %WM_PALETTECHANGED, %WM_DISPLAYCHANGE, %USER_palettechange
        hDc = GetWindowDc( hWnd )
        IF ( GetDeviceCaps( hDc, %RASTERCAPS ) AND %RC_PALETTE ) <> 0 THEN
          IF wMsg = %WM_PALETTECHANGED AND hWnd = wParam THEN
            EXIT SELECT                             ' avoid endless loop
          END IF
          SelectPalette hDc, hPalette, %false
          RealizePalette hDc
          IF wMsg = %WM_QUERYNEWPALETTE THEN
            FUNCTION = %true                        ' the window realized its palette
          END IF
          RedrawWindow hWnd, BYVAL %null, BYVAL %null, %RDW_INVALIDATE OR %RDW_ALLCHILDREN
        END IF
        ReleaseDc hWnd, hDc
      CASE %WM_PAINT
        hDc  = BeginPaint( hWnd, ps )
        IF ( GetDeviceCaps( hDc, %RASTERCAPS ) AND %RC_PALETTE ) <> 0 THEN
          SelectPalette hDc, hPalette, %false
          ...
        END IF
    while the following is an abstract of the Semen's method:
    Code:
      CASE %WM_QUERYNEWPALETTE, %WM_PALETTECHANGED, %USER_palettechange
        RedrawWindow hWnd, BYVAL %null, BYVAL %null, %RDW_INVALIDATE OR %RDW_ALLCHILDREN
      CASE %WM_PAINT
        hDc  = BeginPaint( hWnd, ps )
        IF ( GetDeviceCaps( hDc, %RASTERCAPS ) AND %RC_PALETTE ) <> 0 THEN
          SelectPalette hDc, hPalette, %false
          RealizePalette hDc
          ...
        END IF
    If you look at it, the two methods are very similar. All what is needed is to select a palette into a device context, and to realize it. The difference between the two methods is on when to realize the palette. My method realizes it only when needed (I mean, when Windows sends its messages), while the Semen's method realizes it on every WM_PAINT message. Well, I think both methods work well; but I think my method is a little bit faster.

    To conclude, I'll recall my unsolved quetions - they are unsolved even after a deep testing (I hope someone will post a reply):
    • The use of the WM_PALATTEISCHANGING message
    • The use of the UnrealizeObject function
    • The use of the bForceBackground parameter inside the SelectPalette function.


    What follows is the complete laboratory program code. I'd like to get any comment, and to know if are there other methods I couldn't find. As Lance wrote some time ago, there are not too much palette gurus around...

    Code:
    #COMPILE  EXE
    #REGISTER NONE
    #INCLUDE "win32api.inc"
      
    %USER_palettechange = %WM_USER + 1
      
    GLOBAL flags AS STRING
    $defaults1 = "1111......10011.....1000......"
    $defaults2 = "1101......00001.....1001......"
      
    ' ----------------------------------------------- create palette 128 colors -------------
      
    FUNCTION Palette( BYVAL n AS LONG ) AS LONG     ' 0 to 127: returns the color
                                                    ' -1      : returns the palette handler
                                                    ' -2 to -5: create a red/green/blue/gray palette
    STATIC s AS STRING                              '           returns the palette handler
    STATIC h AS LONG
    LOCAL  i AS LONG
      
      IF n = -1 THEN
        FUNCTION = h
      
      ELSEIF n < -1 THEN
        IF h <> 0 THEN
          DeleteObject h
        END IF
      
        s = MKI$( 768 ) + MKI$( 128 )
        FOR i = 0 TO 127
          SELECT CASE n
          CASE -5
            s = s + CHR$( i * 2 + 1, 0, 0, 0 )
          CASE -4
            s = s + CHR$( 0, i * 2 + 1, 0, 0 )
          CASE -3
            s = s + CHR$( 0, 0, i * 2 + 1, 0 )
          CASE -2
            s = s + CHR$( i * 2 + 1, i * 2 + 1, i * 2 + 1, 0 )
          END SELECT
        NEXT i
        h = CreatePalette( BYVAL STRPTR( s ) )
        FUNCTION = h
      
      ELSEIF h <> 0 THEN
        FUNCTION = CVL( MID$( s, n * 4 + 5, 4 ) )
      END IF
      
    END FUNCTION
      
    ' ----------------------------------------------- colors window callback function -------
      
    FUNCTION CallbackColors( BYVAL hWnd   AS LONG, _
                             BYVAL wMsg   AS LONG, _
                             BYVAL wParam AS LONG, _
                             BYVAL lParam AS LONG) AS LONG
      
    LOCAL  hDc  AS LONG
    LOCAL  ps   AS PAINTSTRUCT
    LOCAL  x    AS LONG
    LOCAL  y    AS LONG
    LOCAL  z    AS LONG
    LOCAL  hPen AS LONG
    LOCAL  hBr  AS LONG
      
      SELECT CASE wMsg
      
      CASE %WM_ERASEBKGND
        FUNCTION = %true
        EXIT FUNCTION
      
      CASE %WM_PAINT
        hDc  = BeginPaint( hWnd, ps )
        IF ( GetDeviceCaps( hDc, %RASTERCAPS ) AND %RC_PALETTE ) <> 0 THEN
          IF MID$( flags, 21, 1 ) = "1" THEN
            SelectPalette hDc, Palette( -1 ), %false
          ELSEIF MID$( flags, 22, 1 ) = "1" THEN
            SelectPalette hDc, Palette( -1 ), %true
          END IF
          IF MID$( flags, 23, 1 ) = "1" THEN
            UnrealizeObject Palette( -1 )
          END IF
          IF MID$( flags, 24, 1 ) = "1" THEN
            RealizePalette hDc
          END IF
        END IF
      
        hPen = SelectObject( hDc, GetStockObject( %BLACK_PEN ) )
        FOR y = 0 TO 15
          FOR x = 0 TO 7
            hBr = SelectObject( hDc, CreateSolidBrush( Palette( y * 8 + x ) OR &H02000000 ) )
            Rectangle hDc, x * 16, y * 16, x * 16 + 16, y * 16 + 16
            DeleteObject SelectObject( hDc, hBr )
          NEXT x
        NEXT y
      
        SelectObject hDc, CreatePen( %PS_SOLID, 0, RGB( 0, 255, 255 ) )
        FOR y = 0 TO 15
          FOR x = 0 TO 7
            IF Palette( y * 8 + x ) <> GetNearestColor( hDc, Palette( y * 8 + x ) OR &H02000000 ) THEN
              MoveToEx hDc, x * 16 +  1, y * 16 + 1, BYVAL %null
              LineTo   hDc, x * 16 + 14, y * 16 + 14
              MoveToEx hDc, x * 16 + 14, y * 16 + 1, BYVAL %null
              LineTo   hDc, x * 16 +  1, y * 16 + 14
            END IF
          NEXT x
        NEXT y
        DeleteObject SelectObject( hDc, hPen )
        EndPaint hWnd, ps
      
      END SELECT
      
      FUNCTION = DefWindowProc( hWnd, wMsg, wParam, lParam )
      
    END FUNCTION
      
    ' ----------------------------------------------- callback function ---------------------
      
    FUNCTION CallBackFunction( BYVAL hWnd   AS LONG, _
                               BYVAL wMsg   AS LONG, _
                               BYVAL wParam AS LONG, _
                               BYVAL lParam AS LONG) AS LONG
      
    LOCAL  h   AS LONG
    LOCAL  hDc AS LONG
    LOCAL  cs  AS CREATESTRUCT PTR
    LOCAL  s   AS STRING
    LOCAL  i   AS LONG
      
      SELECT CASE wMsg
      
      CASE %WM_CREATE
        cs = lParam
        Palette -5
        flags = $defaults1
                                                    ' colors window
        h = CreateWindowEx( 0, "colors", "", %WS_CHILD OR %WS_VISIBLE, _
                            20, 20, 128, 256, hWnd, 0, @cs.hInstance, BYVAL %null )
      
                                                    ' palette selection
        h = CreateWindowEx( 0, "listbox", "RED", %WS_CHILD OR %WS_VISIBLE OR %WS_BORDER OR %LBS_NOTIFY, _
                            360, 10, 150, 70, hWnd, 101, @cs.hInstance, BYVAL %null )
        SendMessage h, %WM_SETFONT, GetStockObject( %ANSI_VAR_FONT ), 0
        FOR i = 1 TO 4
          s = PARSE$( "RED,GREEN,BLUE,GRAY", i )
          SendMessage h, %LB_ADDSTRING, 0, STRPTR( s )
        NEXT i
        SendMessage h, %LB_SETCURSEL, 0, 0
                                                    ' refresh and default buttons
        h = CreateWindowEx( 0, "Button", "Refresh", _
                            %WS_CHILD OR %WS_VISIBLE OR %BS_PUSHBUTTON, _
                            360, 80, 150, 25, hWnd, 102, @cs.hInstance, BYVAL %null )
        SendMessage h, %WM_SETFONT, GetStockObject( %ANSI_VAR_FONT ), 0
      
        h = CreateWindowEx( 0, "Button", "Full Messages Defaults", _
                            %WS_CHILD OR %WS_VISIBLE OR %BS_PUSHBUTTON, _
                            170, 260, 150, 25, hWnd, 103, @cs.hInstance, BYVAL %null )
        SendMessage h, %WM_SETFONT, GetStockObject( %ANSI_VAR_FONT ), 0
      
        h = CreateWindowEx( 0, "Button", "Simple Paint Defaults", _
                            %WS_CHILD OR %WS_VISIBLE OR %BS_PUSHBUTTON, _
                            360, 260, 150, 25, hWnd, 104, @cs.hInstance, BYVAL %null )
        SendMessage h, %WM_SETFONT, GetStockObject( %ANSI_VAR_FONT ), 0
      
                                                    ' palette messages processing
        h = CreateWindowEx( 0, "static", "Enabled Windows Messages :", _
                                %WS_CHILD OR %WS_VISIBLE, _
                                170, 10, 160, 25, hWnd, %null, @cs.hInstance, BYVAL %null )
        SendMessage h, %WM_SETFONT, GetStockObject( %ANSI_VAR_FONT ), 0
      
        s = "WM_QUERYNEWPALETTE,WM_PALETTECHANGED,WM_DISPLAYCHANGE,USER_palettechange"
        FOR i = 1 TO 4
          h = CreateWindowEx( 0, "button", PARSE$( s, i ), %WS_CHILD OR %WS_VISIBLE OR %BS_CHECKBOX, _
                                170, 10 + i * 20, 160, 25, hWnd, 200 + i, @cs.hInstance, BYVAL %null )
          SendMessage h, %WM_SETFONT, GetStockObject( %ANSI_VAR_FONT ), 0
          IF MID$( flags, i, 1 ) = "1" THEN
            SendMessage h, %BM_SETCHECK, %BST_CHECKED, 0
          END IF
        NEXT i
      
        h = CreateWindowEx( 0, "static", "", %WS_CHILD OR %WS_VISIBLE OR %SS_GRAYFRAME, _
                                170, 120, 340, 1, hWnd, %null, @cs.hInstance, BYVAL %null )
      
                                                    ' actions on messages
        s = "SelectPalette( false ),SelectPalette( true ),UnrealizeObject,RealizePalette,RedrawWindow"
      
        h = CreateWindowEx( 0, "static", "Actions on Windows Messages :", _
                                %WS_CHILD OR %WS_VISIBLE, _
                                170, 130, 160, 25, hWnd, %null, @cs.hInstance, BYVAL %null )
        SendMessage h, %WM_SETFONT, GetStockObject( %ANSI_VAR_FONT ), 0
      
        FOR i = 1 TO 5
          h = CreateWindowEx( 0, "button", PARSE$( s, i ), %WS_CHILD OR %WS_VISIBLE OR %BS_CHECKBOX, _
                                170, 130 + i * 20, 160, 25, hWnd, 210 + i, @cs.hInstance, BYVAL %null )
          SendMessage h, %WM_SETFONT, GetStockObject( %ANSI_VAR_FONT ), 0
          IF MID$( flags, i + 10, 1 ) = "1" THEN
            SendMessage h, %BM_SETCHECK, %BST_CHECKED, 0
          END IF
        NEXT i
      
                                                    ' actions on PAINT
        h = CreateWindowEx( 0, "static", "Actions on PAINT :", _
                                %WS_CHILD OR %WS_VISIBLE, _
                                360, 130, 200, 25, hWnd, %null, @cs.hInstance, BYVAL %null )
        SendMessage h, %WM_SETFONT, GetStockObject( %ANSI_VAR_FONT ), 0
      
        FOR i = 1 TO 4
          h = CreateWindowEx( 0, "button", PARSE$( s, i ), %WS_CHILD OR %WS_VISIBLE OR %BS_CHECKBOX, _
                                360, 130 + i * 20, 200, 25, hWnd, 220 + i, @cs.hInstance, BYVAL %null )
          SendMessage h, %WM_SETFONT, GetStockObject( %ANSI_VAR_FONT ), 0
          IF MID$( flags, i + 20, 1 ) = "1" THEN
            SendMessage h, %BM_SETCHECK, %BST_CHECKED, 0
          END IF
        NEXT i
      
      CASE %WM_QUERYNEWPALETTE, %WM_PALETTECHANGED, %WM_DISPLAYCHANGE, %USER_palettechange
        IF wMsg = %WM_PALETTECHANGED AND hWnd = wParam THEN
          EXIT SELECT                               ' avoid endless loop
        END IF
        IF wMsg = %WM_QUERYNEWPALETTE AND MID$( flags, 1, 1 ) = "1" OR _
           wMsg = %WM_PALETTECHANGED  AND MID$( flags, 2, 1 ) = "1" OR _
           wMsg = %WM_DISPLAYCHANGE   AND MID$( flags, 3, 1 ) = "1" OR _
           wMsg = %USER_palettechange AND MID$( flags, 4, 1 ) = "1" THEN
      
          hDc = GetWindowDc( hWnd )
          IF ( GetDeviceCaps( hDc, %RASTERCAPS ) AND %RC_PALETTE ) <> 0 THEN
            IF MID$( flags, 11, 1 ) = "1" THEN
              SelectPalette hDc, Palette( -1 ), %false
            ELSEIF MID$( flags, 12, 1 ) = "1" THEN
              SelectPalette hDc, Palette( -1 ), %true
            END IF
            IF MID$( flags, 13, 1 ) = "1" THEN
              UnrealizeObject Palette( -1 )
            END IF
            IF MID$( flags, 14, 1 ) = "1" THEN
              RealizePalette hDc
              IF wMsg = %WM_QUERYNEWPALETTE THEN
                FUNCTION = %true
              END IF
            END IF
          END IF
          ReleaseDc hWnd, hDc
          IF MID$( flags, 15, 1 ) = "1" THEN
            RedrawWindow hWnd, BYVAL %null, BYVAL %null, %RDW_INVALIDATE OR %RDW_ALLCHILDREN
          END IF
        END IF
      
      CASE %WM_COMMAND
        SELECT CASE HIWRD( wParam )
        CASE %LBN_SELCHANGE
          IF LOWRD( wParam ) = 101 THEN
            Palette SendMessage( lParam, %LB_GETCURSEL, 0, 0 ) - 5
            SendMessage hWnd, %USER_palettechange, 0, 0
          END IF
        CASE %BN_CLICKED
          i = LOWRD( wParam )
          IF i = 102 THEN
            InvalidateRect hWnd, BYVAL %null, %null
          ELSEIF i = 103 OR i = 104 THEN
            IF i = 103 THEN
              flags = $defaults1
            ELSE
              flags = $defaults2
            END IF
            FOR i = 1 TO 30
              IF MID$( flags, i, 1 ) = "1" THEN
                SendMessage GetDlgItem( hWnd, i + 200 ), %BM_SETCHECK, %BST_CHECKED, 0
              ELSEIF MID$( flags, i, 1 ) = "0" THEN
                SendMessage GetDlgItem( hWnd, i + 200 ), %BM_SETCHECK, %BST_UNCHECKED, 0
              END IF
            NEXT i
      
          ELSEIF i >= 201 AND i <= 230 THEN
            IF MID$( flags, i - 200, 1 ) = "1" THEN
              MID$( flags, i - 200, 1 ) = "0"
              SendMessage lParam, %BM_SETCHECK, %BST_UNCHECKED, 0
            ELSE
              MID$( flags, i - 200, 1 ) = "1"
              SendMessage lParam, %BM_SETCHECK, %BST_CHECKED, 0
              IF i = 211 AND MID$( flags, 12, 1 ) = "1" THEN
                MID$( flags, 12, 1 ) = "0"
                SendMessage GetDlgItem( hWnd, 212 ), %BM_SETCHECK, %BST_UNCHECKED, 0
              ELSEIF i = 212 AND MID$( flags, 11, 1 ) = "1" THEN
                MID$( flags, 11, 1 ) = "0"
                SendMessage GetDlgItem( hWnd, 211 ), %BM_SETCHECK, %BST_UNCHECKED, 0
              ELSEIF i = 221 AND MID$( flags, 22, 1 ) = "1" THEN
                MID$( flags, 22, 1 ) = "0"
                SendMessage GetDlgItem( hWnd, 222 ), %BM_SETCHECK, %BST_UNCHECKED, 0
              ELSEIF i = 222 AND MID$( flags, 21, 1 ) = "1" THEN
                MID$( flags, 21, 1 ) = "0"
                SendMessage GetDlgItem( hWnd, 221 ), %BM_SETCHECK, %BST_UNCHECKED, 0
              END IF
            END IF
          END IF
      
        END SELECT
      
      CASE %WM_DESTROY
        DeleteObject Palette( -1 )
        PostQuitMessage 0
      
      END SELECT
      
      FUNCTION = DefWindowProc( hWnd, wMsg, wParam, lParam )
      
    END FUNCTION
      
    ' ----------------------------------------------- main function -------------------------
      
    FUNCTION WINMAIN( BYVAL hCurInstance  AS LONG,       _
                      BYVAL hPrevInstance AS LONG,       _
                            lpszCmdLine   AS ASCIIZ PTR, _
                      BYVAL nCmdShow      AS LONG ) AS LONG
      
    LOCAL Msg        AS tagMsg
    LOCAL hWnd       AS LONG
    LOCAL ascii      AS ASCIIZ * 64
    LOCAL WndCl      AS WndClassEx
    LOCAL MainWindow AS LONG
      
      ascii = "Palette Test"                                  ' creates main window class
      
      WndCl.cbSize        = SIZEOF( WndCl )
      WndCl.style         = 0
      WndCl.lpfnWndProc   = CODEPTR( CallbackFunction )
      WndCl.cbClsExtra    = 0
      WndCl.cbWndExtra    = 4
      WndCl.hInstance     = hCurInstance
      WndCl.hIcon         = LoadIcon( hCurInstance, BYVAL %IDI_APPLICATION )
      WndCl.hCursor       = LoadCursor( %null, BYVAL %IDC_ARROW )
      WndCl.hbrBackground = GetStockObject( %LTGRAY_BRUSH )
      WndCl.lpszMenuName  = %null
      WndCl.lpszClassName = VARPTR( ascii )
      WndCl.hIconSm       = %null
      RegisterClassEx WndCl
      
      ascii = "colors"                                        ' creates colors window class
      
      WndCl.lpfnWndProc   = CODEPTR( CallbackColors )
      WndCl.hbrBackground = GetStockObject( %NULL_BRUSH )
      WndCl.lpszClassName = VARPTR( ascii )
      RegisterClassEx WndCl
                                                              ' creates the main window
      MainWindow = CreateWindowEx(                               _
        0,                                                       _
        "Palette Test",                                          _
        "Palette Test",                                          _
        %WS_OVERLAPPEDWINDOW OR %WS_CLIPCHILDREN,                _
        %CW_USEDEFAULT, %CW_USEDEFAULT,                          _
        540, 330,                                                _
        %HWND_DESKTOP,                                           _
        BYVAL %null,                                             _
        BYVAL hCurInstance,                                      _
        BYVAL %null )
      
      ShowWindow MainWindow, %SW_SHOW
      
      WHILE GetMessage( Msg, %null, 0, 0 )                    ' messages loop
        TranslateMessage Msg
        DispatchMessage Msg
      WEND
      
      FUNCTION = 0
      
    END FUNCTION
    ------------------

    [This message has been edited by Aldo Cavini (edited September 16, 2001).]
Working...
X