For Programmers: Free Programming Magazines  


Home > Archive > Visual Basic Syntax > March 2006 > Silly Shell() question









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author Silly Shell() question
Tony Proctor

2006-03-15, 7:01 pm

I'm banging my head against a wall here. I'm trying to get the Shell()
function to execute a particular command-line, and failing. The command line
is:

CMD /C "path\tool.exe" param 1>stdout.tmp 2>stderr.tmp

I need the CMD /C to enable the I/O redirection, and I need the quotes
because the tool path contains spaces. However, with the extra quotes I get
nothing at all. The tool doesn't even get invoked. If I leave off the quotes
then I get an error recorded in stderr.tmp because it's just trying to
execute a partial path (up to the 1st space). I've also tried putting an
outer set of quotes around the quoted tool path and its parameter, but
nothing seems to work.

For a tool path with no spaces, I can leave off the quotes and it works as
expected.

Anyone have a solution to this?

Tony Proctor


Tony Proctor

2006-03-15, 7:01 pm

OK, I think I cracked this already, but the rules are a bit bizarre
(definitely one for the archives)

Let's assume the worse case where the paths of the tool and both the output
files contain spaces, and so all need to be quoted. The naive command line
would then be:

CMD /C "path\tool.exe" param 1>"stdout.tmp" 2>"stderr.tmp"

For this to work, though, it needs an outer set of quotes around the whole
string specified for the /C option, i.e.

CMD /C ""path\tool.exe" param 1>"stdout.tmp" 2>"stderr.tmp""

The interesting thing here is that the now-embedded quotes don't need
pairing up.

Obviously, if this were stored in a VB String constant then *all* these
quotes would be paired up:

CMD /C """"path\tool.exe"" param 1>""stdout.tmp""
2>""stderr.tmp"""

It seems the problem (and the only bit that didn't make any sense) is that
the enclosing quotes around the whole '/C argument' doesn't require embedded
quotes to be paired up as they would in most other string situations.

....hope someone else finds this useful

Tony Proctor

"Tony Proctor" <tony_proctor@aimtechnology_NoMoreSPAM_.com> wrote in message
news:uS84poFSGHA.1728@TK2MSFTNGP11.phx.gbl...
> I'm banging my head against a wall here. I'm trying to get the Shell()
> function to execute a particular command-line, and failing. The command

line
> is:
>
> CMD /C "path\tool.exe" param 1>stdout.tmp 2>stderr.tmp
>
> I need the CMD /C to enable the I/O redirection, and I need the quotes
> because the tool path contains spaces. However, with the extra quotes I

get
> nothing at all. The tool doesn't even get invoked. If I leave off the

quotes
> then I get an error recorded in stderr.tmp because it's just trying to
> execute a partial path (up to the 1st space). I've also tried putting an
> outer set of quotes around the quoted tool path and its parameter, but
> nothing seems to work.
>
> For a tool path with no spaces, I can leave off the quotes and it works as
> expected.
>
> Anyone have a solution to this?
>
> Tony Proctor
>
>



Ken Halter

2006-03-15, 7:01 pm

"Tony Proctor" <tony_proctor@aimtechnology_NoMoreSPAM_.com> wrote in message
news:uS84poFSGHA.1728@TK2MSFTNGP11.phx.gbl...
> I'm banging my head against a wall here. I'm trying to get the Shell()
> function to execute a particular command-line, and failing. The command
> line
> is:
>
> CMD /C "path\tool.exe" param 1>stdout.tmp 2>stderr.tmp


You've already tried the obvious quote 'doubling' "trick"?

Dim sShellCMD As String
sShellCMD = "CMD /C ""path\tool.exe"" param 1>stdout.tmp 2>stderr.tmp"
Debug.Print sShellCMD 'shows CMD /C "path\tool.exe" param 1>stdout.tmp
2>stderr.tmp

Shell sShellCMD

I don't have any console'ish apps I can test this on.

--
Ken Halter - MS-MVP-VB - Please keep all discussions in the groups..
DLL Hell problems? Try ComGuard - http://www.vbsight.com/ComGuard.htm


Ken Halter

2006-03-15, 7:01 pm

"Tony Proctor" <tony_proctor@aimtechnology_NoMoreSPAM_.com> wrote in message
news:uS84poFSGHA.1728@TK2MSFTNGP11.phx.gbl...
> I'm banging my head against a wall here. I'm trying to get the Shell()
> function to execute a particular command-line, and failing. The command
> line
> is:
>


Ignore my previous answer. After re-reading, I see you've already tried
that. hmmmm

--
Ken Halter - MS-MVP-VB - Please keep all discussions in the groups..
DLL Hell problems? Try ComGuard - http://www.vbsight.com/ComGuard.htm


Rick Rothstein [MVP - Visual Basic]

2006-03-15, 7:01 pm

> I'm banging my head against a wall here. I'm trying to get the Shell()
> function to execute a particular command-line, and failing. The command

line
> is:
>
> CMD /C "path\tool.exe" param 1>stdout.tmp 2>stderr.tmp
>
> I need the CMD /C to enable the I/O redirection, and I need the quotes
> because the tool path contains spaces. However, with the extra quotes I

get
> nothing at all. The tool doesn't even get invoked. If I leave off the

quotes
> then I get an error recorded in stderr.tmp because it's just trying to
> execute a partial path (up to the 1st space). I've also tried putting an
> outer set of quotes around the quoted tool path and its parameter, but
> nothing seems to work.
>
> For a tool path with no spaces, I can leave off the quotes and it works as
> expected.


The following is a compilation of several posts I've given in the past
regarding the Shell command.

Rick

You can use the Shell command. To execute internal DOS command (Dir, Copy,
etc. as well as redirection of screen output), the command processor must be
specified (using the Environ$ function and "comspec" as its argument returns
the correct command processor path on NT and non-NT systems) . Specifying
the command processor is safe & generic and will work with non-internal
commands also. That syntax, using an XCopy command as an example is:

Shell Environ$("comspec") & " /c xcopy """ & _
Source & """ """ & Destination & """ " & Option, vbHide

You set the Source and Destination (string variables) to the appropriate
paths and the Option (string variable), if any, which can be found by
opening an MSDOS Prompt window and typing xcopy /?. (Note: You can type /?
after any DOS command at a DOS prompt to list the available options for that
command.) One more example would be to list all the files in a directory
including subdirectories and subdirectories of subdirectories and all of
their files.

CommandLine = "dir """ & FileSpec & _
""" /s/b > """ & RedirectTo & """"
Shell Environ$("comspec") & " /c " & CommandLine, vbHide

Here, the output of a Dir command is redirected to a file-path you specify
in the RedirectTo (string variable). The /s/b are options to the Dir command
that tell it to recurse throught its subdirectories and not to include
header or summary information.

I used a variable for the file name so that I could more easily explain the
benefit of encasing it in quotemarks. If you redirect to a file that has
spaces in its name, or if there are spaces in the path specification itself,
then the filename *must* be quoted to protect the spaces from DOS's desire
to use them as delimiters. (That's what all those quotemarks in the Shell
statement are for.) If the filename doesn't have spaces in it, the quotes
aren't necessary BUT they don't hurt either. Hence, the above will work with
either.

As for your PING question, something like the following should work:

strIP = "4.17.23.1"
Shell Environ$("comspec") & " /c ping " & _
strIP & " > """ & RedirectFile & """", vbHide

Although you didn't specify it in your original post, I assume you want to
use vbHide for the optional 2nd parameter to Shell. This hides the DOS
window so that your user doesn't see it. If you want the DOS window to
remain visible, you would use the vbNormalFocus BUT you must use a /k
instead of a /c for the command processor argument. Basically, the /c tells
the command processor "here comes a command and, when its finished
executing, close the DOS shell it is running in" whereas the /k also tells
the command processor that a command follows, but it instructs it to leave
the DOS session running.

The above assumes you do NOT have to wait for this file to be completely
written before your code continues executing. If you have to work with this
file right after it is created, consider one of these (which makes your
program wait until the DOS process is finished):

MICROSOFT 'S OFFICIAL WAY
========================
See this link

http://support.microsoft.com/suppor...s/Q129/7/96.asp

Note: This method doesn't use Shell -- it uses CreateProcessA.


FAST AND DIRTY METHOD (WORKS ALMOST ALL THE TIME)
========================================
=========
Paste these lines in the (General)(Declarations) section of the form where
the Shell is being called (or remove the Private keywords and put them in a
BAS module if more than one form will use them):

Private Declare Function OpenProcess _
Lib "kernel32" _
(ByVal dwDesiredAccess As Long, _
ByVal bInheritHandle As Long, _
ByVal dwProcessId As Long) As Long
Private Declare Function CloseHandle _
Lib "kernel32" _
(ByVal hObject As Long) As Long
Private Declare Function WaitForSingleObject _
Lib "kernel32" _
(ByVal hHandle As Long, _
ByVal dwMilliseconds As Long) As Long

Call your Shell command in this form with the appropriate Shell arguments
placed in the parentheses:

PID = Shell( <<Put Shell Arguments Here>> )

And finally, paste the following IMMEDIATELY after the PID=Shell statement
above (making sure to handle the possible error where indicated; i.e. stop
the code from falling through to your other commands if the Shell failed):

If PID = 0 Then
'
'Handle Error, Shell Didn't Work
'
Else
hProcess = OpenProcess(&H100000, True, PID)
WaitForSingleObject hProcess, -1
CloseHandle hProcess
End If


Tony Proctor

2006-03-15, 7:01 pm

Thanks Rick but I've already seen that post of yours :-)

I don't think it covers this particular issue though (as explained in my
follow-up post)

Tony Proctor

"Rick Rothstein [MVP - Visual Basic]" <rickNOSPAMnews@NOSPAMcomcast.net>
wrote in message news:eurQcCGSGHA.424@TK2MSFTNGP12.phx.gbl...
> line
> get
> quotes
as[color=darkred]
>
> The following is a compilation of several posts I've given in the past
> regarding the Shell command.
>
> Rick
>
> You can use the Shell command. To execute internal DOS command (Dir, Copy,
> etc. as well as redirection of screen output), the command processor must

be
> specified (using the Environ$ function and "comspec" as its argument

returns
> the correct command processor path on NT and non-NT systems) . Specifying
> the command processor is safe & generic and will work with non-internal
> commands also. That syntax, using an XCopy command as an example is:
>
> Shell Environ$("comspec") & " /c xcopy """ & _
> Source & """ """ & Destination & """ " & Option, vbHide
>
> You set the Source and Destination (string variables) to the appropriate
> paths and the Option (string variable), if any, which can be found by
> opening an MSDOS Prompt window and typing xcopy /?. (Note: You can type /?
> after any DOS command at a DOS prompt to list the available options for

that
> command.) One more example would be to list all the files in a directory
> including subdirectories and subdirectories of subdirectories and all of
> their files.
>
> CommandLine = "dir """ & FileSpec & _
> """ /s/b > """ & RedirectTo & """"
> Shell Environ$("comspec") & " /c " & CommandLine, vbHide
>
> Here, the output of a Dir command is redirected to a file-path you specify
> in the RedirectTo (string variable). The /s/b are options to the Dir

command
> that tell it to recurse throught its subdirectories and not to include
> header or summary information.
>
> I used a variable for the file name so that I could more easily explain

the
> benefit of encasing it in quotemarks. If you redirect to a file that has
> spaces in its name, or if there are spaces in the path specification

itself,
> then the filename *must* be quoted to protect the spaces from DOS's desire
> to use them as delimiters. (That's what all those quotemarks in the Shell
> statement are for.) If the filename doesn't have spaces in it, the quotes
> aren't necessary BUT they don't hurt either. Hence, the above will work

with
> either.
>
> As for your PING question, something like the following should work:
>
> strIP = "4.17.23.1"
> Shell Environ$("comspec") & " /c ping " & _
> strIP & " > """ & RedirectFile & """", vbHide
>
> Although you didn't specify it in your original post, I assume you want to
> use vbHide for the optional 2nd parameter to Shell. This hides the DOS
> window so that your user doesn't see it. If you want the DOS window to
> remain visible, you would use the vbNormalFocus BUT you must use a /k
> instead of a /c for the command processor argument. Basically, the /c

tells
> the command processor "here comes a command and, when its finished
> executing, close the DOS shell it is running in" whereas the /k also tells
> the command processor that a command follows, but it instructs it to leave
> the DOS session running.
>
> The above assumes you do NOT have to wait for this file to be completely
> written before your code continues executing. If you have to work with

this
> file right after it is created, consider one of these (which makes your
> program wait until the DOS process is finished):
>
> MICROSOFT 'S OFFICIAL WAY
> ========================
> See this link
>
> http://support.microsoft.com/suppor...s/Q129/7/96.asp
>
> Note: This method doesn't use Shell -- it uses CreateProcessA.
>
>
> FAST AND DIRTY METHOD (WORKS ALMOST ALL THE TIME)
> ========================================
=========
> Paste these lines in the (General)(Declarations) section of the form where
> the Shell is being called (or remove the Private keywords and put them in

a
> BAS module if more than one form will use them):
>
> Private Declare Function OpenProcess _
> Lib "kernel32" _
> (ByVal dwDesiredAccess As Long, _
> ByVal bInheritHandle As Long, _
> ByVal dwProcessId As Long) As Long
> Private Declare Function CloseHandle _
> Lib "kernel32" _
> (ByVal hObject As Long) As Long
> Private Declare Function WaitForSingleObject _
> Lib "kernel32" _
> (ByVal hHandle As Long, _
> ByVal dwMilliseconds As Long) As Long
>
> Call your Shell command in this form with the appropriate Shell arguments
> placed in the parentheses:
>
> PID = Shell( <<Put Shell Arguments Here>> )
>
> And finally, paste the following IMMEDIATELY after the PID=Shell statement
> above (making sure to handle the possible error where indicated; i.e. stop
> the code from falling through to your other commands if the Shell failed):
>
> If PID = 0 Then
> '
> 'Handle Error, Shell Didn't Work
> '
> Else
> hProcess = OpenProcess(&H100000, True, PID)
> WaitForSingleObject hProcess, -1
> CloseHandle hProcess
> End If
>
>



Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com