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

Windows Kernel

Development Platform:

Visual C++

  1. #include "priv.h"
  2. // forwarders will be needed to write the named exports to browseui
  3. #include <fsmenu.h>
  4. #include <mstask.h>
  5. #include "favorite.h"
  6. #include "iehelpid.h"
  7. #ifdef UNIX
  8. #include "subsmgr.h"
  9. #else
  10. #include "webcheck.h"
  11. #endif
  12. #include "chanmgr.h"
  13. #include "chanmgrp.h"
  14. #include "resource.h"
  15. #include <platform.h>
  16. #include <mobsync.h>
  17. #include <mobsyncp.h>
  18. #include <mluisupp.h>
  19. #ifdef UNIX
  20. #include "unixstuff.h"
  21. #include "shalias.h"
  22. #endif
  23. UINT IE_ErrorMsgBox(IShellBrowser* psb,
  24.                     HWND hwndOwner, HRESULT hrError, LPCWSTR szError, LPCTSTR pszURLparam,
  25.                     UINT idResource, UINT wFlags);
  26. void ReplaceTransplacedControls (HWND hDlgMaster, HWND hDlgTemplate);
  27. ///////////////////////////////////////////////////////////////////////
  28. // helper function for DoOrganizeFavDlgEx
  29. // the org favs dialog returns a list of null terminated strings containing
  30. //   all the urls to update.
  31. void OrgFavSynchronize(HWND hwnd, VARIANT *pvarUrlsToSynch)
  32. {
  33. #ifndef DISABLE_SUBSCRIPTIONS
  34.     ASSERT(pvarUrlsToSynch);
  35.     
  36.     //if there are no urls to update, it's an empty string so bail
  37.     if ( (pvarUrlsToSynch->vt == VT_BSTR) && (pvarUrlsToSynch->bstrVal) &&
  38.          *(pvarUrlsToSynch->bstrVal) )
  39.     {
  40.         PWSTR pwzUrls = pvarUrlsToSynch->bstrVal;
  41.         ISubscriptionMgr *psm;
  42.         if (SUCCEEDED(JITCoCreateInstance(CLSID_SubscriptionMgr, NULL,
  43.                               CLSCTX_INPROC_SERVER, IID_ISubscriptionMgr,
  44.                               (void**)&psm, hwnd, FIEF_FLAG_FORCE_JITUI)))
  45.         {
  46.             //SysStringLen doesn't look at the string contents, just the cb of the alloc
  47.             while (pwzUrls < (pvarUrlsToSynch->bstrVal + SysStringLen(pvarUrlsToSynch->bstrVal)))
  48.             {
  49.                 psm->UpdateSubscription(pwzUrls);
  50.                 pwzUrls += lstrlenW(pwzUrls) + 1;
  51.             }
  52.             psm->Release();
  53.         }
  54.     }
  55. #endif /* !DISABLE_SUBSCRIPTIONS */
  56. }
  57. /*
  58.  * DoOrganizeFavDlgEx
  59.  *
  60.  * HWND hwnd             Owner window for the dialog.
  61.  * LPWSTR pszInitDir     Dir to use as root. if null, the user's favorites dir is used.
  62.  *
  63.  * Returns:
  64.  *  BOOL.  TRUE if succeeds. FALSE otherwise.
  65.  *
  66.  */
  67. BOOL WINAPI DoOrganizeFavDlgEx(HWND hwnd, LPWSTR pszInitDir)
  68. {
  69.     // The easy answer would be to add an about:OrganizeFavorites that
  70.     // gets registered in our selfreg.inx file.  Unfortunately, multilanguage
  71.     // support requires us to generate the URL on the fly.
  72.     WCHAR wszUrl[6 + MAX_PATH + 11 + 1]; // "res://MAX_PATH/orgfav.dlg"
  73.     StrCpyNW(wszUrl, L"res://", 7);
  74. #ifndef UNIX
  75.     GetModuleFileNameWrapW(MLGetHinst(), wszUrl+6, MAX_PATH);
  76. #else
  77.     // IEUNIX : GetModuleFilename returns /vobs/...../libbrowseui.so
  78.     // We need actual dllname here.
  79.     StrCpyNW(wszUrl + 6, L"shdocvw.dll" , 12);
  80. #endif
  81.     StrCatW(wszUrl, L"/orgfav.dlg");
  82.     IMoniker *pmk;
  83.     if (SUCCEEDED(CreateURLMoniker(NULL, wszUrl, &pmk)))
  84.     {
  85.         ASSERT(pmk);
  86.         VARIANT varUrlsToSynch, varInitialDir;
  87.         BSTR    bstrInitDir;
  88.         VariantInit(&varUrlsToSynch);
  89.         VariantInit(&varInitialDir);
  90.         if (pszInitDir)
  91.         {
  92.             bstrInitDir = SysAllocString(pszInitDir);
  93.             if (bstrInitDir)
  94.             {
  95.                 varInitialDir.vt = VT_BSTR;
  96.                 varInitialDir.bstrVal = bstrInitDir;
  97.             }
  98.         }
  99.         
  100.         ShowHTMLDialog(hwnd, pmk, &varInitialDir, L"Resizable=1", &varUrlsToSynch);
  101.         OrgFavSynchronize(hwnd, &varUrlsToSynch);
  102.         if (pszInitDir && bstrInitDir)
  103.             SysFreeString(bstrInitDir);
  104.         VariantClear(&varUrlsToSynch);
  105.         pmk->Release();
  106.         return TRUE;
  107.     }
  108.     else
  109.         return FALSE;
  110. }
  111. /*
  112.  * DoOrganizeFavDlg
  113.  *
  114.  * This API is exported so that it may be called by explorer and mshtml in
  115.  * addition to being called internally by shdocvw.
  116.  *
  117.  * HWND   hwndOwner       Owner window for the dialog.
  118.  * LPWSTR pszInitDir      Dir to use as root. if null, the user's favorites dir is used.
  119.  *
  120.  * Returns:
  121.  *  BOOL.  TRUE if succeeds. FALSE otherwise.
  122.  *
  123.  */
  124. BOOL WINAPI DoOrganizeFavDlg(HWND hwnd, LPSTR pszInitDir)
  125. {
  126.     BOOL fRet;
  127.     WCHAR szInitDir[MAX_PATH];
  128.     if (pszInitDir)
  129.         SHAnsiToUnicode(pszInitDir, szInitDir, ARRAYSIZE(szInitDir));
  130.     fRet = DoOrganizeFavDlgEx(hwnd, szInitDir);
  131.     return fRet;
  132. }
  133. BOOL WINAPI DoOrganizeFavDlgW(HWND hwnd, LPWSTR pszInitDir)
  134. {
  135.     return DoOrganizeFavDlgEx(hwnd, pszInitDir);
  136. }
  137. #define ADDTOFAVPROP TEXT("SHDOC_ATFPROP")
  138. typedef enum { ATF_FAVORITE,
  139.                ATF_CHANNEL,
  140.                ATF_CHANNEL_MODIFY,
  141.                ATF_CHANNEL_SOFTDIST
  142. } FAVDLGTYPE;
  143. typedef struct _ADDTOFAV
  144. {
  145.     PTSTR pszInitDir;
  146.     UINT cchInitDir;
  147.     PTSTR pszFile;
  148.     UINT cchFile;
  149.     LPITEMIDLIST pidl;
  150.     LPITEMIDLIST pidlSelected;
  151.     LPCITEMIDLIST pidlFavorite;
  152.     FAVDLGTYPE iDlgType;
  153.     SUBSCRIPTIONINFO siSubsInProg;
  154.     SUBSCRIPTIONTYPE subsType;
  155.     BOOL bIsSoftdist;
  156.     BOOL bStartSubscribed;
  157.     BOOL bSubscribed;
  158. } ADDTOFAV;
  159. BOOL IsSubscribed(ADDTOFAV *patf);
  160. typedef struct _BFFFavSubStruct
  161. {
  162.     WNDPROC lpfnOldWndProc;
  163.     HWND hwndNew;
  164.     HWND hwndTV;
  165.     HWND hwndSave;
  166.     HWND hTemplateWnd;
  167.     ADDTOFAV * patf;
  168.     RECT rcRestored;
  169. } BFFFAVSUBSTRUCT;
  170. BOOL CALLBACK NewFavDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  171. {
  172.     switch (uMsg)
  173.     {
  174.     case WM_INITDIALOG:
  175.     {
  176.         HWND hwnd;
  177.         ASSERT(lParam);
  178.         SetWindowLongPtr(hDlg, DWLP_USER, lParam);
  179.         EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
  180.         // cross-lang platform support
  181.         SHSetDefaultDialogFont(hDlg, IDD_NAME);
  182.         hwnd = GetDlgItem(hDlg, IDD_NAME);
  183. #ifndef UNIX
  184.         SendMessage(hwnd, EM_LIMITTEXT, MAX_PATH - 1, 0);
  185. #else
  186.         // IEUNIX : file/dir name on unix is limited to _MAX_FNAME.
  187.         SendMessage(hwnd, EM_LIMITTEXT, (WPARAM)(_MAX_FNAME - 1), (LPARAM)0);
  188. #endif
  189.         EnableOKButtonFromID(hDlg, IDD_NAME);
  190.         break;
  191.     }    
  192.     case WM_DESTROY:
  193.         SHRemoveDefaultDialogFont(hDlg);
  194.         return FALSE;
  195.     case WM_COMMAND:
  196.         switch (GET_WM_COMMAND_ID(wParam, lParam))
  197.         {
  198.         case IDD_NAME:
  199.             {
  200.                 if (GET_WM_COMMAND_CMD(wParam, lParam) == EN_UPDATE)
  201.                 {
  202.                     LPTSTR lpstrName = (LPTSTR) GetWindowLongPtr(hDlg, DWLP_USER);
  203.                     EnableOKButtonFromID(hDlg, IDD_NAME);
  204.                     GetDlgItemText(hDlg, IDD_NAME, lpstrName, MAX_PATH);
  205.                 }
  206.                 break;
  207.             }
  208.         case IDOK:
  209.         {
  210.             TCHAR  szTmp[MAX_PATH];
  211.             StrCpyN(szTmp, (LPTSTR)GetWindowLongPtr(hDlg, DWLP_USER), ARRAYSIZE(szTmp));
  212.             if (PathCleanupSpec(NULL,szTmp))
  213.             {
  214.                HWND hwnd;
  215.              MLShellMessageBox(
  216.                              hDlg,
  217.                              MAKEINTRESOURCE(IDS_FAVS_INVALIDFN),
  218.                              MAKEINTRESOURCE(IDS_FAVS_ADDTOFAVORITES),
  219.                              MB_OK | MB_ICONHAND);
  220.              hwnd = GetDlgItem(hDlg, IDD_NAME);
  221.              SetWindowText(hwnd, TEXT(''));
  222.              EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
  223.              SetFocus(hwnd);
  224.              break;
  225.             }
  226.         }
  227.         // fall through
  228.         case IDCANCEL:
  229.             EndDialog(hDlg, GET_WM_COMMAND_ID(wParam, lParam));
  230.             break;
  231.         default:
  232.             return FALSE;
  233.         }
  234.         break;
  235.     default:
  236.         return FALSE;
  237.     }
  238.     return TRUE;
  239. }
  240. // BOGUS - these id's stolen from SHBrowseForFolder implementation
  241. #define IDD_FOLDERLIST 0x3741
  242. #define IDD_BROWSETITLE 0x3742
  243. #define IDD_BROWSESTATUS 0x3743
  244. const static DWORD aAddToFavHelpIDs[] = {  // Context Help IDs
  245.     IDC_FAVORITE_DESC,          NO_HELP,
  246.     IDD_BROWSETITLE,            NO_HELP,
  247.     IDD_BROWSESTATUS,           NO_HELP,
  248.     IDC_FAVORITE_ICON,          NO_HELP,
  249.     IDC_NAMESTATIC,             IDH_NAMEEDIT,
  250.     IDC_FOLDERLISTSTATIC,       IDH_BROWSELIST,
  251.     IDC_SUBSCRIBE_FOLDERLIST_PLACEHOLDER,     IDH_BROWSELIST,
  252.     IDC_FAVORITE_NEWFOLDER,     IDH_CREATEIN,
  253.     IDC_SUBSCRIBE_CUSTOMIZE,    IDH_CHANNEL_SUBSCR_CUST_BUTTON,
  254.     IDC_FAVORITE_CREATEIN,      IDH_NEWFOLDER,
  255.     IDC_FAVORITE_NAME,          IDH_NAMEEDIT,
  256.     IDC_MAKE_OFFLINE,           IDH_MAKE_AVAIL_OFFLINE,
  257.     0, 0
  258. };
  259. const static DWORD aAddToChanHelpIDs[] = {  // Context Help IDs
  260.     IDC_FAVORITE_DESC,          NO_HELP,
  261.     IDD_BROWSETITLE,            NO_HELP,
  262.     IDD_BROWSESTATUS,           NO_HELP,
  263.     IDC_FAVORITE_ICON,          NO_HELP,
  264.     IDC_NAMESTATIC,             IDH_NAMEEDIT,
  265.     IDC_FOLDERLISTSTATIC,       IDH_BROWSELIST,
  266.     IDC_SUBSCRIBE_FOLDERLIST_PLACEHOLDER,     IDH_BROWSELIST,
  267.     IDC_FAVORITE_NEWFOLDER,     IDH_CREATEIN,
  268.     IDC_SUBSCRIBE_CUSTOMIZE,    IDH_CHANNEL_SUBSCR_CUST_BUTTON,
  269.     IDC_FAVORITE_CREATEIN,      IDH_NEWFOLDER,
  270.     IDC_FAVORITE_NAME,          IDH_NAMEEDIT,
  271.     IDC_MAKE_OFFLINE,           IDH_MAKE_AVAIL_OFFLINE,
  272.     0, 0
  273. };
  274. /*
  275.  * Makes sure the item being added to favorites doesn't already exist.  If it does,
  276.  * puts up a message box to have the user confirm whether they want to overwrite
  277.  * the old favorite or not.  
  278. */
  279. BOOL ConfirmAddToFavorites(HWND hwndOwner, ADDTOFAV * patf)
  280. {
  281.     BOOL fRet = FALSE;
  282.     BOOL fExists;
  283.     int iPromptString = 0;
  284.     if (patf->subsType == SUBSTYPE_CHANNEL)
  285.     {
  286.         //patf->pszInitDir now contains the path with a .url on the end; the channel
  287.         //will be stored in a directory of that name without .url.  Strip it.
  288.         TCHAR szPath[MAX_PATH];
  289.         StrCpyN(szPath, patf->pszInitDir, ARRAYSIZE(szPath));
  290.         PathRemoveExtension (szPath);
  291.         fExists = PathFileExists(szPath);
  292.         iPromptString = IDS_CHANNELS_FILEEXISTS;
  293.     }
  294.     else
  295.     {
  296.         fExists = PathFileExists(patf->pszInitDir);
  297.         iPromptString = IDS_FAVS_FILEEXISTS;
  298.     }
  299.     fRet = ! fExists ||
  300.         (MLShellMessageBox(
  301.                          hwndOwner,
  302.                          MAKEINTRESOURCE(iPromptString),
  303.                          NULL,    //use owner's title
  304.                          MB_ICONQUESTION | MB_YESNO) == IDYES);
  305.     return fRet;
  306. }
  307. //
  308. // Get the localized date and time
  309. //
  310. typedef HRESULT (*PFVARIANTTIMETOSYSTEMTIME)(DOUBLE, LPSYSTEMTIME);
  311. //
  312. // Subscribe to the current site.
  313. //
  314. HRESULT SubscribeToSite(HWND hwnd, LPCTSTR pszFile, LPCITEMIDLIST pidl, DWORD dwFlags,
  315.                         SUBSCRIPTIONINFO* pSubs, SUBSCRIPTIONTYPE subsType)
  316. {
  317. #ifndef DISABLE_SUBSCRIPTIONS
  318.     TCHAR szURL[MAX_URL_STRING];
  319.     ISubscriptionMgr *pISubscriptionMgr;
  320.     //
  321.     // Get a displayable URL.
  322.     //
  323.     IEGetDisplayName(pidl, szURL, SHGDN_FORPARSING);
  324.     //
  325.     // Get a pointer to the subscription manager.
  326.     //
  327.     HRESULT hr = JITCoCreateInstance(CLSID_SubscriptionMgr, NULL, CLSCTX_INPROC_SERVER,
  328.                           IID_ISubscriptionMgr,
  329.                           (void**)&pISubscriptionMgr, hwnd, FIEF_FLAG_FORCE_JITUI);
  330.     if (SUCCEEDED(hr)) 
  331.     {
  332.         //
  333.         // Create a default subscription.
  334.         //
  335.         BSTR bstrURL = SysAllocStringT(szURL);
  336.         if (bstrURL) 
  337.         {
  338.             BSTR bstrName = SysAllocStringT(pszFile);
  339.             if (bstrName) 
  340.             {
  341.                 hr = pISubscriptionMgr->CreateSubscription(hwnd, 
  342.                     bstrURL, bstrName, dwFlags, subsType,  pSubs);
  343.                 SysFreeString(bstrName);
  344.             }
  345.             SysFreeString(bstrURL);
  346.         }
  347.         //
  348.         // Clean up.
  349.         //
  350.         pISubscriptionMgr->Release();
  351.     }
  352.     return hr;
  353. #else  /* !DISABLE_SUBSCRIPTIONS */
  354.     return E_FAIL;
  355. #endif /* !DISABLE_SUBSCRIPTIONS */
  356. }
  357. //
  358. // Create in-memory subscription, but only optionally save it to subscription manager
  359. //
  360. BOOL StartSiteSubscription (HWND hwnd, ADDTOFAV* patf, BOOL bFinalize)
  361. {
  362. #ifndef DISABLE_SUBCRIPTIONS
  363.     //update the changes-only flag (radio buttons here are, effectively, direct access to this flag)
  364.     if (patf->subsType == SUBSTYPE_CHANNEL || patf->subsType == SUBSTYPE_DESKTOPCHANNEL)
  365.     {
  366.         //if set, leave alone; otherwise, put to full download
  367.         if (!(patf->siSubsInProg.fChannelFlags & CHANNEL_AGENT_PRECACHE_SOME))
  368.             patf->siSubsInProg.fChannelFlags |= CHANNEL_AGENT_PRECACHE_ALL;
  369.         patf->siSubsInProg.fUpdateFlags |= SUBSINFO_CHANNELFLAGS | SUBSINFO_SCHEDULE;
  370.     }
  371.     if (S_OK != SubscribeToSite(hwnd, patf->pszFile, patf->pidlFavorite,
  372.                                    bFinalize ? CREATESUBS_NOUI | CREATESUBS_FROMFAVORITES : CREATESUBS_NOSAVE,
  373.                                    &patf->siSubsInProg, patf->subsType))
  374.     {
  375.         return FALSE;
  376.     }
  377.     return TRUE;
  378. #else  /* !DISABLE_SUBSCRIPTIONS */
  379.     return FALSE;
  380. #endif /* !DISABLE_SUBSCRIPTIONS */
  381. }
  382. /*
  383.    Combines the path and the filename of the favorite
  384.    and puts it into patf->pszInitDir, so that it has the fully qualified pathname.
  385. */
  386. #define SZ_URLEXT    TEXT(".url")
  387. #define CCH_URLEXT   SIZECHARS(SZ_URLEXT)
  388. BOOL QualifyFileName(ADDTOFAV *patf)
  389. {
  390.     TCHAR szTemp[MAX_PATH];
  391.     BOOL fRet = FALSE;
  392.     LPTSTR  pstr;
  393.     // Can we safely add the extension to this?
  394.     if (lstrlen(patf->pszFile) < (int)(patf->cchFile - CCH_URLEXT))
  395.     {
  396.         //Add extension .url if its not already there
  397.         //This is to prevent strings like "com"  in "www.microsoft.com" from being interpreted as extensions
  398.         pstr = PathFindExtension(patf->pszFile);
  399.         if (!pstr || (pstr && StrCmpI(pstr, SZ_URLEXT)))// && StrCmpI(pstr, SZ_CDFEXT)))
  400.             StrCatBuff(patf->pszFile, SZ_URLEXT, patf->cchFile);
  401.             
  402.         // Is there a folder associated with the filename?
  403.         if (patf->pidlSelected && SHGetPathFromIDList(patf->pidlSelected, szTemp)) 
  404.         {
  405.             // Yes
  406.             if (PathCombine(szTemp, szTemp, patf->pszFile))
  407.             {
  408.                 if ((UINT)lstrlen(szTemp) < patf->cchInitDir)
  409.                 {
  410.                     StrCpyN(patf->pszInitDir, szTemp, patf->cchInitDir);
  411.                     fRet = TRUE;
  412.                 }
  413.             }
  414.         }
  415.     }
  416.     return fRet;
  417. }
  418. BOOL SubscriptionFailsChannelAuthentication (HWND hDlg, SUBSCRIPTIONINFO* psi)
  419. {
  420. #ifndef DISABLE_SUBSCRIPTIONS  
  421.     if (psi->bNeedPassword && !(psi->bstrPassword && psi->bstrPassword[0]
  422.                              && psi->bstrUserName && psi->bstrUserName[0]))
  423.     {   //password would be required
  424.         if (IsDlgButtonChecked (hDlg, IDC_MAKE_OFFLINE))
  425.         {   //they're trying to subscribe...  WRONG!
  426.             MLShellMessageBox(
  427.                 hDlg,
  428.                 MAKEINTRESOURCE(IDS_NEED_CHANNEL_PASSWORD),
  429.                 NULL,
  430.                 MB_ICONINFORMATION | MB_OK);
  431.             return TRUE;
  432.         }
  433.     }
  434.     return FALSE;
  435. #else  /* !DISABLE_SUBSCRIPTIONS */
  436.     return FALSE;
  437. #endif /* !DISABLE_SUBSCRIPTIONS */
  438. }
  439. LRESULT CALLBACK BFFFavSubclass(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  440. {
  441.     BFFFAVSUBSTRUCT * pbffFS = (BFFFAVSUBSTRUCT *)GetProp(hwnd, ADDTOFAVPROP);
  442.     WNDPROC lpfnOldWndProc = pbffFS->lpfnOldWndProc;
  443.     RECT rc;
  444.     switch (uMsg) {
  445.         case WM_COMMAND:
  446.             // Intercept the command for the New Folder button we hacked into
  447.             // the SHBrowseForFolder dialog.
  448.             switch (GET_WM_COMMAND_ID(wParam, lParam)) {
  449.             case IDC_FAVORITE_NAME:
  450.             {
  451.                 HWND hwndedit;
  452.                 if (GET_WM_COMMAND_CMD(wParam, lParam) == EN_CHANGE) 
  453.                     EnableOKButtonFromID(hwnd, IDC_FAVORITE_NAME);
  454.                 hwndedit = GetDlgItem(hwnd, IDC_FAVORITE_NAME);
  455.                 SendMessage(hwndedit, EM_LIMITTEXT, MAX_PATH - 1, 0);
  456.                 break;
  457.             }    
  458. #ifndef UNIX
  459. // IEUNIX (OFFLINE) : No offline ability
  460.             case IDC_MAKE_OFFLINE:
  461.                 EnableWindow(GetDlgItem(hwnd, IDC_SUBSCRIBE_CUSTOMIZE), 
  462.                              IsDlgButtonChecked(hwnd, IDC_MAKE_OFFLINE));
  463.                 break;
  464.             case IDC_SUBSCRIBE_CUSTOMIZE:
  465.                 //need to create -- but not store -- subscription
  466.                 if (StartSiteSubscription (hwnd, pbffFS->patf, FALSE))
  467.                     SendMessage (hwnd, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwnd, IDOK), TRUE);
  468.                 break;
  469. #endif
  470.             case IDC_FAVORITE_NEWFOLDER:
  471.                 TCHAR szPath[MAX_PATH];
  472.                 TCHAR szName[MAX_PATH];
  473.                 HWND hwndTV;
  474.                 TV_ITEM tv_item;
  475.                 // Bring up the Create New Folder dialog
  476.                 if ((DialogBoxParam(MLGetHinst(), MAKEINTRESOURCE(DLG_NEWFOLDER), hwnd,
  477.                     (DLGPROC)NewFavDlgProc, (LPARAM)szName) == IDOK) &&
  478.                     (SHGetPathFromIDList(pbffFS->patf->pidlSelected, szPath)) &&
  479.                     ((lstrlen(szPath) + lstrlen(szName) + 1) < MAX_PATH))
  480.                 {
  481.                     PathCombine(szPath, szPath, szName);
  482.                     BOOL bSuccess = FALSE;
  483. #ifdef CREATEFOLDERSINCHANNELSDIR
  484.                     if (pbffFS->patf->subsType == SUBSTYPE_CHANNEL)
  485.                     {
  486.                         ASSERT(0);  //should not be possible in this release
  487.                                     //(I removed this button in the .rc dialogs for channels)
  488.                         //Note: to make this work in a future release, reenable this code -- it's
  489.                         //functional.  But the folders created here show up ugly in the channel bar
  490.                         //(just a default folder icon) and if you click on them, you get a shell
  491.                         //Explorer window instead of a theater-mode browser window.  The reason
  492.                         //for this second happening is that the desktop.ini file created in the new
  493.                         //folder has no URL=.  To remedy this: AddCategory() has to be fixed so it
  494.                         //doesn't interpret the pszURL argument as a UNC name (I was using a resouce moniker
  495.                         //pointing into cdfview.dll for the html target), and the OC hosted by the default
  496.                         //html pages has to learn how to be hosted from a html page without a path -- or we
  497.                         //actually have to create an html page in the new directory, which is messy.
  498.                         IChannelMgr* pChanMgr;
  499.                         HRESULT hr;
  500.                         hr = JITCoCreateInstance(CLSID_ChannelMgr, NULL, CLSCTX_INPROC_SERVER,
  501.                                               IID_IChannelMgr, (void**)&pChanMgr, 
  502.                                               hwnd, FIEF_FLAG_FORCE_JITUI);
  503.                         if (SUCCEEDED(hr))
  504.                         {
  505.                             IChannelMgrPriv* pChanMgrPriv;
  506.                             hr = pChanMgr->QueryInterface (IID_IChannelMgrPriv, (void**)&pChanMgrPriv);
  507.                             if (SUCCEEDED(hr))
  508.                             {
  509.                                 char szCFPath[MAX_PATH];
  510.                                 WCHAR wszFolder[MAX_PATH];
  511.                                 IChannelMgrPriv::CHANNELFOLDERLOCATION cflLocation =
  512.                                     (pbffFS->patf->iDlgType == ATF_CHANNEL_SOFTDIST ?
  513.                                         IChannelMgrPriv::CF_SOFTWAREUPDATE :
  514.                                         IChannelMgrPriv::CF_CHANNEL);
  515.                                 hr = pChanMgrPriv->GetChannelFolderPath (szCFPath, ARRAYSIZE(szCFPath), cflLocation);
  516.                                 int cchCommon = PathCommonPrefix (szPath, szCFPath, NULL);
  517.                                 AnsiToUnicode (szPath + cchCommon, wszFolder, ARRAYSIZE(wszFolder));
  518.                                 CHANNELCATEGORYINFO info = {0};
  519.                                 info.cbSize = sizeof(info);
  520.                                 info.pszTitle = wszFolder;
  521.                                 bSuccess = SUCCEEDED (pChanMgr->AddCategory (&info));
  522.                                 pChanMgrPriv->Release();
  523.                             }
  524.                             pChanMgr->Release();
  525.                         }
  526.                     }
  527.                     else
  528. #endif
  529.                     {
  530.                         bSuccess = CreateDirectory(szPath, NULL);
  531.                     }
  532.                     if (bSuccess)
  533.                     {
  534.                         // This code assumes the layout of SHBrowseForFolder!
  535.                         // directory successfully created, must notify registered shell components.
  536.                         SHChangeNotify(SHCNE_MKDIR, SHCNF_PATH, szPath, NULL);
  537.                         // Get the TreeView control
  538.                         hwndTV = GetDlgItem(hwnd, IDD_FOLDERLIST);
  539.                         if (hwndTV) {
  540.                             HTREEITEM hti = TreeView_GetSelection(hwndTV);
  541.                             // Take the selected item and reset it, then reexpand it so
  542.                             // that it shows the new directory we just created.
  543.                             tv_item.mask = TVIF_CHILDREN;
  544.                             tv_item.hItem = hti;
  545.                             tv_item.cChildren = -1;
  546.                             TreeView_SetItem(hwndTV, &tv_item);
  547.                             TreeView_Expand(hwndTV, hti, TVE_COLLAPSE | TVE_COLLAPSERESET);
  548.                             TreeView_Expand(hwndTV, hti, TVE_EXPAND);
  549.                             // Find the new directory we just created and select it by
  550.                             // walking the tree from the selected item down.
  551.                             if (hti = TreeView_GetChild(hwndTV, hti)) {
  552.                                 tv_item.mask = TVIF_TEXT;
  553.                                 tv_item.pszText = szPath;
  554.                                 tv_item.cchTextMax = MAX_PATH;
  555.                                 do {
  556.                                     tv_item.hItem = hti;
  557.                                     TreeView_GetItem(hwndTV, &tv_item);
  558.                                     if (StrCmp(szName, szPath) == 0) {
  559.                                         TreeView_Select(hwndTV, hti, TVGN_CARET);
  560.                                         break;
  561.                                     }
  562.                                 } while (hti = TreeView_GetNextSibling(hwndTV, hti));
  563.                             }
  564.                             SetFocus(hwndTV);
  565.                         }
  566.                     } else {
  567.                         
  568.                         LPVOID lpMsgBuf;
  569.                         FormatMessage( 
  570.                             FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  571.                             NULL,
  572.                             GetLastError(),
  573.                             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  574.                             (LPTSTR) &lpMsgBuf,
  575.                             0,
  576.                             NULL 
  577.                         );
  578.                         MLShellMessageBox(
  579.                                         hwnd,
  580.                                         (LPCTSTR)lpMsgBuf,
  581.                                         MAKEINTRESOURCE(IDS_FAVS_ADDTOFAVORITES),
  582.                                         MB_ICONINFORMATION | MB_OK);
  583.                         
  584.                         // Free the buffer.
  585.                         LocalFree( lpMsgBuf );
  586.                         
  587.                     }
  588.                 }
  589.                 break;
  590.             case IDOK:
  591.                 // first, make sure they're not trying to subscribe to an authenticated
  592.                 // channel without entering a password.
  593.                 if (SubscriptionFailsChannelAuthentication (hwnd, &pbffFS->patf->siSubsInProg))
  594.                     return FALSE;
  595.                 // Retrieve the text from the Name edit control.
  596.                 GetDlgItemText(hwnd, IDC_FAVORITE_NAME, pbffFS->patf->pszFile, pbffFS->patf->cchFile);
  597.                 { // Just  a block to declare variables
  598.                     BOOL fTooBig = TRUE;        // assume failure
  599.                     TCHAR  szTmp[MAX_PATH];
  600.                                        
  601.                     if (lstrlen(pbffFS->patf->pszFile) < MAX_PATH)
  602.                     {
  603.                         StrCpyN(szTmp, pbffFS->patf->pszFile, ARRAYSIZE(szTmp));
  604.                         // PathCleanupSpec deals with MAX_PATH buffers, so we should be fine
  605.                         if (PathCleanupSpec(NULL, szTmp))
  606.                         {
  607.                             MLShellMessageBox(
  608.                                             hwnd,
  609.                                             MAKEINTRESOURCE(IDS_FAVS_INVALIDFN),
  610.                                             MAKEINTRESOURCE(IDS_FAVS_ADDTOFAVORITES),
  611.                                             MB_OK | MB_ICONHAND);
  612.                             return FALSE;
  613.                         }
  614.                                        
  615.                         // Make sure the name is unique and if not, that the user has
  616.                         // specified that it is OK to override.
  617.                         if (QualifyFileName(pbffFS->patf))
  618.                         {
  619.                             if (!ConfirmAddToFavorites(hwnd, pbffFS->patf))
  620.                                 return FALSE;
  621.                             //  BUGBUG: Bogus hack since the ATF stuff is only half done
  622.                             //  Depending on which dlg is shown, look for the appropriate
  623.                             //  check.
  624.                             if (IsDlgButtonChecked (hwnd, IDC_MAKE_OFFLINE))
  625.                             {
  626.                                //they want to subscribe!  save subscription we already have in memory
  627.                                 //trouble is, pbffFS->patf->pszFile ends in a bogus .url
  628.                                 TCHAR* pszTemp = pbffFS->patf->pszFile;
  629.                                 TCHAR szNoExt[MAX_PATH];
  630.                                 StrCpyN(szNoExt, pbffFS->patf->pszFile, ARRAYSIZE(szNoExt));
  631.                                 pbffFS->patf->pszFile = szNoExt;
  632.                                 PathRemoveExtension (szNoExt);
  633.                                 pbffFS->patf->bSubscribed = 
  634.                                     StartSiteSubscription (hwnd, pbffFS->patf, TRUE);
  635.                                 pbffFS->patf->pszFile = pszTemp;
  636.                             }
  637.                             else if (pbffFS->patf->bStartSubscribed)
  638.                             {
  639.                                 //  If we started subscribed and they unchecked make available
  640.                                 //  offline, then delete the subscription.
  641.                                 ISubscriptionMgr* pSubsMgr;
  642.                                 if (SUCCEEDED (CoCreateInstance(CLSID_SubscriptionMgr, NULL, CLSCTX_INPROC_SERVER,
  643.                                                                 IID_ISubscriptionMgr, (void**)&pSubsMgr)))
  644.                                 {
  645.                                     //url is in patf->pidlFavorite
  646.                                     WCHAR wszURL[MAX_URL_STRING];
  647.                                     IEGetDisplayName(pbffFS->patf->pidlFavorite, wszURL, SHGDN_FORPARSING);
  648.                                     pSubsMgr->DeleteSubscription(wszURL, NULL);
  649.                                     pSubsMgr->Release();
  650.                                 }
  651.                             }
  652.                             // Enable and set focus to the tree view so that it is sure to
  653.                             // be selected so that SHBrowseForFolder will return a pidl.
  654.                             EnableWindow(pbffFS->hwndTV, TRUE);
  655.                             SetFocus(pbffFS->hwndTV);
  656.                             fTooBig = FALSE;
  657.                         }
  658.                     }
  659. #ifdef UNIX_FEATURE_ALIAS
  660.                     if( !fTooBig )
  661.                     {
  662.                         TCHAR alias[MAX_ALIAS_LENGTH];
  663.                         TCHAR szThisURL[MAX_URL_STRING];
  664.                         HDPA  aliasList = GetGlobalAliasList();
  665.                         if( aliasList )
  666.                         {
  667. #ifdef UNICODE
  668.                             // TODO :
  669. #else
  670.                             // Retrieve the text from the Alias edit control.
  671.                             GetDlgItemText(hwnd, IDC_ALIAS_NAME, alias, MAX_ALIAS_LENGTH-1);
  672.                             IEGetDisplayName(pbffFS->patf->pidlFavorite, 
  673.                                 szThisURL, SHGDN_FORPARSING);
  674.                             if(AddAliasToListA( aliasList, alias, szThisURL, hwnd ))
  675.                                 SaveAliases(aliasList);
  676. #endif
  677.                         }
  678.                     }
  679. #endif /* UNIX_FEATURE_ALIAS */
  680.                     if (fTooBig)
  681.                     {
  682.                         MLShellMessageBox(
  683.                                         hwnd,
  684.                                         MAKEINTRESOURCE(IDS_FAVS_FNTOOLONG),
  685.                                         MAKEINTRESOURCE(IDS_FAVS_ADDTOFAVORITES),
  686.                                         MB_OK | MB_ICONHAND);
  687.                         return FALSE;
  688.                     }
  689.                 }
  690.                 break;
  691.             case IDC_FAVORITE_CREATEIN:
  692.                 // The advanced button has been clicked.  Enable/disable the tree view
  693.                 // and New button, set focus to the tree view or ok button, disable the advanced
  694.                 // button and then resize the dialog.
  695.             {
  696.                 BOOL fExpanding = !IsWindowEnabled(GetDlgItem(hwnd, IDC_SUBSCRIBE_FOLDERLIST_PLACEHOLDER)); //random control that gets enabled when dialog expanded
  697.                 TCHAR szBuffer[100];
  698.                 EnableWindow(pbffFS->hwndTV, fExpanding);
  699.                 //don't show New Folder button for channels in the channels folder,
  700.                 // see code for case IDC_FAVORITE_NEWFOLDER for why
  701.                 if (fExpanding && pbffFS->patf->subsType == SUBSTYPE_CHANNEL)
  702.                 {
  703.                     LPITEMIDLIST pidlFavs = NULL;
  704.                     TCHAR tzFavsPath[MAX_PATH];
  705.                 
  706.                     if (SUCCEEDED(SHGetSpecialFolderLocation(hwnd, CSIDL_FAVORITES, &pidlFavs)) 
  707.                     &&  SUCCEEDED(SHGetNameAndFlags(pidlFavs, SHGDN_FORPARSING | SHGDN_FORADDRESSBAR, tzFavsPath, SIZECHARS(tzFavsPath), NULL))
  708.                     &&  StrCmpNI(tzFavsPath, pbffFS->patf->pszInitDir, ARRAYSIZE(tzFavsPath))==0)
  709.                     {
  710.                         EnableWindow(pbffFS->hwndNew, TRUE);
  711.                     }
  712.                     if(pidlFavs)
  713.                         ILFree(pidlFavs);
  714.                 }
  715.                 else
  716.                     EnableWindow(pbffFS->hwndNew, fExpanding);
  717.                 GetWindowRect(hwnd, &rc);
  718.                 if (fExpanding)
  719.                 {
  720.                     int lRet = MLLoadString(IDS_FAVS_ADVANCED_COLLAPSE, szBuffer, ARRAYSIZE(szBuffer));
  721.                     ASSERT(lRet);
  722.                     
  723.                     SetFocus(pbffFS->hwndTV);
  724.                     MoveWindow(hwnd, rc.left, rc.top,
  725.                         pbffFS->rcRestored.right - pbffFS->rcRestored.left,
  726.                         pbffFS->rcRestored.bottom - pbffFS->rcRestored.top, TRUE);
  727.                 }
  728.                 else
  729.                 {
  730.                     int lRet = MLLoadString(IDS_FAVS_ADVANCED_EXPAND, szBuffer, ARRAYSIZE(szBuffer));
  731.                     ASSERT(lRet);
  732.                     
  733.                     SetFocus(GetDlgItem(hwnd, IDC_FAVORITE_NAME));
  734.                     MoveWindow(hwnd, rc.left, rc.top,
  735.                         pbffFS->rcRestored.right - pbffFS->rcRestored.left,
  736.                         pbffFS->rcRestored.bottom - pbffFS->rcRestored.top, TRUE);
  737.                     // hide the bottom part of the dialog
  738.                     int cx, cy;
  739.                     RECT rc;
  740.                     GetWindowRect (GetDlgItem (hwnd, IDC_SUBSCRIBE_FOLDERLIST_PLACEHOLDER), &rc);
  741.                     cy = rc.top;
  742.                     GetWindowRect (hwnd, &rc);
  743.                     cx = rc.right - rc.left;
  744.                     cy = cy /*top of ctrl*/ - rc.top; /*top of window*/
  745.                     SetWindowPos (hwnd, NULL, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER);
  746.                 }
  747.                 SetWindowText(GetDlgItem(hwnd, IDC_FAVORITE_CREATEIN), szBuffer);
  748.                 break;
  749.             }
  750.             }
  751.             break;
  752.         case WM_DESTROY:
  753.         {
  754.             DWORD dwValue = IsWindowEnabled(GetDlgItem(hwnd, IDC_FAVORITE_NEWFOLDER)); //random control that gets enabled when dialog expanded
  755.             SHRegSetUSValue(TEXT("Software\Microsoft\Internet Explorer\Main"), TEXT("AddToFavoritesExpanded"),
  756.                 REG_DWORD, &dwValue, 4, SHREGSET_HKCU | SHREGSET_FORCE_HKCU);
  757.             ReplaceTransplacedControls (hwnd, pbffFS->hTemplateWnd);
  758.             DestroyWindow (pbffFS->hTemplateWnd);
  759.             SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) lpfnOldWndProc);
  760.             RemoveProp(hwnd, ADDTOFAVPROP);
  761.             SHRemoveDefaultDialogFont(hwnd);
  762.             ILFree(pbffFS->patf->pidlSelected);
  763.             LocalFree((HLOCAL)pbffFS);
  764.             break;
  765.         }
  766.         case WM_HELP:
  767.             SHWinHelpOnDemandWrap((HWND)((LPHELPINFO) lParam)->hItemHandle, c_szHelpFile,
  768.                 HELP_WM_HELP, (DWORD_PTR)(LPTSTR) (pbffFS->patf->iDlgType == ATF_FAVORITE
  769.                                 ? aAddToFavHelpIDs : aAddToChanHelpIDs));
  770.             return TRUE;
  771.             break;
  772.         case WM_CONTEXTMENU:
  773.             SHWinHelpOnDemandWrap((HWND) wParam, c_szHelpFile, HELP_CONTEXTMENU,
  774.                 (DWORD_PTR)(LPVOID) (pbffFS->patf->iDlgType == ATF_FAVORITE
  775.                              ? aAddToFavHelpIDs : aAddToChanHelpIDs));
  776.             return TRUE;
  777.             break;
  778.     }
  779.     return CallWindowProc(lpfnOldWndProc, hwnd, uMsg, wParam, lParam);
  780. }
  781. static const TCHAR szTransplacedProp[] = TEXT("tp");
  782. void ReplaceTransplacedControls (HWND hDlgMaster, HWND hDlgTemplate)
  783. {
  784.     /*
  785.      * This function moves the controls that we moved from our temporary
  786.      * dialog over to SHBrowseForFolder's dialog, back to their original
  787.      * home, before they get destroyed.  This is because otherwise we have
  788.      * problems when destroying the template dialog -- specifically, we get
  789.      * a GP fault in user.exe when destroying the edit control, because it
  790.      * looks to its parent window to figure out where its data segment is.
  791.      *
  792.      * Solution: (for safety) -- put everything back where it came from.
  793.      * Other possibilities: just move the edit control (by ID) back, or
  794.      *       move all edit controls back, or use DS_LOCALEDIT for edit controls
  795.      *       (but this is documented only for use with multiline edits.)
  796.      *       Or modify SHBrowseForFolder to allow other dialog templates...
  797.      *       but that's over in shell32.
  798.      */
  799.     HWND hCtrl = GetWindow (hDlgMaster, GW_CHILD);
  800.     while (hCtrl)
  801.     {
  802.         HWND hNext = GetWindow (hCtrl, GW_HWNDNEXT);
  803.         if (GetProp (hCtrl, szTransplacedProp) != NULL)
  804.         {
  805.             RemoveProp (hCtrl, szTransplacedProp);
  806.             SetParent (hCtrl, hDlgTemplate);
  807.         }
  808.         hCtrl = hNext;
  809.     }
  810. }
  811. #define szOriginalWND TEXT("WorkaroundOrigWndProc")
  812. INT_PTR CALLBACK MergeFavoritesDialogControls(HWND hDlgTemplate, UINT uMsg, WPARAM wParam, LPARAM lParam)
  813. {
  814.     switch (uMsg)
  815.     {
  816.     case WM_INITDIALOG:
  817.     {
  818.         HWND hDlgMaster = (HWND)lParam;
  819.         ASSERT (IsWindow (hDlgMaster));
  820.         TCHAR szT[200];
  821.         RECT rc;
  822.         //resize master like us
  823.         GetWindowText (hDlgTemplate, szT, ARRAYSIZE(szT));
  824.         SetWindowText (hDlgMaster, szT);
  825.         GetClientRect (hDlgTemplate, &rc);
  826.         AdjustWindowRect (&rc, GetWindowLong (hDlgMaster, GWL_STYLE), FALSE);
  827.         SetWindowPos (hDlgMaster, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top,
  828.             SWP_NOMOVE | SWP_NOZORDER);
  829.         // a-msadek; BUGBUG: if the owned window is mirrored, a dialog with specifed 
  830.         // coordinates, the dialog get moved to the worng direction
  831.         HWND hWndOwner = GetWindow(hDlgMaster, GW_OWNER);
  832.         if(IS_WINDOW_RTL_MIRRORED(hWndOwner))
  833.             {
  834.                 RECT rcOwner, rcDlg;            
  835.                 GetWindowRect(hWndOwner, &rcOwner);
  836.                 GetWindowRect(hDlgMaster, &rcDlg);
  837.                 SetWindowPos(hDlgMaster, NULL, rcDlg.left - (rcDlg.right - rcOwner.right), rcDlg.top, 0 ,0,
  838.                 SWP_NOSIZE | SWP_NOZORDER);
  839.             }
  840.             
  841. #if 0   //now we do this as part of the "move controls from template to master" process,
  842.         //if we notice that a ctrl with that id already exists.  This way we pick up the
  843.         //tab order too.  If someone decides my hack (SetParent) to change tab order is
  844.         //broken, then that code can be nuked and this reenabled.
  845.         //position already-existing controls in master like us
  846.         int ID_PREEXIST_CTRLS[] = { IDOK_PLACEHOLDER, IDCANCEL_PLACEHOLDER,
  847.             IDC_SUBSCRIBE_FOLDERLIST_PLACEHOLDER };
  848.         for (int iCtrl = 0; iCtrl < ARRAYSIZE(ID_PREEXIST_CTRLS); iCtrl++)
  849.         {
  850.             GetWindowRect (GetDlgItem (hDlgTemplate, ID_PREEXIST_CTRLS[iCtrl]), &rc);
  851.             MapWindowPoints (NULL, hDlgTemplate, (LPPOINT)&rc, 2);
  852.             MoveWindow (GetDlgItem (hDlgMaster, ID_PREEXIST_CTRLS[iCtrl]),
  853.                 rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE);
  854.             DestroyWindow (GetDlgItem (hDlgTemplate, ID_PREEXIST_CTRLS[iCtrl]));
  855.         }
  856. #endif
  857.         //copy other controls from us to master
  858.         //find last child
  859.         HWND hCtrlTemplate = NULL;
  860.         HWND hNextCtrl = GetWindow (hDlgTemplate, GW_CHILD);
  861.         if (hNextCtrl)      //can't see how this would fail, but...
  862.             hCtrlTemplate = GetWindow (hNextCtrl, GW_HWNDLAST);
  863.         //have last window in hCtrlTemplate
  864.         //now move controls over in reverse order -- they'll end up stacking up in original order from template
  865.         while (hCtrlTemplate)
  866.         {
  867.             hNextCtrl = GetWindow (hCtrlTemplate, GW_HWNDPREV);
  868.             DWORD id = GetWindowLong (hCtrlTemplate, GWL_ID);
  869.             HWND hCtrlExisting;
  870.             if (id != (USHORT)IDC_STATIC && NULL != (hCtrlExisting = GetDlgItem (hDlgMaster, id)))
  871.                 //it's one of the controls pre-created by SHBrowseForFolder
  872.             {   //so don't move this one over -- adjust existing control for size, position, tab order
  873.                 RECT rc;
  874.                 GetWindowRect (hCtrlTemplate, &rc);
  875.                 MapWindowPoints (NULL, hDlgTemplate, (LPPOINT)&rc, 2);
  876.                 SetWindowPos (hCtrlExisting, NULL, rc.left, rc.top,
  877.                     rc.right - rc.left, rc.bottom - rc.top, SWP_NOACTIVATE | SWP_NOZORDER);
  878.                 DestroyWindow (hCtrlTemplate);
  879.                 //REVIEW
  880.                 //hack -- send control to end of tab order
  881.                 SetParent (hCtrlExisting, hDlgTemplate);
  882.                 SetParent (hCtrlExisting, hDlgMaster);
  883.             }
  884.             else    //we should move this control from template to master
  885.             {
  886.                 SetProp (hCtrlTemplate, szTransplacedProp, (HANDLE)TRUE);  //anything -- it's the existence of the prop that we check for
  887.                 SetParent (hCtrlTemplate, hDlgMaster);          //to know to move this control back later
  888.             }
  889.             hCtrlTemplate = hNextCtrl;
  890.         }
  891.         // Let Template know about the child so that it can forward WM_COMMAND notifications to it
  892.         // to work around the fact that edit controls cache their parent pointers and ignore SetParents
  893.         // when it comes to sending parent notifications
  894.         SetProp(hDlgTemplate, szOriginalWND, hDlgMaster);
  895.     }
  896.         break;
  897.     case WM_COMMAND:
  898.         // Workaround for above bug
  899.         SendMessage((HWND)GetProp(hDlgTemplate, szOriginalWND), uMsg, wParam, lParam);
  900.         break;
  901.     }
  902.     return FALSE;
  903. }
  904. int CALLBACK BFFFavCallback(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
  905. {
  906.     switch (uMsg)
  907.     {
  908.         case BFFM_INITIALIZED:
  909.         {
  910.             ADDTOFAV* patf = (ADDTOFAV*)lpData;
  911.             ASSERT (patf);
  912.             HWND hDlgTemp = CreateDialogParam(MLGetHinst(), 
  913.                                 MAKEINTRESOURCE(IDD_ADDTOFAVORITES_TEMPLATE),
  914.                                 NULL, MergeFavoritesDialogControls, (LPARAM)hwnd);
  915.             //this results in all the controls being copied over
  916.             
  917.             //if successful, make our other modifications
  918.             BFFFAVSUBSTRUCT * pbffFavSubStruct;
  919.             if ((IsWindow(GetDlgItem(hwnd, IDC_SUBSCRIBE_CUSTOMIZE)))   //verify existence of randomly-selected control
  920.                 && (pbffFavSubStruct = (BFFFAVSUBSTRUCT *) LocalAlloc(LPTR, sizeof(BFFFAVSUBSTRUCT))))
  921.             {
  922.                 //done with template, but don't destroy it:
  923.                 //see MSKB Q84190, owner/owned vs parent/child -- the children
  924.                 // of template are now children of master, but still OWNED
  925.                 // by template, and are destroyed when template is destroyed...
  926.                 // this kind of sucks, but we'll just keep template around
  927.                 // invisibly.
  928.                 //we'll take care of it when we go away
  929.                 //BUGBUG do we need to do SetDefaultDialogFont stuff for localization still, since it all comes from the .rc?
  930.                 //set up window stuff for subclass:
  931.                 // Get the TreeView control so we can muck with the style bits and move it down
  932.                 HWND hwndT;
  933.                 if (hwndT = GetDlgItem(hwnd, IDD_FOLDERLIST))
  934.                 {
  935.                     DWORD dwStyle = GetWindowLong(hwndT, GWL_STYLE);
  936.                     dwStyle |= TVS_SHOWSELALWAYS;
  937.                     dwStyle &= ~TVS_LINESATROOT;
  938.                     SetWindowLong(hwndT, GWL_STYLE, dwStyle);
  939.                 }
  940.                 // don't allow subscriptions if the URL is not "http:" protocol, or if already subscribed
  941.                 TCHAR szURL[MAX_URL_STRING];
  942.                 if (!patf->pidlFavorite ||
  943.                     FAILED(IEGetDisplayName(patf->pidlFavorite, szURL, SHGDN_FORPARSING)) ||
  944.                     SHRestricted2(REST_NoAddingSubscriptions, szURL, 0) ||
  945.                     !IsSubscribable(szURL) ||
  946.                     !IsFeaturePotentiallyAvailable(CLSID_SubscriptionMgr) ||
  947.                     !IsBrowserFrameOptionsPidlSet(patf->pidlFavorite, BFO_USE_IE_OFFLINE_SUPPORT))
  948.                 {
  949.                     CheckDlgButton(hwnd, IDC_MAKE_OFFLINE, 0);
  950.                     EnableWindow(GetDlgItem (hwnd, IDC_MAKE_OFFLINE), FALSE);
  951.                     EnableWindow(GetDlgItem (hwnd, IDC_SUBSCRIBE_CUSTOMIZE), FALSE);
  952.                 }
  953.                 else if (IsSubscribed(patf))
  954.                 {
  955.                     patf->bStartSubscribed = TRUE;
  956.                     CheckDlgButton(hwnd, IDC_MAKE_OFFLINE, 1);
  957.                 }
  958.                 else if (patf->bIsSoftdist)
  959.                 {
  960.                     CheckDlgButton(hwnd, IDC_MAKE_OFFLINE, 1);
  961.                 }
  962.                 EnableWindow(GetDlgItem(hwnd, IDC_SUBSCRIBE_CUSTOMIZE),
  963.                              IsDlgButtonChecked(hwnd, IDC_MAKE_OFFLINE));
  964.                 //set the name
  965.                 Edit_LimitText(GetDlgItem(hwnd, IDC_FAVORITE_NAME), MAX_PATH - 1);
  966.                 // Use URL if title string is not displayable
  967.                 if (SHIsDisplayable(patf->pszFile, g_fRunOnFE, g_bRunOnNT5))
  968.                 {  
  969.                     SetDlgItemText(hwnd, IDC_FAVORITE_NAME, patf->pszFile);
  970.                 }
  971.                 else
  972.                 {
  973.                     TCHAR szUrlTemp[MAX_URL_STRING];
  974.                     IEGetDisplayName(patf->pidlFavorite, szUrlTemp, SHGDN_FORPARSING);
  975.                     SetDlgItemText(hwnd, IDC_FAVORITE_NAME, szUrlTemp);
  976.                 }
  977.                 EnableOKButtonFromID(hwnd, IDC_FAVORITE_NAME);
  978.                 // hide the (empty) SHBrowseForFolder prompt control
  979.                 ShowWindow(GetDlgItem (hwnd, IDD_BROWSETITLE), SW_HIDE);
  980.                 // Fill out the structure and set it as a property so that our subclass
  981.                 // proc can get to this data.
  982.                 pbffFavSubStruct->lpfnOldWndProc = (WNDPROC) SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)BFFFavSubclass);
  983.                 pbffFavSubStruct->hwndNew = GetDlgItem(hwnd, IDC_FAVORITE_NEWFOLDER);
  984.                 pbffFavSubStruct->patf = patf;
  985.                 pbffFavSubStruct->hwndTV = GetDlgItem(hwnd, IDC_SUBSCRIBE_FOLDERLIST_PLACEHOLDER);
  986.                 pbffFavSubStruct->hwndSave = GetDlgItem(hwnd, IDC_FAVORITE_CREATEIN);
  987.                 pbffFavSubStruct->hTemplateWnd = hDlgTemp;  //save for explicit destruction later
  988.                 GetWindowRect(hwnd, &(pbffFavSubStruct->rcRestored));
  989.                 SetProp(hwnd, ADDTOFAVPROP, (HANDLE)pbffFavSubStruct);
  990.                 patf->pidlSelected = ILClone(patf->pidl);
  991.                 DWORD dwType, dwValue = 0, dwcData = sizeof(dwValue);
  992.                 TCHAR szBuffer[100];
  993.                 
  994.                 SHRegGetUSValue(TEXT("Software\Microsoft\Internet Explorer\Main"), TEXT("AddToFavoritesExpanded"),
  995.                         &dwType, &dwValue, &dwcData, 0, NULL, sizeof(dwValue));
  996.                 if (dwValue == 0)
  997.                 {
  998.                     int lRet = MLLoadString(IDS_FAVS_ADVANCED_EXPAND, szBuffer, ARRAYSIZE(szBuffer));
  999.                     ASSERT(lRet);
  1000.                     // Disable the tree view and new button so that we can't tab to them.
  1001.                     EnableWindow(GetDlgItem (hwnd, IDC_SUBSCRIBE_FOLDERLIST_PLACEHOLDER), FALSE);
  1002.                     EnableWindow(GetDlgItem (hwnd, IDC_FAVORITE_NEWFOLDER), FALSE);
  1003.                     // hide the bottom part of the dialog
  1004.                     int cx, cy;
  1005.                     RECT rc;
  1006.                     GetWindowRect (GetDlgItem (hwnd, IDC_SUBSCRIBE_FOLDERLIST_PLACEHOLDER), &rc);
  1007.                     cy = rc.top;
  1008.                     GetWindowRect (hwnd, &rc);
  1009.                     cx = rc.right - rc.left;
  1010.                     cy = cy /*top of ctrl*/ - rc.top; /*top of window*/
  1011.                     SetWindowPos (hwnd, NULL, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER);
  1012.                 }
  1013.                 else
  1014.                 {
  1015.                     //don't show New Folder button for channels in the channels folder,
  1016.                     // see code for case IDC_FAVORITE_NEWFOLDER for why
  1017.                     if (patf->subsType == SUBSTYPE_CHANNEL)
  1018.                     {
  1019.                         LPITEMIDLIST pidlFavs = NULL;
  1020.                         TCHAR tzFavsPath[MAX_PATH];
  1021.                     
  1022.                         if (SUCCEEDED(SHGetSpecialFolderLocation(hwnd, CSIDL_FAVORITES, &pidlFavs)) 
  1023.                         && SUCCEEDED(SHGetNameAndFlags(pidlFavs, SHGDN_FORPARSING | SHGDN_FORADDRESSBAR, tzFavsPath, SIZECHARS(tzFavsPath), NULL))
  1024.                         && 0 == StrCmpNI(tzFavsPath, patf->pszInitDir, ARRAYSIZE(tzFavsPath)))
  1025.                         {
  1026.                             EnableWindow(pbffFavSubStruct->hwndNew, TRUE);
  1027.                         }
  1028.                         else
  1029.                             EnableWindow(pbffFavSubStruct->hwndNew, FALSE);
  1030.                         if(pidlFavs)
  1031.                             ILFree(pidlFavs);
  1032.                     }
  1033.                     else
  1034.                         EnableWindow(pbffFavSubStruct->hwndNew, TRUE);
  1035.                     
  1036.                     int lRet = MLLoadString(IDS_FAVS_ADVANCED_COLLAPSE, szBuffer, ARRAYSIZE(szBuffer));
  1037.                     ASSERT(lRet);
  1038.                 }
  1039.                 SetWindowText(GetDlgItem(hwnd, IDC_FAVORITE_CREATEIN), szBuffer);
  1040.                 
  1041.             }
  1042.             else
  1043.             {
  1044.                 EndDialog(hwnd, IDCANCEL);
  1045.             }
  1046.             break;
  1047.         }
  1048.         case BFFM_SELCHANGED:
  1049.         {
  1050.             //the first of these comes during BFFM_INITIALIZED, so ignore it
  1051.             if (((ADDTOFAV *)lpData)->pidlSelected != NULL)
  1052.             {
  1053.                 ILFree(((ADDTOFAV *)lpData)->pidlSelected);
  1054.                 ((ADDTOFAV *)lpData)->pidlSelected = ILClone((LPITEMIDLIST)lParam);
  1055.             }
  1056.             break;
  1057.         }
  1058.     }
  1059.     return 0;
  1060. }
  1061. // This API is not exported.  See below (DoAddToFavDlg) for the exported version
  1062. //
  1063. // hwnd        parent window for the dialog.
  1064. // pszInitDir  input: initial path
  1065. //             output: fully qualified path and filename
  1066. // chInitDir   Length of pszInitDir buffer
  1067. // pszFile     initial (default) filename for shortcut
  1068. // cchFile     Length of pszFile buffer
  1069. // pidlBrowse  associated with pszInitDir
  1070. //
  1071. // Returns:
  1072. //  TRUE if a directory and filename were selected by user, and no error
  1073. //  occurs.  In this case pszInitDir contains the new destination directory
  1074. //  and filename, pszFile contains the new file name.
  1075. //
  1076. //  FALSE if an error occurs or the user selects CANCEL.
  1077. STDAPI_(BOOL) DoAddToFavDlgEx(HWND hwnd, 
  1078.                             TCHAR *pszInitDir, UINT cchInitDir,
  1079.                             TCHAR *pszFile, UINT cchFile, 
  1080.                             LPITEMIDLIST pidlBrowse,
  1081.                             LPCITEMIDLIST pidlFavorite,
  1082.                             FAVDLGTYPE atfDlgType,
  1083.                             SUBSCRIPTIONINFO* pInfo)
  1084. {
  1085.     ADDTOFAV atf = {pszInitDir, cchInitDir - 1, pszFile, cchFile - 1, pidlBrowse, NULL,
  1086.                     pidlFavorite, atfDlgType, {sizeof(SUBSCRIPTIONINFO), 0}, SUBSTYPE_URL };
  1087.     TCHAR szTemp[1];    //NOTE: we're not using SHBrowseForFolder's prompt string (see below)
  1088.     TCHAR szDisplayName[MAX_PATH];
  1089.     BROWSEINFO bi = {
  1090.             hwnd,
  1091.             pidlBrowse,
  1092.             szDisplayName,
  1093.             szTemp,
  1094.             BIF_RETURNONLYFSDIRS,
  1095.             // (BFFCALLBACK)
  1096.             BFFFavCallback,
  1097.             (LPARAM)&atf,
  1098.             0
  1099.     };
  1100.     LPITEMIDLIST pidl;
  1101.     if (pInfo)
  1102.         atf.siSubsInProg = *pInfo;
  1103.     switch (atfDlgType)
  1104.     {
  1105.         case ATF_CHANNEL_SOFTDIST:
  1106.             atf.bIsSoftdist = TRUE;
  1107.             //  fall through
  1108.         case ATF_CHANNEL:
  1109.             atf.subsType = SUBSTYPE_CHANNEL;
  1110.             break;
  1111.         //default:
  1112.         //  set in initialize to SUBSTYPE_URL
  1113.     }
  1114.     //MLLoadString(IDS_FAVS_BROWSETEXT, szTemp, ARRAYSIZE(szTemp));
  1115.     //this string is now in the template dialog in the .rc
  1116.     //REVIEW -- do we want to do it this way (we're hiding SHBrowse...'s control)? then the template dialog looks more like the finished product...
  1117.     szTemp[0] = 0;
  1118.  
  1119.     //init native font control, otherwise dialog may fail to initialize
  1120.     {
  1121.         INITCOMMONCONTROLSEX icc;
  1122.         icc.dwSize = sizeof(INITCOMMONCONTROLSEX);
  1123.         icc.dwICC = ICC_NATIVEFNTCTL_CLASS;
  1124.         InitCommonControlsEx(&icc);
  1125.     }
  1126.     
  1127.     pidl = SHBrowseForFolder(&bi);
  1128.     if (pidl)
  1129.     {
  1130.         ILFree(pidl);
  1131.     }
  1132.     //  If the user created a new subscription, start a download.
  1133.     if (atf.bSubscribed && !atf.bStartSubscribed)
  1134.     {
  1135.         ISubscriptionMgr* pSubsMgr;
  1136.         if (SUCCEEDED (CoCreateInstance(CLSID_SubscriptionMgr, NULL, CLSCTX_INPROC_SERVER,
  1137.                                         IID_ISubscriptionMgr, (void**)&pSubsMgr)))
  1138.         {
  1139.             WCHAR wszURL[MAX_URL_STRING];
  1140.             IEGetDisplayName(atf.pidlFavorite, wszURL, SHGDN_FORPARSING);
  1141.             pSubsMgr->UpdateSubscription(wszURL);
  1142.             pSubsMgr->Release();
  1143.         }
  1144.     }
  1145.     return (pidl != NULL);
  1146. }
  1147. STDAPI_(BOOL) DoSafeAddToFavDlgEx(HWND hwnd, 
  1148.                             TCHAR *pszInitDir, UINT cchInitDir,
  1149.                             TCHAR *pszFile, UINT cchFile, 
  1150.                             LPITEMIDLIST pidlBrowse,
  1151.                             LPCITEMIDLIST pidlFavorite,
  1152.                             FAVDLGTYPE atfDlgType,
  1153.                             SUBSCRIPTIONINFO* pInfo)
  1154. {
  1155.     BOOL fRet;
  1156.     if (IEIsLinkSafe(hwnd, pidlFavorite, ILS_ADDTOFAV))
  1157.     {
  1158.         fRet = DoAddToFavDlgEx(hwnd, pszInitDir, cchInitDir, pszFile, cchFile,
  1159.                                pidlBrowse, pidlFavorite, atfDlgType, pInfo);
  1160.     }
  1161.     else
  1162.     {
  1163.         fRet = FALSE;
  1164.     }
  1165.     return fRet;
  1166. }
  1167. // This API is exported so that it may be called by explorer and mshtml (and MSNVIEWR.EXE)
  1168. // in addition to being called internally by shdocvw.
  1169. // THEREFORE YOU MUST NOT CHANGE THE SIGNATURE OF THIS API
  1170. //
  1171. STDAPI_(BOOL) DoAddToFavDlg(HWND hwnd, 
  1172.                             CHAR *pszInitDir, UINT cchInitDir,
  1173.                             CHAR *pszFile, UINT cchFile, 
  1174.                             LPITEMIDLIST pidlBrowse)
  1175. {
  1176.     BOOL fRet;
  1177.     WCHAR szInitDir[MAX_PATH];
  1178.     WCHAR szFile[MAX_PATH];
  1179.     SHAnsiToUnicode(pszInitDir, szInitDir, ARRAYSIZE(szInitDir));
  1180.     SHAnsiToUnicode(pszFile, szFile, ARRAYSIZE(szFile));
  1181.     fRet = DoSafeAddToFavDlgEx(hwnd, szInitDir, ARRAYSIZE(szInitDir), szFile, ARRAYSIZE(szFile), pidlBrowse, NULL, ATF_FAVORITE, NULL);
  1182.     SHUnicodeToAnsi(szInitDir, pszInitDir, cchInitDir);
  1183.     SHUnicodeToAnsi(szFile, pszFile, cchFile);
  1184.     return fRet;
  1185. }
  1186. STDAPI_(BOOL) DoAddToFavDlgW(HWND hwnd, 
  1187.                              WCHAR *pszInitDir, UINT cchInitDir,
  1188.                              WCHAR *pszFile, UINT cchFile, 
  1189.                              LPITEMIDLIST pidlBrowse)
  1190. {
  1191.     return DoSafeAddToFavDlgEx(hwnd, pszInitDir, cchInitDir, pszFile, cchFile, pidlBrowse, NULL, ATF_FAVORITE, NULL);
  1192. }
  1193. STDAPI AddToFavoritesEx(HWND hwnd, LPCITEMIDLIST pidlCur, LPCTSTR pszTitle, DWORD dwFlags,
  1194.                         SUBSCRIPTIONINFO *pInfo, IOleCommandTarget *pCommandTarget, IHTMLDocument2 *pDoc);
  1195. STDAPI AddToChannelsEx (HWND hwnd, LPCITEMIDLIST pidlUrl, LPTSTR pszName, LPCWSTR pwszURL,
  1196.                         DWORD dwFlags, SUBSCRIPTIONINFO* pInfo);
  1197. STDAPI SubscribeFromFavorites (HWND hwnd, LPCITEMIDLIST pidlUrl, LPTSTR pszName, DWORD dwFlags,
  1198.                                SUBSCRIPTIONTYPE subsType, SUBSCRIPTIONINFO *pInfo);
  1199. // This API is exported privately, and is called by ISubscriptionMgr::CreateSubscription.
  1200. // shuioc uses it too.
  1201. STDAPI SHAddSubscribeFavoriteEx (
  1202.         HWND hwnd, 
  1203.         LPCWSTR pwszURL, 
  1204.         LPCWSTR pwszName, 
  1205.         DWORD dwFlags,
  1206.         SUBSCRIPTIONTYPE subsType, 
  1207.         SUBSCRIPTIONINFO* pInfo, 
  1208.         IOleCommandTarget *pcmdt,
  1209.         IHTMLDocument2 *pDoc)
  1210. {
  1211.     TCHAR           szName[MAX_PATH];
  1212.     LPITEMIDLIST    pidl = NULL;
  1213.     HRESULT         hr;
  1214.     
  1215.     if (pwszURL==NULL || pwszName == NULL)
  1216.         return E_INVALIDARG;
  1217.     //
  1218.     // Need to put pwszName into a buffer because it comes in const
  1219.     // but gets modified in SubscribeFromFavorites.
  1220.     //
  1221.     StrCpyN(szName, pwszName, ARRAYSIZE(szName));
  1222.     hr = IECreateFromPath(pwszURL, &pidl);
  1223.     if (SUCCEEDED(hr))
  1224.     {
  1225.         ASSERT (pidl);
  1226.         if (dwFlags & CREATESUBS_FROMFAVORITES)
  1227.         {
  1228.             if (subsType != SUBSTYPE_URL && subsType != SUBSTYPE_CHANNEL)
  1229.             {
  1230.                 ASSERT(0);
  1231.                 hr = E_INVALIDARG;
  1232.             }
  1233.             else
  1234.             {
  1235.                 hr = SubscribeFromFavorites (hwnd, pidl, szName, dwFlags, subsType, pInfo);
  1236.             }
  1237.         }
  1238.         else
  1239.         {
  1240.             if (subsType == SUBSTYPE_URL)
  1241.             {
  1242.                 hr = AddToFavoritesEx (hwnd, pidl, szName, dwFlags, pInfo, pcmdt, pDoc);
  1243.             }
  1244.             else if (subsType == SUBSTYPE_CHANNEL && !SHIsRestricted2W(hwnd, REST_NoChannelUI, NULL, 0))
  1245.             {
  1246.                 hr = AddToChannelsEx (hwnd, pidl, szName, pwszURL, dwFlags, pInfo);
  1247.             }
  1248.             else
  1249.             {
  1250.                 ASSERT (0);
  1251.                 hr = E_INVALIDARG;
  1252.             }
  1253.         }
  1254.         ILFree(pidl);
  1255.     }
  1256.     return hr;    
  1257. }
  1258. STDAPI SHAddSubscribeFavorite (HWND hwnd, LPCWSTR pwszURL, LPCWSTR pwszName, DWORD dwFlags,
  1259.                                SUBSCRIPTIONTYPE subsType, SUBSCRIPTIONINFO* pInfo)
  1260. {
  1261.     return SHAddSubscribeFavoriteEx ( hwnd, pwszURL, pwszName, dwFlags,
  1262.                                 subsType, pInfo, NULL, NULL);
  1263. }
  1264. // this API is also exported via the .def
  1265. // Use for backward compatibility only -- note that it is only for URL's (not channels)
  1266. // and doesn't know how to subscribe.
  1267. STDAPI AddUrlToFavorites(HWND hwnd, LPWSTR pszUrlW, LPWSTR pszTitleW, BOOL fDisplayUI)
  1268. {
  1269.     return SHAddSubscribeFavorite (hwnd, pszUrlW, pszTitleW,
  1270.         fDisplayUI ? CREATESUBS_NOUI : 0, SUBSTYPE_URL, NULL);
  1271. }
  1272. // this API is in the .h and is used elsewhere in shdocvw, but is not exported
  1273. // Backward compatibility only -- only for URL's (not channels) and can subscribe, but can't
  1274. // pass in subscriptioninfo starter.
  1275. STDAPI AddToFavorites(
  1276.     HWND hwnd, 
  1277.     LPCITEMIDLIST pidlCur, 
  1278.     LPCTSTR pszTitle, 
  1279.     BOOL fDisplayUI, 
  1280.     IOleCommandTarget *pCommandTarget,
  1281.     IHTMLDocument2 *pDoc)
  1282. {
  1283.     return AddToFavoritesEx (hwnd, pidlCur, pszTitle,
  1284.         fDisplayUI ? 0 : CREATESUBS_NOUI, NULL, pCommandTarget, pDoc);
  1285. }
  1286. //helper function to create one column in a ListView control, add one item to that column,
  1287. //size the column to the width of the control, and color the control like a static...
  1288. //basically, like SetWindowText for a ListView.  Because we use a lot of ListViews to display
  1289. //urls that would otherwise be truncated... the ListView gives us automatic ellipsis and ToolTip.
  1290. void SetListViewToString (HWND hLV, LPCTSTR pszString)
  1291. {
  1292.     ASSERT(hLV);
  1293.     
  1294.     LV_COLUMN   lvc = {0};
  1295.     RECT lvRect;
  1296.     GetClientRect (hLV, &lvRect);
  1297.     lvc.mask = LVCF_WIDTH;
  1298.     lvc.cx = lvRect.right - lvRect.left;
  1299.     if (-1 == ListView_InsertColumn(hLV, 0, &lvc))   {
  1300.         ASSERT(0);
  1301.     }
  1302.     SendMessage(hLV, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_INFOTIP, LVS_EX_INFOTIP);
  1303.     LV_ITEM lvi = {0};
  1304.     lvi.iSubItem = 0;
  1305.     lvi.pszText = (LPTSTR)pszString;
  1306.     lvi.mask = LVIF_TEXT;
  1307.     ListView_InsertItem(hLV, &lvi);
  1308.     ListView_EnsureVisible(hLV, 0, TRUE);
  1309.     
  1310.     ListView_SetBkColor(hLV, GetSysColor(COLOR_BTNFACE));
  1311.     ListView_SetTextBkColor(hLV, GetSysColor(COLOR_BTNFACE));
  1312. }
  1313. INT_PTR CALLBACK SubscribeFavoriteDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1314. {
  1315.     ADDTOFAV * patf = (ADDTOFAV*)GetProp(hDlg, ADDTOFAVPROP);
  1316.     switch (uMsg)
  1317.     {
  1318.     case WM_INITDIALOG:
  1319.         {
  1320.             TCHAR szURL[MAX_URL_STRING];
  1321.             patf = (ADDTOFAV*)lParam;
  1322.             SetProp(hDlg, ADDTOFAVPROP, (HANDLE)patf);
  1323.             //set up name and url displays
  1324.             SetDlgItemText (hDlg, IDC_CHANNEL_NAME, patf->pszFile);
  1325.             //url is in patf->pidlFavorite
  1326.             IEGetDisplayName(patf->pidlFavorite, szURL, SHGDN_FORPARSING);
  1327.             SetListViewToString (GetDlgItem (hDlg, IDC_CHANNEL_URL), szURL);
  1328.             //now the tricky part... this is for modifying the subscription associated with
  1329.             //an existing ChannelBar shortcut.  We need to find out if they are subscribed --
  1330.             //if so, load the existing subscription into memory so it can be modified in the
  1331.             //wizard.  If not, leave the information that was passed up because it's got the
  1332.             //schedule extracted from the CDF.  In either case, check the radio button that
  1333.             //corresponds to their current subscription level.
  1334.             ISubscriptionMgr* pSubsMgr;
  1335.             BOOL bSubs = FALSE;
  1336.             HRESULT hr = JITCoCreateInstance(CLSID_SubscriptionMgr, NULL, CLSCTX_INPROC_SERVER,
  1337.                                              IID_ISubscriptionMgr, (void**)&pSubsMgr, 
  1338.                                              hDlg, FIEF_FLAG_FORCE_JITUI | FIEF_FLAG_PEEK);
  1339.             if (SUCCEEDED(hr))
  1340.             {
  1341.                 pSubsMgr->IsSubscribed(szURL, &bSubs);
  1342.                 patf->bStartSubscribed = bSubs;
  1343.                 pSubsMgr->Release();
  1344.             }
  1345.             else if ((E_ACCESSDENIED == hr) || !IsBrowserFrameOptionsPidlSet(patf->pidlFavorite, BFO_USE_IE_OFFLINE_SUPPORT))
  1346.             {
  1347.                 EnableWindow(GetDlgItem(hDlg, IDC_MAKE_OFFLINE), FALSE);
  1348.             }
  1349.             if (!bSubs && patf->bIsSoftdist)
  1350.             {
  1351.                 bSubs = TRUE;
  1352.             }
  1353.             CheckDlgButton(hDlg, IDC_MAKE_OFFLINE, bSubs ? 1 : 0);
  1354.             EnableWindow(GetDlgItem (hDlg, IDC_SUBSCRIBE_CUSTOMIZE), bSubs);
  1355.         }
  1356.         break;
  1357.     case WM_DESTROY:
  1358.         RemoveProp (hDlg, ADDTOFAVPROP);
  1359.         break;
  1360.     case WM_HELP:
  1361.         SHWinHelpOnDemandWrap((HWND)((LPHELPINFO) lParam)->hItemHandle, c_szHelpFile,
  1362.             HELP_WM_HELP, (DWORD_PTR)(LPTSTR) (patf->iDlgType == ATF_FAVORITE
  1363.                             ? aAddToFavHelpIDs : aAddToChanHelpIDs));
  1364.         return TRUE;
  1365.         break;
  1366.     case WM_CONTEXTMENU:
  1367.         SHWinHelpOnDemandWrap((HWND) wParam, c_szHelpFile, HELP_CONTEXTMENU,
  1368.             (DWORD_PTR)(LPVOID) (patf->iDlgType == ATF_FAVORITE
  1369.                          ? aAddToFavHelpIDs : aAddToChanHelpIDs));
  1370.         return TRUE;
  1371.         break;
  1372.     case WM_COMMAND:
  1373.         ASSERT (patf);
  1374.         switch (GET_WM_COMMAND_ID(wParam, lParam))
  1375.         {
  1376.         case IDCANCEL:
  1377.             EndDialog(hDlg, IDCANCEL);
  1378.             break;
  1379.         case IDOK:
  1380.             // first, make sure they're not trying to subscribe to an authenticated
  1381.             // channel without entering a password.
  1382.             if (SubscriptionFailsChannelAuthentication (hDlg, &patf->siSubsInProg))
  1383.                 return FALSE;
  1384.             //find out whether they WERE subscribed, so if they click OK and they
  1385.             //were already subscribed, we delete that subscription -- and either leave it
  1386.             //deleted if "No subs" was the choice, or create the new one.
  1387.             ISubscriptionMgr* pSubsMgr;
  1388.             if (SUCCEEDED (JITCoCreateInstance(CLSID_SubscriptionMgr, NULL, CLSCTX_INPROC_SERVER,
  1389.                                             IID_ISubscriptionMgr, (void**)&pSubsMgr, 
  1390.                                             hDlg, FIEF_FLAG_FORCE_JITUI)))
  1391.             {
  1392.                 //url is in patf->pidlFavorite
  1393.                 TCHAR szURL[MAX_URL_STRING];
  1394.                 IEGetDisplayName(patf->pidlFavorite, szURL, SHGDN_FORPARSING);
  1395.                 BOOL bAlreadySubs;
  1396.                 if (SUCCEEDED (pSubsMgr->IsSubscribed (szURL, &bAlreadySubs)) && bAlreadySubs)
  1397.                 {
  1398.                     pSubsMgr->DeleteSubscription(szURL, NULL);
  1399.                 }
  1400.                 pSubsMgr->Release();
  1401.             }
  1402.             if (IsDlgButtonChecked (hDlg, IDC_MAKE_OFFLINE))
  1403.             {
  1404.                //they want to subscribe!  save subscription we already have in memory
  1405.                 patf->bSubscribed = StartSiteSubscription (hDlg, patf, TRUE);
  1406.             }
  1407.             EndDialog(hDlg, IDOK);
  1408.             break;
  1409.         //BUGBUG common code with ATF dialog
  1410.         case IDC_SUBSCRIBE_CUSTOMIZE:
  1411.             //need to create -- but not store -- subscription
  1412.             //need to (temporarily) trash patf->pidlFavorite so that we can go through the
  1413.             //wizard without colliding with an existing subscription.  When we actually create
  1414.             //the subscription, we'll use the real name.
  1415.             LPCITEMIDLIST pidlSave = patf->pidlFavorite;
  1416.             TCHAR szUrlTemp[MAX_URL_STRING+1];
  1417.             IEGetDisplayName(patf->pidlFavorite, szUrlTemp, SHGDN_FORPARSING);
  1418.             StrCat (szUrlTemp, TEXT("."));   //just put something nearly invisible on the end
  1419.             if (SUCCEEDED (IECreateFromPath(szUrlTemp, (LPITEMIDLIST*)&patf->pidlFavorite)))
  1420.             {
  1421.                 if (StartSiteSubscription (hDlg, patf, FALSE))
  1422.                     SendMessage (hDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hDlg, IDOK), TRUE);
  1423.                 ILFree ((LPITEMIDLIST)patf->pidlFavorite);
  1424.             }
  1425.             patf->pidlFavorite = pidlSave;
  1426.             break;
  1427.         }
  1428.         break;
  1429.     }
  1430.     return FALSE;
  1431. }
  1432. static const int CREATESUBS_ACTIVATE = 0x8000;      //hidden flag meaning channel is already on system
  1433. STDAPI SubscribeFromFavorites (HWND hwnd, LPCITEMIDLIST pidlUrl, LPTSTR pszName, DWORD dwFlags,
  1434.                                SUBSCRIPTIONTYPE subsType, SUBSCRIPTIONINFO *pInfo)
  1435. {
  1436.     //used to subscribe to a channel that's already in the Favorites
  1437.     //or a URL that's already a Favorite
  1438.     //flags are same as ISubscriptionMgr::CreateSubscription
  1439.     //display our part of the fav's dialog -- no need to go through SHBrowseForFolder
  1440.     //or any of that, just our radio buttons in a fixed-size dialog with our own DlgProc
  1441.     INT_PTR iDlgResult;
  1442.     HRESULT hr = S_OK;
  1443.     ADDTOFAV atf = {0};
  1444.     atf.pszFile = pszName;
  1445.     atf.siSubsInProg.cbSize = sizeof(SUBSCRIPTIONINFO);
  1446.     if (pInfo && pInfo->cbSize == sizeof(SUBSCRIPTIONINFO))
  1447.         atf.siSubsInProg = *pInfo;
  1448.     atf.subsType = subsType;
  1449.     //figure out what dialog to use
  1450.     atf.iDlgType = (subsType == SUBSTYPE_URL ? ATF_FAVORITE :
  1451.         (dwFlags & CREATESUBS_ACTIVATE ? ATF_CHANNEL_MODIFY : ATF_CHANNEL));
  1452.     //BUGBUG do we potentially need ANOTHER dialog type for softdist channels?
  1453.     if (dwFlags & CREATESUBS_SOFTWAREUPDATE)
  1454.     {
  1455.         atf.bIsSoftdist = TRUE;
  1456.     }
  1457.     atf.pidlFavorite = pidlUrl;
  1458. #ifdef OLD_FAVORITES
  1459.     int iTemplate;
  1460.     switch (atf.iDlgType)
  1461.     {
  1462.     case ATF_CHANNEL_SOFTDIST: //BUGBUG inappropriate, but it doesn't currently get used
  1463.     case ATF_CHANNEL:
  1464.         iTemplate = IDD_SUBSCRIBE_FAV_CHANNEL;
  1465.         break;
  1466.     case ATF_CHANNEL_MODIFY:
  1467.         iTemplate = IDD_ACTIVATE_PLATINUM_CHANNEL;
  1468.         break;
  1469.     case ATF_FAVORITE:
  1470.         iTemplate = IDD_SUBSCRIBE_FAVORITE;
  1471.         break;
  1472.     }
  1473.     iDlgResult = DialogBoxParam(MLGetHinst(), MAKEINTRESOURCE(iTemplate), hwnd,
  1474.             (DLGPROC)SubscribeFavoriteDlgProc, (LPARAM)&atf);
  1475. #endif
  1476.     iDlgResult = DialogBoxParam(MLGetHinst(), MAKEINTRESOURCE(IDD_ADDTOFAVORITES_TEMPLATE), hwnd,
  1477.             (DLGPROC)SubscribeFavoriteDlgProc, (LPARAM)&atf);
  1478.     switch (iDlgResult)
  1479.     {
  1480.     case -1:
  1481.         hr = E_FAIL;
  1482.         break;
  1483.     case IDCANCEL:
  1484.         hr = S_FALSE;
  1485.         break;
  1486.     default:
  1487.         if (pInfo && (pInfo->cbSize == sizeof(SUBSCRIPTIONINFO))
  1488.                   && (dwFlags & CREATESUBS_NOSAVE))
  1489.             *pInfo = atf.siSubsInProg;
  1490.         hr = S_OK;
  1491.         break;
  1492.     }
  1493.     return hr;
  1494. }
  1495. STDAPI AddToChannelsEx (HWND hwnd, LPCITEMIDLIST pidlUrl, LPTSTR pszName, LPCWSTR pwszURL,
  1496.                         DWORD dwFlags, SUBSCRIPTIONINFO* pInfo)
  1497. {
  1498.     HRESULT hr = S_OK;
  1499.     IChannelMgrPriv* pIChannelMgrPriv;
  1500.     hr = JITCoCreateInstance(CLSID_ChannelMgr, NULL, CLSCTX_INPROC_SERVER,
  1501.                           IID_IChannelMgrPriv, (void**)&pIChannelMgrPriv, 
  1502.                           hwnd, FIEF_FLAG_FORCE_JITUI);
  1503.     if (SUCCEEDED(hr))
  1504.     {
  1505.         if (S_OK == pIChannelMgrPriv->IsChannelInstalled (pwszURL))
  1506.         {
  1507.             hr = SubscribeFromFavorites (hwnd, pidlUrl, pszName, dwFlags | CREATESUBS_ACTIVATE,
  1508.                 SUBSTYPE_CHANNEL, pInfo);
  1509.         }
  1510.         else
  1511.         {
  1512.             LPITEMIDLIST pidlChannelFolder;
  1513.             TCHAR szPath[MAX_PATH];
  1514.             TCHAR szCFPath[MAX_PATH];
  1515.             ASSERT(pIChannelMgrPriv);
  1516.             IChannelMgrPriv::CHANNELFOLDERLOCATION cflLocation =
  1517.                 ((dwFlags & CREATESUBS_SOFTWAREUPDATE) ?
  1518.                     IChannelMgrPriv::CF_SOFTWAREUPDATE :
  1519.                     IChannelMgrPriv::CF_CHANNEL);
  1520.             hr = pIChannelMgrPriv->GetChannelFolder(&pidlChannelFolder, cflLocation);
  1521.             if (SUCCEEDED (hr))
  1522.             {
  1523.                 //
  1524.                 // Change IChannelMgrPriv to unicode!  This has to get fixed to
  1525.                 // support a unicode "Channels" name. (edwardp)
  1526.                 //
  1527.                 CHAR szBuff[MAX_PATH];
  1528.                 hr = pIChannelMgrPriv->GetChannelFolderPath (szBuff, ARRAYSIZE(szBuff), cflLocation);
  1529.                 if (SUCCEEDED(hr))
  1530.                     SHAnsiToUnicode(szBuff, szCFPath, ARRAYSIZE(szCFPath));
  1531.                 
  1532.                 if (SUCCEEDED (hr))
  1533.                 {
  1534.                     TCHAR szDspName[MAX_URL_STRING];
  1535.                     DWORD cchDspName = ARRAYSIZE(szDspName);
  1536.                     StrCpyN(szPath, szCFPath, ARRAYSIZE(szPath));
  1537.             
  1538.                     // When we create a short cut for the URL, we have to make sure it's readable for
  1539.                     // the end user. PrepareURLForDisplay() will unescape the string if it's escaped.
  1540.                     if (!UrlIs(pszName, URLIS_URL) ||
  1541.                         !PrepareURLForDisplay(pszName, szDspName, &cchDspName))
  1542.                     {
  1543.                         // Unescaping wasn't wanted or didn't work.
  1544.                         StrCpyN(szDspName, pszName, ARRAYSIZE(szDspName));
  1545.                     }
  1546.                          
  1547.                     PathCleanupSpec(szPath, szDspName);
  1548.                     FAVDLGTYPE iDlgType = (dwFlags & CREATESUBS_SOFTWAREUPDATE ? ATF_CHANNEL_SOFTDIST : ATF_CHANNEL);
  1549.                     if ((dwFlags & CREATESUBS_NOUI) || 
  1550.                         DoSafeAddToFavDlgEx(hwnd, szPath, ARRAYSIZE(szPath), 
  1551.                                         szDspName, ARRAYSIZE(szDspName), pidlChannelFolder,
  1552.                                         pidlUrl, iDlgType, pInfo))
  1553.                     {
  1554.                         //we create the channelbar entry here, instead of cdfview, because here
  1555.                         //we know where in the channels folder the user wants it to go.
  1556.                         IChannelMgr* pChannelMgr = NULL;
  1557.                         hr = pIChannelMgrPriv->QueryInterface (IID_IChannelMgr, (void**)&pChannelMgr);
  1558.                         if (SUCCEEDED (hr))
  1559.                         {
  1560.                             //prepare strings
  1561.                             PathRemoveExtension(szPath);
  1562.                             //strip off absolute part of folder path, and convert to Unicode
  1563.                             int cchCommon = PathCommonPrefix (szPath, szCFPath, NULL);
  1564.                             //pack in the info we have
  1565.                             CHANNELSHORTCUTINFO csiChannel = {0};
  1566.                             csiChannel.cbSize = sizeof(csiChannel);
  1567.                             csiChannel.pszTitle = szPath + cchCommon;
  1568.                             csiChannel.pszURL = (LPWSTR)pwszURL;
  1569.                             csiChannel.bIsSoftware = (dwFlags & CREATESUBS_SOFTWAREUPDATE) ? TRUE : FALSE;
  1570.                             //and tell the channel mgr to add the channel
  1571.                             hr = pChannelMgr->AddChannelShortcut (&csiChannel);
  1572.                             pChannelMgr->Release();
  1573.                         }
  1574.                     }
  1575.                     else
  1576.                     {
  1577.                         hr = S_FALSE;       //no failure, but no add
  1578.                     }
  1579.                 }
  1580.                 ILFree (pidlChannelFolder);
  1581.             }
  1582.         }
  1583.         pIChannelMgrPriv->Release();
  1584.     }
  1585.     return hr;
  1586. }
  1587. STDAPI AddToFavoritesEx(
  1588.     HWND hwnd, 
  1589.     LPCITEMIDLIST pidlCur, 
  1590.     LPCTSTR pszTitle,
  1591.     DWORD dwFlags, 
  1592.     SUBSCRIPTIONINFO *pInfo, 
  1593.     IOleCommandTarget *pCommandTarget,
  1594.     IHTMLDocument2 *pDoc)
  1595. {
  1596.     HRESULT hres = S_FALSE;
  1597.     HCURSOR hCursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1598.     if (pidlCur)
  1599.     {
  1600.         TCHAR szName[MAX_URL_STRING];
  1601.         TCHAR szPath[MAX_PATH];
  1602.         if (pszTitle)
  1603.         {
  1604.             StrCpyN(szName, pszTitle, ARRAYSIZE(szName));
  1605.         }
  1606.         else
  1607.         {
  1608.             szName[0] = 0;
  1609.             IEGetNameAndFlags(pidlCur, SHGDN_INFOLDER | SHGDN_NORMAL, szName, SIZECHARS(szName), NULL);
  1610.         }
  1611.         LPITEMIDLIST pidlFavorites;
  1612.         if (SHGetSpecialFolderPath(NULL, szPath, CSIDL_FAVORITES, TRUE) &&
  1613.             (pidlFavorites = SHCloneSpecialIDList(NULL, CSIDL_FAVORITES, TRUE)))
  1614.         {
  1615.             TCHAR szDspName[MAX_PATH];
  1616.             DWORD cchDspName = ARRAYSIZE(szDspName);
  1617.             
  1618.             // When we create a short cut for the URL, we have to make sure it's readable for
  1619.             // the end user. PrepareURLForDisplay() will unescape the string if it's escaped.
  1620.             if (!UrlIs(szName, URLIS_URL) ||
  1621.                 !PrepareURLForDisplay(szName, szDspName, &cchDspName))
  1622.             {
  1623.                 // Unescaping wasn't wanted or didn't work.
  1624.                 StrCpyN(szDspName, szName, ARRAYSIZE(szDspName));
  1625.             }
  1626.             PathCleanupSpec(szPath, szDspName);
  1627.             // if left with spaces only, use the filename friendly version of the url instead.
  1628.             StrTrim(szDspName, L" ");
  1629.             if (szDspName[0] == 0)
  1630.             {
  1631.                 if (SUCCEEDED(IEGetNameAndFlags(pidlCur, SHGDN_FORPARSING, szDspName, ARRAYSIZE(szDspName), NULL)))
  1632.                     PathCleanupSpec(szPath, szDspName);
  1633.             }
  1634.             BOOL fDisplayUI = (dwFlags & CREATESUBS_NOUI) ? FALSE : TRUE;
  1635.             if (!fDisplayUI || 
  1636.                 DoSafeAddToFavDlgEx(hwnd, szPath, ARRAYSIZE(szPath), 
  1637.                                     szDspName, ARRAYSIZE(szDspName), pidlFavorites,
  1638.                                     pidlCur, ATF_FAVORITE, NULL))
  1639.             {
  1640.                 if (fDisplayUI)
  1641.                     PathRemoveFileSpec(szPath);
  1642.                     
  1643.                 ISHCUT_PARAMS ShCutParams = {0};
  1644.                 
  1645.                 PathRemoveExtension(szDspName);
  1646.                 
  1647.                 ShCutParams.pidlTarget = pidlCur;
  1648.                 ShCutParams.pszTitle = PathFindFileName(szDspName); 
  1649.                 ShCutParams.pszDir = szPath; 
  1650.                 ShCutParams.pszOut = NULL;
  1651.                 ShCutParams.bUpdateProperties = FALSE;
  1652.                 ShCutParams.bUniqueName = FALSE;
  1653.                 ShCutParams.bUpdateIcon = TRUE;
  1654.                 ShCutParams.pCommand = pCommandTarget;
  1655.                 ShCutParams.pDoc = pDoc;
  1656.                 hres = CreateShortcutInDirEx(&ShCutParams);
  1657.                 if (fDisplayUI && FAILED(hres)) 
  1658.                 {
  1659.                     IE_ErrorMsgBox(NULL, hwnd, GetLastError(), NULL, szDspName, IDS_FAV_UNABLETOCREATE, MB_OK| MB_ICONSTOP);
  1660.                 }
  1661.             }
  1662.             else
  1663.             {
  1664.                 hres = S_FALSE;
  1665.             }
  1666.             ILFree(pidlFavorites);
  1667.         }
  1668.     }
  1669.     SetCursor(hCursorOld);
  1670.     
  1671.     return hres;
  1672. }
  1673. BOOL IsSubscribed(ADDTOFAV *patf)
  1674. {
  1675.     BOOL bSubscribed = FALSE;
  1676.     TCHAR szURL[MAX_URL_STRING];
  1677.     if (SUCCEEDED(IEGetDisplayName(patf->pidlFavorite, szURL, SHGDN_FORPARSING)))
  1678.     {
  1679.         ISubscriptionMgr *pSubscriptionMgr;
  1680.         if (SUCCEEDED(CoCreateInstance(CLSID_SubscriptionMgr,
  1681.                                        NULL, CLSCTX_INPROC_SERVER,
  1682.                                        IID_ISubscriptionMgr,
  1683.                                        (void**)&pSubscriptionMgr)))
  1684.         {
  1685.             BSTR bstrURL = SysAllocStringT(szURL);
  1686.             if (bstrURL)
  1687.             {
  1688.                 if (SUCCEEDED(pSubscriptionMgr->IsSubscribed(bstrURL, &bSubscribed)) &&
  1689.                     bSubscribed)
  1690.                 {
  1691.                     patf->siSubsInProg.fUpdateFlags = SUBSINFO_ALLFLAGS;
  1692.                     pSubscriptionMgr->GetSubscriptionInfo(bstrURL, &patf->siSubsInProg);
  1693.                 }
  1694.                 SysFreeString(bstrURL);
  1695.             }
  1696.             pSubscriptionMgr->Release();
  1697.         }
  1698.     }
  1699.     return bSubscribed;
  1700. }
  1701. BOOL IsSubscribed(LPCITEMIDLIST pidl)
  1702. {
  1703.     BOOL bSubscribed = FALSE;
  1704.     TCHAR szURL[MAX_URL_STRING];
  1705.     if (FAILED(IEGetNameAndFlags(pidl, SHGDN_FORPARSING, szURL, SIZEOF(szURL), NULL)))
  1706.         return FALSE;
  1707.     bSubscribed = IsSubscribed(szURL);    
  1708.     return bSubscribed;
  1709. }
  1710. BOOL IsSubscribed(LPWSTR pwzUrl)
  1711. {
  1712. #ifndef DISABLE_SUBSCRIPTIONS
  1713.     BOOL bSubscribed = FALSE;
  1714.     ISubscriptionMgr * pSubscriptionMgr;
  1715.     if (FAILED(CoCreateInstance(CLSID_SubscriptionMgr,
  1716.                                 NULL,
  1717.                                 CLSCTX_INPROC_SERVER,
  1718.                                 IID_ISubscriptionMgr,
  1719.                                 (void**)&pSubscriptionMgr)))
  1720.     {
  1721.         return FALSE;
  1722.     }
  1723.     pSubscriptionMgr->IsSubscribed(pwzUrl, &bSubscribed);
  1724.     pSubscriptionMgr->Release();
  1725.     return bSubscribed;
  1726. #else  /* !DISABLE_SUBSCRIPTIONS */
  1727.     return FALSE;
  1728. #endif /* !DISABLE_SUBSCRIPTIONS */
  1729. }