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.

2498 lines
80 KiB

  1. #include "shellprv.h"
  2. #include "shlexec.h"
  3. #include "netview.h"
  4. extern "C" {
  5. #include <badapps.h>
  6. }
  7. #include <htmlhelp.h>
  8. #include "ole2dup.h"
  9. #include <vdate.h>
  10. #include <newexe.h>
  11. #include "ids.h"
  12. #define REGSTR_PATH_CHECKBADAPPSNEW TEXT("System\\CurrentControlSet\\Control\\Session Manager\\CheckBadApps")
  13. #define REGSTR_PATH_CHECKBADAPPS400NEW TEXT("System\\CurrentControlSet\\Control\\Session Manager\\CheckBadApps400")
  14. #define REGSTR_TEMP_APPCOMPATPATH TEXT("System\\CurrentControlSet\\Control\\Session Manager\\AppCompatibility\\%s")
  15. #define SAFE_DEBUGSTR(str) ((str) ? (str) : "<NULL>")
  16. HINSTANCE Window_GetInstance(HWND hwnd)
  17. {
  18. DWORD idProcess;
  19. GetWindowThreadProcessId(hwnd, &idProcess);
  20. // HINSTANCEs are pointers valid only within
  21. // a single process, so 33 is returned to indicate success
  22. // as 0-32 are reserved for error. (Actually 32 is supposed
  23. // to be a valid success return but some apps get it wrong.)
  24. return (HINSTANCE)(DWORD_PTR)(idProcess ? 33 : 0);
  25. }
  26. // Return TRUE if the window belongs to a 32bit or a Win4.0 app.
  27. // NB We can't just check if it's a 32bit window
  28. // since many apps use 16bit ddeml windows to communicate with the shell
  29. // On NT we can.
  30. BOOL Window_IsLFNAware(HWND hwnd)
  31. {
  32. // 32-bit window
  33. return LOWORD(GetWindowLongPtr(hwnd,GWLP_HINSTANCE)) == 0;
  34. }
  35. #define COPYTODST(_szdst, _szend, _szsrc, _ulen, _ret) \
  36. { \
  37. UINT _utemp = _ulen; \
  38. if ((UINT)(_szend-_szdst) <= _utemp) { \
  39. return(_ret); \
  40. } \
  41. lstrcpyn(_szdst, _szsrc, _utemp+1); \
  42. _szdst += _utemp; \
  43. }
  44. /* Returns NULL if this is the last parm, pointer to next space otherwise
  45. */
  46. LPTSTR _GetNextParm(LPCTSTR lpSrc, LPTSTR lpDst, UINT cchDst)
  47. {
  48. LPCTSTR lpNextQuote, lpNextSpace;
  49. LPTSTR lpEnd = lpDst+cchDst-1; // dec to account for trailing NULL
  50. BOOL fQuote; // quoted string?
  51. BOOL fDoubleQuote; // is this quote a double quote?
  52. VDATEINPUTBUF(lpDst, TCHAR, cchDst);
  53. while (*lpSrc == TEXT(' '))
  54. ++lpSrc;
  55. if (!*lpSrc)
  56. return(NULL);
  57. fQuote = (*lpSrc == TEXT('"'));
  58. if (fQuote)
  59. lpSrc++; // skip leading quote
  60. for (;;)
  61. {
  62. lpNextQuote = StrChr(lpSrc, TEXT('"'));
  63. if (!fQuote)
  64. {
  65. // for an un-quoted string, copy all chars to first space/null
  66. lpNextSpace = StrChr(lpSrc, TEXT(' '));
  67. if (!lpNextSpace) // null before space! (end of string)
  68. {
  69. if (!lpNextQuote)
  70. {
  71. // copy all chars to the null
  72. if (lpDst)
  73. {
  74. COPYTODST(lpDst, lpEnd, lpSrc, lstrlen(lpSrc), NULL);
  75. }
  76. return NULL;
  77. }
  78. else
  79. {
  80. // we have a quote to convert. Fall through.
  81. }
  82. }
  83. else if (!lpNextQuote || lpNextSpace < lpNextQuote)
  84. {
  85. // copy all chars to the space
  86. if (lpDst)
  87. {
  88. COPYTODST(lpDst, lpEnd, lpSrc, (UINT)(lpNextSpace-lpSrc), NULL);
  89. }
  90. return (LPTSTR)lpNextSpace;
  91. }
  92. else
  93. {
  94. // quote before space. Fall through to convert quote.
  95. }
  96. }
  97. else if (!lpNextQuote)
  98. {
  99. // a quoted string without a terminating quote? Illegal!
  100. ASSERT(0);
  101. return NULL;
  102. }
  103. // we have a potential quote to convert
  104. ASSERT(lpNextQuote);
  105. fDoubleQuote = *(lpNextQuote+1) == TEXT('"');
  106. if (fDoubleQuote)
  107. lpNextQuote++; // so the quote is copied
  108. if (lpDst)
  109. {
  110. COPYTODST(lpDst, lpEnd, lpSrc, (UINT) (lpNextQuote-lpSrc), NULL);
  111. }
  112. lpSrc = lpNextQuote+1;
  113. if (!fDoubleQuote)
  114. {
  115. // we just copied the rest of this quoted string. if this wasn't
  116. // quoted, it's an illegal string... treat the quote as a space.
  117. ASSERT(fQuote);
  118. return (LPTSTR)lpSrc;
  119. }
  120. }
  121. }
  122. #define PEMAGIC ((WORD)'P'+((WORD)'E'<<8))
  123. // Returns TRUE is app is LFN aware.
  124. // This assumes all Win32 apps are LFN aware.
  125. BOOL App_IsLFNAware(LPCTSTR pszFile)
  126. {
  127. BOOL fRet = FALSE;
  128. // Assume Win 4.0 apps and Win32 apps are LFN aware.
  129. DWORD dw = GetExeType(pszFile);
  130. // TraceMsg(TF_SHELLEXEC, "s.aila: %s %s %x", pszFile, szFile, dw);
  131. if ((LOWORD(dw) == PEMAGIC) || ((LOWORD(dw) == NEMAGIC) && (HIWORD(dw) >= 0x0400)))
  132. {
  133. TCHAR sz[MAX_PATH];
  134. PathToAppPathKey(pszFile, sz, ARRAYSIZE(sz));
  135. fRet = (ERROR_SUCCESS != SHGetValue(HKEY_LOCAL_MACHINE, sz, TEXT("UseShortName"), NULL, NULL, NULL));
  136. }
  137. return fRet;
  138. }
  139. // apps can tag themselves in a way so we know we can pass an URL on the cmd
  140. // line. this uses the existance of a value called "UseURL" under the
  141. // App Paths key in the registry associated with the app that is passed in.
  142. // pszPath is the path to the exe
  143. BOOL DoesAppWantUrl(LPCTSTR pszPath)
  144. {
  145. TCHAR sz[MAX_PATH];
  146. PathToAppPathKey(pszPath, sz, ARRAYSIZE(sz));
  147. return (ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, sz, TEXT("UseURL"), NULL, NULL, NULL));
  148. }
  149. BOOL _AppIsLFNAware(LPCTSTR pszFile)
  150. {
  151. TCHAR szFile[MAX_PATH];
  152. // Does it look like a DDE command?
  153. if (pszFile && *pszFile && (*pszFile != TEXT('[')))
  154. {
  155. // Nope - Hopefully just a regular old command %1 thing.
  156. lstrcpyn(szFile, pszFile, ARRAYSIZE(szFile));
  157. LPTSTR pszArgs = PathGetArgs(szFile);
  158. if (*pszArgs)
  159. *(pszArgs - 1) = TEXT('\0');
  160. PathRemoveBlanks(szFile); // remove any blanks that may be after the command
  161. PathUnquoteSpaces(szFile);
  162. return App_IsLFNAware(szFile);
  163. }
  164. return FALSE;
  165. }
  166. // in:
  167. // lpFile exe name (used for %0 or %1 in replacement string)
  168. // lpFrom string template to sub params and file into "excel.exe %1 %2 /n %3"
  169. // lpParams parameter list "foo.txt bar.txt"
  170. // out:
  171. // lpTo output string with all parameters replaced
  172. //
  173. // supports:
  174. // %* replace with all parameters
  175. // %0, %1 replace with file
  176. // %n use nth parameter
  177. //
  178. // replace parameter placeholders (%1 %2 ... %n) with parameters
  179. //
  180. UINT ReplaceParameters(LPTSTR lpTo, UINT cchTo, LPCTSTR lpFile,
  181. LPCTSTR lpFrom, LPCTSTR lpParms, int nShow, DWORD * pdwHotKey, BOOL fLFNAware,
  182. LPCITEMIDLIST lpID, LPITEMIDLIST *ppidlGlobal)
  183. {
  184. int i;
  185. TCHAR c;
  186. LPCTSTR lpT;
  187. TCHAR sz[MAX_PATH];
  188. BOOL fFirstParam = TRUE;
  189. LPTSTR lpEnd = lpTo + cchTo - 1; // dec to allow trailing NULL
  190. LPTSTR pToOrig = lpTo;
  191. for (; *lpFrom; lpFrom++)
  192. {
  193. if (*lpFrom == TEXT('%'))
  194. {
  195. switch (*(++lpFrom))
  196. {
  197. case TEXT('~'): // Copy all parms starting with nth (n >= 2 and <= 9)
  198. c = *(++lpFrom);
  199. if (c >= TEXT('2') && c <= TEXT('9'))
  200. {
  201. for (i = 2, lpT = lpParms; i < c-TEXT('0') && lpT; i++)
  202. {
  203. lpT = _GetNextParm(lpT, NULL, 0);
  204. }
  205. if (lpT)
  206. {
  207. COPYTODST(lpTo, lpEnd, lpT, lstrlen(lpT), SE_ERR_ACCESSDENIED);
  208. }
  209. }
  210. else
  211. {
  212. lpFrom -= 2; // Backup over %~ and pass through
  213. goto NormalChar;
  214. }
  215. break;
  216. case TEXT('*'): // Copy all parms
  217. if (lpParms)
  218. {
  219. COPYTODST(lpTo, lpEnd, lpParms, lstrlen(lpParms), SE_ERR_ACCESSDENIED);
  220. }
  221. break;
  222. case TEXT('0'):
  223. case TEXT('1'):
  224. // %0, %1, copy the file name
  225. // If the filename comes first then we don't need to convert it to
  226. // a shortname. If it appears anywhere else and the app is not LFN
  227. // aware then we must.
  228. if (!(fFirstParam || fLFNAware || _AppIsLFNAware(pToOrig)) &&
  229. GetShortPathName(lpFile, sz, ARRAYSIZE(sz)) > 0)
  230. {
  231. TraceMsg(TF_SHELLEXEC, "ShellExecuteEx: Getting short version of path.");
  232. COPYTODST(lpTo, lpEnd, sz, lstrlen(sz), SE_ERR_ACCESSDENIED);
  233. }
  234. else
  235. {
  236. TraceMsg(TF_SHELLEXEC, "ShellExecuteEx: Using long version of path.");
  237. COPYTODST(lpTo, lpEnd, lpFile, lstrlen(lpFile), SE_ERR_ACCESSDENIED);
  238. }
  239. break;
  240. case TEXT('2'):
  241. case TEXT('3'):
  242. case TEXT('4'):
  243. case TEXT('5'):
  244. case TEXT('6'):
  245. case TEXT('7'):
  246. case TEXT('8'):
  247. case TEXT('9'):
  248. for (i = *lpFrom-TEXT('2'), lpT = lpParms; lpT; --i)
  249. {
  250. if (i)
  251. lpT = _GetNextParm(lpT, NULL, 0);
  252. else
  253. {
  254. sz[0] = '\0'; // ensure a valid string, regardless of what happens within _GetNextParm
  255. _GetNextParm(lpT, sz, ARRAYSIZE(sz));
  256. COPYTODST(lpTo, lpEnd, sz, lstrlen(sz), SE_ERR_ACCESSDENIED);
  257. break;
  258. }
  259. }
  260. break;
  261. case TEXT('s'):
  262. case TEXT('S'):
  263. wsprintf(sz, TEXT("%ld"), nShow);
  264. COPYTODST(lpTo, lpEnd, sz, lstrlen(sz), SE_ERR_ACCESSDENIED);
  265. break;
  266. case TEXT('h'):
  267. case TEXT('H'):
  268. wsprintf(sz, TEXT("%X"), pdwHotKey ? *pdwHotKey : 0);
  269. COPYTODST(lpTo, lpEnd, sz, lstrlen(sz), SE_ERR_ACCESSDENIED);
  270. if (pdwHotKey)
  271. *pdwHotKey = 0;
  272. break;
  273. // Note that a new global IDList is created for each
  274. case TEXT('i'):
  275. case TEXT('I'):
  276. // Note that a single global ID list is created and used over
  277. // again, so that it may be easily destroyed if anything
  278. // goes wrong
  279. if (ppidlGlobal)
  280. {
  281. if (lpID && !*ppidlGlobal)
  282. {
  283. *ppidlGlobal = (LPITEMIDLIST)SHAllocShared(lpID,ILGetSize(lpID),GetCurrentProcessId());
  284. if (!*ppidlGlobal)
  285. {
  286. return SE_ERR_OOM;
  287. }
  288. }
  289. wsprintf(sz, TEXT(":%ld:%ld"), *ppidlGlobal,GetCurrentProcessId());
  290. }
  291. else
  292. {
  293. lstrcpy(sz,TEXT(":0"));
  294. }
  295. COPYTODST(lpTo, lpEnd, sz, lstrlen(sz), SE_ERR_ACCESSDENIED);
  296. break;
  297. case TEXT('l'):
  298. case TEXT('L'):
  299. // Like %1 only using the long name.
  300. // REVIEW UNDONE IANEL Remove the fFirstParam and fLFNAware stuff as soon as this
  301. // is up and running.
  302. TraceMsg(TF_SHELLEXEC, "ShellExecuteEx: Using long version of path.");
  303. COPYTODST(lpTo, lpEnd, lpFile, lstrlen(lpFile), SE_ERR_ACCESSDENIED);
  304. break;
  305. case TEXT('D'):
  306. case TEXT('d'):
  307. {
  308. // %D gives the display name of an object.
  309. if (lpID && SUCCEEDED(SHGetNameAndFlags(lpID, SHGDN_FORPARSING, sz, ARRAYSIZE(sz), NULL)))
  310. {
  311. COPYTODST(lpTo, lpEnd, sz, lstrlen(sz), SE_ERR_ACCESSDENIED);
  312. }
  313. else
  314. return SE_ERR_ACCESSDENIED;
  315. break;
  316. }
  317. default:
  318. goto NormalChar;
  319. }
  320. // TraceMsg(TF_SHELLEXEC, "s.rp: Past first param (1).");
  321. fFirstParam = FALSE;
  322. }
  323. else
  324. {
  325. NormalChar:
  326. // not a "%?" thing, just copy this to the destination
  327. if (lpEnd-lpTo < 2)
  328. {
  329. // Always check for room for DBCS char
  330. return(SE_ERR_ACCESSDENIED);
  331. }
  332. *lpTo++ = *lpFrom;
  333. // Special case for things like "%1" ie don't clear the first param flag
  334. // if we hit a dbl-quote.
  335. if (*lpFrom != TEXT('"'))
  336. {
  337. // TraceMsg(TF_SHELLEXEC, "s.rp: Past first param (2).");
  338. fFirstParam = FALSE;
  339. }
  340. else if (IsDBCSLeadByte(*lpFrom))
  341. {
  342. *lpTo++ = *(++lpFrom);
  343. }
  344. }
  345. }
  346. // We should always have enough room since we dec'ed cchTo when determining
  347. // lpEnd
  348. *lpTo = 0;
  349. // This means success
  350. return(0);
  351. }
  352. HWND ThreadID_GetVisibleWindow(DWORD dwID)
  353. {
  354. HWND hwnd;
  355. for (hwnd = GetWindow(GetDesktopWindow(), GW_CHILD); hwnd; hwnd = GetWindow(hwnd, GW_HWNDNEXT))
  356. {
  357. DWORD dwIDTmp = GetWindowThreadProcessId(hwnd, NULL);
  358. TraceMsg(TF_SHELLEXEC, "s.ti_gvw: Hwnd %x Thread ID %x.", hwnd, dwIDTmp);
  359. if (IsWindowVisible(hwnd) && (dwIDTmp == dwID))
  360. {
  361. TraceMsg(TF_SHELLEXEC, "s.ti_gvw: Found match %x.", hwnd);
  362. return hwnd;
  363. }
  364. }
  365. return NULL;
  366. }
  367. void ActivateHandler(HWND hwnd, DWORD_PTR dwHotKey)
  368. {
  369. ASSERT(hwnd);
  370. hwnd = GetTopParentWindow(hwnd); // returns non-NULL for any non-NULL input
  371. HWND hwndT = GetLastActivePopup(hwnd); // returns non-NULL for any non-NULL input
  372. if (!IsWindowVisible(hwndT))
  373. {
  374. DWORD dwID = GetWindowThreadProcessId(hwnd, NULL);
  375. TraceMsg(TF_SHELLEXEC, "ActivateHandler: Hwnd %x Thread ID %x.", hwnd, dwID);
  376. ASSERT(dwID);
  377. // Find the first visible top level window owned by the
  378. // same guy that's handling the DDE conversation.
  379. hwnd = ThreadID_GetVisibleWindow(dwID);
  380. if (hwnd)
  381. {
  382. hwndT = GetLastActivePopup(hwnd);
  383. if (IsIconic(hwnd))
  384. {
  385. TraceMsg(TF_SHELLEXEC, "ActivateHandler: Window is iconic, restoring.");
  386. ShowWindow(hwnd,SW_RESTORE);
  387. }
  388. else
  389. {
  390. TraceMsg(TF_SHELLEXEC, "ActivateHandler: Window is normal, bringing to top.");
  391. BringWindowToTop(hwnd);
  392. if (hwndT && hwnd != hwndT)
  393. BringWindowToTop(hwndT);
  394. }
  395. // set the hotkey
  396. if (dwHotKey)
  397. {
  398. SendMessage(hwnd, WM_SETHOTKEY, dwHotKey, 0);
  399. }
  400. }
  401. }
  402. }
  403. // Some apps when run no-active steal the focus anyway so we
  404. // we set it back to the previously active window.
  405. void FixActivationStealingApps(HWND hwndOldActive, int nShow)
  406. {
  407. HWND hwndNew;
  408. if (nShow == SW_SHOWMINNOACTIVE && (hwndNew = GetForegroundWindow()) != hwndOldActive && IsIconic(hwndNew))
  409. SetForegroundWindow(hwndOldActive);
  410. }
  411. BOOL FindExistingDrv(LPCTSTR pszUNCRoot, LPTSTR pszLocalName)
  412. {
  413. int iDrive;
  414. for (iDrive = 0; iDrive < 26; iDrive++) {
  415. if (IsRemoteDrive(iDrive)) {
  416. TCHAR szDriveName[3];
  417. DWORD cb = MAX_PATH;
  418. szDriveName[0] = (TCHAR)iDrive + (TCHAR)TEXT('A');
  419. szDriveName[1] = TEXT(':');
  420. szDriveName[2] = 0;
  421. SHWNetGetConnection(szDriveName, pszLocalName, &cb);
  422. if (lstrcmpi(pszUNCRoot, pszLocalName) == 0) {
  423. lstrcpy(pszLocalName, szDriveName);
  424. return(TRUE);
  425. }
  426. }
  427. }
  428. return(FALSE);
  429. }
  430. // Returns whether the given net path exists. This fails for NON net paths.
  431. //
  432. BOOL NetPathExists(LPCTSTR lpszPath, DWORD *lpdwType)
  433. {
  434. BOOL fResult = FALSE;
  435. NETRESOURCE nr;
  436. LPTSTR lpSystem;
  437. DWORD dwRes, dwSize = 1024;
  438. void * lpv;
  439. if (!lpszPath || !*lpszPath)
  440. return FALSE;
  441. lpv = (void *)LocalAlloc(LPTR, dwSize);
  442. if (!lpv)
  443. return FALSE;
  444. TryWNetAgain:
  445. nr.dwScope = RESOURCE_GLOBALNET;
  446. nr.dwType = RESOURCETYPE_ANY;
  447. nr.dwDisplayType = 0;
  448. nr.lpLocalName = NULL;
  449. nr.lpRemoteName = (LPTSTR)lpszPath;
  450. nr.lpProvider = NULL;
  451. nr.lpComment = NULL;
  452. dwRes = WNetGetResourceInformation(&nr, lpv, &dwSize, &lpSystem);
  453. // If our buffer wasn't big enough, try a bigger buffer...
  454. if (dwRes == WN_MORE_DATA)
  455. {
  456. void * tmp = LocalReAlloc(lpv, dwSize, LMEM_MOVEABLE);
  457. if (!tmp)
  458. {
  459. LocalFree(lpv);
  460. SetLastError(ERROR_OUTOFMEMORY);
  461. return FALSE;
  462. }
  463. lpv = tmp;
  464. goto TryWNetAgain;
  465. }
  466. fResult = (dwRes == WN_SUCCESS);
  467. if (fResult && lpdwType)
  468. *lpdwType = ((LPNETRESOURCE)lpv)->dwType;
  469. LocalFree(lpv);
  470. return fResult;
  471. }
  472. HRESULT _CheckExistingNet(LPCTSTR pszFile, LPCTSTR pszRoot, BOOL fPrint)
  473. {
  474. //
  475. // This used to be a call to GetFileAttributes(), but
  476. // GetFileAttributes() doesn't handle net paths very well.
  477. // However, we need to be careful, because other shell code
  478. // expects SHValidateUNC to return false for paths that point
  479. // to print shares.
  480. //
  481. HRESULT hr = S_FALSE;
  482. if (!PathIsRoot(pszFile))
  483. {
  484. // if we are checking for a printshare, then it must be a Root
  485. if (fPrint)
  486. hr = E_FAIL;
  487. else if (PathFileExists(pszFile))
  488. hr = S_OK;
  489. }
  490. if (S_FALSE == hr)
  491. {
  492. DWORD dwType;
  493. if (NetPathExists(pszRoot, &dwType))
  494. {
  495. if (fPrint ? dwType != RESOURCETYPE_PRINT : dwType == RESOURCETYPE_PRINT)
  496. hr = E_FAIL;
  497. else
  498. hr = S_OK;
  499. }
  500. else if (-1 != GetFileAttributes(pszRoot))
  501. {
  502. //
  503. // IE 4.01 SP1 QFE #104. GetFileAttributes now called
  504. // as a last resort become some clients often fail when using
  505. // WNetGetResourceInformation. For example, many NFS clients were
  506. // broken because of this.
  507. //
  508. hr = S_OK;
  509. }
  510. }
  511. if (hr == E_FAIL)
  512. SetLastError(ERROR_NOT_SUPPORTED);
  513. return hr;
  514. }
  515. HRESULT _CheckNetUse(HWND hwnd, LPTSTR pszShare, UINT fConnect, LPTSTR pszOut, DWORD cchOut)
  516. {
  517. NETRESOURCE rc;
  518. DWORD dw, err;
  519. DWORD dwRedir = CONNECT_TEMPORARY;
  520. if (!(fConnect & VALIDATEUNC_NOUI))
  521. dwRedir |= CONNECT_INTERACTIVE;
  522. if (fConnect & VALIDATEUNC_CONNECT)
  523. dwRedir |= CONNECT_REDIRECT;
  524. // VALIDATE_PRINT happens only after a failed attempt to validate for
  525. // a file. That previous attempt will have given the option to
  526. // connect to other media -- don't do it here or the user will be
  527. // presented with the same dialog twice when the first one is cancelled.
  528. if (fConnect & VALIDATEUNC_PRINT)
  529. dwRedir |= CONNECT_CURRENT_MEDIA;
  530. rc.lpRemoteName = pszShare;
  531. rc.lpLocalName = NULL;
  532. rc.lpProvider = NULL;
  533. rc.dwType = (fConnect & VALIDATEUNC_PRINT) ? RESOURCETYPE_PRINT : RESOURCETYPE_DISK;
  534. err = WNetUseConnection(hwnd, &rc, NULL, NULL, dwRedir, pszOut, &cchOut, &dw);
  535. TraceMsg(TF_SHELLEXEC, "SHValidateUNC WNetUseConnection(%s) returned %x", pszShare, err);
  536. if (err)
  537. {
  538. SetLastError(err);
  539. return E_FAIL;
  540. }
  541. else if (fConnect & VALIDATEUNC_PRINT)
  542. {
  543. // just because WNetUse succeeded, doesnt mean
  544. // NetPathExists will. if it fails then
  545. // we shouldnt succeed this call regardless
  546. // because we are only interested in print shares.
  547. if (!NetPathExists(pszShare, &dw)
  548. || (dw != RESOURCETYPE_PRINT))
  549. {
  550. SetLastError(ERROR_NOT_SUPPORTED);
  551. return E_FAIL;
  552. }
  553. }
  554. return S_OK;
  555. }
  556. //
  557. // SHValidateUNC
  558. //
  559. // This function validates a UNC path by calling WNetAddConnection3.
  560. // It will make it possible for the user to type a remote (RNA) UNC
  561. // app/document name from Start->Run dialog.
  562. //
  563. // fConnect - flags controling what to do
  564. //
  565. // VALIDATEUNC_NOUI // dont bring up stinking UI!
  566. // VALIDATEUNC_CONNECT // connect a drive letter
  567. // VALIDATEUNC_PRINT // validate as print share instead of disk share
  568. //
  569. BOOL WINAPI SHValidateUNC(HWND hwndOwner, LPTSTR pszFile, UINT fConnect)
  570. {
  571. HRESULT hr;
  572. TCHAR szShare[MAX_PATH];
  573. BOOL fPrint = (fConnect & VALIDATEUNC_PRINT);
  574. ASSERT(PathIsUNC(pszFile));
  575. ASSERT((fConnect & ~VALIDATEUNC_VALID) == 0);
  576. ASSERT((fConnect & VALIDATEUNC_CONNECT) ? !fPrint : TRUE);
  577. lstrcpyn(szShare, pszFile, ARRAYSIZE(szShare));
  578. if (!PathStripToRoot(szShare))
  579. {
  580. SetLastError(ERROR_PATH_NOT_FOUND);
  581. return FALSE;
  582. }
  583. if (fConnect & VALIDATEUNC_CONNECT)
  584. hr = S_FALSE;
  585. else
  586. hr = _CheckExistingNet(pszFile, szShare, fPrint);
  587. if (S_FALSE == hr)
  588. {
  589. TCHAR szAccessName[MAX_PATH];
  590. if (!fPrint && FindExistingDrv(szShare, szAccessName))
  591. {
  592. hr = S_OK;
  593. }
  594. else
  595. hr = _CheckNetUse(hwndOwner, szShare, fConnect, szAccessName, SIZECHARS(szAccessName));
  596. if (S_OK == hr && !fPrint)
  597. {
  598. StrCatBuff(szAccessName, pszFile + lstrlen(szShare), ARRAYSIZE(szAccessName));
  599. // The name should only get shorter, so no need to check length
  600. lstrcpy(pszFile, szAccessName);
  601. // Handle the root case
  602. if (pszFile[2] == TEXT('\0'))
  603. {
  604. pszFile[2] = TEXT('\\');
  605. pszFile[3] = TEXT('\0');
  606. }
  607. hr = _CheckExistingNet(pszFile, szShare, FALSE);
  608. }
  609. }
  610. return (hr == S_OK);
  611. }
  612. HINSTANCE WINAPI RealShellExecuteExA(HWND hwnd, LPCSTR lpOp, LPCSTR lpFile,
  613. LPCSTR lpArgs, LPCSTR lpDir, LPSTR lpResult,
  614. LPCSTR lpTitle, LPSTR lpReserved,
  615. WORD nShowCmd, LPHANDLE lphProcess,
  616. DWORD dwFlags)
  617. {
  618. SHELLEXECUTEINFOA sei = { sizeof(SHELLEXECUTEINFOA), SEE_MASK_FLAG_NO_UI|SEE_MASK_FORCENOIDLIST, hwnd, lpOp, lpFile, lpArgs, lpDir, nShowCmd, NULL};
  619. TraceMsg(TF_SHELLEXEC, "RealShellExecuteExA(%04X, %s, %s, %s, %s, %s, %s, %s, %d, %08lX, %d)",
  620. hwnd, lpOp, lpFile, lpArgs, lpDir, lpResult, lpTitle,
  621. lpReserved, nShowCmd, lphProcess, dwFlags);
  622. // Pass along the lpReserved parameter to the new process
  623. if (lpReserved)
  624. {
  625. sei.fMask |= SEE_MASK_RESERVED;
  626. sei.hInstApp = (HINSTANCE)lpReserved;
  627. }
  628. // Pass along the lpTitle parameter to the new process
  629. if (lpTitle)
  630. {
  631. sei.fMask |= SEE_MASK_HASTITLE;
  632. sei.lpClass = lpTitle;
  633. }
  634. // Pass along the SEPARATE_VDM flag
  635. if (dwFlags & EXEC_SEPARATE_VDM)
  636. {
  637. sei.fMask |= SEE_MASK_FLAG_SEPVDM;
  638. }
  639. // Pass along the NO_CONSOLE flag
  640. if (dwFlags & EXEC_NO_CONSOLE)
  641. {
  642. sei.fMask |= SEE_MASK_NO_CONSOLE;
  643. }
  644. if (lphProcess)
  645. {
  646. // Return the process handle
  647. sei.fMask |= SEE_MASK_NOCLOSEPROCESS;
  648. ShellExecuteExA(&sei);
  649. *lphProcess = sei.hProcess;
  650. }
  651. else
  652. {
  653. ShellExecuteExA(&sei);
  654. }
  655. return sei.hInstApp;
  656. }
  657. HINSTANCE WINAPI RealShellExecuteExW(HWND hwnd, LPCWSTR lpOp, LPCWSTR lpFile,
  658. LPCWSTR lpArgs, LPCWSTR lpDir, LPWSTR lpResult,
  659. LPCWSTR lpTitle, LPWSTR lpReserved,
  660. WORD nShowCmd, LPHANDLE lphProcess,
  661. DWORD dwFlags)
  662. {
  663. SHELLEXECUTEINFOW sei = { sizeof(SHELLEXECUTEINFOW), SEE_MASK_FLAG_NO_UI|SEE_MASK_FORCENOIDLIST, hwnd, lpOp, lpFile, lpArgs, lpDir, nShowCmd, NULL};
  664. TraceMsg(TF_SHELLEXEC, "RealShellExecuteExW(%04X, %s, %s, %s, %s, %s, %s, %s, %d, %08lX, %d)",
  665. hwnd, lpOp, lpFile, lpArgs, lpDir, lpResult, lpTitle,
  666. lpReserved, nShowCmd, lphProcess, dwFlags);
  667. if (lpReserved)
  668. {
  669. sei.fMask |= SEE_MASK_RESERVED;
  670. sei.hInstApp = (HINSTANCE)lpReserved;
  671. }
  672. if (lpTitle)
  673. {
  674. sei.fMask |= SEE_MASK_HASTITLE;
  675. sei.lpClass = lpTitle;
  676. }
  677. if (dwFlags & EXEC_SEPARATE_VDM)
  678. {
  679. sei.fMask |= SEE_MASK_FLAG_SEPVDM;
  680. }
  681. if (dwFlags & EXEC_NO_CONSOLE)
  682. {
  683. sei.fMask |= SEE_MASK_NO_CONSOLE;
  684. }
  685. if (lphProcess)
  686. {
  687. // Return the process handle
  688. sei.fMask |= SEE_MASK_NOCLOSEPROCESS;
  689. ShellExecuteExW(&sei);
  690. *lphProcess = sei.hProcess;
  691. }
  692. else
  693. {
  694. ShellExecuteExW(&sei);
  695. }
  696. return sei.hInstApp;
  697. }
  698. HINSTANCE WINAPI RealShellExecuteA(HWND hwnd, LPCSTR lpOp, LPCSTR lpFile,
  699. LPCSTR lpArgs, LPCSTR lpDir, LPSTR lpResult,
  700. LPCSTR lpTitle, LPSTR lpReserved,
  701. WORD nShowCmd, LPHANDLE lphProcess)
  702. {
  703. TraceMsg(TF_SHELLEXEC, "RealShellExecuteA(%04X, %s, %s, %s, %s, %s, %s, %s, %d, %08lX)",
  704. hwnd, lpOp, lpFile, lpArgs, lpDir, lpResult, lpTitle,
  705. lpReserved, nShowCmd, lphProcess);
  706. return RealShellExecuteExA(hwnd,lpOp,lpFile,lpArgs,lpDir,lpResult,lpTitle,lpReserved,nShowCmd,lphProcess,0);
  707. }
  708. HINSTANCE RealShellExecuteW(HWND hwnd, LPCWSTR lpOp, LPCWSTR lpFile,
  709. LPCWSTR lpArgs, LPCWSTR lpDir, LPWSTR lpResult,
  710. LPCWSTR lpTitle, LPWSTR lpReserved,
  711. WORD nShowCmd, LPHANDLE lphProcess)
  712. {
  713. TraceMsg(TF_SHELLEXEC, "RealShellExecuteW(%04X, %s, %s, %s, %s, %s, %s, %s, %d, %08lX)",
  714. hwnd, lpOp, lpFile, lpArgs, lpDir, lpResult, lpTitle,
  715. lpReserved, nShowCmd, lphProcess);
  716. return RealShellExecuteExW(hwnd,lpOp,lpFile,lpArgs,lpDir,lpResult,lpTitle,lpReserved,nShowCmd,lphProcess,0);
  717. }
  718. HINSTANCE WINAPI ShellExecute(HWND hwnd, LPCTSTR lpOp, LPCTSTR lpFile, LPCTSTR lpArgs,
  719. LPCTSTR lpDir, int nShowCmd)
  720. {
  721. // NB The FORCENOIDLIST flag stops us from going through the ShellExecPidl()
  722. // code (for backwards compatability with progman).
  723. // DDEWAIT makes us synchronous, and gets around threads without
  724. // msg pumps and ones that are killed immediately after shellexec()
  725. SHELLEXECUTEINFO sei = { sizeof(SHELLEXECUTEINFO), 0, hwnd, lpOp, lpFile, lpArgs, lpDir, nShowCmd, NULL};
  726. ULONG fMask = SEE_MASK_FLAG_NO_UI|SEE_MASK_FORCENOIDLIST;
  727. if(!(SHGetAppCompatFlags(ACF_WIN95SHLEXEC) & ACF_WIN95SHLEXEC))
  728. fMask |= SEE_MASK_FLAG_DDEWAIT;
  729. sei.fMask = fMask;
  730. TraceMsg(TF_SHELLEXEC, "ShellExecute(%04X, %s, %s, %s, %s, %d)", hwnd, lpOp, lpFile, lpArgs, lpDir, nShowCmd);
  731. ShellExecuteEx(&sei);
  732. return sei.hInstApp;
  733. }
  734. HINSTANCE WINAPI ShellExecuteA(HWND hwnd, LPCSTR lpOp, LPCSTR lpFile, LPCSTR lpArgs,
  735. LPCSTR lpDir, int nShowCmd)
  736. {
  737. // NB The FORCENOIDLIST flag stops us from going through the ShellExecPidl()
  738. // code (for backwards compatability with progman).
  739. // DDEWAIT makes us synchronous, and gets around threads without
  740. // msg pumps and ones that are killed immediately after shellexec()
  741. SHELLEXECUTEINFOA sei = { sizeof(SHELLEXECUTEINFOA), 0, hwnd, lpOp, lpFile, lpArgs, lpDir, nShowCmd, NULL};
  742. ULONG fMask = SEE_MASK_FLAG_NO_UI|SEE_MASK_FORCENOIDLIST;
  743. if (!(SHGetAppCompatFlags(ACF_WIN95SHLEXEC) & ACF_WIN95SHLEXEC))
  744. fMask |= SEE_MASK_FLAG_DDEWAIT;
  745. sei.fMask = fMask;
  746. TraceMsg(TF_SHELLEXEC, "ShellExecuteA(%04X, %S, %S, %S, %S, %d)", hwnd,
  747. SAFE_DEBUGSTR(lpOp), SAFE_DEBUGSTR(lpFile), SAFE_DEBUGSTR(lpArgs),
  748. SAFE_DEBUGSTR(lpDir), nShowCmd);
  749. ShellExecuteExA(&sei);
  750. return sei.hInstApp;
  751. }
  752. // Returns TRUE if the specified app is listed under the specified key
  753. STDAPI_(BOOL) IsNameListedUnderKey(LPCTSTR pszFileName, LPCTSTR pszKey)
  754. {
  755. HKEY hkey;
  756. // Enum through the list of apps.
  757. if (RegOpenKey(HKEY_CURRENT_USER, pszKey, &hkey) == ERROR_SUCCESS)
  758. {
  759. TCHAR szValue[MAX_PATH], szData[MAX_PATH];
  760. DWORD dwType, cbData = sizeof(szData);
  761. DWORD cchValue = ARRAYSIZE(szValue);
  762. int iValue = 0;
  763. while (RegEnumValue(hkey, iValue, szValue, &cchValue, NULL, &dwType,
  764. (LPBYTE)szData, &cbData) == ERROR_SUCCESS)
  765. {
  766. if (lstrcmpi(szData, pszFileName) == 0)
  767. {
  768. RegCloseKey(hkey);
  769. return TRUE;
  770. }
  771. cbData = sizeof(szData);
  772. cchValue = ARRAYSIZE(szValue);
  773. iValue++;
  774. }
  775. RegCloseKey(hkey);
  776. }
  777. return FALSE;
  778. }
  779. #define REGSTR_PATH_POLICIES_EXPLORER REGSTR_PATH_POLICIES TEXT("\\Explorer\\RestrictRun")
  780. #define REGSTR_PATH_POLICIES_EXPLORER_DISALLOW REGSTR_PATH_POLICIES TEXT("\\Explorer\\DisallowRun")
  781. //----------------------------------------------------------------------------
  782. // Returns TRUE if the specified app is not on the list of unrestricted apps.
  783. BOOL RestrictedApp(LPCTSTR pszApp)
  784. {
  785. LPTSTR pszFileName;
  786. pszFileName = PathFindFileName(pszApp);
  787. TraceMsg(TF_SHELLEXEC, "RestrictedApp: %s ", pszFileName);
  788. // Special cases:
  789. // Apps you can always run.
  790. if (lstrcmpi(pszFileName, c_szRunDll) == 0)
  791. return FALSE;
  792. if (lstrcmpi(pszFileName, TEXT("systray.exe")) == 0)
  793. return FALSE;
  794. return !IsNameListedUnderKey(pszFileName, REGSTR_PATH_POLICIES_EXPLORER);
  795. }
  796. //----------------------------------------------------------------------------
  797. // Returns TRUE if the specified app is on the list of disallowed apps.
  798. BOOL DisallowedApp(LPCTSTR pszApp)
  799. {
  800. LPTSTR pszFileName;
  801. pszFileName = PathFindFileName(pszApp);
  802. TraceMsg(TF_SHELLEXEC, "DisallowedApp: %s ", pszFileName);
  803. return IsNameListedUnderKey(pszFileName, REGSTR_PATH_POLICIES_EXPLORER_DISALLOW);
  804. }
  805. //----------------------------------------------------------------------------
  806. // Returns TRUE if the system has FAT32 drives.
  807. BOOL HasFat32Drives()
  808. {
  809. static BOOL fHasFat32Drives = -1; // -1 means unverified.
  810. int iDrive;
  811. if (fHasFat32Drives != -1)
  812. return fHasFat32Drives;
  813. // Assume false
  814. fHasFat32Drives = FALSE;
  815. for (iDrive = 0; iDrive < 26; iDrive++)
  816. {
  817. TCHAR szDriveName[4];
  818. if (GetDriveType((LPTSTR)PathBuildRoot(szDriveName, iDrive)) == DRIVE_FIXED)
  819. {
  820. TCHAR szFileSystemName[12];
  821. if (GetVolumeInformation(szDriveName, NULL, 0, NULL, NULL, NULL,
  822. szFileSystemName, ARRAYSIZE(szFileSystemName)))
  823. {
  824. if (lstrcmpi(szFileSystemName, TEXT("FAT32"))==0)
  825. {
  826. fHasFat32Drives = TRUE;
  827. return fHasFat32Drives;
  828. }
  829. }
  830. }
  831. }
  832. return fHasFat32Drives;
  833. }
  834. typedef struct {
  835. // local data
  836. HWND hDlg;
  837. // parameters
  838. DWORD dwHelpId;
  839. LPCTSTR lpszTitle;
  840. DWORD dwResString;
  841. BOOL fHardBlock;
  842. BOOL fDone;
  843. } APPCOMPATDLG_DATA, *PAPPCOMPATDLG_DATA;
  844. BOOL_PTR CALLBACK AppCompat_DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  845. {
  846. PAPPCOMPATDLG_DATA lpdata = (PAPPCOMPATDLG_DATA)GetWindowLongPtr(hDlg, DWLP_USER);
  847. DWORD aHelpIDs[4];
  848. switch (uMsg)
  849. {
  850. case WM_INITDIALOG:
  851. {
  852. TCHAR szMsgText[2048];
  853. /* The title will be in the lParam. */
  854. lpdata = (PAPPCOMPATDLG_DATA)lParam;
  855. lpdata->hDlg = hDlg;
  856. if (lpdata->fHardBlock)
  857. {
  858. // Disable the "Run" button.
  859. EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
  860. }
  861. SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)lpdata);
  862. SetWindowText(hDlg, lpdata->lpszTitle);
  863. LoadString(HINST_THISDLL, lpdata->dwResString, szMsgText, ARRAYSIZE(szMsgText));
  864. SetDlgItemText(hDlg, IDD_LINE_1, szMsgText);
  865. return TRUE;
  866. }
  867. case WM_DESTROY:
  868. break;
  869. case WM_HELP:
  870. // WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle, TEXT("apps.chm>Proc4"), HELP_CONTEXT, 0);
  871. HtmlHelp((HWND)((LPHELPINFO)lParam)->hItemHandle, TEXT("apps.chm>Proc4"), HELP_CONTEXT, 0);
  872. break;
  873. case WM_COMMAND:
  874. switch (GET_WM_COMMAND_ID(wParam, lParam))
  875. {
  876. case IDHELP:
  877. aHelpIDs[0]=IDHELP;
  878. aHelpIDs[1]=lpdata->dwHelpId;
  879. aHelpIDs[2]=0;
  880. aHelpIDs[3]=0;
  881. // WinHelp(hDlg, TEXT("apps.chm>Proc4"), HELP_CONTEXT, (DWORD)lpdata->dwHelpId);
  882. HtmlHelp(hDlg, TEXT("apps.chm>Proc4"), HH_HELP_CONTEXT, (DWORD)lpdata->dwHelpId);
  883. break;
  884. case IDD_COMMAND:
  885. case IDOK:
  886. if (IsDlgButtonChecked(hDlg, IDD_STATE))
  887. EndDialog(hDlg, 0x8000 | IDOK);
  888. else
  889. EndDialog(hDlg, IDOK);
  890. break;
  891. case IDCANCEL:
  892. EndDialog(hDlg, IDCANCEL);
  893. break;
  894. default:
  895. return FALSE;
  896. }
  897. break;
  898. default:
  899. return FALSE;
  900. }
  901. return TRUE;
  902. }
  903. BOOL _GetAppCompatData(LPCTSTR pszAppPath, LPCTSTR pszAppName, LPCTSTR *ppszNewEnvString, HKEY hkApp, APPCOMPATDLG_DATA *pdata, LPTSTR pszValue, DWORD cchValue)
  904. {
  905. BOOL fRet = FALSE;
  906. BOOL fBreakOutOfTheLoop=FALSE;
  907. int iValue;
  908. // Enum keys under this app name and check for dependant files.
  909. for (iValue = 0; !fBreakOutOfTheLoop; iValue++)
  910. {
  911. DWORD cch = cchValue;
  912. DWORD dwType;
  913. BYTE *pvData;
  914. DWORD cbData;
  915. LONG lResult;
  916. lResult = RegEnumValue(hkApp, iValue, pszValue, &cch, NULL, &dwType, NULL, &cbData);
  917. if ((lResult != NOERROR) && (lResult != ERROR_MORE_DATA))
  918. {
  919. // no more values
  920. break;
  921. }
  922. // insure this is our kind of data
  923. if (dwType != REG_BINARY)
  924. continue;
  925. pvData = (BYTE *) GlobalAlloc(GPTR, cbData);
  926. if (pvData)
  927. {
  928. cch = cchValue;
  929. if (NOERROR == RegEnumValue(hkApp, iValue, pszValue, &cch, NULL,
  930. &dwType, pvData, &cbData))
  931. {
  932. BADAPP_DATA badAppData;
  933. BADAPP_PROP badAppProp;
  934. badAppProp.Size = sizeof(BADAPP_PROP);
  935. badAppData.Size = sizeof(BADAPP_DATA);
  936. badAppData.FilePath = pszAppPath;
  937. badAppData.Blob = pvData;
  938. badAppData.BlobSize = cbData;
  939. if (SHIsBadApp(&badAppData, &badAppProp))
  940. {
  941. //
  942. // we found a bad app
  943. //
  944. pdata->dwHelpId = badAppProp.MsgId;
  945. pdata->lpszTitle = pszAppName;
  946. fRet=TRUE;
  947. // Map ids to message strings for the various platforms we run on
  948. switch (badAppProp.AppType & APPTYPE_TYPE_MASK)
  949. {
  950. case APPTYPE_MINORPROBLEM:
  951. pdata->dwResString = IDS_APPCOMPATWIN95L;
  952. break;
  953. case APPTYPE_INC_HARDBLOCK:
  954. pdata->fHardBlock = TRUE;
  955. pdata->dwResString = IDS_APPCOMPATWIN95H;
  956. break;
  957. case APPTYPE_INC_NOBLOCK:
  958. pdata->dwResString = IDS_APPCOMPATWIN95;
  959. break;
  960. case APPTYPE_VERSIONSUB:
  961. {
  962. static const LPCTSTR VersionFlavors[] = {
  963. TEXT("_COMPAT_VER_NNN=4,0,1381,3,0,2,Service Pack 3"),
  964. TEXT("_COMPAT_VER_NNN=4,0,1381,4,0,2,Service Pack 4"),
  965. TEXT("_COMPAT_VER_NNN=4,0,1381,5,0,2,Service Pack 5"),
  966. TEXT("_COMPAT_VER_NNN=4,0,950,0,0,1"),
  967. 0};
  968. //
  969. // Is the ID within the number of strings we have?
  970. //
  971. if (badAppProp.MsgId <= (sizeof(VersionFlavors) / sizeof(LPTSTR) - 1))
  972. {
  973. *ppszNewEnvString = VersionFlavors[badAppProp.MsgId];
  974. }
  975. fRet = FALSE;
  976. }
  977. break;
  978. case APPTYPE_SHIM:
  979. //
  980. // If there is a shim for this app do not display
  981. // any message
  982. //
  983. fRet = FALSE;
  984. break;
  985. default:
  986. continue;
  987. }
  988. // this will break us out
  989. fBreakOutOfTheLoop = TRUE;
  990. }
  991. }
  992. GlobalFree((HANDLE)pvData);
  993. }
  994. }
  995. return fRet;
  996. }
  997. typedef enum {
  998. SEV_DEFAULT = 0,
  999. SEV_LOW,
  1000. SEV_HARD,
  1001. } SEVERITY;
  1002. BOOL _GetBadAppData(LPCTSTR pszAppPath, LPCTSTR pszAppName, HKEY hkApp, APPCOMPATDLG_DATA *pdata, LPTSTR pszValue, DWORD cchValue)
  1003. {
  1004. BOOL fRet = FALSE;
  1005. int iValue;
  1006. TCHAR szPath[MAX_PATH];
  1007. DWORD cchPath;
  1008. LPTSTR pchCopyToPath;
  1009. // Get directory of this app so that we can check for dependant files.
  1010. StrCpyN(szPath, pszAppPath, ARRAYSIZE(szPath));
  1011. PathRemoveFileSpec(szPath);
  1012. PathAddBackslash(szPath);
  1013. cchPath = lstrlen(szPath);
  1014. pchCopyToPath = &szPath[cchPath];
  1015. cchPath = ARRAYSIZE(szPath) - cchPath;
  1016. for (iValue = 0; !fRet; iValue++)
  1017. {
  1018. DWORD cch = cchValue;
  1019. TCHAR szData[MAX_PATH];
  1020. DWORD cbData = sizeof(szData);
  1021. DWORD dwType;
  1022. if (NOERROR == RegEnumValue(hkApp, iValue, pszValue, &cch, NULL, &dwType,
  1023. (LPBYTE)szData, &cbData))
  1024. {
  1025. // Fully qualified path to dependant file
  1026. StrCpyN(pchCopyToPath, pszValue, cchPath);
  1027. // * means match any file.
  1028. if (pszValue[0] == TEXT('*') || PathFileExistsAndAttributes(szPath, NULL))
  1029. {
  1030. DWORD rgData[2];
  1031. DWORD dwHelpId = StrToInt(szData);
  1032. SEVERITY sev = SEV_DEFAULT;
  1033. // Get the flags...
  1034. lstrcpy(szData, TEXT("Flags"));
  1035. StrCatBuff(szData, pszValue, ARRAYSIZE(szData));
  1036. cbData = sizeof(szData);
  1037. if (SHQueryValueEx(hkApp, szData, NULL, &dwType, (LPBYTE)szData, &cbData) == ERROR_SUCCESS && cbData >= 1)
  1038. {
  1039. if (StrChr(szData, TEXT('L')))
  1040. sev = SEV_LOW;
  1041. if (StrChr(szData, TEXT('Y')))
  1042. sev = SEV_HARD;
  1043. if ((StrChr(szData, TEXT('N')) && !(GetSystemMetrics(SM_NETWORK) & RNC_NETWORKS))
  1044. || (StrChr(szData, TEXT('F')) && !HasFat32Drives()))
  1045. {
  1046. continue;
  1047. }
  1048. }
  1049. // Check the version if any...
  1050. lstrcpy(szData, TEXT("Version"));
  1051. StrCatBuff(szData, pszValue, ARRAYSIZE(szData));
  1052. cbData = sizeof(rgData);
  1053. if (SHQueryValueEx(hkApp, szData, NULL, &dwType, (LPBYTE)rgData, &cbData) == ERROR_SUCCESS
  1054. && (cbData == 8))
  1055. {
  1056. DWORD dwVerLen, dwVerHandle;
  1057. DWORD dwMajorVer, dwMinorVer;
  1058. DWORD dwBadMajorVer, dwBadMinorVer;
  1059. LPTSTR lpVerBuffer;
  1060. BOOL fBadApp = FALSE;
  1061. // What is a bad version according to the registry key?
  1062. dwBadMajorVer = rgData[0];
  1063. dwBadMinorVer = rgData[1];
  1064. // If no version resource can be found, assume 0.
  1065. dwMajorVer = 0;
  1066. dwMinorVer = 0;
  1067. // Version data in inf file should be of the form 8 bytes
  1068. // Major Minor
  1069. // 3.10 10.10
  1070. // 40 30 20 10 is 10 20 30 40 in registry
  1071. // cast const -> non const
  1072. if (0 != (dwVerLen = GetFileVersionInfoSize((LPTSTR)pszAppPath, &dwVerHandle)))
  1073. {
  1074. lpVerBuffer = (LPTSTR)GlobalAlloc(GPTR, dwVerLen);
  1075. if (lpVerBuffer)
  1076. {
  1077. VS_FIXEDFILEINFO *pffi = NULL;
  1078. UINT cb;
  1079. if (GetFileVersionInfo((LPTSTR)pszAppPath, dwVerHandle, dwVerLen, lpVerBuffer) &&
  1080. VerQueryValue(lpVerBuffer, TEXT("\\"), (void **)&pffi, &cb))
  1081. {
  1082. dwMajorVer = pffi->dwProductVersionMS;
  1083. dwMinorVer = pffi->dwProductVersionLS;
  1084. }
  1085. GlobalFree((HANDLE)lpVerBuffer);
  1086. }
  1087. }
  1088. if (dwMajorVer < dwBadMajorVer)
  1089. fBadApp = TRUE;
  1090. else if ((dwMajorVer == dwBadMajorVer) && (dwMinorVer <= dwBadMinorVer))
  1091. fBadApp = TRUE;
  1092. if (!fBadApp)
  1093. {
  1094. // This dude is ok
  1095. continue;
  1096. }
  1097. }
  1098. pdata->dwHelpId = dwHelpId;
  1099. pdata->lpszTitle = pszAppName;
  1100. // Map ids to message strings for the various platforms we run on
  1101. switch (sev)
  1102. {
  1103. case SEV_LOW:
  1104. pdata->dwResString = IDS_APPCOMPATWIN95L;
  1105. break;
  1106. case SEV_HARD:
  1107. pdata->fHardBlock = TRUE;
  1108. pdata->dwResString = IDS_APPCOMPATWIN95H;
  1109. break;
  1110. default:
  1111. pdata->dwResString = IDS_APPCOMPATWIN95;
  1112. }
  1113. // this will break us out
  1114. fRet = TRUE;
  1115. }
  1116. }
  1117. else
  1118. break;
  1119. }
  1120. return fRet;
  1121. }
  1122. HKEY _OpenBadAppKey(LPCTSTR pszApp, LPCTSTR pszName)
  1123. {
  1124. HKEY hkBad = NULL;
  1125. DWORD dwAppVersion = GetExeType(pszApp);
  1126. ASSERT(pszApp && *pszApp && pszName && *pszName);
  1127. if (HIWORD(dwAppVersion) < 0x0400)
  1128. {
  1129. // Check the reg key for apps older than 4.00
  1130. RegOpenKey(HKEY_LOCAL_MACHINE, REGSTR_PATH_CHECKBADAPPSNEW, &hkBad);
  1131. }
  1132. else if (HIWORD(dwAppVersion) == 0x0400)
  1133. {
  1134. // Check the reg key for apps == 4.00
  1135. RegOpenKey(HKEY_LOCAL_MACHINE, REGSTR_PATH_CHECKBADAPPS400NEW, &hkBad);
  1136. }
  1137. // else
  1138. // Newer than 4.0 so all should be fine.
  1139. if (hkBad)
  1140. {
  1141. // Check for the app name
  1142. HKEY hkRet = NULL;
  1143. RegOpenKey(hkBad, pszName, &hkRet);
  1144. RegCloseKey(hkBad);
  1145. return hkRet;
  1146. }
  1147. return NULL;
  1148. }
  1149. HKEY _CheckBadApps(LPCTSTR pszAppPath, LPCTSTR pszAppName, APPCOMPATDLG_DATA *pdata, LPTSTR pszValue, DWORD cchValue)
  1150. {
  1151. HKEY hkApp = _OpenBadAppKey(pszAppPath, pszAppName);
  1152. if (hkApp)
  1153. {
  1154. TraceMsg(TF_SHELLEXEC, "CheckBadApps() maybe is bad %s", pszAppName);
  1155. if (_GetBadAppData(pszAppPath, pszAppName, hkApp, pdata, pszValue, cchValue))
  1156. return hkApp;
  1157. RegCloseKey(hkApp);
  1158. }
  1159. return NULL;
  1160. }
  1161. HKEY _OpenAppCompatKey(LPCTSTR pszAppName)
  1162. {
  1163. TCHAR sz[MAX_PATH];
  1164. HKEY hkRet = NULL;
  1165. wnsprintf(sz, SIZECHARS(sz), REGSTR_TEMP_APPCOMPATPATH, pszAppName);
  1166. RegOpenKey(HKEY_LOCAL_MACHINE, sz, &hkRet);
  1167. return hkRet;
  1168. }
  1169. HKEY _CheckAppCompat(LPCTSTR pszAppPath, LPCTSTR pszAppName, LPCTSTR *ppszNewEnvString, APPCOMPATDLG_DATA *pdata, LPTSTR pszValue, DWORD cchValue)
  1170. {
  1171. HKEY hkApp = _OpenAppCompatKey(pszAppName);
  1172. if (hkApp)
  1173. {
  1174. TraceMsg(TF_SHELLEXEC, "CheckAppCompat() maybe is bad %s", pszAppName);
  1175. if (_GetAppCompatData(pszAppPath, pszAppName, ppszNewEnvString, hkApp, pdata, pszValue, cchValue))
  1176. return hkApp;
  1177. RegCloseKey(hkApp);
  1178. }
  1179. return NULL;
  1180. }
  1181. // Returns FALSE if app is fatally incompatible
  1182. BOOL CheckAppCompatibility(LPCTSTR pszApp, LPCTSTR *ppszNewEnvString, BOOL fNoUI, HWND hwnd)
  1183. {
  1184. BOOL fRet = TRUE;
  1185. // If no app name, then nothing to check, so pretend it's a good app.
  1186. // Must check now or RegOpenKey will get a null string and behave
  1187. // "nonintuitively". (If you give RegOpenKey a null string, it
  1188. // returns the same key back and does *not* bump the refcount.)
  1189. if (pszApp && *pszApp)
  1190. {
  1191. LPCTSTR pszFileName = PathFindFileName(pszApp);
  1192. if (pszFileName && *pszFileName)
  1193. {
  1194. APPCOMPATDLG_DATA data = {0};
  1195. TCHAR szValue[MAX_PATH];
  1196. HKEY hkBad = _CheckAppCompat(pszApp, pszFileName, ppszNewEnvString, &data, szValue, ARRAYSIZE(szValue));
  1197. if (!hkBad)
  1198. hkBad = _CheckBadApps(pszApp, pszFileName, &data, szValue, ARRAYSIZE(szValue));
  1199. if (hkBad)
  1200. {
  1201. TraceMsg(TF_SHELLEXEC, "BADAPP %s", pszFileName);
  1202. if (fNoUI && !hwnd)
  1203. {
  1204. //
  1205. // LEGACY - we just let soft blocks right on through - ZekeL - 27-MAY-99
  1206. // the NOUI flag is usually passed by apps when they
  1207. // have very specific behavior they are looking for.
  1208. // if that is the case we should probably just defer to them
  1209. // unless we know it is really bad.
  1210. //
  1211. if (data.fHardBlock)
  1212. fRet = FALSE;
  1213. else
  1214. fRet = TRUE;
  1215. }
  1216. else
  1217. {
  1218. int iRet = (int)DialogBoxParam(HINST_THISDLL,
  1219. MAKEINTRESOURCE(DLG_APPCOMPAT),
  1220. hwnd, AppCompat_DlgProc, (LPARAM)&data);
  1221. if (iRet & 0x8000)
  1222. {
  1223. // Delete so we don't warn again.
  1224. RegDeleteValue(hkBad, szValue);
  1225. }
  1226. if ((iRet & 0x0FFF) != IDOK)
  1227. fRet = FALSE;
  1228. }
  1229. RegCloseKey(hkBad);
  1230. }
  1231. }
  1232. }
  1233. return fRet;
  1234. }
  1235. /*
  1236. * Returns:
  1237. * S_OK or error.
  1238. * *phrHook is hook result if S_OK is returned, otherwise it is S_FALSE.
  1239. */
  1240. HRESULT InvokeShellExecuteHook(REFGUID clsidHook, LPSHELLEXECUTEINFO pei, HRESULT *phrHook)
  1241. {
  1242. *phrHook = S_FALSE;
  1243. IUnknown *punk;
  1244. HRESULT hr = SHExtCoCreateInstance(NULL, &clsidHook, NULL, IID_PPV_ARG(IUnknown, &punk));
  1245. if (hr == S_OK)
  1246. {
  1247. IShellExecuteHook *pshexhk;
  1248. hr = punk->QueryInterface(IID_PPV_ARG(IShellExecuteHook, &pshexhk));
  1249. if (hr == S_OK)
  1250. {
  1251. *phrHook = pshexhk->Execute(pei);
  1252. pshexhk->Release();
  1253. }
  1254. else
  1255. {
  1256. IShellExecuteHookA *pshexhkA;
  1257. hr = punk->QueryInterface(IID_PPV_ARG(IShellExecuteHookA, &pshexhkA));
  1258. if (SUCCEEDED(hr))
  1259. {
  1260. SHELLEXECUTEINFOA seia;
  1261. UINT cchVerb = 0;
  1262. UINT cchFile = 0;
  1263. UINT cchParameters = 0;
  1264. UINT cchDirectory = 0;
  1265. UINT cchClass = 0;
  1266. LPSTR lpszBuffer;
  1267. seia = *(SHELLEXECUTEINFOA*)pei; // Copy all of the binary data
  1268. if (pei->lpVerb)
  1269. {
  1270. cchVerb = WideCharToMultiByte(CP_ACP,0,
  1271. pei->lpVerb, -1,
  1272. NULL, 0,
  1273. NULL, NULL) + 1;
  1274. }
  1275. if (pei->lpFile)
  1276. cchFile = WideCharToMultiByte(CP_ACP,0,
  1277. pei->lpFile, -1,
  1278. NULL, 0,
  1279. NULL, NULL)+1;
  1280. if (pei->lpParameters)
  1281. cchParameters = WideCharToMultiByte(CP_ACP,0,
  1282. pei->lpParameters, -1,
  1283. NULL, 0,
  1284. NULL, NULL)+1;
  1285. if (pei->lpDirectory)
  1286. cchDirectory = WideCharToMultiByte(CP_ACP,0,
  1287. pei->lpDirectory, -1,
  1288. NULL, 0,
  1289. NULL, NULL)+1;
  1290. if (_UseClassName(pei->fMask) && pei->lpClass)
  1291. cchClass = WideCharToMultiByte(CP_ACP,0,
  1292. pei->lpClass, -1,
  1293. NULL, 0,
  1294. NULL, NULL)+1;
  1295. lpszBuffer = (LPSTR) alloca(cchVerb+cchFile+cchParameters+cchDirectory+cchClass);
  1296. seia.lpVerb = NULL;
  1297. seia.lpFile = NULL;
  1298. seia.lpParameters = NULL;
  1299. seia.lpDirectory = NULL;
  1300. seia.lpClass = NULL;
  1301. //
  1302. // Convert all of the strings to ANSI
  1303. //
  1304. if (pei->lpVerb)
  1305. {
  1306. WideCharToMultiByte(CP_ACP, 0, pei->lpVerb, -1,
  1307. lpszBuffer, cchVerb, NULL, NULL);
  1308. seia.lpVerb = lpszBuffer;
  1309. lpszBuffer += cchVerb;
  1310. }
  1311. if (pei->lpFile)
  1312. {
  1313. WideCharToMultiByte(CP_ACP, 0, pei->lpFile, -1,
  1314. lpszBuffer, cchFile, NULL, NULL);
  1315. seia.lpFile = lpszBuffer;
  1316. lpszBuffer += cchFile;
  1317. }
  1318. if (pei->lpParameters)
  1319. {
  1320. WideCharToMultiByte(CP_ACP, 0,
  1321. pei->lpParameters, -1,
  1322. lpszBuffer, cchParameters, NULL, NULL);
  1323. seia.lpParameters = lpszBuffer;
  1324. lpszBuffer += cchParameters;
  1325. }
  1326. if (pei->lpDirectory)
  1327. {
  1328. WideCharToMultiByte(CP_ACP, 0,
  1329. pei->lpDirectory, -1,
  1330. lpszBuffer, cchDirectory, NULL, NULL);
  1331. seia.lpDirectory = lpszBuffer;
  1332. lpszBuffer += cchDirectory;
  1333. }
  1334. if (_UseClassName(pei->fMask) && pei->lpClass)
  1335. {
  1336. WideCharToMultiByte(CP_ACP, 0,
  1337. pei->lpClass, -1,
  1338. lpszBuffer, cchClass, NULL, NULL);
  1339. seia.lpClass = lpszBuffer;
  1340. }
  1341. *phrHook = pshexhkA->Execute(&seia);
  1342. pei->hInstApp = seia.hInstApp;
  1343. // hook may set hProcess (e.g. CURLExec creates dummy process
  1344. // to signal IEAK that IE setup failed -- in browser only mode)
  1345. pei->hProcess = seia.hProcess;
  1346. pshexhkA->Release();
  1347. }
  1348. }
  1349. punk->Release();
  1350. }
  1351. return(hr);
  1352. }
  1353. const TCHAR c_szShellExecuteHooks[] = REGSTR_PATH_EXPLORER TEXT("\\ShellExecuteHooks");
  1354. /*
  1355. * Returns:
  1356. * S_OK Execution handled by hook. pei->hInstApp filled in.
  1357. * S_FALSE Execution not handled by hook. pei->hInstApp not filled in.
  1358. * E_... Error during execution by hook. pei->hInstApp filled in.
  1359. */
  1360. HRESULT TryShellExecuteHooks(LPSHELLEXECUTEINFO pei)
  1361. {
  1362. HRESULT hr = S_FALSE;
  1363. HKEY hkeyHooks;
  1364. // Enumerate the list of hooks. A hook is registered as a GUID value of the
  1365. // c_szShellExecuteHooks key.
  1366. if (RegOpenKey(HKEY_LOCAL_MACHINE, c_szShellExecuteHooks, &hkeyHooks)
  1367. == ERROR_SUCCESS)
  1368. {
  1369. DWORD dwiValue;
  1370. TCHAR szCLSID[GUIDSTR_MAX];
  1371. DWORD cchCLSID;
  1372. // Invoke each hook. A hook returns S_FALSE if it does not handle the
  1373. // exec. Stop when a hook returns S_OK (handled) or an error.
  1374. for (cchCLSID = ARRAYSIZE(szCLSID), dwiValue = 0;
  1375. RegEnumValue(hkeyHooks, dwiValue, szCLSID, &cchCLSID, NULL,
  1376. NULL, NULL, NULL) == ERROR_SUCCESS;
  1377. cchCLSID = ARRAYSIZE(szCLSID), dwiValue++)
  1378. {
  1379. CLSID clsidHook;
  1380. if (SUCCEEDED(SHCLSIDFromString(szCLSID, &clsidHook)))
  1381. {
  1382. HRESULT hrHook;
  1383. if (InvokeShellExecuteHook(clsidHook, pei, &hrHook) == S_OK &&
  1384. hrHook != S_FALSE)
  1385. {
  1386. hr = hrHook;
  1387. break;
  1388. }
  1389. }
  1390. }
  1391. RegCloseKey(hkeyHooks);
  1392. }
  1393. ASSERT(hr == S_FALSE ||
  1394. (hr == S_OK && ISSHELLEXECSUCCEEDED(pei->hInstApp)) ||
  1395. (FAILED(hr) && ! ISSHELLEXECSUCCEEDED(pei->hInstApp)));
  1396. return(hr);
  1397. }
  1398. BOOL InRunDllProcess(void)
  1399. {
  1400. static BOOL s_fInRunDll = -1;
  1401. if (-1 == s_fInRunDll)
  1402. {
  1403. TCHAR sz[MAX_PATH];
  1404. s_fInRunDll = FALSE;
  1405. if (GetModuleFileName(NULL, sz, SIZECHARS(sz)))
  1406. {
  1407. //
  1408. // WARNING - rundll often seems to fail to add the DDEWAIT flag, and
  1409. // it often needs to since it is common to use rundll as a fire
  1410. // and forget process, and it exits too early.
  1411. //
  1412. if (StrStrI(sz, TEXT("rundll")))
  1413. s_fInRunDll = TRUE;
  1414. }
  1415. }
  1416. return s_fInRunDll;
  1417. }
  1418. #ifdef DEBUG
  1419. /*----------------------------------------------------------
  1420. Purpose: Validation function for SHELLEXECUTEINFO
  1421. */
  1422. BOOL IsValidPSHELLEXECUTEINFO(LPSHELLEXECUTEINFO pei)
  1423. {
  1424. //
  1425. // Note that we do *NOT* validate hInstApp, for several reasons.
  1426. //
  1427. // 1. It is an OUT parameter, not an IN parameter.
  1428. // 2. It often contains an error code (see documentation).
  1429. // 3. Even when it contains an HINSTANCE, it's an HINSTANCE
  1430. // in another process, so we can't validate it anyway.
  1431. //
  1432. return (IS_VALID_WRITE_PTR(pei, SHELLEXECUTEINFO) &&
  1433. IS_VALID_SIZE(pei->cbSize, sizeof(*pei)) &&
  1434. (IsFlagSet(pei->fMask, SEE_MASK_FLAG_NO_UI) ||
  1435. NULL == pei->hwnd ||
  1436. IS_VALID_HANDLE(pei->hwnd, WND)) &&
  1437. (NULL == pei->lpVerb || IS_VALID_STRING_PTR(pei->lpVerb, -1)) &&
  1438. (NULL == pei->lpFile || IS_VALID_STRING_PTR(pei->lpFile, -1)) &&
  1439. (NULL == pei->lpParameters || IS_VALID_STRING_PTR(pei->lpParameters, -1)) &&
  1440. (NULL == pei->lpDirectory || IS_VALID_STRING_PTR(pei->lpDirectory, -1)) &&
  1441. (IsFlagClear(pei->fMask, SEE_MASK_IDLIST) ||
  1442. IsFlagSet(pei->fMask, SEE_MASK_INVOKEIDLIST) || // because SEE_MASK_IDLIST is part of SEE_MASK_INVOKEIDLIST this line will
  1443. IS_VALID_PIDL((LPCITEMIDLIST)(pei->lpIDList))) && // defer to the next clause if the superset is true
  1444. (IsFlagClear(pei->fMask, SEE_MASK_INVOKEIDLIST) ||
  1445. NULL == pei->lpIDList ||
  1446. IS_VALID_PIDL((LPCITEMIDLIST)(pei->lpIDList))) &&
  1447. (!_UseClassName(pei->fMask) ||
  1448. IS_VALID_STRING_PTR(pei->lpClass, -1)) &&
  1449. (!_UseTitleName(pei->fMask) ||
  1450. NULL == pei->lpClass ||
  1451. IS_VALID_STRING_PTR(pei->lpClass, -1)) &&
  1452. (!_UseClassKey(pei->fMask) ||
  1453. IS_VALID_HANDLE(pei->hkeyClass, KEY)) &&
  1454. (IsFlagClear(pei->fMask, SEE_MASK_ICON) ||
  1455. IS_VALID_HANDLE(pei->hIcon, ICON)));
  1456. }
  1457. #endif // DEBUG
  1458. //
  1459. // ShellExecuteEx
  1460. //
  1461. // returns TRUE if the execute succeeded, in which case
  1462. // hInstApp should be the hinstance of the app executed (>32)
  1463. // NOTE: in some cases the HINSTANCE cannot (currently) be determined.
  1464. // In these cases, hInstApp is set to 42.
  1465. //
  1466. // returns FALSE if the execute did not succeed, in which case
  1467. // GetLastError will contain error information
  1468. // For backwards compatibility, hInstApp will contain the
  1469. // best SE_ERR_ error information (<=32) possible.
  1470. //
  1471. BOOL WINAPI ShellExecuteEx(LPSHELLEXECUTEINFO pei)
  1472. {
  1473. DWORD err = NOERROR;
  1474. // Don't overreact if CoInitializeEx fails; it just means we
  1475. // can't do our shell hooks.
  1476. HRESULT hrInit = SHCoInitialize();
  1477. if (IS_VALID_STRUCT_PTR(pei, SHELLEXECUTEINFO) &&
  1478. sizeof(*pei) == pei->cbSize)
  1479. {
  1480. // This internal bit prevents error message box reporting
  1481. // when we recurse back into ShellExecuteEx
  1482. ULONG ulOriginalMask = pei->fMask;
  1483. pei->fMask |= SEE_MASK_FLAG_SHELLEXEC;
  1484. if (SHRegGetBoolUSValue(TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"), TEXT("MaximizeApps"),
  1485. FALSE, FALSE)) // && (GetSystemMetrics(SM_CYSCREEN)<=600))
  1486. {
  1487. switch (pei->nShow)
  1488. {
  1489. case SW_NORMAL:
  1490. case SW_SHOW:
  1491. case SW_RESTORE:
  1492. case SW_SHOWDEFAULT:
  1493. pei->nShow = SW_MAXIMIZE;
  1494. }
  1495. }
  1496. if (!(pei->fMask & SEE_MASK_FLAG_DDEWAIT) && InRunDllProcess())
  1497. {
  1498. //
  1499. // WARNING - rundll often seems to fail to add the DDEWAIT flag, and
  1500. // it often needs to since it is common to use rundll as a fire
  1501. // and forget process, and it exits too early.
  1502. //
  1503. pei->fMask |= (SEE_MASK_FLAG_DDEWAIT | SEE_MASK_WAITFORINPUTIDLE);
  1504. }
  1505. // ShellExecuteNormal does its own SetLastError
  1506. err = ShellExecuteNormal(pei);
  1507. // Mike's attempt to be consistent in error reporting:
  1508. if (err != ERROR_SUCCESS)
  1509. {
  1510. // we shouldn't put up errors on dll's not found.
  1511. // this is handled WITHIN shellexecuteNormal because
  1512. // sometimes kernel will put up the message for us, and sometimes
  1513. // we need to. we've put the curtion at ShellExecuteNormal
  1514. // LEGACY - ERROR_RESTRICTED_APP was never mapped to a valid error - ZekeL 2001-FEB-14
  1515. // because we always called _ShellExecuteError() before
  1516. // resetting the mask to ulOriginalMask, we never mapped
  1517. // ERROR_RESTRICTED_APP (which is -1) to a valid code
  1518. if (err != ERROR_DLL_NOT_FOUND &&
  1519. err != ERROR_CANCELLED)
  1520. {
  1521. _ShellExecuteError(pei, NULL, err);
  1522. }
  1523. }
  1524. pei->fMask = ulOriginalMask;
  1525. }
  1526. else
  1527. {
  1528. // Failed parameter validation
  1529. pei->hInstApp = (HINSTANCE)SE_ERR_ACCESSDENIED;
  1530. err = ERROR_ACCESS_DENIED;
  1531. }
  1532. SHCoUninitialize(hrInit);
  1533. if (err != ERROR_SUCCESS)
  1534. SetLastError(err);
  1535. return err == ERROR_SUCCESS;
  1536. }
  1537. //+-------------------------------------------------------------------------
  1538. //
  1539. // Function: ShellExecuteExA
  1540. //
  1541. // Synopsis: Thunks ANSI call to ShellExecuteA to ShellExecuteW
  1542. //
  1543. // Arguments: [pei] -- pointer to an ANSI SHELLEXECUTINFO struct
  1544. //
  1545. // Returns: BOOL success value
  1546. //
  1547. // History: 2-04-95 bobday Created
  1548. // 2-06-95 davepl Changed to ConvertStrings
  1549. //
  1550. // Notes:
  1551. //
  1552. //--------------------------------------------------------------------------
  1553. inline BOOL _ThunkClass(ULONG fMask)
  1554. {
  1555. return (fMask & SEE_MASK_HASLINKNAME)
  1556. || (fMask & SEE_MASK_HASTITLE)
  1557. || _UseClassName(fMask);
  1558. }
  1559. BOOL WINAPI ShellExecuteExA(LPSHELLEXECUTEINFOA pei)
  1560. {
  1561. if (pei->cbSize != sizeof(SHELLEXECUTEINFOA))
  1562. {
  1563. pei->hInstApp = (HINSTANCE)SE_ERR_ACCESSDENIED;
  1564. SetLastError(ERROR_ACCESS_DENIED);
  1565. return FALSE;
  1566. }
  1567. SHELLEXECUTEINFOW seiw = {0};
  1568. seiw.cbSize = sizeof(SHELLEXECUTEINFOW);
  1569. seiw.fMask = pei->fMask;
  1570. seiw.hwnd = pei->hwnd;
  1571. seiw.nShow = pei->nShow;
  1572. if (_UseClassKey(pei->fMask))
  1573. seiw.hkeyClass = pei->hkeyClass;
  1574. if (pei->fMask & SEE_MASK_IDLIST)
  1575. seiw.lpIDList = pei->lpIDList;
  1576. if (pei->fMask & SEE_MASK_HOTKEY)
  1577. seiw.dwHotKey = pei->dwHotKey;
  1578. if (pei->fMask & SEE_MASK_ICON)
  1579. seiw.hIcon = pei->hIcon;
  1580. // Thunk the text fields as appropriate
  1581. ThunkText *pThunkText = ConvertStrings(6,
  1582. pei->lpVerb,
  1583. pei->lpFile,
  1584. pei->lpParameters,
  1585. pei->lpDirectory,
  1586. _ThunkClass(pei->fMask) ? pei->lpClass : NULL,
  1587. (pei->fMask & SEE_MASK_RESERVED) ? pei->hInstApp : NULL);
  1588. if (NULL == pThunkText)
  1589. {
  1590. pei->hInstApp = (HINSTANCE)SE_ERR_OOM;
  1591. return FALSE;
  1592. }
  1593. // Set our UNICODE text fields to point to the thunked strings
  1594. seiw.lpVerb = pThunkText->m_pStr[0];
  1595. seiw.lpFile = pThunkText->m_pStr[1];
  1596. seiw.lpParameters = pThunkText->m_pStr[2];
  1597. seiw.lpDirectory = pThunkText->m_pStr[3];
  1598. seiw.lpClass = pThunkText->m_pStr[4];
  1599. seiw.hInstApp = (HINSTANCE)pThunkText->m_pStr[5];
  1600. // If we are passed the SEE_MASK_FILEANDURL flag, this means that
  1601. // we have a lpFile parameter that has both the CacheFilename and the URL
  1602. // (seperated by a single NULL, eg. "CacheFileName\0UrlName). We therefore
  1603. // need to special case the thunking of pei->lpFile.
  1604. LPWSTR pwszFileAndUrl = NULL;
  1605. if (pei->fMask & SEE_MASK_FILEANDURL)
  1606. {
  1607. int iUrlLength;
  1608. int iCacheFileLength = lstrlenW(pThunkText->m_pStr[1]);
  1609. WCHAR wszURL[INTERNET_MAX_URL_LENGTH];
  1610. LPSTR pszUrlPart = (LPSTR)&pei->lpFile[iCacheFileLength + 1];
  1611. if (IsBadStringPtrA(pszUrlPart, INTERNET_MAX_URL_LENGTH) || !PathIsURLA(pszUrlPart))
  1612. {
  1613. ASSERT(FALSE);
  1614. }
  1615. else
  1616. {
  1617. // we have a vaild URL, so thunk it
  1618. iUrlLength = lstrlenA(pszUrlPart);
  1619. pwszFileAndUrl = (LPWSTR)LocalAlloc(LPTR, (iUrlLength + iCacheFileLength + 2) * sizeof(WCHAR));
  1620. if (!pwszFileAndUrl)
  1621. {
  1622. pei->hInstApp = (HINSTANCE)SE_ERR_OOM;
  1623. return FALSE;
  1624. }
  1625. SHAnsiToUnicode(pszUrlPart, wszURL, INTERNET_MAX_URL_LENGTH);
  1626. // construct the wide multi-string
  1627. lstrcpyW(pwszFileAndUrl, pThunkText->m_pStr[1]);
  1628. lstrcpyW(&pwszFileAndUrl[iCacheFileLength + 1], wszURL);
  1629. seiw.lpFile = pwszFileAndUrl;
  1630. }
  1631. }
  1632. // Call the real UNICODE ShellExecuteEx
  1633. BOOL fRet = ShellExecuteEx(&seiw);
  1634. pei->hInstApp = seiw.hInstApp;
  1635. if (pei->fMask & SEE_MASK_NOCLOSEPROCESS)
  1636. {
  1637. pei->hProcess = seiw.hProcess;
  1638. }
  1639. LocalFree(pThunkText);
  1640. if (pwszFileAndUrl)
  1641. LocalFree(pwszFileAndUrl);
  1642. return fRet;
  1643. }
  1644. // To display an error message appropriately, call this if ShellExecuteEx fails.
  1645. void _DisplayShellExecError(ULONG fMask, HWND hwnd, LPCTSTR pszFile, LPCTSTR pszTitle, DWORD dwErr)
  1646. {
  1647. if (!(fMask & SEE_MASK_FLAG_NO_UI))
  1648. {
  1649. if (dwErr != ERROR_CANCELLED)
  1650. {
  1651. LPCTSTR pszHeader;
  1652. UINT ids;
  1653. // don't display "user cancelled", the user knows that already
  1654. // make sure parent window is the foreground window
  1655. if (hwnd)
  1656. SetForegroundWindow(hwnd);
  1657. if (pszTitle)
  1658. pszHeader = pszTitle;
  1659. else
  1660. pszHeader = pszFile;
  1661. // Use our messages when we can -- they're more descriptive
  1662. switch (dwErr)
  1663. {
  1664. case 0:
  1665. case ERROR_NOT_ENOUGH_MEMORY:
  1666. case ERROR_OUTOFMEMORY:
  1667. ids = IDS_LowMemError;
  1668. break;
  1669. case ERROR_FILE_NOT_FOUND:
  1670. ids = IDS_RunFileNotFound;
  1671. break;
  1672. case ERROR_PATH_NOT_FOUND:
  1673. case ERROR_BAD_PATHNAME:
  1674. ids = IDS_PathNotFound;
  1675. break;
  1676. case ERROR_TOO_MANY_OPEN_FILES:
  1677. ids = IDS_TooManyOpenFiles;
  1678. break;
  1679. case ERROR_ACCESS_DENIED:
  1680. ids = IDS_RunAccessDenied;
  1681. break;
  1682. case ERROR_BAD_FORMAT:
  1683. // NB CreateProcess, when execing a Win16 apps maps just about all of
  1684. // these errors to BadFormat. Not very useful but there it is.
  1685. ids = IDS_BadFormat;
  1686. break;
  1687. case ERROR_SHARING_VIOLATION:
  1688. ids = IDS_ShareError;
  1689. break;
  1690. case ERROR_OLD_WIN_VERSION:
  1691. ids = IDS_OldWindowsVer;
  1692. break;
  1693. case ERROR_APP_WRONG_OS:
  1694. ids = IDS_OS2AppError;
  1695. break;
  1696. case ERROR_SINGLE_INSTANCE_APP:
  1697. ids = IDS_MultipleDS;
  1698. break;
  1699. case ERROR_RMODE_APP:
  1700. ids = IDS_RModeApp;
  1701. break;
  1702. case ERROR_INVALID_DLL:
  1703. ids = IDS_InvalidDLL;
  1704. break;
  1705. case ERROR_NO_ASSOCIATION:
  1706. ids = IDS_NoAssocError;
  1707. break;
  1708. case ERROR_DDE_FAIL:
  1709. ids = IDS_DDEFailError;
  1710. break;
  1711. case ERROR_BAD_NET_NAME:
  1712. case ERROR_SEM_TIMEOUT:
  1713. ids = IDS_REASONS_BADNETNAME;
  1714. break;
  1715. // LEGACY - ERROR_RESTRICTED_APP was never mapped to a valid error - ZekeL 2001-FEB-14
  1716. // because we always called _ShellExecuteError() before
  1717. // resetting the mask to ulOriginalMask, we never mapped
  1718. // ERROR_RESTRICTED_APP (which is -1) to a valid code
  1719. case ERROR_RESTRICTED_APP:
  1720. ids = IDS_RESTRICTIONS;
  1721. // restrictions like to use IDS_RESTRICTIONSTITLE
  1722. if (!pszTitle)
  1723. pszHeader = MAKEINTRESOURCE(IDS_RESTRICTIONSTITLE);
  1724. break;
  1725. // If we don't get a match, let the system handle it for us
  1726. default:
  1727. ids = 0;
  1728. SHSysErrorMessageBox(
  1729. hwnd,
  1730. pszHeader,
  1731. IDS_SHLEXEC_ERROR,
  1732. dwErr,
  1733. pszFile,
  1734. MB_OK | MB_ICONSTOP);
  1735. break;
  1736. }
  1737. if (ids)
  1738. {
  1739. ShellMessageBox(HINST_THISDLL, hwnd, MAKEINTRESOURCE(ids),
  1740. pszHeader, (ids == IDS_LowMemError)?
  1741. (MB_OK | MB_ICONSTOP | MB_SYSTEMMODAL):(MB_OK | MB_ICONSTOP),
  1742. pszFile);
  1743. }
  1744. }
  1745. }
  1746. SetLastError(dwErr); // The message box may have clobbered.
  1747. }
  1748. void _ShellExecuteError(LPSHELLEXECUTEINFO pei, LPCTSTR lpTitle, DWORD dwErr)
  1749. {
  1750. ASSERT(!ISSHELLEXECSUCCEEDED(pei->hInstApp));
  1751. // if dwErr not passed in, get it
  1752. if (dwErr == 0)
  1753. dwErr = GetLastError();
  1754. _DisplayShellExecError(pei->fMask, pei->hwnd, pei->lpFile, lpTitle, dwErr);
  1755. }
  1756. //----------------------------------------------------------------------------
  1757. // Given a file name and directory, get the path to the execuatable that
  1758. // would be exec'd if you tried to ShellExecute this thing.
  1759. HINSTANCE WINAPI FindExecutable(LPCTSTR lpFile, LPCTSTR lpDirectory, LPTSTR lpResult)
  1760. {
  1761. HINSTANCE hInstance = (HINSTANCE)42; // assume success must be > 32
  1762. TCHAR szOldDir[MAX_PATH];
  1763. TCHAR szFile[MAX_PATH];
  1764. LPCTSTR dirs[2];
  1765. // Progman relies on lpResult being a ptr to an null string on error.
  1766. *lpResult = TEXT('\0');
  1767. GetCurrentDirectory(ARRAYSIZE(szOldDir), szOldDir);
  1768. if (lpDirectory && *lpDirectory)
  1769. SetCurrentDirectory(lpDirectory);
  1770. else
  1771. lpDirectory = szOldDir; // needed for PathResolve()
  1772. if (!GetShortPathName(lpFile, szFile, ARRAYSIZE(szFile))) {
  1773. // if the lpFile is unqualified or bogus, let's use it down
  1774. // in PathResolve.
  1775. lstrcpyn(szFile, lpFile, ARRAYSIZE(szFile));
  1776. }
  1777. // get fully qualified path and add .exe extension if needed
  1778. dirs[0] = (LPTSTR)lpDirectory;
  1779. dirs[1] = NULL;
  1780. if (!PathResolve(szFile, dirs, PRF_VERIFYEXISTS | PRF_TRYPROGRAMEXTENSIONS | PRF_FIRSTDIRDEF))
  1781. {
  1782. // File doesn't exist, return file not found.
  1783. hInstance = (HINSTANCE)SE_ERR_FNF;
  1784. goto Exit;
  1785. }
  1786. TraceMsg(TF_SHELLEXEC, "FindExecutable: PathResolve -> %s", (LPCSTR)szFile);
  1787. if (PathIsExe(szFile))
  1788. {
  1789. lstrcpy(lpResult, szFile);
  1790. goto Exit;
  1791. }
  1792. if (SUCCEEDED(AssocQueryString(0, ASSOCSTR_EXECUTABLE, szFile, NULL, szFile, (LPDWORD)MAKEINTRESOURCE(SIZECHARS(szFile)))))
  1793. {
  1794. lstrcpy(lpResult, szFile);
  1795. }
  1796. else
  1797. {
  1798. hInstance = (HINSTANCE)SE_ERR_NOASSOC;
  1799. }
  1800. Exit:
  1801. TraceMsg(TF_SHELLEXEC, "FindExec(%s) ==> %s", (LPTSTR)lpFile, (LPTSTR)lpResult);
  1802. SetCurrentDirectory(szOldDir);
  1803. return hInstance;
  1804. }
  1805. HINSTANCE WINAPI FindExecutableA(LPCSTR lpFile, LPCSTR lpDirectory, LPSTR lpResult)
  1806. {
  1807. HINSTANCE hResult;
  1808. WCHAR wszResult[MAX_PATH];
  1809. ThunkText * pThunkText = ConvertStrings(2, lpFile, lpDirectory);
  1810. *lpResult = '\0';
  1811. if (NULL == pThunkText)
  1812. {
  1813. return (HINSTANCE)SE_ERR_OOM;
  1814. }
  1815. hResult = FindExecutableW(pThunkText->m_pStr[0], pThunkText->m_pStr[1], wszResult);
  1816. LocalFree(pThunkText);
  1817. // FindExecutableW terminates wszResult for us, so this is safe
  1818. // even if the above call fails
  1819. // Thunk the output result string back to ANSI. If the conversion fails,
  1820. // or if the default char is used, we fail the API call.
  1821. if (0 == WideCharToMultiByte(CP_ACP, 0, wszResult, -1, lpResult, MAX_PATH, NULL, NULL))
  1822. {
  1823. SetLastError((DWORD)E_FAIL);
  1824. return (HINSTANCE) SE_ERR_FNF;
  1825. }
  1826. return hResult;
  1827. }
  1828. //----------------------------------------------------------------------------
  1829. // Data structures for our wait for file open functions
  1830. //
  1831. typedef struct _WaitForItem * PWAITFORITEM;
  1832. typedef struct _WaitForItem
  1833. {
  1834. DWORD dwSize;
  1835. DWORD fOperation; // Operation to perform
  1836. PWAITFORITEM pwfiNext;
  1837. HANDLE hEvent; // Handle to event that was registered.
  1838. UINT iWaiting; // Number of clients that are waiting.
  1839. ITEMIDLIST idlItem; // pidl to wait for
  1840. } WAITFORITEM;
  1841. //
  1842. // This is the form of the structure that is shoved into the shared memory
  1843. // block. It must be the 32-bit version for interoperability reasons.
  1844. //
  1845. typedef struct _WaitForItem32
  1846. {
  1847. DWORD dwSize;
  1848. DWORD fOperation; // Operation to perform
  1849. DWORD NotUsed1;
  1850. LONG hEvent; // Truncated event handle
  1851. UINT NotUsed2;
  1852. ITEMIDLIST idlItem; // pidl to wait for
  1853. } WAITFORITEM32, *PWAITFORITEM32;
  1854. //
  1855. // These macros enforce type safety so people are forced to use the
  1856. // WAITFORITEM32 structure when accessing the shared memory block.
  1857. //
  1858. #define SHLockWaitForItem(h, pid) ((PWAITFORITEM32)SHLockShared(h, pid))
  1859. __inline void SHUnlockWaitForItem(PWAITFORITEM32 pwfi)
  1860. {
  1861. SHUnlockShared(pwfi);
  1862. }
  1863. PWAITFORITEM g_pwfiHead = NULL;
  1864. HANDLE SHWaitOp_OperateInternal(DWORD fOperation, LPCITEMIDLIST pidlItem)
  1865. {
  1866. PWAITFORITEM pwfi;
  1867. HANDLE hEvent = (HANDLE)NULL;
  1868. for (pwfi = g_pwfiHead; pwfi != NULL; pwfi = pwfi->pwfiNext)
  1869. {
  1870. if (ILIsEqual(&(pwfi->idlItem), pidlItem))
  1871. {
  1872. hEvent = pwfi->hEvent;
  1873. break;
  1874. }
  1875. }
  1876. if (fOperation & WFFO_ADD)
  1877. {
  1878. if (!pwfi)
  1879. {
  1880. UINT uSize;
  1881. UINT uSizeIDList = 0;
  1882. if (pidlItem)
  1883. uSizeIDList = ILGetSize(pidlItem);
  1884. uSize = sizeof(WAITFORITEM) + uSizeIDList;
  1885. // Create an event to wait for
  1886. hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  1887. if (hEvent)
  1888. pwfi = (PWAITFORITEM)SHAlloc(uSize);
  1889. if (pwfi)
  1890. {
  1891. pwfi->dwSize = uSize;
  1892. // pwfi->fOperation = 0; // Meaningless
  1893. pwfi->hEvent = hEvent;
  1894. pwfi->iWaiting = ((fOperation & WFFO_WAIT) != 0);
  1895. memcpy(&(pwfi->idlItem), pidlItem, uSizeIDList);
  1896. // now link it in
  1897. pwfi->pwfiNext = g_pwfiHead;
  1898. g_pwfiHead = pwfi;
  1899. }
  1900. }
  1901. }
  1902. if (pwfi)
  1903. {
  1904. if (fOperation & WFFO_WAIT)
  1905. pwfi->iWaiting++;
  1906. if (fOperation & WFFO_SIGNAL)
  1907. SetEvent(hEvent);
  1908. if (fOperation & WFFO_REMOVE)
  1909. pwfi->iWaiting--; // decrement in use count;
  1910. // Only check removal case if not adding
  1911. if ((fOperation & WFFO_ADD) == 0)
  1912. {
  1913. // Remove it if nobody waiting on it
  1914. if (pwfi->iWaiting == 0)
  1915. {
  1916. if (g_pwfiHead == pwfi)
  1917. g_pwfiHead = pwfi->pwfiNext;
  1918. else
  1919. {
  1920. PWAITFORITEM pwfiT = g_pwfiHead;
  1921. while ((pwfiT != NULL) && (pwfiT->pwfiNext != pwfi))
  1922. pwfiT = pwfiT->pwfiNext;
  1923. ASSERT(pwfiT != NULL);
  1924. if (pwfiT != NULL)
  1925. pwfiT->pwfiNext = pwfi->pwfiNext;
  1926. }
  1927. // Close the handle
  1928. CloseHandle(pwfi->hEvent);
  1929. // Free the memory
  1930. SHFree(pwfi);
  1931. hEvent = NULL; // NULL indicates nobody waiting... (for remove case)
  1932. }
  1933. }
  1934. }
  1935. return hEvent;
  1936. }
  1937. void SHWaitOp_Operate(HANDLE hWait, DWORD dwProcId)
  1938. {
  1939. PWAITFORITEM32 pwfiFind = SHLockWaitForItem(hWait, dwProcId);
  1940. if (pwfiFind)
  1941. {
  1942. pwfiFind->hEvent = HandleToLong(SHWaitOp_OperateInternal(pwfiFind->fOperation, &(pwfiFind->idlItem)));
  1943. SHUnlockWaitForItem(pwfiFind);
  1944. }
  1945. }
  1946. HANDLE SHWaitOp_Create(DWORD fOperation, LPCITEMIDLIST pidlItem, DWORD dwProcId)
  1947. {
  1948. UINT uSizeIDList = pidlItem ? ILGetSize(pidlItem) : 0;
  1949. UINT uSize = sizeof(WAITFORITEM32) + uSizeIDList;
  1950. HANDLE hWaitOp = SHAllocShared(NULL, uSize, dwProcId);
  1951. if (hWaitOp)
  1952. {
  1953. PWAITFORITEM32 pwfi = SHLockWaitForItem(hWaitOp,dwProcId);
  1954. if (pwfi)
  1955. {
  1956. pwfi->dwSize = uSize;
  1957. pwfi->fOperation = fOperation;
  1958. pwfi->NotUsed1 = 0;
  1959. pwfi->hEvent = HandleToLong((HANDLE)NULL);
  1960. pwfi->NotUsed2 = 0;
  1961. if (pidlItem)
  1962. memcpy(&(pwfi->idlItem), pidlItem, uSizeIDList);
  1963. SHUnlockWaitForItem(pwfi);
  1964. }
  1965. else
  1966. {
  1967. // clean up
  1968. SHFreeShared(hWaitOp, dwProcId);
  1969. hWaitOp = NULL;
  1970. }
  1971. }
  1972. return hWaitOp;
  1973. }
  1974. // This function allows the cabinet to wait for a
  1975. // file (in particular folders) to signal us that they are in an open state.
  1976. // This should take care of several synchronazation problems with the shell
  1977. // not knowing when a folder is in the process of being opened or not
  1978. //
  1979. STDAPI_(DWORD) SHWaitForFileToOpen(LPCITEMIDLIST pidl, UINT uOptions, DWORD dwTimeout)
  1980. {
  1981. HWND hwndShell;
  1982. HANDLE hWaitOp;
  1983. HANDLE hEvent = NULL;
  1984. DWORD dwProcIdSrc = GetCurrentProcessId();
  1985. DWORD dwReturn = WAIT_OBJECT_0; // we need a default
  1986. hwndShell = GetShellWindow();
  1987. if ((uOptions & (WFFO_WAIT | WFFO_ADD)) != 0)
  1988. {
  1989. if (hwndShell)
  1990. {
  1991. DWORD dwProcIdDst;
  1992. GetWindowThreadProcessId(hwndShell, &dwProcIdDst);
  1993. // Do just the add and/or wait portions
  1994. hWaitOp = SHWaitOp_Create(uOptions & (WFFO_WAIT | WFFO_ADD), pidl, dwProcIdSrc);
  1995. if (hWaitOp)
  1996. {
  1997. SendMessage(hwndShell, CWM_WAITOP, (WPARAM)hWaitOp, (LPARAM)dwProcIdSrc);
  1998. // Now get the hEvent and convert to a local handle
  1999. PWAITFORITEM32 pwfi = SHLockWaitForItem(hWaitOp, dwProcIdSrc);
  2000. if (pwfi)
  2001. {
  2002. hEvent = SHMapHandle(LongToHandle(pwfi->hEvent),dwProcIdDst, dwProcIdSrc, EVENT_ALL_ACCESS, 0);
  2003. SHUnlockWaitForItem(pwfi);
  2004. }
  2005. SHFreeShared(hWaitOp,dwProcIdSrc);
  2006. }
  2007. }
  2008. else
  2009. {
  2010. // Do just the add and/or wait portions
  2011. hEvent = SHWaitOp_OperateInternal(uOptions & (WFFO_WAIT | WFFO_ADD), pidl);
  2012. }
  2013. if (hEvent)
  2014. {
  2015. if (uOptions & WFFO_WAIT)
  2016. dwReturn = SHProcessMessagesUntilEvent(NULL, hEvent, dwTimeout);
  2017. if (hwndShell) // Close the duplicated handle.
  2018. CloseHandle(hEvent);
  2019. }
  2020. }
  2021. if (uOptions & WFFO_REMOVE)
  2022. {
  2023. if (hwndShell)
  2024. {
  2025. hWaitOp = SHWaitOp_Create(WFFO_REMOVE, pidl, dwProcIdSrc);
  2026. if (hWaitOp)
  2027. {
  2028. SendMessage(hwndShell, CWM_WAITOP, (WPARAM)hWaitOp, (LPARAM)dwProcIdSrc);
  2029. SHFreeShared(hWaitOp,dwProcIdSrc);
  2030. }
  2031. }
  2032. else
  2033. {
  2034. SHWaitOp_OperateInternal(WFFO_REMOVE, pidl);
  2035. }
  2036. }
  2037. return dwReturn;
  2038. }
  2039. // Signals that the file is open
  2040. //
  2041. STDAPI_(BOOL) SignalFileOpen(LPCITEMIDLIST pidl)
  2042. {
  2043. BOOL fResult = FALSE;
  2044. HWND hwndShell = GetShellWindow();
  2045. if (hwndShell)
  2046. {
  2047. PWAITFORITEM32 pwfi;
  2048. DWORD dwProcId = GetCurrentProcessId();
  2049. HANDLE hWaitOp = SHWaitOp_Create(WFFO_SIGNAL, pidl, dwProcId);
  2050. if (hWaitOp)
  2051. {
  2052. SendMessage(hwndShell, CWM_WAITOP, (WPARAM)hWaitOp, (LPARAM)dwProcId);
  2053. // Now get the hEvent to determine return value...
  2054. pwfi = SHLockWaitForItem(hWaitOp, dwProcId);
  2055. if (pwfi)
  2056. {
  2057. fResult = (LongToHandle(pwfi->hEvent) != (HANDLE)NULL);
  2058. SHUnlockWaitForItem(pwfi);
  2059. }
  2060. SHFreeShared(hWaitOp,dwProcId);
  2061. }
  2062. }
  2063. else
  2064. {
  2065. fResult = (SHWaitOp_OperateInternal(WFFO_SIGNAL, pidl) == (HANDLE)NULL);
  2066. }
  2067. // Let everyone know that we opened something
  2068. UINT uMsg = RegisterWindowMessage(SH_FILEOPENED);
  2069. BroadcastSystemMessage(BSF_POSTMESSAGE, BSM_ALLCOMPONENTS, uMsg, NULL, NULL);
  2070. return fResult;
  2071. }
  2072. //
  2073. // Checks to see if darwin is enabled.
  2074. //
  2075. BOOL IsDarwinEnabled()
  2076. {
  2077. static BOOL s_fDarwinEnabled = TRUE;
  2078. static BOOL s_fInit = FALSE;
  2079. if (!s_fInit)
  2080. {
  2081. HKEY hkeyPolicy = 0;
  2082. if (RegOpenKey(HKEY_CURRENT_USER, REGSTR_PATH_POLICIES_EXPLORER, &hkeyPolicy) == ERROR_SUCCESS)
  2083. {
  2084. if (SHQueryValueEx(hkeyPolicy, TEXT("DisableMSI"), NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
  2085. {
  2086. s_fDarwinEnabled = FALSE; // policy turns MSI off
  2087. }
  2088. RegCloseKey(hkeyPolicy);
  2089. }
  2090. s_fInit = TRUE;
  2091. }
  2092. return s_fDarwinEnabled;
  2093. }
  2094. // takes the darwin ID string from the registry, and calls darwin to get the
  2095. // full path to the application.
  2096. //
  2097. // IN: pszDarwinDescriptor - this has the contents of the darwin key read out of the registry.
  2098. // it should contain a string like "[Darwin-ID-for-App] /switches".
  2099. //
  2100. // OUT: pszDarwinComand - the full path to the application to this buffer w/ switches.
  2101. //
  2102. STDAPI ParseDarwinID(LPTSTR pszDarwinDescriptor, LPTSTR pszDarwinCommand, DWORD cchDarwinCommand)
  2103. {
  2104. DWORD dwError = CommandLineFromMsiDescriptor(pszDarwinDescriptor, pszDarwinCommand, &cchDarwinCommand);
  2105. return HRESULT_FROM_WIN32(dwError);
  2106. }