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.

1187 lines
30 KiB

  1. #include "..\pch\headers.hxx"
  2. #pragma hdrstop
  3. #include "myheaders.hxx"
  4. #include <shlobjp.h> // IShellLinkDataList
  5. #include <shlguidp.h> // IID_IShellLinkDataList
  6. #include <msi.h> // MsiQueryProductState
  7. #include <stdlib.h>
  8. #include <process.h>
  9. #include <winver.h>
  10. #include <errno.h>
  11. #include <fcntl.h>
  12. #include <sys/types.h>
  13. #include <sys/stat.h>
  14. #include <io.h>
  15. #include "walklib.h"
  16. #include "..\inc\misc.hxx"
  17. typedef INSTALLSTATE (WINAPI* PFN_MsiQueryProductState) (LPCTSTR tszProduct);
  18. BOOL
  19. IsMsiApp(
  20. IShellLink * psl
  21. );
  22. /////////////////////////////////////////////////////////////////
  23. /////////////////////////////////////////////////////////////////
  24. /////////////////////////////////////////////////////////////////
  25. HWALK GetFirstFileLnkInfo(LPLINKINFO lpLnkInfo, DWORD dwFlags,
  26. LPTSTR lpszFolder, ERR *pErrRet)
  27. {
  28. BOOL bRC=TRUE;
  29. ERR errVal;
  30. LPWALKHEADER lpWalk;
  31. LPTSTR lpszSubStr;
  32. TCHAR szFullPath[MAX_PATH];
  33. #ifdef _DEBUG
  34. lpWalk = (LPWALKHEADER) MyGlobalAlloc(FAILMEMA, sizeof(WALKHEADER));
  35. #else
  36. lpWalk = (LPWALKHEADER) GlobalAlloc(GPTR, sizeof(WALKHEADER));
  37. #endif
  38. if (lpWalk == NULL)
  39. {
  40. *pErrRet = ERR_NOMEMORY ;//ERR_NOMEMORY -6;
  41. return NULL; // Global Alloc failed
  42. }
  43. lpWalk->lpSrchDirListHead = NULL;
  44. lpWalk->lpSrchDirListTail = NULL;
  45. lpWalk->lpszIniString = NULL;
  46. lpWalk->lpszNextFile = NULL;
  47. lpWalk->dwCurrentFlag = RESET_FLAG;
  48. lpWalk->dwWalkFlags = dwFlags;
  49. if (lpWalk->dwWalkFlags & INPTYPE_ANYFOLDER)
  50. {
  51. if (IsBadStringPtr(lpszFolder, MAX_PATH))
  52. lpWalk->lpszFolder = NULL;
  53. else
  54. lpWalk->lpszFolder = lpszFolder;
  55. }
  56. else
  57. lpWalk->lpszFolder = NULL;
  58. SetLnkInfo(lpLnkInfo);
  59. errVal = GetFileHandle(lpLnkInfo, lpWalk, szFullPath);
  60. if (errVal == 0)
  61. {
  62. *pErrRet = ERR_SUCCESS;//ERR_NOMOREFILES 0;
  63. CloseWalk(lpWalk);
  64. return NULL; /* No more files: Done */
  65. }
  66. else if (errVal < 0)
  67. {
  68. *pErrRet = errVal;
  69. CloseWalk(lpWalk);
  70. return NULL;
  71. }
  72. lpszSubStr = _tcsrchr(lpLnkInfo->szLnkName, TEXT('.'));
  73. if (lpszSubStr)
  74. {
  75. if ((_tcsicmp(lpszSubStr, TEXT(".LNK")) == 0) ||
  76. (_tcsicmp(lpszSubStr, TEXT(".EXE")) == 0))
  77. {
  78. if (!(errVal = GetLnkInfo(lpWalk, lpLnkInfo, szFullPath)))
  79. {
  80. lpszSubStr = _tcsrchr(lpLnkInfo->szExeName, TEXT('.'));
  81. if (lpszSubStr)
  82. {
  83. if (_tcsicmp(lpszSubStr, TEXT(".EXE")) == 0 ||
  84. _tcsicmp(lpszSubStr, TEXT(".LNK")) == 0)
  85. {
  86. *pErrRet = ERR_MOREFILESTOCOME;// ERR_SUCCESS but there are more files;
  87. return lpWalk;
  88. }
  89. }
  90. }
  91. }
  92. }
  93. if ((errVal == ERR_NOTANEXE) || errVal > 0)
  94. {
  95. *pErrRet = GetNextFileLnkInfo(lpWalk, lpLnkInfo);
  96. if ((*pErrRet != ERR_SUCCESS) && (*pErrRet != ERR_MOREFILESTOCOME))
  97. {
  98. CloseWalk(lpWalk);
  99. return NULL;
  100. }
  101. else
  102. return lpWalk;
  103. }
  104. else
  105. {
  106. *pErrRet = errVal;
  107. CloseWalk(lpWalk);
  108. return NULL;
  109. }
  110. }
  111. /////////////////////////////////////////////////////////////////
  112. /////////////////////////////////////////////////////////////////
  113. /////////////////////////////////////////////////////////////////
  114. ERR GetNextFileLnkInfo(HWALK hWalk, LPLINKINFO lpLnkInfo)
  115. {
  116. BOOL bRC=TRUE;
  117. INT retVal;
  118. LPTSTR lpszSubStr;
  119. TCHAR szFullPath[MAX_PATH];
  120. LPWALKHEADER lpWalk = (LPWALKHEADER) hWalk;
  121. while (1)
  122. {
  123. retVal = GetFileHandle(lpLnkInfo, lpWalk, szFullPath);
  124. if (retVal < 0)
  125. return retVal; /* Couldn't find next file */
  126. else if (retVal == 0 ) /* Done : No more files */
  127. return ERR_SUCCESS;
  128. lpszSubStr = _tcsrchr(lpLnkInfo->szLnkName, TEXT('.'));
  129. if (lpszSubStr)
  130. {
  131. if ((_tcsicmp(lpszSubStr, TEXT(".LNK")) == 0) ||
  132. (_tcsicmp(lpszSubStr, TEXT(".EXE")) == 0))
  133. {
  134. if (!(retVal = GetLnkInfo(lpWalk, lpLnkInfo, szFullPath)))
  135. {
  136. lpszSubStr = _tcsrchr(lpLnkInfo->szExeName, TEXT('.'));
  137. if (lpszSubStr)
  138. {
  139. if (_tcsicmp(lpszSubStr, TEXT(".EXE")) == 0 ||
  140. _tcsicmp(lpszSubStr, TEXT(".LNK")) == 0)
  141. {
  142. break;
  143. }
  144. }
  145. }
  146. else if (retVal != ERR_NOTANEXE)
  147. return retVal;
  148. }
  149. }
  150. continue; /* Not a Link File */
  151. }
  152. return ERR_MOREFILESTOCOME;
  153. }
  154. /////////////////////////////////////////////////////////////////
  155. /////////////////////////////////////////////////////////////////
  156. /////////////////////////////////////////////////////////////////
  157. BOOL InSkipList(LPTSTR lpszFileName)
  158. {
  159. INT i;
  160. LPTSTR lplpszToSkipFiles[] =
  161. {
  162. TEXT("write.exe"),
  163. TEXT("winhelp.exe"),
  164. TEXT("winhlp32.exe"),
  165. TEXT("notepad.exe"),
  166. TEXT("wordpad.exe"),
  167. TEXT("rundll32.exe"),
  168. TEXT("explorer.exe"),
  169. TEXT("control.exe")
  170. };
  171. for (i = 0; i < ARRAYLEN(lplpszToSkipFiles); i++)
  172. {
  173. if (_tcsicmp(lpszFileName, lplpszToSkipFiles[i]) == 0)
  174. return TRUE;
  175. }
  176. return FALSE;
  177. }
  178. /////////////////////////////////////////////////////////////////
  179. /////////////////////////////////////////////////////////////////
  180. /////////////////////////////////////////////////////////////////
  181. INT GetFileHandle(LPLINKINFO lpLnkInfo, LPWALKHEADER lpWalk, LPTSTR lpszPath)
  182. {
  183. DWORD dwAttrs;
  184. BOOL bRC;
  185. HANDLE hSearch;
  186. INT retVal;
  187. TCHAR szFolderPath[MAX_PATH];
  188. WIN32_FIND_DATA wfdFileData;
  189. DEBUG_ASSERT(lpWalk != NULL);
  190. while (GetInputType(lpWalk) == FOLDER)
  191. {
  192. SetLnkInfo(lpLnkInfo);
  193. if (lpWalk->lpSrchDirListHead == NULL)
  194. {
  195. if (retVal = GetFolder(szFolderPath, lpWalk))
  196. return retVal;
  197. if (!SetCurrentDirectory(szFolderPath))
  198. {
  199. lpWalk->dwWalkFlags = lpWalk->dwWalkFlags & (~lpWalk->dwCurrentFlag);
  200. goto LoopBack;
  201. // return ERR_SETCURRENTDIR;
  202. }
  203. hSearch = FindFirstFile(TEXT("*"), &wfdFileData);
  204. if (hSearch == INVALID_HANDLE_VALUE)
  205. {
  206. lpWalk->dwWalkFlags = lpWalk->dwWalkFlags & (~lpWalk->dwCurrentFlag);
  207. goto LoopBack;
  208. }
  209. else
  210. {
  211. retVal = AddToList(hSearch, lpWalk);
  212. if (retVal == ERR_NOMEMORY)
  213. return ERR_NOMEMORY; // GlobalAlloc failed
  214. }
  215. }
  216. else
  217. {
  218. while (!(bRC = FindNextFile(lpWalk->lpSrchDirListTail->hDirHandle, &wfdFileData)))
  219. {
  220. if (GetLastError() == ERROR_NO_MORE_FILES)
  221. {
  222. FindClose(lpWalk->lpSrchDirListTail->hDirHandle);
  223. RemoveFromList(lpWalk);
  224. if (lpWalk->lpSrchDirListHead == NULL)
  225. {
  226. lpWalk->dwWalkFlags = lpWalk->dwWalkFlags & (~lpWalk->dwCurrentFlag);
  227. goto LoopBack;
  228. }
  229. SetCurrentDirectory(TEXT(".."));
  230. }
  231. else
  232. return ERR_UNKNOWN ; // should never come here
  233. }
  234. }
  235. dwAttrs = GetFileAttributes(wfdFileData.cFileName);
  236. while (dwAttrs & FILE_ATTRIBUTE_DIRECTORY)
  237. {
  238. if (_tcsicmp(wfdFileData.cFileName, TEXT(".")) &&
  239. _tcsicmp(wfdFileData.cFileName, TEXT("..")))
  240. {
  241. SetCurrentDirectory(wfdFileData.cFileName);
  242. hSearch = FindFirstFile(TEXT("*"), &wfdFileData);
  243. if (hSearch == INVALID_HANDLE_VALUE)
  244. {
  245. if (lpWalk->lpSrchDirListHead == NULL)
  246. {
  247. lpWalk->dwWalkFlags = lpWalk->dwWalkFlags & (~lpWalk->dwCurrentFlag);
  248. goto LoopBack;
  249. }
  250. else
  251. return ERR_UNKNOWN; // Never comes here for all dirs have . and ..
  252. }
  253. retVal = AddToList(hSearch, lpWalk);
  254. if (retVal == ERR_NOMEMORY)
  255. return ERR_NOMEMORY; // GlobalAlloc failed
  256. dwAttrs = GetFileAttributes(wfdFileData.cFileName);
  257. }
  258. else
  259. {
  260. while (!(bRC = FindNextFile(lpWalk->lpSrchDirListTail->hDirHandle, &wfdFileData)))
  261. {
  262. if ((GetLastError() == ERROR_NO_MORE_FILES))
  263. {
  264. FindClose(lpWalk->lpSrchDirListTail->hDirHandle);
  265. RemoveFromList(lpWalk);
  266. if (lpWalk->lpSrchDirListHead == NULL)
  267. {
  268. lpWalk->dwWalkFlags = lpWalk->dwWalkFlags & (~lpWalk->dwCurrentFlag);
  269. goto LoopBack;
  270. }
  271. SetCurrentDirectory(TEXT(".."));
  272. }
  273. else
  274. return ERR_UNKNOWN ; //should never come here
  275. }
  276. dwAttrs = GetFileAttributes(wfdFileData.cFileName);
  277. }
  278. }
  279. lstrcpy(lpLnkInfo->szLnkName, wfdFileData.cFileName);
  280. GetCurrentDirectory(MAX_PATH, lpLnkInfo->szLnkPath); //BUG
  281. lstrcpy(lpLnkInfo->szExeName, lpLnkInfo->szLnkName);
  282. lstrcpy(lpLnkInfo->szExePath, lpLnkInfo->szLnkPath);
  283. wsprintf(lpszPath, TEXT("%s\\%s"), lpLnkInfo->szExePath, lpLnkInfo->szExeName);
  284. return ERR_MOREFILESTOCOME;
  285. LoopBack:
  286. lpWalk->dwCurrentFlag = RESET_FLAG;
  287. continue;
  288. }
  289. DEBUG_ASSERT(GetInputType(lpWalk) != INIFILE);
  290. DEBUG_ASSERT(GetInputType(lpWalk) != REGISTRY);
  291. return ERR_SUCCESS; //This means we are done with all of them.
  292. }
  293. /////////////////////////////////////////////////////////////////
  294. /////////////////////////////////////////////////////////////////
  295. /////////////////////////////////////////////////////////////////
  296. ERR GetNextFileFromString(LPWALKHEADER lpWalk, LPLINKINFO lpLnkInfo)
  297. {
  298. return E_NOTIMPL;
  299. }
  300. /////////////////////////////////////////////////////////////////
  301. /////////////////////////////////////////////////////////////////
  302. /////////////////////////////////////////////////////////////////
  303. BOOL GetFileLAD(LPLINKINFO lpLnkInfo)
  304. {
  305. WIN32_FIND_DATA wfdFileData;
  306. HANDLE hSearch;
  307. TCHAR szTempStr[MAX_PATH];
  308. lstrcpy(szTempStr, lpLnkInfo->szExePath);
  309. lstrcat(szTempStr, TEXT("\\"));
  310. lstrcat(szTempStr, lpLnkInfo->szExeName);
  311. if (!_tcschr(szTempStr, '.'))
  312. lstrcat(szTempStr, TEXT(".exe"));
  313. if ( NULL == szTempStr && _tcsicmp(_tcschr(szTempStr, '.'), TEXT(".exe")) != 0)
  314. return FALSE;
  315. //bugbug performance hit
  316. hSearch = FindFirstFile( szTempStr, &wfdFileData);
  317. if (hSearch == INVALID_HANDLE_VALUE)
  318. return FALSE;
  319. else
  320. {
  321. lpLnkInfo->ftExeLAD = wfdFileData.ftLastAccessTime;
  322. FindClose(hSearch);
  323. return TRUE;
  324. }
  325. }
  326. /////////////////////////////////////////////////////////////////
  327. /////////////////////////////////////////////////////////////////
  328. /////////////////////////////////////////////////////////////////
  329. ERR GetRegistryString(LPWALKHEADER lpWalk, LPLINKINFO lpLnkInfo)
  330. {
  331. return E_NOTIMPL;
  332. }
  333. /////////////////////////////////////////////////////////////////
  334. /////////////////////////////////////////////////////////////////
  335. /////////////////////////////////////////////////////////////////
  336. ERR GetIniString(LPWALKHEADER lpWalk, LPLINKINFO lpLnkInfo)
  337. {
  338. return E_NOTIMPL;
  339. }
  340. /////////////////////////////////////////////////////////////////
  341. /////////////////////////////////////////////////////////////////
  342. /////////////////////////////////////////////////////////////////
  343. INT GetInputType(LPWALKHEADER lpWalk)
  344. {
  345. if (lpWalk->dwWalkFlags & INPTYPE_FOLDER)
  346. {
  347. return FOLDER;
  348. }
  349. if (lpWalk->dwWalkFlags & INPTYPE_INIFILE)
  350. {
  351. return INIFILE;
  352. }
  353. if (lpWalk->dwWalkFlags & INPTYPE_REGISTRY)
  354. {
  355. return REGISTRY;
  356. }
  357. return ERR_UNKNOWN; // should never come here
  358. }
  359. /////////////////////////////////////////////////////////////////
  360. /////////////////////////////////////////////////////////////////
  361. /////////////////////////////////////////////////////////////////
  362. ERR GetFolder(LPTSTR lpszFolder, LPWALKHEADER lpWalk)
  363. {
  364. HKEY hKey;
  365. UINT cchFolder = MAX_PATH;
  366. TCHAR szRegVal[MAX_PATH];
  367. DWORD dwType;
  368. if (!(lpWalk->dwWalkFlags & INPTYPE_ANYFOLDER))
  369. {
  370. if (RegOpenKeyEx(HKEY_CURRENT_USER, REGSTR_SHELLFOLDERS, 0, KEY_READ, &hKey)
  371. == ERROR_SUCCESS)
  372. {
  373. if (lpWalk->dwWalkFlags & INPTYPE_STARTMENU)
  374. {
  375. lstrcpy(szRegVal, TEXT("Start Menu"));
  376. lpWalk->dwCurrentFlag = INPTYPE_STARTMENU;
  377. }
  378. else if (lpWalk->dwWalkFlags & INPTYPE_DESKTOP)
  379. {
  380. lstrcpy(szRegVal, TEXT("Desktop"));
  381. lpWalk->dwCurrentFlag = INPTYPE_DESKTOP;
  382. }
  383. cchFolder = ARRAYLEN(szRegVal);
  384. LONG lr = RegQueryValueEx(hKey,
  385. szRegVal,
  386. NULL,
  387. &dwType,
  388. (LPBYTE)lpszFolder,
  389. (ULONG *)&cchFolder);
  390. if (dwType == REG_EXPAND_SZ)
  391. {
  392. TCHAR tszTemp[MAX_PATH];
  393. ExpandEnvironmentStrings(lpszFolder,
  394. tszTemp,
  395. ARRAYLEN(tszTemp));
  396. lstrcpy(lpszFolder, tszTemp);
  397. }
  398. if (lr != ERROR_SUCCESS)
  399. {
  400. RegCloseKey(hKey);
  401. if (lpWalk->dwWalkFlags & INPTYPE_STARTMENU)
  402. {
  403. return ERR_NOSTARTMENU;
  404. }
  405. else
  406. {
  407. return ERR_NODESKTOP;
  408. }
  409. }
  410. RegCloseKey(hKey);
  411. }
  412. else
  413. return ERR_NOSHELLFOLDERS;
  414. }
  415. else
  416. {
  417. lstrcpy(lpszFolder, (LPTSTR) lpWalk->lpszFolder);
  418. lpWalk->dwCurrentFlag = INPTYPE_ANYFOLDER;
  419. }
  420. return ERR_SUCCESS;
  421. }
  422. /////////////////////////////////////////////////////////////////
  423. /////////////////////////////////////////////////////////////////
  424. /////////////////////////////////////////////////////////////////
  425. ERR GetLnkInfo(LPWALKHEADER lpWalk, LPLINKINFO lpLnkInfo, LPTSTR lpszPath)
  426. {
  427. WIN32_FIND_DATA wfdExeData;
  428. ERR errVal = ERR_NOTANEXE;
  429. UINT uiDType;
  430. TCHAR szExepath[MAX_PATH];
  431. TCHAR szDrivePath[MAX_PATH];
  432. LPTSTR lpszSubStr;
  433. INT iLen1, iLen2;
  434. BOOL bExists;
  435. //BUGBUG THe if thens should be such that there is repetition of code
  436. szExepath[0] = '\0';
  437. LPTSTR ptszExt = PathFindExtension(lpLnkInfo->szLnkName);
  438. if (ptszExt && !_tcsicmp(ptszExt, TEXT(".LNK")))
  439. {
  440. if (!(errVal = ResolveLnk(lpszPath, szExepath, &wfdExeData, (LPTSTR)lpLnkInfo->tszArguments)))
  441. {
  442. if (lpszSubStr = _tcsrchr(szExepath, TEXT('.')))
  443. {
  444. if (_tcsicmp(lpszSubStr, TEXT(".EXE")) == 0 ||
  445. _tcsicmp(lpszSubStr, TEXT(".LNK")) == 0)
  446. {
  447. if (lpszSubStr = _tcsrchr(szExepath, '\\'))
  448. lpszSubStr++;
  449. else
  450. lpszSubStr = szExepath;
  451. lstrcpy(lpLnkInfo->szExeName, lpszSubStr);
  452. iLen1 = lstrlen(szExepath);
  453. iLen2 = lstrlen(lpLnkInfo->szExeName);
  454. *(szExepath + iLen1 - iLen2 - 1) = TEXT('\0');
  455. lstrcpy(lpLnkInfo->szExePath, szExepath);
  456. GetFileLAD(lpLnkInfo);
  457. wsprintf(szExepath, TEXT("%s\\%s"), lpLnkInfo->szExePath, lpLnkInfo->szExeName);
  458. GetDrivePath(szExepath, szDrivePath);
  459. uiDType = GetDriveType(szDrivePath);
  460. if ((lpWalk->dwWalkFlags & INPFLAG_SKIPFILES ) && (InSkipList(lpLnkInfo->szExeName)))
  461. {
  462. errVal = ERR_NOTANEXE;
  463. }
  464. else if (!(lpWalk->dwWalkFlags & INPFLAG_AGGRESSION) &&
  465. (uiDType != DRIVE_FIXED))
  466. errVal = ERR_NOTANEXE;
  467. else if ((lpWalk->dwWalkFlags & INPFLAG_AGGRESSION) &&
  468. (uiDType != DRIVE_FIXED) && (uiDType != DRIVE_REMOTE) && (uiDType != DRIVE_CDROM))
  469. errVal = ERR_NOTANEXE;
  470. else if (!(bExists = CheckFileExists(szExepath, &(lpLnkInfo->ftExeLAD))) && (uiDType == DRIVE_FIXED))
  471. errVal = ERR_NOTANEXE;
  472. else if (!(errVal = GetExeVersion(lpLnkInfo)))
  473. {
  474. errVal = ERR_SUCCESS;
  475. }
  476. }
  477. else
  478. errVal = ERR_NOTANEXE;
  479. }
  480. else
  481. errVal = ERR_NOTANEXE; // link resolved to a non exe
  482. if (errVal == ERR_SUCCESS)
  483. *(_tcsrchr(lpLnkInfo->szLnkName, TEXT('.'))) = '\0';
  484. }
  485. else
  486. errVal = ERR_NOTANEXE;
  487. }
  488. else if (ptszExt && !_tcsicmp(ptszExt, TEXT(".EXE")))
  489. {
  490. lstrcpy(lpLnkInfo->szExeName, lpLnkInfo->szLnkName);
  491. wsprintf(szExepath, TEXT("%s\\%s"), lpLnkInfo->szExePath, lpLnkInfo->szExeName);
  492. GetDrivePath(szExepath, szDrivePath);
  493. uiDType = GetDriveType(szDrivePath);
  494. GetFileLAD(lpLnkInfo);
  495. if ((lpWalk->dwWalkFlags & INPFLAG_SKIPFILES) && (InSkipList(lpLnkInfo->szExeName)))
  496. errVal = ERR_NOTANEXE;
  497. else if (!(lpWalk->dwWalkFlags & INPFLAG_AGGRESSION) &&
  498. (uiDType != DRIVE_FIXED))
  499. errVal = ERR_NOTANEXE;
  500. else if ((lpWalk->dwWalkFlags & INPFLAG_AGGRESSION) &&
  501. (uiDType != DRIVE_FIXED) && (uiDType != DRIVE_REMOTE) && (uiDType != DRIVE_CDROM))
  502. errVal = ERR_NOTANEXE;
  503. else if (!(bExists = CheckFileExists(szExepath, &(lpLnkInfo->ftExeLAD))) && (uiDType == DRIVE_FIXED))
  504. errVal = ERR_NOTANEXE;
  505. else if (!(errVal = GetExeVersion(lpLnkInfo)))
  506. errVal = ERR_SUCCESS;
  507. }
  508. return errVal;
  509. }
  510. /////////////////////////////////////////////////////////////////
  511. /////////////////////////////////////////////////////////////////
  512. /////////////////////////////////////////////////////////////////
  513. void GetDrivePath(LPTSTR lpszExePath, LPTSTR lpszDrPath)
  514. {
  515. LPTSTR lpszSubStr;
  516. if (s_isDriveLetter(lpszExePath[0]) && lpszExePath[1] == TEXT(':'))
  517. {
  518. lstrcpyn(lpszDrPath, lpszExePath, 3);
  519. lstrcat(lpszDrPath, TEXT("\\"));
  520. }
  521. else if (!_tcsncmp(lpszExePath, TEXT("\\\\"), 2))
  522. {
  523. if (lpszSubStr = _tcschr(&lpszExePath[2], TEXT('\\')))
  524. {
  525. if (lpszSubStr = _tcschr(lpszSubStr+1, TEXT('\\')))
  526. {
  527. lstrcpyn(lpszDrPath, lpszExePath, (size_t)(lpszSubStr - lpszExePath + 1));
  528. lpszDrPath[lpszSubStr - lpszExePath + 1] = TEXT('\0');
  529. }
  530. }
  531. }
  532. else
  533. lpszDrPath[0] = '\0';
  534. }
  535. /////////////////////////////////////////////////////////////////
  536. /////////////////////////////////////////////////////////////////
  537. /////////////////////////////////////////////////////////////////
  538. ERR ResolveLnk(LPCTSTR pszShortcutFile, LPTSTR lpszLnkPath,
  539. LPWIN32_FIND_DATA lpwfdExeData, LPTSTR tszArgs)
  540. {
  541. HRESULT hres;
  542. IShellLink *psl;
  543. TCHAR szGotPath[MAX_PATH];
  544. HWND hwnd = NULL;
  545. ERR errVal = ERR_RESOLVEFAIL;
  546. *tszArgs = TEXT('\0');
  547. // Get a pointer to the IShellLink interface.
  548. hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
  549. IID_IShellLink, (void **)&psl);
  550. if (SUCCEEDED(hres))
  551. {
  552. IPersistFile* ppf;
  553. // Get a pointer to the IPersistFile interface.
  554. hres = psl->QueryInterface(IID_IPersistFile, (void **)&ppf);
  555. if (SUCCEEDED(hres))
  556. {
  557. WCHAR wsz[MAX_PATH];
  558. #ifndef UNICODE
  559. // Ensure string is Unicode.
  560. MultiByteToWideChar(CP_ACP, 0, pszShortcutFile, -1, wsz, MAX_PATH);
  561. #else
  562. lstrcpyn(wsz, pszShortcutFile, ARRAYLEN(wsz));
  563. #endif
  564. // Load the shell link.
  565. hres = ppf->Load(wsz, STGM_READ);
  566. if (SUCCEEDED(hres))
  567. {
  568. DEBUG_OUT((DEB_ITRACE, "Link: %ws\n", wsz));
  569. //
  570. // If the link is to an MSI app, don't get the path to the
  571. // link target - use the path to the link itself instead.
  572. //
  573. if (IsMsiApp(psl))
  574. {
  575. errVal = ERR_SUCCESS;
  576. lstrcpy(lpszLnkPath, pszShortcutFile);
  577. }
  578. else
  579. {
  580. lstrcpyn(szGotPath, pszShortcutFile, MAX_PATH);
  581. // Get the path to the link target.
  582. hres = psl->GetPath(szGotPath, MAX_PATH, (LPWIN32_FIND_DATA)lpwfdExeData,
  583. SLGP_SHORTPATH );
  584. if (!SUCCEEDED(hres))
  585. {
  586. DEBUG_OUT((DEB_ITRACE, " GetPath failed %#x\n", hres));
  587. errVal = ERR_RESOLVEFAIL; /* get path failed : Link not resolved */
  588. }
  589. else
  590. {
  591. DEBUG_OUT((DEB_ITRACE, " Path: %ws\n", szGotPath));
  592. if (lstrlen(szGotPath) > 0)
  593. {
  594. errVal = ERR_SUCCESS;
  595. lstrcpy(lpszLnkPath, szGotPath);
  596. }
  597. else
  598. {
  599. errVal = ERR_RESOLVEFAIL;
  600. }
  601. }
  602. hres = psl->GetArguments(tszArgs, MAX_PATH);
  603. CHECK_HRESULT(hres);
  604. }
  605. }
  606. // Release pointer to IPersistFile interface.
  607. ppf->Release();
  608. }
  609. // Release pointer to IShellLink interface.
  610. psl->Release();
  611. }
  612. return errVal;
  613. }
  614. /////////////////////////////////////////////////////////////////
  615. /////////////////////////////////////////////////////////////////
  616. /////////////////////////////////////////////////////////////////
  617. ERR AddToList(HANDLE hDir, LPWALKHEADER lpWalk)
  618. {
  619. LPHSEARCHDIR lpSrchDirNode;
  620. #ifdef _DEBUG
  621. lpSrchDirNode = (LPHSEARCHDIR) MyGlobalAlloc(FAILMEMA, sizeof(HSEARCHDIR));
  622. #else
  623. lpSrchDirNode = (LPHSEARCHDIR) GlobalAlloc(GPTR, sizeof(HSEARCHDIR));
  624. #endif
  625. if (lpSrchDirNode == NULL)
  626. return ERR_NOMEMORY; /* Global Alloc failed */
  627. lpSrchDirNode->hDirHandle = hDir;
  628. lpSrchDirNode->lpSrchDirNext = NULL;
  629. if (lpWalk->lpSrchDirListHead == NULL)
  630. lpWalk->lpSrchDirListHead = lpSrchDirNode;
  631. else
  632. lpWalk->lpSrchDirListTail->lpSrchDirNext = lpSrchDirNode;
  633. lpWalk->lpSrchDirListTail = lpSrchDirNode;
  634. return ERR_SUCCESS;
  635. }
  636. /////////////////////////////////////////////////////////////////
  637. /////////////////////////////////////////////////////////////////
  638. /////////////////////////////////////////////////////////////////
  639. ERR RemoveFromList(LPWALKHEADER lpWalk)
  640. {
  641. LPHSEARCHDIR lpSrchDirNode;
  642. if (lpWalk->lpSrchDirListHead == NULL)
  643. return ERR_SUCCESS;
  644. lpSrchDirNode = lpWalk->lpSrchDirListHead;
  645. while ( (lpSrchDirNode->lpSrchDirNext != lpWalk->lpSrchDirListTail) &&
  646. (lpSrchDirNode != lpWalk->lpSrchDirListTail))
  647. {
  648. lpSrchDirNode = lpSrchDirNode->lpSrchDirNext;
  649. }
  650. if (lpSrchDirNode != lpWalk->lpSrchDirListTail)
  651. {
  652. #ifdef _DEBUG
  653. MyGlobalFree(lpWalk->lpSrchDirListTail, FAILMEMF);
  654. #else
  655. GlobalFree(lpWalk->lpSrchDirListTail);
  656. #endif
  657. lpSrchDirNode->lpSrchDirNext = NULL;
  658. lpWalk->lpSrchDirListTail = lpSrchDirNode;
  659. }
  660. else
  661. {
  662. #ifdef _DEBUG
  663. MyGlobalFree(lpWalk->lpSrchDirListTail, FAILMEMF);
  664. #else
  665. GlobalFree(lpWalk->lpSrchDirListTail);
  666. #endif
  667. lpWalk->lpSrchDirListHead = NULL;
  668. lpWalk->lpSrchDirListTail = NULL;
  669. }
  670. return ERR_SUCCESS;
  671. }
  672. /////////////////////////////////////////////////////////////////
  673. /////////////////////////////////////////////////////////////////
  674. /////////////////////////////////////////////////////////////////
  675. ERR GetExeVersion(LPLINKINFO lpLnkInfo)
  676. {
  677. LPTSTR lpVersion;
  678. DWORD dwVerInfoSize;
  679. DWORD dwVerHnd;
  680. WORD wVersionLen;
  681. WORD wRootLen;
  682. BOOL bRetCode;
  683. TCHAR szGetName[100];
  684. TCHAR szFullName[MAX_PATH];
  685. ERR errVal;
  686. LPTSTR lpstrVffInfo;
  687. // Get the file version info size
  688. wsprintf(szFullName, TEXT("%s\\%s"), lpLnkInfo->szExePath, lpLnkInfo->szExeName);
  689. dwVerInfoSize = GetFileVersionInfoSize(szFullName, &dwVerHnd);
  690. if (dwVerInfoSize)
  691. {
  692. // allocate memory to hold the verinfo block
  693. #ifdef _DEBUG
  694. lpstrVffInfo = (LPTSTR) MyGlobalAlloc(FAILMEMA, dwVerInfoSize);
  695. #else
  696. lpstrVffInfo = (LPTSTR) GlobalAlloc(GPTR, dwVerInfoSize);
  697. #endif
  698. if (lpstrVffInfo == NULL)
  699. {
  700. errVal = ERR_NOMEMORY; //Global Alloc failed
  701. goto Exit;
  702. }
  703. bRetCode = GetFileVersionInfo(szFullName, dwVerHnd, dwVerInfoSize, lpstrVffInfo);
  704. if (!bRetCode)
  705. {
  706. errVal = ERR_SUCCESS; //ERR_FILEVERSIONFAIL;
  707. goto Exit;
  708. }
  709. //GetFileVersionInfo failed
  710. // Do this the American english translation be default.
  711. // Keep track of the string length for easy updating.
  712. // 040904E4 represents the language ID and the four
  713. // least significant digits represent the codepage for
  714. // which the data is formatted. The language ID is
  715. // composed of two parts: the low ten bits represent
  716. // the major language and the high six bits represent
  717. // the sub language.
  718. bRetCode = VerQueryValue((LPVOID)lpstrVffInfo,
  719. TEXT("\\"),
  720. (void FAR* FAR*) &lpVersion,
  721. (UINT FAR*)&wVersionLen);
  722. if ( bRetCode && wVersionLen && lpVersion)
  723. {
  724. lpLnkInfo->dwExeVerMS =
  725. ((VS_FIXEDFILEINFO *)lpVersion)->dwProductVersionMS;
  726. lpLnkInfo->dwExeVerLS =
  727. ((VS_FIXEDFILEINFO *)lpVersion)->dwProductVersionLS;
  728. }
  729. else
  730. {
  731. lpLnkInfo->dwExeVerMS = 0;
  732. lpLnkInfo->dwExeVerLS = 0;
  733. }
  734. bRetCode = VerQueryValue((LPVOID)lpstrVffInfo,
  735. TEXT("\\VarFileInfo\\Translation"),
  736. (void FAR* FAR*) &lpVersion,
  737. (UINT FAR*)&wVersionLen);
  738. if ( bRetCode && wVersionLen && lpVersion)
  739. {
  740. DWORD dwLangCharSet;
  741. WORD wTemp1, wTemp2;
  742. CopyMemory(&dwLangCharSet, lpVersion, 4);
  743. if (!dwLangCharSet)
  744. dwLangCharSet = 0x04E40409; // the Words have been switched
  745. // Need to switch the words back since lpbuffer has them reversed
  746. wTemp1 = LOWORD(dwLangCharSet);
  747. wTemp2 = HIWORD(dwLangCharSet);
  748. wsprintf(szGetName, TEXT("\\StringFileInfo\\%04lx%04lx\\"), wTemp1, wTemp2);
  749. }
  750. else
  751. {
  752. errVal = ERR_SUCCESS;
  753. goto Exit;
  754. }
  755. wRootLen = (WORD)lstrlen(szGetName);
  756. // "Illegal string" "CompanyName" "FileDescription",
  757. // "FileVersion" "InternalName" "LegalCopyright"
  758. // "LegalTrademarks" "ProductName" "ProductVersion
  759. lstrcat(szGetName, TEXT("FileVersion"));
  760. wVersionLen = 0;
  761. lpVersion = NULL;
  762. // Look for the corresponding string.
  763. bRetCode = VerQueryValue((LPVOID)lpstrVffInfo,
  764. szGetName,
  765. (void FAR* FAR*)&lpVersion,
  766. (UINT FAR *) &wVersionLen);
  767. if ( bRetCode && wVersionLen && lpVersion)
  768. {
  769. lstrcpy(lpLnkInfo->szExeVersionInfo, lpVersion);
  770. }
  771. // Now let's get FileDescription
  772. szGetName[wRootLen] = NULL;
  773. lstrcat(szGetName, TEXT("FileDescription"));
  774. wVersionLen = 0;
  775. lpVersion = NULL;
  776. // Look for the corresponding string.
  777. bRetCode = VerQueryValue((LPVOID)lpstrVffInfo,
  778. szGetName,
  779. (void FAR* FAR*)&lpVersion,
  780. (UINT FAR *) &wVersionLen);
  781. if ( bRetCode && wVersionLen && lpVersion)
  782. {
  783. lstrcpy(lpLnkInfo->szExeDesc, lpVersion);
  784. }
  785. szGetName[wRootLen] = NULL;
  786. lstrcat(szGetName, TEXT("CompanyName"));
  787. wVersionLen = 0;
  788. lpVersion = NULL;
  789. // Look for the corresponding string.
  790. bRetCode = VerQueryValue((LPVOID)lpstrVffInfo,
  791. szGetName,
  792. (void FAR* FAR*)&lpVersion,
  793. (UINT FAR *) &wVersionLen);
  794. if ( bRetCode && wVersionLen && lpVersion)
  795. {
  796. lstrcpy(lpLnkInfo->szExeCompName, lpVersion);
  797. }
  798. szGetName[wRootLen] = NULL;
  799. lstrcat(szGetName, TEXT("ProductName"));
  800. wVersionLen = 0;
  801. lpVersion = NULL;
  802. // Look for the corresponding string.
  803. bRetCode = VerQueryValue((LPVOID)lpstrVffInfo,
  804. szGetName,
  805. (void FAR* FAR*)&lpVersion,
  806. (UINT FAR *) &wVersionLen);
  807. if ( bRetCode && wVersionLen && lpVersion)
  808. {
  809. lstrcpy(lpLnkInfo->szExeProdName, lpVersion);
  810. }
  811. /* else if (i == 1)
  812. {
  813. // This is an attempt to special case the multimedia
  814. // extensions. I think they paid attention to the
  815. // original docs which suggested that they use the
  816. // 0409 language ID and 0 codepage which indicates
  817. // 7 bit ASCII.
  818. lstrcpy(szGetName, TEXT("\\StringFileInfo\\04090000\\"));
  819. i = 0; // be sure to reset the counter
  820. }*/
  821. // Be sure to reset to NULL so that we can concat
  822. errVal = ERR_SUCCESS;
  823. goto Exit;
  824. }
  825. else
  826. {
  827. lpLnkInfo->dwExeVerMS = 0;
  828. lpLnkInfo->dwExeVerLS = 0;
  829. return ERR_SUCCESS;
  830. }
  831. Exit :
  832. if (errVal != ERR_NOMEMORY)
  833. {
  834. #ifdef _DEBUG
  835. MyGlobalFree(lpstrVffInfo, FAILMEMF);
  836. #else
  837. GlobalFree(lpstrVffInfo);
  838. #endif
  839. // Be sure to reset to NULL so that we can concat
  840. lpstrVffInfo = NULL;
  841. }
  842. return errVal;
  843. }
  844. /////////////////////////////////////////////////////////////////
  845. /////////////////////////////////////////////////////////////////
  846. /////////////////////////////////////////////////////////////////
  847. void SetLnkInfo(LPLINKINFO lpLinkInfo)
  848. {
  849. ZeroMemory((void *)lpLinkInfo, sizeof(LINKINFO));
  850. lpLinkInfo->iAppCompat = APPCOMPATUNKNOWN;
  851. }
  852. /////////////////////////////////////////////////////////////////
  853. /////////////////////////////////////////////////////////////////
  854. /////////////////////////////////////////////////////////////////
  855. DWORD ReverseDWord(DWORD dwIn)
  856. {
  857. DWORD dwOut= 0;
  858. while (dwIn != 0)
  859. {
  860. dwOut = dwOut << 8;
  861. dwOut = dwOut | (dwIn & 0x000000FF);
  862. dwIn = dwIn >> 8;
  863. }
  864. return dwOut;
  865. }
  866. /////////////////////////////////////////////////////////////////
  867. /////////////////////////////////////////////////////////////////
  868. /////////////////////////////////////////////////////////////////
  869. BOOL CheckFileExists(LPTSTR szFullName, LPVOID ftLAD)
  870. {
  871. BOOL bRC;
  872. HANDLE hFile;
  873. SetErrorMode(SEM_FAILCRITICALERRORS);
  874. hFile = CreateFile(
  875. szFullName, // pointer to name of the file
  876. GENERIC_READ | GENERIC_WRITE, // access (read-write) mode
  877. FILE_SHARE_READ|FILE_SHARE_WRITE, // share mode
  878. NULL, // pointer to security attributes
  879. OPEN_EXISTING, // how to create
  880. NULL, // file attributes
  881. NULL // handle to file with attributes to copy
  882. );
  883. int i = GetLastError();
  884. if ((hFile == INVALID_HANDLE_VALUE) &&
  885. ((i == ERROR_FILE_NOT_FOUND) || (i == ERROR_PATH_NOT_FOUND) ||
  886. (i == ERROR_BAD_NETPATH)))
  887. {
  888. bRC = FALSE;
  889. }
  890. else if (hFile == INVALID_HANDLE_VALUE)
  891. bRC = TRUE;
  892. else
  893. {
  894. if (ftLAD != 0)
  895. SetFileTime(hFile, NULL, (FILETIME *) ftLAD, NULL);
  896. CloseHandle(hFile);
  897. bRC = TRUE;
  898. }
  899. return bRC;
  900. }
  901. /////////////////////////////////////////////////////////////////
  902. /////////////////////////////////////////////////////////////////
  903. /////////////////////////////////////////////////////////////////
  904. void CloseWalk(HWALK hWalk)
  905. {
  906. LPWALKHEADER lpWalk = (LPWALKHEADER) hWalk;
  907. if (lpWalk != NULL)
  908. {
  909. while (lpWalk->lpSrchDirListHead != NULL)
  910. RemoveFromList(lpWalk);
  911. //BUGBUG : Must free everything in hWalk
  912. if (lpWalk != NULL)
  913. {
  914. if (lpWalk->lpszIniString != NULL)
  915. {
  916. #ifdef _DEBUG
  917. MyGlobalFree(lpWalk->lpszIniString, FAILMEMF);
  918. #else
  919. GlobalFree(lpWalk->lpszIniString);
  920. #endif
  921. lpWalk->lpszIniString = NULL;
  922. }
  923. #ifdef _DEBUG
  924. MyGlobalFree(lpWalk, FAILMEMF);
  925. #else
  926. GlobalFree(lpWalk);
  927. #endif
  928. lpWalk = NULL;
  929. }
  930. }
  931. }
  932. #ifdef _DEBUG
  933. HGLOBAL MyGlobalFree(HGLOBAL hGlobal, BOOL FAILMEM)
  934. {
  935. HGLOBAL hGbl;
  936. g_MemAlloced = g_MemAlloced - GlobalSize(hGlobal);
  937. hGbl = GlobalFree(hGlobal);
  938. return hGbl;
  939. };
  940. HGLOBAL MyGlobalAlloc(BOOL FAILMEM, DWORD dwBytes)
  941. {
  942. HGLOBAL hGbl;
  943. if (FAILMEM)
  944. {
  945. hGbl = GlobalAlloc(GPTR, dwBytes);
  946. g_MemAlloced = g_MemAlloced + GlobalSize(hGbl);
  947. return hGbl;
  948. }
  949. else
  950. return NULL;
  951. };
  952. #endif
  953. /////////////////////////////////////////////////////////////////
  954. /////////////////////////////////////////////////////////////////
  955. /////////////////////////////////////////////////////////////////
  956. BOOL
  957. IsMsiApp(
  958. IShellLink * psl
  959. )
  960. {
  961. //
  962. // Find out if this link is to an MSI app.
  963. // The algorithm for finding out is from ProcessDarwinAd in
  964. // shell\shell32\unicpp\startmnu.cpp.
  965. //
  966. IShellLinkDataList * psldl;
  967. HRESULT hr = psl->QueryInterface(IID_IShellLinkDataList, (void **)&psldl);
  968. if (FAILED(hr))
  969. {
  970. DEBUG_OUT((DEB_ITRACE, " QI for IShellLinkDataList failed %#x\n", hr));
  971. return FALSE;
  972. }
  973. EXP_DARWIN_LINK * pexpDarwin;
  974. hr = psldl->CopyDataBlock(EXP_DARWIN_ID_SIG, (void**)&pexpDarwin);
  975. psldl->Release();
  976. if (FAILED(hr))
  977. {
  978. DEBUG_OUT((DEB_ITRACE, " CopyDataBlock failed %#x\n", hr));
  979. return FALSE;
  980. }
  981. DEBUG_OUT((DEB_ITRACE, " This IS a Darwin app\n"));
  982. LocalFree(pexpDarwin);
  983. return TRUE;
  984. }
  985. /////////////////////////////////////////////////////////////////
  986. ///////////////////////DDDDOOOONNNNEEEE//////////////////////////
  987. /////////////////////////////////////////////////////////////////