修补了一些本站漏洞,谢谢热心网友的提醒。 这一次把整个BLOG也更新了一次。 采用了GUO’S BLOG修改而成。
VC/MFC FAQ整理
Q 如何处理ComboBox中的回车键?避免退出程序? A 在一般的EDIT中采用的方法是处理PretranlateMessage(),执行代码 CWnd *pWnd = GetFocus(); if(pWnd != NULL) { if(pWnd == GetDlgItem(IDC_EDIT1) { …//IDC_EDIT1具有焦点 } }
但在ComboBox中好象不同,是ComboBox的编辑控件得到了焦点,所以判断代码: BOOL CDlg::PreTranslateMessage(MSG pMsg) { if(pMsg->message==WM_KEYDOWN && pMsg->wParam == VK_RETURN) { CWnd pWnd = GetFocus(); if(pWnd != NULL) { if(pWnd->GetParent() == GetDlgItem(IDC_COMBO1)//更改ID { return TRUE; } } } return CDialog::PreTranslateMessage(pMsg); }
//————————————————- Q 动态创建的组合框如何设置下拉列表框的高度? A m_combo.Create(WS_CHILD | WS_VISIBLE | WS_VSCROLL CBC_SORT | CBC_DROPDOWNLIST | WS_TABSTOP, CRect(320,10,580,280),this,114); //CRect的最后一个参数(这里是280)就表示下拉大小
//————————————————- Q 是否能不选择下拉列表样式而禁止用户输入值,有什么方法可以实现? A 将下拉列表的编辑控件设置为只读的,方法如下: CComboBox pcombo; CWnd pWnd = pcombo->GetWindow(GW_CHILD); while(pWnd) { char classname[256]; ::GetClassName(pWnd->m_hWnd,classname,256) if(strcmp(classname,”edit”) == 0) { CEdit *pEdit; pEdit = new CEdit(); pEdit->SubClassWindow(pWnd->m_hWnd); pEdit->SetReadOnly(); pWnd = pWnd->GetNextWindow(); delete pEdit; } if(pWnd) pWnd = pWnd->GetNextWindow(); }
//————————————————- Q ComboBox的自定义弹出菜单,想在右击组合框的编辑部分的时候弹出菜单? A 一种方法就是在CCustomCombo的OnCtlColor函数里进行,生成ComboBox中编辑框的子类,示例: HBRUSH CCustomCombo::OnCtlColor(CDC pDC,CWnd pWnd,UINT nCtlColor) { if(nCtlColor == CTLCOLOR_EDIT) { if(m_edit.GetSafeHwnd()==NULL) m_eidt.SubClassWindow(pWnd->GetSafeHwnd()); } HBRUSH hbr = CComboBox::OnCtlColor(pDC,pWnd,nCtlColor); return hbr; } //其中m_edit是CEdit类的实现,它在WM_RBUTTONUP上显示右键菜单
//————————————————- Q 如何给按钮加位图 A 对动态创建的按钮: CButton button; button.Create(_T(“My Button”),WS_CHILD | WS_VISIBLE | BS_BITMAP,CRect(10,10,60,50),pParentWnd,1); button.SetBitmap(::LoadBitmap(NULL,MAKEINTRESOURCE(IBM_CHECK))); 或者修改风格: UINT Style = Button.GetButtonStyle(); Style = Style | BS_BITMAP; Button.SetBitmap(::LoadBitmap(NULL,MAKEINTRESOURCE(IBM_CHECK)));
//————————————————- Q 如何在CButton派生类中以及父对话框中捕获BN_CLICKED消息? A 于WM_NOTIFY消息相反,通知消息BN_CLICKED作为WM_COMMAND消息发送。因此应用程序应该使用ON_CONTROL_REFLECT_EC而不是ON_NOTIFY_REFLECT
//————————————————- Q 如何判断某个对象是否具有当前焦点? A return (CWnd::GetFocus() == pWnd);
//————————————————- Q 如何设置编辑控件的数字限制属性? A long Style = GetWindowLong(m_EditCtrl.m_hWnd,GWL_STYLE); Style |= ES_NUMBER; SetWindowLong(m_EditCtrl.m_hWnd,GWL_STYLE,Style);
//————————————————- Q 希望在LISTCTRL中显示文件,如何才能得到explorer使用的相同图象? A 可以将系统的ImageList加到LISTCTRL上,然后用具有SHGFI_ICON标志的SHGetFileInfo获取适当的图标索引: //图象列表设置 HIMAGELIST himagelist; SHFILEINFO fi; CImageList m_smalllist; //得到系统小图标列表的句柄 himagelist = (HIMAGELIST)SHGetFileInfo((LPCTSTR)_T(“C:\“),0,&fi;,sizeof(SHFILEINFO),SHGFI_SYSICONINDEX | SHGFI_SMALLICON); //添加到小图象列表 m_smalllist.Attach(himagelist); //设置LISTCTRL的图象列表 m_listCtrl.SetImageList(&m;_smalllist,LVSIL_SMALL); //分离图象列表 m_smalllist.Detach();
//————————————————- Q 如何在列表的任何一列显示图标,而不是第一列? A LV_ITEM item; … item.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_PARAM; item.iItem = …//设置行号 item.lParam = …//如何需要就设置lparam参数 item.iSubItem = …//设置列号,从0开始的 item.stateMask = LVIS_STATEIMAGEMASK; item.state = INDEXTOSTATEIMAGEMASK(…);//参数为图标号 item.iImage = …//设置图标号 item.pszText = …//显示文本 //插入新项 m_listctrl.InsertItem(&item;); //现在设置图标 m_listctrl.SetItemText(0,4,szField);
//————————————————- Q 给LISTBOX添加新项时如何实现自动下滚? A 在调用AddString后,添加如下代码: m_listbox.SetTopIndex(m_listbox.GetCount()-1);
//————————————————- Q listBox的文本超过框的宽度时,如何让水平滚动条正常工作? A 用下面的代码,设置滚动条的宽度为最长的字符串宽度 void SetHorizontalExtent(CListBox &listbox;) { int index = listbox.GetCount(); if(index == LB_ERROR) return; int nExtent = 0; if(index) { CDC pDC = listbox.GetDC(); CFont poldfont = pDC->SelectObject(listbox.GetFont()); CString s; SIZE text; LONG maxtxt = 0; whilw(index–) { listbox.GetText(index,s); text = pDC->GetOutputTextExtent(s); if(text.cx > maxtxt) maxtxt = text.cx; } text.cx = maxtxt; pDC->LPToDP(&text;); nExtent = text.cx+2; pDC->SelectObject(poldfont); listbox.ReleaseDC(pDC); } listbox.SetHorizontalExtent(nExtent); }
//————————————————- Q 在拆分视图的时候,创建了四个视图(2行2列),右下的是CFormView,其他的都是CView,在CMainFrame的OnCreateCilent不管怎么指定CRect的大小,下方的两个视图都占了整个窗口,需要拖动! A 一般只需要在OnCreateClient的末尾添加: m_wndSpitter.SetRowInfo(0,200,0);//添加此行代码
//————————————————- Q 如何指定拆分窗口的最小宽度? A 使用CSpitterWnd::SetColumnInfo() void SetColumnInfo(int col, //指定列 int deal, //理想宽度(像素) int cxmin); //最小宽度(像素) 在使用SetColumnInfo之后还应该调用RecalLayout();重新调整布局。
//————————————————– Q 如何判断工具栏是水平还是垂直的? A if((m_toolbar.GetBarStyle() & CBRS_ALIGN_LEFT) == CBRS_ALIGN_LEFT ||
(m_toolbar.GetBarStyle() & CBRS_ALIGN_RIGHT) == CBRS_ALIGN_RIGHT) AfxMessageBox(“vertical”); else AfxMessageBox(“horizontal”);
//————————————————– Q 编程方式修改工具栏按钮的可见性? A 示例代码: DWORD style = m_toolbar.GetButtonStyle(nIndex); if(m_bHide) m_toolbar.SetButtonStyle(nIndex,style & ~WS_VISIBLE); else m_toolbar.SetButtonStyle(nIndex,style | WS_VISIBLE); m_bHide = !m_bHide;
//————————————————– Q 如何在状态栏添加按钮并响应? A 创建一个从CButton派生的CMyButton类,在主框架类添加CMyButton类的成员变量,然后在OnCreate函数中创建按钮,并把它和状态栏关联起来: m_mybtn.Create(“MyButton”,WS_CHILD | VISIBLE,CRect(0,0,60,20),&m;_WndStatusBar,0); 通过处理BN_CLICKED消息,可以在CMyButton类中处理所有的点击事件
//————————————————– Q 如何隐藏属性CPropertySheet的标题栏,使用ModifyStyle(WINDOW_CAPTION,0)没有效果 A 创建自己的CPropertySheet派生类,并覆盖OnInitDialog,转到默认的情况后,使用ModifyStyle来删除WS_CAPTION标志
//————————————————– Q 如何让属性页有两行标签? A 从CPropertySheet派生类,添加PreCreateWindow的处理,在调用基类之前添加代码: cs.style |= TCS_MULTILINE;
//—————————————————— Q 如何在属性表的两个页之间传递数据? A CPropertyPage有一个成员函数QuerySiblings(WPARAM, LPARAM)。应用程序可以使用这个函数。 QuerySiblings生成一条PSM_QUERYSIBLINGS消息,它传递给所有的兄弟,也就是属性表上的其他属性页。 一般可创建一个所有页可见的枚举,如: enum{QUERY_MY_STRING, QUERY_SOMETHING_ELSE,…….} 然后,在一个属性页需要其他属性页中的信息时,使用代码: CString myString; if(lL == QuerySiblings(QUERY_MY_STRING,(LPARAM)&myString;)) { ….//获取字符串 } 提供字符串的页处理PSM_QUERYSIBLINGS消息: LRESULT CPageThatHasString::OnQuerySiblings(WPARAM wParam, LPARAM lParam) { if(QUERY_MY_STRING == wParam) { ((CString )lParam) = _T(“Test String“); return 1L; } else return 0L; }
//———————————————————- Q 如何让属性页具有两行标签? A 从CPropertySheet派生一个自己的类,添加一个PreCreateWindow的处理,然后在调用基类的处理前加如下代码:cs.style |= TCS_MULTILINE;
//———————————————————– Q 如何隐藏属性页的标题栏? A 从CPropertySheet派生一个自己的类,并覆盖OnInitDialog,在转到默认的情况以后,使用 ModifyStyle来删除标题栏标志WS_CAPTION。 ModifyStyle(WS_CAPTION,0);
//——————————————————————- Q 如何枚举桌面项目? A 1 得到指向IShellFolder接口的指针 2 得到指向IMalloc接口的指针 3 得到指向IEnumIDList接口的指针 4 提取枚举中下一项目的PIDL 5 测定PIDL代表的标志符的类型 6 处理该项目 7 释放PIDL分配的内存 8 重复4到7步,知道所有的项目都枚举完 9 释放IShellFolder IMalloc IEnumIDList接口的指针
LPSHELLFOLDER lpshellfolder; LPMALLOC lpmalloc; LPENUMIDLIST lpidlist; m_namecount = 0; HRESULT hr = SHGetDestopFolder(&lpshellfolder;); if(hr == NOERROR) { hr = ::SHGetMalloc(&lpmalloc;); if(hr == NOERROR) { hr = lpshellfolder->EnumObject(NULL,SHCONTF_FOLDERS | SHCONTF_NONFOLDERS,&lpidlist;); if(hr == NOERROR) ProcessFolder(lpshellfolder,lpmalloc,lpidlist);//custom deal function lpmalloc->Release(); lpidlist->Release(); InValidate(); } lpshellfolder->Release(); }
void *::ProcessFolder(LPSHELLFOLDER lpshellfolder,LPMALLOC lpmalloc,LPENUMIDLIST lpidlist) { STRRET strret; ULONG numfetch; LPITEMIDLIST lpitemlist; HRESULT hr = lpidlist->Next(1,&lpitemlist;,&numfetch;); while(hr == NOERROR) { ULONG attributes = SFGAO_FOLDER; lpshellfolder->GetAttributes(1,(const struct _ITEMIDLIST )&lpitemlist;,&attributes;); if(attributes & SFGAO_FOLDER) { hr = lpshellfolder->GetDiaplayNameOf(lpitemlist,SHGDN_NORMAL,&strret;); if(m_nameCount < 20) m_names[m_namecount++] = strret.str; } lpmalloc->Free(lpitemlist); hr = lpidlist->Next(1,&lpitemlist;,&numfetch;); } } //——————————————————————- Q 如何创建桌面快捷方式? A: 1 initialize com 2 create LShellLink Object 3 Use IShellLink interface to get the pointer about IPersistFile 4 Use IShellLink interface to initialize link 5 Use LPersistFile interface to save the link 6 Release all the com pointer 7 Com return to previous status
1 HRESULT hr = CoInitialize(NULL); if(hr == S_OK) { …//Continue }
2 IShellLink *pshelllink; pshelllink = CoCreateInstance(CLSID_ShellLink,NULL,CLSCTX_INPROC_SERVER,IID_IShellLink,(void **)&pshelllink;);
3 IPersistFile *persistfile; persistfile = pshelllink->QueryInterface(IID_IPersistFile,(void **)&persistfile;);
4 pshelllink->SetPath(“C:\config.sys”); pshelllink->SetDescription(“ShortCut to config.sys”);
5 char path[MAX_PATH]; GetWindowsDirectory(path,MAX_PATH); int len = strlen(path); strcpy(&path;[len],”\desktop\config.lik”); //change the char from ANSI to UNICODE OLECHAR widepath[MAX_PATH]; MultiByteToWideChar(CP_ACP,0,path,-1,widepath,MAX_PATH); persistfile->Save(widepath,TRUE);
6 pshelllink->Release(); psersistfile->Release();
7 CoUnInitialize();
VC中的一些常用方法(20条)
1 | //一、打开CD-ROM |
定制自己的EXE文件
主要是为了实现像木马那样的生成自己需要配置的EXE文件。首先要自己写一个EXE,然后以资源的方式导入到工程中。
下边的例子是一个修改MessageBox标题和文字的程序.
HRSRC hResInfo;
HGLOBAL hResData;
DWORD dwSize, dwWritten;
LPBYTE pBuffer;
HANDLE hFile;
TCHAR szMsgBoxTitle[100],szMsgBoxText[100];
szMsgBoxTitle[0] ='\0';
szMsgBoxText[0] = '\0';
得到新数据,比如新的邮箱地址和密码
GetDlgItemText(IDC_EDIT_TITLE,szMsgBoxTitle,100);
GetDlgItemText(IDC_EDIT_TEXT,szMsgBoxText,100);
// 查找所需的资源
hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_DUMMY_EXE), "Dummy_Exe");
if (hResInfo == NULL)
{
::MessageBox(NULL, "查找资源失败!", "错误", MB_OK | MB_ICONINFORMATION);
return;
}
// 获得资源尺寸
dwSize = SizeofResource(NULL, hResInfo);
// 装载资源
hResData = LoadResource(NULL, hResInfo);
if (hResData == NULL)
{
::MessageBox(NULL, "装载资源失败!", "错误", MB_OK | MB_ICONINFORMATION);
return;
}
// 为数据分配空间
pBuffer = (LPBYTE)GlobalAlloc(GPTR, dwSize);
if (pBuffer == NULL)
{
::MessageBox(NULL, "分配内存失败!", "错误", MB_OK | MB_ICONINFORMATION);
return;
}
// 复制资源数据
CopyMemory((LPVOID)pBuffer, (LPCVOID)LockResource(hResData), dwSize);
// 获取标题和文本,并复制数据,具体偏移地址见你的那个EXE资源
CopyMemory((LPVOID)(pBuffer + 0x400), (LPCVOID)szMsgBoxTitle, 100);
CopyMemory((LPVOID)(pBuffer + 0x464), (LPCVOID)szMsgBoxText, 100);
// 创建文件,写数据
hFile = CreateFile("C:\\EnochShen.Exe", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
if (hFile != NULL)
{
WriteFile(hFile, (LPCVOID)pBuffer, dwSize, &dwWritten;, NULL);
}
else
{
::MessageBox(NULL, "创建文件失败!", "错误", MB_OK | MB_ICONINFORMATION);
GlobalFree((HGLOBAL)pBuffer);
return;
}
// 收尾工作,释放资源
CloseHandle(hFile);
GlobalFree((HGLOBAL)pBuffer);
::MessageBox(NULL, "创建文件C:\\cooldog.Exe!", "成功" ,MB_OK | MB_ICONINFORMATION);
ShellExecute(m_hWnd, "open", "C:\\", NULL, NULL, SW_SHOWNORMAL);
下面是那个作为资源的EXE的源代码(MASM32写的):
; —————————————————————– ; 生成的exe只有1k,小巧玲珑,^O^ ; —————————————————————–
; #########################################################################
.386
.model flat, stdcall
option casemap :none ; case sensitive
; #########################################################################
include c:\masm32\include\windows.inc
include c:\masm32\include\user32.inc
include c:\masm32\include\kernel32.inc
includelib c:\masm32\lib\user32.lib
includelib c:\masm32\lib\kernel32.lib
; #########################################################################
.data
szMsgBoxTitle db 100 dup('E')
szMsgBoxText db 100 dup('S')
.code
start: ; —————————————————————– ; 下面的代码生成的Exe只有1k,但是打包会出错 ; ; szMsgBoxTitle db 100 dup(‘E’) ; szMsgBoxText db 100 dup(‘S’) ; ; —————————————————————–
invoke MessageBox,NULL,ADDR szMsgBoxText,ADDR szMsgBoxTitle,MB_OK or MB_ICONINFORMATION
invoke ExitProcess,NULL
end start
参考自CSDN开发高手第N期(具体哪一期我忘了)
VC下用ADO调用存储过程例程
_ConnectionPtr m_pConnection; _CommandPtr m_pCommand; .cpp中在函数中执行 //建立ado连接 HRESULT hr; hr=m_pConnection.CreateInstance(__uuidof(Connection)); try { if(SUCCEEDED(hr)) { hr=m_pConnection->Open(_bstr_t(L”Provider=SQLOLEDB.1;Persist Security Info=False;User ID=sa;Initial Catalog=Viper;Data Source=Viper”),_bstr_t (L”sa”),_bstr_t (L””),adModeUnknown); } } catch(_com_error & err) { AfxMessageBox(err.Description(),MB_OK,0); AfxMessageBox(err.ErrorMessage(),MB_OK,0); AfxMessageBox(“无法连接SQL SERVER 服务器,程序将退出。请检查网络设备”,MB_OK,0); exit(0); }
//执行储存过程 CString cvar1,cvar2; int cvar3; cvar1=”ddd”; cvar2=””; cvar3=0; try { m_pCommand.CreateInstance(__uuidof(Command)); m_pCommand->ActiveConnection=app->m_pConnection; m_pCommand->CommandType=adCmdStoredProc; m_pCommand->CommandText=_bstr_t(“pr_zs_dzdy”);
_variant_t vvar1,vvar2,vvar3; vvar1=_variant_t(_bstr_t(cvar1)); vvar2=_variant_t(_bstr_t(cvar2)); vvar3=_variant_t(cvar3); _ParameterPtr mp_var1,mp_var2,mp_var3; mp_var1.CreateInstance(uuidof(Parameter)); mp_var2.CreateInstance(uuidof(Parameter)); mp_var3.CreateInstance(__uuidof(Parameter));
mp_var1=m_pCommand->CreateParameter ( _bstr_t(“var1”), adVarChar, adParamInput, 3, vvar1 ); m_pCommand->Parameters->Append(mp_var1);
mp_var2=m_pCommand->CreateParameter ( _bstr_t(“var2”), adVarChar, adParamOutput, 3, vvar2 ); m_pCommand->Parameters->Append(mp_var2);
mp_var3=m_pCommand->CreateParameter ( _bstr_t(“var3”), adIntger, adParamOutput, 9, vvar3 ); m_pCommand->Parameters->Append(mp_var3);
_variant_t vNull; vNull.vt=VT_ERROR; vNull.scode=DISP_E_PARAMNOTFOUND; m_pCommand->Execute(&vNull;,&vNull;,adCmdStoredProc); cvar2=mp_var2->Value.bstrVal; cvar3=mp_var3->Value; } catch(_com_error &error;) { MessageBox(error.ErrorMessage(),”ADO错误!”); MessageBox(error.Description(),”ADO错误!”); }
酒店管理系统V1.0
酒店管理系统V1.0 这是我个人完成的一个酒店管理系统模型,拥有客户预订,客户登记,空房查询,服务消费记录和客户结帐,房间管理等多种功能。采用VC++6.0和SQL SERVER开发,大部分业务逻辑采用存储过程实现提高了数据存储的可靠性和速度。 程序界面预览:(点击查看全图) 客户预订界面
客户登记界面
空房查询界面
VC中ADO连接字符串收集
1.ACCESS 2000
_ConnectionPtr m_pConn;
CString m_sConn="Provider=Microsoft.Jet.OLEDB.4.0.1;Data Source=d:\\db1.mdb";
m_pConn.CreateInstance("ADODB.Connection");
try
{
HRESULT hr=m_pConn->Open((_bstr_t)m_sConn,"","",adConnectUnspecified);
if (FAILED(hr))
{
AfxMessageBox("不能连接数据库 source!");
return FALSE;
}
}
catch(_com_error e)
{
AfxMessageBox("不能连接数据库 error!");
return FALSE;
}
2.SQL Server 2000
_ConnectionPtr m_pConn;
CString m_sConn="Provider=SQLOLEDB.1;Data Source=192.168.3.9;Initial
Catalog=sode”; //sode是数据库服务器192.168.3.9上的一个数据库 m_pConn.CreateInstance(“ADODB.Connection”); try { HRESULT hr=m_pConn->Open((_bstr_t)m_sConn,”sa”,”mapper”,adConnectUnspecified); if (FAILED(hr)) { AfxMessageBox(“不能连接数据库 source!”); return FALSE; } } catch(_com_error e) { AfxMessageBox(“不能连接数据库 error!”); return FALSE; }
3.Oracle 9i
_ConnectionPtr m_pConn;
CString m_sConn="Provider=MSDAORA.1;Data Source=sode_192.168.3.9"; //使用
ms连接库,sode为SID,192.168.3.9为机器ip m_pConn.CreateInstance(“ADODB.Connection”); try { HRESULT hr=m_pConn->Open((_bstr_t)m_sConn,”sodeUser”,”sodePw”,adConnectUnspecified); if (FAILED(hr)) { AfxMessageBox(“不能连接数据库 source!”); return FALSE; } } catch(_com_error e) { AfxMessageBox(“不能打开数据库 error!”); return FALSE; }
改变对话框的背景色
方法一:调用CWinApp类的成员函数SetDialogBkColor来实现。 —- 其中函数的第一个参数指定了背景颜色,第二个参数指定了文本颜色。下面的例子是将应用程序对
话框设置为蓝色背景和红色文本,步骤如下: —- ① 新建一个基于Dialog的MFC AppWizard应用程序ExampleDlg。 —- ② 在CExampleDlgApp ::InitInstance()中添加如下代码: BOOL CExampleDlgApp: : InitInstance ( ) { … CExampleDlgDlg dlg; m_pMainWnd = &dlg; //先于DoModal()调用,将对话框设置为蓝色背景、红色文本 SetDialogBkColor(RGB(0,0,255),RGB(255,0,0)); int nResponse = dlg.DoModal(); …} —- 编译并运行,此时对话框的背景色和文本色已发生了改变。值得注意的是:在调用DoModal()之前必
须先调用SetDialogBkColor,且此方法是将改变应用程序中所有的对话框颜色,并不能针对某一个指定的
对话框。 —- 方法二:重载OnPaint(),即WM_PAINT消息。有关代码如下(以上例工程为准): void CExampleDlgDlg::OnPaint() { if (IsIconic()) … else { CRect rect; CPaintDC dc(this); GetClientRect(rect); dc.FillSolidRect(rect,RGB(0,255,0)); //设置为绿色背景 CDialog::OnPaint(); } —- 方法三:重载OnCtlColor (CDC pDC, CWnd pWnd, UINT nCtlColor),即WM_CTLCOLOR消息。具体
步骤如下(以上例工程为准): —- ①在CExampleDlgDlg的头文件中,添加一CBrush的成员变量: class CExampleDlgDlg : public CDialog {… protected: CBrush m_brush; … }; —- ②在OnInitDialog()函数中添加如下代码: BOOL CExampleDlgDlg::OnInitDialog() { … // TODO: Add extra initialization here m_brush.CreateSolidBrush(RGB(0, 255, 0)); // 生成一绿色刷子 … } —- ③利用ClassWizard重载OnCtlColor(…),即WM_CTLCOLOR消息: HBRUSH CExampleDlgDlg::OnCtlColor (CDC pDC, CWnd pWnd, UINT nCtlColor) { / 这里不必编写任何代码! 下行代码要注释掉 ** HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor); / return m_brush; //返加绿色刷子 } —- 方法四:还是重载OnCtlColor (CDC pDC, CWnd pWnd, UINT nCtlColor),即WM_CTLCOLOR消息。
具体步骤如下(以上例工程为准): —- 步骤①、②同上方法三中的步骤①、②。 —- 步骤③利用ClassWizard重载OnCtlColor(…)(即WM_CTLCOLOR消息)时则有些不同: HBRUSH CExampleDlgDlg::OnCtlColor (CDC pDC, CWnd pWnd, UINT nCtlColor) { HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor); //在这加一条是否为对话框的判断语句 if(nCtlColor ==CTLCOLOR_DLG) return m_brush; //返加绿色刷子 return hbr; }
删除、拷贝、移动文件夹及其文件
删除:
void COperationDlg::OnDel2(CString m_strFileDictory) //参数就是目录的路径 { if(m_strFileDictory.GetLength()==0) { ::AfxMessageBox (“目录名非法!”,MB_OK|MB_ICONEXCLAMATION); return; } char FromFileName[80]=”\0”; strcpy(FromFileName,m_strFileDictory); strcat(FromFileName,”\0”); SHFILEOPSTRUCT lpFileOp; lpFileOp.hwnd =GetSafeHwnd(); lpFileOp.wFunc =FO_DELETE; lpFileOp.pFrom =FromFileName; lpFileOp.pTo=NULL; lpFileOp.fFlags =FOF_SILENT|FOF_NOCONFIRMATION; lpFileOp.fAnyOperationsAborted =FALSE; lpFileOp.hNameMappings =NULL; lpFileOp.lpszProgressTitle =NULL; int rval=SHFileOperation(&lpFileOp;); if(rval==0) { if(lpFileOp.fAnyOperationsAborted ==TRUE) ::AfxMessageBox (“删除目录操作取消”,MB_OK); else ::AfxMessageBox(“删除目录操作成功!”,MB_OK|MB_ICONEXCLAMATION); } else { ::AfxMessageBox (“删除目录操作失败!”,MB_OK|MB_ICONEXCLAMATION); } }
拷贝 BOOL CCutfoldDlg::CopyDirectory(CString SourcePath,CString CopytoPath) { CFileFind tempFind; char tempFileFind[200]; char tempFileFind1[200];
SECURITY_ATTRIBUTES lpSecurityDescriptor;
CreateDirectory(CopytoPath,&lpSecurityDescriptor;);
/ { if(::MessageBox(0,”文件已经存在,是否覆盖?”,”警告”,MB_ICONQUESTION|MB_YESNO)==IDNO) return FALSE; } / sprintf(tempFileFind1,”%s\.“,CopytoPath); sprintf(tempFileFind,”%s\.“,SourcePath);
BOOL IsFinded=(BOOL)tempFind.FindFile(tempFileFind);
// BOOL IsFinded1=(BOOL)tempFind.FindFile(tempFileFind1); while(IsFinded) { IsFinded=(BOOL)tempFind.FindNextFile(); if(!tempFind.IsDots()) { char foundFileName[200]; // char foundFileName1[200]; strcpy(foundFileName,tempFind.GetFileName().GetBuffer(200)); // strcpy(foundFileName1,tempFind.GetFileName().GetBuffer(200)); if(tempFind.IsDirectory()) { char tempDir[200]; char tempDir1[200]; sprintf(tempDir,”%s\%s”,SourcePath,foundFileName); sprintf(tempDir1,”%s\%s”,CopytoPath,foundFileName); CopyDirectory(tempDir,tempDir1); } else { char tempFileName[200]; char tempFileName1[200]; sprintf(tempFileName,”%s\%s”,SourcePath,foundFileName); sprintf(tempFileName1,”%s\%s”,CopytoPath,foundFileName); //DeleteFile(tempFileName); CopyFile(tempFileName,tempFileName1,0); } } } tempFind.Close(); return TRUE; }
要实现移动,遍历文件+MoveFile+CreateDirectory 遍历方法参考: HANDLE hFind; WIN32_FIND_DATA dataFind; BOOL bMoreFiles=TRUE; hFind=FindFirstFile(sPath+”\*.txt”,&dataFind;);////sPath表示路径 while(hFind!=INVALID_HANDLE_VALUE && bMoreFiles==TRUE) { if(dataFind.dwFileAttributes==FILE_ATTRIBUTE_ARCHIVE) { MessageBox(dataFind.cFileName); } bMoreFiles=FindNextFile(hFind,&dataFind;); } FindClose(hFind);
模拟按键
模拟键盘我们用Keybd_event这个api函数,模拟鼠标按键用mouse_event函数。在VC里调用api函数是既简单又方便不过的事了。 首先介绍一下Keybd_event函数。Keybd_event能触发一个按键事件,也就是说回产生一个WM_KEYDOWN或WM_KEYUP消息。当然也可以用产生这两个消息来模拟按键,但是没有直接用这个函数方便。Keybd_event共有四个参数,第一个为按键的虚拟键值,如回车键为vk_return, tab键为vk_tab。第二个参数为扫描码,一般不用设置,用0代替就行第三个参数为选项标志,如果为keydown则置0即可,如果为keyup则设成“KEYEVENTF_KEYUP”,第四个参数一般也是置0即可。用如下代码即可实现模拟按下键,其中的XX表示XX键的虚拟键值,在这里也就是各键对应的键码,如’A’=65 keybd_event(65,0,0,0); keybd_event(65,0,KEYEVENTF_KEYUP,0); …
堆和栈的区别
在bbs上,堆与栈的区分问题,似乎是一个永恒的话题,由此可见,初学者对此往往是混淆不清的,所以我决定拿他第一个开刀。 首先,我们举一个例子:
1 | void f() { int* p=new int[5]; } |
这条短短的一句话就包含了堆与栈,看到new,我们首先就应该想到,我们分配了一块堆内存,那么指针p呢?他分配的是一块栈内存,所以这句话的意思就是:在栈内存中存放了一个指向一块堆内存的指针p。在程序会先确定在堆中分配内存的大小,然后调用operator new分配内存,然后返回这块内存的首地址,放入栈中,他在VC6下的汇编代码如下:
1
2
3
4
5
6
00401028 push 14h
0040102A call operator new (00401060)
0040102F add esp,4
00401032 mov dword ptr [ebp-8],eax
00401035 mov eax,dword ptr [ebp-8]
00401038 mov dword ptr [ebp-4],eax
这里,我们为了简单并没有释放内存,那么该怎么去释放呢?是delete p么?澳,错了,应该是```delete []p```,这是为了告诉编译器:我删除的是一个数组,VC6就会根据相应的Cookie信息去进行释放内存的工作。
好了,我们回到我们的主题:堆和栈究竟有什么区别?
主要的区别由以下几点:
1、管理方式不同;
2、空间大小不同;
3、能否产生碎片不同;
4、生长方向不同;
5、分配方式不同;
6、分配效率不同;
管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生memory leak。
空间大小:一般来讲在32位系统下,堆内存可以达到4G的空间,从这个角度来看堆内存几乎是没有什么限制的。但是对于栈来讲,一般都是有一定的空间大小的,例如,在VC6下面,默认的栈空间大小是1M(好像是,记不清楚了)。当然,我们可以修改:
打开工程,依次操作菜单如下:Project->Setting->Link,在Category 中选中Output,然后在Reserve中设定堆栈的最大值和commit。
注意:reserve最小值为4Byte;commit是保留在虚拟内存的页文件里面,它设置的较大会使栈开辟较大的值,可能增加内存的开销和启动时间。 碎片问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出,在他弹出之前,在他上面的后进的栈内容已经被弹出,详细的可以参考数据结构,这里我们就不再一一讨论了。 生长方向:对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;对于栈来讲,它的生长方向是向下的,是向着内存地址减小的方向增长。 分配方式:堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。 分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多。 从这里我们可以看到,堆和栈相比,由于大量new/delete的使用,容易造成大量的内存碎片;由于没有专门的系统支持,效率很低;由于可能引发用户态和核心态的切换,内存的申请,代价变得更加昂贵。所以栈在程序中是应用最广泛的,就算是函数的调用也利用栈去完成,函数调用过程中的参数,返回地址,EBP和局部变量都采用栈的方式存放。所以,我们推荐大家尽量用栈,而不是用堆。 虽然栈有如此众多的好处,但是由于和堆相比不是那么灵活,有时候分配大量的内存空间,还是用堆好一些。 无论是堆还是栈,都要防止越界现象的发生(除非你是故意使其越界),因为越界的结果要么是程序崩溃,要么是摧毁程序的堆、栈结构,产生以想不到的结果,就算是在你的程序运行过程中,没有发生上面的问题,你还是要小心,说不定什么时候就崩掉,那时候debug可是相当困难的:) 对了,还有一件事,如果有人把堆栈合起来说,那它的意思是栈,可不是堆,呵呵,清楚了?
获取CPU序列号
//取得IntelCPU的ID号:
void IntelCPUIDDlg::OnButtonCPUID() { unsigned long s1,s2; unsigned char vendor_id[]=”——————“; CString str1,str2,str3; asm { xor eax,eax cpuid mov dword ptr vendor_id,ebx mov dword ptr vendor_id[+4],edx mov dword ptr vendor_id[+8],ecx } str1.Format(“%s”,vendor_id); asm //取得CPU ID的高32位 { mov eax,01h xor edx,edx cpuid mov s2,eax } str2.Format(“%08X-“,s2);
__asm //取得CPU ID的低64位 { mov eax,03h xor ecx,ecx xor edx,edx cpuid mov s1,edx mov s2,ecx }
str3.Format(“%08X-%08X\n”,s1,s2); str2+=str3; m_editVendor.SetWindowText(str1); m_editCPUID.SetWindowText(str2); }