I have built a networking app for MacOS for private usage. It uses shell commands and runs bash files.
Most of my colleagues are using MacOS, but still need to publish the same app for Windows.
Is there any ways to hide a cmd window when I runs shell script?
Thanks in advance.
On Windows app, you can do that changing the folowing lines in windows/runner/resources/main.cpp
if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {
CreateAndAttachConsole();
}
to this:
if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {
CreateAndAttachConsole();
}else {
STARTUPINFO si = { 0 };
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
PROCESS_INFORMATION pi = { 0 };
WCHAR lpszCmd[MAX_PATH] = L"cmd.exe";
if (::CreateProcess(NULL, lpszCmd, NULL, NULL, FALSE, CREATE_NEW_CONSOLE | CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) {
do {
if (::AttachConsole(pi.dwProcessId)) {
::TerminateProcess(pi.hProcess, 0);
break;
}
} while (ERROR_INVALID_HANDLE == GetLastError());
::CloseHandle(pi.hProcess);
::CloseHandle(pi.hThread);
}
}
More information here: https://github.com/flutter/flutter/issues/47891
There are some options to run a cmd hidden on Windows for example:
start a cmd window as hidden by using the "hide" option on a bat script or programmatically using the Windows API ShowWindow(SW_HIDE). Hidden in this case means you won't see the GUI and it has no presence on the task-bar.
run it through "Task Scheduler"
run it as background service
Some examples:
Bat script: How to run .BAT files invisibly without displaying the Command Prompt
C-sharp: Hide Command Window in Application
C-sharp: Run CMD command without displaying it
C-sharp: Sample code to schedule a task using WindowsTask Scheduler
Related
I want to spawn a batch file from my FMX app (on Win32) with elevated privileges. From Remy's answer at the bottom of this thread on ShellExecute I found how to launch the batch file. Now, i can't figure out how to launch it with elevated privilege. Below is my code:
String Prog = "c:\\Users\\rwp\\Desktop\\test.bat";
int nErrorCode = (int) ShellExecute(NULL, L"runas", Prog.c_str(), NULL, NULL, SW_SHOWNORMAL);
if (nErrorCode <= 32) {
ShowMessage("an error occured");
}
I added "runas" for the second argument after reading this to no avail. Running the batch file manually (right-click and run as admin) works. Here is content of the batch file fyi (just kicks of a system imaging):
c:\Windows\system32\wbAdmin.exe start backup -backupTarget:D: -include:C: -allCritical -quiet
How can i ShellExecute this batch file as admin?
UPDATE 1: I'm attempting to use CreateProcess per Remy suggestion. Here is my code (based on this example):
//Code is inside a __fastcall button click
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.lpReserved = NULL;
siStartInfo.lpReserved2 = NULL;
siStartInfo.cbReserved2 = 0;
siStartInfo.lpDesktop = NULL;
siStartInfo.dwFlags = 0;
// String strCmdLine = "C:\\Users\\rwpatter\\Desktop\\test.bat";
String strCmdLine = "C:\\Windows\\System32\\wbAdmin.exe start backup -backupTarget:T: -include:C: -allCritical -quiet";
// Create the child process.
int rtrn = CreateProcess(
NULL,
strCmdLine.c_str(),
NULL, // process security attributes
NULL, // primary thread security attributes
0, // handles are inherited
0, // creation flags
0, // use parent's environment
0, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo); // receives PROCESS_INFORMATION
// Wait for the processs to finish
DWORD rc = WaitForSingleObject(
piProcInfo.hProcess, // process handle
INFINITE);
ShowMessage(IntToStr(rtrn));
If I run it as shown (right-click on exe and run as admin) it returns 0 which means it failed. If I run it by putting the wbAdmin command line in the test.bat file (see commented line right above String strCmdLine in the code) then CreateProcess returns a 1 (success) but wbAdmin is still not running. It flashed a DOS window and i captured it as shown in the picture below. It shows oriental characters in the title bar and says not recognized as internal or external command. But, if i run that test.bat directly (elevated) it runs wbAdmin no problem.
Any ideas on what is wrong? Besides me obviously being ignorant. (p.s. i'll get to testing Golvind's answer on the ShellExecute after this...)
Running the batch file manually (right-click and run as admin) works.
Because you are running the 64-bit version of cmd when you start it manually.
It shows oriental characters in the title bar and says not recognized
as internal or external command.
Because your application is 32-bit. A 32-bit application does not see the same System32 folder as 64-bit applications. You can access the 64-bit System32 folder in 32-bit applications with the virtual sysnative folder.
#include <shellapi.h>
...
String strCmdLine = "wbAdmin.exe start backup -backupTarget:T: -include:C: -allCritical -quiet";
int rtrn = CreateProcess(
NULL,
strCmdLine.c_str(),
NULL, // process security attributes
NULL, // primary thread security attributes
0, // handles are inherited
0, // creation flags
0, // use parent's environment
0, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo); // receives PROCESS_INFORMATION
if (!rtrn)
{
String newCmdLine = "c:\\windows\\sysnative\\wbAdmin.exe start backup -backupTarget:T: -include:C: -allCritical -quiet";
rtrn = CreateProcess(
NULL,
newCmdLine.c_str(),
NULL, // process security attributes
NULL, // primary thread security attributes
0, // handles are inherited
0, // creation flags
0, // use parent's environment
0, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo); // receives PROCESS_INFORMATION
}
Or compile your application to 64-bit.
You need to launch CMD.exe as Administrator with "runas", and specify the batch file as a "run-me-then-exit" (i.e. /c) argument to command prompt, as so:
WCHAR wszCmdPath[MAX_PATH];
GetEnvironmentVariableW(L"ComSpec", wszCmdPath, MAX_PATH);
ShellExecuteW(NULL, L"runas", wszCmdPath, L"/c \"C:\\Path\\BatchFile.bat\"", L"", SW_SHOW);
Both functions called here can fail, and robust code would test for success before proceeding.
I am trying to implement a method that executes command "ipconfig" in command prompt and show that output in command prompt.
currently i am using
STARTUPINFO StartUpInfo;
PROCESS_INFORMATION ProcInformation;
memset(&StartUpInfo, 0, sizeof(StartUpInfo) );
memset(&ProcInformation, 0, sizeof(ProcInformation) );
StartUpInfo.dwFlags = STARTF_USESHOWWINDOW;
StartUpInfo.wShowWindow = SW_SHOW;
CreateProcess(csCMDExeFullPath_EP, csCommanddLineParams_EP.GetBuffer
( csCommanddLineParams_EP.GetLength() + ONE), NULL,
NULL, NULL, 0, NULL, NULL,&StartUpInfo, &ProcInformation );
//Wait for the executing process to complete
WaitForSingleObject(ProcInformation.hProcess, INFINITE);
GetExitCodeProcess(ProcInformation.hProcess, &dwExecuteProcess_ExecExitCode_EP );
csCommanddLineParams_EP.ReleaseBuffer();
//Close handle of the process
CloseHandle(ProcInformation.hProcess);
//Close handle of the threads
CloseHandle(ProcInformation.hThread);`
My current code is working fine but command prompt visible and disappears in seconds.
But my requirement is to show output in cmd.
Can any one help me on this.
I'm creating a custom build of node.js that should not show a console window to the user.
I've tried changing the linker config in the gyp file to 2 (which should set the linker flag /SUBSYSTEM:WINDOWS), but I still get a console window when I run the resulting node.exe binary.
How can I prevent the console window from appearing?
Edit: Further investigation reveals that the linker config in node.gyp is not taking effect. The generated node.vcxproj still has <Link><SubSystem>Console</SubSystem></Link> (which is very strange to me, since adding 'UACUIAccess': 'true' in the same part of node.gyp did take effect), so the built binary is incorrectly linked.
Solution 1
Save this one line of text as file invisible.vbs:
CreateObject(“Wscript.Shell”).Run “”"” & WScript.Arguments(0) & “”"”, 0, False
To run any program or batch file invisibly, use it like this:
wscript.exe “C:\Wherever\invisible.vbs” “C:\Some Other Place\MyBatchFile.bat”
To also be able to pass-on/relay a list of arguments use only two double quotes
CreateObject(“Wscript.Shell”).Run “” & WScript.Arguments(0) & “”, 0, False
eg: Invisible.vbs “Kill.vbs ME.exe”
Solution 2
Use a command line tool to silently launch a process : Quiet.
Solution 3
Roll your own C++ Win32 App:
PROCESS_INFORMATION procInfo = {0};
STARTUPINFOstartupInfo = {0};
SECURITY_ATTRIBUTESsaAttr = {0};
HANDLEhStdIn = GetStdHandle(STD_INPUT_HANDLE);
HANDLEhStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLEhStdErr = GetStdHandle(STD_ERROR_HANDLE);
// build up security attributes
saAttr.nLength = sizeof(saAttr);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
// set file handles for process to be created
startupInfo.cb = sizeof(startupInfo);
startupInfo.dwFlags = STARTF_USESTDHANDLES;
startupInfo.hStdInput = hStdIn;
startupInfo.hStdOutput = hStdOut;
startupInfo.hStdError = hStdErr;
// build command line: format is [cmd.exe /c "%batchScript%" %batchArgs%]
if (-1 == _snprintf_s(cmd, sizeof(cmd),"cmd.exe /c \"%s\" %s", batchScript, batchArgs))
errorExit("_snprintf_s(\"cmd.exe /c \"%%s\" %%s\"), \"%s\", \"%s\") failed.", batchScript, batchArgs);
rc = CreateProcess(NULL, cmd, NULL, &saAttr, TRUE, CREATE_NO_WINDOW, NULL, tempPath, &startupInfo, &procInfo);
You have to change the SubSystem field value in node.exe PE optional header. The current value is 3 which is defined as Windows Console. If you change it to 2 (which is defined as Windows GUI) there would be no console window. In order to patch the executable file, you have to use utilities to change Optional Header of PE.
One example of such a tool is PE tools.
Click on Optinal Header and then change the Subsystem from 3 to 2.
That`s all.
Remember that with this change you can only run js files. You can not use interactive mode.
It appears that you must:
Comment out the 'SubSystem': 1 line in common.gypi. (Changing it to 2 causes the build to fail in mksnapshot.)
Change SubSystem to 2 in node.gyp
Also add 'EntryPointSymbol': 'wmainCRTStartup' to node.gyp.
This builds a node.exe that does not create a console window.
When I right click on some file in windows in opened menu, there is an Open With... line, by clicking I can select some program, which will open selected file. So now I need to launch this dialog for some file (or just run for "tmp.xml" name) using MFC. I need something like CFileDialog which makes it possible to browse files.
I have found SHOpenWithDialog, but Minimum supported client for it is Windows Vista [desktop apps only], it would be better to support windows XP too.
So I have found this kind of solution.
void OpenWith(CString strFileNameToOpen)
{
TCHAR lpPathBuffer[MAX_PATH];
GetSystemDirectory(lpPathBuffer, MAX_PATH);
CString strSystemDir = lpPathBuffer;
STARTUPINFO si = {0};
PROCESS_INFORMATION pi = {0};
strSystemDir.Format(_T("rundll32.exe %s\\shell32.dll,OpenAs_RunDLL %s"), lpPathBuffer, strFileNameToOpen);
CreateProcess(NULL, strSystemDir.GetBuffer(), NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
I have subversion server with a post-commit hook to do something.
I want the checkin finish soon, not wait the hook script.
But by design, the Subversion post-commit hook script will run until all child process exit, so using somthing like:
start another_prog...
in the hook bat file has no use.
So I want to know how to run another program in Windows bat file which not create child process or let the child process detach from the parent.
Synchronous. The second notepad won't launch until you close the first.
notepad.exe c:\temp\a.txt
notepad.exe c:\temp\b.txt
Asynchronous: The second notepad will launch even if you haven't closed the first.
start notepad.exe c:\temp\a.txt
start notepad.exe c:\temp\b.txt
More info about the start command:
http://www.robvanderwoude.com/ntstart.php
EDIT: The following comment was made elsewhere by #zhongshu, the original poster. I'm only copying it here:
start cmd /c doesn't work because SVN
post-commit hook will wait for the
hook and the child process created by
the hook exit. It's the design of SVN.
I have found a solution, Please refer:
http://svn.haxx.se/users/archive-2008-11/0301.shtml
Assuming that he knows what he's talking about, I'm wrong and...undeserving.
I found a method to resolve my question, compile the following c code and named the exe output as runjob.exe, and then in the hook bat file, use " runjob another_prog " , now it's ok.
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
int _tmain()
{
char * pCmd = ::GetCommandLine();
// skip the executable
if (*pCmd++ == L'"')
{
while (*pCmd++ != L'"');
}
else
{
while (*pCmd != NULL && *pCmd != L' ')
++pCmd;
}
while (*pCmd == L' ')
pCmd++;
STARTUPINFO si;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
PROCESS_INFORMATION pi;
ZeroMemory( &pi, sizeof(pi) );
// Start the child process.
BOOL result = CreateProcess
(
NULL, // No module name (use command line)
pCmd, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set bInheritHandles to FALSE
DETACHED_PROCESS, // Detach process
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi // Pointer to PROCESS_INFORMATION structure (returned)
);
if (result) return 0;
char msg[2048];
FormatMessage
(
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
::GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT),
msg, sizeof(msg),
NULL
);
fputs(msg, stderr);
_flushall();
return -1;
}
What you can do is create a Scheduled Task that executes the batch script or other executable that runs for a long time. Set it to run once, in the past and don't set it to delete the task when no more runs are scheduled. Then in your Subversion hook script, put the following line in:
schtasks /run /tn NameOfYourTaskHere
I confirmed with a test by having my scheduled task run Notepad++ and the Notepad++ executable showed up as a child of svchost.exe, not the cmd.exe window that I executed the schtasks command from.
Use:
start cmd /c "your command"
Cheers.
Try cmd /c "your command"
Could you use the windows task scheduler command line interface "schtasks /run" to start a job that runs the "another_prog"? You'd have to create the job ahead of time. There also used to be a "SOON" program with the Windows (NT) Resource Kit that would create dynamic entries for the "AT" command scheduler to run a job in a few minutes that would not require setting up a job ahead of time, it can still be found with a little searching.
You can create a hybrid batch/JScript file (i.e. a batch file able to run embedded JScript) where the JScript part will run another_prog in detached mode with shell.Run(prog, 0, false):
#if (#X)==(#Y) #end /* JScript comment
rem put any batch code that runs before another_prog here
#cscript //E:JScript //nologo "%~f0" "another_prog" 0 false
rem put any batch code that runs after another_prog here
exit /b %errorlevel%
#if (#X)==(#Y) #end JScript comment */
var ARGS = WScript.Arguments;
var shell = new ActiveXObject("WScript.Shell");
shell.Run(ARGS.Item(0),ARGS.Item(1),ARGS.Item(2));`