하늘소프트SDK API 문서

Win32 샘플 1 - 단일 윈도우에 전자해도 그리기


이 예제는 하늘소프트의 전자해도 커널 사용을 위한 최소 설정을 보여주는 것으로 전자해도 커널의 초기화/종료, ENC 파일의 로드 및 가장 기본적인 해도의 화면 표시에 대한 기본 코딩 과정을 보여준다. 마우스나 키보드 등의 입력 이벤트에 대한 처리는 이 예제에는 포함되어 있지 않다.

코드


커널 초기화

단순하게 hencInit() 함수를 실행하고 반환값을 체크하는 것으로 초기화는 마무리된다.
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
	if( 0 > hencInit() ) {
		MessageBox( GetDesktopWindow(), _T( "hnsEnc 초기화 실패" ), _T( "오류" ), MB_OK );
		return FALSE;
	}
    ...
    return TRUE;
}

해도 파일 로드

커널 초기화 후 해도 데이터 파일을 메모리에 로드한다. 카탈로그 파일을 통해 한 번에 로드할 수도 있지만 이 예제에서는 배경 지도 및 개별 해도 파일을 하나씩 불러오는 예를 보여 주도록 하였다.
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
	if( 0 > hencInit() ) {
		MessageBox( GetDesktopWindow(), _T( "hnsEnc 초기화 실패" ), _T( "오류" ), MB_OK );
		return FALSE;
	}

    TCHAR szBaseDir[1024];
	getPgmDir( GetModuleHandle( NULL ), szBaseDir, 1000 );
	SetCurrentDirectory( szBaseDir );
	hencLoad( _T( "SHP\\CNTRY92.SENC" ) ); // Load 세계지도 배경 SENC. index=0
	hencLoad( _T( "SENC\\KR1A0000.SENC" ) ); // Load 한국 지도 SENC. index=1
	hencLoad( _T( "SENC\\KR1B0000.SENC" ) ); // Load 한국 지도 SENC. index=2
	hencLoad( _T( "SENC\\KR1C0000.SENC" ) ); // Load 한국 지도 SENC. index=3
	hencLoad( _T( "SENC\\KR1D0000.SENC" ) ); // Load 한국 지도 SENC. index=4
	hencLoad( _T( "SENC\\KR1E0000.SENC" ) ); // Load 한국 지도 SENC. index=5
	hencLoad( _T( "SENC\\KR1EN000.SENC" ) ); // Load 한국 지도 SENC. index=6
	hencLoad( _T( "SENC\\KR1ES000.SENC" ) ); // Load 한국 지도 SENC. index=7
	hencLoad( _T( "SENC\\KR1F0000.SENC" ) ); // Load 한국 지도 SENC. index=8
	hencLoad( _T( "SENC\\KR1G0000.SENC" ) ); // Load 한국 지도 SENC. index=9
	hencLoad( _T( "SENC\\KR1H0000.SENC" ) ); // Load 한국 지도 SENC. index=10
	hencLoad( _T( "SENC\\KR1I0000.SENC" ) ); // Load 한국 지도 SENC. index=11
	hencLoad( _T( "SENC\\KR1J0000.SENC" ) ); // Load 한국 지도 SENC. index=12
	hencLoad( _T( "SENC\\KR1K0000.SENC" ) ); // Load 한국 지도 SENC. index=13
	hencLoad( _T( "SENC\\KR1L0000.SENC" ) ); // Load 한국 지도 SENC. index=14
	hencLoad( _T( "SENC\\KR1M0000.SENC" ) ); // Load 한국 지도 SENC. index=15
	hencLoad( _T( "SENC\\KR1N0000.SENC" ) ); // Load 한국 지도 SENC. index=16
	hencLoad( _T( "SENC\\KR1O0000.SENC" ) ); // Load 한국 지도 SENC. index=17
	hencLoad( _T( "SENC\\KR1P0000.SENC" ) ); // Load 한국 지도 SENC. index=18

    ...
    return TRUE;
}

엔진 생성/초기화

hencCreate()를 사용하여 내부적으로 사용될 OpenGL 렌더링 컨텍스트와 DC 핸들을 생성하고, hencSelect() 함수를 사용하여 현재 윈도우와 커널을 연결한다. 어플리케이션 종료시에는 hencDelete() 함수를 사용하여 생성된 OpenGL 렌더링 컨텍스트와 DC 핸들을 제거해 주어야 한다.

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;

	switch (message) {
		case WM_CREATE :
			hencCreate( hWnd );
			hencSelect( hWnd );
			hencSetCenter( 132, 37 );
			hencSetScale( 1500000 );
			break;
        ...
        case WM_DESTROY:
			hencDelete( hWnd );
			PostQuitMessage(0);
			break;
    }
    ...
}

해도 표시

아래의 WM_PAINT 메시지의 처리코드와 같이 구현하도록 한다. hencRender() 후에 hencCopyBuffer()를 하면 전시된 화면에 HDC를 사용해서 GDI 함수를 바로 이용할 수 있어서 GDI에 익숙한 사용자들도 해도 위에 임의의 그래픽 오브젝트를 그릴 수 있다. 이 부분에 대한 실 구현 예는 해도 위에 그래픽 객체 그리기 예제를 통해 익힐 수 있다.
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;

	switch (message) {
        ...
		case WM_PAINT:
			{
				PAINTSTRUCT ps;
				HDC hdc = BeginPaint(hWnd, &ps);

				RECT r;
				GetClientRect( hWnd, &r );
				hencSelect( hWnd );
				hencSetViewport( 0, 0, r.right - r.left, r.bottom - r.top );
				hencClearBackground();
				hencRender();
				hencCopyBuffer();
				EndPaint(hWnd, &ps);
			}
			break;
		case WM_ERASEBKGND :
			return TRUE;
		case WM_DESTROY:
			hencDelete( hWnd );
			PostQuitMessage(0);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

커널 종료

어플리케이션 종료 수 메시지 루프 아래 부분에 hencDeinit() 함수를 실행하여 커널을 종료한다.

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
    ...

	// 응용 프로그램 초기화를 수행합니다.
	if (!InitInstance (hInstance, nCmdShow))
	{
		return FALSE;
	}

	hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_SAMPLE));

	// 기본 메시지 루프입니다.
	while (GetMessage(&msg, NULL, 0, 0))
	{
		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}


	hencDeinit();
	return (int) msg.wParam;
}
				


실행 화면


스크린샷 원본 미보관

보관된 원본 이미지가 없어 표시할 수 없습니다. 위 코드와 설명을 참고해 주십시오.

win32_sample01_01.png

[그림 1-1] 기본적인 해도 전시




전체 코드


stdafx.h

// stdafx.h : 자주 사용하지만 자주 변경되지는 않는
// 표준 시스템 포함 파일 및 프로젝트 관련 포함 파일이
// 들어 있는 포함 파일입니다.
//

#pragma once

#include "targetver.h"

#include "../lib/hnsEnc/hnsEnc.h"
#include "../lib/hnsEnc/hnsEnc_lib.h"

#define WIN32_LEAN_AND_MEAN             // 거의 사용되지 않는 내용은 Windows 헤더에서 제외합니다.
// Windows 헤더 파일:
#include <windows.h>

// C 런타임 헤더 파일입니다.
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>

Sample.h

#pragma once

#include "resource.h"

Sample.cpp

// Sample.cpp : 응용 프로그램에 대한 진입점을 정의합니다.
//

#include "stdafx.h"
#include "Sample.h"

#define MAX_LOADSTRING 100

// 전역 변수:
HINSTANCE hInst;								// 현재 인스턴스입니다.
TCHAR szTitle[MAX_LOADSTRING];					// 제목 표시줄 텍스트입니다.
TCHAR szWindowClass[MAX_LOADSTRING];			// 기본 창 클래스 이름입니다.

// 이 코드 모듈에 들어 있는 함수의 정방향 선언입니다.
ATOM				MyRegisterClass(HINSTANCE hInstance);
BOOL				InitInstance(HINSTANCE, int);
LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK	About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);

 	// TODO: 여기에 코드를 입력합니다.
	MSG msg;
	HACCEL hAccelTable;

	// 전역 문자열을 초기화합니다.
	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
	LoadString(hInstance, IDC_SAMPLE, szWindowClass, MAX_LOADSTRING);
	MyRegisterClass(hInstance);

	// 응용 프로그램 초기화를 수행합니다.
	if (!InitInstance (hInstance, nCmdShow))
	{
		return FALSE;
	}

	hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_SAMPLE));

	// 기본 메시지 루프입니다.
	while (GetMessage(&msg, NULL, 0, 0))
	{
		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}


	hencDeinit();
	return (int) msg.wParam;
}



//
//  함수: MyRegisterClass()
//
//  목적: 창 클래스를 등록합니다.
//
//  설명:
//
//    Windows 95에서 추가된 'RegisterClassEx' 함수보다 먼저
//    해당 코드가 Win32 시스템과 호환되도록
//    하려는 경우에만 이 함수를 사용합니다. 이 함수를 호출해야
//    해당 응용 프로그램에 연결된
//    '올바른 형식의' 작은 아이콘을 가져올 수 있습니다.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX 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_SAMPLE));
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= MAKEINTRESOURCE(IDC_SAMPLE);
	wcex.lpszClassName	= szWindowClass;
	wcex.hIconSm		= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

	return RegisterClassEx(&wcex);
}

//
//   함수: InitInstance(HINSTANCE, int)
//
//   목적: 인스턴스 핸들을 저장하고 주 창을 만듭니다.
//
//   설명:
//
//        이 함수를 통해 인스턴스 핸들을 전역 변수에 저장하고
//        주 프로그램 창을 만든 다음 표시합니다.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
	if( 0 > hencInit() ) {
		MessageBox( GetDesktopWindow(), _T( "hnsEnc 초기화 실패" ), _T( "오류" ), MB_OK );
		return FALSE;
	}

	TCHAR szBaseDir[1024];
	getPgmDir( GetModuleHandle( NULL ), szBaseDir, 1000 );
	SetCurrentDirectory( szBaseDir );
	hencLoad( _T( "SHP\\CNTRY92.SENC" ) ); // Load 세계지도 배경 SENC. index=0
	hencLoad( _T( "SENC\\KR1A0000.SENC" ) ); // Load 한국 지도 SENC. index=1
	hencLoad( _T( "SENC\\KR1B0000.SENC" ) ); // Load 한국 지도 SENC. index=2
	hencLoad( _T( "SENC\\KR1C0000.SENC" ) ); // Load 한국 지도 SENC. index=3
	hencLoad( _T( "SENC\\KR1D0000.SENC" ) ); // Load 한국 지도 SENC. index=4
	hencLoad( _T( "SENC\\KR1E0000.SENC" ) ); // Load 한국 지도 SENC. index=5
	hencLoad( _T( "SENC\\KR1EN000.SENC" ) ); // Load 한국 지도 SENC. index=6
	hencLoad( _T( "SENC\\KR1ES000.SENC" ) ); // Load 한국 지도 SENC. index=7
	hencLoad( _T( "SENC\\KR1F0000.SENC" ) ); // Load 한국 지도 SENC. index=8
	hencLoad( _T( "SENC\\KR1G0000.SENC" ) ); // Load 한국 지도 SENC. index=9
	hencLoad( _T( "SENC\\KR1H0000.SENC" ) ); // Load 한국 지도 SENC. index=10
	hencLoad( _T( "SENC\\KR1I0000.SENC" ) ); // Load 한국 지도 SENC. index=11
	hencLoad( _T( "SENC\\KR1J0000.SENC" ) ); // Load 한국 지도 SENC. index=12
	hencLoad( _T( "SENC\\KR1K0000.SENC" ) ); // Load 한국 지도 SENC. index=13
	hencLoad( _T( "SENC\\KR1L0000.SENC" ) ); // Load 한국 지도 SENC. index=14
	hencLoad( _T( "SENC\\KR1M0000.SENC" ) ); // Load 한국 지도 SENC. index=15
	hencLoad( _T( "SENC\\KR1N0000.SENC" ) ); // Load 한국 지도 SENC. index=16
	hencLoad( _T( "SENC\\KR1O0000.SENC" ) ); // Load 한국 지도 SENC. index=17
	hencLoad( _T( "SENC\\KR1P0000.SENC" ) ); // Load 한국 지도 SENC. index=18

   HWND hWnd;

   hInst = hInstance; // 인스턴스 핸들을 전역 변수에 저장합니다.

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

//
//  함수: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  목적: 주 창의 메시지를 처리합니다.
//
//  WM_COMMAND	- 응용 프로그램 메뉴를 처리합니다.
//  WM_PAINT	- 주 창을 그립니다.
//  WM_DESTROY	- 종료 메시지를 게시하고 반환합니다.
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;

	switch (message) {
		case WM_CREATE :
			hencCreate( hWnd );
			hencSelect( hWnd );
			hencSetCenter( 132, 37 );
			hencSetScale( 1500000 );
			break;
		case WM_COMMAND:
			wmId    = LOWORD(wParam);
			wmEvent = HIWORD(wParam);
			// 메뉴 선택을 구문 분석합니다.
			switch (wmId)
			{
				case IDM_ABOUT:
					DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
					break;
				case IDM_EXIT:
					DestroyWindow(hWnd);
					break;
				default:
					return DefWindowProc(hWnd, message, wParam, lParam);
			}
			break;
		case WM_PAINT:
			{
				PAINTSTRUCT ps;
				HDC hdc = BeginPaint(hWnd, &ps);

				RECT r;
				GetClientRect( hWnd, &r );
				hencSelect( hWnd );
				hencSetViewport( 0, 0, r.right - r.left, r.bottom - r.top );
				hencClearBackground();
				hencRender();
				hencCopyBuffer();
				EndPaint(hWnd, &ps);
			}
			break;
		case WM_ERASEBKGND :
			return TRUE;
		case WM_DESTROY:
			hencDelete( hWnd );
			PostQuitMessage(0);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

// 정보 대화 상자의 메시지 처리기입니다.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	UNREFERENCED_PARAMETER(lParam);
	switch (message)
	{
	case WM_INITDIALOG:
		return (INT_PTR)TRUE;

	case WM_COMMAND:
		if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
		{
			EndDialog(hDlg, LOWORD(wParam));
			return (INT_PTR)TRUE;
		}
		break;
	}
	return (INT_PTR)FALSE;
}