Process.Start and Console Window Issue

S

Stephany Young

When one uses the System.Diagnostics.Process.Start method to launch a common
or garden Console application, one can set the WindowStyle property of the
StartInfo object to ProcessWindowStyle.Hidden so that the window for the
Console application is not visible.

However, when using some of the 'advanced' properties of the StartInfo
object, like Username, Password and Domain, the WindowsStyle property of the
StartInfo object is ignored. (This is because the Process.Start method makes
a call to CreateProcess (or one of it's variants) intead of the 'normal'
call to ShellExecuteEx.)

Unfortunately this results in the Console application window being shown
which looks ugly.

The effect of this can be somewhat mitigated by making the window of the
calling application 'TopMost' for the life of the Console application which,
at least, makes the Console application window appear behind the window of
the calling application.

Has anyone who has encountered this 'issue' managed to find a way to 'hide'
the Console application window under this scenario?
 
R

rowe_newsgroups

When one uses the System.Diagnostics.Process.Start method to launch a common
or garden Console application, one can set the WindowStyle property of the
StartInfo object to ProcessWindowStyle.Hidden so that the window for the
Console application is not visible.

However, when using some of the 'advanced' properties of the StartInfo
object, like Username, Password and Domain, the WindowsStyle property of the
StartInfo object is ignored. (This is because the Process.Start method makes
a call to CreateProcess (or one of it's variants) intead of the 'normal'
call to ShellExecuteEx.)

Unfortunately this results in the Console application window being shown
which looks ugly.

The effect of this can be somewhat mitigated by making the window of the
calling application 'TopMost' for the life of the Console application which,
at least, makes the Console application window appear behind the window of
the calling application.

Has anyone who has encountered this 'issue' managed to find a way to 'hide'
the Console application window under this scenario?


This probably isn't perfect, but with your abilities you should be
able to adapt it to fit your needs.

This is the code for a form with one button named Button1 - it uses
the FindWindow and ShowWindow APIs:

Public Class Form1

Private Sub Form1_Load(ByVal sender As Object, ByVal e As
System.EventArgs) Handles Me.Load
Process.Start("C:\ConsoleApplication1.exe")
End Sub

<System.Runtime.InteropServices.DllImport("user32")> _
Public Shared Sub ShowWindow(ByVal hWnd As IntPtr, ByVal nCmdShow
As Int32)
End Sub

<System.Runtime.InteropServices.DllImport("user32")> _
Public Shared Function FindWindow(ByVal lpClassName As String,
ByVal lpWindowname As String) As IntPtr
End Function

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e
As System.EventArgs) Handles Button1.Click
Dim hWnd As IntPtr = FindWindow(Nothing, "C:
\ConsoleApplication1.exe")
ShowWindow(hWnd, 0)
End Sub

End Class

I hope this helps you out!

Thanks,

Seth Rowe
 
S

Stephany Young

Thanks for that Seth.

The console application is question is one that is short lived, takes
command line arguments and doesn't 'do' interactive input/output.

A call to ShowWindow fails because the console application window has been
and gone before the code in the calling application can deal with it.

It is the console application window appearing and disappearing that makes
it look ugly.
 
R

rowe_newsgroups

Thanks for that Seth.

The console application is question is one that is short lived, takes
command line arguments and doesn't 'do' interactive input/output.

A call to ShowWindow fails because the console application window has been
and gone before the code in the calling application can deal with it.

It is the console application window appearing and disappearing that makes
it look ugly.

Sorry it didn't help.

Can you rewrite the console application or does the "hide" code have
to be in the calling program?

Thanks,

Seth Rowe
 
S

Stephany Young

Rewriting the console application is not an option. It is actually
RegAsm.exe.

Without going into the why's and wherefore's, I need an ordinary user to be
able to unregister a .NET assembly that exposes COM objects and to register
a new version.

The customer's security policy does not allow an ordinary user to have any
more than read access to HKEY_CLASSES_ROOT otherwise it would not be an
issue.

The pertinent code can happily launch RegAsm.exe with the necessary
credentials so the the unregister/register can occur but each 'launch' of
RegAsm.exe results in the ugly console window appearing and disappearing as
I described earlier.

The functionality is NOT an issue. The issue is purely from the visual
asthetics angle.
 
B

Branco Medeiros

Stephany said:
When one uses the System.Diagnostics.Process.Start method to launch a common
or garden Console application, one can set the WindowStyle property of the
StartInfo object to ProcessWindowStyle.Hidden so that the window for the
Console application is not visible.

However, when using some of the 'advanced' properties of the StartInfo
object, like Username, Password and Domain, the WindowsStyle property of the
StartInfo object is ignored. (This is because the Process.Start method makes
a call to CreateProcess (or one of it's variants) intead of the 'normal'
call to ShellExecuteEx.)
Has anyone who has encountered this 'issue' managed to find a way to 'hide'
the Console application window under this scenario?

Since you can't control the console app, maybe you can launch a second
instance of your own app with the necessary credentials and this
second instance in turn launches the console app -- without the need
to specify username and password, since the credentials would be
already in place (or so I guess):

<aircode>
Private STR_CMDLINE = "/launch"

Sub LaunchApp(Application As String, _
Args As String, _
Optional ByVal Login As String = Nothing, _
Optional ByVal Pwd As SecureString = Nothing)

Dim Info As New ProcessStartInfo

If Login IsNot Nothing Then
'Relaunches itself with special cmdline
Info.FileName = Application.ExecutablePath
Info.Arguments = String.Format("{0} {1} {2}", _
STR_CMDLINE, Application, Args)
Info.UserName = Login
Info.Password = Pwd
Info.UseShellExecute = False

Else
'Launches the desired application
Info.FileName = Application
Info.Arguments = Args
Info.WindowStyle = ProcessWindowStyle.Hidden
End If

Dim P As Process = Process.Start(Info)
P.WaitForExit(MAX_WAIT)
End Sub

Sub MainForm_Load(...) Handles MainForm.Load

With My.Application.CommandLineArgs

'Verifies if called with special cmdline arg
'and if so, hides the main window and launches
'the specified app

If .Count > 0 AndAlso _
.Item(0) = STR_CMDLINE Then
Me.Visible = False
Dim App As String = .Item(1)
Dim S As New System.Text.StringBuilder
For Index As Integer = 2 to .Count-1
S.Append(.Item(Index))
S.Append(" "c)
Next
LaunchApp(App, S.ToString)
Close
Return
End If
End With

'... continue with default loading
End Sub
</aircode>

HTH.

Regards,

Branco.
 
S

Stephany Young

Thanks for your input Branco.

I've tried that and unfortunately it doesn't work, (although one might
reasonably have an expectation that it should).

The executable launched with the Process.Start method runs in the security
of the logged in user even if the piece of code that launched it is elevated
by way of impersonation or other means.
 
P

Patrice

Never tried but another option could be to look around :
http://msdn2.microsoft.com/en-us/li...es.registrationservices.registerassembly.aspx

The idea is that most of .NET utilities are not created from scratch but are
using actually .NET framework classes to implement their functionality...

Also I remember to have seen something about no touch COM registration.
Don't know if it could apply also to registering .NET assemblies or if it is
devoted to "true" COM classes.

Also it could be perpaps possible to consider some alternative such as
perhaps registering once for all a .NET "proxy" that will load in turn the
appropriate version making useless to unregister/reregister different .NET
assemblies.

You could also perhaps impersonate in code so that ProcessStart retains your
options....
 
G

Guest

The StartInfo settings shown below are what I use in all cases where I want
to run and exe with an invisible console window and with the ability to read
the exe's stdout. No guarantees, but I suggest you try a couple of
experiments that do what is shown below combined with what you need to do to
run regasm. I have used this logic successfully with ipconfig.exe and
msinfo32.exe. The code is FW 1.1. Good luck.

Dim p As New Process
With p.StartInfo
.FileName = ExeFileName
.Arguments = Arguments
.UseShellExecute = False
.RedirectStandardError = True
.RedirectStandardInput = True
.RedirectStandardOutput = True
.WindowStyle = ProcessWindowStyle.Hidden
.CreateNoWindow = True
End With
 
C

Chris Dunaway

When one uses the System.Diagnostics.Process.Start method to launch a common
or garden Console application, one can set the WindowStyle property of the
StartInfo object to ProcessWindowStyle.Hidden so that the window for the
Console application is not visible.

However, when using some of the 'advanced' properties of the StartInfo
object, like Username, Password and Domain, the WindowsStyle property of the
StartInfo object is ignored. (This is because the Process.Start method makes
a call to CreateProcess (or one of it's variants) intead of the 'normal'
call to ShellExecuteEx.)

Unfortunately this results in the Console application window being shown
which looks ugly.

The effect of this can be somewhat mitigated by making the window of the
calling application 'TopMost' for the life of the Console application which,
at least, makes the Console application window appear behind the window of
the calling application.

Has anyone who has encountered this 'issue' managed to find a way to 'hide'
the Console application window under this scenario?

I don't know if this will help, but I have used the following class to
impersonate a user so perhaps you could use impersonation and then
call the command line app without passing the credentials to the
ProcessStartInfo object.

Chris


'*** BEGIN CODE
/// <summary>
/// Impersonate a windows logon.
/// </summary>
public class ImpersonationUtil {

/// <summary>
/// Impersonate given logon information.
/// </summary>
/// <param name="logon">Windows logon name.</param>
/// <param name="password">password</param>
/// <param name="domain">domain name</param>
/// <returns></returns>
public static bool Impersonate( string logon, string password,
string domain ) {
WindowsIdentity tempWindowsIdentity;
IntPtr token = IntPtr.Zero;
IntPtr tokenDuplicate = IntPtr.Zero;

if( LogonUser( logon, domain, password, LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT, ref token) != 0 ) {

if ( DuplicateToken( token, 2, ref tokenDuplicate ) != 0 ) {
tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
impersonationContext = tempWindowsIdentity.Impersonate();
if ( null != impersonationContext ) return true;
}
}

return false;
}

/// <summary>
/// Unimpersonate.
/// </summary>
public static void UnImpersonate() {
impersonationContext.Undo();
}

[DllImport("advapi32.dll", CharSet=CharSet.Auto)]
public static extern int LogonUser(
string lpszUserName,
String lpszDomain,
String lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken );

[DllImport("advapi32.dll",
CharSet=System.Runtime.InteropServices.CharSet.Auto,
SetLastError=true)]
public extern static int DuplicateToken(
IntPtr hToken,
int impersonationLevel,
ref IntPtr hNewToken );

private const int LOGON32_LOGON_INTERACTIVE = 2;
private const int LOGON32_LOGON_NETWORK_CLEARTEXT = 4;
private const int LOGON32_PROVIDER_DEFAULT = 0;
private static WindowsImpersonationContext impersonationContext;
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top