Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

986 lines
23 KiB

  1. // Util.cpp : Implementation of CUtil
  2. #include "stdafx.h"
  3. #include "CompatUI.h"
  4. #include "Util.h"
  5. #include <shlobj.h>
  6. #include <shellapi.h>
  7. #include <shlwapi.h>
  8. #include <msi.h>
  9. #include <sfc.h>
  10. #include "Aclapi.h"
  11. extern "C" {
  12. #include "shimdb.h"
  13. }
  14. #pragma warning(disable:4786)
  15. #include <string>
  16. #include <xstring>
  17. #include <map>
  18. #include <locale>
  19. #include <algorithm>
  20. #include <vector>
  21. using namespace std;
  22. /////////////////////////////////////////////////////////////////////////////
  23. // CUtil
  24. extern "C"
  25. VOID
  26. InvalidateAppcompatCacheEntry(
  27. LPCWSTR pwszDosPath
  28. );
  29. BOOL
  30. GetExePathFromObject(
  31. LPCTSTR lpszPath, // path to an arbitrary object
  32. CComBSTR& bstrExePath
  33. );
  34. typedef
  35. INSTALLSTATE (WINAPI*PMsiGetComponentPath)(
  36. LPCTSTR szProduct, // product code for client product
  37. LPCTSTR szComponent, // component ID
  38. LPTSTR lpPathBuf, // returned path
  39. DWORD *pcchBuf // buffer character count
  40. );
  41. typedef
  42. UINT (WINAPI* PMsiGetShortcutTarget)(
  43. LPCTSTR szShortcutTarget, // path to shortcut link file
  44. LPTSTR szProductCode, // fixed length buffer for product code
  45. LPTSTR szFeatureId, // fixed length buffer for feature id
  46. LPTSTR szComponentCode // fixed length buffer for component code
  47. );
  48. BOOL
  49. IsUserAdmin(
  50. void
  51. );
  52. BOOL
  53. GiveUsersWriteAccess(
  54. void
  55. );
  56. BOOL
  57. IsLUAEnabled(
  58. LPCWSTR pszLayers
  59. );
  60. wstring
  61. StrUpCase(
  62. wstring& wstr
  63. );
  64. BOOL
  65. ShimExpandEnvironmentVars(
  66. LPCTSTR lpszCmd,
  67. CComBSTR& bstr
  68. )
  69. {
  70. DWORD dwLength;
  71. LPTSTR lpBuffer = NULL;
  72. BOOL bExpanded = FALSE;
  73. if (_tcschr(lpszCmd, TEXT('%')) == NULL) {
  74. goto out;
  75. }
  76. dwLength = ExpandEnvironmentStrings(lpszCmd, NULL, 0);
  77. if (!dwLength) {
  78. goto out;
  79. }
  80. lpBuffer = new TCHAR[dwLength];
  81. if (NULL == lpBuffer) {
  82. goto out;
  83. }
  84. dwLength = ExpandEnvironmentStrings(lpszCmd, lpBuffer, dwLength);
  85. if (!dwLength) {
  86. goto out;
  87. }
  88. bstr = lpBuffer;
  89. bExpanded = TRUE;
  90. out:
  91. if (!bExpanded) {
  92. bstr = lpszCmd;
  93. }
  94. if (lpBuffer) {
  95. delete[] lpBuffer;
  96. }
  97. return bExpanded;
  98. }
  99. wstring
  100. ShimUnquotePath(
  101. LPCTSTR pwszFileName
  102. )
  103. {
  104. wstring sFileName;
  105. LPCTSTR pScan = pwszFileName;
  106. LPCTSTR pQuote;
  107. LPCTSTR pLastQuote = NULL;
  108. // skip over the leading spaces
  109. pScan += _tcsspn(pScan, TEXT(" \t"));
  110. while (*pScan) {
  111. pQuote = _tcschr(pScan, TEXT('\"'));
  112. if (NULL == pQuote) {
  113. sFileName += pScan;
  114. break;
  115. }
  116. //
  117. // we found a quote
  118. // is this the first quote we've found?
  119. if (pLastQuote == NULL) {
  120. pLastQuote = pQuote;
  121. // add the current string
  122. sFileName += wstring(pScan, (int)(pQuote-pScan));
  123. } else {
  124. // we have a closing quote
  125. ++pLastQuote;
  126. sFileName += wstring(pLastQuote, (int)(pQuote-pLastQuote));
  127. pLastQuote = NULL;
  128. }
  129. pScan = pQuote + 1;
  130. }
  131. return sFileName;
  132. }
  133. //
  134. // ShimGetPathFromCmdLine
  135. //
  136. BOOL
  137. ShimGetPathFromCmdLine(
  138. LPCTSTR pwszCmdLine,
  139. CComBSTR& StrPath
  140. )
  141. {
  142. TCHAR chSave;
  143. LPTSTR pScan = (LPTSTR)pwszCmdLine;
  144. LPTSTR pAppName;
  145. TCHAR szBuffer[MAX_PATH];
  146. DWORD dwLength;
  147. DWORD dwAttributes;
  148. BOOL bScan = FALSE;
  149. CComBSTR bstrPathName;
  150. if (*pScan == TEXT('\"')) {
  151. // seek till we find matching "
  152. pAppName = ++pScan;
  153. while (*pScan) {
  154. if (*pScan == TEXT('\"')) {
  155. break;
  156. }
  157. ++pScan;
  158. }
  159. } else {
  160. pAppName = pScan;
  161. while (*pScan) {
  162. if (_istspace(*pScan)) {
  163. bScan = TRUE;
  164. break;
  165. }
  166. ++pScan;
  167. }
  168. }
  169. while (TRUE) {
  170. chSave = *pScan;
  171. *pScan = TEXT('\0');
  172. ShimExpandEnvironmentVars(pAppName, bstrPathName);
  173. //
  174. // Check this path
  175. //
  176. dwLength = SearchPathW(NULL,
  177. bstrPathName,
  178. TEXT(".exe"),
  179. CHARCOUNT(szBuffer),
  180. szBuffer,
  181. NULL);
  182. //
  183. // restore the character
  184. //
  185. *pScan = chSave;
  186. if (dwLength && dwLength < CHARCOUNT(szBuffer)) {
  187. //
  188. // check attributes
  189. //
  190. dwAttributes = GetFileAttributesW(szBuffer);
  191. if ((dwAttributes != (DWORD)-1) &&
  192. !(dwAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  193. //
  194. // we are mighty done
  195. //
  196. StrPath = (LPCWSTR)szBuffer;
  197. return TRUE;
  198. }
  199. }
  200. if (!bScan || *pScan == TEXT('\0')) {
  201. break;
  202. }
  203. ++pScan;
  204. while (*pScan) {
  205. if (_istspace(*pScan)) {
  206. break;
  207. }
  208. ++pScan;
  209. }
  210. }
  211. return FALSE;
  212. }
  213. //
  214. // This class allows us to change error mode on selected apis
  215. //
  216. //
  217. class CSaveErrorMode {
  218. public:
  219. CSaveErrorMode() {
  220. m_uiErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  221. }
  222. ~CSaveErrorMode() {
  223. SetErrorMode(m_uiErrorMode);
  224. }
  225. protected:
  226. UINT m_uiErrorMode;
  227. };
  228. STDMETHODIMP CUtil::IsCompatWizardDisabled(BOOL* pbDisabled)
  229. {
  230. *pbDisabled = FALSE;
  231. return S_OK;
  232. }
  233. STDMETHODIMP CUtil::RemoveArgs(BSTR pVar, VARIANT* pRet)
  234. {
  235. // TODO: Add your implementation code here
  236. CComBSTR bstr;
  237. CSaveErrorMode ErrMode;
  238. if (!ShimGetPathFromCmdLine(pVar, bstr)) {
  239. bstr = pVar;
  240. }
  241. pRet->vt = VT_BSTR;
  242. pRet->bstrVal = bstr.Copy();
  243. return S_OK;
  244. }
  245. STDMETHODIMP CUtil::GetItemKeys(BSTR pVar, VARIANT *pRet)
  246. {
  247. CComBSTR bstr = pVar;
  248. CComBSTR bstrOut;
  249. LPWSTR pwszPermKeys;
  250. DWORD cbSize;
  251. BOOL bLayers;
  252. bLayers = SdbGetPermLayerKeys(bstr, NULL, &cbSize, GPLK_USER);
  253. if (bLayers) {
  254. pwszPermKeys = new WCHAR[cbSize / sizeof(WCHAR)];
  255. bLayers = SdbGetPermLayerKeys(bstr, pwszPermKeys, &cbSize, GPLK_USER);
  256. if (bLayers) {
  257. bstrOut = pwszPermKeys;
  258. }
  259. delete [] pwszPermKeys;
  260. }
  261. if (!bstrOut) {
  262. pRet->vt = VT_NULL;
  263. } else {
  264. pRet->vt = VT_BSTR;
  265. pRet->bstrVal = bstrOut.Copy();
  266. }
  267. return S_OK;
  268. }
  269. STDMETHODIMP CUtil::SetItemKeys(BSTR pszPath, VARIANT* pKeys, BOOL *pVal)
  270. {
  271. // TODO: Add your implementation code here
  272. CComBSTR bstrKeys;
  273. CComBSTR bstrKeysMachine;
  274. BOOL bSuccess = TRUE;
  275. VARIANT varKeys;
  276. VARIANT varKeysMachine;
  277. InvalidateAppcompatCacheEntry(pszPath);
  278. if (pKeys->vt == VT_NULL || pKeys->vt == VT_EMPTY) {
  279. bSuccess &= SdbDeletePermLayerKeys(pszPath, FALSE);
  280. } else {
  281. VariantInit(&varKeys);
  282. if (SUCCEEDED(VariantChangeType(&varKeys, pKeys, 0, VT_BSTR))) {
  283. bstrKeys = varKeys.bstrVal;
  284. VariantClear(&varKeys);
  285. }
  286. if (bstrKeys) {
  287. bSuccess &= SdbSetPermLayerKeys(pszPath, bstrKeys, FALSE);
  288. }
  289. }
  290. *pVal = bSuccess;
  291. return S_OK;
  292. }
  293. BOOL
  294. SearchGroupForSID(
  295. DWORD dwGroup,
  296. BOOL* pfIsMember
  297. )
  298. {
  299. PSID pSID = NULL;
  300. SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
  301. BOOL fRes = TRUE;
  302. if (!AllocateAndInitializeSid(&SIDAuth,
  303. 2,
  304. SECURITY_BUILTIN_DOMAIN_RID,
  305. dwGroup,
  306. 0,
  307. 0,
  308. 0,
  309. 0,
  310. 0,
  311. 0,
  312. &pSID)) {
  313. ATLTRACE(_T("[SearchGroupForSID] AllocateAndInitializeSid failed 0x%lx\n"),
  314. GetLastError());
  315. return FALSE;
  316. }
  317. if (!CheckTokenMembership(NULL, pSID, pfIsMember)) {
  318. ATLTRACE(_T("[SearchGroupForSID] CheckTokenMembership failed 0x%x\n"),
  319. GetLastError());
  320. fRes = FALSE;
  321. }
  322. FreeSid(pSID);
  323. return fRes;
  324. }
  325. BOOL
  326. IsUserAdmin(
  327. void
  328. )
  329. {
  330. BOOL fIsUser, fIsAdmin, fIsPowerUser;
  331. if (!SearchGroupForSID(DOMAIN_ALIAS_RID_USERS, &fIsUser) ||
  332. !SearchGroupForSID(DOMAIN_ALIAS_RID_ADMINS, &fIsAdmin)) {
  333. return FALSE;
  334. }
  335. return (fIsUser && fIsAdmin);
  336. }
  337. #if 0
  338. BOOL
  339. GiveUsersWriteAccess(
  340. void
  341. )
  342. {
  343. DWORD dwRes;
  344. PACL pOldDACL;
  345. PACL pNewDACL = NULL;
  346. SECURITY_DESCRIPTOR sd;
  347. PSECURITY_DESCRIPTOR pSD = &sd;
  348. GUID guidChildObjectType; // GUID of object to control creation of
  349. PSID pTrusteeSID; // trustee for new ACE
  350. EXPLICIT_ACCESS ea;
  351. SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
  352. PSID pUsersSID = NULL;
  353. TCHAR szDir[MAX_PATH];
  354. ExpandEnvironmentStrings(LUA_REDIR_W, szDir, MAX_PATH);
  355. if (!CreateDirectory(szDir, NULL)) {
  356. DWORD err = GetLastError();
  357. if (GetLastError() != ERROR_ALREADY_EXISTS) {
  358. return FALSE;
  359. }
  360. }
  361. dwRes = GetNamedSecurityInfo(szDir,
  362. SE_FILE_OBJECT,
  363. DACL_SECURITY_INFORMATION,
  364. NULL,
  365. NULL,
  366. &pOldDACL,
  367. NULL,
  368. &pSD);
  369. if (ERROR_SUCCESS != dwRes) {
  370. goto Cleanup;
  371. }
  372. if (!AllocateAndInitializeSid(&SIDAuth,
  373. 2,
  374. SECURITY_BUILTIN_DOMAIN_RID,
  375. DOMAIN_ALIAS_RID_USERS,
  376. 0,
  377. 0,
  378. 0,
  379. 0,
  380. 0,
  381. 0,
  382. &pUsersSID) ) {
  383. goto Cleanup;
  384. }
  385. //
  386. // Initialize an EXPLICIT_ACCESS structure for the new ACE.
  387. //
  388. ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
  389. ea.grfAccessPermissions = FILE_ALL_ACCESS;
  390. ea.grfAccessMode = GRANT_ACCESS;
  391. ea.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  392. ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
  393. ea.Trustee.TrusteeType = TRUSTEE_IS_GROUP;
  394. ea.Trustee.ptstrName = (LPTSTR)pUsersSID;
  395. //
  396. // Create a new ACL that merges the new ACE
  397. // into the existing DACL.
  398. //
  399. dwRes = SetEntriesInAcl(1, &ea, pOldDACL, &pNewDACL);
  400. if (ERROR_SUCCESS != dwRes) {
  401. goto Cleanup;
  402. }
  403. dwRes = SetNamedSecurityInfo(szDir,
  404. SE_FILE_OBJECT,
  405. DACL_SECURITY_INFORMATION,
  406. NULL,
  407. NULL,
  408. pNewDACL,
  409. NULL);
  410. if (ERROR_SUCCESS != dwRes) {
  411. goto Cleanup;
  412. }
  413. Cleanup:
  414. if (pUsersSID) {
  415. FreeSid(pUsersSID);
  416. }
  417. return (dwRes == ERROR_SUCCESS);
  418. }
  419. BOOL
  420. IsLUAEnabled(
  421. LPCWSTR pszLayers
  422. )
  423. {
  424. LPCWSTR pchStart = pszLayers;
  425. LPCWSTR pch;
  426. wstring strTok;
  427. BOOL bLUAEnabled = FALSE;
  428. pchStart += wcsspn(pchStart, L"#!");
  429. while (pchStart != NULL && *pchStart != L'\0' && !bLUAEnabled) {
  430. pchStart += wcsspn(pchStart, L" \t");
  431. if (*pchStart == L'\0') {
  432. break;
  433. }
  434. pch = wcspbrk(pchStart, L" \t");
  435. if (pch == NULL) {
  436. strTok = pchStart;
  437. pchStart = NULL;
  438. } else {
  439. strTok = wstring(pchStart, (size_t)(pch - pchStart));
  440. StrUpCase(strTok);
  441. pchStart = pch;
  442. }
  443. bLUAEnabled = (strTok == L"LUA");
  444. }
  445. return bLUAEnabled;
  446. }
  447. #endif
  448. // this method returns true when we should present the LUA checkbox and
  449. // false when we should not
  450. STDMETHODIMP CUtil::CheckAdminPrivileges(BOOL *pVal)
  451. {
  452. *pVal = IsUserAdmin();
  453. return S_OK;
  454. }
  455. STDMETHODIMP CUtil::RunApplication(BSTR pLayers, BSTR pszCmdLine, BOOL bEnableLog, DWORD* pResult)
  456. {
  457. LPCWSTR pszExt;
  458. BOOL bShellExecute = FALSE;
  459. BOOL bSuccess = FALSE;
  460. DWORD dwError = 0;
  461. DWORD dwBinaryType = 0;
  462. DWORD dwCreateProcessFlags = 0;
  463. CSaveErrorMode ErrMode;
  464. CComBSTR bstrAppName = pszCmdLine;
  465. ShimGetPathFromCmdLine(pszCmdLine, bstrAppName);
  466. CComBSTR bstrExePath;
  467. // check if we are using .lnk file
  468. pszExt = PathFindExtension(bstrAppName);
  469. if (pszExt != NULL) {
  470. bShellExecute = !_tcsicmp(pszExt, TEXT(".lnk"));
  471. }
  472. if (!bShellExecute) { // not shell exec? check the binary
  473. if (!pszExt || (_tcsicmp(pszExt, TEXT(".cmd")) && _tcsicmp(pszExt, TEXT(".bat")))) {
  474. bShellExecute = !GetBinaryTypeW(bstrAppName, &dwBinaryType);
  475. if (!bShellExecute && (dwBinaryType == SCS_WOW_BINARY || dwBinaryType == SCS_PIF_BINARY)) {
  476. dwCreateProcessFlags |= CREATE_SEPARATE_WOW_VDM;
  477. }
  478. }
  479. }
  480. //
  481. // invalidate cache
  482. //
  483. if (::GetExePathFromObject(bstrAppName, bstrExePath)) {
  484. InvalidateAppcompatCacheEntry(bstrExePath);
  485. }
  486. SetEnvironmentVariable(TEXT("__COMPAT_LAYER"), pLayers);
  487. SetEnvironmentVariable(TEXT("SHIM_FILE_LOG"), bEnableLog ? TEXT("shim.log") : NULL);
  488. //
  489. // now we shall either ShellExecute or do a CreateProcess
  490. //
  491. if (bShellExecute) {
  492. int nLength = bstrAppName.Length() + 3;
  493. LPTSTR pszCmdLineShellExec = new TCHAR[nLength];
  494. SHELLEXECUTEINFO ShExecInfo = { 0 };
  495. if (pszCmdLineShellExec == NULL) {
  496. //
  497. // out of memory, just do a create process
  498. //
  499. goto HandleCreateProcess;
  500. }
  501. nLength = _sntprintf(pszCmdLineShellExec,
  502. nLength,
  503. TEXT("\"%s\""),
  504. (LPCTSTR)bstrAppName);
  505. if (nLength < 0) {
  506. delete[] pszCmdLineShellExec;
  507. goto HandleCreateProcess;
  508. }
  509. ShExecInfo.cbSize = sizeof(ShExecInfo);
  510. ShExecInfo.fMask = 0; //SEE_MASK_FLAG_NO_UI;
  511. ShExecInfo.lpVerb = L"open";
  512. ShExecInfo.lpFile = pszCmdLineShellExec;
  513. ShExecInfo.nShow = SW_SHOW;
  514. bSuccess = ShellExecuteEx(&ShExecInfo);
  515. if (!bSuccess || (int)((INT_PTR)ShExecInfo.hInstApp) < 32) {
  516. dwError = GetLastError();
  517. }
  518. delete[] pszCmdLineShellExec;
  519. } else {
  520. HandleCreateProcess:
  521. // get working directory
  522. TCHAR szWorkingDir[MAX_PATH];
  523. LPTSTR pAppName = (LPTSTR)bstrAppName.m_str;
  524. int nLength;
  525. LPTSTR pszWorkingDir = NULL;
  526. STARTUPINFO StartupInfo;
  527. PROCESS_INFORMATION ProcessInfo;
  528. LPTSTR pBackslash = _tcsrchr(pAppName, TEXT('\\'));
  529. if (pBackslash != NULL) {
  530. //
  531. // check for root
  532. //
  533. nLength = (int)(pBackslash - pAppName);
  534. if (nLength == 2 && pAppName[1] == TEXT(':')) {
  535. ++nLength;
  536. }
  537. _tcsncpy(szWorkingDir, pAppName, nLength);
  538. szWorkingDir[nLength] = TEXT('\0');
  539. pszWorkingDir = szWorkingDir;
  540. }
  541. ZeroMemory(&StartupInfo, sizeof(StartupInfo));
  542. StartupInfo.cb = sizeof(StartupInfo);
  543. ZeroMemory(&ProcessInfo, sizeof(ProcessInfo));
  544. bSuccess = CreateProcess(NULL,
  545. pszCmdLine,
  546. NULL,
  547. NULL,
  548. FALSE,
  549. 0,
  550. NULL,
  551. pszWorkingDir,
  552. &StartupInfo,
  553. &ProcessInfo);
  554. if (!bSuccess) {
  555. dwError = GetLastError();
  556. }
  557. if (ProcessInfo.hThread) {
  558. CloseHandle(ProcessInfo.hThread);
  559. }
  560. if (ProcessInfo.hProcess) {
  561. CloseHandle(ProcessInfo.hProcess);
  562. }
  563. }
  564. *pResult = dwError;
  565. SetEnvironmentVariable(TEXT("__COMPAT_LAYER"), NULL);
  566. SetEnvironmentVariable(TEXT("SHIM_FILE_LOG") , NULL);
  567. return S_OK;
  568. }
  569. BOOL
  570. GetExePathFromLink(
  571. LPMALLOC pMalloc,
  572. LPCITEMIDLIST pidlLinkFull,
  573. LPCTSTR pszLinkFile,
  574. LPTSTR pszExePath,
  575. DWORD dwBufferSize
  576. )
  577. {
  578. IShellLink* psl = NULL;
  579. WIN32_FIND_DATA wfd;
  580. HRESULT hr;
  581. BOOL bSuccess = FALSE;
  582. TCHAR szPath[MAX_PATH];
  583. IPersistFile* ipf = NULL;
  584. IShellLinkDataList* pdl;
  585. DWORD dwFlags = 0;
  586. BOOL bMsiLink = FALSE;
  587. HMODULE hMSI = NULL;
  588. // first do the link
  589. hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
  590. IID_IShellLink, (LPVOID*)&psl);
  591. if (!SUCCEEDED(hr)) {
  592. return FALSE; // we can't create link object
  593. }
  594. hr = psl->SetIDList(pidlLinkFull); // set the id list
  595. if (!SUCCEEDED(hr)) {
  596. goto out;
  597. }
  598. hr = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ipf);
  599. if (!SUCCEEDED(hr)) {
  600. goto out;
  601. }
  602. hr = ipf->Load(pszLinkFile, STGM_READ);
  603. if (!SUCCEEDED(hr)) {
  604. goto out;
  605. }
  606. //
  607. // resolve the link for now
  608. //
  609. // hr = psl->Resolve(NULL, SLR_NO_UI|SLR_NOUPDATE);
  610. //
  611. hr = psl->QueryInterface(IID_IShellLinkDataList, (LPVOID*)&pdl);
  612. if (SUCCEEDED(hr)) {
  613. hr = pdl->GetFlags(&dwFlags);
  614. bMsiLink = SUCCEEDED(hr) && (dwFlags & SLDF_HAS_DARWINID);
  615. pdl->Release();
  616. }
  617. if (bMsiLink) {
  618. //
  619. // this is msi link, we need to crack it using msi
  620. //
  621. UINT ErrCode;
  622. TCHAR szProduct [MAX_PATH];
  623. TCHAR szFeatureId [MAX_PATH];
  624. TCHAR szComponentCode[MAX_PATH];
  625. INSTALLSTATE is;
  626. hMSI = LoadLibrary(TEXT("Msi.dll"));
  627. if (NULL == hMSI) {
  628. goto out;
  629. }
  630. PMsiGetComponentPath pfnGetComponentPath = (PMsiGetComponentPath )GetProcAddress(hMSI, "MsiGetComponentPathW");
  631. PMsiGetShortcutTarget pfnGetShortcutTarget = (PMsiGetShortcutTarget)GetProcAddress(hMSI, "MsiGetShortcutTargetW");
  632. if (!pfnGetComponentPath || !pfnGetShortcutTarget)
  633. {
  634. goto out;
  635. }
  636. ErrCode = pfnGetShortcutTarget(pszLinkFile,
  637. szProduct,
  638. szFeatureId,
  639. szComponentCode);
  640. if (ERROR_SUCCESS != ErrCode) {
  641. goto out;
  642. }
  643. *pszExePath = TEXT('\0');
  644. is = pfnGetComponentPath(szProduct, szComponentCode, pszExePath, &dwBufferSize);
  645. bSuccess = (INSTALLSTATE_LOCAL == is);
  646. } else {
  647. hr = psl->GetPath(pszExePath, dwBufferSize, &wfd, 0);
  648. bSuccess = SUCCEEDED(hr);
  649. }
  650. out:
  651. if (hMSI) {
  652. FreeLibrary(hMSI);
  653. }
  654. if (NULL != ipf) {
  655. ipf->Release();
  656. }
  657. if (NULL != psl) {
  658. psl->Release();
  659. }
  660. return bSuccess;
  661. }
  662. BOOL
  663. GetExePathFromObject(
  664. LPCTSTR lpszPath, // path to an arbitrary object
  665. CComBSTR& bstrExePath
  666. )
  667. {
  668. IShellFolder* psh = NULL;
  669. LPMALLOC pMalloc = NULL;
  670. HRESULT hr;
  671. LPITEMIDLIST pidl = NULL;
  672. DWORD dwAttributes;
  673. CComBSTR bstr;
  674. BOOL bSuccess = FALSE;
  675. hr = SHGetMalloc(&pMalloc);
  676. if (!SUCCEEDED(hr)) {
  677. goto cleanup;
  678. }
  679. hr = SHGetDesktopFolder(&psh);
  680. if (!SUCCEEDED(hr)) {
  681. goto cleanup;
  682. }
  683. if (!ShimGetPathFromCmdLine(lpszPath, bstr)) {
  684. goto cleanup;
  685. }
  686. //
  687. // parse display name
  688. //
  689. dwAttributes = SFGAO_LINK | SFGAO_FILESYSTEM | SFGAO_VALIDATE;
  690. hr = psh->ParseDisplayName(NULL,
  691. NULL,
  692. bstr, // path to the executable file
  693. NULL, // number of chars eaten
  694. &pidl,
  695. &dwAttributes);
  696. if (!SUCCEEDED(hr)) {
  697. goto cleanup;
  698. }
  699. //
  700. // display name parsed, check whether it's a link
  701. //
  702. if (dwAttributes & SFGAO_LINK) {
  703. TCHAR szExePath[MAX_PATH];
  704. //
  705. // it's a link, crack it
  706. //
  707. bSuccess = GetExePathFromLink(pMalloc,
  708. pidl,
  709. bstr,
  710. szExePath,
  711. CHARCOUNT(szExePath));
  712. // after recovering the path -- get the env vars expanded
  713. if (bSuccess) {
  714. ShimExpandEnvironmentVars(szExePath, bstrExePath);
  715. }
  716. } else if (dwAttributes & SFGAO_FILESYSTEM) {
  717. //
  718. // filesystem object (a file)
  719. //
  720. bstrExePath = bstr;
  721. bSuccess = TRUE;
  722. }
  723. cleanup:
  724. if (pidl) {
  725. pMalloc->Free(pidl);
  726. }
  727. if (psh) {
  728. psh->Release();
  729. }
  730. if (pMalloc) {
  731. pMalloc->Release();
  732. }
  733. return bSuccess;
  734. }
  735. STDMETHODIMP CUtil::GetExePathFromObject(BSTR pszPath, VARIANT* pExePath)
  736. {
  737. CComBSTR bstrExePath;
  738. BOOL bSuccess;
  739. CSaveErrorMode ErrMode;
  740. bSuccess = ::GetExePathFromObject(pszPath, bstrExePath);
  741. if (bSuccess) {
  742. pExePath->vt = VT_BSTR;
  743. pExePath->bstrVal = bstrExePath.Copy();
  744. } else {
  745. pExePath->vt = VT_NULL;
  746. }
  747. return S_OK;
  748. }
  749. STDMETHODIMP CUtil::IsSystemTarget(BSTR bstrPath, BOOL *pbSystemTarget)
  750. {
  751. CComBSTR bstrExePath;
  752. BOOL bSystemTarget = FALSE;
  753. DWORD dwAttributes;
  754. CSaveErrorMode ErrMode;
  755. /*++
  756. //
  757. // This code was used to check system directory
  758. //
  759. ULONG uSize;
  760. int nch;
  761. TCHAR szSystemDir[MAX_PATH];
  762. TCHAR szCommonPath[MAX_PATH];
  763. uSize = ::GetSystemWindowsDirectory(szSystemDir,
  764. CHARCOUNT(szSystemDir));
  765. if (uSize == 0 || uSize > CHARCOUNT(szSystemDir)) {
  766. *pbSystemTarget = FALSE;
  767. return S_OK;
  768. }
  769. --*/
  770. if (!::GetExePathFromObject(bstrPath, bstrExePath)) {
  771. bstrExePath = bstrPath;
  772. }
  773. /*++
  774. // this code was used before -- it checked system directory as
  775. // well as sfc, we are only checking sfc now
  776. nch = PathCommonPrefix(szSystemDir, bstrExePath, szCommonPath);
  777. bSystemTarget = (nch == (int)uSize);
  778. if (!bSystemTarget) {
  779. bSystemTarget = SfcIsFileProtected(NULL, bstrExePath);
  780. }
  781. --*/
  782. bSystemTarget = SfcIsFileProtected(NULL, bstrExePath);
  783. if (!bSystemTarget) {
  784. dwAttributes = GetFileAttributes(bstrExePath);
  785. bSystemTarget = (dwAttributes == (DWORD)-1 || (dwAttributes & FILE_ATTRIBUTE_DIRECTORY));
  786. }
  787. *pbSystemTarget = bSystemTarget;
  788. return S_OK;
  789. }
  790. STDMETHODIMP CUtil::IsExecutableFile(BSTR bstrPath, BOOL *pbExecutableFile)
  791. {
  792. BOOL bExecutable = FALSE;
  793. DWORD dwExeType = 0;
  794. CComBSTR bstrExePath;
  795. LPCWSTR pszExt;
  796. CSaveErrorMode ErrMode;
  797. if (!::GetExePathFromObject(bstrPath, bstrExePath)) {
  798. bstrExePath = bstrPath;
  799. }
  800. bExecutable = GetBinaryTypeW(bstrExePath, &dwExeType);
  801. if (!bExecutable) {
  802. // is this a batch file? if not -- you are out!
  803. pszExt = PathFindExtension(bstrPath);
  804. if (pszExt != NULL) {
  805. bExecutable = !_tcsicmp(pszExt, TEXT(".bat")) ||
  806. !_tcsicmp(pszExt, TEXT(".cmd"));
  807. }
  808. }
  809. *pbExecutableFile = bExecutable;
  810. return S_OK;
  811. }