[Q] TComboBox & ListHandle

Hello there,
 
I'm trying to get handle of the listbox portion of combobox control...
I'm expecting ListHandle property to be a correct thing but it always
returns 0 no matter what style my combobox is.
I tried GetWindow() with various values of relationship parameter. But I
could not get it to work properly anyway. Anybody can help?
 
Thank you!
_art_Asked:
Who is Participating?
 
erajojCommented:
Hi,
You're in for a surprise...
The combo listbox is NOT owned by the combobox but by the desktop unless "Style := csSimple;"! :-(
That's the reason you can't retrieve a handle for it as BoRiS suggested. The only other child a combobox has is the editbox in styles; csDropDown, csSimple.
Because the Combobox List window is not a child of the ComboBox window, there is no simple way to get its handle. Furthermore, because the Combo's list box is a private class registered by USER its class cannot be accessed either.

A way to get the handle is to replace the combobox subclass proc.
Here's some code on how to do it (in C++, mea culpa):

LRESULT CALLBACK NewComboProc (HWND hWnd,   UINT message,   WPARAM
   wParam, LPARAM lParam ); // prototype for the combo box subclass proc

HANDLE hInst;                     // Current app instance
BOOL bFirst;                      // a flag

// Dialog procedure for the dialog containing the combo box.

BOOL __export CALLBACK DialogProc(HWND hDlg, UINT message, WPARAM wParam,
            LPARAM lParam)
{
    FARPROC lpfnNewComboProc;

    switch (message)
    {
    case WM_INITDIALOG:

   bFirst = TRUE;       // set flag here - see below for usage

   // subclass the combo box

   lpfnOldComboProc = (FARPROC ) SetWindowLong (
               GetDlgItem ( hDlg, IDC_COMBO1 ),
               GWL_WNDPROC,
               (LONG)NewComboProc );
   break;

     case WM_DESTROY:
   (FARPROC ) SetWindowLong (    GetDlgItem ( hDlg, IDC_COMBO1 ),
               GWL_WNDPROC,
               (LONG)lpfnOldComboProc );
   break;
     default:
        break;
     }

     return FALSE;

} // end dialog proc



// Combobox subclass proc.

LRESULT CALLBACK NewComboProc (HWND hWnd,   UINT message,   WPARAM
            wParam, LPARAM lParam );

{
   static HWND hwndList;
   static RECT rectList;

#ifdef WIN16
   if (  WM_CTLCOLOR  == message)  // combo controls are to be painted.
#else
   if ( WM_CTLCOLORLISTBOX == message ) // 32 bits has new message.
#endif
   {
      // is this message for the list box control in the combo?
#ifdef WIN16
      if ( CTLCOLOR_LISTBOX==HIWORD (lParam )   ) // need only for 16 bits
      {
#endif
         // Do only the very first time, get the list
         // box handle and the list box rectangle.
         // Note the use of GetWindowRect, as the parent
         // of the list box is the desktop window

         if ( bFirst )
         {
#ifdef WIN16
            hwndList = LOWORD (lParam );
#else
            hwndList = (HWND) lParam ;     // HWND is 32 bits
#endif
            GetWindowRect ( hwndList, &rectList );
                       bFirst = FALSE;
         }

         // Resize listbox window cx by 50 ( use your size here )

         MoveWindow ( hwndList, rectList.left, rectList.top,
         ( rectList.right - rectList.left + 50 ),
         rectList.bottom - rectList.top, TRUE );
#ifdef WIN16
      }
#endif
   }

   // Call original combo box procedure to handle other combo messages.

   return CallWindowProc ( lpfnOldComboProc, hWnd, message,
wParam, lParam ); }

Hope this helps.

/// John
0
 
viktornetCommented:
Hey, How are ya?

I'm not exactly sure what you are looking for? Would exaplin a little more, what handle do you need...???? :)

Regards,
Viktor Ivanov
0
 
BoRiSCommented:
_art_

here is a snippet not very neat and quite untidy, but t was written very quickly...

This will retrieve the handle of a child of the combobox which is the listhandle as far as I understand it...Correct me if I'm wrong

procedure TForm1.Button1Click(Sender: TObject);
var
Lst: HWND;
 Combo: TCustomComboBox;
begin
  Combo := TCustomComboBox.Create(Form1);
   Combo.Parent := Self;
    Combo.Left := 12;
     Combo.Top := 10;
      Combo.Width := 100;
       Combo.Height := 25;
         Lst := GetWindow(Combo.Handle, GW_CHILD);
       if Lst <= 0 then
        Showmessage('No handle caught')
        else
         Showmessage('You have the handle');

end;

Later
BoRiS
0
Cloud Class® Course: Microsoft Office 2010

This course will introduce you to the interfaces and features of Microsoft Office 2010 Word, Excel, PowerPoint, Outlook, and Access. You will learn about the features that are shared between all products in the Office suite, as well as the new features that are product specific.

 
_art_Author Commented:
viktornet: doin' fine. check out my new Delphi site at
www.torry.ru/dpfl/ (other are welcome as well).
BoRiS: Yep, thats exactly how Inprise catches ListHandle
and it is ALWAYS 0 ("No handle caught")!!
viktornet: Once again I need handle of the dropped list that
is part of combobox control and is listbox itself.
0
 
viktornetCommented:
I think what Boris told ya is right...

GetWindow(Combo.Handle, GW_CHILD);

Regards,
Viktor Ivanov
0
 
_art_Author Commented:
yep except that it always returns 0. :-)
0
 
viktornetCommented:
It's not that...did you try his example, when the combo is created it returns other than zero...and shows you the message that the handle is really there..Anyway, I'm not sure what's going on with that ... :)

Regards,
Viktor Ivanov
0
 
MatveyCommented:
Hi everybody...
I don't think it's useful to get the handle of the list attached to the combo. If you want to manipulate the items and stuff, you better use some combo-related-smAPI.

Look at Win32 help on value "Combo Box Reference" and so on.
Search for messages like CB_ADDSTRING, CB_GETCURSEL and so on. All you want to do with the combo-list you can do through CB_ messages.
0
 
_art_Author Commented:
erajoj: Excellent! :-)

I really am surprised because actually even after subclassing the control that receiving messages is still ComboBox. :-)
Anyhow my problem is solved and everything works great. By the way in Delphi it's easier than in code you provided. I had not subclass ComboBox. It was enough to override WndProc() method which declared in TCustomComboBox and then:

procedure TSomeComboBox.WndProc(var Message: TMessage);
begin
  inherited WndProc(Message);

  try
    case Message.Msg of
      WM_CTLCOLORLISTBOX:
          HListBox := Message.lParam;
    end;
  except
    Application.HandleException(Self);
  end;
end;

0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.