MessageBoxTimeoutIndirectW的实现代码如下:
#001 static int
#002 MessageBoxTimeoutIndirectW(
#003 CONST MSGBOXPARAMSW *lpMsgBoxParams, UINT Timeout)
#004 {
#005 DLGTEMPLATE *tpl;
#006 DLGITEMTEMPLATE *iico, *itxt;
#007 NONCLIENTMETRICSW nclm;
#008 WCHAR capbuf[32];
#009 LPVOID buf;
#010 BYTE *dest;
#011 LPCWSTR caption, text;
#012 HFONT hFont;
#013 HICON Icon;
#014 HDC hDC;
#015 int bufsize, ret, caplen, textlen, btnlen, i, btnleft, btntop, lmargin, nButtons = 0;
#016 LONG Buttons[MSGBOXEX_MAXBTNS];
#017 WCHAR ButtonText[MSGBOXEX_MAXBTNS][MSGBOXEX_MAXBTNSTR];
#018 DLGITEMTEMPLATE *ibtn[MSGBOXEX_MAXBTNS];
#019 RECT btnrect, txtrect, rc;
#020 SIZE btnsize;
#021 MSGBOXINFO mbi;
#022 BOOL defbtn = FALSE;
获取对话框架基本显示单元的大小。
#023 DWORD units = GetDialogBaseUnits();
#024
判断是否设置有显示标题字符串,如果没有设置,就从用户应用程序里获取错误显示字符串作为标题。
#025 if(!lpMsgBoxParams->lpszCaption || !HIWORD((LPWSTR)lpMsgBoxParams->lpszCaption))
#026 {
#027 LoadStringW(User32Instance, IDS_ERROR, &capbuf[0], 32);
#028 caption = &capbuf[0];
#029 }
#030 else
#031 caption = (LPWSTR)lpMsgBoxParams->lpszCaption;
#032
判断是否需要显示的字符串。
#033 if(!lpMsgBoxParams->lpszText || !HIWORD(lpMsgBoxParams->lpszText))
#034 text = L"";
#035 else
#036 text = lpMsgBoxParams->lpszText;
#037
获取标题和显示字符串的大小。
#038 caplen = strlenW(caption);
#039 textlen = strlenW(text);
#040
根据用户的设置来选择显示什么类型的按钮。
#041 /* Create selected buttons */
#042 switch(lpMsgBoxParams->dwStyle & MB_TYPEMASK)
#043 {
#044 case MB_OKCANCEL:
#045 Buttons[0] = IDOK;
#046 Buttons[1] = IDCANCEL;
#047 nButtons = 2;
#048 break;
#049 case MB_CANCELTRYCONTINUE:
#050 Buttons[0] = IDCANCEL;
#051 Buttons[1] = IDTRYAGAIN;
#052 Buttons[2] = IDCONTINUE;
#053 nButtons = 3;
#054 break;
#055 case MB_ABORTRETRYIGNORE:
#056 Buttons[0] = IDABORT;
#057 Buttons[1] = IDRETRY;
#058 Buttons[2] = IDIGNORE;
#059 nButtons = 3;
#060 break;
#061 case MB_YESNO:
#062 Buttons[0] = IDYES;
#063 Buttons[1] = IDNO;
#064 nButtons = 2;
#065 break;
#066 case MB_YESNOCANCEL:
#067 Buttons[0] = IDYES;
#068 Buttons[1] = IDNO;
#069 Buttons[2] = IDCANCEL;
#070 nButtons = 3;
#071 break;
#072 case MB_RETRYCANCEL:
#073 Buttons[0] = IDRETRY;
#074 Buttons[1] = IDCANCEL;
#075 nButtons = 2;
#076 break;
#077 case MB_OK:
#078 /* fall through */
#079 default:
#080 Buttons[0] = IDOK;
#081 nButtons = 1;
#082 break;
#083 }
判断是否显示帮助按钮。
#084 /* Create Help button */
#085 if(lpMsgBoxParams->dwStyle & MB_HELP)
#086 Buttons[nButtons++] = IDHELP;
#087
根据用户设置选择什么类型的图标显示,并调用函数MessageBeep提示不同的提示声音。
#088 switch(lpMsgBoxParams->dwStyle & MB_ICONMASK)
#089 {
#090 case MB_ICONEXCLAMATION:
#091 Icon = LoadIconW(0, IDI_EXCLAMATIONW);
#092 MessageBeep(MB_ICONEXCLAMATION);
#093 break;
#094 case MB_ICONQUESTION:
#095 Icon = LoadIconW(0, IDI_QUESTIONW);
#096 MessageBeep(MB_ICONQUESTION);
#097 break;
#098 case MB_ICONASTERISK:
#099 Icon = LoadIconW(0, IDI_ASTERISKW);
#100 MessageBeep(MB_ICONASTERISK);
#101 break;
#102 case MB_ICONHAND:
#103 Icon = LoadIconW(0, IDI_HANDW);
#104 MessageBeep(MB_ICONHAND);
#105 break;
#106 case MB_USERICON:
#107 Icon = LoadIconW(lpMsgBoxParams->hInstance, lpMsgBoxParams->lpszIcon);
#108 MessageBeep(MB_OK);
#109 break;
#110 default:
#111 /* By default, Windows 95/98/NT does not associate an icon to message boxes.
#112 * So ReactOS should do the same.
#113 */
#114 Icon = (HICON)0;
#115 MessageBeep(MB_OK);
#116 break;
#117 }
#118
分配基本空间的大小。
#119 /* Basic space */
#120 bufsize = sizeof(DLGTEMPLATE) +
#121 2 * sizeof(WORD) + /* menu and class */
#122 (caplen + 1) * sizeof(WCHAR); /* title */
#123
图标占用空间的大小。
#124 /* Space for icon */
#125 if (NULL != Icon)
#126 {
#127 bufsize = (bufsize + 3) & ~3;
#128 bufsize += sizeof(DLGITEMTEMPLATE) +
#129 4 * sizeof(WORD) +
#130 sizeof(WCHAR);
#131 }
#132
显示字符串占用空间。
#133 /* Space for text */
#134 bufsize = (bufsize + 3) & ~3;
#135 bufsize += sizeof(DLGITEMTEMPLATE) +
#136 3 * sizeof(WORD) +
#137 (textlen + 1) * sizeof(WCHAR);
#138
#139
加载所有按钮的字符串。
#140 for(i = 0; i < nButtons; i++)
#141 {
#142 switch(Buttons[i])
#143 {
#144 case IDOK:
#145 LoadStringW(User32Instance, IDS_OK, ButtonText[i], MSGBOXEX_MAXBTNSTR - 1);
#146 break;
#147 case IDCANCEL:
#148 LoadStringW(User32Instance, IDS_CANCEL, ButtonText[i], MSGBOXEX_MAXBTNSTR - 1);
#149 break;
#150 case IDYES:
#151 LoadStringW(User32Instance, IDS_YES, ButtonText[i], MSGBOXEX_MAXBTNSTR - 1);
#152 break;
#153 case IDNO:
#154 LoadStringW(User32Instance, IDS_NO, ButtonText[i], MSGBOXEX_MAXBTNSTR - 1);
#155 break;
#156 case IDTRYAGAIN:
#157 LoadStringW(User32Instance, IDS_TRYAGAIN, ButtonText[i], MSGBOXEX_MAXBTNSTR - 1);
#158 break;
#159 case IDCONTINUE:
#160 LoadStringW(User32Instance, IDS_CONTINUE, ButtonText[i], MSGBOXEX_MAXBTNSTR - 1);
#161 break;
#162 case IDABORT:
#163 LoadStringW(User32Instance, IDS_ABORT, ButtonText[i], MSGBOXEX_MAXBTNSTR - 1);
#164 break;
#165 case IDRETRY:
#166 LoadStringW(User32Instance, IDS_RETRY, ButtonText[i], MSGBOXEX_MAXBTNSTR - 1);
#167 break;
#168 case IDIGNORE:
#169 LoadStringW(User32Instance, IDS_IGNORE, ButtonText[i], MSGBOXEX_MAXBTNSTR - 1);
#170 break;
#171 case IDHELP:
#172 LoadStringW(User32Instance, IDS_HELP, ButtonText[i], MSGBOXEX_MAXBTNSTR - 1);
#173 break;
#174 default:
#175 ButtonText[i][0] = (WCHAR)0;
#176 break;
#177 }
#178
按钮的空间大小。
#179 /* Space for buttons */
#180 bufsize = (bufsize + 3) & ~3;
#181 bufsize += sizeof(DLGITEMTEMPLATE) +
#182 3 * sizeof(WORD) +
#183 (wcslen(ButtonText[i]) + 1) * sizeof(WCHAR);
#184 }
#185
从进程堆空间里分配内存。
#186 buf = RtlAllocateHeap(GetProcessHeap(), 0, bufsize);
#187 if(!buf)
#188 {
#189 return 0;
#190 }
#191 iico = itxt = NULL;
#192
创建一个兼容DC。
#193 hDC = CreateCompatibleDC(0);
#194
下面获取消息窗口显示的字体。
#195 nclm.cbSize = sizeof(nclm);
#196 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, sizeof(nclm), &nclm, 0);
#197 hFont = CreateFontIndirectW (&nclm.lfMessageFont);
#198
下面开始根据对话框的资源结构在内存里构造窗口显示模板。
#199 tpl = (DLGTEMPLATE *)buf;
#200
#201 tpl->style = WS_CAPTION | WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_SYSMENU | DS_CENTER | DS_MODALFRAME | DS_NOIDLEMSG;
#202 tpl->dwExtendedStyle = WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT;
#203 if(lpMsgBoxParams->dwStyle & MB_TOPMOST)
#204 tpl->dwExtendedStyle |= WS_EX_TOPMOST;
#205 if(lpMsgBoxParams->dwStyle & MB_RIGHT)
#206 tpl->dwExtendedStyle |= WS_EX_RIGHT;
#207 tpl->x = 100;
#208 tpl->y = 100;
#209 tpl->cdit = nButtons + ((Icon != (HICON)0) ? 1 : 0) + 1;
#210
#211 dest = (BYTE *)(tpl + 1);
#212
#213 *(WORD*)dest = 0; /* no menu */
#214 *(((WORD*)dest) + 1) = 0; /* use default window class */
#215 dest += 2 * sizeof(WORD);
#216 memcpy(dest, caption, caplen * sizeof(WCHAR));
#217 dest += caplen * sizeof(WCHAR);
#218 *(WCHAR*)dest = L'/0';
#219 dest += sizeof(WCHAR);
#220
创建图标。
#221 /* Create icon */
#222 if(Icon)
#223 {
#224 dest = (BYTE*)(((ULONG_PTR)dest + 3) & ~3);
#225 iico = (DLGITEMTEMPLATE *)dest;
#226 iico->style = WS_CHILD | WS_VISIBLE | SS_ICON;
#227 iico->dwExtendedStyle = 0;
#228 iico->id = MSGBOX_IDICON;
#229
#230 dest += sizeof(DLGITEMTEMPLATE);
#231 *(WORD*)dest = 0xFFFF;
#232 dest += sizeof(WORD);
#233 *(WORD*)dest = 0x0082; /* static control */
#234 dest += sizeof(WORD);
#235 *(WORD*)dest = 0xFFFF;
#236 dest += sizeof(WORD);
#237 *(WCHAR*)dest = 0;
#238 dest += sizeof(WCHAR);
#239 *(WORD*)dest = 0;
#240 dest += sizeof(WORD);
#241 }
#242
创建静态框显示字符串。
#243 /* create static for text */
#244 dest = (BYTE*)(((DWORD)dest + 3) & ~3);
#245 itxt = (DLGITEMTEMPLATE *)dest;
#246 itxt->style = WS_CHILD | WS_VISIBLE | SS_NOPREFIX;
#247 if(lpMsgBoxParams->dwStyle & MB_RIGHT)
#248 itxt->style |= SS_RIGHT;
#249 else
#250 itxt->style |= SS_LEFT;
#251 itxt->dwExtendedStyle = 0;
#252 itxt->id = MSGBOX_IDTEXT;
#253 dest += sizeof(DLGITEMTEMPLATE);
#254 *(WORD*)dest = 0xFFFF;
#255 dest += sizeof(WORD);
#256 *(WORD*)dest = 0x0082; /* static control */
#257 dest += sizeof(WORD);
#258 memcpy(dest, text, textlen * sizeof(WCHAR));
#259 dest += textlen * sizeof(WCHAR);
#260 *(WCHAR*)dest = 0;
#261 dest += sizeof(WCHAR);
#262 *(WORD*)dest = 0;
#263 dest += sizeof(WORD);
#264
创建要显示的按钮。
#265 /* create buttons */
#266 btnsize.cx = BTN_CX;
#267 btnsize.cy = BTN_CY;
#268 btnrect.left = btnrect.top = 0;
#269 for(i = 0; i < nButtons; i++)
#270 {
#271 dest = (BYTE*)(((DWORD)dest + 3) & ~3);
#272 ibtn[i] = (DLGITEMTEMPLATE *)dest;
#273 ibtn[i]->style = WS_CHILD | WS_VISIBLE | WS_TABSTOP;
#274 if(!defbtn && (i == ((lpMsgBoxParams->dwStyle & MB_DEFMASK) >> 8)))
#275 {
#276 ibtn[i]->style |= BS_DEFPUSHBUTTON;
#277 mbi.DefBtn = Buttons[i];
#278 defbtn = TRUE;
#279 }
#280 else
#281 ibtn[i]->style |= BS_PUSHBUTTON;
#282 ibtn[i]->dwExtendedStyle = 0;
#283 ibtn[i]->id = Buttons[i];
#284 dest += sizeof(DLGITEMTEMPLATE);
#285 *(WORD*)dest = 0xFFFF;
#286 dest += sizeof(WORD);
#287 *(WORD*)dest = 0x0080; /* button control */
#288 dest += sizeof(WORD);
#289 btnlen = strlenW(ButtonText[i]);
#290 memcpy(dest, ButtonText[i], btnlen * sizeof(WCHAR));
#291 dest += btnlen * sizeof(WCHAR);
#292 *(WORD*)dest = 0;
#293 dest += sizeof(WORD);
#294 *(WORD*)dest = 0;
#295 dest += sizeof(WORD);
#296 SelectObject(hDC, hFont);
显示按钮的字符串。
#297 DrawTextW(hDC, ButtonText[i], btnlen, &btnrect, DT_LEFT | DT_SINGLELINE | DT_CALCRECT);
#298 btnsize.cx = max(btnsize.cx, btnrect.right);
#299 btnsize.cy = max(btnsize.cy, btnrect.bottom);
#300 }
#301
如果有按钮,就设置第一个为缺省选中按钮。
#302 /* make first button the default button if no other is */
#303 if(!defbtn)
#304 {
#305 ibtn[0]->style &= ~BS_PUSHBUTTON;
#306 ibtn[0]->style |= BS_DEFPUSHBUTTON;
#307 mbi.DefBtn = Buttons[0];
#308 }
#309
计算位置和窗口显示的大小。
#310 /* calculate position and size of controls */
#311 txtrect.right = GetSystemMetrics(SM_CXSCREEN) / 5 * 4;
#312 if(Icon)
#313 txtrect.right -= GetSystemMetrics(SM_CXICON) + MSGBOXEX_SPACING;
#314 txtrect.top = txtrect.left = txtrect.bottom = 0;
#315 SelectObject(hDC, hFont);
#316 if (textlen != 0)
#317 {
#318 DrawTextW(hDC, text, textlen, &txtrect, DT_LEFT | DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT);
#319 }
#320 else
#321 {
#322 txtrect.right = txtrect.left + 1;
#323 txtrect.bottom = txtrect.top + 1;
#324 }
#325 txtrect.right++;
#326
计算图标显示的位置和大小。
#327 /* calculate position and size of the icon */
#328 rc.left = rc.bottom = rc.right = 0;
#329 btntop = 0;
#330
#331 if(iico)
#332 {
#333 rc.right = GetSystemMetrics(SM_CXICON);
#334 rc.bottom = GetSystemMetrics(SM_CYICON);
#335 #ifdef MSGBOX_ICONVCENTER
#336 rc.top = MSGBOXEX_MARGIN + (max(txtrect.bottom, rc.bottom) / 2) - (GetSystemMetrics(SM_CYICON) / 2);
#337 rc.top = max(MSGBOXEX_SPACING, rc.top);
#338 #else
#339 rc.top = MSGBOXEX_MARGIN;
#340 #endif
#341 btnleft = (nButtons * (btnsize.cx + MSGBOXEX_BUTTONSPACING)) - MSGBOXEX_BUTTONSPACING;
#342 if(btnleft > txtrect.right + rc.right + MSGBOXEX_SPACING)
#343 {
#344 #ifdef MSGBOX_TEXTHCENTER
#345 lmargin = MSGBOXEX_MARGIN + ((btnleft - txtrect.right - rc.right - MSGBOXEX_SPACING) / 2);
#346 #else
#347 lmargin = MSGBOXEX_MARGIN;
#348 #endif
#349 btnleft = MSGBOXEX_MARGIN;
#350 }
#351 else
#352 {
#353 lmargin = MSGBOXEX_MARGIN;
#354 btnleft = MSGBOXEX_MARGIN + ((txtrect.right + rc.right + MSGBOXEX_SPACING) / 2) - (btnleft / 2);
#355 }
#356 rc.left = lmargin;
#357 iico->x = (rc.left * 4) / LOWORD(units);
#358 iico->y = (rc.top * 8) / HIWORD(units);
#359 iico->cx = (rc.right * 4) / LOWORD(units);
#360 iico->cy = (rc.bottom * 8) / HIWORD(units);
#361 btntop = rc.top + rc.bottom + MSGBOXEX_SPACING;
#362 rc.left += rc.right + MSGBOXEX_SPACING;
#363 }
#364 else
#365 {
#366 btnleft = (nButtons * (btnsize.cx + MSGBOXEX_BUTTONSPACING)) - MSGBOXEX_BUTTONSPACING;
#367 if(btnleft > txtrect.right)
#368 {
#369 #ifdef MSGBOX_TEXTHCENTER
#370 lmargin = MSGBOXEX_MARGIN + ((btnleft - txtrect.right) / 2);
#371 #else
#372 lmargin = MSGBOXEX_MARGIN;
#373 #endif
#374 btnleft = MSGBOXEX_MARGIN;
#375 }
#376 else
#377 {
#378 lmargin = MSGBOXEX_MARGIN;
#379 btnleft = MSGBOXEX_MARGIN + (txtrect.right / 2) - (btnleft / 2);
#380 }
#381 rc.left = lmargin;
#382 }
计算按钮显示位置。
#383 /* calculate position of the text */
#384 rc.top = MSGBOXEX_MARGIN + (rc.bottom / 2) - (txtrect.bottom / 2);
#385 rc.top = max(rc.top, MSGBOXEX_MARGIN);
#386 /* calculate position of the buttons */
#387 btntop = max(rc.top + txtrect.bottom + MSGBOXEX_SPACING, btntop);
#388 for(i = 0; i < nButtons; i++)
#389 {
#390 ibtn[i]->x = (btnleft * 4) / LOWORD(units);
#391 ibtn[i]->y = (btntop * 8) / HIWORD(units);
#392 ibtn[i]->cx = (btnsize.cx * 4) / LOWORD(units);
#393 ibtn[i]->cy = (btnsize.cy * 8) / HIWORD(units);
#394 btnleft += btnsize.cx + MSGBOXEX_BUTTONSPACING;
#395 }
计算消息窗口的大小和位置。
#396 /* calculate size and position of the messagebox window */
#397 btnleft = max(btnleft - MSGBOXEX_BUTTONSPACING, rc.left + txtrect.right);
#398 btnleft += MSGBOXEX_MARGIN;
#399 btntop += btnsize.cy + MSGBOXEX_MARGIN;
#400 /* set size and position of the message static */
#401 itxt->x = (rc.left * 4) / LOWORD(units);
#402 itxt->y = (rc.top * 8) / HIWORD(units);
#403 itxt->cx = (((btnleft - rc.left - MSGBOXEX_MARGIN) * 4) / LOWORD(units));
#404 itxt->cy = ((txtrect.bottom * 8) / HIWORD(units));
#405 /* set size of the window */
#406 tpl->cx = (btnleft * 4) / LOWORD(units);
#407 tpl->cy = (btntop * 8) / HIWORD(units);
#408
填写下面的结构,并调用函数DialogBoxIndirectParamW来显示对话框窗口,MessageBoxProc作为对话框的消息处理函数。
#409 /* finally show the messagebox */
#410 mbi.Icon = Icon;
#411 mbi.Font = hFont;
#412 mbi.ContextHelpId = lpMsgBoxParams->dwContextHelpId;
#413 mbi.Callback = lpMsgBoxParams->lpfnMsgBoxCallback;
#414 mbi.Style = lpMsgBoxParams->dwStyle;
#415 mbi.nButtons = nButtons;
#416 mbi.Btns = &Buttons[0];
#417 mbi.Timeout = Timeout;
#418
#419 if(hDC)
#420 DeleteDC(hDC);
#421
#422 ret = DialogBoxIndirectParamW(lpMsgBoxParams->hInstance, tpl, lpMsgBoxParams->hwndOwner,
#423 MessageBoxProc, (LPARAM)&mbi);
#424
#425 if(hFont)
#426 DeleteObject(hFont);
#427
#428 RtlFreeHeap(GetProcessHeap(), 0, buf);
#429 return ret;
#430 }