windows程序设计之STRPROG学习总结
任务定义:同一程序的多个实例共享一份数据,一个实例对数据的修改会影响到其他实例,具体到窗口中就是,一个实例中的数据显示变化引起其他各个实例中数据显示的更新。
整体分析:编写一个dll,其中包含被同一程序的不同实例共享的内存数据;类似于document-view模式,document对应dll中的共享内存数据,view对应各个实例的显示窗口;由此可以实现一个实例对共享数据的修改,可以影响到其他实例,每次修改后当前实例向所有其他实例发送一个消息,使得各个实例窗口数据同步更新。
关键代码分析:
1、共享数据段
// 创建名为shared的共享数据段
#pragma data_seg ("shared") // 必须对数据初始化,否则编译器将把它们放在普通的未初始化数据段中
int iTotal = 0 ; //标识字符串总数
WCHAR szStrings [MAX_STRINGS][MAX_LENGTH + 1] = { '\0' } ; //关键共享字符串数组,用来在各个实例中显示
#pragma data_seg ()
#pragma comment(linker,"/SECTION:shared,RWS")
2、各个应用程序实例中的字符串显示函数
BOOL CALLBACK GetStrCallBack (PTSTR pString, CBPARAM * pcbp)
{
// 输出字符串
TextOut (pcbp->hdc, pcbp->xText, pcbp->yText,
pString, lstrlen (pString)) ;
// 输出y坐标递增一个字符高度,并与窗口可输出最大行比较
// 如果输出行已到最大行,则执行
if ((pcbp->yText += pcbp->yIncr) > pcbp->yMax)
{
// 使y坐标指向第一行
pcbp->yText = pcbp->yStart ;
// x坐标增加一行字符串最大宽度,并与可输出最大列比较
// 如果输出已到最大行和最大列,则返回FALSE
if ((pcbp->xText += pcbp->xIncr) > pcbp->xMax)
return FALSE ;
}
return TRUE ;
}
3、dll中的字符串获取并显示函数(在内部调用了字符串显示函数)
EXPORT int CALLBACK GetStringsW (GETSTRCB pfnGetStrCallBack, PVOID pParam)
{
BOOL bReturn ;
int i ;
for (i = 0 ; i < iTotal ; i++)
{ //在这里回调了应用程序实例中的字符串显示函数,因为显示只能在各个实例中显示,dll是不能帮助显示的,dll并不知道实例中的显示参数或者显示的上下文环境,因而不能在此直接写出显示的代码,而是要待用实例中的函数,让实例自己去做显示的工作,因为只有它自己才知道如何根据显示的DC来显示。其实这个函数主要的工作就是获取共享数据,因为数据是在dll的控制范围之内的。
bReturn = pfnGetStrCallBack (szStrings[i], pParam) ;
if (bReturn == FALSE)
return i + 1 ;
}
return iTotal ;
}
4、全局消息注册
// 注册字符串更改消息,这个消息是各个实例都能收到的,可参考MSDN
iDataChangeMsg = RegisterWindowMessage (TEXT ("StrProgDataChange")) ;
5、向其他实例广播消息(当在对话框中做出操作之后,会引起共享数据变化,因此向其他实例广播消息,让它们刷新显示)
// 创建输入对话框(删除对话框行为类似,不再分析)
if (DialogBox (hInst, TEXT ("EnterDlg"), hwnd, &DlgProc)
{
// 添加用户输入的字符串到共享内存的字符串数组中
if (AddString (szString))
// 将程序注册的消息发送给所有窗口,用于通知使用共享内存的其它程序
PostMessage (HWND_BROADCAST, iDataChangeMsg, 0, 0) ;
else
MessageBeep (0) ;
}
6、窗口收到广播消息(收到广播消息,立马让客户区无效,从而引起刷新)
default:
// 广播消息,刷新客户区
if (message == iDataChangeMsg)
InvalidateRect (hwnd, NULL, TRUE) ;
7、更新显示(对应共享数据的修改,每个实例做出更新显示)case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
// 初始化输出字符串所需要的数据
cbparam.hdc = hdc ;
cbparam.xText = cbparam.xStart = cxChar ;
cbparam.yText = cbparam.yStart = cyChar ;
cbparam.xIncr = cxChar * MAX_LENGTH ;
cbparam.yIncr = cyChar ;
cbparam.xMax = cbparam.xIncr * (1 + cxClient / cbparam.xIncr) ;
cbparam.yMax = cyChar * (cyClient / cyChar - 1) ;
// 输出字符串
GetStrings ((GETSTRCB) GetStrCallBack, (PVOID) &cbparam) ;
EndPaint (hwnd, &ps) ;
return 0 ;
ps:其他的注意事项还有一些工程配置问题,以及应用程序对dll的依赖配置。