1 /* 2 * COPYRIGHT: GNU GPL, See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * PURPOSE: Coordinate systems 5 * FILE: win32ss/gdi/ntgdi/coord.c 6 * PROGRAMER: Timo Kreuzer (timo.kreuzer@rectos.org) 7 */ 8 9 /* Coordinate translation overview 10 * ------------------------------- 11 * 12 * Windows uses 3 different coordinate systems, referred to as world space, 13 * page space and device space. 14 * 15 * Device space: 16 * This is the coordinate system of the physical device that displays the 17 * graphics. One unit matches one pixel of the surface. The coordinate system 18 * is always orthogonal. 19 * 20 * Page space: 21 * This is the coordinate system on the screen or on the paper layout for 22 * printer devices. The coordinate system is also orthogonal but one unit 23 * does not necessarily match one pixel. Instead there are different mapping 24 * modes that can be set using SetMapMode() that specify how page space units 25 * are transformed into device space units. These mapping modes are: 26 * - MM_TEXT: One unit matches one unit in device space (one pixel) 27 * - MM_TWIPS One unit matches 1/20 point (1/1440 inch) 28 * - MM_LOMETRIC: One unit matches 0.1 millimeter 29 * - MM_HIMETRIC: One unit matches 0.01 millimeter 30 * - MM_LOENGLISH: One unit matches 0.01 inch 31 * - MM_HIENGLISH: One unit matches 0.001 inch 32 * - MM_ISOTROPIC: 33 * - MM_ANISOTROPIC: 34 * If the mapping mode is either MM_ISOTROPIC or MM_ANISOTROPIC, the actual 35 * transformation is calculated from the window and viewport extension. 36 * The window extension can be set using SetWindowExtEx() and describes the 37 * extents of an arbitrary window (not to confuse with the gui element!) in 38 * page space coordinates. 39 * The viewport extension can be set using SetViewportExtEx() and describes 40 * the extent of the same window in device space coordinates. If the mapping 41 * mode is MM_ISOTROPIC one of the viewport extensions can be adjusted by GDI 42 * to make sure the mapping stays isotropic, i.e. that it has the same x/y 43 * ratio as the window extension. 44 * 45 * World space: 46 * World space is the coordinate system that is used for all GDI drawing 47 * operations. The metrics of this coordinate system depend on the DCs 48 * graphics mode, which can be set using SetGraphicsMode(). 49 * If the graphics mode is GM_COMPATIBLE, world space is identical to page 50 * space and no additional transformation is applied. 51 * If the graphics mode is GM_ADVANCED, an arbitrary coordinate transformation 52 * can be set using SetWorldTransform(), which is applied to transform world 53 * space coordinates into page space coordinates. 54 * 55 * User mode data: 56 * All coordinate translation data is stored in the DC attribute, so the values 57 * might be invalid. This has to be taken into account. Values might also be 58 * zero, so when a division is made, the value has to be read first and then 59 * checked! This is true for both integer and floating point values, even if 60 * we cannot get floating point exceptions on x86, we can get them on all other 61 * architectures that use the FPU directly instead of emulation. 62 * The result of all operations might be completely random and invalid, if it was 63 * messed with in an illegal way in user mode. This is not a problem, since the 64 * result of coordinate transformations are never expected to be "valid" values. 65 * In the worst case, the drawing operation draws rubbish into the DC. 66 */ 67 68 /* INCLUDES ******************************************************************/ 69 70 #include <win32k.h> 71 72 #define NDEBUG 73 #include <debug.h> 74 C_ASSERT(sizeof(XFORML) == sizeof(XFORM)); 75 76 77 /* GLOBALS *******************************************************************/ 78 79 const MATRIX gmxIdentity = 80 { 81 FLOATOBJ_1, FLOATOBJ_0, 82 FLOATOBJ_0, FLOATOBJ_1, 83 FLOATOBJ_0, FLOATOBJ_0, 84 0, 0, XFORM_NO_TRANSLATION|XFORM_FORMAT_LTOL|XFORM_UNITY|XFORM_SCALE 85 }; 86 87 88 /* FUNCTIONS *****************************************************************/ 89 90 VOID 91 FASTCALL 92 DC_vFixIsotropicMapping(PDC pdc) 93 { 94 PDC_ATTR pdcattr; 95 LONG64 fx, fy; 96 LONG s; 97 SIZEL szlWindowExt, szlViewportExt; 98 ASSERT(pdc->pdcattr->iMapMode == MM_ISOTROPIC); 99 100 /* Get a pointer to the DC_ATTR */ 101 pdcattr = pdc->pdcattr; 102 103 /* Read the extents, we rely on non-null values */ 104 szlWindowExt = pdcattr->szlWindowExt; 105 szlViewportExt = pdcattr->szlViewportExt; 106 107 /* Check if all values are valid */ 108 if ((szlWindowExt.cx == 0) || (szlWindowExt.cy == 0) || 109 (szlViewportExt.cx == 0) || (szlViewportExt.cy == 0)) 110 { 111 /* Someone put rubbish into the fields, just ignore it. */ 112 return; 113 } 114 115 fx = abs((LONG64)szlWindowExt.cx * szlViewportExt.cy); 116 fy = abs((LONG64)szlWindowExt.cy * szlViewportExt.cx); 117 118 if (fx < fy) 119 { 120 s = (szlWindowExt.cy ^ szlViewportExt.cx) > 0 ? 1 : -1; 121 pdcattr->szlViewportExt.cx = (LONG)(fx * s / szlWindowExt.cy); 122 } 123 else if (fx > fy) 124 { 125 s = (szlWindowExt.cx ^ szlViewportExt.cy) > 0 ? 1 : -1; 126 pdcattr->szlViewportExt.cy = (LONG)(fy * s / szlWindowExt.cx); 127 } 128 129 /* Reset the flag */ 130 pdc->pdcattr->flXform &= ~PAGE_EXTENTS_CHANGED; 131 } 132 133 VOID 134 FASTCALL 135 DC_vGetPageToDevice(PDC pdc, MATRIX *pmx) 136 { 137 PDC_ATTR pdcattr = pdc->pdcattr; 138 PSIZEL pszlViewPortExt; 139 SIZEL szlWindowExt; 140 141 /* Get the viewport extension */ 142 pszlViewPortExt = DC_pszlViewportExt(pdc); 143 144 /* Copy the window extension, so no one can mess with it */ 145 szlWindowExt = pdcattr->szlWindowExt; 146 147 /* No shearing / rotation */ 148 FLOATOBJ_SetLong(&pmx->efM12, 0); 149 FLOATOBJ_SetLong(&pmx->efM21, 0); 150 151 /* Calculate scaling */ 152 if (szlWindowExt.cx != 0) 153 { 154 FLOATOBJ_SetLong(&pmx->efM11, pszlViewPortExt->cx); 155 FLOATOBJ_DivLong(&pmx->efM11, szlWindowExt.cx); 156 } 157 else 158 FLOATOBJ_SetLong(&pmx->efM11, 1); 159 160 if (szlWindowExt.cy != 0) 161 { 162 FLOATOBJ_SetLong(&pmx->efM22, pszlViewPortExt->cy); 163 FLOATOBJ_DivLong(&pmx->efM22, szlWindowExt.cy); 164 } 165 else 166 FLOATOBJ_SetLong(&pmx->efM22, 1); 167 168 /* Calculate x offset */ 169 FLOATOBJ_SetLong(&pmx->efDx, -pdcattr->ptlWindowOrg.x); 170 FLOATOBJ_Mul(&pmx->efDx, &pmx->efM11); 171 FLOATOBJ_AddLong(&pmx->efDx, pdcattr->ptlViewportOrg.x); 172 173 /* Calculate y offset */ 174 FLOATOBJ_SetLong(&pmx->efDy, -pdcattr->ptlWindowOrg.y); 175 FLOATOBJ_Mul(&pmx->efDy, &pmx->efM22); 176 FLOATOBJ_AddLong(&pmx->efDy, pdcattr->ptlViewportOrg.y); 177 } 178 179 VOID 180 FASTCALL 181 DC_vUpdateWorldToDevice(PDC pdc) 182 { 183 XFORMOBJ xoPageToDevice, xoWorldToPage, xoWorldToDevice; 184 MATRIX mxPageToDevice; 185 186 // FIXME: make sure world-to-page is valid! 187 188 /* Construct a transformation to do the page-to-device conversion */ 189 DC_vGetPageToDevice(pdc, &mxPageToDevice); 190 XFORMOBJ_vInit(&xoPageToDevice, &mxPageToDevice); 191 192 /* Recalculate the world-to-device xform */ 193 XFORMOBJ_vInit(&xoWorldToPage, &pdc->pdcattr->mxWorldToPage); 194 XFORMOBJ_vInit(&xoWorldToDevice, &pdc->pdcattr->mxWorldToDevice); 195 XFORMOBJ_iCombine(&xoWorldToDevice, &xoWorldToPage, &xoPageToDevice); 196 197 /* Reset the flags */ 198 pdc->pdcattr->flXform &= ~(PAGE_XLATE_CHANGED|PAGE_EXTENTS_CHANGED|WORLD_XFORM_CHANGED); 199 } 200 201 VOID 202 FASTCALL 203 DC_vUpdateDeviceToWorld(PDC pdc) 204 { 205 XFORMOBJ xoWorldToDevice, xoDeviceToWorld; 206 PMATRIX pmxWorldToDevice; 207 208 /* Get the world-to-device translation */ 209 pmxWorldToDevice = DC_pmxWorldToDevice(pdc); 210 XFORMOBJ_vInit(&xoWorldToDevice, pmxWorldToDevice); 211 212 /* Create inverse of world-to-device transformation */ 213 XFORMOBJ_vInit(&xoDeviceToWorld, &pdc->pdcattr->mxDeviceToWorld); 214 if (XFORMOBJ_iInverse(&xoDeviceToWorld, &xoWorldToDevice) == DDI_ERROR) 215 { 216 // FIXME: do we need to reset anything? 217 return; 218 } 219 220 /* Reset the flag */ 221 pdc->pdcattr->flXform &= ~DEVICE_TO_WORLD_INVALID; 222 } 223 224 BOOL 225 NTAPI 226 GreCombineTransform( 227 XFORML *pxformDest, 228 XFORML *pxform1, 229 XFORML *pxform2) 230 { 231 MATRIX mxDest, mx1, mx2; 232 XFORMOBJ xoDest, xo1, xo2; 233 234 /* Check for illegal parameters */ 235 if (!pxformDest || !pxform1 || !pxform2) return FALSE; 236 237 /* Initialize XFORMOBJs */ 238 XFORMOBJ_vInit(&xoDest, &mxDest); 239 XFORMOBJ_vInit(&xo1, &mx1); 240 XFORMOBJ_vInit(&xo2, &mx2); 241 242 /* Convert the XFORMLs into XFORMOBJs */ 243 XFORMOBJ_iSetXform(&xo1, pxform1); 244 XFORMOBJ_iSetXform(&xo2, pxform2); 245 246 /* Combine them */ 247 XFORMOBJ_iCombine(&xoDest, &xo1, &xo2); 248 249 /* Translate back into XFORML */ 250 XFORMOBJ_iGetXform(&xoDest, pxformDest); 251 252 return TRUE; 253 } 254 255 BOOL 256 APIENTRY 257 NtGdiCombineTransform( 258 LPXFORM UnsafeXFormResult, 259 LPXFORM Unsafexform1, 260 LPXFORM Unsafexform2) 261 { 262 BOOL Ret; 263 264 _SEH2_TRY 265 { 266 ProbeForWrite(UnsafeXFormResult, sizeof(XFORM), 1); 267 ProbeForRead(Unsafexform1, sizeof(XFORM), 1); 268 ProbeForRead(Unsafexform2, sizeof(XFORM), 1); 269 Ret = GreCombineTransform((XFORML*)UnsafeXFormResult, 270 (XFORML*)Unsafexform1, 271 (XFORML*)Unsafexform2); 272 } 273 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 274 { 275 Ret = FALSE; 276 } 277 _SEH2_END; 278 279 return Ret; 280 } 281 282 // FIXME: Should be XFORML and use XFORMOBJ functions directly 283 BOOL 284 APIENTRY 285 NtGdiGetTransform( 286 HDC hdc, 287 DWORD iXform, 288 LPXFORM pXForm) 289 { 290 PDC pdc; 291 BOOL ret = TRUE; 292 MATRIX mxPageToDevice; 293 XFORMOBJ xo; 294 PMATRIX pmx; 295 296 if (!pXForm) 297 { 298 EngSetLastError(ERROR_INVALID_PARAMETER); 299 return FALSE; 300 } 301 302 pdc = DC_LockDc(hdc); 303 if (!pdc) 304 { 305 EngSetLastError(ERROR_INVALID_HANDLE); 306 return FALSE; 307 } 308 309 switch (iXform) 310 { 311 case GdiWorldSpaceToPageSpace: 312 pmx = DC_pmxWorldToPage(pdc); 313 break; 314 315 case GdiWorldSpaceToDeviceSpace: 316 pmx = DC_pmxWorldToDevice(pdc); 317 break; 318 319 case GdiDeviceSpaceToWorldSpace: 320 pmx = DC_pmxDeviceToWorld(pdc); 321 break; 322 323 case GdiPageSpaceToDeviceSpace: 324 DC_vGetPageToDevice(pdc, &mxPageToDevice); 325 pmx = &mxPageToDevice; 326 break; 327 328 default: 329 DPRINT1("Unknown transform %lu\n", iXform); 330 ret = FALSE; 331 goto leave; 332 } 333 334 /* Initialize an XFORMOBJ */ 335 XFORMOBJ_vInit(&xo, pmx); 336 337 _SEH2_TRY 338 { 339 ProbeForWrite(pXForm, sizeof(XFORML), 1); 340 XFORMOBJ_iGetXform(&xo, (XFORML*)pXForm); 341 } 342 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 343 { 344 ret = FALSE; 345 } 346 _SEH2_END; 347 348 leave: 349 DC_UnlockDc(pdc); 350 return ret; 351 } 352 353 354 /*! 355 * Converts points from logical coordinates into device coordinates. 356 * Conversion depends on the mapping mode, 357 * world transfrom, viewport origin settings for the given device context. 358 * \param hDC device context. 359 * \param Points an array of POINT structures (in/out). 360 * \param Count number of elements in the array of POINT structures. 361 * \return TRUE if success, FALSE otherwise. 362 */ 363 BOOL 364 APIENTRY 365 NtGdiTransformPoints( 366 HDC hDC, 367 PPOINT UnsafePtsIn, 368 PPOINT UnsafePtOut, 369 INT Count, 370 INT iMode) 371 { 372 PDC pdc; 373 LPPOINT Points; 374 ULONG Size; 375 BOOL ret = TRUE; 376 377 if (Count <= 0) 378 return TRUE; 379 380 pdc = DC_LockDc(hDC); 381 if (!pdc) 382 { 383 EngSetLastError(ERROR_INVALID_PARAMETER); 384 return FALSE; 385 } 386 387 Size = Count * sizeof(POINT); 388 389 // FIXME: It would be wise to have a small stack buffer as optimization 390 Points = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEMP); 391 if (!Points) 392 { 393 DC_UnlockDc(pdc); 394 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 395 return FALSE; 396 } 397 398 _SEH2_TRY 399 { 400 ProbeForWrite(UnsafePtOut, Size, 1); 401 ProbeForRead(UnsafePtsIn, Size, 1); 402 RtlCopyMemory(Points, UnsafePtsIn, Size); 403 } 404 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 405 { 406 /* Do not set last error */ 407 _SEH2_YIELD(goto leave;) 408 } 409 _SEH2_END; 410 411 switch (iMode) 412 { 413 case GdiDpToLp: 414 DC_vXformDeviceToWorld(pdc, Count, Points, Points); 415 break; 416 417 case GdiLpToDp: 418 DC_vXformWorldToDevice(pdc, Count, Points, Points); 419 break; 420 421 case 2: // Not supported yet. Need testing. 422 default: 423 { 424 EngSetLastError(ERROR_INVALID_PARAMETER); 425 ret = FALSE; 426 goto leave; 427 } 428 } 429 430 _SEH2_TRY 431 { 432 /* Pointer was already probed! */ 433 RtlCopyMemory(UnsafePtOut, Points, Size); 434 } 435 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 436 { 437 /* Do not set last error */ 438 ret = 0; 439 } 440 _SEH2_END; 441 442 // 443 // If we are getting called that means User XForms is a mess! 444 // 445 leave: 446 DC_UnlockDc(pdc); 447 ExFreePoolWithTag(Points, GDITAG_TEMP); 448 return ret; 449 } 450 451 BOOL 452 NTAPI 453 GreModifyWorldTransform( 454 PDC pdc, 455 const XFORML *pxform, 456 DWORD dwMode) 457 { 458 MATRIX mxSrc; 459 XFORMOBJ xoSrc, xoDC; 460 461 switch (dwMode) 462 { 463 case MWT_IDENTITY: 464 pdc->pdcattr->mxWorldToPage = gmxIdentity; 465 break; 466 467 case MWT_LEFTMULTIPLY: 468 XFORMOBJ_vInit(&xoDC, &pdc->pdcattr->mxWorldToPage); 469 XFORMOBJ_vInit(&xoSrc, &mxSrc); 470 if (XFORMOBJ_iSetXform(&xoSrc, pxform) == DDI_ERROR) 471 return FALSE; 472 XFORMOBJ_iCombine(&xoDC, &xoSrc, &xoDC); 473 break; 474 475 case MWT_RIGHTMULTIPLY: 476 XFORMOBJ_vInit(&xoDC, &pdc->pdcattr->mxWorldToPage); 477 XFORMOBJ_vInit(&xoSrc, &mxSrc); 478 if (XFORMOBJ_iSetXform(&xoSrc, pxform) == DDI_ERROR) 479 return FALSE; 480 XFORMOBJ_iCombine(&xoDC, &xoDC, &xoSrc); 481 break; 482 483 case MWT_SET: 484 XFORMOBJ_vInit(&xoDC, &pdc->pdcattr->mxWorldToPage); 485 if (XFORMOBJ_iSetXform(&xoDC, pxform) == DDI_ERROR) 486 return FALSE; 487 break; 488 489 default: 490 return FALSE; 491 } 492 493 /*Set invalidation flags */ 494 pdc->pdcattr->flXform |= WORLD_XFORM_CHANGED|DEVICE_TO_WORLD_INVALID; 495 496 return TRUE; 497 } 498 499 BOOL 500 APIENTRY 501 NtGdiModifyWorldTransform( 502 HDC hdc, 503 LPXFORM pxformUnsafe, 504 DWORD dwMode) 505 { 506 PDC pdc; 507 XFORML xformSafe; 508 BOOL Ret = TRUE; 509 510 pdc = DC_LockDc(hdc); 511 if (!pdc) 512 { 513 EngSetLastError(ERROR_INVALID_HANDLE); 514 return FALSE; 515 } 516 517 /* The xform is permitted to be NULL for MWT_IDENTITY. 518 * However, if it is not NULL, then it must be valid even 519 * though it is not used. */ 520 if ((dwMode != MWT_IDENTITY) && (pxformUnsafe == NULL)) 521 { 522 DC_UnlockDc(pdc); 523 return FALSE; 524 } 525 526 if (pxformUnsafe != NULL) 527 { 528 _SEH2_TRY 529 { 530 ProbeForRead(pxformUnsafe, sizeof(XFORML), 1); 531 RtlCopyMemory(&xformSafe, pxformUnsafe, sizeof(XFORML)); 532 } 533 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 534 { 535 Ret = FALSE; 536 } 537 _SEH2_END; 538 } 539 540 /* Safe to handle kernel mode data. */ 541 if (Ret) Ret = GreModifyWorldTransform(pdc, &xformSafe, dwMode); 542 DC_UnlockDc(pdc); 543 return Ret; 544 } 545 546 BOOL 547 APIENTRY 548 NtGdiOffsetViewportOrgEx( 549 HDC hDC, 550 int XOffset, 551 int YOffset, 552 LPPOINT UnsafePoint) 553 { 554 PDC dc; 555 PDC_ATTR pdcattr; 556 NTSTATUS Status = STATUS_SUCCESS; 557 558 dc = DC_LockDc(hDC); 559 if (!dc) 560 { 561 EngSetLastError(ERROR_INVALID_HANDLE); 562 return FALSE; 563 } 564 pdcattr = dc->pdcattr; 565 566 if (UnsafePoint) 567 { 568 _SEH2_TRY 569 { 570 ProbeForWrite(UnsafePoint, sizeof(POINT), 1); 571 UnsafePoint->x = pdcattr->ptlViewportOrg.x; 572 UnsafePoint->y = pdcattr->ptlViewportOrg.y; 573 if (pdcattr->dwLayout & LAYOUT_RTL) 574 { 575 UnsafePoint->x = -UnsafePoint->x; 576 } 577 } 578 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 579 { 580 Status = _SEH2_GetExceptionCode(); 581 } 582 _SEH2_END; 583 584 if (!NT_SUCCESS(Status)) 585 { 586 SetLastNtError(Status); 587 DC_UnlockDc(dc); 588 return FALSE; 589 } 590 } 591 592 if (pdcattr->dwLayout & LAYOUT_RTL) 593 { 594 XOffset = -XOffset; 595 } 596 pdcattr->ptlViewportOrg.x += XOffset; 597 pdcattr->ptlViewportOrg.y += YOffset; 598 pdcattr->flXform |= PAGE_XLATE_CHANGED; 599 600 DC_UnlockDc(dc); 601 602 return TRUE; 603 } 604 605 BOOL 606 APIENTRY 607 NtGdiOffsetWindowOrgEx( 608 HDC hDC, 609 int XOffset, 610 int YOffset, 611 LPPOINT Point) 612 { 613 PDC dc; 614 PDC_ATTR pdcattr; 615 616 dc = DC_LockDc(hDC); 617 if (!dc) 618 { 619 EngSetLastError(ERROR_INVALID_HANDLE); 620 return FALSE; 621 } 622 pdcattr = dc->pdcattr; 623 624 if (Point) 625 { 626 NTSTATUS Status = STATUS_SUCCESS; 627 628 _SEH2_TRY 629 { 630 ProbeForWrite(Point, sizeof(POINT), 1); 631 Point->x = pdcattr->ptlWindowOrg.x; 632 Point->y = pdcattr->ptlWindowOrg.y; 633 } 634 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 635 { 636 Status = _SEH2_GetExceptionCode(); 637 } 638 _SEH2_END; 639 640 if (!NT_SUCCESS(Status)) 641 { 642 SetLastNtError(Status); 643 DC_UnlockDc(dc); 644 return FALSE; 645 } 646 } 647 648 pdcattr->ptlWindowOrg.x += XOffset; 649 pdcattr->ptlWindowOrg.y += YOffset; 650 pdcattr->flXform |= PAGE_XLATE_CHANGED|DEVICE_TO_WORLD_INVALID; 651 652 DC_UnlockDc(dc); 653 654 return TRUE; 655 } 656 657 BOOL 658 APIENTRY 659 NtGdiScaleViewportExtEx( 660 HDC hDC, 661 int Xnum, 662 int Xdenom, 663 int Ynum, 664 int Ydenom, 665 LPSIZE pSize) 666 { 667 PDC pDC; 668 PDC_ATTR pdcattr; 669 BOOL Ret = FALSE; 670 LONG X, Y; 671 672 pDC = DC_LockDc(hDC); 673 if (!pDC) 674 { 675 EngSetLastError(ERROR_INVALID_HANDLE); 676 return FALSE; 677 } 678 pdcattr = pDC->pdcattr; 679 680 if (pdcattr->iMapMode > MM_TWIPS) 681 { 682 if (Xdenom && Ydenom) 683 { 684 DC_pszlViewportExt(pDC); 685 X = Xnum * pdcattr->szlViewportExt.cx / Xdenom; 686 if (X) 687 { 688 Y = Ynum * pdcattr->szlViewportExt.cy / Ydenom; 689 if (Y) 690 { 691 pdcattr->szlViewportExt.cx = X; 692 pdcattr->szlViewportExt.cy = Y; 693 pdcattr->flXform |= PAGE_XLATE_CHANGED; 694 695 IntMirrorWindowOrg(pDC); 696 697 pdcattr->flXform |= (PAGE_EXTENTS_CHANGED | 698 INVALIDATE_ATTRIBUTES | 699 DEVICE_TO_WORLD_INVALID); 700 701 if (pdcattr->iMapMode == MM_ISOTROPIC) 702 { 703 DC_vFixIsotropicMapping(pDC); 704 } 705 706 Ret = TRUE; 707 } 708 } 709 } 710 } 711 else 712 Ret = TRUE; 713 714 if (pSize) 715 { 716 _SEH2_TRY 717 { 718 ProbeForWrite(pSize, sizeof(SIZE), 1); 719 720 pSize->cx = pdcattr->szlViewportExt.cx; 721 pSize->cy = pdcattr->szlViewportExt.cy; 722 } 723 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 724 { 725 SetLastNtError(_SEH2_GetExceptionCode()); 726 Ret = FALSE; 727 } 728 _SEH2_END; 729 } 730 731 DC_UnlockDc(pDC); 732 return Ret; 733 } 734 735 BOOL 736 APIENTRY 737 NtGdiScaleWindowExtEx( 738 HDC hDC, 739 int Xnum, 740 int Xdenom, 741 int Ynum, 742 int Ydenom, 743 LPSIZE pSize) 744 { 745 PDC pDC; 746 PDC_ATTR pdcattr; 747 BOOL Ret = FALSE; 748 LONG X, Y; 749 750 pDC = DC_LockDc(hDC); 751 if (!pDC) 752 { 753 EngSetLastError(ERROR_INVALID_HANDLE); 754 return FALSE; 755 } 756 pdcattr = pDC->pdcattr; 757 758 if (pSize) 759 { 760 NTSTATUS Status = STATUS_SUCCESS; 761 762 _SEH2_TRY 763 { 764 ProbeForWrite(pSize, sizeof(SIZE), 1); 765 766 X = pdcattr->szlWindowExt.cx; 767 if (pdcattr->dwLayout & LAYOUT_RTL) X = -X; 768 pSize->cx = X; 769 pSize->cy = pdcattr->szlWindowExt.cy; 770 } 771 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 772 { 773 Status = _SEH2_GetExceptionCode(); 774 } 775 _SEH2_END; 776 777 if (!NT_SUCCESS(Status)) 778 { 779 SetLastNtError(Status); 780 DC_UnlockDc(pDC); 781 return FALSE; 782 } 783 } 784 785 if (pdcattr->iMapMode > MM_TWIPS) 786 { 787 if (Xdenom && Ydenom) 788 { 789 X = Xnum * pdcattr->szlWindowExt.cx / Xdenom; 790 if (X) 791 { 792 Y = Ynum * pdcattr->szlWindowExt.cy / Ydenom; 793 if (Y) 794 { 795 pdcattr->szlWindowExt.cx = X; 796 pdcattr->szlWindowExt.cy = Y; 797 798 IntMirrorWindowOrg(pDC); 799 800 pdcattr->flXform |= (PAGE_EXTENTS_CHANGED|INVALIDATE_ATTRIBUTES|DEVICE_TO_WORLD_INVALID); 801 802 Ret = TRUE; 803 } 804 } 805 } 806 } 807 else 808 Ret = TRUE; 809 810 DC_UnlockDc(pDC); 811 return Ret; 812 } 813 814 int 815 APIENTRY 816 IntGdiSetMapMode( 817 PDC dc, 818 int MapMode) 819 { 820 INT iPrevMapMode; 821 FLONG flXform; 822 PDC_ATTR pdcattr = dc->pdcattr; 823 824 flXform = pdcattr->flXform & ~(ISO_OR_ANISO_MAP_MODE|PTOD_EFM22_NEGATIVE| 825 PTOD_EFM11_NEGATIVE|POSITIVE_Y_IS_UP|PAGE_TO_DEVICE_SCALE_IDENTITY| 826 PAGE_TO_DEVICE_IDENTITY); 827 828 switch (MapMode) 829 { 830 case MM_TEXT: 831 pdcattr->szlWindowExt.cx = 1; 832 pdcattr->szlWindowExt.cy = 1; 833 pdcattr->szlViewportExt.cx = 1; 834 pdcattr->szlViewportExt.cy = 1; 835 flXform |= PAGE_TO_DEVICE_SCALE_IDENTITY; 836 break; 837 838 case MM_ISOTROPIC: 839 flXform |= ISO_OR_ANISO_MAP_MODE; 840 /* Fall through */ 841 842 case MM_LOMETRIC: 843 pdcattr->szlWindowExt.cx = pdcattr->szlVirtualDeviceMm.cx * 10; 844 pdcattr->szlWindowExt.cy = pdcattr->szlVirtualDeviceMm.cy * 10; 845 pdcattr->szlViewportExt.cx = pdcattr->szlVirtualDevicePixel.cx; 846 pdcattr->szlViewportExt.cy = -pdcattr->szlVirtualDevicePixel.cy; 847 break; 848 849 case MM_HIMETRIC: 850 pdcattr->szlWindowExt.cx = pdcattr->szlVirtualDeviceMm.cx * 100; 851 pdcattr->szlWindowExt.cy = pdcattr->szlVirtualDeviceMm.cy * 100; 852 pdcattr->szlViewportExt.cx = pdcattr->szlVirtualDevicePixel.cx; 853 pdcattr->szlViewportExt.cy = -pdcattr->szlVirtualDevicePixel.cy; 854 break; 855 856 case MM_LOENGLISH: 857 pdcattr->szlWindowExt.cx = MulDiv(1000, pdcattr->szlVirtualDeviceMm.cx, 254); 858 pdcattr->szlWindowExt.cy = MulDiv(1000, pdcattr->szlVirtualDeviceMm.cy, 254); 859 pdcattr->szlViewportExt.cx = pdcattr->szlVirtualDevicePixel.cx; 860 pdcattr->szlViewportExt.cy = -pdcattr->szlVirtualDevicePixel.cy; 861 break; 862 863 case MM_HIENGLISH: 864 pdcattr->szlWindowExt.cx = MulDiv(10000, pdcattr->szlVirtualDeviceMm.cx, 254); 865 pdcattr->szlWindowExt.cy = MulDiv(10000, pdcattr->szlVirtualDeviceMm.cy, 254); 866 pdcattr->szlViewportExt.cx = pdcattr->szlVirtualDevicePixel.cx; 867 pdcattr->szlViewportExt.cy = -pdcattr->szlVirtualDevicePixel.cy; 868 break; 869 870 case MM_TWIPS: 871 pdcattr->szlWindowExt.cx = MulDiv(14400, pdcattr->szlVirtualDeviceMm.cx, 254); 872 pdcattr->szlWindowExt.cy = MulDiv(14400, pdcattr->szlVirtualDeviceMm.cy, 254); 873 pdcattr->szlViewportExt.cx = pdcattr->szlVirtualDevicePixel.cx; 874 pdcattr->szlViewportExt.cy = -pdcattr->szlVirtualDevicePixel.cy; 875 break; 876 877 case MM_ANISOTROPIC: 878 flXform &= ~(PAGE_TO_DEVICE_IDENTITY|POSITIVE_Y_IS_UP); 879 flXform |= ISO_OR_ANISO_MAP_MODE; 880 break; 881 882 default: 883 return 0; 884 } 885 886 /* Save the old map mode and set the new one */ 887 iPrevMapMode = pdcattr->iMapMode; 888 pdcattr->iMapMode = MapMode; 889 890 /* Update xform flags */ 891 pdcattr->flXform = flXform | (PAGE_XLATE_CHANGED|PAGE_EXTENTS_CHANGED| 892 INVALIDATE_ATTRIBUTES|DEVICE_TO_PAGE_INVALID|DEVICE_TO_WORLD_INVALID); 893 894 return iPrevMapMode; 895 } 896 897 BOOL 898 FASTCALL 899 GreSetViewportOrgEx( 900 HDC hDC, 901 int X, 902 int Y, 903 LPPOINT Point) 904 { 905 PDC dc; 906 PDC_ATTR pdcattr; 907 908 dc = DC_LockDc(hDC); 909 if (!dc) 910 { 911 EngSetLastError(ERROR_INVALID_HANDLE); 912 return FALSE; 913 } 914 pdcattr = dc->pdcattr; 915 916 if (Point) 917 { 918 Point->x = pdcattr->ptlViewportOrg.x; 919 Point->y = pdcattr->ptlViewportOrg.y; 920 } 921 922 pdcattr->ptlViewportOrg.x = X; 923 pdcattr->ptlViewportOrg.y = Y; 924 pdcattr->flXform |= PAGE_XLATE_CHANGED; 925 926 DC_UnlockDc(dc); 927 return TRUE; 928 } 929 930 BOOL 931 APIENTRY 932 NtGdiSetViewportOrgEx( 933 HDC hDC, 934 int X, 935 int Y, 936 LPPOINT Point) 937 { 938 PDC dc; 939 PDC_ATTR pdcattr; 940 941 dc = DC_LockDc(hDC); 942 if (!dc) 943 { 944 EngSetLastError(ERROR_INVALID_HANDLE); 945 return FALSE; 946 } 947 pdcattr = dc->pdcattr; 948 949 if (Point) 950 { 951 NTSTATUS Status = STATUS_SUCCESS; 952 953 _SEH2_TRY 954 { 955 ProbeForWrite(Point, sizeof(POINT), 1); 956 Point->x = pdcattr->ptlViewportOrg.x; 957 Point->y = pdcattr->ptlViewportOrg.y; 958 } 959 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 960 { 961 Status = _SEH2_GetExceptionCode(); 962 } 963 _SEH2_END; 964 965 if (!NT_SUCCESS(Status)) 966 { 967 SetLastNtError(Status); 968 DC_UnlockDc(dc); 969 return FALSE; 970 } 971 } 972 973 pdcattr->ptlViewportOrg.x = X; 974 pdcattr->ptlViewportOrg.y = Y; 975 pdcattr->flXform |= PAGE_XLATE_CHANGED; 976 977 DC_UnlockDc(dc); 978 979 return TRUE; 980 } 981 982 BOOL 983 APIENTRY 984 NtGdiSetWindowOrgEx( 985 HDC hDC, 986 int X, 987 int Y, 988 LPPOINT Point) 989 { 990 PDC dc; 991 PDC_ATTR pdcattr; 992 993 dc = DC_LockDc(hDC); 994 if (!dc) 995 { 996 EngSetLastError(ERROR_INVALID_HANDLE); 997 return FALSE; 998 } 999 pdcattr = dc->pdcattr; 1000 1001 if (Point) 1002 { 1003 NTSTATUS Status = STATUS_SUCCESS; 1004 1005 _SEH2_TRY 1006 { 1007 ProbeForWrite(Point, sizeof(POINT), 1); 1008 Point->x = pdcattr->ptlWindowOrg.x; 1009 Point->y = pdcattr->ptlWindowOrg.y; 1010 } 1011 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1012 { 1013 Status = _SEH2_GetExceptionCode(); 1014 } 1015 _SEH2_END; 1016 1017 if (!NT_SUCCESS(Status)) 1018 { 1019 SetLastNtError(Status); 1020 DC_UnlockDc(dc); 1021 return FALSE; 1022 } 1023 } 1024 1025 pdcattr->ptlWindowOrg.x = X; 1026 pdcattr->ptlWindowOrg.y = Y; 1027 pdcattr->flXform |= PAGE_XLATE_CHANGED; 1028 1029 DC_UnlockDc(dc); 1030 1031 return TRUE; 1032 } 1033 1034 // 1035 // Mirror Window function. 1036 // 1037 VOID 1038 FASTCALL 1039 IntMirrorWindowOrg(PDC dc) 1040 { 1041 PDC_ATTR pdcattr; 1042 LONG X, cx; 1043 1044 pdcattr = dc->pdcattr; 1045 1046 if (!(pdcattr->dwLayout & LAYOUT_RTL)) 1047 { 1048 pdcattr->ptlWindowOrg.x = pdcattr->lWindowOrgx; // Flip it back. 1049 return; 1050 } 1051 1052 /* Copy the window extension, so no one can mess with it */ 1053 cx = pdcattr->szlViewportExt.cx; 1054 if (cx == 0) return; 1055 // 1056 // WOrgx = wox - (Width - 1) * WExtx / VExtx 1057 // 1058 X = (dc->erclWindow.right - dc->erclWindow.left) - 1; // Get device width - 1 1059 1060 X = (X * pdcattr->szlWindowExt.cx) / cx; 1061 1062 pdcattr->ptlWindowOrg.x = pdcattr->lWindowOrgx - X; // Now set the inverted win origion. 1063 pdcattr->flXform |= PAGE_XLATE_CHANGED; 1064 1065 return; 1066 } 1067 1068 VOID 1069 NTAPI 1070 DC_vSetLayout( 1071 IN PDC pdc, 1072 IN LONG wox, 1073 IN DWORD dwLayout) 1074 { 1075 PDC_ATTR pdcattr = pdc->pdcattr; 1076 1077 pdcattr->dwLayout = dwLayout; 1078 1079 if (!(dwLayout & LAYOUT_ORIENTATIONMASK)) return; 1080 1081 if (dwLayout & LAYOUT_RTL) 1082 { 1083 pdcattr->iMapMode = MM_ANISOTROPIC; 1084 } 1085 1086 //pdcattr->szlWindowExt.cy = -pdcattr->szlWindowExt.cy; 1087 //pdcattr->ptlWindowOrg.x = -pdcattr->ptlWindowOrg.x; 1088 1089 //if (wox == -1) 1090 // IntMirrorWindowOrg(pdc); 1091 //else 1092 // pdcattr->ptlWindowOrg.x = wox - pdcattr->ptlWindowOrg.x; 1093 1094 if (!(pdcattr->flTextAlign & TA_CENTER)) pdcattr->flTextAlign |= TA_RIGHT; 1095 1096 if (pdc->dclevel.flPath & DCPATH_CLOCKWISE) 1097 pdc->dclevel.flPath &= ~DCPATH_CLOCKWISE; 1098 else 1099 pdc->dclevel.flPath |= DCPATH_CLOCKWISE; 1100 1101 pdcattr->flXform |= (PAGE_EXTENTS_CHANGED | 1102 INVALIDATE_ATTRIBUTES | 1103 DEVICE_TO_WORLD_INVALID); 1104 } 1105 1106 // NtGdiSetLayout 1107 // 1108 // The default is left to right. This function changes it to right to left, which 1109 // is the standard in Arabic and Hebrew cultures. 1110 // 1111 /* 1112 * @implemented 1113 */ 1114 DWORD 1115 APIENTRY 1116 NtGdiSetLayout( 1117 IN HDC hdc, 1118 IN LONG wox, 1119 IN DWORD dwLayout) 1120 { 1121 PDC pdc; 1122 DWORD dwOldLayout; 1123 1124 pdc = DC_LockDc(hdc); 1125 if (!pdc) 1126 { 1127 EngSetLastError(ERROR_INVALID_HANDLE); 1128 return GDI_ERROR; 1129 } 1130 1131 dwOldLayout = pdc->pdcattr->dwLayout; 1132 DC_vSetLayout(pdc, wox, dwLayout); 1133 1134 DC_UnlockDc(pdc); 1135 return dwOldLayout; 1136 } 1137 1138 /* 1139 * @implemented 1140 */ 1141 LONG 1142 APIENTRY 1143 NtGdiGetDeviceWidth( 1144 IN HDC hdc) 1145 { 1146 PDC dc; 1147 LONG Ret; 1148 dc = DC_LockDc(hdc); 1149 if (!dc) 1150 { 1151 EngSetLastError(ERROR_INVALID_HANDLE); 1152 return 0; 1153 } 1154 Ret = dc->erclWindow.right - dc->erclWindow.left; 1155 DC_UnlockDc(dc); 1156 return Ret; 1157 } 1158 1159 /* 1160 * @implemented 1161 */ 1162 BOOL 1163 APIENTRY 1164 NtGdiMirrorWindowOrg( 1165 IN HDC hdc) 1166 { 1167 PDC dc; 1168 dc = DC_LockDc(hdc); 1169 if (!dc) 1170 { 1171 EngSetLastError(ERROR_INVALID_HANDLE); 1172 return FALSE; 1173 } 1174 IntMirrorWindowOrg(dc); 1175 DC_UnlockDc(dc); 1176 return TRUE; 1177 } 1178 1179 /* 1180 * @implemented 1181 */ 1182 BOOL 1183 APIENTRY 1184 NtGdiSetSizeDevice( 1185 IN HDC hdc, 1186 IN INT cxVirtualDevice, 1187 IN INT cyVirtualDevice) 1188 { 1189 PDC dc; 1190 PDC_ATTR pdcattr; 1191 1192 if (!cxVirtualDevice || !cyVirtualDevice) 1193 { 1194 return FALSE; 1195 } 1196 1197 dc = DC_LockDc(hdc); 1198 if (!dc) return FALSE; 1199 1200 pdcattr = dc->pdcattr; 1201 1202 pdcattr->szlVirtualDeviceSize.cx = cxVirtualDevice; 1203 pdcattr->szlVirtualDeviceSize.cy = cyVirtualDevice; 1204 1205 DC_UnlockDc(dc); 1206 1207 return TRUE; 1208 } 1209 1210 /* 1211 * @implemented 1212 */ 1213 BOOL 1214 APIENTRY 1215 NtGdiSetVirtualResolution( 1216 IN HDC hdc, 1217 IN INT cxVirtualDevicePixel, 1218 IN INT cyVirtualDevicePixel, 1219 IN INT cxVirtualDeviceMm, 1220 IN INT cyVirtualDeviceMm) 1221 { 1222 PDC dc; 1223 PDC_ATTR pdcattr; 1224 1225 /* Check parameters (all zeroes resets to real resolution) */ 1226 if (cxVirtualDevicePixel == 0 && cyVirtualDevicePixel == 0 && 1227 cxVirtualDeviceMm == 0 && cyVirtualDeviceMm == 0) 1228 { 1229 cxVirtualDevicePixel = NtGdiGetDeviceCaps(hdc, HORZRES); 1230 cyVirtualDevicePixel = NtGdiGetDeviceCaps(hdc, VERTRES); 1231 cxVirtualDeviceMm = NtGdiGetDeviceCaps(hdc, HORZSIZE); 1232 cyVirtualDeviceMm = NtGdiGetDeviceCaps(hdc, VERTSIZE); 1233 } 1234 else if (cxVirtualDevicePixel == 0 || cyVirtualDevicePixel == 0 || 1235 cxVirtualDeviceMm == 0 || cyVirtualDeviceMm == 0) 1236 { 1237 return FALSE; 1238 } 1239 1240 dc = DC_LockDc(hdc); 1241 if (!dc) return FALSE; 1242 1243 pdcattr = dc->pdcattr; 1244 1245 pdcattr->szlVirtualDevicePixel.cx = cxVirtualDevicePixel; 1246 pdcattr->szlVirtualDevicePixel.cy = cyVirtualDevicePixel; 1247 pdcattr->szlVirtualDeviceMm.cx = cxVirtualDeviceMm; 1248 pdcattr->szlVirtualDeviceMm.cy = cyVirtualDeviceMm; 1249 1250 // DC_vUpdateXforms(dc); 1251 DC_UnlockDc(dc); 1252 return TRUE; 1253 } 1254 1255 static 1256 VOID FASTCALL 1257 DC_vGetAspectRatioFilter(PDC pDC, LPSIZE AspectRatio) 1258 { 1259 if (pDC->pdcattr->flFontMapper & 1) // TRUE assume 1. 1260 { 1261 // "This specifies that Windows should only match fonts that have the 1262 // same aspect ratio as the display.", Programming Windows, Fifth Ed. 1263 AspectRatio->cx = pDC->ppdev->gdiinfo.ulLogPixelsX; 1264 AspectRatio->cy = pDC->ppdev->gdiinfo.ulLogPixelsY; 1265 } 1266 else 1267 { 1268 AspectRatio->cx = 0; 1269 AspectRatio->cy = 0; 1270 } 1271 } 1272 1273 BOOL APIENTRY 1274 GreGetDCPoint( 1275 HDC hDC, 1276 UINT iPoint, 1277 PPOINTL Point) 1278 { 1279 BOOL Ret = TRUE; 1280 DC *pdc; 1281 SIZE Size; 1282 PSIZEL pszlViewportExt; 1283 1284 if (!Point) 1285 { 1286 EngSetLastError(ERROR_INVALID_PARAMETER); 1287 return FALSE; 1288 } 1289 1290 pdc = DC_LockDc(hDC); 1291 if (!pdc) 1292 { 1293 EngSetLastError(ERROR_INVALID_HANDLE); 1294 return FALSE; 1295 } 1296 1297 switch (iPoint) 1298 { 1299 case GdiGetViewPortExt: 1300 pszlViewportExt = DC_pszlViewportExt(pdc); 1301 Point->x = pszlViewportExt->cx; 1302 Point->y = pszlViewportExt->cy; 1303 break; 1304 1305 case GdiGetWindowExt: 1306 Point->x = pdc->pdcattr->szlWindowExt.cx; 1307 Point->y = pdc->pdcattr->szlWindowExt.cy; 1308 break; 1309 1310 case GdiGetViewPortOrg: 1311 *Point = pdc->pdcattr->ptlViewportOrg; 1312 break; 1313 1314 case GdiGetWindowOrg: 1315 *Point = pdc->pdcattr->ptlWindowOrg; 1316 break; 1317 1318 case GdiGetDCOrg: 1319 *Point = pdc->ptlDCOrig; 1320 break; 1321 1322 case GdiGetAspectRatioFilter: 1323 DC_vGetAspectRatioFilter(pdc, &Size); 1324 Point->x = Size.cx; 1325 Point->y = Size.cy; 1326 break; 1327 1328 default: 1329 EngSetLastError(ERROR_INVALID_PARAMETER); 1330 Ret = FALSE; 1331 break; 1332 } 1333 1334 DC_UnlockDc(pdc); 1335 return Ret; 1336 } 1337 1338 BOOL 1339 WINAPI 1340 GreSetDCOrg( 1341 _In_ HDC hdc, 1342 _In_ LONG x, 1343 _In_ LONG y, 1344 _In_opt_ PRECTL Rect) 1345 { 1346 PDC dc; 1347 1348 dc = DC_LockDc(hdc); 1349 if (!dc) return FALSE; 1350 1351 /* Set DC Origin */ 1352 dc->ptlDCOrig.x = x; 1353 dc->ptlDCOrig.y = y; 1354 1355 /* Recalculate Fill Origin */ 1356 dc->ptlFillOrigin.x = dc->dclevel.ptlBrushOrigin.x + x; 1357 dc->ptlFillOrigin.y = dc->dclevel.ptlBrushOrigin.y + y; 1358 1359 /* Set DC Window Rectangle */ 1360 if (Rect) 1361 dc->erclWindow = *Rect; 1362 1363 DC_UnlockDc(dc); 1364 return TRUE; 1365 } 1366 1367 BOOL 1368 WINAPI 1369 GreGetDCOrgEx( 1370 _In_ HDC hdc, 1371 _Out_ PPOINTL Point, 1372 _Out_ PRECTL Rect) 1373 { 1374 PDC dc; 1375 1376 dc = DC_LockDc(hdc); 1377 if (!dc) return FALSE; 1378 1379 /* Retrieve DC Window Rectangle without a check */ 1380 *Rect = dc->erclWindow; 1381 1382 DC_UnlockDc(dc); 1383 1384 /* Use default call for DC Origin and parameter checking */ 1385 return GreGetDCPoint( hdc, GdiGetDCOrg, Point); 1386 } 1387 1388 BOOL 1389 WINAPI 1390 GreGetWindowExtEx( 1391 _In_ HDC hdc, 1392 _Out_ LPSIZE lpSize) 1393 { 1394 return GreGetDCPoint(hdc, GdiGetWindowExt, (PPOINTL)lpSize); 1395 } 1396 1397 BOOL 1398 WINAPI 1399 GreGetViewportExtEx( 1400 _In_ HDC hdc, 1401 _Out_ LPSIZE lpSize) 1402 { 1403 return GreGetDCPoint(hdc, GdiGetViewPortExt, (PPOINTL)lpSize); 1404 } 1405 1406 BOOL APIENTRY 1407 NtGdiGetDCPoint( 1408 HDC hDC, 1409 UINT iPoint, 1410 PPOINTL Point) 1411 { 1412 BOOL Ret; 1413 POINTL SafePoint; 1414 1415 if (!Point) 1416 { 1417 EngSetLastError(ERROR_INVALID_PARAMETER); 1418 return FALSE; 1419 } 1420 1421 Ret = GreGetDCPoint(hDC, iPoint, &SafePoint); 1422 if (Ret) 1423 { 1424 _SEH2_TRY 1425 { 1426 ProbeForWrite(Point, sizeof(POINT), 1); 1427 *Point = SafePoint; 1428 } 1429 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1430 { 1431 Ret = FALSE; 1432 } 1433 _SEH2_END; 1434 } 1435 1436 return Ret; 1437 } 1438 1439 /* EOF */ 1440