Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

winable2.c

Go to the documentation of this file.
00001 /**************************** Module Header ********************************\ 00002 * Module Name: winable2.c 00003 * 00004 * This has the following Active Accesibility API 00005 * GetGUIThreadInfo 00006 * 00007 * The Win Event Hooks are handled in winable.c 00008 * 00009 * Copyright (c) 1985 - 1999, Microsoft Corporation 00010 * 00011 * History: 00012 * 08-30-96 IanJa Ported from Windows '95 00013 \***************************************************************************/ 00014 00015 #include "precomp.h" 00016 #pragma hdrstop 00017 00018 /*****************************************************************************\ 00019 * 00020 * GetGUIThreadInfo() 00021 * 00022 * This gets GUI information out of context. If you pass in a NULL thread ID, 00023 * we will get the 'global' information, using the foreground thread. This 00024 * is guaranteed to be the real active window, focus window, etc. Yes, you 00025 * could do it yourself by calling GetForegroundWindow, getting the thread ID 00026 * of that window via GetWindowThreadProcessId, then passing the ID into 00027 * GetGUIThreadInfo(). However, that takes three calls and aside from being 00028 * a pain, anything could happen in the middle. So passing in NULL gets 00029 * you stuff in one call and hence also works right. 00030 * 00031 * This function returns FALSE if the thread doesn't have a queue or the 00032 * thread ID is bogus. 00033 * 00034 \*****************************************************************************/ 00035 BOOL WINAPI 00036 _GetGUIThreadInfo(PTHREADINFO pti, PGUITHREADINFO pgui) 00037 { 00038 PQ pq; 00039 00040 /* 00041 * Validate threadinfo structure 00042 */ 00043 if (pgui->cbSize != sizeof(GUITHREADINFO)) { 00044 RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "GUITHREADINFO.cbSize %d is wrong", pgui->cbSize); 00045 return FALSE; 00046 } 00047 00048 /* 00049 * Is this a valid initialized GUI thread? 00050 */ 00051 if (pti != NULL) { 00052 if ((pq = pti->pq) == NULL) { 00053 // does this ever happen? 00054 RIPMSG1(RIP_ERROR, "GetGUIThreadInfo: No queue for pti %lx", pti); 00055 return FALSE; 00056 } 00057 } else { 00058 /* 00059 * Use the foreground queue. To get menu state information we must also 00060 * figure out the right pti. This matches _GetForegroundWindow() logic. 00061 */ 00062 if ((pq = gpqForeground) == NULL) { 00063 // this does sometimes happen... 00064 RIPMSG0(RIP_WARNING, "GetGUIThreadInfo: No foreground queue"); 00065 return FALSE; 00066 } 00067 00068 if (pq->spwndActive && (GETPTI(pq->spwndActive)->pq == pq)) { 00069 pti = GETPTI(pq->spwndActive); 00070 if (PtiCurrentShared()->rpdesk != pti->rpdesk) { 00071 RIPERR0(ERROR_ACCESS_DENIED, RIP_VERBOSE, "Foreground window on different desktop"); 00072 return FALSE; 00073 } 00074 } 00075 } 00076 00077 UserAssert(pq != NULL); 00078 00079 /* 00080 * For C2 security, verify that pq and pti are on the current thread's desktop. 00081 * We can't directly determine which desktop pq belongs to, but we can at 00082 * least ensure that any caret info we return is not from another desktop 00083 */ 00084 if (pq->caret.spwnd && 00085 (GETPTI(pq->caret.spwnd)->rpdesk != PtiCurrentShared()->rpdesk)) { 00086 RIPERR0(ERROR_ACCESS_DENIED, RIP_VERBOSE, "Foreground caret on different desktop"); 00087 return FALSE; 00088 } 00089 if (pti && (pti->rpdesk != PtiCurrentShared()->rpdesk)) { 00090 RIPERR0(ERROR_ACCESS_DENIED, RIP_VERBOSE, "Foreground thread on different desktop"); 00091 return FALSE; 00092 } 00093 00094 pgui->flags = 0; 00095 pgui->hwndMoveSize = NULL; 00096 pgui->hwndMenuOwner = NULL; 00097 00098 /* 00099 * Get Menu information from the THREADINFO 00100 */ 00101 if (pti != NULL) { 00102 if (pti->pmsd && !pti->pmsd->fTrackCancelled && pti->pmsd->spwnd) { 00103 pgui->flags |= GUI_INMOVESIZE; 00104 pgui->hwndMoveSize = HWq(pti->pmsd->spwnd); 00105 } 00106 00107 if (pti->pMenuState && pti->pMenuState->pGlobalPopupMenu) { 00108 pgui->flags |= GUI_INMENUMODE; 00109 00110 if (pti->pMenuState->pGlobalPopupMenu->fHasMenuBar) { 00111 if (pti->pMenuState->pGlobalPopupMenu->fIsSysMenu) { 00112 pgui->flags |= GUI_SYSTEMMENUMODE; 00113 } 00114 } else { 00115 pgui->flags |= GUI_POPUPMENUMODE; 00116 } 00117 00118 if (pti->pMenuState->pGlobalPopupMenu->spwndNotify) 00119 pgui->hwndMenuOwner = HWq(pti->pMenuState->pGlobalPopupMenu->spwndNotify); 00120 } 00121 } 00122 00123 /* 00124 * Get the rest of the information from the queue 00125 */ 00126 pgui->hwndActive = HW(pq->spwndActive); 00127 pgui->hwndFocus = HW(pq->spwndFocus); 00128 pgui->hwndCapture = HW(pq->spwndCapture); 00129 00130 pgui->hwndCaret = NULL; 00131 00132 if (pq->caret.spwnd) { 00133 pgui->hwndCaret = HWq(pq->caret.spwnd); 00134 00135 /* 00136 * These coords are always relative to the client of hwndCaret 00137 * of course. 00138 */ 00139 pgui->rcCaret.left = pq->caret.x; 00140 pgui->rcCaret.right = pgui->rcCaret.left + pq->caret.cx; 00141 pgui->rcCaret.top = pq->caret.y; 00142 pgui->rcCaret.bottom = pgui->rcCaret.top + pq->caret.cy; 00143 00144 if (pq->caret.iHideLevel == 0) 00145 pgui->flags |= GUI_CARETBLINKING; 00146 } else if (pti && (pti->ppi->W32PF_Flags & W32PF_CONSOLEHASFOCUS)) { 00147 /* 00148 * The thread is running in the console window with focus. Pull 00149 * out the info from the console pseudo caret. 00150 */ 00151 pgui->hwndCaret = pti->rpdesk->cciConsole.hwnd; 00152 pgui->rcCaret = pti->rpdesk->cciConsole.rc; 00153 } else { 00154 SetRectEmpty(&pgui->rcCaret); 00155 } 00156 00157 return TRUE; 00158 } 00159 00160 00161 /****************************************************************************\ 00162 * 00163 * _GetTitleBarInfo() 00164 * 00165 * Gets info about a window's title bar. If the window is bogus or 00166 * doesn't have a titlebar, this will fail. 00167 * 00168 \****************************************************************************/ 00169 BOOL WINAPI 00170 xxxGetTitleBarInfo(PWND pwnd, PTITLEBARINFO ptbi) 00171 { 00172 int cxB; 00173 00174 CheckLock(pwnd); 00175 00176 /* 00177 * Validate titlebarinfo structure 00178 */ 00179 if (ptbi->cbSize != sizeof(TITLEBARINFO)) { 00180 RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "TITLEBARINFO.cbSize %d is wrong", ptbi->cbSize); 00181 return FALSE; 00182 } 00183 00184 RtlZeroMemory(&ptbi->rgstate, sizeof(ptbi->rgstate)); 00185 00186 ptbi->rgstate[INDEX_TITLEBAR_SELF] |= STATE_SYSTEM_FOCUSABLE; 00187 if (TestWF(pwnd, WFBORDERMASK) != LOBYTE(WFCAPTION)) 00188 { 00189 // No titlebar. 00190 ptbi->rgstate[INDEX_TITLEBAR_SELF] |= STATE_SYSTEM_INVISIBLE; 00191 return TRUE; 00192 } 00193 00194 if (!TestWF(pwnd, WFMINIMIZED) && !TestWF(pwnd, WFCPRESENT)) 00195 { 00196 // Off screen (didn't fit) 00197 ptbi->rgstate[INDEX_TITLEBAR_SELF] |= STATE_SYSTEM_OFFSCREEN; 00198 SetRectEmpty(&ptbi->rcTitleBar); 00199 return TRUE; 00200 } 00201 00202 /* 00203 * Get titlebar rect 00204 */ 00205 ptbi->rcTitleBar = pwnd->rcWindow; 00206 cxB = GetWindowBorders(pwnd->style, pwnd->ExStyle, TRUE, FALSE); 00207 InflateRect(&ptbi->rcTitleBar, -cxB * SYSMET(CXBORDER), -cxB * SYSMET(CYBORDER)); 00208 if (TestWF(pwnd, WEFTOOLWINDOW)) { 00209 ptbi->rcTitleBar.bottom = ptbi->rcTitleBar.top + SYSMET(CYSMCAPTION); 00210 } else { 00211 ptbi->rcTitleBar.bottom = ptbi->rcTitleBar.top + SYSMET(CYCAPTION); 00212 } 00213 00214 /* 00215 * Don't include the system menu area! 00216 */ 00217 if (TestWF(pwnd, WFSYSMENU) && _HasCaptionIcon(pwnd)) 00218 ptbi->rcTitleBar.left += (ptbi->rcTitleBar.bottom - ptbi->rcTitleBar.top - SYSMET(CYBORDER)); 00219 00220 /* 00221 * Close button 00222 */ 00223 if (!TestWF(pwnd, WFSYSMENU) && TestWF(pwnd, WFWIN40COMPAT)) { 00224 ptbi->rgstate[INDEX_TITLEBAR_CLOSEBUTTON] |= STATE_SYSTEM_INVISIBLE; 00225 } else { 00226 if (!xxxMNCanClose(pwnd)) 00227 ptbi->rgstate[INDEX_TITLEBAR_CLOSEBUTTON] |= STATE_SYSTEM_UNAVAILABLE; 00228 00229 if (TestWF(pwnd, WFCLOSEBUTTONDOWN)) 00230 ptbi->rgstate[INDEX_TITLEBAR_CLOSEBUTTON] |= STATE_SYSTEM_PRESSED; 00231 } 00232 00233 00234 /* 00235 * Max button 00236 */ 00237 if (! TestWF(pwnd, WFSYSMENU) && TestWF(pwnd, WFWIN40COMPAT)) { 00238 ptbi->rgstate[INDEX_TITLEBAR_MAXBUTTON] |= STATE_SYSTEM_INVISIBLE; 00239 } else { 00240 if (! TestWF(pwnd, WFMAXBOX)) { 00241 if (! TestWF(pwnd, WFMINBOX)) { 00242 ptbi->rgstate[INDEX_TITLEBAR_MAXBUTTON] |= STATE_SYSTEM_INVISIBLE; 00243 } else { 00244 ptbi->rgstate[INDEX_TITLEBAR_MAXBUTTON] |= STATE_SYSTEM_UNAVAILABLE; 00245 } 00246 } 00247 00248 if (TestWF(pwnd, WFZOOMBUTTONDOWN)) 00249 ptbi->rgstate[INDEX_TITLEBAR_MAXBUTTON] |= STATE_SYSTEM_PRESSED; 00250 } 00251 00252 00253 /* 00254 * Min button 00255 */ 00256 if (! TestWF(pwnd, WFSYSMENU) && TestWF(pwnd, WFWIN40COMPAT)) { 00257 ptbi->rgstate[INDEX_TITLEBAR_MINBUTTON] |= STATE_SYSTEM_INVISIBLE; 00258 } else { 00259 if (! TestWF(pwnd, WFMINBOX)) { 00260 if (! TestWF(pwnd, WFMAXBOX)) { 00261 ptbi->rgstate[INDEX_TITLEBAR_MINBUTTON] |= STATE_SYSTEM_INVISIBLE; 00262 } else { 00263 ptbi->rgstate[INDEX_TITLEBAR_MINBUTTON] |= STATE_SYSTEM_UNAVAILABLE; 00264 } 00265 } 00266 00267 if (TestWF(pwnd, WFREDUCEBUTTONDOWN)) 00268 ptbi->rgstate[INDEX_TITLEBAR_MINBUTTON] |= STATE_SYSTEM_PRESSED; 00269 } 00270 00271 00272 /* 00273 * Help button 00274 */ 00275 if (!TestWF(pwnd, WEFCONTEXTHELP) || TestWF(pwnd, WFMINBOX) || 00276 TestWF(pwnd, WFMAXBOX)) { 00277 ptbi->rgstate[INDEX_TITLEBAR_HELPBUTTON] |= STATE_SYSTEM_INVISIBLE; 00278 } else { 00279 if (TestWF(pwnd, WFHELPBUTTONDOWN)) 00280 ptbi->rgstate[INDEX_TITLEBAR_HELPBUTTON] |= STATE_SYSTEM_PRESSED; 00281 } 00282 00283 // IME button BOGUS! 00284 ptbi->rgstate[INDEX_TITLEBAR_IMEBUTTON] = STATE_SYSTEM_INVISIBLE; 00285 00286 #if 0 00287 /* 00288 * System menu 00289 */ 00290 if (!TestWF(pwnd, WFSYSMENU) || !_HasCaptionIcon(pwnd)) 00291 ptbi->stateSysMenu |= STATE_SYSTEM_INVISIBLE; 00292 #endif 00293 00294 return TRUE; 00295 } 00296 00297 /*****************************************************************************\ 00298 * 00299 * _GetScrollBarInfo() 00300 * 00301 * Gets state & location information about a scrollbar. 00302 * 00303 * Note we fill in the minimal amount of useful info. OLEACC is responsible 00304 * for extrapolation. I.E., if both the line up and line down buttons are 00305 * disabled, the whole scrollbar is, and the thumb is invisible. 00306 * 00307 \*****************************************************************************/ 00308 BOOL WINAPI 00309 _GetScrollBarInfo(PWND pwnd, LONG idObject, PSCROLLBARINFO psbi) 00310 { 00311 UINT wDisable; 00312 BOOL fVertical; 00313 SBCALC SBCalc; 00314 00315 /* 00316 * Validate scrollbarinfo structure 00317 */ 00318 if (psbi->cbSize != sizeof(SCROLLBARINFO)) { 00319 RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "SCROLLBARINFO.cbSize %d is wrong", psbi->cbSize); 00320 return FALSE; 00321 } 00322 00323 RtlZeroMemory(&psbi->rgstate, sizeof(psbi->rgstate)); 00324 00325 /* 00326 * Calculate where everything is. 00327 */ 00328 if (idObject == OBJID_CLIENT) { 00329 RECT rc; 00330 wDisable = ((PSBWND)pwnd)->wDisableFlags; 00331 fVertical = ((PSBWND)pwnd)->fVert; 00332 GetRect(pwnd, &rc, GRECT_CLIENT | GRECT_CLIENTCOORDS); 00333 CalcSBStuff2(&SBCalc, &rc, (PSBDATA)&((PSBWND)pwnd)->SBCalc, ((PSBWND)pwnd)->fVert); 00334 } else { 00335 /* 00336 * Is this window scrollbar here? 00337 */ 00338 if (idObject == OBJID_VSCROLL) { 00339 fVertical = TRUE; 00340 if (! TestWF(pwnd, WFVSCROLL)) { 00341 // No scrollbar. 00342 psbi->rgstate[INDEX_SCROLLBAR_SELF] |= STATE_SYSTEM_INVISIBLE; 00343 } else if (! TestWF(pwnd, WFVPRESENT)) { 00344 // Window too short to display it. 00345 psbi->rgstate[INDEX_SCROLLBAR_SELF] |= STATE_SYSTEM_OFFSCREEN; 00346 } 00347 } else if (idObject == OBJID_HSCROLL) { 00348 fVertical = FALSE; 00349 if (! TestWF(pwnd, WFHSCROLL)) { 00350 // No scrollbar. 00351 psbi->rgstate[INDEX_SCROLLBAR_SELF] |= STATE_SYSTEM_INVISIBLE; 00352 } else if (! TestWF(pwnd, WFHPRESENT)) { 00353 psbi->rgstate[INDEX_SCROLLBAR_SELF] |= STATE_SYSTEM_OFFSCREEN; 00354 } 00355 } else { 00356 RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "invalid idObject %d", idObject); 00357 return FALSE; 00358 } 00359 00360 if (psbi->rgstate[INDEX_SCROLLBAR_SELF] & STATE_SYSTEM_INVISIBLE) 00361 return TRUE; 00362 00363 wDisable = GetWndSBDisableFlags(pwnd, fVertical); 00364 00365 if (!(psbi->rgstate[INDEX_SCROLLBAR_SELF] & STATE_SYSTEM_OFFSCREEN)) 00366 CalcSBStuff(pwnd, &SBCalc, fVertical); 00367 } 00368 00369 /* 00370 * Setup button states. 00371 */ 00372 if (wDisable & LTUPFLAG) { 00373 psbi->rgstate[INDEX_SCROLLBAR_UP] |= STATE_SYSTEM_UNAVAILABLE; 00374 psbi->rgstate[INDEX_SCROLLBAR_UPPAGE] |= STATE_SYSTEM_UNAVAILABLE; 00375 } 00376 00377 if (wDisable & RTDNFLAG) { 00378 psbi->rgstate[INDEX_SCROLLBAR_DOWN] |= STATE_SYSTEM_UNAVAILABLE; 00379 psbi->rgstate[INDEX_SCROLLBAR_DOWNPAGE] |= STATE_SYSTEM_UNAVAILABLE; 00380 } 00381 00382 if ((wDisable & (LTUPFLAG | RTDNFLAG)) == (LTUPFLAG | RTDNFLAG)) 00383 psbi->rgstate[INDEX_SCROLLBAR_SELF] |= STATE_SYSTEM_UNAVAILABLE; 00384 00385 /* 00386 * Button pressed? 00387 */ 00388 if (TestWF(pwnd, WFSCROLLBUTTONDOWN) && 00389 ((idObject != OBJID_VSCROLL) || TestWF(pwnd, WFVERTSCROLLTRACK))) { 00390 if (TestWF(pwnd, WFLINEUPBUTTONDOWN)) 00391 psbi->rgstate[INDEX_SCROLLBAR_UP] |= STATE_SYSTEM_PRESSED; 00392 00393 if (TestWF(pwnd, WFPAGEUPBUTTONDOWN)) 00394 psbi->rgstate[INDEX_SCROLLBAR_UPPAGE] |= STATE_SYSTEM_PRESSED; 00395 00396 if (TestWF(pwnd, WFPAGEDNBUTTONDOWN)) 00397 psbi->rgstate[INDEX_SCROLLBAR_DOWNPAGE] |= STATE_SYSTEM_PRESSED; 00398 00399 if (TestWF(pwnd, WFLINEDNBUTTONDOWN)) 00400 psbi->rgstate[INDEX_SCROLLBAR_DOWN] |= STATE_SYSTEM_PRESSED; 00401 } 00402 00403 /* 00404 * Fill in area locations. 00405 */ 00406 if (!(psbi->rgstate[INDEX_SCROLLBAR_SELF] & STATE_SYSTEM_OFFSCREEN)) { 00407 if (fVertical) { 00408 psbi->rcScrollBar.left = SBCalc.pxLeft; 00409 psbi->rcScrollBar.top = SBCalc.pxTop; 00410 psbi->rcScrollBar.right = SBCalc.pxRight; 00411 psbi->rcScrollBar.bottom = SBCalc.pxBottom; 00412 } else { 00413 psbi->rcScrollBar.left = SBCalc.pxTop; 00414 psbi->rcScrollBar.top = SBCalc.pxLeft; 00415 psbi->rcScrollBar.right = SBCalc.pxBottom; 00416 psbi->rcScrollBar.bottom = SBCalc.pxRight; 00417 } 00418 00419 if (idObject == OBJID_CLIENT) { 00420 OffsetRect(&psbi->rcScrollBar, pwnd->rcClient.left, pwnd->rcClient.top); 00421 } else { 00422 OffsetRect(&psbi->rcScrollBar, pwnd->rcWindow.left, pwnd->rcWindow.top); 00423 } 00424 00425 psbi->dxyLineButton = (SBCalc.pxUpArrow - SBCalc.pxTop); 00426 psbi->xyThumbTop = (SBCalc.pxThumbTop - SBCalc.pxTop); 00427 psbi->xyThumbBottom = (SBCalc.pxThumbBottom - SBCalc.pxTop); 00428 00429 /* 00430 * Is the thumb all the way to the left/top? If so, page up is 00431 * not visible. 00432 */ 00433 if (SBCalc.pxThumbTop == SBCalc.pxUpArrow) 00434 psbi->rgstate[INDEX_SCROLLBAR_UPPAGE] |= STATE_SYSTEM_INVISIBLE; 00435 00436 /* 00437 * Is the thumb all the way to the right/down? If so, page down 00438 * is not visible. 00439 */ 00440 if (SBCalc.pxThumbBottom == SBCalc.pxDownArrow) 00441 psbi->rgstate[INDEX_SCROLLBAR_DOWNPAGE] |= STATE_SYSTEM_INVISIBLE; 00442 } 00443 00444 return TRUE; 00445 } 00446 00447 00448 /*****************************************************************************\ 00449 * GetAncestor() 00450 * 00451 * This gets one of: 00452 * * The _real_ parent. This does NOT include the owner, unlike 00453 * GetParent(). Stops at a top level window unless we start with 00454 * the desktop. In which case, we return the desktop. 00455 * * The _real_ root, caused by walking up the chain getting the 00456 * ancestor. 00457 * * The _real_ owned root, caused by GetParent()ing up. 00458 \*****************************************************************************/ 00459 PWND WINAPI 00460 _GetAncestor(PWND pwnd, UINT gaFlags) 00461 { 00462 PWND pwndParent; 00463 00464 /* 00465 * If we start with the desktop return NULL. 00466 */ 00467 if (pwnd == PWNDDESKTOP(pwnd)) 00468 return NULL; 00469 00470 switch (gaFlags) { 00471 case GA_PARENT: 00472 pwnd = pwnd->spwndParent; 00473 break; 00474 00475 case GA_ROOT: 00476 while ((pwnd->spwndParent != PWNDDESKTOP(pwnd)) && 00477 (pwnd->spwndParent != PWNDMESSAGE(pwnd))) { 00478 pwnd = pwnd->spwndParent; 00479 } 00480 break; 00481 00482 case GA_ROOTOWNER: 00483 while (pwndParent = _GetParent(pwnd)) { 00484 pwnd = pwndParent; 00485 } 00486 break; 00487 } 00488 00489 return pwnd; 00490 } 00491 00492 00493 /*****************************************************************************\ 00494 * 00495 * RealChildWindowFromPoint() 00496 * 00497 * This returns the REAL child window at a point. The problem is that 00498 * ChildWindowFromPoint() doesn't deal with HTTRANSPARENT areas of 00499 * standard controls. We want to return a child behind a groupbox if it 00500 * is in the "clear" area. But we want to return a static field always 00501 * even though it too returns HTTRANSPARENT. 00502 * 00503 \*****************************************************************************/ 00504 PWND WINAPI 00505 _RealChildWindowFromPoint(PWND pwndParent, POINT pt) 00506 { 00507 PWND pwndChild; 00508 PWND pwndSave; 00509 00510 if (pwndParent != PWNDDESKTOP(pwndParent)) { 00511 pt.x += pwndParent->rcClient.left; 00512 pt.y += pwndParent->rcClient.top; 00513 } 00514 00515 /* 00516 * Is this point even in the parent? 00517 */ 00518 if (!PtInRect(&pwndParent->rcClient, pt) || 00519 (pwndParent->hrgnClip && !GrePtInRegion(pwndParent->hrgnClip, pt.x, pt.y))) { 00520 // Nope 00521 return NULL; 00522 } 00523 00524 pwndSave = NULL; 00525 00526 /* 00527 * Loop through the children. 00528 */ 00529 for (pwndChild = pwndParent->spwndChild; pwndChild; pwndChild = pwndChild->spwndNext) { 00530 if (!TestWF(pwndChild, WFVISIBLE)) 00531 continue; 00532 00533 /* 00534 * Is this point in the child's window? 00535 */ 00536 if (!PtInRect(&pwndChild->rcWindow, pt) || 00537 (pwndChild->hrgnClip && !GrePtInRegion(pwndChild->hrgnClip, pt.x, pt.y))) 00538 continue; 00539 00540 /* 00541 * OK, we are in somebody's window. Is this by chance a group box? 00542 */ 00543 if ((pwndChild->pcls->atomClassName == gpsi->atomSysClass[ICLS_BUTTON]) || 00544 (GETFNID(pwndChild) == FNID_BUTTON)) { 00545 if (TestWF(pwndChild, BFTYPEMASK) == LOBYTE(BS_GROUPBOX)) { 00546 pwndSave = pwndChild; 00547 continue; 00548 } 00549 } 00550 00551 return pwndChild; 00552 } 00553 00554 /* 00555 * Did we save a groupbox which turned out to have nothing behind it 00556 * at that point? 00557 */ 00558 if (pwndSave) { 00559 return pwndSave; 00560 } else { 00561 return pwndParent; 00562 } 00563 } 00564 00565 00566 /*****************************************************************************\ 00567 * xxxGetMenuBarInfo() 00568 * 00569 * This succeeds if the menu/menu item exists. 00570 * 00571 * Parameters: 00572 * pwnd window 00573 * idObject this can be OBJID_MENU, OBJID_SYSMENU, or OBJID_CLIENT 00574 * idItem which thing do we need info on? 0..cItems. 0 indicates 00575 * the menu itself, 1 is the first item on the menu... 00576 * pmbi Pointer to a MENUBARINFO structure that gets filled in 00577 * 00578 \*****************************************************************************/ 00579 BOOL WINAPI 00580 xxxGetMenuBarInfo(PWND pwnd, long idObject, long idItem, PMENUBARINFO pmbi) 00581 { 00582 PMENU pMenu; 00583 int cBorders; 00584 PITEM pItem; 00585 PPOPUPMENU ppopup; 00586 00587 CheckLock(pwnd); 00588 00589 /* 00590 * Validate menubarinfo structure 00591 */ 00592 if (pmbi->cbSize != sizeof(MENUBARINFO)) { 00593 RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "MENUBARINFO.cbSize %d is wrong", pmbi->cbSize); 00594 return FALSE; 00595 } 00596 00597 /* 00598 * Initialize the fields 00599 */ 00600 SetRectEmpty(&pmbi->rcBar); 00601 pmbi->hMenu = NULL; 00602 pmbi->hwndMenu = NULL; 00603 pmbi->fBarFocused = FALSE; 00604 pmbi->fFocused = FALSE; 00605 00606 /* 00607 * Get the menu handle we will deal with. 00608 */ 00609 if (idObject == OBJID_MENU) { 00610 int cBorders; 00611 00612 if (TestWF(pwnd, WFCHILD) || !pwnd->spmenu) 00613 return FALSE; 00614 00615 pMenu = pwnd->spmenu; 00616 if (!pMenu) 00617 return FALSE; 00618 00619 // If we have an item, is it in the valid range? 00620 if ((idItem < 0) || ((DWORD)idItem > pMenu->cItems)) 00621 return FALSE; 00622 00623 /* 00624 * Menu handle 00625 */ 00626 pmbi->hMenu = PtoHq(pMenu); 00627 00628 /* 00629 * Menu rect 00630 */ 00631 if (pMenu->cxMenu && pMenu->cyMenu) { 00632 if (!idItem) { 00633 cBorders = GetWindowBorders(pwnd->style, pwnd->ExStyle, TRUE, FALSE); 00634 pmbi->rcBar.left = pwnd->rcWindow.left + cBorders * SYSMET(CXBORDER); 00635 pmbi->rcBar.top = pwnd->rcWindow.top + cBorders * SYSMET(CYBORDER); 00636 00637 if (TestWF(pwnd, WFCPRESENT)) { 00638 pmbi->rcBar.top += (TestWF(pwnd, WEFTOOLWINDOW) ? SYSMET(CYSMCAPTION) : SYSMET(CYCAPTION)); 00639 } 00640 00641 pmbi->rcBar.right = pmbi->rcBar.left + pMenu->cxMenu; 00642 pmbi->rcBar.bottom = pmbi->rcBar.top + pMenu->cyMenu; 00643 } else { 00644 pItem = pMenu->rgItems + idItem - 1; 00645 00646 pmbi->rcBar.left = pwnd->rcWindow.left + pItem->xItem; 00647 pmbi->rcBar.top = pwnd->rcWindow.top + pItem->yItem; 00648 pmbi->rcBar.right = pmbi->rcBar.left + pItem->cxItem; 00649 pmbi->rcBar.bottom = pmbi->rcBar.top + pItem->cyItem; 00650 } 00651 } 00652 00653 /* 00654 * Are we currently in app menu bar mode? 00655 */ 00656 ppopup = GetpGlobalPopupMenu(pwnd); 00657 if (ppopup && ppopup->fHasMenuBar && !ppopup->fIsSysMenu && 00658 (ppopup->spwndNotify == pwnd)) 00659 { 00660 // Yes, we are. 00661 pmbi->fBarFocused = TRUE; 00662 00663 if (!idItem) { 00664 pmbi->fFocused = TRUE; 00665 } else if (ppopup->ppopupmenuRoot->posSelectedItem == (UINT)idItem-1) { 00666 pmbi->fFocused = TRUE; 00667 UserAssert(ppopup->ppopupmenuRoot); 00668 pmbi->hwndMenu = HW(ppopup->ppopupmenuRoot->spwndNextPopup); 00669 } 00670 } 00671 00672 } else if (idObject == OBJID_SYSMENU) { 00673 if (!TestWF(pwnd, WFSYSMENU)) 00674 return FALSE; 00675 00676 pMenu = xxxGetSysMenu(pwnd, FALSE); 00677 if (!pMenu) 00678 return FALSE; 00679 00680 // If we have an item, is it in the valid range? 00681 if ((idItem < 0) || ((DWORD)idItem > pMenu->cItems)) 00682 return FALSE; 00683 00684 pmbi->hMenu = PtoHq(pMenu); 00685 00686 /* 00687 * Menu rect 00688 */ 00689 if (_HasCaptionIcon(pwnd)) { 00690 // The menu and single item take up the same space 00691 cBorders = GetWindowBorders(pwnd->style, pwnd->ExStyle, TRUE, FALSE); 00692 pmbi->rcBar.left = pwnd->rcWindow.left + cBorders * SYSMET(CXBORDER); 00693 pmbi->rcBar.top = pwnd->rcWindow.top + cBorders * SYSMET(CYBORDER); 00694 00695 pmbi->rcBar.right = pmbi->rcBar.left + 00696 (TestWF(pwnd, WEFTOOLWINDOW) ? SYSMET(CXSMSIZE) : SYSMET(CXSIZE)); 00697 00698 pmbi->rcBar.bottom = pmbi->rcBar.top + 00699 (TestWF(pwnd, WEFTOOLWINDOW) ? SYSMET(CYSMSIZE) : SYSMET(CYSIZE)); 00700 } 00701 00702 /* 00703 * Are we currently in system menu bar mode? 00704 */ 00705 ppopup = GetpGlobalPopupMenu(pwnd); 00706 if (ppopup && ppopup->fHasMenuBar && ppopup->fIsSysMenu && 00707 (ppopup->spwndNotify == pwnd)) 00708 { 00709 // Yes, we are. 00710 pmbi->fBarFocused = TRUE; 00711 00712 if (!idItem) { 00713 pmbi->fFocused = TRUE; 00714 } else if (ppopup->ppopupmenuRoot->posSelectedItem == (UINT)idItem - 1) { 00715 pmbi->fFocused = TRUE; 00716 UserAssert(ppopup->ppopupmenuRoot); 00717 pmbi->hwndMenu = HW(ppopup->ppopupmenuRoot->spwndNextPopup); 00718 } 00719 } 00720 } 00721 else if (idObject == OBJID_CLIENT) 00722 { 00723 HMENU hMenu; 00724 hMenu = (HMENU)xxxSendMessage(pwnd, MN_GETHMENU, 0, 0); 00725 pMenu = HtoP(hMenu); 00726 if (!pMenu) 00727 return FALSE; 00728 00729 // If we have an item, is it in the valid range? 00730 if ((idItem < 0) || ((DWORD)idItem > pMenu->cItems)) 00731 return FALSE; 00732 00733 pmbi->hMenu = hMenu; 00734 00735 if (!idItem) { 00736 pmbi->rcBar = pwnd->rcClient; 00737 } else { 00738 pItem = pMenu->rgItems + idItem - 1; 00739 00740 pmbi->rcBar.left = pwnd->rcClient.left + pItem->xItem; 00741 pmbi->rcBar.top = pwnd->rcClient.top + pItem->yItem; 00742 pmbi->rcBar.right = pmbi->rcBar.left + pItem->cxItem; 00743 pmbi->rcBar.bottom = pmbi->rcBar.top + pItem->cyItem; 00744 } 00745 00746 /* 00747 * Are we currently in popup mode with us as one of the popups 00748 * showing? 00749 */ 00750 ppopup = ((PMENUWND)pwnd)->ppopupmenu; 00751 if (ppopup && (ppopup->ppopupmenuRoot == GetpGlobalPopupMenu(pwnd))) { 00752 pmbi->fBarFocused = TRUE; 00753 00754 if (!idItem) { 00755 pmbi->fFocused = TRUE; 00756 } else if ((UINT)idItem == ppopup->posSelectedItem + 1) { 00757 pmbi->fFocused = TRUE; 00758 pmbi->hwndMenu = HW(ppopup->spwndNextPopup); 00759 } 00760 } 00761 } else { 00762 return FALSE; 00763 } 00764 00765 return TRUE; 00766 } 00767 00768 00769 /***************************************************************************\ 00770 * 00771 * _GetComboBoxInfo() 00772 * 00773 * This returns combobox information for either a combo or its dropdown 00774 * list. 00775 * 00776 \***************************************************************************/ 00777 BOOL WINAPI 00778 _GetComboBoxInfo(PWND pwnd, PCOMBOBOXINFO pcbi) 00779 { 00780 PCLS pcls; 00781 COMBOBOXINFO cbi = { 00782 sizeof cbi, 00783 }; 00784 BOOL fOtherProcess; 00785 BOOL bRetval = FALSE; 00786 WORD wWindowType = 0; 00787 00788 /* 00789 * Make sure it is a combobox or a dropdown 00790 */ 00791 pcls = pwnd->pcls; 00792 00793 00794 if ((GETFNID(pwnd) == FNID_COMBOBOX) || 00795 (pcls->atomClassName == gpsi->atomSysClass[ICLS_COMBOBOX])) { 00796 wWindowType = FNID_COMBOBOX; 00797 } else if ((GETFNID(pwnd) == FNID_COMBOLISTBOX) || 00798 (pcls->atomClassName == gpsi->atomSysClass[ICLS_COMBOLISTBOX])) { 00799 wWindowType = FNID_COMBOLISTBOX; 00800 } else { 00801 RIPERR1(ERROR_WINDOW_NOT_COMBOBOX, RIP_WARNING, 00802 "pwnd %#p not a combobox or dropdown", pwnd); 00803 return FALSE; 00804 } 00805 00806 /* 00807 * Validate combo structure 00808 */ 00809 if (pcbi->cbSize != sizeof(COMBOBOXINFO)) { 00810 RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "COMBOBOXINFO.cbSize %d is wrong", pcbi->cbSize); 00811 return FALSE; 00812 } 00813 00814 if (fOtherProcess = (GETPTI(pwnd)->ppi != PpiCurrent())) { 00815 KeAttachProcess(&GETPTI(pwnd)->ppi->Process->Pcb); 00816 } 00817 00818 try { 00819 PCBOX ccxPcboxSnap; 00820 PWND ccxPwndSnap; 00821 HWND ccxHwndSnap; 00822 00823 /* 00824 * Snap and probe the CBOX structure, since it is client side. 00825 */ 00826 if (wWindowType == FNID_COMBOBOX) { 00827 ccxPcboxSnap = ((PCOMBOWND)pwnd)->pcbox; 00828 } else { 00829 PLBIV ccxPlbSnap; 00830 /* 00831 * If this is a listbox, we must snap and probe the LBIV structure 00832 * in order to get to the CBOX structure. 00833 */ 00834 ccxPlbSnap = ((PLBWND)pwnd)->pLBIV; 00835 if (!ccxPlbSnap) { 00836 goto errorexit; 00837 } 00838 ProbeForRead(ccxPlbSnap, sizeof(LBIV), DATAALIGN); 00839 ccxPcboxSnap = ccxPlbSnap->pcbox; 00840 } 00841 if (!ccxPcboxSnap) { 00842 goto errorexit; 00843 } 00844 ProbeForRead(ccxPcboxSnap, sizeof(CBOX), DATAALIGN); 00845 00846 /* 00847 * Get the combo information now 00848 */ 00849 00850 /* 00851 * Snap and probe the client side pointer to the Combo window 00852 */ 00853 ccxPwndSnap = ccxPcboxSnap->spwnd; 00854 ProbeForRead(ccxPwndSnap, sizeof(HEAD), DATAALIGN); 00855 cbi.hwndCombo = HWCCX(ccxPwndSnap); 00856 00857 /* 00858 * Snap & probe the client side pointer to the Edit window. 00859 * To compare spwndEdit and pwnd, we should compare handles 00860 * since spwndEdit is a client-side address and pwnd is a 00861 * kernel-mode address, 00862 */ 00863 00864 ccxPwndSnap = ccxPcboxSnap->spwndEdit; 00865 /* 00866 * If combobox is not fully initialized and spwndEdit is NULL, 00867 * we should fail. 00868 */ 00869 ProbeForRead(ccxPwndSnap, sizeof(HEAD), DATAALIGN); 00870 ccxHwndSnap = HWCCX(ccxPwndSnap); 00871 if (ccxHwndSnap == HW(pwnd)) { 00872 /* 00873 * ComboBox doesn't have Edit control. 00874 */ 00875 cbi.hwndItem = NULL; 00876 } else { 00877 cbi.hwndItem = HWCCX(ccxPwndSnap); 00878 } 00879 00880 /* 00881 * Snap and probe the client side pointer to the List window 00882 */ 00883 ccxPwndSnap = ccxPcboxSnap->spwndList; 00884 /* 00885 * If combobox is not fully initialized and spwndList is NULL, 00886 * we should fail. 00887 */ 00888 ProbeForRead(ccxPwndSnap, sizeof(HEAD), DATAALIGN); 00889 cbi.hwndList = HWCCX(ccxPwndSnap); 00890 00891 /* 00892 * Snap the rest of the combo information. 00893 * We don't need to probe any of these, since there are no more indirections. 00894 */ 00895 cbi.rcItem = ccxPcboxSnap->editrc; 00896 cbi.rcButton = ccxPcboxSnap->buttonrc; 00897 00898 /* 00899 * Button state 00900 */ 00901 cbi.stateButton = 0; 00902 if (ccxPcboxSnap->CBoxStyle == CBS_SIMPLE) { 00903 cbi.stateButton |= STATE_SYSTEM_INVISIBLE; 00904 } 00905 if (ccxPcboxSnap->fButtonPressed) { 00906 cbi.stateButton |= STATE_SYSTEM_PRESSED; 00907 } 00908 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 00909 goto errorexit; 00910 } 00911 00912 *pcbi = cbi; 00913 bRetval = TRUE; 00914 00915 errorexit: 00916 if (fOtherProcess) { 00917 KeDetachProcess(); 00918 } 00919 return bRetval; 00920 } 00921 00922 00923 /***************************************************************************\ 00924 * 00925 * _GetListBoxInfo() 00926 * 00927 * Currently returns back the # of items per column. There is no way to get 00928 * or calculate this info any other way in a multicolumn list. 00929 * 00930 * For now, no structure is returned. If we ever need one more thing, make one. 00931 * 00932 * Since I have to run on multiple platforms, I can't define a message. 00933 * To do so would require that 00934 * * I make changes to the thunk table 00935 * * I make sure the 32-bit define doesn't collide with some NT new msg 00936 * * I use a different value on Win '95 vs Memphis due to additions 00937 * * I test apps extensively since many of them pass on bogus valued 00938 * messages to the listbox handler which checks to see if they 00939 * are in range. In other words, any value I pick is probably 00940 * going to flake out MSVC++ 4.0. 00941 * 00942 * Ergo an API instead. 00943 * 00944 \***************************************************************************/ 00945 DWORD WINAPI 00946 _GetListBoxInfo(PWND pwnd) 00947 { 00948 PCLS pcls; 00949 DWORD dwRet = 0; 00950 BOOL fOtherProcess; 00951 00952 /* 00953 * Make sure it is a combobox or a dropdown 00954 */ 00955 pcls = pwnd->pcls; 00956 if ((pcls->atomClassName != gpsi->atomSysClass[ICLS_LISTBOX]) && 00957 (GETFNID(pwnd) != FNID_LISTBOX)) { 00958 RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "pwnd %#p is not a listbox", pwnd); 00959 return 0; 00960 } 00961 00962 if (fOtherProcess = (GETPTI(pwnd)->ppi != PpiCurrent())) { 00963 KeAttachProcess(&GETPTI(pwnd)->ppi->Process->Pcb); 00964 } 00965 00966 try { 00967 PLBIV ccxPlbSnap; 00968 00969 /* 00970 * Snap and probe the pointer to the LBIV, since it is client-side. 00971 */ 00972 ccxPlbSnap = ((PLBWND)pwnd)->pLBIV; 00973 if (!ccxPlbSnap) { 00974 goto errorexit; 00975 } 00976 ProbeForRead(ccxPlbSnap, sizeof(LBIV), DATAALIGN); 00977 00978 if (ccxPlbSnap->fMultiColumn) { 00979 dwRet = ccxPlbSnap->itemsPerColumn; 00980 } else { 00981 dwRet = ccxPlbSnap->cMac; 00982 } 00983 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 00984 dwRet = 0; 00985 } 00986 00987 errorexit: 00988 if (fOtherProcess) { 00989 KeDetachProcess(); 00990 } 00991 00992 return dwRet; 00993 }

Generated on Sat May 15 19:42:25 2004 for test by doxygen 1.3.7