shellExecute 16bit support
authorClaus Gittinger <cg@exept.de>
Fri, 10 Aug 2018 12:03:54 +0200
changeset 23272 943caf3090c8
parent 23271 676915d2e795
child 23273 937be20520a7
shellExecute 16bit support
Win32OperatingSystem.st
--- a/Win32OperatingSystem.st	Thu Aug 09 17:33:11 2018 +0200
+++ b/Win32OperatingSystem.st	Fri Aug 10 12:03:54 2018 +0200
@@ -598,6 +598,7 @@
 	    buffer[i] = __unicode16StringVal(string)[i];
 	}
     } else {
+	buffer[0] = 0;
 	return(-1);
     }
     buffer[len] = 0;
@@ -1669,7 +1670,7 @@
 
     result := self primCloseClipboard.
     result ifFalse: [
-        self error:'Clipboard close failed'
+	self error:'Clipboard close failed'
     ].
     ^ result
 
@@ -1677,11 +1678,11 @@
 !
 
 emptyClipboard
-        "Private - empty the clipboard. Note: it must be opened first."
+	"Private - empty the clipboard. Note: it must be opened first."
     | result |
     result := self primEmptyClipboard.
     result ifFalse: [
-        self error:'Clipboard empty failed'
+	self error:'Clipboard empty failed'
     ].
     ^result
 
@@ -1703,7 +1704,7 @@
 
     result := self primOpenClipboard: aHwnd.
     result ifFalse: [
-        self error:'Clipboard open failed'
+	self error:'Clipboard open failed'
     ].
     ^ result
 
@@ -1761,7 +1762,7 @@
     self closeClipboard
 
     "
-        Win32OperatingSystem setBitmapToClipboard: Image fromUser
+	Win32OperatingSystem setBitmapToClipboard: Image fromUser
     "
 
     "Modified (format): / 03-08-2018 / 11:24:11 / Stefan Vogel"
@@ -1772,7 +1773,7 @@
 
     result := self primSetClipboardData: aCfConstant hMem: aMemHandle address.
     result = 0 ifTrue: [
-        self error:'Set clipboard data failed'
+	self error:'Set clipboard data failed'
     ].
     ^ result.
 
@@ -4374,7 +4375,7 @@
     handle := Win32ProcessHandle new.
 
 %{
-    SHELLEXECUTEINFO shExecInfo = {0};
+    SHELLEXECUTEINFOW shExecInfo = {0};
     shExecInfo.cbSize = sizeof(shExecInfo);
 
     if (__isSmallInteger(nShowCmd)) {
@@ -4405,30 +4406,40 @@
 	}
     }
     if (((lpOperationArg == nil) || __isStringLike(lpOperationArg))
-     && ((lpFileArg == nil) || __isStringLike(lpFileArg))
-     && ((lpParametersArg == nil) || __isStringLike(lpParametersArg))
-     && ((lpDirectoryArg == nil) || __isStringLike(lpDirectoryArg))
+     && ((lpFileArg == nil) || __isStringLike(lpFileArg) || __isUnicode16String(lpFileArg))
+     && ((lpParametersArg == nil) || __isStringLike(lpParametersArg) || __isUnicode16String(lpParametersArg))
+     && ((lpDirectoryArg == nil) || __isStringLike(lpDirectoryArg) || __isUnicode16String(lpDirectoryArg))
     ) {
 	// hProcess member receives the process handle
 	shExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
+	wchar_t _wFileArg[MAXPATHLEN+1];
+	wchar_t _wParametersArg[MAXPATHLEN+1];
+	wchar_t _wDirectoryArg[MAXPATHLEN+1];
+	wchar_t _wVerbArg[128];
+
+	_makeWchar(lpOperationArg, _wVerbArg, sizeof(_wVerbArg));
+	_makeWchar(lpFileArg, _wFileArg, sizeof(_wFileArg));
+	_makeWchar(lpParametersArg, _wParametersArg, sizeof(_wParametersArg));
+	_makeWchar(lpDirectoryArg, _wDirectoryArg, sizeof(_wDirectoryArg));
+
+	shExecInfo.lpVerb        = (lpOperationArg != nil) ? _wVerbArg : NULL;
+	shExecInfo.lpFile        = (lpFileArg != nil) ? _wFileArg : NULL;
+	shExecInfo.lpParameters  = (lpParametersArg != nil) ? _wParametersArg : NULL;
+	shExecInfo.lpDirectory   = (lpDirectoryArg != nil) ? _wDirectoryArg : NULL;
 
 	shExecInfo.hwnd = 0;
-	shExecInfo.lpVerb        = (lpOperationArg != nil) ? __stringVal(lpOperationArg) : NULL;
-	shExecInfo.lpFile        = (lpFileArg != nil) ? __stringVal(lpFileArg) : NULL;
-	shExecInfo.lpParameters  = (lpParametersArg != nil) ? __stringVal(lpParametersArg) : NULL;
-	shExecInfo.lpDirectory   = (lpDirectoryArg != nil) ? __stringVal(lpDirectoryArg) : NULL;
 	if (hwndArg != nil) {
 	    if (__isExternalAddressLike(hwndArg)) {
 		shExecInfo.hwnd = _HANDLEVal(hwndArg);
 	    } else
 		goto badArgument;
 	}
-	if (ShellExecuteEx(&shExecInfo)) {
+	if (ShellExecuteExW(&shExecInfo)) {
 	    if (shExecInfo.hProcess) {
 		DWORD_PTR processAffinityMask, systemAffinityMask;
 		/*
-		 * Set the affinity mask
-		 * to any processor, and resume the processes main thread.
+		 * Set the affinity mask to any processor,
+		 * and resume the processes main thread.
 		 * (librun/process.s limited the affinity to a single processor).
 		 */
 		GetProcessAffinityMask(shExecInfo.hProcess, &processAffinityMask, &systemAffinityMask);
@@ -6021,10 +6032,10 @@
     codePage := vfi unsignedInt16At:3.
     assocs := infoKeys collect:[:each |
        sfi := self extractVersionValue:('\StringFileInfo\%1%2\%3'
-                                       bindWith:(lang hexPrintString:4)
-                                       with:(codePage hexPrintString:4)
-                                       with:each)
-                from:bytes.
+				       bindWith:(lang hexPrintString:4)
+				       with:(codePage hexPrintString:4)
+				       with:each)
+		from:bytes.
        each -> (sfi zeroByteStringAt:1 maximumSize:999)
     ].
     ^ Dictionary withAssociations:assocs
@@ -7601,8 +7612,8 @@
      The process terminates immediately and has no chance to perform any cleanup actions.
 
      WARNING: in order to avoid zombie processes (on unix),
-              you have to fetch the processes exitstatus with
-              OperatingSystem>>getStatusOfProcess:aProcessId."
+	      you have to fetch the processes exitstatus with
+	      OperatingSystem>>getStatusOfProcess:aProcessId."
 
     self killProcess:processHandleOrPid exitCode:0.
 
@@ -7615,20 +7626,20 @@
 
 %{
     if (__isExternalAddressLike(processHandleOrPid) ) {
-        HANDLE hProcess = _HANDLEVal(processHandleOrPid);
-
-        if (hProcess != 0) {
-            TerminateProcess( hProcess, __intVal(exitCode) );
-        }
-        RETURN( true );
+	HANDLE hProcess = _HANDLEVal(processHandleOrPid);
+
+	if (hProcess != 0) {
+	    TerminateProcess( hProcess, __intVal(exitCode) );
+	}
+	RETURN( true );
     } else if( __isSmallInteger(processHandleOrPid) ) {
-        HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, 0, __smallIntegerVal(processHandleOrPid));
-
-        if( hProcess != 0 ) {
-            TerminateProcess( hProcess, __intVal(exitCode) );
-            CloseHandle(hProcess);
-        }
-        RETURN( true );
+	HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, 0, __smallIntegerVal(processHandleOrPid));
+
+	if( hProcess != 0 ) {
+	    TerminateProcess( hProcess, __intVal(exitCode) );
+	    CloseHandle(hProcess);
+	}
+	RETURN( true );
     }
 %}.
     self primitiveFailed:#invalidParameter.
@@ -7642,15 +7653,15 @@
      Here we kill any offspring of the process identified by processGroupHandleOrPid.
 
      WARNING: in order to avoid zombie processes (on unix),
-              you have to fetch the processes exitstatus with
-              OperatingSystem>>getStatusOfProcess:aProcessId."
+	      you have to fetch the processes exitstatus with
+	      OperatingSystem>>getStatusOfProcess:aProcessId."
 
     | pid processList groupsToTerminate anyMore |
 
     processGroupHandleOrPid isInteger ifTrue:[
-        pid := processGroupHandleOrPid
+	pid := processGroupHandleOrPid
     ] ifFalse:[
-        pid := processGroupHandleOrPid pid.
+	pid := processGroupHandleOrPid pid.
     ].
     groupsToTerminate := Set with:pid.
     processList := self getAllProcesses asSet.
@@ -7658,21 +7669,21 @@
     "/ Transcript show:'terminate group '; showCR:pid.
     anyMore := true.
     [anyMore] whileTrue:[
-        anyMore := false.
-        processList doWithExit:[:anOSProcess :exit |
-            |pid|
-
-            (groupsToTerminate includes:anOSProcess parentPid) ifTrue:[
-                pid := anOSProcess pid.
-                groupsToTerminate add:pid.
-                "/ Transcript show:'terminate '; showCR:pid.
-                self killProcess:pid.
-                processList remove:anOSProcess.
-                anyMore := true.
-                "/ need to restart: we have removed an element inside the loop
-                exit value:nil
-            ].
-        ].
+	anyMore := false.
+	processList doWithExit:[:anOSProcess :exit |
+	    |pid|
+
+	    (groupsToTerminate includes:anOSProcess parentPid) ifTrue:[
+		pid := anOSProcess pid.
+		groupsToTerminate add:pid.
+		"/ Transcript show:'terminate '; showCR:pid.
+		self killProcess:pid.
+		processList remove:anOSProcess.
+		anyMore := true.
+		"/ need to restart: we have removed an element inside the loop
+		exit value:nil
+	    ].
+	].
     ].
 
     "Modified: / 03-08-2018 / 09:58:21 / Stefan Vogel"
@@ -7774,15 +7785,15 @@
     "terminate a process.
 
      ATTENTION WIN32:
-         Under unix, we have terminateProcess, which does a soft
-         terminate (giving the process a chance to cleanup) and
-         killProcess, which does a hard terminate.
-         Under WIN32, both (currently) use the TerminateProcess
-         function, which unconditionally causes a process to exit.
-         I.e. under WIN32, the process has no chance to perform cleanup.
-         Use it only in extreme circumstances. The state of
-         global data maintained by dynamic-link libraries (DLLs)
-         may be compromised if TerminateProcess is used.
+	 Under unix, we have terminateProcess, which does a soft
+	 terminate (giving the process a chance to cleanup) and
+	 killProcess, which does a hard terminate.
+	 Under WIN32, both (currently) use the TerminateProcess
+	 function, which unconditionally causes a process to exit.
+	 I.e. under WIN32, the process has no chance to perform cleanup.
+	 Use it only in extreme circumstances. The state of
+	 global data maintained by dynamic-link libraries (DLLs)
+	 may be compromised if TerminateProcess is used.
 
      TODO: send a WM_QUIT instead, to allow for proper shutdown."
 
@@ -7797,15 +7808,15 @@
     "terminate a process group (that is all subprocesses of a process).
 
      ATTENTION WIN32:
-         Under unix, we have terminateProcess, which does a soft
-         terminate (giving the process a chance to cleanup) and
-         killProcess, which does a hard terminate.
-         Under WIN32, both (currently) use the TerminateProcess
-         function, which unconditionally causes a process to exit.
-         I.e. under WIN32, the process has no chance to perform cleanup.
-         Use it only in extreme circumstances. The state of
-         global data maintained by dynamic-link libraries (DLLs)
-         may be compromised if TerminateProcess is used.
+	 Under unix, we have terminateProcess, which does a soft
+	 terminate (giving the process a chance to cleanup) and
+	 killProcess, which does a hard terminate.
+	 Under WIN32, both (currently) use the TerminateProcess
+	 function, which unconditionally causes a process to exit.
+	 I.e. under WIN32, the process has no chance to perform cleanup.
+	 Use it only in extreme circumstances. The state of
+	 global data maintained by dynamic-link libraries (DLLs)
+	 may be compromised if TerminateProcess is used.
      TODO: send a WM_QUIT instead, to allow for proper shutdown."
 
     self killProcessGroup:processGroupHandleOrPid.
@@ -11194,11 +11205,11 @@
     "commands to try for speech output"
 
     ^ #(
-        ('powershell'
-         'powershell -Command "Add-Type -AssemblyName System.Speech; (New-Object System.Speech.Synthesis.SPeechSynthesizer).Speak(''%2'');"'
-         'powershell -Command "Add-Type -AssemblyName System.Speech; (New-Object System.Speech.Synthesis.SPeechSynthesizer).Speak(''%2'');"'
-        )
-    )    
+	('powershell'
+	 'powershell -Command "Add-Type -AssemblyName System.Speech; (New-Object System.Speech.Synthesis.SPeechSynthesizer).Speak(''%2'');"'
+	 'powershell -Command "Add-Type -AssemblyName System.Speech; (New-Object System.Speech.Synthesis.SPeechSynthesizer).Speak(''%2'');"'
+	)
+    )
 
     "
      self speak:'hello'