Win32 API를 이용한 윈도우 창 예제




 




http://soen.kr/



#ifndef UNICODE #define UNICODE #endif #include <windows.h> #include <tchar.h> #include <string> // DX Header #include <d3d11.h> // DirectX 11 헤더 #include <d3dcompiler.h> // 쉐이더 컴파일러 기능 // lib 링킹 #pragma comment(lib,"d3d11.lib") #pragma comment(lib, "d3dcompiler.lib") /* 전역변수 */ std::wstring className = TEXT("Sample Window Class"); std::wstring title = TEXT("STL Render Engine"); HINSTANCE hInstance = nullptr; int width = 640; int height = 480; HWND hwnd = nullptr; //DX 변수 //DX 장치 ID3D11Device* device = nullptr; ID3D11DeviceContext* context = nullptr; IDXGISwapChain* swapChain = nullptr; void InitializeDevice(); LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); int WINAPI wWinMain( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nShowCmd) { // Register the window class. ::hInstance = hInstance; // ::전역 변수를 쓴다는 의미 //const wchar_t CLASS_NAME[] = L"Sample Window Class"; //const wchar_t CLASS_NAME[] = TEXT("Sample Window Class"); // #include <tchar.h> WNDCLASS wc = { }; //memset(&wc, 0, sizeof(wc)); 이거랑 같은 의미. 초기화. // Invoke (함수를 내 대신 누군가 호출을 해주는구나... wc.lpfnWndProc = WindowProc; // 롱 포인터 펑션 프로시저 호출. 콜백(Callback). 간접 호출. 위임(Delegate) wc.hInstance = hInstance; wc.lpszClassName = className.c_str(); // 창 클래스 이름을 등록해준다 RegisterClass(&wc); // Create the window. // 창 크기 조정. // RECT는 직사각형 구조체다. (left,top,right,bottom) //RECT rect = { 0, 0, width, height }; RECT rect = { 0, 0, static_cast<long>(width), static_cast<long>(height) }; AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE); int windowWidth = rect.right - rect.left; int windowHeight = rect.bottom - rect.top; // 화면 중심에서 창을 그려라 int xPosition = (GetSystemMetrics(SM_CXSCREEN) - windowWidth) / 2; int yPosition = (GetSystemMetrics(SM_CYSCREEN) - windowHeight) / 2; hwnd = CreateWindowEx( // 창을 만들고 핸들 값을 만든다 0, // Optional window styles. className.c_str(), // Window class title.c_str(), // Window text WS_OVERLAPPEDWINDOW, // Window style // Size and position xPosition, yPosition, windowWidth, windowHeight, nullptr, // Parent window nullptr, // Menu hInstance, // Instance handle nullptr // Additional application data ); if (hwnd == nullptr) // 창을 만들지 못했으면 핸들값(포인터) 생성을 못 했으므로 프로그램 종료해버린다 { return 0; } ShowWindow(hwnd, SW_SHOW); UpdateWindow(hwnd); //창 생성 //DX 초기화 // Run the message loop. // WM_QUIT가 아니라면 계속 수행 MSG msg = { }; while (msg.message != WM_QUIT) //GetMessage(수동적) 말고 Peek(능동적)이 있다 { // 윈도우가 메시지 전달하면 실행 //if (GetMessage(&msg, NULL, 0, 0) > 0) // NULL은 부모 창 포인터 get은 계속 대기해야 하므로 필요한 메시지만 받는 peek을 사용한다 if(PeekMessage(&msg,nullptr,0u,0u,PM_REMOVE)) { // 윈도우(OS)가 전달한 메시지 해석 및 전달 (WindowsProc 함수 호출) TranslateMessage(&msg); DispatchMessage(&msg); } else { // 일반적인 수행과정 // GameLoop // Rendering // ProcessInput // Update // Render // Postrender } } // 창 등록 해제 UnregisterClass(className.c_str(), hInstance); return 0; } void InitializeDevice() { unsigned int createFlag = 0; #if _DEBUG // debug 모드인 경우 // 장치 생성 과정에서 오류 발생 하면 createFlag |= D3D11_CREATE_DEVICE_DEBUG; #endif D3D_FEATURE_LEVEL levels[] = { D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, }; //스왑체인 생성을 위한 구조체 설정 DXGI_SWAP_CHAIN_DESC swapChainDesc = {}; swapChainDesc.BufferCount = 1; //백버퍼 개수 설정 , 최소 1개 이상 swapChainDesc.BufferDesc.Width = width; // 프레임 가로크기 swapChainDesc.BufferDesc.Height = height; // 프레임 세로크기 swapChainDesc.BufferDesc.Format= DXGI_FORMAT_R8G8B8A8_UNORM; //이미지 채널별 포맷 swapChainDesc.Windowed = true; // 프레임(이미지)의 용도 (렌더링) swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // 임시 버퍼를 만들어서 화면 출력용으로 쓰겠다 swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; // front->back 버퍼 변경할 때 효과 넣을지 설정 (그래픽 카드의 성능에 맡기겠다!) swapChainDesc.SampleDesc.Count = 1; //멀티 샘플링 할지 여부 설정 -> 안함 -> 안티앨리어싱 관련 swapChainDesc.SampleDesc.Quality = 0; //멀티 샘플링 품질 설정 -> 기본값 (count -1) swapChainDesc.OutputWindow = hwnd; D3D_FEATURE_LEVEL finalFeature; //장치 초기화 //D3D11CreateDevice // 모니터 해상도 스펙 정보까지 가져옴 auto result = D3D11CreateDeviceAndSwapChain( // HRESULT 성공 여부 값을 반환 받는다 nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, createFlag, levels, //ARRAYSIZE(levels), _countof(levels), D3D11_SDK_VERSION, &swapChainDesc, &swapChain, &device, &finalFeature, &context ); //실패 여부 확인 if (FAILED(result)) { MessageBox(nullptr, L"Failed to Creat Device.",L"Error",MB_OK); exit(-1); } } LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_DESTROY: // 창 삭제(종료)가 되었을 때 받는 메시지. { PostQuitMessage(0); return 0; // 메인 함수에서는 워낙 일반적이라 자동으로 처리해 주는 거임. } case WM_KEYDOWN: { if (wParam == VK_ESCAPE) { if (MessageBox(nullptr, TEXT("ESC키를 눌렀군요. 끝낼까요?"), TEXT("테스트창"), MB_YESNO) == IDYES) { DestroyWindow(hwnd); } } return 0; } case WM_MOUSEWHEEL: { if (MessageBox(nullptr, TEXT("마우스 휠 돌렸죠? 끝낼까요?"), TEXT("테스트창"), MB_YESNO) == IDYES) { DestroyWindow(hwnd); } return 0; } case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd, &ps); // All painting occurs here, between BeginPaint and EndPaint. FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1)); EndPaint(hwnd, &ps); return 0; } } return DefWindowProc(hwnd, uMsg, wParam, lParam); }




0 comments:

댓글 쓰기