/****************************************************************************\ DISKAPI.C / OPK Wizard (OPKWIZ.EXE) Microsoft Confidential Copyright (c) Microsoft Corporation 1999 All rights reserved Disk API source file for custom disk APIs used in the OPK Wizard. 4/99 - Jason Cohen (JCOHEN) Added this new source file for the OPK Wizard as part of the Millennium rewrite. \****************************************************************************/ // // Include file(s) // #include #include #include #include // // Internal Define(s): // #define IDC_BROWSE_EDIT 0x3744 // Common dialogs edit box in the SHBrowseForFolder function. // // Internal Function Prototype(s): // static DWORD CopyDirectoryEngine(HWND hwnd, HANDLE hEvent, LPCTSTR lpSrc, LPCTSTR lpDst, BOOL fCount); static CALLBACK BrowseCallbackProc(HWND, UINT, LPARAM, LPARAM); // // External Function(s): // BOOL DirectoryExists(LPCTSTR lpDirectory) { DWORD dwAttr; return ( ( lpDirectory != NULL ) && ( *lpDirectory != NULLCHR ) && ( (dwAttr = GetFileAttributes(lpDirectory)) != 0xFFFFFFFF ) && ( dwAttr & FILE_ATTRIBUTE_DIRECTORY ) ); } BOOL FileExists(LPCTSTR lpFile) { DWORD dwAttr; return ( ( lpFile != NULL ) && ( *lpFile != NULLCHR ) && ( (dwAttr = GetFileAttributes(lpFile)) != 0xFFFFFFFF ) && ( !(dwAttr & FILE_ATTRIBUTE_DIRECTORY) ) ); } BOOL CopyResetFile(LPCTSTR lpSource, LPCTSTR lpTarget) { if ( !CopyFile(lpSource, lpTarget, FALSE) ) return FALSE; SetFileAttributes(lpTarget, FILE_ATTRIBUTE_NORMAL); return TRUE; } DWORD IfGetLongPathName(LPCTSTR lpszShortPath, LPTSTR lpszLongPath, DWORD cchBuffer) { // // See also \nt\base\win32\client\vdm.c. // DWORD dwReturn = 0; #if defined(_WIN64) // _WIN64 postdates the introduction of GetLongPathName. typedef (WINAPI* PFNGetLongPathNameA)( PCSTR lpszShortPath, PSTR lpszLongPath, DWORD cchBuffer); typedef (WINAPI* PFNGetLongPathNameW)(PCWSTR lpszShortPath, PWSTR lpszLongPath, DWORD cchBuffer); #ifdef UNICODE typedef PFNGetLongPathNameW PFNGetLongPathName; const static char ProcName[] = "GetLongPathNameW"; #else typedef PFNGetLongPathNameA PFNGetLongPathName; const static char ProcName[] = "GetLongPathNameA"; #endif static PFNGetLongPathName hGetLongPathName = NULL; static BOOL fInited = FALSE; if (!fInited) { // // GetModuleHandle is in kernel32, so as long as this lib code // is around, the handle to kernel32 is constant and the result of // GetProcAccess is valid. // // The old code that called LoadLibrary/FreeLibrary would lose the // value of GetLastError by calling FreeLibrary. // HMODULE hKernel32; if (hKernel32 = GetModuleHandle(TEXT("Kernel32.dll"))) hGetLongPathName = (PFNGetLongPathName)(GetProcAddress(hKernel32, ProcName)); fInited = TRUE; } if (hGetLongPathName) { dwReturn = hGetLongPathName(lpszShortPath, lpszLongPath, cchBuffer); } #else dwReturn = GetLongPathName(lpszShortPath, lpszLongPath, cchBuffer); #endif return dwReturn; } BOOL CreatePath(LPCTSTR lpPath) { LPTSTR lpFind = (LPTSTR) lpPath; while ( lpFind = _tcschr(lpFind + 1, CHR_BACKSLASH) ) { if ( !((lpFind - lpPath <= 2) && (*(lpFind - 1) == _T(':'))) ) { *lpFind = NULLCHR; if ( !DirectoryExists(lpPath) ) CreateDirectory(lpPath, NULL); *lpFind = CHR_BACKSLASH; } } if ( !DirectoryExists(lpPath) ) CreateDirectory(lpPath, NULL); return DirectoryExists(lpPath); } BOOL DeletePath(LPCTSTR lpDirectory) { WIN32_FIND_DATA FileFound; HANDLE hFile; // Validate the parameters. // if ( ( lpDirectory == NULL ) || ( *lpDirectory == NULLCHR ) || ( !SetCurrentDirectory(lpDirectory) ) ) { return TRUE; } // Process all the files and directories in the directory passed in. // SetCurrentDirectory(lpDirectory); if ( (hFile = FindFirstFile(_T("*"), &FileFound)) != INVALID_HANDLE_VALUE ) { do { // First check to see if this is a file (not a directory). // if ( !( FileFound.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) ) { // Make sure we clear the readonly flag // SetFileAttributes(FileFound.cFileName, FILE_ATTRIBUTE_NORMAL); DeleteFile(FileFound.cFileName); } // Otherwise, make sure the directory is not "." or "..". // else if ( ( lstrcmp(FileFound.cFileName, _T(".")) ) && ( lstrcmp(FileFound.cFileName, _T("..")) ) ) { DeletePath(FileFound.cFileName); } } while ( FindNextFile(hFile, &FileFound) ); FindClose(hFile); } // Go to the parent directory and remove the current one. // We have to make sure and reset the readonly attributes // on the dir also. // SetCurrentDirectory(_T("..")); SetFileAttributes(lpDirectory, FILE_ATTRIBUTE_NORMAL); return RemoveDirectory(lpDirectory); } BOOL DeleteFilesEx(LPCTSTR lpDirectory, LPCTSTR lpFileSpec) { WIN32_FIND_DATA FileFound; HANDLE hFile; TCHAR szCurDir[MAX_PATH]; // Validate the parameters. // if ( ( lpDirectory == NULL ) || ( *lpDirectory == NULLCHR ) || ( !SetCurrentDirectory(lpDirectory) ) ) { return FALSE; } // Get our current directory so we can set ourself back // GetCurrentDirectory(MAX_PATH, szCurDir); // Process all the files and directories in the directory passed in. // SetCurrentDirectory(lpDirectory); if ( (hFile = FindFirstFile(lpFileSpec, &FileFound)) != INVALID_HANDLE_VALUE ) { do { // First check to see if this is a file (not a directory). // if ( !( FileFound.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) ) { DeleteFile(FileFound.cFileName); } } while ( FindNextFile(hFile, &FileFound) ); FindClose(hFile); } SetCurrentDirectory(szCurDir); return TRUE; } LPTSTR AddPathN(LPTSTR lpPath, LPCTSTR lpName, DWORD cbPath) { LPTSTR lpTemp = lpPath; // Validate the parameters passed in. // if ( ( lpPath == NULL ) || ( lpName == NULL ) ) { return NULL; } // Find the end of the path. // while ( *lpTemp ) { lpTemp = CharNext(lpTemp); if ( cbPath ) { cbPath--; } } // If no trailing backslash on the path then add one. // if ( ( lpTemp > lpPath ) && ( *CharPrev(lpPath, lpTemp) != CHR_BACKSLASH ) ) { // Make sure there is room in the path buffer to // add the backslash and the null terminator. // if ( cbPath < 2 ) { return NULL; } *lpTemp = CHR_BACKSLASH; lpTemp = CharNext(lpTemp); cbPath--; } else { // Make sure there is at least room for the null // terminator. // if ( cbPath < 1 ) { return NULL; } } // Make sure there is no preceeding spaces or backslashes // on the name to add. // while ( ( *lpName == CHR_SPACE ) || ( *lpName == CHR_BACKSLASH ) ) { lpName = CharNext(lpName); } // Add the new name to existing path. // lstrcpyn(lpTemp, lpName, cbPath); // Trim trailing spaces from result. // while ( ( lpTemp > lpPath ) && ( *(lpTemp = CharPrev(lpPath, lpTemp)) == CHR_SPACE ) ) { *lpTemp = NULLCHR; } return lpPath; } LPTSTR AddPath(LPTSTR lpPath, LPCTSTR lpName) { return AddPathN(lpPath, lpName, 0xFFFFFFFF); } DWORD ExpandFullPath(LPTSTR lpszPath, LPTSTR lpszReturn, DWORD cbReturn) { LPTSTR lpszExpanded = AllocateExpand(lpszPath ? lpszPath : lpszReturn), lpszDontCare; DWORD dwRet; *lpszReturn = NULLCHR; if ( NULL == lpszExpanded ) { return 0; } dwRet = GetFullPathName(lpszExpanded, cbReturn, lpszReturn, &lpszDontCare); FREE(lpszExpanded); return dwRet; } BOOL CopyDirectory(LPCTSTR lpSrc, LPCTSTR lpDst) { return ( CopyDirectoryEngine(NULL, NULL, lpSrc, lpDst, FALSE) != 0 ); } BOOL CopyDirectoryProgress(HWND hwnd, LPCTSTR lpSrc, LPCTSTR lpDst) { return ( CopyDirectoryEngine(hwnd, NULL, lpSrc, lpDst, FALSE) != 0 ); } BOOL CopyDirectoryProgressCancel(HWND hwnd, HANDLE hEvent, LPCTSTR lpSrc, LPCTSTR lpDst) { return ( CopyDirectoryEngine(hwnd, hEvent, lpSrc, lpDst, FALSE) != 0 ); } DWORD FileCount(LPCTSTR lpSrc) { return CopyDirectoryEngine(NULL, NULL, lpSrc, NULL, TRUE); } BOOL BrowseForFolder(HWND hwndParent, INT iString, LPTSTR lpDirBuf, DWORD dwFlags) { BROWSEINFO bi = {0}; TCHAR szBuffer[MAX_PATH], szPath[MAX_PATH], szTitle[256] = NULLSTR; LPITEMIDLIST lpil; // Copy the current directory into the buffer so // we start out from that folder. // lstrcpyn(szPath, lpDirBuf, AS(szPath)); // Load the instructional text for the dialog. // if ( iString ) LoadString(NULL, iString, szTitle, sizeof(szTitle) / sizeof(TCHAR)); // Setup the BrowseInfo struct. // bi.hwndOwner = hwndParent; bi.pidlRoot = NULL; bi.pszDisplayName = szBuffer; bi.lpszTitle = szTitle; bi.ulFlags = dwFlags ? dwFlags : BIF_RETURNONLYFSDIRS; bi.lpfn = (BFFCALLBACK) BrowseCallbackProc; bi.lParam = (LPARAM) szPath; // Return the new path if we got one. // if ( ( (lpil = SHBrowseForFolder(&bi)) != NULL ) && ( SHGetPathFromIDList(lpil, szPath) && szPath[0] && DirectoryExists(szPath) ) ) { lstrcpy(lpDirBuf, szPath); return TRUE; } return FALSE; } BOOL BrowseForFile(HWND hwnd, INT iTitle, INT iFilter, INT iExtension, LPTSTR lpFileName, DWORD cbFileName, LPTSTR lpDirectory, DWORD dwFlags) { OPENFILENAME ofn = {sizeof(ofn)}; TCHAR szTitle[256] = NULLSTR, szFilter[256] = NULLSTR, szExtension[256] = NULLSTR, szFullPath[MAX_PATH] = NULLSTR; LPTSTR lpSearch, lpNext, lpFilePart = NULL; // Load all the strings we need for the open file structure. // if ( iTitle ) LoadString(NULL, iTitle, szTitle, sizeof(szTitle) / sizeof(TCHAR)); if ( iFilter ) LoadString(NULL, iFilter, szFilter, sizeof(szFilter) / sizeof(TCHAR)); if ( iExtension ) LoadString(NULL, iExtension, szExtension, sizeof(szExtension) / sizeof(TCHAR)); // Replace all the | in the filter string with \0. // lpSearch = szFilter; while ( *lpSearch ) { lpNext = CharNext(lpSearch); if ( *lpSearch == _T('|') ) *lpSearch = NULLCHR; lpSearch = lpNext; } // Figure out what the default directory and file will be. // if ( *lpFileName && GetFullPathName(lpFileName, STRSIZE(szFullPath), szFullPath, &lpFilePart) && szFullPath[0] ) { // If the whole path is a directory, there is no file part. // if ( DirectoryExists(szFullPath) ) lpFilePart = NULL; // Copy off the file name part. // if ( lpFilePart && ( (DWORD) lstrlen(lpFilePart) < cbFileName ) ) lstrcpy(lpFileName, lpFilePart); else *lpFileName = NULLCHR; // Now chop off the file name so we are left with the directory. // if ( lpFilePart ) *lpFilePart = NULLCHR; } else { // No cool default directory or file name to use, so we use the // directory passed in and no file name. // *lpFileName = NULLCHR; szFullPath[0] = NULLCHR; } // Setup the open file struture. // ofn.hwndOwner = hwnd; ofn.lpstrFilter = szFilter[0] ? szFilter : NULL; ofn.nFilterIndex = szFilter[0] ? 1 : 0; ofn.lpstrFile = lpFileName; ofn.nMaxFile = cbFileName; ofn.lpstrInitialDir = ( szFullPath[0] && DirectoryExists(szFullPath) ) ? szFullPath : lpDirectory; ofn.lpstrTitle = szTitle[0] ? szTitle : NULL; ofn.lpstrDefExt = szExtension[0] ? szExtension : NULL; ofn.Flags = dwFlags ? dwFlags : (OFN_HIDEREADONLY | OFN_FILEMUSTEXIST); // Make sure the buffer is zero'ed out if the function failes. // if ( !GetOpenFileName(&ofn) ) *lpFileName = NULLCHR; // Return true only if we are passing back a file name. // return ( *lpFileName != NULLCHR ); } // // Internal Functions: // static DWORD CopyDirectoryEngine(HWND hwnd, HANDLE hEvent, LPCTSTR lpSrc, LPCTSTR lpDst, BOOL fCount) { WIN32_FIND_DATA FileFound; HANDLE hFile; BOOL bReturn = TRUE; DWORD dwReturn = 0; TCHAR szDst[MAX_PATH]; LPTSTR lpFileName, lpSearch = NULL; // If a source directory was passed in, set the current directory // to it because that is we we are going to search for files. // if ( lpSrc ) { // If the source isn't a directory, it is a file or file pattern we are // copying. // if ( DirectoryExists(lpSrc) ) { // Now make sure we set the current directory to the source directory. // bReturn = SetCurrentDirectory(lpSrc); } else { // We have to separate the path from the file or file pattern. // if ( lpSearch = _tcsrchr(lpSrc, CHR_BACKSLASH) ) { // Set the current directory to the path part of the source buffer. // TCHAR szPath[MAX_PATH]; lstrcpyn(szPath, lpSrc, 1 + (int)(lpSearch - lpSrc)); if ( *(lpSearch = CharNext(lpSearch)) == NULLCHR ) lpSearch = NULL; bReturn = SetCurrentDirectory(szPath); } else lpSearch = (LPTSTR) lpSrc; } } // Make sure the source directory existed, create the // destination directory, and make sure it exists also. // if ( bReturn && ( fCount || ( bReturn = CreatePath(lpDst) ) ) ) { // Setup the destination buffer with a pointer to the // end of the path. // if ( !fCount ) { lstrcpy(szDst, lpDst); AddPath(szDst, NULLSTR); lpFileName = szDst + lstrlen(szDst); } // Process all the files and directories in the directory passed in. // if ( (hFile = FindFirstFile(lpSearch ? lpSearch : _T("*"), &FileFound)) != INVALID_HANDLE_VALUE ) { do { // Create the full path destination name. // if ( !fCount ) lstrcpy(lpFileName, FileFound.cFileName); // First check to see if this is a file (not a directory). // if ( !( FileFound.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) ) { // Copy the file from the source to the destination. // fCount ? (dwReturn++) : (bReturn = CopyResetFile(FileFound.cFileName, szDst)); // Increase the progress bar. This is the only difference between // CopyDirectroy() and CopyDirectoryProgress(). // if ( hwnd ) SendMessage(hwnd, PBM_STEPIT, 0, 0); } // Otherwise, make sure the directory is not "." or "..". // else if ( lstrcmp(FileFound.cFileName, _T(".")) && lstrcmp(FileFound.cFileName, _T("..")) && SetCurrentDirectory(FileFound.cFileName) ) { // Process all the files there. // DWORD dwBuffer = CopyDirectoryEngine(hwnd, hEvent, NULL, szDst, fCount); fCount ? (dwReturn += dwBuffer) : (bReturn = (dwBuffer != 0)); SetCurrentDirectory(_T("..")); } // Check event to see if the user canceled. // if ( hEvent && ( WaitForSingleObject(hEvent, 0) != WAIT_TIMEOUT ) ) bReturn = FALSE; } while ( bReturn && FindNextFile(hFile, &FileFound) ); FindClose(hFile); } } return bReturn ? (fCount ? dwReturn : 1) : 0; } static CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData) { TCHAR szPathName[MAX_PATH]; LPTSTR lpszData = (LPTSTR) lpData; switch ( uMsg ) { case BFFM_INITIALIZED: // Initialize the dialog with the OK button and current directory. // if ( lpszData && *lpszData ) { LPTSTR lpEnd; // Make sure there is a trailing backslash so that a drive passed in // works (like c:). // szPathName[0] = NULLCHR; if ( GetFullPathName(lpszData, STRSIZE(szPathName), szPathName, NULL) && szPathName[0] ) lstrcpy(lpszData, szPathName); // For some dumb reason, the BFFM_SETSELECTION doesn't like it when there // is a trailing backslash on the path. // if ( ( lstrlen(lpszData) > 3 ) && ( lpEnd = CharPrev(lpszData, lpszData + lstrlen(lpszData)) ) && ( *lpEnd == CHR_BACKSLASH ) ) { *lpEnd = NULLCHR; } // Update the tree with the default dir and enable/disable the OK button // if there is a valid directory. // SendMessage(hwnd, BFFM_SETSELECTION, TRUE, lpData); SendMessage(hwnd, BFFM_ENABLEOK, 0, (DirectoryExists(lpszData) != 0)); } else SendMessage(hwnd, BFFM_ENABLEOK, 0, 0); break; case BFFM_SELCHANGED: // Turn the id into a folder name. // szPathName[0] = NULLCHR; if ( SHGetPathFromIDList((LPITEMIDLIST) lParam, szPathName) && szPathName[0] && DirectoryExists(szPathName) ) { SetDlgItemText(hwnd, IDC_BROWSE_EDIT, szPathName); SendMessage(hwnd, BFFM_ENABLEOK, 0, 1); } else SendMessage(hwnd, BFFM_ENABLEOK, 0, 0); break; case BFFM_VALIDATEFAILED: SendMessage(hwnd, BFFM_ENABLEOK, 0, 0); return TRUE; } return 0; } BOOL CreateUnicodeFile(LPCTSTR lpFile) { HANDLE hFile; DWORD dwWritten = 0; WCHAR cHeader = 0xFEFF; BOOL bReturn = FALSE; // If we have a file name and the file does not exist, attempt to create // if ( lpFile && *lpFile && !FileExists(lpFile)) { if ( (hFile = CreateFile(lpFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE) { WriteFile(hFile, &cHeader, sizeof(cHeader), &dwWritten, NULL); CloseHandle(hFile); bReturn = TRUE; } } return bReturn; }