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.

2062 lines
48 KiB

  1. /*
  2. * urlprop.cpp - Implementation for URLProp class.
  3. */
  4. #include "priv.h"
  5. #include "ishcut.h"
  6. STDAPI_(LPITEMIDLIST) IEILCreate(UINT cbSize);
  7. #define MAX_BUF_INT (1 + 10 + 1) // -2147483647
  8. const TCHAR c_szIntshcut[] = ISHCUT_INISTRING_SECTION;
  9. #ifdef DEBUG
  10. BOOL IsValidPCURLProp(PCURLProp pcurlprop)
  11. {
  12. return (IS_VALID_READ_PTR(pcurlprop, CURLProp) &&
  13. (NULL == pcurlprop->m_hstg ||
  14. IS_VALID_HANDLE(pcurlprop->m_hstg, PROPSTG)));
  15. }
  16. BOOL IsValidPCIntshcutProp(PCIntshcutProp pcisprop)
  17. {
  18. return (IS_VALID_READ_PTR(pcisprop, CIntshcutProp) &&
  19. IS_VALID_STRUCT_PTR(pcisprop, CURLProp));
  20. }
  21. BOOL IsValidPCIntsiteProp(PCIntsiteProp pcisprop)
  22. {
  23. return (IS_VALID_READ_PTR(pcisprop, CIntsiteProp) &&
  24. IS_VALID_STRUCT_PTR(pcisprop, CURLProp));
  25. }
  26. #endif
  27. BOOL AnyMeatW(LPCWSTR pcsz)
  28. {
  29. ASSERT(! pcsz || IS_VALID_STRING_PTRW(pcsz, -1));
  30. return(pcsz ? StrSpnW(pcsz, L" \t") < lstrlenW(pcsz) : FALSE);
  31. }
  32. BOOL AnyMeatA(LPCSTR pcsz)
  33. {
  34. ASSERT(! pcsz || IS_VALID_STRING_PTRA(pcsz, -1));
  35. return(pcsz ? StrSpnA(pcsz, " \t") < lstrlenA(pcsz) : FALSE);
  36. }
  37. /*----------------------------------------------------------
  38. Purpose: Read an arbitrary named string from the .ini file.
  39. Returns: S_OK if the name exists
  40. S_FALSE if it doesn't
  41. E_OUTOFMEMORY
  42. */
  43. HRESULT ReadStringFromFile(IN LPCTSTR pszFile,
  44. IN LPCTSTR pszSectionName,
  45. IN LPCTSTR pszName,
  46. OUT LPWSTR * ppwsz,
  47. IN CHAR * pszBuf)
  48. {
  49. HRESULT hres = E_OUTOFMEMORY;
  50. ASSERT(IS_VALID_STRING_PTR(pszFile, -1));
  51. ASSERT(IS_VALID_STRING_PTR(pszName, -1));
  52. ASSERT(IS_VALID_WRITE_PTR(ppwsz, PWSTR));
  53. *ppwsz = (LPWSTR)LocalAlloc(LPTR, SIZEOF(WCHAR) * INTERNET_MAX_URL_LENGTH);
  54. if (*ppwsz)
  55. {
  56. DWORD cch;
  57. hres = S_OK;
  58. cch = SHGetIniString(pszSectionName, pszName,
  59. *ppwsz, INTERNET_MAX_URL_LENGTH, pszFile);
  60. if (0 == cch)
  61. {
  62. hres = S_FALSE;
  63. LocalFree(*ppwsz);
  64. *ppwsz = NULL;
  65. }
  66. }
  67. return hres;
  68. }
  69. /*----------------------------------------------------------
  70. Purpose: Read an arbitrary named string from the .ini file.
  71. Return a BSTR
  72. Returns: S_OK if the name exists
  73. S_FALSE if it doesn't
  74. E_OUTOFMEMORY
  75. */
  76. HRESULT ReadBStrFromFile(IN LPCTSTR pszFile,
  77. IN LPCTSTR pszSectionName,
  78. IN LPCTSTR pszName,
  79. OUT BSTR * pBStr)
  80. {
  81. CHAR szTempBuf[INTERNET_MAX_URL_LENGTH];
  82. WCHAR *pwsz;
  83. HRESULT hres = E_OUTOFMEMORY;
  84. *pBStr = NULL;
  85. ASSERT(IS_VALID_STRING_PTR(pszFile, -1));
  86. ASSERT(IS_VALID_STRING_PTR(pszName, -1));
  87. ASSERT(IS_VALID_WRITE_PTR(pBStr, PWSTR));
  88. // (Pass in an empty string so we can determine from the return
  89. // value whether there is any text associated with this name.)
  90. hres = ReadStringFromFile(pszFile, pszSectionName, pszName, &pwsz, szTempBuf);
  91. if (S_OK == hres)
  92. {
  93. *pBStr = SysAllocString(pwsz);
  94. LocalFree(pwsz);
  95. pwsz = NULL;
  96. }
  97. return hres;
  98. }
  99. /*----------------------------------------------------------
  100. Purpose: read an arbitrary named unsigend int from the .ini file. note in order to implement
  101. ReadSignedFromFile one'll need to use ReadStringFromFile and then StrToIntEx. this is
  102. because GetPrivateProfileInt can't return a negative.
  103. Returns: S_OK if the name exists
  104. S_FALSE if it doesn't
  105. E_OUTOFMEMORY
  106. */
  107. HRESULT
  108. ReadUnsignedFromFile(
  109. IN LPCTSTR pszFile,
  110. IN LPCTSTR pszSectionName,
  111. IN LPCTSTR pszName,
  112. IN LPDWORD pdwVal)
  113. {
  114. HRESULT hr;
  115. int iValue;
  116. ASSERT(IS_VALID_STRING_PTR(pszFile, -1));
  117. ASSERT(IS_VALID_STRING_PTR(pszSectionName, -1));
  118. ASSERT(IS_VALID_STRING_PTR(pszName, -1));
  119. if (NULL == pdwVal)
  120. return E_INVALIDARG;
  121. *pdwVal = 0;
  122. hr = S_OK;
  123. iValue = GetPrivateProfileInt(pszSectionName, pszName, 1, pszFile);
  124. if (1 == iValue) {
  125. iValue = GetPrivateProfileInt(pszSectionName, pszName, 2, pszFile);
  126. hr = (2 != iValue) ? S_OK : S_FALSE;
  127. ASSERT(S_FALSE == hr || 1 == iValue);
  128. }
  129. if (S_OK == hr)
  130. *pdwVal = (DWORD)iValue;
  131. return hr;
  132. }
  133. /*----------------------------------------------------------
  134. Purpose: Write number to URL (ini) file
  135. */
  136. HRESULT WriteSignedToFile(IN LPCTSTR pszFile,
  137. IN LPCTSTR pszSectionName,
  138. IN LPCTSTR pszName,
  139. IN int nVal)
  140. {
  141. HRESULT hres;
  142. TCHAR szVal[MAX_BUF_INT];
  143. int cch;
  144. ASSERT(IS_VALID_STRING_PTR(pszFile, -1));
  145. ASSERT(IS_VALID_STRING_PTR(pszName, -1));
  146. cch = wnsprintf(szVal, ARRAYSIZE(szVal), TEXT("%d"), nVal);
  147. ASSERT(cch > 0);
  148. ASSERT(cch < SIZECHARS(szVal));
  149. ASSERT(cch == lstrlen(szVal));
  150. hres = WritePrivateProfileString(pszSectionName, pszName, szVal,
  151. pszFile) ? S_OK : E_FAIL;
  152. return hres;
  153. }
  154. /*----------------------------------------------------------
  155. Purpose: Write number to URL (ini) file
  156. */
  157. HRESULT WriteUnsignedToFile(IN LPCTSTR pszFile,
  158. IN LPCTSTR pszSectionName,
  159. IN LPCTSTR pszName,
  160. IN DWORD nVal)
  161. {
  162. HRESULT hres;
  163. TCHAR szVal[MAX_BUF_INT];
  164. int cch;
  165. ASSERT(IS_VALID_STRING_PTR(pszFile, -1));
  166. ASSERT(IS_VALID_STRING_PTR(pszName, -1));
  167. cch = wnsprintf(szVal, ARRAYSIZE(szVal), TEXT("%u"), nVal);
  168. ASSERT(cch > 0);
  169. ASSERT(cch < SIZECHARS(szVal));
  170. ASSERT(cch == lstrlen(szVal));
  171. hres = WritePrivateProfileString(pszSectionName, pszName, szVal,
  172. pszFile) ? S_OK : E_FAIL;
  173. return hres;
  174. }
  175. /*----------------------------------------------------------
  176. Purpose: Write binary data to URL (ini) file
  177. */
  178. HRESULT WriteBinaryToFile(IN LPCTSTR pszFile,
  179. IN LPCTSTR pszSectionName,
  180. IN LPCTSTR pszName,
  181. IN LPVOID pvData,
  182. IN DWORD cbSize)
  183. {
  184. HRESULT hres;
  185. ASSERT(IS_VALID_STRING_PTR(pszFile, -1));
  186. ASSERT(IS_VALID_STRING_PTR(pszName, -1));
  187. hres = (WritePrivateProfileStruct(pszSectionName, pszName, pvData, cbSize, pszFile))
  188. ? S_OK : E_FAIL;
  189. return hres;
  190. }
  191. /*----------------------------------------------------------
  192. Purpose: Read the hotkey from the URL (ini) file
  193. */
  194. HRESULT ReadBinaryFromFile(IN LPCTSTR pszFile,
  195. IN LPCTSTR pszSectionName,
  196. IN LPCTSTR pszName,
  197. IN LPVOID pvData,
  198. IN DWORD cbData)
  199. {
  200. HRESULT hres = S_FALSE;
  201. ASSERT(IS_VALID_STRING_PTR(pszFile, -1));
  202. memset(pvData, 0, cbData);
  203. if (GetPrivateProfileStruct(pszSectionName, pszName, pvData, cbData, pszFile))
  204. hres = S_OK;
  205. return hres;
  206. }
  207. /*----------------------------------------------------------
  208. Purpose: Real the URL from the URL (ini) file
  209. */
  210. HRESULT
  211. ReadURLFromFile(
  212. IN LPCTSTR pszFile,
  213. IN LPCTSTR pszSectionName,
  214. OUT LPTSTR * ppsz)
  215. {
  216. HRESULT hres = E_OUTOFMEMORY;
  217. *ppsz = (LPTSTR)LocalAlloc(LPTR, SIZEOF(TCHAR) * INTERNET_MAX_URL_LENGTH);
  218. if (*ppsz)
  219. {
  220. DWORD cch;
  221. cch = SHGetIniString(pszSectionName, ISHCUT_INISTRING_URL,
  222. *ppsz, INTERNET_MAX_URL_LENGTH, pszFile);
  223. if (0 != cch)
  224. {
  225. PathRemoveBlanks(*ppsz);
  226. hres = S_OK;
  227. }
  228. else
  229. {
  230. LocalFree(*ppsz);
  231. *ppsz = NULL;
  232. hres = S_FALSE;
  233. }
  234. }
  235. return hres;
  236. }
  237. /*----------------------------------------------------------
  238. Purpose: Read the icon location from the URL (ini) file
  239. Returns: S_OK value was obtained from file
  240. S_FALSE value wasn't in file
  241. E_OUTOFMEMORY
  242. */
  243. HRESULT
  244. ReadIconLocation(
  245. IN LPCTSTR pszFile,
  246. OUT LPWSTR * ppwsz,
  247. OUT int * pniIcon,
  248. IN CHAR * pszBuf)
  249. {
  250. HRESULT hres = E_OUTOFMEMORY;
  251. DWORD cch;
  252. ASSERT(IS_VALID_STRING_PTR(pszFile, -1));
  253. ASSERT(IS_VALID_WRITE_PTR(ppwsz, PTSTR));
  254. ASSERT(IS_VALID_WRITE_PTR(pniIcon, INT));
  255. *ppwsz = NULL;
  256. *pniIcon = 0;
  257. *ppwsz = (LPWSTR)LocalAlloc(LPTR, SIZEOF(WCHAR) * MAX_PATH);
  258. if (*ppwsz)
  259. {
  260. hres = S_FALSE; // assume no value exists in the file
  261. cch = SHGetIniString(c_szIntshcut,
  262. ISHCUT_INISTRING_ICONFILE, *ppwsz,
  263. MAX_PATH, pszFile);
  264. if (0 != cch)
  265. {
  266. TCHAR szIndex[MAX_BUF_INT];
  267. // The icon index is all ASCII so don't need SHGetIniString
  268. cch = GetPrivateProfileString(c_szIntshcut,
  269. ISHCUT_INISTRING_ICONINDEX, c_szNULL,
  270. szIndex, SIZECHARS(szIndex),
  271. pszFile);
  272. if (0 != cch)
  273. {
  274. if (StrToIntEx(szIndex, 0, pniIcon))
  275. hres = S_OK;
  276. }
  277. }
  278. if (S_OK != hres)
  279. {
  280. LocalFree(*ppwsz);
  281. *ppwsz = NULL;
  282. }
  283. }
  284. return hres;
  285. }
  286. /*----------------------------------------------------------
  287. Purpose: Write icon location to URL (ini) file
  288. */
  289. HRESULT
  290. WriteIconFile(
  291. IN LPCTSTR pszFile,
  292. IN LPCWSTR pszIconFile)
  293. {
  294. HRESULT hres = S_OK;
  295. ASSERT(IS_VALID_STRING_PTR(pszFile, -1));
  296. ASSERT(! pszIconFile ||
  297. IS_VALID_STRING_PTRW(pszIconFile, -1));
  298. if (*pszFile)
  299. {
  300. if (AnyMeatW(pszIconFile))
  301. {
  302. hres = SHSetIniString(c_szIntshcut, ISHCUT_INISTRING_ICONFILE, pszIconFile,
  303. pszFile) ? S_OK : E_FAIL;
  304. }
  305. else
  306. {
  307. // NOTE: since this function removes both the file and the index
  308. // values, then this function must be called *after* any call
  309. // to WriteIconIndex. One way to do this is make sure
  310. // PID_IS_ICONINDEX < PID_IS_ICONFILE, since the index will
  311. // be enumerated first.
  312. hres = (SHDeleteIniString(c_szIntshcut, ISHCUT_INISTRING_ICONFILE,
  313. pszFile) &&
  314. DeletePrivateProfileString(c_szIntshcut, ISHCUT_INISTRING_ICONINDEX,
  315. pszFile))
  316. ? S_OK : E_FAIL;
  317. }
  318. }
  319. return hres;
  320. }
  321. /*----------------------------------------------------------
  322. Purpose: Write icon index to URL (ini) file
  323. */
  324. HRESULT
  325. WriteIconIndex(
  326. IN LPCTSTR pszFile,
  327. IN int niIcon)
  328. {
  329. HRESULT hres;
  330. if (*pszFile)
  331. hres = WriteSignedToFile(pszFile, c_szIntshcut, ISHCUT_INISTRING_ICONINDEX, niIcon);
  332. else
  333. hres = S_FALSE;
  334. return hres;
  335. }
  336. /*----------------------------------------------------------
  337. Purpose: Read the hotkey from the URL (ini) file
  338. */
  339. HRESULT
  340. ReadHotkey(
  341. IN LPCTSTR pszFile,
  342. IN WORD * pwHotkey)
  343. {
  344. HRESULT hres = S_FALSE;
  345. TCHAR szHotkey[MAX_BUF_INT];
  346. DWORD cch;
  347. ASSERT(IS_VALID_STRING_PTR(pszFile, -1));
  348. ASSERT(IS_VALID_WRITE_PTR(pwHotkey, WORD));
  349. *pwHotkey = 0;
  350. cch = GetPrivateProfileString(c_szIntshcut,
  351. TEXT("Hotkey"), c_szNULL,
  352. szHotkey, SIZECHARS(szHotkey),
  353. pszFile);
  354. if (0 != cch)
  355. {
  356. int nVal;
  357. if (StrToIntEx(szHotkey, 0, &nVal))
  358. {
  359. *pwHotkey = nVal;
  360. hres = S_OK;
  361. }
  362. }
  363. return hres;
  364. }
  365. /*----------------------------------------------------------
  366. Purpose: Write hotkey to URL (ini) file
  367. */
  368. HRESULT
  369. WriteHotkey(
  370. IN LPCTSTR pszFile,
  371. IN WORD wHotkey)
  372. {
  373. HRESULT hres = S_FALSE;
  374. ASSERT(IS_VALID_STRING_PTR(pszFile, -1));
  375. if (*pszFile)
  376. {
  377. if (wHotkey)
  378. {
  379. hres = WriteUnsignedToFile(pszFile, c_szIntshcut, TEXT("Hotkey"), wHotkey);
  380. }
  381. else
  382. {
  383. hres = DeletePrivateProfileString(c_szIntshcut, TEXT("Hotkey"), pszFile)
  384. ? S_OK
  385. : E_FAIL;
  386. }
  387. }
  388. return hres;
  389. }
  390. /*----------------------------------------------------------
  391. Purpose: Read the working directory from the URL (ini) file
  392. */
  393. HRESULT
  394. ReadWorkingDirectory(
  395. IN LPCTSTR pszFile,
  396. OUT LPWSTR * ppwsz)
  397. {
  398. HRESULT hres = E_OUTOFMEMORY;
  399. TCHAR szPath[MAX_PATH];
  400. DWORD cch;
  401. ASSERT(IS_VALID_STRING_PTR(pszFile, -1));
  402. ASSERT(IS_VALID_WRITE_PTR(ppwsz, PWSTR));
  403. *ppwsz = NULL;
  404. *ppwsz = (LPWSTR)LocalAlloc(LPTR, SIZEOF(WCHAR) * MAX_PATH);
  405. if (*ppwsz)
  406. {
  407. hres = S_FALSE;
  408. cch = SHGetIniString(c_szIntshcut,
  409. ISHCUT_INISTRING_WORKINGDIR,
  410. szPath, SIZECHARS(szPath), pszFile);
  411. if (0 != cch)
  412. {
  413. TCHAR szFullPath[MAX_PATH];
  414. PTSTR pszFileName;
  415. if (0 < GetFullPathName(szPath, SIZECHARS(szFullPath), szFullPath,
  416. &pszFileName))
  417. {
  418. SHTCharToUnicode(szFullPath, *ppwsz, MAX_PATH);
  419. hres = S_OK;
  420. }
  421. }
  422. if (S_OK != hres)
  423. {
  424. LocalFree(*ppwsz);
  425. *ppwsz = NULL;
  426. }
  427. }
  428. return hres;
  429. }
  430. /*----------------------------------------------------------
  431. Purpose: Write the working directory to the URL (ini) file.
  432. */
  433. HRESULT
  434. WriteGenericString(
  435. IN LPCTSTR pszFile,
  436. IN LPCTSTR pszSectionName,
  437. IN LPCTSTR pszName,
  438. IN LPCWSTR pwsz) OPTIONAL
  439. {
  440. HRESULT hres = S_FALSE;
  441. ASSERT(IS_VALID_STRING_PTR(pszFile, -1));
  442. ASSERT(IS_VALID_STRING_PTR(pszName, -1));
  443. ASSERT(! pwsz || IS_VALID_STRING_PTRW(pwsz, -1));
  444. if (*pszFile)
  445. {
  446. if (AnyMeatW(pwsz))
  447. {
  448. hres = (SHSetIniString(pszSectionName, pszName, pwsz,
  449. pszFile)) ? S_OK : E_FAIL;
  450. }
  451. else
  452. {
  453. hres = (SHDeleteIniString(pszSectionName, pszName, pszFile))
  454. ? S_OK : E_FAIL;
  455. }
  456. }
  457. return hres;
  458. }
  459. /*----------------------------------------------------------
  460. Purpose: Read the show-command flag from the URL (ini) file
  461. */
  462. HRESULT
  463. ReadShowCmd(
  464. IN LPCTSTR pszFile,
  465. OUT PINT pnShowCmd)
  466. {
  467. HRESULT hres = S_FALSE;
  468. TCHAR szT[MAX_BUF_INT];
  469. DWORD cch;
  470. ASSERT(IS_VALID_STRING_PTR(pszFile, -1));
  471. ASSERT(IS_VALID_WRITE_PTR(pnShowCmd, INT));
  472. *pnShowCmd = SW_NORMAL;
  473. cch = GetPrivateProfileString(c_szIntshcut,
  474. TEXT("ShowCommand"), c_szNULL, szT,
  475. SIZECHARS(szT), pszFile);
  476. if (0 != cch)
  477. {
  478. if (StrToIntEx(szT, 0, pnShowCmd))
  479. {
  480. hres = S_OK;
  481. }
  482. }
  483. return hres;
  484. }
  485. /*----------------------------------------------------------
  486. Purpose: Write showcmd to URL (ini) file
  487. */
  488. HRESULT
  489. WriteShowCmd(
  490. IN LPCTSTR pszFile,
  491. IN int nShowCmd)
  492. {
  493. HRESULT hres = S_FALSE;
  494. ASSERT(IS_VALID_STRING_PTR(pszFile, -1));
  495. if (*pszFile)
  496. {
  497. if (SW_NORMAL != nShowCmd)
  498. {
  499. hres = WriteSignedToFile(pszFile, c_szIntshcut, TEXT("ShowCommand"), nShowCmd);
  500. }
  501. else
  502. {
  503. hres = DeletePrivateProfileString(c_szIntshcut, TEXT("ShowCommand"), pszFile)
  504. ? S_OK
  505. : E_FAIL;
  506. }
  507. }
  508. return hres;
  509. }
  510. /*----------------------------------------------------------
  511. Purpose: Read the IDList from the URL (ini) file
  512. */
  513. HRESULT
  514. ReadIDList(
  515. IN LPCTSTR pszFile,
  516. OUT LPITEMIDLIST *ppidl)
  517. {
  518. HRESULT hres = S_FALSE;
  519. ULONG cb;
  520. ASSERT(ppidl);
  521. // Delete the old one if any.
  522. if (*ppidl)
  523. {
  524. ILFree(*ppidl);
  525. *ppidl = NULL;
  526. }
  527. // Read the size of the IDLIST
  528. cb = GetPrivateProfileInt(c_szIntshcut, TEXT("ILSize"), 0, pszFile);
  529. if (cb)
  530. {
  531. // Create a IDLIST
  532. LPITEMIDLIST pidl = IEILCreate(cb);
  533. if (pidl)
  534. {
  535. // Read its contents
  536. if (GetPrivateProfileStruct(c_szIntshcut, TEXT("IDList"), (LPVOID)pidl, cb, pszFile))
  537. {
  538. *ppidl = pidl;
  539. hres = S_OK;
  540. }
  541. else
  542. {
  543. ILFree(pidl);
  544. hres = E_FAIL;
  545. }
  546. }
  547. else
  548. {
  549. hres = E_OUTOFMEMORY;
  550. }
  551. }
  552. return hres;
  553. }
  554. HRESULT
  555. WriteStream(
  556. IN LPCTSTR pszFile,
  557. IN IStream *pStream,
  558. IN LPCTSTR pszStreamName,
  559. IN LPCTSTR pszSizeName)
  560. {
  561. HRESULT hr = E_FAIL;
  562. ULARGE_INTEGER li = {0};
  563. if(pStream)
  564. IStream_Size(pStream, &li);
  565. if (li.LowPart)
  566. {
  567. ASSERT(!li.HighPart);
  568. LPVOID pv = LocalAlloc(LPTR, li.LowPart);
  569. if (pv && SUCCEEDED(hr = IStream_Read(pStream, pv, li.LowPart)))
  570. {
  571. // we have loaded the data properly, time to write it out
  572. if (SUCCEEDED(hr = WriteUnsignedToFile(pszFile, c_szIntshcut, pszSizeName, li.LowPart)))
  573. hr = WriteBinaryToFile(pszFile, c_szIntshcut, pszStreamName, pv, li.LowPart);
  574. }
  575. if (pv)
  576. {
  577. LocalFree(pv);
  578. pv = NULL;
  579. }
  580. }
  581. else
  582. {
  583. // delete the keys if
  584. // 1. pStream is NULL, or
  585. // 2. pStream in empty (cbPidl == 0).
  586. if (DeletePrivateProfileString(c_szIntshcut, pszSizeName, pszFile) &&
  587. DeletePrivateProfileString(c_szIntshcut, pszStreamName, pszFile))
  588. {
  589. hr = S_OK;
  590. }
  591. }
  592. return hr;
  593. }
  594. /*----------------------------------------------------------
  595. Purpose: Write IDList to URL (ini) file
  596. */
  597. HRESULT
  598. WriteIDList(
  599. IN LPCTSTR pszFile,
  600. IN IStream *pStream)
  601. {
  602. return WriteStream(pszFile, pStream, TEXT("IDList"), TEXT("ILSize"));
  603. }
  604. /********************************** Methods **********************************/
  605. //==========================================================================================
  606. // URLProp class implementation
  607. //==========================================================================================
  608. #ifdef DEBUG
  609. /*----------------------------------------------------------
  610. Purpose: Dump the properties in this object
  611. */
  612. STDMETHODIMP_(void) URLProp::Dump(void)
  613. {
  614. if (IsFlagSet(g_dwDumpFlags, DF_URLPROP))
  615. {
  616. PropStg_Dump(m_hstg, 0);
  617. }
  618. }
  619. #endif
  620. /*----------------------------------------------------------
  621. Purpose: Constructor for URLProp
  622. */
  623. URLProp::URLProp(void) : m_cRef(1)
  624. {
  625. // Don't validate this until after construction.
  626. m_hstg = NULL;
  627. ASSERT(IS_VALID_STRUCT_PTR(this, CURLProp));
  628. return;
  629. }
  630. /*----------------------------------------------------------
  631. Purpose: Destructor for URLProp
  632. */
  633. URLProp::~URLProp(void)
  634. {
  635. ASSERT(IS_VALID_STRUCT_PTR(this, CURLProp));
  636. if (m_hstg)
  637. {
  638. PropStg_Destroy(m_hstg);
  639. m_hstg = NULL;
  640. }
  641. ASSERT(IS_VALID_STRUCT_PTR(this, CURLProp));
  642. return;
  643. }
  644. STDMETHODIMP_(ULONG) URLProp::AddRef()
  645. {
  646. return ++m_cRef;
  647. }
  648. STDMETHODIMP_(ULONG) URLProp::Release()
  649. {
  650. m_cRef--;
  651. if (m_cRef > 0)
  652. return m_cRef;
  653. delete this;
  654. return 0;
  655. }
  656. /*----------------------------------------------------------
  657. Purpose: IUnknown::QueryInterface method for URLProp
  658. */
  659. STDMETHODIMP URLProp::QueryInterface(REFIID riid, void **ppvObj)
  660. {
  661. if (IsEqualIID(riid, IID_IUnknown) ||
  662. IsEqualIID(riid, IID_IPropertyStorage))
  663. {
  664. *ppvObj = SAFECAST(this, IPropertyStorage *);
  665. }
  666. else
  667. {
  668. *ppvObj = NULL;
  669. return E_NOINTERFACE;
  670. }
  671. AddRef();
  672. return NOERROR;
  673. }
  674. /*----------------------------------------------------------
  675. Purpose: Initialize the object
  676. Returns: S_OK
  677. E_OUTOFMEMORY
  678. */
  679. STDMETHODIMP URLProp::Init(void)
  680. {
  681. HRESULT hres = S_OK;
  682. // Don't stomp on ourselves if this has already been initialized
  683. if (NULL == m_hstg)
  684. {
  685. hres = PropStg_Create(&m_hstg, PSTGF_DEFAULT);
  686. }
  687. return hres;
  688. }
  689. /*----------------------------------------------------------
  690. Purpose: Helper function that retrieves the string property
  691. */
  692. STDMETHODIMP
  693. URLProp::GetProp(
  694. IN PROPID pid,
  695. IN LPTSTR pszBuf,
  696. IN int cchBuf)
  697. {
  698. HRESULT hres;
  699. PROPSPEC propspec;
  700. PROPVARIANT propvar;
  701. ASSERT(pszBuf);
  702. propspec.ulKind = PRSPEC_PROPID;
  703. propspec.propid = pid;
  704. *pszBuf = TEXT('\0');
  705. hres = ReadMultiple(1, &propspec, &propvar);
  706. if (SUCCEEDED(hres))
  707. {
  708. if (VT_LPWSTR == propvar.vt)
  709. {
  710. SHUnicodeToTChar(propvar.pwszVal, pszBuf, cchBuf);
  711. hres = S_OK;
  712. }
  713. else
  714. {
  715. if (VT_EMPTY != propvar.vt && VT_ILLEGAL != propvar.vt)
  716. TraceMsg(TF_WARNING, "URLProp::GetProp: expected propid %#lx to be VT_LPWSTR, but is %s", pid, Dbg_GetVTName(propvar.vt));
  717. hres = S_FALSE;
  718. }
  719. PropVariantClear(&propvar);
  720. }
  721. return hres;
  722. }
  723. /*----------------------------------------------------------
  724. Purpose: Helper function that retrieves the word property
  725. */
  726. STDMETHODIMP
  727. URLProp::GetProp(
  728. IN PROPID pid,
  729. IN int * piVal)
  730. {
  731. HRESULT hres;
  732. PROPSPEC propspec;
  733. PROPVARIANT propvar;
  734. ASSERT(piVal);
  735. propspec.ulKind = PRSPEC_PROPID;
  736. propspec.propid = pid;
  737. *piVal = 0;
  738. hres = ReadMultiple(1, &propspec, &propvar);
  739. if (SUCCEEDED(hres))
  740. {
  741. if (VT_I4 == propvar.vt)
  742. {
  743. *piVal = propvar.lVal;
  744. hres = S_OK;
  745. }
  746. else
  747. {
  748. if (VT_EMPTY != propvar.vt && VT_ILLEGAL != propvar.vt)
  749. TraceMsg(TF_WARNING, "URLProp::GetProp: expected propid %#lx to be VT_I4, but is %s", pid, Dbg_GetVTName(propvar.vt));
  750. hres = S_FALSE;
  751. }
  752. PropVariantClear(&propvar);
  753. }
  754. return hres;
  755. }
  756. /*----------------------------------------------------------
  757. Purpose: Helper function that retrieves the word property
  758. */
  759. STDMETHODIMP
  760. URLProp::GetProp(
  761. IN PROPID pid,
  762. IN LPDWORD pdwVal)
  763. {
  764. HRESULT hres;
  765. PROPSPEC propspec;
  766. PROPVARIANT propvar;
  767. ASSERT(pdwVal);
  768. propspec.ulKind = PRSPEC_PROPID;
  769. propspec.propid = pid;
  770. *pdwVal = 0;
  771. hres = ReadMultiple(1, &propspec, &propvar);
  772. if (SUCCEEDED(hres))
  773. {
  774. if (VT_UI4 == propvar.vt)
  775. {
  776. *pdwVal = propvar.ulVal;
  777. hres = S_OK;
  778. }
  779. else
  780. {
  781. if (VT_EMPTY != propvar.vt && VT_ILLEGAL != propvar.vt)
  782. TraceMsg(TF_WARNING, "URLProp::GetProp: expected propid %#lx to be VT_UI4, but is %s", pid, Dbg_GetVTName(propvar.vt));
  783. hres = S_FALSE;
  784. }
  785. PropVariantClear(&propvar);
  786. }
  787. return hres;
  788. }
  789. /*----------------------------------------------------------
  790. Purpose: Helper function that retrieves the word property
  791. */
  792. STDMETHODIMP
  793. URLProp::GetProp(
  794. IN PROPID pid,
  795. IN WORD * pwVal)
  796. {
  797. HRESULT hres;
  798. PROPSPEC propspec;
  799. PROPVARIANT propvar;
  800. ASSERT(pwVal);
  801. propspec.ulKind = PRSPEC_PROPID;
  802. propspec.propid = pid;
  803. *pwVal = 0;
  804. hres = ReadMultiple(1, &propspec, &propvar);
  805. if (SUCCEEDED(hres))
  806. {
  807. if (VT_UI2 == propvar.vt)
  808. {
  809. *pwVal = propvar.uiVal;
  810. hres = S_OK;
  811. }
  812. else
  813. {
  814. if (VT_EMPTY != propvar.vt && VT_ILLEGAL != propvar.vt)
  815. TraceMsg(TF_WARNING, "URLProp::GetProp: expected propid %#lx to be VT_UI2, but is %s", pid, Dbg_GetVTName(propvar.vt));
  816. hres = S_FALSE;
  817. }
  818. PropVariantClear(&propvar);
  819. }
  820. return hres;
  821. }
  822. /*----------------------------------------------------------
  823. Purpose: Helper function that retrieves the IStream property
  824. */
  825. STDMETHODIMP
  826. URLProp::GetProp(
  827. IN PROPID pid,
  828. IN IStream **ppStream)
  829. {
  830. HRESULT hres;
  831. PROPSPEC propspec;
  832. PROPVARIANT propvar;
  833. ASSERT(ppStream);
  834. propspec.ulKind = PRSPEC_PROPID;
  835. propspec.propid = pid;
  836. *ppStream = 0;
  837. hres = ReadMultiple(1, &propspec, &propvar);
  838. if (SUCCEEDED(hres))
  839. {
  840. if (VT_STREAM == propvar.vt)
  841. {
  842. *ppStream = propvar.pStream;
  843. hres = S_OK;
  844. }
  845. else
  846. {
  847. if (VT_EMPTY != propvar.vt && VT_ILLEGAL != propvar.vt && propvar.lVal != 0)
  848. TraceMsg(TF_WARNING, "URLProp::GetProp: expected propid %#lx to be VT_STREAM, but is %s", pid, Dbg_GetVTName(propvar.vt));
  849. hres = S_FALSE;
  850. }
  851. // Do not PropVariantClear(&propvar), because it will call pStream->Release().
  852. }
  853. return hres;
  854. }
  855. /*----------------------------------------------------------
  856. Purpose: Helper function that sets the string property
  857. */
  858. STDMETHODIMP
  859. URLProp::SetProp(
  860. IN PROPID pid,
  861. IN LPCTSTR psz) OPTIONAL
  862. {
  863. HRESULT hres;
  864. PROPSPEC propspec;
  865. PROPVARIANT propvar;
  866. // WARNING:: this function gets called as part of ShellExecute which can be
  867. // called by 16 bit apps so don't put mondo strings on stack...
  868. WCHAR *pwsz = NULL;
  869. propspec.ulKind = PRSPEC_PROPID;
  870. propspec.propid = pid;
  871. if (psz && *psz)
  872. {
  873. SHStrDup(psz, &pwsz);
  874. propvar.vt = VT_LPWSTR;
  875. propvar.pwszVal = pwsz;
  876. }
  877. else
  878. propvar.vt = VT_EMPTY;
  879. hres = WriteMultiple(1, &propspec, &propvar, 0);
  880. if (pwsz)
  881. CoTaskMemFree(pwsz);
  882. return hres;
  883. }
  884. /*----------------------------------------------------------
  885. Purpose: Helper function that sets the int property
  886. */
  887. STDMETHODIMP
  888. URLProp::SetProp(
  889. IN PROPID pid,
  890. IN int iVal)
  891. {
  892. PROPSPEC propspec;
  893. PROPVARIANT propvar;
  894. propspec.ulKind = PRSPEC_PROPID;
  895. propspec.propid = pid;
  896. propvar.vt = VT_I4;
  897. propvar.lVal = iVal;
  898. return WriteMultiple(1, &propspec, &propvar, 0);
  899. }
  900. /*----------------------------------------------------------
  901. Purpose: Helper function that sets the dword property
  902. */
  903. STDMETHODIMP
  904. URLProp::SetProp(
  905. IN PROPID pid,
  906. IN DWORD dwVal)
  907. {
  908. HRESULT hres;
  909. PROPSPEC propspec;
  910. PROPVARIANT propvar;
  911. propspec.ulKind = PRSPEC_PROPID;
  912. propspec.propid = pid;
  913. propvar.vt = VT_UI4;
  914. propvar.ulVal = dwVal;
  915. hres = WriteMultiple(1, &propspec, &propvar, 0);
  916. return hres;
  917. }
  918. /*----------------------------------------------------------
  919. Purpose: Helper function that sets the word property
  920. */
  921. STDMETHODIMP
  922. URLProp::SetProp(
  923. IN PROPID pid,
  924. IN WORD wVal)
  925. {
  926. HRESULT hres;
  927. PROPSPEC propspec;
  928. PROPVARIANT propvar;
  929. propspec.ulKind = PRSPEC_PROPID;
  930. propspec.propid = pid;
  931. propvar.vt = VT_UI2;
  932. propvar.uiVal = wVal;
  933. hres = WriteMultiple(1, &propspec, &propvar, 0);
  934. return hres;
  935. }
  936. /*----------------------------------------------------------
  937. Purpose: Helper function that sets the IStream* property
  938. */
  939. STDMETHODIMP
  940. URLProp::SetProp(
  941. IN PROPID pid,
  942. IN IStream *pStream)
  943. {
  944. HRESULT hres;
  945. PROPSPEC propspec;
  946. PROPVARIANT propvar;
  947. propspec.ulKind = PRSPEC_PROPID;
  948. propspec.propid = pid;
  949. propvar.vt = VT_STREAM;
  950. propvar.pStream = pStream;
  951. hres = WriteMultiple(1, &propspec, &propvar, 0);
  952. return hres;
  953. }
  954. STDMETHODIMP URLProp::IsDirty(void)
  955. {
  956. return PropStg_IsDirty(m_hstg);
  957. }
  958. STDMETHODIMP URLProp::ReadMultiple(IN ULONG cpspec,
  959. IN const PROPSPEC rgpropspec[],
  960. IN PROPVARIANT rgpropvar[])
  961. {
  962. HRESULT hres = PropStg_ReadMultiple(m_hstg, cpspec, rgpropspec, rgpropvar);
  963. if (SUCCEEDED(hres))
  964. {
  965. // Set the accessed time
  966. SYSTEMTIME st;
  967. GetSystemTime(&st);
  968. SystemTimeToFileTime(&st, &m_ftAccessed);
  969. }
  970. return hres;
  971. }
  972. STDMETHODIMP URLProp::WriteMultiple(IN ULONG cpspec,
  973. IN const PROPSPEC rgpropspec[],
  974. IN const PROPVARIANT rgpropvar[],
  975. IN PROPID propidFirst)
  976. {
  977. HRESULT hres = PropStg_WriteMultiple(m_hstg, cpspec, rgpropspec,
  978. rgpropvar, propidFirst);
  979. if (SUCCEEDED(hres))
  980. {
  981. // Set the modified time
  982. SYSTEMTIME st;
  983. GetSystemTime(&st);
  984. SystemTimeToFileTime(&st, &m_ftModified);
  985. }
  986. return hres;
  987. }
  988. STDMETHODIMP URLProp::DeleteMultiple(ULONG cpspec, const PROPSPEC rgpropspec[])
  989. {
  990. return PropStg_DeleteMultiple(m_hstg, cpspec, rgpropspec);
  991. }
  992. STDMETHODIMP URLProp::ReadPropertyNames(ULONG cpropid, const PROPID rgpropid[], LPWSTR rgpwszName[])
  993. {
  994. return E_NOTIMPL;
  995. }
  996. STDMETHODIMP URLProp::WritePropertyNames(ULONG cpropid, const PROPID rgpropid[], const LPWSTR rgpwszName[])
  997. {
  998. return E_NOTIMPL;
  999. }
  1000. /*----------------------------------------------------------
  1001. Purpose: IPropertyStorage::DeletePropertyNames method for URLProp
  1002. */
  1003. STDMETHODIMP
  1004. URLProp::DeletePropertyNames(
  1005. IN ULONG cpropid,
  1006. IN const PROPID rgpropid[])
  1007. {
  1008. return E_NOTIMPL;
  1009. }
  1010. /*----------------------------------------------------------
  1011. Purpose: IPropertyStorage::SetClass method for URLProp
  1012. */
  1013. STDMETHODIMP
  1014. URLProp::SetClass(
  1015. IN REFCLSID rclsid)
  1016. {
  1017. CopyMemory(&m_clsid, &rclsid, SIZEOF(m_clsid));
  1018. return S_OK;
  1019. }
  1020. /*----------------------------------------------------------
  1021. Purpose: IPropertyStorage::Commit method for URLProp
  1022. */
  1023. STDMETHODIMP
  1024. URLProp::Commit(
  1025. IN DWORD dwFlags)
  1026. {
  1027. return E_NOTIMPL;
  1028. }
  1029. /*----------------------------------------------------------
  1030. Purpose: IPropertyStorage::Revert method for URLProp
  1031. */
  1032. STDMETHODIMP URLProp::Revert(void)
  1033. {
  1034. #ifdef DEBUG
  1035. Dump();
  1036. #endif
  1037. return E_NOTIMPL;
  1038. }
  1039. /*----------------------------------------------------------
  1040. Purpose: IPropertyStorage::Enum method for URLProp
  1041. */
  1042. STDMETHODIMP URLProp::Enum(IEnumSTATPROPSTG ** ppenum)
  1043. {
  1044. *ppenum = NULL;
  1045. return E_NOTIMPL;
  1046. }
  1047. /*----------------------------------------------------------
  1048. Purpose: IPropertyStorage::Stat method for URLProp
  1049. */
  1050. STDMETHODIMP
  1051. URLProp::Stat(
  1052. IN STATPROPSETSTG * pstat)
  1053. {
  1054. HRESULT hres = STG_E_INVALIDPARAMETER;
  1055. if (IS_VALID_WRITE_PTR(pstat, STATPROPSETSTG))
  1056. {
  1057. pstat->fmtid = m_fmtid;
  1058. pstat->clsid = m_clsid;
  1059. pstat->grfFlags = m_grfFlags;
  1060. pstat->mtime = m_ftModified;
  1061. pstat->ctime = m_ftCreated;
  1062. pstat->atime = m_ftAccessed;
  1063. hres = S_OK;
  1064. }
  1065. return hres;
  1066. }
  1067. /*----------------------------------------------------------
  1068. Purpose: IPropertyStorage::SetTimes method for URLProp
  1069. */
  1070. STDMETHODIMP
  1071. URLProp::SetTimes(
  1072. IN const FILETIME * pftModified, OPTIONAL
  1073. IN const FILETIME * pftCreated, OPTIONAL
  1074. IN const FILETIME * pftAccessed) OPTIONAL
  1075. {
  1076. HRESULT hres;
  1077. if (pftModified && !IS_VALID_READ_PTR(pftModified, FILETIME) ||
  1078. pftCreated && !IS_VALID_READ_PTR(pftCreated, FILETIME) ||
  1079. pftAccessed && !IS_VALID_READ_PTR(pftAccessed, FILETIME))
  1080. {
  1081. hres = STG_E_INVALIDPARAMETER;
  1082. }
  1083. else
  1084. {
  1085. if (pftModified)
  1086. m_ftModified = *pftModified;
  1087. if (pftCreated)
  1088. m_ftCreated = *pftCreated;
  1089. if (pftAccessed)
  1090. m_ftAccessed = *pftAccessed;
  1091. hres = S_OK;
  1092. }
  1093. return hres;
  1094. }
  1095. #ifdef DEBUG
  1096. STDMETHODIMP_(void) IntshcutProp::Dump(void)
  1097. {
  1098. if (IsFlagSet(g_dwDumpFlags, DF_URLPROP))
  1099. {
  1100. TraceMsg(TF_ALWAYS, " IntshcutProp obj: %s", m_szFile);
  1101. URLProp::Dump();
  1102. }
  1103. }
  1104. #endif
  1105. IntshcutProp::IntshcutProp(void)
  1106. {
  1107. // Don't validate this until after construction.
  1108. *m_szFile = 0;
  1109. ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcutProp));
  1110. }
  1111. IntshcutProp::~IntshcutProp(void)
  1112. {
  1113. ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcutProp));
  1114. ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcutProp));
  1115. }
  1116. // (These are not related to PID_IS_*)
  1117. #define IPROP_ICONINDEX 0
  1118. #define IPROP_ICONFILE 1
  1119. #define IPROP_HOTKEY 2
  1120. #define IPROP_WORKINGDIR 3
  1121. #define IPROP_SHOWCMD 4
  1122. #define IPROP_WHATSNEW 5
  1123. #define IPROP_AUTHOR 6
  1124. #define IPROP_DESC 7
  1125. #define IPROP_COMMENT 8
  1126. #define IPROP_URL 9 // these two must be the last
  1127. #define IPROP_SCHEME 10 // in this list. See LoadFromFile.
  1128. #define CPROP_INTSHCUT 11 // Count of properties
  1129. // (we don't write the URL or the scheme in the massive write sweep)
  1130. #define CPROP_INTSHCUT_WRITE (CPROP_INTSHCUT - 2)
  1131. /*----------------------------------------------------------
  1132. Purpose: Load the basic property info like URL.
  1133. Returns:
  1134. Cond: --
  1135. */
  1136. STDMETHODIMP IntshcutProp::LoadFromFile(LPCTSTR pszFile)
  1137. {
  1138. HRESULT hres;
  1139. LPWSTR pwszBuf;
  1140. LPTSTR pszBuf;
  1141. CHAR *pszTempBuf;
  1142. static const PROPSPEC rgpropspec[CPROP_INTSHCUT] =
  1143. {
  1144. // This must be initialized in the same order as how the
  1145. // IPROP_* values were defined.
  1146. { PRSPEC_PROPID, PID_IS_ICONINDEX },
  1147. { PRSPEC_PROPID, PID_IS_ICONFILE },
  1148. { PRSPEC_PROPID, PID_IS_HOTKEY },
  1149. { PRSPEC_PROPID, PID_IS_WORKINGDIR },
  1150. { PRSPEC_PROPID, PID_IS_SHOWCMD },
  1151. { PRSPEC_PROPID, PID_IS_WHATSNEW },
  1152. { PRSPEC_PROPID, PID_IS_AUTHOR },
  1153. { PRSPEC_PROPID, PID_IS_DESCRIPTION },
  1154. { PRSPEC_PROPID, PID_IS_COMMENT },
  1155. { PRSPEC_PROPID, PID_IS_URL },
  1156. { PRSPEC_PROPID, PID_IS_SCHEME },
  1157. };
  1158. PROPVARIANT rgpropvar[CPROP_INTSHCUT] = { 0 };
  1159. ASSERT(pszFile);
  1160. // try to allocate a temporary buffer, don't put on stack as this may be called
  1161. // by 16 bit apps through the shellexecute thunk
  1162. pszTempBuf = (CHAR*)LocalAlloc(LMEM_FIXED, INTERNET_MAX_URL_LENGTH * sizeof(CHAR));
  1163. if (!pszTempBuf)
  1164. return E_OUTOFMEMORY;
  1165. if (!g_fRunningOnNT)
  1166. {
  1167. // Flush the cache first to encourage Win95 kernel to zero-out
  1168. // its buffer. Kernel GP-faults with hundreds of writes made to
  1169. // ini files.
  1170. WritePrivateProfileString(NULL, NULL, NULL, pszFile);
  1171. }
  1172. // Get the URL
  1173. hres = ReadURLFromFile(pszFile, c_szIntshcut, &pszBuf);
  1174. if (S_OK == hres)
  1175. {
  1176. // Call this method because it does more work before
  1177. // setting the property
  1178. SetURLProp(pszBuf, (IURL_SETURL_FL_GUESS_PROTOCOL | IURL_SETURL_FL_USE_DEFAULT_PROTOCOL));
  1179. LocalFree(pszBuf);
  1180. pszBuf = NULL;
  1181. }
  1182. // Get the IDList
  1183. LPITEMIDLIST pidl = NULL;
  1184. hres = ReadIDList(pszFile, &pidl);
  1185. if (S_OK == hres)
  1186. {
  1187. // Call this method because it does more work before
  1188. // setting the property
  1189. SetIDListProp(pidl);
  1190. ILFree(pidl);
  1191. }
  1192. #ifndef UNIX
  1193. // Get icon location
  1194. int nVal;
  1195. hres = ReadIconLocation(pszFile, &pwszBuf, &nVal, pszTempBuf);
  1196. if (S_OK == hres)
  1197. {
  1198. rgpropvar[IPROP_ICONFILE].vt = VT_LPWSTR;
  1199. rgpropvar[IPROP_ICONFILE].pwszVal = pwszBuf;
  1200. rgpropvar[IPROP_ICONINDEX].vt = VT_I4;
  1201. rgpropvar[IPROP_ICONINDEX].lVal = nVal;
  1202. }
  1203. // Get the hotkey
  1204. WORD wHotkey;
  1205. hres = ReadHotkey(pszFile, &wHotkey);
  1206. if (S_OK == hres)
  1207. {
  1208. rgpropvar[IPROP_HOTKEY].vt = VT_UI2;
  1209. rgpropvar[IPROP_HOTKEY].uiVal = wHotkey;
  1210. }
  1211. // Get the working directory
  1212. hres = ReadWorkingDirectory(pszFile, &pwszBuf);
  1213. if (S_OK == hres)
  1214. {
  1215. rgpropvar[IPROP_WORKINGDIR].vt = VT_LPWSTR;
  1216. rgpropvar[IPROP_WORKINGDIR].pwszVal = pwszBuf;
  1217. }
  1218. // Get the showcmd flag
  1219. hres = ReadShowCmd(pszFile, &nVal);
  1220. rgpropvar[IPROP_SHOWCMD].vt = VT_I4;
  1221. if (S_OK == hres)
  1222. rgpropvar[IPROP_SHOWCMD].lVal = nVal;
  1223. else
  1224. rgpropvar[IPROP_SHOWCMD].lVal = SW_NORMAL;
  1225. // Get the What's New bulletin
  1226. hres = ReadStringFromFile(pszFile, c_szIntshcut, ISHCUT_INISTRING_WHATSNEW, &pwszBuf, pszTempBuf);
  1227. if (S_OK == hres)
  1228. {
  1229. rgpropvar[IPROP_WHATSNEW].vt = VT_LPWSTR;
  1230. rgpropvar[IPROP_WHATSNEW].pwszVal = pwszBuf;
  1231. }
  1232. // Get the Author
  1233. hres = ReadStringFromFile(pszFile, c_szIntshcut, ISHCUT_INISTRING_AUTHOR, &pwszBuf, pszTempBuf);
  1234. if (S_OK == hres)
  1235. {
  1236. rgpropvar[IPROP_AUTHOR].vt = VT_LPWSTR;
  1237. rgpropvar[IPROP_AUTHOR].pwszVal = pwszBuf;
  1238. }
  1239. // Get the Description
  1240. hres = ReadStringFromFile(pszFile, c_szIntshcut, ISHCUT_INISTRING_DESC, &pwszBuf, pszTempBuf);
  1241. if (S_OK == hres)
  1242. {
  1243. rgpropvar[IPROP_DESC].vt = VT_LPWSTR;
  1244. rgpropvar[IPROP_DESC].pwszVal = pwszBuf;
  1245. }
  1246. // Get the Comment
  1247. hres = ReadStringFromFile(pszFile, c_szIntshcut, ISHCUT_INISTRING_COMMENT, &pwszBuf, pszTempBuf);
  1248. if (S_OK == hres)
  1249. {
  1250. rgpropvar[IPROP_COMMENT].vt = VT_LPWSTR;
  1251. rgpropvar[IPROP_COMMENT].pwszVal = pwszBuf;
  1252. }
  1253. #endif /* !UNIX */
  1254. // Write it all out to our in-memory storage. Note we're using
  1255. // CPROP_INTSHCUT_WRITE, which should be the size of the array minus the
  1256. // url and scheme propids, since they were written separately
  1257. // above.
  1258. hres = WriteMultiple(CPROP_INTSHCUT_WRITE, (PROPSPEC *)rgpropspec, rgpropvar, 0);
  1259. if (SUCCEEDED(hres))
  1260. {
  1261. // Unmark *all* these properties, since we're initializing from
  1262. // the file
  1263. PropStg_DirtyMultiple(m_hstg, ARRAYSIZE(rgpropspec), rgpropspec, FALSE);
  1264. }
  1265. // Get the times. We don't support the Accessed time for internet
  1266. // shortcuts updating this field would cause the shortcut to be
  1267. // constantly written to disk to record the Accessed time simply
  1268. // when a property is read. A huge perf hit!
  1269. ZeroMemory(&m_ftAccessed, sizeof(m_ftAccessed));
  1270. DWORD cbData = SIZEOF(m_ftModified);
  1271. ReadBinaryFromFile(pszFile, c_szIntshcut, ISHCUT_INISTRING_MODIFIED, &m_ftModified, cbData);
  1272. // Free up the buffers that we allocated
  1273. int cprops;
  1274. PROPVARIANT * ppropvar;
  1275. for (cprops = ARRAYSIZE(rgpropvar), ppropvar = rgpropvar; 0 < cprops; cprops--)
  1276. {
  1277. if (VT_LPWSTR == ppropvar->vt)
  1278. {
  1279. ASSERT(ppropvar->pwszVal);
  1280. LocalFree(ppropvar->pwszVal);
  1281. ppropvar->pwszVal = NULL;
  1282. }
  1283. ppropvar++;
  1284. }
  1285. LocalFree((HLOCAL)pszTempBuf);
  1286. pszTempBuf = NULL;
  1287. return hres;
  1288. }
  1289. STDMETHODIMP IntshcutProp::Init(void)
  1290. {
  1291. return URLProp::Init();
  1292. }
  1293. STDMETHODIMP IntshcutProp::InitFromFile(LPCTSTR pszFile)
  1294. {
  1295. // Initialize the in-memory property storage from the file
  1296. // and database
  1297. HRESULT hres = Init();
  1298. if (SUCCEEDED(hres) && pszFile)
  1299. {
  1300. StrCpyN(m_szFile, pszFile, SIZECHARS(m_szFile));
  1301. hres = LoadFromFile(m_szFile);
  1302. }
  1303. else
  1304. m_szFile[0] = 0;
  1305. return hres;
  1306. }
  1307. typedef struct
  1308. {
  1309. LPTSTR pszFile;
  1310. } COMMITISDATA;
  1311. /*----------------------------------------------------------
  1312. Purpose: Commit the values for any known properties to the file
  1313. Note this callback is called only for dirty values.
  1314. Returns: S_OK if alright
  1315. S_FALSE to skip this value
  1316. error to stop
  1317. */
  1318. STDAPI CommitISProp(
  1319. IN PROPID propid,
  1320. IN PROPVARIANT * ppropvar,
  1321. IN LPARAM lParam)
  1322. {
  1323. HRESULT hres = S_OK;
  1324. COMMITISDATA * pcd = (COMMITISDATA *)lParam;
  1325. ASSERT(ppropvar);
  1326. ASSERT(pcd);
  1327. LPWSTR pwsz;
  1328. USHORT uiVal;
  1329. LONG lVal;
  1330. IStream *pStream;
  1331. switch (propid)
  1332. {
  1333. case PID_IS_URL:
  1334. case PID_IS_ICONFILE:
  1335. case PID_IS_WORKINGDIR:
  1336. case PID_IS_WHATSNEW:
  1337. case PID_IS_AUTHOR:
  1338. case PID_IS_DESCRIPTION:
  1339. case PID_IS_COMMENT:
  1340. if (VT_LPWSTR == ppropvar->vt)
  1341. pwsz = ppropvar->pwszVal;
  1342. else
  1343. pwsz = NULL;
  1344. switch (propid)
  1345. {
  1346. case PID_IS_URL:
  1347. hres = WriteGenericString(pcd->pszFile, c_szIntshcut, ISHCUT_INISTRING_URL, pwsz);
  1348. break;
  1349. case PID_IS_ICONFILE:
  1350. hres = WriteIconFile(pcd->pszFile, pwsz);
  1351. break;
  1352. case PID_IS_WORKINGDIR:
  1353. hres = WriteGenericString(pcd->pszFile, c_szIntshcut, ISHCUT_INISTRING_WORKINGDIR, pwsz);
  1354. break;
  1355. case PID_IS_WHATSNEW:
  1356. hres = WriteGenericString(pcd->pszFile, c_szIntshcut, ISHCUT_INISTRING_WHATSNEW, pwsz);
  1357. break;
  1358. case PID_IS_AUTHOR:
  1359. hres = WriteGenericString(pcd->pszFile, c_szIntshcut, ISHCUT_INISTRING_AUTHOR, pwsz);
  1360. break;
  1361. case PID_IS_DESCRIPTION:
  1362. hres = WriteGenericString(pcd->pszFile, c_szIntshcut, ISHCUT_INISTRING_DESC, pwsz);
  1363. break;
  1364. case PID_IS_COMMENT:
  1365. hres = WriteGenericString(pcd->pszFile, c_szIntshcut, ISHCUT_INISTRING_COMMENT, pwsz);
  1366. break;
  1367. default:
  1368. ASSERT(0); // should never get here
  1369. break;
  1370. }
  1371. break;
  1372. case PID_IS_ICONINDEX:
  1373. if (VT_I4 == ppropvar->vt)
  1374. hres = WriteIconIndex(pcd->pszFile, ppropvar->lVal);
  1375. break;
  1376. case PID_IS_HOTKEY:
  1377. if (VT_UI2 == ppropvar->vt)
  1378. uiVal = ppropvar->uiVal;
  1379. else
  1380. uiVal = 0;
  1381. hres = WriteHotkey(pcd->pszFile, uiVal);
  1382. break;
  1383. case PID_IS_SHOWCMD:
  1384. if (VT_I4 == ppropvar->vt)
  1385. lVal = ppropvar->lVal;
  1386. else
  1387. lVal = SW_NORMAL;
  1388. hres = WriteShowCmd(pcd->pszFile, lVal);
  1389. break;
  1390. case PID_IS_SCHEME:
  1391. // Don't write this one out
  1392. break;
  1393. case PID_IS_IDLIST:
  1394. if (VT_STREAM == ppropvar->vt)
  1395. pStream = ppropvar->pStream;
  1396. else
  1397. pStream = NULL;
  1398. hres = WriteIDList(pcd->pszFile, pStream);
  1399. break;
  1400. default:
  1401. TraceMsg(TF_WARNING, "Don't know how to commit url property (%#lx)", propid);
  1402. ASSERT(0);
  1403. break;
  1404. }
  1405. #ifdef DEBUG
  1406. if (FAILED(hres))
  1407. TraceMsg(TF_WARNING, "Failed to save url property (%#lx) to file %s", propid, pcd->pszFile);
  1408. #endif
  1409. return hres;
  1410. }
  1411. /*----------------------------------------------------------
  1412. Purpose: IPropertyStorage::Commit method for URLProp
  1413. */
  1414. STDMETHODIMP
  1415. IntshcutProp::Commit(
  1416. IN DWORD dwFlags)
  1417. {
  1418. HRESULT hres;
  1419. COMMITISDATA cd;
  1420. TraceMsg(TF_INTSHCUT, "Writing properties to \"%s\"", m_szFile);
  1421. cd.pszFile = m_szFile;
  1422. // Enumerate thru the dirty property values that get saved to the
  1423. // file
  1424. hres = PropStg_Enum(m_hstg, PSTGEF_DIRTY, CommitISProp, (LPARAM)&cd);
  1425. if (SUCCEEDED(hres))
  1426. {
  1427. // Now mark everything clean
  1428. PropStg_DirtyAll(m_hstg, FALSE);
  1429. // Save the times. Don't write out the Accessed time for perf.
  1430. // See LoadFromFile.
  1431. EVAL(SUCCEEDED(WriteBinaryToFile(m_szFile, c_szIntshcut, ISHCUT_INISTRING_MODIFIED, &m_ftModified,
  1432. SIZEOF(m_ftModified))));
  1433. }
  1434. #ifdef DEBUG
  1435. Dump();
  1436. #endif
  1437. return hres;
  1438. }
  1439. /*----------------------------------------------------------
  1440. Purpose: Helper function to set the file name.
  1441. */
  1442. STDMETHODIMP
  1443. IntshcutProp::SetFileName(
  1444. IN LPCTSTR pszFile)
  1445. {
  1446. if(pszFile)
  1447. {
  1448. ASSERT(IS_VALID_STRING_PTR(pszFile, -1));
  1449. StrCpyN(m_szFile, pszFile, SIZECHARS(m_szFile));
  1450. }
  1451. else
  1452. {
  1453. *m_szFile = TEXT('\0');;
  1454. }
  1455. return S_OK;
  1456. }
  1457. /*----------------------------------------------------------
  1458. Purpose: Helper function that sets the URL.
  1459. */
  1460. STDMETHODIMP
  1461. IntshcutProp::SetIDListProp(
  1462. LPCITEMIDLIST pcidl)
  1463. {
  1464. HRESULT hres;
  1465. IStream *pstmPidl;
  1466. if (pcidl)
  1467. {
  1468. // ???
  1469. // PERF: This loads OLE. Is this OK?
  1470. hres = CreateStreamOnHGlobal(NULL, TRUE, &pstmPidl);
  1471. if (SUCCEEDED(hres))
  1472. {
  1473. hres = ILSaveToStream(pstmPidl, pcidl);
  1474. if (SUCCEEDED(hres))
  1475. hres = SetProp(PID_IS_IDLIST, pstmPidl);
  1476. pstmPidl->Release();
  1477. }
  1478. }
  1479. else
  1480. {
  1481. hres = SetProp(PID_IS_IDLIST, NULL);
  1482. }
  1483. return hres;
  1484. }
  1485. /*----------------------------------------------------------
  1486. Purpose: Helper function that sets the URL. This function
  1487. optionally canonicalizes the string as well.
  1488. */
  1489. STDMETHODIMP
  1490. IntshcutProp::SetURLProp(
  1491. IN LPCTSTR pszURL, OPTIONAL
  1492. IN DWORD dwFlags)
  1493. {
  1494. HRESULT hres;
  1495. // Warning this function can be called as part of shellexecute which can be
  1496. // thunked up to by a 16 bit app, so be carefull what you put on stack...
  1497. BOOL bChanged;
  1498. struct tbufs
  1499. {
  1500. TCHAR szUrl[INTERNET_MAX_URL_LENGTH];
  1501. TCHAR szUrlT[INTERNET_MAX_URL_LENGTH];
  1502. };
  1503. struct tbufs *ptbufs;
  1504. ptbufs = (struct tbufs *)LocalAlloc(LMEM_FIXED, sizeof(struct tbufs));
  1505. if (!ptbufs)
  1506. return E_OUTOFMEMORY;
  1507. hres = GetProp(PID_IS_URL, ptbufs->szUrl, INTERNET_MAX_URL_LENGTH);
  1508. bChanged = !(( !pszURL && S_OK != hres) ||
  1509. (pszURL && S_OK == hres && 0 == StrCmp(pszURL, ptbufs->szUrl)));
  1510. hres = S_OK;
  1511. if (bChanged)
  1512. {
  1513. if (NULL == pszURL)
  1514. {
  1515. hres = SetProp(PID_IS_URL, pszURL);
  1516. if (S_OK == hres)
  1517. hres = SetProp(PID_IS_SCHEME, URL_SCHEME_UNKNOWN);
  1518. }
  1519. else
  1520. {
  1521. DWORD dwFlagsT = UQF_CANONICALIZE;
  1522. // Translate the URL
  1523. if (IsFlagSet(dwFlags, IURL_SETURL_FL_GUESS_PROTOCOL))
  1524. SetFlag(dwFlagsT, UQF_GUESS_PROTOCOL);
  1525. if (IsFlagSet(dwFlags, IURL_SETURL_FL_USE_DEFAULT_PROTOCOL))
  1526. SetFlag(dwFlagsT, UQF_USE_DEFAULT_PROTOCOL);
  1527. // Translate the URL
  1528. hres = IURLQualify(pszURL, dwFlagsT, ptbufs->szUrlT, NULL, NULL);
  1529. if (SUCCEEDED(hres))
  1530. {
  1531. // Is the URL different after being translated?
  1532. bChanged = (0 != StrCmp(ptbufs->szUrlT, ptbufs->szUrl));
  1533. hres = S_OK;
  1534. if (bChanged)
  1535. {
  1536. // Yes; validate and get the scheme
  1537. PARSEDURL pu;
  1538. pu.cbSize = SIZEOF(pu);
  1539. hres = ParseURL(ptbufs->szUrlT, &pu);
  1540. if (S_OK == hres)
  1541. hres = SetProp(PID_IS_URL, ptbufs->szUrlT);
  1542. if (S_OK == hres)
  1543. hres = SetProp(PID_IS_SCHEME, (DWORD)pu.nScheme);
  1544. }
  1545. }
  1546. }
  1547. }
  1548. LocalFree((HLOCAL)ptbufs);
  1549. ptbufs = NULL;
  1550. return hres;
  1551. }
  1552. /*----------------------------------------------------------
  1553. Purpose: Helper function that sets the string property
  1554. */
  1555. STDMETHODIMP
  1556. IntshcutProp::SetProp(
  1557. IN PROPID pid,
  1558. IN LPCTSTR psz) OPTIONAL
  1559. {
  1560. HRESULT hr;
  1561. // WARNING:: this function gets called as part of ShellExecute which can be
  1562. // called by 16 bit apps so don't put mondo strings on stack...
  1563. LPCWSTR pszUrl = psz;
  1564. LPWSTR pszTemp = NULL;
  1565. // For URLs, we need to check for security spoofs
  1566. if (PID_IS_URL == pid && psz && IsSpecialUrl((LPWSTR)psz)) //FEATURE: remove cast
  1567. {
  1568. SHStrDup(psz, &pszTemp);
  1569. if (NULL != pszTemp)
  1570. {
  1571. // Unescape the url and look for a security context delimitor
  1572. hr = WrapSpecialUrlFlat(pszTemp, lstrlen(pszTemp)+1);
  1573. if (E_ACCESSDENIED == hr)
  1574. {
  1575. // Security delimitor found, so wack it off
  1576. SHRemoveURLTurd(pszTemp);
  1577. pszUrl = pszTemp;
  1578. }
  1579. }
  1580. else
  1581. {
  1582. return E_OUTOFMEMORY;
  1583. }
  1584. }
  1585. hr = super::SetProp(pid, pszUrl);
  1586. if (pszTemp)
  1587. {
  1588. CoTaskMemFree(pszTemp);
  1589. }
  1590. return hr;
  1591. }
  1592. STDAPI CIntshcutProp_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppvOut)
  1593. {
  1594. HRESULT hres;
  1595. *ppvOut = NULL;
  1596. if (punkOuter)
  1597. {
  1598. // No
  1599. hres = CLASS_E_NOAGGREGATION;
  1600. }
  1601. else
  1602. {
  1603. IUnknown * piunk = (IUnknown *)(IPropertyStorage *)new IntshcutProp;
  1604. if ( !piunk )
  1605. {
  1606. hres = E_OUTOFMEMORY;
  1607. }
  1608. else
  1609. {
  1610. hres = piunk->QueryInterface(riid, ppvOut);
  1611. piunk->Release();
  1612. }
  1613. }
  1614. return hres; // S_OK or E_NOINTERFACE
  1615. }