/* * isprsht.cpp - IPropSheetExt implementation for URL class. */ #include "priv.h" #include "ishcut.h" #include #include // for WMTRAY_ messages #include // VER_XXX for FaultInFeature #include // ISubscriptionMgrPriv #include #undef NO_HELP // for help.h #include "resource.h" #include #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)); hr = StringCchCopy(pisdata->rgchIconFile, ARRAYSIZE(pisdata->rgchIconFile), szExpandedPath); pisdata->niIcon = niIcon; } 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; }