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.

1076 lines
30 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 2001 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // WizardUtils.cpp
  7. //
  8. // Maintained By:
  9. // David Potter (DavidP) 30-JAN-2001
  10. //
  11. //////////////////////////////////////////////////////////////////////////////
  12. #include "Pch.h"
  13. #include "WizardUtils.h"
  14. #include "Nameutil.h"
  15. //////////////////////////////////////////////////////////////////////////////
  16. //++
  17. //
  18. // HrCreateFQN
  19. //
  20. // Description:
  21. // Validate a label (or IP address) and domain by creating an FQN from
  22. // them, prompting the user to choose whether to accept any non-RFC
  23. // characters present.
  24. //
  25. // Arguments:
  26. // hwndParentIn
  27. // Parent window for user prompts.
  28. //
  29. // pcwszLabelIn
  30. // The label (or IP address) of the FQN.
  31. //
  32. // pcwszDomainIn
  33. // The domain of the FQN.
  34. //
  35. // pfnLabelValidatorIn
  36. // Pointer to a function that determines whether the label is valid.
  37. //
  38. // pbstrFQNOut
  39. // Upon success, the created FQN.
  40. //
  41. // pefeoOut
  42. // Upon failure, indicates whether the problem arose from the label,
  43. // the domain, or a system call (such as allocating memory).
  44. //
  45. // Return Values:
  46. // S_OK
  47. // The label and domain are valid, and *pbstrFQNOut is a BSTR that
  48. // contains the resulting FQN; the caller must free *pbstrFQNOut with
  49. // SysFreeString.
  50. //
  51. // Failure
  52. // pefeoOut provides additional information regarding the source of
  53. // the failure.
  54. //
  55. // Remarks:
  56. //
  57. // This function enforces the UI policy of prohibiting users from
  58. // entering FQDNs for machine names; the label must be only a label.
  59. //
  60. // pefeoOut lets the caller take further action (such as setting the
  61. // focus on a control) according to the source of an error.
  62. //
  63. //--
  64. //////////////////////////////////////////////////////////////////////////////
  65. HRESULT
  66. HrCreateFQN(
  67. HWND hwndParentIn
  68. , LPCWSTR pcwszLabelIn
  69. , LPCWSTR pcwszDomainIn
  70. , PFN_LABEL_VALIDATOR pfnLabelValidatorIn
  71. , BSTR * pbstrFQNOut
  72. , EFQNErrorOrigin * pefeoOut
  73. )
  74. {
  75. TraceFunc( "" );
  76. HRESULT hr = S_OK;
  77. bool fTryAgain = true;
  78. bool fAcceptNonRFCLabel = false;
  79. bool fAcceptNonRFCDomain = false;
  80. EFQNErrorOrigin efeo = feoSYSTEM;
  81. Assert( pcwszLabelIn != NULL );
  82. // pcwszDomainIn can be null, which means to use local machine's domain.
  83. Assert( pfnLabelValidatorIn != NULL );
  84. Assert( pbstrFQNOut != NULL );
  85. Assert( *pbstrFQNOut == NULL );
  86. // pefeoOut can be null, which means the caller doesn't care about the source of failure.
  87. // Disallow FQDNs for the label, and allow IP addresses.
  88. hr = THR( ( *pfnLabelValidatorIn )( pcwszLabelIn, true ) );
  89. if ( FAILED( hr ) )
  90. {
  91. efeo = feoLABEL;
  92. THR( HrShowInvalidLabelPrompt( hwndParentIn, pcwszLabelIn, hr, &fAcceptNonRFCLabel ) );
  93. goto Error;
  94. }
  95. //
  96. // Make the FQN, trying first without RFC chars, and again if it makes a difference.
  97. //
  98. while ( fTryAgain )
  99. {
  100. hr = THR( HrMakeFQN( pcwszLabelIn, pcwszDomainIn, fAcceptNonRFCLabel || fAcceptNonRFCDomain, pbstrFQNOut, &efeo ) );
  101. if ( FAILED( hr ) )
  102. {
  103. if ( efeo == feoLABEL )
  104. {
  105. HRESULT hrPrompt = S_OK;
  106. hrPrompt = THR( HrShowInvalidLabelPrompt( hwndParentIn, pcwszLabelIn, hr, &fAcceptNonRFCLabel ) );
  107. if ( FAILED( hrPrompt ) )
  108. {
  109. goto Error;
  110. }
  111. fTryAgain = fAcceptNonRFCLabel;
  112. }
  113. else if ( efeo == feoDOMAIN )
  114. {
  115. HRESULT hrPrompt = S_OK;
  116. hrPrompt = THR( HrShowInvalidDomainPrompt( hwndParentIn, pcwszDomainIn, hr, &fAcceptNonRFCDomain ) );
  117. if ( FAILED( hrPrompt ) )
  118. {
  119. goto Error;
  120. }
  121. fTryAgain = fAcceptNonRFCDomain;
  122. }
  123. else // efeo is neither feoLABEL nor feoDOMAIN
  124. {
  125. THR( HrMessageBoxWithStatus(
  126. hwndParentIn
  127. , IDS_ERR_FQN_CREATE_TITLE
  128. , IDS_ERR_FQN_CREATE_TEXT
  129. , hr
  130. , 0
  131. , MB_OK | MB_ICONSTOP
  132. , NULL
  133. , pcwszLabelIn
  134. , pcwszDomainIn
  135. ) );
  136. fTryAgain = false;
  137. }
  138. }
  139. else // FQN creation succeeded, so trying again is not necessary.
  140. {
  141. fTryAgain = false;
  142. }
  143. } // Loop to attempt FQN creation.
  144. goto Cleanup;
  145. Error:
  146. if ( pefeoOut != NULL )
  147. {
  148. *pefeoOut = efeo;
  149. }
  150. goto Cleanup;
  151. Cleanup:
  152. HRETURN( hr );
  153. } //*** HrCreateFQN
  154. //////////////////////////////////////////////////////////////////////////////
  155. //++
  156. //
  157. // HrShowInvalidLabelPrompt
  158. //
  159. // Description:
  160. // Show a message box to the user indicating a problem with the given
  161. // label; if the label contains non-RFC characters, allow the user to
  162. // choose to proceed with the label.
  163. //
  164. // Arguments:
  165. // hwndParentIn
  166. // Parent window for the message box.
  167. //
  168. // pcwszLabelIn
  169. // The label of interest.
  170. //
  171. // hrErrorIn
  172. // The error that arose when validating the label.
  173. //
  174. // pfAcceptedNonRFCOut
  175. // The user chose to accept non-RFC characters.
  176. //
  177. // Return Values:
  178. // S_OK
  179. // The message box displayed successfully, and if the error was that
  180. // the label contained non-RFC characters, *pfAcceptedNonRFCOut
  181. // indicates whether the user chose to accept them.
  182. //
  183. // Failure
  184. // The message box did not display successfully.
  185. //
  186. // Remarks:
  187. //
  188. //--
  189. //////////////////////////////////////////////////////////////////////////////
  190. HRESULT
  191. HrShowInvalidLabelPrompt(
  192. HWND hwndParentIn
  193. , LPCWSTR pcwszLabelIn
  194. , HRESULT hrErrorIn
  195. , bool * pfAcceptedNonRFCOut
  196. )
  197. {
  198. TraceFunc1( "pcwszLabelIn = '%1!ws!", pcwszLabelIn );
  199. HRESULT hr = S_OK;
  200. int iRet = IDNO;
  201. UINT idsStatus = 0;
  202. UINT idsSubStatus = 0;
  203. UINT idsMsgTitle = IDS_ERR_VALIDATING_NAME_TITLE;
  204. UINT idsMsgText = IDS_ERR_VALIDATING_NAME_TEXT;
  205. UINT nMsgBoxType = MB_OK | MB_ICONSTOP;
  206. Assert( pcwszLabelIn != NULL );
  207. // pfAcceptedNonRFCOut can be NULL, which means the caller doesn't expect
  208. // or care about the non-RFC case.
  209. Assert( FAILED( hrErrorIn ) );
  210. if ( pfAcceptedNonRFCOut != NULL )
  211. {
  212. *pfAcceptedNonRFCOut = false;
  213. }
  214. // Format the error message string for the message box.
  215. switch ( hrErrorIn )
  216. {
  217. case HRESULT_FROM_WIN32( ERROR_NOT_FOUND ):
  218. idsStatus = IDS_ERR_INVALID_DNS_NAME_TEXT;
  219. idsSubStatus = IDS_ERR_DNS_HOSTNAME_LABEL_EMPTY_TEXT;
  220. break;
  221. case HRESULT_FROM_WIN32( ERROR_DS_NAME_TOO_LONG ):
  222. idsStatus = IDS_ERR_DNS_HOSTNAME_LABEL_NO_NETBIOS;
  223. idsSubStatus = IDS_ERR_DNS_HOSTNAME_LABEL_LONG_TEXT;
  224. break;
  225. case HRESULT_FROM_WIN32( DNS_ERROR_NON_RFC_NAME ):
  226. idsStatus = IDS_ERR_NON_RFC_NAME_STATUS;
  227. idsSubStatus = IDS_ERR_NON_RFC_NAME_QUERY;
  228. idsMsgTitle = IDS_ERR_NON_RFC_NAME_TITLE;
  229. idsMsgText = IDS_ERR_NON_RFC_NAME_TEXT;
  230. nMsgBoxType = MB_YESNO | MB_ICONQUESTION;
  231. break;
  232. case HRESULT_FROM_WIN32( DNS_ERROR_INVALID_NAME_CHAR ):
  233. default:
  234. idsStatus = 0;
  235. idsSubStatus = IDS_ERR_DNS_HOSTNAME_INVALID_CHAR;
  236. break;
  237. }// end switch ( hrErrorIn )
  238. // Display the error message box.
  239. if ( idsStatus == 0 )
  240. {
  241. hr = THR( HrMessageBoxWithStatus(
  242. hwndParentIn
  243. , idsMsgTitle
  244. , idsMsgText
  245. , hrErrorIn
  246. , idsSubStatus
  247. , nMsgBoxType
  248. , &iRet
  249. , pcwszLabelIn
  250. ) );
  251. } // end if ( idsStatus == 0 )
  252. else // idsStatus != 0
  253. {
  254. hr = THR( HrMessageBoxWithStatusString(
  255. hwndParentIn
  256. , idsMsgTitle
  257. , idsMsgText
  258. , idsStatus
  259. , idsSubStatus
  260. , nMsgBoxType
  261. , &iRet
  262. , pcwszLabelIn
  263. ) );
  264. } // end idsStatus != 0
  265. if ( FAILED( hr ) )
  266. {
  267. goto Cleanup;
  268. }
  269. if ( ( iRet == IDYES ) && ( pfAcceptedNonRFCOut != NULL ) )
  270. {
  271. *pfAcceptedNonRFCOut = true;
  272. }
  273. Cleanup:
  274. HRETURN( hr );
  275. } //*** HrShowInvalidLabelPrompt
  276. //////////////////////////////////////////////////////////////////////////////
  277. //++
  278. //
  279. // HrShowInvalidDomainPrompt
  280. //
  281. // Description:
  282. // Show a message box to the user indicating a problem with the given
  283. // domain; if the domain contains non-RFC characters, allow the user to
  284. // choose to proceed with the domain.
  285. //
  286. // Arguments:
  287. // hwndParentIn
  288. // Parent window for the message box.
  289. //
  290. // pcwszDomainIn
  291. // The domain of interest.
  292. //
  293. // hrErrorIn
  294. // The error that arose when validating the domain.
  295. //
  296. // pfAcceptedNonRFCOut
  297. // The user chose to accept non-RFC characters.
  298. //
  299. // Return Values:
  300. // S_OK
  301. // The message box displayed successfully, and if the error was that
  302. // the domain contained non-RFC characters, *pfAcceptedNonRFCOut
  303. // indicates whether the user chose to accept them.
  304. //
  305. // Failure
  306. // The message box did not display successfully.
  307. //
  308. // Remarks:
  309. //
  310. //--
  311. //////////////////////////////////////////////////////////////////////////////
  312. HRESULT
  313. HrShowInvalidDomainPrompt(
  314. HWND hwndParentIn
  315. , LPCWSTR pcwszDomainIn
  316. , HRESULT hrErrorIn
  317. , bool * pfAcceptedNonRFCOut
  318. )
  319. {
  320. TraceFunc1( "pcwszDomainIn = '%1!ws!", pcwszDomainIn );
  321. HRESULT hr = S_OK;
  322. int iRet = IDNO;
  323. UINT idsStatus = 0;
  324. UINT idsSubStatus = 0;
  325. UINT idsMsgTitle = IDS_ERR_VALIDATING_NAME_TITLE;
  326. UINT idsMsgText = IDS_ERR_VALIDATING_NAME_TEXT;
  327. UINT nMsgBoxType = MB_OK | MB_ICONSTOP;
  328. Assert( pcwszDomainIn != NULL );
  329. Assert( pfAcceptedNonRFCOut != NULL );
  330. Assert( FAILED( hrErrorIn ) );
  331. *pfAcceptedNonRFCOut = false;
  332. // Format the error message string for the message box.
  333. switch ( hrErrorIn )
  334. {
  335. case HRESULT_FROM_WIN32( ERROR_INVALID_NAME ):
  336. idsStatus = IDS_ERR_INVALID_DNS_NAME_TEXT;
  337. idsSubStatus = IDS_ERR_FULL_DNS_NAME_INFO_TEXT;
  338. break;
  339. case HRESULT_FROM_WIN32( DNS_ERROR_NON_RFC_NAME ):
  340. idsStatus = IDS_ERR_NON_RFC_NAME_STATUS;
  341. idsSubStatus = IDS_ERR_NON_RFC_NAME_QUERY;
  342. idsMsgTitle = IDS_ERR_NON_RFC_NAME_TITLE;
  343. idsMsgText = IDS_ERR_NON_RFC_NAME_TEXT;
  344. nMsgBoxType = MB_YESNO | MB_ICONQUESTION;
  345. break;
  346. case HRESULT_FROM_WIN32( DNS_ERROR_NUMERIC_NAME ):
  347. idsStatus = IDS_ERR_INVALID_DNS_NAME_TEXT;
  348. idsSubStatus = IDS_ERR_FULL_DNS_NAME_NUMERIC;
  349. break;
  350. case HRESULT_FROM_WIN32( DNS_ERROR_INVALID_NAME_CHAR ):
  351. default:
  352. idsStatus = 0;
  353. idsSubStatus = IDS_ERR_DNS_NAME_INVALID_CHAR;
  354. break;
  355. }// end switch ( hrErrorIn )
  356. // Display the error message box.
  357. if ( idsStatus == 0 )
  358. {
  359. hr = THR( HrMessageBoxWithStatus(
  360. hwndParentIn
  361. , idsMsgTitle
  362. , idsMsgText
  363. , hrErrorIn
  364. , idsSubStatus
  365. , nMsgBoxType
  366. , &iRet
  367. , pcwszDomainIn
  368. ) );
  369. } // end if ( idsStatus == 0 )
  370. else // idsStatus != 0
  371. {
  372. hr = THR( HrMessageBoxWithStatusString(
  373. hwndParentIn
  374. , idsMsgTitle
  375. , idsMsgText
  376. , idsStatus
  377. , idsSubStatus
  378. , nMsgBoxType
  379. , &iRet
  380. , pcwszDomainIn
  381. ) );
  382. } // end idsStatus != 0
  383. if ( FAILED( hr ) )
  384. {
  385. goto Cleanup;
  386. }
  387. if ( iRet == IDYES )
  388. {
  389. *pfAcceptedNonRFCOut = true;
  390. }
  391. Cleanup:
  392. HRETURN( hr );
  393. } //*** HrShowInvalidDomainPrompt
  394. //////////////////////////////////////////////////////////////////////////////
  395. //++
  396. //
  397. // HrMessageBoxWithStatus
  398. //
  399. // Description:
  400. // Display an error message box.
  401. //
  402. // Arguments:
  403. // hwndParentIn
  404. // idsTitleIn
  405. // idsOperationIn
  406. // hrStatusIn
  407. // idsSubStatusIn
  408. // uTypeIn
  409. // pidReturnOut -- IDABORT on error or any return value from MessageBox()
  410. // ...
  411. //
  412. // Return Values:
  413. // Any return values from the MessageBox() Win32 API.
  414. //
  415. // Remarks:
  416. //
  417. //--
  418. //////////////////////////////////////////////////////////////////////////////
  419. HRESULT
  420. HrMessageBoxWithStatus(
  421. HWND hwndParentIn
  422. , UINT idsTitleIn
  423. , UINT idsOperationIn
  424. , HRESULT hrStatusIn
  425. , UINT idsSubStatusIn
  426. , UINT uTypeIn
  427. , int * pidReturnOut
  428. , ...
  429. )
  430. {
  431. TraceFunc( "" );
  432. HRESULT hr = S_OK;
  433. int idReturn = IDABORT; // Default in case of error.
  434. BSTR bstrTitle = NULL;
  435. BSTR bstrOperation = NULL;
  436. BSTR bstrStatus = NULL;
  437. BSTR bstrSubStatus = NULL;
  438. BSTR bstrFullText = NULL;
  439. va_list valist;
  440. va_start( valist, pidReturnOut );
  441. // Load the title string if one is specified.
  442. if ( idsTitleIn != 0 )
  443. {
  444. hr = THR( HrLoadStringIntoBSTR( g_hInstance, idsTitleIn, &bstrTitle ) );
  445. if ( FAILED( hr ) )
  446. {
  447. goto Cleanup;
  448. }
  449. }
  450. // Load the text string.
  451. hr = THR( HrFormatStringWithVAListIntoBSTR( g_hInstance, idsOperationIn, &bstrOperation, valist ) );
  452. if ( FAILED( hr ) )
  453. {
  454. goto Cleanup;
  455. }
  456. // Format the status.
  457. hr = THR( HrFormatErrorIntoBSTR( hrStatusIn, &bstrStatus ) );
  458. if ( FAILED( hr ) )
  459. {
  460. goto Cleanup;
  461. }
  462. // Load the substatus string if specified.
  463. if ( idsSubStatusIn != 0 )
  464. {
  465. hr = THR( HrLoadStringIntoBSTR( g_hInstance, idsSubStatusIn, &bstrSubStatus ) );
  466. if ( FAILED( hr ) )
  467. {
  468. goto Cleanup;
  469. }
  470. }
  471. // Format all the strings into a single string.
  472. if ( bstrSubStatus == NULL )
  473. {
  474. hr = THR( HrFormatStringIntoBSTR(
  475. L"%1!ws!\n\n%2!ws!"
  476. , &bstrFullText
  477. , bstrOperation
  478. , bstrStatus
  479. ) );
  480. }
  481. else
  482. {
  483. hr = THR( HrFormatStringIntoBSTR(
  484. L"%1!ws!\n\n%2!ws!\n\n%3!ws!"
  485. , &bstrFullText
  486. , bstrOperation
  487. , bstrStatus
  488. , bstrSubStatus
  489. ) );
  490. }
  491. if ( FAILED( hr ) )
  492. {
  493. goto Cleanup;
  494. }
  495. // Display the status.
  496. idReturn = MessageBox( hwndParentIn, bstrFullText, bstrTitle, uTypeIn );
  497. Cleanup:
  498. TraceSysFreeString( bstrTitle );
  499. TraceSysFreeString( bstrOperation );
  500. TraceSysFreeString( bstrStatus );
  501. TraceSysFreeString( bstrSubStatus );
  502. TraceSysFreeString( bstrFullText );
  503. va_end( valist );
  504. if ( pidReturnOut != NULL )
  505. {
  506. *pidReturnOut = idReturn;
  507. }
  508. HRETURN( hr );
  509. } //*** HrMessageBoxWithStatus( hrStatusIn )
  510. //////////////////////////////////////////////////////////////////////////////
  511. //++
  512. //
  513. // HrMessageBoxWithStatusString
  514. //
  515. // Description:
  516. // Display an error message box.
  517. //
  518. // Arguments:
  519. // hwndParentIn
  520. // idsTitleIn
  521. // idsOperationIn
  522. // idsStatusIn
  523. // idsSubStatusIn
  524. // uTypeIn
  525. // pidReturnOut -- IDABORT on error or any return value from MessageBox()
  526. // ...
  527. //
  528. // Return Values:
  529. // Any return values from the MessageBox() Win32 API.
  530. //
  531. // Remarks:
  532. //
  533. //--
  534. //////////////////////////////////////////////////////////////////////////////
  535. HRESULT
  536. HrMessageBoxWithStatusString(
  537. HWND hwndParentIn
  538. , UINT idsTitleIn
  539. , UINT idsOperationIn
  540. , UINT idsStatusIn
  541. , UINT idsSubStatusIn
  542. , UINT uTypeIn
  543. , int * pidReturnOut
  544. , ...
  545. )
  546. {
  547. TraceFunc( "" );
  548. HRESULT hr = S_OK;
  549. int idReturn = IDABORT; // Default in case of error.
  550. BSTR bstrTitle = NULL;
  551. BSTR bstrOperation = NULL;
  552. BSTR bstrStatus = NULL;
  553. BSTR bstrSubStatus = NULL;
  554. BSTR bstrFullText = NULL;
  555. va_list valist;
  556. va_start( valist, pidReturnOut );
  557. // Load the title string if one is specified.
  558. if ( idsTitleIn != 0 )
  559. {
  560. hr = THR( HrLoadStringIntoBSTR( g_hInstance, idsTitleIn, &bstrTitle ) );
  561. if ( FAILED( hr ) )
  562. {
  563. goto Cleanup;
  564. }
  565. }
  566. // Load the text string.
  567. hr = THR( HrFormatStringWithVAListIntoBSTR( g_hInstance, idsOperationIn, &bstrOperation, valist ) );
  568. if ( FAILED( hr ) )
  569. {
  570. goto Cleanup;
  571. }
  572. // Format the status.
  573. hr = THR( HrLoadStringIntoBSTR( g_hInstance, idsStatusIn, &bstrStatus ) );
  574. if ( FAILED( hr ) )
  575. {
  576. goto Cleanup;
  577. }
  578. // Load the substatus string if specified.
  579. if ( idsSubStatusIn != 0 )
  580. {
  581. hr = THR( HrLoadStringIntoBSTR( g_hInstance, idsSubStatusIn, &bstrSubStatus ) );
  582. if ( FAILED( hr ) )
  583. {
  584. goto Cleanup;
  585. }
  586. }
  587. // Format all the strings into a single string.
  588. if ( bstrSubStatus == NULL )
  589. {
  590. hr = THR( HrFormatStringIntoBSTR(
  591. L"%1!ws!\n\n%2!ws!"
  592. , &bstrFullText
  593. , bstrOperation
  594. , bstrStatus
  595. ) );
  596. }
  597. else
  598. {
  599. hr = THR( HrFormatStringIntoBSTR(
  600. L"%1!ws!\n\n%2!ws!\n\n%3!ws!"
  601. , &bstrFullText
  602. , bstrOperation
  603. , bstrStatus
  604. , bstrSubStatus
  605. ) );
  606. }
  607. if ( FAILED( hr ) )
  608. {
  609. goto Cleanup;
  610. }
  611. // Display the status.
  612. idReturn = MessageBox( hwndParentIn, bstrFullText, bstrTitle, uTypeIn );
  613. Cleanup:
  614. TraceSysFreeString( bstrTitle );
  615. TraceSysFreeString( bstrOperation );
  616. TraceSysFreeString( bstrStatus );
  617. TraceSysFreeString( bstrSubStatus );
  618. TraceSysFreeString( bstrFullText );
  619. va_end( valist );
  620. if ( pidReturnOut != NULL )
  621. {
  622. *pidReturnOut = idReturn;
  623. }
  624. HRETURN( hr );
  625. } //*** HrMessageBoxWithStatusString( idsStatusTextIn )
  626. //////////////////////////////////////////////////////////////////////////////
  627. //++
  628. //
  629. // HrViewLogFile
  630. //
  631. // Description:
  632. // View the log file.
  633. //
  634. // Arguments:
  635. // hwndParentIn
  636. //
  637. // Return Values:
  638. // S_OK - Operation completed successfully
  639. // Other HRESULT values from ShellExecute().
  640. //
  641. // Remarks:
  642. //
  643. //--
  644. //////////////////////////////////////////////////////////////////////////////
  645. HRESULT
  646. HrViewLogFile(
  647. HWND hwndParentIn
  648. )
  649. {
  650. TraceFunc( "" );
  651. static const WCHAR s_szVerb[] = L"open";
  652. static LPCTSTR s_pszLogFileName = PszLogFilePath();
  653. HRESULT hr = S_OK;
  654. DWORD sc;
  655. DWORD cch;
  656. DWORD cchRet;
  657. LPWSTR pszFile = NULL;
  658. //
  659. // Expand environment variables in the file to open.
  660. //
  661. // Get the size of the output buffer.
  662. cch = 0;
  663. cchRet = ExpandEnvironmentStrings( s_pszLogFileName, NULL, cch );
  664. if ( cchRet == 0 )
  665. {
  666. sc = TW32( GetLastError() );
  667. goto Win32Error;
  668. } // if: error getting length of the expansion string
  669. // Allocate the output buffer.
  670. cch = cchRet;
  671. pszFile = new WCHAR[ cch ];
  672. if ( pszFile == NULL )
  673. {
  674. sc = TW32( ERROR_OUTOFMEMORY );
  675. goto Win32Error;
  676. }
  677. // Expand the string into the output buffer.
  678. cchRet = ExpandEnvironmentStrings( s_pszLogFileName, pszFile, cch );
  679. if ( cchRet == 0 )
  680. {
  681. sc = TW32( GetLastError() );
  682. goto Win32Error;
  683. }
  684. Assert( cchRet == cch );
  685. //
  686. // Execute the file.
  687. //
  688. sc = HandleToULong( ShellExecute(
  689. hwndParentIn // hwnd
  690. , s_szVerb // lpVerb
  691. , pszFile // lpFile
  692. , NULL // lpParameters
  693. , NULL // lpDirectory
  694. , SW_SHOWNORMAL // nShowCommand
  695. ) );
  696. if ( sc < 32 )
  697. {
  698. // Values less than 32 indicate an error occurred.
  699. TW32( sc );
  700. goto Win32Error;
  701. } // if: error executing the file
  702. goto Cleanup;
  703. Win32Error:
  704. THR( HrMessageBoxWithStatus(
  705. hwndParentIn
  706. , IDS_ERR_VIEW_LOG_TITLE
  707. , IDS_ERR_VIEW_LOG_TEXT
  708. , sc
  709. , 0 // idsSubStatusIn
  710. , ( MB_OK
  711. | MB_ICONEXCLAMATION )
  712. , NULL // pidReturnOut
  713. , s_pszLogFileName
  714. ) );
  715. hr = HRESULT_FROM_WIN32( sc );
  716. goto Cleanup;
  717. Cleanup:
  718. delete [] pszFile;
  719. HRETURN( hr );
  720. } //*** HrViewLogFile()
  721. //////////////////////////////////////////////////////////////////////////////
  722. //++
  723. //
  724. // HrGetTrimmedText
  725. //
  726. // Description:
  727. // Extract a control's text, if any, with leading and trailing spaces
  728. // removed.
  729. //
  730. // Arguments:
  731. // hwndControlIn - The control.
  732. // pbstrTrimmedTextOut - On success, the trimmed text.
  733. //
  734. // Return Values:
  735. // S_OK
  736. // *pbstrTrimmedTextOut points to the trimmed text and the caller
  737. // must free it.
  738. //
  739. // S_FALSE
  740. // Either the control is empty or it contains only spaces, and
  741. // *pbstrTrimmedTextOut is null.
  742. //
  743. // E_POINTER
  744. // pbstrTrimmedTextOut was null.
  745. //
  746. // E_OUTOFMEMORY
  747. // Couldn't allocate memory for *pbstrTrimmedTextOut.
  748. //
  749. // Remarks:
  750. //
  751. //--
  752. //////////////////////////////////////////////////////////////////////////////
  753. HRESULT
  754. HrGetTrimmedText(
  755. HWND hwndControlIn
  756. , BSTR* pbstrTrimmedTextOut
  757. )
  758. {
  759. TraceFunc( "" );
  760. HRESULT hr = S_OK;
  761. DWORD cchControlText = 0;
  762. LPWSTR wszUntrimmedText = NULL;
  763. Assert( pbstrTrimmedTextOut != NULL );
  764. if ( pbstrTrimmedTextOut == NULL )
  765. {
  766. hr = THR( E_POINTER );
  767. goto Cleanup;
  768. }
  769. *pbstrTrimmedTextOut = NULL;
  770. cchControlText = GetWindowTextLength( hwndControlIn );
  771. if ( cchControlText == 0 )
  772. {
  773. hr = S_FALSE;
  774. goto Cleanup;
  775. }
  776. wszUntrimmedText = new WCHAR[ cchControlText + 1 ];
  777. if ( wszUntrimmedText == NULL )
  778. {
  779. hr = THR( E_OUTOFMEMORY );
  780. goto Cleanup;
  781. }
  782. cchControlText = GetWindowText( hwndControlIn, wszUntrimmedText, cchControlText + 1 );
  783. if ( cchControlText == 0 )
  784. {
  785. hr = S_FALSE;
  786. goto Cleanup;
  787. }
  788. {
  789. DWORD idxNonBlankStart = 0;
  790. DWORD idxNonBlankEnd = cchControlText - 1;
  791. while ( ( idxNonBlankStart < cchControlText ) && ( wszUntrimmedText[ idxNonBlankStart ] == L' ' ) )
  792. {
  793. idxNonBlankStart += 1;
  794. }
  795. while ( ( idxNonBlankEnd > idxNonBlankStart ) && ( wszUntrimmedText[ idxNonBlankEnd ] == L' ' ) )
  796. {
  797. idxNonBlankEnd -= 1;
  798. }
  799. if ( idxNonBlankStart <= idxNonBlankEnd )
  800. {
  801. DWORD cchTrimmedText = idxNonBlankEnd - idxNonBlankStart + 1;
  802. *pbstrTrimmedTextOut = TraceSysAllocStringLen( wszUntrimmedText + idxNonBlankStart, cchTrimmedText );
  803. if ( *pbstrTrimmedTextOut == NULL )
  804. {
  805. hr = THR( E_OUTOFMEMORY );
  806. goto Cleanup;
  807. }
  808. }
  809. else
  810. {
  811. hr = S_FALSE;
  812. goto Cleanup;
  813. }
  814. }
  815. Cleanup:
  816. if ( wszUntrimmedText != NULL )
  817. {
  818. delete [] wszUntrimmedText;
  819. }
  820. HRETURN( hr );
  821. } //*** HrGetTrimmedText
  822. //////////////////////////////////////////////////////////////////////////////
  823. //++
  824. //
  825. // HrGetPrincipalName
  826. //
  827. // Description:
  828. // Form a user-domain pair from a given pair of controls, ignoring the
  829. // second control and using the domain from the first if the first has
  830. // a string in the user@domain format.
  831. //
  832. // Arguments:
  833. // hwndUserNameControlIn
  834. // The control for either the user name or the user@domain pair.
  835. //
  836. // hwndDomainControlIn
  837. // The control for the domain name in the non-user@domain case.
  838. //
  839. // pbstrUserNameOut
  840. // On success, the user name.
  841. //
  842. // pbstrDomainNameOut
  843. // On success, the domain name.
  844. //
  845. // pfUserIsDNSNameOut
  846. // Tells the caller whether hwndUserNameControlIn has text in the
  847. // user@domain format. Can be null if the caller doesn't care.
  848. //
  849. // Return Values:
  850. // S_OK
  851. // *pbstrUserNameOut and *pbstrDomainNameOut point to the
  852. // corresponding names, and the caller must free them.
  853. //
  854. // S_FALSE
  855. // Either the user control is empty, or it does not have a user@domain
  856. // pair and the domain control is empty.
  857. // The two BSTR out parameters are null.
  858. //
  859. // E_POINTER
  860. // pbstrUserNameOut or pbstrDomainNameOut was null.
  861. //
  862. // E_OUTOFMEMORY
  863. //
  864. // Remarks:
  865. //
  866. //--
  867. //////////////////////////////////////////////////////////////////////////////
  868. HRESULT
  869. HrGetPrincipalName(
  870. HWND hwndUserNameControlIn
  871. , HWND hwndDomainControlIn
  872. , BSTR* pbstrUserNameOut
  873. , BSTR* pbstrDomainNameOut
  874. , BOOL* pfUserIsDNSNameOut
  875. )
  876. {
  877. TraceFunc( "" );
  878. HRESULT hr = S_OK;
  879. BSTR bstrFullUserText = NULL;
  880. BSTR bstrUserName = NULL;
  881. BSTR bstrDomainName = NULL;
  882. BOOL fUserIsDNSName = FALSE;
  883. LPWSTR wszDNSDelimiter = NULL;
  884. Assert( pbstrUserNameOut != NULL );
  885. if ( pbstrUserNameOut == NULL )
  886. {
  887. hr = THR( E_POINTER );
  888. goto Cleanup;
  889. }
  890. *pbstrUserNameOut = NULL;
  891. Assert( pbstrDomainNameOut != NULL );
  892. if ( pbstrDomainNameOut == NULL )
  893. {
  894. hr = THR( E_POINTER );
  895. goto Cleanup;
  896. }
  897. *pbstrDomainNameOut = NULL;
  898. // pfUserIsDNSNameOut can be null, which means the caller doesn't care.
  899. // Get text from user control.
  900. hr = STHR( HrGetTrimmedText( hwndUserNameControlIn, &bstrFullUserText ) );
  901. if ( hr != S_OK )
  902. {
  903. goto Cleanup;
  904. }
  905. // If the user text has an @ sign,
  906. wszDNSDelimiter = wcschr( bstrFullUserText, L'@' );
  907. if ( wszDNSDelimiter != NULL )
  908. {
  909. // Split user text into user name and domain name.
  910. DWORD cchUserName = (DWORD)( wszDNSDelimiter - bstrFullUserText );
  911. DWORD cchDomainName = SysStringLen( bstrFullUserText ) - cchUserName - 1; // -1 to account for the @ sign.
  912. LPWSTR wszDomainStart = wszDNSDelimiter + 1; // +1 to skip the @ sign.
  913. fUserIsDNSName = TRUE;
  914. // If either user or domain are empty, bail out.
  915. if ( ( cchUserName == 0 ) || ( cchDomainName == 0 ) )
  916. {
  917. hr = S_FALSE;
  918. goto Cleanup;
  919. }
  920. bstrUserName = TraceSysAllocStringLen( bstrFullUserText, cchUserName );
  921. if ( bstrUserName == NULL )
  922. {
  923. hr = THR( E_OUTOFMEMORY );
  924. goto Cleanup;
  925. }
  926. bstrDomainName = TraceSysAllocString( wszDomainStart );
  927. if ( bstrDomainName == NULL )
  928. {
  929. hr = THR( E_OUTOFMEMORY );
  930. goto Cleanup;
  931. }
  932. } // if: the user text has an @ sign.
  933. else
  934. {
  935. // Set user name to full user control text.
  936. bstrUserName = bstrFullUserText;
  937. bstrFullUserText = NULL;
  938. // Get domain name from domain control.
  939. hr = STHR( HrGetTrimmedText( hwndDomainControlIn, &bstrDomainName ) );
  940. if ( hr != S_OK )
  941. {
  942. goto Cleanup;
  943. }
  944. }
  945. // Transfer ownership of the strings to the caller.
  946. *pbstrUserNameOut = bstrUserName;
  947. bstrUserName = NULL;
  948. *pbstrDomainNameOut = bstrDomainName;
  949. bstrDomainName = NULL;
  950. Cleanup:
  951. if ( pfUserIsDNSNameOut != NULL )
  952. {
  953. *pfUserIsDNSNameOut = fUserIsDNSName;
  954. }
  955. TraceSysFreeString( bstrFullUserText );
  956. TraceSysFreeString( bstrUserName );
  957. TraceSysFreeString( bstrDomainName );
  958. HRETURN( hr );
  959. } //*** HrGetPrincipalName