Download source code User Interface Thread
Some time back we saw how to build an application that uses a worker thread. A worker thread is used to perform background tasks that receive no direct input from the user. Unlike this user-interface(UI) threads are used to create windows and process messages sent to those windows. In this article we will write a small application that uses a UI thread.
On executing the application a dialog box containing a list box and a ‘Browse’ button is displayed. If ‘Browse’ button is clicked all the network resources are displayed in the list box. If we double click a resource like remote drive all the directories and files of that drive are displayed in a different UI thread. This thread contains a list view window housed in a frame window. On double clicking a directory, subdirectories contained in it are displayed. Let us now see how do we go about building this application.
Create a dialog-based application called Mthread_net. Add a list box (with id as IDC_LISTRES) and a ‘Browse’ button to the template as shown below:

Add a control variable m_listres of type CListBox for the list box to the CMthread_netDlg class. Since we are going to access this variable in the thread function declare it as static. Add a handler OnBrowse( ) for ‘Browse’ button. In this handler create a worker thread to enumerate and display the network resources in the list box as shown below:
void CMthread_netDlg::OnBrowse( )
{
AfxBeginThread ( enumnet, NULL ) ;
}
enumnet is the thread function. Declare this function in ‘Mthread_netDlg.h’ as follows:
UINT enumnet ( LPVOID param ) ;
The code of enumnet function is given below:
UINT enumnet ( LPVOID param )
{
LPNETRESOURCE lpnr = ( LPNETRESOURCE ) param ;
HANDLE h ;
DWORD cn = 0xFFFFFFFF, s = 16384 ;
LPNETRESOURCE nr ;
int res = WNetOpenEnum ( RESOURCE_GLOBALNET,
RESOURCETYPE_ANY, 0, lpnr, &h ) ;
nr = ( LPNETRESOURCE ) new char[s] ;
do
{
res = WNetEnumResource ( h, &cn, nr, &s ) ;
if ( res == NO_ERROR )
{
for ( int i = 0 ; i <= ( int ) cn ; i++ )
{
if ( RESOURCEUSAGE_CONTAINER == (nr[i].dwUsage & RESOURCEUSAGE_CONTAINER ) )
enumnet ( &nr[i] ) ;
else
{
if ( nr[i].dwType != RESOURCEDISPLAYTYPE_GENERIC )
CMthread_netDlg::m_listres.AddString( nr[i].lpRemoteName ) ;
}
}
}
} while ( res == ERROR_NO_MORE_ITEMS ) ;
WNetCloseEnum ( h ) ;
return 0 ;
}
To enumerate a network resource, we have used the functions WNetOpenEnum( ) and WNetEnumResource( ). The name of the remote drive stored in lpRemoteName is then added to the list box.
Add a LBN_DBLCLK notification handler to the CMthread_netDlg class. Add the following code to the handler.
void CMthread_netDlg::OnDblclk( )
{
int item = m_listres.GetCurSel( ) ;
CString str ;
m_listres.GetText ( item, str ) ;
m_filepath = str ;
AfxBeginThread ( RUNTIME_CLASS ( UIthread ) ) ;
}
Here, the name of the remote computer double clicked in the list box is retrieved using CListBox::GetCurSel( ) and CListBox::GetText( ) functions. This name is stored in a CString variable m_filepath that is declared globally in ‘Mthread_netDlg.cpp’ file. This is necessary since we need the path of the drive whose directories are to be displayed in the UI thread. Next we have created a UI thread by calling AfxBeginThread( ) function. To this function we have passed CRuntimeClass structure of the thread class UIthread. Whenever the user clicks on a network resource a new window should be popped up through the UI thread. Since we do not know how many threads the user will start the objects of this class must be created dynamically.
Using ClassWizard add a new class called UIthread derived from CWinThread. Add following code to it.
class UIthread : public CWinThread
{
DECLARE_DYNCREATE ( UIthread )
public :
BOOL InitInstance( ) ;
} ;
Add the following code to the class’ implementation file.
#include “myframe.h”
IMPLEMENT_DYNCREATE ( UIthread, CWinThread )
BOOL UIthread::InitInstance( )
{
myframe *p = new myframe ;
m_pMainWnd = p ;
p -> ShowWindow ( 1 ) ;
return TRUE ;
}
In InitInstance( ) function the frame window is created using the myframe class. The myframe class is derived from CFrameWnd class. Insert this class by selecting ‘Insert | New Class’. Type the class name as myframe and select CFrameWnd class as the base class. Two files, ‘myframe.h’ and ‘myframe.cpp’ get added to the project.
In ‘myframe.h’ make the declaration of the myframe( ) constructor public (by default it is protected) as we have to access it in UIthread class). Add the following statement to the constructor:
myframe::myframe( )
{
Create ( 0, “View Thread” ) ;
}
Add a variable m_view of type myview* to myframe class. myview is a user-defined class derived from CListView class in which we will list the contents of selected drive. #include ‘myview.h’ in ‘myframe.h’ file. Add OnCreate( ) handler to the myframe class and add the following code to it.
int myframe::OnCreate ( LPCREATESTRUCT lpCreateStruct )
{
if ( CFrameWnd::OnCreate ( lpCreateStruct ) == -1 )
return -1;
m_view = new myview ;
m_view -> Create ( 0, “”, WS_CHILD | WS_VISIBLE | LVS_SMALLICON, rectDefault, this, AFX_IDW_PANE_FIRST ) ;
return 0 ;
}
Here, we are creating the view window dynamically.
Add myview class by selecting ‘Insert | New Class’. Give the class name as myview and select CListView as the base class. Add OnCreate( ) handler to the myview class. The code for this function is given below:
int myview::OnCreate ( LPCREATESTRUCT lpCreateStruct )
{
if (CListView::OnCreate ( lpCreateStruct ) == -1)
return -1;
m_img.Create ( 16, 16, ILC_COLOR16 | ILC_MASK, 0, 10 ) ;
GetListCtrl( ).SetImageList ( &m_img, LVSIL_SMALL ) ;
GetListCtrl( ).InsertColumn ( 0, “File Name”, LVCFMT_LEFT, 150, 0 ) ;
m_path = m_filepath ;
displayfiles ( m_path ) ;
return 0 ;
}
Add the following variables to the myview class.
CString m_path ;
CImageList m_img ;
In this function, we have created an image list by calling CImageList::Create( ) function and set this image list to the list control using CListCtrl::SetImageList( ) function.
We have assigned the drive path stored in the global variable to the m_path data member. Next, we have called displayfiles( ) function to display the files in the list view control. The code of displayfiles( ) is given below:
void myview::displayfiles ( CString path )
{
CFileFind fd ;
int i = 0 ;
if ( path.Right ( 1 ) != ‘\\’ )
path += “\\” ;
path += “*.*” ;
SHFILEINFO sh = { 0 } ;
if ( fd.FindFile ( path ) == NULL )
return ;
BOOL f = fd.FindNextFile( ) ;
while ( f )
{
f = fd.FindNextFile( ) ;
if ( fd.IsDots( ) )
continue ;
SHGetFileInfo ( fd.GetFilePath( ), NULL, &sh, sizeof ( SHFILEINFO ), SHGFI_ICON ) ;
int i = m_imgsmall.Add ( sh.hIcon ) ;
GetListCtrl( ).InsertItem ( 0, fd.GetFileName( ), i ) ;
}
fd.Close( ) ;
}
We have used the functions CFileFind::FindFile( ) and CFileFind::FindNextFile( ) to browse the selected drive. We have retrieved the system icon attached to the file using SHGetFileInfo( ) function. We have then added this icon to the image list and displayed it along with the filename.
Our program allows user to view the contents of the directory by double clicking it. For this, add double click notification handler as shown below:
void myview::OnDblclkItem ( NMHDR* pNMHDR, LRESULT* pResult )
{
NM_LISTVIEW *plist = ( NM_LISTVIEW* ) pNMHDR ;
if ( m_path.GetAt ( m_path.GetLength( ) – 1 ) != ‘\\’ )
m_path += “\\” ;
int item = plist -> iItem ;
m_path += GetListCtrl( ).GetItemText ( item, 0 ) ;
GetListCtrl( ).DeleteAllItems( ) ;
displayfiles ( m_path ) ;
*pResult = 0;
}
Here, we have retrieved the name of the directory that is double clicked and created a valid path so that we can pass it to the displayfiles( ) function which will perform the job of displaying the contents of the directory. Note that we are starting only one UI thread. So the contents of directory will get displayed in the same thread. We could have also started another UI thread by calling AfxBeginThread( ) in the OnDblclkItem( ) function as we did in CMthread_netDlg::OnDblclk( ) function.
Don’t forget to change the myview constructor to public as we are accessing it in myframe class. You can now compile and run the program. You will see the list of connected computers in the list box. You can double click the computer name and see the output as given below:

Download source code User Interface Thread