*** 공부 방법 ***
1. 코딩을 해야 하는 부분은 첫 부분에 변수나 함수, 메소드에 대한 선언이 코드블럭으로 표시되어 있다. //ex) MakeFunction(); 2. 코드블럭 하단에는 해당 선언에 대한 구현 로직이 작성되어 있다. 처
hyrule.tistory.com
[사전 지식]
TCHAR Root[MAX_PATH] = {};
GetModuleFileName(0, Root, MAX_PATH);
- MAX_PATH: 윈도우에서 기본으로 제공하는 매크로 -> 최대 경로 길이를 설정(260)
- GetModuleFileName
--1번 인자: 0을 넣어야 실행 파일의 주소가 반환된다.
--2번 인자: 실행 파일의 주소를 반환할 문자열의 주소
--3번 인자: 해당 문자열의 최대 길이
-- 이 주소를 통해 프로그램이 어느 곳에 있든 주소를 쉽게 구해올 수 있다.
-- 이 함수를 사용하면, "전체경로/프로그램_이름.exe" 문자열이 나오게 되는데, 경로만 사용하려면 반복문을 통해 프로그램 이름을 제거해주어야 한다.
--- 뒤에서부터 반복문을 돌려서 '/' 또는 '\\'를 찾을 경우 거기서 멈추고, 그 뒤를 memset을 통해 싹 날려버리면 된다.
int PathLength = WideCharToMultiByte(CP_ACP, 0, Info->Path, -1, nullptr, 0, 0, 0);
https://docs.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-widechartomultibyte
WideCharToMultiByte function (stringapiset.h) - Win32 apps
Maps a UTF-16 (wide character) string to a new character string.
docs.microsoft.com
- 유니코드를 멀티바이트로 바꿔주는 함수이다.
-1번 인자: CP_ACP -> 아스키 코드 페이지로 들어간다(고정)
-2번 인자: 플래그 -> 0(고정): 특정 조건에 해당하는 문자를 변경할 때 넣는 인자
-3번 인자: 바꿔줄 문자열 주소
-4번 인자: 바꿔줄 문자열의 개수 -> -1 = 전체를 바꿔주겠다
-5번 인자: 변환된 문자열을 넣을 주소
-> 5번 인자부터 0을 넣을 시 변환된 문자열의 길이(int)가 return됨.
-6번 인자: 변환된 문자열의 길이 -> 5번 인자에 nullptr을 넣어 반환된 값을 여기에 다시 넣어주면 된다.
▼사용 방법은 다음과 같다.
//길이를 먼저 리턴받은 다음,
int PathLength = WideCharToMultiByte(CP_ACP, 0, Info->Path, -1, nullptr, 0, 0, 0);
//리턴받은 길이를 다시 인자에 넣고 주소를 할당하여 변환을 완료한다.
WidCharToMultiByte(CP_ACP, 0, Info->Path, -1, Info->PathMultiByte, PathLength, 0, 0);
- 현재 컴파일 설정이 Unicode인지 Multibyte인지 구분하는 법
- 지난번에 사용했던 #ifdef 기능을 사용하면 된다.
#ifdef UNICODE
//원하는 코드//
#endif
- 프로그램은 어느 경로에 저장되어 있든 실행이 될 수 있어야 한다.
-- 프로그램은 이것을 '상대 경로'를 통해 처리하고 있다.
- 이미지 파일도 마찬가지로 프로그램이 어디에 있든 로드할 수 있어야 한다.
하지만 이미지 파일은 전체 경로가 필요하다. -> 매번 바뀌는 전체 경로를 따와서 로딩할 수 있어야 한다.
- 그러므로 이미지 파일을 처리하기 전에 경로를 관리해줄 클래스의 생성이 필요하다.
class CPathManager
- 루트 폴더에 생성한다.
- 싱글턴 패턴으로 생성하고, CGameManager에서 생성, 초기화 및 삭제를 담당한다.
struct PathInfo
- 경로에 대한 지원은, 유니코드와 멀티바이트 모두를 지원해주어야 문제가 발생할 여지가 없다.
-- 그러므로 경로 저장은 구조체를 통해 저장한다.
-- 기본적으로 멀티바이트로 하나 저장하고,
-- 만약 유니코드면 유니코드 형식으로 저장되는 변수 타입을 통해 하나 더 저장한다.
--- 생성 시 0으로 초기화되도록 해준다.
struct PathInfo
{
TCHAR Path[MAX_PATH];
char PathMultiByte[MAX_PATH];
PathInfo():
Path{},
PathMultiByte{}
{}
};
- 위 구조체를 모아서 저장할 자료구조를 생성한다. key로 문자열 이름을 저장하고, value로 PathInfo 구조체 포인터를 반환한다.
//PathManager.h
private:
std::unordered_map<std::string, PathInfo*> m_mapPath;
- 경로 이용의 편의를 위해, 기본 경로를 찾기 위한 문자열("RootPath")와,
텍스처 파일들의 경로를 찾기 위한 문자열("TexturePath")를
GameInfo.h에 매크로로 등록해 준다.
//GameInfo.h
//경로 매크로 설정
#define ROOT_PATH "RootPath"
#define TEXTURE_PATH "TexturePath"
CPathManager::FindPath()
- 인자로 이름(문자열)을 받아서
- PathInfo 구조체의 주소를 수정 불가능하게 return
- 위에 저장한 자료구조에서 인자로 받은 이름이 존재하는지 찾는다.
-- 찾지 못했으면 nullptr을 리턴한다.
const PathInfo* CPathManager::FindPath(const std::string& Name)
{
auto iter = m_mapPath.find(Name);
if (iter == m_mapPath.end())
return nullptr;
return iter->second;
}
CPathManager::AddPath()
<인자>
- 새로 만들 경로의 이름(문자열)
- 뒤에 추가할 경로(수정 불가능한 포인터)
- 앞에 추가할 기초경로를 찾기 위한 이름(문자열) -> 기본 인자로 ROOT_PATH를 전달.
<반환값>
- boolean
<로직>
- 위에서 만든 FindPath() 메소드를 활용.
- 만약 새로 만들 경로로 이미 이름이 있으면 false를 반환하고 return
- 앞에 추가할 기초경로를 이름으로 찾아서 임시로 저장
- PathInfo를 동적할당
- 기초 경로가 있다면 동적할당한 PathInfo에 해당 기초경로를 복사
- PathInfo에 복사된 기초경로에 '뒤에 추가할 경로'를 추가
- 추가가 완료되면 ifdef를 통해 멀티바이트로 바꾸는 작업을 진행
- 모든 단계가 성공적으로 끝날 시 true 반환
bool CPathManager::AddPath(const std::string& Name,
const TCHAR* Path, const std::string& BasePathName)
{
if (FindPath(Name))
return false;
const PathInfo* BasePath = FindPath(BasePathName);
PathInfo* Info = new PathInfo;
if (BasePath)
lstrcpy(Info->Path, BasePath->Path);
lstrcat(Info->Path, Path);
#ifdef UNICODE
// 유니코드로 되어있는 문자열을 멀티바이트로 바꾸기 위한 수를
// 얻어온다.
int PathLength = WideCharToMultiByte(CP_ACP, 0, Info->Path, -1,
0, 0, 0, 0);
WideCharToMultiByte(CP_ACP, 0, Info->Path, -1,
Info->PathMultibyte, PathLength, 0, 0);
#else
strcpy_s(Info->PathMultibyte, Info->Path);
#endif // UNICODE
m_mapPath.insert(std::make_pair(Name, Info));
return true;
}
CPath::Init()
- CPathManager의 초기화 과정에서 전체 경로에서 프로그램 이름만 뺀 경로를 구한다.
-- 해당 경로가 "RootPath"(ROOT_PATH)가 된다.
-- 해당 경로를 위의 자료구조에 첫 번째 원소로 저장한다.
- 위의 2가지 메소드들을 사용해 TEXTURE_PATH를 두 번째 원소로 등록해준다.
- "ROOT_PATH/Texture/"이 등록되어야 한다.
bool CPathManager::Init()
{
TCHAR Root[MAX_PATH] = {};
// 실행파일이있는 폴더까지의 전체경로/실행파일이름.exe 로 문자열이
// 나오게 된다.
// Bin/aa.exe
GetModuleFileName(0, Root, MAX_PATH);
int Length = lstrlen(Root);
for (int i = Length - 1; i >= 0; --i)
{
if (Root[i] == '/' || Root[i] == '\\')
{
memset(&Root[i + 1], 0, sizeof(TCHAR) * (Length - i - 1));
break;
}
}
PathInfo* Info = new PathInfo;
lstrcpy(Info->Path, Root);
// #ifdef : 뒤에 있는 내용이 #define으로 정의되어 있는지를
// 판단하는 if문이다.
// 컴파일 단계에서 뒤에 있는 내용이 #define으로 정의되어 있는지 판단.
#ifdef UNICODE
// 유니코드로 되어있는 문자열을 멀티바이트로 바꾸기 위한 수를
// 얻어온다.
int PathLength = WideCharToMultiByte(CP_ACP, 0, Info->Path, -1,
0, 0, 0, 0);
WideCharToMultiByte(CP_ACP, 0, Info->Path, -1,
Info->PathMultibyte, PathLength, 0, 0);
#else
strcpy_s(Info->PathMultibyte, Info->Path);
#endif // UNICODE
m_mapPath.insert(std::make_pair(ROOT_PATH, Info));
AddPath(TEXTURE_PATH, TEXT("Texture/"));
return true;
}
'WIN32API FrameWork > 한단계씩 직접 구현' 카테고리의 다른 글
33. 이미지의 애니메이션화를 위한 준비 (0) | 2022.05.25 |
---|---|
32. 이미지 등의 리소스 관리자 (0) | 2022.05.24 |
30. 스킬 구현 2 - 아우렐리온 솔 W (0) | 2022.05.23 |
29. CreateObject 메소드 수정 (0) | 2022.05.23 |
28. 스킬 구현 1 - 토네이도 총알 (0) | 2022.05.23 |