我怎样才能做 FreeConsole() 但在 C++ 上更快
How can I do the FreeConsole() but faster on c++
我非常想知道我如何能够执行与 FreeConsole()
Windows API function 相同的功能但速度更快。
FreeConsole()
确实隐藏了控制台,但是,控制台 window 在隐藏之前仍然会闪现。如果可能的话,我想让控制台完全不打开。谢谢。
根据评论更新
我的 OS 是 Windows。我将 gcc 编译器与 windows.h
header 一起使用,并使用 Visual Studio 代码。
在 Microsoft documentation About Consoles 中有这段文字:
The system creates a new console when it starts a console process, a
character-mode process whose entry point is the main function. For
example, the system creates a new console when it starts the command
processor cmd.exe. When the command processor starts a new console
process, the user can specify whether the system creates a new console
for the new process or whether it inherits the command processor's
console.
文档指出,为了不显示控制台,您需要创建一个不是控制台应用程序的可执行文件。
第二个更好的答案
经过深思熟虑,我意识到我的第一个答案可以简化。您可以编写作为非控制台应用程序的 Windows GUI 应用程序,而不是启动非控制台进程的 Windows GUI 应用程序。
我认为控制它的两件事是:(1) C++ 源代码和指定的主要入口点以及 (2) /SUBSYSTEM 链接器选项,它决定链接器用于应用程序的可执行环境和入口点。
有关 /SUBSYSTEM 链接器指令的详细信息,请参阅这篇 Microsoft 文章 /SUBSYSTEM (Specify Subsystem)。
The /SUBSYSTEM option specifies the environment for the executable.
The choice of subsystem affects the entry point symbol (or entry point
function) that the linker will select.
使用 Visual Studio 2019,我创建了一个 Windows 桌面应用程序,然后将其删除,删除了所有 Windows GUI 应用程序源代码,只保留 wWinMain()
入口点。然后我修改了这个应用程序以使用标准 C++ 库创建一个简单的文本文件并退出以证明它有效。
我最终得到了以下 C++ 测试应用程序的源代码。
// cmndline_non_console.cpp : Defines the entry point for the application.
//
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files
#include <windows.h>
#include <iostream>
#include <fstream>
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
std::ofstream myfile;
myfile.open("test.txt");
myfile << "Writing this to a file. more\n";
myfile.close();
return 0;
}
Link 的解决方案属性正在使用 /SUBSYSTEM:WINDOWS.
第一个回答
此 Microsoft documentation Windows Console and Terminal Ecosystem Roadmap 描述了 Windows 控制台的历史以及对较新的伪控制台和虚拟终端功能的更改
这是一个简化的 GUI,它启动时没有控制台启动子进程,然后退出。它使用 CreateProcess()
Windows API 函数。参见 and see also Creating Processes in the Microsoft Docs。
我通过使用 Visual Studio 2019 IDE 创建了一个新的 Windows 桌面 GUI 应用程序来创建主应用程序,然后对生成的代码进行了一些更改。您可能可以减少更多。依赖于几个标准生成的文件:framework.h
、Resource.h
和 targetver.h
。头文件 startconsoleless.h
仅包含 Resource.h
.
的 include 指令
InitInstance()
函数returnsFALSE
使应用程序退出
InitInstance()
函数使用CActualApp
class创建一个没有控制台的新进程
About
对话框处理已被删除,因为它未被使用
此示例使用硬编码命令行来指示要启动的可执行文件。需要使用 wchar_t
个字符数组,否则 CreateProcess()
函数将根据引用的 SO post 触发异常。
文件startconsoless.cpp
// startconsoleless.cpp : Defines the entry point for the application.
//
#include "framework.h"
#include "startconsoleless.h"
#include "CActualApp.h"
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
CActualApp myApp;
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
// Initialize global strings
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_STARTCONSOLELESS, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_STARTCONSOLELESS));
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_STARTCONSOLELESS));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_STARTCONSOLELESS);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
{
return FALSE;
}
// Comment out following code in order to not show the created window.
// ShowWindow(hWnd, nCmdShow);
// UpdateWindow(hWnd);
// At this point we can now have our main thread of this process
// start another thread to do the work we want to do
// See
wchar_t appLine[] = L"C:\WINDOWS\system32\notepad.exe";
myApp.StartAnApp(appLine);
// return FALSE so that this Windows GUI app will exit after
// starting the child process.
return FALSE;
}
//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
这是一个非常简单的 class 上面用来启动应用程序的方法。
文件CAcutalApp.h
#pragma once
class CActualApp
{
public:
CActualApp() {}
~CActualApp() {}
int StartAnApp(wchar_t * pAppComndLine);
};
文件CActualApp.cpp
#include "framework.h"
#include "CActualApp.h"
int CActualApp::StartAnApp(wchar_t * pAppComndLine)
{
// See
int retStatus = 0;
PROCESS_INFORMATION processInformation = { 0 };
STARTUPINFO startupInfo = { 0 };
startupInfo.cb = sizeof(startupInfo);
BOOL apStart = CreateProcess(NULL, pAppComndLine, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInformation);
if (!apStart)
{
// create process failed
DWORD errorCode = GetLastError();
retStatus = errorCode;
}
else {
// close process and thread handles
CloseHandle(processInformation.hProcess);
CloseHandle(processInformation.hThread);
}
return retStatus;
}
我非常想知道我如何能够执行与 FreeConsole()
Windows API function 相同的功能但速度更快。
FreeConsole()
确实隐藏了控制台,但是,控制台 window 在隐藏之前仍然会闪现。如果可能的话,我想让控制台完全不打开。谢谢。
根据评论更新
我的 OS 是 Windows。我将 gcc 编译器与 windows.h
header 一起使用,并使用 Visual Studio 代码。
在 Microsoft documentation About Consoles 中有这段文字:
The system creates a new console when it starts a console process, a character-mode process whose entry point is the main function. For example, the system creates a new console when it starts the command processor cmd.exe. When the command processor starts a new console process, the user can specify whether the system creates a new console for the new process or whether it inherits the command processor's console.
文档指出,为了不显示控制台,您需要创建一个不是控制台应用程序的可执行文件。
第二个更好的答案
经过深思熟虑,我意识到我的第一个答案可以简化。您可以编写作为非控制台应用程序的 Windows GUI 应用程序,而不是启动非控制台进程的 Windows GUI 应用程序。
我认为控制它的两件事是:(1) C++ 源代码和指定的主要入口点以及 (2) /SUBSYSTEM 链接器选项,它决定链接器用于应用程序的可执行环境和入口点。
有关 /SUBSYSTEM 链接器指令的详细信息,请参阅这篇 Microsoft 文章 /SUBSYSTEM (Specify Subsystem)。
The /SUBSYSTEM option specifies the environment for the executable.
The choice of subsystem affects the entry point symbol (or entry point function) that the linker will select.
使用 Visual Studio 2019,我创建了一个 Windows 桌面应用程序,然后将其删除,删除了所有 Windows GUI 应用程序源代码,只保留 wWinMain()
入口点。然后我修改了这个应用程序以使用标准 C++ 库创建一个简单的文本文件并退出以证明它有效。
我最终得到了以下 C++ 测试应用程序的源代码。
// cmndline_non_console.cpp : Defines the entry point for the application.
//
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files
#include <windows.h>
#include <iostream>
#include <fstream>
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
std::ofstream myfile;
myfile.open("test.txt");
myfile << "Writing this to a file. more\n";
myfile.close();
return 0;
}
Link 的解决方案属性正在使用 /SUBSYSTEM:WINDOWS.
第一个回答
此 Microsoft documentation Windows Console and Terminal Ecosystem Roadmap 描述了 Windows 控制台的历史以及对较新的伪控制台和虚拟终端功能的更改
这是一个简化的 GUI,它启动时没有控制台启动子进程,然后退出。它使用 CreateProcess()
Windows API 函数。参见
我通过使用 Visual Studio 2019 IDE 创建了一个新的 Windows 桌面 GUI 应用程序来创建主应用程序,然后对生成的代码进行了一些更改。您可能可以减少更多。依赖于几个标准生成的文件:framework.h
、Resource.h
和 targetver.h
。头文件 startconsoleless.h
仅包含 Resource.h
.
InitInstance()
函数returnsFALSE
使应用程序退出InitInstance()
函数使用CActualApp
class创建一个没有控制台的新进程About
对话框处理已被删除,因为它未被使用
此示例使用硬编码命令行来指示要启动的可执行文件。需要使用 wchar_t
个字符数组,否则 CreateProcess()
函数将根据引用的 SO post 触发异常。
文件startconsoless.cpp
// startconsoleless.cpp : Defines the entry point for the application.
//
#include "framework.h"
#include "startconsoleless.h"
#include "CActualApp.h"
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
CActualApp myApp;
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
// Initialize global strings
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_STARTCONSOLELESS, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_STARTCONSOLELESS));
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_STARTCONSOLELESS));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_STARTCONSOLELESS);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
{
return FALSE;
}
// Comment out following code in order to not show the created window.
// ShowWindow(hWnd, nCmdShow);
// UpdateWindow(hWnd);
// At this point we can now have our main thread of this process
// start another thread to do the work we want to do
// See
wchar_t appLine[] = L"C:\WINDOWS\system32\notepad.exe";
myApp.StartAnApp(appLine);
// return FALSE so that this Windows GUI app will exit after
// starting the child process.
return FALSE;
}
//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
这是一个非常简单的 class 上面用来启动应用程序的方法。
文件CAcutalApp.h
#pragma once
class CActualApp
{
public:
CActualApp() {}
~CActualApp() {}
int StartAnApp(wchar_t * pAppComndLine);
};
文件CActualApp.cpp
#include "framework.h"
#include "CActualApp.h"
int CActualApp::StartAnApp(wchar_t * pAppComndLine)
{
// See
int retStatus = 0;
PROCESS_INFORMATION processInformation = { 0 };
STARTUPINFO startupInfo = { 0 };
startupInfo.cb = sizeof(startupInfo);
BOOL apStart = CreateProcess(NULL, pAppComndLine, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInformation);
if (!apStart)
{
// create process failed
DWORD errorCode = GetLastError();
retStatus = errorCode;
}
else {
// close process and thread handles
CloseHandle(processInformation.hProcess);
CloseHandle(processInformation.hThread);
}
return retStatus;
}