Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

675 lines
20 KiB

  1. /****************************************************************************\
  2. DISKAPI.C / OPK Wizard (OPKWIZ.EXE)
  3. Microsoft Confidential
  4. Copyright (c) Microsoft Corporation 1999
  5. All rights reserved
  6. Disk API source file for custom disk APIs used in the OPK Wizard.
  7. 4/99 - Jason Cohen (JCOHEN)
  8. Added this new source file for the OPK Wizard as part of the
  9. Millennium rewrite.
  10. \****************************************************************************/
  11. //
  12. // Include file(s)
  13. //
  14. #include <pch.h>
  15. #include <commdlg.h>
  16. #include <tchar.h>
  17. #include <shlobj.h>
  18. //
  19. // Internal Define(s):
  20. //
  21. #define IDC_BROWSE_EDIT 0x3744 // Common dialogs edit box in the SHBrowseForFolder function.
  22. //
  23. // Internal Function Prototype(s):
  24. //
  25. static DWORD CopyDirectoryEngine(HWND hwnd, HANDLE hEvent, LPCTSTR lpSrc, LPCTSTR lpDst, BOOL fCount);
  26. static CALLBACK BrowseCallbackProc(HWND, UINT, LPARAM, LPARAM);
  27. //
  28. // External Function(s):
  29. //
  30. BOOL DirectoryExists(LPCTSTR lpDirectory)
  31. {
  32. DWORD dwAttr;
  33. return ( ( lpDirectory != NULL ) &&
  34. ( *lpDirectory != NULLCHR ) &&
  35. ( (dwAttr = GetFileAttributes(lpDirectory)) != 0xFFFFFFFF ) &&
  36. ( dwAttr & FILE_ATTRIBUTE_DIRECTORY ) );
  37. }
  38. BOOL FileExists(LPCTSTR lpFile)
  39. {
  40. DWORD dwAttr;
  41. return ( ( lpFile != NULL ) &&
  42. ( *lpFile != NULLCHR ) &&
  43. ( (dwAttr = GetFileAttributes(lpFile)) != 0xFFFFFFFF ) &&
  44. ( !(dwAttr & FILE_ATTRIBUTE_DIRECTORY) ) );
  45. }
  46. BOOL CopyResetFile(LPCTSTR lpSource, LPCTSTR lpTarget)
  47. {
  48. if ( !CopyFile(lpSource, lpTarget, FALSE) )
  49. return FALSE;
  50. SetFileAttributes(lpTarget, FILE_ATTRIBUTE_NORMAL);
  51. return TRUE;
  52. }
  53. DWORD IfGetLongPathName(LPCTSTR lpszShortPath, LPTSTR lpszLongPath, DWORD cchBuffer)
  54. {
  55. //
  56. // See also \nt\base\win32\client\vdm.c.
  57. //
  58. DWORD dwReturn = 0;
  59. #if defined(_WIN64) // _WIN64 postdates the introduction of GetLongPathName.
  60. typedef (WINAPI* PFNGetLongPathNameA)( PCSTR lpszShortPath, PSTR lpszLongPath, DWORD cchBuffer);
  61. typedef (WINAPI* PFNGetLongPathNameW)(PCWSTR lpszShortPath, PWSTR lpszLongPath, DWORD cchBuffer);
  62. #ifdef UNICODE
  63. typedef PFNGetLongPathNameW PFNGetLongPathName;
  64. const static char ProcName[] = "GetLongPathNameW";
  65. #else
  66. typedef PFNGetLongPathNameA PFNGetLongPathName;
  67. const static char ProcName[] = "GetLongPathNameA";
  68. #endif
  69. static PFNGetLongPathName hGetLongPathName = NULL;
  70. static BOOL fInited = FALSE;
  71. if (!fInited)
  72. {
  73. //
  74. // GetModuleHandle is in kernel32, so as long as this lib code
  75. // is around, the handle to kernel32 is constant and the result of
  76. // GetProcAccess is valid.
  77. //
  78. // The old code that called LoadLibrary/FreeLibrary would lose the
  79. // value of GetLastError by calling FreeLibrary.
  80. //
  81. HMODULE hKernel32;
  82. if (hKernel32 = GetModuleHandle(TEXT("Kernel32.dll")))
  83. hGetLongPathName = (PFNGetLongPathName)(GetProcAddress(hKernel32, ProcName));
  84. fInited = TRUE;
  85. }
  86. if (hGetLongPathName)
  87. {
  88. dwReturn = hGetLongPathName(lpszShortPath, lpszLongPath, cchBuffer);
  89. }
  90. #else
  91. dwReturn = GetLongPathName(lpszShortPath, lpszLongPath, cchBuffer);
  92. #endif
  93. return dwReturn;
  94. }
  95. BOOL CreatePath(LPCTSTR lpPath)
  96. {
  97. LPTSTR lpFind = (LPTSTR) lpPath;
  98. while ( lpFind = _tcschr(lpFind + 1, CHR_BACKSLASH) )
  99. {
  100. if ( !((lpFind - lpPath <= 2) && (*(lpFind - 1) == _T(':'))) )
  101. {
  102. *lpFind = NULLCHR;
  103. if ( !DirectoryExists(lpPath) )
  104. CreateDirectory(lpPath, NULL);
  105. *lpFind = CHR_BACKSLASH;
  106. }
  107. }
  108. if ( !DirectoryExists(lpPath) )
  109. CreateDirectory(lpPath, NULL);
  110. return DirectoryExists(lpPath);
  111. }
  112. BOOL DeletePath(LPCTSTR lpDirectory)
  113. {
  114. WIN32_FIND_DATA FileFound;
  115. HANDLE hFile;
  116. // Validate the parameters.
  117. //
  118. if ( ( lpDirectory == NULL ) ||
  119. ( *lpDirectory == NULLCHR ) ||
  120. ( !SetCurrentDirectory(lpDirectory) ) )
  121. {
  122. return TRUE;
  123. }
  124. // Process all the files and directories in the directory passed in.
  125. //
  126. SetCurrentDirectory(lpDirectory);
  127. if ( (hFile = FindFirstFile(_T("*"), &FileFound)) != INVALID_HANDLE_VALUE )
  128. {
  129. do
  130. {
  131. // First check to see if this is a file (not a directory).
  132. //
  133. if ( !( FileFound.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) )
  134. {
  135. // Make sure we clear the readonly flag
  136. //
  137. SetFileAttributes(FileFound.cFileName, FILE_ATTRIBUTE_NORMAL);
  138. DeleteFile(FileFound.cFileName);
  139. }
  140. // Otherwise, make sure the directory is not "." or "..".
  141. //
  142. else if ( ( lstrcmp(FileFound.cFileName, _T(".")) ) &&
  143. ( lstrcmp(FileFound.cFileName, _T("..")) ) )
  144. {
  145. DeletePath(FileFound.cFileName);
  146. }
  147. }
  148. while ( FindNextFile(hFile, &FileFound) );
  149. FindClose(hFile);
  150. }
  151. // Go to the parent directory and remove the current one.
  152. // We have to make sure and reset the readonly attributes
  153. // on the dir also.
  154. //
  155. SetCurrentDirectory(_T(".."));
  156. SetFileAttributes(lpDirectory, FILE_ATTRIBUTE_NORMAL);
  157. return RemoveDirectory(lpDirectory);
  158. }
  159. BOOL DeleteFilesEx(LPCTSTR lpDirectory, LPCTSTR lpFileSpec)
  160. {
  161. WIN32_FIND_DATA FileFound;
  162. HANDLE hFile;
  163. TCHAR szCurDir[MAX_PATH];
  164. // Validate the parameters.
  165. //
  166. if ( ( lpDirectory == NULL ) ||
  167. ( *lpDirectory == NULLCHR ) ||
  168. ( !SetCurrentDirectory(lpDirectory) ) )
  169. {
  170. return FALSE;
  171. }
  172. // Get our current directory so we can set ourself back
  173. //
  174. GetCurrentDirectory(MAX_PATH, szCurDir);
  175. // Process all the files and directories in the directory passed in.
  176. //
  177. SetCurrentDirectory(lpDirectory);
  178. if ( (hFile = FindFirstFile(lpFileSpec, &FileFound)) != INVALID_HANDLE_VALUE )
  179. {
  180. do
  181. {
  182. // First check to see if this is a file (not a directory).
  183. //
  184. if ( !( FileFound.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) )
  185. {
  186. DeleteFile(FileFound.cFileName);
  187. }
  188. }
  189. while ( FindNextFile(hFile, &FileFound) );
  190. FindClose(hFile);
  191. }
  192. SetCurrentDirectory(szCurDir);
  193. return TRUE;
  194. }
  195. LPTSTR AddPathN(LPTSTR lpPath, LPCTSTR lpName, DWORD cbPath)
  196. {
  197. LPTSTR lpTemp = lpPath;
  198. // Validate the parameters passed in.
  199. //
  200. if ( ( lpPath == NULL ) ||
  201. ( lpName == NULL ) )
  202. {
  203. return NULL;
  204. }
  205. // Find the end of the path.
  206. //
  207. while ( *lpTemp )
  208. {
  209. lpTemp = CharNext(lpTemp);
  210. if ( cbPath )
  211. {
  212. cbPath--;
  213. }
  214. }
  215. // If no trailing backslash on the path then add one.
  216. //
  217. if ( ( lpTemp > lpPath ) &&
  218. ( *CharPrev(lpPath, lpTemp) != CHR_BACKSLASH ) )
  219. {
  220. // Make sure there is room in the path buffer to
  221. // add the backslash and the null terminator.
  222. //
  223. if ( cbPath < 2 )
  224. {
  225. return NULL;
  226. }
  227. *lpTemp = CHR_BACKSLASH;
  228. lpTemp = CharNext(lpTemp);
  229. cbPath--;
  230. }
  231. else
  232. {
  233. // Make sure there is at least room for the null
  234. // terminator.
  235. //
  236. if ( cbPath < 1 )
  237. {
  238. return NULL;
  239. }
  240. }
  241. // Make sure there is no preceeding spaces or backslashes
  242. // on the name to add.
  243. //
  244. while ( ( *lpName == CHR_SPACE ) ||
  245. ( *lpName == CHR_BACKSLASH ) )
  246. {
  247. lpName = CharNext(lpName);
  248. }
  249. // Add the new name to existing path.
  250. //
  251. lstrcpyn(lpTemp, lpName, cbPath);
  252. // Trim trailing spaces from result.
  253. //
  254. while ( ( lpTemp > lpPath ) &&
  255. ( *(lpTemp = CharPrev(lpPath, lpTemp)) == CHR_SPACE ) )
  256. {
  257. *lpTemp = NULLCHR;
  258. }
  259. return lpPath;
  260. }
  261. LPTSTR AddPath(LPTSTR lpPath, LPCTSTR lpName)
  262. {
  263. return AddPathN(lpPath, lpName, 0xFFFFFFFF);
  264. }
  265. DWORD ExpandFullPath(LPTSTR lpszPath, LPTSTR lpszReturn, DWORD cbReturn)
  266. {
  267. LPTSTR lpszExpanded = AllocateExpand(lpszPath ? lpszPath : lpszReturn),
  268. lpszDontCare;
  269. DWORD dwRet;
  270. *lpszReturn = NULLCHR;
  271. if ( NULL == lpszExpanded )
  272. {
  273. return 0;
  274. }
  275. dwRet = GetFullPathName(lpszExpanded, cbReturn, lpszReturn, &lpszDontCare);
  276. FREE(lpszExpanded);
  277. return dwRet;
  278. }
  279. BOOL CopyDirectory(LPCTSTR lpSrc, LPCTSTR lpDst)
  280. {
  281. return ( CopyDirectoryEngine(NULL, NULL, lpSrc, lpDst, FALSE) != 0 );
  282. }
  283. BOOL CopyDirectoryProgress(HWND hwnd, LPCTSTR lpSrc, LPCTSTR lpDst)
  284. {
  285. return ( CopyDirectoryEngine(hwnd, NULL, lpSrc, lpDst, FALSE) != 0 );
  286. }
  287. BOOL CopyDirectoryProgressCancel(HWND hwnd, HANDLE hEvent, LPCTSTR lpSrc, LPCTSTR lpDst)
  288. {
  289. return ( CopyDirectoryEngine(hwnd, hEvent, lpSrc, lpDst, FALSE) != 0 );
  290. }
  291. DWORD FileCount(LPCTSTR lpSrc)
  292. {
  293. return CopyDirectoryEngine(NULL, NULL, lpSrc, NULL, TRUE);
  294. }
  295. BOOL BrowseForFolder(HWND hwndParent, INT iString, LPTSTR lpDirBuf, DWORD dwFlags)
  296. {
  297. BROWSEINFO bi = {0};
  298. TCHAR szBuffer[MAX_PATH],
  299. szPath[MAX_PATH],
  300. szTitle[256] = NULLSTR;
  301. LPITEMIDLIST lpil;
  302. // Copy the current directory into the buffer so
  303. // we start out from that folder.
  304. //
  305. lstrcpyn(szPath, lpDirBuf, AS(szPath));
  306. // Load the instructional text for the dialog.
  307. //
  308. if ( iString )
  309. LoadString(NULL, iString, szTitle, sizeof(szTitle) / sizeof(TCHAR));
  310. // Setup the BrowseInfo struct.
  311. //
  312. bi.hwndOwner = hwndParent;
  313. bi.pidlRoot = NULL;
  314. bi.pszDisplayName = szBuffer;
  315. bi.lpszTitle = szTitle;
  316. bi.ulFlags = dwFlags ? dwFlags : BIF_RETURNONLYFSDIRS;
  317. bi.lpfn = (BFFCALLBACK) BrowseCallbackProc;
  318. bi.lParam = (LPARAM) szPath;
  319. // Return the new path if we got one.
  320. //
  321. if ( ( (lpil = SHBrowseForFolder(&bi)) != NULL ) &&
  322. ( SHGetPathFromIDList(lpil, szPath) && szPath[0] && DirectoryExists(szPath) ) )
  323. {
  324. lstrcpy(lpDirBuf, szPath);
  325. return TRUE;
  326. }
  327. return FALSE;
  328. }
  329. BOOL BrowseForFile(HWND hwnd, INT iTitle, INT iFilter, INT iExtension, LPTSTR lpFileName, DWORD cbFileName, LPTSTR lpDirectory, DWORD dwFlags)
  330. {
  331. OPENFILENAME ofn = {sizeof(ofn)};
  332. TCHAR szTitle[256] = NULLSTR,
  333. szFilter[256] = NULLSTR,
  334. szExtension[256] = NULLSTR,
  335. szFullPath[MAX_PATH] = NULLSTR;
  336. LPTSTR lpSearch,
  337. lpNext,
  338. lpFilePart = NULL;
  339. // Load all the strings we need for the open file structure.
  340. //
  341. if ( iTitle )
  342. LoadString(NULL, iTitle, szTitle, sizeof(szTitle) / sizeof(TCHAR));
  343. if ( iFilter )
  344. LoadString(NULL, iFilter, szFilter, sizeof(szFilter) / sizeof(TCHAR));
  345. if ( iExtension )
  346. LoadString(NULL, iExtension, szExtension, sizeof(szExtension) / sizeof(TCHAR));
  347. // Replace all the | in the filter string with \0.
  348. //
  349. lpSearch = szFilter;
  350. while ( *lpSearch )
  351. {
  352. lpNext = CharNext(lpSearch);
  353. if ( *lpSearch == _T('|') )
  354. *lpSearch = NULLCHR;
  355. lpSearch = lpNext;
  356. }
  357. // Figure out what the default directory and file will be.
  358. //
  359. if ( *lpFileName && GetFullPathName(lpFileName, STRSIZE(szFullPath), szFullPath, &lpFilePart) && szFullPath[0] )
  360. {
  361. // If the whole path is a directory, there is no file part.
  362. //
  363. if ( DirectoryExists(szFullPath) )
  364. lpFilePart = NULL;
  365. // Copy off the file name part.
  366. //
  367. if ( lpFilePart && ( (DWORD) lstrlen(lpFilePart) < cbFileName ) )
  368. lstrcpy(lpFileName, lpFilePart);
  369. else
  370. *lpFileName = NULLCHR;
  371. // Now chop off the file name so we are left with the directory.
  372. //
  373. if ( lpFilePart )
  374. *lpFilePart = NULLCHR;
  375. }
  376. else
  377. {
  378. // No cool default directory or file name to use, so we use the
  379. // directory passed in and no file name.
  380. //
  381. *lpFileName = NULLCHR;
  382. szFullPath[0] = NULLCHR;
  383. }
  384. // Setup the open file struture.
  385. //
  386. ofn.hwndOwner = hwnd;
  387. ofn.lpstrFilter = szFilter[0] ? szFilter : NULL;
  388. ofn.nFilterIndex = szFilter[0] ? 1 : 0;
  389. ofn.lpstrFile = lpFileName;
  390. ofn.nMaxFile = cbFileName;
  391. ofn.lpstrInitialDir = ( szFullPath[0] && DirectoryExists(szFullPath) ) ? szFullPath : lpDirectory;
  392. ofn.lpstrTitle = szTitle[0] ? szTitle : NULL;
  393. ofn.lpstrDefExt = szExtension[0] ? szExtension : NULL;
  394. ofn.Flags = dwFlags ? dwFlags : (OFN_HIDEREADONLY | OFN_FILEMUSTEXIST);
  395. // Make sure the buffer is zero'ed out if the function failes.
  396. //
  397. if ( !GetOpenFileName(&ofn) )
  398. *lpFileName = NULLCHR;
  399. // Return true only if we are passing back a file name.
  400. //
  401. return ( *lpFileName != NULLCHR );
  402. }
  403. //
  404. // Internal Functions:
  405. //
  406. static DWORD CopyDirectoryEngine(HWND hwnd, HANDLE hEvent, LPCTSTR lpSrc, LPCTSTR lpDst, BOOL fCount)
  407. {
  408. WIN32_FIND_DATA FileFound;
  409. HANDLE hFile;
  410. BOOL bReturn = TRUE;
  411. DWORD dwReturn = 0;
  412. TCHAR szDst[MAX_PATH];
  413. LPTSTR lpFileName,
  414. lpSearch = NULL;
  415. // If a source directory was passed in, set the current directory
  416. // to it because that is we we are going to search for files.
  417. //
  418. if ( lpSrc )
  419. {
  420. // If the source isn't a directory, it is a file or file pattern we are
  421. // copying.
  422. //
  423. if ( DirectoryExists(lpSrc) )
  424. {
  425. // Now make sure we set the current directory to the source directory.
  426. //
  427. bReturn = SetCurrentDirectory(lpSrc);
  428. }
  429. else
  430. {
  431. // We have to separate the path from the file or file pattern.
  432. //
  433. if ( lpSearch = _tcsrchr(lpSrc, CHR_BACKSLASH) )
  434. {
  435. // Set the current directory to the path part of the source buffer.
  436. //
  437. TCHAR szPath[MAX_PATH];
  438. lstrcpyn(szPath, lpSrc, 1 + (int)(lpSearch - lpSrc));
  439. if ( *(lpSearch = CharNext(lpSearch)) == NULLCHR )
  440. lpSearch = NULL;
  441. bReturn = SetCurrentDirectory(szPath);
  442. }
  443. else
  444. lpSearch = (LPTSTR) lpSrc;
  445. }
  446. }
  447. // Make sure the source directory existed, create the
  448. // destination directory, and make sure it exists also.
  449. //
  450. if ( bReturn && ( fCount || ( bReturn = CreatePath(lpDst) ) ) )
  451. {
  452. // Setup the destination buffer with a pointer to the
  453. // end of the path.
  454. //
  455. if ( !fCount )
  456. {
  457. lstrcpy(szDst, lpDst);
  458. AddPath(szDst, NULLSTR);
  459. lpFileName = szDst + lstrlen(szDst);
  460. }
  461. // Process all the files and directories in the directory passed in.
  462. //
  463. if ( (hFile = FindFirstFile(lpSearch ? lpSearch : _T("*"), &FileFound)) != INVALID_HANDLE_VALUE )
  464. {
  465. do
  466. {
  467. // Create the full path destination name.
  468. //
  469. if ( !fCount )
  470. lstrcpy(lpFileName, FileFound.cFileName);
  471. // First check to see if this is a file (not a directory).
  472. //
  473. if ( !( FileFound.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) )
  474. {
  475. // Copy the file from the source to the destination.
  476. //
  477. fCount ? (dwReturn++) : (bReturn = CopyResetFile(FileFound.cFileName, szDst));
  478. // Increase the progress bar. This is the only difference between
  479. // CopyDirectroy() and CopyDirectoryProgress().
  480. //
  481. if ( hwnd )
  482. SendMessage(hwnd, PBM_STEPIT, 0, 0);
  483. }
  484. // Otherwise, make sure the directory is not "." or "..".
  485. //
  486. else if ( lstrcmp(FileFound.cFileName, _T(".")) &&
  487. lstrcmp(FileFound.cFileName, _T("..")) &&
  488. SetCurrentDirectory(FileFound.cFileName) )
  489. {
  490. // Process all the files there.
  491. //
  492. DWORD dwBuffer = CopyDirectoryEngine(hwnd, hEvent, NULL, szDst, fCount);
  493. fCount ? (dwReturn += dwBuffer) : (bReturn = (dwBuffer != 0));
  494. SetCurrentDirectory(_T(".."));
  495. }
  496. // Check event to see if the user canceled.
  497. //
  498. if ( hEvent && ( WaitForSingleObject(hEvent, 0) != WAIT_TIMEOUT ) )
  499. bReturn = FALSE;
  500. }
  501. while ( bReturn && FindNextFile(hFile, &FileFound) );
  502. FindClose(hFile);
  503. }
  504. }
  505. return bReturn ? (fCount ? dwReturn : 1) : 0;
  506. }
  507. static CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
  508. {
  509. TCHAR szPathName[MAX_PATH];
  510. LPTSTR lpszData = (LPTSTR) lpData;
  511. switch ( uMsg )
  512. {
  513. case BFFM_INITIALIZED:
  514. // Initialize the dialog with the OK button and current directory.
  515. //
  516. if ( lpszData && *lpszData )
  517. {
  518. LPTSTR lpEnd;
  519. // Make sure there is a trailing backslash so that a drive passed in
  520. // works (like c:).
  521. //
  522. szPathName[0] = NULLCHR;
  523. if ( GetFullPathName(lpszData, STRSIZE(szPathName), szPathName, NULL) && szPathName[0] )
  524. lstrcpy(lpszData, szPathName);
  525. // For some dumb reason, the BFFM_SETSELECTION doesn't like it when there
  526. // is a trailing backslash on the path.
  527. //
  528. if ( ( lstrlen(lpszData) > 3 ) &&
  529. ( lpEnd = CharPrev(lpszData, lpszData + lstrlen(lpszData)) ) &&
  530. ( *lpEnd == CHR_BACKSLASH ) )
  531. {
  532. *lpEnd = NULLCHR;
  533. }
  534. // Update the tree with the default dir and enable/disable the OK button
  535. // if there is a valid directory.
  536. //
  537. SendMessage(hwnd, BFFM_SETSELECTION, TRUE, lpData);
  538. SendMessage(hwnd, BFFM_ENABLEOK, 0, (DirectoryExists(lpszData) != 0));
  539. }
  540. else
  541. SendMessage(hwnd, BFFM_ENABLEOK, 0, 0);
  542. break;
  543. case BFFM_SELCHANGED:
  544. // Turn the id into a folder name.
  545. //
  546. szPathName[0] = NULLCHR;
  547. if ( SHGetPathFromIDList((LPITEMIDLIST) lParam, szPathName) && szPathName[0] && DirectoryExists(szPathName) )
  548. {
  549. SetDlgItemText(hwnd, IDC_BROWSE_EDIT, szPathName);
  550. SendMessage(hwnd, BFFM_ENABLEOK, 0, 1);
  551. }
  552. else
  553. SendMessage(hwnd, BFFM_ENABLEOK, 0, 0);
  554. break;
  555. case BFFM_VALIDATEFAILED:
  556. SendMessage(hwnd, BFFM_ENABLEOK, 0, 0);
  557. return TRUE;
  558. }
  559. return 0;
  560. }
  561. BOOL CreateUnicodeFile(LPCTSTR lpFile)
  562. {
  563. HANDLE hFile;
  564. DWORD dwWritten = 0;
  565. WCHAR cHeader = 0xFEFF;
  566. BOOL bReturn = FALSE;
  567. // If we have a file name and the file does not exist, attempt to create
  568. //
  569. if ( lpFile && *lpFile && !FileExists(lpFile))
  570. {
  571. if ( (hFile = CreateFile(lpFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE)
  572. {
  573. WriteFile(hFile, &cHeader, sizeof(cHeader), &dwWritten, NULL);
  574. CloseHandle(hFile);
  575. bReturn = TRUE;
  576. }
  577. }
  578. return bReturn;
  579. }