入门指南






3.49/5 (26投票s)
2005年5月26日
4分钟阅读

77861
了解简单的 DLL、多线程以及其他一些内容……
引言
动态链接库、多线程……这些概念对于初学者来说都有些高深。但正如“简单”二字所言,它们在概念上是简单的。本文旨在为你提供关于这些概念的一些有用的技术基础知识,特别是为初学者准备。本文不涉及概念的理论定义。
创建一个简单的 DLL
DLL 部分
- 在 Win32 动态链接库上创建一个空项目。
- 在工作区创建一个新的 CPP 文件。(在工作区的“文件视图”选项卡中,右键单击“源文件”->“添加文件到文件夹…”然后创建一个新的 CPP 文件)。
- 按以下方式编写你的代码……
#include <afxwin.h> extern "C" _declspec(dllexport) void SayHello() { AfxMessageBox(“Hello World”); }
DLL 代码就这些了……编译它,然后得到你的 DLL。
应用程序部分
- 创建一个应用程序向导(对话框或 SDI 或 MDI……随意选择)。
- 使用任何消息处理程序来测试这个 DLL……例如,一个按钮处理程序。
- 使用以下代码加载你的 DLL
typedef void (*SayHello) (); // typedef a function pointer // load your dll into the memory HMODULE hmodule=::LoadLibrary("yourDLLName.dll"); if(hmodule) { //get your function SayHello sm=(SayHello) GetProcAddress(hmodule,"SayHello"); sm(); // thatzaal call your function now }
- 将你的 DLL 放在应用程序的路径中……
- 现在编译你的应用程序……
技巧
- 这是上述应用程序中一个简单的单行代码。如果 DLL 或函数不存在,可能会导致问题……
GetProcessAddress(LoadLibrary(“yourDLLName.dll”),”SayHello”)();
GetProcessAddress()
将返回你 DLL 中函数的地址。第二个参数是你正在查找的确切函数名,所以请确保函数名拼写正确。
简单的多线程概念
- 创建一个结构用于你的线程和应用程序之间的数据传输。例如
struct threadinfo{ CString somedata; } info;
- 声明一个 `CWinThread` 类型的指针成员变量(对象)。这里是 `CWinThread *m_pthread`。
- 在你的应用程序中的任何地方初始化你的线程,如下所示
m_pthread=AfxBeginThread(functionname,(LPVOID) &info);
AfxBeginThread()
API 接受两个参数,函数名(将是你的线程)和必要的信息,例如 `threadinfo` 结构。 - 将你的线程函数编写为
UINT functionname(LPVOID param) { threadinfo *info=(threadinfo *)param; CString s=info->somedata; // handle your thread code here… }
- 终止线程
::TerminateThread(m_pthread->m_hThread,0);
将你的应用程序最小化到系统托盘
- 使用任何向导创建你的应用程序(SDI、MDI 或对话框)。
- 添加 `NOTIFYICONDATA` 和 `CMenu` 的成员变量。
例如
NOTIFYICONDATA m_traydata; CMenu m_menu;
- 将以下代码添加到你的 `OnSysCommand()` 消息处理程序中
void CYourDialog::OnSysCommand(UINT nID, LPARAM lParam) { if(nID==SC_MINIMIZE) { m_traydata.cbSize=sizeof(NOTIFYICONDATA); m_traydata.hWnd =this->m_hWnd; m_traydata.uID = 1; m_traydata.hIcon=AfxGetApp()->LoadIcon(IDI_YOURICON); m_traydata.uCallbackMessage =WM_MY_TRAY; strcpy(m_traydata.szTip,"Systray application"); m_traydata.uFlags=NIF_ICON|NIF_MESSAGE; m_menu.DestroyMenu(); // if already exists if(!m_menu.LoadMenu(IDR_MENU1)) return; Shell_NotifyIcon(NIM_DELETE,&m_traydata); // if already exisits If(!Shell_NotifyIcon(NIM_ADD,&m_traydata)) return; this->ShowWindow(SW_HIDE); } }
- 在你的头文件中定义一个消息,例如 ` #define WM_MY_TRAY (WM_USER+1)`。
- 为该消息添加一个消息处理程序,例如 `OnTrayNotify()`,如下所示
void OnTrayNotify(WPARAM wParam, LPARAM lParam);
// 在你的头文件中ON_MESSAGE(WM_MY_TRAY,OnTrayNotify)
// 在你的 `MESSAGE_MAP` 中- 在你的 CPP 文件中的以下代码
void CYourDialog::OnTrayNotify(WPARAM wParam, LPARAM lParam) { UINT uID,uMsg; uID=(UINT)wParam; uMsg=(UINT)lParam; if(uID!=1) return; CPoint pt; switch(uMsg) { case WM_LBUTTONDOWN: this->ShowWindow(SW_SHOW); this->ShowWindow(SW_NORMAL); Shell_NotifyIcon(NIM_DELETE,&m_traydata); break; case WM_RBUTTONDOWN: case WM_CONTEXTMENU: GetCursorPos(&pt); OnTrayRButton(pt); break; } return; }
- 添加一个名为 `OnTrayRButton(CPoint point)` 的成员函数
void CYourDialog::OnTrayRButton(CPoint point) { // assuming that the IDR_MENU1 is having atleast one submenu m_menu.GetSubMenu(0)->TrackPopupMenu(TPM_BOTTOMALIGN| TPM_LEFTBUTTON| TPM_RIGHTBUTTON,point.x,point.y,this); }
OnDestroy
方法void CYourDialog::OnDestroy() { CDialog::OnDestroy(); Shell_NotifyIcon(NIM_DELETE,&m_traydata); }
- 好了,你的应用程序现在就在系统托盘里了。
应用程序的弹出菜单
方法 1
- 为 `CMenu` 添加一个成员变量(例如 `m_menu`);
- 将菜单资源加载到你的菜单成员 `m_menu.LoadMenu(IDR_MENU1);` 中
- 为你的应用程序添加上下文菜单处理程序(`WM_CONTEXTMENU`)。
void CYourDlg:: OnContextMenu(CWnd* pWnd, CPoint point) { m_menu.GetSubMenu(0)->TrackPopupMenu(TPM_RIGHTBUTTON, point.x,point.y,this); }
方法 2
- 为 `CMenu` 添加一个成员变量(例如 `m_menu`);
- 为你的应用程序添加上下文菜单处理程序(`WM_CONTEXTMENU`)。
void CYourDlg:: OnContextMenu(CWnd* pWnd, CPoint point) { m_menu.DestroyMenu(); // Destroy the old menu if any. m_menu.CreatePopupMenu(); m_menu.AppendMenu(MF_STRING,1000,"item 1"); m_menu.AppendMenu(MF_SEPARATOR); m_menu.AppendMenu(MF_STRING,1001,"item 2"); m_menu.AppendMenu(MF_STRING,1002,"item 3"); m_menu.AppendMenu(MF_POPUP,(UINT) m_menu2.m_hMenu,”sub menu”); m_menu.TrackPopupMenu(TPM_RIGHTBUTTON,point.x,point.y,this); }
- 1000、1001、1002 是菜单项的命令 ID。使用此 ID 在 `WM_COMMAND` 消息的 `wParam` 中识别你的菜单项。
- `MF_POPUP` 用于将子菜单附加到你的弹出菜单。在这种情况下,命令 ID 参数将接受一个菜单句柄而不是 ID。菜单句柄可以是任何你创建的其他菜单,例如 `m_menu`。
关于 CPtrList 类
CPtrList
是一个指针列表类(链表)。它可以动态地存储任意数量的项目。- 要向列表中添加项目,请调用 `CPtrList::AddTail()` / `CPtrList:::AddHead()` / `CPtrList::InsertAfter()` / `CPtrList::InsertBefore()` /
CPtrList::SetAt()
。 CPtrList
中的项目是void*
类型。在将对象添加到列表时,将其类型转换为void*
。- 要从列表中检索项目,请使用 `CPtrList::GetHead()` / `CPtrList::GetTail()` / `CPtrList::GetAt()` / `CPtrList:::GetNext()` / `CPtrList::GetPrev()`。
- 从列表中检索项目时,将
void
类型转换为你的对象类型。 - 使用 `POSITION` 句柄来遍历列表。它不是索引。它是一个指向列表中对象的句柄。
- 你列表中的所有元素都将仅通过 `POSITION` 句柄进行处理。
- 要查找列表中的项目,你可以同时使用索引和 `POSITION`。`CPtrList::FindIndex(index)` 将返回 `POSTION` 值。`CPtrList::Find(void *)` 将返回项目。
CPtrList::GetNext(POSITION)
将返回当前对象并将位置值递增到下一个。`POSITION` 是引用参数。- 要从列表中删除项目/所有项目:`CPtrList::RemoveAt()` / `CPtrList::RemoveAll()`。
- 在添加和删除对象时,要注意分配和释放对象的内存。你有责任删除分配的对象。`CPtrList` 在从列表中删除对象时不会删除它们。
示例
// Adding an object to the list // Should be deleted. Caution: Memory Leak m_objList.AddTail((void *) new CPoint(2,2)); // Traversing a CPtrList; and assigning value to the objects POSITION pos=m_objList.GetHeadPosition(); while(pos) { CPoint *obj=(CPoint *)m_objList.GetNext(pos); obj->x=10;obj->y=10; } // Removing the objects from the list POSITION pos=m_objList.GetHeadPosition(); while(pos) { CPoint *obj=(CPoint *)m_objList.GetNext(pos); delete obj; } m_objList.RemoveAll();
关于 CListCtrl
- 显示网格线
CListCtrl::SetExtendedStyle(LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES);
- 添加列
CListCtrl::InsertColumn(index,title,alignment,<title length>*25,-1)
对齐方式 - `LVCFMT_LEFT`、`LVCFMT_RIGHT`、`LVCFMT_CENTER`
- 设置列的宽度
CListCtrl::SetColumnWidth(index,size);
- 向列表中插入项目
CListCtrl::InsertItem(index,””); CListCtrl::SetItemText(index,column,item_text);
- 从列表中获取项目
CString txt=CListCtrl::GetItemText(item,column);
- 获取列表中的选定项目
POSITION pos=CListCtrl:: GetFirstSelectedItemPosition(); while(pos) { int item=CListCtrl::GetNextSelectedItem(pos); CString txt=CListCtrl::GetItemText(item,column); }
- 将焦点设置到某一行
CListCtrl::SetItemState(index,LVIS_FOCUSED,LVIS_FOCUSED);
- 删除列表中的所有项目
CListCtrl::DeleteAllItems();
关于数据库连接……
- 打开数据库
CDatabase db; db.OpenEx("DRIVER=Microsoft Access Driver (*.mdb);DBQ=mydatabase.mdb;")
- 为数据库创建记录集
CRecordset rs; rs.m_pDatabase=&db;
- 从记录集中获取值
rs.GetFieldValue(index,CString&);
- 获取记录总数
rs.GetRecordCount();
- 遍历数据库的完整记录集
if(rs.GetRecordCount()==0) return; rs.MoveFirst(); for(int i=0; i<rs.GetRecordCount(); i++) { CString emp_no,emp_name,; rs.GetFieldValue(0,emp_no); rs.GetFieldValue(1,emp_name); MessageBox(emp_no+” “+emp_name); rs.MoveNext(); }
(待续……)
结论
我并不是说这些是标题所包含的全部概念。但这些是基础。本文可能无法涵盖这些概念的全部领域。没有哪篇文章能完全满足所有人的期望。但是,每篇文章都应该成为你技术成长的一颗种子。因此,我相信这会是一颗种子。谢谢大家。