1 /* 2 * PROJECT: ReactOS Win32k Subsystem 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: win32ss/gdi/ntgdi/line.c 5 * PURPOSE: Line functions 6 * PROGRAMMERS: ... 7 */ 8 9 #include <win32k.h> 10 11 #define NDEBUG 12 #include <debug.h> 13 14 // Some code from the WINE project source (www.winehq.com) 15 16 VOID FASTCALL 17 AddPenLinesBounds(PDC dc, int count, POINT *points) 18 { 19 DWORD join, endcap; 20 RECTL bounds, rect; 21 LONG lWidth; 22 PBRUSH pbrLine; 23 24 /* Get BRUSH from current pen. */ 25 pbrLine = dc->dclevel.pbrLine; 26 ASSERT(pbrLine); 27 28 lWidth = 0; 29 30 // Setup bounds 31 bounds.left = bounds.top = INT_MAX; 32 bounds.right = bounds.bottom = INT_MIN; 33 34 if (((pbrLine->ulPenStyle & PS_TYPE_MASK) & PS_GEOMETRIC) || pbrLine->lWidth > 1) 35 { 36 /* Windows uses some heuristics to estimate the distance from the point that will be painted */ 37 lWidth = pbrLine->lWidth + 2; 38 endcap = (PS_ENDCAP_MASK & pbrLine->ulPenStyle); 39 join = (PS_JOIN_MASK & pbrLine->ulPenStyle); 40 if (join == PS_JOIN_MITER) 41 { 42 lWidth *= 5; 43 if (endcap == PS_ENDCAP_SQUARE) lWidth = (lWidth * 3 + 1) / 2; 44 } 45 else 46 { 47 if (endcap == PS_ENDCAP_SQUARE) lWidth -= lWidth / 4; 48 else lWidth = (lWidth + 1) / 2; 49 } 50 } 51 52 while (count-- > 0) 53 { 54 rect.left = points->x - lWidth; 55 rect.top = points->y - lWidth; 56 rect.right = points->x + lWidth + 1; 57 rect.bottom = points->y + lWidth + 1; 58 RECTL_bUnionRect(&bounds, &bounds, &rect); 59 points++; 60 } 61 62 DPRINT("APLB dc %p l %d t %d\n",dc,rect.left,rect.top); 63 DPRINT(" r %d b %d\n",rect.right,rect.bottom); 64 65 { 66 RECTL rcRgn = dc->erclClip; // Use the clip box for now. 67 68 if (RECTL_bIntersectRect( &rcRgn, &rcRgn, &bounds )) 69 IntUpdateBoundsRect(dc, &rcRgn); 70 else 71 IntUpdateBoundsRect(dc, &bounds); 72 } 73 } 74 75 // Should use Fx in Point 76 // 77 BOOL FASTCALL 78 IntGdiMoveToEx(DC *dc, 79 int X, 80 int Y, 81 LPPOINT Point) 82 { 83 PDC_ATTR pdcattr = dc->pdcattr; 84 if ( Point ) 85 { 86 if ( pdcattr->ulDirty_ & DIRTY_PTLCURRENT ) // Double hit! 87 { 88 Point->x = pdcattr->ptfxCurrent.x; // ret prev before change. 89 Point->y = pdcattr->ptfxCurrent.y; 90 IntDPtoLP ( dc, Point, 1); // Reconvert back. 91 } 92 else 93 { 94 Point->x = pdcattr->ptlCurrent.x; 95 Point->y = pdcattr->ptlCurrent.y; 96 } 97 } 98 pdcattr->ptlCurrent.x = X; 99 pdcattr->ptlCurrent.y = Y; 100 pdcattr->ptfxCurrent = pdcattr->ptlCurrent; 101 CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx 102 pdcattr->ulDirty_ &= ~(DIRTY_PTLCURRENT|DIRTY_PTFXCURRENT|DIRTY_STYLESTATE); 103 104 return TRUE; 105 } 106 107 BOOL FASTCALL 108 GreMoveTo( HDC hdc, 109 INT x, 110 INT y, 111 LPPOINT pptOut) 112 { 113 BOOL Ret; 114 PDC dc; 115 if (!(dc = DC_LockDc(hdc))) 116 { 117 EngSetLastError(ERROR_INVALID_HANDLE); 118 return FALSE; 119 } 120 Ret = IntGdiMoveToEx(dc, x, y, pptOut); 121 DC_UnlockDc(dc); 122 return Ret; 123 } 124 125 // Should use Fx in pt 126 // 127 VOID FASTCALL 128 IntGetCurrentPositionEx(PDC dc, LPPOINT pt) 129 { 130 PDC_ATTR pdcattr = dc->pdcattr; 131 132 if ( pt ) 133 { 134 if (pdcattr->ulDirty_ & DIRTY_PTFXCURRENT) 135 { 136 pdcattr->ptfxCurrent = pdcattr->ptlCurrent; 137 CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx 138 pdcattr->ulDirty_ &= ~(DIRTY_PTFXCURRENT|DIRTY_STYLESTATE); 139 } 140 pt->x = pdcattr->ptlCurrent.x; 141 pt->y = pdcattr->ptlCurrent.y; 142 } 143 } 144 145 BOOL FASTCALL 146 IntGdiLineTo(DC *dc, 147 int XEnd, 148 int YEnd) 149 { 150 SURFACE *psurf; 151 BOOL Ret = TRUE; 152 PBRUSH pbrLine; 153 RECTL Bounds; 154 POINT Points[2]; 155 PDC_ATTR pdcattr; 156 PPATH pPath; 157 158 ASSERT_DC_PREPARED(dc); 159 160 pdcattr = dc->pdcattr; 161 162 if (PATH_IsPathOpen(dc->dclevel)) 163 { 164 Ret = PATH_LineTo(dc, XEnd, YEnd); 165 } 166 else 167 { 168 psurf = dc->dclevel.pSurface; 169 if (NULL == psurf) 170 { 171 EngSetLastError(ERROR_INVALID_HANDLE); 172 return FALSE; 173 } 174 175 Points[0].x = pdcattr->ptlCurrent.x; 176 Points[0].y = pdcattr->ptlCurrent.y; 177 Points[1].x = XEnd; 178 Points[1].y = YEnd; 179 180 IntLPtoDP(dc, Points, 2); 181 182 /* The DCOrg is in device coordinates */ 183 Points[0].x += dc->ptlDCOrig.x; 184 Points[0].y += dc->ptlDCOrig.y; 185 Points[1].x += dc->ptlDCOrig.x; 186 Points[1].y += dc->ptlDCOrig.y; 187 188 Bounds.left = min(Points[0].x, Points[1].x); 189 Bounds.top = min(Points[0].y, Points[1].y); 190 Bounds.right = max(Points[0].x, Points[1].x); 191 Bounds.bottom = max(Points[0].y, Points[1].y); 192 193 /* Get BRUSH from current pen. */ 194 pbrLine = dc->dclevel.pbrLine; 195 ASSERT(pbrLine); 196 197 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR)) 198 { 199 DPRINT("Bounds dc %p l %d t %d\n",dc,Bounds.left,Bounds.top); 200 DPRINT(" r %d b %d\n",Bounds.right,Bounds.bottom); 201 AddPenLinesBounds(dc, 2, Points); 202 } 203 204 if (!(pbrLine->flAttrs & BR_IS_NULL)) 205 { 206 if (IntIsEffectiveWidePen(pbrLine)) 207 { 208 /* Clear the path */ 209 PATH_Delete(dc->dclevel.hPath); 210 dc->dclevel.hPath = NULL; 211 212 /* Begin a path */ 213 pPath = PATH_CreatePath(2); 214 dc->dclevel.flPath |= DCPATH_ACTIVE; 215 dc->dclevel.hPath = pPath->BaseObject.hHmgr; 216 IntGetCurrentPositionEx(dc, &pPath->pos); 217 IntLPtoDP(dc, &pPath->pos, 1); 218 219 PATH_MoveTo(dc, pPath); 220 PATH_LineTo(dc, XEnd, YEnd); 221 222 /* Close the path */ 223 pPath->state = PATH_Closed; 224 dc->dclevel.flPath &= ~DCPATH_ACTIVE; 225 226 /* Actually stroke a path */ 227 Ret = PATH_StrokePath(dc, pPath); 228 229 /* Clear the path */ 230 PATH_UnlockPath(pPath); 231 PATH_Delete(dc->dclevel.hPath); 232 dc->dclevel.hPath = NULL; 233 } 234 else 235 { 236 Ret = IntEngLineTo(&psurf->SurfObj, 237 (CLIPOBJ *)&dc->co, 238 &dc->eboLine.BrushObject, 239 Points[0].x, Points[0].y, 240 Points[1].x, Points[1].y, 241 &Bounds, 242 ROP2_TO_MIX(pdcattr->jROP2)); 243 } 244 } 245 } 246 247 if (Ret) 248 { 249 pdcattr->ptlCurrent.x = XEnd; 250 pdcattr->ptlCurrent.y = YEnd; 251 pdcattr->ptfxCurrent = pdcattr->ptlCurrent; 252 CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx 253 pdcattr->ulDirty_ &= ~(DIRTY_PTLCURRENT|DIRTY_PTFXCURRENT|DIRTY_STYLESTATE); 254 } 255 256 return Ret; 257 } 258 259 BOOL FASTCALL 260 IntGdiPolyBezier(DC *dc, 261 LPPOINT pt, 262 DWORD Count) 263 { 264 BOOL ret = FALSE; // Default to FAILURE 265 266 if ( PATH_IsPathOpen(dc->dclevel) ) 267 { 268 return PATH_PolyBezier ( dc, pt, Count ); 269 } 270 271 /* We'll convert it into line segments and draw them using Polyline */ 272 { 273 POINT *Pts; 274 INT nOut; 275 276 Pts = GDI_Bezier ( pt, Count, &nOut ); 277 if ( Pts ) 278 { 279 ret = IntGdiPolyline(dc, Pts, nOut); 280 ExFreePoolWithTag(Pts, TAG_BEZIER); 281 } 282 } 283 284 return ret; 285 } 286 287 BOOL FASTCALL 288 IntGdiPolyBezierTo(DC *dc, 289 LPPOINT pt, 290 DWORD Count) 291 { 292 BOOL ret = FALSE; // Default to failure 293 PDC_ATTR pdcattr = dc->pdcattr; 294 295 if ( PATH_IsPathOpen(dc->dclevel) ) 296 ret = PATH_PolyBezierTo ( dc, pt, Count ); 297 else /* We'll do it using PolyBezier */ 298 { 299 POINT *npt; 300 npt = ExAllocatePoolWithTag(PagedPool, 301 sizeof(POINT) * (Count + 1), 302 TAG_BEZIER); 303 if ( npt ) 304 { 305 npt[0].x = pdcattr->ptlCurrent.x; 306 npt[0].y = pdcattr->ptlCurrent.y; 307 memcpy(npt + 1, pt, sizeof(POINT) * Count); 308 ret = IntGdiPolyBezier(dc, npt, Count+1); 309 ExFreePoolWithTag(npt, TAG_BEZIER); 310 } 311 } 312 if ( ret ) 313 { 314 pdcattr->ptlCurrent.x = pt[Count-1].x; 315 pdcattr->ptlCurrent.y = pt[Count-1].y; 316 pdcattr->ptfxCurrent = pdcattr->ptlCurrent; 317 CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx 318 pdcattr->ulDirty_ &= ~(DIRTY_PTLCURRENT|DIRTY_PTFXCURRENT|DIRTY_STYLESTATE); 319 } 320 321 return ret; 322 } 323 324 BOOL FASTCALL 325 IntGdiPolyline(DC *dc, 326 LPPOINT pt, 327 int Count) 328 { 329 SURFACE *psurf; 330 BRUSH *pbrLine; 331 LPPOINT Points; 332 BOOL Ret = TRUE; 333 LONG i; 334 PDC_ATTR pdcattr = dc->pdcattr; 335 PPATH pPath; 336 337 if (!dc->dclevel.pSurface) 338 { 339 return TRUE; 340 } 341 342 DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL); 343 psurf = dc->dclevel.pSurface; 344 345 /* Get BRUSHOBJ from current pen. */ 346 pbrLine = dc->dclevel.pbrLine; 347 ASSERT(pbrLine); 348 349 if (!(pbrLine->flAttrs & BR_IS_NULL)) 350 { 351 Points = EngAllocMem(0, Count * sizeof(POINT), GDITAG_TEMP); 352 if (Points != NULL) 353 { 354 RtlCopyMemory(Points, pt, Count * sizeof(POINT)); 355 IntLPtoDP(dc, Points, Count); 356 357 /* Offset the array of points by the DC origin */ 358 for (i = 0; i < Count; i++) 359 { 360 Points[i].x += dc->ptlDCOrig.x; 361 Points[i].y += dc->ptlDCOrig.y; 362 } 363 364 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR)) 365 { 366 AddPenLinesBounds(dc, Count, Points); 367 } 368 369 if (IntIsEffectiveWidePen(pbrLine)) 370 { 371 /* Clear the path */ 372 PATH_Delete(dc->dclevel.hPath); 373 dc->dclevel.hPath = NULL; 374 375 /* Begin a path */ 376 pPath = PATH_CreatePath(Count); 377 dc->dclevel.flPath |= DCPATH_ACTIVE; 378 dc->dclevel.hPath = pPath->BaseObject.hHmgr; 379 pPath->pos = pt[0]; 380 IntLPtoDP(dc, &pPath->pos, 1); 381 382 PATH_MoveTo(dc, pPath); 383 for (i = 1; i < Count; ++i) 384 { 385 PATH_LineTo(dc, pt[i].x, pt[i].y); 386 } 387 388 /* Close the path */ 389 pPath->state = PATH_Closed; 390 dc->dclevel.flPath &= ~DCPATH_ACTIVE; 391 392 /* Actually stroke a path */ 393 Ret = PATH_StrokePath(dc, pPath); 394 395 /* Clear the path */ 396 PATH_UnlockPath(pPath); 397 PATH_Delete(dc->dclevel.hPath); 398 dc->dclevel.hPath = NULL; 399 } 400 else 401 { 402 Ret = IntEngPolyline(&psurf->SurfObj, 403 (CLIPOBJ *)&dc->co, 404 &dc->eboLine.BrushObject, 405 Points, 406 Count, 407 ROP2_TO_MIX(pdcattr->jROP2)); 408 } 409 EngFreeMem(Points); 410 } 411 else 412 { 413 Ret = FALSE; 414 } 415 } 416 417 DC_vFinishBlit(dc, NULL); 418 419 return Ret; 420 } 421 422 BOOL FASTCALL 423 IntGdiPolylineTo(DC *dc, 424 LPPOINT pt, 425 DWORD Count) 426 { 427 BOOL ret = FALSE; // Default to failure 428 PDC_ATTR pdcattr = dc->pdcattr; 429 430 if (PATH_IsPathOpen(dc->dclevel)) 431 { 432 ret = PATH_PolylineTo(dc, pt, Count); 433 } 434 else /* Do it using Polyline */ 435 { 436 POINT *pts = ExAllocatePoolWithTag(PagedPool, 437 sizeof(POINT) * (Count + 1), 438 TAG_SHAPE); 439 if ( pts ) 440 { 441 pts[0].x = pdcattr->ptlCurrent.x; 442 pts[0].y = pdcattr->ptlCurrent.y; 443 memcpy( pts + 1, pt, sizeof(POINT) * Count); 444 ret = IntGdiPolyline(dc, pts, Count + 1); 445 ExFreePoolWithTag(pts, TAG_SHAPE); 446 } 447 } 448 if ( ret ) 449 { 450 pdcattr->ptlCurrent.x = pt[Count-1].x; 451 pdcattr->ptlCurrent.y = pt[Count-1].y; 452 pdcattr->ptfxCurrent = pdcattr->ptlCurrent; 453 CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx 454 pdcattr->ulDirty_ &= ~(DIRTY_PTLCURRENT|DIRTY_PTFXCURRENT|DIRTY_STYLESTATE); 455 } 456 457 return ret; 458 } 459 460 461 BOOL FASTCALL 462 IntGdiPolyPolyline(DC *dc, 463 LPPOINT pt, 464 PULONG PolyPoints, 465 DWORD Count) 466 { 467 ULONG i; 468 LPPOINT pts; 469 PULONG pc; 470 BOOL ret = FALSE; // Default to failure 471 pts = pt; 472 pc = PolyPoints; 473 474 if (PATH_IsPathOpen(dc->dclevel)) 475 { 476 return PATH_PolyPolyline( dc, pt, PolyPoints, Count ); 477 } 478 for (i = 0; i < Count; i++) 479 { 480 ret = IntGdiPolyline ( dc, pts, *pc ); 481 if (ret == FALSE) 482 { 483 return ret; 484 } 485 pts+=*pc++; 486 } 487 488 return ret; 489 } 490 491 /******************************************************************************/ 492 493 BOOL 494 APIENTRY 495 NtGdiLineTo(HDC hDC, 496 int XEnd, 497 int YEnd) 498 { 499 DC *dc; 500 BOOL Ret; 501 RECT rcLockRect ; 502 503 dc = DC_LockDc(hDC); 504 if (!dc) 505 { 506 EngSetLastError(ERROR_INVALID_HANDLE); 507 return FALSE; 508 } 509 510 rcLockRect.left = dc->pdcattr->ptlCurrent.x; 511 rcLockRect.top = dc->pdcattr->ptlCurrent.y; 512 rcLockRect.right = XEnd; 513 rcLockRect.bottom = YEnd; 514 515 IntLPtoDP(dc, (PPOINT)&rcLockRect, 2); 516 517 /* The DCOrg is in device coordinates */ 518 rcLockRect.left += dc->ptlDCOrig.x; 519 rcLockRect.top += dc->ptlDCOrig.y; 520 rcLockRect.right += dc->ptlDCOrig.x; 521 rcLockRect.bottom += dc->ptlDCOrig.y; 522 523 DC_vPrepareDCsForBlit(dc, &rcLockRect, NULL, NULL); 524 525 Ret = IntGdiLineTo(dc, XEnd, YEnd); 526 527 DC_vFinishBlit(dc, NULL); 528 529 DC_UnlockDc(dc); 530 return Ret; 531 } 532 533 // FIXME: This function is completely broken 534 BOOL 535 APIENTRY 536 NtGdiPolyDraw( 537 IN HDC hdc, 538 IN LPPOINT lppt, 539 IN LPBYTE lpbTypes, 540 IN ULONG cCount) 541 { 542 PDC dc; 543 PDC_ATTR pdcattr; 544 POINT bzr[4]; 545 volatile PPOINT line_pts, line_pts_old, bzr_pts; 546 INT num_pts, num_bzr_pts, space, space_old, size; 547 ULONG i; 548 BOOL result = FALSE; 549 550 dc = DC_LockDc(hdc); 551 if (!dc) return FALSE; 552 pdcattr = dc->pdcattr; 553 554 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)) 555 DC_vUpdateFillBrush(dc); 556 557 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY)) 558 DC_vUpdateLineBrush(dc); 559 560 if (!cCount) 561 { 562 DC_UnlockDc(dc); 563 return TRUE; 564 } 565 566 line_pts = NULL; 567 line_pts_old = NULL; 568 bzr_pts = NULL; 569 570 _SEH2_TRY 571 { 572 ProbeArrayForRead(lppt, sizeof(POINT), cCount, sizeof(LONG)); 573 ProbeArrayForRead(lpbTypes, sizeof(BYTE), cCount, sizeof(BYTE)); 574 575 if (PATH_IsPathOpen(dc->dclevel)) 576 { 577 result = PATH_PolyDraw(dc, (const POINT *)lppt, (const BYTE *)lpbTypes, cCount); 578 _SEH2_LEAVE; 579 } 580 581 /* Check for valid point types */ 582 for (i = 0; i < cCount; i++) 583 { 584 switch (lpbTypes[i]) 585 { 586 case PT_MOVETO: 587 case PT_LINETO | PT_CLOSEFIGURE: 588 case PT_LINETO: 589 break; 590 case PT_BEZIERTO: 591 if((i + 2 < cCount) && (lpbTypes[i + 1] == PT_BEZIERTO) && 592 ((lpbTypes[i + 2] & ~PT_CLOSEFIGURE) == PT_BEZIERTO)) 593 { 594 i += 2; 595 break; 596 } 597 default: 598 _SEH2_LEAVE; 599 } 600 } 601 602 space = cCount + 300; 603 line_pts = ExAllocatePoolWithTag(PagedPool, space * sizeof(POINT), TAG_SHAPE); 604 if (line_pts == NULL) 605 { 606 result = FALSE; 607 _SEH2_LEAVE; 608 } 609 610 num_pts = 1; 611 612 line_pts[0].x = pdcattr->ptlCurrent.x; 613 line_pts[0].y = pdcattr->ptlCurrent.y; 614 615 for ( i = 0; i < cCount; i++ ) 616 { 617 switch (lpbTypes[i]) 618 { 619 case PT_MOVETO: 620 if (num_pts >= 2) IntGdiPolyline( dc, line_pts, num_pts ); 621 num_pts = 0; 622 line_pts[num_pts++] = lppt[i]; 623 break; 624 case PT_LINETO: 625 case (PT_LINETO | PT_CLOSEFIGURE): 626 line_pts[num_pts++] = lppt[i]; 627 break; 628 case PT_BEZIERTO: 629 bzr[0].x = line_pts[num_pts - 1].x; 630 bzr[0].y = line_pts[num_pts - 1].y; 631 RtlCopyMemory( &bzr[1], &lppt[i], 3 * sizeof(POINT) ); 632 633 if ((bzr_pts = GDI_Bezier( bzr, 4, &num_bzr_pts ))) 634 { 635 size = num_pts + (cCount - i) + num_bzr_pts; 636 if (space < size) 637 { 638 space_old = space; 639 space = size * 2; 640 line_pts_old = line_pts; 641 line_pts = ExAllocatePoolWithTag(PagedPool, space * sizeof(POINT), TAG_SHAPE); 642 if (!line_pts) _SEH2_LEAVE; 643 RtlCopyMemory(line_pts, line_pts_old, space_old * sizeof(POINT)); 644 ExFreePoolWithTag(line_pts_old, TAG_SHAPE); 645 line_pts_old = NULL; 646 } 647 RtlCopyMemory( &line_pts[num_pts], &bzr_pts[1], (num_bzr_pts - 1) * sizeof(POINT) ); 648 num_pts += num_bzr_pts - 1; 649 ExFreePoolWithTag(bzr_pts, TAG_BEZIER); 650 bzr_pts = NULL; 651 } 652 i += 2; 653 break; 654 } 655 if (lpbTypes[i] & PT_CLOSEFIGURE) line_pts[num_pts++] = line_pts[0]; 656 } 657 658 if (num_pts >= 2) IntGdiPolyline( dc, line_pts, num_pts ); 659 IntGdiMoveToEx( dc, line_pts[num_pts - 1].x, line_pts[num_pts - 1].y, NULL ); 660 result = TRUE; 661 } 662 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 663 { 664 SetLastNtError(_SEH2_GetExceptionCode()); 665 } 666 _SEH2_END; 667 668 if (line_pts != NULL) 669 { 670 ExFreePoolWithTag(line_pts, TAG_SHAPE); 671 } 672 673 if ((line_pts_old != NULL) && (line_pts_old != line_pts)) 674 { 675 ExFreePoolWithTag(line_pts_old, TAG_SHAPE); 676 } 677 678 if (bzr_pts != NULL) 679 { 680 ExFreePoolWithTag(bzr_pts, TAG_BEZIER); 681 } 682 683 DC_UnlockDc(dc); 684 685 return result; 686 } 687 688 /* 689 * @implemented 690 */ 691 _Success_(return != FALSE) 692 BOOL 693 APIENTRY 694 NtGdiMoveTo( 695 IN HDC hdc, 696 IN INT x, 697 IN INT y, 698 OUT OPTIONAL LPPOINT pptOut) 699 { 700 PDC pdc; 701 BOOL Ret; 702 POINT Point; 703 704 pdc = DC_LockDc(hdc); 705 if (!pdc) return FALSE; 706 707 Ret = IntGdiMoveToEx(pdc, x, y, &Point); 708 709 if (Ret && pptOut) 710 { 711 _SEH2_TRY 712 { 713 ProbeForWrite(pptOut, sizeof(POINT), 1); 714 RtlCopyMemory(pptOut, &Point, sizeof(POINT)); 715 } 716 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 717 { 718 SetLastNtError(_SEH2_GetExceptionCode()); 719 Ret = FALSE; // CHECKME: is this correct? 720 } 721 _SEH2_END; 722 } 723 724 DC_UnlockDc(pdc); 725 726 return Ret; 727 } 728 729 /* EOF */ 730