From: Trung Nguyen <me@trungnt2910.com> This specifier allows printing the `UNICODE_STRING` and `ANSI_STRING` structures. It is useful for running unit tests for kernel mode or shared components on WINE. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=59563 --- dlls/msvcrt/printf.h | 47 +++++++++++++++++++++++++++++++++++++------- dlls/msvcrt/wcs.c | 1 + 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/dlls/msvcrt/printf.h b/dlls/msvcrt/printf.h index cfcfd5be771..9cc9c3b237c 100644 --- a/dlls/msvcrt/printf.h +++ b/dlls/msvcrt/printf.h @@ -255,11 +255,34 @@ static inline int FUNC_NAME(pf_output_format_str)(FUNC_NAME(puts_clbk) pf_puts, return r>=0 ? ret : r; } -static inline int FUNC_NAME(pf_handle_string)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx, - const void *str, int len, pf_flags *flags, _locale_t locale, BOOL legacy_wide) +static inline BOOL FUNC_NAME(pf_is_str_wide)(pf_flags *flags, BOOL legacy_wide) { BOOL api_is_wide = sizeof(APICHAR) == sizeof(wchar_t); BOOL complement_is_narrow = legacy_wide ? api_is_wide : FALSE; + + if((flags->NaturalString && api_is_wide) || flags->WideString || flags->IntegerLength == LEN_LONG) + return TRUE; + if((flags->NaturalString && !api_is_wide) || flags->IntegerLength == LEN_SHORT) + return FALSE; + +#if _MSVCR_VER >= 140 + if (flags->Format == 'Z') + return legacy_wide ? !api_is_wide : TRUE; +#else + if (flags->Format == 'Z') + return FALSE; +#endif + + if((flags->Format=='S' || flags->Format=='C') == complement_is_narrow) + return FALSE; + else + return TRUE; +} + +static inline int FUNC_NAME(pf_handle_string)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx, + const void *str, int len, pf_flags *flags, _locale_t locale, BOOL legacy_wide) +{ + BOOL str_is_wide; #ifdef PRINTF_WIDE if(!str) @@ -269,12 +292,13 @@ static inline int FUNC_NAME(pf_handle_string)(FUNC_NAME(puts_clbk) pf_puts, void return FUNC_NAME(pf_output_format_str)(pf_puts, puts_ctx, "(null)", 6, flags, locale); #endif - if((flags->NaturalString && api_is_wide) || flags->WideString || flags->IntegerLength == LEN_LONG) - return FUNC_NAME(pf_output_format_wstr)(pf_puts, puts_ctx, str, len, flags, locale); - if((flags->NaturalString && !api_is_wide) || flags->IntegerLength == LEN_SHORT) - return FUNC_NAME(pf_output_format_str)(pf_puts, puts_ctx, str, len, flags, locale); + str_is_wide = FUNC_NAME(pf_is_str_wide)(flags, legacy_wide); - if((flags->Format=='S' || flags->Format=='C') == complement_is_narrow) + /* UNICODE_STRING passes the number of bytes. */ + if(flags->Format=='Z' && str_is_wide && len != -1) + len /= sizeof(wchar_t); + + if(!str_is_wide) return FUNC_NAME(pf_output_format_str)(pf_puts, puts_ctx, str, len, flags, locale); else return FUNC_NAME(pf_output_format_wstr)(pf_puts, puts_ctx, str, len, flags, locale); @@ -1142,6 +1166,15 @@ int FUNC_NAME(pf_printf)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx, const API i = FUNC_NAME(pf_handle_string)(pf_puts, puts_ctx, &ch, 1, &flags, locale, legacy_wide); if(i < 0) i = 0; /* ignore conversion error */ + } else if(flags.Format == 'Z') { + /* UNICODE_STRING and ANSI_STRING have the same layout. */ + UNICODE_STRING *str = pf_args(args_ctx, pos, VT_PTR, valist).get_ptr; + if(!str) + i = FUNC_NAME(pf_handle_string)(pf_puts, puts_ctx, NULL, -1, + &flags, locale, legacy_wide); + else + i = FUNC_NAME(pf_handle_string)(pf_puts, puts_ctx, str->Buffer, str->Length, + &flags, locale, legacy_wide); } else if(flags.Format == 'p') { flags.Format = 'X'; flags.PadZero = TRUE; diff --git a/dlls/msvcrt/wcs.c b/dlls/msvcrt/wcs.c index 1b7bc3e54e0..9ad7181311a 100644 --- a/dlls/msvcrt/wcs.c +++ b/dlls/msvcrt/wcs.c @@ -28,6 +28,7 @@ #include <wctype.h> #include "msvcrt.h" #include "winnls.h" +#include "winternl.h" #include "wtypes.h" #include "wine/debug.h" -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10460