1- using System . Diagnostics ;
1+ using System . Diagnostics ;
2+ using System . Runtime . InteropServices ;
3+ using System . Text . RegularExpressions ;
24
35namespace WineBridge . Commands ;
46
57internal class RunExe : ICommand
68{
79 public void Execute ( string [ ] ? args )
810 {
9- if ( args is null )
11+ if ( args is null || args . Length == 0 )
1012 {
11- Console . WriteLine ( "Error. Usage: WineBridge.exe runExe fullPathToExe [arg1] [arg2] [arg3 ...]" ) ;
13+ Console . WriteLine ( "Error. Usage: WineBridge.exe runExe [--shell] fullPathToExe [ ...]" ) ;
1214 return ;
1315 }
14- if ( args . Length == 0 )
16+
17+ var useShell = false ;
18+ var index = 0 ;
19+
20+ if ( args [ 0 ] . Equals ( "--shell" , StringComparison . OrdinalIgnoreCase ) )
21+ {
22+ useShell = true ;
23+ index ++ ;
24+ }
25+
26+ if ( index >= args . Length )
27+ {
28+ Console . WriteLine ( "Error. Usage: WineBridge.exe runExe [--shell] fullPathToExe [...]" ) ;
29+ return ;
30+ }
31+
32+ var raw = args [ index ] ? . Trim ( ) . Trim ( '"' , '\' ' ) ?? string . Empty ;
33+
34+ var m = Regex . Match (
35+ raw ,
36+ @"[A-Za-z]:\\[^:]+?\.exe" ,
37+ RegexOptions . IgnoreCase
38+ ) ;
39+
40+ if ( ! m . Success )
1541 {
16- Console . WriteLine ( "Error. Usage: WineBridge.exe runExe fullPathToExe [arg1] [arg2] [arg3...] " ) ;
42+ Console . WriteLine ( "Error: no valid Windows executable path found. " ) ;
1743 return ;
1844 }
19-
20- var executable = args [ 0 ] ;
21- var arguments = args . Skip ( 1 ) . ToArray ( ) ;
22-
45+
46+ var executable = m . Value ;
47+ var cwd = Path . GetDirectoryName ( executable ) ?? string . Empty ;
48+
49+ var remaining = raw . Substring ( m . Index + m . Length ) . Trim ( ) ;
50+ var arguments = remaining ;
51+
52+ Console . WriteLine ( "[RunExe] Mode: " + ( useShell ? "shell" : "direct" ) ) ;
53+ Console . WriteLine ( "[RunExe] FileName: " + executable ) ;
54+ Console . WriteLine ( "[RunExe] CWD: " + cwd ) ;
55+ Console . WriteLine ( "[RunExe] Args: " + arguments ) ;
56+
57+ try
58+ {
59+ if ( useShell )
60+ {
61+ RunViaShell ( executable , arguments , cwd ) ;
62+ }
63+ else
64+ {
65+ RunDirect ( executable , arguments , cwd ) ;
66+ }
67+ }
68+ catch ( Exception ex )
69+ {
70+ Console . WriteLine ( "Error launching process: " + ex . Message ) ;
71+ }
72+ }
73+
74+ private static void RunDirect ( string executable , string arguments , string cwd )
75+ {
2376 var startInfo = new ProcessStartInfo
2477 {
2578 FileName = executable ,
26- Arguments = string . Join ( " " , arguments )
79+ WorkingDirectory = cwd ,
80+ UseShellExecute = false ,
81+ Arguments = arguments
2782 } ;
2883
2984 Process . Start ( startInfo ) ;
3085 }
31- }
86+
87+ private static void RunViaShell ( string executable , string arguments , string cwd )
88+ {
89+ var info = new SHELLEXECUTEINFOW
90+ {
91+ cbSize = Marshal . SizeOf < SHELLEXECUTEINFOW > ( ) ,
92+ fMask = SEE_MASK_NOCLOSEPROCESS ,
93+ hwnd = IntPtr . Zero ,
94+ lpVerb = "open" ,
95+ lpFile = executable ,
96+ lpParameters = arguments ,
97+ lpDirectory = string . IsNullOrWhiteSpace ( cwd ) ? null : cwd ,
98+ nShow = SW_SHOWNORMAL ,
99+ hInstApp = IntPtr . Zero ,
100+ lpIDList = IntPtr . Zero ,
101+ lpClass = null ,
102+ hkeyClass = IntPtr . Zero ,
103+ dwHotKey = 0 ,
104+ hIcon = IntPtr . Zero ,
105+ hProcess = IntPtr . Zero
106+ } ;
107+
108+ if ( ! ShellExecuteExW ( ref info ) )
109+ {
110+ var err = Marshal . GetLastWin32Error ( ) ;
111+ Console . WriteLine ( "ShellExecuteExW failed. Win32 error: " + err ) ;
112+ return ;
113+ }
114+
115+ if ( info . hProcess != IntPtr . Zero )
116+ {
117+ // TODO: this might be introduced with a ne flag, in case we need to wait for the procss to exit
118+ }
119+ }
120+
121+ private const uint SEE_MASK_NOCLOSEPROCESS = 0x00000040 ;
122+ private const int SW_SHOWNORMAL = 1 ;
123+
124+ [ StructLayout ( LayoutKind . Sequential , CharSet = CharSet . Unicode ) ]
125+ private struct SHELLEXECUTEINFOW
126+ {
127+ public int cbSize ;
128+ public uint fMask ;
129+ public IntPtr hwnd ;
130+ [ MarshalAs ( UnmanagedType . LPWStr ) ]
131+ public string ? lpVerb ;
132+ [ MarshalAs ( UnmanagedType . LPWStr ) ]
133+ public string lpFile ;
134+ [ MarshalAs ( UnmanagedType . LPWStr ) ]
135+ public string ? lpParameters ;
136+ [ MarshalAs ( UnmanagedType . LPWStr ) ]
137+ public string ? lpDirectory ;
138+ public int nShow ;
139+ public IntPtr hInstApp ;
140+ public IntPtr lpIDList ;
141+ [ MarshalAs ( UnmanagedType . LPWStr ) ]
142+ public string ? lpClass ;
143+ public IntPtr hkeyClass ;
144+ public uint dwHotKey ;
145+ public IntPtr hIcon ;
146+ public IntPtr hProcess ;
147+ }
148+
149+ [ DllImport ( "shell32.dll" , CharSet = CharSet . Unicode , SetLastError = true ) ]
150+ [ return : MarshalAs ( UnmanagedType . Bool ) ]
151+ private static extern bool ShellExecuteExW ( ref SHELLEXECUTEINFOW lpExecInfo ) ;
152+ }
0 commit comments