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.

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