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.

3253 lines
76 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1995 - 1999
  3. All rights reserved.
  4. Module Name:
  5. Util.cxx
  6. Abstract:
  7. Misc util functions.
  8. Author:
  9. Albert Ting (AlbertT) 27-Jan-1995
  10. Revision History:
  11. --*/
  12. #include "precomp.hxx"
  13. #pragma hdrstop
  14. #include <shgina.h>
  15. #include "result.hxx"
  16. #include "msgbox.hxx"
  17. #include "spllibex.hxx"
  18. #include "prndata.hxx"
  19. //
  20. // Global functions
  21. //
  22. static MSG_HLPMAP gMsgHelpTable [] =
  23. {
  24. { ERROR_INVALID_PRINTER_NAME, IDS_ERR_WITH_HELP1, gszHelpTroubleShooterURL},
  25. { ERROR_KM_DRIVER_BLOCKED, IDS_COULDNOTCONNECTTOPRINTER_BLOCKED_HELP, gszHelpTroubleShooterURL},
  26. { 0, 0, 0},
  27. };
  28. enum
  29. {
  30. //
  31. // Not mapped error code.
  32. // Show up the text from the GetLastError()
  33. //
  34. IDS_NOT_MAPPED = (UINT )(-1)
  35. };
  36. #define MAKERESOURCEINT(psz) PTR2UINT(psz)
  37. //
  38. // This global error mapping table is proposed to filter out
  39. // the errors that are showed up to the end user to a certain
  40. // well known set, which we have a good explanation for. All the
  41. // rest of the errors will be mapped to the generic error text.
  42. // if the message mapping is IDS_NOT_MAPPED it means the text
  43. // coming from the GetLastError/FormatMessage APIs is good enough
  44. // so we are going to use it. Otherwise the mapping ID is a
  45. // resource id of the remapped text.
  46. //
  47. static MSG_ERRMAP gGlobalErrorMapTable[] =
  48. {
  49. //
  50. // Category 1 - Print Spooler Error Codes
  51. //
  52. ERROR_UNKNOWN_PRINT_MONITOR, IDS_NOT_MAPPED,
  53. ERROR_PRINTER_DRIVER_IN_USE, IDS_NOT_MAPPED,
  54. ERROR_SPOOL_FILE_NOT_FOUND, IDS_ERRMAP_SPOOL_FILE_NOT_FOUND,
  55. ERROR_SPL_NO_STARTDOC, IDS_ERRMAP_SPL_NO_STARTDOC,
  56. ERROR_SPL_NO_ADDJOB, IDS_ERRMAP_SPL_NO_STARTDOC,
  57. ERROR_PRINT_PROCESSOR_ALREADY_INSTALLED, IDS_NOT_MAPPED,
  58. ERROR_PRINT_MONITOR_ALREADY_INSTALLED, IDS_NOT_MAPPED,
  59. ERROR_INVALID_PRINT_MONITOR, IDS_NOT_MAPPED,
  60. ERROR_PRINT_MONITOR_IN_USE, IDS_NOT_MAPPED,
  61. ERROR_PRINTER_HAS_JOBS_QUEUED, IDS_NOT_MAPPED,
  62. ERROR_SUCCESS_REBOOT_REQUIRED, IDS_NOT_MAPPED,
  63. ERROR_SUCCESS_RESTART_REQUIRED, IDS_NOT_MAPPED,
  64. ERROR_PRINTER_NOT_FOUND, IDS_NOT_MAPPED,
  65. //
  66. // Category 2 - Print Subsystem Related Error Codes
  67. //
  68. ERROR_OUT_OF_PAPER, IDS_NOT_MAPPED,
  69. ERROR_PRINTQ_FULL, IDS_NOT_MAPPED,
  70. ERROR_NO_SPOOL_SPACE, IDS_ERRMAP_NO_SPOOL_SPACE,
  71. ERROR_PRINT_CANCELLED, IDS_NOT_MAPPED,
  72. ERROR_REDIR_PAUSED, IDS_NOT_MAPPED,
  73. ERROR_PRINTER_DRIVER_ALREADY_INSTALLED, IDS_NOT_MAPPED,
  74. ERROR_UNKNOWN_PRINTER_DRIVER, IDS_ERROR_UNKNOWN_DRIVER,
  75. ERROR_UNKNOWN_PRINTPROCESSOR, IDS_ERRMAP_UNKNOWN_PRINTPROCESSOR,
  76. ERROR_INVALID_PRINTER_NAME, IDS_NOT_MAPPED,
  77. ERROR_PRINTER_ALREADY_EXISTS, IDS_ERRMAP_PRINTER_ALREADY_EXISTS,
  78. ERROR_INVALID_PRINTER_COMMAND, IDS_NOT_MAPPED,
  79. ERROR_ALREADY_WAITING, IDS_NOT_MAPPED,
  80. ERROR_PRINTER_DELETED, IDS_NOT_MAPPED,
  81. ERROR_INVALID_PRINTER_STATE, IDS_NOT_MAPPED,
  82. ERROR_BAD_DRIVER, IDS_NOT_MAPPED,
  83. //
  84. // Category 3 - Common Win32/RPC
  85. //
  86. RPC_S_SERVER_UNAVAILABLE, IDS_ERRMAP_RPC_S_SERVER_UNAVAILABLE,
  87. RPC_S_INVALID_NET_ADDR, IDS_NOT_MAPPED,
  88. ERROR_ACCESS_DENIED, IDS_NOT_MAPPED,
  89. ERROR_DISK_FULL, IDS_ERRMAP_DISK_FULL,
  90. ERROR_NOT_READY, IDS_NOT_MAPPED,
  91. ERROR_DEVICE_NOT_AVAILABLE, IDS_NOT_MAPPED,
  92. ERROR_WRITE_PROTECT, IDS_NOT_MAPPED,
  93. ERROR_SHARING_VIOLATION, IDS_NOT_MAPPED,
  94. ERROR_LOCK_VIOLATION, IDS_NOT_MAPPED,
  95. ERROR_HANDLE_DISK_FULL, IDS_ERRMAP_DISK_FULL,
  96. ERROR_NETWORK_BUSY, IDS_NOT_MAPPED,
  97. ERROR_NETWORK_ACCESS_DENIED, IDS_ERRMAP_NETWORK_ACCESS_DENIED,
  98. ERROR_NETNAME_DELETED, IDS_NOT_MAPPED,
  99. ERROR_CANNOT_MAKE, IDS_NOT_MAPPED,
  100. ERROR_NET_WRITE_FAULT, IDS_ERRMAP_NET_WRITE_FAULT,
  101. ERROR_INVALID_PASSWORD, IDS_NOT_MAPPED,
  102. ERROR_NOT_SUPPORTED, IDS_ERRMAP_NOT_SUPPORTED,
  103. ERROR_OUTOFMEMORY, IDS_ERRMAP_OUTOFMEMORY,
  104. ERROR_NOT_ENOUGH_MEMORY, IDS_ERRMAP_OUTOFMEMORY,
  105. ERROR_CANCELLED, IDS_NOT_MAPPED,
  106. ERROR_BAD_DRIVER, IDS_NOT_MAPPED,
  107. ERROR_DRIVE_LOCKED, IDS_NOT_MAPPED,
  108. ERROR_DEV_NOT_EXIST, IDS_NOT_MAPPED,
  109. ERROR_OPEN_FAILED, IDS_NOT_MAPPED,
  110. ERROR_DEVICE_DOOR_OPEN, IDS_NOT_MAPPED,
  111. ERROR_BAD_DEVICE, IDS_NOT_MAPPED,
  112. ERROR_INVALID_PROFILE, IDS_NOT_MAPPED,
  113. ERROR_PROFILE_NOT_ASSOCIATED_WITH_DEVICE, IDS_NOT_MAPPED,
  114. ERROR_PROFILE_NOT_FOUND, IDS_NOT_MAPPED,
  115. ERROR_DEVICE_NOT_AVAILABLE, IDS_NOT_MAPPED,
  116. ERROR_NO_MEDIA_IN_DRIVE, IDS_NOT_MAPPED,
  117. ERROR_UNRECOGNIZED_MEDIA, IDS_NOT_MAPPED,
  118. ERROR_MEDIA_NOT_AVAILABLE, IDS_NOT_MAPPED,
  119. ERROR_UNKNOWN_PORT, IDS_NOT_MAPPED,
  120. ERROR_FILE_CORRUPT, IDS_ERRMAP_FILE_CORRUPT,
  121. ERROR_DISK_CORRUPT, IDS_NOT_MAPPED,
  122. ERROR_ALREADY_EXISTS, IDS_NOT_MAPPED,
  123. ERROR_KM_DRIVER_BLOCKED, IDS_NOT_MAPPED,
  124. ERROR_PRINTER_DRIVER_BLOCKED, IDS_PRINTER_DRIVER_BLOCKED,
  125. ERROR_REQ_NOT_ACCEP, IDS_NOT_MAPPED,
  126. // end of the table
  127. 0, 0
  128. }; // gGlobalErrorMapTable
  129. inline static HRESULT CreateError()
  130. {
  131. DWORD dw = GetLastError();
  132. if (ERROR_SUCCESS == dw) return E_FAIL;
  133. return HRESULT_FROM_WIN32(dw);
  134. }
  135. LPTSTR
  136. pszStrCat(
  137. IN OUT LPTSTR pszDest,
  138. OUT LPCTSTR pszSource, OPTIONAL
  139. IN OUT UINT& cchDest
  140. )
  141. /*++
  142. Routine Description:
  143. Copies pszSource to pszDest iff there is enough space in cchDest.
  144. Arguments:
  145. pszDest - Destination buffer
  146. pszSource - Source string, may be NULL (no action taken)
  147. cchDest - char count size of pszDest, on return, space remaining
  148. Return Value:
  149. LPTSTR - pointer to remaining space
  150. NULL - out of space.
  151. --*/
  152. {
  153. if( !pszSource ){
  154. return pszDest;
  155. }
  156. UINT cchSource = lstrlen( pszSource );
  157. //
  158. // Fail if dest can't hold source (equal case doesn't hold NULL term)
  159. // OR dest string is NULL.
  160. //
  161. if( !pszDest || cchDest <= cchSource + 1 ){
  162. return pszDest;
  163. }
  164. lstrcpy( pszDest, pszSource );
  165. cchDest -= cchSource;
  166. return pszDest + cchSource;
  167. }
  168. INT
  169. iMessage(
  170. IN HWND hwnd,
  171. IN UINT idsTitle,
  172. IN UINT idsMessage,
  173. IN UINT uType,
  174. IN DWORD dwLastError,
  175. IN const PMSG_ERRMAP pMsgErrMap,
  176. ...
  177. )
  178. /*++
  179. Routine Description:
  180. Formats error message.
  181. Arguments:
  182. See Internal_Message for details
  183. Return Value:
  184. returns value from MessageBox on sucess
  185. and zero on failure
  186. --*/
  187. {
  188. va_list valist;
  189. va_start(valist, pMsgErrMap);
  190. INT iRetval = 0;
  191. if( FAILED(Internal_Message(&iRetval,
  192. ghInst,
  193. hwnd,
  194. MAKEINTRESOURCE(idsTitle),
  195. MAKEINTRESOURCE(idsMessage),
  196. uType,
  197. dwLastError,
  198. pMsgErrMap,
  199. NULL,
  200. 0,
  201. valist)) )
  202. {
  203. // make sure we return zero in the failure case
  204. iRetval = 0;
  205. }
  206. va_end(valist);
  207. return iRetval;
  208. }
  209. INT
  210. iMessage2(
  211. IN HWND hwnd,
  212. IN LPCTSTR pszTitle,
  213. IN LPCTSTR pszMessage,
  214. IN UINT uType,
  215. IN DWORD dwLastError,
  216. IN const PMSG_ERRMAP pMsgErrMap
  217. ...
  218. )
  219. /*++
  220. Routine Description:
  221. Formats error message.
  222. Arguments:
  223. See Internal_Message for details
  224. pszTitle and pszMessage can be resource IDs i.e. MAKEINTRESOURCE(id)
  225. Return Value:
  226. returns value from MessageBox on sucess
  227. and zero on failure
  228. --*/
  229. {
  230. va_list valist;
  231. va_start(valist, pMsgErrMap);
  232. INT iRetval = 0;
  233. if( FAILED(Internal_Message(&iRetval,
  234. ghInst,
  235. hwnd,
  236. pszTitle,
  237. pszMessage,
  238. uType,
  239. dwLastError,
  240. pMsgErrMap,
  241. NULL,
  242. 0,
  243. valist)) )
  244. {
  245. // make sure we return zero in the failure case
  246. iRetval = 0;
  247. }
  248. va_end(valist);
  249. return iRetval;
  250. }
  251. INT
  252. iMessageEx(
  253. IN HWND hwnd,
  254. IN UINT idsTitle,
  255. IN UINT idsMessage,
  256. IN UINT uType,
  257. IN DWORD dwLastError,
  258. IN const PMSG_ERRMAP pMsgErrMap,
  259. IN UINT idMessage,
  260. IN const PMSG_HLPMAP pHlpErrMap,
  261. ...
  262. )
  263. /*++
  264. Routine Description:
  265. Formats error message.
  266. Arguments:
  267. See Internal_Message for details
  268. Return Value:
  269. returns value from MessageBox on sucess
  270. and zero on failure
  271. --*/
  272. {
  273. va_list valist;
  274. va_start(valist, pHlpErrMap);
  275. INT iRetval = 0;
  276. if( FAILED(Internal_Message(&iRetval,
  277. ghInst,
  278. hwnd,
  279. MAKEINTRESOURCE(idsTitle),
  280. MAKEINTRESOURCE(idsMessage),
  281. uType,
  282. dwLastError,
  283. pMsgErrMap,
  284. idMessage,
  285. pHlpErrMap,
  286. valist)) )
  287. {
  288. // make sure we return zero in the failure case
  289. iRetval = 0;
  290. }
  291. va_end(valist);
  292. return iRetval;
  293. }
  294. HRESULT
  295. Internal_Message(
  296. OUT INT *piResult,
  297. IN HINSTANCE hModule,
  298. IN HWND hwnd,
  299. IN LPCTSTR pszTitle,
  300. IN LPCTSTR pszMessage,
  301. IN UINT uType,
  302. IN DWORD dwLastError,
  303. IN const PMSG_ERRMAP pMsgErrMap,
  304. IN UINT idHlpMessage,
  305. IN const PMSG_HLPMAP pHlpErrMap,
  306. IN va_list valist
  307. )
  308. /*++
  309. Routine Description:
  310. Formats error message.
  311. Arguments:
  312. piResult - the message box return value (on success)
  313. hModule - module where to load the resources from
  314. hwnd - Parent windows. This only be NULL if there is a synchronous
  315. error (an error that occurs immediately after a user action).
  316. If it is NULL, then we set it to foreground.
  317. pszTitle - Title of message box. Can be a resource ID i.e. MAKEINTRESOURCE(id)
  318. pszMessage - Message text. May have inserts. Can be a resource ID too.
  319. uType - Type of message box. See MessageBox api.
  320. dwLastError - 0 indicates don't cat error string onto end of message text
  321. kMsgGetLastError: Use GetLastError(). Other: format to LastError
  322. text.
  323. pMsgErrMap - Translate some error messages into friendlier text.
  324. May be NULL.
  325. idMessage - Help message ids to look for in the help message map.
  326. pHlpErrMap - Pointer to error message map where look, If a match
  327. is found in this map then the help button will be
  328. displayed on the message box. May be MULL
  329. ... extra parameters to idsMessage follow.
  330. Return Value:
  331. S_OK on success and COM error on failure
  332. --*/
  333. {
  334. TStatusB bStatus;
  335. TString strMappedMessage;
  336. TString strMsgTemplate;
  337. TString strMessage;
  338. TString strTitle;
  339. INT iResult = 0;
  340. BOOL bFormatNeeded = FALSE;
  341. MSG_HLPMAP *pHelpMapEntry = NULL;
  342. MSG_ERRMAP *pErrMapEntry = NULL;
  343. UINT idsTitle = IDS_NOT_MAPPED;
  344. UINT idsMessage = IDS_NOT_MAPPED;
  345. HRESULT hr = S_OK;
  346. if( NULL == hModule )
  347. {
  348. hModule = ghInst;
  349. }
  350. HINSTANCE hInstTitle = hModule,
  351. hInstMessage = hModule;
  352. if( NULL == pszTitle )
  353. {
  354. pszTitle = MAKEINTRESOURCE(IDS_PRINTERS_TITLE);
  355. hInstTitle = ghInst;
  356. }
  357. if( NULL == pszMessage )
  358. {
  359. pszMessage = MAKEINTRESOURCE(IDS_ERR_GENERIC);
  360. hInstMessage = ghInst;
  361. }
  362. // first load the title and format strings and
  363. // then format the string with any following aguments.
  364. if( SUCCEEDED(hr) && IS_INTRESOURCE(pszTitle) )
  365. {
  366. idsTitle = MAKERESOURCEINT(pszTitle);
  367. bStatus DBGCHK = strTitle.bLoadString(hInstTitle, idsTitle);
  368. pszTitle = strTitle;
  369. if( !bStatus )
  370. {
  371. hr = CreateError();
  372. }
  373. }
  374. if( SUCCEEDED(hr) && IS_INTRESOURCE(pszMessage) )
  375. {
  376. idsMessage = MAKERESOURCEINT(pszMessage);
  377. bStatus DBGCHK = strMsgTemplate.bLoadString(hInstMessage, idsMessage);
  378. pszMessage = strMsgTemplate;
  379. if( !bStatus )
  380. {
  381. hr = CreateError();
  382. }
  383. }
  384. if( SUCCEEDED(hr) )
  385. {
  386. bStatus DBGCHK = strMessage.bvFormat(pszMessage, valist);
  387. if( !bStatus )
  388. {
  389. hr = CreateError();
  390. }
  391. }
  392. if( SUCCEEDED(hr) )
  393. {
  394. // check to see if last error format is needed
  395. switch( dwLastError )
  396. {
  397. case kMsgGetLastError:
  398. //
  399. // Get the last error.
  400. //
  401. dwLastError = GetLastError();
  402. //
  403. // If for some reason there wasn't an error code, don't
  404. // append the error string.
  405. //
  406. bFormatNeeded = !!dwLastError;
  407. break;
  408. case kMsgNone:
  409. //
  410. // No format message needed.
  411. //
  412. bFormatNeeded = FALSE;
  413. break;
  414. default:
  415. //
  416. // Format needed, use provided error value.
  417. //
  418. bFormatNeeded = TRUE;
  419. break;
  420. }
  421. if( bFormatNeeded )
  422. {
  423. //
  424. // If there was a help message map passed then look up the id in this
  425. // help message map, note this call does not use the last error for finding a match
  426. //
  427. if( bLookupHelpMessageMap(pHlpErrMap, idHlpMessage, &pHelpMapEntry) )
  428. {
  429. //
  430. // Extract the message string from the resource file.
  431. //
  432. bStatus DBGCHK = strMappedMessage.bLoadString(ghInst, pHelpMapEntry->uIdMessage);
  433. //
  434. // Indicate the message box should have the help button on it.
  435. //
  436. uType |= MB_HELP;
  437. }
  438. //
  439. // If there was not a remapped message then lookup this error value
  440. // to see if this message has help remapped to it.
  441. //
  442. else if( bLookupHelpMessageMap( gMsgHelpTable, dwLastError, &pHelpMapEntry ) )
  443. {
  444. //
  445. // Extract the message string from the resource file.
  446. //
  447. bStatus DBGCHK = strMappedMessage.bLoadString(ghInst, pHelpMapEntry->uIdMessage);
  448. //
  449. // Indicate the message box should have the help button on it.
  450. //
  451. uType |= MB_HELP;
  452. }
  453. //
  454. // Check if this last error has a remapped message in the provided message map.
  455. //
  456. else if( bLookupErrorMessageMap( pMsgErrMap, dwLastError, &pErrMapEntry ) )
  457. {
  458. //
  459. // Extract the message string from the resource file.
  460. //
  461. bStatus DBGCHK = strMappedMessage.bLoadString(ghInst, pErrMapEntry->idsString);
  462. }
  463. //
  464. // Check if this last error is a known error or the error code is pretty
  465. // useless for the end users (like "Invalid Handle"), so we need to re-map
  466. // the text to a generic error message.
  467. //
  468. else if( bLookupErrorMessageMap( gGlobalErrorMapTable, dwLastError, &pErrMapEntry ) )
  469. {
  470. if( CMsgBoxCounter::GetMsg() )
  471. {
  472. // we have a message ID set based on the context where command
  473. // gets executed - use this message ID instead the defaults
  474. bStatus DBGCHK = strMappedMessage.bLoadString(ghInst, CMsgBoxCounter::GetMsg());
  475. }
  476. else if( IDS_NOT_MAPPED == pErrMapEntry->idsString )
  477. {
  478. //
  479. // The error text, which is coming from the GetLastError/FormatMessage
  480. // APIs is good enough for this error, so we are going to use it. Just get
  481. // the error string from the FormatMessage API.
  482. //
  483. TResult result(dwLastError);
  484. if( VALID_OBJ(result) )
  485. {
  486. bStatus DBGCHK = result.bGetErrorString(strMappedMessage);
  487. }
  488. }
  489. else
  490. {
  491. //
  492. // This error message is re-mapped to a better text. - Just
  493. // load the re-mapped message string from the resource file.
  494. //
  495. bStatus DBGCHK = strMappedMessage.bLoadString(ghInst, pErrMapEntry->idsString);
  496. }
  497. }
  498. else
  499. {
  500. if( IDS_ERR_GENERIC != idsMessage )
  501. {
  502. //
  503. // This error code is unknown or useless to be displayed
  504. // to the end user. Just load the generic error text string
  505. // in this case.
  506. //
  507. bStatus DBGCHK = strMappedMessage.bLoadString(ghInst, IDS_ERR_GENERIC);
  508. }
  509. }
  510. if( !bStatus )
  511. {
  512. hr = CreateError();
  513. }
  514. if( SUCCEEDED(hr) && !strMappedMessage.bEmpty() )
  515. {
  516. //
  517. // Tack on the mapped, help or error string, with a two space separator.
  518. //
  519. bStatus DBGCHK = strMessage.bCat(TEXT(" ")) &&
  520. strMessage.bCat(strMappedMessage);
  521. if( !bStatus )
  522. {
  523. hr = E_OUTOFMEMORY;
  524. }
  525. }
  526. }
  527. // if succeeded - show up the message box
  528. if( SUCCEEDED(hr) )
  529. {
  530. if( FAILED(GetCurrentThreadLastPopup(&hwnd)) )
  531. {
  532. // if the parent is going to be NULL then push in foreground
  533. uType |= MB_SETFOREGROUND;
  534. }
  535. // display the message box.
  536. iResult = PrintUIMessageBox(hwnd, strMessage, pszTitle, uType, UtilHelpCallback, pHelpMapEntry);
  537. // log this messsage into the message box counter
  538. CMsgBoxCounter::LogMessage(uType);
  539. }
  540. }
  541. if( SUCCEEDED(hr) && piResult )
  542. {
  543. *piResult = iResult;
  544. }
  545. return hr;
  546. }
  547. BOOL
  548. WINAPI
  549. UtilHelpCallback(
  550. IN HWND hwnd,
  551. IN PVOID pVoid
  552. )
  553. /*++
  554. Routine Name:
  555. UtilHelpCallback
  556. Routine Description:
  557. This routine is the called back that is called when a
  558. message box is displayed with a help button and the user
  559. clicks on the help button.
  560. Arguments:
  561. hwnd - handle to windows that recieved the WM_HELP message.
  562. pVoid - pointer to the user data passsed in the call to
  563. PrintUIMessageBox. The client can store any value
  564. in this paramter.
  565. Return Value:
  566. TRUE callback was successful, FALSE some error occurred.
  567. --*/
  568. {
  569. DBGMSG( DBG_TRACE, ( "UtilHelpCallback\n") );
  570. //
  571. // Get a usable pointer to the help map entry.
  572. //
  573. MSG_HLPMAP *pHelpMapEntry = reinterpret_cast<MSG_HLPMAP *>( pVoid );
  574. if (pHelpMapEntry)
  575. {
  576. //
  577. // Invoke troubleshooter for this topic
  578. //
  579. DWORD_PTR dwRet = (DWORD_PTR)ShellExecute(hwnd, gszOpen,
  580. TEXT("helpctr.exe"),
  581. pHelpMapEntry->pszHelpFile,
  582. NULL,
  583. SW_SHOWNORMAL);
  584. return dwRet > 32;
  585. }
  586. else
  587. {
  588. DBGMSG( DBG_ERROR, ( "UtilHelpCallback (pVoid == NULL)\n") );
  589. return FALSE;
  590. }
  591. }
  592. VOID
  593. vShowResourceError(
  594. HWND hwnd
  595. )
  596. {
  597. //
  598. // Show up the generic error message here.
  599. //
  600. vShowUnexpectedError(hwnd, IDS_PRINTERS_TITLE);
  601. }
  602. VOID
  603. vShowUnexpectedError(
  604. HWND hwnd,
  605. UINT idsTitle
  606. )
  607. {
  608. iMessage( hwnd,
  609. idsTitle,
  610. IDS_ERR_GENERIC,
  611. MB_OK|MB_ICONSTOP|MB_SETFOREGROUND,
  612. kMsgGetLastError,
  613. NULL );
  614. }
  615. VOID
  616. vPrinterSplitFullName(
  617. IN LPTSTR pszScratch,
  618. IN LPCTSTR pszFullName,
  619. IN LPCTSTR *ppszServer,
  620. IN LPCTSTR *ppszPrinter
  621. )
  622. /*++
  623. Routine Description:
  624. Splits a fully qualified printer connection name into server and
  625. printer name parts.
  626. Arguments:
  627. pszScratch - Scratch buffer used to store output strings. Must
  628. be MAXNAMELENBUFFER in size.
  629. pszFullName - Input name of a printer. If it is a printer
  630. connection (\\server\printer), then we will split it. If
  631. it is a true local printer (not a masq) then the server is
  632. szNULL.
  633. ppszServer - Receives pointer to the server string. If it is a
  634. local printer, szNULL is returned.
  635. ppszPrinter - Receives a pointer to the printer string. OPTIONAL
  636. Return Value:
  637. --*/
  638. {
  639. LPTSTR pszPrinter;
  640. lstrcpyn(pszScratch, pszFullName, kPrinterBufMax);
  641. if (pszFullName[0] != TEXT('\\') || pszFullName[1] != TEXT('\\'))
  642. {
  643. //
  644. // Set *ppszServer to szNULL since it's the local machine.
  645. //
  646. *ppszServer = gszNULL;
  647. pszPrinter = pszScratch;
  648. }
  649. else
  650. {
  651. *ppszServer = pszScratch;
  652. pszPrinter = _tcschr(*ppszServer + 2, TEXT('\\'));
  653. if (!pszPrinter)
  654. {
  655. //
  656. // We've encountered a printer called "\\server"
  657. // (only two backslashes in the string). We'll treat
  658. // it as a local printer. We should never hit this,
  659. // but the spooler doesn't enforce this. We won't
  660. // format the string. Server is local, so set to szNULL.
  661. //
  662. pszPrinter = pszScratch;
  663. *ppszServer = gszNULL;
  664. }
  665. else
  666. {
  667. //
  668. // We found the third backslash; null terminate our
  669. // copy and set bRemote TRUE to format the string.
  670. //
  671. *pszPrinter++ = 0;
  672. }
  673. }
  674. if (ppszPrinter)
  675. {
  676. *ppszPrinter = pszPrinter;
  677. }
  678. }
  679. BOOL
  680. bBuildFullPrinterName(
  681. IN LPCTSTR pszServer,
  682. IN LPCTSTR pszPrinterName,
  683. IN TString &strFullName
  684. )
  685. /*++
  686. Routine Description:
  687. Builds a fully qualified printer name from a server name
  688. and a printer name.
  689. Arguments:
  690. pszServer - Pointer to server name, if this parameter is null
  691. the machine name is used. If this parameter is non
  692. null it is assumed it is a server name of the form
  693. \\server including the leading wacks.
  694. pszPrinterName - Pointer to printer name. This parameter must be a
  695. a valid string.
  696. strFullName - Reference where to return full printer name.
  697. Return Value:
  698. TRUE strFullName contains a full printer name, FALSE error.
  699. --*/
  700. {
  701. SPLASSERT( pszPrinterName );
  702. TStatusB bStatus;
  703. bStatus DBGNOCHK = TRUE;
  704. bStatus DBGCHK = strFullName.bUpdate( NULL );
  705. //
  706. // If the printer name is already fully qualified then do
  707. // not prepend the server name.
  708. //
  709. if( bStatus && *(pszPrinterName+0) != TEXT('\\') && *(pszPrinterName+1) != TEXT('\\') )
  710. {
  711. //
  712. // If the server name is null, get the current machine name.
  713. //
  714. if( !pszServer || !*pszServer )
  715. {
  716. bStatus DBGCHK = bGetMachineName( strFullName, FALSE );
  717. }
  718. else
  719. {
  720. bStatus DBGCHK = strFullName.bUpdate( pszServer );
  721. }
  722. //
  723. // Append the wack separator.
  724. //
  725. if( bStatus )
  726. {
  727. bStatus DBGCHK = strFullName.bCat( gszWack );
  728. }
  729. }
  730. //
  731. // Append the printer name or copy the already fully qualified printer name.
  732. //
  733. if( bStatus )
  734. {
  735. bStatus DBGCHK = strFullName.bCat( pszPrinterName );
  736. }
  737. return bStatus;
  738. }
  739. /*++
  740. bGetMachineName
  741. Routine Description:
  742. Get the machine name if the local machine.
  743. Arguments:
  744. String to return machine name.
  745. Flag TRUE do not add leading slashes, FALSE add leading slashes.
  746. Return Value:
  747. TRUE machine name returned.
  748. --*/
  749. BOOL
  750. bGetMachineName(
  751. IN OUT TString &strMachineName,
  752. IN BOOL bNoLeadingSlashes
  753. )
  754. {
  755. TCHAR szBuffer[2 + MAX_COMPUTERNAME_LENGTH + 1];
  756. DWORD dwBufferSize;
  757. BOOL bStatus = FALSE;
  758. DWORD dwSizeAdjust = 0;
  759. //
  760. // Prepend with the wack wack.
  761. //
  762. if( !bNoLeadingSlashes ){
  763. szBuffer[0] = TEXT( '\\' );
  764. szBuffer[1] = TEXT( '\\' );
  765. dwSizeAdjust = 2;
  766. }
  767. //
  768. // Get the computer name.
  769. //
  770. dwBufferSize = COUNTOF( szBuffer ) - dwSizeAdjust;
  771. if( GetComputerName( szBuffer+dwSizeAdjust, &dwBufferSize ) ){
  772. bStatus = strMachineName.bUpdate( szBuffer );
  773. }
  774. return bStatus;
  775. }
  776. /*++
  777. NewFriendlyName
  778. Routine Description:
  779. Create a new (and unique) friendly name
  780. Arguments:
  781. pszServerName - print server name
  782. lpBaseName - base printer name
  783. lpNewName - new printer name is base name is not unique
  784. pwInstance - [in,out],
  785. if NULL (this is by default) then:
  786. [in] - assume instance equals to zero
  787. [out] - <NA> (don't care)
  788. if not NULL then:
  789. [in] - instance to start from
  790. [out] - instance choosen
  791. Return Value:
  792. TRUE if lpFriendlyName recevies new unique name, FALSE if not
  793. --*/
  794. BOOL
  795. NewFriendlyName(
  796. IN LPCTSTR pszServerName,
  797. IN LPCTSTR lpBaseName,
  798. IN LPTSTR lpNewName,
  799. IN OUT WORD *pwInstance
  800. )
  801. {
  802. TCHAR szTestName[kPrinterBufMax];
  803. WORD wCount = 0;
  804. DWORD cPrinterInfo2 = 0;
  805. DWORD cbPrinterInfo2 = 0;
  806. PRINTER_INFO_2 *pPrinterInfo2 = NULL;
  807. BOOL bStatus = FALSE;
  808. TStatusB bEnumStatus;
  809. if( pwInstance ){
  810. wCount = *pwInstance;
  811. }
  812. //
  813. // Enumerate the current printers.
  814. //
  815. bEnumStatus DBGCHK = VDataRefresh::bEnumPrinters(
  816. PRINTER_ENUM_NAME,
  817. (LPTSTR)pszServerName,
  818. 2,
  819. (PVOID *)&pPrinterInfo2,
  820. &cbPrinterInfo2,
  821. &cPrinterInfo2 );
  822. //
  823. // Failure enumerating printers.
  824. //
  825. if( !bEnumStatus ){
  826. DBGMSG( DBG_WARN, ( "Error enumerating printers.\n" ) );
  827. bStatus = FALSE;
  828. goto Cleanup;
  829. }
  830. //
  831. // Set upper limit of 1000 tries, just to avoid hanging forever
  832. //
  833. bStatus = FALSE;
  834. for( ; wCount < 1000; wCount++ ){
  835. if( CreateUniqueName( szTestName, COUNTOF(szTestName), lpBaseName, wCount )){
  836. LPCTSTR pszName;
  837. BOOL bFound = FALSE;
  838. for ( UINT i = 0; i < cPrinterInfo2; i++ ){
  839. pszName = pPrinterInfo2[i].pPrinterName;
  840. //
  841. // Strip the server name if not the local machine.
  842. //
  843. if( pszServerName ){
  844. if( pszName[0] == TEXT( '\\' ) &&
  845. pszName[1] == TEXT( '\\' ) ){
  846. pszName = _tcschr( &pszName[2], TEXT( '\\' ) );
  847. if( !pszName ){
  848. pszName = pPrinterInfo2[i].pPrinterName;
  849. } else {
  850. pszName += 1;
  851. }
  852. }
  853. }
  854. //
  855. // If name matches indicate found and continue trying to
  856. // create a unique name.
  857. //
  858. if( !lstrcmpi( szTestName, pszName ) ){
  859. bFound = TRUE;
  860. break;
  861. }
  862. //
  863. // Check if there is a printer share name that matches and
  864. // if so continue trying to create a unique name.
  865. //
  866. if( pPrinterInfo2[i].pShareName &&
  867. pPrinterInfo2[i].pShareName[0] &&
  868. !lstrcmpi( szTestName, pPrinterInfo2[i].pShareName ) ){
  869. bFound = TRUE;
  870. break;
  871. }
  872. }
  873. //
  874. // If a unique name was found and this was not the
  875. // first time trough the loop copy the new unique name
  876. // to the provided buffer.
  877. //
  878. if( bFound == FALSE ) {
  879. if( wCount != 0 ){
  880. lstrcpyn( lpNewName, szTestName, kPrinterBufMax );
  881. bStatus = TRUE;
  882. }
  883. break;
  884. }
  885. }
  886. }
  887. //
  888. // Insure we clean up.
  889. //
  890. Cleanup:
  891. if( pPrinterInfo2 ){
  892. DBGMSG( DBG_TRACE, ( "Releaseing printer info 2 memory.\n" ) );
  893. FreeMem( pPrinterInfo2 );
  894. }
  895. if( pwInstance ){
  896. *pwInstance = wCount;
  897. }
  898. return bStatus;
  899. }
  900. /*++
  901. CreateUniqueName
  902. Routine Description:
  903. Create a unique friendly name for this printer. If wInstance
  904. is 0, just copy the name over. Otherwise, play some games
  905. with truncating the name so it will fit.
  906. Arguments:
  907. lpDest - destination buffer
  908. cchMaxChars - max number of chars in lpDest
  909. lpBaseName - base printer name
  910. wInstance - the instance number
  911. Return Value:
  912. TRUE if we created a name, FALSE if something went wrong
  913. Note:
  914. This code is from msprint2.dll! we should match their naming scheme.
  915. --*/
  916. BOOL
  917. CreateUniqueName(
  918. IN LPTSTR lpDest,
  919. IN UINT cchMaxChars,
  920. IN LPCTSTR lpBaseName,
  921. IN WORD wInstance
  922. )
  923. {
  924. BOOL bRet = FALSE;
  925. if (wInstance)
  926. {
  927. // We want to provide a fully localizable way to create a
  928. // unique friendly name for each instance. We start with
  929. // a single string from the resource, and call wsprintf
  930. // twice, getting something like this:
  931. //
  932. // "%%s (Copy %u)" From resource
  933. // "%s (Copy 2)" After first wsprintf
  934. // "Foobar Laser (Copy 2)" After second wsprintf
  935. //
  936. // We can't make a single wsprintf call, since it has no
  937. // concept of limiting the string size. We truncate the
  938. // model name (in a DBCS-aware fashion) to the appropriate
  939. // size, so the whole string fits in kPrinterBufMax bytes. This
  940. // may cause some name truncation, but only in cases where
  941. // the model name is extremely long.
  942. CAutoPtrArray<TCHAR> spszFormat1 = new TCHAR[kPrinterBufMax];
  943. CAutoPtrArray<TCHAR> spszFormat2 = new TCHAR[kPrinterBufMax];
  944. if (spszFormat1 && spszFormat2)
  945. {
  946. if (LoadString(ghInst, IDS_PRTPROP_UNIQUE_FORMAT, spszFormat1, kPrinterBufMax))
  947. {
  948. // wFormatLength is length of format string before inserting
  949. // the model name. Subtract 2 to remove the "%s", and add
  950. // 1 to compensate for the terminating NULL, which is
  951. // counted in the total buffer length, but not the string length
  952. wnsprintf(spszFormat2, kPrinterBufMax, spszFormat1, wInstance);
  953. wnsprintf(lpDest, cchMaxChars, spszFormat2, lpBaseName);
  954. bRet = TRUE;
  955. }
  956. }
  957. else
  958. {
  959. // some of the allocations failed
  960. SetLastError(ERROR_OUTOFMEMORY);
  961. }
  962. }
  963. else
  964. {
  965. // if wInstance is zero then just copy lpBaseName to lpDest
  966. lstrcpyn(lpDest, lpBaseName, cchMaxChars);
  967. bRet = TRUE;
  968. }
  969. return bRet;
  970. }
  971. /*++
  972. bSplitPath
  973. Routine Description:
  974. splits a file path in to the path and file component.
  975. Arguments:
  976. pszScratch - pointer to sratch buffer, must be minimum max path.
  977. ppszFile - pointer where to return file pointer, may be null.
  978. ppszPath - pointer where to return path pointer, may be null.
  979. ppszExt - pointer where to return ext pointer, may be null.
  980. pszFull - pointer to fully qualified path\file
  981. Return Value:
  982. TRUE file and path part split.
  983. --*/
  984. BOOL
  985. bSplitPath(
  986. IN LPTSTR pszScratch,
  987. IN LPCTSTR *ppszFile,
  988. IN LPCTSTR *ppszPath,
  989. IN LPCTSTR *ppszExt,
  990. IN LPCTSTR pszFull
  991. )
  992. {
  993. SPLASSERT( pszScratch );
  994. SPLASSERT( pszFull );
  995. BOOL bStatus = FALSE;
  996. if( ppszFile )
  997. *ppszFile = NULL;
  998. if( ppszPath )
  999. *ppszPath = NULL;
  1000. if( ppszExt )
  1001. *ppszExt = NULL;
  1002. if( pszScratch && pszFull )
  1003. {
  1004. _tcscpy( pszScratch, pszFull );
  1005. //
  1006. // Full is of the form d:\test
  1007. //
  1008. LPTSTR pszFile = _tcsrchr( pszScratch, TEXT('\\') );
  1009. //
  1010. // Full is of the form d:test
  1011. //
  1012. if( !pszFile )
  1013. {
  1014. pszFile = _tcsrchr( pszScratch, TEXT(':') );
  1015. }
  1016. if( pszFile )
  1017. {
  1018. *pszFile++ = NULL;
  1019. //
  1020. // Locate the file extension.
  1021. //
  1022. if( ppszExt )
  1023. {
  1024. LPTSTR pszExt = _tcsrchr( pszFile, TEXT('.') );
  1025. if( pszExt )
  1026. {
  1027. *ppszExt = pszExt + 1;
  1028. }
  1029. }
  1030. if( ppszFile )
  1031. *ppszFile = pszFile;
  1032. if( ppszPath )
  1033. *ppszPath = pszScratch;
  1034. }
  1035. //
  1036. // Success.
  1037. //
  1038. bStatus = TRUE;
  1039. }
  1040. return bStatus;
  1041. }
  1042. /*++
  1043. bCopyMultizString
  1044. Routine Description:
  1045. Copies a multiz string.
  1046. Arguments:
  1047. ppszCopy - pointer where to return multiz string copy.
  1048. pszMultizString - pointer to multiz string.
  1049. Return Value:
  1050. TRUE success, FALSE copy multiz string failed, out of memory etc.
  1051. --*/
  1052. BOOL
  1053. bCopyMultizString(
  1054. IN LPTSTR *ppszMultizCopy,
  1055. IN LPCTSTR pszMultizString
  1056. )
  1057. {
  1058. SPLASSERT( ppszMultizCopy );
  1059. BOOL bStatus = TRUE;
  1060. if( pszMultizString )
  1061. {
  1062. //
  1063. // Calculate the length of the multiz string.
  1064. //
  1065. for( LPCTSTR psz = pszMultizString; psz && *psz; psz += _tcslen( psz ) + 1 );
  1066. UINT uSize = (UINT)(psz - pszMultizString) + 1;
  1067. if( uSize )
  1068. {
  1069. //
  1070. // Alocate the new multiz string.
  1071. //
  1072. *ppszMultizCopy = new TCHAR[uSize];
  1073. if( *ppszMultizCopy )
  1074. {
  1075. CopyMemory( *ppszMultizCopy, pszMultizString, uSize * sizeof( TCHAR ) );
  1076. }
  1077. else
  1078. {
  1079. bStatus = FALSE;
  1080. }
  1081. }
  1082. }
  1083. else
  1084. {
  1085. *ppszMultizCopy = NULL;
  1086. }
  1087. return bStatus;
  1088. }
  1089. /*++
  1090. Name:
  1091. vStripTrailWhiteSpace
  1092. Routine Description:
  1093. Strips trailing white space in a single forward scan.
  1094. Arguments:
  1095. pszString - Pointer to a null terminated string.
  1096. Return Value:
  1097. Nothing.
  1098. Notes:
  1099. The string is modified in place.
  1100. --*/
  1101. VOID
  1102. vStripTrailWhiteSpace(
  1103. IN LPTSTR pszString
  1104. )
  1105. {
  1106. for( LPTSTR pBlank = NULL; pszString && *pszString; ++pszString )
  1107. {
  1108. if( *pszString == TEXT(' ') )
  1109. pBlank = pBlank == NULL ? pszString : pBlank;
  1110. else
  1111. pBlank = NULL;
  1112. }
  1113. if( pBlank )
  1114. {
  1115. *pBlank = 0;
  1116. }
  1117. }
  1118. /*++
  1119. Routine Name:
  1120. bTrimString
  1121. Routine Description:
  1122. Trim the string pszTrimMe of any leading or trailing
  1123. characters that are in pszTrimChars.
  1124. Return Value:
  1125. TRUE if anything was stripped
  1126. --*/
  1127. BOOL
  1128. bTrimString(
  1129. IN OUT LPTSTR pszTrimMe,
  1130. IN LPCTSTR pszTrimChars
  1131. )
  1132. {
  1133. BOOL bRet = FALSE;
  1134. LPTSTR psz;
  1135. LPTSTR pszStartMeat;
  1136. LPTSTR pszMark = NULL;
  1137. SPLASSERT(pszTrimMe);
  1138. SPLASSERT(pszTrimChars);
  1139. if (pszTrimMe)
  1140. {
  1141. //
  1142. // Trim leading characters.
  1143. //
  1144. psz = pszTrimMe;
  1145. while (*psz && _tcschr(pszTrimChars, *psz))
  1146. psz++;
  1147. pszStartMeat = psz;
  1148. //
  1149. // Trim trailing characters.
  1150. //
  1151. while (*psz)
  1152. {
  1153. if (_tcschr(pszTrimChars, *psz))
  1154. {
  1155. if (!pszMark)
  1156. {
  1157. pszMark = psz;
  1158. }
  1159. }
  1160. else
  1161. {
  1162. pszMark = NULL;
  1163. }
  1164. psz++;
  1165. }
  1166. //
  1167. // Any trailing characters to clip?
  1168. //
  1169. if (pszMark)
  1170. {
  1171. *pszMark = '\0';
  1172. bRet = TRUE;
  1173. }
  1174. //
  1175. // Relocate stripped string.
  1176. //
  1177. if (pszStartMeat > pszTrimMe)
  1178. {
  1179. //
  1180. // (+ 1) for null terminator.
  1181. //
  1182. MoveMemory(pszTrimMe, pszStartMeat, (_tcslen(pszStartMeat) + 1) * sizeof(TCHAR));
  1183. bRet = TRUE;
  1184. }
  1185. else
  1186. {
  1187. SPLASSERT(pszStartMeat == pszTrimMe);
  1188. }
  1189. SPLASSERT(pszTrimMe);
  1190. }
  1191. return bRet;
  1192. }
  1193. /*++
  1194. Routine Name:
  1195. bIsRemote
  1196. Routine Description:
  1197. Determines if the specified name is a
  1198. remote machine or local machine name.
  1199. Arguments:
  1200. pszString - Pointer to string which contains the machine name.
  1201. Return Value:
  1202. TRUE machine name is a remote machine name, FALSE local machine name.
  1203. --*/
  1204. BOOL
  1205. bIsRemote(
  1206. IN LPCTSTR pszName
  1207. )
  1208. {
  1209. BOOL bRetval = FALSE;
  1210. //
  1211. // Null pointer or null string is assumed to be
  1212. // the local machine. (Spooler's definition)
  1213. //
  1214. if( !pszName || !*pszName )
  1215. {
  1216. return bRetval;
  1217. }
  1218. //
  1219. // Get the local machines name.
  1220. //
  1221. TString strLocalName;
  1222. if( !bGetMachineName( strLocalName, TRUE ) )
  1223. {
  1224. DBGMSG( DBG_ERROR, ("bIsRemote::bGetMachineName Failed!") );
  1225. return bRetval;
  1226. }
  1227. //
  1228. // If the provided name has leading '\\' then compare with
  1229. // '\\' else point to just after the '\\' and compare.
  1230. //
  1231. if( *(pszName+0) == TEXT('\\') && *(pszName+1) == TEXT('\\') )
  1232. {
  1233. pszName += 2;
  1234. }
  1235. //
  1236. // If the machine names are different then the provided
  1237. // name is assumed to be a remote machine.
  1238. //
  1239. if( _tcsicmp( pszName, strLocalName ) )
  1240. {
  1241. bRetval = TRUE;
  1242. }
  1243. return bRetval;
  1244. }
  1245. BOOL
  1246. bLookupErrorMessageMap(
  1247. IN const PMSG_ERRMAP pMsgErrMap,
  1248. IN DWORD dwLastError,
  1249. IN OUT MSG_ERRMAP **ppErrMapEntry
  1250. )
  1251. /*++
  1252. Routine Name:
  1253. bLookupErrorMessageMap
  1254. Routine Description:
  1255. Scanns the error message map for a matching
  1256. last error. If the message is found in the map
  1257. the string is returned in the specified string
  1258. mapped message object.
  1259. Arguments:
  1260. pMsgErrMap - pointer to error message map
  1261. dwLastError - last error to look for in error message map
  1262. ppErrMapEntry - pointer to error map entry where match was found
  1263. Return Value:
  1264. TRUE success, FALSE error occurred.
  1265. --*/
  1266. {
  1267. BOOL bStatus = FALSE;
  1268. //
  1269. // If there is a message map, use it.
  1270. //
  1271. if( pMsgErrMap )
  1272. {
  1273. for( UINT i = 0; pMsgErrMap[i].dwError; i++ )
  1274. {
  1275. //
  1276. // If we have a matching error, then return a pointer to this entry.
  1277. //
  1278. if( dwLastError == pMsgErrMap[i].dwError )
  1279. {
  1280. *ppErrMapEntry = &pMsgErrMap[i];
  1281. bStatus = TRUE;
  1282. break;
  1283. }
  1284. }
  1285. }
  1286. return bStatus;
  1287. }
  1288. BOOL
  1289. bLookupHelpMessageMap(
  1290. IN const PMSG_HLPMAP pMsgHlpMap,
  1291. IN DWORD dwLastError,
  1292. IN OUT MSG_HLPMAP **ppHelpMapEntry
  1293. )
  1294. /*++
  1295. Routine Name:
  1296. bLookupHelpMessageMap
  1297. Routine Description:
  1298. Scans the error message map for a matching
  1299. last error. If the message is found in the map
  1300. the string is returned in the specified string
  1301. object.
  1302. Arguments:
  1303. pMsgHlpMap - pointer to help error message map
  1304. dwLastError - last error to look for in error message map
  1305. ppHelpMapEntry - pointer to help map entry where match was found
  1306. Return Value:
  1307. TRUE success match found, FALSE error occurred.
  1308. --*/
  1309. {
  1310. BOOL bStatus = FALSE;
  1311. //
  1312. // If there is a message map, use it.
  1313. //
  1314. if( pMsgHlpMap )
  1315. {
  1316. for( UINT i = 0; pMsgHlpMap[i].dwError; i++ )
  1317. {
  1318. //
  1319. // If we have a matching error, then return a pointer to this entry.
  1320. //
  1321. if( dwLastError == pMsgHlpMap[i].dwError )
  1322. {
  1323. *ppHelpMapEntry = &pMsgHlpMap[i];
  1324. bStatus = TRUE;
  1325. break;
  1326. }
  1327. }
  1328. }
  1329. return bStatus;
  1330. }
  1331. BOOL
  1332. bGoodLastError(
  1333. IN DWORD dwLastError
  1334. )
  1335. /*++
  1336. Routine Description:
  1337. Checks if this is a good last error - i.e. has
  1338. a good real message associated with it.
  1339. Arguments:
  1340. dwLastError - the last error to check for
  1341. Return Value:
  1342. TRUE if good, FALSE if not good
  1343. --*/
  1344. {
  1345. MSG_ERRMAP *pErrMapEntry = NULL;
  1346. return bLookupErrorMessageMap( gGlobalErrorMapTable, dwLastError, &pErrMapEntry );
  1347. }
  1348. BOOL
  1349. StringA2W(
  1350. IN OUT LPWSTR *ppResult,
  1351. IN LPCSTR pString
  1352. )
  1353. /*++
  1354. Routine Description:
  1355. Convert an ansi string to a wide string returning
  1356. a pointer to a newly allocated string.
  1357. Arguments:
  1358. ppResult - pointer to where to return pointer to new wide string.
  1359. pString - pointer to ansi string.
  1360. Return Value:
  1361. TRUE success, FALSE error occurred.
  1362. --*/
  1363. {
  1364. SPLASSERT( ppResult || pString );
  1365. BOOL bReturn = FALSE;
  1366. INT iLen = ( strlen( pString ) + 1 ) * sizeof( WCHAR );
  1367. *ppResult = reinterpret_cast<LPWSTR>( AllocMem( iLen ) );
  1368. if( *ppResult )
  1369. {
  1370. if( MultiByteToWideChar( CP_ACP, 0, pString, -1, *ppResult, iLen ) )
  1371. {
  1372. bReturn = TRUE;
  1373. }
  1374. else
  1375. {
  1376. FreeMem( *ppResult );
  1377. *ppResult = NULL;
  1378. }
  1379. }
  1380. return bReturn;
  1381. }
  1382. BOOL
  1383. StringW2A(
  1384. IN OUT LPSTR *ppResult,
  1385. IN LPCWSTR pString
  1386. )
  1387. /*++
  1388. Routine Description:
  1389. Convert a wide string to and ansi string returning
  1390. a pointer to a newly allocated string.
  1391. Arguments:
  1392. ppResult - pointer to where to return pointer to new ansi string.
  1393. pString - pointer to wide string.
  1394. Return Value:
  1395. TRUE success, FALSE error occurred.
  1396. --*/
  1397. {
  1398. SPLASSERT( ppResult || pString );
  1399. BOOL bReturn = FALSE;
  1400. INT iLen = ( wcslen( pString ) + 1 ) * sizeof( CHAR );
  1401. *ppResult = reinterpret_cast<LPSTR>( AllocMem( iLen ) );
  1402. if( *ppResult )
  1403. {
  1404. if( WideCharToMultiByte( CP_ACP, 0, pString, -1, *ppResult, iLen, NULL, NULL ) )
  1405. {
  1406. bReturn = TRUE;
  1407. }
  1408. else
  1409. {
  1410. FreeMem( *ppResult );
  1411. *ppResult = NULL;
  1412. }
  1413. }
  1414. return bReturn;
  1415. }
  1416. /*++
  1417. Routine Description:
  1418. Centers a dialog relative to hwndContext
  1419. Arguments:
  1420. hwndToCenter - window handle of dialog to center
  1421. hwndContext - window handle of window to center with respect to
  1422. Return Value:
  1423. None.
  1424. --*/
  1425. VOID
  1426. CenterDialog(
  1427. IN HWND hwndToCenter,
  1428. IN HWND hwndContext
  1429. )
  1430. {
  1431. POINT point;
  1432. RECT rcContext, rcWindow;
  1433. LONG x, y, w, h;
  1434. LONG sx = GetSystemMetrics(SM_CXSCREEN);
  1435. LONG sy = GetSystemMetrics(SM_CYSCREEN);
  1436. point.x = point.y = 0;
  1437. if (hwndContext)
  1438. {
  1439. ClientToScreen(hwndContext, &point);
  1440. GetClientRect (hwndContext, &rcContext);
  1441. }
  1442. else
  1443. {
  1444. rcContext.top = rcContext.left = 0;
  1445. rcContext.right = sx;
  1446. rcContext.bottom = sy;
  1447. }
  1448. GetWindowRect (hwndToCenter, &rcWindow);
  1449. w = rcWindow.right - rcWindow.left + 1;
  1450. h = rcWindow.bottom - rcWindow.top + 1;
  1451. x = point.x + ((rcContext.right - rcContext.left + 1 - w) / 2);
  1452. y = point.y + ((rcContext.bottom - rcContext.top + 1 - h) / 2);
  1453. if (x + w > sx)
  1454. {
  1455. x = sx - w;
  1456. }
  1457. else if (x < 0)
  1458. {
  1459. x = 0;
  1460. }
  1461. if (y + h > sy)
  1462. {
  1463. y = sy - h;
  1464. }
  1465. else if (y < 0)
  1466. {
  1467. y = 0;
  1468. }
  1469. MoveWindow(hwndToCenter, x, y, w, h, FALSE);
  1470. }
  1471. /*++
  1472. Name:
  1473. GetDomainName
  1474. Routine Description:
  1475. Returns the DNS domain name where the current computer is located.
  1476. Arguments:
  1477. pstrDomainName - pointer to a string refrence where to return the domain name.
  1478. Return Value:
  1479. TRUE success, FALSE error occurred.
  1480. --*/
  1481. BOOL
  1482. GetDomainName(
  1483. OUT TString &strDomainName
  1484. )
  1485. {
  1486. static TString *g_pstrDomainName = NULL;
  1487. TStatusB bStatus;
  1488. bStatus DBGNOCHK = FALSE;
  1489. CCSLock::Locker CSL( *gpCritSec );
  1490. if( !g_pstrDomainName )
  1491. {
  1492. g_pstrDomainName = new TString;
  1493. if( VALID_PTR( g_pstrDomainName ) )
  1494. {
  1495. typedef DWORD (WINAPI *pfDsRoleGetPrimaryDomainInformation)( LPCTSTR, DSROLE_PRIMARY_DOMAIN_INFO_LEVEL, PBYTE * );
  1496. typedef VOID (WINAPI *pfDsRoleFreeMemory)( PVOID );
  1497. TLibrary Lib( gszNetApiLibrary );
  1498. //
  1499. // Check if the netapi library was loaded.
  1500. //
  1501. bStatus DBGNOCHK = VALID_OBJ( Lib );
  1502. if (bStatus)
  1503. {
  1504. pfDsRoleGetPrimaryDomainInformation pfGetPrimrayDomainInformation = reinterpret_cast<pfDsRoleGetPrimaryDomainInformation>( Lib.pfnGetProc( "DsRoleGetPrimaryDomainInformation" ) );
  1505. pfDsRoleFreeMemory pfFreeMemory = reinterpret_cast<pfDsRoleFreeMemory>( Lib.pfnGetProc( "DsRoleFreeMemory" ) );
  1506. if( pfGetPrimrayDomainInformation && pfFreeMemory )
  1507. {
  1508. DWORD dwStatus = ERROR_SUCCESS;
  1509. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pDsRole = NULL;
  1510. dwStatus = pfGetPrimrayDomainInformation(NULL, DsRolePrimaryDomainInfoBasic, (PBYTE *)&pDsRole);
  1511. if (dwStatus == ERROR_SUCCESS)
  1512. {
  1513. bStatus DBGCHK = g_pstrDomainName->bUpdate( pDsRole->DomainNameDns );
  1514. if( bStatus )
  1515. {
  1516. bStatus DBGCHK = strDomainName.bUpdate( *g_pstrDomainName );
  1517. }
  1518. }
  1519. if (pDsRole)
  1520. {
  1521. pfFreeMemory((PVOID) pDsRole);
  1522. }
  1523. }
  1524. }
  1525. }
  1526. }
  1527. else
  1528. {
  1529. bStatus DBGCHK = strDomainName.bUpdate( *g_pstrDomainName );
  1530. }
  1531. DBGMSG( DBG_TRACE, ( "GetDomainName " TSTR "\n", DBGSTR((LPCTSTR)*g_pstrDomainName) ) );
  1532. return bStatus;
  1533. }
  1534. /*++
  1535. Name:
  1536. AreWeOnADomain
  1537. Routine Description:
  1538. Returns whether we are on a domain.
  1539. Arguments:
  1540. pbOnDomain - If TRUE, we are on a domain.
  1541. Return Value:
  1542. TRUE success, FALSE error occurred.
  1543. --*/
  1544. BOOL
  1545. AreWeOnADomain(
  1546. OUT BOOL *pbOnDomain
  1547. )
  1548. {
  1549. typedef DWORD (WINAPI *pfDsRoleGetPrimaryDomainInformation)( LPCTSTR, DSROLE_PRIMARY_DOMAIN_INFO_LEVEL, PBYTE * );
  1550. typedef VOID (WINAPI *pfDsRoleFreeMemory)( PVOID );
  1551. BOOL bOnDomain = FALSE;
  1552. TStatusB bStatus;
  1553. TLibrary Lib(gszNetApiLibrary);
  1554. //
  1555. // Check if the netapi library was loaded.
  1556. //
  1557. bStatus DBGNOCHK = VALID_OBJ( Lib );
  1558. if (bStatus)
  1559. {
  1560. pfDsRoleGetPrimaryDomainInformation pfGetPrimrayDomainInformation = NULL;
  1561. pfDsRoleFreeMemory pfFreeMemory = NULL;
  1562. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pDsRole = NULL;
  1563. pfGetPrimrayDomainInformation = reinterpret_cast<pfDsRoleGetPrimaryDomainInformation>(Lib.pfnGetProc("DsRoleGetPrimaryDomainInformation"));
  1564. pfFreeMemory = reinterpret_cast<pfDsRoleFreeMemory>(Lib.pfnGetProc("DsRoleFreeMemory"));
  1565. bStatus DBGCHK = pfGetPrimrayDomainInformation && pfFreeMemory;
  1566. if (bStatus)
  1567. {
  1568. DWORD dwStatus = pfGetPrimrayDomainInformation(NULL, DsRolePrimaryDomainInfoBasic, (PBYTE *)&pDsRole);
  1569. if (dwStatus)
  1570. {
  1571. SetLastError(dwStatus);
  1572. bStatus DBGCHK = FALSE;
  1573. }
  1574. }
  1575. if (bStatus)
  1576. {
  1577. bOnDomain = pDsRole->MachineRole == DsRole_RoleMemberWorkstation ||
  1578. pDsRole->MachineRole == DsRole_RoleMemberServer ||
  1579. pDsRole->MachineRole == DsRole_RoleBackupDomainController ||
  1580. pDsRole->MachineRole == DsRole_RolePrimaryDomainController;
  1581. }
  1582. if (pDsRole)
  1583. {
  1584. pfFreeMemory(pDsRole);
  1585. }
  1586. }
  1587. *pbOnDomain = bOnDomain;
  1588. return bStatus;
  1589. }
  1590. BOOL
  1591. ConstructPrinterFriendlyName(
  1592. IN LPCTSTR pszFullPrinter,
  1593. IN OUT LPTSTR pszPrinterBuffer,
  1594. IN OUT UINT *pcchSize
  1595. )
  1596. /*++
  1597. Routine Description:
  1598. Returns printer name formatted like "printer on server." if the provided
  1599. printer name is fully qualified, else it just returns the passed in
  1600. printer name.
  1601. Arguments:
  1602. pszPrinter - pointer to printer name, if fully qualified the
  1603. name is formatted to printer on server, if not a
  1604. fully qualified name then the printer name is not
  1605. altered.
  1606. pszPrinterBuffer - Output buffer to receive the printer name. May be
  1607. NULL of the caller want only the size of the buffer
  1608. returned.
  1609. pcchSize - pointer to a variable that specifies the size
  1610. in characters of pszPrinterBuffer includeing the
  1611. null terminator.
  1612. Return Value:
  1613. TRUE success, FALSE error occurred.
  1614. --*/
  1615. {
  1616. LPCTSTR pszServer;
  1617. LPCTSTR pszPrinter;
  1618. LPCTSTR pszFriendly;
  1619. TString strPrinter;
  1620. TStatusB bStatus;
  1621. TCHAR szScratch[kPrinterBufMax];
  1622. //
  1623. // Validate the printer name and buffer pointer size.
  1624. //
  1625. if( pszFullPrinter && pcchSize )
  1626. {
  1627. //
  1628. // Split the printer name into its components.
  1629. //
  1630. vPrinterSplitFullName( szScratch, pszFullPrinter, &pszServer, &pszPrinter );
  1631. //
  1632. // If this printer has a server name component then construct a
  1633. // 'printer on server' friendly name.
  1634. //
  1635. if( pszServer && *pszServer )
  1636. {
  1637. //
  1638. // Strip the leading slashes.
  1639. //
  1640. if( *(pszServer+0) == _T('\\') && *(pszServer+1) == _T('\\') )
  1641. {
  1642. pszServer = pszServer + 2;
  1643. }
  1644. bStatus DBGCHK = bConstructMessageString( ghInst, strPrinter, IDS_DSPTEMPLATE_WITH_ON, pszPrinter, pszServer );
  1645. if( bStatus )
  1646. {
  1647. pszFriendly = strPrinter;
  1648. }
  1649. }
  1650. else
  1651. {
  1652. //
  1653. // Just use the current printer name if it is not fully qualified.
  1654. //
  1655. bStatus DBGNOCHK = TRUE;
  1656. pszFriendly = pszFullPrinter;
  1657. }
  1658. if( bStatus )
  1659. {
  1660. UINT uFriendlySize = _tcslen( pszFriendly );
  1661. //
  1662. // If a buffer was provided then check if it is large enough to
  1663. // hold the friendly name. If it is large enough then copy the
  1664. // friendly name into it.
  1665. //
  1666. if( pszPrinterBuffer && ( *pcchSize > uFriendlySize ) )
  1667. {
  1668. _tcscpy( pszPrinterBuffer, pszFriendly );
  1669. }
  1670. else
  1671. {
  1672. bStatus DBGNOCHK = FALSE;
  1673. SetLastError( ERROR_INSUFFICIENT_BUFFER );
  1674. }
  1675. //
  1676. // Return the friendly name size.
  1677. //
  1678. *pcchSize = uFriendlySize + 1;
  1679. }
  1680. }
  1681. else
  1682. {
  1683. bStatus DBGNOCHK = FALSE;
  1684. SetLastError( ERROR_INVALID_PARAMETER );
  1685. }
  1686. return bStatus;
  1687. }
  1688. BOOL
  1689. WINAPIV
  1690. bConstructMessageString(
  1691. IN HINSTANCE hInst,
  1692. IN TString &strString,
  1693. IN INT iResId,
  1694. IN ...
  1695. )
  1696. /*++
  1697. Routine Description:
  1698. This routine formats the specified string using a format string.
  1699. The format string is extracted from the resouce file using the
  1700. passed in resouce id. The format is of the form required by
  1701. FormatMessage API. See FormatMessage for more details.
  1702. Arguments:
  1703. hInst - Instance handle where resource is loaded.
  1704. strString - Place to return resultant formatted string,
  1705. iResId - Format string resource id.
  1706. .. - Variable number of arguments
  1707. Return Value:
  1708. TRUE success, FALSE if error occurred.
  1709. --*/
  1710. {
  1711. LPTSTR pszRet = NULL;
  1712. DWORD dwBytes = 0;
  1713. TString strRes;
  1714. TStatusB bStatus;
  1715. va_list pArgs;
  1716. //
  1717. // Load the resource string.
  1718. //
  1719. bStatus DBGCHK = strRes.bLoadString( hInst, iResId );
  1720. if( bStatus )
  1721. {
  1722. va_start( pArgs, iResId );
  1723. //
  1724. // Format the message.
  1725. //
  1726. dwBytes = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
  1727. strRes,
  1728. 0,
  1729. 0,
  1730. (LPTSTR)&pszRet,
  1731. 0,
  1732. &pArgs );
  1733. va_end( pArgs );
  1734. //
  1735. // If the number of bytes is non zero the API formatted the
  1736. // string.
  1737. //
  1738. if( dwBytes )
  1739. {
  1740. //
  1741. // Update the return string object.
  1742. //
  1743. bStatus DBGCHK = strString.bUpdate( pszRet );
  1744. //
  1745. // Release the formated string.
  1746. //
  1747. if( pszRet )
  1748. {
  1749. LocalFree(pszRet);
  1750. }
  1751. }
  1752. else
  1753. {
  1754. bStatus DBGNOCHK = FALSE;
  1755. }
  1756. }
  1757. return bStatus;
  1758. }
  1759. BOOL
  1760. bIsLocalPrinterNameValid(
  1761. IN LPCTSTR pszPrinter
  1762. )
  1763. /*++
  1764. Routine Description:
  1765. This routine checks if the specified local printer name contains
  1766. any illegal characters. Note the spooler also inforces the illegal
  1767. characters but doing the check in the UI code is more efficent and
  1768. nicer to the user, rather than having to call add printer with a
  1769. printer name that is invalid.
  1770. Arguments:
  1771. pszPrinter - pointer to local printer name
  1772. Return Value:
  1773. TRUE printer name is valid, FALSE name contains illegal character
  1774. --*/
  1775. {
  1776. BOOL bRetval = TRUE;
  1777. //
  1778. // Check if the name has any illegal characters.
  1779. //
  1780. for( LPCTSTR p = pszPrinter; p && *p; p++ )
  1781. {
  1782. if( *p == TEXT( ',' ) || *p == TEXT( '!' ) || *p == TEXT( '\\' ) )
  1783. {
  1784. bRetval = FALSE;
  1785. break;
  1786. }
  1787. }
  1788. return bRetval;
  1789. }
  1790. BOOL
  1791. CheckRestrictions(
  1792. IN HWND hwnd,
  1793. IN RESTRICTIONS rest
  1794. )
  1795. /*++
  1796. Routine Description:
  1797. Verify the resrtictions of the explorer policies
  1798. Arguments:
  1799. hwnd - Handle to the parent window
  1800. rest - Restriction to check.
  1801. Return Value:
  1802. TRUE - Restriction apply
  1803. FALSE - Not restrcited
  1804. --*/
  1805. {
  1806. if (SHRestricted(rest))
  1807. {
  1808. iMessage( hwnd,
  1809. IDS_RESTRICTIONSTITLE,
  1810. IDS_RESTRICTIONS,
  1811. MB_OK|MB_ICONSTOP,
  1812. kMsgNone,
  1813. NULL );
  1814. return TRUE;
  1815. }
  1816. return FALSE;
  1817. }
  1818. VOID
  1819. vAdjustHeaderColumns(
  1820. IN HWND hwndLV,
  1821. IN UINT uColumnsCount,
  1822. IN UINT uPercentages[]
  1823. )
  1824. /*++
  1825. Routine Description:
  1826. Adjusts the columns to a certan percentages
  1827. in a list view
  1828. Arguments:
  1829. hwndLV - Handle to a list view control
  1830. uColumnsCount - Number of columns
  1831. uPercentages - The percentage of the total width
  1832. each column will take. 100 == SUM(uPercentages)
  1833. Return Value:
  1834. None
  1835. --*/
  1836. {
  1837. //
  1838. // Calculate the header column width.
  1839. //
  1840. RECT rc;
  1841. DWORD Interval = 20; // why not
  1842. if( GetClientRect( hwndLV, &rc ))
  1843. {
  1844. Interval = rc.right;
  1845. }
  1846. for( UINT iCol = 0; iCol < uColumnsCount; ++iCol )
  1847. {
  1848. ListView_SetColumnWidth( hwndLV, iCol, (Interval * uPercentages[iCol]) / 100 );
  1849. }
  1850. }
  1851. VOID
  1852. LoadPrinterIcons(
  1853. IN LPCTSTR pszPrinterName,
  1854. OUT HICON *phLargeIcon,
  1855. OUT HICON *phSmallIcon
  1856. )
  1857. /*++
  1858. Routine Description:
  1859. Loads a printer icon with the requested size.
  1860. Arguments:
  1861. IN pszPrinterName - the printer name of the printer we want icon for
  1862. OUT phLargeIcon - where to put the large icon
  1863. OUT phSmallIcon - where to put the small icon
  1864. Return Value:
  1865. --*/
  1866. {
  1867. // invoke shell to do the right thing
  1868. Printer_LoadIcons(pszPrinterName, phLargeIcon, phSmallIcon);
  1869. }
  1870. BOOL
  1871. CommandConfirmationPurge(
  1872. IN HWND hwnd,
  1873. IN LPCTSTR pszPrinterName
  1874. )
  1875. /*++
  1876. Routine Description:
  1877. Dispalys confirmation message box for the purge command.
  1878. Arguments:
  1879. Return Value:
  1880. TRUE user wants to execute command, FALSE cancel.
  1881. --*/
  1882. {
  1883. TCHAR szText[kStrMax+kPrinterBufMax] = {0};
  1884. UINT nSize = COUNTOF( szText );
  1885. //
  1886. // Build the printer status string.
  1887. //
  1888. ConstructPrinterFriendlyName(pszPrinterName, szText, &nSize);
  1889. return iMessage( hwnd,
  1890. IDS_PRINTERS_TITLE,
  1891. IDS_PRINTER_SUREPURGE,
  1892. MB_YESNO|MB_ICONQUESTION,
  1893. kMsgNone,
  1894. NULL,
  1895. szText ) == IDYES;
  1896. }
  1897. /********************************************************************
  1898. Functions specific for the RTL (right-to-left) locales.
  1899. For more information about how this function works
  1900. contact SamerA.
  1901. ********************************************************************/
  1902. BOOL
  1903. IsRTLLocale(
  1904. LCID iLCID
  1905. )
  1906. /*++
  1907. Routine Description:
  1908. Check if a particular locale is RTL (right-to-left)
  1909. locale
  1910. Arguments:
  1911. iLCID - Locale to check
  1912. Return Value:
  1913. TRUE - The locale is RTL locale
  1914. FALSE - Oterwise
  1915. --*/
  1916. {
  1917. //
  1918. // Length of font signature string
  1919. //
  1920. #define MAX_FONTSIGNATURE 16
  1921. WORD wLCIDFontSignature[MAX_FONTSIGNATURE];
  1922. BOOL bRet = FALSE;
  1923. //
  1924. // Verify that this is an RTL (BiDi) locale. Call GetLocaleInfo with
  1925. // LOCALE_FONTSIGNATURE which always gives back 16 WORDs.
  1926. //
  1927. if( GetLocaleInfo( iLCID,
  1928. LOCALE_FONTSIGNATURE,
  1929. (LPTSTR )&wLCIDFontSignature,
  1930. (sizeof(wLCIDFontSignature)/sizeof(wLCIDFontSignature[0]))))
  1931. {
  1932. //
  1933. // Verify the bits show a BiDi UI locale.
  1934. //
  1935. if( wLCIDFontSignature[7] & 0x0800 )
  1936. {
  1937. bRet = TRUE;
  1938. }
  1939. }
  1940. return bRet;
  1941. }
  1942. DWORD
  1943. dwDateFormatFlags(
  1944. HWND hWnd
  1945. )
  1946. /*++
  1947. Routine Description:
  1948. Build appropriate flags for GetDateFormat(...) API
  1949. depending on the current locale. Check if it is an
  1950. RTL locale.
  1951. Arguments:
  1952. hWnd - Window where the text will be drawn
  1953. Return Value:
  1954. The appropriate flags to be passed to
  1955. GetDateFormat(...)
  1956. --*/
  1957. {
  1958. DWORD dwFlags = 0;
  1959. //
  1960. // Check if the default locale is RTL locale
  1961. //
  1962. if( IsRTLLocale( GetUserDefaultLCID( ) ) )
  1963. {
  1964. //
  1965. // Check if this is a RTL (right-to-left) mirrored window
  1966. // or normal LTR window
  1967. //
  1968. if( GetWindowLong( hWnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL )
  1969. {
  1970. dwFlags |= DATE_RTLREADING;
  1971. }
  1972. else
  1973. {
  1974. dwFlags |= DATE_LTRREADING;
  1975. }
  1976. }
  1977. return dwFlags;
  1978. }
  1979. BOOL
  1980. bMatchTemplate(
  1981. IN LPCTSTR pszTemplate,
  1982. IN LPCTSTR pszText
  1983. )
  1984. /*++
  1985. Routine Description:
  1986. Simple template matching routine
  1987. Arguments:
  1988. pszTemplate - pointer to a simple template string
  1989. pszText - pointer to a text to match against the template
  1990. Return Value:
  1991. TRUE matched, FALSE not matched
  1992. --*/
  1993. {
  1994. int iLen = lstrlen(pszTemplate);
  1995. if( iLen != lstrlen(pszText) )
  1996. {
  1997. return FALSE;
  1998. }
  1999. TString strText, strTemplate;
  2000. if( strText.bUpdate(pszText) &&
  2001. strTemplate.bUpdate(pszTemplate) )
  2002. {
  2003. // convert to uppercase prior the matching
  2004. strText.vToUpper();
  2005. strTemplate.vToUpper();
  2006. for( int i = 0; i < iLen; i++ )
  2007. {
  2008. if( TEXT('?') == strTemplate[i] )
  2009. {
  2010. continue;
  2011. }
  2012. if( strTemplate[i] != strText[i] )
  2013. {
  2014. return FALSE;
  2015. }
  2016. }
  2017. }
  2018. else
  2019. {
  2020. // failed to allocate the strings
  2021. return FALSE;
  2022. }
  2023. return TRUE;
  2024. }
  2025. BOOL
  2026. bIsFaxPort(
  2027. IN LPCTSTR pszName,
  2028. IN LPCTSTR pszMonitor
  2029. )
  2030. /*++
  2031. Routine Description:
  2032. Determins if this port is a fax port. A fax
  2033. port is a port managed by the fax port monitor.
  2034. Arguments:
  2035. pszName - pointer to port name.
  2036. pszMonitor - pointer to port monitor.
  2037. Return Value:
  2038. TRUE port is a fax port, FALSE port is not a fax port.
  2039. --*/
  2040. {
  2041. // the monitor name can be null on downlevel servers.
  2042. return ((pszName && 0 == lstrcmp(pszName, FAX_MONITOR_PORT_NAME)) ||
  2043. (pszMonitor && 0 == lstrcmp(pszMonitor, FAX_MONITOR_NAME)));
  2044. }
  2045. /*++
  2046. Routine Description:
  2047. shows up an appropriate error message based on the last error code
  2048. (if spcified) this function is exported from printui to shell, so
  2049. shell error messages can be consistent with us.
  2050. Arguments:
  2051. piResult - the result from MessageBox
  2052. hModule - module who contains the test resources
  2053. hwnd - parent window
  2054. pszTitle - msg title (uID or text)
  2055. pszMessage - msg itself or msg context (uID or text)
  2056. uType - msg type
  2057. iLastError - the last error (-1 means don't append the last error text)
  2058. Return Value:
  2059. S_OK on success or COM error otherwise
  2060. --*/
  2061. HRESULT
  2062. ShowErrorMessageSC(
  2063. OUT INT *piResult,
  2064. IN HINSTANCE hModule,
  2065. IN HWND hwnd,
  2066. IN LPCTSTR pszTitle,
  2067. IN LPCTSTR pszMessage,
  2068. IN UINT uType,
  2069. IN DWORD dwCode
  2070. )
  2071. {
  2072. return Internal_Message(piResult, hModule, hwnd, pszTitle, pszMessage,
  2073. uType, dwCode, NULL, NULL, 0, NULL);
  2074. }
  2075. /*++
  2076. Routine Description:
  2077. shows up an appropriate error message based on the last error code
  2078. (if spcified) this function is exported from printui to shell, so
  2079. shell error messages can be consistent with us.
  2080. Arguments:
  2081. piResult - the result from MessageBox
  2082. hModule - module who contains the test resources
  2083. hwnd - parent window
  2084. pszTitle - msg title (uID or text)
  2085. pszMessage - msg itself or msg context (uID or text)
  2086. uType - msg type
  2087. iLastError - the last error (-1 means don't append the last error text)
  2088. Return Value:
  2089. S_OK on success or COM error otherwise
  2090. --*/
  2091. HRESULT
  2092. ShowErrorMessageHR(
  2093. OUT INT *piResult,
  2094. IN HINSTANCE hModule,
  2095. IN HWND hwnd,
  2096. IN LPCTSTR pszTitle,
  2097. IN LPCTSTR pszMessage,
  2098. IN UINT uType,
  2099. IN HRESULT hr
  2100. )
  2101. {
  2102. return Internal_Message(piResult, hModule, hwnd, pszTitle, pszMessage,
  2103. uType, SCODE_CODE(GetScode(hr)), NULL, NULL, 0, NULL);
  2104. }
  2105. /*++
  2106. Routine Description:
  2107. abbreviates text by adding ellipses if text is longer than cchMaxChars
  2108. Arguments:
  2109. pszText - [in] text to abbreviate
  2110. cchMaxChars - [in] max characters of the output (abbreviated) text
  2111. pstrAbbreviatedText - [out] the abbreviated text
  2112. Return Value:
  2113. S_OK on success or COM error otherwise
  2114. --*/
  2115. HRESULT
  2116. AbbreviateText(
  2117. IN LPCTSTR pszText,
  2118. IN UINT cchMaxChars,
  2119. OUT TString *pstrAbbreviatedText
  2120. )
  2121. {
  2122. HRESULT hr = E_INVALIDARG;
  2123. if( pszText && cchMaxChars && pstrAbbreviatedText )
  2124. {
  2125. TStatusB bStatus;
  2126. if( lstrlen(pszText) <= cchMaxChars )
  2127. {
  2128. // the text fits in the buffer, just copy it
  2129. bStatus DBGCHK = pstrAbbreviatedText->bUpdate(pszText);
  2130. hr = bStatus ? S_OK : E_OUTOFMEMORY;
  2131. }
  2132. else
  2133. {
  2134. // the text doesn't fit in the buffer, add ellipses
  2135. TString strEllipses;
  2136. bStatus DBGCHK = strEllipses.bLoadString(ghInst, IDS_TEXT_ELLIPSES);
  2137. if( bStatus && strEllipses.uLen() < cchMaxChars )
  2138. {
  2139. TCHAR szBuffer[255];
  2140. lstrcpyn(szBuffer, pszText, min(cchMaxChars - strEllipses.uLen(), ARRAYSIZE(szBuffer)));
  2141. bStatus DBGCHK = pstrAbbreviatedText->bFormat(TEXT("%s%s"), szBuffer, static_cast<LPCTSTR>(strEllipses));
  2142. hr = bStatus ? S_OK : E_OUTOFMEMORY;
  2143. }
  2144. else
  2145. {
  2146. // generate proper HRESULT from Win32 last error
  2147. hr = CreateHRFromWin32();
  2148. }
  2149. }
  2150. }
  2151. return hr;
  2152. }
  2153. /*++
  2154. Routine Name:
  2155. MoveWindowWrap
  2156. Routine Description:
  2157. Move specific window by given offset.
  2158. Arguments:
  2159. hWnd -- window handle
  2160. deltaX -- horizonal offset
  2161. deltaY -- vertical offset
  2162. Return Value:
  2163. Return value by MoveWindow().
  2164. --*/
  2165. BOOL
  2166. MoveWindowWrap(
  2167. HWND hwnd,
  2168. int deltaX,
  2169. int deltaY
  2170. )
  2171. {
  2172. RECT rect;
  2173. GetWindowRect(hwnd, &rect);
  2174. MapWindowPoints(HWND_DESKTOP, GetParent(hwnd), (LPPOINT)&rect, 2);
  2175. return MoveWindow(hwnd, rect.left + deltaX, rect.top + deltaY,
  2176. rect.right - rect.left, rect.bottom - rect.top, TRUE);
  2177. }
  2178. /*++
  2179. Routine Name:
  2180. IsColorPrinter
  2181. Routine Description:
  2182. Checks if a printer supports color
  2183. Arguments:
  2184. pszPrinter - printer name
  2185. pbColor - pointer to bool
  2186. Return Value:
  2187. S_OK - the function succeded and pbColor can be used
  2188. anything else - the function failed
  2189. --*/
  2190. HRESULT
  2191. IsColorPrinter(
  2192. IN LPCWSTR pszPrinter,
  2193. IN OUT LPBOOL pbColor
  2194. )
  2195. {
  2196. TStatusH hStatus;
  2197. hStatus DBGNOCHK = E_INVALIDARG;
  2198. if (pszPrinter && pbColor)
  2199. {
  2200. hStatus DBGNOCHK = E_FAIL;
  2201. //
  2202. // Create the printer data access class.
  2203. //
  2204. TPrinterDataAccess Data(pszPrinter,
  2205. TPrinterDataAccess::kResourcePrinter,
  2206. TPrinterDataAccess::kAccessRead);
  2207. //
  2208. // Relax the return type checking, BOOL are not REG_DWORD but REG_BINARY
  2209. //
  2210. Data.RelaxReturnTypeCheck(TRUE);
  2211. //
  2212. // Initialize the data class.
  2213. //
  2214. if (Data.Init())
  2215. {
  2216. hStatus DBGCHK = Data.Get(SPLDS_DRIVER_KEY, SPLDS_PRINT_COLOR, *pbColor);
  2217. }
  2218. }
  2219. return hStatus;
  2220. }
  2221. /*++
  2222. Routine Name:
  2223. IsGuestAccessMode
  2224. Routine Description:
  2225. Checks if guest access mode is enabled for the local machine.
  2226. Arguments:
  2227. pbGuestAccessMode - [out] TRUE if guest access mode is enabled
  2228. for the local machine and FALSE otherwise.
  2229. Return Value:
  2230. S_OK if succeded and OLE error otherwise.
  2231. History:
  2232. Lazar Ivanov (LazarI), Mar-19-2001 - created.
  2233. --*/
  2234. HRESULT
  2235. IsGuestAccessMode(
  2236. OUT BOOL *pbGuestAccessMode
  2237. )
  2238. {
  2239. HRESULT hr = S_OK;
  2240. if (pbGuestAccessMode)
  2241. {
  2242. if (GetCurrentPlatform() == kPlatform_IA64)
  2243. {
  2244. //
  2245. // Guest mode is always off for IA64 machine since we don't have
  2246. // homenetworking wizard for IA64 machine
  2247. //
  2248. *pbGuestAccessMode = FALSE;
  2249. }
  2250. else if (IsOS(OS_PERSONAL))
  2251. {
  2252. //
  2253. // Guest mode is always on for Personal.
  2254. //
  2255. *pbGuestAccessMode = TRUE;
  2256. }
  2257. else if (IsOS(OS_PROFESSIONAL) && !IsOS(OS_DOMAINMEMBER))
  2258. {
  2259. //
  2260. // Professional, not in a domain. Check the "ForceGuest" value
  2261. // in the registry.
  2262. //
  2263. LONG errCode;
  2264. CAutoHandleHKEY shKey;
  2265. DWORD dwValue = 0;
  2266. DWORD dwValueSize = sizeof(dwValue);
  2267. errCode = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  2268. TEXT("SYSTEM\\CurrentControlSet\\Control\\LSA"),
  2269. 0, KEY_QUERY_VALUE, &shKey);
  2270. if (errCode == ERROR_SUCCESS)
  2271. {
  2272. errCode = RegQueryValueEx(shKey, TEXT("ForceGuest"), NULL, NULL,
  2273. (LPBYTE)&dwValue, &dwValueSize);
  2274. if (errCode == ERROR_SUCCESS)
  2275. {
  2276. //
  2277. // Declare success here.
  2278. //
  2279. *pbGuestAccessMode = (1 == dwValue);
  2280. hr = S_OK;
  2281. }
  2282. else
  2283. {
  2284. hr = HRESULT_FROM_WIN32(errCode);
  2285. }
  2286. }
  2287. else
  2288. {
  2289. hr = HRESULT_FROM_WIN32(errCode);
  2290. }
  2291. }
  2292. else
  2293. {
  2294. //
  2295. // Not in guest mode.
  2296. //
  2297. *pbGuestAccessMode = FALSE;
  2298. }
  2299. }
  2300. else
  2301. {
  2302. hr = E_INVALIDARG;
  2303. }
  2304. return hr;
  2305. }
  2306. /*++
  2307. Routine Name:
  2308. IsGuestEnabledForNetworkAccess
  2309. Routine Description:
  2310. Checks if the Guest account is enabled for network access.
  2311. Arguments:
  2312. pbGuestEnabledForNetworkAccess - [out] TRUE if the Guest
  2313. account is enabled for network access and FALSE otherwise.
  2314. Return Value:
  2315. S_OK if succeded and OLE error otherwise.
  2316. History:
  2317. Lazar Ivanov (LazarI), Mar-19-2001 - created.
  2318. --*/
  2319. HRESULT
  2320. IsGuestEnabledForNetworkAccess(
  2321. OUT BOOL *pbGuestEnabledForNetworkAccess
  2322. )
  2323. {
  2324. HRESULT hr = S_OK;
  2325. if (pbGuestEnabledForNetworkAccess)
  2326. {
  2327. CRefPtrCOM<ILocalMachine> spLM;
  2328. VARIANT_BOOL vbEnabled = VARIANT_FALSE;
  2329. //
  2330. // Get pointer to ILocalMachine to check ILM_GUEST_NETWORK_LOGON
  2331. //
  2332. if (SUCCEEDED(hr = CoCreateInstance(CLSID_ShellLocalMachine, NULL,
  2333. CLSCTX_INPROC_SERVER, IID_ILocalMachine, (void**)&spLM)) &&
  2334. SUCCEEDED(hr = spLM->get_isGuestEnabled(ILM_GUEST_NETWORK_LOGON, &vbEnabled)))
  2335. {
  2336. //
  2337. // Declare success here.
  2338. //
  2339. *pbGuestEnabledForNetworkAccess = (VARIANT_TRUE == vbEnabled);
  2340. hr = S_OK;
  2341. }
  2342. }
  2343. else
  2344. {
  2345. hr = E_INVALIDARG;
  2346. }
  2347. return hr;
  2348. }
  2349. /*++
  2350. Routine Name:
  2351. IsSharingEnabled
  2352. Routine Description:
  2353. Checks if sharing is enabled or we should launch the home
  2354. networking wizard to enable sharing before allowing the
  2355. users to share out printers.
  2356. Arguments:
  2357. pbSharingEnabled - [out] TRUE if sharing is enabled and
  2358. FALSE otherwise (in which case we should launch HNW)
  2359. Return Value:
  2360. S_OK if succeded and OLE error otherwise.
  2361. History:
  2362. Lazar Ivanov (LazarI), Mar-19-2001 - created.
  2363. --*/
  2364. HRESULT
  2365. IsSharingEnabled(
  2366. OUT BOOL *pbSharingEnabled
  2367. )
  2368. {
  2369. HRESULT hr = S_OK;
  2370. if (pbSharingEnabled)
  2371. {
  2372. BOOL bGuestAccessMode = FALSE;
  2373. BOOL bGuestEnabledForNetworkAccess = FALSE;
  2374. //
  2375. // First get the values of bGuestAccessMode & bGuestEnabledForNetworkAccess
  2376. //
  2377. if (SUCCEEDED(hr = IsGuestAccessMode(&bGuestAccessMode)) &&
  2378. SUCCEEDED(hr = IsGuestEnabledForNetworkAccess(&bGuestEnabledForNetworkAccess)))
  2379. {
  2380. //
  2381. // Sharing is enabled *only* if not in guest mode OR the guest account is
  2382. // enabled for network access.
  2383. //
  2384. *pbSharingEnabled = (!bGuestAccessMode || bGuestEnabledForNetworkAccess);
  2385. hr = S_OK;
  2386. }
  2387. }
  2388. else
  2389. {
  2390. hr = E_INVALIDARG;
  2391. }
  2392. return hr;
  2393. }
  2394. /*++
  2395. Routine Name:
  2396. LaunchHomeNetworkingWizard
  2397. Routine Description:
  2398. Launches the home networking wizard
  2399. Arguments:
  2400. hwnd - [in] window handle to show the wizard modally against
  2401. pbRebootRequired - [out] TRUE if the user made a change which
  2402. requires to reboot the system.
  2403. Return Value:
  2404. S_OK if succeded and OLE error otherwise.
  2405. History:
  2406. Lazar Ivanov (LazarI), Mar-19-2001 - created.
  2407. --*/
  2408. HRESULT
  2409. LaunchHomeNetworkingWizard(
  2410. IN HWND hwnd,
  2411. OUT BOOL *pbRebootRequired
  2412. )
  2413. {
  2414. HRESULT hr = S_OK;
  2415. if (hwnd && pbRebootRequired)
  2416. {
  2417. CRefPtrCOM<IHomeNetworkWizard> spHNW;
  2418. //
  2419. // Get pointer to IHomeNetworkWizard, get the top level owner of hwnd
  2420. // and then show the wizard.
  2421. //
  2422. if (SUCCEEDED(hr = CoCreateInstance(CLSID_HomeNetworkWizard, NULL,
  2423. CLSCTX_INPROC_SERVER, IID_IHomeNetworkWizard, (void**)&spHNW)) &&
  2424. SUCCEEDED(hr = GetCurrentThreadLastPopup(&hwnd)) &&
  2425. SUCCEEDED(hr = spHNW->ShowWizard(hwnd, pbRebootRequired)))
  2426. {
  2427. //
  2428. // Declare success here.
  2429. //
  2430. hr = S_OK;
  2431. }
  2432. }
  2433. else
  2434. {
  2435. hr = E_INVALIDARG;
  2436. }
  2437. return hr;
  2438. }
  2439. /*++
  2440. Routine Name:
  2441. IsRedirectedPort
  2442. Routine Description:
  2443. Determines if the specified port name is a redirected port.
  2444. Arguments:
  2445. pszPortName - Port name.
  2446. Return Value:
  2447. Standard HRESULT value.
  2448. --*/
  2449. HRESULT
  2450. IsRedirectedPort(
  2451. IN LPCTSTR pszPortName,
  2452. OUT BOOL *pbIsRedirected
  2453. )
  2454. {
  2455. HRESULT hr = S_OK;
  2456. if (!pszPortName || lstrlen(pszPortName) < 2)
  2457. {
  2458. *pbIsRedirected = FALSE;
  2459. }
  2460. else
  2461. {
  2462. *pbIsRedirected = (*(pszPortName+0) == TEXT('\\')) && (*(pszPortName+1) == TEXT('\\'));
  2463. }
  2464. return hr;
  2465. }
  2466. /*++
  2467. Routine Name:
  2468. DisplayMessageFromOtherResourceDll
  2469. Routine Description:
  2470. This displays a message where the message comes from another resource DLL, the
  2471. title comes from printui.
  2472. Arguments:
  2473. hwnd - Parent window for this window.
  2474. idsTitle - The res id of the title to display
  2475. pszMessageDll - The message DLL to load and display.
  2476. idsMessage - The res id of the message
  2477. uType - The type of message box to display.
  2478. ... - Arguments formatted by idsMessage
  2479. Return Value:
  2480. returns value from MessageBox on sucess
  2481. and zero on failure
  2482. --*/
  2483. INT
  2484. DisplayMessageFromOtherResourceDll(
  2485. IN HWND hwnd,
  2486. IN UINT idsTitle,
  2487. IN PCWSTR pszMessageDll,
  2488. IN UINT idsMessage,
  2489. IN UINT uType,
  2490. ...
  2491. )
  2492. {
  2493. HMODULE hMessage = NULL;
  2494. TString strTitle;
  2495. INT iRet = TRUE;
  2496. if (pszMessageDll)
  2497. {
  2498. iRet = TRUE;
  2499. }
  2500. else
  2501. {
  2502. SetLastError(ERROR_INVALID_PARAMETER);
  2503. iRet = FALSE;
  2504. }
  2505. if (iRet)
  2506. {
  2507. iRet = (hMessage = LoadLibraryEx(pszMessageDll, NULL, LOAD_LIBRARY_AS_DATAFILE)) != NULL;
  2508. }
  2509. if (iRet)
  2510. {
  2511. iRet = strTitle.bLoadString(ghInst, idsTitle);
  2512. }
  2513. if (iRet)
  2514. {
  2515. va_list valist;
  2516. va_start(valist, uType);
  2517. if(FAILED(Internal_Message(&iRet,
  2518. hMessage,
  2519. hwnd,
  2520. strTitle,
  2521. MAKEINTRESOURCE(idsMessage),
  2522. uType,
  2523. ERROR_SUCCESS,
  2524. NULL,
  2525. 0,
  2526. NULL,
  2527. valist)) )
  2528. {
  2529. // make sure we return zero in the failure case
  2530. iRet = 0;
  2531. }
  2532. va_end(valist);
  2533. }
  2534. if (hMessage)
  2535. {
  2536. FreeLibrary(hMessage);
  2537. }
  2538. return iRet;
  2539. }