[미완] [Win32/MFC] 작업관리자의 프로세스와 응용프로그램 추출
위 그림에서 프로세스 이름(보라)와 타이틀명(빨강) 추출하는 법
프로세스 이름(보라)는 2가지가 있고 타이틀명(빨강)은 1개 올림
블로그로 보면 상당히 지저분한데 소스는 헤더파일로 분리해서 심플합니다.
단 VS6에서 잘 돌아가나 유니코드때문에 다른 버전은 수정을 해야 합니다.
(*지금은 그냥 올리고 나중에 유니코드로 수정해서 다시 올리 예정)
소스 다운로드
http://cfile218.uf.daum.net/attach/246D7D4A563822CF31088D
타이틀명(빨강) 추출
#include <windows.h>
#include <stdio.h>
#include <tlhelp32.h>
#include <vdmdbg.h>
#include <tchar.h>
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
_TCHAR szTitle[MAX_PATH] = {0, };
DWORD dwPID = 0;
PROCESSENTRY32 pEntry;
memset(&pEntry, 0x00, sizeof(PROCESSENTRY32));
pEntry.dwSize = sizeof(pEntry);
// process list(like taskmgr)
DWORD exStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
BOOL isVisible = IsWindowVisible(hwnd);
BOOL isToolWindow = (exStyle & WS_EX_TOOLWINDOW);
BOOL isAppWindow = (exStyle & WS_EX_APPWINDOW);
BOOL isOwned = GetWindow(hwnd, GW_OWNER) ? TRUE : FALSE;
if (!(isVisible && (isAppWindow || (!isToolWindow && !isOwned))))
return TRUE;
GetWindowText(hwnd, szTitle, MAX_PATH); // get caption
GetWindowThreadProcessId(hwnd, &dwPID);
HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, dwPID);
Process32First(hSnapShot, &pEntry);
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwPID);
while (!(dwPID == pEntry.th32ProcessID) && IsWindowVisible(hwnd))
{
if (FALSE == Process32Next(hSnapShot, &pEntry))
break;
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwPID);
}
_TCHAR szRes[MAX_PATH] = {0, };
_stprintf(szRes, _T("PID : 0x%08x, Title : %s, Filename : %s\n"), dwPID, szTitle, pEntry.szExeFile);
_tprintf( szRes );
return TRUE;
}
프로세스 이름(보라) 추출 방벙 1
#include <windows.h>
#include <stdio.h>
#include <tlhelp32.h>
#include <vdmdbg.h>
#include <tchar.h>
BOOL ProcessList()
{
HANDLE hProcess = NULL;
PROCESSENTRY32 ppe = {0};
hProcess = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
ppe.dwSize = sizeof( PROCESSENTRY32 );
if( Process32First( hProcess, &ppe ) )
{
do
{
_tprintf(_T("%-30s (%d) \n"), ppe.szExeFile, ppe.th32ProcessID);
} while ( Process32Next( hProcess, &ppe ) );
}
CloseHandle (hProcess);
return TRUE;
}
프로세스 이름(보라) 추출 방벙 2
#include <windows.h>
#include <stdio.h>
#include <tlhelp32.h>
#include <vdmdbg.h>
#include <tchar.h>
typedef BOOL (CALLBACK *PROCENUMPROC)(DWORD, WORD, LPSTR, LPARAM);
typedef struct {
DWORD dwPID;
PROCENUMPROC lpProc;
DWORD lParam;
BOOL bEnd;
} EnumInfoStruct;
BOOL WINAPI EnumProcs(PROCENUMPROC lpProc, LPARAM lParam);
BOOL WINAPI Enum16(DWORD dwThreadId, WORD hMod16, WORD hTask16,
PSZ pszModName, PSZ pszFileName, LPARAM lpUserDefined);
//
// The EnumProcs function takes a pointer to a callback function
// that will be called once per process with the process filename
// and process ID.
//
// lpProc -- Address of callback routine.
//
// lParam -- A user-defined LPARAM value to be passed to
// the callback routine.
//
// Callback function definition:
// BOOL CALLBACK Proc(DWORD dw, WORD w, LPCSTR lpstr, LPARAM lParam);
//
BOOL WINAPI EnumProcs(PROCENUMPROC lpProc, LPARAM lParam) {
OSVERSIONINFO osver;
HINSTANCE hInstLib = NULL;
HINSTANCE hInstLib2 = NULL;
HANDLE hSnapShot = NULL;
LPDWORD lpdwPIDs = NULL;
PROCESSENTRY32 procentry;
BOOL bFlag;
DWORD dwSize;
DWORD dwSize2;
DWORD dwIndex;
HMODULE hMod;
HANDLE hProcess;
char szFileName[MAX_PATH];
EnumInfoStruct sInfo;
// ToolHelp Function Pointers.
HANDLE (WINAPI *lpfCreateToolhelp32Snapshot)(DWORD, DWORD);
BOOL (WINAPI *lpfProcess32First)(HANDLE, LPPROCESSENTRY32);
BOOL (WINAPI *lpfProcess32Next)(HANDLE, LPPROCESSENTRY32);
// PSAPI Function Pointers.
BOOL (WINAPI *lpfEnumProcesses)(DWORD *, DWORD, DWORD *);
BOOL (WINAPI *lpfEnumProcessModules)(HANDLE, HMODULE *, DWORD,
LPDWORD);
DWORD (WINAPI *lpfGetModuleBaseName)(HANDLE, HMODULE, LPTSTR, DWORD);
// VDMDBG Function Pointers.
INT (WINAPI *lpfVDMEnumTaskWOWEx)(DWORD, TASKENUMPROCEX, LPARAM);
// Retrieve the OS version
osver.dwOSVersionInfoSize = sizeof(osver);
if (!GetVersionEx(&osver))
return FALSE;
// If Windows NT 4.0
if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT
&& osver.dwMajorVersion == 4) {
__try {
// Get the procedure addresses explicitly. We do
// this so we don't have to worry about modules
// failing to load under OSes other than Windows NT 4.0
// because references to PSAPI.DLL can't be resolved.
hInstLib = LoadLibraryA("PSAPI.DLL");
if (hInstLib == NULL)
__leave;
hInstLib2 = LoadLibraryA("VDMDBG.DLL");
if (hInstLib2 == NULL)
__leave;
// Get procedure addresses.
lpfEnumProcesses = (BOOL (WINAPI *)(DWORD *, DWORD, DWORD*))
GetProcAddress(hInstLib, "EnumProcesses");
lpfEnumProcessModules = (BOOL (WINAPI *)(HANDLE, HMODULE *,
DWORD, LPDWORD)) GetProcAddress(hInstLib,
"EnumProcessModules");
lpfGetModuleBaseName = (DWORD (WINAPI *)(HANDLE, HMODULE,
LPTSTR, DWORD)) GetProcAddress(hInstLib,
"GetModuleBaseNameA");
lpfVDMEnumTaskWOWEx = (INT (WINAPI *)(DWORD, TASKENUMPROCEX,
LPARAM)) GetProcAddress(hInstLib2, "VDMEnumTaskWOWEx");
if (lpfEnumProcesses == NULL
|| lpfEnumProcessModules == NULL
|| lpfGetModuleBaseName == NULL
|| lpfVDMEnumTaskWOWEx == NULL)
__leave;
//
// Call the PSAPI function EnumProcesses to get all of the
// ProcID's currently in the system.
//
// NOTE: In the documentation, the third parameter of
// EnumProcesses is named cbNeeded, which implies that you
// can call the function once to find out how much space to
// allocate for a buffer and again to fill the buffer.
// This is not the case. The cbNeeded parameter returns
// the number of PIDs returned, so if your buffer size is
// zero cbNeeded returns zero.
//
// NOTE: The "HeapAlloc" loop here ensures that we
// actually allocate a buffer large enough for all the
// PIDs in the system.
//
dwSize2 = 256 * sizeof(DWORD);
do {
if (lpdwPIDs) {
HeapFree(GetProcessHeap(), 0, lpdwPIDs);
dwSize2 *= 2;
}
lpdwPIDs = (LPDWORD) HeapAlloc(GetProcessHeap(), 0,
dwSize2);
if (lpdwPIDs == NULL)
__leave;
if (!lpfEnumProcesses(lpdwPIDs, dwSize2, &dwSize))
__leave;
} while (dwSize == dwSize2);
// How many ProcID's did we get?
dwSize /= sizeof(DWORD);
// Loop through each ProcID.
for (dwIndex = 0; dwIndex < dwSize; dwIndex++) {
szFileName[0] = 0;
// Open the process (if we can... security does not
// permit every process in the system to be opened).
hProcess = OpenProcess(
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE, lpdwPIDs[dwIndex]);
if (hProcess != NULL) {
// Here we call EnumProcessModules to get only the
// first module in the process. This will be the
// EXE module for which we will retrieve the name.
if (lpfEnumProcessModules(hProcess, &hMod,
sizeof(hMod), &dwSize2)) {
// Get the module name
if (!lpfGetModuleBaseName(hProcess, hMod,
szFileName, sizeof(szFileName)))
szFileName[0] = 0;
}
CloseHandle(hProcess);
}
// Regardless of OpenProcess success or failure, we
// still call the enum func with the ProcID.
if (!lpProc(lpdwPIDs[dwIndex], 0, szFileName, lParam))
break;
// Did we just bump into an NTVDM?
if (_stricmp(szFileName, "NTVDM.EXE") == 0) {
// Fill in some info for the 16-bit enum proc.
sInfo.dwPID = lpdwPIDs[dwIndex];
sInfo.lpProc = lpProc;
sInfo.lParam = (DWORD) lParam;
sInfo.bEnd = FALSE;
// Enum the 16-bit stuff.
lpfVDMEnumTaskWOWEx(lpdwPIDs[dwIndex],
(TASKENUMPROCEX) Enum16, (LPARAM) &sInfo);
// Did our main enum func say quit?
if (sInfo.bEnd)
break;
}
}
} __finally {
if (hInstLib)
FreeLibrary(hInstLib);
if (hInstLib2)
FreeLibrary(hInstLib2);
if (lpdwPIDs)
HeapFree(GetProcessHeap(), 0, lpdwPIDs);
}
// If any OS other than Windows NT 4.0.
} else if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS
|| (osver.dwPlatformId == VER_PLATFORM_WIN32_NT
&& osver.dwMajorVersion > 4)) {
__try {
hInstLib = LoadLibraryA("Kernel32.DLL");
if (hInstLib == NULL)
__leave;
// If NT-based OS, load VDMDBG.DLL.
if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
hInstLib2 = LoadLibraryA("VDMDBG.DLL");
if (hInstLib2 == NULL)
__leave;
}
// Get procedure addresses. We are linking to
// these functions explicitly, because a module using
// this code would fail to load under Windows NT,
// which does not have the Toolhelp32
// functions in KERNEL32.DLL.
lpfCreateToolhelp32Snapshot =
(HANDLE (WINAPI *)(DWORD,DWORD))
GetProcAddress(hInstLib, "CreateToolhelp32Snapshot");
lpfProcess32First =
(BOOL (WINAPI *)(HANDLE,LPPROCESSENTRY32))
GetProcAddress(hInstLib, "Process32First");
lpfProcess32Next =
(BOOL (WINAPI *)(HANDLE,LPPROCESSENTRY32))
GetProcAddress(hInstLib, "Process32Next");
if (lpfProcess32Next == NULL
|| lpfProcess32First == NULL
|| lpfCreateToolhelp32Snapshot == NULL)
__leave;
if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
lpfVDMEnumTaskWOWEx = (INT (WINAPI *)(DWORD, TASKENUMPROCEX,
LPARAM)) GetProcAddress(hInstLib2, "VDMEnumTaskWOWEx");
if (lpfVDMEnumTaskWOWEx == NULL)
__leave;
}
// Get a handle to a Toolhelp snapshot of all processes.
hSnapShot = lpfCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapShot == INVALID_HANDLE_VALUE) {
FreeLibrary(hInstLib);
return FALSE;
}
// Get the first process' information.
procentry.dwSize = sizeof(PROCESSENTRY32);
bFlag = lpfProcess32First(hSnapShot, &procentry);
// While there are processes, keep looping.
while (bFlag) {
// Call the enum func with the filename and ProcID.
if (lpProc(procentry.th32ProcessID, 0,
procentry.szExeFile, lParam)) {
// Did we just bump into an NTVDM?
if (_stricmp(procentry.szExeFile, "NTVDM.EXE") == 0) {
// Fill in some info for the 16-bit enum proc.
sInfo.dwPID = procentry.th32ProcessID;
sInfo.lpProc = lpProc;
sInfo.lParam = (DWORD) lParam;
sInfo.bEnd = FALSE;
// Enum the 16-bit stuff.
lpfVDMEnumTaskWOWEx(procentry.th32ProcessID,
(TASKENUMPROCEX) Enum16, (LPARAM) &sInfo);
// Did our main enum func say quit?
if (sInfo.bEnd)
break;
}
procentry.dwSize = sizeof(PROCESSENTRY32);
bFlag = lpfProcess32Next(hSnapShot, &procentry);
} else
bFlag = FALSE;
}
} __finally {
if (hInstLib)
FreeLibrary(hInstLib);
if (hInstLib2)
FreeLibrary(hInstLib2);
}
} else
return FALSE;
// Free the library.
FreeLibrary(hInstLib);
return TRUE;
}
BOOL WINAPI Enum16(DWORD dwThreadId, WORD hMod16, WORD hTask16,
PSZ pszModName, PSZ pszFileName, LPARAM lpUserDefined) {
BOOL bRet;
EnumInfoStruct *psInfo = (EnumInfoStruct *)lpUserDefined;
bRet = psInfo->lpProc(psInfo->dwPID, hTask16, pszFileName,
psInfo->lParam);
if (!bRet)
psInfo->bEnd = TRUE;
return !bRet;
}
BOOL CALLBACK MyProcessEnumerator(DWORD dwPID, WORD wTask,
LPCSTR szProcess, LPARAM lParam) {
if (wTask == 0)
printf("%5u %s\n", dwPID, szProcess);
else
printf(" %5u %s\n", wTask, szProcess);
return TRUE;
}
2015년 11월 3일 화요일
2015년 10월 21일 수요일
[미완] [Win32/MFC] 파일유무 확인
[Win32/MFC] 파일유무 확인
#include <Shlwapi.h>
#pragma comment(lib, "shlwapi.lib")
// 파일유무 확인
int nRet = PathFileExists( TEXT("파일명.txt") );
if ( 1 == nRet ) // 존재 하면
{
}
else // 없으면
{
}
#include <Shlwapi.h>
#pragma comment(lib, "shlwapi.lib")
// 파일유무 확인
int nRet = PathFileExists( TEXT("파일명.txt") );
if ( 1 == nRet ) // 존재 하면
{
}
else // 없으면
{
}
2015년 7월 14일 화요일
2014년 1월 23일 목요일
[Win32/MFC] Win32 기본 윈도우창 출력
// Win32 기본창 출력
#include <Windows.h>
#include <tchar.h>
HINSTANCE g_hInst = NULL;
void InitWndClass( HINSTANCE hInstance, LPCTSTR lpszClassName );
int MessageRun( void );
LRESULT CALLBACK WndProc( HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam );
//////////////////////////////////////////////////////////////////////////
// hPrevInstance=16비트 윈도우의 잔재로 항상 NULL값을 가지고 사용하지 않는다.
int APIENTRY _tWinMain( __in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in_opt LPTSTR lpCmdLine, __in int nShowCmd )
{
const LPCTSTR lpszClassName = _T("x108zero");
g_hInst = hInstance;
// Window Class Struct에 값 입력
InitWndClass( hInstance, lpszClassName );
// Windows 생성
HWND hWnd = CreateWindow( lpszClassName, lpszClassName, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, (HMENU)NULL, hInstance, NULL );
if( NULL == hWnd )
{
MessageBox( hWnd, _T("Window Create Error"), _T("Error"), MB_OK );
return -1;
}
ShowWindow( hWnd, nShowCmd );
// 메시지 처리
int nMessage = MessageRun();
return nMessage;
}
//////////////////////////////////////////////////////////////////////////
void InitWndClass( HINSTANCE hInstance, LPCTSTR lpszClassName )
{
WNDCLASS WndClass;
ZeroMemory( &WndClass, sizeof(WndClass) );
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1 );
WndClass.hCursor = LoadCursor( NULL, IDC_ARROW );
WndClass.hIcon = LoadIcon( NULL, IDI_APPLICATION );
WndClass.hInstance = hInstance;
WndClass.lpfnWndProc = WndProc;
WndClass.lpszClassName = lpszClassName;
WndClass.lpszMenuName = NULL;
WndClass.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass( &WndClass ); // Window Class 등록
}
//////////////////////////////////////////////////////////////////////////
int MessageRun( void )
{
MSG Message;
ZeroMemory( &Message, sizeof(Message) );
while( GetMessage( &Message, NULL, 0, 0 ) )
{
TranslateMessage( &Message );
DispatchMessage( &Message );
} // end of while( GetMessage( &Message, NULL, 0, 0 ) )
return (int)Message.wParam;
}
//////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK WndProc( HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam )
{
switch( iMessage )
{
case WM_CREATE:
return 0;
case WM_PAINT:
{
PAINTSTRUCT ps;
ZeroMemory( &ps, sizeof(ps) );
HDC hDC = BeginPaint( hWnd, &ps );
EndPaint( hWnd, &ps );
}
return 0;
case WM_DESTROY:
PostQuitMessage( 0 );
return 0;
} // end of switch( iMessage )
return DefWindowProc( hWnd, iMessage, wParam, lParam );
}
#include <Windows.h>
#include <tchar.h>
HINSTANCE g_hInst = NULL;
void InitWndClass( HINSTANCE hInstance, LPCTSTR lpszClassName );
int MessageRun( void );
LRESULT CALLBACK WndProc( HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam );
//////////////////////////////////////////////////////////////////////////
// hPrevInstance=16비트 윈도우의 잔재로 항상 NULL값을 가지고 사용하지 않는다.
int APIENTRY _tWinMain( __in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in_opt LPTSTR lpCmdLine, __in int nShowCmd )
{
const LPCTSTR lpszClassName = _T("x108zero");
g_hInst = hInstance;
// Window Class Struct에 값 입력
InitWndClass( hInstance, lpszClassName );
// Windows 생성
HWND hWnd = CreateWindow( lpszClassName, lpszClassName, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, (HMENU)NULL, hInstance, NULL );
if( NULL == hWnd )
{
MessageBox( hWnd, _T("Window Create Error"), _T("Error"), MB_OK );
return -1;
}
ShowWindow( hWnd, nShowCmd );
// 메시지 처리
int nMessage = MessageRun();
return nMessage;
}
//////////////////////////////////////////////////////////////////////////
void InitWndClass( HINSTANCE hInstance, LPCTSTR lpszClassName )
{
WNDCLASS WndClass;
ZeroMemory( &WndClass, sizeof(WndClass) );
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1 );
WndClass.hCursor = LoadCursor( NULL, IDC_ARROW );
WndClass.hIcon = LoadIcon( NULL, IDI_APPLICATION );
WndClass.hInstance = hInstance;
WndClass.lpfnWndProc = WndProc;
WndClass.lpszClassName = lpszClassName;
WndClass.lpszMenuName = NULL;
WndClass.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass( &WndClass ); // Window Class 등록
}
//////////////////////////////////////////////////////////////////////////
int MessageRun( void )
{
MSG Message;
ZeroMemory( &Message, sizeof(Message) );
while( GetMessage( &Message, NULL, 0, 0 ) )
{
TranslateMessage( &Message );
DispatchMessage( &Message );
} // end of while( GetMessage( &Message, NULL, 0, 0 ) )
return (int)Message.wParam;
}
//////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK WndProc( HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam )
{
switch( iMessage )
{
case WM_CREATE:
return 0;
case WM_PAINT:
{
PAINTSTRUCT ps;
ZeroMemory( &ps, sizeof(ps) );
HDC hDC = BeginPaint( hWnd, &ps );
EndPaint( hWnd, &ps );
}
return 0;
case WM_DESTROY:
PostQuitMessage( 0 );
return 0;
} // end of switch( iMessage )
return DefWindowProc( hWnd, iMessage, wParam, lParam );
}
2013년 12월 18일 수요일
[Win32/MFC] "", L"", TEXT(""), _T("") 차이점
Visual C++에서 문자 처리는 2가지가 있다.
"멀티바이트"와 "유니코드"다.
(C#은 유니코드만 있는걸로 알고 있음)
멀티바이트(MBCS=Multi Byte Character Set): 영어는 1바이트, 그 외 문자는 2바이트로 처리.
유니코드(WBCS=Wide Byte Character Set): 모든 문자를 2바이트로 처리.(참고로 GCC는 4바이트로 처리)

그래서 Visual Studio에서 프로젝트 속성을
멀티바이트로 하면 "" 이렇게 문자를 입력하고
유니코드로 하면 L"" 이렇게 문자를 입력해야 한다.
ex)
멀티바이트일때 MessageBox( NULL, "a", "b", MB_OK );
유니코드일때 MessageBox( NULL, L"a", L"b", MB_OK );
근데 유니코드로 설정 후 개발 했다가
멀티바이트로 변경 해야될때(외부 라이브러리와의 호환성 등)
L"" 이렇게 입력한 부분을 모두 찾아서
"" 이렇게 변경을 해줘야 한다.(완전 노가다)
그래서 TEXT("")와 _T("")를 #define 했다.
ex)
MessageBox( NULL, TEXT("a"), TEXT("b"), MB_OK );
이렇게 입력을 하면
멀티바이트일때 MessageBox( NULL, "a", "b", MB_OK );
유니코드일때 MessageBox( NULL, L"a", L"b", MB_OK );
이렇게 변환이 되어서 컴파일 된다.
TEXT("")과 _T("")의 차이점은
TEXT("")는 WinNT.h에서 #define했고
_T("")는 tchar.h에서 TEXT가 4글자라서 _T이렇게 2글자로 #define했다.
즉 Win32에서는 TEXT("")를 쓰고 MFC에서는 _T("")를 사용한다.
Win32에서 _T("")를 사용하고 싶으면 tchar.h를 추가하면 되고
MFC에서는 당연히 TEXT("")도 사용 가능하다.
--- 결론
윈도우즈 프로그램 개발시
문자를 "" 또는 L"" 이렇게 입력하지 말고
TEXT("") 또는 _T("") 이렇게 입력하자.
"멀티바이트"와 "유니코드"다.
(C#은 유니코드만 있는걸로 알고 있음)
유니코드(WBCS=Wide Byte Character Set): 모든 문자를 2바이트로 처리.(참고로 GCC는 4바이트로 처리)

그래서 Visual Studio에서 프로젝트 속성을
멀티바이트로 하면 "" 이렇게 문자를 입력하고
유니코드로 하면 L"" 이렇게 문자를 입력해야 한다.
ex)
멀티바이트일때 MessageBox( NULL, "a", "b", MB_OK );
유니코드일때 MessageBox( NULL, L"a", L"b", MB_OK );
근데 유니코드로 설정 후 개발 했다가
멀티바이트로 변경 해야될때(외부 라이브러리와의 호환성 등)
L"" 이렇게 입력한 부분을 모두 찾아서
"" 이렇게 변경을 해줘야 한다.(완전 노가다)
그래서 TEXT("")와 _T("")를 #define 했다.
ex)
MessageBox( NULL, TEXT("a"), TEXT("b"), MB_OK );
이렇게 입력을 하면
멀티바이트일때 MessageBox( NULL, "a", "b", MB_OK );
유니코드일때 MessageBox( NULL, L"a", L"b", MB_OK );
이렇게 변환이 되어서 컴파일 된다.
TEXT("")과 _T("")의 차이점은
TEXT("")는 WinNT.h에서 #define했고
_T("")는 tchar.h에서 TEXT가 4글자라서 _T이렇게 2글자로 #define했다.
즉 Win32에서는 TEXT("")를 쓰고 MFC에서는 _T("")를 사용한다.
Win32에서 _T("")를 사용하고 싶으면 tchar.h를 추가하면 되고
MFC에서는 당연히 TEXT("")도 사용 가능하다.
--- 결론
윈도우즈 프로그램 개발시
문자를 "" 또는 L"" 이렇게 입력하지 말고
TEXT("") 또는 _T("") 이렇게 입력하자.
피드 구독하기:
글 (Atom)
