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.

1204 lines
33 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 +1];
  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, MAX_PATH +1);
  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 +1];
  120. LPWALKHEADER lpWalk = (LPWALKHEADER) hWalk;
  121. while (1)
  122. {
  123. retVal = GetFileHandle(lpLnkInfo, lpWalk, szFullPath, MAX_PATH +1);
  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, size_t pathBufSize)
  182. {
  183. DWORD dwAttrs;
  184. BOOL bRC;
  185. HANDLE hSearch;
  186. INT retVal;
  187. TCHAR szFolderPath[MAX_PATH +1];
  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, MAX_PATH +1, 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. StringCchCopy(lpLnkInfo->szLnkName, MAX_PATH, wfdFileData.cFileName);
  280. GetCurrentDirectory(MAX_PATH, lpLnkInfo->szLnkPath); //BUG
  281. StringCchCopy(lpLnkInfo->szExeName, MAX_PATH, lpLnkInfo->szLnkName);
  282. StringCchCopy(lpLnkInfo->szExePath, MAX_PATH, lpLnkInfo->szLnkPath);
  283. StringCchPrintf(lpszPath, pathBufSize, 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+1];
  308. StringCchCopy(szTempStr, MAX_PATH +1, lpLnkInfo->szExePath);
  309. StringCchCat(szTempStr, MAX_PATH +1, TEXT("\\"));
  310. StringCchCat(szTempStr, MAX_PATH +1, lpLnkInfo->szExeName);
  311. if (!_tcschr(szTempStr, '.'))
  312. StringCchCat(szTempStr, MAX_PATH +1, 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, size_t folderBufSize, 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. StringCchCopy(szRegVal, MAX_PATH, TEXT("Start Menu"));
  376. lpWalk->dwCurrentFlag = INPTYPE_STARTMENU;
  377. }
  378. else if (lpWalk->dwWalkFlags & INPTYPE_DESKTOP)
  379. {
  380. StringCchCopy(szRegVal, MAX_PATH, 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] = { 0 };
  393. DWORD dwSize = ExpandEnvironmentStrings(lpszFolder, tszTemp, ARRAYLEN(tszTemp));
  394. if (!dwSize)
  395. {
  396. return ERR_UNKNOWN; // should never come here
  397. }
  398. if (dwSize > ARRAYLEN(tszTemp))
  399. {
  400. return ERR_BUFFERTOOSMALL; // should not come here either; but if it does, we'll return this error
  401. // we could dynamically allocate a buffer large enough,
  402. // but since almost all storage for paths in this component
  403. // seem to be MAX_PATH, it would surely overflow someplace else
  404. // if everything weren't changed to allow larger sizes
  405. }
  406. StringCchCopy(lpszFolder, folderBufSize, tszTemp);
  407. }
  408. if (lr != ERROR_SUCCESS)
  409. {
  410. RegCloseKey(hKey);
  411. if (lpWalk->dwWalkFlags & INPTYPE_STARTMENU)
  412. {
  413. return ERR_NOSTARTMENU;
  414. }
  415. else
  416. {
  417. return ERR_NODESKTOP;
  418. }
  419. }
  420. RegCloseKey(hKey);
  421. }
  422. else
  423. return ERR_NOSHELLFOLDERS;
  424. }
  425. else
  426. {
  427. StringCchCopy(lpszFolder, folderBufSize, (LPTSTR) lpWalk->lpszFolder);
  428. lpWalk->dwCurrentFlag = INPTYPE_ANYFOLDER;
  429. }
  430. return ERR_SUCCESS;
  431. }
  432. /////////////////////////////////////////////////////////////////
  433. /////////////////////////////////////////////////////////////////
  434. /////////////////////////////////////////////////////////////////
  435. ERR GetLnkInfo(LPWALKHEADER lpWalk, LPLINKINFO lpLnkInfo, LPTSTR lpszPath)
  436. {
  437. WIN32_FIND_DATA wfdExeData;
  438. ERR errVal = ERR_NOTANEXE;
  439. UINT uiDType;
  440. TCHAR szExepath[MAX_PATH +1];
  441. TCHAR szDrivePath[MAX_PATH];
  442. LPTSTR lpszSubStr;
  443. INT iLen1, iLen2;
  444. BOOL bExists;
  445. //BUGBUG THe if thens should be such that there is repetition of code
  446. szExepath[0] = '\0';
  447. LPTSTR ptszExt = PathFindExtension(lpLnkInfo->szLnkName);
  448. if (ptszExt && !_tcsicmp(ptszExt, TEXT(".LNK")))
  449. {
  450. if (!(errVal = ResolveLnk(lpszPath, szExepath, &wfdExeData, (LPTSTR)lpLnkInfo->tszArguments)))
  451. {
  452. if (lpszSubStr = _tcsrchr(szExepath, TEXT('.')))
  453. {
  454. if (_tcsicmp(lpszSubStr, TEXT(".EXE")) == 0 ||
  455. _tcsicmp(lpszSubStr, TEXT(".LNK")) == 0)
  456. {
  457. if (lpszSubStr = _tcsrchr(szExepath, '\\'))
  458. lpszSubStr++;
  459. else
  460. lpszSubStr = szExepath;
  461. StringCchCopy(lpLnkInfo->szExeName, MAX_PATH, lpszSubStr);
  462. iLen1 = lstrlen(szExepath);
  463. iLen2 = lstrlen(lpLnkInfo->szExeName);
  464. *(szExepath + iLen1 - iLen2 - 1) = TEXT('\0');
  465. StringCchCopy(lpLnkInfo->szExePath, MAX_PATH, szExepath);
  466. GetFileLAD(lpLnkInfo);
  467. StringCchPrintf(szExepath, MAX_PATH +1, TEXT("%s\\%s"), lpLnkInfo->szExePath, lpLnkInfo->szExeName);
  468. GetDrivePath(szExepath, szDrivePath, MAX_PATH);
  469. uiDType = GetDriveType(szDrivePath);
  470. if ((lpWalk->dwWalkFlags & INPFLAG_SKIPFILES ) && (InSkipList(lpLnkInfo->szExeName)))
  471. {
  472. errVal = ERR_NOTANEXE;
  473. }
  474. else if (!(lpWalk->dwWalkFlags & INPFLAG_AGGRESSION) &&
  475. (uiDType != DRIVE_FIXED))
  476. errVal = ERR_NOTANEXE;
  477. else if ((lpWalk->dwWalkFlags & INPFLAG_AGGRESSION) &&
  478. (uiDType != DRIVE_FIXED) && (uiDType != DRIVE_REMOTE) && (uiDType != DRIVE_CDROM))
  479. errVal = ERR_NOTANEXE;
  480. else if (!(bExists = CheckFileExists(szExepath, &(lpLnkInfo->ftExeLAD))) && (uiDType == DRIVE_FIXED))
  481. errVal = ERR_NOTANEXE;
  482. else if (!(errVal = GetExeVersion(lpLnkInfo)))
  483. {
  484. errVal = ERR_SUCCESS;
  485. }
  486. }
  487. else
  488. errVal = ERR_NOTANEXE;
  489. }
  490. else
  491. errVal = ERR_NOTANEXE; // link resolved to a non exe
  492. if (errVal == ERR_SUCCESS)
  493. *(_tcsrchr(lpLnkInfo->szLnkName, TEXT('.'))) = '\0';
  494. }
  495. else
  496. errVal = ERR_NOTANEXE;
  497. }
  498. else if (ptszExt && !_tcsicmp(ptszExt, TEXT(".EXE")))
  499. {
  500. StringCchCopy(lpLnkInfo->szExeName, MAX_PATH, lpLnkInfo->szLnkName);
  501. StringCchPrintf(szExepath, MAX_PATH +1, TEXT("%s\\%s"), lpLnkInfo->szExePath, lpLnkInfo->szExeName);
  502. GetDrivePath(szExepath, szDrivePath, MAX_PATH);
  503. uiDType = GetDriveType(szDrivePath);
  504. GetFileLAD(lpLnkInfo);
  505. if ((lpWalk->dwWalkFlags & INPFLAG_SKIPFILES) && (InSkipList(lpLnkInfo->szExeName)))
  506. errVal = ERR_NOTANEXE;
  507. else if (!(lpWalk->dwWalkFlags & INPFLAG_AGGRESSION) &&
  508. (uiDType != DRIVE_FIXED))
  509. errVal = ERR_NOTANEXE;
  510. else if ((lpWalk->dwWalkFlags & INPFLAG_AGGRESSION) &&
  511. (uiDType != DRIVE_FIXED) && (uiDType != DRIVE_REMOTE) && (uiDType != DRIVE_CDROM))
  512. errVal = ERR_NOTANEXE;
  513. else if (!(bExists = CheckFileExists(szExepath, &(lpLnkInfo->ftExeLAD))) && (uiDType == DRIVE_FIXED))
  514. errVal = ERR_NOTANEXE;
  515. else if (!(errVal = GetExeVersion(lpLnkInfo)))
  516. errVal = ERR_SUCCESS;
  517. }
  518. return errVal;
  519. }
  520. /////////////////////////////////////////////////////////////////
  521. /////////////////////////////////////////////////////////////////
  522. /////////////////////////////////////////////////////////////////
  523. void GetDrivePath(LPTSTR lpszExePath, LPTSTR lpszDrPath, size_t drPathSize)
  524. {
  525. LPTSTR lpszSubStr;
  526. if (s_isDriveLetter(lpszExePath[0]) && lpszExePath[1] == TEXT(':'))
  527. {
  528. lstrcpyn(lpszDrPath, lpszExePath, 3);
  529. StringCchCat(lpszDrPath, drPathSize, TEXT("\\"));
  530. }
  531. else if (!_tcsncmp(lpszExePath, TEXT("\\\\"), 2))
  532. {
  533. if (lpszSubStr = _tcschr(&lpszExePath[2], TEXT('\\')))
  534. {
  535. if (lpszSubStr = _tcschr(lpszSubStr+1, TEXT('\\')))
  536. {
  537. lstrcpyn(lpszDrPath, lpszExePath, (size_t)(lpszSubStr - lpszExePath + 1));
  538. lpszDrPath[lpszSubStr - lpszExePath + 1] = TEXT('\0');
  539. }
  540. }
  541. }
  542. else
  543. lpszDrPath[0] = '\0';
  544. }
  545. /////////////////////////////////////////////////////////////////
  546. /////////////////////////////////////////////////////////////////
  547. /////////////////////////////////////////////////////////////////
  548. ERR ResolveLnk(LPCTSTR pszShortcutFile, LPTSTR lpszLnkPath,
  549. LPWIN32_FIND_DATA lpwfdExeData, LPTSTR tszArgs)
  550. {
  551. HRESULT hres;
  552. IShellLink *psl;
  553. TCHAR szGotPath[MAX_PATH +1];
  554. HWND hwnd = NULL;
  555. ERR errVal = ERR_RESOLVEFAIL;
  556. *tszArgs = TEXT('\0');
  557. // Get a pointer to the IShellLink interface.
  558. hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
  559. IID_IShellLink, (void **)&psl);
  560. if (SUCCEEDED(hres))
  561. {
  562. IPersistFile* ppf;
  563. // Get a pointer to the IPersistFile interface.
  564. hres = psl->QueryInterface(IID_IPersistFile, (void **)&ppf);
  565. if (SUCCEEDED(hres))
  566. {
  567. WCHAR wsz[MAX_PATH +1];
  568. lstrcpyn(wsz, pszShortcutFile, ARRAYLEN(wsz));
  569. // Load the shell link.
  570. hres = ppf->Load(wsz, STGM_READ);
  571. if (SUCCEEDED(hres))
  572. {
  573. DEBUG_OUT((DEB_ITRACE, "Link: %ws\n", wsz));
  574. //
  575. // If the link is to an MSI app, don't get the path to the
  576. // link target - use the path to the link itself instead.
  577. //
  578. if (IsMsiApp(psl))
  579. {
  580. errVal = ERR_SUCCESS;
  581. lstrcpyn(lpszLnkPath, pszShortcutFile, MAX_PATH);
  582. }
  583. else
  584. {
  585. lstrcpyn(szGotPath, pszShortcutFile, MAX_PATH);
  586. // Get the path to the link target.
  587. hres = psl->GetPath(szGotPath, MAX_PATH, (LPWIN32_FIND_DATA)lpwfdExeData,
  588. SLGP_SHORTPATH );
  589. if (!SUCCEEDED(hres))
  590. {
  591. DEBUG_OUT((DEB_ITRACE, " GetPath failed %#x\n", hres));
  592. errVal = ERR_RESOLVEFAIL; /* get path failed : Link not resolved */
  593. }
  594. else
  595. {
  596. DEBUG_OUT((DEB_ITRACE, " Path: %ws\n", szGotPath));
  597. if (lstrlen(szGotPath) > 0)
  598. {
  599. errVal = ERR_SUCCESS;
  600. lstrcpyn(lpszLnkPath, szGotPath, MAX_PATH);
  601. }
  602. else
  603. {
  604. errVal = ERR_RESOLVEFAIL;
  605. }
  606. }
  607. hres = psl->GetArguments(tszArgs, MAX_PATH);
  608. CHECK_HRESULT(hres);
  609. }
  610. }
  611. // Release pointer to IPersistFile interface.
  612. ppf->Release();
  613. }
  614. // Release pointer to IShellLink interface.
  615. psl->Release();
  616. }
  617. return errVal;
  618. }
  619. /////////////////////////////////////////////////////////////////
  620. /////////////////////////////////////////////////////////////////
  621. /////////////////////////////////////////////////////////////////
  622. ERR AddToList(HANDLE hDir, LPWALKHEADER lpWalk)
  623. {
  624. LPHSEARCHDIR lpSrchDirNode;
  625. #ifdef _DEBUG
  626. lpSrchDirNode = (LPHSEARCHDIR) MyGlobalAlloc(FAILMEMA, sizeof(HSEARCHDIR));
  627. #else
  628. lpSrchDirNode = (LPHSEARCHDIR) GlobalAlloc(GPTR, sizeof(HSEARCHDIR));
  629. #endif
  630. if (lpSrchDirNode == NULL)
  631. return ERR_NOMEMORY; /* Global Alloc failed */
  632. lpSrchDirNode->hDirHandle = hDir;
  633. lpSrchDirNode->lpSrchDirNext = NULL;
  634. if (lpWalk->lpSrchDirListHead == NULL)
  635. lpWalk->lpSrchDirListHead = lpSrchDirNode;
  636. else
  637. lpWalk->lpSrchDirListTail->lpSrchDirNext = lpSrchDirNode;
  638. lpWalk->lpSrchDirListTail = lpSrchDirNode;
  639. return ERR_SUCCESS;
  640. }
  641. /////////////////////////////////////////////////////////////////
  642. /////////////////////////////////////////////////////////////////
  643. /////////////////////////////////////////////////////////////////
  644. ERR RemoveFromList(LPWALKHEADER lpWalk)
  645. {
  646. LPHSEARCHDIR lpSrchDirNode;
  647. if (lpWalk->lpSrchDirListHead == NULL)
  648. return ERR_SUCCESS;
  649. lpSrchDirNode = lpWalk->lpSrchDirListHead;
  650. while ( (lpSrchDirNode->lpSrchDirNext != lpWalk->lpSrchDirListTail) &&
  651. (lpSrchDirNode != lpWalk->lpSrchDirListTail))
  652. {
  653. lpSrchDirNode = lpSrchDirNode->lpSrchDirNext;
  654. }
  655. if (lpSrchDirNode != lpWalk->lpSrchDirListTail)
  656. {
  657. #ifdef _DEBUG
  658. MyGlobalFree(lpWalk->lpSrchDirListTail, FAILMEMF);
  659. #else
  660. GlobalFree(lpWalk->lpSrchDirListTail);
  661. #endif
  662. lpSrchDirNode->lpSrchDirNext = NULL;
  663. lpWalk->lpSrchDirListTail = lpSrchDirNode;
  664. }
  665. else
  666. {
  667. #ifdef _DEBUG
  668. MyGlobalFree(lpWalk->lpSrchDirListTail, FAILMEMF);
  669. #else
  670. GlobalFree(lpWalk->lpSrchDirListTail);
  671. #endif
  672. lpWalk->lpSrchDirListHead = NULL;
  673. lpWalk->lpSrchDirListTail = NULL;
  674. }
  675. return ERR_SUCCESS;
  676. }
  677. /////////////////////////////////////////////////////////////////
  678. /////////////////////////////////////////////////////////////////
  679. /////////////////////////////////////////////////////////////////
  680. ERR GetExeVersion(LPLINKINFO lpLnkInfo)
  681. {
  682. LPTSTR lpVersion;
  683. DWORD dwVerInfoSize;
  684. DWORD dwVerHnd;
  685. WORD wVersionLen;
  686. WORD wRootLen;
  687. BOOL bRetCode;
  688. const size_t GetNameLength = 100;
  689. TCHAR szGetName[GetNameLength];
  690. TCHAR szFullName[MAX_PATH];
  691. ERR errVal;
  692. LPTSTR lpstrVffInfo;
  693. // Get the file version info size
  694. StringCchPrintf(szFullName, MAX_PATH, TEXT("%s\\%s"), lpLnkInfo->szExePath, lpLnkInfo->szExeName);
  695. dwVerInfoSize = GetFileVersionInfoSize(szFullName, &dwVerHnd);
  696. if (dwVerInfoSize)
  697. {
  698. // allocate memory to hold the verinfo block
  699. #ifdef _DEBUG
  700. lpstrVffInfo = (LPTSTR) MyGlobalAlloc(FAILMEMA, dwVerInfoSize);
  701. #else
  702. lpstrVffInfo = (LPTSTR) GlobalAlloc(GPTR, dwVerInfoSize);
  703. #endif
  704. if (lpstrVffInfo == NULL)
  705. {
  706. errVal = ERR_NOMEMORY; //Global Alloc failed
  707. goto Exit;
  708. }
  709. bRetCode = GetFileVersionInfo(szFullName, dwVerHnd, dwVerInfoSize, lpstrVffInfo);
  710. if (!bRetCode)
  711. {
  712. errVal = ERR_SUCCESS; //ERR_FILEVERSIONFAIL;
  713. goto Exit;
  714. }
  715. //GetFileVersionInfo failed
  716. // Do this the American english translation be default.
  717. // Keep track of the string length for easy updating.
  718. // 040904E4 represents the language ID and the four
  719. // least significant digits represent the codepage for
  720. // which the data is formatted. The language ID is
  721. // composed of two parts: the low ten bits represent
  722. // the major language and the high six bits represent
  723. // the sub language.
  724. bRetCode = VerQueryValue((LPVOID)lpstrVffInfo,
  725. TEXT("\\"),
  726. (void FAR* FAR*) &lpVersion,
  727. (UINT FAR*)&wVersionLen);
  728. if ( bRetCode && wVersionLen && lpVersion)
  729. {
  730. lpLnkInfo->dwExeVerMS =
  731. ((VS_FIXEDFILEINFO *)lpVersion)->dwProductVersionMS;
  732. lpLnkInfo->dwExeVerLS =
  733. ((VS_FIXEDFILEINFO *)lpVersion)->dwProductVersionLS;
  734. }
  735. else
  736. {
  737. lpLnkInfo->dwExeVerMS = 0;
  738. lpLnkInfo->dwExeVerLS = 0;
  739. }
  740. bRetCode = VerQueryValue((LPVOID)lpstrVffInfo,
  741. TEXT("\\VarFileInfo\\Translation"),
  742. (void FAR* FAR*) &lpVersion,
  743. (UINT FAR*)&wVersionLen);
  744. if ( bRetCode && wVersionLen && lpVersion)
  745. {
  746. DWORD dwLangCharSet;
  747. WORD wTemp1, wTemp2;
  748. CopyMemory(&dwLangCharSet, lpVersion, 4);
  749. if (!dwLangCharSet)
  750. dwLangCharSet = 0x04E40409; // the Words have been switched
  751. // Need to switch the words back since lpbuffer has them reversed
  752. wTemp1 = LOWORD(dwLangCharSet);
  753. wTemp2 = HIWORD(dwLangCharSet);
  754. StringCchPrintf(szGetName, GetNameLength, TEXT("\\StringFileInfo\\%04lx%04lx\\"), wTemp1, wTemp2);
  755. }
  756. else
  757. {
  758. errVal = ERR_SUCCESS;
  759. goto Exit;
  760. }
  761. wRootLen = (WORD)lstrlen(szGetName);
  762. // "Illegal string" "CompanyName" "FileDescription",
  763. // "FileVersion" "InternalName" "LegalCopyright"
  764. // "LegalTrademarks" "ProductName" "ProductVersion
  765. StringCchCat(szGetName, GetNameLength, TEXT("FileVersion"));
  766. wVersionLen = 0;
  767. lpVersion = NULL;
  768. // Look for the corresponding string.
  769. bRetCode = VerQueryValue((LPVOID)lpstrVffInfo,
  770. szGetName,
  771. (void FAR* FAR*)&lpVersion,
  772. (UINT FAR *) &wVersionLen);
  773. if ( bRetCode && wVersionLen && lpVersion)
  774. {
  775. StringCchCopy(lpLnkInfo->szExeVersionInfo, MAX_PATH, lpVersion);
  776. }
  777. // Now let's get FileDescription
  778. szGetName[wRootLen] = NULL;
  779. StringCchCat(szGetName, GetNameLength, TEXT("FileDescription"));
  780. wVersionLen = 0;
  781. lpVersion = NULL;
  782. // Look for the corresponding string.
  783. bRetCode = VerQueryValue((LPVOID)lpstrVffInfo,
  784. szGetName,
  785. (void FAR* FAR*)&lpVersion,
  786. (UINT FAR *) &wVersionLen);
  787. if ( bRetCode && wVersionLen && lpVersion)
  788. {
  789. StringCchCopy(lpLnkInfo->szExeDesc, MAX_DESC, lpVersion);
  790. }
  791. szGetName[wRootLen] = NULL;
  792. StringCchCat(szGetName, GetNameLength, TEXT("CompanyName"));
  793. wVersionLen = 0;
  794. lpVersion = NULL;
  795. // Look for the corresponding string.
  796. bRetCode = VerQueryValue((LPVOID)lpstrVffInfo,
  797. szGetName,
  798. (void FAR* FAR*)&lpVersion,
  799. (UINT FAR *) &wVersionLen);
  800. if ( bRetCode && wVersionLen && lpVersion)
  801. {
  802. StringCchCopy(lpLnkInfo->szExeCompName, MAX_COMPNAME, lpVersion);
  803. }
  804. szGetName[wRootLen] = NULL;
  805. StringCchCat(szGetName, GetNameLength, TEXT("ProductName"));
  806. wVersionLen = 0;
  807. lpVersion = NULL;
  808. // Look for the corresponding string.
  809. bRetCode = VerQueryValue((LPVOID)lpstrVffInfo,
  810. szGetName,
  811. (void FAR* FAR*)&lpVersion,
  812. (UINT FAR *) &wVersionLen);
  813. if ( bRetCode && wVersionLen && lpVersion)
  814. {
  815. StringCchCopy(lpLnkInfo->szExeProdName, MAX_PRODNAME, lpVersion);
  816. }
  817. /* else if (i == 1)
  818. {
  819. // This is an attempt to special case the multimedia
  820. // extensions. I think they paid attention to the
  821. // original docs which suggested that they use the
  822. // 0409 language ID and 0 codepage which indicates
  823. // 7 bit ASCII.
  824. StringCchCopy(szGetName, GetNameLength, TEXT("\\StringFileInfo\\04090000\\"));
  825. i = 0; // be sure to reset the counter
  826. }*/
  827. // Be sure to reset to NULL so that we can concat
  828. errVal = ERR_SUCCESS;
  829. goto Exit;
  830. }
  831. else
  832. {
  833. lpLnkInfo->dwExeVerMS = 0;
  834. lpLnkInfo->dwExeVerLS = 0;
  835. return ERR_SUCCESS;
  836. }
  837. Exit :
  838. if (errVal != ERR_NOMEMORY)
  839. {
  840. #ifdef _DEBUG
  841. MyGlobalFree(lpstrVffInfo, FAILMEMF);
  842. #else
  843. GlobalFree(lpstrVffInfo);
  844. #endif
  845. // Be sure to reset to NULL so that we can concat
  846. lpstrVffInfo = NULL;
  847. }
  848. return errVal;
  849. }
  850. /////////////////////////////////////////////////////////////////
  851. /////////////////////////////////////////////////////////////////
  852. /////////////////////////////////////////////////////////////////
  853. void SetLnkInfo(LPLINKINFO lpLinkInfo)
  854. {
  855. SecureZeroMemory((void *)lpLinkInfo, sizeof(LINKINFO));
  856. lpLinkInfo->iAppCompat = APPCOMPATUNKNOWN;
  857. }
  858. /////////////////////////////////////////////////////////////////
  859. /////////////////////////////////////////////////////////////////
  860. /////////////////////////////////////////////////////////////////
  861. DWORD ReverseDWord(DWORD dwIn)
  862. {
  863. DWORD dwOut= 0;
  864. while (dwIn != 0)
  865. {
  866. dwOut = dwOut << 8;
  867. dwOut = dwOut | (dwIn & 0x000000FF);
  868. dwIn = dwIn >> 8;
  869. }
  870. return dwOut;
  871. }
  872. /////////////////////////////////////////////////////////////////
  873. /////////////////////////////////////////////////////////////////
  874. /////////////////////////////////////////////////////////////////
  875. BOOL CheckFileExists(LPTSTR szFullName, LPVOID ftLAD)
  876. {
  877. BOOL bRC;
  878. HANDLE hFile;
  879. SetErrorMode(SEM_FAILCRITICALERRORS);
  880. hFile = CreateFile(
  881. szFullName, // pointer to name of the file
  882. GENERIC_READ | GENERIC_WRITE, // access (read-write) mode
  883. FILE_SHARE_READ|FILE_SHARE_WRITE, // share mode
  884. NULL, // pointer to security attributes
  885. OPEN_EXISTING, // how to create
  886. NULL, // file attributes
  887. NULL // handle to file with attributes to copy
  888. );
  889. int i = GetLastError();
  890. if ((hFile == INVALID_HANDLE_VALUE) &&
  891. ((i == ERROR_FILE_NOT_FOUND) || (i == ERROR_PATH_NOT_FOUND) ||
  892. (i == ERROR_BAD_NETPATH)))
  893. {
  894. bRC = FALSE;
  895. }
  896. else if (hFile == INVALID_HANDLE_VALUE)
  897. bRC = TRUE;
  898. else
  899. {
  900. if (ftLAD != 0)
  901. SetFileTime(hFile, NULL, (FILETIME *) ftLAD, NULL);
  902. CloseHandle(hFile);
  903. bRC = TRUE;
  904. }
  905. return bRC;
  906. }
  907. /////////////////////////////////////////////////////////////////
  908. /////////////////////////////////////////////////////////////////
  909. /////////////////////////////////////////////////////////////////
  910. void CloseWalk(HWALK hWalk)
  911. {
  912. LPWALKHEADER lpWalk = (LPWALKHEADER) hWalk;
  913. if (lpWalk != NULL)
  914. {
  915. while (lpWalk->lpSrchDirListHead != NULL)
  916. RemoveFromList(lpWalk);
  917. //BUGBUG : Must free everything in hWalk
  918. if (lpWalk != NULL)
  919. {
  920. if (lpWalk->lpszIniString != NULL)
  921. {
  922. #ifdef _DEBUG
  923. MyGlobalFree(lpWalk->lpszIniString, FAILMEMF);
  924. #else
  925. GlobalFree(lpWalk->lpszIniString);
  926. #endif
  927. lpWalk->lpszIniString = NULL;
  928. }
  929. #ifdef _DEBUG
  930. MyGlobalFree(lpWalk, FAILMEMF);
  931. #else
  932. GlobalFree(lpWalk);
  933. #endif
  934. lpWalk = NULL;
  935. }
  936. }
  937. }
  938. #ifdef _DEBUG
  939. HGLOBAL MyGlobalFree(HGLOBAL hGlobal, BOOL FAILMEM)
  940. {
  941. HGLOBAL hGbl;
  942. g_MemAlloced = g_MemAlloced - GlobalSize(hGlobal);
  943. hGbl = GlobalFree(hGlobal);
  944. return hGbl;
  945. };
  946. HGLOBAL MyGlobalAlloc(BOOL FAILMEM, DWORD dwBytes)
  947. {
  948. HGLOBAL hGbl;
  949. if (FAILMEM)
  950. {
  951. hGbl = GlobalAlloc(GPTR, dwBytes);
  952. g_MemAlloced = g_MemAlloced + GlobalSize(hGbl);
  953. return hGbl;
  954. }
  955. else
  956. return NULL;
  957. };
  958. #endif
  959. /////////////////////////////////////////////////////////////////
  960. /////////////////////////////////////////////////////////////////
  961. /////////////////////////////////////////////////////////////////
  962. BOOL
  963. IsMsiApp(
  964. IShellLink * psl
  965. )
  966. {
  967. //
  968. // Find out if this link is to an MSI app.
  969. // The algorithm for finding out is from ProcessDarwinAd in
  970. // shell\shell32\unicpp\startmnu.cpp.
  971. //
  972. IShellLinkDataList * psldl;
  973. HRESULT hr = psl->QueryInterface(IID_IShellLinkDataList, (void **)&psldl);
  974. if (FAILED(hr))
  975. {
  976. DEBUG_OUT((DEB_ITRACE, " QI for IShellLinkDataList failed %#x\n", hr));
  977. return FALSE;
  978. }
  979. EXP_DARWIN_LINK * pexpDarwin;
  980. hr = psldl->CopyDataBlock(EXP_DARWIN_ID_SIG, (void**)&pexpDarwin);
  981. psldl->Release();
  982. if (FAILED(hr))
  983. {
  984. DEBUG_OUT((DEB_ITRACE, " CopyDataBlock failed %#x\n", hr));
  985. return FALSE;
  986. }
  987. DEBUG_OUT((DEB_ITRACE, " This IS a Darwin app\n"));
  988. LocalFree(pexpDarwin);
  989. return TRUE;
  990. }
  991. /////////////////////////////////////////////////////////////////
  992. ///////////////////////DDDDOOOONNNNEEEE//////////////////////////
  993. /////////////////////////////////////////////////////////////////