본문 바로가기
IT-개발,DB

[개발/MFC] VC++/MFC API 팁

by SB리치퍼슨 2012. 11. 15.

[개발/MFC] VC++/MFC API 팁



1. 특정 디렉토리 뒤지기
2. API를 이용하는 유니코드와 ANSI 문자열간의 변환 방법 
3. 윈도우 탐색기로부터의 Drag&Drop을 받으려면
4. 시스템의 모든 드라이브 알아내기
5. 레지스트리 읽기/쓰기



1. 특정 디렉토리 뒤지기 

지정한 디렉토리에 있는 모든 파일을 찾아내는 코드를 만들려면 어떻게 해야 합니까 ?

이 때 사용할 수 있는 API가 바로 FindFirstFile과 FindNextFile, FindClose라는 API들입니다. 사용 예제는 다음과 같습니다.

WIN32_FIND_DATA  findFileData; 
HANDLE hFileHandle;

// szDir에 뒤지고자 하는 디렉토리의 경로명을 준다. 예를 들면 "C:\\TEMP\\*.*" 
// 찾아진 파일의 속성은 findFileData의 dwFileAttributes를 살펴본다. 
hFileHandle = FindFirstFile(m_szDir, &findFileData);  
if (hFileHandle != INVALID_HANDLE_VALUE)  // 파일을 찾은 경우 

 // 찾은 파일의 이름은 cFileName 필드로 들어온다. 
 ... 
 // 다음 파일을 찾는다. 
 while(FindNextFile(hFileHandle, &findFileData)) { 
  ... 
 } 
 FindClose(hFileHandle); 
}


2. API를 이용하는 유니코드와 ANSI 문자열간의 변환 방법
 
API를 이용해서 유니코드와 ANSI 문자열간의 변환은 어떻게 수행합니까 ?

Visual C++에서 유니코드 문자열은 BSTR이란 타입으로 표시됩니다. 또 유니코드와 ANSI 문자열간의 변환을 위해서 윈도우 시스템에는 MultiByteToWideChar와 WideCharToMultiByte라는 API가 존재합니다. MFC에서의 BSTR 타입 변환방법이나 ATL로 하는 BSTR 타입 변환도 참고하시기 바랍니다.


ANSI 문자열에서 유니코드로의 변환 방법

// sTime이란 ANSI 문자열을 bstr이란 이름의 유니코드(BSTR 타입) 변수로 변환 
char sTime[] = "유니코드 변환 예제"; 
BSTR bstr;

// sTime을 유니코드로 변환하기에 앞서 먼저 그 길이를 알아야 한다. 
int nLen = MultiByteToWideChar(CP_ACP, 0, sTime, lstrlen(sTime), NULL, NULL); 
// 얻어낸 길이만큼 메모리를 할당한다. 
bstr = SysAllocStringLen(NULL, nLen); 
// 이제 변환을 수행한다. 
MultiByteToWideChar(CP_ACP, 0, sTime, lstrlen(sTime), bstr, nLen); 
// 필요없어지면 제거한다. 
SysFreeString(bstr);


유니코드에서 ANSI 문자열로의 변환 방법

// newVal이란 BSTR 타입에 있는 유니코드 문자열을 sTime이라는 ANSI 문자열로 변환 
char *sTime; 
int nLen = WideCharToMultiByte(CP_ACP, 0, newVal, -1, sTime, 0, NULL, NULL); 
sTime = malloc(nLen+1); 
WideCharToMultiByte(CP_ACP, 0, newVal, -1, sTime, 128, NULL, NULL); 
// 필요없으면 메모리를 제거한다. 
free(sTime);

유니코드 문자열을 UTF-8으로 변환하기

WideCharToMultiByte 함수를 호출할 때 첫 번째 인자로 CP_UTF8을 지정하면 된다.UTF-8은 유니코드의 인코딩 스킴 중의 하나로 쉽게 말하자면 문자열 스트림에서 0을 빼고 표현하는 방법이라고 볼 수 있다 


3. 윈도우 탐색기로부터의 Drag&Drop을 받으려면

윈도우 탐색기로부터 제가 만든 윈도우로의 drag&drop이 가능하게 하려면 어떻게 해야 합니까 ?

다음 순서를 따라서 프로그래밍하시면 됩니다.

프로그램의 초기화시에 DragAcceptFiles(hWnd, TRUE) 함수를 호출한다. 첫 번째 인자인 hWnd는 드롭의 타겟이 되는 윈도우의 핸들이다. 
탐색기로부터 파일이 드롭되는 순간에 WM_DROPFILES 메시지가 날라온다. 이를 처리한다.

case WM_DROPFILES : 

 POINT pt; 
 // 어느 위치에 드롭되었는지 그 항목을 알아낸다. 
 if (DragQueryPoint((HDROP)wParam, &pt)) 
 { 
  UINT i = 0; 
  // 모두 몇 개의 파일이 드롭되었는지 알아낸다. 
  // 만일 폴더가 드롭되었다면 폴더의 이름만 넘어온다. 
  UINT uCount = DragQueryFile((HDROP)wParam, 0xFFFFFFFF, NULL ,0);

  for(i = 0;i < uCount;i++) 
  { 
  // 드롭된 파일의 이름을 알아온다. 
  DragQueryFile((HDROP)wParam, i, buffer ,255); 
  // 드롭된 파일 이름을 출력해본다. 
  MessageBox(hWnd, buffer, "File Name", MB_OK); 
  } 
 } 
 // drag and drop 작업을 끝낸다. 
 DragFinish((HDROP)wParam); 
 break; 

Drag&drop을 더 사용할 필요가 없어지면 DragAcceptFiles를 호출한다. 
DragAcceptFiles(hWnd, FALSE); 


4. 시스템의 모든 드라이브 알아내기

현재 시스템에 붙어있는 모든 드라이브(네트웍 드라이브 포함)에 대한 정보를 알아내고 싶습니다.

GetLogicalDriveStrings로 시스템에 마운트되어있는 모든 드라이브 정보를 알아낸다. 두 번째 인자인 buffer로 드라이브 정보가 들어오는데 그 구조는 c:\,d:\과 같은 형식이며 리턴값으로 그 버퍼의 크기가 들어온다.

char buffer[256]; 
DWORD dwRet; 
LPSTR token;

dwRet = GetLogicalDriveStrings(256, buffer);

// 루프를 돌면서 드라이브별 정보를 알아낸다. 이 때는 GetVolumeInformation 함수를 이용한다.

token = buffer; // token이 지금 처리해야할 드라이브를 가리킨다. 
while (dwRet > 0) 

 DWORD FileSystemFlag; 
 char FileSystemName[64];

 strcpy(DriveString, token); 
 // VolumeName으로 드라이브에 대한 설명 문자열이 넘어온다. 
 if (GetVolumeInformation(token, VolumeName, 255, NULL, NULL, 
      &FileSystemFlag, FileSystemName, 63)) 
 { 
  // 원하는 작업을 수행한다. 
 } 
 dwRet -= (strlen(token)+1); 
 token = token + strlen(token)+1; // 다음 드라이브로 진행한다. 
}
 

5. 레지스트리 읽기/쓰기

API를 이용해서 레지스트리에 한 항목을 생성하거나 기존 항목의 값을 읽어들이려면 어떻게 해야합니까 ?

레지스트리 관련 API를 사용하려면 winreg.h라는 헤더 파일을 소스에 포함해야 합니다. 레지스트리에 키를 생성하는 방법과 레지스트리에 존재하는 키의 값을 읽는 방법을 차례로 살펴보겠습니다.


레지스트리 키 생성 예제

// 예를 들어 HKEY_LOCAL_MACHINE밑의 System\CurrentControlSet\Services\GenPort라는 키를 
// 생성하고 거기에 DWORD 타입의 값으로 Type을 만들고 문자열 타입의 값으로 Group 
// 을 만들어 본다. 
#include "winreg.h" 
LONG error = 0; 
HKEY hKey; 
DWORD dwDisp, dwData; 
char lpData[] = "Write this down";

// 먼저 만들려는 키가 이미 존재하는 것인지 살혀본다. 
error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\GenPort", 
                        0, KEY_ALL_ACCESS, &hKey);

if (error != ERROR_SUCCESS) // 없다면 새로 생성한다. 

 // 키를 생성한다. 
 error = RegCreateKeyEx(HKEY_LOCAL_MACHINE, 
  "System\\CurrentControlSet\\Services\\GenPort", 0, "REG_BINARY", 
         REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, &dwDisp); 
        // 위의 키 밑에 Type이란 DWORD 타입의 값을 만들고 1로 초기화 
 dwData = 0x1; 
 error = RegSetValueEx( hKey, "Type", 0, REG_DWORD,&dwData,4); 
        // 위의 키 밑에 Group이란 문자열 타입의 값을 만들고 lpData의 값으로 초기화 
 error = RegSetValueEx( hKey, "Group", 0, REG_SZ, lpData, strlen(lpData));

        // 키를 닫는다. 
 RegCloseKey(hKey); 
}

기존의 레지스트리 키에서 값 읽기

// HKEY_CURRENT_USER\Software\Netscape\Netscape Navigator\Main 밑의 Install Directory 
// 값의 문자열 값을 읽어들인다. 
DWORD dwType, cbData; 
HKEY hSubKey; 
long lRet; 
char pszString[255];

// 키를 오픈한다. 
if ((lRet = RegOpenKeyEx(HKEY_CURRENT_USER, 
                "Software\\Netscape\\Netscape Navigator\\Main", 
  0, KEY_READ | KEY_QUERY_VALUE , &hSubKey)) == ERROR_SUCCESS) 

 cbData = 255; // 문자열 값을 읽어올 데이터의 크기를 준다. 
 if ((lRet = RegQueryValueEx(hSubKey, "Install Directory", 
  NULL, &dwType, pszString, &cbData)) == ERROR_SUCCESS) 
 { 
  // 제대로 읽힌 경우 
 } 
 else 
 { 
  // 에러가 발생한 경우 
 } 
 RegCloseKey(hSubKey); 
}

레지스트리 키 삭제하기 
- RegDeleteKey 함수를 사용한다.

반응형

댓글