Windowsにおける絶対パスと相対パスの判定や相互変換

のサンプルモジュールです。

#module

	;必要なDLLをロードし、APIをインポート
	#uselib "kernel32"
	#func GetFullPathNameA "GetFullPathNameA" sptr, int, var, var
	#uselib "shlwapi"
	#cfunc PathIsRelativeA "PathIsRelativeA" sptr
	#func PathRelativePathToA "PathRelativePathToA" var, sptr, int, sptr, int

	;必要なフラグ整数値
	#const FILE_ATTRIBUTE_DIRECTORY  0x00000010

	#const _MAX_PATH  260

	;ファイルパスが相対パスかどうか判定
	#defcfunc is_relpath str _fpath
		return PathIsRelativeA(_fpath)

	;ファイルパスが絶対パスかどうか判定
	#defcfunc is_abspath str _fpath
		return (PathIsRelativeA(_fpath) == 0)

	;相対パスを絶対パスに変換
	;to_abspath buffer, relpath[, curdir]
	;
	;引数
	;  buffer   相対パスを格納するバッファ。
	;  abspath  変換する絶対パス。
	;  curdir   変換後の相対パスの基準となるカレントディレクトリのパス。省略時は
	;           dir_curの値が用いられる。
	;
	;戻り値
	;   0  成功
	;  -1  変換に失敗 (GetFullPathNameA関数が失敗)
	;
	#define global to_abspath(%1,%2,%3="")  _to_abspath %1,%2,%3
	#deffunc _to_abspath var _buf, str _relpath, str _curdir
		
		;カレントディレクトリを変更
		if( _curdir != "" ){
			is_chdir = 1
			old_curdir = dir_cur
			chdir _curdir
		}else{
			is_chdir = 0
		}
		
		;絶対パスに変換
		sdim _buf, _MAX_PATH
		offset = 0
		GetFullPathNameA _relpath, _MAX_PATH, _buf, offset
		if( stat == 0 ){
			return -1
		}else:if( _buf == "" ){
			;足りない文字数分のバッファを再確保して、再変換
			bufsize = stat
			sdim _buf, bufsize
			offset = 0
			GetFullPathNameA _relpath, bufsize, _buf, offset
			if( stat == 0 ): return -1
		}
		
		;カレントディレクトリを元に戻す
		if( is_chdir ): chdir old_curdir
		
		return 0

	;絶対パスを相対パスに変換
	;to_relpath buffer, abspath[, curdir]
	;
	;引数
	;  buffer   相対パスを格納するバッファ。
	;  abspath  変換する絶対パス。
	;  curdir   変換後の相対パスの基準となるカレントディレクトリのパス。省略時は
	;           dir_curの値が用いられる。
	;
	;戻り値
	;   0  成功
	;  -1  指定されたパスが相対パスだった
	;  -2  カレントディレクトリと指定された絶対パスのドライブ文字が異なる (変換不可)
	;  -3  変換に失敗 (PathRelativePathTo関数が失敗)
	;
	#define global to_relpath(%1,%2,%3="")  _to_relpath %1,%2,%3
	#deffunc _to_relpath var _buf, str _abspath, str _curdir
		
		;カレントディレクトリが省略された場合は、現在のカレントディレクトリを使用する。
		if( _curdir != "" ){
			curdir = _curdir
		}else{
			curdir = dir_cur
		}
		
		;指定されたパスが絶対パスか判定
		if( PathIsRelativeA(_abspath) ): return -1
		
		;ドライブが同じか判定
		abspath = _abspath
		if( peek(curdir, 0) != peek(abspath, 0) ): return -2
		
		;相対パスに変換
		sdim _buf, _MAX_PATH
		PathRelativePathToA _buf, dir_cur, FILE_ATTRIBUTE_DIRECTORY, _abspath, 0
		if( stat == 0 ): return -2
		
		return 0

#global

モジュールのテストコード。

	;ファイルパス
	curdir = dir_cur
	abspath = "C:\\Windows\\explorer.exe"
	
	mes "カレントディレクトリ '"+curdir+"'"
	mes ""
	
	;相対パスかどうか判定
	if( is_relpath(abspath) ){
		mes "'"+abspath+"'は相対パスです。"
	}else{
		mes "'"+abspath+"'は相対パスではありません。"
	}
	
	;絶対パスかどうか判定
	if( is_abspath(abspath) ){
		mes "'"+abspath+"'は絶対パスです。"
	}else{
		mes "'"+abspath+"'は絶対パスではありません。"
	}
	
	;相対パスに変換
	to_relpath relpath, abspath, curdir
	if( stat ){
		mes "相対パスへの変換に失敗しました。[ERROR "+stat+"]"
		stop
	}
	mes ""
	mes "'"+abspath+"'の相対パスは"
	mes "'"+relpath+"'です。"
	
	;絶対パスに変換
	sdim abspath, 0
	to_abspath abspath, relpath, curdir
	if( stat ){
		mes "絶対パスへの変換に失敗しました。[ERROR "+stat+"]"
		stop
	}
	mes ""
	mes "'"+relpath+"'の絶対パスは"
	mes "'"+abspath+"'です。"

参考サイト等。