urlprop.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 50k
Category:

Windows Kernel

Development Platform:

Visual C++

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