Klasik
Klasik

Reputation: 892

Add visible window titles to combobox MFC

I want to add visible window titles to a combobox. Here is my source:

BOOL CALLBACK EnumWindowsProc(HWND hWnd, long lParam) 
{
     TCHAR buff[255];
     CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_PROCESS);
     if (IsWindowVisible(hWnd)) 
     {
         GetWindowText(hWnd, buff, 254);
         pComboBox->AddString(buff);
     }
     return TRUE;
}

void CFindProcess::OnDropdownComboProcess()
{
    EnumWindows(EnumWindowsProc, 0);
}

but I get error:

error C2660: 'GetDlgItem' : function does not take 1 arguments  60

How I can correctly add titles to combo?

Upvotes: 3

Views: 850

Answers (3)

Ajay
Ajay

Reputation: 18431

In addition to what user @mfc has provided, I would not do UI update from a different thread. I believe EnumWindows does not create thread for enumeration. It would call the callbacks within the call-stack of current thread.

This, in turn, means that UI may freeze for a while. Thus, it is recommended to create a thread for enumeration. More over, I would not directly update UI from different thread. May be a vector of string, or a PostMessage (on each iteration) I would have used.

It is true that EnumWindows may perform quite fast. But when you move to enumerate other (kernel) objects like file, printers, users etc - the UI is definitely going to freeze. So, better practice writing multithreaded code. Initially writing MT-code would be a pain, but later you'd love it, appreciate it, and cannot live without it.

Upvotes: 2

mfc
mfc

Reputation: 565

MFC objects are thread-sensitive, GetDlgItem works well in the thread that created the object, probably the main UI thread. Function EnumWindows probably creates a worker thread to access the callback function, and that is why GetDlgItem failed to get a valid handle of the combobox.

To access the combobox properly in another thread, you have to use the static function: CWnd::FromHandle with the raw handle of the combobox object as follows:

BOOL CALLBACK EnumWindowsProc(HWND hWnd, long lParam) 
{
    if (IsWindowVisible(hWnd)) 
    {   TCHAR szBuffer[255];
        INT nLength = GetWindowText(hWnd, szBuffer, 254);
        if (nLength>0)
        {   // only add windows that has a caption
            CComboBox *pComboBox = (CComboBox*)CWnd::FromHandle((HWND)lParam);
            pComboBox->AddString(szBuffer);
        }
    }
    return TRUE;
}

// call EnumWindows --------------------
CComboBox *pComboBox = (CComboBox *)GetDlgItem(IDC_COMBO1);
// passing the raw handle of the combobox as parameter
EnumWindows(EnumWindowsProc, (LPARAM)pComboBox->m_hWnd);

Upvotes: 3

Tony The Lion
Tony The Lion

Reputation: 63210

Firstly, your GetDlgItem has two parameters, and the first is a handle to the dialog box that contains the control.

So it expects a HWND parameter of the dialog that contains this control, I would presume that will be the HWND you pass as a parameter to your function.

 CComboBox* pComboBox = (CComboBox*)GetDlgItem(hWnd,IDC_COMBO_PROCESS);
                                                 ^^^^ added parameter

If you look at EnumWindows in MSDN, you'll see you have to pass a callback and it has a HWND parameter, if you look at what this parameter is for it says:

A handle to a top-level window.

This is exactly what you have to pass to GetDlgItem.

Also, you should check the return value of GetWindowText as this returns the number of characters written to the buff you passed it.

     int ret = GetWindowText(hWnd, buff, 254);
     if (ret > 0) pComboBox->AddString(buff); // only add non-empty strings.

Upvotes: 2

Related Questions