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.

1344 lines
28 KiB

  1. // Copyright (c) 2001 Microsoft Corporation
  2. //
  3. // File: common.cpp
  4. //
  5. // Synopsis: Commonly used functions
  6. //
  7. // History: 02/03/2001 JeffJon Created
  8. #include "pch.h"
  9. bool
  10. IsServiceInstalledHelper(const wchar_t* serviceName)
  11. {
  12. LOG_FUNCTION2(IsServiceInstalledHelper, serviceName);
  13. ASSERT(serviceName);
  14. // if we can open the service, then it is installed
  15. bool result = false;
  16. SC_HANDLE hsc =
  17. ::OpenSCManager(0, SERVICES_ACTIVE_DATABASE, GENERIC_READ);
  18. if (hsc)
  19. {
  20. SC_HANDLE hs = ::OpenServiceW(hsc, serviceName, GENERIC_READ);
  21. if (hs)
  22. {
  23. ::CloseServiceHandle(hs);
  24. result = true;
  25. }
  26. ::CloseServiceHandle(hsc);
  27. }
  28. LOG_BOOL(result);
  29. return result;
  30. }
  31. // Wait for a handle to become signalled, or a timeout to expire, or WM_QUIT
  32. // to appear in the message queue. Pump the message queue while we wait.
  33. //
  34. // WARNING: UI should diable itself before calling any function that invokes
  35. // this function, or functions calling this one should guard against
  36. // re-entrance. Otherwise there will be a re-entrancy problem.
  37. //
  38. // e.g. command handler gets button clicked message, calls a func that calls
  39. // this wait function, then user clicks the button again, command handler call
  40. // a func that calls this one, and so on.
  41. DWORD
  42. MyWaitForSendMessageThread(HANDLE hThread, DWORD dwTimeout)
  43. {
  44. LOG_FUNCTION(MyWaitForSendMessageThread);
  45. ASSERT(hThread);
  46. MSG msg;
  47. DWORD dwRet;
  48. DWORD dwEnd = GetTickCount() + dwTimeout;
  49. bool quit = false;
  50. // We will attempt to wait up to dwTimeout for the thread to
  51. // terminate
  52. do
  53. {
  54. dwRet = MsgWaitForMultipleObjects(1, &hThread, FALSE,
  55. dwTimeout, QS_ALLEVENTS | QS_SENDMESSAGE );
  56. if (dwRet == (WAIT_OBJECT_0 + 1))
  57. {
  58. // empty out the message queue. We call DispatchMessage to
  59. // ensure that we still process the WM_PAINT messages.
  60. // DANGER: Make sure that the CYS UI is completely disabled
  61. // or there will be re-entrancy problems here
  62. while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  63. {
  64. if (msg.message == WM_QUIT)
  65. {
  66. // Need to re-post this so that we know to close CYS
  67. ::PostMessage(msg.hwnd, WM_QUIT, 0, 0);
  68. quit = true;
  69. break;
  70. }
  71. ::TranslateMessage(&msg);
  72. ::DispatchMessage(&msg);
  73. }
  74. // Calculate if we have any more time left in the timeout to
  75. // wait on.
  76. if (dwTimeout != INFINITE)
  77. {
  78. dwTimeout = dwEnd - GetTickCount();
  79. if ((long)dwTimeout <= 0)
  80. {
  81. // No more time left, fail with WAIT_TIMEOUT
  82. dwRet = WAIT_TIMEOUT;
  83. }
  84. }
  85. }
  86. // dwRet == WAIT_OBJECT_0 || dwRet == WAIT_FAILED
  87. // The thread must have exited, so we are happy
  88. //
  89. // dwRet == WAIT_TIMEOUT
  90. // The thread is taking too long to finish, so just
  91. // return and let the caller kill it
  92. } while (dwRet == (WAIT_OBJECT_0 + 1) && !quit);
  93. return(dwRet);
  94. }
  95. HRESULT
  96. CreateAndWaitForProcess(
  97. const String& fullPath,
  98. String& commandLine,
  99. DWORD& exitCode,
  100. bool minimize)
  101. {
  102. LOG_FUNCTION2(CreateAndWaitForProcess, fullPath);
  103. LOG(commandLine);
  104. ASSERT(!fullPath.empty());
  105. exitCode = 0;
  106. HRESULT hr = S_OK;
  107. do
  108. {
  109. PROCESS_INFORMATION procInfo;
  110. memset(&procInfo, 0, sizeof(procInfo));
  111. STARTUPINFO startup;
  112. memset(&startup, 0, sizeof(startup));
  113. if (minimize)
  114. {
  115. LOG(L"Starting minimized");
  116. startup.dwFlags = STARTF_USESHOWWINDOW;
  117. startup.wShowWindow = SW_MINIMIZE;
  118. }
  119. LOG(L"Calling CreateProcess");
  120. LOG(fullPath);
  121. LOG(commandLine);
  122. hr =
  123. Win::CreateProcess(
  124. fullPath,
  125. commandLine,
  126. 0,
  127. String(),
  128. startup,
  129. procInfo);
  130. BREAK_ON_FAILED_HRESULT(hr);
  131. ASSERT(procInfo.hProcess);
  132. DWORD dwRet = MyWaitForSendMessageThread(procInfo.hProcess, INFINITE);
  133. ASSERT(dwRet == WAIT_OBJECT_0);
  134. hr = Win::GetExitCodeProcess(procInfo.hProcess, exitCode);
  135. BREAK_ON_FAILED_HRESULT(hr);
  136. Win::CloseHandle(procInfo.hThread);
  137. Win::CloseHandle(procInfo.hProcess);
  138. }
  139. while (0);
  140. LOG(String::format(L"exit code = %1!x!", exitCode));
  141. LOG_HRESULT(hr);
  142. return hr;
  143. }
  144. HRESULT
  145. MyCreateProcess(
  146. const String& fullPath,
  147. String& commandline)
  148. {
  149. LOG_FUNCTION2(MyCreateProcess, fullPath);
  150. LOG(commandline);
  151. ASSERT(!fullPath.empty());
  152. HRESULT hr = S_OK;
  153. do
  154. {
  155. PROCESS_INFORMATION procInfo;
  156. memset(&procInfo, 0, sizeof(procInfo));
  157. STARTUPINFO startup;
  158. memset(&startup, 0, sizeof(startup));
  159. LOG(L"Calling CreateProcess");
  160. hr =
  161. Win::CreateProcess(
  162. fullPath,
  163. commandline,
  164. 0,
  165. String(),
  166. startup,
  167. procInfo);
  168. BREAK_ON_FAILED_HRESULT(hr);
  169. ASSERT(procInfo.hProcess);
  170. Win::CloseHandle(procInfo.hThread);
  171. Win::CloseHandle(procInfo.hProcess);
  172. }
  173. while (0);
  174. LOG_HRESULT(hr);
  175. return hr;
  176. }
  177. bool
  178. IsKeyValuePresent(RegistryKey& key, const String& valueKey)
  179. {
  180. LOG_FUNCTION(IsKeyValuePresent);
  181. bool result = false;
  182. do
  183. {
  184. String value;
  185. HRESULT hr = key.GetValue(valueKey, value);
  186. if (FAILED(hr))
  187. {
  188. LOG(String::format(
  189. L"Failed to read regkey %1 because: hr = %2!x!",
  190. valueKey,
  191. hr));
  192. break;
  193. }
  194. if (!value.empty())
  195. {
  196. result = true;
  197. break;
  198. }
  199. } while (false);
  200. LOG_BOOL(result);
  201. return result;
  202. }
  203. bool
  204. GetRegKeyValue(
  205. const String& keyName,
  206. const String& value,
  207. String& resultString,
  208. HKEY parentKey)
  209. {
  210. LOG_FUNCTION(GetRegKeyValue);
  211. bool result = true;
  212. do
  213. {
  214. HRESULT hr = S_OK;
  215. RegistryKey key;
  216. hr = key.Open(parentKey, keyName);
  217. if (FAILED(hr))
  218. {
  219. LOG(String::format(
  220. L"Failed to open regkey %1 because: hr = %2!x!",
  221. keyName.c_str(),
  222. hr));
  223. result = false;
  224. break;
  225. }
  226. hr = key.GetValue(value, resultString);
  227. if (FAILED(hr))
  228. {
  229. LOG(String::format(
  230. L"Failed to read regkey %1 because: hr = %2!x!",
  231. value.c_str(),
  232. hr));
  233. result = false;
  234. break;
  235. }
  236. LOG(String::format(
  237. L"Value of key: %1",
  238. resultString.c_str()));
  239. } while (false);
  240. LOG_BOOL(result);
  241. return result;
  242. }
  243. bool
  244. GetRegKeyValue(
  245. const String& keyName,
  246. const String& value,
  247. DWORD& resultValue,
  248. HKEY parentKey)
  249. {
  250. LOG_FUNCTION(GetRegKeyValue);
  251. bool result = true;
  252. do
  253. {
  254. HRESULT hr = S_OK;
  255. RegistryKey key;
  256. hr = key.Open(parentKey, keyName);
  257. if (FAILED(hr))
  258. {
  259. LOG(String::format(
  260. L"Failed to open regkey %1 because: hr = %2!x!",
  261. keyName.c_str(),
  262. hr));
  263. result = false;
  264. break;
  265. }
  266. hr = key.GetValue(value, resultValue);
  267. if (FAILED(hr))
  268. {
  269. LOG(String::format(
  270. L"Failed to read regkey %1 because: hr = %2!x!",
  271. value.c_str(),
  272. hr));
  273. result = false;
  274. break;
  275. }
  276. LOG(String::format(
  277. L"Key value: %1!d!",
  278. resultValue));
  279. } while (false);
  280. LOG_BOOL(result);
  281. return result;
  282. }
  283. bool
  284. SetRegKeyValue(
  285. const String& keyName,
  286. const String& value,
  287. const String& newString,
  288. HKEY parentKey,
  289. bool create
  290. )
  291. {
  292. LOG_FUNCTION(SetRegKeyValue);
  293. bool result = true;
  294. do
  295. {
  296. HRESULT hr = S_OK;
  297. RegistryKey key;
  298. if (create)
  299. {
  300. hr = key.Create(parentKey, keyName);
  301. }
  302. else
  303. {
  304. hr = key.Open(parentKey, keyName, KEY_SET_VALUE);
  305. }
  306. if (FAILED(hr))
  307. {
  308. LOG(String::format(
  309. L"Failed to open regkey %1 because: hr = %2!x!",
  310. keyName.c_str(),
  311. hr));
  312. result = false;
  313. break;
  314. }
  315. hr = key.SetValue(value, newString);
  316. if (FAILED(hr))
  317. {
  318. LOG(String::format(
  319. L"Failed to write regkey %1 because: hr = %2!x!",
  320. value.c_str(),
  321. hr));
  322. result = false;
  323. break;
  324. }
  325. } while (false);
  326. LOG_BOOL(result);
  327. return result;
  328. }
  329. bool
  330. SetRegKeyValue(
  331. const String& keyName,
  332. const String& value,
  333. DWORD newValue,
  334. HKEY parentKey,
  335. bool create)
  336. {
  337. LOG_FUNCTION(SetRegKeyValue);
  338. bool result = true;
  339. do
  340. {
  341. HRESULT hr = S_OK;
  342. RegistryKey key;
  343. if (create)
  344. {
  345. hr = key.Create(parentKey, keyName);
  346. }
  347. else
  348. {
  349. hr = key.Open(parentKey, keyName, KEY_WRITE);
  350. }
  351. if (FAILED(hr))
  352. {
  353. LOG(String::format(
  354. L"Failed to open regkey %1 because: hr = %2!x!",
  355. keyName.c_str(),
  356. hr));
  357. result = false;
  358. break;
  359. }
  360. hr = key.SetValue(value, newValue);
  361. if (FAILED(hr))
  362. {
  363. LOG(String::format(
  364. L"Failed to write regkey %1 because: hr = %2!x!",
  365. value.c_str(),
  366. hr));
  367. result = false;
  368. break;
  369. }
  370. } while (false);
  371. LOG_BOOL(result);
  372. return result;
  373. }
  374. HRESULT
  375. VariantArrayToStringVector(VARIANT* variant, StringVector& stringList)
  376. {
  377. LOG_FUNCTION(VariantArrayToStringVector);
  378. HRESULT hr = S_OK;
  379. stringList.clear();
  380. do
  381. {
  382. ASSERT(variant);
  383. LOG(String::format(
  384. L"Variant type = 0x%1!x!",
  385. V_VT(variant)));
  386. if (V_VT(variant) == VT_EMPTY ||
  387. V_VT(variant) == VT_NULL)
  388. {
  389. break;
  390. }
  391. ASSERT(V_VT(variant) == (VT_ARRAY | VT_BSTR));
  392. SAFEARRAY* psa = V_ARRAY(variant);
  393. ASSERT(psa);
  394. ASSERT(psa != (SAFEARRAY*)-1);
  395. if (!psa || psa == (SAFEARRAY*)-1)
  396. {
  397. LOG(L"variant not safe array");
  398. break;
  399. }
  400. if (::SafeArrayGetDim(psa) != 1)
  401. {
  402. LOG(L"safe array: wrong number of dimensions");
  403. break;
  404. }
  405. VARTYPE vt = VT_EMPTY;
  406. hr = ::SafeArrayGetVartype(psa, &vt);
  407. if (FAILED(hr) || vt != VT_BSTR)
  408. {
  409. LOG(L"safe array: wrong element type");
  410. break;
  411. }
  412. long lower = 0;
  413. long upper = 0;
  414. hr = ::SafeArrayGetLBound(psa, 1, &lower);
  415. if (FAILED(hr))
  416. {
  417. LOG(L"can't get lower bound");
  418. break;
  419. }
  420. hr = ::SafeArrayGetUBound(psa, 1, &upper);
  421. if (FAILED(hr))
  422. {
  423. LOG(L"can't get upper bound");
  424. break;
  425. }
  426. for (long i = lower; i <= upper; ++i)
  427. {
  428. BSTR item;
  429. hr = ::SafeArrayGetElement(psa, &i, &item);
  430. if (FAILED(hr))
  431. {
  432. LOG(String::format(L"index %1!d! failed", i));
  433. continue;
  434. }
  435. if (item)
  436. {
  437. stringList.push_back(String(item));
  438. }
  439. ::SysFreeString(item);
  440. }
  441. }
  442. while (0);
  443. LOG_HRESULT(hr);
  444. return hr;
  445. }
  446. String
  447. IPAddressToString(DWORD ipAddress)
  448. {
  449. String result = String::format(
  450. L"%1!d!.%2!d!.%3!d!.%4!d!",
  451. FIRST_IPADDRESS(ipAddress),
  452. SECOND_IPADDRESS(ipAddress),
  453. THIRD_IPADDRESS(ipAddress),
  454. FOURTH_IPADDRESS(ipAddress));
  455. return result;
  456. }
  457. // Will convert a string in the form of an IP address to
  458. // a DWORD. A return value of INADDR_NONE means that we failed
  459. // to do the conversion
  460. DWORD
  461. StringToIPAddress(const String& stringIPAddress)
  462. {
  463. DWORD result = INADDR_NONE;
  464. // Convert the string to ansi so that we can use inet_addr
  465. // to convert to an IP address DWORD
  466. AnsiString ansi;
  467. String::ConvertResult convertResult = stringIPAddress.convert(ansi);
  468. if (String::CONVERT_SUCCESSFUL == convertResult)
  469. {
  470. // Convert the string to an address
  471. result = inet_addr(ansi.c_str());
  472. }
  473. return result;
  474. }
  475. DWORD
  476. ConvertIPAddressOrder(DWORD address)
  477. {
  478. DWORD result = 0;
  479. result |= (address & 0xff) << 24;
  480. result |= (address & 0xff00) << 8;
  481. result |= (address >> 8) & 0x0000ff00;
  482. result |= (address >> 24) & 0x000000ff;
  483. return result;
  484. }
  485. // This function allocates an array of DWORDs and fills it with the IP addresses
  486. // from the StringList. The caller must free the returned pointer using
  487. // delete[]
  488. DWORD*
  489. StringIPListToDWORDArray(
  490. const StringList& stringIPList,
  491. DWORD& count)
  492. {
  493. // This is an exception throwing new so there is no
  494. // reason to check for NULL
  495. count = 0;
  496. DWORD ipCount = static_cast<DWORD>(stringIPList.size());
  497. DWORD* array = new DWORD[ipCount];
  498. try
  499. {
  500. // Copy the forwarders addresses into the array
  501. for (StringList::iterator itr = stringIPList.begin();
  502. itr != stringIPList.end();
  503. ++itr)
  504. {
  505. if (!(*itr).empty())
  506. {
  507. DWORD newAddress = StringToIPAddress(*itr);
  508. if (newAddress != INADDR_NONE)
  509. {
  510. array[count++] = newAddress;
  511. }
  512. }
  513. }
  514. }
  515. catch (exception &e)
  516. {
  517. // NTRAID#NTBUG9-654260-2002/07/08-artm
  518. // Avoid leaking "array" if encounter any exceptions based on
  519. // std::exception. Among these are std::length_error and std::bad_alloc,
  520. // but there could be others.
  521. delete [] array;
  522. // Don't really know how to handle exceptions at this level, so pass the buck.
  523. throw e;
  524. }
  525. return array;
  526. }
  527. void
  528. CreateInfFileText(
  529. String& infFileText,
  530. unsigned int windowTitleResourceID)
  531. {
  532. LOG_FUNCTION(CreateInfFileText);
  533. infFileText = L"[Version]\n";
  534. infFileText += L"Signature = \"$Windows NT$\"\n";
  535. infFileText += L"[Components]\n";
  536. infFileText += L"NetOC=netoc.dll,NetOcSetupProc,netoc.inf\n";
  537. infFileText += L"[Global]\n";
  538. infFileText += L"WindowTitle=";
  539. infFileText += String::load(windowTitleResourceID, hResourceModuleHandle);
  540. infFileText += L"\n";
  541. infFileText += L"[Strings]\n";
  542. infFileText += L";(empty)";
  543. }
  544. void
  545. CreateUnattendFileText(
  546. String& unattendFileText,
  547. PCWSTR serviceName,
  548. bool install)
  549. {
  550. LOG_FUNCTION(CreateUnattendFileText);
  551. ASSERT(serviceName);
  552. unattendFileText = L"[NetOptionalComponents]\n";
  553. unattendFileText += serviceName;
  554. if (install)
  555. {
  556. unattendFileText += L"=1";
  557. }
  558. else
  559. {
  560. unattendFileText += L"=0";
  561. }
  562. }
  563. HRESULT
  564. GetShellPath(
  565. int folder,
  566. String& shellPath,
  567. HWND hwnd = 0)
  568. {
  569. LOG_FUNCTION(GetShellPath);
  570. HRESULT hr = S_OK;
  571. PWSTR path = 0;
  572. do
  573. {
  574. path = new WCHAR[MAX_PATH];
  575. ZeroMemory(path, sizeof(WCHAR) * MAX_PATH);
  576. hr = ::SHGetFolderPath(
  577. hwnd,
  578. folder,
  579. 0,
  580. SHGFP_TYPE_DEFAULT,
  581. path);
  582. if (FAILED(hr))
  583. {
  584. LOG(
  585. String::format(
  586. L"Failed to get shell path: hr = %1!x!",
  587. hr));
  588. break;
  589. }
  590. shellPath = path;
  591. } while(false);
  592. if (path)
  593. {
  594. delete[] path;
  595. path = 0;
  596. }
  597. LOG_HRESULT(hr);
  598. return hr;
  599. }
  600. // Opens the favorites folder and creates a favorite for
  601. // the specified URL
  602. HRESULT
  603. AddURLToFavorites(HWND hwnd, const String& url, const String& fileName)
  604. {
  605. LOG_FUNCTION(AddURLToFavorites);
  606. ASSERT(Win::IsWindow(hwnd));
  607. ASSERT(!url.empty());
  608. ASSERT(!fileName.empty());
  609. HRESULT hr = S_OK;
  610. do
  611. {
  612. String path;
  613. hr = GetShellPath(
  614. CSIDL_FAVORITES,
  615. path);
  616. if (FAILED(hr))
  617. {
  618. LOG(String::format(
  619. L"Failed to get favorites path: hr = %1!x!",
  620. hr));
  621. break;
  622. }
  623. // Create the favorites .url file
  624. String fileContents = L"[InternetShortcut]\r\n";
  625. fileContents += L"URL=";
  626. fileContents += url;
  627. fileContents += L"\r\n";
  628. String fullPath = FS::AppendPath(path, fileName);
  629. if (fullPath.empty())
  630. {
  631. LOG(L"Failed to append path");
  632. hr = E_FAIL;
  633. break;
  634. }
  635. HANDLE h = 0;
  636. hr =
  637. FS::CreateFile(
  638. fullPath,
  639. h,
  640. GENERIC_WRITE,
  641. 0,
  642. CREATE_NEW,
  643. FILE_ATTRIBUTE_NORMAL);
  644. if (FAILED(hr))
  645. {
  646. LOG(
  647. String::format(
  648. L"Failed to create file: hr = %1!x!",
  649. hr));
  650. break;
  651. }
  652. // Write contents and end-of-file marker
  653. hr = FS::Write(h, fileContents + L"\032");
  654. if (FAILED(hr))
  655. {
  656. LOG(
  657. String::format(
  658. L"Failed to write contents to file: hr = %1!x!",
  659. hr));
  660. break;
  661. }
  662. } while (false);
  663. LOG_HRESULT(hr);
  664. return hr;
  665. }
  666. void
  667. LaunchMMCConsole(
  668. const String& consoleFile,
  669. String& alternatePath)
  670. {
  671. LOG_FUNCTION2(LaunchMMCConsole, consoleFile);
  672. String fullPath = Win::GetSystemDirectory() + L"\\mmc.exe";
  673. String commandLine = L"\"";
  674. if (!alternatePath.empty())
  675. {
  676. LOG(String::format(L"alternatePath = %1", alternatePath.c_str()));
  677. commandLine += alternatePath;
  678. }
  679. else
  680. {
  681. commandLine += Win::GetSystemDirectory();
  682. }
  683. commandLine += L"\\" + consoleFile + L"\"";
  684. LOG(String::format(L"fullPath = %1", fullPath.c_str()));
  685. LOG(String::format(L"commandLine = %1", commandLine.c_str()));
  686. HRESULT unused = MyCreateProcess(fullPath, commandLine);
  687. ASSERT(SUCCEEDED(unused));
  688. LOG_HRESULT(unused);
  689. }
  690. void
  691. LaunchMYS()
  692. {
  693. LOG_FUNCTION(LaunchMYS);
  694. String fullPath =
  695. Win::GetSystemDirectory() +
  696. L"\\mshta.exe";
  697. String commandLine = L"res://" +
  698. Win::GetSystemDirectory() +
  699. L"\\mys.dll/mys.hta";
  700. LOG(String::format(
  701. L"MYS path = %1",
  702. fullPath.c_str()));
  703. LOG(String::format(
  704. L"MYS commandline = %1",
  705. commandLine.c_str()));
  706. HRESULT unused = MyCreateProcess(fullPath, commandLine);
  707. ASSERT(SUCCEEDED(unused));
  708. LOG_HRESULT(unused);
  709. }
  710. HRESULT
  711. GetAllUsersStartMenu(String& startMenuPath)
  712. {
  713. LOG_FUNCTION(GetAllUsersStartMenu);
  714. HRESULT hr = GetShellPath(
  715. CSIDL_COMMON_STARTMENU,
  716. startMenuPath);
  717. if (FAILED(hr))
  718. {
  719. LOG(String::format(
  720. L"Failed to get the start menu path: hr = %1!x!",
  721. hr));
  722. }
  723. LOG_HRESULT(hr);
  724. return hr;
  725. }
  726. HRESULT
  727. GetAllUsersAdminTools(String& adminToolsPath)
  728. {
  729. LOG_FUNCTION(GetAllUsersAdminTools);
  730. HRESULT hr = GetShellPath(
  731. CSIDL_COMMON_ADMINTOOLS,
  732. adminToolsPath);
  733. if (FAILED(hr))
  734. {
  735. LOG(String::format(
  736. L"Failed to get the admin tools path: hr = %1!x!",
  737. hr));
  738. }
  739. LOG_HRESULT(hr);
  740. return hr;
  741. }
  742. HRESULT
  743. CreateShortcut(
  744. const String& shortcutPath,
  745. const String& target,
  746. const String& description)
  747. {
  748. LOG_FUNCTION(CreateShortcut);
  749. HRESULT hr = S_OK;
  750. do
  751. {
  752. ASSERT(!shortcutPath.empty());
  753. ASSERT(!target.empty());
  754. if (shortcutPath.empty() ||
  755. target.empty())
  756. {
  757. LOG(String::format(
  758. L"A parameter was empty: shortcutPath = %1, target = %2",
  759. shortcutPath.c_str(),
  760. target.c_str()));
  761. hr = E_INVALIDARG;
  762. break;
  763. }
  764. LOG(String::format(
  765. L"shortcutPath = %1",
  766. shortcutPath.c_str()));
  767. LOG(String::format(
  768. L"target = %1",
  769. target.c_str()));
  770. SmartInterface<IShellLink> shellLink;
  771. hr = shellLink.AcquireViaCreateInstance(
  772. CLSID_ShellLink,
  773. 0,
  774. CLSCTX_INPROC_SERVER);
  775. if (FAILED(hr))
  776. {
  777. LOG(String::format(
  778. L"Failed to CoCreate IShellLink: hr = %1!x!",
  779. hr));
  780. break;
  781. }
  782. hr = shellLink->SetPath(target.c_str());
  783. if (FAILED(hr))
  784. {
  785. LOG(String::format(
  786. L"Failed to set the target path: hr = %1!x!",
  787. hr));
  788. break;
  789. }
  790. if (!description.empty())
  791. {
  792. LOG(L"Setting description");
  793. hr = shellLink->SetDescription(description.c_str());
  794. if (FAILED(hr))
  795. {
  796. LOG(String::format(
  797. L"Failed to set shortcut description: hr = 0x%1!x!",
  798. hr));
  799. }
  800. }
  801. SmartInterface<IPersistFile> persistFile;
  802. hr = persistFile.AcquireViaQueryInterface(
  803. shellLink,
  804. IID_IPersistFile);
  805. if (FAILED(hr))
  806. {
  807. LOG(String::format(
  808. L"Failed to QI for IPersistFile: hr = %1!x!",
  809. hr));
  810. break;
  811. }
  812. hr = persistFile->Save(shortcutPath.c_str(), FALSE);
  813. if (FAILED(hr))
  814. {
  815. LOG(String::format(
  816. L"Failed to save the shortcut: hr = %1!x!",
  817. hr));
  818. break;
  819. }
  820. } while (false);
  821. LOG_HRESULT(hr);
  822. return hr;
  823. }
  824. int
  825. LinkIndexFromNotifyLPARAM(LPARAM lParam)
  826. {
  827. LOG_FUNCTION(LinkIndexFromNotifyLPARAM);
  828. int result = 0;
  829. do
  830. {
  831. ASSERT(lParam);
  832. if (!lParam)
  833. {
  834. break;
  835. }
  836. NMLINK* linkHeader = reinterpret_cast<NMLINK*>(lParam);
  837. if (!linkHeader)
  838. {
  839. LOG(L"Cast of notify link header failed");
  840. break;
  841. }
  842. result = linkHeader->item.iLink;
  843. } while (false);
  844. LOG(String::format(
  845. L"result = %1!d!",
  846. result));
  847. return result;
  848. }
  849. void
  850. ShowHelp(
  851. const String& helpTopic)
  852. {
  853. LOG_FUNCTION2(
  854. ShowHelp,
  855. helpTopic.c_str());
  856. // NOTE: I am not using Win::HtmlHelp here so that the help
  857. // is actually running in a different process. This
  858. // allows us to close down CYS without closing the help
  859. // window.
  860. String fullPath = Win::GetSystemWindowsDirectory() + L"\\hh.exe";
  861. String commandLine = helpTopic;
  862. HRESULT hr = MyCreateProcess(fullPath, commandLine);
  863. if (FAILED(hr))
  864. {
  865. LOG(String::format(
  866. L"Failed to open help: hr = 0x%1!x!",
  867. hr));
  868. }
  869. }
  870. void
  871. OpenLogFile()
  872. {
  873. LOG_FUNCTION(OpenLogFile);
  874. String fullPath = Win::GetSystemDirectory() + L"\\notepad.exe";
  875. String commandLine = Win::GetWindowsDirectory();
  876. commandLine += L"\\Debug\\";
  877. commandLine += CYS_LOGFILE_NAME;
  878. commandLine += L".log";
  879. HRESULT hr = MyCreateProcess(fullPath, commandLine);
  880. ASSERT(SUCCEEDED(hr));
  881. }
  882. bool
  883. IsLogFilePresent()
  884. {
  885. LOG_FUNCTION(IsLogFilePresent);
  886. bool result = false;
  887. String logfile = Win::GetWindowsDirectory();
  888. logfile += L"\\Debug\\";
  889. logfile += CYS_LOGFILE_NAME;
  890. logfile += L".log";
  891. result = FS::FileExists(logfile);
  892. LOG_BOOL(result);
  893. return result;
  894. }
  895. HRESULT
  896. GetAdminToolsShortcutPath(
  897. String& adminToolsShortcutPath,
  898. const String& linkToAppend)
  899. {
  900. LOG_FUNCTION(GetAdminToolsShortcutPath);
  901. HRESULT hr = S_OK;
  902. String adminToolsPath;
  903. hr = GetAllUsersAdminTools(adminToolsPath);
  904. if (SUCCEEDED(hr))
  905. {
  906. if (!linkToAppend.empty())
  907. {
  908. adminToolsShortcutPath =
  909. FS::AppendPath(
  910. adminToolsPath,
  911. linkToAppend);
  912. }
  913. LOG(String::format(
  914. L"Admin Tools Link = %1",
  915. adminToolsShortcutPath.c_str()));
  916. }
  917. LOG_HRESULT(hr);
  918. return hr;
  919. }
  920. HRESULT
  921. AddShortcutToAdminTools(
  922. const String& target,
  923. unsigned int descriptionID,
  924. unsigned int linkID)
  925. {
  926. LOG_FUNCTION2(
  927. AddShortcutToAdminTools,
  928. target);
  929. HRESULT hr = S_OK;
  930. String description = String::load(descriptionID);
  931. String link = String::load(linkID);
  932. do
  933. {
  934. String adminToolsLinkPath;
  935. hr = GetAdminToolsShortcutPath(
  936. adminToolsLinkPath,
  937. link);
  938. if (FAILED(hr))
  939. {
  940. LOG(String::format(
  941. L"Failed to GetAdminToolsShortcutPath: hr = 0x%1!x!",
  942. hr));
  943. }
  944. else
  945. {
  946. hr = CreateShortcut(
  947. adminToolsLinkPath,
  948. target,
  949. description);
  950. if (FAILED(hr))
  951. {
  952. LOG(String::format(
  953. L"Failed to create admin tools shortcut: hr = %1!x!",
  954. hr));
  955. }
  956. }
  957. } while (false);
  958. LOG_HRESULT(hr);
  959. return hr;
  960. }
  961. bool
  962. IsSpecialShare(const SHARE_INFO_1& shareInfo)
  963. {
  964. LOG_FUNCTION2(
  965. IsSpecialShare,
  966. shareInfo.shi1_netname);
  967. bool result = false;
  968. if (shareInfo.shi1_type == STYPE_DISKTREE)
  969. {
  970. LOG(L"Share is of type STYPE_DISKTREE");
  971. String shareName = shareInfo.shi1_netname;
  972. if (shareName.icompare(CYS_SPECIAL_SHARE_SYSVOL) == 0 ||
  973. shareName.icompare(CYS_SPECIAL_SHARE_NETLOGON) == 0 ||
  974. shareName.icompare(CYS_SPECIAL_SHARE_PRINT) == 0)
  975. {
  976. LOG(L"Share has a special name");
  977. result = true;
  978. }
  979. }
  980. else
  981. {
  982. LOG(L"Share is not of type STYPE_DISKTREE");
  983. result = true;
  984. }
  985. LOG_BOOL(result);
  986. return result;
  987. }
  988. bool
  989. IsNonSpecialSharePresent()
  990. {
  991. LOG_FUNCTION(IsNonSpecialSharePresent);
  992. bool result = false;
  993. SHARE_INFO_1* shareInfoArray = 0;
  994. NET_API_STATUS shareResult = 0;
  995. do
  996. {
  997. DWORD entriesRead = 0;
  998. DWORD totalEntries = 0;
  999. DWORD resumeHandle = 0;
  1000. shareResult = NetShareEnum(
  1001. 0,
  1002. 1,
  1003. reinterpret_cast<BYTE**>(&shareInfoArray),
  1004. static_cast<DWORD>(-1),
  1005. &entriesRead,
  1006. &totalEntries,
  1007. &resumeHandle);
  1008. if ((shareResult == ERROR_SUCCESS ||
  1009. shareResult == ERROR_MORE_DATA) &&
  1010. shareInfoArray)
  1011. {
  1012. for (
  1013. DWORD index = 0;
  1014. index < entriesRead;
  1015. ++index)
  1016. {
  1017. // Look for only normal shares and ignore special shares
  1018. // like C$, ADMIN$, and IPC$
  1019. if (!IsSpecialShare(shareInfoArray[index]))
  1020. {
  1021. LOG(String::format(
  1022. L"Share found: %1",
  1023. shareInfoArray[index].shi1_netname));
  1024. result = true;
  1025. break;
  1026. }
  1027. }
  1028. }
  1029. else
  1030. {
  1031. LOG(String::format(
  1032. L"NetShareEnum failed: result = %1!x!",
  1033. shareResult));
  1034. }
  1035. if (shareInfoArray)
  1036. {
  1037. NetApiBufferFree(shareInfoArray);
  1038. shareInfoArray = 0;
  1039. }
  1040. if (result)
  1041. {
  1042. break;
  1043. }
  1044. } while(shareResult == ERROR_MORE_DATA);
  1045. LOG_BOOL(result);
  1046. return result;
  1047. }