본문 바로가기

3.구현/VC++

Vista 호환 프로그램 데이터 저장위치 다루기

최근 Vista용 프로그램을 코딩을 했었다. 이때 설치된 폴더에서 설정파일 읽어오고 해당 폴더에 데이터를 기록하였다. 시간이 바빠서 대충 때빵한 코드였다. Vista 지원에 대해 예전부터 관심을 가지고 대충 감만 잡고 있었던 중에 이번에 제대로 수정하고자 이것 저것 자료를 찾고 정리를 해보았다.

XP은 사용자 권한이 자동으로 관리자 권한을 갖게되어 프로그램이 아무 곳에나 데이터를 기록할 수 있었다. 그러나 Vista에서는 그렇게 할 수 없다. 이는 파일뿐만 아니라 레지스트리에도 해당된다.

Vista에서 데이터 저장에 대한 내용은 XP에서도 이미 존재했고, 그 이전 버전에도 있었다. 그러나 개발자들은 이를 무시하고 (아니 있는지도 모르는) 개발하고 Vista로 오면서 당연히 문제가 되었고, Vista에서는 이른 보완하고자 호환되는 폴더를 제공하였다. 이런 호환도 어느정도 지나면 더이상 지원되지 않는다. 즉, 근본적 해결책은 되지 못한다.

먼저 프로그램 실행과 작업 폴더에 대한 개념을 먼저 다루고, 그리고 데이터 저장에 대한 전략을 간단하게 실핀 후, 저장되는 폴더를 다루는 것에 대해서 살펴보겠다.

작성일: 2009.07.31 (http://ospace.tistory.com/), ospace114@empal.com

프로그램 실행 및 작업 폴더

프로그램 실행이 되면 연관된 두가지 폴더가 있다. 시작폴더와 작업폴더이다. 이 명칭은 실제 사용되는 명칭과 다를 수는 있습니다. 이는 제가 임의로 정의한 것입니다.
시작폴더는 프로그램 시작이 되는 폴더라고 보면된다. 작업폴더는 파일 불러오기나 기본적으로 파일 저장이되는 경우 현재 디렉토리(.\)가 되는 폴더이다.

일반적으로 두개의 폴더 위치는 일치한다. 그러나 항상 그런 것은 아니다. 예를 들어 단축아이콘으로 시작되는 경우는 시작폴더는 단축아이콘이 있는 위치가 된다. 그리고 작업 폴더는 단축아이콘 속성 중에 "시작 위치"의 입력된 폴더가 된다. Vista인 경우는 폴더 엑세스 권한이 있기 때문에 시작폴더는 같지만, 작업폴더는 해당 폴더에 엑세스 권한이 없다면 Windows폴더의 system32이가 작업 폴더가 된다.

물론 해당 사용자가 사용 가능한 폴더를 절대 경로로 정해줘도 된다. 그러나 이때 주의해야될 것은 절대 경로를 정할 때에 환경변수에 의한 변동을 적용하지 않고 "C:\Program Files\..."이라는 식으로 사용할 경우 문제가 발생한다. 예를 들어 사용자가 설치위치를 C 드라이브가 아닌 D드라이브에 설치하면 오류가 발생한다.

대충 개념을 이해했으리라 보고 이런 폴더의 위치를 얻고 지정하는 방법을 보도록 하자. 시작폴더 변경이 필요하지 않기 때문에 값만 읽어오는 것만 보고, 작업폴더 위치와 변경을 하겠다.

다음은 시작폴더를 얻는 예이다.

STARTUPINFO startupInfo;
memset(&startupInfo, 0, sizeof(startupInfo));
GetStartupInfo(&startupInfo);

TRACE("Startup: %s", startupInfo.lpTitle);

위의 예제로 시작폴더를 lpTitle에서 얻게 된다. 이는 LPTSTR형이다. 주의 할 것은 lpTitle에는 폴더 외에 실행되는 파일 명도 같이 포함되어 있다. 그렇기에 폴더명을 얻으려면 뒤에 파일명을 제거해줘야한다.

작업폴더 위치를 획득하고 변경하는 코드이다. 이는 간단하다. GetCurrentDirectory()와 SetCurrentDirectory()를 사용하면된다.

TCHAR currDir[MAX_PATH];
DWORD dwRet = GetCurrentDirectory(MAX_PATH, currDir);
TRACE("Current Directory: %s", currDir);

BOOL bRet = SetCurrentDirectory(currDir);

혹시나해서 이야기하는 것이지만, SetCurrentDirectory(currDir)은 예를 들기위해서 넣은 것이지, 실제 위코드를 실행하면 변경되는 것은 아무것도 없다.

데이터 저장 전략

윈도우에서 프로그램 데이터를 저장하는 방법은 크게 두가지가 있다. 파일에 저장하는 것과 레지스트리에 저장하는 것이다. 파일도 프로그램이 설치된 폴더나 My Pictures나 My Docuements같은 폴더를 사용할 수 있다. 이러한 것에 대해서 강제는 없고, 프로그램 재량이나 사용자 요구사항에 따라 정해진다.

보통 데이터 위치가 파일나 레지스트리로 구분이 명확하지는 않다. 일반적으로 64KB를 초과하는 데이터는 파일로, 그렇지 않다면 레지스트리로 저장한다.[1] 그리고 COM는 HKEY_CLASSES_ROOT(HKCR)에 등록되는데 이는 최대 128KB이하로만 저장한다. 용량으로 저장위치를 구분할 수는 있지만, 절대적인 기준은 아니다. 근데, 거의 절대적이지 않을까?

그리고 레지스트리인 경우 개별 사용자에 저장되는 데이터는 HKEY_CURRENT_USER(HKCU)에 저장되며 시스템 전체에 해당하는 데이터는 HKEY_LOCAL_MACHINE(HKLM)에 저장된다.

저장되는 파일이나 경로 이름은 어떻게 될까? MS에서 권장하는 것은 다음과 같다.

~\Company Name\Product Name\Product Version

사실 위와 같이 사용하는 프로그램은 많지는 않다. 보통 버전은 레지스트리에서 하나의 키로 사용하는 경우도 많다. 그리고 Company Name을 생략하고 Product Name이 먼저 나오는 경우도 있다. 이런 것은 상황에 맞게 선택하면 될 듯 한다.

여기서는 레지스트리에 대해서 다루지는 않고 파일 저장에 대해서만 다룰 것이다. 그렇기에 레지스트리에 관한 것을 따로 참고하길 바란다. 추가로 덧붙이면 레지스트리 관련 API는 다음과 같다.

RegCreateKeyEx
RegSetValueEx

저장되는 폴더 다루기

파일은 저장위치가 무한하다. 마음대로 만들 수 있지만, 보통 제공되는 특정 디렉토리가 있다. 대충 어떤 것인지 감이 올 것이다. 너무 많기 때문에 이런 값을 환경변수로 지정되어 해당 값을 바로 환경변수에서 가져올 수 있다. 이때 사용할 수 있는 함수가 getenv()이다. 실제 이것 보다 SHGetFolderPath()를 추천한다. 이는 Win95 with IE5.0이상 모든 운영체제에서 지원된다. 헤더 파일은 "shfolder.h"를 사용한다. 헤더 파일은 PlatformSDK를 설치한 경우이고, 설치가 안되었다면 "shlobj.h"를 사용하면 될 것이다. 일반적으로 PlatformSDK 설치는 기본이기에 "shfolder.h"를 사용하면 된다.

선언

HRESULT SHGetFolderPath( HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath );

헤더파일

shfolder.h

위의 인자 중에 dwFlags에 의해서 가져오는 폴더 값이 달라진다. 아래 목록을 참고하길 바란다.

  • CSIDL_ADMINTOOLS
  • CSIDL_COMMON_ADMINTOOLS
  • CSIDL_APPDATA
  • CSIDL_COMMON_APPDATA
  • CSIDL_COMMON_DOCUMENTS
  • CSIDL_COOKIES
  • CSIDL_FLAG_CREATE
  • CSIDL_HISTORY
  • CSIDL_INTERNET_CACHE
  • CSIDL_LOCAL_APPDATA
  • CSIDL_MYPICTURES
  • CSIDL_PERSONAL
  • CSIDL_PROGRAM_FILES
  • CSIDL_PROGRAM_FILES_COMMON
  • CSIDL_SYSTEM
  • CSIDL_WINDOWS

대충 값만 봐도 뭐지 알 수 있을 것이다. 여기서 관심의 대상이 되는 것이 CSIDL_APPDATA이다. 일반적으로 이 값은 XP인 경우 다음과 같다.

C:\Documents and Settings\(사용자 ID)\Application Data\

위의 폴더가 프로그램에서 자유롭게 접근할 수 있는 폴더다. 이 경로를 이하 APPDATA라고 한다. Vista에서 더욱 그러하다. 최근 크롬이나 FireFox도 이 곳에 사용자관련 데이터가 저장된다. 물론 일반 프로그램 외에도 COM도 실행에 관련된 데이터를 저장하기도 한다.

APPDATA에 바로 저장하는 것이 아니라, 앞에서 말한 저장 경로에 맞춰서 저장한다. 예를 들어,

C:\Documents and Settings\(사용자 ID)\Application Data\Product Name

뒤에 "Product Name"이 덧붙여진다. 이를 덧붙이는 이름을 문자열 조합으로 바로 만드는 것이 아니라 PathAppend()를 사용하고 있습니다.[1] 원하는 결과만 얻을 수 있다면, 사실 꼭 PathAppend()를 사용할 필요는 없겠지요. 이를 사용하기 위해서 헤더 파일 "shlwapi.h"이 있어야 한다.

혹시 더 좋은 방안이 있다면 메일을 꼭 주시길 바란다. 위의 방안이 나름대로 정리한 것이라서 최적의 방안이 아닐 수 도 있다. 이상으로 마친다. 모두 즐프하길 바란다. ospace.

참고

[1] http://support.microsoft.com/kb/310294/ko

반응형