パス文字列の操作

ファイルやディレクトリなどの場所を示す文字列をパスと言います。
ここではパス文字列を操作・加工する関数を一部紹介します。

PathCch系関数とPath系関数

パス操作関数には主に「PathCch○○」の形式と「Path○○」の形式があります。
PathCch系の関数はWindows8以降で使用可能です。
Windows7以前の環境に対応する場合はPath系関数を使用する必要があります。

Path系関数はバッファのサイズを指定する引数がなく、バッファオーバーランの危険性があるので、可能ならPathCch系を使用します。
(ただし全てのPath系関数に対応するPathCch版があるわけではありません)

PathCch系の関数の使用にはPathcch.libのリンクおよびPathcch.hのインクルードが必要です。


#pragma comment(lib, "Pathcch.lib")
#include <windows.h>
#include <Pathcch.h>

PathCch系関数では、文字列の「サイズ」「長さ」は文字数を意味します。
全てWCHAR型文字列用で、char型文字列用はありません。

戻り値がHRESULT型の場合、関数の成功/失敗を示す定数が返されます。
SUCCEEDEDマクロまたはFAILEDマクロで成否を判別します。


WCHAR path[MAX_PATH] = L"C:\\test";
HRESULT result = PathCchAddBackslash(path, MAX_PATH);
if(SUCCEEDED(result)) {
	//成功
}
else
{
	//失敗
}S

Path系の関数の使用にはShlwapi.libのリンクおよびShlwapi.hのインクルードが必要です。


#pragma comment(lib, "Shlwapi.lib")
#include <windows.h>
#include <Shlwapi.h>

Path系の関数を使用する場合はコピー先となる文字列バッファのサイズは十分な大きさを取るようにしてください。
(MAX_PATHが望ましいが、それでも完全には防げない)

元のパス文字列よりも長くなる可能性のある加工を行うPath系関数は、バッファオーバーランの危険性が特に高いため標準で無効になっています。
使用する場合はコードの先頭に以下の一行を追加します。


#pragma warning(disable : 4995)

なお、ここで紹介する関数はすべて指定のパスにファイルやディレクトリが存在するか否かは動作に関係しない、単純な文字列操作関数です。
例えばPathFileExists関数などは実際のファイルの有無により動作が変わりますが、そういった関数はこのページでは紹介しません。
また、実際のファイルが操作されることはありません。

目次

パスに使用可能な文字のチェック

PathGetCharType関数

PathGetCharType関数は、文字がパス文字として使用可能かをチェックします。

UINT PathGetCharTypeW(
 WCHAR ch
);
文字chがパスに使用可能かを判定する。

戻り値は以下の定数の組み合わせです。

定数 説明
GCT_INVALID
(0)
パスとして無効な文字
GCT_LFNCHAR
(1)
長いファイル名で有効な文字
GCT_SHORTCHAR
(2)
短いファイル名(8.3形式)で有効な文字
GCT_WILD
(4)
ワイルドカード文字
GCT_SEPARATOR
(8)
区切り文字

例えばアルファベットは長いファイル名にも短いファイル名にも使用できるので、GCT_LFNCHARGCT_SHORTCHARの組み合わせが返ります。
ワイルドカード文字は「?」と「*」で、通常のパス文字列には使用できず、プログラム上で使用される文字です。

この関数は「文字」ひとつをチェックする関数です。
文字列全体が有効なパス文字列かをチェックするものではないので注意してください。

末尾に区切り文字を追加

PathCchAddBackslash関数

PathCchAddBackslash関数は、パス文字列の末尾にパス区切り文字(\記号)を追加します。

WINPATHCCHAPI HRESULT PathCchAddBackslash(
 PWSTR pszPath,
 size_t cchPath
);
長さcchPathのパス文字列pszPathの末尾にパス区切り文字を追加する。
成功した場合はS_OKを返す。
末尾が既に区切り文字である場合はS_FALSEを返す。
失敗した場合はそれ以外の値を返す。

この関数は文字列の末尾が既に区切り文字である場合は何もしません。

PathCchAddBackslashEx関数

PathCchAddBackslashEx関数は基本的にPathCchAddBackslash関数と同じですが、関数成功時に文字列バッファの残りの領域に関する情報を得ることができます。

WINPATHCCHAPI HRESULT PathCchAddBackslashEx(
 PWSTR pszPath,
 size_t cchPath,
 PWSTR *ppszEnd,
 size_t *pcchRemaining
);
長さcchPathのパス文字列pszPathの末尾にパス区切り文字を追加する。
文字ポインタppszEndには終端のNULL文字へのポインタが格納される。
サイズポインタpcchRemainingにはpszPathの残りのサイズが格納される。
成功した場合はS_OKを返す。
末尾が既に区切り文字である場合はS_FALSEを返す。
失敗した場合はそれ以外の値を返す。

第三引数ppszEndは文字列型のポインタを指定します。
(要するにWCHAR*型のポインタ渡し)
関数成功時、ここには終端のNULL文字の位置が格納されます。

第四引数pcchRemainingはsize_t型のポインタを指定します。
関数成功時、ここには終端のNULL文字以降の余った文字列の数が格納されます。
(NULL文字を含む)

PathAddBackslash関数

PathAddBackslash関数は、パス文字列の末尾にパス区切り文字(\記号)を追加します。

LPWSTR PathAddBackslashW(
 LPWSTR pszPath
);
パス文字列pszPathの末尾にパス区切り文字を追加する。
戻り値は終端のNULL文字へのポインタ。
失敗した場合はNULL。

この関数は文字列の末尾が既に区切り文字である場合は何もしません。

末尾の区切り文字を除去

PathCchRemoveBackslash

PathCchRemoveBackslash関数は、パス文字列の末尾の区切り文字を除去します。

WINPATHCCHAPI HRESULT PathCchRemoveBackslash(
 PWSTR pszPath,
 size_t cchPath
);
長さcchPathのパス文字列pszPathから、末尾のパス区切り文字を除去する。
成功した場合はS_OKを返す。
末尾が区切り文字でない場合はS_FALSEを返す。
失敗した場合はそれ以外の値を返す。

PathCchAddBackslash関数の逆の働きをする関数です。

PathCchRemoveBackslashEx関数

PathCchRemoveBackslashEx関数は基本的にPathCchRemoveBackslash関数と同じですが、関数成功時に文字列バッファの残りの領域に関する情報を得ることができます。
(→PathCchAddBackslashEx関数)

WINPATHCCHAPI HRESULT PathCchRemoveBackslashEx(
 PWSTR pszPath,
 size_t cchPath,
 PWSTR *ppszEnd,
 size_t *pcchRemaining
);
長さcchPathのパス文字列pszPathから、末尾のパス区切り文字を除去する。
文字ポインタppszEndには終端のNULL文字へのポインタが格納される。
サイズポインタpcchRemainingにはpszPathの残りのサイズが格納される。
成功した場合はS_OKを返す。
末尾が既に区切り文字である場合はS_FALSEを返す。
失敗した場合はそれ以外の値を返す。

PathRemoveBackslash関数

PathRemoveBackslash関数は、パス文字列の末尾の区切り文字を除去します。

LPWSTR PathRemoveBackslashW(
 LPWSTR pszPath
);
パス文字列pszPathから、末尾のパス区切り文字を除去する。

拡張子の追加

PathCchAddExtension関数

PathCchAddExtension関数は、パス文字列の末尾に拡張子を追加します。

WINPATHCCHAPI HRESULT PathCchAddExtension(
 PWSTR pszPath,
 size_t cchPath,
 PCWSTR pszExt
);
長さcchPathのパス文字列pszPathの末尾に拡張子文字列pszExtを追加する。
成功した場合はS_OKを返す。
文字列pszPathに既に拡張子がある場合はS_FALSEを返す。

戻り値は以下の定数のいずれかです。

定数 説明
S_OK 関数の成功。
S_FALSE パス文字列にはすでに拡張子がある。
PATHCCH_E_FILENAME_TOO_LONG バッファサイズが足りないため追加できなかった。
E_INVALIDARG その他のエラー。

パス文字列にすでに拡張子がある場合は文字列は変更されません。

第三引数pszExtは拡張子を示す文字列ですが、ピリオドの有無はどちらでも構いません。
つまり「.txt」でも「txt」でも同じ動作になります。
ピリオドのみを指定した場合はS_OKを返し、元の文字列は変更されません。

拡張子を操作する関数全般に言えることですが、ドット(ピリオド)を含むファイル名の場合は意図した通りの動作にはなりません。

PathAddExtension関数

PathAddExtension関数は、パス文字列の末尾に拡張子を追加します。

BOOL PathAddExtensionW(
 LPWSTR pszPath,
 LPCWSTR pszExt
);
パス文字列pszPathの末尾に拡張子文字列pszExtを追加する。
成功した場合はTRUEを、失敗した場合はFALSEを返す。

パス文字列にすでに拡張子がある場合は文字列は変更されません。

第一引数pszPathNULLを指定すると結果は拡張子のみの文字列となります。
第二引数pszExtNULLを指定すると拡張子「.exe」が追加されます。

拡張子の削除

PathCchRemoveExtension関数

PathCchRemoveExtension関数は、パス文字列から拡張子を削除します。

WINPATHCCHAPI HRESULT PathCchRemoveExtension(
 PWSTR pszPath,
 size_t cchPath
);
長さcchPathのパス文字列pszPathから拡張子を削除する。
成功した場合はS_OKを返す。
拡張子が無い場合はS_FALSEを返す。
失敗した場合はそれ以外の値を返す。

PathRemoveExtension関数

PathRemoveExtension関数は、パス文字列から拡張子を削除します。

void PathRemoveExtensionW(
 LPWSTR pszPath
);
パス文字列pszPathから拡張子を削除する。
戻り値はなし。

拡張子の変更

PathCchRenameExtension関数

PathCchRenameExtension関数は、パス文字列の拡張子を置き換えます。

WINPATHCCHAPI HRESULT PathCchRenameExtension(
 pszPath,
 size_t cchPath,
 PCWSTR pszExt
);
長さcchPathのパス文字列pszPathの拡張子を文字列pszExtに置き換える。
文字列pszPathに拡張子が存在しない場合は追加する。
成功した場合はS_OKを返す。
失敗した場合はそれ以外の値を返す。

第三引数pszExtは拡張子を示す文字列ですが、ピリオドの有無はどちらでも構いません。
つまり「.txt」でも「txt」でも同じ動作になります。

パス文字列に拡張子がない場合は追加します。
拡張子に空の文字列を指定するとパス文字列から拡張子を削除します。

PathRenameExtension関数

PathRenameExtension関数は、パス文字列の拡張子を置き換えます。

BOOL PathRenameExtensionW(
 LPWSTR pszPath,
 LPCWSTR pszExt
);
パス文字列pszPathの拡張子を文字列pszExtに置き換える。
成功した場合はTRUEを、失敗した場合はFALSEを返す。

拡張子の検索

PathCchFindExtension関数

PathCchFindExtension関数は、パス文字列から拡張子を検索します。

WINPATHCCHAPI HRESULT PathCchFindExtension(
 PCWSTR pszPath,
 size_t cchPath,
 PCWSTR *ppszExt
);
長さcchPathのパス文字列pszPathから拡張子のピリオドの位置へのポインタを取得し、文字ポインタ変数ppszExtに格納する。
成功した場合はS_OKを返す。
失敗した場合はそれ以外の値を返す。

PathFindExtension関数

PathFindExtension関数は、パス文字列から拡張子を検索し位置を返します。

LPCWSTR PathFindExtensionW(
 LPCWSTR pszPath
);
パス文字列pszPathから拡張子のピリオドの位置へのポインタを返す。
見つからなかった場合はNULLを返す。

ファイル名の検索

PathFindFileName関数

PathFindFileName関数は、パス文字列からファイル名の位置を返します。

LPCWSTR PathFindFileNameW(
 LPCWSTR pszPath
);
パス文字列pszPathからファイル名の位置へのポインタを返す。
見つからなかった場合はパス文字列先頭へのポインタを返す。

「ファイル名」はパス文字列中の最後の区切り文字以降の文字列です。
ただし文字列の末尾が区切り文字の場合は最後から二番目の区切り文字以降をファイル名とみなします。
ルートディレクトリ名のみを指定した場合はパス文字列の先頭位置を返します。


WCHAR* p;
WCHAR* path = L"C:\\test\\abc.txt";
p = PathFindFileName(path);
//abc.txt

path = L"C:\\test\\abc.txt\\";
p = PathFindFileName(path);
//abc.txt\

path = L"C:\\";
p = PathFindFileName(path);
//C:\

バッファ文字列自体を加工したい場合はPathStripPath関数を使用します。

区切り文字の検索

PathFindNextComponent関数

PathFindNextComponent関数は、パス文字列から区切り文字を検索し、その次の文字の位置を返します。

LPCWSTR PathFindNextComponentW(
 LPCWSTR pszPath
);
パス文字列pszPathから区切り文字(\記号)の次の文字へのポインタを返す。
見つからなかった場合はパス文字列の終端NULL文字へのポインタを返す。
パス文字列pszPathがNULL文字の場合、および関数が失敗した場合はNULLを返す。

この関数は文字列中の最初の区切り文字の次の文字へのポインタを返します。
終端のNULL文字が現れるまで繰り返すことで、パス文字列中のディレクトリ名とファイル名をすべて取得することができます。

末尾文字列の検索

PathFindSuffixArray関数

PathFindSuffixArray関数は、パス文字列の末尾が文字列配列中のいずれかの文字列と一致するかを検索し、その位置を返します。

LPCWSTR PathFindSuffixArrayW(
 LPCWSTR pszPath,
 const LPCWSTR *apszSuffix,
 int iArraySize
);
パス文字列pszPathが、要素数iArraySizeの文字列配列apszSuffix内のいずれかの文字列で終了するかを検索する。
成功した場合は見つかった文字列へのポインタを返す。
失敗した場合はNULLを返す。

関数の呼び出しの前に、末尾文字列リストを格納する配列を用意しておきます。
文字列は大文字と小文字を区別します。


WCHAR *path = L"C:\\test\\abc.txt";
WCHAR *suffixs[] = {
	L".exe", L".txt", L".jpg"
};
int suffixsLen = sizeof(suffixs) / sizeof(suffixs[0]);

WCHAR *suffix = PathFindSuffixArray(path, suffixs, suffixsLen);
//ポインタsuffixはpath中の「.txt」の位置を指す

先頭文字列のチェック

PathIsPrefix関数

PathIsPrefix関数は、パス文字列が指定の文字列から始まるか否かを判定します。

BOOL PathIsPrefixW(
 LPCWSTR pszPrefix,
 LPCWSTR pszPath
);
パス文字列pszPathが文字列pszPrefixで始まる場合はTRUEを返す。
それ以外の場合はFALSEを返す。

ドライブ名のチェック

PathGetDriveNumber関数

PathGetDriveNumber関数は、パス文字列が有効なドライブ文字列から始まるか否かを判定します。

int PathGetDriveNumberW(
 LPCWSTR pszPath
);
パス文字列pszPathが「A:」から「Z:」の範囲の文字列から始まる場合は対応するドライブ番号を返す。
それ以外の場合は-1を返す。

ドライブ文字列は「A:」から「Z:」の範囲で、0から25の範囲の数値が返されます。
大文字小文字は区別されません。
コロン以降の文字列は無視されます。

あくまでもパス文字列のチェックで、システムにそのドライブが存在しなくても動作は変わりません。

ファイル名か否かのチェック

PathIsFileSpec関数

PathIsFileSpec関数は、パス文字列がファイル名か否かを判定します。

BOOL PathIsFileSpecW(
 LPCWSTR pszPath
);
パス文字列pszPathに区切り文字(\記号および:記号)が含まれない場合はTRUEを返す。
含まれる場合はFALSEを返す。

あくまでも区切り文字とドライブ記号のチェックしかしないので、ファイル名として使用できない文字が含まれていてもTRUEを返します。

ルートディレクトリのチェック

PathCchIsRoot関数

PathCchIsRoot関数は、パス文字列がルートディレクトリを示しているか否かを判定します。

WINPATHCCHAPI BOOL PathCchIsRoot(
 PCWSTR pszPath
);
パス文字列pszPathがルートディレクトリならTRUEを返す。
それ以外の場合はFALSEを返す。

ルートディレクトリとは、パスの階層構造の最上位となるディレクトリのことです。
例えば「C:\」「\」などはルートディレクトリとみなされます。
「C:」「C:\abc」「\abc」「abc\def」などはFALSEになります。

PathIsRoot関数

PathIsRoot関数は、パス文字列がルートディレクトリを示しているか否かを判定します。

BOOL PathIsRootW(
 LPCWSTR pszPath
);
パス文字列pszPathがルートディレクトリならTRUEを返す。
それ以外の場合はFALSEを返す。

共通のルートをチェック

PathIsSameRoot関数

PathIsSameRoot関数は、二つのパス文字列が同じルートディレクトリか否かを判定します。

BOOL PathIsSameRootW(
 LPCWSTR pszPath1,
 LPCWSTR pszPath2
);
パス文字列pszPathがパス文字列pszPath2と共通のルートを持つ場合はTRUEを返す。
それ以外の場合はFALSEを返す。

指定するパス文字列は絶対パスでなければなりません。
「C:\abc」と「C:\def」の比較はTRUEを返しますが、「abc\def」と「abc\ghi」の比較ではFALSEを返します。

共通の接頭辞の検索

PathCommonPrefix関数

PathCommonPrefix関数は、二つのパス文字列の先頭から共通するパス文字列を調べます。

int PathCommonPrefixW(
 LPCWSTR pszFile1,
 LPCWSTR pszFile2,
 LPWSTR achPath
);
パス文字列pszFile1とパス文字列pszFile2に共通するパス文字列を検索し、文字列バッファachPathに格納する。
戻り値はバッファachPathの文字数。

この関数は単純に先頭から一致する文字を検索するのではなく、一致するディレクトリ構造を調べます。
一致するものがなかった場合は第三引数achPathNULLになり、0が返されます。
また、achPathは少なくともMAX_PATH以上のサイズを確保しておく必要があります。


WCHAR path[MAX_PATH];
int len;

len = PathCommonPrefix(L"C:\\aaa\\bbb", L"C:\\aaa\\ccc", path);
//path = C:\aaa, len = 6


len = PathCommonPrefix(L"C:\\aaax\\bbb", L"C:\\aaay\\ccc", path);
//path = C:\, len = 3

ワイルドカードのテスト

PathMatchSpec関数

PathMatchSpec関数は、パス文字列がワイルドカードに一致するかを判定します。

BOOL PathMatchSpecW(
 LPCWSTR pszFile,
 LPCWSTR pszSpec
);
パス文字列pszFileからワイルドカードパターン文字列pszSpecを検索する。
パターンが一致したらTRUEを、一致しなければFALSEを返す。

ワイルドカードは「?」が任意の一文字、「*」が0文字以上の任意の文字列にマッチします。


BOOL match;

//「.txt」で終わるかをチェック
match = PathMatchSpec(L"C:\\aaa\\file.txt", L"*.txt");
//TRUE

match = PathMatchSpec(L"C:\\aaa\\file.exe", L"*.txt");
//FALSE

//「C:\aaa\」フォルダ内にあるかをチェック
match = PathMatchSpec(L"C:\\aaa\\file.exe", L"C:\\aaa\\*");
//TRUE

match = PathMatchSpec(L"C:\\bbb\\file.exe", L"C:\\aaa\\*");
//FALSE

//「202○.txt」に一致するかをチェック
match = PathMatchSpec(L"2021.txt", L"202?.txt");
//TRUE

match = PathMatchSpec(L"2022.txt", L"202?.txt");
//TRUE

match = PathMatchSpec(L"2019.txt", L"202?.txt");
//FALSE

ルートの除去

PathCchSkipRoot関数

PathCchSkipRoot関数は、パス文字列からルート文字列を検索し、その次の文字列の位置を取得します。

WINPATHCCHAPI HRESULT PathCchSkipRoot(
 PCWSTR pszPath,
 PCWSTR *ppszRootEnd
);
パス文字列pszPathからルート文字列を検索し、その次の文字の位置を文字ポインタppszRootEndに格納する。
成功した場合はS_OKを返す。
失敗した場合はそれ以外の値を返す。

この関数は文字列バッファに変更を加えず、ルート文字列を除いた位置のポインタを取得します。
ルート文字列とは例えば「C:\」「\\server\share\」などです。
得られるポインタの先頭には区切り文字は含まれません。
文字列の先頭がルート文字列でない場合は関数は失敗します。

PathSkipRoot関数

PathSkipRoot関数は、パス文字列からルート文字列を検索し、その次の文字列の位置を返します。

LPCWSTR PathSkipRootW(
 LPCWSTR pszPath
);
パス文字列pszPathからルート文字列を検索し、その次の文字の位置を返す。

位置ポインタを受け取る方法は異なりますが、動作はPathCchSkipRoot関数と同じです。

ディレクトリの除去

PathStripPath関数

PathStripPath関数は、パス文字列からディレクトリ部分を取り除きます。

void PathStripPathW(
 LPWSTR pszPath
);
パス文字列pszPathからディレクトリを示す箇所を除去する。

結果として、文字列バッファにはファイル名が格納された状態になります。
区切り文字がない場合やルートディレクトリ名のみを指定した場合は何もしません。

ファイル名の位置のポインタを取得する場合はPathFindFileName関数を使用します。

ルートディレクトリの取得

PathCchStripToRoot関数

PathCchStripToRoot関数は、パス文字列からルートディレクトリ部分以外を取り除きます。

WINPATHCCHAPI HRESULT PathCchStripToRoot(
 PWSTR pszPath,
 size_t cchPath
);
長さcchPathのパス文字列pszPathからルートディレクトリを示す箇所以外を除去する。
成功した場合はS_OKを返す。
失敗した場合はそれ以外を返す。

PathStripToRoot関数

PathStripToRoot関数は、パス文字列からルートディレクトリ部分以外を取り除きます。

BOOL PathStripToRootW(
 LPWSTR pszPath
fds );
パス文字列pszPathからルートディレクトリを示す箇所以外を除去する。
成功した場合はTRUEを、失敗した場合はFALSEを返す。

ルートディレクトリに該当する部分がない場合は文字列はすべて消去されます。

末尾要素の除去

PathCchRemoveFileSpec関数

PathCchRemoveFileSpec関数は、末尾のファイル名/ディレクトリ名、および区切り文字を取り除きます。

WINPATHCCHAPI HRESULT PathCchRemoveFileSpec(
 PWSTR pszPath,
 size_t cchPath
);
長さcchPathのパス文字列pszPathから、末尾のファイル名またはディレクトリ名と区切り文字を除去する。
成功した場合はS_OKを返す。
失敗した場合はそれ以外の値を返す。

要するに現在の場所からひとつ上の階層に移動した時のパス文字列を取得します。
ルートディレクトリ(ある場合)は除去されずに残ります。


WCHAR path1[MAX_PATH] = L"C:\\aaa\\bbb";
PathCchRemoveFileSpec(path1, MAX_PATH);
//C:\aaa

WCHAR path2[MAX_PATH] = L"C:\\aaa\\bbb\\";
PathCchRemoveFileSpec(path2, MAX_PATH);
//C:\aaa\\bbb

WCHAR path3[MAX_PATH] = L"C:\\";
PathCchRemoveFileSpec(path3, MAX_PATH);
//C:\

WCHAR path4[MAX_PATH] = L"aaa\\bbb";
PathCchRemoveFileSpec(path4, MAX_PATH);
//aaa

WCHAR path5[MAX_PATH] = L"\\aaa";
PathCchRemoveFileSpec(path5, MAX_PATH);
//\

WCHAR path6[MAX_PATH] = L"aaa";
PathCchRemoveFileSpec(path6, MAX_PATH);
//(空文字)

PathRemoveFileSpec関数

PathRemoveFileSpec関数は、末尾のファイル名/ディレクトリ名、および区切り文字を取り除きます。

BOOL PathRemoveFileSpecW(
 LPWSTR pszPath
);
パス文字列pszPathから、末尾のファイル名またはディレクトリ名と区切り文字を除去する。
成功した場合はTRUEを、失敗した場合はFALSEを返す。

パスの正規化

PathCchCanonicalize関数

PathCchCanonicalize関数は、パス文字列を正規化します。

WINPATHCCHAPI HRESULT PathCchCanonicalize(
 PWSTR pszPathOut,
 size_t cchPathOut,
 PCWSTR pszPathIn
);
長さcchPathOutの文字列バッファpszPathOutに、パス文字列pszPathInを正規化して格納する。
成功した場合はS_OKを返す。
失敗した場合はそれ以外の値を返す。

この場合の正規化とは、ディレクトリの階層構造を示すピリオドを含むパス文字列を展開することを言います。
パス文字列として使用できない文字を取り除いたり、スラッシュをバックスラッシュ(円記号)に置き換えたりはしません。

「.\aaa」は同じ階層の「aaa」ディレクトリ(またはファイル)を意味します。
「..\aaa」はひとつ上の階層の「aaa」ディレクトリ(またはファイル)を意味します。


WCHAR path[MAX_PATH];
PathCchCanonicalize(path, MAX_PATH, L"C:\\aaa\\.\\bbb");
//C:\aaa\bbb

PathCchCanonicalize(path, MAX_PATH, L"C:\\aaa\\..\\bbb");
//C:\bbb

PathCchCanonicalize(path, MAX_PATH, L"C:\\aaa\\bbb\\..\\..\\ccc");
//C:\ccc

PathCchCanonicalize(path, MAX_PATH, L"C:\\aaa\\bbb\\.");
//C:\aaa\bbb

PathCchCanonicalize(path, MAX_PATH, L"C:\\aaa\\bbb\\..");
//C:\aaa

PathCchCanonicalize(path, MAX_PATH, L"C:\\..\\..\\..");
//C:\

PathCchCanonicalize(path, MAX_PATH, L"aaa\\bbb\\..\\..");
//\

PathCanonicalize関数

PathCanonicalize関数は、パス文字列を正規化します。

BOOL PathCanonicalizeW(
 LPWSTR pszBuf,
 LPCWSTR pszPath
);
文字列バッファpszBufに、パス文字列pszPathを正規化して格納する。
成功した場合はTRUEを、失敗した場合はFALSEを返す。

相対パスのチェック

PathIsRelative関数

PathIsRelative関数は、パス文字列が相対パスか否かを判定します。

BOOL PathIsRelativeW(
 LPCWSTR pszPath
);
パス文字列pszPathが相対パスならTRUEを返す。
絶対パスならFALSEを返す。

相対パスはたとえば「abc\def」「.\abc」「..\abc」といった形式、および単純なファイル名です。
区切り文字から始まるパス文字列は絶対パスとみなされます。
(Windowsではあり得ませんが、UNIX系では有効な絶対パスです)

相対パスの取得

PathRelativePathTo関数

PathRelativePathTo関数は、あるパスからもうひとつのパスへの相対パスを取得します。

BOOL PathRelativePathToW(
 LPWSTR pszPath,
 LPCWSTR pszFrom,
 DWORD dwAttrFrom,
 LPCWSTR pszTo,
 DWORD dwAttrTo );

パス文字列pszFromからパス文字列pszToへの相対パスを生成し、文字列バッファpszPathに格納する。
成功した場合はTRUEを、失敗した場合はFALSEを返す。

第一引数pszPathは生成された文字列を格納するバッファです。
少なくともMAX_PATH以上のサイズを確保しておく必要があります。

第二引数pszFromは起点となるパス文字列、第四引数pszToは目的となるパス文字列です。
pszFromからpszToへの相対パス文字列を生成します。

第三引数dwAttrFromと第五引数dwAttrToは、それぞれpszFromとpszToがディレクトリかファイルかを示す定数を指定します。
ここに定数FILE_ATTRIBUTE_DIRECTORYを指定するとパスはディレクトリであるとみなされます。
それ以外を指定するとファイルとみなされます。


WCHAR path[MAX_PATH];

PathRelativePathTo(path,
	L"C:\\aaa\\", FILE_ATTRIBUTE_DIRECTORY,
	L"C:\\aaa\\bbb", FILE_ATTRIBUTE_DIRECTORY);
//.\bbb

PathRelativePathTo(path,
	L"C:\\aaa\\bbb", FILE_ATTRIBUTE_DIRECTORY,
	L"C:\\aaa", FILE_ATTRIBUTE_DIRECTORY);
//..

PathRelativePathTo(path, 
	L"C:\\aaa\\bbb", FILE_ATTRIBUTE_DIRECTORY,
	L"C:\\aaa\\ccc", FILE_ATTRIBUTE_DIRECTORY);
//..\ccc

PathRelativePathTo(path,
	L"aaa\\bbb", FILE_ATTRIBUTE_DIRECTORY,
	L"aaa\\ccc", FILE_ATTRIBUTE_DIRECTORY);
//..\ccc

PathRelativePathTo(path,
	L"C:\\aaa", FILE_ATTRIBUTE_DIRECTORY,
	L"D:\\aaa", FILE_ATTRIBUTE_DIRECTORY);
//※関数失敗
//異なるドライブへの相対パスは作成できない

PathRelativePathTo(path,
	L"aaa\\bbb", FILE_ATTRIBUTE_DIRECTORY,
	L"ccc\\ddd", FILE_ATTRIBUTE_DIRECTORY);
//※関数失敗
//共通のディレクトリがないため相対的な位置がわからない

パスには相対パスを指定することも可能ですが、先頭のディレクトリは共通である必要があります。

URL形式のチェック

PathIsURL関数

PathIsURL関数は、パス文字列がURL形式か否かを判定します。

BOOL PathIsURLW(
 LPCWSTR pszPath
);
パス文字列pszPathが有効なURL形式ならTRUEを返す。
絶対パスならFALSEを返す。

URL形式とは例えば「http:」などから始まる文字列です。
この関数は「C:」はFALSEになりますが、「CC:」「123:」などはTRUEとなります。
コロン以降の文字列のチェックも行わないので、一般的なウェブサイトのアドレス形式のチェックとしては使えません。

パスの結合

PathCchCombine関数

PathCchCombine関数は、二つのパス文字列を結合します。

WINPATHCCHAPI HRESULT PathCchCombine(
 PWSTR pszPathOut,
 size_t cchPathOut,
 PCWSTR pszPathIn,
 PCWSTR pszMore
);
長さcchPathOutの文字列バッファpszPathOutに、パス文字列pszPathInとパス文字列pszMoreを結合して格納する。
成功した場合はS_OKを返す。 失敗した場合はそれ以外の値を返す。

戻り値は以下の定数のいずれかです。

定数 説明
S_OK 関数の成功。
E_OUTOFMEMORY メモリ不足エラー。
PATHCCH_E_FILENAME_TOO_LONG パス文字列のサイズが大きすぎる。
(PATHCCH_MAX_CCHを超えた)
E_INVALIDARG その他のエラー。

パスを結合する関数は単純な文字列の結合ではなく、パスの整合性を考慮して結合されます。
区切り文字が必要な場合は自動で挿入されます。
第三引数第三引数pszPathInが相対パスを示す「.\」「..\」から始まる場合は除去されます。
第四引数pszMoreの相対パスの指定は結果に反映されます。


WCHAR path[MAX_PATH];
PathCchCombine(path, MAX_PATH, L"C:\\aaa\\bbb", L"ccc\\ddd");
//pathには「C:\aaa\bbb\ccc\ddd」が格納される

PathCchCombine(path, MAX_PATH, L"..\\aaa\\bbb", L"ccc\\ddd");
//pathには「aaa\bbb\ccc\ddd」が格納される

PathCchCombine(path, MAX_PATH, L"aaa\\bbb", L"..\\ccc\\ddd");
//pathには「aaa\ccc\ddd」が格納される
//(「..\」はひとつ上の階層を意味する)

第四引数pszMoreに区切り文字から始まる文字列を指定すると、第三引数pszPathInのルート(ドライブ文字列)と結合した文字列が作成されます。
第三引数が相対パスの場合は関数は失敗します。


WCHAR path[MAX_PATH];
PathCchCombine(path, MAX_PATH, L"C:\\aaa\\bbb", L"\\ccc\\ddd");
//pathには「C:\ccc\ddd」が格納される

第四引数pszMoreに絶対パスを指定すると第四引数のパス文字列がそのままバッファにコピーされます。
(第三引数は無視される)

この関数は第一引数と第三引数or第四引数に同じ変数を指定することができます。


WCHAR path[MAX_PATH] = L"C:\\aaa\\bbb";
PathCchCombine(path, MAX_PATH, path, L"ccc\\ddd");

PathCombine関数

PathCombine関数は、二つのパス文字列を結合します。

LPWSTR PathCombineW(
 LPWSTR pszDest,
 LPCWSTR pszDir,
 LPCWSTR pszFile
);
文字列バッファpszDestに、パス文字列pszDirとパス文字列pszFileを結合して格納する。
成功した場合はpszDestへのポインタを、失敗した場合はNULLを返す。

PathCchAppend関数

PathCchAppend関数は、二つのパス文字列を結合します。

WINPATHCCHAPI HRESULT PathCchAppend(
 PWSTR pszPath,
 size_t cchPath,
 PCWSTR pszMore
);
長さcchPathの文字列バッファpszPathの末尾にパス文字列pszMoreを結合する。
成功した場合はS_OKを、失敗した場合はそれ以外を返す。

パス結合のルールはPathCchCombine関数と基本的に同じですが、第三引数pszMoreに区切り文字から始まるパスを指定した場合の動作は異なります。
PathCchCombine関数の場合は先頭パスのルート文字列と追加のパスが結合されますが、PathCchAppend関数では単純にパスの結合になります。


WCHAR path[MAX_PATH] = L"C:\\aaa\\bbb";
PathCchAppend(path, MAX_PATH, L"\\ccc\\ddd");
//pathには「C:\aaa\bbb\ccc\ddd」が格納される

PathCchCombine(path, MAX_PATH, L"C:\\aaa\\bbb", L"\\ccc\\ddd");
//pathには「C:\ccc\ddd」が格納される

PathAppend関数

PathAppend関数は、二つのパス文字列を結合します。
結合のルールはPathCchAppend関数と同じです。

BOOL PathAppendW(
 LPWSTR pszPath,
 LPCWSTR pszMore
);
文字列バッファpszPathの末尾にパス文字列pszMoreを結合する。
成功した場合はTRUEを、失敗した場合はFALSEを返す。