From fc29e334f6dcaf566bc17c5c5514929a395686f8 Mon Sep 17 00:00:00 2001 From: Vincent Povirk Date: Sat, 12 Apr 2008 20:30:42 -0400 Subject: [PATCH] start.exe: Add /Unix switch for native file managers. --- programs/start/En.rc | 5 +- programs/start/resources.h | 1 + programs/start/start.c | 97 +++++++++++++++++++++++++++++++++++++- 3 files changed, 101 insertions(+), 2 deletions(-) diff --git a/programs/start/En.rc b/programs/start/En.rc index 3817a59677e..212046c6b2c 100644 --- a/programs/start/En.rc +++ b/programs/start/En.rc @@ -33,6 +33,7 @@ Options: \n\ /MAX[imized] Start the program maximized. \n\ /R[estored] Start the program normally (neither minimized nor maximized). \n\ /W[ait] Wait for started program to finish, then exit with its exit code. \n\ +/Unix Use a Unix filename and start the file like windows explorer. \n\ /L Show end-user license. \n\ \n\ start.exe version 0.2 Copyright (C) 2003, Dan Kegel \n\ @@ -59,5 +60,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. \n\ See the COPYING.LIB file for license information. \n\ " -STRING_EXECFAIL "Application could not be started, or no application associated with the specified file.\nShellExecuteEx failed" +STRING_EXECFAIL, "Application could not be started, or no application associated with the specified file.\nShellExecuteEx failed" + +STRING_UNIXFAIL "Could not translate the specified Unix filename to a DOS filename." } diff --git a/programs/start/resources.h b/programs/start/resources.h index fb4fff8832c..f5abd31302a 100644 --- a/programs/start/resources.h +++ b/programs/start/resources.h @@ -21,3 +21,4 @@ #define STRING_USAGE 101 #define STRING_LICENSE 102 #define STRING_EXECFAIL 103 +#define STRING_UNIXFAIL 104 diff --git a/programs/start/start.c b/programs/start/start.c index 58748c8ba37..c7a4ba438fc 100644 --- a/programs/start/start.c +++ b/programs/start/start.c @@ -151,13 +151,37 @@ static WCHAR *build_args( int argc, WCHAR **argvW ) return ret; } +static WCHAR *get_parent_dir(WCHAR* path) +{ + WCHAR *last_slash; + WCHAR *result; + int len; + + last_slash = strrchrW( path, '\\' ); + if (last_slash == NULL) + len = 1; + else + len = last_slash - path + 1; + + result = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + CopyMemory(result, path, (len-1)*sizeof(WCHAR)); + result[len-1] = '\0'; + + return result; +} + int wmain (int argc, WCHAR *argv[]) { SHELLEXECUTEINFOW sei; WCHAR *args = NULL; int i; + int unix_mode = 0; + WCHAR *dos_filename = NULL; + WCHAR *parent_directory = NULL; + DWORD binary_type; static const WCHAR openW[] = { 'o', 'p', 'e', 'n', 0 }; + static const WCHAR unixW[] = { 'u', 'n', 'i', 'x', 0 }; memset(&sei, 0, sizeof(sei)); sei.cbSize = sizeof(sei); @@ -178,6 +202,10 @@ int wmain (int argc, WCHAR *argv[]) if (argv[i][0] != '/') break; + /* Unix paths can start with / so we have to assume anything following /U is not a flag */ + if (unix_mode) + break; + /* Handle all options in this word */ for (ci=0; argv[i][ci]; ) { /* Skip slash */ @@ -198,6 +226,15 @@ int wmain (int argc, WCHAR *argv[]) case 'R': /* sei.nShow = SW_SHOWNORMAL; */ break; + case 'u': + case 'U': + if (strncmpiW(&argv[i][ci], unixW, 4) == 0) + unix_mode = 1; + else { + WINE_ERR("Option '%s' not recognized\n", wine_dbgstr_w( argv[i]+ci-1)); + usage(); + } + break; case 'w': case 'W': sei.fMask |= SEE_MASK_NOCLOSEPROCESS; @@ -220,10 +257,68 @@ int wmain (int argc, WCHAR *argv[]) args = build_args( argc - i, &argv[i] ); sei.lpParameters = args; - if (!ShellExecuteExW(&sei)) + if (unix_mode) { + LPWSTR (*wine_get_dos_file_name_ptr)(LPCSTR); + char* multibyte_unixpath; + int multibyte_unixpath_len; + + wine_get_dos_file_name_ptr = (void*)GetProcAddress(GetModuleHandle("KERNEL32"), "wine_get_dos_file_name"); + + if (!wine_get_dos_file_name_ptr) + fatal_string(STRING_UNIXFAIL); + + multibyte_unixpath_len = WideCharToMultiByte(CP_UNIXCP, 0, sei.lpFile, -1, NULL, 0, NULL, NULL); + multibyte_unixpath = HeapAlloc(GetProcessHeap(), 0, multibyte_unixpath_len); + + WideCharToMultiByte(CP_UNIXCP, 0, sei.lpFile, -1, multibyte_unixpath, multibyte_unixpath_len, NULL, NULL); + + dos_filename = wine_get_dos_file_name_ptr(multibyte_unixpath); + + HeapFree(GetProcessHeap(), 0, multibyte_unixpath); + + if (!dos_filename) + fatal_string(STRING_UNIXFAIL); + + sei.lpFile = dos_filename; + sei.lpDirectory = parent_directory = get_parent_dir(dos_filename); + + if (GetBinaryTypeW(sei.lpFile, &binary_type)) { + WCHAR *commandline; + STARTUPINFOW startup_info; + PROCESS_INFORMATION process_information; + static WCHAR commandlineformat[] = {'"','%','s','"','%','s',0}; + + /* explorer on windows always quotes the filename when running a binary on windows (see bug 5224) so we have to use CreateProcessW in this case */ + + commandline = HeapAlloc(GetProcessHeap(), 0, (strlenW(sei.lpFile)+3+strlenW(sei.lpParameters))*sizeof(WCHAR)); + sprintfW(commandline, commandlineformat, sei.lpFile, sei.lpParameters); + + ZeroMemory(&startup_info, sizeof(startup_info)); + startup_info.cb = sizeof(startup_info); + + if (!CreateProcessW( + NULL, /* lpApplicationName */ + commandline, /* lpCommandLine */ + NULL, /* lpProcessAttributes */ + NULL, /* lpThreadAttributes */ + FALSE, /* bInheritHandles */ + CREATE_NEW_CONSOLE, /* dwCreationFlags */ + NULL, /* lpEnvironment */ + sei.lpDirectory, /* lpCurrentDirectory */ + &startup_info, /* lpStartupInfo */ + &process_information /* lpProcessInformation */ )) + { + fatal_string_error(STRING_EXECFAIL, GetLastError()); + } + sei.hProcess = process_information.hProcess; + } + } + else if (!ShellExecuteExW(&sei)) fatal_string_error(STRING_EXECFAIL, GetLastError()); HeapFree( GetProcessHeap(), 0, args ); + HeapFree( GetProcessHeap(), 0, dos_filename ); + HeapFree( GetProcessHeap(), 0, parent_directory ); if (sei.fMask & SEE_MASK_NOCLOSEPROCESS) { DWORD exitcode;