^(코딩캣)^ = @"코딩"하는 고양이;
썸네일 이미지
[Windows API] 크리티컬 섹션을 사용하여 스레드간 변수 공유
Windows API 본 시리즈에서는 Windows API 개별 함수에 대해 간략한 사용법 및 응용에 대해 정리한다. 이전 게시글: 스레드의 생존 여부 확인하기 다음 게시글: OutputDebugString을 printf처럼 서식(포맷) 적용하여 사용하기 크리티컬 섹션을 사용하여 스레드간 변수 공유 본 포스팅에서는 크리티컬 섹션(CRITICAL_SECTION) 구조체를 사용하여 스레드간 변수를 공유하는 방법에 대해 정리한다. CRITICAL_SECTION 스레드간 공유하고자 하는 변수와 함께 CRITICAL_SECTION 구조체 변수를 선언한다. /* 스레드간 공유하고자 하는 정수형 변수 */ DWORD g_dwInteger = 0; /* 상기 정수형 변수에 접근하려면 아래 구조체를 통해 권한을 얻어야 ..
API/Windows API
2019. 12. 19. 11:19

[Windows API] 크리티컬 섹션을 사용하여 스레드간 변수 공유

API/Windows API
2019. 12. 19. 11:19

Windows API


본 시리즈에서는 Windows API 개별 함수에 대해 간략한 사용법 및 응용에 대해 정리한다.

이전 게시글: 스레드의 생존 여부 확인하기

다음 게시글: OutputDebugString을 printf처럼 서식(포맷) 적용하여 사용하기

 

크리티컬 섹션을 사용하여 스레드간 변수 공유


본 포스팅에서는 크리티컬 섹션(CRITICAL_SECTION) 구조체를 사용하여 스레드간 변수를 공유하는 방법에 대해 정리한다.

 

CRITICAL_SECTION


스레드간 공유하고자 하는 변수와 함께 CRITICAL_SECTION 구조체 변수를 선언한다.

/* 스레드간 공유하고자 하는 정수형 변수 */
DWORD g_dwInteger = 0;
/* 상기 정수형 변수에 접근하려면 아래 구조체를 통해 권한을 얻어야 한다. */
CRITICAL_SECTION g_stCriticalSection;

 

InitializeCriticalSection


CRITICAL_SECTION 구조체를 사용하기 위해서는 반드시 리셋되어야 한다. 구조체를 리셋하는 함수는 InitializeCriticalSection이다.

VOID InitializeCriticalSection(
    LPCRITICAL_SECTION lpCriticalSection 
);

 

lpCriticalSection 매개변수를 통해 리셋할 CRITICAL_SECTION을 지정한다.

InitializeCriticalSection(&g_stCriticalSection);

 

EnterCriticalSection, LeaveCriticalSection


VOID EnterCriticalSection(
    LPCRITICAL_SECTION lpCriticalSection  
);
BOOL TryEnterCriticalSection(
    LPCRITICAL_SECTION lpCriticalSection
);
VOID LeaveCriticalSection(
    LPCRITICAL_SECTION lpCriticalSection
);

스레드간 공유 변수에 접근할 때 EnterCriticalSection으로 크리티컬 섹션에 진입하고 공유 변수 사용이 끝나면 LeaveCriticalSection으로 크리티컬 섹션을 벗어난다. EnterCriticalSection은 타 스레드에서 크리티컬 섹션을 사용하고 있을 때 대기한다. 대기과정(현재 스레드의 중지) 없이 즉시 사용중 여부를 확인하고자 하면 TryEnterCriticalSection을 사용한다. 임계영역에 진입했다면 TRUE를 반환하고 그렇지 못했다면 FALSE를 반환한다.

EnterCriticalSection(&g_stCriticalSection);
{
    /* ... g_dwInteger에 대한 읽고 쓰기 */
}
LeaveCriticalSection(&g_stCriticalSection);

 

실행 예제


다음은 크리티컬 섹션의 실행 예이다. 창에 대한 스레드, 콘솔창에 대한 스레드 총 2개의 스레드가 실행중이며 콘솔창으로 1부터 30까지 센 후 콘솔창은 닫힌다. 창의 버튼을 클릭하면 콘솔창에서 세고 있는 숫자는 1로 리셋된다. 이 과정에서 크리티컬 섹션이 사용된다.

크리티컬 섹션을 사용하여 공유 변수가 수정될 수 있다.
카테고리 “API/Windows API”
more...
썸네일 이미지
[단막 Windows API] 스레드의 생존 여부 확인하기
단막 Windows API 스레드의 생존 여부 확인하기 본 포스팅에서는 특정 핸들(HANDLE)에 대한 스레드의 생존 여부, 다시 말해서 현재 실행중인지 종료되었는지 여부를 확인하는 방법을 정리한다. GetExitCodeThread 스레드의 생존 여부를 확인할 수 있는 함수로는 GetExitCodeThread가 있다. 이 함수의 원형은 다음과 같다. BOOL GetExitCodeThread( HANDLE hThread, LPDWORD lpExitCode ); hThread는 생존 여부를 확인하고자 하는 스레드의 핸들(HANDLE)이다. lpExitCode를 통해 특정 스레드의 생존 또는 종료 코드를 얻을 수 있다. 생존 여부를 확인할 수 있으면 TRUE를 반환하고 그렇지 않으면(즉, 오류가 발생하면) F..
API/Windows API
2019. 12. 18. 22:57

[단막 Windows API] 스레드의 생존 여부 확인하기

API/Windows API
2019. 12. 18. 22:57

단막 Windows API


스레드의 생존 여부 확인하기


본 포스팅에서는 특정 핸들(HANDLE)에 대한 스레드의 생존 여부, 다시 말해서 현재 실행중인지 종료되었는지 여부를 확인하는 방법을 정리한다.

 

GetExitCodeThread


스레드의 생존 여부를 확인할 수 있는 함수로는 GetExitCodeThread가 있다. 이 함수의 원형은 다음과 같다.

BOOL GetExitCodeThread(
    HANDLE hThread,
    LPDWORD lpExitCode
);

 

hThread는 생존 여부를 확인하고자 하는 스레드의 핸들(HANDLE)이다. lpExitCode를 통해 특정 스레드의 생존 또는 종료 코드를 얻을 수 있다.

생존 여부를 확인할 수 있으면 TRUE를 반환하고 그렇지 않으면(즉, 오류가 발생하면) FALSE를 반환한다. 이 때 오류 내용은 GetLastError 함수로 확인 가능하다.

스레드의 생존 여부를 위해 GetExitCodeThread를 호출하는 예이다.

BOOL fResult = FALSE;
DWORD dwExitCode = 0;
/* ... */
fResult = GetExitCodeThread(/* THREAD */, &dwExitCode);

 

위와 같이 호출하여 dwExitCode의 값이 STILL_ACTIVE이면 해당 스레드는 현재 실행중인 상태임을 의미한다. 해당 스레드가 종료되었다면, 종료 당시 스레드 프로시저가 리턴한 값이 보관된다. 여기서 알 수 있는 사실은, 스레드 프로시저를 작성할 때 종료 코드를 STILL_ACTIVE와 중복시키면 안 된다는 사실이다. STILL_ACTIVE의 실제 값은 정수 259이다.

 

실행 예제


static TCHAR szTextBuffer[4096];
HANDLE hThread = /* CreateThread(...) */;
DWORD dwErrorCode = 0;
/* ... */
GetExitCodeThread(hThread, &dwErrorCode);
if (dwErrorCode == STILL_ACTIVE) {
    _stprintf(szTextBuffer, TEXT("WM_USER: hThread = %08p, dwErrorCode = STILL_ACTIVE\n"), hThread);
} else {
    _stprintf(szTextBuffer, TEXT("WM_USER: hThread = %08p, dwErrorCode = %08lx\n"), hThread, dwErrorCode);
}
OutputDebugString(szTextBuffer);
/* ... */

 

버튼으로 채워진 창을 하나 열고, 이 창이 열릴 때 오랜 시간이 걸리는 작업을 수행하는 콘솔창도 하나 더 띄운다. 이 콘솔창은 스레드가 종료되면 자동으로 닫힌다. 버튼을 클릭하면 GetExitCodeThread을 실행하여 해당 스레드의 생존 여부를 디버그 출력창으로 보일 것이다.

스레드가 실행중일 때는 STILL_ACTIVE 값이 반환된다.

 

스레드가 종료되었을 때는 해당 프로시저의 리턴 값을 알 수 있다.
카테고리 “API/Windows API”
more...
[Win32 문자열 종류와 상호 변환 방법] Part 3 - COM/.NET 문자열 (完)
Win32 C/C++ 문자열 종류와 상호 변환 방법 Win32 C/C++에는 문자열을 나타내는 자료형이 다양하다. 그리고 그 자료형마다 용도와 역할이 있기 때문에 어느 하나만을 선택해서 사용할 수도 없다. 본 포스트에서는 이전 포스트에 이어서 Win32 C/C++에서 사용하는 문자열의 종류 중 COM, .NET에서 사용하는 문자열에 대해 설명하고 상호 변환 방법에 대해 설명하겠다. 1. BSTR, __bstr_t, CComBSTR BSTRBasic String / Binary String은 COM에서 표준으로 사용하는 문자열이다. 이 문자열은 마지막에 NULL 문자가 붙지 않는 대신 문자열의 맨 앞에 4바이트 정수로 크기를 명시하는 특징이 있다. 그렇기 때문에 Win32 C/C++에서 문자열 리터럴을 B..
Microsoft Windows/Win32 문자열 처리
2019. 3. 11. 11:13

[Win32 문자열 종류와 상호 변환 방법] Part 3 - COM/.NET 문자열 (完)

Microsoft Windows/Win32 문자열 처리
2019. 3. 11. 11:13

Win32 C/C++ 문자열 종류와 상호 변환 방법


Win32 C/C++에는 문자열을 나타내는 자료형이 다양하다. 그리고 그 자료형마다 용도와 역할이 있기 때문에 어느 하나만을 선택해서 사용할 수도 없다. 본 포스트에서는 이전 포스트에 이어서 Win32 C/C++에서 사용하는 문자열의 종류 중 COM, .NET에서 사용하는 문자열에 대해 설명하고 상호 변환 방법에 대해 설명하겠다.

 

1. BSTR, __bstr_t, CComBSTR


BSTRBasic String / Binary String은 COM에서 표준으로 사용하는 문자열이다. 이 문자열은 마지막에 NULL 문자가 붙지 않는 대신 문자열의 맨 앞에 4바이트 정수로 크기를 명시하는 특징이 있다. 그렇기 때문에 Win32 C/C++에서 문자열 리터럴을 BSTR형 객체에 보관하기 위해서는 다음과 같이 SysAllocString으로 동적할당을 수행하며, 사용이 완료된 객체는 SysFreeString으로 해제한다. 다음은 BSTR의 선언이다.

typedef OLECHAR * BSTR;

 

여기서 혼동하지 말아야 할 것은, BSTR이 문자열 앞에 문자수를 동반하지만, BSTR이 가리키는 포인터는 문자열 그 자체라는 것이다. 문자수를 얻고자 한다면 해당 포인터에서 4바이트 앞을 참조하면 되지만, 항상 4바이트일 것이라는 억측을 하면 안되므로 SysStringLen 함수로 하여금 문자 수를 대신 가져오게 한다.

또한 문자열 앞에 문자열의 길이를 명시하므로 문자열의 끝에 반드시 NULL 문자가 붙을 필요는 없다. 다른 말로 문자열 끝에 NULL 문자가 있을 것이라는 억측을 하면 안 된다. 그러므로 BSTR을 C-Style로 변환하기 위해서 강제 형변환하는 것보다는, 별도로 제공된 함수를 사용하는 것이 안전하다.

 

BSTR SysAllocString(
    OPT IN const OLECHAR * psz
);
void SysFreeString(
    BSTR bstrString
);
UINT SysStringLen(
    OPT IN BSTR bstr
);

 

이 함수를 사용하여 OLECHAR 문자열을 BSTR로 변환하고, 사용이 끝난 문자열을 해제해 보겠다.

/* Example */
OLECHAR ocs[] = OLESTR("테스트 문자열.");
BSTR bstr;

/* ... */

bstr = SysAllocString(ocs);

// ... BSTR로 처리될 작업

SysFreeString(bstr);

/* ... */

 

BSTR에서 OLECHAR 문자열로 변환하기 위해, 앞서 설명된 매크로 함수를 사용할 수 있다.

/* Example */
#include <atlconv.h>

BSTR bstr;
LPTSTR tcs = NULL;

/* ... */

USES_CONVERSION;
tcs = OLE2T(bstr);

/* ... */

 

1-2. __bstr_t, CComBSTR

__bstr_t와 CComBSTR은 공통적으로 BSTR 형 문자열과 관련 함수들을 하나의 클래스로 캡슐화 한 것이다. 다만, __bstr_t는 Compiler COM Support에서 사용하는 자료형으로서 comutil.h 헤더파일에 정의되어 있고, CComBSTR은 ATL에서 사용하는 자료형으로서 atlbase.h에 정의되어 있다는 차이가 있다. 여기서 Compiler COM Support는 COM을 지원하는 라이브러리 파일을 소스 코드에서 #import 구문으로 포함시켰을 때 컴파일러가 자동으로 내부 클래스와 메서드를 선언하는 구문을 생성하는 것을 뜻한다.

 

2. System::String ^

System::String ^은 .NET Framework에서 지원하는 System.String 형을 C++/CLI에서 부르는 명칭이다. 다음과 같이 생성자로 Multibyte String과 Wide String의 두 가지를 받을 수 있고, 메모리 고정을 통해 Wide String으로 변환할 수 있다.

/* Example */
TCHAR tcs1[] = TEXT("안녕하세요.");
TCHAR tcs2[56] = { TEXT('\0'), };

System::String ^ gcs = nullptr;
pin_ptr pcs = nullptr;

gcs = gcnew System::String(tcs1); // C-Style에서 관리되는 문자열로 변환
pcs = PtrToStringChars(gcs); // 관리되는 문자열에서 C-Style 버퍼 얻기

// wchar_t *가 필요한 곳에 pcs를 대입 가능

 

추가적으로 관리되는 배열을 C-Style 배열로 변환하는 소스 패턴은 다음과 같다.

/* Example */
cli::array^ origin = gcnew cli::array(/* ... */);
cli::pin_ptr conv = &origin[0];

// ... conv를 포인터 배열처럼 사용

 

참고 자료

pin_ptr (C++/CLI) - MSDN
https://msdn.microsoft.com/ko-kr/library/1dz8byfh.aspx
How to convert from System::String* to Char* in Visual C++ - MSDN
https://support.microsoft.com/en-us/help/311259/how-to-convert-from-system-string-to-char-in-visual-c
Working with strings in COM, MFC, Win32, STL / Unraveling Strings in Visual C++
https://www.johndcook.com/blog/cplusplus_strings/

 

 

카테고리 “Microsoft Windows/Win32 문자열 처리”
more...
[Win32 문자열 종류와 상호 변환 방법] Part 2 - Windows API 문자열
Win32 C/C++ 문자열 종류와 상호 변환 방법 Win32 C/C++에는 문자열을 나타내는 자료형이 다양하다. 그리고 그 자료형마다 용도와 역할이 있기 때문에 어느 하나만을 선택해서 사용할 수도 없다. 본 포스트에서는 이전 포스트에 이어서 Win32 C/C++에서 사용하는 문자열의 종류 중 Windows API에서 사용하는 문자열에 대해 설명하고 상호 변환 방법에 대해 설명하겠다. 1. CHAR, LPSTR, LPCSTR, WCHAR, LPWSTR, LPCWSTR, TCHAR, LPTSTR, LPCTSTR 지금까지의 설명의 C/C++의 표준 문자열이었다면 지금부터는 Win32에서 쓰이는 문자열 형에 대한 설명이다. 우선, Windows API에서 기본적으로 쓰이는 문자형은 CHAR과 WCHAR이다. ..
Microsoft Windows/Win32 문자열 처리
2019. 3. 11. 11:03

[Win32 문자열 종류와 상호 변환 방법] Part 2 - Windows API 문자열

Microsoft Windows/Win32 문자열 처리
2019. 3. 11. 11:03

Win32 C/C++ 문자열 종류와 상호 변환 방법


Win32 C/C++에는 문자열을 나타내는 자료형이 다양하다. 그리고 그 자료형마다 용도와 역할이 있기 때문에 어느 하나만을 선택해서 사용할 수도 없다. 본 포스트에서는 이전 포스트에 이어서 Win32 C/C++에서 사용하는 문자열의 종류 중 Windows API에서 사용하는 문자열에 대해 설명하고 상호 변환 방법에 대해 설명하겠다.

 

1. CHAR, LPSTR, LPCSTR, WCHAR, LPWSTR, LPCWSTR, TCHAR, LPTSTR, LPCTSTR


지금까지의 설명의 C/C++의 표준 문자열이었다면 지금부터는 Win32에서 쓰이는 문자열 형에 대한 설명이다. 우선, Windows API에서 기본적으로 쓰이는 문자형은 CHAR과 WCHAR이다. 각각은 표준 자료형을 다르게 이름붙인 것이다.

typedef char CHAR;
typedef wchar_t WCHAR;

 

두 종류의 문자가 각각 NULL 문자로 끝나는 C-Style 문자열로 구성될 경우 이를 LPSTR, LPWSTR이라 한다.

typedef CHAR * LPSTR;
typedef WCHAR * LPWSTR;

 

LPSTR과 LPWSTR이 상수 속성을 가질 경우 LPCSTR와 LPCWSTR이라 한다.

typedef CONST CHAR * LPCSTR;
typedef CONST WCHAR * LPCWSTR;

 

마지막으로 Visual Studio(Visual C++) 컴파일러의 설정에 따라 유니코드를 지원하면 Widechar를 쓰고 지원하지 않으면 ANSI 문자열을 사용하도록 가변적으로 설정한 문자열이 TCHAR, LPTSTR, LPCTSTR이다. 그리고 문자열 리터럴이 이에 맞춰 지정되도록 TEXT 매크로가 사용된다.

/* TCHAR, LPTSTR, LPCTSTR */
#ifdef _UNICODE
    typedef WCHAR TCHAR;
    typedef LPWSTR LPTSTR;
    typedef LPCWSTR LPCTSTR;
    #define TEXT(str) L##str
#else
    typedef CHAR TCHAR;
    typedef LPSTR LPTSTR;
    typedef LPCSTR LPCTSTR;
    #define TEXT(str) str
#endif

 

1-1. CHAR과 WCHAR간 상호변환


일반적으로 Windows API는 A로 끝나는 ANSI형(예: DrawTextA)과 W로 끝나는 Widechar형(예: DrawTextW)를 모두 선언한 뒤 TCHAR 형으로 컴파일러에 따라 매크로에 의해 전환하는 형태(예: DrawText)를 갖고 있다. 하지만, 명시적으로 Widechar 문자열과 ANSI 문자열을 상호 변환하고자 한다면 다음과 같은 Windows API를 사용한다.

int MultiByteToWideChar(
    IN UINT CodePage,
    IN DWORD dwFlags,
    IN LPCSTR lpMultiByteStr,
    IN INT cbMultiByte,
    OPT OUT LPWSTR lpWideCharStr,
    IN INT cchWideChar
);
int WideCharToMultiByte(
    IN UINT CodePage,
    IN DWORD dwFlags,
    IN LPCWSTR lpWideCharStr,
    IN INT cchWideChar,
    OPT OUT LPSTR lpMultiByteStr,
    IN INT cbMultiByte,
    OPT IN LPCSTR lpDefaultChar,
    OPT OUT LPBOOL lpUsedDefaultChar
);

 

CodePage
Multibyte 문자열에 대해 어떤 코드페이지를 기준으로 인코드되었는지(인코드 할 것인지)를 지정하는 옵션이다.
CP_ACP
현재 Windows의 기본 코드 페이지를 사용한다.
CP_THREAD_ACP
본 프로그램이 실행되는 Thread에 할당된 코드 페이지를 적용한다.
CP_UTF7 또는 CP_UTF8
UTF-7 또는 UTF-8로 인코드한다. 이 옵션을 사용할 경우 lpDefaultCharlpUsedDefaultChar 매개변수는 항상 NULL이어야 한다.
dwFlags
각종 플래그 옵션이다.
WC_COMPOSITECHECK
강세가 붙는 문자에 대해 기본 알파벳 + 강세표시로 분리하여 인코드한다. 이 옵션을 명시하지 않을 경우 강세 붙는 문자 그대로 인코드된다.
lpWideCharStr
변환할 또는 변환될 문자열을 수용하는 Widechar형 문자열 버퍼이다.
cchWideChar
lpWideCharStr의 버퍼의 크기이다. 단위는 문자 수이다. 상기 문자열이 NULL 문자로 끝나는 C-Style 문자열이면 이 매개변수는 -1을 전달해도 무방하다.
lpMultiByteStr
변환할 또는 변환될 문자열을 수용하는 Multibyte형 문자열 버퍼이다.
cbMultiByte
lpMultiByteStr의 버퍼의 크기이다. 단위는 바이트이다. 이 매개변수의 값으로 0을 전달할 경우 변환 시 필요한 버퍼의 바이트 수가 반환되며 상기 Multibyte형 문자열 버퍼 매개변수는 무시된다.
lpDefaultChar
특정 WCHAR에 대응하는 Multibyte 문자가 없는 경우(예: 유니코드에는 있는데 KS-X-1001/1002에는 없는 글자) 대체할 기본 문자이다. 단, UTF-7/UTF-8로 변환되는 경우 이 매개변수는 반드시 NULL이어야 한다.
lpUsedDefaultChar
상기 lpDefaultChar를 한번이라도 사용하게 된 경우가 생겼다면 이 매개변수로 TRUE가 출력된다. 이 매개변수를 사용할 필요가 없을 경우 NULL로 지정해도 무방하며, UTF-7/UTF-8로 변환하는 경우 이 매개변수는 반드시 NULL이어야 한다.

 

다음은 WCHAR형 문자열에서 CHAR형 문자열로 변환하는 예이다.

/* Example */
#include <windows.h>

/* ... */

WCHAR wcs[] = L"안녕하세요.";
CHAR mbs[56] = { '\0', };

WideCharToMultiByte(CP_ACP, 0, wcs, _countof(wcs), mbs, sizeof(mbs), NULL, NULL);

/* ... */

 

다음은 CHAR형 문자열에서 WCHAR형 문자열로 변환하는 예이다.

/* Example */
#include <windows.h>

/* ... */

CHAR mbs[] = "안녕하세요.";
WCHAR wcs[56] = { L'\0', };

MultiByteToWideChar(CP_ACP, 0, mbs, sizeof(mbs), wcs, _countof(wcs));

/* ... */

 

2. OLECHAR, LPOLESTR, LPCOLESTR


이 문자열은 ATLActive Template Library, OLEObject Linking and Embedding에서 정의된 문자열 중 하나이다. Windows 운영체제에서 이 문자열은 항상 WCHAR형 문자열과 같다. 구 Macintosh(현재의 OS X가 아닌 클래식 맥)에서 구동되던 COM/OLE에서는 이 문자열이 CHAR형 Multibyte 문자열과 같았다. 문자열 리터럴 상수를 이 문자열형에 대입하기 위해서는 OLESTR 매크로를 사용한다.

/* Definition */
#ifdef _WIN32
    typedef wchar_t OLECHAR;
    typedef wchar_t * LPOLESTR;
    typedef const wchar_t * LPCOLESTR;
    #define OLESTR(str) L##str
#else
    typedef char OLECHAR;
    typedef char * LPOLESTR;
    typedef const char * LPCOLESTR;
    #define OLESTR(str) str
#else

 

2-1. OLECHAR과 WCHAR 상호변환, OLECHAR과 CHAR 상호변환 OLECHAR과 TCHAR간 상호 변환


atlconv.h 헤더파일을 include하면 OLESTR, WCHAR, TCHAR, CHAR, BSTR간 상호 변환이 가능합니다. BSTR에 대해서는 다음 문단에 이어서 설명하고 여기에서는 OLESTR, WCHAR, TCHAR, CHAR간의 상호 변환만을 사용해보겠다.

OLECHAR에서 WCHAR로 변환하기 위한 함수는 다음과 같다.

  • OLE2W(LPOLESTR에서 LPWSTR)
  • OLE2CW(LPOLESTR에서 LPCWSTR)
  • COLE2W(LPCOLESTR에서 LPWSTR)
  • COLE2CW(LPCOLESTR에서 LPCWSTR)

 

OLESTR에서 CHAR로 변환하기 위한 함수는 다음과 같다.

  • OLE2A(LPOLESTR에서 LPSTR)
  • OLE2CA(LPOLESTR에서 LPCSTR)
  • COLE2A(LPCOLESTR에서 LPSTR)
  • COLE2CA(LPCOLESTR에서 LPCSTR)

 

OLESTR에서 TCHAR로 변환하기 위한 함수는 다음과 같다.

  • OLE2T(LPOLESTR에서 LPTSTR)
  • OLE2CT(LPOLESTR에서 LPCTSTR)
  • COLE2T(LPCOLESTR에서 LPTSTR)
  • COLE2CT(LPCOLESTR에서 LPCTSTR)

 

WCHAR에서 OLECHAR로 변환하기 위한 함수는 다음과 같다.

  • W2OLE(LPWSTR에서 LPOLESTR)
  • W2COLE(LPWSTR에서 LPCOLESTR)
  • CW2OLE(LPCWSTR에서 LPOLESTR)
  • CW2COLE(LPCWSTR에서 LPCOLESTR)

 

CHAR에서 OLECHAR로 변환하기 위한 함수는 다음과 같다.

  • A2OLE(LPSTR에서 LPOLESTR)
  • A2COLE(LPSTR에서 LPCOLESTR)
  • CA2OLE(LPCSTR에서 LPOLESTR)
  • CA2COLE(LPCSTR에서 LPCOLESTR)

 

TCHAR에서 OLECHAR로 변환하기 위한 함수는 다음과 같다.

  • T2OLE(LPTSTR에서 LPOLESTR)
  • T2COLE(LPTSTR에서 LPCOLESTR)
  • CT2OLE(LPCTSTR에서 LPOLESTR)
  • CT2COLE(LPCTSTR에서 LPCOLESTR)

 

위 함수를 사용하여 OLECHAR을 WCHAR, CHAR, TCHAR로 변환해보겠다. 이 함수들은 atlconv.h에 정의되어 있으며 호출 전에 USES_CONVERSION 매크로 호출을 필요로 합니다. 이 매크로는 내부적으로 로케일에 맞춰 리셋하는 것과 관련한 내용이 있다.

/* Example */
#include <windows.h>
#include <atlconv.h>

/* ... */

OLECHAR ocs[] = OLESTR("안녕하세요.");

LPTSTR tcs = NULL;
LPWSTR wcs = NULL;
LPSTR mbs = NULL;

LPCTSTR ctcs = NULL;
LPCWSTR cwcs = NULL;
LPCSTR cmbs = NULL;

USES_CONVERSION;

tcs = OLE2T(ocs);
wcs = OLE2W(ocs);
mbs = OLE2A(ocs);

ctcs = OLE2CT(ocs);
cwcs = OLE2CW(ocs);
cmbs = OLE2CA(ocs);

/* ... */

 

여기서 tcs, wcs, mbs 포인터는 각 변환함수로부터 반환된 포인터를 반환받는데, 이 포인터를 직접 해제할 필요는 없다. 오히려 해제하면 안 된다. 왜냐하면 MSDN이 이 버퍼는 정적 버퍼이므로 해제하지 않는다고 되어 있기 때문이다. 다만, 정적버퍼이기 때문에 너무 1MB를 넘는 긴 문자열을 이 함수를 통해 변환해서는 안될 것이다.

이번에는 이 ATL 매크로 함수를 사용하여 TCHAR, CHAR, WCHAR간 상호 변환에 대해 알아보겠다.

TCHAR과 CHAR간 변환하기 위한 함수는 다음과 같다.

  • T2A(LPTSTR에서 LPSTR)
  • T2CA(LPTSTR에서 LPCSTR)
  • CT2A(LPCTSTR에서 LPSTR)
  • CT2CA(LPCTSTR에서 LPCSTR)
  • A2T(LPSTR에서 LPSTR)
  • A2CT(LPSTR에서 LPCSTR)
  • CA2T(LPCSTR에서 LPSTR)
  • CA2CT(LPCSTR에서 LPCSTR)

 

TCHAR과 WCHAR간 변환하기 위한 함수는 다음과 같다.

  • T2W(LPTSTR에서 LPWSTR)
  • T2CW(LPTSTR에서 LPCWSTR)
  • W2T(LPWSTR에서 LPTSTR)
  • W2CT(LPWSTR에서 LPCTSTR)
  • CT2W(LPCTSTR에서 LPWSTR)
  • CT2CW(LPCTSTR에서 LPCWSTR)
  • CW2T(LPCWSTR에서 LPTSTR)
  • CW2CT(LPCWSTR에서 LPCTSTR)

 

CHAR과 WCHAR간 변환하기 위한 함수는 다음과 같다.

  • A2W(LPSTR에서 LPWSTR)
  • A2CW(LPSTR에서 LPCWSTR)
  • W2A(LPWSTR에서 LPSTR)
  • W2CA(LPWSTR에서 LPCSTR)
  • CA2W(LPCSTR에서 LPWSTR)
  • CA2CW(LPCSTR에서 LPCWSTR)
  • CW2A(LPCWSTR에서 LPSTR)
  • CW2CA(LPCWSTR에서 LPCSTR)

 

3. CString


CString은 MFCMicrosoft Foundation Class에서 사용하는 문자열로서 Multibyte String 또는 Wide String 및 각종 문자열 함수를 래핑한 자료형이다. C++ 클래스로 작성되었으며 생성자를 통해 다양한 형식의 문자열을 받아 내부적으로 자동 변환하므로 사용이 편하다.

다음은 CHAR, WCHAR, TCHAR 문자열을 각각 CString으로 변환하는 예이다.

/* Example */
#include <afxwin.h>

/* ... */

TCHAR tcs[] = TEXT("피자");
WCHAR wcs[] = L"햄버거";
CHAR mbs[] = "스파게티";

CString cst1 = CString(tcs);
CString cst2 = CString(wcs);
CString cst3 = CString(mbs);

/* ... */

 

CString에서 포인터 문자열로의 변환은 GetBuffer 함수로 수행한다. 이 때 반환형이 TCHAR임에 주의하기 바라며, 사용 후에는 반드시 ReleaseBuffer를 호출한다.

/* Example */
#include <afxwin.h>

/* ... */	

CString cst = CString(TEXT("안녕하세요."));
LPTSTR tcs = NULL;

tcs = cst.GetBuffer();

// ... 포인터 문자열에 대한 작업

cst.ReleaseBuffer();

/* ... */

 

3. 마무리

여기까지 해서 Windows API 및 ATL 문자열에 대해 설명하였다. 다음 포스트에서는 COM 문자열에 대해 설명하겠다.

 

 

카테고리 “Microsoft Windows/Win32 문자열 처리”
more...
[Win32 문자열 종류와 상호 변환 방법] Part 1 - C/C++ 기본 문자열
Win32 C/C++ 문자열 종류와 상호 변환 방법 Win32 C/C++에는 문자열을 나타내는 자료형이 다양하다. 그리고 그 자료형마다 용도와 역할이 있기 때문에 어느 하나만을 선택해서 사용할 수는 없고, 적절한 형태로 변환하는 과정이 일반적으로 쓰인다. 본 시리즈에서는 Win32 C/C++에서 사용하는 문자열의 종류에 대해 설명하고 상호 변환 방법에 대해 설명하겠다. 1. char, char *, const char * C/C++은 기본적으로 ASCII 코드로 인코딩된 ANSI 문자열을 지원한다. 가장 기본적인 문자와 문자열의 형태이다. charchar는 ASCII로 인코딩된 문자 하나를 표현하는 자료형으로서 1바이트의 크기를 갖는다. char *char *는 ASCII 문자로 구성되며 항상 끝이 1바..
Microsoft Windows/Win32 문자열 처리
2019. 3. 11. 10:52

[Win32 문자열 종류와 상호 변환 방법] Part 1 - C/C++ 기본 문자열

Microsoft Windows/Win32 문자열 처리
2019. 3. 11. 10:52

Win32 C/C++ 문자열 종류와 상호 변환 방법


Win32 C/C++에는 문자열을 나타내는 자료형이 다양하다. 그리고 그 자료형마다 용도와 역할이 있기 때문에 어느 하나만을 선택해서 사용할 수는 없고, 적절한 형태로 변환하는 과정이 일반적으로 쓰인다. 본 시리즈에서는 Win32 C/C++에서 사용하는 문자열의 종류에 대해 설명하고 상호 변환 방법에 대해 설명하겠다.

 

1. char, char *, const char *


C/C++은 기본적으로 ASCII 코드로 인코딩된 ANSI 문자열을 지원한다. 가장 기본적인 문자와 문자열의 형태이다.

char
char는 ASCII로 인코딩된 문자 하나를 표현하는 자료형으로서 1바이트의 크기를 갖는다.
char *
char *는 ASCII 문자로 구성되며 항상 끝이 1바이트의 NULL 문자로 끝나는 문자열을 나타내는 자료형이다.
const char *
const char *는 ASCII 문자로 구성되며 항상 끝이 1바이트의 NULL 문자로 끝나는 문자열 상수를 나타내는 자료형이다.

 

문자열과 문자열 상수에 대해 좀 더 설명하자면, 둘 다 끝이 NULL 문자로 끝나야 하는 특징이 있지만 문자열은 중간의 일부 문자를 변경할 수 있고 문자열 상수는 변경이 불가하다. 또한 문자열은 주로 버퍼에 복사된 문자열을 뜻하고, 문자열 상수는 주로 소스 코드를 작성할 때 처음부터 정해진 문자열을 뜻한다. 소스 코드에서부터 정해진 문자열은 실행파일 내에 내장되고, 프로그램이 적재될 때 함께 메모리에 로드되며 이는 프로그램이 진행되는 내내 변경될 수 없다.

 

1-1. Multibyte ANSI String


영어권 이외의 국가에서는 자국의 문자를 표현하기 위해 확장 ASCII 영역을 새롭게 정의해서 사용한다. 그러나 이것으로도 글자를 표현하기에 부족한 경우(예: 완성형 한글 및 한자)에는 확장 ASCII 문자 2개를 묶어서 자국의 문자를 할당하기도 하였다. 여기에서 영문자는 1바이트, 한글/한자는 2바이트 크기라는 규칙이 생겼다. 이러한 인코딩으로 된 문자열을 부르는 명칭에는 여러가지가 있겠으나 여기에서는 Multibyte ANSI String이라 하겠다.

Multibyte ANSI String도 컴퓨터의 입장에서는 ASCII 코드이므로 char *, const char * 형으로 표현가능하다. 단 자국 문자는 기본 2바이트이기 때문에 1 문자를 char 단독으로 저장할 수 없다. 예를 들어,

char a = 'A'; // 가능하다.
char b = '가'; // 불가능하다.

 

2. wchar_t, wchar_t *, const wchar_t *


영어권 이외의 국가를 고려하여 모든 문자가 n바이트의 크기를 갖는 Widechar 문자열을 지원하는 형식이다. Multibyte가 문자의 종류마다 1 문자당 크기(바이트)가 달라졌다면, Widechar는 모든 문자가 1 바이트 이상의 동일한 크기를 갖는 차이가 있다. 일반적으로 Windows 운영체제에서는 wchar_t의 크기가 2 바이트이며 UCS-2로 인코딩된다. Linux 운영체제에서는 wchar_t의 크기가 4 바이트이며 UCS-4로 인코딩되지만 컴파일러 설정에 따라 Windows 방식과 동일하게 변경 가능하다. (그러나 wchar_t를 쓸 경우 반드시 유니코드로 처리된다는 규칙은 없으므로 코딩에 참고하기 바란다.)

wchar_t
wchar_t는 Widechar로 표현된 1개 문자이다.
wchar_t *
wchar _t *는 Widechar로 표현된 문자열이며 1바이트 이상의 크기를 갖는 NULL 문자로 끝난다.
const wchar_t *
const wchar_t *wchar_t *와 동일하지만 상수 특성을 갖는다.

 

2-1. 문자열 리터럴 접두어


문자열 상수를 유니코드 문자열로 정의하기 위해서는 문자열 앞에 접두어를 붙이면 된다. C++11에서 정의된 문자열 리터럴literal 접두어의 종류로는 아무것도 안 붙임, L, u8, u, U의 5가지가 있다.

"문자열"
표준 ASCII 문자 및 Multibyte 문자로 구성된 ANSI 문자열이다.
L"문자열"
Widechar 문자로 구성된 문자열이다. 일반적으로 유니코드로 인코드된다.

 

이외의 문자열에 대해서는 다음 문단에서 이어진다.

 

3. 유니코드 문자로서의 char, char16_t, char32_t


char는 경우에 따라 ASCII 문자를 나타낼 때도 쓰이지만 유니코드(UTF-8) 문자를 나타낼 때도 쓰인다. 이는 일반적인 로마자에 대하여 ASCII와 Unicode가 호환되기 때문이다. 물론 로마자 이외의 문자는 유니코드로 표현된 char라고 해도 문자의 종류에 따라 Multibyte처럼 여러 바이트에 걸쳐져서 표현된다.

char16_tchar32_t는 C++11부터 도입된 자료형으로 uchar.h 또는 cuchar에 정의되어 있습니다. 각각 UTF-16과 UTF-32로 인코드된 문자 및 문자열을 표현할 때 사용된다.

 

2-1. 유니코드 문자열 리터럴의 접두어


문자열 상수를 유니코드 문자열로 인코드 하고자 할 때는 u8, u, U의 세가지 중 하나를 사용한다.

u8"문자열"
문자열 상수를 UTF-8로 저장한다. 이 때는 char 자료형으로 문자와 문자열을 표현한다.
u"문자열"
문자열 상수를 UTF-16으로 저장한다. 이 때는 char16_t 자료형으로 문자와 문자열을 표현한다.
U"문자열"
문자열 상수를 UTF-32로 저장한다. 이 때는 char32_t 자료형으로 문자와 문자열을 표현한다.

 

4. Multibyte - Widechar간 상호 변환


지금까지는 C/C++ 표준에 정의된 자료형에 대한 설명이었다. 위 세 종류의 자료형으로된 문자열 및 문자열 상수를 상호변환해 보겠다.

Multibyte(ANSI 문자의 char 형)와 Widechar(wchar_t 형)의 상호 변환은 wctomb, mbtowc, wcstombs 또는 mbstowcs를 사용한다. 전자는 1개 문자를 변환하고 후자는 문자열을 변환하며 stdlib.h 또는 cstdlib 헤더파일에 정의되어 있다.

int mbtowc (wchar_t * pwc, const char * pmb, size_t max); // Multibyte에서 Widechar로 1개 문자를 변환
size_t mbstowcs (wchar_t * dest, const char * src, size_t max); // Multibyte에서 Widechar로 문자열을 변환
int wctomb(char * pmb, wchar_t wc); // Multibyte에서 Widechar로 1개 문자를 변환
size_t wcstombs(char * dest, const wchar_t * src, size_t max); // Multibyte에서 Widechar로 문자열을 변환

 

4-1. Wide Character에서 Multibyte Character로 변환


다음은 1개의 문자를 Widechar에서 Multibyte로 변환하는 예이다.

/* C++ Source */
#include <cstdlib>
#include <cassert>
#include <clocale>

using namespace std;

/* ... */

wchar_t wc = L'가'; // 변환할 1개의 Wide Character
char mbc[8] = { 0, }; // 인코딩을 고려할 때 1개의 Wide Character에 대한 충분한 Multi Byte 공간을 제공합니다. 대체로 1개 문자당 8 바이트를 부여하면 충분하다.
int mbn = 0; // 해당 문자가 Multibyte Character로 변환시 실제로 몇 바이트를 차지하는지 확인한다.

setlocale(LC_ALL, ""); // 변환에 앞서 프로그램의 로케일을 시스템에서 기본으로 설정한 로케일로 리셋한다.

/* 1개의 Wide Character를 Multibyte Character로 변환한다. */
/* 이 때 변환된 Multibyte Character의 바이트 수를 반환받는다. */
/* 지정한 Wide Character가 현재의 로케일에서 표현할 수 없는 문자일 때, -1이 반환된다. */
assert((mbn = wctomb(mbc, wc)) != -1);

printf("Wide Character = %lc [%d byte(s)]\n", wc, sizeof(wc));
printf("Multibyte Character = %s [%d byte(s)]\n", mbc, mbn);

/* ... */

 

4-2. Wide String에서 Multibyte String으로 변환


다음은 Wide 문자열(wchar_t *)에서 Multibyte 문자열(char */ANSI)로 변환하는 예이다.

/* C++ Source */
#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <clocale>

using namespace std;

/* ... */

wchar_t wcs[] = L"안녕하세요."; // 변환할 Wide String
char mbs[112] = { 0, }; // 인코딩을 고려할 때 1개의 Wide Character에 대한 충분한 Multi Byte 공간을 제공합니다. 대체로 1개 문자당 8 바이트를 부여하면 남아돕니다.
int mbn = 0; // 해당 문자가 Multibyte Character로 변환시 실제로 몇 바이트를 차지하는지 확인합니다.

setlocale(LC_ALL, ""); // 변환에 앞서 프로그램의 로케일을 시스템에서 기본으로 설정한 로케일로 리셋합니다.

/* Wide String을 Multibyte String으로 변환한다. */
/* 이 때 변환된 Multibyte String의 바이트 수를 반환받는다. */
/* 지정한 Wide Character가 현재의 로케일에서 표현할 수 없는 문자일 때, ((size_t)(-1))이 반환된다. */
/* ((size_t)(-1))은 컴파일러에 따라 0xFFFF, 0xFFFFFFFF, 0xFFFFFFFFFFFFFFFF 중 하나를 말한다. */
assert((mbn = wcstombs(mbs, wcs, sizeof(mbs))) != ((size_t)(-1)));

printf("Wide String = %ls [%d byte(s)]\n", wcs, sizeof(wcs));
printf("Multibyte Character = %s [%d byte(s)]\n", mbs, mbn);

/* ... */

 

4-3. Multibyte Character에서 Wide Character으로 변환


다음은 Multibyte Character를 Wide Character로 변환하는 예이다.

/* C++ Source */
#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <clocale>

using namespace std;

/* ... */

char mbc[] = "가"; // 1개의 문자를 n바이트에 저장
size_t mbn = sizeof(mbc) - 1; // 끝의 NULL을 제외한 순수 1글자의 크기(바이트)
wchar_t wc[4] = { L'\0', }; // 1개의 문자를 1개의 Widechar에 저장, Surrogate로 변환될 것을 가정하여 1문자당 최대 4개의 wchar_t를 확보해 놓으면 넉넉하다.

setlocale(LC_ALL, ""); // 변환에 앞서 프로그램의 로케일을 시스템에서 기본으로 설정한 로케일로 리셋한다.

/* Multibyte Character를 Wide Character로 변환한다. */
/* 이 로케일에서 정의하는 문자가 Wide Character로 표현될 수 없을 경우 -1을 반환한다. */
assert(mbtowc(wc, mbc, mbn) != -1); 

printf("Multibyte Character = %s [%d byte(s)]\n", mbc, mbn);
printf("Wide Character = %ls [%d byte(s)]\n", wc, sizeof(wc));

/* ... */

 

4-4. Multibyte String에서 Wide String으로 변환


다음은 Multibyte 문자열을 Widechar 문자열로 변환하는 예이다.

/* C++ Source */
#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <clocale>

/* ... */

char mbs[] = "안녕하세요."; // 변환할 Multibyte String
wchar_t wcs[28] = { L'\0', }; // 인코딩을 고려할 때 1개의 Multibyte Character에 대한 충분한 Wide String 공간을 제공한다. Surrogate로 변환될 것을 가정하여 1개 문자당 최대 4개의 wchar_t를 확보해 놓으면 넉넉하다. 
size_t wcn = 0; // 실제로 변환되어 생성된 문자 수를 받아온다.

setlocale(LC_ALL, ""); // 변환에 앞서 프로그램의 로케일을 시스템에서 기본으로 설정한 로케일로 리셋한다.

/* Multibyte String를 Wide String으로 변환한다. */
/* 이 로케일에서 정의하는 문자가 Wide String으로 표현될 수 없을 경우 -1을 반환한다. */	
assert((wcn = mbstowcs(wcs, mbs, sizeof(wcs) / sizeof(wchar_t))) != ((size_t)(-1)));

/* ... */

 

4-5. (덧) Multibyte String과 Wide String의 문자 개수 세는 방법


strlen 함수는 문자열을 구성하는 모든 문자가 표준 ASCII 코드로 표현된 ANSI 문자일 경우에 유효하다. 그러나 KS 완성형 코드나 JIS 코드 등 특정 인코딩을 사용하는 시스템일 경우 strlen 함수가 반환하는 문자의 수가 실제와 다르다. Multibyte String일 때 사용하는 함수는 mblen이다.

int mblen (const char* pmb, size_t max);
pmb
문자의 개수를 구하고자 하는 Multibyte String이다.
max
pmb 버퍼의 최대 크기이다.

 

Wide String의 문자수를 세는 함수는 wcslen이다. 사용법은 strlen과 같다.

 

5. Wide Character - Unicode간 상호 변환


Wide Character/String과 Unicode간 변환을 지원하는 표준 함수는 이 포스트가 작성된 현재 없다. 이 경우 다음에 설명되는 Windows API를 사용한다.

 

6. Multibyte Character - Unicode간 상호 변환


Multibyte Character와 UTF-16/UTF-32간 변환은 표준 함수로 제공된다. 그 외 UTF-7/UTF-8은 이 포스트가 작성된 현재 표준에 없다. 이 경우 다음에 설명되는 Windows API를 사용한다.

 

6-1. Multibyte Character에서 UTF-16으로 변환


Multibyte Character에서 UTF-16 Character로 변환하기 위해서는 mbrtoc16 함수를 사용합니다.

/* C++ Source */
#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <clocale>
#include <cuchar>

using namespace std;

/* ... */

char mbc[8] = "가";
char16_t uc[8] = { '\0', };
mbstate_t mbstate = { 0 };

setlocale(LC_ALL, "");
assert((mbn = mbrtoc16(uc, mbc, sizeof(mbc), &mbstate)) != (size_t)(-1));

/* ... */

 

6-2. UTF-16에서 Multibyte Character으로 변환


UTF-16 Character에서 Multibyte Character로 변환하기 위해서는 c16rtomb 함수를 사용한다.

/* C++ Source */
#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <clocale>
#include <cuchar>

using namespace std;

/* ... */

char16_t uc = u'가';
char mbc[8] = { '\0', };
size_t mbn = 0;
mbstate_t mbstate = { 0 };

setlocale(LC_ALL, "");

assert((mbn = c16rtomb(mbc, uc, &mbstate)) != (size_t)(-1));

/* ... */

 

6-3. Multibyte Character에서 UTF-32으로 변환


Multibyte Character에서 UTF-32 Character로 변환하기 위해서는 mbrtoc32 함수를 사용한다.

/* C++ Source */
#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <clocale>
#include <cuchar>

using namespace std;

/* ... */

char mbc[8] = "가";
char32_t uc[8] = { U'\0', };
mbstate_t mbstate = { 0 };

setlocale(LC_ALL, "");
assert((mbn = mbrtoc32(uc, mbc, sizeof(mbc), &mbstate)) != (size_t)(-1));

/* ... */

 

6-4. UTF-32에서 Multibyte Character으로 변환

UTF-32 Character에서 Multibyte Character로 변환하기 위해서는 c32rtomb 함수를 사용한다.

/* C++ Source */
#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <clocale>
#include <cuchar>

using namespace std;

/* ... */

char32_t uc = U'가';
char mbc[8] = { '\0', };
size_t mbn = 0;
mbstate_t mbstate = { 0 };

setlocale(LC_ALL, "");

assert((mbn = c32rtomb(mbc, uc, &mbstate)) != (size_t)(-1));

/* ... */

 

7. 마무리

여기까지 해서 Win32 C/C++ 문자열 중 C/C++ 표준 문자열 타입에 대해 알아보았다. 다음 포스트에서는 Windows API에서 정의된 기본 문자열 타입에 대해 알아보겠다.

 

 

카테고리 “Microsoft Windows/Win32 문자열 처리”
more...
썸네일 이미지
[단막 Windows API 활용법] Windows API 폰트 변경하기
단막 Windows API 활용법 Windows API 폰트 변경하기 Windows API로 UI를 만들 경우 폰트가 다음과 같이 투박하게 보여짐을 확인할 수 있다. 기본적으로 투박한 폰트로 보여지는 Windows API 윈도우 본 포스팅에서는 Windows API로 작성한 윈도우에 폰트를 적용하는 방법에 대해 정리하겠다. 시스템 정의 기본 폰트 사용하기 시스템 정의 기본 폰트는 제목 표시줄, 메시지 박스, 메뉴, 상태 표시줄, 캡션 표시줄 등에 사용되기 위해 미리 정의된 폰트이다. 이를 불러오기 위해서는 SystemParametersInfo 함수를 SPI_GETNONCLIENTMETRICS 매개변수를 적용하여 호출한다. WndProc 콜백 프로시저의 WM_CREATE 섹션에 다음과 같이 적는다. /* ..
API/Windows API
2019. 1. 20. 20:51

[단막 Windows API 활용법] Windows API 폰트 변경하기

API/Windows API
2019. 1. 20. 20:51

단막 Windows API 활용법


Windows API 폰트 변경하기


Windows API로 UI를 만들 경우 폰트가 다음과 같이 투박하게 보여짐을 확인할 수 있다.

기본적으로 투박한 폰트로 보여지는 Windows API 윈도우

 

본 포스팅에서는 Windows API로 작성한 윈도우에 폰트를 적용하는 방법에 대해 정리하겠다.

 

시스템 정의 기본 폰트 사용하기


시스템 정의 기본 폰트는 제목 표시줄, 메시지 박스, 메뉴, 상태 표시줄, 캡션 표시줄 등에 사용되기 위해 미리 정의된 폰트이다. 이를 불러오기 위해서는 SystemParametersInfo 함수를 SPI_GETNONCLIENTMETRICS 매개변수를 적용하여 호출한다.

WndProc 콜백 프로시저의 WM_CREATE 섹션에 다음과 같이 적는다.

/* WndProc: HWND, UINT, WPARAM, LPARAM */
// 새로 지정할 폰트 핸들
static HFONT s_hFont = (HFONT)NULL;
// 시스템 정의 폰트는 NONCLIENTMETRICS라는 구조체를 통해 전달된다.
NONCLIENTMETRICS nonClientMetrics;
/* ... */
// 구조체의 내용을 0으로 리셋한다.
ZeroMemory(&nonClientMetrics, sizeof(NONCLIENTMETRICS));
// cbSize 필드만 특별히 구조체의 크기로 지정한다.
nonClientMetrics.cbSize = sizeof(NONCLIENTMETRICS);

// 구조체를 통해 전달되는 폰트는 LOGFONT 형식이다.
// GDI에서 사용하기 위해 LOGFONT에서 기술된 폰트 정보를 바탕으로 HFONT를 생성한다.
s_hFont = CreateFontIndirect(&nonClientMetrics.lfCaptionFont);

// 창 스스로에게 WM_SETFONT 메시지를 전달한다.
SendMessage(hWnd, WM_SETFONT, (WPARAM)s_hFont, (LPARAM)MAKELONG(TRUE, 0));

 

자기 자신에게 WM_SETFONT를 전달했으므로 WndProc에서 WM_SETFONT 섹션을 추가하여 이벤트를 처리해보겠다. 다음은 그 예이다.

/* WndProc: HWND, UINT, WPARAM, LPARAM */
// 새로 지정할 폰트 핸들
static HFONT s_hFont = (HFONT)NULL;
// 시스템 정의 폰트는 NONCLIENTMETRICS라는 구조체를 통해 전달된다.
NONCLIENTMETRICS nonClientMetrics;
/* ... */
lResult = DefWindowProc(hWnd, uMessage, wParam, lParam);
// Static 윈도우에 폰트 변경 메시지를 보낸다.
SendMessage(s_hwndStatic, WM_SETFONT, wParam, lParam);
/* ... */

 

다음과 같이 윈도우의 폰트가 변경되었음을 확인할 수 있다.

시스템 정의 기본 폰트로 변경된 모습

 

LOGFONT 직접 지정하기


시스템 기본 폰트 외에 다른 폰트를 지정해보겠다. LOGFONT 구조체의 각 멤버들을 직접 지정하면 다양한 폰트들을 얻어서 윈도우에 적용 가능하다.

이번에는 굴림, 10 포인트를 LOGFONT를 활용해 적용한다.

/* WndProc: HWND, UINT, WPARAM, LPARAM */
HDC hDC = (HDC)NULL;
LOGFONT logFont;
/* ... */

/* 굴림, 10 포인트로 폰트 설정 */
ZeroMemory(&logFont, sizeof(LOGFONT));
hDC = GetDC(hWnd);
\logFont.lfHeight = -MulDiv(10, GetDeviceCaps(hDC, LOGPIXELSY), 72);
logFont.lfWeight = FW_NORMAL;
_tcscpy(logFont.lfFaceName, TEXT("Gulim"));
s_hFont = CreateFontIndirect(&logFont);
ReleaseDC(hDC);

/* ... */

 

10 포인트의 굴림으로 적용된 모습

 


카테고리 “API/Windows API”
more...
썸네일 이미지
[단막 Windows API 활용법] OpenFolderDialog 열기
단막 Windows API 활용법 OpenFolder Dialog 열기 [폴더 찾아보기...] 종류의 버튼을 클릭할 때 나오는 다이얼로그를 Windows API에서 어떻게 호출하고, 그 선택된 폴더 경로를 가져오는 방법에 대해 설명한다. 이 기능은 쉘shell에 대한 기능이므로 쉘 함수를 사용하기 위하여 #include 를 포함한다. 레이아웃 설정 빈 화면에 다음과 같이 윈도우들을 배치하도록 WndProc을 작성한다. /* WndProc: HWND, UINT, WPARAM, LPARAM */ static HWND s_hwndStatic1 = (HWND)NULL; static HWND s_hwndStatic2 = (HWND)NULL; static HWND s_hwndStatic3 = (HWND)NULL; ..
API/Windows API
2019. 1. 20. 16:15

[단막 Windows API 활용법] OpenFolderDialog 열기

API/Windows API
2019. 1. 20. 16:15

단막 Windows API 활용법


OpenFolder Dialog 열기


[폴더 찾아보기...] 종류의 버튼을 클릭할 때 나오는 다이얼로그를 Windows API에서 어떻게 호출하고, 그 선택된 폴더 경로를 가져오는 방법에 대해 설명한다.

이 기능은 쉘shell에 대한 기능이므로 쉘 함수를 사용하기 위하여

#include <ShlObj.h>

를 포함한다.

 

레이아웃 설정


빈 화면에 다음과 같이 윈도우들을 배치하도록 WndProc을 작성한다.

/* WndProc: HWND, UINT, WPARAM, LPARAM */
static HWND s_hwndStatic1 = (HWND)NULL;
static HWND s_hwndStatic2 = (HWND)NULL;
static HWND s_hwndStatic3 = (HWND)NULL;
static HWND s_hwndStatic4 = (HWND)NULL;
static HWND s_hwndEdit = (HWND)NULL;
static HWND s_hwndButton = (HWND)NULL;
/* ... */
case WM_CREATE:
	s_hwndStatic1 = CreateWindow
	(
		TEXT("STATIC"),
		TEXT("폴더 경로를 입력하시오."),
		WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE,
		0, 0, 300, 30,
		hWnd,
		(HMENU)ID_STATIC1,
		g_hInstance,
		(LPVOID)NULL
	);
	s_hwndEdit = CreateWindow
	(
		TEXT("EDIT"),
		TEXT(""),
		WS_CHILD | WS_VISIBLE | WS_THICKFRAME,
		0, 30, 180, 30,
		hWnd,
		(HMENU)ID_EDIT,
		g_hInstance,
		(LPVOID)NULL
	);
	s_hwndButton = CreateWindow
	(
		TEXT("BUTTON"),
		TEXT("찾아보기(&B)..."),
		WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
		180, 30, 105, 30,
		hWnd,
		(HMENU)ID_BUTTON,
		g_hInstance,
		(LPVOID)NULL
	);
	s_hwndStatic2 = CreateWindow
	(
		TEXT("STATIC"),
		TEXT("폴더 이름은 :"),
		WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE,
		0, 60, 150, 30,
		hWnd,
		(HMENU)ID_STATIC2,
		g_hInstance,
		(LPVOID)NULL
	);
	s_hwndStatic3 = CreateWindow
	(
		TEXT("STATIC"),
		TEXT(""),
		WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE,
		150, 60, 150, 30,
		hWnd,
		(HMENU)ID_STATIC3,
		g_hInstance,
		(LPVOID)NULL
	);
	s_hwndStatic4 = CreateWindow
	(
		TEXT("STATIC"),
		TEXT("^(코딩캣)^ = @\"코딩\"하는 고양이."),
		WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE,
		0, 90, 300, 30,
		hWnd,
		(HMENU)ID_STATIC3,
		g_hInstance,
		(LPVOID)NULL
	);
	break;
/* ... */

 

WM_CREATE 메시지 처리에서 지정한 레이아웃의 실행 결과

 

폴더 다이얼로그 띄우기


위와 같이 레이아웃을 구성한 다음 [찾아보기(B)...] 버튼(ID_BUTTON, s_hwndButton)을 클릭하여 폴더 다이얼로그를 띄우도록 하겠다. WM_COMMAND에서 LOWORD(wParam) 값이 ID_BUTTON인 경우에 다음과 같이 이벤트를 처리한다.

/* WndProc: HWND, UINT, WPARAM, LPARAM */
case WM_COMMAND:
	switch (LOWORD(wParam))
	{
	case ID_BUTTON:
		{
			BROWSEINFO browseInfo;
			ITEMIDLIST * pidlBrowse = NULL;
			TCHAR szPath[MAX_PATH];
			TCHAR szDisplayName[MAX_PATH];

			ZeroMemory(&browseInfo, sizeof(BROWSEINFO));

			// 본 다이얼로그를 소유한 창의 핸들이다.
			browseInfo.hwndOwner = hWnd;

			// 여기서 지정한 특정 폴더 이하의 경로만 선택 가능하다.
			browseInfo.pidlRoot = (LPCITEMIDLIST)NULL;

			// 폴더의 실제 이름과 보여지는 이름이 다를 때 지정한 버퍼로 보여지는 이름을 전달한다.
			browseInfo.pszDisplayName = szDisplayName; 

			// 폴더 다이얼로그를 통해 사용자에게 보여질 메시지를 지정한다.
			browseInfo.lpszTitle = TEXT("선택하고 싶은 폴더를 선택합니다...");
				
			// 각종 옵션을 지정한다.
			browseInfo.ulFlags =
				BIF_NEWDIALOGSTYLE | // 새로운 형식의 다이얼로그([새 폴더 만들기] 버튼 있는 창)
				BIF_RETURNONLYFSDIRS | // 로컬 경로의 디렉토리만 선택 가능하도록 함
				BIF_EDITBOX; // 폴더 이름을 타자로도 입력할 수 있도록 텍스트 상자 제공함

			// 다이얼로그 창에 대한 콜백을 지정한다.
			browseInfo.lpfn = BrowseProc;

			// 콜백 함수에 전달할 추가적인 데이터가 있다면 이것을 통해 전달한다.
			browseInfo.lParam = (LPARAM)NULL;

			// 폴더 열기 다이얼로그를 실행한다.
			pidlBrowse = SHBrowseForFolder(&browseInfo);
			if (pidlBrowse != NULL)
			{
				// 다이얼로그에서 선택한 폴더 항목을 문자열 경로로 변환한다.
				if (SHGetPathFromIDList(pidlBrowse, szPath))
				{
					// 경로를 Edit로 출력하고
					SetWindowText(s_hwndEdit, szPath);
					// 선택한 폴더의 DisplayName도 Static으로 출력한다.
					SetWindowText(s_hwndStatic3, szDisplayName);
				}
				else
				{
					OutputDebugString(TEXT("Invalid Path\n"));
				}
			}
		}
		break;
/* ... */

 

BROWSEINFO 구조체의 ulFlags에 지정 가능한 옵션은 MSDN(https://docs.microsoft.com/ko-kr/windows/desktop/api/shlobj_core/ns-shlobj_core-_browseinfoa)을 참조하면 된다.

 

BIF_NEWDIALOGSTYLE를 적용한 다이얼로그
BIF_NEWDIALOGSTYLE를 적용하지 않은 다이얼로그

 

콜백 프로시저


다이얼로그의 콜백 프로시저는 다음과 같이 선언한다.

int CALLBACK BrowseProc(HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData)

 

다음은 콜백 함수의 구현 예시이다.

/* BrowseProc: HWND, UINT, LPARAM, LPARAM */
int CALLBACK BrowseProc(HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{
	static TCHAR s_szPath[MAX_PATH];
	int iResult = 0;

	switch (uMsg)
	{
	case BFFM_INITIALIZED:
		// 다이얼로그 상자가 이제 막 떴을 때 처리할 내용은 이 곳에 적는다.

		// BFFM_SETSELECTION: 기본 값으로 선택하고 있을 폴더가 있을 때 사용한다.
		// lParam은 선택하고 있을 폴더이다.
		// lParam이 텍스트 형식의 경로라면 wParam = TRUE
		// lParam이 PIDL 형식의 객체라면 wParam = FALSE
		SendMessage(hWnd, BFFM_SETSELECTION, TRUE, lParam);

		// BFFM_SEROKTEXT: [확인] 버튼의 텍스트를 변경한다.
		// lParam은 [확인] 버튼에 새로 넣을 텍스트이다.
		SendMessage(hWnd, BFFM_SETOKTEXT, 0, (LPARAM)TEXT("이걸로"));
		break;
	case BFFM_SELCHANGED:
		
		if (SHGetPathFromIDList((LPITEMIDLIST)lParam, s_szPath))
		{
			if (_tcsstr(s_szPath, TEXT("blocked")))
			{
				// 예를 들어,
				// 경로 중 일부 문자에 "blocked"가 포함되면 확인버튼 비활성화.

				// BFFM_ENABLEOK: [확인] 버튼을 활성화/비활성화 한다.
				// lParam은 [확인] 버튼의 활성화(TRUE) / 비활성화(FALSE) 여부이다.
				SendMessage(hWnd, BFFM_ENABLEOK, 0, FALSE);
			}
			else
			{
				SendMessage(hWnd, BFFM_ENABLEOK, 0, TRUE);

				// BFFM_SETSTATUSTEXT: 현재 선택한 폴더 경로를 다이얼로그의 Text 속성으로 지정함.
				// lParam은 새로 선택된 폴더 경로
				SendMessage(hWnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)s_szPath);
			}
		}
		break;
	case BFFM_VALIDATEFAILED:
		// 다이얼로그에 전달된 문자열이 잘못되었을 때 처리할 내용은 이 곳에 적는다.

		// 다이얼로그를 계속 띄우고 있으려면 콜백이 Non-zero를 반환한다.
		// 다이얼로그를 닫으려면 콜백이 0을 반환한다.
		break;
	}

	return 0;
}

 

실행 결과

 

위 그림은 C:\Users를 선택한 후 [확인] 버튼을 누른 결과이다. 해당 폴더의 실제 이름은 Users이지만 한국어 모드에서는 사용자라는 이름으로 표시된다. 이것은 BROWSERINFO.pszDisplayName멤버로 전달된다.

카테고리 “API/Windows API”
more...
썸네일 이미지
HLP 형식의 윈도우 도움말 제작하기 #5 [完]
HLP 형식의 윈도우 도움말 제작하기 본 시리즈에서는 윈도우 도움말 형식 중 하나인 HLP 형식의 도움말을 생성하기 위한 방법에 대해 정리한다. 참고로 HLP 파일은 Windows XP까지만 열기가 지원된다. HLP 형식의 윈도우 도움말 제작하기 #1 HLP 형식의 윈도우 도움말 제작하기 #2 HLP 형식의 윈도우 도움말 제작하기 #3 HLP 형식의 윈도우 도움말 제작하기 #4 HLP 형식의 윈도우 도움말 제작하기 #5 [完] HLP 형식의 윈도우 도움말 제작하기 #5 (완결) HLP 도움말은 Windows 3.1부터 Windows XP까지 지원하던 도움말 형식으로서, 내부적으로는 여러개의 RTF 문서 파일로 이루어져 있다. Windows Vista 이후에 출시되는 Windows 운영체제(Vista, 2..
Microsoft Windows/Win32 도움말 연동
2018. 11. 19. 18:06

HLP 형식의 윈도우 도움말 제작하기 #5 [完]

Microsoft Windows/Win32 도움말 연동
2018. 11. 19. 18:06

HLP 형식의 윈도우 도움말 제작하기


본 시리즈에서는 윈도우 도움말 형식 중 하나인 HLP 형식의 도움말을 생성하기 위한 방법에 대해 정리한다. 참고로 HLP 파일은 Windows XP까지만 열기가 지원된다.

  1. HLP 형식의 윈도우 도움말 제작하기 #1
  2. HLP 형식의 윈도우 도움말 제작하기 #2
  3. HLP 형식의 윈도우 도움말 제작하기 #3
  4. HLP 형식의 윈도우 도움말 제작하기 #4
  5. HLP 형식의 윈도우 도움말 제작하기 #5 [完]

HLP 형식의 윈도우 도움말 제작하기 #5 (완결)


HLP 도움말은 Windows 3.1부터 Windows XP까지 지원하던 도움말 형식으로서, 내부적으로는 여러개의 RTF 문서 파일로 이루어져 있다. Windows Vista 이후에 출시되는 Windows 운영체제(Vista, 2008, 7, 2010, 8, 2012, 8.1, 10, ...)에서는 공식적으로 지원하지는 않는다. 이번 시리즈에서는 HLP 도움말을 제작하고, WinAPI에서 이를 불러오는 방법까지 알아보겠다.

준비물: 1. Windows XP 또는 그 이전 버전 운영체제, 2. Microsoft Word (아무 버전이나), 3. Microsoft Visual Studio 6.0

 

WinAPI에서 hlp 도움말 호출하기


WinAPI에서 .hlp 파일 내의 내용을 띄워주기 위해서는 .hlp 파일을 구성하는 각 파일마다 프로그램적으로 구분 가능한 일련번호가 부여되어야 한다. 프로젝트 화면에서 [Map...] 버튼을 누른다. "Map" 대화상자가 뜨면 [Add...] 버튼을 눌러 "App Map Entry" 대화상자를 연다.

"Topic ID:"에는 .rtf 파일에서 '#' 각주로 지정한 문서의 ID를 적고, "Mapped numeric value:"에는 .hlp 파일 내에서 중복되지 않는 유일한 값을 임의로 부여한다. "Comment:"에는 간단한 설명을 붙일 수 있다.

 

프로젝트 화면에 [MAP] 항목이 새로 나타나면서 위에서 적었던 내용들이 나타난다면 컴파일한다.

 

여기서부터는 코딩이 시작된다. Visual C++를 실행한다. Win32 Application을 선택하여 새로 만든다.

 

소스 파일이 있는 경로와 출력 파일(.exe 파일)이 있는 경로에 각각 Help Workshop에서 만든 .cnt 파일과 .hlp 파일을 붙여넣는다.

 

WinAPI로 버튼을 하나 만든 다음, 버튼을 클릭 시 메시지를 처리하는 부분에서 아래의 함수를 호출해본다.

WinHelp(소유주가 되는 창의 핸들, TEXT(".hlp파일명"), HELP_CONTEXT, 보여줄 문서의 일련번호);

 

이 함수의 원형은 다음과 같다. 성공하면 TRUE를 반환하고 그렇지 않으면 FALSE를 반환한다.

BOOL WinHelp(
    HWND      hWndMain,
    LPCTSTR   lpszHelp,
    UINT      uCommand,
    ULONG_PTR dwData
);

 

만일 이 함수를 C# 언어에서 사용하고자 하면, 다음과 같이 외부함수를 정의한다. 아래의 정의는 MS의 공식적인 변환은 아니며 소스코드의 특성에 따라 커스터마이징이 가능하다.

[DllImport("user32.dll", CharSet=CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool WinHelp(
    [MarshalAs(UnmanagedType.SysInt)] IntPtr hWndMain,
    [MarshalAs(UnmanagedType.LPTStr)] string lpszHelp,
    [MarshalAs(UnmanagedType.SysUInt)] int uCommand,
    [MarshalAs(UnmanagedType.SysInt)] IntPtr dwData
);

 

첫 번째 매개변수는 대체로 NULL을 쓰면 되고, 네 번째 매개변수는 Help Workshop의 Map 대화상자에서 부여된 일련번호를 입력한다.

 

버튼을 클릭 시 해당 내용이 보여지는 것을 확인할 수 있다.

 

네 번째 매개변수를 바꿈으로써 상황에 맞는 적절한 도움말을 보여줄 수 있다.

 

Epilogue


이것으로 HLP 형식의 도움말 파일을 생성하고 Windows API와 연동하는 방법에 대해 마친다.

 

카테고리 “Microsoft Windows/Win32 도움말 연동”
more...
썸네일 이미지
HLP 형식의 윈도우 도움말 제작하기 #4
HLP 형식의 윈도우 도움말 제작하기 본 시리즈에서는 윈도우 도움말 형식 중 하나인 HLP 형식의 도움말을 생성하기 위한 방법에 대해 정리한다. 참고로 HLP 파일은 Windows XP까지만 열기가 지원된다. HLP 형식의 윈도우 도움말 제작하기 #1 HLP 형식의 윈도우 도움말 제작하기 #2 HLP 형식의 윈도우 도움말 제작하기 #3 HLP 형식의 윈도우 도움말 제작하기 #4 HLP 형식의 윈도우 도움말 제작하기 #5 [完] HLP 형식의 윈도우 도움말 제작하기 #4 HLP 도움말은 Windows 3.1부터 Windows XP까지 지원하던 도움말 형식으로서, 내부적으로는 여러개의 RTF 문서 파일로 이루어져 있다. Windows Vista 이후에 출시되는 Windows 운영체제(Vista, 2008, ..
Microsoft Windows/Win32 도움말 연동
2018. 11. 18. 21:55

HLP 형식의 윈도우 도움말 제작하기 #4

Microsoft Windows/Win32 도움말 연동
2018. 11. 18. 21:55

HLP 형식의 윈도우 도움말 제작하기


본 시리즈에서는 윈도우 도움말 형식 중 하나인 HLP 형식의 도움말을 생성하기 위한 방법에 대해 정리한다. 참고로 HLP 파일은 Windows XP까지만 열기가 지원된다.

  1. HLP 형식의 윈도우 도움말 제작하기 #1
  2. HLP 형식의 윈도우 도움말 제작하기 #2
  3. HLP 형식의 윈도우 도움말 제작하기 #3
  4. HLP 형식의 윈도우 도움말 제작하기 #4
  5. HLP 형식의 윈도우 도움말 제작하기 #5 [完]

HLP 형식의 윈도우 도움말 제작하기 #4


HLP 도움말은 Windows 3.1부터 Windows XP까지 지원하던 도움말 형식으로서, 내부적으로는 여러개의 RTF 문서 파일로 이루어져 있다. Windows Vista 이후에 출시되는 Windows 운영체제(Vista, 2008, 7, 2010, 8, 2012, 8.1, 10, ...)에서는 공식적으로 지원하지는 않는다. 이번 시리즈에서는 HLP 도움말을 제작하고, WinAPI에서 이를 불러오는 방법까지 알아보겠다.

준비물: 1. Windows XP 또는 그 이전 버전 운영체제, 2. Microsoft Word (아무 버전이나), 3. Microsoft Visual Studio 6.0

 

일반 링크 만들기


이번에는 도움말 본문에 링크를 만들어서 클릭하면 해당 문서로 이동하는 기능을 넣어보겠다. 먼저 도움말 파일의 개요를 보여 줄 예제 파일을 아래와 같이 작성한다.

 

파일 ID는 ID_HELP_ABSTRACT, 키워드는 '예제 도움말 파일의 개요 파일'로 지정한다.

 

파일명은 abstract, 파일형식은 서식 있는 텍스트(*.rtf)로 지정하여 저장한다.

 

이전 단계와 마찬가지로 [Files...] 버튼을 눌러 abstract.rtf 파일을 프로젝트에 추가한다.

 

색인 파일(project.cnt)도 함께 열어 이전 단계와 마찬가지로 abstract.rtf에 대한 항목을 추가한다.

 

도움말 생성 프로젝트에 파일 추가가 완료되면 index.rtf를 열어 링크를 삽입한다. 링크를 삽입하고 싶은 문단의 끝에 클릭 시 전환하게 될 문서의 ID를 "띄어쓰기 없이" 곧바로 적는다. 여기서는 클릭 시 ID_HELP_ABSTRACT의 ID가 붙은 문서가 보여져야 하므로 "1. 개요ID_HELP_ABSTRACT"와 같이 문단 끝에 곧바로 이 ID를 적어야 한다.

 

링크를 넣을 문구인 "1. 개요"까지만 선택한 후 마우스 오른쪽 버튼을 클릭한다. 다음 [단락(P)...] 메뉴를 클릭한다.

 

"효과" 영역 중 [취소선(K)] 버튼에 체크하여 선택한 문구가 "1. 개요"와 같이 취소선이 그어지게 설정한 다음 [확인] 버튼을 누른다.

 

이번에는 클릭 시 링크될 대상으로서 적은 ID_HELP_ABSTRACT에 대하여 블록을 지정하고 선택 후 마우스 오른쪽 버튼을 눌러 [단락(P)...] 메뉴를 클릭한다.

 

"효과" 영역 중 [숨김(H)] 버튼에 체크하고 [확인] 버튼을 누른다.

 

아래와 같이 ID가 사라지고, 링크할 텍스트에 취소선이 그어져있으면 된다.

 

숨겨진 텍스트로 된 링크 ID를 확인 또는 수정하고자 할 때는 [리본] 버튼 클릭 후 [Word 옵션(I)] 버튼을 클릭한다.

 

[표시] 버튼을 눌러 [숨겨진 텍스트(D)] 항목에 체크한 후 [확인] 버튼을 누른다.

 

아래와 같이 숨겨졌던 ID가 밑줄 표시된 채 보여질 것이다.

 

이제 프로젝트를 컴파일해보자. Help Workshop 컴파일러가 링크를 감지하여 "1 Jump"를 표시하는 것을 볼 수 있다.

 

.hlp 파일을 실행했을 때 취소선 서식을 넣었던 텍스트가 링크로 나타나는 것을 볼 수 있다.

 

이 링크를 클릭 시 해당 ID의 RTF 문서가 보여지고 [뒤로(B)] 버튼이 활성화 됨을 확인할 수 있다.

 

팝업 링크 만들기


이번에는 copyright.rtf 로 저작권 관련 내용을 적어서 도움말에 팝업 형태로 띄워보겠다. 예시 파일을 작성해본다.

 

'#' 각주에는 이 문서의 ID로 ID_HELP_COPYRIGHT를 부여하고, 'K' 각주에는 "이 예제 도움말 파일의 저작권"이라는 문구를 적어보겠다.

 

프로젝트로 가서 [Files...] 버튼을 눌러 copyright.rtf를 추가하고...

 

목차 파일에도 [Add Below...] 버튼을 눌러 저작권 항목을 추가한다.

 

링크를 삽입할 index.rtf를 열어 "5. 저작권" 글자 뒤에 띄어쓰기 없이 copyright.rtf의 ID인 ID_HELP_COPYRIGHT를 적는다.

 

링크를 넣을 텍스트만 블록을 설정한 후 마우스 오른쪽 버튼을 눌러 [글꼴(F)...] 메뉴를 클릭하고,

 

"밑줄 스타일(U):"의 옵션 중 실선을 클릭하여 평범한 밑줄을 넣는다. 그 다음 [확인] 버튼을 누른다.

 

마찬가지로 ID도 블록을 정해 글꼴 옵션에서 숨겨진 텍스트를 클릭한다.

 

아래와 같이 만들면 완성이다.

 

프로젝트로 돌아가 도움말 파일을 컴파일 해 본다. 앞서 만든 링크와 함께, Help Workshop 컴파일러가 두 개의 링크를 감지하여 "2 Jumps"가 뜨는 것을 볼 수 있다.

 

생성된 .hlp 파일을 실행하면 "5. 저작권"에 밑줄이 그어진 것을 볼 수 있다. 이를 클릭해보면...

아래와 같이 팝업 형태로 내용이 보여지게 된다.

 

Epilogue


다음 포스트에서는 만들어진 .hlp 파일을 이용해 WinAPI에서 불러올 수 있도록 해보겠다.

 

카테고리 “Microsoft Windows/Win32 도움말 연동”
more...
썸네일 이미지
HLP 형식의 윈도우 도움말 제작하기 #3
HLP 형식의 윈도우 도움말 제작하기 본 시리즈에서는 윈도우 도움말 형식 중 하나인 HLP 형식의 도움말을 생성하기 위한 방법에 대해 정리한다. 참고로 HLP 파일은 Windows XP까지만 열기가 지원된다. HLP 형식의 윈도우 도움말 제작하기 #1 HLP 형식의 윈도우 도움말 제작하기 #2 HLP 형식의 윈도우 도움말 제작하기 #3 HLP 형식의 윈도우 도움말 제작하기 #4 HLP 형식의 윈도우 도움말 제작하기 #5 [完] HLP 형식의 윈도우 도움말 제작하기 #3 HLP 도움말은 Windows 3.1부터 Windows XP까지 지원하던 도움말 형식으로서, 내부적으로는 여러개의 RTF 문서 파일로 이루어져 있다. Windows Vista 이후에 출시되는 Windows 운영체제(Vista, 2008, ..
Microsoft Windows/Win32 도움말 연동
2018. 11. 18. 21:41

HLP 형식의 윈도우 도움말 제작하기 #3

Microsoft Windows/Win32 도움말 연동
2018. 11. 18. 21:41

HLP 형식의 윈도우 도움말 제작하기


본 시리즈에서는 윈도우 도움말 형식 중 하나인 HLP 형식의 도움말을 생성하기 위한 방법에 대해 정리한다. 참고로 HLP 파일은 Windows XP까지만 열기가 지원된다.

  1. HLP 형식의 윈도우 도움말 제작하기 #1
  2. HLP 형식의 윈도우 도움말 제작하기 #2
  3. HLP 형식의 윈도우 도움말 제작하기 #3
  4. HLP 형식의 윈도우 도움말 제작하기 #4
  5. HLP 형식의 윈도우 도움말 제작하기 #5 [完]

HLP 형식의 윈도우 도움말 제작하기 #3


HLP 도움말은 Windows 3.1부터 Windows XP까지 지원하던 도움말 형식으로서, 내부적으로는 여러개의 RTF 문서 파일로 이루어져 있다. Windows Vista 이후에 출시되는 Windows 운영체제(Vista, 2008, 7, 2010, 8, 2012, 8.1, 10, ...)에서는 공식적으로 지원하지는 않는다. 이번 시리즈에서는 HLP 도움말을 제작하고, WinAPI에서 이를 불러오는 방법까지 알아보겠다.

준비물: 1. Windows XP 또는 그 이전 버전 운영체제, 2. Microsoft Word (아무 버전이나), 3. Microsoft Visual Studio 6.0

 

문서에 식별 ID 부여하기


먼저, 각 문서별로 hlp 파일 내에서 식별할 수 있는 ID를 부여한다. [참조]-[각주] 카테고리 옆에 달린 작은 단추를 클릭한다.

 

[각주 및 미주] 대화상자가 뜬다. "위치"는 "각주(F):"를 선택하고, "서식"에는 "사용자 지정 표시(U):" 옆의 텍스트상자에 '#'을 입력한다. 그리고 [삽입(I)] 버튼을 누른다.

 

페이지 하단 각주 편집창으로 화면이 이동하는데, 여기에 이 문서의 고유 ID를 각자 알아서 지정하면 된다. 예를 들면, 이 문서에 ID_HELP_INDEX라는 ID를 부여할 수 있다.

 

Help Workshop으로 돌아가 우선 컴파일을 한다. 생성 결과에는 아직 아무런 차이도 보이지 않음을 확인할 수 있다.

 

문서에 색인 정보 추가하기


도움말의 '색인' 창을 통해 이 문서로 접근해오려면, 어떤 단어를 검색했을 때 이 문서가 나타나게 할 지를 지정하는 방법이 필요하다. 이를 위해 [참조]-[각주] 카테고리 옆에 달린 작은 단추를 다시 클릭하여 또 다른 각주를 추가한다.

 

이번에는 "사용자 지정 표시(U):" 텍스트 입력창에 Keyword의 약자인 'K'를 입력하고 [삽입(I)]를 클릭한다.

 

각주 편집으로 화면이 이동하면 이 페이지의 목적을 묘사할 수 있는 적절한 문구를 삽입한다.

 

Help Workshop에서 컴파일을 해 본다. 'K' 각주에 의해 아래 표시와 같이 "1 Keyword"가 뜸을 확인할 수 있다.

 

결과물을 확인한다. 전에는 비활성화 상태였던 [색인(I)] 단추가 활성화되어있음을 확인할 수 있다. 이를 클릭한다. [색인] 탭에서 'K' 각주에 적은 문구가 나타날 것이다.

 

목차 삽입하기


이번에는 목차를 삽입한다. Help Workshop 화면에서 [File]-[New] 메뉴를 클릭한다. 대화상자가 뜨면 [Help Contents]를 선택하고 [OK] 버튼을 누른다.

 

목차를 편집할 수 있는 화면으로 바뀌면서 새 목차 파일이 생성됨을 확인할 수 있다.

 

먼저 "Default filename (and window):" 칸에는 지금 컴파일에 의해 생성되고 있는 hlp 파일 이름을 적는다. "Default title:"에는 목차 및 색인 화면 상단 타이틀 바에서 보여질 제목을 적는다.

 

그 다음 [Add Above...] 버튼을 누른다. "Edit Contents Tab Entry" 대화상자가 뜬다. 대주제를 삽입하기 위해 Heading을 선택 후 "Title:" 텍스트박스에 대주제를 적는다. [OK] 버튼을 누른다.

 

아래와 같이 대주제가 삽입되었다.

 

소주제를 삽입하고 싶은 위치에 항목을 선택한 후 [Add Above] 또는 [Add Below]를 눌러 소주제를 삽입할 수 있다. 이 소주제가 우리가 작성하고 있는 RTF 파일로 연결될 것이다. "Edit Contents Tab Entry" 대화상자에서 Topic을 선택한 다음, "Title:"에는 소주제의 명칭을 적고, "Topic ID:"에는 RTF 파일에서 '#' 각주로 지정한 문서의 식별 ID를 적는다. 그리고 OK를 누른다.

 

아래와 같이 대주제 아래 소주제가 삽입되었음을 확인할 수 있다.

 

이제 이 목차를 저장한다. 파일명은 반드시 .hlp 파일과 같게 적고, 확장자는 .cnt여야 한다. 나중에 이 파일은 .hlp파일과 함께 배포되어야 한다.

 

목차 파일이 생성된 후에는 hlp 파일을 더블클릭하였을 때, RTF 문서의 내용이 그대로 출력되지 않고 아래와 같이 목차 및 색인 대화상자가 우선 뜨게 된다.

 

 

목차(C) 버튼을 눌렀을 때 아래와 같이 목차 화면이 뜬다면 성공이다.

 

카테고리 “Microsoft Windows/Win32 도움말 연동”
more...
썸네일 이미지
HLP 형식의 윈도우 도움말 제작하기 #2
HLP 형식의 윈도우 도움말 제작하기 본 시리즈에서는 윈도우 도움말 형식 중 하나인 HLP 형식의 도움말을 생성하기 위한 방법에 대해 정리한다. 참고로 HLP 파일은 Windows XP까지만 열기가 지원된다. HLP 형식의 윈도우 도움말 제작하기 #1 HLP 형식의 윈도우 도움말 제작하기 #2 HLP 형식의 윈도우 도움말 제작하기 #3 HLP 형식의 윈도우 도움말 제작하기 #4 HLP 형식의 윈도우 도움말 제작하기 #5 [完] HLP 형식의 윈도우 도움말 제작하기 #2 HLP 도움말은 Windows 3.1부터 Windows XP까지 지원하던 도움말 형식으로서, 내부적으로는 여러개의 RTF 문서 파일로 이루어져 있다. Windows Vista 이후에 출시되는 Windows 운영체제(Vista, 2008, ..
Microsoft Windows/Win32 도움말 연동
2018. 11. 18. 19:43

HLP 형식의 윈도우 도움말 제작하기 #2

Microsoft Windows/Win32 도움말 연동
2018. 11. 18. 19:43

HLP 형식의 윈도우 도움말 제작하기


본 시리즈에서는 윈도우 도움말 형식 중 하나인 HLP 형식의 도움말을 생성하기 위한 방법에 대해 정리한다. 참고로 HLP 파일은 Windows XP까지만 열기가 지원된다.

  1. HLP 형식의 윈도우 도움말 제작하기 #1
  2. HLP 형식의 윈도우 도움말 제작하기 #2
  3. HLP 형식의 윈도우 도움말 제작하기 #3
  4. HLP 형식의 윈도우 도움말 제작하기 #4
  5. HLP 형식의 윈도우 도움말 제작하기 #5 [完]

HLP 형식의 윈도우 도움말 제작하기 #2


HLP 도움말은 Windows 3.1부터 Windows XP까지 지원하던 도움말 형식으로서, 내부적으로는 여러개의 RTF 문서 파일로 이루어져 있다. Windows Vista 이후에 출시되는 Windows 운영체제(Vista, 2008, 7, 2010, 8, 2012, 8.1, 10, ...)에서는 공식적으로 지원하지는 않는다. 이번 시리즈에서는 HLP 도움말을 제작하고, WinAPI에서 이를 불러오는 방법까지 알아보겠다.

준비물: 1. Windows XP 또는 그 이전 버전 운영체제, 2. Microsoft Word (아무 버전이나), 3. Microsoft Visual Studio 6.0

 

1. 미디어 삽입


이전 포스트에 이어서 이번에는 rtf 파일에 표와 그림을 삽입하여 도움말 파일을 제작한다.

1-1. 표 삽입


Microsoft Word의 [삽입]-[표]-[표] 메뉴를 클릭하여 표를 삽입한다.

 

아래와 같이 표에 적절한 내용을 채운다.

 

Help Workshop으로 돌아가 컴파일한 후 결과를 확인한다. 표의 테두리가 사라져 있음을 확인할 수 있다. hlp 형식의 도움말 파일은 표의 테두리 모양까지 지원하지는 않기 때문에 이렇게 보인다.

 

1-2. 그림 삽입


이번에는 그림을 삽입한다. 그림을 복사하여 워드에 직접 붙여넣기하면 된다. 일반적인 문서 작성과 다르지 않다.

 

만일 구 버전의 Microsoft Word(2007 버전 미만)를 사용중이라면 컴파일된 hlp 파일에서 이와 같이 붙여넣기로 삽입된 그림이 보이지 않을 수 있다. 이 때는 rtf 파일과 같은 폴더 안에 그림 파일을 생성한 후...

 

[삽입]-[일러스트레이션]-[그림] 메뉴를 클릭하여 그림 파일을 삽입한다.

 

컴파일한 hlp 결과이다.

 

Epilogue


이번 포스트에서는 매우 간단한 내용을 다루어보았다. 다음 포스트에서는 "색인과 목차" 기능에 대해 알아보겠다.

카테고리 “Microsoft Windows/Win32 도움말 연동”
more...
썸네일 이미지
HLP 형식의 윈도우 도움말 제작하기 #1
HLP 형식의 윈도우 도움말 제작하기 본 시리즈에서는 윈도우 도움말 형식 중 하나인 HLP 형식의 도움말을 생성하기 위한 방법에 대해 정리한다. 참고로 HLP 파일은 Windows XP까지만 열기가 지원된다. HLP 형식의 윈도우 도움말 제작하기 #1 HLP 형식의 윈도우 도움말 제작하기 #2 HLP 형식의 윈도우 도움말 제작하기 #3 HLP 형식의 윈도우 도움말 제작하기 #4 HLP 형식의 윈도우 도움말 제작하기 #5 [完] HLP 형식의 윈도우 도움말 제작하기 #1 HLP 도움말은 Windows 3.1부터 Windows XP까지 지원하던 도움말 형식으로서, 내부적으로는 여러개의 RTF 문서 파일로 이루어져 있다. Windows Vista 이후에 출시되는 Windows 운영체제(Vista, 2008, ..
Microsoft Windows/Win32 도움말 연동
2018. 11. 18. 17:47

HLP 형식의 윈도우 도움말 제작하기 #1

Microsoft Windows/Win32 도움말 연동
2018. 11. 18. 17:47

HLP 형식의 윈도우 도움말 제작하기


본 시리즈에서는 윈도우 도움말 형식 중 하나인 HLP 형식의 도움말을 생성하기 위한 방법에 대해 정리한다. 참고로 HLP 파일은 Windows XP까지만 열기가 지원된다.

  1. HLP 형식의 윈도우 도움말 제작하기 #1
  2. HLP 형식의 윈도우 도움말 제작하기 #2
  3. HLP 형식의 윈도우 도움말 제작하기 #3
  4. HLP 형식의 윈도우 도움말 제작하기 #4
  5. HLP 형식의 윈도우 도움말 제작하기 #5 [完]

HLP 형식의 윈도우 도움말 제작하기 #1


HLP 도움말은 Windows 3.1부터 Windows XP까지 지원하던 도움말 형식으로서, 내부적으로는 여러개의 RTF 문서 파일로 이루어져 있다. Windows Vista 이후에 출시되는 Windows 운영체제(Vista, 2008, 7, 2010, 8, 2012, 8.1, 10, ...)에서는 공식적으로 지원하지는 않는다. 이번 시리즈에서는 HLP 도움말을 제작하고, WinAPI에서 이를 불러오는 방법까지 알아보겠다.

준비물: 1. Windows XP 또는 그 이전 버전 운영체제, 2. Microsoft Word (아무 버전이나), 3. Microsoft Visual Studio 6.0

 

RTF 문서 준비하기


Microsoft Word를 켜고 아래와 같이 예제 문서를 작성해본다. 예제 문서니까 이것저것 서식도 마음대로 넣어보는 것이 가능하다.

 

저장할 때 파일 형식은 반드시 서식 있는 텍스트 또는 서식 있는 텍스트 (*.rtf)으로 지정한다.

 

HLP 문서 생성하기


[시작] 버튼-[모든 프로그램]-[Microsoft Visual Studio 6.0]-[Microsoft Visual Studio 6.0 도구들]-[Help Workshop]을 클릭한다.

 

프로젝트 생성하기


[File]-[New]를 눌러 [Help Project]를 선택한 후 [OK]를 누른다. 파일 저장 대화상자가 뜨면 적당한 경로에 프로젝트 파일 이름을 지정한 후 [저장(S)] 버튼을 누른다. 이 때, 확장자는 .hpj이다. 주의할 것은, 경로명에 한글이 들어갈 경우 hlp 파일이 제대로 생성되지 않을 수 있다는 것이다. 경로에 한글이 들어가지 않도록 주의해야 한다.

예) C:\프로젝트\project.hpj (X) -> C:\project\project.hpj (O)

 

프로젝트에 RTF 문서 추가하기


프로젝트 파일이 생성되며 화면이 아래와 같이 변한다. [Options...] 버튼을 누른다. 이 도움말 파일의 이름이나 내용 등을 적을 수 있는 부분이다.

'Help title:'에는 이 도움말 파일의 제목을 적는다. 'Copyright Information'에는 저작권 관련 문구를 적어넣을 수 있다. 'Display this text in the Version dialog box:'에는 버전 정보 대화상자에 보여줄 문구를 지정하고, 'If users paste or print Help text, display:'에는 사용자가 도움말의 일부를 복사/붙여넣기하거나 인쇄를 할 때 딸려오는 저작권 관련 문구를 적을 수 있다.

 

대화상자에 입력한 내용이 프로젝트 파일에 반영되었음을 확인할 수 있다.

 

이번에는 [Files...]를 누른다. 'Topic Files'이라는 대화상자는 이 도움말에 포함된 .rtf 파일들의 목록들을 보여주는 창인데, 아무것도 없으므로 [Add...]를 눌러 파일을 하나 추가한다.

 

프로젝트 컴파일


아래와 같이 Microsoft Word에서 작성했던 rtf 파일이 추가되었다. 우선 결과를 보기위해 우측 하단의 [Save and Compile] 버튼을 클릭한다.

아무 문제없이 .hlp 형식 도움말 파일이 생성완료 되었다면 hlp 파일의 경로가 뜨면서 생성 완료되었다는 메시지가 출력될 것이다.

 

아래와 같이 .hlp 도움말 파일이 생성되었음을 확인할 수 있다. 더블클릭하여 열었을 때, Microsoft Word에서 작성했던 .rtf 파일과 같은 내용이 보인다면 성공한 것이다.

 

Epilogue


그럼 이어서 다음 글에서는 rtf 파일에 이미지와 표를 넣어보도록 한다.

 

카테고리 “Microsoft Windows/Win32 도움말 연동”
more...

“windows api” (12건)