forked from bhoogter/VB6TocSharp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
modShell.bas
182 lines (159 loc) · 6.54 KB
/
modShell.bas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
Attribute VB_Name = "modShell"
Option Explicit
Public Const SW_HIDE As Long = 0
Public Const SW_SHOWNORMAL As Long = 1
Public Const SW_SHOWMINIMIZED As Long = 2
Public Const SW_SHOWMAXIMIZED As Long = 3
Public Const SW_SHOW As Long = 5
Public Const SW_SHOWDEFAULT As Long = 10
Public Const CREATE_NO_WINDOW As Long = &H8000000
Global Const INFINITE As Long = -1
Private LastProcessID As Long
Private Const DIRSEP As String = "\"
Global Const NORMAL_PRIORITY_CLASS As Long = &H20
Enum enSW
enSW_HIDE = 0
enSW_NORMAL = 1
enSW_MAXIMIZE = 3
enSW_MINIMIZE = 6
'' try with comment ' and a second comment
End Enum
Type STARTUPINFO
Cb As Long
lpReserved As String
lpDesktop As String
lpTitle As String
dwX As Long
dwY As Long
dwXSize As Long
dwYSize As Long
dwXCountChars As Long
dwYCountChars As Long
dwFillAttribute As Long
dwFlags As Long
wShowWindow As Integer
cbReserved2 As Integer
lpReserved2 As Long
hStdInput As Long
hStdOutput As Long
hStdError As Long
End Type
Type PROCESS_INFORMATION
hProcess As Long
hThread As Long
dwProcessId As Long
dwThreadId As Long
End Type
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Private Declare Function CreateProcessA Lib "kernel32" (ByVal lpApplicationName As Long, ByVal lpCommandLine As String, ByVal lpProcessAttributes As Long, ByVal lpThreadAttributes As Long, ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, ByVal lpEnvironment As Long, ByVal lpCurrentDirectory As Long, lpStartupInfo As STARTUPINFO, lpProcessInformation As PROCESS_INFORMATION) As Long
Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (hObject As Long) As Boolean
Private Declare Function GetDesktopWindow Lib "USER32" () As Long
Private Declare Function ShellExecute Lib "shell32" Alias "ShellExecuteA" (ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
' Run a given command and return stdout as a string.
Public Function RunCmdToOutput(ByVal Cmd As String, Optional ByRef ErrStr As String = "", Optional ByVal AsAdmin As Boolean = False) As String
On Error GoTo RunError
Dim A As String, B As String, C As String
Dim tLen As Long, Iter As Long
A = TempFile
B = TempFile
If Not AsAdmin Then
ShellAndWait "cmd /c " & Cmd & " 1> " & A & " 2> " & B, enSW_HIDE
Else
C = TempFile(, , ".bat")
WriteFile C, Cmd & " 1> " & A & " 2> " & B, True
RunFileAsAdmin C, , enSW_HIDE
End If
Iter = 0
Const MaxIter As Long = 10
Do While True
tLen = FileLen(A)
Sleep 800
If Iter > MaxIter Or FileLen(A) = tLen Then Exit Do
Iter = Iter + 1
Loop
RunCmdToOutput = ReadEntireFileAndDelete(A)
If Iter > MaxIter Then RunCmdToOutput = RunCmdToOutput & vbCrLf2 & "<<< OUTPUT TRUNCATED >>>"
ErrStr = ReadEntireFileAndDelete(B)
DeleteFileIfExists C
Exit Function
RunError:
RunCmdToOutput = ""
ErrStr = "ShellOut.RunCmdToOutput: Command Execution Error - [" & Err.Number & "] " & Err.Description
End Function
' to allow for Shell.
' This routine shells out to another application and waits for it to exit.
Public Sub ShellAndWait(ByVal AppToRun As String, Optional ByVal SW As enSW = enSW_NORMAL)
Dim NameOfProc As PROCESS_INFORMATION
Dim NameStart As STARTUPINFO
Dim RC As Long
On Error GoTo ErrorRoutineErr
NameStart.Cb = Len(NameStart)
If SW = enSW_HIDE Then
RC = CreateProcessA(0&, AppToRun, 0&, 0&, CLng(SW), CREATE_NO_WINDOW, 0&, 0&, NameStart, NameOfProc)
Else
RC = CreateProcessA(0&, AppToRun, 0&, 0&, CLng(SW), NORMAL_PRIORITY_CLASS, 0&, 0&, NameStart, NameOfProc)
End If
LastProcessID = NameOfProc.dwProcessId
RC = WaitForSingleObject(NameOfProc.hProcess, INFINITE)
RC = CloseHandle(NameOfProc.hProcess)
ErrorRoutineResume:
Exit Sub
ErrorRoutineErr:
MsgBox "AppShell.Form1.ShellAndWait [" & Err.Number & "]: " & Err.Description
Resume Next
End Sub
' Generic temporary file. Clean up is your responsibility. Various configs available.
Public Function TempFile(Optional ByVal UseFolder As String = "", Optional ByVal UsePrefix As String = "tmp_", Optional ByVal Extension As String = ".tmp", Optional ByVal TestWrite As Boolean = True) As String
Dim FN As String, Res As String
If UseFolder <> "" And Not DirExists(UseFolder) Then UseFolder = ""
If UseFolder = "" Then UseFolder = App.Path & DIRSEP
If Right(UseFolder, 1) <> DIRSEP Then UseFolder = UseFolder & DIRSEP
FN = Replace(UsePrefix & CDbl(Now) & "_" & App.ThreadID & "_" & Random(999999), ".", "_")
Do While FileExists(UseFolder & FN & ".tmp")
FN = FN & Chr(Random(25) + Asc("a"))
Loop
TempFile = UseFolder & FN & Extension
If TestWrite Then
On Error GoTo TestWriteFailed
WriteFile TempFile, "TEST", True, True
On Error GoTo TestReadFailed
Res = ReadFile(TempFile)
If Res <> "TEST" Then MsgBox "Test write to temp file " & TempFile & " failed." & vbCrLf & "Result (Len=" & Len(Res) & "):" & vbCrLf & Res, vbCritical
On Error GoTo TestClearFailed
Kill TempFile
End If
Exit Function
TestWriteFailed:
MsgBox "Failed to write temp file " & TempFile & "." & vbCrLf & Err.Description, vbCritical
Exit Function
TestReadFailed:
MsgBox "Failed to read temp file " & TempFile & "." & vbCrLf & Err.Description, vbCritical
Exit Function
TestClearFailed:
If Err.Number = 53 Then
Err.Clear
Resume Next
End If
'BFH20160627
' Jerry wanted this commented out. Absolutely horrible idea.
' If IsDevelopment Then
MsgBox "Failed to clear temp file " & TempFile & "." & vbCrLf & Err.Description, vbCritical
' End If
Exit Function
End Function
' run as admin
Public Sub RunShellExecuteAdmin(ByVal App As String, Optional ByVal nHwnd As Long = 0, Optional ByVal WindowState As Long = SW_SHOWNORMAL)
If nHwnd = 0 Then nHwnd = GetDesktopWindow()
LastProcessID = ShellExecute(nHwnd, "runas", App, vbNullString, vbNullString, WindowState)
' ShellExecute nHwnd, "runas", App, Command & " /admin", vbNullString, SW_SHOWNORMAL
End Sub
' Run as admin 2
Public Function RunFileAsAdmin(ByVal App As String, Optional ByVal nHwnd As Long = 0, Optional ByVal WindowState As Long = SW_SHOWNORMAL) As Boolean
' If Not IsWinXP Then
RunShellExecuteAdmin App, nHwnd, WindowState
' Else
' ShellOut App
' End If
RunFileAsAdmin = True
End Function