DXUT源碼分析 ---- 媒體文件查找函數
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中,該函數聲明如下:
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;
判斷要查找的媒體文件是否存在,該函數聲明如下:
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返回的是最后一個目錄的名稱,而不是文件名。
該函數聲明如下:
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;
該函數聲明如下:
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;
posted on 2008-05-28 16:33 lovedday 閱讀(2013) 評論(2) 編輯 收藏 引用 所屬分類: ■ DXUT Research

