2

I have made a C++ code in visual studio, a console application. My question is how to make the final exe run without console ( a process only seen from task manager )

The solutions I have seen till now all make the console appear for a second then go out. I don't want this. Don't appear at all.

is there any option or flag in visual studio to do this? ( something like -mwindows flag in g++ )

Thank's in advance

Mohammed B.
  • 160
  • 1
  • 3
  • 13

1 Answers1

2

In the Project Properties on the Configuration Properties->Linker->System page, you need to set the value of SubSystem to Windows (/SUBSYSTEM:WINDOWS). The default for a new console application project is Console (/SUBSYSTEM:CONSOLE), which causes Windows to allocate a new console or attach to the parent process's console when starting your program.

enter image description here


You also need to change your main function to be WinMain. The signature for `WinMain is:

int CALLBACK WinMain(
  _In_ HINSTANCE hInstance,
  _In_ HINSTANCE hPrevInstance,
  _In_ LPSTR     lpCmdLine,
  _In_ int       nCmdShow)
{
    // Your code here
}

With the above approach, child console processes will still create console windows. Since you stated in a comment that you want to use popen, you can't really easily use the normal way of calling CreateProcess with SW_HIDE.

What you really want to do is to attach a hidden console window to your process and allow your child processes to inherit it. This probably isn't the best code, but here's a way to do it:

// Allocates a hidden console window for this process. This console can be
// inherited by child console processes, preventing them from creating a
// visible console. Returns false if the attempt fails.
bool AllocHiddenConsole()
{
  TCHAR command[] = _T("cmd.exe");
  STARTUPINFO startupInfo{};
  PROCESS_INFORMATION processInfo{};
  startupInfo.cb = sizeof(startupInfo);
  startupInfo.dwFlags = STARTF_USESHOWWINDOW;
  startupInfo.wShowWindow = SW_HIDE;

  if (!CreateProcess(NULL, command, NULL, NULL, FALSE,
    CREATE_NEW_CONSOLE, NULL, NULL, &startupInfo, &processInfo))
  {
    return false;
  }

  bool attached = false;
  for (int i = 0; i < 1000; i++)
  {
    if (AttachConsole(processInfo.dwProcessId))
    {
      attached = true;
      break;
    }
    Sleep(10);
  }

  TerminateProcess(processInfo.hProcess, 0);
  CloseHandle(processInfo.hProcess);
  CloseHandle(processInfo.hThread);

  return attached;
}
Dark Falcon
  • 43,592
  • 5
  • 83
  • 98
  • You need to also mention that main() must become WinMain(). – Hans Passant Aug 10 '18 at 14:08
  • I got WinMain function cannot be overloaded – Mohammed B. Aug 10 '18 at 14:35
  • @HansPassant: Thanks, I forgot that because I usually do this with C# where the signature of `Main` doesn't change between the various application types. – Dark Falcon Aug 10 '18 at 15:26
  • This makes many console windows to appear, blink and disappear. They still appear – Mohammed B. Aug 10 '18 at 15:43
  • Let me guess: Your program starts other programs which are also console applications? That is the only explanation that comes to mind. Without further details on what your program does, I can't determine how to fix it. – Dark Falcon Aug 10 '18 at 16:08
  • You are right, my code internally deals with windows shell (using popen function ). I think there must be a way to do it, it is done easily in python ( the code also uses popen python function ) and even in G++ with a flag ! how can something like this not found in Visual studio..... – Mohammed B. Aug 10 '18 at 16:17
  • You are incorrect. Simply running a program which spawns console programs with `pythonw` or using that g++ flag is NOT going to solve the problem of opening child consoles. Those two options do the exact same thing as the change above in Visual Studio (they involve running a program targeting the Windows subsystem). The resulting program will still cause child processes to open a console. You would need to [use `CreateProcess`](https://learn.microsoft.com/en-us/windows/desktop/procthread/creating-a-child-process-with-redirected-input-and-output) if you want to hide the child window. – Dark Falcon Aug 10 '18 at 16:33
  • Note: in addition to the article on how to redirect I/O, you would need to [set `wShowWindow` to `SW_HIDE` to also hide the console window.](https://stackoverflow.com/a/4005553/2101267) – Dark Falcon Aug 10 '18 at 16:35
  • My main purpose is "silent run" of the software, according to what you said, what is the best way to do it ? My software deals heavily with shell internally. It doesn't matter a lot anything except for "silence" – Mohammed B. Aug 10 '18 at 16:41
  • @MohamedIbrahim, please see the addition to the end of the answer. – Dark Falcon Aug 10 '18 at 17:10
  • @DarkFalcon Glad with your edit but I have some questions concerning it I don't understand what will code exactly replace ? does every time I execute a command I will use this ? Also how to get the response ? sorry as I am completely new to win32api. – Mohammed B. Aug 10 '18 at 17:29
  • You call this once before you do anything else. It doesn't replace anything. It is in addition to whatever else you're doing. – Dark Falcon Aug 10 '18 at 17:42
  • So you mean that using _popen() after calling AllocHiddenConsole() will do the trick ? – Mohammed B. Aug 10 '18 at 17:49
  • Yes, assuming `AllocHiddenConsole` returns `true`. – Dark Falcon Aug 10 '18 at 17:51
  • what can make it return false? – Mohammed B. Aug 10 '18 at 18:09
  • I tried the code in the edit - after removing {} from STARTUPINFO startupInfo{}; PROCESS_INFORMATION processInfo{}; as they give error ! - The console application stops working :D – Mohammed B. Aug 10 '18 at 19:20
  • I fixed it but unfortunately, cmd blinks then disappear :( I used it before using any _popen - directly after wmain. Is there anything I got wrong ? – Mohammed B. Aug 10 '18 at 19:33
  • You cannot remove the `{}` and expect it to work the same. That zeros the memory of the structure. If that syntax was not valid, then do it with a call to `ZeroMemory` or `memset` – Dark Falcon Aug 10 '18 at 21:03
  • I fixed it by making it STARTUPINFO startupInfo= {}, but as I said, still appears :( – Mohammed B. Aug 10 '18 at 22:22
  • I want to add that this code worked well when the project itself a win32 application NOT a console application that I changed its subsystem – Mohammed B. Aug 13 '18 at 15:46
  • Yes, the whole point was that you need to use ALL of the answer for this to work... – Dark Falcon Aug 13 '18 at 16:16