diff options
| author | Rob Mensching <rob@firegiant.com> | 2022-11-17 16:05:22 -0800 |
|---|---|---|
| committer | Rob Mensching <rob@firegiant.com> | 2022-11-21 09:12:41 -0800 |
| commit | 83a63bdc1943187e93749420a3408cd6248eedb9 (patch) | |
| tree | 617e931eddbf3ed96839ad4e100421e627a1ced5 /src | |
| parent | 307e3f1bb587b93ad386bbfd9b2d4603a72d80c4 (diff) | |
| download | wix-83a63bdc1943187e93749420a3408cd6248eedb9.tar.gz wix-83a63bdc1943187e93749420a3408cd6248eedb9.tar.bz2 wix-83a63bdc1943187e93749420a3408cd6248eedb9.zip | |
Add support for UTF-8 console and use it for passing smartcab paths
Fixes 7024
Diffstat (limited to 'src')
| -rw-r--r-- | src/libs/dutil/WixToolset.DUtil/conutil.cpp | 374 | ||||
| -rw-r--r-- | src/libs/dutil/WixToolset.DUtil/inc/conutil.h | 70 | ||||
| -rw-r--r-- | src/wix/WixToolset.Core.Native/WixNativeExe.cs | 5 | ||||
| -rw-r--r-- | src/wix/test/WixToolsetTest.Core.Native/CabinetFixture.cs | 21 | ||||
| -rw-r--r-- | src/wix/test/WixToolsetTest.Core.Native/TestData/Testüber/t道場t.txt | 1 | ||||
| -rw-r--r-- | src/wix/wixnative/smartcab.cpp | 14 |
6 files changed, 321 insertions, 164 deletions
diff --git a/src/libs/dutil/WixToolset.DUtil/conutil.cpp b/src/libs/dutil/WixToolset.DUtil/conutil.cpp index 7ca17439..2aec36e5 100644 --- a/src/libs/dutil/WixToolset.DUtil/conutil.cpp +++ b/src/libs/dutil/WixToolset.DUtil/conutil.cpp | |||
| @@ -18,18 +18,33 @@ | |||
| 18 | #define ConExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_CONUTIL, g, x, s, __VA_ARGS__) | 18 | #define ConExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_CONUTIL, g, x, s, __VA_ARGS__) |
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | LPCSTR NEWLINE = "\r\n"; | ||
| 22 | |||
| 21 | static HANDLE vhStdIn = INVALID_HANDLE_VALUE; | 23 | static HANDLE vhStdIn = INVALID_HANDLE_VALUE; |
| 22 | static HANDLE vhStdOut = INVALID_HANDLE_VALUE; | 24 | static HANDLE vhStdOut = INVALID_HANDLE_VALUE; |
| 23 | static BOOL vfConsoleIn = FALSE; | 25 | static BOOL vfStdInInteractive = FALSE; |
| 26 | static BOOL vfStdOutInteractive = FALSE; | ||
| 24 | static BOOL vfConsoleOut = FALSE; | 27 | static BOOL vfConsoleOut = FALSE; |
| 25 | static CONSOLE_SCREEN_BUFFER_INFO vcsbiInfo; | 28 | static CONSOLE_SCREEN_BUFFER_INFO vcsbiInfo; |
| 26 | 29 | ||
| 27 | 30 | ||
| 31 | static HRESULT DAPI ReadInteractiveStdIn( | ||
| 32 | __deref_out_z LPWSTR* ppwzBuffer | ||
| 33 | ); | ||
| 34 | static HRESULT ReadRedirectedStdIn( | ||
| 35 | __deref_out_ecount_opt(*pcchSize) LPWSTR* ppwzBuffer, | ||
| 36 | __out DWORD* pcchSize, | ||
| 37 | BOOL fReadLine, | ||
| 38 | DWORD dwMaxRead | ||
| 39 | ); | ||
| 40 | |||
| 41 | |||
| 28 | extern "C" HRESULT DAPI ConsoleInitialize() | 42 | extern "C" HRESULT DAPI ConsoleInitialize() |
| 29 | { | 43 | { |
| 30 | Assert(INVALID_HANDLE_VALUE == vhStdOut); | 44 | Assert(INVALID_HANDLE_VALUE == vhStdOut); |
| 31 | HRESULT hr = S_OK; | 45 | HRESULT hr = S_OK; |
| 32 | UINT er; | 46 | DWORD dwStdInMode = 0; |
| 47 | DWORD dwStdOutMode = 0; | ||
| 33 | 48 | ||
| 34 | vhStdIn = ::GetStdHandle(STD_INPUT_HANDLE); | 49 | vhStdIn = ::GetStdHandle(STD_INPUT_HANDLE); |
| 35 | if (INVALID_HANDLE_VALUE == vhStdIn) | 50 | if (INVALID_HANDLE_VALUE == vhStdIn) |
| @@ -37,48 +52,24 @@ extern "C" HRESULT DAPI ConsoleInitialize() | |||
| 37 | ConExitOnLastError(hr, "failed to open stdin"); | 52 | ConExitOnLastError(hr, "failed to open stdin"); |
| 38 | } | 53 | } |
| 39 | 54 | ||
| 55 | vfStdInInteractive = ::GetFileType(vhStdIn) == FILE_TYPE_CHAR && ::GetConsoleMode(vhStdIn, &dwStdInMode); | ||
| 56 | |||
| 40 | vhStdOut = ::GetStdHandle(STD_OUTPUT_HANDLE); | 57 | vhStdOut = ::GetStdHandle(STD_OUTPUT_HANDLE); |
| 41 | if (INVALID_HANDLE_VALUE == vhStdOut) | 58 | if (INVALID_HANDLE_VALUE == vhStdOut) |
| 42 | { | 59 | { |
| 43 | ConExitOnLastError(hr, "failed to open stdout"); | 60 | ConExitOnLastError(hr, "failed to open stdout"); |
| 44 | } | 61 | } |
| 45 | 62 | ||
| 46 | // check if we have a std in on the console | 63 | vfStdOutInteractive = ::GetFileType(vhStdOut) == FILE_TYPE_CHAR && ::GetConsoleMode(vhStdOut, &dwStdOutMode); |
| 47 | if (::GetConsoleScreenBufferInfo(vhStdIn, &vcsbiInfo)) | ||
| 48 | { | ||
| 49 | vfConsoleIn = TRUE; | ||
| 50 | } | ||
| 51 | else | ||
| 52 | { | ||
| 53 | er = ::GetLastError(); | ||
| 54 | if (ERROR_INVALID_HANDLE == er) | ||
| 55 | { | ||
| 56 | vfConsoleIn= FALSE; | ||
| 57 | hr = S_OK; | ||
| 58 | } | ||
| 59 | else | ||
| 60 | { | ||
| 61 | ConExitOnWin32Error(er, hr, "failed to get input console screen buffer info"); | ||
| 62 | } | ||
| 63 | } | ||
| 64 | 64 | ||
| 65 | if (::GetConsoleScreenBufferInfo(vhStdOut, &vcsbiInfo)) | 65 | if (::GetConsoleScreenBufferInfo(vhStdOut, &vcsbiInfo)) |
| 66 | { | 66 | { |
| 67 | vfConsoleOut = TRUE; | 67 | vfConsoleOut = TRUE; |
| 68 | } | 68 | } |
| 69 | else // no console | 69 | |
| 70 | if (!::SetConsoleCP(CP_UTF8) || !::SetConsoleOutputCP(CP_UTF8)) | ||
| 70 | { | 71 | { |
| 71 | memset(&vcsbiInfo, 0, sizeof(vcsbiInfo)); | 72 | ConExitWithLastError(hr, "failed to set console codepage to UTF-8"); |
| 72 | er = ::GetLastError(); | ||
| 73 | if (ERROR_INVALID_HANDLE == er) | ||
| 74 | { | ||
| 75 | vfConsoleOut = FALSE; | ||
| 76 | hr = S_OK; | ||
| 77 | } | ||
| 78 | else | ||
| 79 | { | ||
| 80 | ConExitOnWin32Error(er, hr, "failed to get output console screen buffer info"); | ||
| 81 | } | ||
| 82 | } | 73 | } |
| 83 | 74 | ||
| 84 | LExit: | 75 | LExit: |
| @@ -162,13 +153,6 @@ extern "C" void DAPI ConsoleNormal() | |||
| 162 | } | 153 | } |
| 163 | } | 154 | } |
| 164 | 155 | ||
| 165 | |||
| 166 | /******************************************************************** | ||
| 167 | ConsoleWrite - full color printfA without libc | ||
| 168 | |||
| 169 | NOTE: use FormatMessage formatting ("%1" or "%1!d!") not plain printf formatting ("%ls" or "%d") | ||
| 170 | assumes already in normal color and resets the screen to normal color | ||
| 171 | ********************************************************************/ | ||
| 172 | extern "C" HRESULT DAPI ConsoleWrite( | 156 | extern "C" HRESULT DAPI ConsoleWrite( |
| 173 | CONSOLE_COLOR cc, | 157 | CONSOLE_COLOR cc, |
| 174 | __in_z __format_string LPCSTR szFormat, | 158 | __in_z __format_string LPCSTR szFormat, |
| @@ -202,7 +186,7 @@ extern "C" HRESULT DAPI ConsoleWrite( | |||
| 202 | { | 186 | { |
| 203 | if (!::WriteFile(vhStdOut, reinterpret_cast<BYTE*>(pszOutput) + cbTotal, cchOutput * sizeof(*pszOutput) - cbTotal, &cbWrote, NULL)) | 187 | if (!::WriteFile(vhStdOut, reinterpret_cast<BYTE*>(pszOutput) + cbTotal, cchOutput * sizeof(*pszOutput) - cbTotal, &cbWrote, NULL)) |
| 204 | { | 188 | { |
| 205 | ConExitOnLastError(hr, "failed to write output to console: %s", pszOutput); | 189 | ConExitOnLastError(hr, "failed to write output to console with format: %s", szFormat); |
| 206 | } | 190 | } |
| 207 | 191 | ||
| 208 | cbTotal += cbWrote; | 192 | cbTotal += cbWrote; |
| @@ -220,12 +204,53 @@ LExit: | |||
| 220 | } | 204 | } |
| 221 | 205 | ||
| 222 | 206 | ||
| 223 | /******************************************************************** | 207 | extern "C" HRESULT DAPI ConsoleWriteW( |
| 224 | ConsoleWriteLine - full color printfA plus newline without libc | 208 | __in CONSOLE_COLOR cc, |
| 209 | __in_z LPCWSTR wzData | ||
| 210 | ) | ||
| 211 | { | ||
| 212 | AssertSz(INVALID_HANDLE_VALUE != vhStdOut, "ConsoleInitialize() has not been called"); | ||
| 213 | HRESULT hr = S_OK; | ||
| 214 | LPSTR pszOutput = NULL; | ||
| 215 | DWORD cchOutput = 0; | ||
| 216 | DWORD cbWrote = 0; | ||
| 217 | DWORD cbTotal = 0; | ||
| 218 | |||
| 219 | // set the color | ||
| 220 | switch (cc) | ||
| 221 | { | ||
| 222 | case CONSOLE_COLOR_NORMAL: break; // do nothing | ||
| 223 | case CONSOLE_COLOR_RED: ConsoleRed(); break; | ||
| 224 | case CONSOLE_COLOR_YELLOW: ConsoleYellow(); break; | ||
| 225 | case CONSOLE_COLOR_GREEN: ConsoleGreen(); break; | ||
| 226 | } | ||
| 227 | |||
| 228 | hr = StrAnsiAllocString(&pszOutput, wzData, 0, CP_UTF8); | ||
| 229 | ExitOnFailure(hr, "failed to convert console output to utf-8: %ls", wzData); | ||
| 230 | |||
| 231 | cchOutput = lstrlenA(pszOutput); | ||
| 232 | while (cbTotal < (sizeof(*pszOutput) * cchOutput)) | ||
| 233 | { | ||
| 234 | if (!::WriteFile(vhStdOut, reinterpret_cast<BYTE*>(pszOutput) + cbTotal, cchOutput * sizeof(*pszOutput) - cbTotal, &cbWrote, NULL)) | ||
| 235 | { | ||
| 236 | ConExitOnLastError(hr, "failed to write output to console with format: %ls", wzData); | ||
| 237 | } | ||
| 238 | |||
| 239 | cbTotal += cbWrote; | ||
| 240 | } | ||
| 241 | |||
| 242 | // reset the color to normal | ||
| 243 | if (CONSOLE_COLOR_NORMAL != cc) | ||
| 244 | { | ||
| 245 | ConsoleNormal(); | ||
| 246 | } | ||
| 247 | |||
| 248 | LExit: | ||
| 249 | ReleaseStr(pszOutput); | ||
| 250 | return hr; | ||
| 251 | } | ||
| 252 | |||
| 225 | 253 | ||
| 226 | NOTE: use FormatMessage formatting ("%1" or "%1!d!") not plain printf formatting ("%ls" or "%d") | ||
| 227 | assumes already in normal color and resets the screen to normal color | ||
| 228 | ********************************************************************/ | ||
| 229 | extern "C" HRESULT DAPI ConsoleWriteLine( | 254 | extern "C" HRESULT DAPI ConsoleWriteLine( |
| 230 | CONSOLE_COLOR cc, | 255 | CONSOLE_COLOR cc, |
| 231 | __in_z __format_string LPCSTR szFormat, | 256 | __in_z __format_string LPCSTR szFormat, |
| @@ -238,7 +263,6 @@ extern "C" HRESULT DAPI ConsoleWriteLine( | |||
| 238 | DWORD cchOutput = 0; | 263 | DWORD cchOutput = 0; |
| 239 | DWORD cbWrote = 0; | 264 | DWORD cbWrote = 0; |
| 240 | DWORD cbTotal = 0; | 265 | DWORD cbTotal = 0; |
| 241 | LPCSTR szNewLine = "\r\n"; | ||
| 242 | 266 | ||
| 243 | // set the color | 267 | // set the color |
| 244 | switch (cc) | 268 | switch (cc) |
| @@ -270,7 +294,7 @@ extern "C" HRESULT DAPI ConsoleWriteLine( | |||
| 270 | // | 294 | // |
| 271 | // write the newline | 295 | // write the newline |
| 272 | // | 296 | // |
| 273 | if (!::WriteFile(vhStdOut, reinterpret_cast<const BYTE*>(szNewLine), 2, &cbWrote, NULL)) | 297 | if (!::WriteFile(vhStdOut, reinterpret_cast<const BYTE*>(NEWLINE), 2, &cbWrote, NULL)) |
| 274 | { | 298 | { |
| 275 | ConExitOnLastError(hr, "failed to write newline to console"); | 299 | ConExitOnLastError(hr, "failed to write newline to console"); |
| 276 | } | 300 | } |
| @@ -287,11 +311,6 @@ LExit: | |||
| 287 | } | 311 | } |
| 288 | 312 | ||
| 289 | 313 | ||
| 290 | /******************************************************************** | ||
| 291 | ConsoleWriteError - display an error to the screen | ||
| 292 | |||
| 293 | NOTE: use FormatMessage formatting ("%1" or "%1!d!") not plain printf formatting ("%s" or "%d") | ||
| 294 | ********************************************************************/ | ||
| 295 | HRESULT ConsoleWriteError( | 314 | HRESULT ConsoleWriteError( |
| 296 | HRESULT hrError, | 315 | HRESULT hrError, |
| 297 | CONSOLE_COLOR cc, | 316 | CONSOLE_COLOR cc, |
| @@ -323,11 +342,6 @@ LExit: | |||
| 323 | } | 342 | } |
| 324 | 343 | ||
| 325 | 344 | ||
| 326 | /******************************************************************** | ||
| 327 | ConsoleReadW - get console input without libc | ||
| 328 | |||
| 329 | NOTE: only supports reading ANSI characters | ||
| 330 | ********************************************************************/ | ||
| 331 | extern "C" HRESULT DAPI ConsoleReadW( | 345 | extern "C" HRESULT DAPI ConsoleReadW( |
| 332 | __deref_out_z LPWSTR* ppwzBuffer | 346 | __deref_out_z LPWSTR* ppwzBuffer |
| 333 | ) | 347 | ) |
| @@ -336,57 +350,24 @@ extern "C" HRESULT DAPI ConsoleReadW( | |||
| 336 | Assert(ppwzBuffer); | 350 | Assert(ppwzBuffer); |
| 337 | 351 | ||
| 338 | HRESULT hr = S_OK; | 352 | HRESULT hr = S_OK; |
| 339 | LPSTR psz = NULL; | 353 | DWORD cchSize = 0; |
| 340 | DWORD cch = 0; | ||
| 341 | DWORD cchRead = 0; | ||
| 342 | DWORD cchTotalRead = 0; | ||
| 343 | 354 | ||
| 344 | cch = 64; | 355 | if (vfStdInInteractive) |
| 345 | hr = StrAnsiAlloc(&psz, cch); | ||
| 346 | ConExitOnFailure(hr, "failed to allocate memory to read from console"); | ||
| 347 | |||
| 348 | // loop until we read the \r\n from the console | ||
| 349 | for (;;) | ||
| 350 | { | 356 | { |
| 351 | // read one character at a time, since that seems to be the only way to make this work | 357 | hr = ReadInteractiveStdIn(ppwzBuffer); |
| 352 | if (!::ReadFile(vhStdIn, psz + cchTotalRead, 1, &cchRead, NULL)) | 358 | ExitOnFailure(hr, "failed to read from interactive console"); |
| 353 | ConExitOnLastError(hr, "failed to read string from console"); | 359 | } |
| 354 | 360 | else | |
| 355 | cchTotalRead += cchRead; | 361 | { |
| 356 | if (1 < cchTotalRead && '\r' == psz[cchTotalRead - 2] && '\n' == psz[cchTotalRead - 1]) | 362 | hr = ReadRedirectedStdIn(ppwzBuffer, &cchSize, TRUE, 0); |
| 357 | { | 363 | ExitOnFailure(hr, "failed to read from redirected console"); |
| 358 | psz[cchTotalRead - 2] = '\0'; // chop off the \r\n | ||
| 359 | break; | ||
| 360 | } | ||
| 361 | else if (0 == cchRead) // nothing more was read | ||
| 362 | { | ||
| 363 | psz[cchTotalRead] = '\0'; // null termintate and bail | ||
| 364 | break; | ||
| 365 | } | ||
| 366 | |||
| 367 | if (cchTotalRead == cch) | ||
| 368 | { | ||
| 369 | cch *= 2; // double everytime we run out of space | ||
| 370 | hr = StrAnsiAlloc(&psz, cch); | ||
| 371 | ConExitOnFailure(hr, "failed to allocate memory to read from console"); | ||
| 372 | } | ||
| 373 | } | 364 | } |
| 374 | |||
| 375 | hr = StrAllocStringAnsi(ppwzBuffer, psz, 0, CP_ACP); | ||
| 376 | 365 | ||
| 377 | LExit: | 366 | LExit: |
| 378 | ReleaseStr(psz); | ||
| 379 | return hr; | 367 | return hr; |
| 380 | } | 368 | } |
| 381 | 369 | ||
| 382 | 370 | ||
| 383 | /******************************************************************** | ||
| 384 | ConsoleReadNonBlockingW - Read from the console without blocking | ||
| 385 | Won't work for redirected files (exe < txtfile), but will work for stdin redirected to | ||
| 386 | an anonymous or named pipe | ||
| 387 | |||
| 388 | if (fReadLine), stop reading immediately when \r\n is found | ||
| 389 | *********************************************************************/ | ||
| 390 | extern "C" HRESULT DAPI ConsoleReadNonBlockingW( | 371 | extern "C" HRESULT DAPI ConsoleReadNonBlockingW( |
| 391 | __deref_out_ecount_opt(*pcchSize) LPWSTR* ppwzBuffer, | 372 | __deref_out_ecount_opt(*pcchSize) LPWSTR* ppwzBuffer, |
| 392 | __out DWORD* pcchSize, | 373 | __out DWORD* pcchSize, |
| @@ -406,9 +387,6 @@ extern "C" HRESULT DAPI ConsoleReadNonBlockingW( | |||
| 406 | DWORD cchTotal = 0; | 387 | DWORD cchTotal = 0; |
| 407 | DWORD cch = 8; | 388 | DWORD cch = 8; |
| 408 | 389 | ||
| 409 | DWORD cchRead = 0; | ||
| 410 | DWORD cchTotalRead = 0; | ||
| 411 | |||
| 412 | DWORD dwIndex = 0; | 390 | DWORD dwIndex = 0; |
| 413 | DWORD er; | 391 | DWORD er; |
| 414 | 392 | ||
| @@ -476,45 +454,13 @@ extern "C" HRESULT DAPI ConsoleReadNonBlockingW( | |||
| 476 | { | 454 | { |
| 477 | // otherwise, the peek worked, and we have the end of a pipe | 455 | // otherwise, the peek worked, and we have the end of a pipe |
| 478 | if (0 == dwRead) | 456 | if (0 == dwRead) |
| 479 | ExitFunction1(hr = S_FALSE); | ||
| 480 | |||
| 481 | cch = 8; | ||
| 482 | hr = StrAnsiAlloc(&psz, cch); | ||
| 483 | ConExitOnFailure(hr, "failed to allocate memory to read from console"); | ||
| 484 | |||
| 485 | for (/*dwRead from PeekNamedPipe*/; dwRead > 0; dwRead--) | ||
| 486 | { | 457 | { |
| 487 | // read one character at a time, since that seems to be the only way to make this work | 458 | ExitFunction1(hr = S_FALSE); |
| 488 | if (!::ReadFile(vhStdIn, psz + cchTotalRead, 1, &cchRead, NULL)) | ||
| 489 | { | ||
| 490 | ConExitOnLastError(hr, "failed to read string from console"); | ||
| 491 | } | ||
| 492 | |||
| 493 | cchTotalRead += cchRead; | ||
| 494 | if (fReadLine && '\r' == psz[cchTotalRead - 1] && '\n' == psz[cchTotalRead]) | ||
| 495 | { | ||
| 496 | psz[cchTotalRead - 1] = '\0'; // chop off the \r\n | ||
| 497 | cchTotalRead -= 1; | ||
| 498 | break; | ||
| 499 | } | ||
| 500 | else if (0 == cchRead) // nothing more was read | ||
| 501 | { | ||
| 502 | psz[cchTotalRead] = '\0'; // null termintate and bail | ||
| 503 | break; | ||
| 504 | } | ||
| 505 | |||
| 506 | if (cchTotalRead == cch) | ||
| 507 | { | ||
| 508 | cch *= 2; // double everytime we run out of space | ||
| 509 | hr = StrAnsiAlloc(&psz, cch); | ||
| 510 | ConExitOnFailure(hr, "failed to allocate memory to read from console"); | ||
| 511 | } | ||
| 512 | } | 459 | } |
| 513 | 460 | ||
| 514 | *pcchSize = cchTotalRead; | 461 | hr = ReadRedirectedStdIn(ppwzBuffer, pcchSize, fReadLine, dwRead); |
| 515 | hr = StrAllocStringAnsi(ppwzBuffer, psz, cchTotalRead, CP_ACP); | ||
| 516 | } | 462 | } |
| 517 | 463 | ||
| 518 | LExit: | 464 | LExit: |
| 519 | ReleaseStr(psz); | 465 | ReleaseStr(psz); |
| 520 | 466 | ||
| @@ -522,10 +468,6 @@ LExit: | |||
| 522 | } | 468 | } |
| 523 | 469 | ||
| 524 | 470 | ||
| 525 | /******************************************************************** | ||
| 526 | ConsoleReadStringA - get console input without libc | ||
| 527 | |||
| 528 | *********************************************************************/ | ||
| 529 | extern "C" HRESULT DAPI ConsoleReadStringA( | 471 | extern "C" HRESULT DAPI ConsoleReadStringA( |
| 530 | __deref_inout_ecount_part(cchCharBuffer,*pcchNumCharReturn) LPSTR* ppszCharBuffer, | 472 | __deref_inout_ecount_part(cchCharBuffer,*pcchNumCharReturn) LPSTR* ppszCharBuffer, |
| 531 | CONST DWORD cchCharBuffer, | 473 | CONST DWORD cchCharBuffer, |
| @@ -543,16 +485,18 @@ extern "C" HRESULT DAPI ConsoleReadStringA( | |||
| 543 | do | 485 | do |
| 544 | { | 486 | { |
| 545 | hr = StrAnsiAlloc(ppszCharBuffer, cchCharBuffer * iRead); | 487 | hr = StrAnsiAlloc(ppszCharBuffer, cchCharBuffer * iRead); |
| 546 | ConExitOnFailure(hr, "failed to allocate memory for ConsoleReadStringW"); | 488 | ConExitOnFailure(hr, "failed to allocate memory for ConsoleReadStringA"); |
| 489 | |||
| 547 | // ReadConsoleW will not return until <Return>, the last two chars are 13 and 10. | 490 | // ReadConsoleW will not return until <Return>, the last two chars are 13 and 10. |
| 548 | if (!::ReadConsoleA(vhStdIn, *ppszCharBuffer + iReadCharTotal, cchCharBuffer, pcchNumCharReturn, NULL) || *pcchNumCharReturn == 0) | 491 | if (!::ReadConsoleA(vhStdIn, *ppszCharBuffer + iReadCharTotal, cchCharBuffer, pcchNumCharReturn, NULL) || *pcchNumCharReturn == 0) |
| 549 | { | 492 | { |
| 550 | ConExitOnLastError(hr, "failed to read string from console"); | 493 | ConExitOnLastError(hr, "failed to read string from console"); |
| 551 | } | 494 | } |
| 495 | |||
| 552 | iReadCharTotal += *pcchNumCharReturn; | 496 | iReadCharTotal += *pcchNumCharReturn; |
| 553 | iRead += 1; | 497 | iRead += 1; |
| 554 | } | 498 | } while((*ppszCharBuffer)[iReadCharTotal - 1] != 10 || (*ppszCharBuffer)[iReadCharTotal - 2] != 13); |
| 555 | while((*ppszCharBuffer)[iReadCharTotal - 1] != 10 || (*ppszCharBuffer)[iReadCharTotal - 2] != 13); | 499 | |
| 556 | *pcchNumCharReturn = iReadCharTotal; | 500 | *pcchNumCharReturn = iReadCharTotal; |
| 557 | } | 501 | } |
| 558 | else | 502 | else |
| @@ -562,6 +506,7 @@ extern "C" HRESULT DAPI ConsoleReadStringA( | |||
| 562 | { | 506 | { |
| 563 | ConExitOnLastError(hr, "failed to read string from console"); | 507 | ConExitOnLastError(hr, "failed to read string from console"); |
| 564 | } | 508 | } |
| 509 | |||
| 565 | if ((*ppszCharBuffer)[*pcchNumCharReturn - 1] != 10 || | 510 | if ((*ppszCharBuffer)[*pcchNumCharReturn - 1] != 10 || |
| 566 | (*ppszCharBuffer)[*pcchNumCharReturn - 2] != 13) | 511 | (*ppszCharBuffer)[*pcchNumCharReturn - 2] != 13) |
| 567 | { | 512 | { |
| @@ -579,18 +524,16 @@ LExit: | |||
| 579 | return hr; | 524 | return hr; |
| 580 | } | 525 | } |
| 581 | 526 | ||
| 582 | /******************************************************************** | ||
| 583 | ConsoleReadStringW - get console input without libc | ||
| 584 | 527 | ||
| 585 | *********************************************************************/ | ||
| 586 | extern "C" HRESULT DAPI ConsoleReadStringW( | 528 | extern "C" HRESULT DAPI ConsoleReadStringW( |
| 587 | __deref_inout_ecount_part(cchCharBuffer,*pcchNumCharReturn) LPWSTR* ppwzCharBuffer, | 529 | __deref_inout_ecount_part(cchCharBuffer,*pcchNumCharReturn) LPWSTR* ppwzCharBuffer, |
| 588 | const DWORD cchCharBuffer, | 530 | CONST DWORD cchCharBuffer, |
| 589 | __out DWORD* pcchNumCharReturn | 531 | __out DWORD* pcchNumCharReturn |
| 590 | ) | 532 | ) |
| 591 | { | 533 | { |
| 592 | AssertSz(INVALID_HANDLE_VALUE != vhStdIn, "ConsoleInitialize() has not been called"); | 534 | AssertSz(INVALID_HANDLE_VALUE != vhStdIn, "ConsoleInitialize() has not been called"); |
| 593 | HRESULT hr = S_OK; | 535 | HRESULT hr = S_OK; |
| 536 | |||
| 594 | if (ppwzCharBuffer && (pcchNumCharReturn || cchCharBuffer < 2)) | 537 | if (ppwzCharBuffer && (pcchNumCharReturn || cchCharBuffer < 2)) |
| 595 | { | 538 | { |
| 596 | DWORD iRead = 1; | 539 | DWORD iRead = 1; |
| @@ -601,15 +544,17 @@ extern "C" HRESULT DAPI ConsoleReadStringW( | |||
| 601 | { | 544 | { |
| 602 | hr = StrAlloc(ppwzCharBuffer, cchCharBuffer * iRead); | 545 | hr = StrAlloc(ppwzCharBuffer, cchCharBuffer * iRead); |
| 603 | ConExitOnFailure(hr, "failed to allocate memory for ConsoleReadStringW"); | 546 | ConExitOnFailure(hr, "failed to allocate memory for ConsoleReadStringW"); |
| 547 | |||
| 604 | // ReadConsoleW will not return until <Return>, the last two chars are 13 and 10. | 548 | // ReadConsoleW will not return until <Return>, the last two chars are 13 and 10. |
| 605 | if (!::ReadConsoleW(vhStdIn, *ppwzCharBuffer + iReadCharTotal, cchCharBuffer, pcchNumCharReturn, NULL) || *pcchNumCharReturn == 0) | 549 | if (!::ReadConsoleW(vhStdIn, *ppwzCharBuffer + iReadCharTotal, cchCharBuffer, pcchNumCharReturn, NULL) || *pcchNumCharReturn == 0) |
| 606 | { | 550 | { |
| 607 | ConExitOnLastError(hr, "failed to read string from console"); | 551 | ConExitOnLastError(hr, "failed to read string from console"); |
| 608 | } | 552 | } |
| 553 | |||
| 609 | iReadCharTotal += *pcchNumCharReturn; | 554 | iReadCharTotal += *pcchNumCharReturn; |
| 610 | iRead += 1; | 555 | iRead += 1; |
| 611 | } | 556 | } while((*ppwzCharBuffer)[iReadCharTotal - 1] != 10 || (*ppwzCharBuffer)[iReadCharTotal - 2] != 13); |
| 612 | while((*ppwzCharBuffer)[iReadCharTotal - 1] != 10 || (*ppwzCharBuffer)[iReadCharTotal - 2] != 13); | 557 | |
| 613 | *pcchNumCharReturn = iReadCharTotal; | 558 | *pcchNumCharReturn = iReadCharTotal; |
| 614 | } | 559 | } |
| 615 | else | 560 | else |
| @@ -619,6 +564,7 @@ extern "C" HRESULT DAPI ConsoleReadStringW( | |||
| 619 | { | 564 | { |
| 620 | ConExitOnLastError(hr, "failed to read string from console"); | 565 | ConExitOnLastError(hr, "failed to read string from console"); |
| 621 | } | 566 | } |
| 567 | |||
| 622 | if ((*ppwzCharBuffer)[*pcchNumCharReturn - 1] != 10 || | 568 | if ((*ppwzCharBuffer)[*pcchNumCharReturn - 1] != 10 || |
| 623 | (*ppwzCharBuffer)[*pcchNumCharReturn - 2] != 13) | 569 | (*ppwzCharBuffer)[*pcchNumCharReturn - 2] != 13) |
| 624 | { | 570 | { |
| @@ -636,14 +582,12 @@ LExit: | |||
| 636 | return hr; | 582 | return hr; |
| 637 | } | 583 | } |
| 638 | 584 | ||
| 639 | /******************************************************************** | ||
| 640 | ConsoleSetReadHidden - set console input no echo | ||
| 641 | 585 | ||
| 642 | *********************************************************************/ | ||
| 643 | extern "C" HRESULT DAPI ConsoleSetReadHidden(void) | 586 | extern "C" HRESULT DAPI ConsoleSetReadHidden(void) |
| 644 | { | 587 | { |
| 645 | AssertSz(INVALID_HANDLE_VALUE != vhStdIn, "ConsoleInitialize() has not been called"); | 588 | AssertSz(INVALID_HANDLE_VALUE != vhStdIn, "ConsoleInitialize() has not been called"); |
| 646 | HRESULT hr = S_OK; | 589 | HRESULT hr = S_OK; |
| 590 | |||
| 647 | ::FlushConsoleInputBuffer(vhStdIn); | 591 | ::FlushConsoleInputBuffer(vhStdIn); |
| 648 | if (!::SetConsoleMode(vhStdIn, ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT)) | 592 | if (!::SetConsoleMode(vhStdIn, ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT)) |
| 649 | { | 593 | { |
| @@ -654,14 +598,12 @@ LExit: | |||
| 654 | return hr; | 598 | return hr; |
| 655 | } | 599 | } |
| 656 | 600 | ||
| 657 | /******************************************************************** | ||
| 658 | ConsoleSetReadNormal - reset to echo | ||
| 659 | 601 | ||
| 660 | *********************************************************************/ | ||
| 661 | extern "C" HRESULT DAPI ConsoleSetReadNormal(void) | 602 | extern "C" HRESULT DAPI ConsoleSetReadNormal(void) |
| 662 | { | 603 | { |
| 663 | AssertSz(INVALID_HANDLE_VALUE != vhStdIn, "ConsoleInitialize() has not been called"); | 604 | AssertSz(INVALID_HANDLE_VALUE != vhStdIn, "ConsoleInitialize() has not been called"); |
| 664 | HRESULT hr = S_OK; | 605 | HRESULT hr = S_OK; |
| 606 | |||
| 665 | if (!::SetConsoleMode(vhStdIn, ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT)) | 607 | if (!::SetConsoleMode(vhStdIn, ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT)) |
| 666 | { | 608 | { |
| 667 | ConExitOnLastError(hr, "failed to set console input mode to be normal"); | 609 | ConExitOnLastError(hr, "failed to set console input mode to be normal"); |
| @@ -671,3 +613,123 @@ LExit: | |||
| 671 | return hr; | 613 | return hr; |
| 672 | } | 614 | } |
| 673 | 615 | ||
| 616 | |||
| 617 | static HRESULT DAPI ReadInteractiveStdIn( | ||
| 618 | __deref_out_z LPWSTR* ppwzBuffer | ||
| 619 | ) | ||
| 620 | { | ||
| 621 | HRESULT hr = S_OK; | ||
| 622 | LPWSTR pwz = NULL; | ||
| 623 | DWORD cch = 8; | ||
| 624 | DWORD cchRead = 0; | ||
| 625 | DWORD cchTotalRead = 0; | ||
| 626 | |||
| 627 | hr = StrAlloc(&pwz, cch); | ||
| 628 | ConExitOnFailure(hr, "failed to allocate memory to read from console"); | ||
| 629 | |||
| 630 | // loop until we read the \r\n from the console | ||
| 631 | for (;;) | ||
| 632 | { | ||
| 633 | // read one character at a time, since that seems to be the only way to make this work | ||
| 634 | if (!::ReadConsoleW(vhStdIn, pwz + cchTotalRead, 1, &cchRead, NULL)) | ||
| 635 | { | ||
| 636 | ConExitOnLastError(hr, "failed to read string from console"); | ||
| 637 | } | ||
| 638 | |||
| 639 | cchTotalRead += cchRead; | ||
| 640 | if (0 == cchRead) // nothing more was read | ||
| 641 | { | ||
| 642 | pwz[cchTotalRead] = L'\0'; // null terminate and bail | ||
| 643 | break; | ||
| 644 | } | ||
| 645 | else if (0 < cchTotalRead && L'\n' == pwz[cchTotalRead - 1]) | ||
| 646 | { | ||
| 647 | if (1 < cchTotalRead && L'\r' == pwz[cchTotalRead - 2]) | ||
| 648 | { | ||
| 649 | pwz[cchTotalRead - 2] = L'\0'; // chop off the \r\n | ||
| 650 | } | ||
| 651 | else | ||
| 652 | { | ||
| 653 | pwz[cchTotalRead - 1] = L'\0'; // chop off the \n | ||
| 654 | } | ||
| 655 | |||
| 656 | break; | ||
| 657 | } | ||
| 658 | |||
| 659 | if (cchTotalRead == cch) | ||
| 660 | { | ||
| 661 | cch *= 2; // double everytime we run out of space | ||
| 662 | hr = StrAlloc(&pwz, cch); | ||
| 663 | ConExitOnFailure(hr, "failed to allocate memory to read from console"); | ||
| 664 | } | ||
| 665 | } | ||
| 666 | |||
| 667 | hr = StrAllocString(ppwzBuffer, pwz, 0); | ||
| 668 | ConExitOnFailure(hr, "failed to copy stdin buffer to return buffer"); | ||
| 669 | |||
| 670 | LExit: | ||
| 671 | ReleaseStr(pwz); | ||
| 672 | return hr; | ||
| 673 | } | ||
| 674 | |||
| 675 | |||
| 676 | static HRESULT ReadRedirectedStdIn( | ||
| 677 | __deref_out_ecount_opt(*pcchSize) LPWSTR* ppwzBuffer, | ||
| 678 | __out DWORD* pcchSize, | ||
| 679 | BOOL fReadLine, | ||
| 680 | DWORD dwMaxRead | ||
| 681 | ) | ||
| 682 | { | ||
| 683 | HRESULT hr = S_OK; | ||
| 684 | LPSTR psz = NULL; | ||
| 685 | DWORD cch = 8; | ||
| 686 | DWORD cchRead = 0; | ||
| 687 | DWORD cchTotalRead = 0; | ||
| 688 | |||
| 689 | hr = StrAnsiAlloc(&psz, cch); | ||
| 690 | ConExitOnFailure(hr, "failed to allocate memory to read from console"); | ||
| 691 | |||
| 692 | while (dwMaxRead == 0 || cchTotalRead < dwMaxRead) | ||
| 693 | { | ||
| 694 | // read one character at a time, since that seems to be the only way to make this work | ||
| 695 | if (!::ReadFile(vhStdIn, psz + cchTotalRead, 1, &cchRead, NULL)) | ||
| 696 | { | ||
| 697 | ConExitOnLastError(hr, "failed to read string from console"); | ||
| 698 | } | ||
| 699 | |||
| 700 | cchTotalRead += cchRead; | ||
| 701 | if (0 == cchRead) // nothing more was read | ||
| 702 | { | ||
| 703 | psz[cchTotalRead] = '\0'; // null terminate and bail | ||
| 704 | break; | ||
| 705 | } | ||
| 706 | else if (fReadLine && 0 < cchTotalRead && '\n' == psz[cchTotalRead - 1]) | ||
| 707 | { | ||
| 708 | if (1 < cchTotalRead && '\r' == psz[cchTotalRead - 2]) | ||
| 709 | { | ||
| 710 | psz[cchTotalRead - 2] = '\0'; // chop off the \r\n | ||
| 711 | } | ||
| 712 | else | ||
| 713 | { | ||
| 714 | psz[cchTotalRead - 1] = '\0'; // chop off the \n | ||
| 715 | } | ||
| 716 | |||
| 717 | break; | ||
| 718 | } | ||
| 719 | |||
| 720 | if (cchTotalRead == cch) | ||
| 721 | { | ||
| 722 | cch *= 2; // double everytime we run out of space | ||
| 723 | hr = StrAnsiAlloc(&psz, cch); | ||
| 724 | ConExitOnFailure(hr, "failed to allocate memory to read from console"); | ||
| 725 | } | ||
| 726 | } | ||
| 727 | |||
| 728 | *pcchSize = cchTotalRead; | ||
| 729 | |||
| 730 | hr = StrAllocStringAnsi(ppwzBuffer, psz, 0, CP_UTF8); | ||
| 731 | ConExitOnFailure(hr, "failed to convert console data"); | ||
| 732 | |||
| 733 | LExit: | ||
| 734 | return hr; | ||
| 735 | } | ||
diff --git a/src/libs/dutil/WixToolset.DUtil/inc/conutil.h b/src/libs/dutil/WixToolset.DUtil/inc/conutil.h index 38aaea84..92e7f600 100644 --- a/src/libs/dutil/WixToolset.DUtil/inc/conutil.h +++ b/src/libs/dutil/WixToolset.DUtil/inc/conutil.h | |||
| @@ -33,16 +33,46 @@ void DAPI ConsoleRed(); | |||
| 33 | void DAPI ConsoleYellow(); | 33 | void DAPI ConsoleYellow(); |
| 34 | void DAPI ConsoleNormal(); | 34 | void DAPI ConsoleNormal(); |
| 35 | 35 | ||
| 36 | /******************************************************************** | ||
| 37 | ConsoleWrite - full color printfA without libc | ||
| 38 | |||
| 39 | NOTE: only supports ANSI characters | ||
| 40 | assumes already in normal color and resets the screen to normal color | ||
| 41 | ********************************************************************/ | ||
| 36 | HRESULT DAPI ConsoleWrite( | 42 | HRESULT DAPI ConsoleWrite( |
| 37 | CONSOLE_COLOR cc, | 43 | CONSOLE_COLOR cc, |
| 38 | __in_z __format_string LPCSTR szFormat, | 44 | __in_z __format_string LPCSTR szFormat, |
| 39 | ... | 45 | ... |
| 40 | ); | 46 | ); |
| 47 | |||
| 48 | /******************************************************************** | ||
| 49 | ConsoleWriteW - sends UTF-8 characters to console out in color. | ||
| 50 | |||
| 51 | NOTE: assumes already in normal color and resets the screen to normal color | ||
| 52 | ********************************************************************/ | ||
| 53 | HRESULT DAPI ConsoleWriteW( | ||
| 54 | __in CONSOLE_COLOR cc, | ||
| 55 | __in_z LPCWSTR wzData | ||
| 56 | ); | ||
| 57 | |||
| 58 | /******************************************************************** | ||
| 59 | ConsoleWriteLine - full color printfA plus newline without libc | ||
| 60 | |||
| 61 | NOTE: only supports ANSI characters | ||
| 62 | assumes already in normal color and resets the screen to normal color | ||
| 63 | ********************************************************************/ | ||
| 41 | HRESULT DAPI ConsoleWriteLine( | 64 | HRESULT DAPI ConsoleWriteLine( |
| 42 | CONSOLE_COLOR cc, | 65 | CONSOLE_COLOR cc, |
| 43 | __in_z __format_string LPCSTR szFormat, | 66 | __in_z __format_string LPCSTR szFormat, |
| 44 | ... | 67 | ... |
| 45 | ); | 68 | ); |
| 69 | |||
| 70 | /******************************************************************** | ||
| 71 | ConsoleWriteError - display an error to the console out | ||
| 72 | |||
| 73 | NOTE: only supports ANSI characters | ||
| 74 | does not write to stderr | ||
| 75 | ********************************************************************/ | ||
| 46 | HRESULT DAPI ConsoleWriteError( | 76 | HRESULT DAPI ConsoleWriteError( |
| 47 | HRESULT hrError, | 77 | HRESULT hrError, |
| 48 | CONSOLE_COLOR cc, | 78 | CONSOLE_COLOR cc, |
| @@ -50,28 +80,58 @@ HRESULT DAPI ConsoleWriteError( | |||
| 50 | ... | 80 | ... |
| 51 | ); | 81 | ); |
| 52 | 82 | ||
| 83 | /******************************************************************** | ||
| 84 | ConsoleReadW - reads a line from console in as UTF-8 to populate Unicode buffer | ||
| 85 | |||
| 86 | ********************************************************************/ | ||
| 53 | HRESULT DAPI ConsoleReadW( | 87 | HRESULT DAPI ConsoleReadW( |
| 54 | __deref_out_z LPWSTR* ppwzBuffer | 88 | __deref_out_z LPWSTR* ppwzBuffer |
| 55 | ); | 89 | ); |
| 56 | 90 | ||
| 91 | /******************************************************************** | ||
| 92 | ConsoleReadNonBlockingW - Read from the console without blocking | ||
| 93 | Won't work for redirected files (exe < txtfile), but will work for stdin redirected to | ||
| 94 | an anonymous or named pipe | ||
| 95 | |||
| 96 | if (fReadLine), stop reading immediately when \r\n is found | ||
| 97 | *********************************************************************/ | ||
| 98 | HRESULT DAPI ConsoleReadNonBlockingW( | ||
| 99 | __deref_out_ecount_opt(*pcchSize) LPWSTR* ppwzBuffer, | ||
| 100 | __out DWORD* pcchSize, | ||
| 101 | BOOL fReadLine | ||
| 102 | ); | ||
| 103 | |||
| 104 | /******************************************************************** | ||
| 105 | ConsoleReadStringA - get console input without libc | ||
| 106 | |||
| 107 | NOTE: only supports ANSI characters | ||
| 108 | *********************************************************************/ | ||
| 57 | HRESULT DAPI ConsoleReadStringA( | 109 | HRESULT DAPI ConsoleReadStringA( |
| 58 | __deref_inout_ecount_part(cchCharBuffer,*pcchNumCharReturn) LPSTR* szCharBuffer, | 110 | __deref_inout_ecount_part(cchCharBuffer,*pcchNumCharReturn) LPSTR* szCharBuffer, |
| 59 | CONST DWORD cchCharBuffer, | 111 | CONST DWORD cchCharBuffer, |
| 60 | __out DWORD* pcchNumCharReturn | 112 | __out DWORD* pcchNumCharReturn |
| 61 | ); | 113 | ); |
| 114 | |||
| 115 | /******************************************************************** | ||
| 116 | ConsoleReadStringW - get console input without libc | ||
| 117 | |||
| 118 | *********************************************************************/ | ||
| 62 | HRESULT DAPI ConsoleReadStringW( | 119 | HRESULT DAPI ConsoleReadStringW( |
| 63 | __deref_inout_ecount_part(cchCharBuffer,*pcchNumCharReturn) LPWSTR* szCharBuffer, | 120 | __deref_inout_ecount_part(cchCharBuffer,*pcchNumCharReturn) LPWSTR* szCharBuffer, |
| 64 | CONST DWORD cchCharBuffer, | 121 | CONST DWORD cchCharBuffer, |
| 65 | __out DWORD* pcchNumCharReturn | 122 | __out DWORD* pcchNumCharReturn |
| 66 | ); | 123 | ); |
| 67 | 124 | ||
| 68 | HRESULT DAPI ConsoleReadNonBlockingW( | 125 | /******************************************************************** |
| 69 | __deref_out_ecount_opt(*pcchSize) LPWSTR* ppwzBuffer, | 126 | ConsoleSetReadHidden - set console input no echo |
| 70 | __out DWORD* pcchSize, | ||
| 71 | BOOL fReadLine | ||
| 72 | ); | ||
| 73 | 127 | ||
| 128 | *********************************************************************/ | ||
| 74 | HRESULT DAPI ConsoleSetReadHidden(void); | 129 | HRESULT DAPI ConsoleSetReadHidden(void); |
| 130 | |||
| 131 | /******************************************************************** | ||
| 132 | ConsoleSetReadNormal - reset to echo | ||
| 133 | |||
| 134 | *********************************************************************/ | ||
| 75 | HRESULT DAPI ConsoleSetReadNormal(void); | 135 | HRESULT DAPI ConsoleSetReadNormal(void); |
| 76 | 136 | ||
| 77 | #ifdef __cplusplus | 137 | #ifdef __cplusplus |
diff --git a/src/wix/WixToolset.Core.Native/WixNativeExe.cs b/src/wix/WixToolset.Core.Native/WixNativeExe.cs index b3b248c0..8b75f508 100644 --- a/src/wix/WixToolset.Core.Native/WixNativeExe.cs +++ b/src/wix/WixToolset.Core.Native/WixNativeExe.cs | |||
| @@ -6,6 +6,7 @@ namespace WixToolset.Core.Native | |||
| 6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
| 7 | using System.Diagnostics; | 7 | using System.Diagnostics; |
| 8 | using System.IO; | 8 | using System.IO; |
| 9 | using System.Text; | ||
| 9 | 10 | ||
| 10 | internal class WixNativeExe | 11 | internal class WixNativeExe |
| 11 | { | 12 | { |
| @@ -40,6 +41,7 @@ namespace WixToolset.Core.Native | |||
| 40 | RedirectStandardInput = true, | 41 | RedirectStandardInput = true, |
| 41 | RedirectStandardOutput = true, | 42 | RedirectStandardOutput = true, |
| 42 | RedirectStandardError = true, | 43 | RedirectStandardError = true, |
| 44 | StandardOutputEncoding = Encoding.UTF8, | ||
| 43 | CreateNoWindow = true, | 45 | CreateNoWindow = true, |
| 44 | ErrorDialog = false, | 46 | ErrorDialog = false, |
| 45 | UseShellExecute = false | 47 | UseShellExecute = false |
| @@ -61,7 +63,8 @@ namespace WixToolset.Core.Native | |||
| 61 | { | 63 | { |
| 62 | foreach (var line in this.stdinLines) | 64 | foreach (var line in this.stdinLines) |
| 63 | { | 65 | { |
| 64 | process.StandardInput.WriteLine(line); | 66 | var bytes = Encoding.UTF8.GetBytes(line + Environment.NewLine); |
| 67 | process.StandardInput.BaseStream.Write(bytes, 0, bytes.Length); | ||
| 65 | } | 68 | } |
| 66 | 69 | ||
| 67 | // Trailing blank line indicates stdin complete. | 70 | // Trailing blank line indicates stdin complete. |
diff --git a/src/wix/test/WixToolsetTest.Core.Native/CabinetFixture.cs b/src/wix/test/WixToolsetTest.Core.Native/CabinetFixture.cs index 56bc8fb4..c15d2c74 100644 --- a/src/wix/test/WixToolsetTest.Core.Native/CabinetFixture.cs +++ b/src/wix/test/WixToolsetTest.Core.Native/CabinetFixture.cs | |||
| @@ -34,6 +34,27 @@ namespace WixToolsetTest.CoreNative | |||
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | [Fact] | 36 | [Fact] |
| 37 | public void CanCreateCabinetUsingLocalizedPath() | ||
| 38 | { | ||
| 39 | using (var fs = new DisposableFileSystem()) | ||
| 40 | { | ||
| 41 | var intermediateFolder = fs.GetFolder(true); | ||
| 42 | var cabPath = Path.Combine(intermediateFolder, "testout.cab"); | ||
| 43 | |||
| 44 | var files = new[] { new CabinetCompressFile(TestData.Get(@"TestData", "Testüber", "t道場t.txt"), "test.txt") }; | ||
| 45 | |||
| 46 | var cabinet = new Cabinet(cabPath); | ||
| 47 | var created = cabinet.Compress(files, CompressionLevel.Low); | ||
| 48 | |||
| 49 | Assert.True(File.Exists(cabPath)); | ||
| 50 | Assert.Equal(new[] | ||
| 51 | { | ||
| 52 | "testout.cab, test.txt" | ||
| 53 | }, created.Select(c => String.Join(", ", c.CabinetName, c.FirstFileToken)).ToArray()); | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | [Fact] | ||
| 37 | public void CanCreateSpannedFileCabinet() | 58 | public void CanCreateSpannedFileCabinet() |
| 38 | { | 59 | { |
| 39 | using (var fs = new DisposableFileSystem()) | 60 | using (var fs = new DisposableFileSystem()) |
diff --git a/src/wix/test/WixToolsetTest.Core.Native/TestData/Testüber/t道場t.txt b/src/wix/test/WixToolsetTest.Core.Native/TestData/Testüber/t道場t.txt new file mode 100644 index 00000000..cd0db0e1 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Core.Native/TestData/Testüber/t道場t.txt | |||
| @@ -0,0 +1 @@ | |||
| This is test.txt. \ No newline at end of file | |||
diff --git a/src/wix/wixnative/smartcab.cpp b/src/wix/wixnative/smartcab.cpp index 9c441a34..1b925d42 100644 --- a/src/wix/wixnative/smartcab.cpp +++ b/src/wix/wixnative/smartcab.cpp | |||
| @@ -123,7 +123,7 @@ static HRESULT CompressFiles( | |||
| 123 | hr = StrSplitAllocArray(&rgsczSplit, &cSplit, sczLine, L"\t"); | 123 | hr = StrSplitAllocArray(&rgsczSplit, &cSplit, sczLine, L"\t"); |
| 124 | ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "failed to split smartcab line from stdin: %ls", sczLine); | 124 | ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "failed to split smartcab line from stdin: %ls", sczLine); |
| 125 | 125 | ||
| 126 | if (cSplit != 2 && cSplit != 6) | 126 | if (!rgsczSplit || (cSplit != 2 && cSplit != 6)) |
| 127 | { | 127 | { |
| 128 | hr = E_INVALIDARG; | 128 | hr = E_INVALIDARG; |
| 129 | ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "failed to split smartcab line into hash x 4, token, source file: %ls", sczLine); | 129 | ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "failed to split smartcab line into hash x 4, token, source file: %ls", sczLine); |
| @@ -176,5 +176,15 @@ static void __stdcall CabNamesCallback( | |||
| 176 | __in_z LPCWSTR wzFileToken | 176 | __in_z LPCWSTR wzFileToken |
| 177 | ) | 177 | ) |
| 178 | { | 178 | { |
| 179 | ConsoleWriteLine(CONSOLE_COLOR_NORMAL, "%ls\t%ls\t%ls", wzFirstCabName, wzNewCabName, wzFileToken); | 179 | HRESULT hr; |
| 180 | LPWSTR scz = NULL; | ||
| 181 | |||
| 182 | hr = StrAllocFormatted(&scz, L"%s\t%s\t%s\r\n", wzFirstCabName, wzNewCabName, wzFileToken); | ||
| 183 | ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "failed to allocate cabinet names message"); | ||
| 184 | |||
| 185 | hr = ConsoleWriteW(CONSOLE_COLOR_NORMAL, scz); | ||
| 186 | ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "failed to send cabinet names message"); | ||
| 187 | |||
| 188 | LExit: | ||
| 189 | ReleaseStr(scz); | ||
| 180 | } | 190 | } |
