Leaked source code of windows server 2003
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.

785 lines
22 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Copyright (c) 1997-1999 Microsoft Corporation
  4. // All rights reserved.
  5. //
  6. // File Name:
  7. // save.c
  8. //
  9. // Description:
  10. // This file has the code that dumps the user's answers to the
  11. // answer file.
  12. //
  13. // The entry point SaveAllSettings() is called by the wizard when
  14. // it is time to save the answer file (and possibly the .udf and
  15. // sample batch script).
  16. //
  17. // The global vars GenSettings, NetSettings, etc. are examined
  18. // and we decide what [Section] key=value settings need to be
  19. // written.
  20. //
  21. // If you're adding a page to this wizard, see the function
  22. // QueueSettingsToAnswerFile().
  23. //
  24. //----------------------------------------------------------------------------
  25. #include "pch.h"
  26. #include "allres.h"
  27. #define FILE_DOT_UDB _T(".udb")
  28. //
  29. // local prototypes
  30. //
  31. static BOOL IsOkToOverwriteFiles(HWND hwnd);
  32. static BOOL BuildAltFileNames(HWND hwnd);
  33. static BOOL WriteSampleBatchScript(HWND hwnd);
  34. static VOID QuoteStringIfNecessary( OUT TCHAR *szOutputString,
  35. IN const TCHAR* const szInputString,
  36. IN DWORD cbSize);
  37. //
  38. // Localized "Usage" string
  39. //
  40. static TCHAR *StrUsage = NULL;
  41. //
  42. // External function in savefile.c
  43. //
  44. extern BOOL QueueSettingsToAnswerFile(HWND hwnd);
  45. BOOL SettingQueueHalScsi_Flush(LPTSTR lpFileName,
  46. QUEUENUM dwWhichQueue);
  47. static TCHAR *StrSampleBatchScriptLine1 = NULL;
  48. static TCHAR *StrSampleBatchScriptLine2 = NULL;
  49. static TCHAR *StrBatchScriptSysprepWarning = NULL;
  50. //----------------------------------------------------------------------------
  51. //
  52. // Function: SetCdRomPath
  53. //
  54. // Purpose: To find the CD-ROM on this local machine and set
  55. // WizGlobals.CdSourcePath to it.
  56. //
  57. // Arguments: VOID
  58. //
  59. // Returns: BOOL TRUE - if the CD path was set
  60. // FALSE - if no CD path was found
  61. //
  62. //----------------------------------------------------------------------------
  63. static BOOL
  64. SetCdRomPath( VOID )
  65. {
  66. TCHAR *p;
  67. TCHAR DriveLetters[MAX_PATH];
  68. TCHAR PathBuffer[MAX_PATH];
  69. //
  70. // Find the CD-ROM
  71. //
  72. // GetLogicalDriveStrings() fills in the DriveLetters buffer, and it
  73. // looks like:
  74. //
  75. // c:\(null)d:\(null)x:\(null)(null)
  76. //
  77. // (i.e. double-null at the end)
  78. //
  79. // ISSUE-2002/02/27-stelo,swamip - Replace with existing code that searches drives
  80. //
  81. if ( ! GetLogicalDriveStrings(MAX_PATH, DriveLetters) )
  82. DriveLetters[0] = _T('\0');
  83. p = DriveLetters;
  84. while ( *p ) {
  85. if ( GetDriveType(p) == DRIVE_CDROM ) {
  86. SYSTEM_INFO SystemInfo;
  87. HRESULT hrCat;
  88. lstrcpyn( PathBuffer, p , AS(PathBuffer));
  89. GetSystemInfo( &SystemInfo );
  90. switch( SystemInfo.wProcessorArchitecture )
  91. {
  92. case PROCESSOR_ARCHITECTURE_INTEL:
  93. hrCat=StringCchCat( PathBuffer, AS(PathBuffer), _T("i386") );
  94. break;
  95. case PROCESSOR_ARCHITECTURE_AMD64:
  96. hrCat=StringCchCat( PathBuffer, AS(PathBuffer), _T("amd64") );
  97. break;
  98. default:
  99. hrCat=StringCchCat( PathBuffer, AS(PathBuffer), _T("i386") );
  100. AssertMsg( FALSE,
  101. "Unknown Processor. Can't set setup files path." );
  102. }
  103. break;
  104. }
  105. while ( *p++ );
  106. }
  107. //
  108. // If no CD Found, leave the setup files path blank
  109. //
  110. if( *p == _T('\0') )
  111. {
  112. lstrcpyn( WizGlobals.CdSourcePath, _T(""), AS(WizGlobals.CdSourcePath) );
  113. return( FALSE );
  114. }
  115. else
  116. {
  117. lstrcpyn( WizGlobals.CdSourcePath, PathBuffer, AS(WizGlobals.CdSourcePath) );
  118. return( TRUE );
  119. }
  120. }
  121. //----------------------------------------------------------------------------
  122. //
  123. // Function: DidSetupmgrWriteThisFile
  124. //
  125. // Purpose: To check to see if a specific file was written by Setup Manager
  126. //
  127. // Arguments: IN LPTSTR lpFile - the full path and name of the file to check
  128. //
  129. // Returns: BOOL TRUE - if setup manager wrote the file
  130. // FALSE - if it didn't
  131. //
  132. //----------------------------------------------------------------------------
  133. static BOOL
  134. DidSetupmgrWriteThisFile( IN LPTSTR lpFile )
  135. {
  136. INT iRet;
  137. TCHAR Buffer[MAX_INILINE_LEN];
  138. FILE *fp = My_fopen(lpFile, _T("r") );
  139. if ( fp == NULL )
  140. return( FALSE );
  141. if ( My_fgets(Buffer, MAX_INILINE_LEN - 1, fp) == NULL )
  142. return( FALSE );
  143. My_fclose(fp);
  144. if ( lstrcmp(Buffer, _T(";SetupMgrTag\n")) == 0 ||
  145. lstrcmp(Buffer, _T("@rem SetupMgrTag\n")) == 0 )
  146. {
  147. return( TRUE );
  148. }
  149. else
  150. {
  151. return( FALSE );
  152. }
  153. }
  154. //----------------------------------------------------------------------------
  155. //
  156. // Function: SaveAllSettings
  157. //
  158. // Purpose: This is the entry point for saving the answer file. It is
  159. // called by the SaveScript page.
  160. //
  161. // If multiple computers were specified, it also writes a .udf.
  162. //
  163. // It always writes a batch file that makes it easy to use the
  164. // answer file just created.
  165. //
  166. // Arguments: HWND hwnd
  167. //
  168. // Returns: BOOL
  169. //
  170. //----------------------------------------------------------------------------
  171. BOOL
  172. SaveAllSettings(HWND hwnd)
  173. {
  174. //
  175. // Build the file names for the .udf and sample batch script. The
  176. // results are stored in FixedGlobals.
  177. //
  178. // After calling BuildAltFileNames(), FixedGlobals.UdfFileName and
  179. // FixedGlobals.BatchFileName will be null strings if we're not
  180. // supposed to write those files out
  181. //
  182. if ( ! BuildAltFileNames(hwnd) )
  183. return FALSE;
  184. //
  185. // Before overwriting anything do some checks.
  186. //
  187. if ( ! IsOkToOverwriteFiles(hwnd) )
  188. return FALSE;
  189. //
  190. // Empty any intermediatte stuff we have on the queues because
  191. // user is going back & next alot.
  192. //
  193. // Then initialize the queues with the original settings.
  194. //
  195. SettingQueue_Empty(SETTING_QUEUE_ANSWERS);
  196. SettingQueue_Empty(SETTING_QUEUE_UDF);
  197. SettingQueue_Copy(SETTING_QUEUE_ORIG_ANSWERS,
  198. SETTING_QUEUE_ANSWERS);
  199. SettingQueue_Copy(SETTING_QUEUE_ORIG_UDF,
  200. SETTING_QUEUE_UDF);
  201. //
  202. // Call the function that everybody plugs into in savefile.c to
  203. // queue up all the answers from the UI.
  204. //
  205. if (!QueueSettingsToAnswerFile(hwnd))
  206. return FALSE;
  207. //
  208. // Flush the answer file queue.
  209. //
  210. if ( ! SettingQueue_Flush(FixedGlobals.ScriptName,
  211. SETTING_QUEUE_ANSWERS) ) {
  212. ReportErrorId(hwnd,
  213. MSGTYPE_ERR | MSGTYPE_WIN32,
  214. IDS_ERRORS_WRITING_ANSWER_FILE,
  215. FixedGlobals.ScriptName);
  216. return FALSE;
  217. }
  218. //
  219. // If multiple computernames, flush the .udf queue
  220. //
  221. if ( FixedGlobals.UdfFileName[0] ) {
  222. if ( ! SettingQueue_Flush(FixedGlobals.UdfFileName,
  223. SETTING_QUEUE_UDF) ) {
  224. ReportErrorId(hwnd,
  225. MSGTYPE_ERR | MSGTYPE_WIN32,
  226. IDS_ERRORS_WRITING_UDF,
  227. FixedGlobals.UdfFileName);
  228. return FALSE;
  229. }
  230. }
  231. //
  232. // If they are using SCSI or HAL files, then flush the txtsetup.oem queue
  233. //
  234. // NTRAID#NTBUG9-551746-2002/02/27-stelo,swamip - Unused code, should be removed
  235. //
  236. if ( GetNameListSize( &GenSettings.OemScsiFiles ) > 0 ||
  237. GetNameListSize( &GenSettings.OemHalFiles ) > 0 ) {
  238. TCHAR szTextmodePath[MAX_PATH + 1] = _T("");
  239. // Note-ConcatenatePaths truncates to prevent overflow
  240. ConcatenatePaths( szTextmodePath,
  241. WizGlobals.OemFilesPath,
  242. _T("Textmode\\txtsetup.oem"),
  243. NULL );
  244. if ( ! SettingQueueHalScsi_Flush(szTextmodePath,
  245. SETTING_QUEUE_TXTSETUP_OEM) ) {
  246. ReportErrorId(hwnd,
  247. MSGTYPE_ERR | MSGTYPE_WIN32,
  248. IDS_ERRORS_WRITING_ANSWER_FILE,
  249. szTextmodePath);
  250. return FALSE;
  251. }
  252. }
  253. //
  254. // Write the sample batch script if BuildAltFileNames hasn't already
  255. // determined that we should not (i.e. If a remote boot answer file,
  256. // don't write a sample batch script)
  257. //
  258. if ( FixedGlobals.BatchFileName[0] ) {
  259. if ( ! WriteSampleBatchScript(hwnd) )
  260. return FALSE;
  261. }
  262. return TRUE;
  263. }
  264. //----------------------------------------------------------------------------
  265. //
  266. // Function: IsOkToOverwriteFiles
  267. //
  268. // Purpose: This is called prior to writing the answer file, .udf and sample
  269. // batch script.
  270. //
  271. // Before overwriting any file, we make sure that it was created
  272. // by setupmgr. If not, we prompt the user.
  273. //
  274. // Returns:
  275. // TRUE - to go ahead and overwrite any of the files that might exist
  276. // FALSE - user canceled the overwrite
  277. //
  278. //----------------------------------------------------------------------------
  279. static BOOL
  280. IsOkToOverwriteFiles(HWND hwnd)
  281. {
  282. INT i;
  283. INT iRet;
  284. //
  285. // If we are editing a script just write out the files
  286. //
  287. if( ! WizGlobals.bNewScript )
  288. {
  289. return( TRUE );
  290. }
  291. //
  292. // Check foo.txt foo.udf and foo.bat that we're about to write out.
  293. // If any of them already exists, then check to see if they were
  294. // created by setupmgr. We will prompt the user before overwriting
  295. // something we didn't write before.
  296. //
  297. for ( i=0; i<3; i++ ) {
  298. LPTSTR lpFile = NULL;
  299. //
  300. // The answer file, .udf or the batch script?
  301. //
  302. if ( i == 0 )
  303. lpFile = FixedGlobals.ScriptName;
  304. else if ( i == 1 )
  305. lpFile = FixedGlobals.UdfFileName;
  306. else
  307. lpFile = FixedGlobals.BatchFileName;
  308. //
  309. // If the file already exists, prompt the user if it doesn't
  310. // have our tag.
  311. //
  312. // Look for ;SetupMgrTag in the answer file and .udf
  313. // Look for rem SetupMgrTag in the batch script
  314. //
  315. if ( lpFile[0] && DoesFileExist(lpFile) ) {
  316. if( DidSetupmgrWriteThisFile( lpFile ) )
  317. {
  318. iRet = ReportErrorId(hwnd,
  319. MSGTYPE_YESNO,
  320. IDS_ERR_FILE_ALREADY_EXISTS,
  321. lpFile);
  322. if ( iRet == IDNO )
  323. return( FALSE );
  324. }
  325. else {
  326. iRet = ReportErrorId(hwnd,
  327. MSGTYPE_YESNO,
  328. IDS_ERR_SAVEFILE_NOT_SETUPMGR,
  329. lpFile);
  330. if ( iRet == IDNO )
  331. return( FALSE );
  332. }
  333. }
  334. }
  335. return( TRUE );
  336. }
  337. //----------------------------------------------------------------------------
  338. //
  339. // Function: BuildAltFileNames
  340. //
  341. // Purpose: This function derives the name for the .udf and the .bat
  342. // associatted with a given answer filename.
  343. //
  344. // Note: This function has a couple of side-effects. If there is no
  345. // extension on FixedGlobals.ScriptName, it adds one.
  346. //
  347. // Also, after this function runs, FixedGlobals.UdfFileName will
  348. // be a null string if there <= 1 computer names (i.e. no udf)
  349. //
  350. // If we're writing a .sif (remote boot), FixGlobals.BatchFileName
  351. // will be a null-string.
  352. //
  353. // The finish page relies on this.
  354. //
  355. // Returns: BOOL
  356. //
  357. //----------------------------------------------------------------------------
  358. static BOOL
  359. BuildAltFileNames(HWND hwnd)
  360. {
  361. TCHAR PathBuffer[MAX_PATH],
  362. *lpFilePart = NULL,
  363. *pExtension;
  364. INT nEntries = GetNameListSize(&GenSettings.ComputerNames);
  365. BOOL bMultipleComputers = ( nEntries > 1 );
  366. HRESULT hrCat;
  367. //
  368. // Find out the filename part of the answer file pathname and copy
  369. // it to PathBuffer[]
  370. //
  371. GetFullPathName(FixedGlobals.ScriptName,
  372. MAX_PATH,
  373. PathBuffer,
  374. &lpFilePart);
  375. if (lpFilePart == NULL)
  376. return FALSE;
  377. //
  378. // Point at the extension in the PathBuffer[].
  379. //
  380. // e.g. foo.txt, point at the dot.
  381. // foo, point at the null byte.
  382. //
  383. // If there is no extension, put one on it
  384. //
  385. if ( (pExtension = wcsrchr(lpFilePart, _T('.'))) == NULL ) {
  386. pExtension = &lpFilePart[lstrlen(lpFilePart)];
  387. if ( WizGlobals.iProductInstall == PRODUCT_REMOTEINSTALL )
  388. hrCat=StringCchCat(FixedGlobals.ScriptName, AS(FixedGlobals.ScriptName), _T(".sif"));
  389. else
  390. hrCat=StringCchCat(FixedGlobals.ScriptName, AS(FixedGlobals.ScriptName), _T(".txt"));
  391. }
  392. //
  393. // Cannot allow foo.bat or foo.udf as answer file names because we
  394. // will probably be writing other stuff to foo.bat and/or foo.udf
  395. //
  396. if ( (LSTRCMPI(pExtension, _T(".bat")) == 0) ||
  397. (LSTRCMPI(pExtension, FILE_DOT_UDB) == 0) )
  398. {
  399. ReportErrorId(hwnd,
  400. MSGTYPE_ERR,
  401. IDS_ERR_BAD_SCRIPT_EXTENSION);
  402. return FALSE;
  403. }
  404. //
  405. // Build the .udf name if there was > 1 computer names specified
  406. //
  407. if ( bMultipleComputers ) {
  408. lstrcpyn(pExtension, FILE_DOT_UDB, MAX_PATH- (int)(pExtension - PathBuffer) );
  409. lstrcpyn(FixedGlobals.UdfFileName, PathBuffer,AS(FixedGlobals.UdfFileName));
  410. } else {
  411. FixedGlobals.UdfFileName[0] = _T('\0');
  412. }
  413. //
  414. // Build the .bat file name. We won't be creating a sample batch
  415. // script in the case of remote boot, so null it out, else the Finish
  416. // page will be broken.
  417. //
  418. if ( (WizGlobals.iProductInstall == PRODUCT_REMOTEINSTALL) ||
  419. (WizGlobals.iProductInstall == PRODUCT_SYSPREP) ) {
  420. FixedGlobals.BatchFileName[0] = _T('\0');
  421. } else {
  422. lstrcpyn(pExtension, _T(".bat"), MAX_PATH - (int)(pExtension - PathBuffer) );
  423. lstrcpyn(FixedGlobals.BatchFileName, PathBuffer,AS(FixedGlobals.BatchFileName));
  424. }
  425. return TRUE;
  426. }
  427. //----------------------------------------------------------------------------
  428. //
  429. // Function: AddLanguageSwitch
  430. //
  431. // Purpose: Add the /copysource language switch to copy over the right
  432. // language files
  433. //
  434. // Returns: VOID
  435. //
  436. //----------------------------------------------------------------------------
  437. static VOID
  438. AddLanguageSwitch( TCHAR *Buffer, DWORD cbSize )
  439. {
  440. INT iNumLanguages;
  441. HRESULT hrCat;
  442. iNumLanguages = GetNameListSize( &GenSettings.LanguageFilePaths );
  443. if ( iNumLanguages > 0 )
  444. {
  445. hrCat=StringCchCat( Buffer, cbSize, _T(" /copysource:lang") );
  446. }
  447. hrCat=StringCchCat( Buffer, cbSize, _T("\n") ); // make sure it has a line-feed at the end
  448. }
  449. //----------------------------------------------------------------------------
  450. //
  451. // Function: WriteSampleBatchScript
  452. //
  453. // Purpose: writes the sample batch script
  454. //
  455. // Returns: FALSE if errors writing the file. Any errors are reported
  456. // to the user.
  457. //
  458. //----------------------------------------------------------------------------
  459. static BOOL
  460. WriteSampleBatchScript(HWND hwnd)
  461. {
  462. FILE *fp;
  463. TCHAR Buffer[MAX_INILINE_LEN];
  464. TCHAR *pszScriptName = NULL;
  465. TCHAR szComputerName[MAX_PATH];
  466. TCHAR SetupFilesBuffer[MAX_INILINE_LEN];
  467. TCHAR AnswerFileBuffer[MAX_INILINE_LEN];
  468. TCHAR SetupFilesQuotedBuffer[MAX_INILINE_LEN];
  469. TCHAR Winnt32Buffer[MAX_INILINE_LEN];
  470. DWORD dwSize;
  471. INT nEntries = GetNameListSize(&GenSettings.ComputerNames);
  472. BOOL bMultipleComputers = ( nEntries > 1 );
  473. HRESULT hrPrintf;
  474. if ( (fp = My_fopen(FixedGlobals.BatchFileName, _T("w")) ) == NULL ) {
  475. ReportErrorId(hwnd,
  476. MSGTYPE_ERR | MSGTYPE_WIN32,
  477. IDS_ERR_OPEN_SAMPLE_BAT,
  478. FixedGlobals.BatchFileName);
  479. return FALSE;
  480. }
  481. My_fputs(_T("@rem SetupMgrTag\n@echo off\n\n"), fp);
  482. if( StrSampleBatchScriptLine1 == NULL )
  483. {
  484. StrSampleBatchScriptLine1 = MyLoadString( IDS_BATCH_SCRIPT_LINE1 );
  485. StrSampleBatchScriptLine2 = MyLoadString( IDS_BATCH_SCRIPT_LINE2 );
  486. }
  487. My_fputs( _T("rem\nrem "), fp );
  488. My_fputs( StrSampleBatchScriptLine1, fp );
  489. My_fputs( _T("\nrem "), fp );
  490. My_fputs( StrSampleBatchScriptLine2, fp );
  491. My_fputs( _T("\nrem\n\n"), fp );
  492. if ( !(pszScriptName = MyGetFullPath( FixedGlobals.ScriptName )) )
  493. {
  494. My_fclose( fp );
  495. return FALSE;
  496. }
  497. //
  498. // Quote the Script name if it contains spaces
  499. //
  500. QuoteStringIfNecessary( AnswerFileBuffer, pszScriptName, AS(AnswerFileBuffer) );
  501. // Note: MAX_INILINE_LEN=1K AnswerFileBuffer at this time is MAX_PATH+2 MAX
  502. // buffer overrun should not be a problem.
  503. hrPrintf=StringCchPrintf( Buffer, AS(Buffer), _T("set AnswerFile=.\\%s\n"), AnswerFileBuffer );
  504. My_fputs( Buffer, fp );
  505. if( bMultipleComputers )
  506. {
  507. TCHAR UdfFileBuffer[1024];
  508. pszScriptName = MyGetFullPath( FixedGlobals.UdfFileName );
  509. //
  510. // Quote the UDF name if it contains spaces
  511. //
  512. QuoteStringIfNecessary( UdfFileBuffer, pszScriptName, AS(UdfFileBuffer) );
  513. hrPrintf=StringCchPrintf( Buffer, AS(Buffer),
  514. _T("set UdfFile=.\\%s\nset ComputerName=%%1\n"),
  515. UdfFileBuffer );
  516. My_fputs( Buffer, fp );
  517. }
  518. if( WizGlobals.bStandAloneScript )
  519. {
  520. SetCdRomPath();
  521. lstrcpyn( SetupFilesBuffer, WizGlobals.CdSourcePath, AS(SetupFilesBuffer) );
  522. }
  523. else
  524. {
  525. GetComputerNameFromUnc( WizGlobals.UncDistFolder, szComputerName, AS(szComputerName) );
  526. hrPrintf=StringCchPrintf( SetupFilesBuffer, AS(SetupFilesBuffer),
  527. _T("%s%s%s%s%s"),
  528. szComputerName,
  529. _T("\\"),
  530. WizGlobals.DistShareName,
  531. _T("\\"),
  532. WizGlobals.Architecture );
  533. }
  534. QuoteStringIfNecessary( SetupFilesQuotedBuffer, SetupFilesBuffer, AS(SetupFilesQuotedBuffer) );
  535. hrPrintf=StringCchPrintf( Buffer, AS(Buffer),
  536. _T("set SetupFiles=%s\n\n"),
  537. SetupFilesQuotedBuffer );
  538. My_fputs( Buffer, fp );
  539. hrPrintf=StringCchPrintf( Buffer, AS(Buffer),
  540. _T("%s\\winnt32"),
  541. SetupFilesBuffer );
  542. QuoteStringIfNecessary( Winnt32Buffer, Buffer, AS(Winnt32Buffer) );
  543. if( bMultipleComputers )
  544. {
  545. if( StrUsage == NULL )
  546. {
  547. StrUsage = MyLoadString( IDS_USAGE );
  548. }
  549. hrPrintf=StringCchPrintf( Buffer, AS(Buffer),
  550. _T("if \"%%ComputerName%%\" == \"\" goto USAGE\n\n") );
  551. My_fputs( Buffer, fp );
  552. hrPrintf=StringCchPrintf( Buffer, AS(Buffer),
  553. _T("%s%s"),
  554. Winnt32Buffer,
  555. _T(" /s:%SetupFiles% ")
  556. _T("/unattend:%AnswerFile% ")
  557. _T("/udf:%ComputerName%,%UdfFile% ")
  558. _T("/makelocalsource") );
  559. AddLanguageSwitch( Buffer, AS(Buffer) );
  560. My_fputs( Buffer, fp );
  561. My_fputs( _T("goto DONE\n\n"), fp );
  562. My_fputs( _T(":USAGE\n"), fp );
  563. My_fputs( _T("echo.\n"), fp );
  564. hrPrintf=StringCchPrintf( Buffer, AS(Buffer),
  565. _T("echo %s: unattend ^<computername^>\n"),
  566. StrUsage );
  567. My_fputs( Buffer, fp );
  568. My_fputs( _T("echo.\n\n"), fp );
  569. My_fputs( _T(":DONE\n"), fp );
  570. }
  571. else
  572. {
  573. hrPrintf=StringCchPrintf(Buffer, AS(Buffer),
  574. _T("%s%s"),
  575. Winnt32Buffer,
  576. _T(" /s:%SetupFiles% ")
  577. _T("/unattend:%AnswerFile%"));
  578. AddLanguageSwitch( Buffer, AS(Buffer) );
  579. My_fputs( Buffer, fp );
  580. }
  581. My_fclose( fp );
  582. return( TRUE );
  583. }
  584. //----------------------------------------------------------------------------
  585. //
  586. // Function: QuoteStringIfNecessary
  587. //
  588. // Purpose: If the given input string has white space then the whole string
  589. // is quoted and returned in the output string. Else just the string
  590. // is returned in the output string.
  591. //
  592. // szOutputString is assumed to be of size MAX_INILINE_LEN
  593. //
  594. // Arguments: OUT TCHAR *szOutputString
  595. //
  596. // Returns: VOID
  597. //
  598. //----------------------------------------------------------------------------
  599. static VOID
  600. QuoteStringIfNecessary( OUT TCHAR *szOutputString,
  601. IN const TCHAR* const szInputString,
  602. IN DWORD cbSize)
  603. {
  604. HRESULT hrPrintf;
  605. if( DoesContainWhiteSpace( szInputString ) )
  606. {
  607. hrPrintf=StringCchPrintf( szOutputString, cbSize,
  608. _T("\"%s\""),
  609. szInputString );
  610. }
  611. else
  612. {
  613. lstrcpyn( szOutputString, szInputString ,cbSize);
  614. }
  615. }