Advertisement
Guest User

Capture output value shell command in VBA

a guest
Dec 21st, 2023
164
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
VB.NET 14.46 KB | None | 0 0
  1. Option Explicit
  2.  
  3. 'Constants
  4. Private Const WAIT_INFINITE         As Long = (-1&)
  5. Private Const STARTF_USESHOWWINDOW  As Long = &H1
  6. Private Const STARTF_USESTDHANDLES  As Long = &H100
  7. Private Const SW_HIDE               As Integer = 0& '?  LONG
  8.  
  9. #If Win64 Then
  10.     'For 64 bit Excel.
  11.     'Contains the security descriptor for an object and specifies whether the handle retrieved by specifying this structure is inheritable.
  12.     Private Type SECURITY_ATTRIBUTES
  13.         nLength                 As Long
  14.         lpSecurityDescriptor    As LongPtr
  15.         bInheritHandle          As Long
  16.     End Type
  17.        
  18.     'Specifies the window station, desktop, standard handles, and appearance of the main window for a process at creation time.
  19.     Private Type STARTUPINFO
  20.         cb                      As Long
  21.         lpReserved              As String
  22.         lpDesktop               As String
  23.         lpTitle                 As String
  24.         dwX                     As Long
  25.         dwY                     As Long
  26.         dwXSize                 As Long
  27.         dwYSize                 As Long
  28.         dwXCountChars           As Long
  29.         dwYCountChars           As Long
  30.         dwFillAttribute         As Long
  31.         dwFlags                 As Long
  32.         wShowWindow             As Integer
  33.         cbReserved2             As Integer
  34.         lpReserved2             As Byte
  35.         hStdInput               As LongPtr
  36.         hStdOutput              As LongPtr
  37.         hStdError               As LongPtr
  38.     End Type
  39.        
  40.        
  41.     'Contains information about a newly created process and its primary thread.
  42.     Private Type PROCESS_INFORMATION
  43.         hProcess        As LongPtr
  44.         hThread         As LongPtr
  45.         dwProcessId     As Long
  46.         dwThreadId      As Long
  47.     End Type
  48.        
  49.    
  50.    
  51.    
  52.    
  53.     'Creates a new process and its primary thread. The new process runs in the security context of the calling process.
  54.     Private Declare PtrSafe Function CreateProcess Lib "kernel32" Alias "CreateProcessA" (ByVal lpApplicationName As String, _
  55.                                                                                             ByVal lpCommandLine As String, _
  56.                                                                                             lpProcessAttributes As Any, _
  57.                                                                                             lpThreadAttributes As Any, _
  58.                                                                                             ByVal bInheritHandles As Long, _
  59.                                                                                             ByVal dwCreationFlags As Long, _
  60.                                                                                             lpEnvironment As Any, _
  61.                                                                                             ByVal lpCurrentDriectory As String, _
  62.                                                                                             lpStartupInfo As STARTUPINFO, _
  63.                                                                                             lpProcessInformation As PROCESS_INFORMATION) As Long
  64.    
  65.     'Creates an anonymous pipe, and returns handles to the read and write ends of the pipe.
  66.     Private Declare PtrSafe Function CreatePipe Lib "kernel32" (phReadPipe As LongPtr, _
  67.                                                                 phWritePipe As LongPtr, _
  68.                                                                 lpPipeAttributes As Any, _
  69.                                                                 ByVal nSize As Long) As Long
  70.    
  71.     'Reads data from the specified file or input/output (I/O) device. Reads occur at the position specified by the file pointer if supported by the device.
  72.     Private Declare PtrSafe Function ReadFile Lib "kernel32" (ByVal hFile As LongPtr, _
  73.                                                              lpBuffer As Any, _
  74.                                                              ByVal nNumberOfBytesToRead As Long, _
  75.                                                              lpNumberOfBytesRead As Long, _
  76.                                                              lpOverlapped As Any) As Long
  77.    
  78.     'Closes an open object handle.
  79.     Private Declare PtrSafe Function CloseHandle Lib "kernel32" (ByVal hObject As LongPtr) As Long
  80.    
  81.     'Waitingfor a single object to terminite
  82.     Private Declare PtrSafe Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As LongPtr, ByVal dwMilliseconds As Long) As Long
  83.    
  84.     'Get process running result.
  85.     Private Declare PtrSafe Function GetExitCodeProcess Lib "kernel32" (ByVal hProcess As LongPtr, lpExitCode As Long) As Long
  86.    
  87.     'I don't know what this for.vRetrieves the contents of the STARTUPINFO structure that was specified when the calling process was created. Not called
  88.     'Private Declare PtrSafe Sub GetStartupInfo Lib "kernel32" Alias "GetStartupInfoA" (ByVal lpStartupInfo As LongPtr)
  89.    
  90.     'Get file size
  91.     Private Declare PtrSafe Function GetFileSize Lib "kernel32" (ByVal hFile As LongPtr, lpFileSizeHigh As Long) As Long
  92. #Else
  93.     'For 32 bit Excel.
  94.     'Contains the security descriptor for an object and specifies whether the handle retrieved by specifying this structure is inheritable.
  95.     Private Type SECURITY_ATTRIBUTES
  96.         nLength                 As Long
  97.         lpSecurityDescriptor    As Long
  98.         bInheritHandle          As Long
  99.     End Type
  100.        
  101.     'Specifies the window station, desktop, standard handles, and appearance of the main window for a process at creation time.
  102.     Private Type STARTUPINFO
  103.         cb                      As Long
  104.         lpReserved              As String
  105.         lpDesktop               As String
  106.         lpTitle                 As String
  107.         dwX                     As Long
  108.         dwY                     As Long
  109.         dwXSize                 As Long
  110.         dwYSize                 As Long
  111.         dwXCountChars           As Long
  112.         dwYCountChars           As Long
  113.         dwFillAttribute         As Long
  114.         dwFlags                 As Long
  115.         wShowWindow             As Integer
  116.         cbReserved2             As Integer
  117.         lpReserved2             As Byte
  118.         hStdInput               As Long
  119.         hStdOutput              As Long
  120.         hStdError               As Long
  121.     End Type
  122.        
  123.        
  124.     'Contains information about a newly created process and its primary thread.
  125.     Private Type PROCESS_INFORMATION
  126.         hProcess        As Long
  127.         hThread         As Long
  128.         dwProcessId     As Long
  129.         dwThreadId      As Long
  130.     End Type
  131.        
  132.    
  133.    
  134.    
  135.    
  136.     'Creates a new process and its primary thread. The new process runs in the security context of the calling process.
  137.     Private Declare PtrSafe Function CreateProcess Lib "kernel32" Alias "CreateProcessA" (ByVal lpApplicationName As String, _
  138.                                                                                             ByVal lpCommandLine As String, _
  139.                                                                                             lpProcessAttributes As Any, _
  140.                                                                                             lpThreadAttributes As Any, _
  141.                                                                                             ByVal bInheritHandles As Long, _
  142.                                                                                             ByVal dwCreationFlags As Long, _
  143.                                                                                             lpEnvironment As Any, _
  144.                                                                                             ByVal lpCurrentDriectory As String, _
  145.                                                                                             lpStartupInfo As STARTUPINFO, _
  146.                                                                                             lpProcessInformation As PROCESS_INFORMATION) As Long
  147.    
  148.     'Creates an anonymous pipe, and returns handles to the read and write ends of the pipe.
  149.     Private Declare PtrSafe Function CreatePipe Lib "kernel32" (phReadPipe As Long, _
  150.                                                                 phWritePipe As Long, _
  151.                                                                 lpPipeAttributes As Any, _
  152.                                                                 ByVal nSize As Long) As Long
  153.    
  154.     'Reads data from the specified file or input/output (I/O) device. Reads occur at the position specified by the file pointer if supported by the device.
  155.     Private Declare PtrSafe Function ReadFile Lib "kernel32" (ByVal hFile As Long, _
  156.                                                              lpBuffer As Any, _
  157.                                                              ByVal nNumberOfBytesToRead As Long, _
  158.                                                              lpNumberOfBytesRead As Long, _
  159.                                                              lpOverlapped As Any) As Long
  160.    
  161.     'Closes an open object handle.
  162.     Private Declare PtrSafe Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
  163.    
  164.     'Waitingfor a single object to terminite
  165.     Private Declare PtrSafe Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, _
  166.                                                                             ByVal dwMilliseconds As Long) As Long
  167.    
  168.     'Get process running result.
  169.     Private Declare PtrSafe Function GetExitCodeProcess Lib "kernel32" (ByVal hProcess As Long, _
  170.                                                                             lpExitCode As Long) As Long
  171.    
  172.     'I don't know what this for.vRetrieves the contents of the STARTUPINFO structure that was specified when the calling process was created. Not called
  173.     'Private Declare PtrSafe Sub GetStartupInfo Lib "kernel32" Alias "GetStartupInfoA" (ByVal lpStartupInfo As Long)
  174.    
  175.     'Get file size
  176.     Private Declare PtrSafe Function GetFileSize Lib "kernel32" (ByVal hFile As Long, _
  177.                                                                     lpFileSizeHigh As Long) As Long
  178. #End If
  179.  
  180. Public Function RunDosCmd2(szBinaryPath As String, szCommandLn As String) As String
  181.  
  182. 'Declaring the necessary variables (different for 32 or 64 bit Excel).
  183. #If Win64 Then
  184.     Dim hRead                       As LongPtr
  185.     Dim hWrite                      As LongPtr
  186. #Else
  187.     Dim hRead                       As Long
  188.     Dim hWrite                      As Long
  189. #End If
  190.  
  191. Dim tSA_CreatePipe              As SECURITY_ATTRIBUTES
  192. Dim tSA_CreateProcessPrc        As SECURITY_ATTRIBUTES
  193. Dim tSA_CreateProcessThrd       As SECURITY_ATTRIBUTES
  194. Dim tSA_CreateProcessPrcInfo    As PROCESS_INFORMATION
  195. Dim tStartupInfo                As STARTUPINFO
  196. Dim bRead                       As Long
  197. Dim abytBuff()                  As Byte
  198. Dim lngResult                   As Long
  199. Dim szFullCommand               As String
  200. Dim lngExitCode                 As Long
  201. Dim lngSizeOf                   As Long
  202. Dim Result                      As String
  203.  
  204. 'Set the pipe security attributes.
  205. tSA_CreatePipe.nLength = Len(tSA_CreatePipe)
  206. tSA_CreatePipe.lpSecurityDescriptor = 0&
  207. tSA_CreatePipe.bInheritHandle = True
  208.  
  209. 'Set the process and thread security attributes
  210. tSA_CreateProcessPrc.nLength = Len(tSA_CreateProcessPrc)
  211. tSA_CreateProcessThrd.nLength = Len(tSA_CreateProcessThrd)
  212.  
  213. 'Create the pipe.
  214. If (CreatePipe(hRead, hWrite, tSA_CreatePipe, 0&) <> 0&) Then
  215.  
  216.     'Set the startup information.
  217.     With tStartupInfo
  218.         .cb = LenB(tStartupInfo)    'lenb? why not len, string may contain multibyte characters?
  219.         .hStdOutput = hWrite
  220.         .hStdError = hWrite
  221.         .dwFlags = STARTF_USESHOWWINDOW Or STARTF_USESTDHANDLES 'The CreateProcess function wShowWindow member contains additional information. The hStdInput, hStdOutput, and hStdError members contain additional information.
  222.         .wShowWindow = SW_HIDE  'Do not show windows
  223.         '.lpReserved = vbNullString  'Reserved; must be NULL.
  224.         '.cbReserved2 = 0    'Reserved for use by the C Run-time; must be zero.
  225.         '.lpReserved2 = 0&   'Reserved for use by the C Run-time; must be NULL. https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfoa
  226.     End With
  227.  
  228.     'Make the full command string using binary path and parameters, binary path can also include parameters(means parameters can be intergred into binarypath)
  229.     szFullCommand = """" & szBinaryPath & """" & " " & szCommandLn
  230.    
  231.     'Create the process and run the console application.
  232.     lngResult = CreateProcess(vbNullString, szFullCommand, tSA_CreateProcessPrc, tSA_CreateProcessThrd, 1, 0&, ByVal 0&, vbNullString, tStartupInfo, tSA_CreateProcessPrcInfo)
  233.     If (lngResult <> 0&) Then   'If create proess sucess
  234.    
  235.         'Wainting for the process to end for infinite time.
  236.         lngResult = WaitForSingleObject(tSA_CreateProcessPrcInfo.hProcess, WAIT_INFINITE)
  237.        
  238.         'Get command line output file size (in memeory).
  239.         lngSizeOf = GetFileSize(hRead, 0&)
  240.         If (lngSizeOf > 0) Then
  241.             ReDim abytBuff(lngSizeOf - 1)
  242.            
  243.             'Retrieve output from pipe.
  244.             If ReadFile(hRead, abytBuff(0), UBound(abytBuff) + 1, bRead, ByVal 0&) Then
  245.                 If bRead > 0 Then
  246.                     ReDim Preserve abytBuff(bRead - 1)
  247.                     Result = StrConv(abytBuff, vbUnicode)
  248.                 End If
  249.             End If
  250.         End If
  251.        
  252.         'Get process exit code, if exitcode=0, means suceed without error
  253.         Call GetExitCodeProcess(tSA_CreateProcessPrcInfo.hProcess, lngExitCode)
  254.        
  255.         'Close handle to the thread
  256.         CloseHandle tSA_CreateProcessPrcInfo.hThread
  257.        
  258.         'Close handle to the process
  259.         CloseHandle tSA_CreateProcessPrcInfo.hProcess
  260.                
  261.         'If process ended with error number
  262.         If (lngExitCode <> 0&) Then Err.Raise vbObject + 1235&, "GetExitCodeProcess", "Non-zero Application exist code"
  263.        
  264.         'Close pipe handles
  265.         CloseHandle hWrite
  266.         CloseHandle hRead
  267.        
  268.     'If create process failed
  269.     Else
  270.         Err.Raise vbObject + 1236&, "CreateProcess", "CreateProcess Failed, Code: " & Err.LastDllError
  271.     End If
  272. End If
  273.  
  274. 'Return the output.
  275. RunDosCmd2 = Result
  276.  
  277. End Function
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement