mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2024-11-21 16:46:54 -08:00
Added cmd-launch-association patchset
This commit is contained in:
parent
0bdc57245a
commit
394c51bd20
@ -0,0 +1,203 @@
|
||||
From 25b5e818272cf6fc52a8707c80b9ade3a5ca5df5 Mon Sep 17 00:00:00 2001
|
||||
From: Jason Edmeades <us@edmeades.me.uk>
|
||||
Date: Tue, 16 Jul 2019 13:49:18 +1000
|
||||
Subject: [PATCH 1/2] cmd: Support for launching programs based on file
|
||||
association
|
||||
|
||||
cmd already handles exe, cmd, bat etc but if you run a file with another extension,
|
||||
then use the associations set in the registry (for example via ftype / assoc) to
|
||||
launch a program. This enables you to run test.txt and notepad to pop up, or
|
||||
fred.msi for msiexec to be launched.
|
||||
|
||||
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=18154
|
||||
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=36646
|
||||
---
|
||||
programs/cmd/wcmdmain.c | 140 +++++++++++++++++++++++++++++-----------
|
||||
1 file changed, 104 insertions(+), 36 deletions(-)
|
||||
|
||||
diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c
|
||||
index 29e498a48d..2a9e4c75ee 100644
|
||||
--- a/programs/cmd/wcmdmain.c
|
||||
+++ b/programs/cmd/wcmdmain.c
|
||||
@@ -1142,8 +1142,10 @@ void WCMD_run_program (WCHAR *command, BOOL called)
|
||||
|
||||
/* 1. If extension supplied, see if that file exists */
|
||||
if (extensionsupplied) {
|
||||
- if (GetFileAttributesW(thisDir) != INVALID_FILE_ATTRIBUTES) {
|
||||
+ DWORD attribs = GetFileAttributesW(thisDir);
|
||||
+ if (attribs != INVALID_FILE_ATTRIBUTES && !(attribs&FILE_ATTRIBUTE_DIRECTORY)) {
|
||||
found = TRUE;
|
||||
+ WINE_TRACE("Found as file with extension as '%s'\n", wine_dbgstr_w(thisDir));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1174,6 +1176,7 @@ void WCMD_run_program (WCHAR *command, BOOL called)
|
||||
}
|
||||
|
||||
if (GetFileAttributesW(thisDir) != INVALID_FILE_ATTRIBUTES) {
|
||||
+ WINE_TRACE("Found via search and pathext as '%s'\n", wine_dbgstr_w(thisDir));
|
||||
found = TRUE;
|
||||
thisExt = NULL;
|
||||
}
|
||||
@@ -1191,58 +1194,123 @@ void WCMD_run_program (WCHAR *command, BOOL called)
|
||||
WCHAR *ext = wcsrchr( thisDir, '.' );
|
||||
static const WCHAR batExt[] = {'.','b','a','t','\0'};
|
||||
static const WCHAR cmdExt[] = {'.','c','m','d','\0'};
|
||||
+ static const WCHAR exeExt[] = {'.','e','x','e','\0'};
|
||||
+ static const WCHAR comExt[] = {'.','c','o','m','\0'};
|
||||
|
||||
WINE_TRACE("Found as %s\n", wine_dbgstr_w(thisDir));
|
||||
|
||||
/* Special case BAT and CMD */
|
||||
if (ext && (!wcsicmp(ext, batExt) || !wcsicmp(ext, cmdExt))) {
|
||||
BOOL oldinteractive = interactive;
|
||||
+ WINE_TRACE("Calling batch program\n");
|
||||
interactive = FALSE;
|
||||
WCMD_batch (thisDir, command, called, NULL, INVALID_HANDLE_VALUE);
|
||||
interactive = oldinteractive;
|
||||
+ WINE_TRACE("Back from call to batch program\n");
|
||||
return;
|
||||
- } else {
|
||||
+ }
|
||||
|
||||
- /* thisDir contains the file to be launched, but with what?
|
||||
- eg. a.exe will require a.exe to be launched, a.html may be iexplore */
|
||||
- hinst = FindExecutableW (thisDir, NULL, temp);
|
||||
- if ((INT_PTR)hinst < 32)
|
||||
- console = 0;
|
||||
- else
|
||||
- console = SHGetFileInfoW(temp, 0, &psfi, sizeof(psfi), SHGFI_EXETYPE);
|
||||
-
|
||||
- ZeroMemory (&st, sizeof(STARTUPINFOW));
|
||||
- st.cb = sizeof(STARTUPINFOW);
|
||||
- init_msvcrt_io_block(&st);
|
||||
-
|
||||
- /* Launch the process and if a CUI wait on it to complete
|
||||
- Note: Launching internal wine processes cannot specify a full path to exe */
|
||||
- status = CreateProcessW(thisDir,
|
||||
- command, NULL, NULL, TRUE, 0, NULL, NULL, &st, &pe);
|
||||
- heap_free(st.lpReserved2);
|
||||
- if ((opt_c || opt_k) && !opt_s && !status
|
||||
- && GetLastError()==ERROR_FILE_NOT_FOUND && command[0]=='\"') {
|
||||
- /* strip first and last quote WCHARacters and try again */
|
||||
- WCMD_strip_quotes(command);
|
||||
- opt_s = TRUE;
|
||||
- WCMD_run_program(command, called);
|
||||
+ /* Calculate what program will be launched, and whether it is a
|
||||
+ console application or not. Note the program may be different
|
||||
+ from the parameter (eg running a .txt file will launch notepad.exe) */
|
||||
+ hinst = FindExecutableW (thisDir, NULL, temp);
|
||||
+ if ((INT_PTR)hinst < 32)
|
||||
+ console = 0; /* Assume not console app by default */
|
||||
+ else
|
||||
+ console = SHGetFileInfoW(temp, 0, &psfi, sizeof(psfi), SHGFI_EXETYPE);
|
||||
+
|
||||
+
|
||||
+ /* If it is not a .com or .exe, try to launch through ShellExecuteExW
|
||||
+ which takes into account the association for the extension. */
|
||||
+ if (ext && (wcsicmp(ext, exeExt) && wcsicmp(ext, comExt))) {
|
||||
+
|
||||
+ SHELLEXECUTEINFOW shexw;
|
||||
+ BOOL rc;
|
||||
+ WCHAR *rawarg;
|
||||
+
|
||||
+ WCMD_parameter(command, 1, &rawarg, FALSE, TRUE);
|
||||
+ WINE_TRACE("Launching via ShellExecuteEx\n");
|
||||
+ memset(&shexw, 0x00, sizeof(shexw));
|
||||
+ shexw.cbSize = sizeof(SHELLEXECUTEINFOW);
|
||||
+ shexw.fMask = SEE_MASK_NO_CONSOLE | /* Run in same console as currently using */
|
||||
+ SEE_MASK_NOCLOSEPROCESS; /* We need a process handle to possibly wait on */
|
||||
+ shexw.lpFile = thisDir;
|
||||
+ shexw.lpParameters = rawarg;
|
||||
+ shexw.nShow = SW_SHOWNORMAL;
|
||||
+
|
||||
+ /* Try to launch the binary or its associated program */
|
||||
+ rc = ShellExecuteExW(&shexw);
|
||||
+
|
||||
+ if (rc && (INT_PTR)shexw.hInstApp >= 32) {
|
||||
+
|
||||
+ WINE_TRACE("Successfully launched\n");
|
||||
+
|
||||
+ /* It worked... Always wait when non-interactive (cmd /c or in
|
||||
+ batch program), or for console applications */
|
||||
+ if (!interactive || (console && !HIWORD(console))) {
|
||||
+ WINE_TRACE("Waiting for process to end\n");
|
||||
+ WaitForSingleObject (shexw.hProcess, INFINITE);
|
||||
+ }
|
||||
+
|
||||
+ GetExitCodeProcess (shexw.hProcess, &errorlevel);
|
||||
+ if (errorlevel == STILL_ACTIVE) {
|
||||
+ WINE_TRACE("Process still running, but returning anyway\n");
|
||||
+ errorlevel = 0;
|
||||
+ } else {
|
||||
+ WINE_TRACE("Process ended, errorlevel %d\n", errorlevel);
|
||||
+ }
|
||||
+
|
||||
+ CloseHandle(pe.hProcess);
|
||||
return;
|
||||
+
|
||||
}
|
||||
+ }
|
||||
|
||||
- if (!status)
|
||||
- break;
|
||||
+ /* If its a .exe or .com or the shellexecute failed due to no association,
|
||||
+ CreateProcess directly */
|
||||
+ ZeroMemory (&st, sizeof(STARTUPINFOW));
|
||||
+ st.cb = sizeof(STARTUPINFOW);
|
||||
+ init_msvcrt_io_block(&st);
|
||||
+
|
||||
+ /* Launch the process and if a CUI wait on it to complete
|
||||
+ Note: Launching internal wine processes cannot specify a full path to exe */
|
||||
+ WINE_TRACE("Launching via CreateProcess\n");
|
||||
+ status = CreateProcessW(thisDir,
|
||||
+ command, NULL, NULL, TRUE, 0, NULL, NULL, &st, &pe);
|
||||
+ heap_free(st.lpReserved2);
|
||||
+ if ((opt_c || opt_k) && !opt_s && !status
|
||||
+ && GetLastError()==ERROR_FILE_NOT_FOUND && command[0]=='\"') {
|
||||
+ /* strip first and last quote WCHARacters and try again */
|
||||
+ WCMD_strip_quotes(command);
|
||||
+ opt_s = TRUE;
|
||||
+ WCMD_run_program(command, called);
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
- /* Always wait when non-interactive (cmd /c or in batch program),
|
||||
- or for console applications */
|
||||
- if (!interactive || (console && !HIWORD(console)))
|
||||
- WaitForSingleObject (pe.hProcess, INFINITE);
|
||||
- GetExitCodeProcess (pe.hProcess, &errorlevel);
|
||||
- if (errorlevel == STILL_ACTIVE) errorlevel = 0;
|
||||
+ if (!status) {
|
||||
+ WINE_TRACE("Failed to launch via CreateProcess, rc %d (%d)\n",
|
||||
+ status, GetLastError());
|
||||
+ break;
|
||||
+ }
|
||||
|
||||
- CloseHandle(pe.hProcess);
|
||||
- CloseHandle(pe.hThread);
|
||||
- return;
|
||||
+ /* Always wait when non-interactive (cmd /c or in batch program),
|
||||
+ or for console applications */
|
||||
+ if (!interactive || (console && !HIWORD(console))) {
|
||||
+ WINE_TRACE("Waiting for process to end\n");
|
||||
+ WaitForSingleObject (pe.hProcess, INFINITE);
|
||||
}
|
||||
+
|
||||
+ GetExitCodeProcess (pe.hProcess, &errorlevel);
|
||||
+ if (errorlevel == STILL_ACTIVE) {
|
||||
+ WINE_TRACE("Process still running, but returning anyway\n");
|
||||
+ errorlevel = 0;
|
||||
+ } else {
|
||||
+ WINE_TRACE("Process ended, errorlevel %d\n", errorlevel);
|
||||
+ }
|
||||
+
|
||||
+ CloseHandle(pe.hProcess);
|
||||
+ CloseHandle(pe.hThread);
|
||||
+ return;
|
||||
}
|
||||
}
|
||||
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,79 @@
|
||||
From 7bb9825d921f91be01144110f6478a0c017cbd79 Mon Sep 17 00:00:00 2001
|
||||
From: Jason Edmeades <us@edmeades.me.uk>
|
||||
Date: Tue, 16 Jul 2019 13:51:58 +1000
|
||||
Subject: [PATCH 2/2] cmd: ftype failed to clear file associations
|
||||
|
||||
If a file association was set (e.g. ftype fred=xxx), ftype fred= needs to clear it,
|
||||
but previously it failed to do so.
|
||||
---
|
||||
programs/cmd/builtins.c | 6 +++---
|
||||
programs/cmd/tests/test_builtins.cmd | 9 +++++++++
|
||||
programs/cmd/tests/test_builtins.cmd.exp | 5 ++++-
|
||||
3 files changed, 16 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c
|
||||
index 62ae19a494..e85e553c05 100644
|
||||
--- a/programs/cmd/builtins.c
|
||||
+++ b/programs/cmd/builtins.c
|
||||
@@ -4939,11 +4939,11 @@ void WCMD_assoc (const WCHAR *args, BOOL assoc) {
|
||||
/* If nothing after '=' then clear value - only valid for ASSOC */
|
||||
if (*newValue == 0x00) {
|
||||
|
||||
- if (assoc) rc = RegDeleteKeyW(key, args);
|
||||
- if (assoc && rc == ERROR_SUCCESS) {
|
||||
+ rc = RegDeleteTreeW(key, args);
|
||||
+ if (rc == ERROR_SUCCESS) {
|
||||
WINE_TRACE("HKCR Key '%s' deleted\n", wine_dbgstr_w(args));
|
||||
|
||||
- } else if (assoc && rc != ERROR_FILE_NOT_FOUND) {
|
||||
+ } else if (rc != ERROR_FILE_NOT_FOUND) {
|
||||
WCMD_print_error();
|
||||
errorlevel = 2;
|
||||
|
||||
diff --git a/programs/cmd/tests/test_builtins.cmd b/programs/cmd/tests/test_builtins.cmd
|
||||
index f4dfc9f26d..0ef049a4ab 100644
|
||||
--- a/programs/cmd/tests/test_builtins.cmd
|
||||
+++ b/programs/cmd/tests/test_builtins.cmd
|
||||
@@ -2440,6 +2440,12 @@ echo echo +++>> tmp.cmd
|
||||
echo ftype footype>> tmp.cmd
|
||||
cmd /c tmp.cmd
|
||||
|
||||
+echo --- testing association
|
||||
+ftype footype=cmd.exe /c "echo '%%1'"
|
||||
+echo dummy>test.foo
|
||||
+test.foo
|
||||
+del test.foo
|
||||
+
|
||||
echo --- resetting association
|
||||
assoc .foo=
|
||||
|
||||
@@ -2471,6 +2477,9 @@ echo .foo=footype
|
||||
echo footype=foo_opencmd
|
||||
echo +++
|
||||
echo footype=foo_opencmd
|
||||
+echo --- testing association
|
||||
+echo footype=cmd.exe /c "echo '%%1'"
|
||||
+echo Skipped as not enough permissions
|
||||
echo --- resetting association
|
||||
echo original value
|
||||
|
||||
diff --git a/programs/cmd/tests/test_builtins.cmd.exp b/programs/cmd/tests/test_builtins.cmd.exp
|
||||
index d78d91a6cf..e6ebe06714 100644
|
||||
--- a/programs/cmd/tests/test_builtins.cmd.exp
|
||||
+++ b/programs/cmd/tests/test_builtins.cmd.exp
|
||||
@@ -1444,8 +1444,11 @@ footype=foo_opencmd
|
||||
footype=foo_opencmd
|
||||
+++
|
||||
footype=foo_opencmd
|
||||
+--- testing association
|
||||
+footype=cmd.exe /c "echo '%1'"
|
||||
+'@drive@@path@foobar\test.foo'@or_broken@Skipped as not enough permissions
|
||||
--- resetting association
|
||||
-@todo_wine@original value@or_broken@buggyXP@or_broken@!WINE_FOO!
|
||||
+original value@or_broken@buggyXP@or_broken@!WINE_FOO!
|
||||
------------ Testing CALL ------------
|
||||
--- external script
|
||||
foo@space@
|
||||
--
|
||||
2.17.1
|
||||
|
2
patches/cmd-launch-association/definition
Normal file
2
patches/cmd-launch-association/definition
Normal file
@ -0,0 +1,2 @@
|
||||
Fixes: [18154] cmd: Support for launching programs based on file association
|
||||
# Fixes: [36646]
|
@ -92,6 +92,7 @@ patch_enable_all ()
|
||||
enable_advapi32_Token_Integrity_Level="$1"
|
||||
enable_api_ms_win_Stub_DLLs="$1"
|
||||
enable_atl_AtlAxDialogBox="$1"
|
||||
enable_cmd_launch_association="$1"
|
||||
enable_combase_GetRestrictedErrorInfo="$1"
|
||||
enable_comctl32_Listview_DrawItem="$1"
|
||||
enable_comctl32_alpha_bitmaps="$1"
|
||||
@ -407,6 +408,9 @@ patch_enable ()
|
||||
atl-AtlAxDialogBox)
|
||||
enable_atl_AtlAxDialogBox="$2"
|
||||
;;
|
||||
cmd-launch-association)
|
||||
enable_cmd_launch_association="$2"
|
||||
;;
|
||||
combase-GetRestrictedErrorInfo)
|
||||
enable_combase_GetRestrictedErrorInfo="$2"
|
||||
;;
|
||||
@ -2335,6 +2339,24 @@ if test "$enable_atl_AtlAxDialogBox" -eq 1; then
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset cmd-launch-association
|
||||
# |
|
||||
# | This patchset fixes the following Wine bugs:
|
||||
# | * [#18154] cmd: Support for launching programs based on file association
|
||||
# |
|
||||
# | Modified files:
|
||||
# | * programs/cmd/builtins.c, programs/cmd/tests/test_builtins.cmd, programs/cmd/tests/test_builtins.cmd.exp,
|
||||
# | programs/cmd/wcmdmain.c
|
||||
# |
|
||||
if test "$enable_cmd_launch_association" -eq 1; then
|
||||
patch_apply cmd-launch-association/0001-cmd-Support-for-launching-programs-based-on-file-ass.patch
|
||||
patch_apply cmd-launch-association/0002-cmd-ftype-failed-to-clear-file-associations.patch
|
||||
(
|
||||
printf '%s\n' '+ { "Jason Edmeades", "cmd: Support for launching programs based on file association.", 1 },';
|
||||
printf '%s\n' '+ { "Jason Edmeades", "cmd: Ftype failed to clear file associations.", 1 },';
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset combase-GetRestrictedErrorInfo
|
||||
# |
|
||||
# | This patchset fixes the following Wine bugs:
|
||||
|
Loading…
Reference in New Issue
Block a user