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.

1991 lines
48 KiB

  1. /* Copyright (c) 1995, Microsoft Corporation, all rights reserved
  2. **
  3. ** noui.c
  4. ** Non-UI helper routines (no HWNDs required)
  5. ** Listed alphabetically
  6. **
  7. ** 08/25/95 Steve Cobb
  8. */
  9. #include <windows.h> // Win32 root
  10. #include <stdlib.h> // for atol()
  11. #include <nouiutil.h> // Our public header
  12. #include <debug.h> // Trace/Assert library
  13. #include <nnetcfg.h>
  14. WCHAR*
  15. StrDupWFromAInternal(
  16. LPCSTR psz,
  17. UINT uiCodePage);
  18. INT
  19. ComparePszNode(
  20. IN DTLNODE* pNode1,
  21. IN DTLNODE* pNode2 )
  22. /* Callback for DtlMergeSort; takes two DTLNODE*'s whose data
  23. ** are assumed to be strings (TCHAR*), and compares the strings.
  24. **
  25. ** Return value is as defined for 'lstrcmpi'.
  26. */
  27. {
  28. return lstrcmpi( (TCHAR *)DtlGetData(pNode1), (TCHAR *)DtlGetData(pNode2) );
  29. }
  30. DWORD
  31. CreateDirectoriesOnPath(
  32. LPTSTR pszPath,
  33. LPSECURITY_ATTRIBUTES psa)
  34. {
  35. DWORD dwErr = ERROR_SUCCESS;
  36. if (pszPath && *pszPath)
  37. {
  38. LPTSTR pch = pszPath;
  39. // If the path is a UNC path, we need to skip the \\server\share
  40. // portion.
  41. //
  42. if ((TEXT('\\') == *pch) && (TEXT('\\') == *(pch+1)))
  43. {
  44. // pch now pointing at the server name. Skip to the backslash
  45. // before the share name.
  46. //
  47. pch += 2;
  48. while (*pch && (TEXT('\\') != *pch))
  49. {
  50. pch++;
  51. }
  52. if (!*pch)
  53. {
  54. // Just the \\server was specified. This is bogus.
  55. //
  56. return ERROR_INVALID_PARAMETER;
  57. }
  58. // pch now pointing at the backslash before the share name.
  59. // Skip to the backslash that should come after the share name.
  60. //
  61. pch++;
  62. while (*pch && (TEXT('\\') != *pch))
  63. {
  64. pch++;
  65. }
  66. if (!*pch)
  67. {
  68. // Just the \\server\share was specified. No subdirectories
  69. // to create.
  70. //
  71. return ERROR_SUCCESS;
  72. }
  73. }
  74. // Loop through the path.
  75. //
  76. for (; *pch; pch++)
  77. {
  78. // Stop at each backslash and make sure the path
  79. // is created to that point. Do this by changing the
  80. // backslash to a null-terminator, calling CreateDirecotry,
  81. // and changing it back.
  82. //
  83. if (TEXT('\\') == *pch)
  84. {
  85. BOOL fOk;
  86. *pch = 0;
  87. fOk = CreateDirectory (pszPath, psa);
  88. *pch = TEXT('\\');
  89. // Any errors other than path alredy exists and we should
  90. // bail out. We also get access denied when trying to
  91. // create a root drive (i.e. c:) so check for this too.
  92. //
  93. if (!fOk)
  94. {
  95. dwErr = GetLastError ();
  96. if (ERROR_ALREADY_EXISTS == dwErr)
  97. {
  98. dwErr = ERROR_SUCCESS;
  99. }
  100. else if ((ERROR_ACCESS_DENIED == dwErr) &&
  101. (pch - 1 > pszPath) && (TEXT(':') == *(pch - 1)))
  102. {
  103. dwErr = ERROR_SUCCESS;
  104. }
  105. else
  106. {
  107. break;
  108. }
  109. }
  110. }
  111. }
  112. if (ERROR_ALREADY_EXISTS == dwErr)
  113. {
  114. dwErr = ERROR_SUCCESS;
  115. }
  116. }
  117. return dwErr;
  118. }
  119. DTLNODE*
  120. CreateKvNode(
  121. IN LPCTSTR pszKey,
  122. IN LPCTSTR pszValue )
  123. /* Returns a KEYVALUE node containing a copy of 'pszKey' and 'pszValue' or
  124. ** NULL on error. It is caller's responsibility to DestroyKvNode the
  125. ** returned node.
  126. */
  127. {
  128. DTLNODE* pNode;
  129. KEYVALUE* pkv;
  130. pNode = DtlCreateSizedNode( sizeof(KEYVALUE), 0L );
  131. if (!pNode)
  132. return NULL;
  133. pkv = (KEYVALUE* )DtlGetData( pNode );
  134. ASSERT( pkv );
  135. pkv->pszKey = StrDup( pszKey );
  136. pkv->pszValue = StrDup( pszValue );
  137. if (!pkv->pszKey || !pkv->pszValue)
  138. {
  139. DestroyKvNode( pNode );
  140. return NULL;
  141. }
  142. return pNode;
  143. }
  144. DTLNODE*
  145. CreatePszNode(
  146. IN LPCTSTR psz )
  147. /* Returns a node containing a copy of 'psz' or NULL on error. It is
  148. ** caller's responsibility to DestroyPszNode the returned node.
  149. */
  150. {
  151. TCHAR* pszData;
  152. DTLNODE* pNode;
  153. pszData = StrDup( psz );
  154. if (!pszData)
  155. return NULL;
  156. pNode = DtlCreateNode( pszData, 0L );
  157. if (!pNode)
  158. {
  159. Free( pszData );
  160. return NULL;
  161. }
  162. return pNode;
  163. }
  164. VOID
  165. DestroyPszNode(
  166. IN DTLNODE* pdtlnode )
  167. /* Release memory associated with string (or any simple Malloc) node
  168. ** 'pdtlnode'. See DtlDestroyList.
  169. */
  170. {
  171. TCHAR* psz;
  172. ASSERT(pdtlnode);
  173. psz = (TCHAR* )DtlGetData( pdtlnode );
  174. Free0( psz );
  175. DtlDestroyNode( pdtlnode );
  176. }
  177. VOID
  178. DestroyKvNode(
  179. IN DTLNODE* pdtlnode )
  180. /* Release memory associated with a KEYVALUE node 'pdtlnode'. See
  181. ** DtlDestroyList.
  182. */
  183. {
  184. KEYVALUE* pkv;
  185. ASSERT(pdtlnode);
  186. pkv = (KEYVALUE* )DtlGetData( pdtlnode );
  187. ASSERT(pkv);
  188. Free0( pkv->pszKey );
  189. Free0( pkv->pszValue );
  190. DtlDestroyNode( pdtlnode );
  191. }
  192. BOOL
  193. DeviceAndPortFromPsz(
  194. IN TCHAR* pszDP,
  195. OUT TCHAR** ppszDevice,
  196. OUT TCHAR** ppszPort )
  197. /* Loads '*ppszDevice' and '*ppszPort' with the parsed out device and port
  198. ** names from 'pszDP', a display string created with PszFromDeviceAndPort.
  199. **
  200. ** Returns true if successful, false if 'pszDP' is not of the stated form.
  201. ** It is caller's responsibility to Free the returned '*ppszDevice' and
  202. ** '*ppszPort'.
  203. */
  204. {
  205. TCHAR szDP[ RAS_MaxDeviceName + 2 + MAX_PORT_NAME + 1 + 1 ];
  206. INT cb;
  207. *ppszDevice = NULL;
  208. *ppszPort = NULL;
  209. lstrcpyn( szDP, pszDP, sizeof(szDP) / sizeof(TCHAR) );
  210. cb = lstrlen( szDP );
  211. if (cb > 0)
  212. {
  213. TCHAR* pch;
  214. pch = szDP + cb;
  215. pch = CharPrev( szDP, pch );
  216. while (pch != szDP)
  217. {
  218. if (*pch == TEXT(')'))
  219. {
  220. *pch = TEXT('\0');
  221. }
  222. else if (*pch == TEXT('('))
  223. {
  224. *ppszPort = StrDup( CharNext( pch ) );
  225. // [pmay] backup trailing spaces
  226. pch--;
  227. while ((*pch == TEXT(' ')) && (pch != szDP))
  228. pch--;
  229. pch++;
  230. *pch = TEXT('\0');
  231. *ppszDevice = StrDup( szDP );
  232. break;
  233. }
  234. pch = CharPrev( szDP, pch );
  235. }
  236. }
  237. return (*ppszDevice && *ppszPort);
  238. }
  239. DTLNODE*
  240. DuplicateKvNode(
  241. IN DTLNODE* pdtlnode )
  242. /* Duplicates KEYVALUE node 'pdtlnode'. See DtlDuplicateList.
  243. **
  244. ** Returns the address of the allocated node or NULL if out of memory. It
  245. ** is caller's responsibility to free the returned node.
  246. */
  247. {
  248. DTLNODE* pNode;
  249. KEYVALUE* pKv;
  250. pKv = (KEYVALUE* )DtlGetData( pdtlnode );
  251. ASSERT(pKv);
  252. pNode = CreateKvNode( pKv->pszKey, pKv->pszValue );
  253. if (pNode)
  254. {
  255. DtlPutNodeId( pNode, DtlGetNodeId( pdtlnode ) );
  256. }
  257. return pNode;
  258. }
  259. DTLNODE*
  260. DuplicatePszNode(
  261. IN DTLNODE* pdtlnode )
  262. /* Duplicates string node 'pdtlnode'. See DtlDuplicateList.
  263. **
  264. ** Returns the address of the allocated node or NULL if out of memory. It
  265. ** is caller's responsibility to free the returned node.
  266. */
  267. {
  268. DTLNODE* pNode;
  269. TCHAR* psz;
  270. psz = (TCHAR* )DtlGetData( pdtlnode );
  271. ASSERT(psz);
  272. pNode = CreatePszNode( psz );
  273. if (pNode)
  274. {
  275. DtlPutNodeId( pNode, DtlGetNodeId( pdtlnode ) );
  276. }
  277. return pNode;
  278. }
  279. BOOL
  280. FFileExists(
  281. IN TCHAR* pszPath )
  282. /* Returns true if the path 'pszPath' exists, false otherwise.
  283. */
  284. {
  285. WIN32_FIND_DATA finddata;
  286. HANDLE h;
  287. DWORD dwErr;
  288. if ((h = FindFirstFile( pszPath, &finddata )) != INVALID_HANDLE_VALUE)
  289. {
  290. FindClose( h );
  291. return TRUE;
  292. }
  293. dwErr = GetLastError();
  294. TRACE1("FindFirstFile failed with 0x%x",
  295. dwErr);
  296. return FALSE;
  297. }
  298. BOOL
  299. FIsTcpipInstalled()
  300. {
  301. BOOL fInstalled;
  302. SC_HANDLE ScmHandle;
  303. ScmHandle = OpenSCManager(NULL, NULL, GENERIC_READ);
  304. if (!ScmHandle) {
  305. fInstalled = FALSE;
  306. } else {
  307. static const TCHAR c_szTcpip[] = TEXT("Tcpip");
  308. SC_HANDLE ServiceHandle;
  309. ServiceHandle = OpenService(ScmHandle, c_szTcpip, SERVICE_QUERY_STATUS);
  310. if (!ServiceHandle) {
  311. fInstalled = FALSE;
  312. } else {
  313. SERVICE_STATUS ServiceStatus;
  314. if (!QueryServiceStatus(ServiceHandle, &ServiceStatus)) {
  315. fInstalled = FALSE;
  316. } else {
  317. fInstalled = (ServiceStatus.dwCurrentState == SERVICE_RUNNING);
  318. }
  319. CloseServiceHandle(ServiceHandle);
  320. }
  321. CloseServiceHandle(ScmHandle);
  322. }
  323. return fInstalled;
  324. }
  325. BOOL
  326. FIsUserAdminOrPowerUser()
  327. {
  328. SID_IDENTIFIER_AUTHORITY SidAuth = SECURITY_NT_AUTHORITY;
  329. PSID psid;
  330. BOOL fIsMember = FALSE;
  331. BOOL fRet = FALSE;
  332. SID sidLocalSystem = { 1, 1,
  333. SECURITY_NT_AUTHORITY,
  334. SECURITY_LOCAL_SYSTEM_RID };
  335. // Check to see if running under local system first
  336. //
  337. if (!CheckTokenMembership( NULL, &sidLocalSystem, &fIsMember ))
  338. {
  339. TRACE( "CheckTokenMemberShip for local system failed.");
  340. fIsMember = FALSE;
  341. }
  342. fRet = fIsMember;
  343. if (!fIsMember)
  344. {
  345. // Allocate a SID for the Administrators group and check to see
  346. // if the user is a member.
  347. //
  348. if (AllocateAndInitializeSid( &SidAuth, 2,
  349. SECURITY_BUILTIN_DOMAIN_RID,
  350. DOMAIN_ALIAS_RID_ADMINS,
  351. 0, 0, 0, 0, 0, 0,
  352. &psid ))
  353. {
  354. if (!CheckTokenMembership( NULL, psid, &fIsMember ))
  355. {
  356. TRACE( "CheckTokenMemberShip for admins failed.");
  357. fIsMember = FALSE;
  358. }
  359. FreeSid( psid );
  360. // Changes to the Windows 2000 permission model mean that regular Users
  361. // on workstations are in the power user group. So we no longer want to
  362. // check for power user.
  363. #if 0
  364. if (!fIsMember)
  365. {
  366. // They're not a member of the Administrators group so allocate a
  367. // SID for the Power Users group and check to see
  368. // if the user is a member.
  369. //
  370. if (AllocateAndInitializeSid( &SidAuth, 2,
  371. SECURITY_BUILTIN_DOMAIN_RID,
  372. DOMAIN_ALIAS_RID_POWER_USERS,
  373. 0, 0, 0, 0, 0, 0,
  374. &psid ))
  375. {
  376. if (!CheckTokenMembership( NULL, psid, &fIsMember ))
  377. {
  378. TRACE( "CheckTokenMemberShip for power users failed.");
  379. fIsMember = FALSE;
  380. }
  381. FreeSid( psid );
  382. }
  383. }
  384. #endif
  385. }
  386. fRet = fIsMember;
  387. }
  388. return fRet;
  389. }
  390. VOID*
  391. Free0(
  392. VOID* p )
  393. /* Like Free, but deals with NULL 'p'.
  394. */
  395. {
  396. if (!p)
  397. return NULL;
  398. return Free( p );
  399. }
  400. DWORD
  401. GetInstalledProtocols(
  402. void
  403. )
  404. {
  405. ASSERT(FALSE);
  406. return 0 ;
  407. }
  408. LONG
  409. RegQueryDword (HKEY hkey, LPCTSTR szValueName, LPDWORD pdwValue)
  410. {
  411. // Get the value.
  412. //
  413. DWORD dwType;
  414. DWORD cbData = sizeof(DWORD);
  415. LONG lr = RegQueryValueEx (hkey, szValueName, NULL, &dwType,
  416. (LPBYTE)pdwValue, &cbData);
  417. // It's type should be REG_DWORD. (duh).
  418. //
  419. if ((ERROR_SUCCESS == lr) && (REG_DWORD != dwType))
  420. {
  421. lr = ERROR_INVALID_DATATYPE;
  422. }
  423. // Make sure we initialize the output value on error.
  424. // (We don't know for sure that RegQueryValueEx does this.)
  425. //
  426. if (ERROR_SUCCESS != lr)
  427. {
  428. *pdwValue = 0;
  429. }
  430. return lr;
  431. }
  432. BOOL
  433. FProtocolEnabled(
  434. HKEY hkeyProtocol,
  435. BOOL fRasSrv,
  436. BOOL fRouter )
  437. {
  438. static const TCHAR c_szRegValEnableIn[] = TEXT("EnableIn");
  439. static const TCHAR c_szRegValEnableRoute[] = TEXT("EnableRoute");
  440. DWORD dwValue;
  441. LONG lr;
  442. if (fRasSrv)
  443. {
  444. lr = RegQueryDword(hkeyProtocol, c_szRegValEnableIn, &dwValue);
  445. if ((ERROR_FILE_NOT_FOUND == lr) ||
  446. ((ERROR_SUCCESS == lr) && (dwValue != 0)))
  447. {
  448. return TRUE;
  449. }
  450. }
  451. if (fRouter)
  452. {
  453. lr = RegQueryDword(hkeyProtocol, c_szRegValEnableRoute, &dwValue);
  454. if ((ERROR_FILE_NOT_FOUND == lr) ||
  455. ((ERROR_SUCCESS == lr) && (dwValue != 0)))
  456. {
  457. return TRUE;
  458. }
  459. }
  460. return FALSE;
  461. }
  462. DWORD
  463. DwGetInstalledProtocolsEx(
  464. BOOL fRouter,
  465. BOOL fRasCli,
  466. BOOL fRasSrv )
  467. /* Returns a bit field containing NP_<protocol> flags for the installed
  468. ** PPP protocols. The term "installed" here includes enabling in RAS
  469. ** Setup.
  470. */
  471. {
  472. static const TCHAR c_szRegKeyIp[] = TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip");
  473. static const TCHAR c_szRegKeyIpx[] = TEXT("SYSTEM\\CurrentControlSet\\Services\\NwlnkIpx");
  474. static const TCHAR c_szRegKeyNbf[] = TEXT("SYSTEM\\CurrentControlSet\\Services\\Nbf");
  475. static const TCHAR c_szRegKeyRemoteAccessParams[] =
  476. TEXT("SYSTEM\\CurrentControlSet\\Services\\RemoteAccess\\Parameters");
  477. static const TCHAR c_szRegSubkeyIp[] = TEXT("Ip");
  478. static const TCHAR c_szRegSubkeyIpx[] = TEXT("Ipx");
  479. static const TCHAR c_szRegSubkeyNbf[] = TEXT("Nbf");
  480. DWORD dwfInstalledProtocols = 0;
  481. // First check if the protocols are installed.
  482. //
  483. struct INSTALLED_PROTOCOL_INFO
  484. {
  485. DWORD dwFlag;
  486. LPCTSTR pszRegKey;
  487. LPCTSTR pszSubkey;
  488. };
  489. static const struct INSTALLED_PROTOCOL_INFO c_aProtocolInfo[] =
  490. {
  491. { NP_Ip, c_szRegKeyIp, c_szRegSubkeyIp },
  492. { NP_Ipx, c_szRegKeyIpx, c_szRegSubkeyIpx },
  493. { NP_Nbf, c_szRegKeyNbf, c_szRegSubkeyNbf },
  494. };
  495. #define celems(_x) (sizeof(_x) / sizeof(_x[0]))
  496. HKEY hkey;
  497. int i;
  498. for (i = 0; i < celems (c_aProtocolInfo); i++)
  499. {
  500. const struct INSTALLED_PROTOCOL_INFO* pInfo = c_aProtocolInfo + i;
  501. if (RegOpenKey( HKEY_LOCAL_MACHINE, pInfo->pszRegKey, &hkey ) == 0)
  502. {
  503. dwfInstalledProtocols |= pInfo->dwFlag;
  504. RegCloseKey( hkey );
  505. }
  506. }
  507. // Now see if they are to be used for the router and/or server.
  508. // The client uses the protocols if they are installed and not excluded
  509. // in the phonebook entry.
  510. //
  511. if ((fRouter || fRasSrv) && dwfInstalledProtocols)
  512. {
  513. if (RegOpenKey( HKEY_LOCAL_MACHINE, c_szRegKeyRemoteAccessParams, &hkey ) == 0)
  514. {
  515. for (i = 0; i < celems (c_aProtocolInfo); i++)
  516. {
  517. const struct INSTALLED_PROTOCOL_INFO* pInfo = c_aProtocolInfo + i;
  518. // If the protocol is installed (as determined above), check
  519. // to see if its enabled.
  520. //
  521. if (dwfInstalledProtocols & pInfo->dwFlag)
  522. {
  523. HKEY hkeyProtocol;
  524. if (RegOpenKey( hkey, pInfo->pszSubkey, &hkeyProtocol ) == 0)
  525. {
  526. if (!FProtocolEnabled( hkeyProtocol, fRasSrv, fRouter ))
  527. {
  528. dwfInstalledProtocols &= ~pInfo->dwFlag;
  529. }
  530. RegCloseKey( hkeyProtocol );
  531. }
  532. }
  533. }
  534. RegCloseKey( hkey );
  535. }
  536. else
  537. {
  538. dwfInstalledProtocols = 0;
  539. }
  540. }
  541. TRACE1("GetInstalledProtocolsEx=$%x. ",dwfInstalledProtocols);
  542. return dwfInstalledProtocols;
  543. }
  544. DWORD
  545. GetInstalledProtocolsEx(HANDLE hConnection,
  546. BOOL fRouter,
  547. BOOL fRasCli,
  548. BOOL fRasSrv)
  549. {
  550. RAS_RPC *pRasRpcConnection = (RAS_RPC *) hConnection;
  551. if( NULL == pRasRpcConnection
  552. || pRasRpcConnection->fLocal)
  553. {
  554. return DwGetInstalledProtocolsEx(fRouter,
  555. fRasCli,
  556. fRasSrv);
  557. }
  558. else
  559. {
  560. //
  561. // Remote Server
  562. //
  563. return RemoteGetInstalledProtocolsEx(hConnection,
  564. fRouter,
  565. fRasCli,
  566. fRasSrv);
  567. }
  568. }
  569. /*
  570. DWORD
  571. GetInstalledProtocolsEx(
  572. BOOL fRouter,
  573. BOOL fRasCli,
  574. BOOL fRasSrv )
  575. {
  576. DWORD dwRetCode;
  577. DWORD dwfInstalledProtocols;
  578. dwRetCode = dwGetInstalledProtocols ( &dwfInstalledProtocols,
  579. fRouter,
  580. fRasCli,
  581. fRasSrv);
  582. TRACE2("GetInstalledProtocols=$%x. dwErr = %d",dwfInstalledProtocols, dwRetCode);
  583. return dwfInstalledProtocols;
  584. } */
  585. CHAR
  586. HexChar(
  587. IN BYTE byte )
  588. /* Returns an ASCII hexidecimal character corresponding to 0 to 15 value,
  589. ** 'byte'.
  590. */
  591. {
  592. const CHAR* pszHexDigits = "0123456789ABCDEF";
  593. if (byte >= 0 && byte < 16)
  594. return pszHexDigits[ byte ];
  595. else
  596. return '0';
  597. }
  598. BYTE
  599. HexValue(
  600. IN CHAR ch )
  601. /* Returns the value 0 to 15 of hexadecimal character 'ch'.
  602. */
  603. {
  604. if (ch >= '0' && ch <= '9')
  605. return (BYTE )(ch - '0');
  606. else if (ch >= 'A' && ch <= 'F')
  607. return (BYTE )((ch - 'A') + 10);
  608. else if (ch >= 'a' && ch <= 'f')
  609. return (BYTE )((ch - 'a') + 10);
  610. else
  611. return 0;
  612. }
  613. BOOL
  614. IsAllWhite(
  615. IN LPCTSTR psz )
  616. /* Returns true if 'psz' consists entirely of spaces and tabs. NULL
  617. ** pointers and empty strings are considered all white. Otherwise,
  618. ** returns false.
  619. */
  620. {
  621. LPCTSTR pszThis;
  622. for (pszThis = psz; *pszThis != TEXT('\0'); ++pszThis)
  623. {
  624. if (*pszThis != TEXT(' ') && *pszThis != TEXT('\t'))
  625. return FALSE;
  626. }
  627. return TRUE;
  628. }
  629. void
  630. IpHostAddrToPsz(
  631. IN DWORD dwAddr,
  632. OUT LPTSTR pszBuffer )
  633. // Converts an IP address in host byte order to its
  634. // string representation.
  635. // pszBuffer should be allocated by the caller and be
  636. // at least 16 characters long.
  637. //
  638. {
  639. BYTE* pb = (BYTE*)&dwAddr;
  640. static const TCHAR c_szIpAddr [] = TEXT("%d.%d.%d.%d");
  641. wsprintf (pszBuffer, c_szIpAddr, pb[3], pb[2], pb[1], pb[0]);
  642. }
  643. DWORD
  644. IpPszToHostAddr(
  645. IN LPCTSTR cp )
  646. // Converts an IP address represented as a string to
  647. // host byte order.
  648. //
  649. {
  650. DWORD val, base, n;
  651. TCHAR c;
  652. DWORD parts[4], *pp = parts;
  653. again:
  654. // Collect number up to ``.''.
  655. // Values are specified as for C:
  656. // 0x=hex, 0=octal, other=decimal.
  657. //
  658. val = 0; base = 10;
  659. if (*cp == TEXT('0'))
  660. base = 8, cp++;
  661. if (*cp == TEXT('x') || *cp == TEXT('X'))
  662. base = 16, cp++;
  663. while (c = *cp)
  664. {
  665. if ((c >= TEXT('0')) && (c <= TEXT('9')))
  666. {
  667. val = (val * base) + (c - TEXT('0'));
  668. cp++;
  669. continue;
  670. }
  671. if ((base == 16) &&
  672. ( ((c >= TEXT('0')) && (c <= TEXT('9'))) ||
  673. ((c >= TEXT('A')) && (c <= TEXT('F'))) ||
  674. ((c >= TEXT('a')) && (c <= TEXT('f'))) ))
  675. {
  676. val = (val << 4) + (c + 10 - (
  677. ((c >= TEXT('a')) && (c <= TEXT('f')))
  678. ? TEXT('a')
  679. : TEXT('A') ) );
  680. cp++;
  681. continue;
  682. }
  683. break;
  684. }
  685. if (*cp == TEXT('.'))
  686. {
  687. // Internet format:
  688. // a.b.c.d
  689. // a.b.c (with c treated as 16-bits)
  690. // a.b (with b treated as 24 bits)
  691. //
  692. if (pp >= parts + 3)
  693. return (DWORD) -1;
  694. *pp++ = val, cp++;
  695. goto again;
  696. }
  697. // Check for trailing characters.
  698. //
  699. if (*cp && (*cp != TEXT(' ')))
  700. return 0xffffffff;
  701. *pp++ = val;
  702. // Concoct the address according to
  703. // the number of parts specified.
  704. //
  705. n = (DWORD) (pp - parts);
  706. switch (n)
  707. {
  708. case 1: // a -- 32 bits
  709. val = parts[0];
  710. break;
  711. case 2: // a.b -- 8.24 bits
  712. val = (parts[0] << 24) | (parts[1] & 0xffffff);
  713. break;
  714. case 3: // a.b.c -- 8.8.16 bits
  715. val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
  716. (parts[2] & 0xffff);
  717. break;
  718. case 4: // a.b.c.d -- 8.8.8.8 bits
  719. val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
  720. ((parts[2] & 0xff) << 8) | (parts[3] & 0xff);
  721. break;
  722. default:
  723. return 0xffffffff;
  724. }
  725. return val;
  726. }
  727. #if 0
  728. BOOL
  729. IsNullTerminatedA(
  730. IN CHAR* psz,
  731. IN DWORD dwSize )
  732. /* Returns true is 'psz' contains a null character somewhere in it's
  733. ** 'dwSize' bytes, false otherwise.
  734. */
  735. {
  736. CHAR* pszThis;
  737. CHAR* pszEnd;
  738. pszEnd = psz + dwSize;
  739. for (pszThis = psz; pszThis < pszEnd; ++pszThis)
  740. {
  741. if (*pszThis == '\0')
  742. return TRUE;
  743. }
  744. return FALSE;
  745. }
  746. #endif
  747. TCHAR*
  748. LToT(
  749. LONG lValue,
  750. TCHAR* pszBuf,
  751. INT nRadix )
  752. /* Like ltoa, but returns TCHAR*.
  753. */
  754. {
  755. #ifdef UNICODE
  756. WCHAR szBuf[ MAXLTOTLEN + 1 ];
  757. ASSERT(nRadix==10||nRadix==16);
  758. if (nRadix == 10)
  759. wsprintf( pszBuf, TEXT("%d"), lValue );
  760. else
  761. wsprintf( pszBuf, TEXT("%x"), lValue );
  762. #else
  763. _ltoa( lValue, pszBuf, nRadix );
  764. #endif
  765. return pszBuf;
  766. }
  767. LONG
  768. TToL(
  769. TCHAR *pszBuf )
  770. /* Like atol, but accepts TCHAR*.
  771. */
  772. {
  773. CHAR* psz;
  774. CHAR szBuf[ MAXLTOTLEN + 1 ];
  775. #ifdef UNICODE
  776. psz = szBuf;
  777. WideCharToMultiByte(
  778. CP_ACP, 0, pszBuf, -1, psz, MAXLTOTLEN + 1, NULL, NULL );
  779. #else
  780. psz = pszBuf;
  781. #endif
  782. return atol( psz );
  783. }
  784. TCHAR*
  785. PszFromDeviceAndPort(
  786. IN TCHAR* pszDevice,
  787. IN TCHAR* pszPort )
  788. /* Returns address of heap block psz containing the MXS modem list display
  789. ** form, i.e. the device name 'pszDevice' followed by the port name
  790. ** 'pszPort'. It's caller's responsibility to Free the returned string.
  791. */
  792. {
  793. /* If you're thinking of changing this format string be aware that
  794. ** DeviceAndPortFromPsz parses it.
  795. */
  796. const TCHAR* pszF = TEXT("%s (%s)");
  797. TCHAR* pszResult;
  798. TCHAR* pszD;
  799. TCHAR* pszP;
  800. if (pszDevice)
  801. pszD = pszDevice;
  802. else
  803. pszD = TEXT("");
  804. if (pszPort)
  805. pszP = pszPort;
  806. else
  807. pszP = TEXT("");
  808. pszResult = Malloc(
  809. (lstrlen( pszD ) + lstrlen( pszP ) + lstrlen( pszF ) + 1)
  810. * sizeof(TCHAR) );
  811. if (pszResult)
  812. wsprintf( pszResult, pszF, pszD, pszP );
  813. return pszResult;
  814. }
  815. TCHAR*
  816. PszFromId(
  817. IN HINSTANCE hInstance,
  818. IN DWORD dwStringId )
  819. /* String resource message loader routine.
  820. **
  821. ** Returns the address of a heap block containing the string corresponding
  822. ** to string resource 'dwStringId' or NULL if error. It is caller's
  823. ** responsibility to Free the returned string.
  824. */
  825. {
  826. HRSRC hrsrc;
  827. TCHAR* pszBuf = NULL;
  828. int cchBuf = 256;
  829. int cchGot;
  830. for (;;)
  831. {
  832. pszBuf = Malloc( cchBuf * sizeof(TCHAR) );
  833. if (!pszBuf)
  834. break;
  835. /* LoadString wants to deal with character-counts rather than
  836. ** byte-counts...weird. Oh, and if you're thinking I could
  837. ** FindResource then SizeofResource to figure out the string size, be
  838. ** advised it doesn't work. From perusing the LoadString source, it
  839. ** appears the RT_STRING resource type requests a segment of 16
  840. ** strings not an individual string.
  841. */
  842. cchGot = LoadString( hInstance, (UINT )dwStringId, pszBuf, cchBuf );
  843. if (cchGot < cchBuf - 1)
  844. {
  845. /* Good, got the whole string. Reduce heap block to actual size
  846. ** needed.
  847. */
  848. // For whistler 517008
  849. //
  850. TCHAR *pszTemp = NULL;
  851. pszTemp = Realloc( pszBuf, (cchGot + 1) * sizeof(TCHAR));
  852. if ( NULL == pszTemp )
  853. {
  854. Free(pszBuf);
  855. pszBuf = NULL;
  856. }
  857. else
  858. {
  859. pszBuf = pszTemp;
  860. }
  861. break;
  862. }
  863. /* Uh oh, LoadStringW filled the buffer entirely which could mean the
  864. ** string was truncated. Try again with a larger buffer to be sure it
  865. ** wasn't.
  866. */
  867. Free( pszBuf );
  868. pszBuf = NULL;
  869. cchBuf += 256;
  870. TRACE1("Grow string buf to %d",cchBuf);
  871. }
  872. return pszBuf;
  873. }
  874. #if 0
  875. TCHAR*
  876. PszFromError(
  877. IN DWORD dwError )
  878. /* Error message loader routine.
  879. **
  880. ** Returns the address of a heap block containing the error string
  881. ** corresponding to RAS or system error code 'dwMsgid' or NULL if error.
  882. ** It is caller's responsibility to Free the returned string.
  883. */
  884. {
  885. return NULL;
  886. }
  887. #endif
  888. BOOL
  889. RestartComputer()
  890. /* Called if user chooses to shut down the computer.
  891. **
  892. ** Return false if failure, true otherwise
  893. */
  894. {
  895. HANDLE hToken = NULL; /* handle to process token */
  896. TOKEN_PRIVILEGES tkp; /* ptr. to token structure */
  897. BOOL fResult; /* system shutdown flag */
  898. TRACE("RestartComputer");
  899. /* Enable the shutdown privilege */
  900. if (!OpenProcessToken( GetCurrentProcess(),
  901. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  902. &hToken))
  903. return FALSE;
  904. /* Get the LUID for shutdown privilege. */
  905. LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);
  906. tkp.PrivilegeCount = 1; /* one privilege to set */
  907. tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  908. /* Get shutdown privilege for this process. */
  909. AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0);
  910. /* Cannot test the return value of AdjustTokenPrivileges. */
  911. if (GetLastError() != ERROR_SUCCESS)
  912. {
  913. CloseHandle(hToken);
  914. return FALSE;
  915. }
  916. if( !ExitWindowsEx(EWX_REBOOT, 0))
  917. {
  918. CloseHandle(hToken);
  919. return FALSE;
  920. }
  921. /* Disable shutdown privilege. */
  922. tkp.Privileges[0].Attributes = 0;
  923. AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0);
  924. if (GetLastError() != ERROR_SUCCESS)
  925. {
  926. CloseHandle(hToken);
  927. return FALSE;
  928. }
  929. CloseHandle(hToken);
  930. return TRUE;
  931. }
  932. //+---------------------------------------------------------------------------
  933. //
  934. // Function: PszLoadStringPcch
  935. //
  936. // Purpose: Load a resource string. (This function will never return NULL.)
  937. //
  938. // Arguments:
  939. // hinst [in] Instance handle of module with the string resource.
  940. // unId [in] Resource ID of the string to load.
  941. // pcch [out] Pointer to returned character length.
  942. //
  943. // Returns: Pointer to the constant string.
  944. //
  945. // Author: shaunco 24 Mar 1997
  946. //
  947. // Notes: The loaded string is pointer directly into the read-only
  948. // resource section. Any attempt to write through this pointer
  949. // will generate an access violation.
  950. //
  951. // The implementations is referenced from "Win32 Binary Resource
  952. // Formats" (MSDN) 4.8 String Table Resources
  953. //
  954. // User must have RCOPTIONS = -N turned on in the sources file.
  955. //
  956. LPCTSTR
  957. PszLoadStringPcch (
  958. HINSTANCE hinst,
  959. UINT unId,
  960. int* pcch)
  961. {
  962. static const WCHAR c_szwSpace[] = L" ";
  963. LPCWSTR pszw;
  964. int cch;
  965. HRSRC hrsrcInfo;
  966. ASSERT(hinst);
  967. ASSERT(unId);
  968. ASSERT(pcch);
  969. pszw = c_szwSpace;
  970. cch = 0;
  971. // String Tables are broken up into 16 string segments. Find the segment
  972. // containing the string we are interested in.
  973. hrsrcInfo = FindResource(hinst, (LPTSTR)UlongToPtr((LONG)(((USHORT)unId >> 4) + 1)),
  974. RT_STRING);
  975. if (hrsrcInfo)
  976. {
  977. // Page the resource segment into memory.
  978. HGLOBAL hglbSeg = LoadResource(hinst, hrsrcInfo);
  979. if (hglbSeg)
  980. {
  981. // Lock the resource.
  982. pszw = (LPCWSTR)LockResource(hglbSeg);
  983. if (pszw)
  984. {
  985. // Move past the other strings in this segment.
  986. // (16 strings in a segment -> & 0x0F)
  987. unId &= 0x0F;
  988. ASSERT(!cch); // first time through, cch should be zero
  989. do
  990. {
  991. pszw += cch; // Step to start of next string
  992. cch = *((WCHAR*)pszw++); // PASCAL like string count
  993. }
  994. while (unId--);
  995. if (!cch)
  996. {
  997. ASSERT(0); // String resource not found
  998. pszw = c_szwSpace;
  999. }
  1000. }
  1001. else
  1002. {
  1003. pszw = c_szwSpace;
  1004. TRACE("PszLoadStringPcch: LockResource failed.");
  1005. }
  1006. }
  1007. else
  1008. TRACE("PszLoadStringPcch: LoadResource failed.");
  1009. }
  1010. else
  1011. TRACE("PszLoadStringPcch: FindResource failed.");
  1012. *pcch = cch;
  1013. ASSERT(*pcch);
  1014. ASSERT(pszw);
  1015. return pszw;
  1016. }
  1017. //+---------------------------------------------------------------------------
  1018. //
  1019. // Function: PszLoadString
  1020. //
  1021. // Purpose: Load a resource string. (This function will never return NULL.)
  1022. //
  1023. // Arguments:
  1024. // hinst [in] Instance handle of module with the string resource.
  1025. // unId [in] Resource ID of the string to load.
  1026. //
  1027. // Returns: Pointer to the constant string.
  1028. //
  1029. // Author: shaunco 24 Mar 1997
  1030. //
  1031. // Notes: See PszLoadStringPcch()
  1032. //
  1033. LPCTSTR
  1034. PszLoadString (
  1035. HINSTANCE hinst,
  1036. UINT unId)
  1037. {
  1038. int cch;
  1039. return PszLoadStringPcch (hinst, unId, &cch);
  1040. }
  1041. DWORD
  1042. ShellSort(
  1043. IN VOID* pItemTable,
  1044. IN DWORD dwItemSize,
  1045. IN DWORD dwItemCount,
  1046. IN PFNCOMPARE pfnCompare )
  1047. /* Sort an array of items in-place using shell-sort.
  1048. ** This function calls ShellSortIndirect to sort a table of pointers
  1049. ** to table items. We then move the items into place by copying.
  1050. ** This algorithm allows us to guarantee that the number
  1051. ** of copies necessary in the worst case is N + 1.
  1052. **
  1053. ** Note that if the caller merely needs to know the sorted order
  1054. ** of the array, ShellSortIndirect should be called since that function
  1055. ** avoids moving items altogether, and instead fills an array with pointers
  1056. ** to the array items in the correct order. The array items can then
  1057. ** be accessed through the array of pointers.
  1058. */
  1059. {
  1060. VOID** ppItemTable;
  1061. INT N;
  1062. INT i;
  1063. BYTE *a, **p, *t = NULL;
  1064. if (!dwItemCount) { return NO_ERROR; }
  1065. /* allocate space for the table of pointers.
  1066. */
  1067. ppItemTable = Malloc(dwItemCount * sizeof(VOID*));
  1068. if (!ppItemTable) { return ERROR_NOT_ENOUGH_MEMORY; }
  1069. /* call ShellSortIndirect to fill our table of pointers
  1070. ** with the sorted positions for each table element.
  1071. */
  1072. ShellSortIndirect(
  1073. pItemTable, ppItemTable, dwItemSize, dwItemCount, pfnCompare );
  1074. /* now that we know the sort order, move each table item into place.
  1075. ** This involves going through the table of pointers making sure
  1076. ** that the item which should be in 'i' is in fact in 'i', moving
  1077. ** things around if necessary to achieve this condition.
  1078. */
  1079. a = (BYTE*)pItemTable;
  1080. p = (BYTE**)ppItemTable;
  1081. N = (INT)dwItemCount;
  1082. for (i = 0; i < N; i++)
  1083. {
  1084. INT j, k;
  1085. BYTE* ai = (a + i * dwItemSize), *ak, *aj;
  1086. /* see if item 'i' is not in-place
  1087. */
  1088. if (p[i] != ai)
  1089. {
  1090. /* item 'i' isn't in-place, so we'll have to move it.
  1091. ** if we've delayed allocating a temporary buffer so far,
  1092. ** we'll need one now.
  1093. */
  1094. if (!t) {
  1095. t = Malloc(dwItemSize);
  1096. if (!t) { return ERROR_NOT_ENOUGH_MEMORY; }
  1097. }
  1098. /* save a copy of the item to be overwritten
  1099. */
  1100. CopyMemory(t, ai, dwItemSize);
  1101. k = i;
  1102. ak = ai;
  1103. /* Now move whatever item is occupying the space where it should be.
  1104. ** This may involve moving the item occupying the space where
  1105. ** it should be, etc.
  1106. */
  1107. do
  1108. {
  1109. /* copy the item which should be in position 'j'
  1110. ** over the item which is currently in position 'j'.
  1111. */
  1112. j = k;
  1113. aj = ak;
  1114. CopyMemory(aj, p[j], dwItemSize);
  1115. /* set 'k' to the position from which we copied
  1116. ** into position 'j'; this is where we will copy
  1117. ** the next out-of-place item in the array.
  1118. */
  1119. ak = p[j];
  1120. k = (INT)(ak - a) / dwItemSize;
  1121. /* keep the array of position pointers up-to-date;
  1122. ** the contents of 'aj' are now in their sorted position.
  1123. */
  1124. p[j] = aj;
  1125. } while (ak != ai);
  1126. /* now write the item which we first overwrote.
  1127. */
  1128. CopyMemory(aj, t, dwItemSize);
  1129. }
  1130. }
  1131. Free0(t);
  1132. Free(ppItemTable);
  1133. return NO_ERROR;
  1134. }
  1135. VOID
  1136. ShellSortIndirect(
  1137. IN VOID* pItemTable,
  1138. IN VOID** ppItemTable,
  1139. IN DWORD dwItemSize,
  1140. IN DWORD dwItemCount,
  1141. IN PFNCOMPARE pfnCompare )
  1142. /* Sorts an array of items indirectly using shell-sort.
  1143. ** 'pItemTable' points to the table of items, 'dwItemCount' is the number
  1144. ** of items in the table, and 'pfnCompare' is a function called
  1145. ** to compare items.
  1146. **
  1147. ** Rather than sort the items by moving them around,
  1148. ** we sort them by initializing the table of pointers 'ppItemTable'
  1149. ** with pointers such that 'ppItemTable[i]' contains a pointer
  1150. ** into 'pItemTable' for the item which would be in position 'i'
  1151. ** if 'pItemTable' were sorted.
  1152. **
  1153. ** For instance, given an array pItemTable of 5 strings as follows
  1154. **
  1155. ** pItemTable[0]: "xyz"
  1156. ** pItemTable[1]: "abc"
  1157. ** pItemTable[2]: "mno"
  1158. ** pItemTable[3]: "qrs"
  1159. ** pItemTable[4]: "def"
  1160. **
  1161. ** on output ppItemTable contains the following pointers
  1162. **
  1163. ** ppItemTable[0]: &pItemTable[1] ("abc")
  1164. ** ppItemTable[1]: &pItemTable[4] ("def")
  1165. ** ppItemTable[2]: &pItemTable[2] ("mno")
  1166. ** ppItemTable[3]: &pItemTable[3] ("qrs")
  1167. ** ppItemTable[4]: &pItemTable[0] ("xyz")
  1168. **
  1169. ** and the contents of pItemTable are untouched.
  1170. ** And the caller can print out the array in sorted order using
  1171. ** for (i = 0; i < 4; i++) {
  1172. ** printf("%s\n", (char *)*ppItemTable[i]);
  1173. ** }
  1174. */
  1175. {
  1176. /* The following algorithm is derived from Sedgewick's Shellsort,
  1177. ** as given in "Algorithms in C++".
  1178. **
  1179. ** The Shellsort algorithm sorts the table by viewing it as
  1180. ** a number of interleaved arrays, each of whose elements are 'h'
  1181. ** spaces apart for some 'h'. Each array is sorted separately,
  1182. ** starting with the array whose elements are farthest apart and
  1183. ** ending with the array whose elements are closest together.
  1184. ** Since the 'last' such array always has elements next to each other,
  1185. ** this degenerates to Insertion sort, but by the time we get down
  1186. ** to the 'last' array, the table is pretty much sorted.
  1187. **
  1188. ** The sequence of values chosen below for 'h' is 1, 4, 13, 40, 121, ...
  1189. ** and the worst-case running time for the sequence is N^(3/2), where
  1190. ** the running time is measured in number of comparisons.
  1191. */
  1192. #define PFNSHELLCMP(a,b) (++Ncmp, pfnCompare((a),(b)))
  1193. DWORD dwErr;
  1194. INT i, j, h, N, Ncmp;
  1195. BYTE* a, *v, **p;
  1196. a = (BYTE*)pItemTable;
  1197. p = (BYTE**)ppItemTable;
  1198. N = (INT)dwItemCount;
  1199. Ncmp = 0;
  1200. TRACE1("ShellSortIndirect: N=%d", N);
  1201. /* Initialize the table of position pointers.
  1202. */
  1203. for (i = 0; i < N; i++) { p[i] = (a + i * dwItemSize); }
  1204. /* Move 'h' to the largest increment in our series
  1205. */
  1206. for (h = 1; h < N/9; h = 3 * h + 1) { }
  1207. /* For each increment in our series, sort the 'array' for that increment
  1208. */
  1209. for ( ; h > 0; h /= 3)
  1210. {
  1211. /* For each element in the 'array', get the pointer to its
  1212. ** sorted position.
  1213. */
  1214. for (i = h; i < N; i++)
  1215. {
  1216. /* save the pointer to be inserted
  1217. */
  1218. v = p[i]; j = i;
  1219. /* Move all the larger elements to the right
  1220. */
  1221. while (j >= h && PFNSHELLCMP(p[j - h], v) > 0)
  1222. {
  1223. p[j] = p[j - h]; j -= h;
  1224. }
  1225. /* put the saved pointer in the position where we stopped.
  1226. */
  1227. p[j] = v;
  1228. }
  1229. }
  1230. TRACE1("ShellSortIndirect: Ncmp=%d", Ncmp);
  1231. #undef PFNSHELLCMP
  1232. }
  1233. TCHAR*
  1234. StrDup(
  1235. LPCTSTR psz )
  1236. /* Returns heap block containing a copy of 0-terminated string 'psz' or
  1237. ** NULL on error or is 'psz' is NULL. It is caller's responsibility to
  1238. ** 'Free' the returned string.
  1239. */
  1240. {
  1241. TCHAR* pszNew = NULL;
  1242. if (psz)
  1243. {
  1244. pszNew = Malloc( (lstrlen( psz ) + 1) * sizeof(TCHAR) );
  1245. if (!pszNew)
  1246. {
  1247. TRACE("StrDup Malloc failed");
  1248. return NULL;
  1249. }
  1250. lstrcpy( pszNew, psz );
  1251. }
  1252. return pszNew;
  1253. }
  1254. CHAR*
  1255. StrDupAFromTInternal(
  1256. LPCTSTR psz,
  1257. IN DWORD dwCp)
  1258. /* Returns heap block containing a copy of 0-terminated string 'psz' or
  1259. ** NULL on error or is 'psz' is NULL. The output string is converted to
  1260. ** MB ANSI. It is caller's responsibility to 'Free' the returned string.
  1261. */
  1262. {
  1263. #ifdef UNICODE
  1264. CHAR* pszNew = NULL;
  1265. if (psz)
  1266. {
  1267. DWORD cb;
  1268. cb = WideCharToMultiByte( dwCp, 0, psz, -1, NULL, 0, NULL, NULL );
  1269. ASSERT(cb);
  1270. pszNew = (CHAR* )Malloc( cb + 1 );
  1271. if (!pszNew)
  1272. {
  1273. TRACE("StrDupAFromT Malloc failed");
  1274. return NULL;
  1275. }
  1276. cb = WideCharToMultiByte( dwCp, 0, psz, -1, pszNew, cb, NULL, NULL );
  1277. if (cb == 0)
  1278. {
  1279. Free( pszNew );
  1280. TRACE("StrDupAFromT conversion failed");
  1281. return NULL;
  1282. }
  1283. }
  1284. return pszNew;
  1285. #else // !UNICODE
  1286. return StrDup( psz );
  1287. #endif
  1288. }
  1289. CHAR*
  1290. StrDupAFromT(
  1291. LPCTSTR psz)
  1292. {
  1293. return StrDupAFromTInternal(psz, CP_UTF8);
  1294. }
  1295. CHAR*
  1296. StrDupAFromTAnsi(
  1297. LPCTSTR psz)
  1298. {
  1299. return StrDupAFromTInternal(psz, CP_ACP);
  1300. }
  1301. TCHAR*
  1302. StrDupTFromA(
  1303. LPCSTR psz )
  1304. /* Returns heap block containing a copy of 0-terminated string 'psz' or
  1305. ** NULL on error or is 'psz' is NULL. The output string is converted to
  1306. ** UNICODE. It is caller's responsibility to Free the returned string.
  1307. */
  1308. {
  1309. #ifdef UNICODE
  1310. return StrDupWFromA( psz );
  1311. #else // !UNICODE
  1312. return StrDup( psz );
  1313. #endif
  1314. }
  1315. TCHAR*
  1316. StrDupTFromAUsingAnsiEncoding(
  1317. LPCSTR psz )
  1318. {
  1319. #ifdef UNICODE
  1320. return StrDupWFromAInternal(psz, CP_ACP);
  1321. #else // !UNICODE
  1322. return StrDup( psz );
  1323. #endif
  1324. }
  1325. TCHAR*
  1326. StrDupTFromW(
  1327. LPCWSTR psz )
  1328. /* Returns heap block containing a copy of 0-terminated string 'psz' or
  1329. ** NULL on error or is 'psz' is NULL. The output string is converted to
  1330. ** UNICODE. It is caller's responsibility to Free the returned string.
  1331. */
  1332. {
  1333. #ifdef UNICODE
  1334. return StrDup( psz );
  1335. #else // !UNICODE
  1336. CHAR* pszNew = NULL;
  1337. if (psz)
  1338. {
  1339. DWORD cb;
  1340. cb = WideCharToMultiByte( CP_UTF8, 0, psz, -1, NULL, 0, NULL, NULL );
  1341. ASSERT(cb);
  1342. pszNew = (CHAR* )Malloc( cb + 1 );
  1343. if (!pszNew)
  1344. {
  1345. TRACE("StrDupTFromW Malloc failed");
  1346. return NULL;
  1347. }
  1348. cb = WideCharToMultiByte( CP_UTF8, 0, psz, -1, pszNew, cb, NULL, NULL );
  1349. if (cb == 0)
  1350. {
  1351. Free( pszNew );
  1352. TRACE("StrDupTFromW conversion failed");
  1353. return NULL;
  1354. }
  1355. }
  1356. return pszNew;
  1357. #endif
  1358. }
  1359. WCHAR*
  1360. StrDupWFromAInternal(
  1361. LPCSTR psz,
  1362. UINT uiCodePage)
  1363. /* Returns heap block containing a copy of 0-terminated string 'psz' or
  1364. ** NULL on error or if 'psz' is NULL. The output string is converted to
  1365. ** UNICODE. It is caller's responsibility to Free the returned string.
  1366. */
  1367. {
  1368. WCHAR* pszNew = NULL;
  1369. if (psz)
  1370. {
  1371. DWORD cb;
  1372. cb = MultiByteToWideChar( uiCodePage, 0, psz, -1, NULL, 0 );
  1373. ASSERT(cb);
  1374. pszNew = Malloc( (cb + 1) * sizeof(TCHAR) );
  1375. if (!pszNew)
  1376. {
  1377. TRACE("StrDupWFromA Malloc failed");
  1378. return NULL;
  1379. }
  1380. cb = MultiByteToWideChar( uiCodePage, 0, psz, -1, pszNew, cb );
  1381. if (cb == 0)
  1382. {
  1383. Free( pszNew );
  1384. TRACE("StrDupWFromA conversion failed");
  1385. return NULL;
  1386. }
  1387. }
  1388. return pszNew;
  1389. }
  1390. WCHAR*
  1391. StrDupWFromA(
  1392. LPCSTR psz )
  1393. {
  1394. return StrDupWFromAInternal(psz, CP_UTF8);
  1395. }
  1396. WCHAR*
  1397. StrDupWFromT(
  1398. LPCTSTR psz )
  1399. /* Returns heap block containing a copy of 0-terminated string 'psz' or
  1400. ** NULL on error or if 'psz' is NULL. The output string is converted to
  1401. ** UNICODE. It is caller's responsibility to Free the returned string.
  1402. */
  1403. {
  1404. #ifdef UNICODE
  1405. return StrDup( psz );
  1406. #else // !UNICODE
  1407. WCHAR* pszNew = NULL;
  1408. if (psz)
  1409. {
  1410. DWORD cb;
  1411. cb = MultiByteToWideChar( CP_UTF8, 0, psz, -1, NULL, 0 );
  1412. ASSERT(cb);
  1413. pszNew = Malloc( (cb + 1) * sizeof(TCHAR) );
  1414. if (!pszNew)
  1415. {
  1416. TRACE("StrDupWFromT Malloc failed");
  1417. return NULL;
  1418. }
  1419. cb = MultiByteToWideChar( CP_UTF8, 0, psz, -1, pszNew, cb );
  1420. if (cb == 0)
  1421. {
  1422. Free( pszNew );
  1423. TRACE1("StrDupWFromT conversion failed");
  1424. return NULL;
  1425. }
  1426. }
  1427. return pszNew;
  1428. #endif
  1429. }
  1430. WCHAR*
  1431. StrDupWFromAUsingAnsiEncoding(
  1432. LPCSTR psz )
  1433. {
  1434. return StrDupWFromAInternal(psz, CP_ACP);
  1435. }
  1436. DWORD
  1437. StrCpyWFromA(
  1438. WCHAR* pszDst,
  1439. LPCSTR pszSrc,
  1440. DWORD dwDstChars)
  1441. {
  1442. DWORD cb, dwErr;
  1443. cb = MultiByteToWideChar( CP_UTF8, 0, pszSrc, -1, pszDst, dwDstChars );
  1444. if (cb == 0)
  1445. {
  1446. dwErr = GetLastError();
  1447. TRACE1("StrCpyWFromA conversion failed %x", dwErr);
  1448. dwErr;
  1449. }
  1450. return NO_ERROR;
  1451. }
  1452. DWORD
  1453. StrCpyAFromW(
  1454. LPSTR pszDst,
  1455. LPCWSTR pszSrc,
  1456. DWORD dwDstChars)
  1457. {
  1458. DWORD cb, dwErr;
  1459. cb = WideCharToMultiByte(
  1460. CP_UTF8, 0, pszSrc, -1,
  1461. pszDst, dwDstChars, NULL, NULL );
  1462. if (cb == 0)
  1463. {
  1464. dwErr = GetLastError();
  1465. TRACE1("StrCpyAFromW conversion failed %x", dwErr);
  1466. dwErr;
  1467. }
  1468. return NO_ERROR;
  1469. }
  1470. DWORD
  1471. StrCpyAFromWUsingAnsiEncoding(
  1472. LPSTR pszDst,
  1473. LPCWSTR pszSrc,
  1474. DWORD dwDstChars)
  1475. {
  1476. DWORD cb, dwErr;
  1477. cb = WideCharToMultiByte(
  1478. CP_ACP, 0, pszSrc, -1,
  1479. pszDst, dwDstChars, NULL, NULL );
  1480. if (cb == 0)
  1481. {
  1482. dwErr = GetLastError();
  1483. TRACE1("StrCpyAFromWUsingAnsiEncoding conversion failed %x", dwErr);
  1484. dwErr;
  1485. }
  1486. return NO_ERROR;
  1487. }
  1488. DWORD
  1489. StrCpyWFromAUsingAnsiEncoding(
  1490. WCHAR* pszDst,
  1491. LPCSTR pszSrc,
  1492. DWORD dwDstChars)
  1493. {
  1494. DWORD cb, dwErr;
  1495. *pszDst = L'\0';
  1496. cb = MultiByteToWideChar( CP_ACP, 0, pszSrc, -1, pszDst, dwDstChars );
  1497. if (cb == 0)
  1498. {
  1499. dwErr = GetLastError();
  1500. TRACE1("StrCpyWFromA conversion failed %x", dwErr);
  1501. dwErr;
  1502. }
  1503. return NO_ERROR;
  1504. }
  1505. TCHAR*
  1506. StripPath(
  1507. IN TCHAR* pszPath )
  1508. /* Returns a pointer to the file name within 'pszPath'.
  1509. */
  1510. {
  1511. TCHAR* p;
  1512. p = pszPath + lstrlen( pszPath );
  1513. while (p > pszPath)
  1514. {
  1515. if (*p == TEXT('\\') || *p == TEXT('/') || *p == TEXT(':'))
  1516. {
  1517. p = CharNext( p );
  1518. break;
  1519. }
  1520. p = CharPrev( pszPath, p );
  1521. }
  1522. return p;
  1523. }
  1524. int
  1525. StrNCmpA(
  1526. IN CHAR* psz1,
  1527. IN CHAR* psz2,
  1528. IN INT nLen )
  1529. /* Like strncmp, which is not in Win32 for some reason.
  1530. */
  1531. {
  1532. INT i;
  1533. for (i= 0; i < nLen; ++i)
  1534. {
  1535. if (*psz1 == *psz2)
  1536. {
  1537. if (*psz1 == '\0')
  1538. return 0;
  1539. }
  1540. else if (*psz1 < *psz2)
  1541. return -1;
  1542. else
  1543. return 1;
  1544. ++psz1;
  1545. ++psz2;
  1546. }
  1547. return 0;
  1548. }
  1549. CHAR*
  1550. StrStrA(
  1551. IN CHAR* psz1,
  1552. IN CHAR* psz2 )
  1553. /* Like strstr, which is not in Win32.
  1554. */
  1555. {
  1556. CHAR* psz;
  1557. INT nLen2;
  1558. if (!psz1 || !psz2 || !*psz1 || !*psz2)
  1559. return NULL;
  1560. nLen2 = lstrlenA( psz2 );
  1561. for (psz = psz1;
  1562. *psz && StrNCmpA( psz, psz2, nLen2 ) != 0;
  1563. ++psz);
  1564. if (*psz)
  1565. return psz;
  1566. else
  1567. return NULL;
  1568. }
  1569. TCHAR*
  1570. UnNull(
  1571. TCHAR* psz )
  1572. // Returns 'psz' or, if NULL, empty string.
  1573. //
  1574. {
  1575. return (psz) ? psz : TEXT("");
  1576. }
  1577. DWORD
  1578. DwGetExpandedDllPath(LPTSTR pszDllPath,
  1579. LPTSTR *ppszExpandedDllPath)
  1580. {
  1581. DWORD dwErr = 0;
  1582. DWORD dwSize = 0;
  1583. //
  1584. // find the size of the expanded string
  1585. //
  1586. if (0 == (dwSize =
  1587. ExpandEnvironmentStrings(pszDllPath,
  1588. NULL,
  1589. 0)))
  1590. {
  1591. dwErr = GetLastError();
  1592. goto done;
  1593. }
  1594. *ppszExpandedDllPath = LocalAlloc(
  1595. LPTR,
  1596. dwSize * sizeof (TCHAR));
  1597. if (NULL == *ppszExpandedDllPath)
  1598. {
  1599. dwErr = GetLastError();
  1600. goto done;
  1601. }
  1602. //
  1603. // Get the expanded string
  1604. //
  1605. if (0 == ExpandEnvironmentStrings(
  1606. pszDllPath,
  1607. *ppszExpandedDllPath,
  1608. dwSize))
  1609. {
  1610. dwErr = GetLastError();
  1611. }
  1612. done:
  1613. return dwErr;
  1614. }