3

There is any command line or .NET method that runs a process in the background hiding any window it tries to open?

Already tried:

 var process = new Process()
 {
      StartInfo = new ProcessStartInfo()
      {
          CreateNoWindow = true,
          WindowStyle = ProcessWindowStyle.Hidden,
          FileName = TheRealExecutableFileNameHere
      }
 }
 process.Start();

With no success so far

Jader Dias
  • 88,211
  • 155
  • 421
  • 625
  • Might help telling us what process you're trying to run. – Noldorin Jul 12 '09 at 01:19
  • what, does nothing start or does the window show? If nothing starts, it's because you forgot process.Start()... – Dave Markle Jul 12 '09 at 01:20
  • Yes, do you have a process.Start() call that is part of this? I don't see anywhere where you are assigning the process and command line arguments either. – jjxtra Jul 12 '09 at 01:23
  • @Dave edited for clarification. The window appears, I want it to disappear. – Jader Dias Jul 12 '09 at 01:23
  • @Jeff edited for clarification. I am using it correctly. – Jader Dias Jul 12 '09 at 01:24
  • Hmm. Is the window you're talking about the cmd shell? That would behave differently than an actual windowed application. – Sean Jul 12 '09 at 01:25
  • @Darth the cmd shell is hidden, the application spawns a new window, is that new window I am talking about – Jader Dias Jul 12 '09 at 01:29
  • 2
    Hmm. Well, I just tried that exact code with notepad.exe as the executable, and it worked fine, so it must be an issue with whatever the process is you are trying to run. Maybe it forces its windows to show somehow? – Sean Jul 12 '09 at 01:33
  • @Darth Eru, I think the process is a Console application that spawns a Forms application in another thread, and that's why it always shows the window. – Jader Dias Jul 12 '09 at 01:46
  • @Noldorin The process is matlab.exe -nodisplay -nojvm – Jader Dias Jul 12 '09 at 01:47
  • 1
    @Jader: Is matlab.exe the console application you are attempting to run from .NET that in turn is spawning a windowed process? – Abhijeet Patel Jul 27 '09 at 05:20
  • @Abhijeet Yes, but I abandoned this question approach, since I found a better way to communicate with Matlab – Jader Dias Jul 27 '09 at 11:21

14 Answers14

15

I reviewed my code and it looks nearly identical to yours:

ProcessStartInfo psi = new ProcessStartInfo(fileName, arguments)
{
   CreateNoWindow = true,
   WindowStyle = ProcessWindowStyle.Hidden,
   UseShellExecute = false,
   RedirectStandardOutput = true                                               
};

Process process = Process.Start(psi);

The only notable difference (other than formatting and which PSI constructor we chose) is my use of UseShellExecute and RedirectStandardOutput as I needed to read the result of the ran process.

I have found the code above consistently runs a hidden process on XP and Vista. I have also found, however, and you may be experiencing the same, that a hidden process may kick off another process which by default isn't hidden. In other words, if you start hidden Process A and Process A, in turn, kicks off Process B, you have no control as to how Process B will be displayed. Windows which you have no control over may be displayed.

I hope this helps a little. Good luck.

Ben Griswold
  • 17,793
  • 14
  • 58
  • 60
6

Check out the Matlab Engine.

There's even an interesting article on CodeProject, if this approach fits your needs.

Kenan E. K.
  • 13,955
  • 3
  • 43
  • 48
  • 1
    +1 Besides not answering the title question, it is the best solution for my problem. I should give up doing the wrong way. – Jader Dias Jul 20 '09 at 23:23
  • Other than this, I've seen people use WinAPI FindWindow and SendMessage with CS_MINIMIZE or something like that, in case you really want to try it out. – Kenan E. K. Jul 21 '09 at 00:06
  • 4
    A way to run a process in the background is ... to use a matlab engine. ... I must be missing something. – bohdan_trotsenko Jul 21 '09 at 07:26
  • @modosansreves: Check the entire thread and comments, it boils down to matlab actually in this case. – Kenan E. K. Jul 21 '09 at 09:01
  • @jader dias: unless i'm missing something, shouldn't you be "accepting" this answer, since you find it the best answer so far? – Liao Jul 27 '09 at 06:19
5

Have you tried using the Microsoft DOS start command with the /B switch?

Microsoft DOS start command

For example,

START /B cmd.exe
Mark Good
  • 4,271
  • 2
  • 31
  • 43
  • 3
    More specifically, replace Process.Start(exe, args), with Process.Start("cmd.exe", string.Format("/c start \"notitle\" /B \"{0}\" {1}", exe, args). If you don't want the command window to flash into view then use ProcessStartInfo instead, and set UseShellExecute = false. – yoyo Nov 21 '13 at 01:42
3

There is no I do not know a pure .Net way to achieve this.

Then I thought about kernel Job Objects, but found no similar option in UI restrictions.

So, the next (yet unverified) idea is to create than process suspended, create a windows hook then, which will monitor CallWndProc and filter out WM_SHOW messages. (Then, surely, resume the process, wait in a separate thread till it terminates, remove the hook)

bohdan_trotsenko
  • 5,167
  • 3
  • 43
  • 70
2

You may want to try the BackgroundWorker Class in the .Net Framework if you haven't already. It's for executing long running processes on a separate thread to prevent them from impeding the UI. Give it a look.

CertifiedCrazy
  • 935
  • 5
  • 14
2

I realize this has been answered but you could force a window to hide with unmanaged calls to FindWindow and ShowWindow.

[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

psi = new ProcessStartInfo(); // etc..
some_process = Process.Start(psi);
System.Threading.Thread.Sleep(50); // need give the window a chance to be created
IntPtr hWnd = FindWindow(null, "name of the window");
if (hWnd != IntPtr.Zero) ShowWindow(hWnd, 0); // 0 = SW_HIDE

Rather kludgy.

Mark
  • 106,305
  • 20
  • 172
  • 230
  • +1. I think that's a really simple and effective solution, but I don't need to Sleep(50) since some_process.WaitToEnd() will do. – Jader Dias Jul 27 '09 at 17:13
1

It depends on whether you want to start the application minimized, but allow it to interact with the user if required, or if you want to prohibit all access with the user regardless of what happens.

If the latter, you could run the process under a different desktop context to the current user.

Different Desktop contexts are used, for example, by the Login dialog and by Vista UAC - anything that happens in one desktop context is independent of others.

Might be a sledgehammer approach to your problem though.

Bevan
  • 43,618
  • 10
  • 81
  • 133
  • I want to prohibit all access with the user regardless of what happens. – Jader Dias Jul 12 '09 at 01:24
  • I couldn't find an article about "desktop context in .net", can you help me find it? – Jader Dias Jul 12 '09 at 01:28
  • I was't able to find the exact page that I wanted, but did find a page that talks about some of the standard desktops that are normally present. Start here (http://msdn.microsoft.com/en-us/library/aa375994(VS.85).aspx) and look around, you should find what you need. – Bevan Jul 12 '09 at 10:29
  • I tried to run the process as another user, but it didn't solve the problem – Jader Dias Jul 12 '09 at 22:29
1

I noticed that if CreateNoWindow = false does absolutely nothing when the Filename is pointing to a Windows executable, if you have access to the source code of the winform app then you might be able to provide a command line argument which controls the default visibility of the form, and do something like this in the Winform App startup code:

static void Main(string[] args)
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Form1 form1 = new Form1();

        form1.Load += new EventHandler((s,o) =>
            {
              //check if the form should be shown based on command line arg
                if (args.Contains("dontShowWindow"))
                {
                    //hide it
                    form1.ShowInTaskbar = false;
                    form1.Visible = form1.ShowInTaskbar = false;
                }
            }
        );
        Application.Run(form1);
    }

In you calling code, you can now specify "dontShowWindow" as a process Argument:

 ProcessStartInfo info = new ProcessStartInfo
        {
            CreateNoWindow = false, 
            WindowStyle = ProcessWindowStyle.Hidden,
            UseShellExecute = false, 
            FileName = @"C:\temp\testWinForm.exe",
            Arguments = "dontShowWindow"
        };
        Process.Start(info);

Hope this helps

Abhijeet Patel
  • 6,562
  • 8
  • 50
  • 93
1

One very simply way to achieve this is to create a Service Account and run the executable under the context of the Service Account user via the Windows Task Scheduler.

You could use this CodeProject to setup the scheduled task:

http://www.codeproject.com/KB/cs/tsnewlib.aspx

You could create the service account programatically in the Domain or local machine very easily with C#.

http://www.codeproject.com/KB/system/OSUserMangement.aspx http://support.microsoft.com/kb/306273

Processes running as scheduled tasks in the context of another user do not appear interactively unless that user is logged in; hence the use of a service account.

Keith Adler
  • 20,880
  • 28
  • 119
  • 189
1
public Form1()
    {
        InitializeComponent();
        Form1 fm = new Form1();
        fm.ShowInTaskbar = false;
        fm.Visible = fm.ShowInTaskbar = false;
    }

Works great !

Rage
  • 31
  • 1
  • 6
0

I assume you want a process that is not visible to users while running.

You can try the following to see whether this is what you want.

  1. Create a simple console app that keeps running (and launch it to test).
  2. Right click on Project --> Properties --> Application tab --> Output type --> Change it from "Console Application" to Windows Application.
  3. Launch the same app one more time (to see whether this is what you want).
  4. Close the app via Windows Task Manager :)

It seems that the process appears in Task Manager, yet, is not visible in the task bar. Alt+TAB cannot bring this process up.

I just hope that you are not making any malicious app, though :)

Chansik Im
  • 1,473
  • 8
  • 13
  • Thanks, but it will not work for me, since the application is not a console application. Matlab is not malicious. – Jader Dias Jul 12 '09 at 13:33
0

I think what you might want to try is to create a new Windows Station. Check out this article that explains a bit about them on msdn.

http://msdn.microsoft.com/en-us/library/ms681928(VS.85).aspx

Jeff Yates
  • 61,417
  • 20
  • 137
  • 189
Matt
  • 224
  • 1
  • 5
0

You could make a Windows' service. Any window a service tries to open just runs in session 0, which means no user can see it. That goes for all windows though, so perhaps that's not what you're looking for.

NathanTempelman
  • 1,301
  • 9
  • 34
0

Below code worked for me: Earlier the process (notepad) used to flash the notepad on desktop screen for printing, but it distract the user , so below code hides the notepad process in background.

                System.Windows.Forms.PrintDialog printDialog = new PrintDialog();
                System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo(Application.StartupPath + "/PrintingDocketFile/PrintCustomerOrder.txt");
                psi.Verb = "PRINT";

                //Process.Start(psi);
                //psi.CreateNoWindow = true;
                psi.UseShellExecute = false;
                //---------------------------------------------------

                psi.CreateNoWindow = false;
                psi.UseShellExecute = true;
                psi.FileName = Application.StartupPath + "/PrintingDocketFile/PrintCustomerOrder.txt";
                psi.WindowStyle = ProcessWindowStyle.Hidden;
                psi.Arguments =  @"%windir%\system32\notepad.exe"; 
                //Process.Start(psi);
                //------------------------------------------------------

                /////////////////////----------------------------------

                printProcess.StartInfo = psi;
                /////psi.CreateNoWindow = true;

                //psi.FileName = "Application.StartupPath" + "/PrintingDocketFile/PrintCustomerOrder.txt";
                //p.StartInfo.FileName = "Notepad.EXE";
                //p.StartInfo.Arguments = "/i /q \"" + installationPackages[i] + "\"";

                printProcess.Start();

                /////////////////////////-------------------------------
                while (!printProcess.HasExited) ;


                if (!printProcess.HasExited)
                {
                    printProcess.Close();
                }