环 境: Windows NT Server 4.0 VC++5.0
pdh.dll (Win32 SDK 4)Demo例程pdh目录中带有该动态链接库,将这个文件放在VC的bin 目录中。
如果在VC+6.0中使用,则要将pdh目录中的pdh.dll、pdh.h、pdh.lib ,分别放在VC 的bin、include和lib目录中,重新编译、链接。
使用方法:
先在Meters菜单中选择监控面板,与所要连接的机器建立连接(本地或网络),如下图示。然后在Timer菜单中选择Start,就可以进行监视了。
如何实现图像列表
在利用VC开发应用程序时,通常会用到列表控件,它的使用是相当容易的,但对于用户来说,在列表上查看信息时形式比较简单,特别是一些数据库应用,需要在查看记录的同时,显示出相应的图像信息,对于这一点常用的列表控件就无能为力了。
如果需要在应用中设置更为直观的列表,特别是在列表中以一定规律显示图象,可以为列表控件增加相应的属性和操作来完成。这里介绍一个实现图像列表控件的方法.
1图像列表控件的定义
以列表控件为基类,我们可以如下定义图像列表控件:
class CImageListBox : public CListBox
{
DECLARE_DYNAMIC(CImageListBox)
// Constructors
public:
CImageListBox();
BOOL Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID);
// Attributes
CImageList* SetImageList(CImageList* pImageList);
CImageList* GetImageList();
int AddItem(int nImageIndex, DWORD dwItemData = 0);
// Overridables
virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);
// Implementation
protected:
void PreDrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
void PreMeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);
int PreCompareItem(LPCOMPAREITEMSTRUCT lpCompareItemStruct);
void PreDeleteItem(LPDELETEITEMSTRUCT lpDeleteItemStruct);
virtual BOOL OnChildNotify(UINT, WPARAM, LPARAM, LRESULT*);
#ifdef _DEBUG
virtual void PreSubclassWindow();
#endif
int CalcMinimumItemHeight();
CImageList* m_pImageList;
CSize m_bmSize;
// Message map functions
protected:
//{{AFX_MSG(CImageListBox)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg LRESULT OnSetFont(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnLBAddString(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnLBFindString(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnLBFindStringExact(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnLBGetItemData(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnLBGetText(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnLBInsertString(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnLBSelectString(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnLBSetItemData(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnLBSetItemHeight(WPARAM wParam, LPARAM lParam);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
2 消息响应函数的实现
在以上的定义中可以看到,较之列表控件而言,在图像列表控件中定义了一组消息响应函数,下面介绍两个主要的消息响应函数的实现方法。
l OnLBGetItemData
OnLBGetItemData的作用是获得当前项的数据内容,实现时需要调用系统的DefWindowProc(LB_GETITEMDATA, wParam, lParam)方法,若返回结果不会出现错误,则进入具体的取数据阶段,这里有一个很重要的结构ILB_IMAGE_DATA,即图像数据内容,结构定义为:
struct ILB_IMAGE_DATA
{
public:
int m_nImage;
DWORD m_dwUserData;
ILB_IMAGE_DATA()
{
m_nImage = -1;
m_dwUserData = 0;
};
};
将系统调用的结果数据强制为ILB_IMAGE_DATA类型,由于有关项的实际数据就是在ILB_IMAGE_DATA结构中的m_dwUserData属性中保存,其初始值定为0,因此再将结构中的m_dwUserData域内容返回即可。
具体实现为:
LRESULT CImageListBox::OnLBGetItemData(WPARAM wParam, LPARAM lParam)
{
LRESULT lResult = DefWindowProc(LB_GETITEMDATA, wParam, lParam);
if (lResult != LB_ERR)
{
ILB_IMAGE_DATA* pState = (ILB_IMAGE_DATA*)lResult;
if (pState == NULL)
return 0; // default
lResult = pState->m_dwUserData;
}
return lResult;
}
l OnLBSetItemData
与获取项数据对应,OnLBSetItemData完成项图像数据的设置,与获取事件不同的是,如果由系统调用返回的数据内容为空,需要申请一个ILB_IMAGE_DATA结点空间,并且设置其数据域内容m_dwUserData为参数lParam的值,再调用DefWindowProc,并置消息类型为LB_SETITEMDATA,lParam参数设置为pState,注意这里需要对pState进行类型强制。具体实现为:
LRESULT CImageListBox::OnLBSetItemData(WPARAM wParam, LPARAM lParam)
{
LRESULT lResult = DefWindowProc(LB_GETITEMDATA, wParam, 0);
if (lResult != LB_ERR)
{
ILB_IMAGE_DATA* pState = (ILB_IMAGE_DATA*)lResult;
if (pState == NULL)
pState = new ILB_IMAGE_DATA;
pState->m_dwUserData = lParam;
lResult = DefWindowProc(LB_SETITEMDATA, wParam, (LPARAM)pState);
if (lResult == LB_ERR)
delete pState;
}
return lResult;
}
3 成员函数的实现
在图像列表控件中还定义了一组成员函数,正是对这些成员函数的实现可以完成列表控件功能的扩充。下面介绍几个重要的成员函数的实现方法。
l AddItem
AddItem的作用是在图像列表控件中增加一项,具体项的图像和数据内容由参数nImageIndex和dwItemData确定,其中nImageIndex为与控件对应的图像列表中的元素下标,dwItemData为新增项的数据内容。实现时首先需要判断现有的图像个数是否超出范围,再调用DefWindowProc,发出 LB_ADDSTRING消息,若响应结果没有异常的话,申请一个图像数据结占空间,并置图像域内容m_nImage为参数nImageIndex的值,实际上它反映了该图像项所对应的索引值,另外置数据域内容m_dwUserData为dwItemData,同样需要发出LB_SETITEMDATA消息,由系统调用完成图像项的增加。具体实现如下:
int CImageListBox::AddItem(int nImageIndex, DWORD dwItemData)
{
ASSERT(m_pImageList != NULL);
if (m_pImageList->GetImageCount() < nImageIndex)
return LB_ERR;
char szText[] = "";
WPARAM wParam = 0;
LRESULT lResult = DefWindowProc(LB_ADDSTRING, wParam, (LPARAM)szText);
if (lResult == LB_ERR || lResult == LB_ERRSPACE)
return lResult;
ILB_IMAGE_DATA* pState = NULL;
pState = new ILB_IMAGE_DATA;
pState->m_nImage = nImageIndex;
pState->m_dwUserData = dwItemData;
wParam = (WPARAM)lResult;
LRESULT lRes = DefWindowProc(LB_SETITEMDATA, wParam, (LPARAM)pState);
if (lRes == LB_ERR && pState != NULL)
delete pState;
return lResult;
}
l PreDrawItem
PreDrawItem完成图像项的绘制工作,这里有一个重要的参数lpDrawItemStruct,它是一个LPDRAWITEMSTRUCT类型的结构,首先需要将此结构内容复制到drawItem变量中,这是函数的工作变量。在项索引合理的情况下,利用一系列的图形设备操作完成项的绘制,特别要注意这里的图像大小的设置。具体实现如下:
void CImageListBox::PreDrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
DRAWITEMSTRUCT drawItem;
memcpy(&drawItem, lpDrawItemStruct, sizeof(DRAWITEMSTRUCT));
if ((((LONG)drawItem.itemID) >= 0) &&
((drawItem.itemAction & (ODA_DRAWENTIRE | ODA_SELECT)) != 0))
{
int cyItem = GetItemHeight(drawItem.itemID);
CDC* pDC = CDC::FromHandle(drawItem.hDC);
COLORREF newBkColor = GetSysColor(COLOR_WINDOW);
BOOL fDisabled = !IsWindowEnabled();
if ((drawItem.itemState & ODS_SELECTED) && !fDisabled)
newBkColor = GetSysColor(COLOR_HIGHLIGHT);
COLORREF oldBkColor = pDC->SetBkColor(newBkColor);
CDC bitmapDC;
if (bitmapDC.CreateCompatibleDC(pDC))
{
ILB_IMAGE_DATA*pState=(ILB_IMAGE_DATA*)lpDrawItemStruct->itemData;
CRect rectImage = drawItem.rcItem;
RectImage.left += 1 + max(0, (rectImage.right - m_bmSize.cx) / 2);
rectImage.top += 1 + max(0, (cyItem - m_bmSize.cy) / 2);
rectImage.right = rectImage.left + m_bmSize.cx;
rectImage.bottom = rectImage.top + m_bmSize.cy;
CBrush brush(newBkColor);
pDC->FillRect(&(drawItem.rcItem), &brush);
POINT pt;
pt.x = rectImage.left;
pt.y = rectImage.top;
m_pImageList->Draw(pDC, pState->m_nImage, pt, ILD_NORMAL);
}
pDC->SetBkColor(oldBkColor);
}
if ((drawItem.itemAction & ODA_FOCUS) != 0)
{
CDC* pDC = CDC::FromHandle(drawItem.hDC);
pDC->DrawFocusRect(&(drawItem.rcItem));
}
}
l PreDeleteItem
与一般的列表项相比,图像项的删除需要更多的操作完成,首先将待删除的图像项内容作为参数交给PreDeleteItem处理,此内容将复制到工作变量deleteItem中,这里需要区别两种情况,首先如果其数据内容itemData返回为0,则调用DefWindowProc发出LB_GETITEMDATA消息,并将左右参数设置为deleteItem.itemID和0,由系统调用的处理完成删除工作;或itemData域内容不为0,则取出具体数据内容,强制化为ILB_IMAGE_DATA类型,并将其m_dwUserData域的内容赋予工作变量的itemData域,这样就可以调用其父类的删除项操作完成工作了。具体实现如下:
void CImageListBox::PreDeleteItem(LPDELETEITEMSTRUCT lpDeleteItemStruct)
{
DELETEITEMSTRUCT deleteItem;
memcpy(&deleteItem, lpDeleteItemStruct, sizeof(DELETEITEMSTRUCT));
if (deleteItem.itemData == 0)
{
LRESULT lResult = DefWindowProc(LB_GETITEMDATA, deleteItem.itemID, 0);
if (lResult != LB_ERR)
deleteItem.itemData = (UINT)lResult;
}
if (deleteItem.itemData != 0)
{
ILB_IMAGE_DATA* pState = (ILB_IMAGE_DATA*)deleteItem.itemData;
deleteItem.itemData = pState->m_dwUserData;
delete pState;
}
DeleteItem(&deleteItem);
}
4 图像列表控件的使用
在主对话框的定义中需要增加以下代码:
//{{AFX_DATA(CDemoDlg)
enum { IDD = IDD_DEMO_DIALOG };
CImageListBox m_lstDemo;
//}}AFX_DATA
m_lstDemo即为对应列表框控件的成员变量,其类型不是CListBox 而是CImageListBox,表明可以由m_lstDemo表示图像列表控件的内容。
如若生成以下的图像列表:
需要在对话框的初始化函数OnInitDialog中只要增加如下代码:
m_ImageList.Create(IDB_BITMAP, 40, 0, RGB(255, 255, 255));
//创建图像列表
m_lstDemo.SetImageList(&m_ImageList); //设置图像列表属性
for (int i=0; i<7; i++) //增加图像列表项
m_lstDemo.AddItem(i);
可见,图像列表控件的初始化主要是各图像项的加入,图像列表控件要与图像列表对应起来,即图像列表中元素的下标即对应到图像列表控件的项索引。
另外,需要说明的是,为了在列表框控件中显示图像,需要增加相应的位图资源。
|