1 /* 2 * PROJECT: ReactOS GDI32 3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) 4 * PURPOSE: Text drawing API. 5 * COPYRIGHT: Copyright 2014 Timo Kreuzer 6 * Copyright 2017 Katayama Hirofumi MZ 7 */ 8 9 #include <precomp.h> 10 11 #define NDEBUG 12 #include <debug.h> 13 14 /* 15 * @implemented 16 */ 17 BOOL 18 WINAPI 19 TextOutA( 20 _In_ HDC hdc, 21 _In_ INT nXStart, 22 _In_ INT nYStart, 23 _In_reads_(cchString) LPCSTR lpString, 24 _In_ INT cchString) 25 { 26 ANSI_STRING StringA; 27 UNICODE_STRING StringU; 28 BOOL bResult; 29 NTSTATUS Status; 30 31 if (lpString != NULL && cchString > 0) 32 { 33 if (cchString > MAXUSHORT) 34 cchString = MAXUSHORT; 35 36 StringA.Length = (USHORT)cchString; 37 StringA.MaximumLength = (USHORT)cchString; 38 StringA.Buffer = (PCHAR)lpString; 39 40 Status = RtlAnsiStringToUnicodeString(&StringU, &StringA, TRUE); 41 if (!NT_SUCCESS(Status)) 42 { 43 StringU.Buffer = NULL; 44 StringU.Length = 0; 45 } 46 } 47 else 48 { 49 StringU.Buffer = NULL; 50 StringU.Length = 0; 51 } 52 53 bResult = TextOutW(hdc, nXStart, nYStart, 54 StringU.Buffer, StringU.Length / sizeof(WCHAR)); 55 56 RtlFreeUnicodeString(&StringU); 57 return bResult; 58 } 59 60 61 /* 62 * @implemented 63 */ 64 BOOL 65 WINAPI 66 TextOutW( 67 _In_ HDC hdc, 68 _In_ INT nXStart, 69 _In_ INT nYStart, 70 _In_reads_(cchString) LPCWSTR lpString, 71 _In_ INT cchString) 72 { 73 return ExtTextOutW(hdc, nXStart, nYStart, 0, NULL, (LPWSTR)lpString, cchString, NULL); 74 } 75 76 77 /* 78 * @unimplemented 79 */ 80 BOOL 81 WINAPI 82 PolyTextOutA( 83 _In_ HDC hdc, 84 _In_reads_(cStrings) const POLYTEXTA *pptxt, 85 _In_ INT cStrings) 86 { 87 for (; cStrings>0; cStrings--, pptxt++) 88 { 89 if (!ExtTextOutA(hdc, 90 pptxt->x, 91 pptxt->y, 92 pptxt->uiFlags, 93 &pptxt->rcl, 94 pptxt->lpstr, 95 pptxt->n, 96 pptxt->pdx)) 97 { 98 return FALSE; 99 } 100 } 101 102 return TRUE; 103 } 104 105 106 /* 107 * @unimplemented 108 */ 109 BOOL 110 WINAPI 111 PolyTextOutW( 112 _In_ HDC hdc, 113 _In_reads_(cStrings) const POLYTEXTW *pptxt, 114 _In_ INT cStrings) 115 { 116 for (; cStrings>0; cStrings--, pptxt++) 117 { 118 if (!ExtTextOutW(hdc, 119 pptxt->x, 120 pptxt->y, 121 pptxt->uiFlags, 122 &pptxt->rcl, 123 pptxt->lpstr, 124 pptxt->n, 125 pptxt->pdx)) 126 { 127 return FALSE; 128 } 129 } 130 131 return TRUE; 132 } 133 134 135 /* 136 * @implemented 137 */ 138 DWORD 139 WINAPI 140 GdiGetCodePage( 141 _In_ HDC hdc) 142 { 143 PDC_ATTR pdcattr; 144 145 /* Get the DC attribute */ 146 pdcattr = GdiGetDcAttr(hdc); 147 if (pdcattr == NULL) 148 { 149 SetLastError(ERROR_INVALID_PARAMETER); 150 return 0; 151 } 152 153 if (pdcattr->ulDirty_ & DIRTY_CHARSET) 154 return LOWORD(NtGdiGetCharSet(hdc)); 155 156 return LOWORD(pdcattr->iCS_CP); 157 } 158 159 160 /* 161 * @unimplemented 162 */ 163 INT 164 WINAPI 165 GetTextCharacterExtra( 166 _In_ HDC hdc) 167 { 168 PDC_ATTR pdcattr; 169 170 /* Get the DC attribute */ 171 pdcattr = GdiGetDcAttr(hdc); 172 if (pdcattr == NULL) 173 { 174 /* Do not set LastError here! */ 175 return 0x8000000; 176 } 177 178 return pdcattr->lTextExtra; 179 } 180 181 182 /* 183 * @implemented 184 */ 185 INT 186 WINAPI 187 GetTextCharset( 188 _In_ HDC hdc) 189 { 190 /* MSDN docs say this is equivalent */ 191 return NtGdiGetTextCharsetInfo(hdc,NULL,0); 192 } 193 194 195 /* 196 * @implemented 197 */ 198 BOOL 199 WINAPI 200 GetTextMetricsA( 201 _In_ HDC hdc, 202 _Out_ LPTEXTMETRICA lptm) 203 { 204 TMW_INTERNAL tmwi; 205 206 if (!NtGdiGetTextMetricsW(hdc, &tmwi, sizeof(TMW_INTERNAL))) 207 { 208 return FALSE; 209 } 210 211 FONT_TextMetricWToA(&tmwi.TextMetric, lptm); 212 return TRUE; 213 } 214 215 216 /* 217 * @implemented 218 */ 219 BOOL 220 WINAPI 221 GetTextMetricsW( 222 _In_ HDC hdc, 223 _Out_ LPTEXTMETRICW lptm) 224 { 225 TMW_INTERNAL tmwi; 226 227 if (!NtGdiGetTextMetricsW(hdc, &tmwi, sizeof(TMW_INTERNAL))) 228 { 229 return FALSE; 230 } 231 232 *lptm = tmwi.TextMetric; 233 return TRUE; 234 } 235 236 237 /* 238 * @implemented 239 */ 240 BOOL 241 APIENTRY 242 GetTextExtentPointA( 243 _In_ HDC hdc, 244 _In_reads_(cchString) LPCSTR lpString, 245 _In_ INT cchString, 246 _Out_ LPSIZE lpsz) 247 { 248 ANSI_STRING StringA; 249 UNICODE_STRING StringU; 250 BOOL ret; 251 252 RtlInitAnsiString(&StringA, (LPSTR)lpString); 253 RtlAnsiStringToUnicodeString(&StringU, &StringA, TRUE); 254 255 ret = GetTextExtentPointW(hdc, StringU.Buffer, cchString, lpsz); 256 257 RtlFreeUnicodeString(&StringU); 258 259 return ret; 260 } 261 262 263 /* 264 * @implemented 265 */ 266 BOOL 267 APIENTRY 268 GetTextExtentPointW( 269 _In_ HDC hdc, 270 _In_reads_(cchString) LPCWSTR lpString, 271 _In_ INT cchString, 272 _Out_ LPSIZE lpsz) 273 { 274 return NtGdiGetTextExtent(hdc, (LPWSTR)lpString, cchString, lpsz, 0); 275 } 276 277 278 /* 279 * @implemented 280 */ 281 BOOL 282 WINAPI 283 GetTextExtentExPointW( 284 _In_ HDC hdc, 285 _In_reads_(cchString) LPCWSTR lpszString, 286 _In_ INT cchString, 287 _In_ INT nMaxExtent, 288 _Out_opt_ LPINT lpnFit, 289 _Out_writes_to_opt_(cchString, *lpnFit) LPINT lpnDx, 290 _Out_ LPSIZE lpSize) 291 { 292 293 /* Windows doesn't check nMaxExtent validity in unicode version */ 294 if (nMaxExtent < -1) 295 { 296 DPRINT("nMaxExtent is invalid: %d\n", nMaxExtent); 297 } 298 299 return NtGdiGetTextExtentExW ( 300 hdc, (LPWSTR)lpszString, cchString, nMaxExtent, (PULONG)lpnFit, (PULONG)lpnDx, lpSize, 0 ); 301 } 302 303 304 /* 305 * @implemented 306 */ 307 BOOL 308 WINAPI 309 GetTextExtentExPointWPri( 310 _In_ HDC hdc, 311 _In_reads_(cwc) LPWSTR lpwsz, 312 _In_ ULONG cwc, 313 _In_ ULONG dxMax, 314 _Out_opt_ ULONG *pcCh, 315 _Out_writes_to_opt_(cwc, *pcCh) PULONG pdxOut, 316 _In_ LPSIZE psize) 317 { 318 return NtGdiGetTextExtentExW(hdc, lpwsz, cwc, dxMax, pcCh, pdxOut, psize, 0); 319 } 320 321 /* 322 * @implemented 323 */ 324 BOOL 325 WINAPI 326 GetTextExtentExPointA( 327 _In_ HDC hdc, 328 _In_reads_(cchString) LPCSTR lpszStr, 329 _In_ INT cchString, 330 _In_ INT nMaxExtent, 331 _Out_opt_ LPINT lpnFit, 332 _Out_writes_to_opt_ (cchString, *lpnFit) LPINT lpnDx, 333 _Out_ LPSIZE lpSize) 334 { 335 NTSTATUS Status; 336 LPWSTR lpszStrW; 337 BOOL bResult = FALSE; 338 339 if (nMaxExtent < -1) 340 { 341 SetLastError(ERROR_INVALID_PARAMETER); 342 return FALSE; 343 } 344 345 Status = HEAP_strdupA2W(&lpszStrW, lpszStr); 346 if (!NT_SUCCESS (Status)) 347 { 348 SetLastError(RtlNtStatusToDosError(Status)); 349 return FALSE; 350 } 351 352 bResult = NtGdiGetTextExtentExW(hdc, 353 lpszStrW, 354 cchString, 355 nMaxExtent, 356 (PULONG)lpnFit, 357 (PULONG)lpnDx, 358 lpSize, 359 0); 360 361 HEAP_free(lpszStrW); 362 363 return bResult; 364 } 365 366 367 /* 368 * @implemented 369 */ 370 BOOL 371 WINAPI 372 GetTextExtentPoint32A( 373 _In_ HDC hdc, 374 _In_reads_(cchString) LPCSTR lpString, 375 _In_ INT cchString, 376 _Out_ LPSIZE lpSize) 377 { 378 ANSI_STRING StringA; 379 UNICODE_STRING StringU; 380 BOOL ret; 381 382 StringA.Buffer = (LPSTR)lpString; 383 StringA.Length = cchString; 384 RtlAnsiStringToUnicodeString(&StringU, &StringA, TRUE); 385 386 ret = GetTextExtentPoint32W(hdc, StringU.Buffer, cchString, lpSize); 387 388 RtlFreeUnicodeString(&StringU); 389 390 return ret; 391 } 392 393 394 /* 395 * @implemented 396 */ 397 BOOL 398 WINAPI 399 GetTextExtentPoint32W( 400 _In_ HDC hdc, 401 _In_reads_(cchString) LPCWSTR lpString, 402 _In_ int cchString, 403 _Out_ LPSIZE lpSize) 404 { 405 return NtGdiGetTextExtent(hdc, (LPWSTR)lpString, cchString, lpSize, 0); 406 } 407 408 /* 409 * @implemented 410 */ 411 BOOL 412 WINAPI 413 GetTextExtentExPointI( 414 _In_ HDC hdc, 415 _In_reads_(cgi) LPWORD pgiIn, 416 _In_ INT cgi, 417 _In_ INT nMaxExtent, 418 _Out_opt_ LPINT lpnFit, 419 _Out_writes_to_opt_(cwchString, *lpnFit) LPINT lpnDx, 420 _Out_ LPSIZE lpSize) 421 { 422 return NtGdiGetTextExtentExW(hdc, 423 pgiIn, 424 cgi, 425 nMaxExtent, 426 (PULONG)lpnFit, 427 (PULONG)lpnDx, 428 lpSize, 429 GTEF_INDICES); 430 } 431 432 /* 433 * @implemented 434 */ 435 BOOL 436 WINAPI 437 GetTextExtentPointI( 438 _In_ HDC hdc, 439 _In_reads_(cgi) LPWORD pgiIn, 440 _In_ int cgi, 441 _Out_ LPSIZE lpSize) 442 { 443 return NtGdiGetTextExtent(hdc, pgiIn, cgi, lpSize, GTEF_INDICES); 444 } 445 446 /* 447 * @implemented 448 */ 449 BOOL 450 WINAPI 451 ExtTextOutA( 452 _In_ HDC hdc, 453 _In_ INT x, 454 _In_ INT y, 455 _In_ UINT fuOptions, 456 _In_opt_ const RECT *lprc, 457 _In_reads_opt_(cch) LPCSTR lpString, 458 _In_ UINT cch, 459 _In_reads_opt_(cch) const INT *lpDx) 460 { 461 ANSI_STRING StringA; 462 UNICODE_STRING StringU; 463 BOOL ret; 464 465 RtlInitAnsiString(&StringA, (LPSTR)lpString); 466 RtlAnsiStringToUnicodeString(&StringU, &StringA, TRUE); 467 468 ret = ExtTextOutW(hdc, x, y, fuOptions, lprc, StringU.Buffer, cch, lpDx); 469 470 RtlFreeUnicodeString(&StringU); 471 472 return ret; 473 } 474 475 476 /* 477 * @implemented 478 */ 479 BOOL 480 WINAPI 481 ExtTextOutW( 482 _In_ HDC hdc, 483 _In_ INT x, 484 _In_ INT y, 485 _In_ UINT fuOptions, 486 _In_opt_ const RECT *lprc, 487 _In_reads_opt_(cwc) LPCWSTR lpString, 488 _In_ UINT cwc, 489 _In_reads_opt_(cwc) const INT *lpDx) 490 { 491 HANDLE_METADC(BOOL, 492 ExtTextOut, 493 FALSE, 494 hdc, 495 x, 496 y, 497 fuOptions, 498 lprc, 499 lpString, 500 cwc, 501 lpDx); 502 503 return NtGdiExtTextOutW(hdc, 504 x, 505 y, 506 fuOptions, 507 (LPRECT)lprc, 508 (LPWSTR)lpString, 509 cwc, 510 (LPINT)lpDx, 511 0); 512 } 513 514 515 /* 516 * @implemented 517 */ 518 INT 519 WINAPI 520 GetTextFaceW( 521 _In_ HDC hdc, 522 _In_ INT cwcMax, 523 _Out_writes_to_opt_(cwcMax, return) LPWSTR pFaceName) 524 { 525 /* Validate parameters */ 526 if (pFaceName && cwcMax <= 0) 527 { 528 /* Set last error and return failure */ 529 GdiSetLastError(ERROR_INVALID_PARAMETER); 530 return 0; 531 } 532 533 /* Forward to kernel */ 534 return NtGdiGetTextFaceW(hdc, cwcMax, pFaceName, FALSE); 535 } 536 537 538 /* 539 * @implemented 540 */ 541 INT 542 WINAPI 543 GetTextFaceA( 544 _In_ HDC hdc, 545 _In_ INT cchMax, 546 _Out_writes_to_opt_(cchMax, return) LPSTR lpName) 547 { 548 INT res; 549 LPWSTR nameW; 550 551 /* Validate parameters */ 552 if (lpName && cchMax <= 0) 553 { 554 /* Set last error and return failure */ 555 GdiSetLastError(ERROR_INVALID_PARAMETER); 556 return 0; 557 } 558 559 res = GetTextFaceW(hdc, 0, NULL); 560 nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 ); 561 if (nameW == NULL) 562 { 563 return 0; 564 } 565 566 GetTextFaceW( hdc, res, nameW ); 567 568 if (lpName) 569 { 570 if (cchMax && !WideCharToMultiByte( CP_ACP, 0, nameW, -1, lpName, cchMax, NULL, NULL)) 571 lpName[cchMax-1] = 0; 572 res = strlen(lpName); 573 } 574 else 575 { 576 res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL); 577 } 578 579 HeapFree( GetProcessHeap(), 0, nameW ); 580 return res; 581 } 582 583 584 /* 585 * @implemented 586 */ 587 INT 588 WINAPI 589 GetTextFaceAliasW( 590 _In_ HDC hdc, 591 _In_ INT cwcMax, 592 _Out_writes_to_opt_(cwcMax, return) LPWSTR pszOut) 593 { 594 if (pszOut && !cwcMax) 595 { 596 GdiSetLastError(ERROR_INVALID_PARAMETER); 597 return 0; 598 } 599 600 return NtGdiGetTextFaceW(hdc, cwcMax, pszOut, TRUE); 601 } 602 603 604 BOOL 605 WINAPI 606 GetFontResourceInfoW( 607 _In_z_ LPCWSTR lpFileName, 608 _Inout_ DWORD *pdwBufSize, 609 _Out_writes_to_opt_(*pdwBufSize, 1) PVOID lpBuffer, 610 _In_ DWORD dwType) 611 { 612 BOOL bRet; 613 UNICODE_STRING NtFileName; 614 615 DPRINT("GetFontResourceInfoW: dwType = %lu\n", dwType); 616 617 if (!lpFileName || !pdwBufSize) 618 { 619 SetLastError(ERROR_INVALID_PARAMETER); 620 return FALSE; 621 } 622 623 if (!RtlDosPathNameToNtPathName_U(lpFileName, 624 &NtFileName, 625 NULL, 626 NULL)) 627 { 628 SetLastError(ERROR_PATH_NOT_FOUND); 629 return FALSE; 630 } 631 632 bRet = NtGdiGetFontResourceInfoInternalW( 633 NtFileName.Buffer, 634 (NtFileName.Length / sizeof(WCHAR)) + 1, 635 1, 636 *pdwBufSize, 637 pdwBufSize, 638 lpBuffer, 639 dwType); 640 641 RtlFreeHeap(RtlGetProcessHeap(), 0, NtFileName.Buffer); 642 643 return bRet; 644 } 645 646 647 /* 648 * @unimplemented 649 */ 650 INT 651 WINAPI 652 SetTextCharacterExtra( 653 _In_ HDC hdc, 654 _In_ INT nCharExtra) 655 { 656 PDC_ATTR pdcattr; 657 INT nOldCharExtra; 658 659 if (nCharExtra == 0x80000000) 660 { 661 SetLastError(ERROR_INVALID_PARAMETER); 662 return 0x80000000; 663 } 664 665 if (GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE) 666 { 667 HANDLE_METADC(INT, SetTextCharacterExtra, 0x80000000, hdc, nCharExtra); 668 } 669 670 /* Get the DC attribute */ 671 pdcattr = GdiGetDcAttr(hdc); 672 if (pdcattr == NULL) 673 { 674 SetLastError(ERROR_INVALID_PARAMETER); 675 return 0x8000000; 676 } 677 678 if (NtCurrentTeb()->GdiTebBatch.HDC == hdc) 679 { 680 if (pdcattr->ulDirty_ & DC_FONTTEXT_DIRTY) 681 { 682 NtGdiFlush(); // Sync up pdcattr from Kernel space. 683 pdcattr->ulDirty_ &= ~(DC_MODE_DIRTY|DC_FONTTEXT_DIRTY); 684 } 685 } 686 687 nOldCharExtra = pdcattr->lTextExtra; 688 pdcattr->lTextExtra = nCharExtra; 689 return nOldCharExtra; 690 } 691 692 /* 693 * @implemented 694 * 695 */ 696 UINT 697 WINAPI 698 GetTextAlign( 699 _In_ HDC hdc) 700 { 701 PDC_ATTR pdcattr; 702 703 /* Get the DC attribute */ 704 pdcattr = GdiGetDcAttr(hdc); 705 if (pdcattr == NULL) 706 { 707 /* Do not set LastError here! */ 708 return GDI_ERROR; 709 } 710 711 return pdcattr->lTextAlign; 712 } 713 714 715 /* 716 * @implemented 717 * 718 */ 719 COLORREF 720 WINAPI 721 GetTextColor( 722 _In_ HDC hdc) 723 { 724 PDC_ATTR pdcattr; 725 726 /* Get the DC attribute */ 727 pdcattr = GdiGetDcAttr(hdc); 728 if (pdcattr == NULL) 729 { 730 /* Do not set LastError here! */ 731 return CLR_INVALID; 732 } 733 734 return pdcattr->ulForegroundClr; 735 } 736 737 738 /* 739 * @unimplemented 740 */ 741 UINT 742 WINAPI 743 SetTextAlign( 744 _In_ HDC hdc, 745 _In_ UINT fMode) 746 { 747 PDC_ATTR pdcattr; 748 UINT fOldMode; 749 750 HANDLE_METADC(BOOL, SetTextAlign, GDI_ERROR, hdc, fMode); 751 752 /* Get the DC attribute */ 753 pdcattr = GdiGetDcAttr(hdc); 754 if (pdcattr == NULL) 755 { 756 SetLastError(ERROR_INVALID_PARAMETER); 757 return GDI_ERROR; 758 } 759 760 761 fOldMode = pdcattr->lTextAlign; 762 pdcattr->lTextAlign = fMode; // Raw 763 if (pdcattr->dwLayout & LAYOUT_RTL) 764 { 765 if ((fMode & TA_CENTER) != TA_CENTER) fMode ^= TA_RIGHT; 766 } 767 768 pdcattr->flTextAlign = fMode & TA_MASK; 769 return fOldMode; 770 } 771 772 773 /* 774 * @implemented 775 */ 776 COLORREF 777 WINAPI 778 SetTextColor( 779 _In_ HDC hdc, 780 _In_ COLORREF crColor) 781 { 782 PDC_ATTR pdcattr; 783 COLORREF crOldColor; 784 785 HANDLE_METADC(COLORREF, SetTextColor, CLR_INVALID, hdc, crColor); 786 787 pdcattr = GdiGetDcAttr(hdc); 788 if (pdcattr == NULL) 789 { 790 SetLastError(ERROR_INVALID_PARAMETER); 791 return CLR_INVALID; 792 } 793 794 crOldColor = (COLORREF) pdcattr->ulForegroundClr; 795 pdcattr->ulForegroundClr = (ULONG)crColor; 796 797 if (pdcattr->crForegroundClr != crColor) 798 { 799 pdcattr->ulDirty_ |= (DIRTY_TEXT|DIRTY_LINE|DIRTY_FILL); 800 pdcattr->crForegroundClr = crColor; 801 } 802 803 return crOldColor; 804 } 805 806 /* 807 * @implemented 808 */ 809 BOOL 810 WINAPI 811 SetTextJustification( 812 _In_ HDC hdc, 813 _In_ INT nBreakExtra, 814 _In_ INT nBreakCount) 815 { 816 PDC_ATTR pdcattr; 817 818 if (GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE) 819 { 820 HANDLE_METADC(BOOL, SetTextJustification, FALSE, hdc, nBreakExtra, nBreakCount); 821 } 822 823 /* Get the DC attribute */ 824 pdcattr = GdiGetDcAttr(hdc); 825 if (pdcattr == NULL) 826 { 827 /* Do not set LastError here! */ 828 return GDI_ERROR; 829 } 830 831 832 if (NtCurrentTeb()->GdiTebBatch.HDC == hdc) 833 { 834 if (pdcattr->ulDirty_ & DC_FONTTEXT_DIRTY) 835 { 836 NtGdiFlush(); // Sync up pdcattr from Kernel space. 837 pdcattr->ulDirty_ &= ~(DC_MODE_DIRTY|DC_FONTTEXT_DIRTY); 838 } 839 } 840 841 pdcattr->cBreak = nBreakCount; 842 pdcattr->lBreakExtra = nBreakExtra; 843 return TRUE; 844 } 845 846 /* 847 * @implemented 848 */ 849 UINT 850 WINAPI 851 GetStringBitmapA( 852 _In_ HDC hdc, 853 _In_ LPSTR psz, 854 _In_ BOOL bDoCall, 855 _In_ UINT cj, 856 _Out_writes_(cj) BYTE *lpSB) 857 { 858 859 NTSTATUS Status; 860 PWSTR pwsz; 861 UINT uResult = 0; 862 863 if (!bDoCall) 864 { 865 return 0; 866 } 867 868 Status = HEAP_strdupA2W(&pwsz, psz); 869 if (!NT_SUCCESS(Status)) 870 { 871 SetLastError (RtlNtStatusToDosError(Status)); 872 } 873 else 874 { 875 uResult = NtGdiGetStringBitmapW(hdc, pwsz, 1, lpSB, cj); 876 HEAP_free(pwsz); 877 } 878 879 return uResult; 880 881 } 882 883 /* 884 * @implemented 885 */ 886 UINT 887 WINAPI 888 GetStringBitmapW( 889 _In_ HDC hdc, 890 _In_ LPWSTR pwsz, 891 _In_ BOOL bDoCall, 892 _In_ UINT cj, 893 _Out_writes_(cj) BYTE *lpSB) 894 { 895 if (!bDoCall) 896 { 897 return 0; 898 } 899 900 return NtGdiGetStringBitmapW(hdc, pwsz, 1, lpSB, cj); 901 902 } 903 904 /* 905 * @implemented 906 */ 907 BOOL 908 WINAPI 909 GetETM( 910 _In_ HDC hdc, 911 _Out_ EXTTEXTMETRIC *petm) 912 { 913 BOOL bResult; 914 915 bResult = NtGdiGetETM(hdc, petm); 916 917 if (bResult && petm) 918 { 919 petm->emKernPairs = (WORD)GetKerningPairsA(hdc, 0, 0); 920 } 921 922 return bResult; 923 } 924