Search code examples
vb.nettfstf-cli

TF.exe doesn't prompt for checkin confirmation when executed directly, without using the operating system shell to start the process


I'm using TF.exe command-line for some simple TFS commands such as getting the latest version of the files (tf.exe vc get), checking out some files (tf.exe vc checkout) and then checking them in at the end of use (tf.exe vc checkin).

After some tests I've noticed that when I run the checkin command through Windows Command Prompt (cmd.exe), the prompt window is displayed asking for confirmation before the check-in command is done:

C:\Program Files\Microsoft Visual Studio\2022\Community
  \Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer>
      tf.exe vc checkin "C:\TfsTestProject\test.txt" /comment:"Checked via command-line."

Window displayed asking for checkin confirmation

For my project that was a good thing, displaying the prompt window for check-in confirmation.

However, when I started the TF command through code I found a problem: I have to start the TF.exe process redirecting the standard output, so I can display what's happening when the command is executed, and for that I have to set process.StartInfo.UseShellExecute = False. But when I do that, the prompt window is no longer displayed, as if I was using the /noprompt parameter (and I'm not using it).

So, when I use the code below the prompt window is stil displayed, as in the picture, but I cannot receive the standard output stream feedback:

Dim p = New Process()
' I removed the full path for clarity, but that's:
' "C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer\TF.exe"
p.StartInfo.FileName = "TF.exe"
p.StartInfo.Arguments = $"vc checkin ""{testFilePath}"" /comment:""Checked via code."""
p.StartInfo.UseShellExecute = True
p.StartInfo.CreateNoWindow = True

p.Start()
p.WaitForExit()

But, when I use this other code, the one that I need, the prompt window for check-in confirmation is no longer displayed, even though I'm not using /noprompt parameter:

Dim p = New Process()
' I removed the full path for clarity, but that's:
' "C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer\TF.exe"
p.StartInfo.FileName = "TF.exe"
p.StartInfo.Arguments = $"vc checkin ""{testFilePath}"" /comment:""Checked via code."""
p.StartInfo.UseShellExecute = False   ' <- That's the problem, apparently.
p.StartInfo.RedirectStandardOutput = True
p.StartInfo.CreateNoWindow = True

p.EnableRaisingEvents = True
AddHandler p.OutputDataReceived, Sub(s, e) Console.WriteLine(e.Data)

p.Start()
p.BeginOutputReadLine()
p.WaitForExit()

I couldn't find any information about that behaviour, maybe it's just a bug?


Solution

  • Shame on me, I've done some research before posting the question and found nothing, but, just after posting it I found this:

    c# - How can I capture tf.exe stderr without stopping its dialog prompts? - Stack Overflow

    This problem is old, since that question is from 10 years ago, facing the same "bug". Apparently there is an undocumented parameter /prompt that makes the prompt window to be displayed even though the TF command is not executed through shell.

    So this code (with undocumented /prompt parameter) worked:

    Dim p = New Process()
    ' I removed the full path for clarity, but that's:
    ' "C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer\TF.exe"
    p.StartInfo.FileName = "TF.exe"
    ' With undocumented /prompt parameter the prompt window is
    ' displayed even when the command is not executed through shell.
    p.StartInfo.Arguments = $"vc checkin ""{testFilePath}"" /prompt /comment:""Checked via code."""
    p.StartInfo.UseShellExecute = False
    p.StartInfo.RedirectStandardOutput = True
    p.StartInfo.CreateNoWindow = True
    
    p.EnableRaisingEvents = True
    AddHandler p.OutputDataReceived, Sub(s, e) Console.WriteLine(e.Data)
    
    p.Start()
    p.BeginOutputReadLine()
    p.WaitForExit()
    

    And after that question and answer from long time ago I've tested a little more and found that I was wrong, the problem is not about not starting the command from shell, the problem really happens when the streams (output or error) are redirected. When you just set UseShellExecute = False, without redirecting, the prompt window is still displayed.