C ++ (확장)의 WINMAIN 및 main ()
맞아요,이 게시물을 보았습니다 : C ++에서 WinMain, main 및 DllMain의 차이점
나는 이제 그것이 WINMAIN
창 응용 프로그램과 main()
콘솔에 사용 된다는 것을 알고 있습니다. 그러나 게시물을 읽는 것은 그 차이가 정확히 무엇인지 정확히 알려주지 않습니다.
프로그램을 시작하기 위해 서로 다른 주전원 기능을 분리하는 이유는 무엇입니까? 성능 문제 때문입니까? 아니면 무엇입니까?
기능에 대해.
C 및 C ++ 표준에서는 모든 프로그램 ( "호스팅 된"C 또는 C ++ 구현 용)에 main
프로그램의 시작 함수 역할을하는 라는 함수가 있어야 합니다 . 이 main
함수는 로컬이 아닌 정적 변수를 0으로 초기화 한 후 호출 되며 반드시 그런 것은 아니지만 (!, C ++ 11 §3.6.2 / 4) 이러한 변수의 동적 초기화 후에이 호출이 발생 합니다. 다음 서명 중 하나를 가질 수 있습니다.
int main()
int main( int argc, char* argv[] )
또한 가능한 구현 정의 서명 (C ++ 11 §3.6.1 / 2) (결과 유형이 int
.
C ++에서 이러한 함수 main
는 기본 결과 값, 즉 0 main
을 갖기 때문에 반환 exit
하면 main
결과 값을 인수로 사용하여 일반 함수 return 이 호출됩니다 . 표준은 사용할 수있는 세 가지 값을 정의합니다. 0 (성공을 나타냄), EXIT_SUCCESS
(성공을 나타내며 일반적으로 0으로 정의 됨) 및 EXIT_FAILURE
(실패를 나타냄) 두 개의 명명 된 상수는 <stdlib.h>
또한 다음을 선언하는 헤더에 의해 정의됩니다 . exit
함수.
main
인수는 표현하기위한 것입니다 명령 줄 인수를 프로세스를 시작하는 데 사용되는 명령. argc
(인수 개수)는 argv
(인수 값) 배열 의 항목 수입니다 . 이러한 항목에 추가로 argv[argc]
0이 보장됩니다. argc
> 0 인 경우 -보장되지 않습니다! – 그러면 argv[0]
빈 문자열에 대한 포인터 또는 "프로그램 호출에 사용 된 이름"에 대한 포인터가 보장됩니다. 이 이름은 경로를 포함 할 수 있으며 실행 파일의 이름 일 수 있습니다.
은 Using main
C와 C ++는 * nix에서 비롯 때문에 명령 줄 인수를 얻기 위해 인수하는 것은, * nix에서 스크립트에서 잘 작동합니다. 그러나 인수 인코딩에 대한 사실상의 Windows 표준 main
은 Windows ANSI입니다 . 이는 일반적인 Windows 파일 이름 (예 : 노르웨이어 Windows 설치의 경우 그리스어 또는 키릴 문자가있는 파일 이름)을 지원하지 않습니다. 따라서 Microsoft는 모든 파일 이름을 나타낼 수있는 UTF-16으로wmain
인코딩 된 와이드 문자 기반 인수를 갖는 라는 Windows 관련 시작 함수를 사용하여 C 및 C ++ 언어를 확장하기로 결정했습니다 .
wmain
기능을 가질 수 이러한 서명 중 하나를 위한 표준 서명에 해당 main
:
int wmain()
int wmain( int argc, wchar_t* argv[] )
특히 유용하지 않은 몇 가지가 더 있습니다.
즉, wmain
에 대한 직접 다양한 캐릭터를 기반으로 대체합니다 main
.
기반 기능은 1980 년대 초에, Windows와 함께 소개되었다 :WinMain
char
int CALLBACK WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow
);
여기서 CALLBACK
, HINSTANCE
및 헤더에 LPSTR
의해 정의됩니다 <windows.h>
( LPSTR
is just char*
).
인수 :
hInstance
인수 값, 그것은 주로 실행 자원으로부터 부하에 사용되는 실행 파일의 화상 메모리의 기본 주소이며,이 대안에서 얻을 수GetModuleHandle
API 함수hPrevInstance
인수는 항상 0입니다lpCmdLine
인수는 대안에서 얻을 수 있습니다GetCommandLine
API 기능, 플러스 이상한 논리의 비트는 명령 줄의 프로그램 이름 부분을 생략하고,nCmdShow
인수 값은 교대에서 얻을 수있다GetStartupInfo
API의 기능을하지만, 현대 창문이있는 최상위 윈도우의 첫 번째 창조는 자동으로 그래서 어떤 실제 사용의 아니에요 않습니다.
따라서이 WinMain
함수는 standard와 동일한 단점 main
과 일부 (특히 장황함과 비표준)의 단점을 가지고 있으며 자체적 인 장점이 없기 때문에 벤더 종속 항목을 제외하고는 실제로 설명 할 수 없습니다. 그러나 Microsoft 도구 체인을 사용하면 링커가 GUI 하위 시스템으로 기본 설정되어 일부는 이점으로 간주합니다. 그러나 예를 들어 GNU 툴체인에서는 그러한 효과가 없으므로이 효과는 신뢰할 수 없습니다.
기반 기능의 다양한 문자 변종 과 동일한 방식으로, 표준의 다양한 특성 변이체이다 :wWinMain
wchar_t
WinMain
wmain
main
int WINAPI wWinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
PWSTR lpCmdLine,
int nCmdShow
);
곳 WINAPI
과 동일 CALLBACK
하고, PWSTR
단순히 wchar_t*
.
가장 덜 알려지고 가장 적게 지원되는 기능을 제외하고는 비표준 함수를 사용할 이유가 없습니다. 즉 wmain
, 편의상 GetCommandLine
및 CommandLineToArgvW
API 함수를 사용하여 UTF-16으로 인코딩 된 인수를 선택하는 것을 방지합니다 .
Microsoft 링커가 작동하지 않도록 (GNU 도구 체인의 링커는 작동하지 않음) LINK
환경 변수를로 설정 /entry:mainCRTStartup
하거나 해당 옵션을 직접 지정하십시오. 이것은 일부 초기화 후 표준 main
함수를 호출하는 Microsoft 런타임 라이브러리 진입 점 함수입니다 . 다른 시작 함수에는 동일한 체계적인 방식으로 명명 된 해당 진입 점 함수가 있습니다.
표준 main
기능 사용의 예 .
공통 소스 코드 :
foo.cpp
#undef UNICODE
#define UNICODE
#include <windows.h>
int main()
{
MessageBox( 0, L"Press OK", L"Hi", MB_SETFOREGROUND );
}
아래 예제에서 (먼저 GNU 도구 체인을 사용한 다음 Microsoft 도구 체인을 사용하여)이 프로그램은 먼저 콘솔 하위 시스템 프로그램 으로 빌드 된 다음 GUI 하위 시스템 프로그램 으로 빌드됩니다 . 콘솔 서브 시스템 프로그램 또는 간단히 말해서 콘솔 프로그램 은 콘솔 창이 필요한 프로그램 입니다. 이것은 내가 사용한 모든 Windows 링커에 대한 기본 하위 시스템입니다 (확실히 많지는 않음). 모든 Windows 링커 기간에 대해 가능합니다.
콘솔 프로그램의 경우 Windows는 필요한 경우 자동으로 콘솔 창을 만듭니다 . 하위 시스템에 관계없이 모든 Windows 프로세스에는 연결된 콘솔 창이 있고 최대 하나만있을 수 있습니다. 또한 Windows 명령 인터프리터는 콘솔 프로그램 프로그램이 완료 될 때까지 대기하므로 프로그램의 텍스트 표시가 완료됩니다.
반대로 GUI 하위 시스템 프로그램은 콘솔 창을 필요로하지 않는 프로그램입니다. 명령 인터프리터는 배치 파일을 제외하고 GUI 하위 시스템 프로그램을 기다리지 않습니다. 두 종류의 프로그램에 대해 완료 대기를 피하는 한 가지 방법은 start
명령 을 사용하는 것 입니다. GUI 하위 시스템 프로그램에서 콘솔 창 텍스트를 표시하는 한 가지 방법은 표준 출력 스트림을 리디렉션하는 것입니다. 또 다른 방법은 프로그램의 코드에서 콘솔 창을 명시 적으로 만드는 것입니다.
프로그램의 하위 시스템은 실행 파일의 헤더에 인코딩됩니다. Windows 탐색기에는 표시되지 않습니다 (Windows 9x에서는 Microsoft dumpbin
도구 와 거의 동일한 정보를 제공하는 실행 파일을 "빠르게 볼"수 있다는 점을 제외하면 ). 해당하는 C ++ 개념이 없습니다.
main
GNU 툴체인으로.
[D : \ dev \ test] > g ++ foo.cpp [D : \ dev \ test] > objdump -x a.exe | / i "subsys"찾기 MajorSubsystem 버전 4 MinorSubsystemVersion 0 하위 시스템 00000003 (Windows CUI) [544] (초 -1) (fl 0x00) (ty 0) (scl 2) (nx 0) 0x00000004 __major_subsystem_version__ [612] (초 -1) (fl 0x00) (ty 0) (scl 2) (nx 0) 0x00000003 __subsystem__ [636] (초 -1) (fl 0x00) (ty 0) (scl 2) (nx 0) 0x00000000 __minor_subsystem_version__ [D : \ dev \ test] > g ++ foo.cpp -mwindows [D : \ dev \ test] > objdump -x a.exe | / i "subsys"찾기 MajorSubsystem 버전 4 MinorSubsystemVersion 0 하위 시스템 00000002 (Windows GUI) [544] (초 -1) (fl 0x00) (ty 0) (scl 2) (nx 0) 0x00000004 __major_subsystem_version__ [612] (초 -1) (fl 0x00) (ty 0) (scl 2) (nx 0) 0x00000002 __subsystem__ [636] (초 -1) (fl 0x00) (ty 0) (scl 2) (nx 0) 0x00000000 __minor_subsystem_version__ [D : \ dev \ test] > _
main
Microsoft의 툴체인 :
[D : \ dev \ test] > LINK = / entry : mainCRTStartup 설정 [D : \ dev \ test] > cl foo.cpp user32.lib foo.cpp [D : \ dev \ test] > dumpbin / headers foo.exe | / i "subsys"찾기 6.00 하위 시스템 버전 3 하위 시스템 (Windows CUI) [D : \ dev \ test] > cl foo.cpp / link user32.lib / subsystem : windows foo.cpp [D : \ dev \ test] > dumpbin / headers foo.exe | / i "subsys"찾기 6.00 하위 시스템 버전 2 하위 시스템 (Windows GUI) [D : \ dev \ test] > _
Microsoft의 wmain
기능 을 사용하는 예 .
다음 기본 코드는 GNU 도구 모음 및 Microsoft 도구 모음 데모 모두에 공통입니다.
bar.cpp
#undef UNICODE
#define UNICODE
#include <windows.h>
#include <string> // std::wstring
#include <sstream> // std::wostringstream
using namespace std;
int wmain( int argc, wchar_t* argv[] )
{
wostringstream text;
text << argc - 1 << L" command line arguments:\n";
for( int i = 1; i < argc; ++i )
{
text << "\n[" << argv[i] << "]";
}
MessageBox( 0, text.str().c_str(), argv[0], MB_SETFOREGROUND );
}
wmain
GNU 툴체인으로.
GNU 도구 모음은 Microsoft의 wmain
기능을 지원하지 않습니다 .
[D : \ dev \ test] > g ++ bar.cpp d : / bin / mingw / bin /../ lib / gcc / i686-pc-mingw32 / 4.7.1 /../../../ libmingw32.a (main.o) : main.c :(. text.startup + 0xa3) :`WinMain에 대한 정의되지 않은 참조 @ 16 ' collect2.exe : 오류 : ld가 1 종료 상태를 리턴했습니다. [D : \ dev \ test] > _
여기에있는 링크 오류 메시지 WinMain
는 GNU 도구 모음이 해당 기능을 지원 하기 때문이며 (아마도 너무 많은 고대 코드에서이 기능을 사용하기 때문일 것입니다) 표준을 찾지 못한 후 최후의 수단으로 검색하기 때문 main
입니다.
그러나 다음 main
을 호출 하는 표준으로 모듈을 추가하는 것은 간단 합니다 wmain
.
wmain_support.cpp
extern int wmain( int, wchar_t** );
#undef UNICODE
#define UNICODE
#include <windows.h> // GetCommandLine, CommandLineToArgvW, LocalFree
#include <stdlib.h> // EXIT_FAILURE
int main()
{
struct Args
{
int n;
wchar_t** p;
~Args() { if( p != 0 ) { ::LocalFree( p ); } }
Args(): p( ::CommandLineToArgvW( ::GetCommandLine(), &n ) ) {}
};
Args args;
if( args.p == 0 )
{
return EXIT_FAILURE;
}
return wmain( args.n, args.p );
}
지금,
[D : \ dev \ test] > g ++ bar.cpp wmain_support.cpp [D : \ dev \ test] > objdump -x a.exe | / i "서브 시스템"찾기 MajorSubsystem 버전 4 MinorSubsystemVersion 0 하위 시스템 00000003 (Windows CUI) [13134] (초 -1) (fl 0x00) (ty 0) (scl 2) (nx 0) 0x00000004 __major_subsystem_version__ [13576] (초 -1) (fl 0x00) (ty 0) (scl 2) (nx 0) 0x00000003 __subsystem__ [13689] (초 -1) (fl 0x00) (ty 0) (scl 2) (nx 0) 0x00000000 __minor_subsystem_version__ [D : \ dev \ test] > g ++ bar.cpp wmain_support.cpp -mwindows [D : \ dev \ test] > objdump -x a.exe | / i "서브 시스템"찾기 MajorSubsystem 버전 4 MinorSubsystemVersion 0 하위 시스템 00000002 (Windows GUI) [13134] (초 -1) (fl 0x00) (ty 0) (scl 2) (nx 0) 0x00000004 __major_subsystem_version__ [13576] (초 -1) (fl 0x00) (ty 0) (scl 2) (nx 0) 0x00000002 __subsystem__ [13689] (초 -1) (fl 0x00) (ty 0) (scl 2) (nx 0) 0x00000000 __minor_subsystem_version__ [D : \ dev \ test] > _
wmain
Microsoft의 도구 체인으로.
Microsoft의 도구 모음을 사용하면 링커는 wmainCRTStartup
진입 점이 지정되지 않고 wmain
함수가 있는 경우 자동으로 진입 점을 유추합니다 (표준 main
도 있는 경우 어떻게되는지 확실하지 않으며 최근 몇 년 동안 확인하지 않았습니다).
[D : \ dev \ test] > set link=/entry:mainCRTStartup [D:\dev\test] > cl bar.cpp user32.lib bar.cpp LIBCMT.lib(crt0.obj) : error LNK2019: unresolved external symbol _main referenced in function ___tmainCRTStartup bar.exe : fatal error LNK1120: 1 unresolved externals [D:\dev\test] > set link= [D:\dev\test] > cl bar.cpp user32.lib bar.cpp [D:\dev\test] > _
With a non-standard startup function such as wmain
it is, however, probably best to specify the entry point explicitly, so as to be very clear about the intention:
[D:\dev\test] > cl bar.cpp /link user32.lib /entry:wmainCRTStartup bar.cpp [D:\dev\test] > dumpbin /headers bar.exe | find /i "subsystem" 6.00 subsystem version 3 subsystem (Windows CUI) [D:\dev\test] > cl bar.cpp /link user32.lib /entry:wmainCRTStartup /subsystem:windows bar.cpp [D:\dev\test] > dumpbin /headers bar.exe | find /i "subsystem" 6.00 subsystem version 2 subsystem (Windows GUI) [D:\dev\test] > _
According to @RaymondChen
The name WinMain is just a convention
Although the function WinMain is documented in the Platform SDK, it's not really part of the platform. Rather, WinMain is the conventional name for the user-provided entry point to a Windows program.
The real entry point is in the C runtime library, which initializes the runtime, runs global constructors, and then calls your WinMain function (or wWinMain if you prefer a Unicode entry point).
DllMain and WinMain is different in their prototypes itself. WinMain accepts commandline argument while the other one talks about how it's attached to the process.
As per MSDN documentation
By default, the starting address is a function name from the C run-time library. The linker selects it according to the attributes of the program, as shown in the following table.
mainCRTStartup
(orwmainCRTStartup
) An application using/SUBSYSTEM:CONSOLE;
calls main (orwmain
)WinMainCRTStartup
(orwWinMainCRTStartup
) An application using/SUBSYSTEM:WINDOWS;
callsWinMain
(orwWinMain
), which must be defined with__stdcall
_DllMainCRTStartup
A DLL; callsDllMain
, which must be defined with__stdcall
, if it exists
A standard C program is passed 2 parameters by the command line at start up:
int main( int argc, char** argv ) ;
char** argv
is an array of strings (char*
)int argc
is the number ofchar*
in argv
The booting function WinMain
that programmers have to write for a windows program is slightly different. WinMain
takes 4 parameters that are passed to the program by Win O/S at start up:
int WINAPI WinMain( HINSTANCE hInstance, // HANDLE TO AN INSTANCE. This is the "handle" to YOUR PROGRAM ITSELF.
HINSTANCE hPrevInstance,// USELESS on modern windows (totally ignore hPrevInstance)
LPSTR szCmdLine, // Command line arguments. similar to argv in standard C programs
int iCmdShow ) // Start window maximized, minimized, etc.
See my article How to create a basic window in C for more
I vaguely recall reading somewhere that Windows programs have a main()
function. It is just hidden in a header or library somewhere. I believe this main()
function initializes all of the variables needed by WinMain()
and then calls it.
Of course, I'm a WinAPI noob, so I hope others who are more knowledgeable will correct me if I am wrong.
I had an exe using _tWinMain and Configuration Properties.Linker.System.Subsystem: Windows (/SUBSYSTEM:WINDOWS). Later I wanted it to support cmdline args and print to the console so I added:
// We need to printf to stdout and we don't have one, so get one
AllocConsole();
// Redirect pre-opened STDOUT to the console
freopen_s((FILE **)stdout, "CONOUT$", "w", stdout);
but that only worked by printing in another console window that went away so was not that useful. Below is the way I changed it to work with Console (/SUBSYSTEM:CONSOLE) in such a way as I could go back and forth, if I needed to.
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
UNREFERENCED_PARAMETER(argc);
UNREFERENCED_PARAMETER(argv);
UNREFERENCED_PARAMETER(envp);
return (_tWinMain(NULL, NULL, ::GetCommandLineW(), 0));
}
ReferenceURL : https://stackoverflow.com/questions/13871617/winmain-and-main-in-c-extended
'developer tip' 카테고리의 다른 글
WPF : UserControl에서 표시하는 대화 상자의 소유자 창을 어떻게 설정합니까? (0) | 2021.01.09 |
---|---|
Python Selenium으로 요소가 존재하는지 확인 (0) | 2021.01.09 |
특별한 경우로 빈 문자열? (0) | 2021.01.08 |
PHP에서 이미지 조각을 사용하여 모양을 그리는 방법 (0) | 2021.01.08 |
Java에서 런타임에 열거 요소를 추가하고 제거 할 수 있습니까? (0) | 2021.01.08 |