Jump to content
Tuts 4 You

Listbox & Color questions


LCF-AT

Recommended Posts

Posted

Hi guys,

just have a quick question about Listbox control and using some colors into them.Normaly I dont use OD for ListBox control but in this case it seems I have to use any.My goal is it just to color the background and specific text entrys I do send into the LB.All in all just 3 colors

- Background, - TextColor Blue for normal logs / state (all ok) & TextColor Red for Error logs.So in normal case I color back / text at WM_CTLCOLORLISTBOX message but it seems I can not color the text entrys seperated...

Info 1 <-- Blue

Info 2 <-- Blue

ErrorX <-- Red

....I get all blue or red only = Bad.Otherwise I dont wanna make any large OwnerDraw code just to create 2 diffrent text colors for normal & error logs you know.So is there a method I can send diffrent text colors without OD?If not how to do this again?I just forgot it already and can not find any example at the moment.

DRAWITEMSTRUCT STRUCT
  CtlType       DWORD      ?
  CtlID         DWORD      ?
  itemID        DWORD      ?
  itemAction    DWORD      ?
  itemState     DWORD      ?
  hwndItem      DWORD      ?
  hdc           DWORD      ?
  rcItem        RECT <>
  itemData      DWORD      ?
DRAWITEMSTRUCT ENDS

.elseif eax == WM_DRAWITEM
	mov edx, lParam
	.if [edx].DRAWITEMSTRUCT.CtlType == ODT_LISTBOX
		
	.endif

Has anyone short example or template for the LB stuff?Somehow I dont get it work.Not sure anymore whether I have to use with Select functions here too.Thank you.

greetz

Posted (edited)

Hello,
waiting for experts I'll try to reply :)

As far as I know you can't do that without owner-drawing.
Owner drawing is basically the same you already used here:

You need to handle both WM_MEASUREITEM and WM_DRAWITEM that will be called when you set the ownerdraw flag.

You would need to select the needed font into your hDC (read SelectObject) and do the text measuring with, for example, GetTextExtentPoint32 and/or GetTextMetrics function.

https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-gettextextentpoint32a

Probably, going through your previous post, you would remember what is all about ;)

Check also the example here:

https://docs.microsoft.com/de-de/windows/win32/controls/create-an-owner-drawn-list-box

 

Best Regards,
Tony

Edited by tonyweb
  • Like 1
Posted

Hi tonyweb,

ok thanks  but it looks again a little uhmmm you know.Just wanted ONLY to use 2 diffrent colors for the text lines I do send to the LB as I told before and that all.Dont wanna change any sizes or look of the default LB.Otherwise how to do that?

invoke SendDlgItemMessage,hWnd,IDC_EDITLOG,LB_ADDSTRING,NULL,chr$("Test-String")
invoke SendDlgItemMessage,hWnd,IDC_EDITLOG,WM_VSCROLL,SB_BOTTOM,NULL

invoke SendDlgItemMessage,hWnd,IDC_EDITLOG,LB_ADDSTRING,NULL,chr$("Test-Error")
invoke SendDlgItemMessage,hWnd,IDC_EDITLOG,WM_VSCROLL,SB_BOTTOM,NULL

The normal strings I wanna log in color A (Blue) = default and all others with "Error" in the string I wanna log in Red color so that the user can see it quickly that something did fail.Simple thing right.Problem is that I can manage that on WM_CTLCOLORLISTBOX message so there I can just set one color only for entire LB each time = 💩 and how its going when I do use OD code stuff?Have I then always check all logged entrys for the Error string and color them?Sounds also bad somehow.

My thing I wanna do (2 colors text) is so simple but the implementation is always such a PITA. :(

greetz

Posted

Hi again,

ok I was playing around and made some code like this....so far...

    .elseif eax == WM_DRAWITEM
	        mov edi, lParam
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
			.if 	[edi].DRAWITEMSTRUCT.CtlType == ODT_LISTBOX
				.if 		[edi].DRAWITEMSTRUCT.itemID     != -1h                  ; nothing
					.if 	[edi].DRAWITEMSTRUCT.itemAction == ODA_DRAWENTIRE
						invoke FillRect,[edi].DRAWITEMSTRUCT.hdc,addr [edi].DRAWITEMSTRUCT.rcItem,GSC ; brush color
					.elseif [edi].DRAWITEMSTRUCT.itemAction == ODA_SELECT
						
					.elseif [edi].DRAWITEMSTRUCT.itemAction == ODA_FOCUS
						
					.endif
					
					invoke SendMessage,[edi].DRAWITEMSTRUCT.hwndItem,LB_GETTEXTLEN,[edi].DRAWITEMSTRUCT.itemID,NULL
					.if eax > NULL
						invoke SendMessage,[edi].DRAWITEMSTRUCT.hwndItem,LB_GETTEXT,[edi].DRAWITEMSTRUCT.itemID,addr _LBBUFFER
						.if eax > NULL
							lea esi, _LBBUFFER
							mov esi, [esi]
							invoke lenA,esi
							invoke TextOut,[edi].DRAWITEMSTRUCT.hdc,[edi].DRAWITEMSTRUCT.rcItem.left,[edi].DRAWITEMSTRUCT.rcItem.top,esi, eax
						.endif
					.endif
				.endif
			.endif
			MOV EAX,TRUE
			ret  

...somehow its not working correctly with my code above.The ODA_DRAWENTIRE  does not draw the whole background only the background of logged strings.Also on TextOut function it does fill the entire LB with the same strings which I have logged as last!?The text color is also looking smudged / unclean / bold etc.Can anyone edit my code example to fix the wrong parts of me?

greetz

Posted (edited)

Hi @LCF-AT,
still trying to help waiting for "real" guys :)

Quote

The ODA_DRAWENTIRE  does not draw the whole background only the background of logged strings.

This may be related to how you handle the MEASUREITEM event message.

Try to take inspiration from this code, taken from CodeProject: all credits to the author, of course!

// Source: https://www.codeproject.com/Articles/135855/Owner-Drawn-CListBox

void CMultiLineListBox::AppendString(LPCSTR lpszText, COLORREF fgColor, COLORREF bgColor)
{
	LISTBOX_COLOR* pInfo = new LISTBOX_COLOR;

	pInfo->strText.Format(_T("%s"), lpszText);
	pInfo->fgColor = fgColor; 
	pInfo->bgColor = bgColor;

	SetItemDataPtr(AddString(pInfo->strText), pInfo);              // LB_SETITEMDATA, LB_ADDSTRING (SendMessage)
}

void CMultiLineListBox::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct) 
{
	// TODO: Add your code to determine the size of specified item
	ASSERT(lpMeasureItemStruct->CtlType == ODT_LISTBOX);
	
	CString strText(_T(""));
	GetText(lpMeasureItemStruct->itemID, strText);
	ASSERT(TRUE != strText.IsEmpty());

	CRect rect;
	GetItemRect(lpMeasureItemStruct->itemID, &rect);
	
	CDC* pDC = GetDC(); 
	lpMeasureItemStruct->itemHeight = pDC->DrawText(strText, -1, rect, DT_WORDBREAK | DT_CALCRECT); 
	ReleaseDC(pDC);
}

void CMultiLineListBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) 
{
	// TODO: Add your code to draw the specified item
	ASSERT(lpDrawItemStruct->CtlType == ODT_LISTBOX);

	LISTBOX_COLOR* pListBox = (LISTBOX_COLOR*)GetItemDataPtr(lpDrawItemStruct->itemID);       //  // LB_GETITEMDATA (SendMessage)
	ASSERT(NULL != pListBox);

	CDC dc;
	
	dc.Attach(lpDrawItemStruct->hDC);
	
	// Save these value to restore them when done drawing.
	COLORREF crOldTextColor = dc.GetTextColor();
	COLORREF crOldBkColor = dc.GetBkColor();
	
	// If this item is selected, set the background color 
	// and the text color to appropriate values. Also, erase
	// rect by filling it with the background color.
	if ((lpDrawItemStruct->itemAction | ODA_SELECT) &&
		(lpDrawItemStruct->itemState & ODS_SELECTED))
	{
		dc.SetTextColor(pListBox->bgColor);
		dc.SetBkColor(pListBox->fgColor);
		dc.FillSolidRect(&lpDrawItemStruct->rcItem, pListBox->fgColor);
	}
	else
	{
		dc.SetTextColor(pListBox->fgColor);
		dc.SetBkColor(pListBox->bgColor);
		dc.FillSolidRect(&lpDrawItemStruct->rcItem, pListBox->bgColor);
	}
	
	lpDrawItemStruct->rcItem.left += 5;
	// Draw the text.
	
	dc.DrawText(pListBox->strText, pListBox->strText.GetLength(), &lpDrawItemStruct->rcItem, DT_WORDBREAK);
	
	// Reset the background color and the text color back to their
	// original values.
	dc.SetTextColor(crOldTextColor);
	dc.SetBkColor(crOldBkColor);
	
	dc.Detach();	
}

I chose to compile it and attach it here, so you can see the code at assembly level (you're very familiar with, see RVA: 1FD0).

Demo.zip

Don't know if it's completely okay to attach: it should be, cause we're giving proper credts :)

So again, this is simply compiled from :

https://www.codeproject.com/Articles/135855/Owner-Drawn-CListBox

I changed a bit the code to have some blue and one red string only (even if I changed only the "main" code):

Demo_Modded.zip

Hope this helps a bit.

Best Regards,
Tony

 

Edited by tonyweb
Replaced with a /MT compiled executable, Demo modded, some remarks for ItemData
  • Like 2
Posted

Hi Tony,

thanks for that infos / examples but I don't get it work correctly in my case. :( I also get always just the same logged text into the LB to too.If I send 3 diffrent text lines then all getting same in the entire LB.Somehow it sucks again.By the way, I am using a LB from resources with enabled style LBS_OWNERDRAWFIXED.

What about the whole LB background (which is empty)?I can not color that?Only background of logged text?

greetz

Teddy Rogers
Posted

What about adding an icon before the text to indicate what it is you want the user to know?

Ted.

  • Like 1
Posted

Probably easier to use a listview with customdraw handling and you can assign text color based on some condition stored in lparam - pointer to a structure for each item that contains a type (so you can color code accordingly) or just use lparam as the 'type' value. 0 normal, 1 cool blue, 2 red, 3 something else etc.

  • Like 1
Posted

Hi guys,

sure I could use a LV where I have more infos about and examples but I wanna also know how to deal with LBs too.At the moment I try to create a example project just using a LB from resources and doing some WM_DRAWITTEM handling.Now I have some diffrent questions.

Which messages I have to catch / handle for a ListBox at WM_DRAWITTEM?In my case I just get the itemActions only and NO itemStates!Why?See my new code below....

CONTROL "",IDC_LISTBOX,"ListBox",0x50010150,17,9,354,74,0x00000200

	.elseif eax == WM_DRAWITEM
		mov edi, lParam
		assume	edi: ptr DRAWITEMSTRUCT
		.if [edi].CtlType == ODT_LISTBOX
			.if	[edi].itemID	!= -1
				.if	[edi].CtlID == IDC_LISTBOX
					.if 	[edi].itemAction == ODA_DRAWENTIRE
							invoke FillRect,[edi].hdc,addr [edi].rcItem,GSC    ; brush color yellow
							invoke SetTextColor,[edi].hdc,Blue
					.elseif [edi].itemAction == ODA_SELECT
							invoke SetTextColor,[edi].hdc,Red
					;		invoke FillRect,[edi].hdc,addr [edi].rcItem,GSC2    ; brush color gray
					.elseif [edi].itemAction == ODA_FOCUS
							invoke SetTextColor,[edi].hdc,Red
							invoke FillRect,[edi].hdc,addr [edi].rcItem,GSC2    ; brush color gray
							
					.endif
					
					invoke SendMessage,[edi].hwndItem,LB_GETTEXT,[edi].itemID,addr _LBBUFFER
					mov ecx, eax
					invoke DrawText,[edi].hdc,addr _LBBUFFER,ecx,addr [edi].rcItem,DT_WORDBREAK
					
					.if 	[edi].itemState == ODS_DEFAULT
						exit
					.elseif [edi].itemState == ODS_SELECTED
						exit
					.elseif [edi].itemState == ODS_DISABLED
						exit
					.elseif [edi].itemState == ODS_FOCUS
						exit
					.endif
					
					
					
					
				.endif
			.endif
		.endif
		assume	edi: nothing

....I get nothing on itemstate check = no exit call.In the LB I have pushed some strings.Somehow it looks not so good.Has nobody a already done template for that etc?

LB_2021-05-22_204437.png.2f65dc1f97b042d3eb3f2075fd69bf05.png

....so when I have to fill the background of item?On every message of itemAction?The second entry I have selected and the line is gray but the background of text is still yellow a little.Not sure why its mixed here.The visible LB emty box is white so this sucks.Why I can not color this too?In default mode I get also the whole LB background colored at WM_CTLCOLORLISTBOX color for listbox message.

@fearless

Do you have not any template laying around somewhere for that OD LB?Just need to know what to catch / handle and where to draw etc you know.

@Teddy Rogers

Sure, a Icon before would be also nice.Main goal was it for me just to log the strings into 2 diffrent colors (specially RED color for Error logs) so that the user can see it quickly.Other having a whole OD template for a entire LB (example) would also be nice.

greetz

  • Like 1
Posted

Hi again,

so I did debug that struct in Olly now and I see some issues by checking the itemState.So the struct is this.....

DRAWITEMSTRUCT STRUCT
  CtlType       DWORD      ?
  CtlID         DWORD      ?
  itemID        DWORD      ?
  itemAction    DWORD      ?
  itemState     DWORD      ?
  hwndItem      DWORD      ?
  hdc           DWORD      ?
  rcItem        RECT <>
  itemData      DWORD      ?
DRAWITEMSTRUCT ENDS

or on MSDN =

typedef struct tagDRAWITEMSTRUCT {
  UINT      CtlType;
  UINT      CtlID;
  UINT      itemID;
  UINT      itemAction;
  UINT      itemState;
  HWND      hwndItem;
  HDC       hDC;
  RECT      rcItem;
  ULONG_PTR itemData;
} DRAWITEMSTRUCT, *PDRAWITEMSTRUCT, *LPDRAWITEMSTRUCT;

As you can see all paramters holding a DWORD lenght typedef (itemAction / itemState).In that case I should check the itemAction / itsemState with a DWORD but its not working for the itemState!Lets have a look in Olly...

ODT_MENU                             equ 1
ODT_LISTBOX                          equ 2
ODT_COMBOBOX                         equ 3
ODT_BUTTON                           equ 4
ODT_STATIC					 		 equ 5
ODA_DRAWENTIRE                       equ 1h
ODA_SELECT                           equ 2h
ODA_FOCUS                            equ 4h
ODS_SELECTED                         equ 1h
ODS_GRAYED                           equ 2h
ODS_DISABLED                         equ 4h
ODS_CHECKED                          equ 8h
ODS_FOCUS                            equ 10h
ODS_DEFAULT         			 	 equ 20h
ODS_COMBOBOXEDIT    			 	 equ 1000h
ODS_HOTLIGHT        			   	equ 40h
ODS_INACTIVE        			 	 equ 80h

$ ==>    012FF0CC <CtlType>         00000002
$+4      012FF0D0 <CtlID>           000003E8
$+8      012FF0D4 <itemID>          00000001
$+C      012FF0D8 <itemAction>      00000002  <-- ODA_SELECT
$+10     012FF0DC <itemState>       00000301  <-- ODS_SELECTED byte 01
$+14     012FF0E0 <hwndItem>        00090846
$+18     012FF0E4 <hdc>             A60111B4
$+1C     012FF0E8 <rcItem.left>     00000000
$+20     012FF0EC <rcItem.top>      00000010
$+24     012FF0F0 <rcItem.right>    000001C7
$+28     012FF0F4 <rcItem.bottom>   00000020
$+2C     012FF0F8 <itemData>        0344AB60

My code by checking the state seperated does fail
  
					.if 	[edi].itemState == ODS_DEFAULT
						exit
					.elseif [edi].itemState == ODS_SELECTED
						exit
					.elseif [edi].itemState == ODS_DISABLED
						exit
					.elseif [edi].itemState == ODS_FOCUS
						exit
					.endif
  
So I can change it by adding byte ptr onto
  
.elseif byte ptr [edi].itemState == ODS_SELECTED ; Seems to work.

Now lets check again your code @tonyweb you did post above...

if ((lpDrawItemStruct->itemAction | ODA_SELECT) && (lpDrawItemStruct->itemState & ODS_SELECTED))
	

...you do check itemAction for ODA_SELECT & itemState for ODS_SELECTED together but your code in Olly dosen't check the DWORDs...

003C1F43  |.  8B4F 0C               MOV ECX,DWORD PTR DS:[EDI+C]                   ;  itsemAction DWORD to ecx
003C1F46  |.  83C9 02               OR ECX,2                                       ;  or ecx 2 why?
003C1F49  |.  8945 08               MOV DWORD PTR SS:[EBP+8],EAX
003C1F4C  |.  74 23                 JE SHORT 003C1F71                           
003C1F4E  |.  F647 10 01            TEST BYTE PTR DS:[EDI+10],1                    ;  Test byte edi+10 = itsemState
003C1F52  |.  74 1D                 JE SHORT 003C1F71                              

So if I do use that command style like you do =......

.elseif [edi].itemAction == ODA_SELECT && [edi].itemState == ODS_SELECTED

...then its looking so in Olly...

0116F62C <CtlType>         00000002
0116F630 <CtlID>           000003EA
0116F634 <itemID>          00000000
0116F638 <itemAction>      00000002  <--
0116F63C <itemState>       00000301  <--
0116F640 <hwndItem>        00020A4A
0116F644 <hdc>             CA011544
0116F648 <rcItem.left>     00000000
0116F64C <rcItem.top>      00000000
0116F650 <rcItem.right>    0000020F
0116F654 <rcItem.bottom>   00000010
0116F658 <itemData>        00000000

00881327   > \837F 0C 02            CMP DWORD PTR DS:[EDI+C],2                     ;  itsemAction
0088132B   .  75 38                 JNZ SHORT 00881365                           
0088132D   .  837F 10 01            CMP DWORD PTR DS:[EDI+10],1                    ;  itsemState
00881331   .  75 32                 JNZ SHORT 00881365                           
Exit  <--- Never reached

Its not checking the same way in my case.Only can change it by checking the byte directly itself....

.elseif [edi].itemAction == ODA_SELECT && byte ptr [edi].itemState == ODS_SELECTED

...then it seems to work.Somehow strange that the struct for itemState is declared as DWORD but not working to check it as DWORD or UINT  (typedef DWORD) which is also DWORD.So whats the problem in this case?Is it me again to understand something not correctly or am I right and MSDN did some fail?Its pretty bad that I get sometimes such strange errors / something not working like it works for you & others you know.Just because of such issues.Maybe anyone can explain it to me.

greetz

  • Like 1
Posted
1 hour ago, LCF-AT said:

Is it me again to understand something not correctly

You just didn't read MSDN properly. See https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-drawitemstruct (emphasis mine):

Quote

itemState Type: UINT

The visual state of the item after the current drawing action takes place. This member can be a combination of the values shown in the following table.

Value 0x301 decodes as ODS_NOFOCUSRECT | ODS_NOACCEL | ODS_SELECTED. 

The correct way for checking such flags is by using "and" or "test" operation, just like Tonyweb's code does. Your code comparing byte value will fail, for example, on flags ODS_DEFAULT | ODS_SELECTED or anything like that..

 

 

  • Like 3
Posted

Hi,

hhmm.But on itemAction you can read same too (This member can be one or more of the values).Otherwise if I use DRAWITEMSTRUCT for buttons I can check all seperated.That again really confusing.So if the command by Tony is right....

if ((lpDrawItemStruct->itemAction | ODA_SELECT) && (lpDrawItemStruct->itemState & ODS_SELECTED))

....how should it look for me then in MASM using high syntax commands...

.if [edi].itemAction == ODA_SELECT && [edi].itemState == ODS_SELECTED
=
??

greetz

  • Like 1
Posted

If you only want to process if action is select and state is selected then something like:
 

mov eax, [edi].itemState
and eax, ODS_SELECTED
mov ebx, [edi].ItemAction
and ebx, ODA_SELECT

.IF eax == ODS_SELECTED && ebx == ODA_SELECT

 

  • Like 1
Posted

Hi,

so that what I don't wanna do fearless.Using manually register moves / and operation (looks total bad adding that extra code).Just wanted to write it directly at once but seems not to work with MASM as on C or C++ like Tony did.There you also see no extra moves you know. :(

So what is if I do it like you postet fearless.How should the entire template look like?What if I need or have to check more than one itemState etc?

What is if I wanna check every single itemState one by one?How should that look please!Like dirt!Maybe like this...?

mov eax, [edi].itemState
and eax, ODS_SELECTED

.if eax == ODS_SELECTED 
	nop
.else
	mov eax, [edi].itemState
	and eax, ODS_DEFAULT
	.if eax == ODS_DEFAULT
		nop
	.else
		mov eax, [edi].itemState
		and eax, ODS_FOCUS
		.if eax == ODS_FOCUS
			nop
		.else
			nop
		.endif
	.endif
.endif

Ah come on!You can't be seroius or?How to manage that checks if I have a LOT to check?There are 11 itsemStates conditions which could happen and can be checked (also if there are not all for a LB).Sorry fearless, but this method is total bad.Is there no special macro we can use?Otherwise to write in such a style is also messy and my goal was it to write codes clean and clear you know.How would you do write the code with few more checks (3-5 etc)?

greetz

Posted

Hi again,

so what about using switch & case commands?

					switch [edi].DRAWITEMSTRUCT.itemState
						case	ODS_SELECTED
						nop
						case	ODS_DEFAULT
						nop
						case	ODS_FOCUS
						nop
						default
						nop
						nop
					endsw

Where to set a "and" operation for EAX?How to manage that in this example?

Example of code I found....of C or C++ etc.

http://cplusplus.com/forum/windows/14130/#msg69044

        case ODA_DRAWENTIRE:
            if (lpDStruct->itemState & ODS_SELECTED)
            {
                DrawSelected(lpDStruct);
            }
            else
            {
                DrawEntire(lpDStruct);
            }
            break;
        case ODA_FOCUS:
            DrawFocused(lpDStruct);
            break;
        case ODA_SELECT:
            //DrawSelected(lpDStruct);
            if (lpDStruct->itemState & ODS_SELECTED)
            {
                DrawSelected(lpDStruct);
            }
            else
            {
                DrawEntire(lpDStruct);
            }

            break;
        default:
            break;

Does it mean at the end that I can forget it to check such flags / combinations similar like above for C / C++ and that I HAVE to do some and / or extra ASM commands stuff and blowing up the whole code with if/else/endif statements between?Just asking only of course.

greetz

Posted

Hi again,

still need some help and info how to check the flags & combined flag combos.Just check it for listbox...just can check one by one but how if they combined?That really makes me sick and the checks are looking like crap!Some better infos / hints are welcome if you got any. :)

	.elseif eax == WM_DRAWITEM
		mov edi, lParam
		assume	edi: ptr DRAWITEMSTRUCT
		.if 	[edi].CtlType == ODT_BUTTON
			
		.elseif	[edi].CtlType == ODT_COMBOBOX
			.if [edi].itemID  == -1				; no items
				nop                             ; draw only the focus rectangle
			.else
				
			.endif
		.elseif	[edi].CtlType == ODT_LISTBOX
			.if [edi].itemID  == -1				; no items
				nop                             ; draw only the focus rectangle
			.else
				.if [edi].CtlID == IDC_LISTBOX  ; optional check for ID equ of control
					.if		[edi].itemAction == ODA_DRAWENTIRE
						mov eax, [edi].DRAWITEMSTRUCT.itemState
						and eax, ODS_SELECTED
						.if eax == ODS_SELECTED
							nop
						.else
							mov eax, [edi].DRAWITEMSTRUCT.itemState
							and eax, ODS_FOCUS
							.if eax == ODS_FOCUS
									nop
							.else
								mov eax, [edi].DRAWITEMSTRUCT.itemState
								and eax, ODS_DEFAULT
								.if eax == ODS_DEFAULT
									nop
								.else
									mov eax, [edi].DRAWITEMSTRUCT.itemState
									and eax, ODS_DISABLED
									.if eax == ODS_DISABLED
										nop
									.endif
								.endif
							.endif
						.endif
					.endif
				.endif
			.endif			
		.elseif	[edi].CtlType == ODT_LISTVIEW
			
		.elseif	[edi].CtlType == ODT_MENU
			
		.elseif [edi].CtlType == ODT_STATIC
			
		.elseif [edi].CtlType == ODT_TAB
			
		.endif
		assume	edi: nothing

greetz

Posted (edited)

There is no need to do IF cases for things you do not support. It takes up a lot of space and gives you zero value. So, I would get rid of those immediately.

 

As for the rest:

On 5/24/2021 at 1:06 AM, kao said:

The correct way for checking such flags is by using "and" or "test" operation, just like Tonyweb's code does.

Here are few options how I would write such code. It's a matter of personal preference, every coder has his/her personal style. 

* jump-style. This is my personal favorite, as it's the closest to the actual assembly code:

	test [edi].DRAWITEMSTRUCT.itemState, ODS_DEFAULT
	jz notODS_DEFAULT

	; process ODS_DEFAULT
	nop
	jmp afterItemState

notODS_DEFAULT:
	test [edi].DRAWITEMSTRUCT.itemState, ODS_SELECTED
	jz notODS_SELECTED

	; process ODS_SELECTED
	nop
	jmp afterItemState

notODS_SELECTED:
	test [edi].DRAWITEMSTRUCT.itemState, ODS_FOCUS
	jz afterItemState

	; process ODS_FOCUS
	nop
	; fallthrough, so no jump here

afterItemState:

* .if style. It looks closer to C code and generates the exact same assembly code as above. I'm not a fan of this but if you like it, why not..

	.if [edi].DRAWITEMSTRUCT.itemState & ODS_DEFAULT
		; process ODS_DEFAULT
		nop
	.elseif [edi].DRAWITEMSTRUCT.itemState & ODS_SELECTED
		; process ODS_SELECTED
		nop
	.elseif [edi].DRAWITEMSTRUCT.itemState & ODS_FOCUS
		; process ODS_FOCUS
		nop
	.endif

 

EDIT: depending on what you want to do, you might need to replace ".elseif" with ".endif" + another ".if". My point was to show a method how to test bitflags, nothing else.

Edited by kao
  • Like 1
Posted

Hi kao,

thanks for trying to help but I see your code examples are looking similar bad as my with If / Endif commands.Its maybe ok to check single statement flags one by one but what about flag combos?How to check them?

Lets say there are 10 possible diffrent flags a state can have.10 single diffrent states = Ok alright so that possible to check one by one.Now lets say the state can also be a combo of max 6 flags so how to find out / check them?Do you know what I mean?Its just crazy.

Question: Just in the example of a LISTBOX lets try to find out what I need to know to create a 100% right working OwnerDraw template for WM_DRAWITTEM.First I need to check for CtlType which can be...

The control type. This member can be one of the following values. See Remarks.

ODT_BUTTON
ODT_COMBOBOX
ODT_LISTBOX
ODT_LISTVIEW
ODT_MENU
ODT_STATIC
ODT_TAB

Remarks
Some control types, such as status bars, do not set the value of CtlType

...MSDN tells me that only one control member can be inside of CtlType I have to check for.Ok, lets check next important one itemAction...

The required drawing action. This member can be one or more of the values.

ODA_DRAWENTIRE
ODA_FOCUS
ODA_SELECT

....Ohhhh, that member can be ONE or MORE!?Danger!You have to make a ONE or MORE checking code right!WHat does it mean?It can be just one by one = checking just the DWORD itsemAction for one of them OR what can it be else?

ODA_DRAWENTIRE + ODA_FOCUS + ODA_SELECT
ODA_DRAWENTIRE + ODA_FOCUS
ODA_DRAWENTIRE + ODA_SELECT
etc....

Now the itemState....

The visual state of the item after the current drawing action takes place. 
This member can be a combination of the values shown in the following table.

ODS_CHECKED			This bit is used only in a menu.
ODS_COMBOBOXEDIT		Just owner-drawn for combo box.
ODS_DEFAULT			The item is the default item. <--- What does that mean?
ODS_DISABLED			The item is to be drawn as disabled.
ODS_FOCUS			The item has the keyboard focus.
ODS_GRAYED			The item is to be grayed. This bit is used only in a menu.
ODS_HOTLIGHT			The item is being hot-tracked, that is, the item will be highlighted when the mouse is on the item.
ODS_INACTIVE			The item is inactive and the window associated with the menu is inactive.
ODS_NOACCEL			The control is drawn without the keyboard accelerator cues.
ODS_NOFOCUSRECT			The control is drawn without focus indicator cues.
ODS_SELECTED			The menu item's status is selected. 

What I have to check for an LISTBOX = All except ODS_CHECKED, ODS_COMBOBOXEDIT, ODS_GRAYED...right?There are 11 diffrent flags minus 3 flags = 8 flags left to check in the case of a LISTBOX..right?Now I would like to know how a really smart checking template would look like to handle ALL diffrent cases / combinations.Sorry, maybe I do think again in a wrong direction or my logical thinking is on vacation but somehow I don't get smarter by trying to handle all those diffrent situations without to write tons of code checkings you know.Otherwise I also have to find out which flag combinations are possible....so there I see no information on MSDN.As I said, I'am maybe just too un-smart for that to get any good checking solution in my head or whatever the reason.If possible then it would be nice if someone could example it to me HOW I have/must understand that DRAWITEMSTRUCT + handling at WM_DRAWITTEM message.

greetz

Posted

Hi,

just another small AddOn question.Is there anywhere a list to find about the themes I can use with the SetWindowTheme function and which controls getting be affected etc?The description of that function is again pretty small and the example does just show one info...

Examples
The following example code gives a list-view control the appearance of a Windows Explorer list:

SetWindowTheme(hwndList, L"Explorer", NULL);

...so I'am using this for my listviews but what about LixtBoxes?Seems that this is not working for it.I would like to give my Listbox the same look / selecting style as for my listview you know.Is that also possible or not?

greetz

Posted

Hi again,

does anyone know any good complete tutorial/s about OwnerDraws for all controls?Anyway if in C++ or other languages etc.

I also wanna know where I can find a complete list of all controls & classes I can use.I found something here...

https://docs.microsoft.com/en-us/windows/win32/winauto/uiauto-controlsupport

...just wanna know whether they are more and if yes I need the names & description etc.

I also wanna know what kind of intern ready controls I can use.Something like the color controls to pick colors (dont know the class / control name of it) or the explorer Window to load / save files etc you know what I mean right.Just wanna get / create a list of everything I can already use (nothing I need to create by myself later) if I need any of them.Maybe you can help with that a little.Thank you.

PS: Still wanna know what flag conditions I have to check for my ListBox I did post above or for any other controls.Any infos would be welcome before trying all out manually.

greetz

Posted

Hi kao,

thanks for the new links, thats what I was looking for.Just wanna ask whether that all or are there some more etc?

About my Listbox OD problem.So I'am always happy to get some help for my questions you know.In the cases of itemAction & itsemState its still hard for me to find any description about a complete OD (of LB in this case) which does handle really ALL possible conditions but for this I need to find out what conditions can be hit together as I told above.Maybe its important to know if someone wants to create extra OD for every single case.Otherwise I'am thinking maybe again in a wrong direction or whatever it is again.Maybe I should just care about the minimum important flags only.Will see. :)

greetz

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...