DXUT中涉及到媒体文件查找的函数有3个:DXUTFindMediaSearchTypicalDirs()、DXUTFindMediaSearchParentDirs()、DXUTFindDXSDKMediaFileCch(),都位于DXUTmisc.cpp文件中。
DXUTFindMediaSearchTypicalDirs()分析:
DXUTFindMediaSearchTypicalDirs()这个函数用于在特定的搜索路径中查找媒体文件,主要供DXUTFindDXSDKMediaFileCch()调用以查找媒体文件。
参数分析:
strSearchPath:
函数调用完后将媒体文件的路径返回给该字符串(可能是当前工作目录路径,也可能是全路径)
cchSearch: strSearchPath的长度
strLeaf:指定要查找的媒体文件名
strExePath:当前进程执行文件所在的目录(全路径名)
strExeName:当前进程执行文件名(不包含扩展名)
//--------------------------------------------------------------------------------------
// Search a set of typical directories
//--------------------------------------------------------------------------------------
bool DXUTFindMediaSearchTypicalDirs( WCHAR* strSearchPath, int cchSearch, LPCWSTR strLeaf,
WCHAR* strExePath, WCHAR* strExeName )
{
// Typical directories:
// .\
// ..\
// ..\..\
// %EXE_DIR%\
// %EXE_DIR%\..\
// %EXE_DIR%\..\..\
// %EXE_DIR%\..\%EXE_NAME%
// %EXE_DIR%\..\..\%EXE_NAME%
// DXSDK media path
// Search in .\
StringCchCopy( strSearchPath, cchSearch, strLeaf );
if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
return true;
// Search in ..\
StringCchPrintf( strSearchPath, cchSearch, L"..\\%s", strLeaf );
if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
return true;
// Search in ..\..\
StringCchPrintf( strSearchPath, cchSearch, L"..\\..\\%s", strLeaf );
if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
return true;
// Search in the %EXE_DIR%\
StringCchPrintf( strSearchPath, cchSearch, L"%s\\%s", strExePath, strLeaf );
if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
return true;
// Search in the %EXE_DIR%\..\
StringCchPrintf( strSearchPath, cchSearch, L"%s\\..\\%s", strExePath, strLeaf );
if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
return true;
// Search in the %EXE_DIR%\..\..\
StringCchPrintf( strSearchPath, cchSearch, L"%s\\..\\..\\%s", strExePath, strLeaf );
if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
return true;
// Search in "%EXE_DIR%\..\%EXE_NAME%\". This matches the DirectX SDK layout
StringCchPrintf( strSearchPath, cchSearch, L"%s\\..\\%s\\%s", strExePath, strExeName, strLeaf );
if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
return true;
// Search in "%EXE_DIR%\..\..\%EXE_NAME%\". This matches the DirectX SDK layout
StringCchPrintf( strSearchPath, cchSearch, L"%s\\..\\..\\%s\\%s", strExePath, strExeName, strLeaf );
if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
return true;
// Search in media search dir
WCHAR* s_strSearchPath = DXUTMediaSearchPath();
if( s_strSearchPath[0] != 0 )
{
StringCchPrintf( strSearchPath, cchSearch, L"%s%s", s_strSearchPath, strLeaf );
if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
return true;
}
return false;
}
函数首先在当前工作目录(.\)查找,它首先调用
StringCchCopy( strSearchPath, cchSearch, strLeaf );
将要查找的媒体文件名复制到字符串strSearchPath中,该函数声明如下:
StringCchCopy is a replacement for strcpy. The size, in
characters, of the destination buffer is provided to the function to ensure
that StringCchCopy does not write past the end of this buffer.
Syntax
HRESULT StringCchCopy(
LPTSTR pszDest,
size_t cchDest,
LPCTSTR pszSrc
);
Parameters
- pszDest
- [out] Pointer to a buffer which receives
the copied string.
- cchDest
- [in] Size of the destination buffer, in
characters. This value must equal the length of pszSrc
plus 1 to account for the copied source string and the terminating
null character. The maximum number of characters allowed is
STRSAFE_MAX_CCH.
- pszSrc
- [in] Pointer to a buffer containing the
source string. This source string must be null-terminated.
Return Value
Note that this function returns an HRESULT
as opposed to strcpy, which returns a pointer. It is strongly
recommended that you use the SUCCEEDED and FAILED macros to test the return value of
this function.
S_OK |
Source data was
present, fully copied without truncation, and the resultant
destination buffer is null-terminated. |
STRSAFE_E_INVALID_PARAMETER |
The value in
cchDest is either 0 or larger than STRSAFE_MAX_CCH. |
STRSAFE_E_INSUFFICIENT_BUFFER |
The copy
operation failed due to insufficient buffer space. The
destination buffer contains a truncated, null-terminated version
of the intended result. In situations where truncation is
acceptable, this may not necessarily be seen as a failure
condition. |
Remarks
StringCchCopy provides additional
processing for proper buffer handling in your code. Poor buffer handling
is implicated in many security issues that involve buffer overruns.
StringCchCopy always null-terminates a non-zero-length
destination buffer.
StringCchCopy can be used in its generic
form, or specifically as StringCchCopyA (for ANSI strings) or
StringCchCopyW (for Unicode strings). The form to use is determined
by your data.
String Data
Type |
String Literal |
Function |
char |
"string" |
StringCchCopyA |
TCHAR |
TEXT("string") |
StringCchCopy |
WCHAR |
L"string" |
StringCchCopyW |
接着调用
if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
return true;
判断要查找的媒体文件是否存在,该函数声明如下:
The GetFileAttributes function retrieves a set
of FAT file system attributes for a specified file or directory.
To get more attribute information, use the
GetFileAttributesEx function.
DWORD GetFileAttributes(
LPCTSTR lpFileName
);
Parameters
- lpFileName
- [in] A pointer to a null-terminated string
that specifies the name of a file or directory.
In the ANSI version of this function, the name
is limited to MAX_PATH characters. To extend this limit to 32,767 wide
characters, call the Unicode version of the function and prepend "\\?\"
to the path. For more information, see Naming a File.
Windows Me/98/95: This string must not
exceed MAX_PATH characters.
Return Values
If the function succeeds, the return value contains
the attributes of the specified file or directory.
If the function fails, the return value is
INVALID_FILE_ATTRIBUTES. To get extended error information, call GetLastError.
The attributes can be one or more of the following
values.
Attribute |
Meaning |
FILE_ATTRIBUTE_ARCHIVE |
A file
or directory that is an archive file or directory.
Applications use
this attribute to mark files for backup or removal.
|
FILE_ATTRIBUTE_COMPRESSED |
A file
or directory that is compressed.
For a file, all of
the data in the file is compressed.
For a directory,
compression is the default for newly created files and
subdirectories.
|
FILE_ATTRIBUTE_DEVICE |
Reserved; do not use. |
FILE_ATTRIBUTE_DIRECTORY |
The
handle that identifies a directory. |
FILE_ATTRIBUTE_ENCRYPTED |
A file
or directory that is encrypted.
For a file, all data
streams in the file are encrypted.
For a directory,
encryption is the default for newly created files and
subdirectories.
|
FILE_ATTRIBUTE_HIDDEN |
The
file or directory is hidden. It is not included in an ordinary
directory listing. |
FILE_ATTRIBUTE_NORMAL |
A file
or directory that does not have other attributes set.
This attribute is
valid only when used alone.
|
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED |
The
file is not be indexed by the content indexing service. |
FILE_ATTRIBUTE_OFFLINE |
The
data of a file is not available immediately.
This attribute
indicates that the file data is physically moved to offline storage.
This attribute is used by Remote Storage, which is the hierarchical
storage management software. Applications should not arbitrarily
change this attribute.
|
FILE_ATTRIBUTE_READONLY |
A file
or directory that is read-only.
For a file,
applications can read the file, but cannot write to it or delete it.
For a directory,
applications cannot delete it.
|
FILE_ATTRIBUTE_REPARSE_POINT |
A file
or directory that has an associated reparse point. |
FILE_ATTRIBUTE_SPARSE_FILE |
A file
that is a sparse file. |
FILE_ATTRIBUTE_SYSTEM |
A file
or directory that the operating system uses a part of, or uses
exclusively. |
FILE_ATTRIBUTE_TEMPORARY |
A file
that is being used for temporary storage.
File systems avoid
writing data back to mass storage if sufficient cache memory is
available, because typically, an application deletes a temporary
file after the handle is closed. In that scenario, the system can
entirely avoid writing the data. Otherwise, the data is written
after the handle is closed.
|
Remarks
When GetFileAttributes is called on a
directory that contains a volume mount point, the file attributes returned
are those of the directory where the volume mount point is set, not those of
the root directory in a target mounted volume. To obtain the file attributes
of a mounted volume, call GetVolumeNameForVolumeMountPoint
to obtain the name of the target volume. Then use the resulting name in a
call to GetFileAttributes. The results are the attributes of the root
directory on the target volume.
接着按以下路径搜索媒体文件:
//
..\
// ..\..\
// %EXE_DIR%\
// %EXE_DIR%\..\
// %EXE_DIR%\..\..\
// %EXE_DIR%\..\%EXE_NAME%
// %EXE_DIR%\..\..\%EXE_NAME%
最后在DirectX SDK媒体文件目录中搜索媒体文件,当然该目录必须首先在程序中设置才会被搜索:
// Search in media search dir
WCHAR* s_strSearchPath = DXUTMediaSearchPath();
if( s_strSearchPath[0] != 0 )
{
StringCchPrintf( strSearchPath, cchSearch, L"%s%s", s_strSearchPath, strLeaf );
if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
return true;
}
函数DXUTMediaSearchPath()返回设置的媒体文件搜索路径:
//--------------------------------------------------------------------------------------
// Returns pointer to static media search buffer
//--------------------------------------------------------------------------------------
WCHAR* DXUTMediaSearchPath()
{
static WCHAR s_strMediaSearchPath[MAX_PATH] = {0};
return s_strMediaSearchPath;
}
DXUTFindMediaSearchParentDirs()分析
DXUTFindMediaSearchParentDirs()用于在指定搜索路径的父目录中查找媒体文件,主要供DXUTFindDXSDKMediaFileCch()调用。
参数分析:
strSearchPath:当找到媒体文件时,将媒体文件的全路径名返回给这个字符串。
cchSearch:strSearchPath的长度
strStartAt:指定开始搜索的路径
strLeafName:媒体文件名(包含扩展名)
//--------------------------------------------------------------------------------------
// Search parent directories starting at strStartAt, and appending strLeafName
// at each parent directory. It stops at the root directory.
//--------------------------------------------------------------------------------------
bool DXUTFindMediaSearchParentDirs( WCHAR* strSearchPath, int cchSearch, WCHAR* strStartAt, WCHAR* strLeafName )
{
WCHAR strFullPath[MAX_PATH] = {0};
WCHAR strFullFileName[MAX_PATH] = {0};
WCHAR strSearch[MAX_PATH] = {0};
WCHAR* strFilePart = NULL;
GetFullPathName( strStartAt, MAX_PATH, strFullPath, &strFilePart );
if( strFilePart == NULL )
return false;
while( strFilePart != NULL && *strFilePart != '\0' )
{
StringCchPrintf( strFullFileName, MAX_PATH, L"%s\\%s", strFullPath, strLeafName );
if( GetFileAttributes( strFullFileName ) != 0xFFFFFFFF )
{
StringCchCopy( strSearchPath, cchSearch, strFullFileName );
return true;
}
StringCchPrintf( strSearch, MAX_PATH, L"%s\\..", strFullPath );
GetFullPathName( strSearch, MAX_PATH, strFullPath, &strFilePart );
}
return false;
}
函数首先调用
GetFullPathName( strStartAt,
MAX_PATH, strFullPath, &strFilePart );
if( strFilePart == NULL )
return false;
获取开始搜索的路径全名和文件名,注意如果strStartAt指定的是一个目录,则strFillPart返回的是最后一个目录的名称,而不是文件名。
该函数声明如下:
The GetFullPathName function retrieves the full
path and file name of a specified file.
DWORD GetFullPathName(
LPCTSTR lpFileName,
DWORD nBufferLength,
LPTSTR lpBuffer,
LPTSTR* lpFilePart
);
Parameters
- lpFileName
- [in] A pointer to a null-terminated string
that specifies a valid file name.
This string can use short (the 8.3 form) or
long file names.
- nBufferLength
- [in] The size of the buffer to receive the
null-terminated string for the drive and path, in TCHARs.
- lpBuffer
- [out] A pointer to a buffer that receives the
null-terminated string for the drive and path.
- lpFilePart
- [out] A pointer to a buffer that receives the
address (in lpBuffer) of the final file name component in the
path.
If lpBuffer points to a directory and
not a file, lpFilePart receives 0 (zero).
Return Values
If the function succeeds, the return value is the
length of the string copied to lpBuffer, not including the
terminating null character, in TCHARs.
If the lpBuffer buffer is too small to
contain the path, the return value is the size of the buffer that is
required to hold the path and the terminating null character, in TCHARs.
Therefore, if the return value is greater than nBufferLength, call
the function again with a buffer that is large enough to hold the path.
If the function fails for any other reason, the
return value is 0 (zero). To get extended error information, call GetLastError.
Remarks
GetFullPathName merges the name of the
current drive and directory with a specified file name to determine the full
path and file name of the specified file. It also calculates the address of
the file name portion of the full path and file name. This function does not
verify that the resulting path and file name are valid, or that they see an
existing file on the associated volume.
GetFullPathName does not convert the
specified file name, lpFileName. If the specified file name exists,
you can use GetLongPathName and
GetShortPathName to
convert to long and short path names, respectively.
函数接着不断的上溯目录层查找直到到达分区的根目录为止,如果找到就将strSearchPath置为媒体文件所在的路径全名,并返回true,否则返回false。
while( strFilePart != NULL && *strFilePart != '\0' )
{
StringCchPrintf( strFullFileName, MAX_PATH, L"%s\\%s", strFullPath, strLeafName );
if( GetFileAttributes( strFullFileName ) != 0xFFFFFFFF )
{
StringCchCopy( strSearchPath, cchSearch, strFullFileName );
return true;
}
StringCchPrintf( strSearch, MAX_PATH, L"%s\\..", strFullPath );
GetFullPathName( strSearch, MAX_PATH, strFullPath, &strFilePart );
}
DXUTFindDXSDKMediaFileCch()分析
该函数主要用于查找媒体文件。
参数分析:
strDestPath:函数调用成功后将返回媒体文件的全路径名(若在当前工作目录找到该文件则仅返回媒体文件名),若调用失败则返回媒体文件名。
cchDest:strDestPath的长度。
strFilename:要查找的媒体文件名。
//--------------------------------------------------------------------------------------
// Tries to find the location of a SDK media file.
//
// cchDest is the size in WCHARs of strDestPath.
// Be careful not to pass in sizeof(strDest) on UNICODE builds.
//--------------------------------------------------------------------------------------
HRESULT DXUTFindDXSDKMediaFileCch( WCHAR* strDestPath, int cchDest, LPCWSTR strFilename )
{
bool bFound;
WCHAR strSearchFor[MAX_PATH];
if( NULL==strFilename || strFilename[0] == 0 || NULL==strDestPath || cchDest < 10 )
return E_INVALIDARG;
// Get the exe name, and exe path
WCHAR strExePath[MAX_PATH] = {0};
WCHAR strExeName[MAX_PATH] = {0};
WCHAR* strLastSlash = NULL;
GetModuleFileName(NULL, strExePath, MAX_PATH);
strExePath[MAX_PATH-1] = 0;
strLastSlash = wcsrchr( strExePath, TEXT('\\') );
if( strLastSlash )
{
StringCchCopy( strExeName, MAX_PATH, &strLastSlash[1] );
// Chop the exe name from the exe path
*strLastSlash = 0;
// Chop the .exe from the exe name
strLastSlash = wcsrchr( strExeName, TEXT('.') );
if( strLastSlash )
*strLastSlash = 0;
}
// Typical directories:
// .\
// ..\
// ..\..\
// %EXE_DIR%\
// %EXE_DIR%\..\
// %EXE_DIR%\..\..\
// %EXE_DIR%\..\%EXE_NAME%
// %EXE_DIR%\..\..\%EXE_NAME%
// Typical directory search
bFound = DXUTFindMediaSearchTypicalDirs( strDestPath, cchDest, strFilename, strExePath, strExeName );
if( bFound )
return S_OK;
// Typical directory search again, but also look in a subdir called "\media\"
StringCchPrintf( strSearchFor, MAX_PATH, L"media\\%s", strFilename );
bFound = DXUTFindMediaSearchTypicalDirs( strDestPath, cchDest, strSearchFor, strExePath, strExeName );
if( bFound )
return S_OK;
WCHAR strLeafName[MAX_PATH] = {0};
// Search all parent directories starting at .\ and using strFilename as the leaf name
StringCchCopy( strLeafName, MAX_PATH, strFilename );
bFound = DXUTFindMediaSearchParentDirs( strDestPath, cchDest, L".", strLeafName );
if( bFound )
return S_OK;
// Search all parent directories starting at the exe's dir and using strFilename as the leaf name
bFound = DXUTFindMediaSearchParentDirs( strDestPath, cchDest, strExePath, strLeafName );
if( bFound )
return S_OK;
// Search all parent directories starting at .\ and using "media\strFilename" as the leaf name
StringCchPrintf( strLeafName, MAX_PATH, L"media\\%s", strFilename );
bFound = DXUTFindMediaSearchParentDirs( strDestPath, cchDest, L".", strLeafName );
if( bFound )
return S_OK;
// Search all parent directories starting at the exe's dir and using "media\strFilename" as the leaf name
bFound = DXUTFindMediaSearchParentDirs( strDestPath, cchDest, strExePath, strLeafName );
if( bFound )
return S_OK;
// On failure, return the file as the path but also return an error code
StringCchCopy( strDestPath, cchDest, strFilename );
return DXUTERR_MEDIANOTFOUND;
}
函数首先对参数的合法性进行检查,接着调用GetModuleName()取得进程的全路径名:
// Get the exe name, and exe path
WCHAR strExePath[MAX_PATH] = {0};
WCHAR strExeName[MAX_PATH] = {0};
WCHAR* strLastSlash = NULL;
GetModuleFileName(NULL, strExePath, MAX_PATH);
strExePath[MAX_PATH-1] = 0;
该函数声明如下:
The GetModuleFileName function retrieves the
fully-qualified path for the file that contains the specified module that
the current process owns.
GetModuleFileName operates only on modules that the current process
owns. To specify modules that belong to another process, use the GetModuleFileNameEx
function.
DWORD GetModuleFileName(
HMODULE hModule,
LPTSTR lpFilename,
DWORD nSize
);
Parameters
- hModule
- [in] Handle to the module whose path is being
requested. If this parameter is NULL, GetModuleFileName retrieves
the path of the executable file of the current process.
- lpFilename
- [out] Pointer to a buffer that receives a
null-terminated string that specifies the fully-qualified path of the
module. If the length of the path exceeds the size that the nSize
parameter specifies, the function succeeds, and the string is truncated
to nSize characters and cannot be null terminated.
The string returned will use the same format
that was specified when the module was loaded. Therefore, the path can
be a long or short file name, and can use the prefix "\\?\". For more
information, see Naming a File.
To separate the path from the file name and
extension, use the PathRemoveFileSpec
function. Note that this function does not support paths with the "\\?\"
prefix.
- nSize
- [in] Size of the lpFilename buffer, in
TCHARs.
Return Values
If the function succeeds, the return value is the
length of the string that is copied to the buffer, in TCHARs. If the
buffer is too small to hold the module name, the string is truncated to
nSize, and the function returns nSize.
If the function fails, the return value is 0
(zero). To get extended error information, call GetLastError.
Remarks
If a DLL is loaded in two processes, its file name
in one process may differ in case from its file name in the other process.
For the ANSI version of the function, the number of
TCHARs is the number of bytes; for the Unicode version, it is the
number of characters.
The global variable _pgmptr is automatically
initialized to the full path of the executable file, and can be used to
retrieve the full path name of an executable file.
Windows Me/98/95: This function retrieves
long file names when an application version number is greater than or
equal to 4.00 and the long file name is available. Otherwise, it returns
only 8.3 format file names.
接着将当前进程执行文件的路径存储在strExePath,将进程执行文件名存储在strExeName:
strLastSlash = wcsrchr( strExePath, TEXT('\\') );
if( strLastSlash )
{
StringCchCopy( strExeName, MAX_PATH, &strLastSlash[1] );
// Chop the exe name from the exe path
*strLastSlash = 0;
// Chop the .exe from the exe name
strLastSlash = wcsrchr( strExeName, TEXT('.') );
if( strLastSlash )
*strLastSlash = 0;
}
函数接着按下面的路径查找顺序查找媒体文件:
// Typical directories:
// .\
// ..\
// ..\..\
// %EXE_DIR%\
// %EXE_DIR%\..\
// %EXE_DIR%\..\..\
// %EXE_DIR%\..\%EXE_NAME%
// %EXE_DIR%\..\..\%EXE_NAME%
// Typical directory search
bFound = DXUTFindMediaSearchTypicalDirs( strDestPath, cchDest, strFilename, strExePath, strExeName );
if( bFound )
return S_OK;
如果没有找到,则在上面指定的路径中增加一级目录media查找,即:
// Typical directories:
// .\media
// ..\media
// ..\..\media
// %EXE_DIR%\media
// %EXE_DIR%\..\media
// %EXE_DIR%\..\..\media
// %EXE_DIR%\..\%EXE_NAME%\media
// %EXE_DIR%\..\..\%EXE_NAME%\media
// Typical directory search again, but also look in a subdir called "\media\"
StringCchPrintf( strSearchFor, MAX_PATH, L"media\\%s", strFilename );
bFound = DXUTFindMediaSearchTypicalDirs( strDestPath, cchDest, strSearchFor, strExePath, strExeName );
if( bFound )
return S_OK;
若还没找到,则在当前工作目录的所有父目录中查找:
// Search all parent directories starting at .\ and using strFilename as the leaf name
StringCchCopy( strLeafName, MAX_PATH, strFilename );
bFound = DXUTFindMediaSearchParentDirs( strDestPath, cchDest, L".", strLeafName );
if( bFound )
return S_OK;
若还没找到,则在可执行文件的所有父目录中查找:
// Search all parent directories starting at the exe's dir and using strFilename as the leaf name
bFound = DXUTFindMediaSearchParentDirs( strDestPath, cchDest, strExePath, strLeafName );
if( bFound )
return S_OK;
若还没找到,则在当前工作目录的所有父目录中增加一层目录media中(相当于文件名变为media\filename)查找:
// Search all parent directories starting at .\ and using "media\strFilename" as the leaf name
StringCchPrintf( strLeafName, MAX_PATH, L"media\\%s", strFilename );
bFound = DXUTFindMediaSearchParentDirs( strDestPath, cchDest, L".", strLeafName );
if( bFound )
return S_OK;
若还没找到,则在可执行文件的所有父目录中增加一层目录media中(相当于文件名变为media\filename)查找:
// Search all parent directories starting at the exe's dir and using "media\strFilename" as the leaf name
bFound = DXUTFindMediaSearchParentDirs( strDestPath, cchDest, strExePath, strLeafName );
if( bFound )
return S_OK;
若都没找到,则返回文件名为参数strDestPath,并返回错误值。
// On failure, return the file as the path but also return an error code
StringCchCopy( strDestPath, cchDest, strFilename );
return DXUTERR_MEDIANOTFOUND;