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.

814 lines
24 KiB

  1. //
  2. // shint.cpp: client shell utitilies
  3. // internal functions
  4. //
  5. #include "stdafx.h"
  6. #define TRC_GROUP TRC_GROUP_UI
  7. #define TRC_FILE "shint.cpp"
  8. #include <atrcapi.h>
  9. #include "sh.h"
  10. #include "rmigrate.h"
  11. //
  12. // Fix union names, because some headers redifine this
  13. // and break STRRET to str field access
  14. //
  15. #undef DUMMYUNIONNAME
  16. #define NONAMELESSUNION
  17. #define CLXSERVER TEXT("CLXSERVER")
  18. #define CLXCMDLINE TEXT("CLXCMDLINE")
  19. #define FULLSCREEN TEXT("FULLSCREEN")
  20. #define SWITCH_EDIT TEXT("EDIT")
  21. #define SWITCH_MIGRATE TEXT("MIGRATE")
  22. #define SWITCH_CONSOLE TEXT("CONSOLE")
  23. #ifdef NONAMELESSUNION
  24. #define NAMELESS_MEMBER(member) DUMMYUNIONNAME.##member
  25. #else
  26. #define NAMELESS_MEMBER(member) member
  27. #endif
  28. #define STRRET_OLESTR STRRET_WSTR // same as STRRET_WSTR
  29. #define STRRET_OFFPTR(pidl,lpstrret) \
  30. ((LPSTR)((LPBYTE)(pidl)+(lpstrret)->NAMELESS_MEMBER(uOffset)))
  31. /****************************************************************************/
  32. /* Name: SHValidateParsedCmdParam */
  33. /* */
  34. /* Purpose: validates settings in _SH that were read from the cmd line */
  35. /* */
  36. /* Returns: Nothing */
  37. /* */
  38. /* Params: IN - lpszCmdParam */
  39. /* */
  40. /****************************************************************************/
  41. DCBOOL CSH::SHValidateParsedCmdParam()
  42. {
  43. DC_BEGIN_FN("SHValidateParsedCmdParam");
  44. //
  45. //["<session>"] [-v:<server>] [-f[ullscreen]] [-w[idth]:<wd> -h[eight]:<ht>]
  46. //
  47. //
  48. // if one of width/height is specified but not the other..
  49. // then fill with defaults
  50. //
  51. if (_SH.commandLineHeight != _SH.commandLineWidth)
  52. {
  53. if (!_SH.commandLineHeight)
  54. {
  55. _SH.commandLineHeight = DEFAULT_DESKTOP_HEIGHT;
  56. }
  57. if (!_SH.commandLineWidth)
  58. {
  59. _SH.commandLineWidth = DEFAULT_DESKTOP_WIDTH;
  60. }
  61. }
  62. //
  63. // clamp to min max sizes. 0 means we are not set
  64. //
  65. if (_SH.commandLineHeight != 0)
  66. {
  67. if (_SH.commandLineHeight < MIN_DESKTOP_HEIGHT)
  68. {
  69. _SH.commandLineHeight = MIN_DESKTOP_HEIGHT;
  70. }
  71. else if (_SH.commandLineHeight > MAX_DESKTOP_HEIGHT)
  72. {
  73. _SH.commandLineHeight = MAX_DESKTOP_HEIGHT;
  74. }
  75. }
  76. if (_SH.commandLineWidth != 0)
  77. {
  78. if (_SH.commandLineWidth < MIN_DESKTOP_WIDTH)
  79. {
  80. _SH.commandLineWidth = MIN_DESKTOP_WIDTH;
  81. }
  82. else if (_SH.commandLineWidth > MAX_DESKTOP_WIDTH)
  83. {
  84. _SH.commandLineWidth = MAX_DESKTOP_WIDTH;
  85. }
  86. }
  87. DC_END_FN();
  88. return TRUE;
  89. }
  90. //*************************************************************
  91. //
  92. // CLX_SkipWhite()
  93. //
  94. // Purpose: Skips whitespace characters
  95. //
  96. // Parameters: IN [lpszCmdParam] - Ptr to string
  97. //
  98. // Return: Ptr string past whitespace
  99. //
  100. // History: 09-30-97 BrianTa Created
  101. //
  102. //*************************************************************
  103. LPTSTR
  104. CLX_SkipWhite(IN LPTSTR lpszCmdParam)
  105. {
  106. while (*lpszCmdParam)
  107. {
  108. if (*lpszCmdParam != ' ')
  109. break;
  110. lpszCmdParam++;
  111. }
  112. return(lpszCmdParam);
  113. }
  114. //*************************************************************
  115. //
  116. // CLX_SkipNonWhite()
  117. //
  118. // Purpose: Skips non-whitespace characters
  119. //
  120. // Parameters: IN [lpszCmdParam] - Ptr to string
  121. //
  122. // Return: Ptr string past non-whitespace
  123. //
  124. // History: 09-30-97 BrianTa Created
  125. //
  126. //*************************************************************
  127. LPTSTR CLX_SkipNonWhite(LPTSTR lpszCmdParam)
  128. {
  129. char Delim;
  130. Delim = ' ';
  131. if (*lpszCmdParam == '"')
  132. {
  133. Delim = '"';
  134. lpszCmdParam++;
  135. }
  136. while (*lpszCmdParam)
  137. {
  138. if (*lpszCmdParam == Delim)
  139. break;
  140. lpszCmdParam++;
  141. }
  142. if (*lpszCmdParam == Delim)
  143. lpszCmdParam++;
  144. return(lpszCmdParam);
  145. }
  146. //*************************************************************
  147. //
  148. // CLX_GetSwitch_CLXSERVER()
  149. //
  150. // Purpose: Processes /CLXSERVER cmdline switch
  151. //
  152. // Parameters: IN [lpszCmdParam] - Ptr to cmdline
  153. //
  154. // Return: Number of characters consumed
  155. //
  156. // History: 09-30-97 BrianTa Created
  157. //
  158. //*************************************************************
  159. UINT
  160. CLX_GetSwitch_CLXSERVER(IN LPTSTR lpszCmdParam)
  161. {
  162. DC_BEGIN_FN("CLX_GetSwitch_CLXSERVER");
  163. int len;
  164. LPTSTR pszEnd;
  165. LPTSTR pszStart;
  166. pszStart = CLX_SkipWhite(lpszCmdParam);
  167. TRC_ASSERT(*pszStart == _T('='),
  168. (TB,_T("Invalid /clxserver syntax - expected '='\n")));
  169. pszStart++;
  170. pszStart = CLX_SkipWhite(pszStart);
  171. pszEnd = CLX_SkipNonWhite(pszStart);
  172. len = (INT) (pszEnd - pszStart);
  173. DC_END_FN();
  174. return(UINT) (pszEnd - lpszCmdParam);
  175. }
  176. //*************************************************************
  177. //
  178. // CLX_GetSwitch_CLXCMDLINE()
  179. //
  180. // Purpose: Processes /CLXCMDLINE cmdline switch
  181. //
  182. // Parameters: IN [lpszCmdParam] - Ptr to cmdline
  183. //
  184. // Return: Number of characters consumed
  185. //
  186. // History: 09-30-97 BrianTa Created
  187. //
  188. //*************************************************************
  189. UINT
  190. CSH::CLX_GetSwitch_CLXCMDLINE(IN LPTSTR lpszCmdParam)
  191. {
  192. int len;
  193. LPTSTR pszEnd;
  194. LPTSTR pszStart;
  195. DC_BEGIN_FN("CLX_GetSwitch_CLXCMDLINE");
  196. pszStart = CLX_SkipWhite(lpszCmdParam);
  197. TRC_ASSERT(*pszStart == _T('='),
  198. (TB,_T("Invalid /clxserver syntax - expected '='\n")));
  199. pszStart++;
  200. pszStart = CLX_SkipWhite(pszStart);
  201. pszEnd = CLX_SkipNonWhite(pszStart);
  202. len = (INT) (pszEnd - pszStart);
  203. if (len > 0)
  204. {
  205. memmove(_SH.szCLXCmdLine, pszStart, len*sizeof(TCHAR));
  206. _SH.szCLXCmdLine[len] = 0;
  207. }
  208. DC_END_FN();
  209. return(UINT) (pszEnd - lpszCmdParam);
  210. }
  211. /****************************************************************************/
  212. /* Name: SHGetSwitch */
  213. /* */
  214. /* Purpose: Retrieves cmdline switches */
  215. /* */
  216. /* Returns: Nothing */
  217. /* */
  218. /* Params: IN - lpszCmdParam */
  219. /* */
  220. /****************************************************************************/
  221. LPTSTR CSH::SHGetSwitch(LPTSTR lpszCmdParam)
  222. {
  223. DCINT i;
  224. DCTCHAR szParam[100];
  225. DC_BEGIN_FN("SHGetSwitch");
  226. /************************************************************************/
  227. /* Retrieve the switch (case insensitive) */
  228. /************************************************************************/
  229. i=0;
  230. while (*lpszCmdParam)
  231. {
  232. if (*lpszCmdParam == _T(' ') || *lpszCmdParam == _T('=') ||
  233. *lpszCmdParam == _T(':'))
  234. break;
  235. if (i < sizeof(szParam) / sizeof(DCTCHAR) - 1)
  236. {
  237. #ifdef UNICODE
  238. szParam[i] = (DCTCHAR) towupper(*lpszCmdParam);
  239. #else // UNICODE
  240. szParam[i] = (DCTCHAR) toupper(*lpszCmdParam);
  241. #endif // UNICODE
  242. i++;
  243. }
  244. lpszCmdParam++;
  245. }
  246. szParam[i] = 0;
  247. #ifndef OS_WINCE
  248. // Are we seeing the "/f" from /F[ullscreen]
  249. if (szParam[0] == _T('F'))
  250. {
  251. _SH.fCommandStartFullScreen = TRUE;
  252. }
  253. // Are we seeing the "/W" from /w[idth]
  254. else if (szParam[0] == _T('W'))
  255. {
  256. lpszCmdParam = SHGetCmdLineInt(lpszCmdParam, &_SH.commandLineWidth);
  257. }
  258. // Are we seeing the "/H" from /h[eight]
  259. else if (szParam[0] == _T('H'))
  260. {
  261. lpszCmdParam = SHGetCmdLineInt(lpszCmdParam, &_SH.commandLineHeight);
  262. }
  263. // Are we seeing the "/V" for server
  264. else
  265. #endif
  266. if (szParam[0] == _T('V'))
  267. {
  268. lpszCmdParam = SHGetServer(lpszCmdParam);
  269. }
  270. // Are we seeing the "/S"
  271. else if (memcmp(szParam, "S", i) == 0)
  272. {
  273. lpszCmdParam = SHGetSession(lpszCmdParam);
  274. }
  275. // Are we seeing the "/C"
  276. else if (memcmp(szParam, "C", i) == 0)
  277. {
  278. lpszCmdParam = SHGetCacheToClear(lpszCmdParam);
  279. }
  280. // Are we seeing the "/CLXCMDLINE=xyzzy"
  281. else if (memcmp(szParam, CLXCMDLINE, i) == 0)
  282. {
  283. lpszCmdParam += CLX_GetSwitch_CLXCMDLINE(lpszCmdParam);
  284. }
  285. else if (memcmp(szParam, FULLSCREEN, i) == 0)
  286. {
  287. lpszCmdParam += SIZECHAR(FULLSCREEN);
  288. }
  289. else if (memcmp(szParam, SWITCH_EDIT,i) == 0)
  290. {
  291. lpszCmdParam = SHGetFileName(lpszCmdParam);
  292. _fFileForEdit = TRUE;
  293. _SH.autoConnectEnabled = FALSE;
  294. }
  295. else if (memcmp(szParam, SWITCH_MIGRATE,i) == 0)
  296. {
  297. _fMigrateOnly = TRUE;
  298. }
  299. else if (memcmp(szParam, SWITCH_CONSOLE,i) == 0)
  300. {
  301. SH_SetCmdConnectToConsole(TRUE);
  302. }
  303. /************************************************************************/
  304. /* Not a recognized switch. Bring up usage */
  305. /************************************************************************/
  306. else
  307. {
  308. TRC_NRM((TB,_T("Invalid CmdLine switch - Display Usage AND EXIT %s"),
  309. szParam));
  310. DCTCHAR szCmdLineUsage[4096]; //Long string here.
  311. DCTCHAR szUsageTitle[256];
  312. if (!LoadString(_hInstance,
  313. UI_IDS_USAGE_TITLE,
  314. szUsageTitle,
  315. SIZECHAR(szUsageTitle)))
  316. {
  317. TRC_ERR((TB,_T("Error loading UI_IDS_USAGE_TITLE")));
  318. return NULL;
  319. }
  320. if (!LoadString(_hInstance,
  321. UI_IDS_CMD_LINE_USAGE,
  322. szCmdLineUsage,
  323. SIZECHAR(szCmdLineUsage)))
  324. {
  325. TRC_NRM((TB,_T("Error loading UI_IDS_CMD_LINE_USAGE")));
  326. return NULL;
  327. }
  328. MessageBox(NULL, szCmdLineUsage, szUsageTitle,
  329. MB_ICONINFORMATION | MB_OK);
  330. return NULL;
  331. }
  332. DC_END_FN();
  333. return(lpszCmdParam);
  334. }
  335. /****************************************************************************/
  336. /* Name: SHGetServer */
  337. /* */
  338. /* Purpose: Retrieves the server name (if specified) */
  339. /* */
  340. /* Returns: Nothing */
  341. /* */
  342. /* Params: IN - lpszCmdParam */
  343. /* */
  344. /****************************************************************************/
  345. LPTSTR CSH::SHGetServer(LPTSTR lpszCmdParam)
  346. {
  347. DC_BEGIN_FN("SHGetServer");
  348. if (!lpszCmdParam)
  349. {
  350. return NULL;
  351. }
  352. /************************************************************************/
  353. /* Retrieve the server */
  354. /************************************************************************/
  355. lpszCmdParam = SHGetCmdLineString(lpszCmdParam, _SH.szCommandLineServer,
  356. SIZECHAR(_SH.szCommandLineServer) -1);
  357. DC_END_FN();
  358. return lpszCmdParam;
  359. }
  360. /****************************************************************************/
  361. /* Name: SHGetSession */
  362. /* */
  363. /* Purpose: Retrieves the session name (if specified) */
  364. /* */
  365. /* Returns: Nothing */
  366. /* */
  367. /* Params: IN - lpszCmdParam */
  368. /* */
  369. /****************************************************************************/
  370. LPTSTR CSH::SHGetSession(LPTSTR lpszCmdParam)
  371. {
  372. BOOL fQuote = FALSE;
  373. DC_BEGIN_FN("SHGetSession");
  374. TRC_ASSERT((_SH.fRegDefault == TRUE),
  375. (TB,_T("Invalid CmdLine syntax - session respecified.")));
  376. // Retrieve the reg session
  377. lpszCmdParam = SHGetCmdLineString(lpszCmdParam, _SH.regSession,
  378. SIZECHAR(_SH.regSession) -1);
  379. // In the non-default session, display the session name. Choose the
  380. // appropriate connected/disconnected strings.
  381. TRC_DBG((TB, _T("Named session")));
  382. _SH.fRegDefault = FALSE;
  383. _SH.connectedStringID = UI_IDS_FRAME_TITLE_CONNECTED;
  384. _SH.disconnectedStringID = UI_IDS_FRAME_TITLE_DISCONNECTED;
  385. DC_END_FN();
  386. return(lpszCmdParam);
  387. }
  388. LPTSTR CSH::SHGetFileName(LPTSTR lpszCmdParam)
  389. {
  390. BOOL fQuote = FALSE;
  391. DC_BEGIN_FN("SHGetSession");
  392. TRC_ASSERT((_SH.fRegDefault == TRUE),
  393. (TB,_T("Invalid CmdLine syntax - session respecified.")));
  394. // Retrieve the filename
  395. lpszCmdParam = SHGetCmdLineString(lpszCmdParam, _szFileName,
  396. SIZECHAR(_szFileName) -1);
  397. _SH.fRegDefault = FALSE;
  398. _SH.connectedStringID = UI_IDS_FRAME_TITLE_CONNECTED;
  399. _SH.disconnectedStringID = UI_IDS_FRAME_TITLE_DISCONNECTED;
  400. DC_END_FN();
  401. return(lpszCmdParam);
  402. }
  403. /****************************************************************************/
  404. /* Name: SHGetCmdLineString */
  405. /* */
  406. /* Purpose: Retrieve a string parameter */
  407. /* */
  408. /* Returns: Nothing */
  409. /* */
  410. /* Params: IN - lpszCmdParam */
  411. /* */
  412. /****************************************************************************/
  413. LPTSTR CSH::SHGetCmdLineString(LPTSTR lpszCmdParam, LPTSTR lpszDest,
  414. DCINT cbDestLen)
  415. {
  416. DCINT i;
  417. BOOL fQuote = FALSE;
  418. DC_BEGIN_FN("SHGetCmdLineString");
  419. TRC_ASSERT(lpszCmdParam && lpszDest && cbDestLen,
  420. (TB, _T("SHGetCmdLineString. Invalid param(s)\n")));
  421. if (!lpszCmdParam || !lpszDest || !cbDestLen)
  422. {
  423. return NULL;
  424. }
  425. /************************************************************************/
  426. /* Retrieve a command line string parameter */
  427. /************************************************************************/
  428. while (*lpszCmdParam == _T(' '))
  429. lpszCmdParam++;
  430. if (*lpszCmdParam == _T('=') || *lpszCmdParam == _T(':'))
  431. lpszCmdParam++;
  432. while (*lpszCmdParam == _T(' '))
  433. lpszCmdParam++;
  434. i=0;
  435. while (*lpszCmdParam)
  436. {
  437. switch (*lpszCmdParam)
  438. {
  439. case _T('"'):
  440. fQuote = !fQuote;
  441. lpszCmdParam++;
  442. break;
  443. case _T(' '):
  444. if (!fQuote)
  445. {
  446. lpszCmdParam++;
  447. DC_QUIT;
  448. }
  449. // else fall through
  450. default:
  451. if (i < cbDestLen)
  452. lpszDest[i++] = *lpszCmdParam;
  453. lpszCmdParam++;
  454. }
  455. }
  456. DC_EXIT_POINT:
  457. DC_END_FN();
  458. lpszDest[i] = 0;
  459. return lpszCmdParam;
  460. }
  461. /****************************************************************************/
  462. /* Name: SHGetCmdLineInt */
  463. /* */
  464. /* Purpose: Retrieves an integer parameter */
  465. /* */
  466. /* Returns: Nothing */
  467. /* */
  468. /* Params: IN - lpszCmdParam, OUT- PInt */
  469. /* */
  470. /****************************************************************************/
  471. LPTSTR CSH::SHGetCmdLineInt(LPTSTR lpszCmdParam, PDCUINT pInt)
  472. {
  473. DC_BEGIN_FN("SHGetCmdLineInt");
  474. if (!pInt)
  475. {
  476. return NULL;
  477. }
  478. if (!lpszCmdParam)
  479. {
  480. return NULL;
  481. }
  482. /************************************************************************/
  483. /* Retrieve an integer parameter */
  484. /************************************************************************/
  485. while (*lpszCmdParam == _T(' '))
  486. lpszCmdParam++;
  487. if (*lpszCmdParam == _T('=') || *lpszCmdParam == _T(':'))
  488. lpszCmdParam++;
  489. while (*lpszCmdParam == _T(' '))
  490. lpszCmdParam++;
  491. DCUINT readInt = 0;
  492. while (*lpszCmdParam)
  493. {
  494. if (*lpszCmdParam == _T(' '))
  495. break;
  496. if (_istdigit(*lpszCmdParam))
  497. {
  498. DCINT digit = *lpszCmdParam - _T('0');
  499. TRC_ASSERT(digit >=0 && digit <=9, (TB,_T("digit read error\n")));
  500. if (digit <0 || digit >9)
  501. {
  502. break;
  503. }
  504. readInt = readInt * 10 + digit;
  505. }
  506. else
  507. {
  508. break;
  509. }
  510. lpszCmdParam++;
  511. }
  512. *pInt = readInt;
  513. DC_END_FN();
  514. return lpszCmdParam;
  515. }
  516. /****************************************************************************/
  517. /* Name: SHGetCacheToClear */
  518. /* */
  519. /* Purpose: Retrieves the cache type (e.g. bitmap) to be cleared */
  520. /* */
  521. /* Returns: Nothing */
  522. /* */
  523. /* Params: IN - lpszCmdParam */
  524. /* */
  525. /****************************************************************************/
  526. LPTSTR CSH::SHGetCacheToClear(LPTSTR lpszCmdParam)
  527. {
  528. DCINT i;
  529. TCHAR cacheType[10];
  530. DC_BEGIN_FN("SHGetCacheToClear");
  531. /************************************************************************/
  532. /* Retrieve the cache type */
  533. /************************************************************************/
  534. while (*lpszCmdParam == _T(' '))
  535. lpszCmdParam++;
  536. if (*lpszCmdParam == _T('=') || *lpszCmdParam == _T(':'))
  537. lpszCmdParam++;
  538. while (*lpszCmdParam == _T(' '))
  539. lpszCmdParam++;
  540. i=0;
  541. while (*lpszCmdParam)
  542. {
  543. if (*lpszCmdParam == _T(' '))
  544. break;
  545. if (i < sizeof(cacheType) / sizeof(DCTCHAR) -1)
  546. #ifdef UNICODE
  547. cacheType[i++] = (DCTCHAR) towupper(*lpszCmdParam);
  548. #else // UNICODE
  549. cacheType[i++] = (DCTCHAR) toupper(*lpszCmdParam);
  550. #endif // UNICODE
  551. lpszCmdParam++;
  552. }
  553. cacheType[i] = 0;
  554. if (memcmp(cacheType, "BITMAP", i) == 0)
  555. {
  556. _SH.fClearPersistBitmapCache = TRUE;
  557. }
  558. else
  559. {
  560. TRC_NRM((TB,_T("Invalid Cache Type - %s"), cacheType));
  561. }
  562. DC_END_FN();
  563. return(lpszCmdParam);
  564. }
  565. //
  566. // Take the session in _SH.regSession and figure out
  567. // if it is a file or a registry session
  568. //
  569. // We need to do this because for compatability reasons
  570. // the client has to be able to support both a file name
  571. // and the registry session name as default command line
  572. // params (enter this logic to determine which is which).
  573. //
  574. //
  575. // Return TRUE if it's a valid reg or connection param
  576. // or FALSE otherwise
  577. //
  578. BOOL CSH::ParseFileOrRegConnectionParam()
  579. {
  580. BOOL fRet = TRUE;
  581. DC_BEGIN_FN("ParseFileOrRegConnectionParam");
  582. //
  583. // If a connection parameter is specified that is
  584. // different from the default
  585. //
  586. if(_tcscmp(_SH.regSession, SH_DEFAULT_REG_SESSION)) {
  587. //
  588. // A connection parameter is specified
  589. // check for the three possible cases
  590. // 1) it's an RDP file
  591. // 2) it's a registry connection
  592. // 3) it's INVALID!
  593. //
  594. //a) check if the session is really a file
  595. if (SH_FileExists(_SH.regSession)) {
  596. _tcsncpy(_szFileName, _SH.regSession,
  597. SIZECHAR(_szFileName));
  598. _fFileForConnect = TRUE;
  599. _SH.autoConnectEnabled = TRUE;
  600. SetRegSessionSpecified(FALSE);
  601. }
  602. else if (SH_TSSettingsRegKeyExists(_SH.regSession)) {
  603. //Assume it's an old registry style session name
  604. SetRegSessionSpecified(TRUE);
  605. }
  606. else {
  607. TRC_ERR((TB,_T("Reg session is neither file nore reg key: %s"),
  608. _SH.regSession));
  609. fRet = FALSE;
  610. }
  611. }
  612. DC_END_FN();
  613. return fRet;
  614. }
  615. #ifndef OS_WINCE
  616. //
  617. // Copy of StrRetToStrW from \shell\shlwapi\strings.c
  618. //
  619. //
  620. // dupe a string using the task allocator for returing from a COM interface
  621. //
  622. HRESULT XSHStrDupA(LPCSTR psz, WCHAR **ppwsz)
  623. {
  624. WCHAR *pwsz;
  625. DWORD cch;
  626. //RIPMSG(psz && IS_VALID_STRING_PTRA(psz, -1), "SHStrDupA: Caller passed invalid psz");
  627. if (psz)
  628. {
  629. cch = MultiByteToWideChar(CP_ACP, 0, psz, -1, NULL, 0);
  630. pwsz = (WCHAR *)CoTaskMemAlloc((cch + 1) * sizeof(WCHAR));
  631. }
  632. else
  633. pwsz = NULL;
  634. *((PVOID UNALIGNED64 *) ppwsz) = pwsz;
  635. if (pwsz)
  636. {
  637. MultiByteToWideChar(CP_ACP, 0, psz, -1, *ppwsz, cch);
  638. return S_OK;
  639. }
  640. return E_OUTOFMEMORY;
  641. }
  642. HRESULT XStrRetToStrW(LPSTRRET psr, LPCITEMIDLIST pidl, WCHAR **ppsz)
  643. {
  644. HRESULT hres = S_OK;
  645. switch (psr->uType)
  646. {
  647. case STRRET_WSTR:
  648. *ppsz = psr->DUMMYUNIONNAME.pOleStr;
  649. psr->DUMMYUNIONNAME.pOleStr = NULL; // avoid alias
  650. hres = *ppsz ? S_OK : E_FAIL;
  651. break;
  652. case STRRET_OFFSET:
  653. hres = XSHStrDupA(STRRET_OFFPTR(pidl, psr), ppsz);
  654. break;
  655. case STRRET_CSTR:
  656. hres = XSHStrDupA(psr->DUMMYUNIONNAME.cStr, ppsz);
  657. break;
  658. default:
  659. *ppsz = NULL;
  660. hres = E_FAIL;
  661. }
  662. return hres;
  663. }
  664. #endif