/*
 * isprsht.cpp - IPropSheetExt implementation for URL class.
 */


#include "priv.h"
#include "ishcut.h"
#include <limits.h>
#include <trayp.h>          // for WMTRAY_ messages
#include <ntverp.h>         // VER_XXX for FaultInFeature
#include <webcheck.h>       // ISubscriptionMgrPriv

#include <mluisupp.h>

#undef NO_HELP              // for help.h
#include "resource.h"
#include <iehelpid.h>

#ifndef UNIX
const WCHAR c_szPropCrawlActualSize[] = L"ActualSizeKB";
const WCHAR c_szPropStatusString[] = L"StatusString";
const WCHAR c_szPropCompletionTime[] = L"CompletionTime";
#else
#include "unixstuff.h"
#include "shalias.h"
const LPCWSTR c_szPropCrawlActualSize = L"ActualSizeKB";
const LPCWSTR c_szPropStatusString = L"StatusString";
const LPCWSTR c_szPropCompletionTime = L"CompletionTime";
#endif

#include "apithk.h"

/* stuff a point value packed in an LPARAM into a POINT */

#define LPARAM_TO_POINT(lParam, pt)       ((pt).x = GET_X_LPARAM(lParam), \
                                           (pt).y = GET_Y_LPARAM(lParam))


#define ISF_STARTSUBSCRIBED     0x00010000      // URL was subscribed to start with
#define ISF_NOWEBCHECK          0x00020000      // Webcheck is not installed
#define ISF_DISABLEOFFLINE      0x00080000      // Disable "make available offline" menus/checkboxes
#define ISF_SUMMARYEXTRACTED    0x00100000      // Has the summary been extracted
#define ISF_HAVEINITED          0x00200000      // Has the subsmgr extension been inited?




/* Internet Shortcut property sheet data */

/*  
    Mental note(tnoonan): this helper class should be shared with the context menu 
    code soon.
*/

class CSubsHelper
{
    IUniformResourceLocatorW    *m_pIURLW;
    ISubscriptionMgr2           *m_pSubsMgr2;
    HINSTANCE                   m_hinstWebcheck;
    HWND                        m_hwndParent;
    
public:
    DWORD               m_dwFlags;

    ~CSubsHelper()
    {
        if (NULL != m_pSubsMgr2)
        {
            m_pSubsMgr2->Release();
        }

        if (NULL != m_pIURLW)
        {
            m_pIURLW->Release();
        }

        if (NULL != m_hinstWebcheck)
        {
            FreeLibrary(m_hinstWebcheck);
        }
    }

    void SetParentHwnd(HWND hwndParent)
    {
        m_hwndParent = hwndParent;
    }

    void SetIURLW(IUniformResourceLocatorW *pIURLW)
    {
        if (NULL != m_pIURLW)
        {
            m_pIURLW->Release();
        }

        if (NULL != pIURLW)
        {
            pIURLW->AddRef();
        }

        m_pIURLW = pIURLW;
    }

    HRESULT GetIURLW(IUniformResourceLocatorW **ppIURLW)
    {
        HRESULT hr;
        
        ASSERT(NULL != ppIURLW);

        if (NULL != m_pIURLW)
        {
            m_pIURLW->AddRef();
            *ppIURLW = m_pIURLW;
            hr = S_OK;
        }
        else
        {
            *ppIURLW = NULL;
            hr = E_FAIL;
        }

        return hr;
    }
   
    HRESULT Init()
    {
        HRESULT hr;
        WCHAR *pwszURL;

        ASSERT(NULL != m_pIURLW);

        hr = m_pIURLW->GetURL(&pwszURL);

        if (SUCCEEDED(hr))
        {

            hr = LoadSubsMgr2(FIEF_FLAG_PEEK | FIEF_FLAG_FORCE_JITUI);

            if (SUCCEEDED(hr))
            {
                BOOL bSubscribed; 

                if (SUCCEEDED(m_pSubsMgr2->IsSubscribed(pwszURL, &bSubscribed)) && 
                    (TRUE == bSubscribed))
                {
                    m_dwFlags |= ISF_STARTSUBSCRIBED;
                }
            }

            if (m_dwFlags & ISF_STARTSUBSCRIBED)
            {
                if (SHRestricted2W(REST_NoRemovingSubscriptions, pwszURL, 0))
                {
                    m_dwFlags |= ISF_DISABLEOFFLINE;
                }
            }
            else
            {
                if (SHRestricted2W(REST_NoAddingSubscriptions, pwszURL, 0))
                {
                    m_dwFlags |= ISF_DISABLEOFFLINE;
                }
            }

            SHFree(pwszURL);
        }

        return hr;
    }

    HRESULT LoadSubsMgr2(DWORD dwFaultInFlags)
    {
        HRESULT hr;
        uCLSSPEC ucs;
        QUERYCONTEXT qc = { 0 };

        ucs.tyspec = TYSPEC_CLSID;
        ucs.tagged_union.clsid = CLSID_SubscriptionMgr;

        hr = FaultInIEFeature(m_hwndParent, &ucs, &qc, dwFaultInFlags);

        if (SUCCEEDED(hr))
        {
            m_dwFlags &= ~ISF_NOWEBCHECK;
        }
        else
        {
            m_dwFlags |= ISF_NOWEBCHECK;

            if (E_ACCESSDENIED == hr)
            {
                //  Admin has disabled demand install
                m_dwFlags |= ISF_DISABLEOFFLINE;
            }
        }

        if (!(m_dwFlags & ISF_NOWEBCHECK))
        {
            ASSERT(NULL == m_pSubsMgr2)
            
            //  HACKHACKHACK
            hr = CoInitialize(NULL);
            if (SUCCEEDED(hr))
            {
                m_hinstWebcheck = SHPinDllOfCLSID(&CLSID_SubscriptionMgr);
                if (NULL != m_hinstWebcheck)
                {
                    hr = CoCreateInstance(CLSID_SubscriptionMgr, NULL, CLSCTX_INPROC_SERVER,
                                          IID_PPV_ARG(ISubscriptionMgr2, &m_pSubsMgr2));
                }
                else
                {
                    m_dwFlags |= ISF_NOWEBCHECK;
                    hr = E_FAIL;
                }

                //  HACKHACKHACK
                CoUninitialize();
            }
        }

        return hr;
    }

    HRESULT GetSubsMgr2(ISubscriptionMgr2 **ppSubsMgr2, DWORD dwFaultInFlags)
    {
        HRESULT hr = E_FAIL;

        ASSERT(NULL != ppSubsMgr2);
        *ppSubsMgr2 = NULL;

        if ((NULL == m_pSubsMgr2) && (0xffffffff != dwFaultInFlags))
        {
            hr = LoadSubsMgr2(dwFaultInFlags);
        }
        
        if (NULL != m_pSubsMgr2)
        {
            m_pSubsMgr2->AddRef();
            *ppSubsMgr2 = m_pSubsMgr2;
            hr = S_OK;
        }
        return hr;
    }

    HRESULT DeleteSubscription()
    {
        HRESULT hr = S_FALSE;
        
        if (m_pSubsMgr2)
        {
            WCHAR *pwszURL;

            ASSERT(NULL != m_pIURLW);

            hr = m_pIURLW->GetURL(&pwszURL);

            if (SUCCEEDED(hr))
            {
                hr = m_pSubsMgr2->DeleteSubscription(pwszURL, NULL);
                SHFree(pwszURL);
            }
        }

        return hr;
    }

    HRESULT SaveSubscription()
    {
        HRESULT hr;
#ifndef UNIX
        ISubscriptionMgrPriv *psmp;

        if (m_pSubsMgr2)
        {

            hr = m_pSubsMgr2->QueryInterface(IID_PPV_ARG(ISubscriptionMgrPriv, &psmp));

            if (SUCCEEDED(hr))
            {
                hr = psmp->SaveSubscription();
                psmp->Release();
            }
        }
        else
#endif
        {
            hr = E_FAIL;
        }
        return hr;
    }

    HRESULT UpdateSubscription()
    {
        HRESULT hr;
        
        if (m_pSubsMgr2)
        {
            WCHAR *pwszURL;

            ASSERT(NULL != m_pIURLW);

            hr = m_pIURLW->GetURL(&pwszURL);
            if (SUCCEEDED(hr))
            {
                hr = m_pSubsMgr2->UpdateSubscription(pwszURL);
                SHFree(pwszURL);
            }
        }
        else
        {
            hr = E_FAIL;
        }

        return hr;
    }

    HRESULT DoShellExtInit(IDataObject *pdo)
    {
        HRESULT hr = E_FAIL;

        if (NULL != m_pSubsMgr2)
        {
            if (!(m_dwFlags & ISF_HAVEINITED))
            {
                IShellExtInit *psei;

                hr = m_pSubsMgr2->QueryInterface(IID_PPV_ARG(IShellExtInit, &psei));

                if (SUCCEEDED(hr))
                {
                    hr = psei->Initialize(NULL, pdo, NULL);

                    if (SUCCEEDED(hr))
                    {
                        m_dwFlags |= ISF_HAVEINITED;
                    }
                    psei->Release();
                }
            }
            else
            {
                hr = S_FALSE;
            }
        }
        
        return hr;
    }


};

struct ISDATA
{
private:
    Intshcut            *m_pintshcut;
    
public:
    TCHAR               rgchIconFile[MAX_PATH];
    int                 niIcon;
    CSubsHelper         SubsHelper;
    BOOL                bUserEditedPage;

    inline void SetIntshcut(Intshcut *pintshcut)
    {
        IUniformResourceLocatorW *pIURLW;

        ASSERT(NULL == m_pintshcut);
        ASSERT(NULL != pintshcut);

        pintshcut->AddRef();

        if (SUCCEEDED(pintshcut->QueryInterface(IID_PPV_ARG(IUniformResourceLocatorW, &pIURLW))))
        {
            SubsHelper.SetIURLW(pIURLW);
            pIURLW->Release();
        }

        m_pintshcut = pintshcut;
    }

    inline Intshcut *GetIntshcut() const
    { 
        ASSERT(NULL != m_pintshcut);
        return m_pintshcut;
    }

    ~ISDATA()
    {
        if (NULL != m_pintshcut)
        {
            m_pintshcut->Release();
        }
    }
};

typedef ISDATA *PISDATA;


#ifdef DEBUG

BOOL
IsValidPISDATA(
    PISDATA pisdata)
{
    return(IS_VALID_READ_PTR(pisdata, ISDATA) &&
           IS_VALID_STRUCT_PTR(pisdata->GetIntshcut(), CIntshcut) &&
           EVAL(IsValidIconIndex(*(pisdata->rgchIconFile) ? S_OK : S_FALSE, pisdata->rgchIconFile, SIZECHARS(pisdata->rgchIconFile), pisdata->niIcon)));
}

PISDATA ISPS_GetPISDATA(HWND hdlg)
{
    PISDATA pd = (PISDATA) GetWindowLongPtr(hdlg, DWLP_USER);

    IS_VALID_STRUCT_PTR(pd, ISDATA);

    return pd;
}

Intshcut *ISPS_GetThisPtr(HWND hdlg)
{
    Intshcut *pintshcut = ISPS_GetPISDATA(hdlg)->GetIntshcut();

    IS_VALID_STRUCT_PTR(pintshcut, CIntshcut);

    return pintshcut;
}
#else
#define ISPS_GetPISDATA(hdlg)   ((PISDATA)GetWindowLongPtr(hdlg, DWLP_USER))
#define ISPS_GetThisPtr(hdlg)   (ISPS_GetPISDATA(hdlg)->GetIntshcut())
#endif

// help files

TCHAR const s_cszIEHelpFile[]   = TEXT("iexplore.hlp");

// help topics

DWORD const c_rgdwHelpIDs[] =
{
    IDC_ICON,                   IDH_FCAB_LINK_ICON,
    IDC_NAME,                   IDH_FCAB_LINK_NAME,
    IDC_URL_TEXT,               IDH_SUBPROPS_SUBTAB_SUBSCRIBED_URL,
    IDC_URL,                    IDH_SUBPROPS_SUBTAB_SUBSCRIBED_URL,
    IDC_HOTKEY_TEXT,            IDH_FCAB_LINK_HOTKEY,
    IDC_HOTKEY,                 IDH_FCAB_LINK_HOTKEY,
    IDC_CHANGE_ICON,            IDH_FCAB_LINK_CHANGEICON,
    IDC_VISITS_TEXT,            IDH_WEBDOC_VISITS,
    IDC_VISITS,                 IDH_WEBDOC_VISITS,
    IDC_MAKE_OFFLINE,           IDH_MAKE_AVAIL_OFFLINE,
    IDC_SUMMARY,                IDH_GROUPBOX,
    IDC_LAST_SYNC_TEXT,         IDH_SUBPROPS_SUBTAB_LAST,
    IDC_LAST_SYNC,              IDH_SUBPROPS_SUBTAB_LAST,
    IDC_DOWNLOAD_SIZE_TEXT,     IDH_SUBPROPS_DLSIZE,
    IDC_DOWNLOAD_SIZE,          IDH_SUBPROPS_DLSIZE,
    IDC_DOWNLOAD_RESULT_TEXT,   IDH_SUBPROPS_SUBTAB_RESULT,
    IDC_DOWNLOAD_RESULT,        IDH_SUBPROPS_SUBTAB_RESULT,
    0,                          0
};


/***************************** Private Functions *****************************/

void SetEditFocus(HWND hwnd)
{
    SetFocus(hwnd);
    Edit_SetSel(hwnd, 0, -1);
}


#define SetDlgCtlText      SetDlgItemTextW

UINT
CALLBACK
ISPSCallback(
    HWND hwnd, 
    UINT uMsg, 
    LPPROPSHEETPAGE ppsp)
{
    UINT uResult = TRUE;
    PISDATA pisdata = (PISDATA)ppsp->lParam;

    // uMsg may be any value.

    ASSERT(! hwnd ||
           IS_VALID_HANDLE(hwnd, WND));

    switch (uMsg)
    {
        case PSPCB_CREATE:
            break;

        case PSPCB_RELEASE:
            TraceMsg(TF_INTSHCUT, "ISPSCallback(): Received PSPCB_RELEASE.");

            if (pisdata)
            {   
                delete pisdata;         
            }
            break;

        default:
            break;
    }

    return(uResult);
}

HRESULT
CopyDlgItemText(
    HWND hdlg,
    int nControlID, 
    TCHAR * UNALIGNED * ppszText)
{
    HRESULT hr;
    HWND hwndControl;

    // nContolID may be any value.

    ASSERT(IS_VALID_HANDLE(hdlg, WND));
    ASSERT(IS_VALID_WRITE_PTR(ppszText, PTSTR));

    *ppszText = NULL;

    hwndControl = GetDlgItem(hdlg, nControlID);

    if (hwndControl)
    {
        int cchTextLen;

        cchTextLen = GetWindowTextLength(hwndControl);

        if (cchTextLen > 0)
        {
            LPTSTR pszText;

            ASSERT(cchTextLen < INT_MAX);
            cchTextLen++;
            ASSERT(cchTextLen > 0);

            pszText = (LPTSTR)LocalAlloc(LPTR, CbFromCch(cchTextLen));

            if (pszText)
            {
                int ncchCopiedLen;

                ncchCopiedLen = GetWindowText(hwndControl, pszText, cchTextLen);
                ASSERT(ncchCopiedLen == cchTextLen - 1);

                if (EVAL(ncchCopiedLen > 0))
                {
                    if (AnyMeat(pszText))
                    {
                        *ppszText = pszText;

                        hr = S_OK;
                    }
                    else
                        hr = S_FALSE;
                }
                else
                    hr = E_FAIL;

                if (hr != S_OK)
                {
                    LocalFree(pszText);
                    pszText = NULL;
                }
            }
            else
                hr = E_OUTOFMEMORY;
        }
        else
            // No text.
            hr = S_FALSE;
    }
    else
        hr = E_FAIL;

    return(hr);
}

void
SetISPSIcon(
    HWND hdlg, 
    HICON hicon)
{
    HICON hiconOld;

    ASSERT(IS_VALID_HANDLE(hdlg, WND));
    ASSERT(IS_VALID_HANDLE(hicon, ICON));

    hiconOld = (HICON)SendDlgItemMessage(hdlg, IDC_ICON, STM_SETICON,
                                         (WPARAM)hicon, 0);

    if (hiconOld)
        DestroyIcon(hiconOld);

    TraceMsg(TF_INTSHCUT, "SetISPSIcon(): Set property sheet icon to %#lx.",
               hicon);

    return;
}

void
SetISPSFileNameAndIcon(
    HWND hdlg)
{
    HRESULT hr;
    PIntshcut pintshcut;
    TCHAR rgchFile[MAX_PATH];

    ASSERT(IS_VALID_HANDLE(hdlg, WND));

    pintshcut = ISPS_GetThisPtr(hdlg);

    hr = pintshcut->GetCurFile(rgchFile, SIZECHARS(rgchFile));

    if (hr == S_OK)
    {
        SHFILEINFO shfi;
        DWORD_PTR dwResult;

        dwResult = SHGetFileInfo(rgchFile, 0, &shfi, SIZEOF(shfi),
                                 (SHGFI_DISPLAYNAME | SHGFI_ICON));

        if (dwResult)
        {
            LPTSTR pszFileName;

            pszFileName = (PTSTR)PathFindFileName(shfi.szDisplayName);

            EVAL(SetDlgItemText(hdlg, IDC_NAME, pszFileName));

            SetISPSIcon(hdlg, shfi.hIcon);
        }
        else
        {
           hr = E_FAIL;

           TraceMsg(TF_INTSHCUT, "SetISPSFileNameAndIcon(): SHGetFileInfo() failed, returning %lu.",
                      dwResult);
        }
    }
    else
        TraceMsg(TF_INTSHCUT, "SetISPSFileNameAndIcon(): GetCurFile() failed, returning %s.",
                   Dbg_GetHRESULTName(hr));

    if (hr != S_OK)
        EVAL(SetDlgItemText(hdlg, IDC_NAME, c_szNULL));

    return;
}

void
SetISPSURL(
    HWND hdlg,
    BOOL *pbSubscribable)
{
    PIntshcut pintshcut;
    HRESULT hr;
    PTSTR pszURL;

    *pbSubscribable = FALSE;

    ASSERT(IS_VALID_HANDLE(hdlg, WND));

    pintshcut = ISPS_GetThisPtr(hdlg);

    hr = pintshcut->GetURL(&pszURL);

    if (hr == S_OK)
    {
        TCHAR szVisits[256];
        EVAL(SetDlgItemText(hdlg, IDC_URL, pszURL));

        TraceMsg(TF_INTSHCUT, "SetISPSURL(): Set property sheet URL to \"%s\".",
                   pszURL);

        *pbSubscribable = IsSubscribable(pszURL);
        
        BYTE cei[MAX_CACHE_ENTRY_INFO_SIZE];
        LPINTERNET_CACHE_ENTRY_INFO pcei = (LPINTERNET_CACHE_ENTRY_INFO)cei;
        DWORD       cbcei = MAX_CACHE_ENTRY_INFO_SIZE;

#ifdef UNIX_FEATURE_ALIAS
        {
            HDPA  aliasList = GetGlobalAliasList();
            if( aliasList )
            {
#ifdef UNICODE
            // TODO :
#else
            CHAR szAlias[ MAX_ALIAS_LENGTH ];
            if(FindAliasByURLA( aliasList, pszURL, szAlias, sizeof(szAlias) ) )
                 SetDlgItemText(hdlg, IDC_ALIAS_NAME, szAlias);
#endif
            }
        }
#endif  /* UNIX_FEATURE_ALIAS */

        if (GetUrlCacheEntryInfo(pszURL, pcei, &cbcei))
        {
            wnsprintf(szVisits, ARRAYSIZE(szVisits), TEXT("%d"), pcei->dwHitRate);
        }
        else
        {
            MLLoadString(IDS_VALUE_UNKNOWN, szVisits, ARRAYSIZE(szVisits));
        }

        EVAL(SetDlgItemText(hdlg, IDC_VISITS, szVisits));

        SHFree(pszURL);
        pszURL = NULL;
    }
    else
        EVAL(SetDlgItemText(hdlg, IDC_URL, c_szNULL));

    return;
}

void 
InitISPSHotkey(
    HWND hdlg)
{
    PIntshcut pintshcut;
    WORD wHotkey;
    HRESULT hr;

    ASSERT(IS_VALID_HANDLE(hdlg, WND));

    // Set hotkey combinations.

    SendDlgItemMessage(hdlg, IDC_HOTKEY, HKM_SETRULES,
                       (HKCOMB_NONE | HKCOMB_A | HKCOMB_C | HKCOMB_S),
                       (HOTKEYF_CONTROL | HOTKEYF_ALT));

    // Set current hotkey.

    pintshcut = ISPS_GetThisPtr(hdlg);
    ASSERT(IS_VALID_STRUCT_PTR(pintshcut, CIntshcut));

    hr = pintshcut->GetHotkey(&wHotkey);
    SendDlgItemMessage(hdlg, IDC_HOTKEY, HKM_SETHOTKEY, wHotkey, 0);

    return;
}


void ISPS_ShowOfflineSummary(HWND hdlg, BOOL bShow, PISDATA pisdata)
{
    static const int offSumIDs[] =
    {
        IDC_SUMMARY,
        IDC_LAST_SYNC_TEXT,
        IDC_LAST_SYNC,
        IDC_DOWNLOAD_SIZE_TEXT,
        IDC_DOWNLOAD_SIZE,
        IDC_DOWNLOAD_RESULT,
        IDC_DOWNLOAD_RESULT_TEXT,
        IDC_FREESPACE_TEXT
    };

    if (bShow)
    {
        IUniformResourceLocatorW *pIURLW;

        TCHAR szLastSync[128];
        TCHAR szDownloadSize[128];
        TCHAR szDownloadResult[128];

        MLLoadString(IDS_VALUE_UNKNOWN, szLastSync, ARRAYSIZE(szLastSync));
        StrCpyN(szDownloadSize, szLastSync, ARRAYSIZE(szDownloadSize));
        StrCpyN(szDownloadResult, szLastSync, ARRAYSIZE(szDownloadResult));

        if (SUCCEEDED(pisdata->SubsHelper.GetIURLW(&pIURLW)))
        {
            WCHAR *pwszURL;

            if (SUCCEEDED(pIURLW->GetURL(&pwszURL)))
            {            
                ISubscriptionMgr2 *pSubsMgr2;
               
                if (SUCCEEDED(pisdata->SubsHelper.GetSubsMgr2(&pSubsMgr2, FIEF_FLAG_PEEK | FIEF_FLAG_FORCE_JITUI)))
                {
                    ISubscriptionItem *psi;
                    
                    if (SUCCEEDED(pSubsMgr2->GetItemFromURL(pwszURL, &psi)))
                    {
                        enum { spLastSync, spDownloadSize, spDownloadResult };
                        static const LPCWSTR pProps[] =
                        { 
                            c_szPropCompletionTime,
                            c_szPropCrawlActualSize,
                            c_szPropStatusString
                        };
                        VARIANT vars[ARRAYSIZE(pProps)];

                        if (SUCCEEDED(psi->ReadProperties(ARRAYSIZE(pProps), pProps, vars)))
                        {
                            if (VT_DATE == vars[spLastSync].vt)
                            {
                                FILETIME ft, ft2;
                                DWORD dwFlags = FDTF_DEFAULT;
                                SYSTEMTIME st;

                                if (VariantTimeToSystemTime(vars[spLastSync].date, &st))
                                {
                                    SystemTimeToFileTime(&st, &ft);
                                    LocalFileTimeToFileTime(&ft, &ft2);
                                    SHFormatDateTime(&ft2, &dwFlags, szLastSync, ARRAYSIZE(szLastSync));
                                }
                            }

                            if (VT_I4 == vars[spDownloadSize].vt)
                            {
                                StrFormatByteSize(vars[spDownloadSize].lVal * 1024, 
                                                  szDownloadSize, ARRAYSIZE(szDownloadSize));
                            }

                            if (VT_BSTR == vars[spDownloadResult].vt)
                            {
                                wnsprintf(szDownloadResult, ARRAYSIZE(szDownloadResult),
                                          TEXT("%s"), vars[spDownloadResult].bstrVal);
                            }

                            for (int i = 0; i < ARRAYSIZE(pProps); i++)
                            {
                                VariantClear(&vars[i]);
                            }
                        }
                        
                        psi->Release();
                    }

                    pSubsMgr2->Release();
                }
                
                SHFree(pwszURL);
            }
            
            pIURLW->Release();
        }

        EVAL(SetDlgItemText(hdlg, IDC_LAST_SYNC, szLastSync));
        EVAL(SetDlgItemText(hdlg, IDC_DOWNLOAD_SIZE, szDownloadSize));
        EVAL(SetDlgItemText(hdlg, IDC_DOWNLOAD_RESULT, szDownloadResult));
    }

    for (int i = 0; i < ARRAYSIZE(offSumIDs); i++)
    {
        ShowWindow(GetDlgItem(hdlg, offSumIDs[i]), bShow ? SW_SHOW : SW_HIDE);
    }
}

BOOL ISPS_AddSubsPropsCallback(HPROPSHEETPAGE hpage, LPARAM lParam)
{
    return BOOLFROMPTR(PropSheet_AddPage((HWND)lParam, hpage));
}

STDMETHODIMP ISPS_AddSubsProps(HWND hdlg, ISubscriptionMgr2 *pSubsMgr2, PISDATA pisdata)
{
    HRESULT hr = S_OK;
    IShellPropSheetExt *pspse;

    ASSERT(NULL != pisdata);
    ASSERT(NULL != pSubsMgr2);

    hr = pisdata->SubsHelper.DoShellExtInit(pisdata->GetIntshcut()->GetInitDataObject());

    if (SUCCEEDED(hr))
    {
        hr = pSubsMgr2->QueryInterface(IID_PPV_ARG(IShellPropSheetExt, &pspse));

        if (SUCCEEDED(hr))
        {
            hr = pspse->AddPages(ISPS_AddSubsPropsCallback,
                                 (LPARAM)GetParent(hdlg)) ? S_OK : E_FAIL;
            pspse->Release();
        }
    }

    return hr;
}

STDMETHODIMP ISPS_RemoveSubsProps(HWND hdlg, ISubscriptionMgr2 *pSubsMgr2)
{
    HRESULT hr;
    ISubscriptionMgrPriv *psmp;

    ASSERT(NULL != pSubsMgr2);

#ifndef UNIX
    hr = pSubsMgr2->QueryInterface(IID_PPV_ARG(ISubscriptionMgrPriv, &psmp));

    if (SUCCEEDED(hr))
    {
        hr = psmp->RemovePages(GetParent(hdlg));
        psmp->Release();
    }
#else
    hr = E_FAIL;
#endif

    return hr;
}

HRESULT ISPS_OnMakeOfflineClicked(HWND hdlg)
{
#ifndef UNIX
    HRESULT hr;
    BOOL bChecked = IsDlgButtonChecked(hdlg, IDC_MAKE_OFFLINE);
    PISDATA pisdata = ISPS_GetPISDATA(hdlg);
    ISubscriptionMgr2 *pSubsMgr2;

    hr = pisdata->SubsHelper.GetSubsMgr2(&pSubsMgr2, FIEF_FLAG_FORCE_JITUI);

    ASSERT((SUCCEEDED(hr) && pSubsMgr2) || (FAILED(hr) && !pSubsMgr2));
        
    if (bChecked)
    {
        if (SUCCEEDED(hr))
        {
            ASSERT(NULL != pSubsMgr2);
            
            hr = ISPS_AddSubsProps(hdlg, pSubsMgr2, pisdata);
        }
        else
        {
            //  Can't do this without subsmgr
            CheckDlgButton(hdlg, IDC_MAKE_OFFLINE, BST_UNCHECKED);
            bChecked = FALSE;
        }
    }
    else
    {
        if (SUCCEEDED(hr))
        {
            ASSERT(NULL != pSubsMgr2);
            hr = ISPS_RemoveSubsProps(hdlg, pSubsMgr2);
        }
    }

    if (NULL != pSubsMgr2)
    {
        pSubsMgr2->Release();
    }

    ISPS_ShowOfflineSummary(hdlg, bChecked, pisdata);

    return hr;
#else
    // IEUNIX : ( MAKE_OFFLINE disabled )
    return E_FAIL;
#endif
}


BOOL 
ISPS_InitDialog(
    HWND hdlg, 
    WPARAM wParam, 
    LPARAM lParam)
{
    LPPROPSHEETPAGE ppsp = (LPPROPSHEETPAGE)lParam;
    PIntshcut pintshcut;
    PISDATA pisdata;
    BOOL bSubscribable;
    
    // wParam may be any value.

    ASSERT(IS_VALID_HANDLE(hdlg, WND));
    
    pisdata = (PISDATA)ppsp->lParam;
    ASSERT(IS_VALID_STRUCT_PTR(pisdata, ISDATA));

    SetWindowLongPtr(hdlg, DWLP_USER, ppsp->lParam);

    pintshcut = pisdata->GetIntshcut();
    pisdata->SubsHelper.SetParentHwnd(hdlg);
    
    // Cross-lang platform support
    SHSetDefaultDialogFont(hdlg, IDC_START_IN);
    SHSetDefaultDialogFont(hdlg, IDC_URL); // for intra-net

    // Initialize control contents.
    SetISPSFileNameAndIcon(hdlg);

    InitISPSHotkey(hdlg);

    SendDlgItemMessage(hdlg, IDC_URL, EM_LIMITTEXT, INTERNET_MAX_URL_LENGTH - 1, 0);
    SetISPSURL(hdlg, &bSubscribable);

#ifndef UNIX
    // IEUNIX : ( MAKE_OFFLINE disabled )
    if (pisdata->SubsHelper.m_dwFlags & ISF_STARTSUBSCRIBED)
    {
        CheckDlgButton(hdlg, IDC_MAKE_OFFLINE, TRUE);
    }

    if (!bSubscribable)
    {
        pisdata->SubsHelper.m_dwFlags |= ISF_DISABLEOFFLINE;
    }

    if (pisdata->SubsHelper.m_dwFlags & ISF_DISABLEOFFLINE)
    {
        EnableWindow(GetDlgItem(hdlg, IDC_MAKE_OFFLINE), FALSE);
    }

    ISPS_ShowOfflineSummary(hdlg, 
                            pisdata->SubsHelper.m_dwFlags & ISF_STARTSUBSCRIBED, 
                            pisdata);
#endif

    // since we just finished initing the dialog, set pisdata->bUserEditedPage to
    // FALSE. If the user messes with the page (eg clicks a button or types in an edit box),
    // we will set it to TRUE so we know that we actually have changes to apply.
    //
    // NOTE: this must come last since when we call SetDlgItemText above, we will
    // generate WM_COMMAND messages that cause us to set bUserEditedPage to TRUE.
    pisdata->bUserEditedPage = FALSE;

    return(TRUE);
}


BOOL
ISPS_Destroy(
    HWND hdlg, 
    WPARAM wParam, 
    LPARAM lParam)
{
    ASSERT(IS_VALID_HANDLE(hdlg, WND));
    PISDATA pisdata = ISPS_GetPISDATA(hdlg);
    
#ifndef UNIX
    // IEUNIX : ( MAKE_OFFLINE disabled )
    if ((!(pisdata->SubsHelper.m_dwFlags & ISF_STARTSUBSCRIBED)) && 
        IsDlgButtonChecked(hdlg, IDC_MAKE_OFFLINE))

    {
        pisdata->SubsHelper.UpdateSubscription();
    }
#endif
    

    SetWindowLongPtr(hdlg, DWLP_USER, NULL);
    SHRemoveDefaultDialogFont(hdlg);

    return(TRUE);
}

void
ISPSChanged(
    HWND hdlg)
{
    PISDATA pisdata;
    ASSERT(IS_VALID_HANDLE(hdlg, WND));

    pisdata = ISPS_GetPISDATA(hdlg);
    pisdata->bUserEditedPage = TRUE;
    
    PropSheet_Changed(GetParent(hdlg), hdlg);
    
    return;
}

HRESULT
ChooseIcon(
    HWND hdlg)
{
    HRESULT hr;
    PISDATA pisdata;
    PIntshcut pintshcut;
    TCHAR szPath[MAX_PATH], szExpandedPath[MAX_PATH];
    int niIcon;

    ASSERT(IS_VALID_HANDLE(hdlg, WND));

    pisdata = ISPS_GetPISDATA(hdlg);
    pintshcut = pisdata->GetIntshcut();

    ASSERT(IS_VALID_STRUCT_PTR(pintshcut, CIntshcut));

    szPath[0] = TEXT('\0');

    hr = pintshcut->GetIconLocation(szPath, MAX_PATH, (int *)(&niIcon));
                                             
    if((FAILED(hr)) || (FALSE == PathFileExists(szPath)))
    {
        hr = GetGenericURLIcon(szPath, MAX_PATH, (int *)(&niIcon));
        if(FAILED(hr))
        {
            szPath[0] = '\0';
            niIcon = 0;
        }
    }

    ASSERT(lstrlen(szPath) < SIZECHARS(szPath));

    if (PickIconDlg(hdlg, szPath, SIZECHARS(szPath), &niIcon) &&
        SHExpandEnvironmentStrings(szPath, szExpandedPath, SIZECHARS(szExpandedPath)))
    {
        ASSERT(lstrlen(szExpandedPath) < SIZECHARS(pisdata->rgchIconFile));
        StrCpyN(pisdata->rgchIconFile, szExpandedPath, ARRAYSIZE(pisdata->rgchIconFile));
        pisdata->niIcon = niIcon;
        hr = S_OK;
    }
    else
    {
        hr = E_FAIL;

        TraceMsg(TF_INTSHCUT, "ChooseIcon(): PickIconDlg() failed.");
    }

    return(hr);
}

void
UpdateISPSIcon(
    HWND hdlg)
{
    PIntshcut pintshcut;
    PISDATA pisdata;
    HICON hicon;

    ASSERT(IS_VALID_HANDLE(hdlg, WND));

    pisdata = ISPS_GetPISDATA(hdlg);
    pintshcut = pisdata->GetIntshcut();

    ASSERT(IS_VALID_STRUCT_PTR(pintshcut, CIntshcut));

    ASSERT(pisdata->rgchIconFile[0]);

    // This icon does not have the link arrow overlayed.  shell32.dll's
    // Shortcut property sheet has the same bug.

    hicon = ExtractIcon(g_hinst, pisdata->rgchIconFile, pisdata->niIcon);

    if (hicon)
        SetISPSIcon(hdlg, hicon);
    else
        TraceMsg(TF_WARNING, "UpdateISPSIcon(): ExtractIcon() failed for icon %d in file %s.",
                 pisdata->niIcon,
                 pisdata->rgchIconFile);
}

BOOL 
ISPS_Command(
    HWND hdlg, 
    WPARAM wParam, 
    LPARAM lParam)
{
    BOOL bMsgHandled = FALSE;
    WORD wCmd;

    // wParam may be any value.
    // lParam may be any value.

    ASSERT(IS_VALID_HANDLE(hdlg, WND));

    wCmd = HIWORD(wParam);

    switch (LOWORD(wParam))
    {
        case IDC_URL:
        case IDC_HOTKEY:
            if (wCmd == EN_CHANGE)
            {
                ISPSChanged(hdlg);

                bMsgHandled = TRUE;
            }
            break;

#ifndef UNIX
        // IEUNIX : ( MAKE_OFFLINE disabled )
        case IDC_MAKE_OFFLINE:
            if (wCmd == BN_CLICKED)
            {
                ISPS_OnMakeOfflineClicked(hdlg);

                ISPSChanged(hdlg);

                bMsgHandled = TRUE;
            }
            break;


        case IDC_CHANGE_ICON:
            // Ignore return value.
            if (ChooseIcon(hdlg) == S_OK)
            {
                UpdateISPSIcon(hdlg);
                ISPSChanged(hdlg);
            }
            bMsgHandled = TRUE;
            break;
#endif

        default:
            break;
    }

    return(bMsgHandled);
}

HRESULT 
ComplainAboutURL(
    HWND hwndParent, 
    LPCTSTR pcszURL, 
    HRESULT hrError)
{
    HRESULT hr;
    int nResult;

    // Validate hrError below.

    ASSERT(IS_VALID_HANDLE(hwndParent, WND));
    ASSERT(IS_VALID_STRING_PTR(pcszURL, -1));

    switch (hrError)
    {
        case URL_E_UNREGISTERED_PROTOCOL:
        {
            LPTSTR pszProtocol;

            hr = CopyURLProtocol(pcszURL, &pszProtocol, NULL);

            if (hr == S_OK)
            {
                nResult = MLShellMessageBox(
                                          hwndParent, 
                                          MAKEINTRESOURCE(IDS_UNREGISTERED_PROTOCOL),
                                          MAKEINTRESOURCE(IDS_SHORTCUT_ERROR_TITLE),
                                          (MB_YESNO | MB_DEFBUTTON2 | MB_ICONEXCLAMATION),
                                          pszProtocol);

                if (-1 != nResult)
                {
                    switch (nResult)
                    {
                        case IDYES:
                            hr = S_OK;
                            TraceMsg(TF_INTSHCUT, "ComplainAboutURL(): Allowing URL %s despite unregistered protocol %s, by request.",
                                       pcszURL,
                                       pszProtocol);
                            break;

                        default:
                            ASSERT(nResult == IDNO);
                            hr = E_FAIL;
                            TraceMsg(TF_INTSHCUT, "ComplainAboutURL(): Not allowing URL %s because of unregistered protocol %s, as directed.",
                                       pcszURL,
                                       pszProtocol);
                            break;
                    }
                }

                LocalFree(pszProtocol);
                pszProtocol = NULL;
            }

            break;
        }

        default:
            ASSERT(hrError == URL_E_INVALID_SYNTAX);

            MLShellMessageBox(
                            hwndParent, 
                            MAKEINTRESOURCE(IDS_INVALID_URL_SYNTAX),
                            MAKEINTRESOURCE(IDS_SHORTCUT_ERROR_TITLE),
                            MB_OK | MB_ICONEXCLAMATION,
                            pcszURL);

            hr = E_FAIL;

            TraceMsg(TF_INTSHCUT, "ComplainAboutURL(): Not allowing URL %s because of invalid syntax.",
                       pcszURL);

            break;
    }

    return(hr);
}

HRESULT 
InjectISPSData(
    HWND hdlg)
{
    HRESULT hr;
    PISDATA pisdata;
    PIntshcut pintshcut;
    PTSTR pszURL;

    ASSERT(IS_VALID_HANDLE(hdlg, WND));

    pisdata = ISPS_GetPISDATA(hdlg);
    pintshcut = pisdata->GetIntshcut();

    ASSERT(IS_VALID_STRUCT_PTR(pintshcut, CIntshcut));

    //  TODO: Inform the subsmgr of any URL changes!  IE 4 didn't handle this...

    hr = CopyDlgItemText(hdlg, IDC_URL, &pszURL);

    if (SUCCEEDED(hr))
    {
        LPCTSTR pcszURLToUse;
        TCHAR szURL[MAX_URL_STRING];

        pcszURLToUse = pszURL;

        if (hr == S_OK)
        {
            hr = IURLQualify(pszURL, UQF_DEFAULT, szURL, NULL, NULL);

            if (SUCCEEDED(hr))
            {
                pcszURLToUse = szURL;

                hr = ValidateURL(pcszURLToUse);

                if (FAILED(hr))
                {
                    hr = ComplainAboutURL(hdlg, pcszURLToUse, hr);
                  
                    if (FAILED(hr))
                        SetEditFocus(GetDlgItem(hdlg, IDC_URL));
                }
            }
        }
        else
        {
            // A blank URL is not OK.
            ASSERT(hr == S_FALSE);

            hr = ComplainAboutURL(hdlg, TEXT(""), URL_E_INVALID_SYNTAX);

            if (FAILED(hr))
                SetEditFocus(GetDlgItem(hdlg, IDC_URL));

        }

        if (SUCCEEDED(hr))
        {
            hr = pintshcut->SetURL(pcszURLToUse, 0);

            if (hr == S_OK)
            {
                WORD wHotkey;
                WORD wOldHotkey;
                BOOL bSubscribable;

                // Refresh URL in case it was changed by IURLQualify().

                SetISPSURL(hdlg, &bSubscribable);

#ifndef UNIX
                // IEUNIX : ( MAKE_OFFLINE disabled )
                if (!bSubscribable)
                {
                    EnableWindow(GetDlgItem(hdlg, IDC_MAKE_OFFLINE), FALSE);
                }

                // IEUNIX : Hot key and working directory are N/A on UNIX.
                wHotkey = (WORD)SendDlgItemMessage(hdlg, IDC_HOTKEY, HKM_GETHOTKEY, 0, 0);

                hr = pintshcut->GetHotkey(&wOldHotkey);
                if (hr == S_OK)
                {
                    hr = pintshcut->SetHotkey(wHotkey);
                    if (hr == S_OK)
                    {
                        TCHAR szFile[MAX_PATH];
                        hr = pintshcut->GetCurFile(szFile, SIZECHARS(szFile));
                        if (hr == S_OK)
                        {
                            if (RegisterGlobalHotkey(wOldHotkey, wHotkey, szFile))
                            {
                                if (pisdata->rgchIconFile[0])
                                {
                                    hr = pintshcut->SetIconLocation(pisdata->rgchIconFile, pisdata->niIcon);
                                }
                            }
                            else
                            {
                                hr = E_FAIL;
                            }
                        }
                    }
                }
#endif //!UNIX
                pintshcut->ChangeNotify(SHCNE_UPDATEITEM, 0);
            }
        }

        if (pszURL)
        {
            LocalFree(pszURL);
            pszURL = NULL;
        }
    }

    if (hr == S_OK)
        TraceMsg(TF_INTSHCUT, "InjectISPSData(): Injected property sheet data into Internet Shortcut successfully.");
    else
        TraceMsg(TF_WARNING, "InjectISPSData(): Failed to inject property sheet data into Internet Shortcut, returning %s.",
                     Dbg_GetHRESULTName(hr));

    return(hr);
}

HRESULT 
ISPSSave(
    HWND hdlg)
{
    HRESULT hr;
    PIntshcut pintshcut;

    ASSERT(IS_VALID_HANDLE(hdlg, WND));

    pintshcut = ISPS_GetThisPtr(hdlg);

    if (pintshcut->IsDirty() == S_OK)
    {
        hr = pintshcut->Save((LPCOLESTR)NULL, FALSE);

        if (hr == S_OK)
        {
            TraceMsg(TF_INTSHCUT, "ISPSSave(): Saved Internet Shortcut successfully.");
        }
        else
        {
            TraceMsg(TF_WARNING, "ISPSSave(): Save() failed, returning %s.",
                         Dbg_GetHRESULTName(hr));
            MLShellMessageBox(
                            hdlg,
                            MAKEINTRESOURCE(IDS_IS_APPLY_FAILED),
                            MAKEINTRESOURCE(IDS_SHORTCUT_ERROR_TITLE),
                            (MB_OK | MB_ICONEXCLAMATION));
        }
    }
    else
    {
        TraceMsg(TF_INTSHCUT, "ISPSSave(): Internet Shortcut unchanged.  No save required.");

        hr = S_OK;
    }

    return(hr);
}

BOOL 
ISPS_Notify(
    HWND hdlg, 
    WPARAM wParam, 
    LPARAM lParam)
{
    BOOL bMsgHandled = FALSE;

    // wParam may be any value.
    // lParam may be any value.

    ASSERT(IS_VALID_HANDLE(hdlg, WND));

    switch (((NMHDR *)lParam)->code)
    {
        case PSN_APPLY:
        {
#ifndef UNIX
            // IEUNIX : ( MAKE_OFFLINE disabled )
            BOOL bSubscribed = IsDlgButtonChecked(hdlg, IDC_MAKE_OFFLINE);
            PISDATA pisdata = ISPS_GetPISDATA(hdlg);
            
            if (!bSubscribed)
            {
                pisdata->SubsHelper.DeleteSubscription();
            }
            else
            {
                pisdata->SubsHelper.SaveSubscription();
            }

#endif /* !UNIX */

            SetWindowLongPtr(hdlg, DWLP_MSGRESULT, ISPSSave(hdlg) == S_OK ?
                                                   PSNRET_NOERROR :
                                                   PSNRET_INVALID_NOCHANGEPAGE);
            bMsgHandled = TRUE;
            break;
        }

        case PSN_KILLACTIVE:
        {
            PISDATA pisdata = ISPS_GetPISDATA(hdlg);

            if (pisdata->bUserEditedPage)
            {
                // only try to inject the data if the user actually changed something
                SetWindowLongPtr(hdlg, DWLP_MSGRESULT, FAILED(InjectISPSData(hdlg)));
            }
            bMsgHandled = TRUE;
            break;
        }

        default:
            break;
    }

    return(bMsgHandled);
}

LPCTSTR 
ISPS_GetHelpFileFromControl(
    HWND hwndControl)
{
    LPCTSTR pcszHelpFile = NULL;
    int nControlID = 0;

    ASSERT(! hwndControl ||
           IS_VALID_HANDLE(hwndControl, WND));

    if (hwndControl)
    {
        nControlID = GetDlgCtrlID(hwndControl);

        switch (nControlID)
        {
            default:
                // URL help comes from the iexplore.hlp
                pcszHelpFile = s_cszIEHelpFile;
                break;

            // Other help is borrowed from the default Win95 help file.
            case IDC_ICON:
            case IDC_NAME:
            case IDC_HOTKEY_TEXT:
            case IDC_HOTKEY:
            case IDC_CHANGE_ICON:
                break;
        }
    }

    TraceMsg(TF_INTSHCUT, "ISPS_GetHelpFileFromControl(): Using %s for control %d (HWND %#lx).",
               pcszHelpFile ? pcszHelpFile : TEXT("default Win95 help file"),
               nControlID,
               hwndControl);

    ASSERT(! pcszHelpFile ||
           IS_VALID_STRING_PTR(pcszHelpFile, -1));

    return(pcszHelpFile);
}

INT_PTR 
CALLBACK 
ISPS_DlgProc(
    HWND hdlg, 
    UINT uMsg, 
    WPARAM wParam, 
    LPARAM lParam)
{
    BOOL bMsgHandled = FALSE;

    // uMsg may be any value.
    // wParam may be any value.
    // lParam may be any value.

    ASSERT(IS_VALID_HANDLE(hdlg, WND));

    switch (uMsg)
    {
        case WM_INITDIALOG:
            bMsgHandled = ISPS_InitDialog(hdlg, wParam, lParam);
            break;

        case WM_DESTROY:
            bMsgHandled = ISPS_Destroy(hdlg, wParam, lParam);
            break;

        case WM_COMMAND:
            bMsgHandled = ISPS_Command(hdlg, wParam, lParam);
            break;

        case WM_NOTIFY:
            bMsgHandled = ISPS_Notify(hdlg, wParam, lParam);
            break;

        case WM_HELP:
            SHWinHelpOnDemandWrap((HWND)(((LPHELPINFO)lParam)->hItemHandle),
                    ISPS_GetHelpFileFromControl((HWND)(((LPHELPINFO)lParam)->hItemHandle)),
                    HELP_WM_HELP, (DWORD_PTR)(PVOID)c_rgdwHelpIDs);
            bMsgHandled = TRUE;
            break;

        case WM_CONTEXTMENU:
        {
            HWND hwnd;

            if (!IS_WM_CONTEXTMENU_KEYBOARD(lParam))
            {
                POINT pt;
                LPARAM_TO_POINT(lParam, pt);
                EVAL(ScreenToClient(hdlg, &pt));
                hwnd = ChildWindowFromPoint(hdlg, pt);
            }
            else
            {
                // For some reason on the keyboard case we don't actually
                // come to this WM_CONTEXTMENU handler -- someone somewhere
                // else is popping up the menu at the cursor instead of on
                // this hwnd...
                //
                hwnd = GetFocus();
            }

            SHWinHelpOnDemandWrap((HWND)wParam,
                    ISPS_GetHelpFileFromControl(hwnd),
                    HELP_CONTEXTMENU, (DWORD_PTR)(PVOID)c_rgdwHelpIDs);
            bMsgHandled = TRUE;
            break;
        }
        
        default:
           break;
    }

    return(bMsgHandled);
}

HRESULT AddISPage(HPROPSHEETPAGE * phpsp,
                  PROPSHEETPAGE * ppsp,
                  LPFNADDPROPSHEETPAGE pfnAddPage,
                  LPARAM lParam)
{
    HRESULT hres;
    
    ASSERT(phpsp);
    ASSERT(ppsp);
    
    *phpsp = Whistler_CreatePropertySheetPageW(ppsp);
    
    if (NULL == *phpsp)
    {
        hres = E_OUTOFMEMORY;
    }
    else
    {
        if ( !(*pfnAddPage)(*phpsp, lParam) )
        {
            DestroyPropertySheetPage(*phpsp);
            *phpsp = NULL;
            hres = E_OUTOFMEMORY;
        }
        else
        {
            hres = NO_ERROR;
        }
    }
    return hres;
}

HRESULT AddISPS(PIntshcut pintshcut, LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam)
{
    HRESULT hr;
    PISDATA pisdata;
    
    // lParam may be any value.
    
    ASSERT(IS_VALID_STRUCT_PTR(pintshcut, CIntshcut));
    ASSERT(IS_VALID_CODE_PTR(pfnAddPage, LPFNADDPROPSHEETPAGE));
    
    // Initialize instance data between property pages
    
    pisdata = new ISDATA;
    if ( !pisdata )
    {
        hr = E_OUTOFMEMORY;
    }
    else
    {
        PROPSHEETPAGE psp;
        HPROPSHEETPAGE hpsp;
        WCHAR *pwszURL;

        hr = pintshcut->GetURLW(&pwszURL);

        if (SUCCEEDED(hr))
        {
            pisdata->SetIntshcut(pintshcut);
            pisdata->SubsHelper.Init();
            SHFree(pwszURL);
            
            ASSERT(IS_VALID_STRUCT_PTR(pisdata, ISDATA));
            
            // Add the Internet Shortcut page
            
            ZeroMemory(&psp, SIZEOF(psp));
            psp.dwSize       = SIZEOF(psp);
            psp.dwFlags      = PSP_DEFAULT | PSP_USECALLBACK;
            psp.hInstance    = MLGetHinst();
            psp.pszTemplate  = MAKEINTRESOURCE(IDD_INTSHCUT_PROP);
            psp.pfnDlgProc   = &ISPS_DlgProc;
            psp.lParam       = (LPARAM)pisdata;
            psp.pfnCallback  = &ISPSCallback;
            
            hr = AddISPage(&hpsp, &psp, pfnAddPage, lParam);

            if (SUCCEEDED(hr) && (pisdata->SubsHelper.m_dwFlags & ISF_STARTSUBSCRIBED))
            {
                HRESULT hrTmp = pisdata->SubsHelper.DoShellExtInit(pisdata->GetIntshcut()->GetInitDataObject());

                if (SUCCEEDED(hrTmp))
                {
                    ISubscriptionMgr2 *pSubsMgr2;

                    hrTmp = pisdata->SubsHelper.GetSubsMgr2(&pSubsMgr2, FIEF_FLAG_PEEK | FIEF_FLAG_FORCE_JITUI);

                    if (SUCCEEDED(hrTmp))
                    {
                        IShellPropSheetExt *pspse;

                        hrTmp = pSubsMgr2->QueryInterface(IID_PPV_ARG(IShellPropSheetExt, &pspse));

                        if (SUCCEEDED(hrTmp))
                        {
                            hrTmp = pspse->AddPages(pfnAddPage, lParam);
                            pspse->Release();
                        }

                        pSubsMgr2->Release();
                    }
                }
            }
        }
        
        if (FAILED(hr))
        {
            delete pisdata;
            pisdata = NULL;
        }
    }
    
    return hr;
}

// IShellExtInit::Initialize method for Intshcut

STDMETHODIMP Intshcut::Initialize(LPCITEMIDLIST pcidlFolder, IDataObject * pido, HKEY hkeyProgID)
{
    HRESULT hr;
    STGMEDIUM stgmed;
    FORMATETC fmtetc = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
    ASSERT(NULL != pido);
    
    if (m_pInitDataObject)
    {
        m_pInitDataObject->Release();
    }
    m_pInitDataObject = pido;
    m_pInitDataObject->AddRef();

    hr = pido->GetData(&fmtetc, &stgmed);
    if (hr == S_OK)
    {
        TCHAR szPath[MAX_PATH];
        if (DragQueryFile((HDROP)stgmed.hGlobal, 0, szPath, SIZECHARS(szPath)))
        {
            m_fProbablyDefCM = TRUE;
            hr = LoadFromFile(szPath);
        }

        ReleaseStgMedium(&stgmed);
    }

    return(hr);
}

// IShellPropSheetExt::AddPages method for Intshcut

STDMETHODIMP Intshcut::AddPages(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam)
{
    ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
    ASSERT(IS_VALID_CODE_PTR(pfnAddPage, LPFNADDPROPSHEETPAGE));

    HRESULT hres = AddISPS(this, pfnAddPage, lParam);
    if (SUCCEEDED(hres))
    {
        // Make the Internet Shortcut page be the default page
        hres = ResultFromShort(1);  
    }

    return hres;
}

STDMETHODIMP Intshcut::ReplacePage(UINT uPageID, LPFNADDPROPSHEETPAGE pfnReplaceWith, LPARAM lParam)
{
    return E_NOTIMPL;
}
