iTimothy

君看一叶舟,出没风波里


  • 首页

  • 分类

  • 归档

  • 项目

  • 关于

VC/MFC FAQ整理

发表于 2005-01-13 | 分类于 技术控 | | 阅读次数:
字数统计: 2k 字 | 阅读时长 ≈ 8 分钟

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条)

发表于 2005-01-13 | 分类于 技术控 | | 阅读次数:
字数统计: 1.9k 字 | 阅读时长 ≈ 9 分钟
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
//一、打开CD-ROM

mciSendString("Set cdAudio door open wait",NULL,0,NULL);

//二、关闭CD_ROM

mciSendString("Set cdAudio door closed wait",NULL,0,NULL);

//三、关闭计算机

OSVERSIONINFO OsVersionInfo; //包含操作系统版本信息的数据结构
OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&OsVersionInfo;); //获取操作系统版本信息
if(OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
{
//Windows98,调用ExitWindowsEx()函数重新启动计算机
DWORD dwReserved;
ExitWindowsEx(EWX_REBOOT,dwReserved); //可以改变第一个参数,实现注销用户、
//关机、关闭电源等操作
// 退出前的一些处理程序
}

//四、重启计算机


typedef int (CALLBACK *SHUTDOWNDLG)(int); //显示关机对话框函数的指针
HINSTANCE hInst = LoadLibrary("shell32.dll"); //装入shell32.dll
SHUTDOWNDLG ShutDownDialog; //指向shell32.dll库中显示关机对话框函数的指针
if(hInst != NULL)
{
//获得函数的地址并调用之
ShutDownDialog = (SHUTDOWNDLG)GetProcAddress(hInst,(LPSTR)60);

(*ShutDownDialog)(0);
}


//五、枚举所有字体


LOGFONT lf;
lf.lfCharSet = DEFAULT_CHARSET; // Initialize the LOGFONT structure
strcpy(lf.lfFaceName,"");
CClientDC dc (this);
// Enumerate the font families
::EnumFontFamiliesEx((HDC) dc,&lf;, (FONTENUMPROC) EnumFontFamProc,(LPARAM) this,0);
//枚举函数
int CALLBACK EnumFontFamProc(LPENUMLOGFONT lpelf,
LPNEWTEXTMETRIC lpntm,DWORD nFontType,long lparam)

{
// Create a pointer to the dialog window
CDay7Dlg* pWnd = (CDay7Dlg*) lparam;
// add the font name to the list box
pWnd ->m_ctlFontList.AddString(lpelf ->elfLogFont.lfFaceName);
// Return 1 to continue font enumeration
return 1;
}

//其中m_ctlFontList是一个列表控件变量


//六、一次只运行一个程序实例,如果已运行则退出

if( FindWindow(NULL,"程序标题")) exit(0);

//七、得到当前鼠标所在位置

CPoint pt;
GetCursorPos(&pt;); //得到位置

//八、上下文菜单事件触发事件:OnContextMenu事件

//九、显示和隐藏程序菜单

CWnd *pWnd=AfxGetMainWnd();
if(b_m) //隐藏菜单
{
pWnd->SetMenu(NULL);
pWnd->DrawMenuBar();
b_m=false;
}
else
{
CMenu menu;
menu.LoadMenu(IDR_MAINFRAME); ////显示菜单 也可改变菜单项
pWnd->SetMenu(&menu;);
pWnd->DrawMenuBar();
b_m=true;
menu.Detach();
}

//十、获取可执行文件的图标

HICON hIcon=::ExtractIcon(AfxGetInstanceHandle(),_T("NotePad.exe"),0);
if (hIcon &&hIcon;!=(HICON)-1)
{
pDC->DrawIcon(10,10,hIcon);

}
DestroyIcon(hIcon);

//十一、窗口自动靠边程序演示

BOOL AdjustPos(CRect* lpRect)
{//自动靠边
int iSX=GetSystemMetrics(SM_CXFULLSCREEN);
int iSY=GetSystemMetrics(SM_CYFULLSCREEN);
RECT rWorkArea;
BOOL bResult = SystemParametersInfo(SPI_GETWORKAREA, sizeof(RECT), &rWorkAre;
a, 0);
CRect rcWA;
if(!bResult)
{//如果调用不成功就利用GetSystemMetrics获取屏幕面积
rcWA=CRect(0,0,iSX,iSY);
}
else
rcWA=rWorkArea;
int iX=lpRect->left;
int iY=lpRect->top;

if(iX < rcWA.left + DETASTEP && iX!=rcWA.left)
{//调整左
//pWnd->SetWindowPos(NULL,rcWA.left,iY,0,0,SWP_NOSIZE);
lpRect->OffsetRect(rcWA.left-iX,0);
AdjustPos(lpRect);
return TRUE;
}
if(iY < rcWA.top + DETASTEP && iY!=rcWA.top)
{//调整上
//pWnd->SetWindowPos(NULL ,iX,rcWA.top,0,0,SWP_NOSIZE);
lpRect->OffsetRect(0,rcWA.top-iY);
AdjustPos(lpRect);
return TRUE;
}
if(iX + lpRect->Width() > rcWA.right - DETASTEP && iX !=rcWA.right-lpRect->Width())
{//调整右
//pWnd->SetWindowPos(NULL ,rcWA.right-rcW.Width(),iY,0,0,SWP_NOSIZE);
lpRect->OffsetRect(rcWA.right-lpRect->right,0);
AdjustPos(lpRect);
return TRUE;
}
if(iY + lpRect->Height() > rcWA.bottom - DETASTEP && iY !=rcWA.bottom-lpRect
->Height())
{//调整下
//pWnd->SetWindowPos(NULL ,iX,rcWA.bottom-rcW.Height(),0,0,SWP_NOSIZE);
lpRect->OffsetRect(0,rcWA.bottom-lpRect->bottom);
return TRUE;
}
return FALSE;
}
//然后在ONMOVEING事件中使用所下过程调用

CRect r=*pRect;
AdjustPos(&r;);
*pRect=(RECT)r;

//十二、给系统菜单添加一个菜单项给系统菜单添加一个菜单项需要进行下述三个步骤:
//首先,使用Resource Symbols对话(在View菜单中选择Resource Symbols...可以显
//示该对话)定义菜单项ID,该ID应大于0x0F而小于0xF000;
//其次,调用CWnd::GetSystemMenu获取系统菜单的指针并调用CWnd:: Appendmenu将菜单
//项添加到菜单中。下例给系统菜单添加两个新的

int CMainFrame:: OnCreate (LPCREATESTRUCT lpCreateStruct)
{
//…
//Make sure system menu item is in the right range.
ASSERT(IDM_MYSYSITEM<0xF000);
//Get pointer to system menu.
CMenu* pSysMenu=GetSystemMenu(FALSE);
ASSERT_VALID(pSysMenu);
//Add a separator and our menu item to system menu.
CString StrMenuItem(_T ("New menu item"));
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_MYSYSITEM, StrMenuItem);
//…
}

//十三、运行其它程序

//1、运行EMAIL或网址

char szMailAddress[80];
strcpy(szMailAddress,"mailto:[email protected]");
ShellExecute(NULL, "open", szMailAddress, NULL, NULL, SW_SHOWNORMAL);

//2、运行可执行程序
WinExec("notepad.exe",SW_SHOW); //运行计事本

//十四、动态增加或删除菜单

//1、 增加菜单
//添加
CMenu *mainmenu;
mainmenu=AfxGetMainWnd()->GetMenu(); //得到主菜单
(mainmenu->GetSubMenu (0))->AppendMenu (MF_SEPARATOR);//添加分隔符
(mainmenu->GetSubMenu (0))->AppendMenu(MF_STRING,ID_APP_ABOUT,
_T("Always on &Top;")); //添加新的菜单项
DrawMenuBar(); //重画菜单
//2、 删除菜单
//删除
CMenu *mainmenu;
mainmenu=AfxGetMainWnd()->GetMenu(); //得到主菜单

CString str ;
for(int i=(mainmenu->GetSubMenu (0))->GetMenuItemCount()-1;i>=0;i--) //取得菜单的项数。
{
(mainmenu->GetSubMenu (0))->GetMenuString(i,str,MF_BYPOSITION);
//将指定菜单项的标签拷贝到指定的缓冲区。MF_BYPOSITION的解释见上。
if(str=="Always on &Top;") //如果是刚才我们增加的菜单项,则删除。
{
(mainmenu->GetSubMenu (0))->DeleteMenu(i,MF_BYPOSITION);
break;
}
}

//十五、改变应用程序的图标静态更改:

//修改图标资源IDR_MAINFRAME。它有两个图标,一个是16*16的,另一个是32*32的,注意要一起修改。

//动态更改: 向主窗口发送WM_SETICON消息.代码如下:
HICON hIcon=AfxGetApp()->LoadIcon(IDI_ICON);
ASSERT(hIcon);
AfxGetMainWnd()->SendMessage(WM_SETICON,TRUE,(LPARAM)hIcon);

//十六、另一种改变窗口标题的方法

//使用语句 CWnd* m_pCWnd = AfxGetMainWnd( ),然后,再以如下形式调用SetWindowText()函数:
SetWindowText( *m_pCWnd,(LPCTSTR)m_WindowText);// m_WindowText可以是一个CString类的变量。

//十七、剪切板上通过增强元文件拷贝图像数据下面代码拷贝通过元文件拷贝图像数据到任何应用程序,
//其可以放置在CView派生类的函数中。

CMetaFileDC * m_pMetaDC = new CMetaFileDC();
m_pMetaDC->CreateEnhanced(GetDC(),NULL,NULL,"whatever");
//draw meta file
//do what ever you want to do: bitmaps, lines, text...
//close meta file dc and prepare for clipboard;
HENHMETAFILE hMF = m_pMetaDC->CloseEnhanced();
//copy to clipboard
OpenClipboard();
EmptyClipboard();
::SetClipboardData(CF_ENHMETAFILE,hMF);
CloseClipboard();

//DeleteMetaFile(hMF);
delete m_pMetaDC;

//十八、剪切板上文本数据的传送把文本放置到剪接板上:

CString source;
//put your text in source
if(OpenClipboard())
{
HGLOBAL clipbuffer;
char * buffer;
EmptyClipboard();
clipbuffer = GlobalAlloc(GMEM_DDESHARE, source.GetLength()+1);
buffer = (char*)GlobalLock(clipbuffer);
strcpy(buffer, LPCSTR(source));
GlobalUnlock(clipbuffer);
SetClipboardData(CF_TEXT,clipbuffer);
CloseClipboard();
}

//从剪接板上获取文本:

char * buffer;
if(OpenClipboard())
{
buffer = (char*)GetClipboardData(CF_TEXT);
//do something with buffer here
//before it goes out of scope
}
CloseClipboard();

//十九、将捕捉屏幕图像到剪切版中

void CShowBmpInDlgDlg::OnCutScreen()
{
ShowWindow(SW_HIDE);
RECT r_bmp={0,0,::GetSystemMetrics(SM_CXSCREEN),
::GetSystemMetrics(SM_CYSCREEN)};
HBITMAP hBitmap;
hBitmap=CopyScreenToBitmap(&r;_bmp);

//hWnd为程序窗口句柄
if (OpenClipboard())
{
EmptyClipboard();
SetClipboardData(CF_BITMAP, hBitmap);
CloseClipboard();
}
ShowWindow(SW_SHOW);
}
HBITMAP CShowBmpInDlgDlg::CopyScreenToBitmap(LPRECT lpRect)
{
//lpRect 代表选定区域
{
HDC hScrDC, hMemDC;
// 屏幕和内存设备描述表
HBITMAP hBitmap, hOldBitmap;
// 位图句柄
int nX, nY, nX2, nY2;
// 选定区域坐标
int nWidth, nHeight;
// 位图宽度和高度
int xScrn, yScrn;
// 屏幕分辨率

// 确保选定区域不为空矩形
if (IsRectEmpty(lpRect))
return NULL;
//为屏幕创建设备描述表
hScrDC = CreateDC("DISPLAY", NULL, NULL, NULL);
//为屏幕设备描述表创建兼容的内存设备描述表
hMemDC = CreateCompatibleDC(hScrDC);
// 获得选定区域坐标
nX = lpRect->left;
nY = lpRect->top;
nX2 = lpRect->right;
nY2 = lpRect->bottom;
// 获得屏幕分辨率
xScrn = GetDeviceCaps(hScrDC, HORZRES);
yScrn = GetDeviceCaps(hScrDC, VERTRES);
//确保选定区域是可见的
if (nX<0)

nX = 0;
if (nY<0)
nY = 0;
if (nX2>xScrn)
nX2 = xScrn;
if (nY2>yScrn)
nY2 = yScrn;
nWidth = nX2 - nX;
nHeight = nY2 - nY;
// 创建一个与屏幕设备描述表兼容的位图
hBitmap = CreateCompatibleBitmap
(hScrDC, nWidth, nHeight);
// 把新位图选到内存设备描述表中
hOldBitmap =(HBITMAP)SelectObject(hMemDC, hBitmap);
// 把屏幕设备描述表拷贝到内存设备描述表中
BitBlt(hMemDC, 0, 0, nWidth, nHeight, hScrDC, nX, nY, SRCCOPY);
//得到屏幕位图的句柄
hBitmap = (HBITMAP)SelectObject(hMemDC, hOldBitmap);

//清除
DeleteDC(hScrDC);
DeleteDC(hMemDC);
// 返回位图句柄
return hBitmap;
}
}

//二十、如何将位图缩放显示在Static控件中

//在Staic控件内显示位图
void CShowBmpInDlgDlg::ShowBmpInStaic()
{
CBitmap hbmp;
HBITMAP hbitmap;
//将pStatic指向要显示的地方
CStatic *pStaic;
pStaic=(CStatic*)GetDlgItem(IDC_IMAGE);
//装载资源 MM.bmp是我的一个文件名,用你的替换
hbitmap=(HBITMAP)::LoadImage (::AfxGetInstanceHandle(),"MM.bmp",
IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION);

hbmp.Attach(hbitmap);
//获取图片格式
BITMAP bm;
hbmp.GetBitmap(&bm;);
CDC dcMem;
dcMem.CreateCompatibleDC(GetDC());
CBitmap *poldBitmap=(CBitmap*)dcMem.SelectObject(hbmp);
CRect lRect;
pStaic->GetClientRect(&lRect;);
//显示位图
pStaic->GetDC()->StretchBlt(lRect.left ,lRect.top ,lRect.Width(),lRect.Height(),
&dcMem;,0 ,0,bm.bmWidth,bm.bmHeight,SRCCOPY);
dcMem.SelectObject(&poldBitmap;);
}

定制自己的EXE文件

发表于 2005-01-11 | 分类于 技术控 | | 阅读次数:
字数统计: 513 字 | 阅读时长 ≈ 2 分钟

主要是为了实现像木马那样的生成自己需要配置的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调用存储过程例程

发表于 2005-01-05 | 分类于 技术控 | | 阅读次数:
字数统计: 249 字 | 阅读时长 ≈ 1 分钟

_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

发表于 2005-01-05 | 分类于 我的拙作 | | 阅读次数:
字数统计: 135 字 | 阅读时长 ≈ 1 分钟

酒店管理系统V1.0 这是我个人完成的一个酒店管理系统模型,拥有客户预订,客户登记,空房查询,服务消费记录和客户结帐,房间管理等多种功能。采用VC++6.0和SQL SERVER开发,大部分业务逻辑采用存储过程实现提高了数据存储的可靠性和速度。 程序界面预览:(点击查看全图) 客户预订界面 客户登记界面 空房查询界面

点击下载此文件

VC中ADO连接字符串收集

发表于 2005-01-04 | 分类于 技术控 | | 阅读次数:
字数统计: 227 字 | 阅读时长 ≈ 1 分钟

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; }

改变对话框的背景色

发表于 2004-12-30 | 分类于 技术控 | | 阅读次数:
字数统计: 505 字 | 阅读时长 ≈ 2 分钟

方法一:调用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; }

删除、拷贝、移动文件夹及其文件

发表于 2004-12-29 | 分类于 技术控 | | 阅读次数:
字数统计: 308 字 | 阅读时长 ≈ 1 分钟

删除:

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);

模拟按键

发表于 2004-12-29 | 分类于 技术控 | | 阅读次数:
字数统计: 243 字 | 阅读时长 ≈ 1 分钟

模拟键盘我们用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); …

堆和栈的区别

发表于 2004-12-29 | 分类于 技术控 | | 阅读次数:
字数统计: 1.5k 字 | 阅读时长 ≈ 5 分钟

在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序列号

发表于 2004-12-29 | 分类于 技术控 | | 阅读次数:
字数统计: 106 字 | 阅读时长 ≈ 1 分钟

//取得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); }

获取磁盘使用空间和剩余空间

发表于 2004-12-28 | 分类于 技术控 | | 阅读次数:
字数统计: 170 字 | 阅读时长 ≈ 1 分钟

char crDrv[3]; CStringArray strArray; _ULARGE_INTEGER n64TotalNumberOfBytes, n64TotalNumberOfFreeBytes; __int64 n64TotalFree = 0,n64TotalSpace = 0; float fTotalFree,fTotalSpace,fTempFree,fTempTotal; ULONG lTotalFree = 0,lTotalSpace = 0, lTempFree = 0,lTempTotal = 0; CString strInfo; BOOL bSuccess;

for(int n=2;n<=25;n++) { CString str; str.Format(“%c:\“,n+’A’); strcpy(crDrv,str); UINT nDrvType = GetDriveType(crDrv); switch(nDrvType) { case DRIVE_FIXED: { strArray.Add(crDrv); break; } default: { break; } } }

for(n = 0;n < strArray.GetSize();n ++) { bSuccess = SHGetDiskFreeSpace(strArray.GetAt(n), NULL,&n64TotalNumberOfBytes;, &n64TotalNumberOfFreeBytes;); n64TotalSpace += n64TotalNumberOfBytes.QuadPart; n64TotalFree += n64TotalNumberOfFreeBytes.QuadPart;

lTempTotal = (ULONG)(n64TotalNumberOfBytes.QuadPart/1024); lTempFree = (ULONG)(n64TotalNumberOfFreeBytes.QuadPart/1024); fTempTotal = (float)lTempTotal; fTempTotal = fTempTotal/1024/1024; fTempFree = (float)lTempFree; fTempFree = fTempFree/1024/1024;

strInfo.Format(“%s 容量: %4.2fGB,可用空间: %4.2fGB.”, strArray.GetAt(n),fTempTotal,fTempFree); AfxMessageBox(strInfo); }

lTotalSpace = (ULONG)(n64TotalSpace/1024); lTotalFree = (ULONG)(n64TotalFree/1024); fTotalSpace = (float)lTotalSpace; fTotalSpace = fTotalSpace/1024/1024; fTotalFree = (float)lTotalFree; fTotalFree = fTotalFree/1024/1024;

strInfo.Format(“总容量: %4.2fGB,总共可用空间: %4.2fGB.”, fTotalSpace,fTotalFree); AfxMessageBox(strInfo);

1…424344…47
Timothy

Timothy

Timothy的技术博客,记录技术以及生活点滴

564 日志
8 分类
1187 标签
RSS
github twitter
Links
  • ZWWoOoOo
  • 花開未央
  • 守望轩
  • 大漠说程序
  • ChengBo
  • BlueAndHack
  • 程序员小辉
  • 子痕的博客
  • WoodenRobot
  • VPS大佬
  • 毕扬博客
  • VPSDad
  • 猫爪导航
  • ss1271的奋斗
  • Kian.Li
  • YoungForest
  • Fred's Blog
  • Jacklandrin
© 2025 Timothy
由 Hexo 强力驱动
|
主题 — NexT.Muse v5.1.4