Skip to content

Commit

Permalink
Add msvctricks.exe to replace problematic wine-msvc.bat
Browse files Browse the repository at this point in the history
  • Loading branch information
huangqinjin authored and mstorsjo committed May 22, 2023
1 parent 05c97a8 commit 2146cbf
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 44 deletions.
14 changes: 14 additions & 0 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -137,3 +137,17 @@ for arch in x86 x64 arm arm64; do
cat msvcenv.sh | sed 's/ARCH=.*/ARCH='$arch/ > bin/$arch/msvcenv.sh
done
rm msvcenv.sh

host=x64
if [ -d "$DEST/bin/$host" ] && [ -x "$(which wine64 2>/dev/null)" ]; then
WINEDEBUG=-all wine64 wineboot &>/dev/null
echo "Build msvctricks ..."
"$DEST/bin/$host/cl" /EHsc /O2 "$ORIG/msvctricks.cpp"
if [ $? -eq 0 ]; then
mv msvctricks.exe bin/
rm msvctricks.obj
echo "Build msvctricks done."
else
echo "Build msvctricks failed."
fi
fi
133 changes: 133 additions & 0 deletions msvctricks.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/*
* Copyright (c) 2023 Huang Qinjin
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include <windows.h>
#include <shlwapi.h>


#pragma comment(lib, "shell32.lib")
#pragma comment(lib, "shlwapi.lib")
#pragma comment(linker, "/ENTRY:wWinMainCRTStartup")
#pragma comment(linker, "/SUBSYSTEM:CONSOLE")


static HANDLE hStdIn = INVALID_HANDLE_VALUE;
static HANDLE hStdOut = INVALID_HANDLE_VALUE;
static HANDLE hStdErr = INVALID_HANDLE_VALUE;

static DWORD run(LPWSTR lpCmdLine)
{
STARTUPINFOW si = {};
si.cb = sizeof(si);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdInput = hStdIn;
si.hStdOutput = hStdOut;
si.hStdError = hStdErr;

PROCESS_INFORMATION pi = {};

DWORD dwExitCode;
if (CreateProcessW(nullptr, lpCmdLine, nullptr, nullptr, TRUE, 0, nullptr, nullptr, &si, &pi))
{
WaitForSingleObject(pi.hProcess, INFINITE);

if (!GetExitCodeProcess(pi.hProcess, &dwExitCode))
{
dwExitCode = GetLastError();
}

CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
else
{
dwExitCode = GetLastError();
}

return dwExitCode;
}

static DWORD mt(LPWSTR lpCmdLine)
{
DWORD dwExitCode = run(lpCmdLine);
// https://gitlab.kitware.com/cmake/cmake/-/blob/v3.26.0/Source/cmcmd.cxx#L2405
if (dwExitCode == 0x41020001)
dwExitCode = 0xbb;
return dwExitCode;
}

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
(void) hInstance;
(void) hPrevInstance;
(void) nCmdShow;

int argc = 0;
wchar_t** argv = CommandLineToArgvW(lpCmdLine, &argc);
if (argc <= 0) return 0;

wchar_t buf[32768];
if (GetEnvironmentVariableW(L"WINE_MSVC_STDIN", buf, ARRAYSIZE(buf)))
{
SECURITY_ATTRIBUTES attr = {};
attr.nLength = sizeof(attr);
attr.bInheritHandle = TRUE;

hStdIn = CreateFileW(buf, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
&attr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
}
if (GetEnvironmentVariableW(L"WINE_MSVC_STDOUT", buf, ARRAYSIZE(buf)))
{
SECURITY_ATTRIBUTES attr = {};
attr.nLength = sizeof(attr);
attr.bInheritHandle = TRUE;

hStdOut = CreateFileW(buf, GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
&attr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
}
if (GetEnvironmentVariableW(L"WINE_MSVC_STDERR", buf, ARRAYSIZE(buf)))
{
SECURITY_ATTRIBUTES attr = {};
attr.nLength = sizeof(attr);
attr.bInheritHandle = TRUE;

hStdErr = CreateFileW(buf, GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
&attr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
}

if (hStdIn == INVALID_HANDLE_VALUE)
{
hStdIn = GetStdHandle(STD_INPUT_HANDLE);
}
if (hStdOut == INVALID_HANDLE_VALUE)
{
hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
}
if (hStdErr == INVALID_HANDLE_VALUE)
{
hStdErr = GetStdHandle(STD_ERROR_HANDLE);
}

LPCWSTR const exe = PathFindFileNameW(argv[0]);

if (PathMatchSpecW(exe, L"mt.exe"))
return mt(lpCmdLine);

return run(lpCmdLine);
}
10 changes: 0 additions & 10 deletions wrappers/wine-msvc.bat

This file was deleted.

49 changes: 15 additions & 34 deletions wrappers/wine-msvc.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,15 @@
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

EXE=$1
shift
EXE=$(dirname $0)/../msvctricks.exe
if [ -f "$EXE" ]; then
HAS_MSVCTRICKS=true
else
HAS_MSVCTRICKS=false
EXE=$1
shift
fi

ARGS=()
while [ $# -gt 0 ]; do
a=$1
Expand All @@ -39,44 +46,18 @@ while [ $# -gt 0 ]; do
shift
done

if [ ${#ARGS[@]} -gt 0 ]; then
# 1. Escape all double-quotes.
# 2. Enclose each argument with double quotes.
# 3. Join all arguments with spaces.
export WINE_MSVC_ARGS=$(printf ' "%s"' "${ARGS[@]//\"/\\\"}")
else
export WINE_MSVC_ARGS=
fi
# 4. Split the argument string into multiple variables with smaller length.
# https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw
# The maximum length of lpCommandLine for CreateProcess is 32,767 characters.
# https://learn.microsoft.com/en-us/troubleshoot/windows-client/shell-experience/command-line-string-limitation
n=8191 # The maximum length of the string that you can use at the command prompt is 8191 characters.
export WINE_MSVC_ARGS0=${WINE_MSVC_ARGS:0*$n:$n}
export WINE_MSVC_ARGS1=${WINE_MSVC_ARGS:1*$n:$n}
export WINE_MSVC_ARGS2=${WINE_MSVC_ARGS:2*$n:$n}
export WINE_MSVC_ARGS3=${WINE_MSVC_ARGS:3*$n:$n}
export WINE_MSVC_ARGS4=${WINE_MSVC_ARGS:4*$n:$n}
export WINE_MSVC_ARGS5=${WINE_MSVC_ARGS:5*$n:$n}
export WINE_MSVC_ARGS6=${WINE_MSVC_ARGS:6*$n:$n}
export WINE_MSVC_ARGS7=${WINE_MSVC_ARGS:7*$n:$n}
export WINE_MSVC_ARGS8=${WINE_MSVC_ARGS:8*$n:$n}
export WINE_MSVC_ARGS9=${WINE_MSVC_ARGS:9*$n:$n}

if [ ${#WINE_MSVC_ARGS9} -ge $n ]; then
echo "Command line arguments are too long." >&2
exit 1
fi

unixify_path='s/\r// ; s/z:\([\\/]\)/\1/i ; /^Note:/s,\\,/,g'

if [ -d /proc/$$/fd ]; then
if ! $HAS_MSVCTRICKS; then
WINEDEBUG=-all wine64 "$EXE" "${ARGS[@]}" 2> >(sed -e "$unixify_path" >&2) | sed -e "$unixify_path"
exit $PIPESTATUS
elif [ -d /proc/$$/fd ]; then
exec {fd1}> >(sed -e "$unixify_path")
exec {fd2}> >(sed -e "$unixify_path" >&2)

export WINE_MSVC_STDOUT=/proc/$$/fd/$fd1
export WINE_MSVC_STDERR=/proc/$$/fd/$fd2
WINEDEBUG=-all wine64 'C:\Windows\System32\cmd.exe' /C $(dirname $0)/wine-msvc.bat "$EXE" &>/dev/null {fd1}>&- {fd2}>&-
WINEDEBUG=-all wine64 "$EXE" "${ARGS[@]}" &>/dev/null {fd1}>&- {fd2}>&-
else
export WINE_MSVC_STDOUT=${TMPDIR:-/tmp}/wine-msvc.stdout.$$
export WINE_MSVC_STDERR=${TMPDIR:-/tmp}/wine-msvc.stderr.$$
Expand All @@ -92,5 +73,5 @@ else

sed -e "$unixify_path" <$WINE_MSVC_STDOUT &
sed -e "$unixify_path" <$WINE_MSVC_STDERR >&2 &
WINEDEBUG=-all wine64 'C:\Windows\System32\cmd.exe' /C $(dirname $0)/wine-msvc.bat "$EXE" &>/dev/null
WINEDEBUG=-all wine64 "$EXE" "${ARGS[@]}" &>/dev/null
fi

0 comments on commit 2146cbf

Please sign in to comment.