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 if (!(fuOptions & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE))) 504 { 505 if (LoadLPK(LPK_ETO)) 506 return LpkExtTextOut(hdc, x, y, fuOptions, lprc, lpString, cwc , lpDx, 0); 507 } 508 509 return NtGdiExtTextOutW(hdc, 510 x, 511 y, 512 fuOptions, 513 (LPRECT)lprc, 514 (LPWSTR)lpString, 515 cwc, 516 (LPINT)lpDx, 517 0); 518 } 519 520 521 /* 522 * @implemented 523 */ 524 INT 525 WINAPI 526 GetTextFaceW( 527 _In_ HDC hdc, 528 _In_ INT cwcMax, 529 _Out_writes_to_opt_(cwcMax, return) LPWSTR pFaceName) 530 { 531 /* Validate parameters */ 532 if (pFaceName && cwcMax <= 0) 533 { 534 /* Set last error and return failure */ 535 GdiSetLastError(ERROR_INVALID_PARAMETER); 536 return 0; 537 } 538 539 /* Forward to kernel */ 540 return NtGdiGetTextFaceW(hdc, cwcMax, pFaceName, FALSE); 541 } 542 543 544 /* 545 * @implemented 546 */ 547 INT 548 WINAPI 549 GetTextFaceA( 550 _In_ HDC hdc, 551 _In_ INT cchMax, 552 _Out_writes_to_opt_(cchMax, return) LPSTR lpName) 553 { 554 INT res; 555 LPWSTR nameW; 556 557 /* Validate parameters */ 558 if (lpName && cchMax <= 0) 559 { 560 /* Set last error and return failure */ 561 GdiSetLastError(ERROR_INVALID_PARAMETER); 562 return 0; 563 } 564 565 res = GetTextFaceW(hdc, 0, NULL); 566 nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 ); 567 if (nameW == NULL) 568 { 569 return 0; 570 } 571 572 GetTextFaceW( hdc, res, nameW ); 573 574 if (lpName) 575 { 576 if (cchMax && !WideCharToMultiByte( CP_ACP, 0, nameW, -1, lpName, cchMax, NULL, NULL)) 577 lpName[cchMax-1] = 0; 578 res = strlen(lpName); 579 } 580 else 581 { 582 res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL); 583 } 584 585 HeapFree( GetProcessHeap(), 0, nameW ); 586 return res; 587 } 588 589 590 /* 591 * @implemented 592 */ 593 INT 594 WINAPI 595 GetTextFaceAliasW( 596 _In_ HDC hdc, 597 _In_ INT cwcMax, 598 _Out_writes_to_opt_(cwcMax, return) LPWSTR pszOut) 599 { 600 if (pszOut && !cwcMax) 601 { 602 GdiSetLastError(ERROR_INVALID_PARAMETER); 603 return 0; 604 } 605 606 return NtGdiGetTextFaceW(hdc, cwcMax, pszOut, TRUE); 607 } 608 609 610 BOOL 611 WINAPI 612 GetFontResourceInfoW( 613 _In_z_ LPCWSTR lpFileName, 614 _Inout_ DWORD *pdwBufSize, 615 _Out_writes_to_opt_(*pdwBufSize, 1) PVOID lpBuffer, 616 _In_ DWORD dwType) 617 { 618 BOOL bRet; 619 UNICODE_STRING NtFileName; 620 621 DPRINT("GetFontResourceInfoW: dwType = %lu\n", dwType); 622 623 if (!lpFileName || !pdwBufSize) 624 { 625 SetLastError(ERROR_INVALID_PARAMETER); 626 return FALSE; 627 } 628 629 if (!RtlDosPathNameToNtPathName_U(lpFileName, 630 &NtFileName, 631 NULL, 632 NULL)) 633 { 634 SetLastError(ERROR_PATH_NOT_FOUND); 635 return FALSE; 636 } 637 638 bRet = NtGdiGetFontResourceInfoInternalW( 639 NtFileName.Buffer, 640 (NtFileName.Length / sizeof(WCHAR)) + 1, 641 1, 642 *pdwBufSize, 643 pdwBufSize, 644 lpBuffer, 645 dwType); 646 647 RtlFreeHeap(RtlGetProcessHeap(), 0, NtFileName.Buffer); 648 649 return bRet; 650 } 651 652 653 /* 654 * @unimplemented 655 */ 656 INT 657 WINAPI 658 SetTextCharacterExtra( 659 _In_ HDC hdc, 660 _In_ INT nCharExtra) 661 { 662 PDC_ATTR pdcattr; 663 INT nOldCharExtra; 664 665 if (nCharExtra == 0x80000000) 666 { 667 SetLastError(ERROR_INVALID_PARAMETER); 668 return 0x80000000; 669 } 670 671 if (GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE) 672 { 673 HANDLE_METADC(INT, SetTextCharacterExtra, 0x80000000, hdc, nCharExtra); 674 } 675 676 /* Get the DC attribute */ 677 pdcattr = GdiGetDcAttr(hdc); 678 if (pdcattr == NULL) 679 { 680 SetLastError(ERROR_INVALID_PARAMETER); 681 return 0x8000000; 682 } 683 684 if (NtCurrentTeb()->GdiTebBatch.HDC == hdc) 685 { 686 if (pdcattr->ulDirty_ & DC_FONTTEXT_DIRTY) 687 { 688 NtGdiFlush(); // Sync up pdcattr from Kernel space. 689 pdcattr->ulDirty_ &= ~(DC_MODE_DIRTY|DC_FONTTEXT_DIRTY); 690 } 691 } 692 693 nOldCharExtra = pdcattr->lTextExtra; 694 pdcattr->lTextExtra = nCharExtra; 695 return nOldCharExtra; 696 } 697 698 /* 699 * @implemented 700 * 701 */ 702 UINT 703 WINAPI 704 GetTextAlign( 705 _In_ HDC hdc) 706 { 707 PDC_ATTR pdcattr; 708 709 /* Get the DC attribute */ 710 pdcattr = GdiGetDcAttr(hdc); 711 if (pdcattr == NULL) 712 { 713 /* Do not set LastError here! */ 714 return GDI_ERROR; 715 } 716 717 return pdcattr->lTextAlign; 718 } 719 720 721 /* 722 * @implemented 723 * 724 */ 725 COLORREF 726 WINAPI 727 GetTextColor( 728 _In_ HDC hdc) 729 { 730 PDC_ATTR pdcattr; 731 732 /* Get the DC attribute */ 733 pdcattr = GdiGetDcAttr(hdc); 734 if (pdcattr == NULL) 735 { 736 /* Do not set LastError here! */ 737 return CLR_INVALID; 738 } 739 740 return pdcattr->ulForegroundClr; 741 } 742 743 744 /* 745 * @unimplemented 746 */ 747 UINT 748 WINAPI 749 SetTextAlign( 750 _In_ HDC hdc, 751 _In_ UINT fMode) 752 { 753 PDC_ATTR pdcattr; 754 UINT fOldMode; 755 756 HANDLE_METADC(BOOL, SetTextAlign, GDI_ERROR, hdc, fMode); 757 758 /* Get the DC attribute */ 759 pdcattr = GdiGetDcAttr(hdc); 760 if (pdcattr == NULL) 761 { 762 SetLastError(ERROR_INVALID_PARAMETER); 763 return GDI_ERROR; 764 } 765 766 767 fOldMode = pdcattr->lTextAlign; 768 pdcattr->lTextAlign = fMode; // Raw 769 if (pdcattr->dwLayout & LAYOUT_RTL) 770 { 771 if ((fMode & TA_CENTER) != TA_CENTER) fMode ^= TA_RIGHT; 772 } 773 774 pdcattr->flTextAlign = fMode & TA_MASK; 775 return fOldMode; 776 } 777 778 779 /* 780 * @implemented 781 */ 782 COLORREF 783 WINAPI 784 SetTextColor( 785 _In_ HDC hdc, 786 _In_ COLORREF crColor) 787 { 788 PDC_ATTR pdcattr; 789 COLORREF crOldColor; 790 791 HANDLE_METADC(COLORREF, SetTextColor, CLR_INVALID, hdc, crColor); 792 793 pdcattr = GdiGetDcAttr(hdc); 794 if (pdcattr == NULL) 795 { 796 SetLastError(ERROR_INVALID_PARAMETER); 797 return CLR_INVALID; 798 } 799 800 crOldColor = (COLORREF) pdcattr->ulForegroundClr; 801 pdcattr->ulForegroundClr = (ULONG)crColor; 802 803 if (pdcattr->crForegroundClr != crColor) 804 { 805 pdcattr->ulDirty_ |= (DIRTY_TEXT|DIRTY_LINE|DIRTY_FILL); 806 pdcattr->crForegroundClr = crColor; 807 } 808 809 return crOldColor; 810 } 811 812 /* 813 * @implemented 814 */ 815 BOOL 816 WINAPI 817 SetTextJustification( 818 _In_ HDC hdc, 819 _In_ INT nBreakExtra, 820 _In_ INT nBreakCount) 821 { 822 PDC_ATTR pdcattr; 823 824 if (GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE) 825 { 826 HANDLE_METADC(BOOL, SetTextJustification, FALSE, hdc, nBreakExtra, nBreakCount); 827 } 828 829 /* Get the DC attribute */ 830 pdcattr = GdiGetDcAttr(hdc); 831 if (pdcattr == NULL) 832 { 833 /* Do not set LastError here! */ 834 return GDI_ERROR; 835 } 836 837 838 if (NtCurrentTeb()->GdiTebBatch.HDC == hdc) 839 { 840 if (pdcattr->ulDirty_ & DC_FONTTEXT_DIRTY) 841 { 842 NtGdiFlush(); // Sync up pdcattr from Kernel space. 843 pdcattr->ulDirty_ &= ~(DC_MODE_DIRTY|DC_FONTTEXT_DIRTY); 844 } 845 } 846 847 pdcattr->cBreak = nBreakCount; 848 pdcattr->lBreakExtra = nBreakExtra; 849 return TRUE; 850 } 851 852 /* 853 * @implemented 854 */ 855 UINT 856 WINAPI 857 GetStringBitmapA( 858 _In_ HDC hdc, 859 _In_ LPSTR psz, 860 _In_ BOOL bDoCall, 861 _In_ UINT cj, 862 _Out_writes_(cj) BYTE *lpSB) 863 { 864 865 NTSTATUS Status; 866 PWSTR pwsz; 867 UINT uResult = 0; 868 869 if (!bDoCall) 870 { 871 return 0; 872 } 873 874 Status = HEAP_strdupA2W(&pwsz, psz); 875 if (!NT_SUCCESS(Status)) 876 { 877 SetLastError (RtlNtStatusToDosError(Status)); 878 } 879 else 880 { 881 uResult = NtGdiGetStringBitmapW(hdc, pwsz, 1, lpSB, cj); 882 HEAP_free(pwsz); 883 } 884 885 return uResult; 886 887 } 888 889 /* 890 * @implemented 891 */ 892 UINT 893 WINAPI 894 GetStringBitmapW( 895 _In_ HDC hdc, 896 _In_ LPWSTR pwsz, 897 _In_ BOOL bDoCall, 898 _In_ UINT cj, 899 _Out_writes_(cj) BYTE *lpSB) 900 { 901 if (!bDoCall) 902 { 903 return 0; 904 } 905 906 return NtGdiGetStringBitmapW(hdc, pwsz, 1, lpSB, cj); 907 908 } 909 910 /* 911 * @implemented 912 */ 913 BOOL 914 WINAPI 915 GetETM( 916 _In_ HDC hdc, 917 _Out_ EXTTEXTMETRIC *petm) 918 { 919 BOOL bResult; 920 921 bResult = NtGdiGetETM(hdc, petm); 922 923 if (bResult && petm) 924 { 925 petm->emKernPairs = (WORD)GetKerningPairsA(hdc, 0, 0); 926 } 927 928 return bResult; 929 } 930