In the last installment, we began the examination of a desktop MFC application that scans a remote device, inventorying the databases it finds there. Now, we continue our exploration of this example, RemoteDBScan.
Initialization
When the RemoteDBScan application opens, it displays a control populated with a list of remote databases and their attributes. We build and initialize the list control in the OnInitialUpdate() member of the CRemoteDBScanView class. Building a list view is a two-step process. First, we add columns to the list control, and after that we can add individual rows, one item at a time.
Before we begin to build the list control, we do the base class initialization, calling CListViewEx:: OnInitialUpdate(). Next, we test the CRemoteDBScanView member variable m_bColumnsExist to see whether columns have already been added to the control (m_bColumnsExist is set to FALSE in the constructor for the class). If there are columns already, we bail out of the initialization. Otherwise, we set this member to TRUE and procede.
void CRemoteDBScanView::OnInitialUpdate() { CListViewEx::OnInitialUpdate(); // TODO: You may populate your ListView with items by directly // accessing its list control through a call to GetListCtrl(). CListViewEx::OnInitialUpdate(); if( m_bColumnsExist ) { return; } else { m_bColumnsExist = TRUE; }
Now, we add seven columns to the list control. To add columns, first we get a reference to the list control associated with the view.
// insert columns CListCtrl& ListCtrl = GetListCtrl();
We define the attributes of individual columns by initializing an LV_COLUMN structure. Here’s the typedef for LV_COLUMN:
typedef struct _LVCOLUMN { UINT mask; //mask flags define which members are valid int fmt; //flag for column heading alignment int cx; //column width in pixels LPTSTR pszText; //column heading int cchTextMax; //length of heading buffer int iSubItem; //this column's sub item index int iImage; //image list index for column icon int iOrder; //0 based column index } LVCOLUMN;
The LV_ COLUMN structure is used both to set and retrieve information about a column. The mask member defines which members of the structure are to be considered valid, and has these possible values:
Table 1: LV_COLUMN Mask Flag Constants and Their Meanings
Mask Flag Constant | Meaning |
LVCF_FMT | fmt is valid or should be returned |
LVCF_IMAGE | iImage is valid or should be returned |
LVCF_ORDER | iOrder is valid or should be returned |
LVCF_SUBITEM | iSubItem is valid or should be returned |
LVCF_TEXT | pPszText is valid or should be returned |
LVCF_WIDTH | cx is valid or should be returned |
The mask flags may be combined with logical OR, so that you can set or retrieve as many or few LV_COLUMN members as you like.
The fmt member controls the column heading alignment and the placement of an optional image next to the heading. The heading of the leftmost column must be left aligned. You can use one of heading styles shown in the table below:
Table 2: LV_COLUMN Heading Style Flags and Their Meanings
Heading Format Flag | Meaning |
LVCFMT_CENTER | Center heading text |
LVCFMT_LEFT | Left align heading text |
LVCFMT_RIGHT | Right align heading text |
Now, we declare and initialize an LV_COLUMN structure. We set the mask for members fmt, cx, pszText an iSubItem members. We get the dimensions of the client area, and use this to set the column width. Looping through the string resources, we load the caption string for each column and also use the loop index to set the value of iSubItem. We set each column heading format to left alignment, and insert the column with a call to ListCtrl.InsertColumn().
int i; LV_COLUMN lvc; lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; CRect rectClient; this->GetClientRect( &rectClient ); for(i = IDS_DATABASE_NAME; i<= IDS_DATABASE_CEOID; i++) { CString str; str.LoadString(i); lvc.iSubItem = i - IDS_DATABASE_NAME; lvc.pszText = (LPSTR)(LPCTSTR)str; lvc.cx = rectClient.right / (IDS_DATABASE_CEOID - IDS_DATABASE_NAME); lvc.fmt = LVCFMT_LEFT; ListCtrl.InsertColumn(i,&lvc); }
Once we have columns in the list control, we are ready to add rows containing the remote database attributes. The first step is a familiar one—we initialize RAPI with a call to CeRapiInit().
HRESULT hr = CeRapiInit(); if( hr != ERROR_SUCCESS ) {return ;}
If we are successful, we’ll begin our search for remote databases.