4692 lines
146 KiB
C++
4692 lines
146 KiB
C++
#include "priv.h"
|
|
#include "sccls.h"
|
|
#include "shlobj.h"
|
|
|
|
#include <tchar.h>
|
|
|
|
#ifndef UNIX
|
|
#include <webcheck.h>
|
|
#else
|
|
#include <subsmgr.h>
|
|
#endif
|
|
|
|
#include "resource.h"
|
|
#include "mshtml.h" // for IHTMLElement
|
|
#include "mlang.h" // fo char conversion
|
|
#include <advpub.h> // for IE activesetup GUID
|
|
#include "winineti.h" // For name of a mutex used in IsWininetLoadedAnywhere()
|
|
#include "htregmng.h"
|
|
#include <ntverp.h>
|
|
#include <platform.h>
|
|
#include <mobsync.h>
|
|
#include <mobsyncp.h>
|
|
#include <winuser.h>
|
|
#include <mluisupp.h>
|
|
#include "shdocfl.h"
|
|
#include <shlwapip.h>
|
|
#include "inetnot.h"
|
|
#include <shfolder.h>
|
|
|
|
#include "..\inc\brutil.cpp"
|
|
|
|
STDAPI CDelegateMalloc_Create(void *pv, SIZE_T cbSize, WORD wOuter, IMalloc **ppmalloc);
|
|
|
|
const VARIANT c_vaEmpty = {0};
|
|
|
|
const TCHAR c_szRegKeyTypedURLs[] = TEXT("Software\\Microsoft\\Internet Explorer\\TypedURLs");
|
|
|
|
#define DM_SESSIONCOUNT 0
|
|
|
|
int g_cxIcon = 0;
|
|
int g_cyIcon = 0;
|
|
int g_cxSmIcon = 0;
|
|
int g_cySmIcon = 0;
|
|
|
|
|
|
const DISPPARAMS c_dispparamsNoArgs = {NULL, NULL, 0, 0};
|
|
const LARGE_INTEGER c_li0 = { 0, 0 };
|
|
|
|
const ITEMIDLIST s_idlNULL = { 0 } ;
|
|
|
|
// 07.28.2000 - Moved from urlhist.cpp since its used in two places now.
|
|
#ifdef UNICODE
|
|
#define SHGETFOLDERPATH "SHGetFolderPathW"
|
|
#else
|
|
#define SHGETFOLDERPATH "SHGetFolderPathA"
|
|
#endif
|
|
#undef SHGetFolderPath
|
|
typedef HRESULT (*PFNSHGETFOLDERPATH)(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath);
|
|
|
|
PFNSHGETFOLDERPATH g_pfnGetFolderPath = NULL;
|
|
|
|
HRESULT SHGetFolderPathD(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath)
|
|
{
|
|
if (!g_pfnGetFolderPath)
|
|
{
|
|
// note, this is already loaded so this LoadLibray() is fast
|
|
HMODULE hmod = LoadLibrary(TEXT("shell32.dll"));
|
|
g_pfnGetFolderPath = (PFNSHGETFOLDERPATH)GetProcAddress(hmod, SHGETFOLDERPATH);
|
|
|
|
// not there, must be downlevel shell32, use shfolder.dll instead
|
|
if (!g_pfnGetFolderPath)
|
|
{
|
|
hmod = LoadLibrary(TEXT("shfolder.dll"));
|
|
g_pfnGetFolderPath = (PFNSHGETFOLDERPATH)GetProcAddress(hmod, SHGETFOLDERPATH);
|
|
}
|
|
// note, we leak the hmod, for shell32/shfolder that is OK
|
|
}
|
|
|
|
HRESULT hr;
|
|
if (g_pfnGetFolderPath)
|
|
hr = g_pfnGetFolderPath(hwnd, csidl, hToken, dwFlags, pszPath);
|
|
else
|
|
{
|
|
*pszPath = 0;
|
|
hr = E_FAIL;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
int InitColorDepth(void)
|
|
{
|
|
static int s_lrFlags = 0; // Flags passed to LoadImage
|
|
if (s_lrFlags == 0)
|
|
{
|
|
int nColorRes, nIconDepth = 0;
|
|
HKEY hkey;
|
|
|
|
// Determine the color depth so we can load the best image
|
|
// (This code was stolen from FileIconInit in shell32)
|
|
|
|
// Get the user preferred icon size (and color depth) from the
|
|
// registry.
|
|
//
|
|
if (NO_ERROR == RegOpenKey(HKEY_CURRENT_USER, REGSTR_PATH_METRICS, &hkey))
|
|
{
|
|
nIconDepth = SHRegGetIntW(hkey, L"Shell Icon Bpp", nIconDepth);
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
nColorRes = GetCurColorRes();
|
|
|
|
if (nIconDepth > nColorRes)
|
|
nIconDepth = 0;
|
|
|
|
if (nColorRes <= 8)
|
|
nIconDepth = 0; // wouldn't have worked anyway
|
|
|
|
if (nColorRes > 4 && nIconDepth <= 4)
|
|
s_lrFlags = LR_VGACOLOR;
|
|
else
|
|
s_lrFlags = LR_DEFAULTCOLOR;
|
|
}
|
|
return s_lrFlags;
|
|
}
|
|
|
|
HICON g_hiconSplat = NULL;
|
|
HICON g_hiconSplatSm = NULL; // small version
|
|
|
|
void LoadCommonIcons(void)
|
|
{
|
|
if (NULL == g_hiconSplat)
|
|
{
|
|
// Use LoadLibraryEx so we don't load code pages
|
|
HINSTANCE hinst = LoadLibrary(TEXT("url.dll"));
|
|
if (hinst)
|
|
{
|
|
int lrFlags = InitColorDepth();
|
|
g_hiconSplat = (HICON)LoadImage(hinst, MAKEINTRESOURCE(IDI_URL_SPLAT), IMAGE_ICON, g_cxIcon, g_cyIcon, lrFlags);
|
|
g_hiconSplatSm = (HICON)LoadImage(hinst, MAKEINTRESOURCE(IDI_URL_SPLAT), IMAGE_ICON, g_cxSmIcon, g_cySmIcon, lrFlags);
|
|
|
|
FreeLibrary(hinst);
|
|
}
|
|
}
|
|
}
|
|
|
|
STDAPI_(BOOL) UrlHitsNetW(LPCWSTR pszURL)
|
|
{
|
|
BOOL fResult;
|
|
|
|
// Handle the easy ones on our own and call URLMON for the others.
|
|
|
|
switch (GetUrlScheme(pszURL))
|
|
{
|
|
case URL_SCHEME_FILE:
|
|
case URL_SCHEME_RES:
|
|
fResult = FALSE;
|
|
break;
|
|
|
|
case URL_SCHEME_HTTP:
|
|
case URL_SCHEME_HTTPS:
|
|
case URL_SCHEME_FTP:
|
|
case URL_SCHEME_GOPHER:
|
|
case URL_SCHEME_TELNET:
|
|
case URL_SCHEME_WAIS:
|
|
fResult = TRUE;
|
|
break;
|
|
|
|
default:
|
|
{
|
|
DWORD fHitsNet;
|
|
DWORD dwSize;
|
|
fResult = SUCCEEDED(CoInternetQueryInfo(
|
|
pszURL, QUERY_USES_NETWORK,
|
|
0, &fHitsNet, sizeof(fHitsNet), &dwSize, 0)) && fHitsNet;
|
|
}
|
|
}
|
|
|
|
return fResult;
|
|
}
|
|
|
|
STDAPI_(BOOL) CallCoInternetQueryInfo(LPCTSTR pszURL, QUERYOPTION QueryOption)
|
|
{
|
|
DWORD fRetVal;
|
|
DWORD dwSize;
|
|
return SUCCEEDED(CoInternetQueryInfo(
|
|
pszURL, QueryOption,
|
|
0, &fRetVal, sizeof(fRetVal), &dwSize, 0)) && fRetVal;
|
|
}
|
|
|
|
// see if a given URL is in the cache
|
|
STDAPI_(BOOL) UrlIsInCache(LPCTSTR pszURL)
|
|
{
|
|
return CallCoInternetQueryInfo(pszURL, QUERY_IS_CACHED);
|
|
}
|
|
|
|
// See if a give URL is actually present as an installed entry
|
|
STDAPI_(BOOL) UrlIsInstalledEntry(LPCTSTR pszURL)
|
|
{
|
|
return CallCoInternetQueryInfo(pszURL, QUERY_IS_INSTALLEDENTRY);
|
|
}
|
|
|
|
|
|
// see if a given URL is in the cache OR if it is mapped
|
|
|
|
STDAPI_(BOOL) UrlIsMappedOrInCache(LPCTSTR pszURL)
|
|
{
|
|
return CallCoInternetQueryInfo(pszURL, QUERY_IS_CACHED_OR_MAPPED);
|
|
}
|
|
|
|
BOOL IsFileUrlW(LPCWSTR pcwzUrl)
|
|
{
|
|
return (GetUrlSchemeW(pcwzUrl) == URL_SCHEME_FILE);
|
|
}
|
|
|
|
BOOL IsFileUrl(LPCSTR psz)
|
|
{
|
|
return (GetUrlSchemeA(psz) == URL_SCHEME_FILE);
|
|
}
|
|
|
|
BOOL PathIsFilePath(LPCWSTR lpszPath)
|
|
{
|
|
#ifdef UNIX
|
|
if (lpszPath[0] == TEXT('/'))
|
|
#else
|
|
if ((lpszPath[0] == TEXT('\\')) || (lpszPath[0] != TEXT('\0') && lpszPath[1] == TEXT(':')))
|
|
#endif
|
|
return TRUE;
|
|
|
|
return IsFileUrlW(lpszPath);
|
|
}
|
|
|
|
BOOL IsSubscribableW(LPCWSTR pszUrl)
|
|
{
|
|
// FEATURE: this should be method on the subscription mgr interface - zekel
|
|
DWORD dwScheme = GetUrlSchemeW(pszUrl);
|
|
return (dwScheme == URL_SCHEME_HTTP) || (dwScheme == URL_SCHEME_HTTPS);
|
|
}
|
|
|
|
BOOL IsSubscribableA(LPCSTR pszUrl)
|
|
{
|
|
// FEATURE: this should be method on the subscription mgr interface - zekel
|
|
DWORD dwScheme = GetUrlSchemeA(pszUrl);
|
|
return (dwScheme == URL_SCHEME_HTTP) || (dwScheme == URL_SCHEME_HTTPS);
|
|
}
|
|
|
|
DWORD SHRandom(void)
|
|
{
|
|
GUID guid;
|
|
DWORD dw;
|
|
|
|
CoCreateGuid(&guid);
|
|
HashData((LPBYTE)&guid, SIZEOF(guid), (LPBYTE)&dw, SIZEOF(dw));
|
|
|
|
return dw;
|
|
}
|
|
|
|
// See if we are hosted by IE (explorer.exe or iexplore.exe)
|
|
BOOL IsInternetExplorerApp()
|
|
{
|
|
if ((g_fBrowserOnlyProcess) || // if in iexplore.exe process,
|
|
(GetModuleHandle(TEXT("EXPLORER.EXE")))) // or explorer.exe process,
|
|
{
|
|
return TRUE; // then we are IE
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL IsTopFrameBrowser(IServiceProvider *psp, IUnknown *punk)
|
|
{
|
|
IShellBrowser *psb;
|
|
|
|
ASSERT(psp);
|
|
ASSERT(punk);
|
|
|
|
BOOL fRet = FALSE;
|
|
if (SUCCEEDED(psp->QueryService(SID_STopFrameBrowser, IID_PPV_ARG(IShellBrowser, &psb))))
|
|
{
|
|
fRet = IsSameObject(psb, punk);
|
|
psb->Release();
|
|
}
|
|
return fRet;
|
|
}
|
|
|
|
DWORD GetUrlSchemePidl(LPITEMIDLIST pidl)
|
|
{
|
|
if (pidl && IsURLChild(pidl, TRUE))
|
|
{
|
|
TCHAR szUrl[MAX_URL_STRING];
|
|
if (SUCCEEDED(IEGetDisplayName(pidl, szUrl, SHGDN_FORPARSING)))
|
|
return GetUrlScheme(szUrl);
|
|
}
|
|
return URL_SCHEME_INVALID;
|
|
}
|
|
|
|
|
|
STDAPI_(BSTR) LoadBSTR(UINT uID)
|
|
{
|
|
WCHAR wszBuf[MAX_PATH];
|
|
if (MLLoadStringW(uID, wszBuf, ARRAYSIZE(wszBuf)))
|
|
{
|
|
return SysAllocString(wszBuf);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
BOOL StringIsUTF8A(LPCSTR psz, DWORD cb)
|
|
{
|
|
BOOL fRC = FALSE;
|
|
CHAR *pb;
|
|
CHAR b;
|
|
DWORD dwCnt;
|
|
DWORD dwUTF8Cnt;
|
|
|
|
if (!psz || !(*psz) || cb == 0)
|
|
return(FALSE);
|
|
|
|
pb = (CHAR*)psz;
|
|
while(cb-- && *pb)
|
|
{
|
|
if ((*pb & 0xc0) == 0xc0) // bit pattern starts with 11
|
|
{
|
|
dwCnt = dwUTF8Cnt = 0;
|
|
b = *pb;
|
|
while((b & 0xc0) == 0xc0)
|
|
{
|
|
dwCnt++;
|
|
if ((*(pb+dwCnt) & 0xc0) == 0x80) // bits at dwCnt bytes from current offset in str aren't 10
|
|
dwUTF8Cnt++;
|
|
b = (b << 1) & 0xff;
|
|
}
|
|
if (dwCnt == dwUTF8Cnt)
|
|
fRC = TRUE; // Found UTF8 encoded chars
|
|
|
|
pb += ++dwCnt;
|
|
}
|
|
else
|
|
{
|
|
pb++;
|
|
}
|
|
}
|
|
|
|
return(fRC);
|
|
}
|
|
|
|
|
|
BOOL StringIsUTF8W(LPCWSTR pwz, DWORD cb)
|
|
{
|
|
BOOL fRC = FALSE;
|
|
WCHAR *pb;
|
|
WCHAR b;
|
|
DWORD dwCnt;
|
|
DWORD dwUTF8Cnt;
|
|
|
|
if (!pwz || !(*pwz) || cb == 0)
|
|
return(FALSE);
|
|
|
|
pb = (WCHAR*)pwz;
|
|
while(cb-- && *pb)
|
|
{
|
|
if (*pb > 255) // Non ansi so bail
|
|
return(FALSE);
|
|
|
|
if ((*pb & 0xc0) == 0xc0) // bit pattern starts with 11
|
|
{
|
|
dwCnt = dwUTF8Cnt = 0;
|
|
b = *pb;
|
|
while((b & 0xc0) == 0xc0)
|
|
{
|
|
dwCnt++;
|
|
if ((*(pb+dwCnt) & 0xc0) == 0x80) // bits at dwCnt bytes from current offset in str aren't 10
|
|
dwUTF8Cnt++;
|
|
b = (b << 1) & 0xff;
|
|
}
|
|
if (dwCnt == dwUTF8Cnt)
|
|
fRC = TRUE; // Found UTF8 encoded chars
|
|
|
|
pb += ++dwCnt;
|
|
}
|
|
else
|
|
{
|
|
pb++;
|
|
}
|
|
}
|
|
|
|
return(fRC);
|
|
}
|
|
|
|
//
|
|
// StringContainsHighAnsi
|
|
//
|
|
// Determine if string contains high-ANSI characters. Search is
|
|
// stopped when we hit the first high-ANSI character, when we hit the terminator
|
|
// or when we have decremented dwInLen to zero
|
|
//
|
|
// Return Value:
|
|
// TRUE - pszIn contains one or more high-ANSI characters
|
|
//
|
|
// FALSE - pszIn (or substring of length dwInLen) does not contain
|
|
// high-ANSI characters
|
|
//
|
|
BOOL StringContainsHighAnsiA(LPCSTR pszIn, DWORD dwInLen)
|
|
{
|
|
while (dwInLen-- && *pszIn)
|
|
{
|
|
if (*pszIn++ & 0x80)
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL StringContainsHighAnsiW(LPCWSTR pszIn, DWORD dwInLen)
|
|
{
|
|
while (dwInLen-- && *pszIn)
|
|
{
|
|
if (*pszIn++ & 0x80)
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL UTF8Enabled(void)
|
|
{
|
|
static DWORD dwIE = URL_ENCODING_NONE;
|
|
DWORD dwOutLen = sizeof(DWORD);
|
|
|
|
if (dwIE == URL_ENCODING_NONE)
|
|
UrlMkGetSessionOption(URLMON_OPTION_URL_ENCODING, &dwIE, sizeof(DWORD), &dwOutLen, NULL);
|
|
return dwIE == URL_ENCODING_ENABLE_UTF8;
|
|
}
|
|
|
|
//
|
|
// PrepareURLForDisplay
|
|
//
|
|
// Decodes without stripping file:// prefix
|
|
//
|
|
|
|
#undef PrepareURLForDisplay
|
|
BOOL PrepareURLForDisplayW(LPCWSTR pwz, LPWSTR pwzOut, LPDWORD pcbOut)
|
|
{
|
|
if (PathIsFilePath(pwz))
|
|
{
|
|
if (IsFileUrlW(pwz))
|
|
return SUCCEEDED(PathCreateFromUrlW(pwz, pwzOut, pcbOut, 0));
|
|
|
|
StrCpyNW(pwzOut, pwz, *pcbOut);
|
|
*pcbOut = lstrlenW(pwzOut);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL fRet = SUCCEEDED(UrlUnescapeW((LPWSTR)pwz, pwzOut, pcbOut, 0));
|
|
if (fRet)
|
|
{
|
|
SHCleanupUrlForDisplay(pwzOut);
|
|
}
|
|
return fRet;
|
|
}
|
|
|
|
// ****************************************************************************
|
|
// BEGIN - MOVE TO SHLWAPI
|
|
//
|
|
// TODO (grzegorz): move this code to shlwapi.dll
|
|
// ****************************************************************************
|
|
|
|
#define QUERY L'?'
|
|
#define POUND L'#'
|
|
#define HEX_ESCAPE L'%'
|
|
#define TERMSTR(pch) *(pch) = L'\0'
|
|
|
|
BOOL IsHex(WCHAR ch)
|
|
{
|
|
return ( (ch >= TEXT('0') && ch <= TEXT('9'))
|
|
|| (ch >= TEXT('A') && ch <= TEXT('F'))
|
|
|| (ch >= TEXT('a') && ch <= TEXT('f')));
|
|
}
|
|
|
|
WORD HexToWord(WCHAR ch)
|
|
{
|
|
if(ch >= TEXT('0') && ch <= TEXT('9'))
|
|
return (WORD) ch - TEXT('0');
|
|
if(ch >= TEXT('A') && ch <= TEXT('F'))
|
|
return (WORD) ch - TEXT('A') + 10;
|
|
if(ch >= TEXT('a') && ch <= TEXT('f'))
|
|
return (WORD) ch - TEXT('a') + 10;
|
|
|
|
ASSERT(FALSE); //we have tried to use a non-hex number
|
|
return (WORD) -1;
|
|
}
|
|
|
|
inline BOOL IsEscapedOctetW(LPCWSTR pch)
|
|
{
|
|
return (pch[0] == HEX_ESCAPE && IsHex(pch[1]) && IsHex(pch[2])) ? TRUE : FALSE;
|
|
}
|
|
|
|
WCHAR TranslateEscapedOctetW(LPCWSTR pch)
|
|
{
|
|
WCHAR ch;
|
|
ASSERT(IsEscapedOctetW(pch));
|
|
|
|
pch++;
|
|
ch = (WCHAR) HexToWord(*pch++) * 16; // hi nibble
|
|
ch += HexToWord(*pch); // lo nibble
|
|
|
|
return ch;
|
|
}
|
|
|
|
HRESULT CopyOutW(PSHSTRW pstr, LPWSTR psz, LPDWORD pcch)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD cch;
|
|
ASSERT(pstr);
|
|
ASSERT(psz);
|
|
ASSERT(pcch);
|
|
|
|
cch = pstr->GetLen();
|
|
if ((*pcch > cch) && psz)
|
|
StrCpyNW(psz, pstr->GetStr(), pstr->GetLen() + 1);
|
|
else
|
|
hr = E_POINTER;
|
|
|
|
*pcch = cch + (FAILED(hr) ? 1 : 0);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT ShdocvwUrlUnescapeInplaceW(LPWSTR psz, DWORD dwFlags, UINT uiCP)
|
|
{
|
|
WCHAR *pchSrc = psz;
|
|
WCHAR *pchDst = psz;
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
while (*pchSrc)
|
|
{
|
|
if ((*pchSrc == POUND || *pchSrc == QUERY) && (dwFlags & URL_DONT_ESCAPE_EXTRA_INFO))
|
|
{
|
|
StrCpyNW(pchDst, pchSrc, lstrlenW(pchSrc));
|
|
pchDst += lstrlenW(pchDst);
|
|
break;
|
|
}
|
|
|
|
if (IsEscapedOctetW(pchSrc))
|
|
{
|
|
int cchAnsi = 0;
|
|
int cchDst;
|
|
SHSTRA strAnsi;
|
|
LPSTR pchDstAnsi;
|
|
|
|
hr = strAnsi.SetStr(pchDst);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
else
|
|
pchDstAnsi = strAnsi.GetInplaceStr();
|
|
|
|
while (*pchSrc && IsEscapedOctetW(pchSrc))
|
|
{
|
|
WCHAR ch = TranslateEscapedOctetW(pchSrc);
|
|
|
|
*pchDstAnsi++ = LOBYTE(ch);
|
|
pchSrc += 3; // enuff for "%XX"
|
|
cchAnsi++;
|
|
}
|
|
|
|
if (cchAnsi)
|
|
{
|
|
TERMSTR(pchDstAnsi);
|
|
// we have min 2 extra chars in pchDst to use, so we can pass cchAnsi + 1
|
|
cchDst = SHAnsiToUnicodeCP(uiCP, strAnsi, pchDst, cchAnsi + 1);
|
|
pchDst += cchDst - 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*pchDst++ = *pchSrc++;
|
|
}
|
|
}
|
|
|
|
TERMSTR(pchDst);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT ShdocvwUrlUnescapeW(LPWSTR pszUrl, LPWSTR pszOut, LPDWORD pcchOut, DWORD dwFlags, UINT uiCP)
|
|
{
|
|
RIPMSG(pszUrl && IS_VALID_STRING_PTRW(pszUrl, -1), "ShdocvwUrlUnescapeW: Caller passed invalid pszUrl");
|
|
|
|
if (dwFlags & URL_UNESCAPE_INPLACE)
|
|
{
|
|
return ShdocvwUrlUnescapeInplaceW(pszUrl, dwFlags, uiCP);
|
|
}
|
|
|
|
RIPMSG(NULL != pcchOut && IS_VALID_WRITE_PTR(pcchOut, DWORD), "ShdocvwUrlUnescapeW: Caller passed invalid pcchOut");
|
|
RIPMSG(pszOut && (NULL == pcchOut || IS_VALID_WRITE_BUFFER(pszOut, WCHAR, *pcchOut)), "ShdocvwUrlUnescapeW: Caller passed invalid pszOut");
|
|
|
|
if ( !pszUrl
|
|
|| !pcchOut
|
|
|| !*pcchOut
|
|
|| !pszOut)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
SHSTRW str;
|
|
HRESULT hr = str.SetStr(pszUrl);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ShdocvwUrlUnescapeInplaceW(str.GetInplaceStr(), dwFlags, uiCP);
|
|
hr = CopyOutW(&str, pszOut, pcchOut);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
// ****************************************************************************
|
|
// END - MOVE TO SHLWAPI
|
|
// ****************************************************************************
|
|
|
|
//
|
|
// PrepareURLForDisplayUTF8W
|
|
//
|
|
// pwz - [In] UTF8 encoded string like "%e6%aa%e4%a6.doc".
|
|
// pwzOut - [Out] UTF8 decoded string.
|
|
// pcchOut - [In/Out] Count of characters in pwzOut on input. Number of chars copies to pwzOut on output
|
|
// including the terminating null.
|
|
// fUTF8Enabled - [In] Flag to indicated whether UTF8 is enabled.
|
|
// uiCP - [In] Codepage used to convert escaped characters, when fUTF8Enabled is false
|
|
//
|
|
// pwz and pwzOut can be the same buffer.
|
|
//
|
|
// Returns:
|
|
// S_OK upon success.
|
|
// E_FAIL for failure.
|
|
// ERROR_BUFFER_OVERFLOW if the number of converted chars is greater than the passed in size of output buffer.
|
|
//
|
|
// Note: If UTF8 is not enabled or the string does not contain UTF8 the output string will be unescaped
|
|
// and will return S_OK.
|
|
//
|
|
HRESULT _PrepareURLForDisplayUTF8W(LPCWSTR pwz, LPWSTR pwzOut, LPDWORD pcchOut, BOOL fUTF8Enabled, UINT uiCP)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
DWORD cch;
|
|
DWORD cch1;
|
|
CHAR szBuf[MAX_URL_STRING];
|
|
CHAR *pszBuf = szBuf;
|
|
|
|
if (!pwz || !pwzOut || !pcchOut)
|
|
{
|
|
if (pcchOut)
|
|
*pcchOut = 0;
|
|
return(hr);
|
|
}
|
|
|
|
cch = *pcchOut;
|
|
cch1 = ARRAYSIZE(szBuf);
|
|
if (uiCP != (UINT)-1)
|
|
hr = ShdocvwUrlUnescapeW((LPWSTR)pwz, pwzOut, pcchOut, 0, fUTF8Enabled ? CP_UTF8 : uiCP);
|
|
else
|
|
{
|
|
hr = UrlUnescapeW((LPWSTR)pwz, pwzOut, pcchOut, 0);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (fUTF8Enabled && StringIsUTF8W(pwzOut, cch))
|
|
{
|
|
if (*pcchOut > ARRAYSIZE(szBuf)) // Internal buffer not big enough so alloc one
|
|
{
|
|
if ((pszBuf = (CHAR *)LocalAlloc(LPTR, ((*pcchOut)+1) * sizeof(CHAR))) == NULL)
|
|
{
|
|
*pcchOut = 0;
|
|
return(E_OUTOFMEMORY);
|
|
}
|
|
cch1 = *pcchOut;
|
|
}
|
|
|
|
// Compress wide string
|
|
CHAR *pIn = (CHAR *)pwzOut;
|
|
CHAR *pOut = pszBuf;
|
|
while((*pIn != '\0') || (*(pIn+1) != '\0') && --cch1)
|
|
{
|
|
if (*pIn != '\0')
|
|
{
|
|
*pOut = *pIn;
|
|
pOut++;
|
|
}
|
|
pIn++;
|
|
}
|
|
*pOut = '\0';
|
|
|
|
// Convert to UTF8 wide string
|
|
if ((cch1 = SHAnsiToUnicodeCP(CP_UTF8, pszBuf, pwzOut, cch)) != 0)
|
|
{
|
|
hr = S_OK;
|
|
*pcchOut = cch1;
|
|
}
|
|
|
|
// SHAnsiToUnicode doesn't tell us if it has truncated the convertion to fit the output buffer
|
|
RIPMSG(cch1 != cch, "_PrepareURLForDisplayUTF8W: Passed in size of out buf equal to converted size; buffer might be truncated");
|
|
|
|
if ((pszBuf != NULL) && (pszBuf != szBuf))
|
|
{
|
|
LocalFree((CHAR *)pszBuf);
|
|
pszBuf = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = S_OK;;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
SHCleanupUrlForDisplay(pwzOut);
|
|
}
|
|
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT PrepareURLForDisplayUTF8W(LPCWSTR pwz, LPWSTR pwzOut, LPDWORD pcchOut, BOOL fUTF8Enabled)
|
|
{
|
|
return _PrepareURLForDisplayUTF8W(pwz, pwzOut, pcchOut, fUTF8Enabled, (UINT)-1);
|
|
}
|
|
|
|
//
|
|
// PrepareURLForExternalApp -
|
|
//
|
|
// Decodes and strips, if needed, file:// prefix
|
|
//
|
|
|
|
// APPCOMPAT - for IE30 compatibility reasons, we have to Unescape all Urls - zekel - 1-JUL-97
|
|
// before passing them to an APP. this does limit their use, but
|
|
// people already depend on this behavior. specifically MS Chat.
|
|
BOOL PrepareURLForExternalApp (LPCWSTR psz, LPWSTR pszOut, LPDWORD pcchOut)
|
|
{
|
|
if (IsFileUrlW(psz))
|
|
return SUCCEEDED(PathCreateFromUrl(psz, pszOut, pcchOut, 0));
|
|
else
|
|
return SUCCEEDED(UrlUnescape((LPWSTR)psz, pszOut, pcchOut, 0));
|
|
|
|
}
|
|
|
|
SHDOCAPI
|
|
IURLQualifyWithContext(
|
|
IN LPCWSTR pcszURL,
|
|
IN DWORD dwFlags, // UQF_*
|
|
OUT LPWSTR pszTranslatedURL,
|
|
LPBOOL pbWasSearchURL,
|
|
LPBOOL pbWasCorrected,
|
|
ISearchContext * pSC);
|
|
|
|
BOOL ParseURLFromOutsideSourceWithContextW (LPCWSTR psz, LPWSTR pszOut, LPDWORD pcchOut, LPBOOL pbWasSearchURL, ISearchContext * pSC)
|
|
{
|
|
// This is our hardest case. Users and outside applications might
|
|
// type fully-escaped, partially-escaped, or unescaped URLs at us.
|
|
// We need to handle all these correctly. This API will attempt to
|
|
// determine what sort of URL we've got, and provide us a returned URL
|
|
// that is guaranteed to be FULLY escaped.
|
|
|
|
IURLQualifyWithContext(psz, UQF_DEFAULT, pszOut, pbWasSearchURL, NULL, pSC);
|
|
|
|
//
|
|
// go ahead and canonicalize this appropriately
|
|
//
|
|
if (FAILED(UrlCanonicalize(pszOut, pszOut, pcchOut, URL_ESCAPE_SPACES_ONLY)))
|
|
{
|
|
//
|
|
// we cant resize from here.
|
|
// NOTE UrlCan will return E_POINTER if it is an insufficient buffer
|
|
//
|
|
TraceMsg(DM_ERROR, "sdv PUFOS:UC() failed.");
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
} // ParseURLFromOutsideSource
|
|
|
|
BOOL ParseURLFromOutsideSourceW (LPCWSTR psz, LPWSTR pszOut, LPDWORD pcchOut, LPBOOL pbWasSearchURL)
|
|
{
|
|
return ParseURLFromOutsideSourceWithContextW(psz, pszOut, pcchOut, pbWasSearchURL, NULL);
|
|
} // ParseURLFromOutsideSource
|
|
BOOL ParseURLFromOutsideSourceA (LPCSTR psz, LPSTR pszOut, LPDWORD pcchOut, LPBOOL pbWasSearchURL)
|
|
{
|
|
SHSTRW strw;
|
|
DWORD cch ;
|
|
|
|
ASSERT(psz);
|
|
ASSERT(pszOut);
|
|
ASSERT(pcchOut && *pcchOut);
|
|
|
|
//
|
|
// WARNING: we arent guaranteed to have the correct cch's here - zekel - 27-jan-97
|
|
// but for now this is adequate.
|
|
//
|
|
if (SUCCEEDED(strw.SetStr(psz)) && SUCCEEDED(strw.SetSize(cch = *pcchOut)) &&
|
|
ParseURLFromOutsideSourceW(strw, strw.GetInplaceStr(), pcchOut, pbWasSearchURL))
|
|
{
|
|
return SHUnicodeToAnsi((LPCWSTR)strw, pszOut, cch);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
int DPA_ILFreeCallback(void * p, void * d)
|
|
{
|
|
Pidl_Set((LPITEMIDLIST*)&p, NULL);
|
|
return 1;
|
|
}
|
|
|
|
void _DeletePidlDPA(HDPA hdpa)
|
|
{
|
|
DPA_DestroyCallback(hdpa, (PFNDPAENUMCALLBACK)DPA_ILFreeCallback, 0);
|
|
hdpa = NULL;
|
|
}
|
|
|
|
BOOL _InitComCtl32()
|
|
{
|
|
static BOOL fInitialized = FALSE;
|
|
|
|
if (!fInitialized)
|
|
{
|
|
INITCOMMONCONTROLSEX icc;
|
|
|
|
icc.dwSize = sizeof(INITCOMMONCONTROLSEX);
|
|
icc.dwICC = ICC_USEREX_CLASSES | ICC_COOL_CLASSES | ICC_INTERNET_CLASSES | ICC_PAGESCROLLER_CLASS | ICC_NATIVEFNTCTL_CLASS;
|
|
fInitialized = InitCommonControlsEx(&icc);
|
|
}
|
|
return fInitialized;
|
|
}
|
|
|
|
#ifndef ALPHA_WARNING_IS_DUMB
|
|
|
|
#pragma message("building with alpha warning enabled")
|
|
|
|
void AlphaWarning(HWND hwnd)
|
|
{
|
|
static BOOL fShown = FALSE;
|
|
TCHAR szTemp[265];
|
|
TCHAR szFull[2048];
|
|
szFull[0] = TEXT('\0');
|
|
int i = IDS_ALPHAWARNING;
|
|
|
|
if (fShown)
|
|
return;
|
|
|
|
fShown = TRUE;
|
|
|
|
while(MLLoadShellLangString (i++, szTemp, ARRAYSIZE(szTemp))) {
|
|
StrCatBuff(szFull, szTemp, ARRAYSIZE(szFull));
|
|
}
|
|
|
|
MessageBox(hwnd, szFull, TEXT("Internet Explorer"), MB_ICONINFORMATION | MB_OK);
|
|
}
|
|
#endif
|
|
|
|
|
|
#define DM_NAV TF_SHDNAVIGATE
|
|
#define DM_ZONE TF_SHDNAVIGATE
|
|
#define DM_IEDDE DM_TRACE
|
|
#define DM_CANCELMODE 0
|
|
#define DM_UIWINDOW 0
|
|
#define DM_ENABLEMODELESS 0
|
|
#define DM_EXPLORERMENU 0
|
|
#define DM_BACKFORWARD 0
|
|
#define DM_PROTOCOL 0
|
|
#define DM_ITBAR 0
|
|
#define DM_STARTUP 0
|
|
#define DM_AUTOLIFE 0
|
|
#define DM_PALETTE 0
|
|
|
|
PFNSHCHANGENOTIFYREGISTER g_pfnSHChangeNotifyRegister = NULL;
|
|
PFNSHCHANGENOTIFYDEREGISTER g_pfnSHChangeNotifyDeregister = NULL;
|
|
|
|
BOOL g_fNewNotify = FALSE; // Are we using classic mode (W95 or new mode?
|
|
|
|
BOOL CALLBACK AddPropSheetPage(HPROPSHEETPAGE hpage, LPARAM lParam)
|
|
{
|
|
PROPSHEETHEADER * ppsh = (PROPSHEETHEADER *)lParam;
|
|
|
|
if (ppsh->nPages < MAX_PAGES)
|
|
{
|
|
ppsh->phpage[ppsh->nPages++] = hpage;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL SHIsRegisteredClient(LPCTSTR pszClient)
|
|
{
|
|
LONG cbSize = 0;
|
|
TCHAR szKey[80];
|
|
|
|
wnsprintf(szKey, ARRAYSIZE(szKey), TEXT("Software\\Clients\\%s"), pszClient);
|
|
return (RegQueryValue(HKEY_LOCAL_MACHINE, szKey, NULL, &cbSize) == ERROR_SUCCESS) &&
|
|
(cbSize > sizeof(TCHAR));
|
|
}
|
|
|
|
// Exporting by ordinal is not available on UNIX.
|
|
// But we have all these symbols exported because it's UNIX default.
|
|
#ifdef UNIX
|
|
#define GET_PRIVATE_PROC_ADDRESS(_hinst, _fname, _ord) GetProcAddress(_hinst, _fname)
|
|
#else
|
|
#define GET_PRIVATE_PROC_ADDRESS(_hinst, _fname, _ord) GetProcAddress(_hinst, _ord)
|
|
#endif
|
|
|
|
ULONG RegisterNotify(HWND hwnd, UINT nMsg, LPCITEMIDLIST pidl, DWORD dwEvents, UINT uFlags, BOOL fRecursive)
|
|
{
|
|
SHChangeNotifyEntry fsne;
|
|
|
|
// See if we need to still figure out which version of SHChange Notify to call?
|
|
if (g_pfnSHChangeNotifyDeregister == NULL)
|
|
{
|
|
|
|
HMODULE hmodShell32 = ::GetModuleHandle(TEXT("SHELL32"));
|
|
if (!hmodShell32)
|
|
return 0; // Nothing registered...
|
|
|
|
g_pfnSHChangeNotifyRegister = (PFNSHCHANGENOTIFYREGISTER)GET_PRIVATE_PROC_ADDRESS(hmodShell32,
|
|
"NTSHChangeNotifyRegister",
|
|
(LPSTR)640);
|
|
if (g_pfnSHChangeNotifyRegister && (WhichPlatform() == PLATFORM_INTEGRATED))
|
|
{
|
|
g_pfnSHChangeNotifyDeregister = (PFNSHCHANGENOTIFYDEREGISTER)GET_PRIVATE_PROC_ADDRESS(hmodShell32,
|
|
"NTSHChangeNotifyDeregister",
|
|
(LPSTR)641);
|
|
g_fNewNotify = TRUE;
|
|
}
|
|
else
|
|
{
|
|
g_pfnSHChangeNotifyRegister = (PFNSHCHANGENOTIFYREGISTER)GET_PRIVATE_PROC_ADDRESS(hmodShell32,
|
|
"SHChangeNotifyRegister",
|
|
(LPSTR)2);
|
|
g_pfnSHChangeNotifyDeregister = (PFNSHCHANGENOTIFYDEREGISTER)GET_PRIVATE_PROC_ADDRESS(hmodShell32,
|
|
"SHChangeNotifyDeregister",
|
|
(LPSTR)4);
|
|
}
|
|
|
|
if (g_pfnSHChangeNotifyDeregister == NULL)
|
|
return 0; // Could not get either to work...
|
|
}
|
|
|
|
uFlags |= SHCNRF_ShellLevel | SHCNRF_InterruptLevel;
|
|
if (g_fNewNotify)
|
|
uFlags |= SHCNRF_NewDelivery;
|
|
|
|
fsne.fRecursive = fRecursive;
|
|
fsne.pidl = pidl;
|
|
return g_pfnSHChangeNotifyRegister(hwnd, uFlags, dwEvents, nMsg, 1, &fsne);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Just like shells SHRestricted() only this put up a message if the restricion
|
|
// is in effect.
|
|
// REARCHITECT: this function is identical to shell32's SHIsRestricted
|
|
BOOL SHIsRestricted(HWND hwnd, RESTRICTIONS rest)
|
|
{
|
|
if (SHRestricted(rest))
|
|
{
|
|
ULONG_PTR uCookie = 0;
|
|
SHActivateContext(&uCookie);
|
|
SHRestrictedMessageBox(hwnd);
|
|
if (uCookie)
|
|
{
|
|
SHDeactivateContext(uCookie);
|
|
}
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL SHIsRestricted2W(HWND hwnd, BROWSER_RESTRICTIONS rest, LPCWSTR pwzUrl, DWORD dwReserved)
|
|
{
|
|
if (SHRestricted2W(rest, pwzUrl, dwReserved))
|
|
{
|
|
ULONG_PTR uCookie = 0;
|
|
SHActivateContext(&uCookie);
|
|
SHRestrictedMessageBox(hwnd);
|
|
if (uCookie)
|
|
{
|
|
SHDeactivateContext(uCookie);
|
|
}
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL bIsValidString(LPCSTR pszString, ULONG cbLen)
|
|
{
|
|
if (cbLen == 0) return TRUE;
|
|
while (cbLen--)
|
|
if (*pszString++ == '\0') return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL ViewIDFromViewMode(UINT uViewMode, SHELLVIEWID *pvid)
|
|
{
|
|
switch (uViewMode)
|
|
{
|
|
case FVM_ICON:
|
|
*pvid = VID_LargeIcons;
|
|
break;
|
|
|
|
case FVM_SMALLICON:
|
|
*pvid = VID_SmallIcons;
|
|
break;
|
|
|
|
case FVM_LIST:
|
|
*pvid = VID_List;
|
|
break;
|
|
|
|
case FVM_DETAILS:
|
|
*pvid = VID_Details;
|
|
break;
|
|
|
|
case FVM_THUMBNAIL:
|
|
*pvid = VID_Thumbnails;
|
|
break;
|
|
|
|
case FVM_TILE:
|
|
*pvid = VID_Tile;
|
|
break;
|
|
|
|
default:
|
|
*pvid = VID_LargeIcons;
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
HIMAGELIST g_himlSysSmall = NULL;
|
|
HIMAGELIST g_himlSysLarge = NULL;
|
|
|
|
void _InitSysImageLists()
|
|
{
|
|
if (!g_himlSysSmall)
|
|
{
|
|
Shell_GetImageLists(&g_himlSysLarge, &g_himlSysSmall);
|
|
|
|
ImageList_GetIconSize(g_himlSysLarge, &g_cxIcon, &g_cyIcon);
|
|
ImageList_GetIconSize(g_himlSysSmall, &g_cxSmIcon, &g_cySmIcon);
|
|
}
|
|
}
|
|
|
|
// Copied from shell32 (was _ILCreate), which does not export this.
|
|
// The fsmenu code needs this function.
|
|
STDAPI_(LPITEMIDLIST) IEILCreate(UINT cbSize)
|
|
{
|
|
LPITEMIDLIST pidl = (LPITEMIDLIST)SHAlloc(cbSize);
|
|
if (pidl)
|
|
memset(pidl, 0, cbSize); // needed for external task allicator
|
|
|
|
return pidl;
|
|
}
|
|
|
|
DWORD CommonDragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt)
|
|
{
|
|
DWORD dwEffect = DROPEFFECT_NONE;
|
|
FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
|
|
|
|
if (pdtobj->QueryGetData(&fmte) == S_OK)
|
|
dwEffect = DROPEFFECT_COPY | DROPEFFECT_LINK;
|
|
else
|
|
{
|
|
InitClipboardFormats();
|
|
|
|
fmte.cfFormat = g_cfHIDA;
|
|
if (pdtobj->QueryGetData(&fmte) == S_OK)
|
|
dwEffect = DROPEFFECT_LINK;
|
|
else {
|
|
fmte.cfFormat = g_cfURL;
|
|
|
|
if (pdtobj->QueryGetData(&fmte) == S_OK)
|
|
dwEffect = DROPEFFECT_LINK | DROPEFFECT_COPY | DROPEFFECT_MOVE;
|
|
}
|
|
}
|
|
|
|
return dwEffect;
|
|
}
|
|
|
|
|
|
|
|
// MapNbspToSp
|
|
//
|
|
// Purpose:
|
|
// Unicode character code point 0x00a0 is designated to HTML
|
|
// entity  , but some windows code pages don't have code
|
|
// point that can map from 0x00a0. In the most occasion in the
|
|
// shell, NBSP is just a space when it's rendered so we can
|
|
// replace it with 0x0020 safely.
|
|
// This function takes lpwszIn as a string that has
|
|
// non-displayable characters in it, and tries to translate
|
|
// it again after removing NBSP (00a0) from it.
|
|
// returns S_OK if this re-translation is successful.
|
|
//
|
|
#define nbsp 0x00a0
|
|
HRESULT SHMapNbspToSp(LPCWSTR lpwszIn, LPSTR lpszOut, int cbszOut)
|
|
{
|
|
BOOL fFoundNbsp = FALSE;
|
|
BOOL fNotDisplayable = TRUE; // assumes FAIL
|
|
LPWSTR pwsz, p;
|
|
|
|
if (!lpwszIn || !lpszOut || cbszOut == 0)
|
|
return E_FAIL;
|
|
|
|
ASSERT(IS_VALID_STRING_PTRW(lpwszIn, -1));
|
|
ASSERT(IS_VALID_WRITE_BUFFER(lpszOut, TCHAR, cbszOut));
|
|
|
|
int cch = lstrlenW(lpwszIn) + 1;
|
|
pwsz = (LPWSTR)LocalAlloc(LPTR, cch * sizeof(WCHAR));
|
|
if (pwsz)
|
|
{
|
|
StrCpyNW(pwsz, lpwszIn, cch);
|
|
p = pwsz;
|
|
while (*p)
|
|
{
|
|
if (*p== nbsp)
|
|
{
|
|
*p= 0x0020; // replace with space
|
|
if (!fFoundNbsp)
|
|
fFoundNbsp = TRUE;
|
|
}
|
|
p++;
|
|
}
|
|
|
|
// don't call WC2MB unless we found Nbsp - for perf reason
|
|
if (fFoundNbsp)
|
|
{
|
|
int iret = WideCharToMultiByte(CP_ACP, 0, pwsz, -1, lpszOut,
|
|
cbszOut, NULL, &fNotDisplayable);
|
|
|
|
if (!fNotDisplayable && iret == 0)
|
|
{
|
|
// truncated. make it dbcs safe.
|
|
SHTruncateString(lpszOut, cbszOut);
|
|
}
|
|
}
|
|
|
|
LocalFree((LOCALHANDLE)pwsz);
|
|
pwsz = NULL;
|
|
}
|
|
|
|
return (fFoundNbsp && !fNotDisplayable) ? S_OK : S_FALSE;
|
|
}
|
|
#undef nbsp
|
|
|
|
|
|
int PropBag_ReadInt4(IPropertyBag* pPropBag, LPWSTR pszKey, int iDefault)
|
|
{
|
|
SHPropertyBag_ReadInt(pPropBag, pszKey, &iDefault);
|
|
return iDefault;
|
|
}
|
|
|
|
HRESULT _SetPreferredDropEffect(IDataObject *pdtobj, DWORD dwEffect)
|
|
{
|
|
InitClipboardFormats();
|
|
|
|
HRESULT hres = E_OUTOFMEMORY;
|
|
DWORD *pdw = (DWORD *)GlobalAlloc(GPTR, sizeof(DWORD));
|
|
if (pdw)
|
|
{
|
|
STGMEDIUM medium;
|
|
FORMATETC fmte = {g_cfPreferredEffect, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
|
|
*pdw = dwEffect;
|
|
|
|
medium.tymed = TYMED_HGLOBAL;
|
|
medium.hGlobal = pdw;
|
|
medium.pUnkForRelease = NULL;
|
|
|
|
hres = pdtobj->SetData(&fmte, &medium, TRUE);
|
|
|
|
if (FAILED(hres))
|
|
{
|
|
GlobalFree((HGLOBAL)pdw);
|
|
pdw = NULL;
|
|
}
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
HRESULT DragDrop(HWND hwnd, IShellFolder * psfParent, LPCITEMIDLIST pidl, DWORD dwPrefEffect, DWORD *pdwEffect)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
LPCITEMIDLIST pidlChild;
|
|
|
|
if (!psfParent)
|
|
IEBindToParentFolder(pidl, &psfParent, &pidlChild);
|
|
else
|
|
{
|
|
pidlChild = pidl;
|
|
psfParent->AddRef();
|
|
}
|
|
|
|
if (psfParent)
|
|
{
|
|
DWORD dwAttrib = DROPEFFECT_MOVE | DROPEFFECT_COPY | DROPEFFECT_LINK;
|
|
|
|
psfParent->GetAttributesOf(1, &pidlChild, &dwAttrib);
|
|
|
|
IDataObject *pdtobj;
|
|
hres = psfParent->GetUIObjectOf(NULL, 1, &pidlChild, IID_IDataObject, NULL, (void**)&pdtobj);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
DWORD dwEffect = (DROPEFFECT_MOVE | DROPEFFECT_COPY | DROPEFFECT_LINK) & dwAttrib;
|
|
|
|
if (dwPrefEffect)
|
|
{
|
|
//win95 shell32 doesn't know about preferred drop effect, so make it the only effect
|
|
if (IsOS(OS_WIN95ORGREATER) && (WhichPlatform() == PLATFORM_BROWSERONLY))
|
|
{
|
|
dwEffect = DROPEFFECT_LINK & dwAttrib;
|
|
}
|
|
else if (dwPrefEffect & dwEffect)
|
|
{
|
|
_SetPreferredDropEffect(pdtobj, dwPrefEffect);
|
|
}
|
|
}
|
|
ASSERT(dwEffect);
|
|
|
|
// Win95 Browser Only - the shell32 in this process doesn't know
|
|
// ole is loaded, even though it is.
|
|
SHLoadOLE(SHELLNOTIFY_OLELOADED);
|
|
IDragSourceHelper* pDragImages;
|
|
|
|
if (SUCCEEDED(CoCreateInstance(CLSID_DragDropHelper, NULL, CLSCTX_INPROC_SERVER, IID_IDragSourceHelper, (void**)&pDragImages)))
|
|
{
|
|
pDragImages->InitializeFromWindow(hwnd, 0, pdtobj);
|
|
pDragImages->Release();
|
|
}
|
|
|
|
hres = SHDoDragDrop(hwnd, pdtobj, NULL, dwEffect, &dwEffect);
|
|
if (pdwEffect)
|
|
*pdwEffect = dwEffect;
|
|
|
|
pdtobj->Release();
|
|
}
|
|
|
|
psfParent->Release();
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
#define IEICONTYPE_GETFILEINFO 0x00000001
|
|
#define IEICONTYPE_DEFAULTICON 0x00000002
|
|
|
|
typedef struct tagIEICONS
|
|
{
|
|
int nDefaultIcon;
|
|
int nIEIcon;
|
|
LPCTSTR szFile;
|
|
LPCTSTR szFileExt;
|
|
int nIconResourceNum;
|
|
LPCTSTR szCLSID;
|
|
DWORD dwType;
|
|
} IEICONS;
|
|
|
|
IEICONS g_IEIcons[] = {
|
|
{-1, -1, TEXT("MSHTML.DLL"), TEXT(".htm"), 1, NULL, IEICONTYPE_GETFILEINFO},
|
|
{-1, -1, TEXT("URL.DLL"), TEXT("http\\DefaultIcon"), 0, TEXT("{FBF23B42-E3F0-101B-8488-00AA003E56F8}"), IEICONTYPE_DEFAULTICON}
|
|
};
|
|
|
|
//This function returns the IE icon regardless of the which browser is default
|
|
|
|
|
|
void _GenerateIEIcons(void)
|
|
{
|
|
int nIndex;
|
|
|
|
for (nIndex = 0; nIndex < ARRAYSIZE(g_IEIcons); nIndex++)
|
|
{
|
|
SHFILEINFO sfi;
|
|
TCHAR szModule[MAX_PATH];
|
|
|
|
HMODULE hmod = GetModuleHandle(g_IEIcons[nIndex].szFile);
|
|
if (hmod)
|
|
{
|
|
GetModuleFileName(hmod, szModule, ARRAYSIZE(szModule));
|
|
}
|
|
else
|
|
{ //HACKHACK : This is a hack to get the mstml
|
|
TCHAR szKey[GUIDSTR_MAX * 4];
|
|
TCHAR szGuid[GUIDSTR_MAX];
|
|
|
|
//The CLSID used here belongs to MS HTML Generic Page. If someone changes the guid then we
|
|
// are tossed.
|
|
if (!g_IEIcons[nIndex].szCLSID)
|
|
SHStringFromGUID(CLSID_HTMLDocument, szGuid, GUIDSTR_MAX);
|
|
wnsprintf(szKey, ARRAYSIZE(szKey), TEXT("CLSID\\%s\\InProcServer32"), g_IEIcons[nIndex].szCLSID ? g_IEIcons[nIndex].szCLSID : szGuid);
|
|
|
|
long cb = SIZEOF(szModule);
|
|
RegQueryValue(HKEY_CLASSES_ROOT, szKey, szModule, &cb);
|
|
|
|
}
|
|
g_IEIcons[nIndex].nIEIcon = Shell_GetCachedImageIndex(szModule, g_IEIcons[nIndex].nIconResourceNum, 0);
|
|
|
|
switch(g_IEIcons[nIndex].dwType)
|
|
{
|
|
case IEICONTYPE_GETFILEINFO:
|
|
sfi.iIcon = 0;
|
|
StrCpyN(szModule, TEXT("c:\\notexist"), ARRAYSIZE(szModule));
|
|
StrCatBuff(szModule, g_IEIcons[nIndex].szFileExt, ARRAYSIZE(szModule));
|
|
SHGetFileInfo(szModule, FILE_ATTRIBUTE_NORMAL, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX | SHGFI_USEFILEATTRIBUTES);
|
|
g_IEIcons[nIndex].nDefaultIcon = sfi.iIcon;
|
|
break;
|
|
|
|
case IEICONTYPE_DEFAULTICON:
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
DWORD cbSize = SIZEOF(szPath);
|
|
|
|
SHGetValue(HKEY_CLASSES_ROOT, g_IEIcons[nIndex].szFileExt, TEXT(""), NULL, szPath, &cbSize);
|
|
g_IEIcons[nIndex].nDefaultIcon = Shell_GetCachedImageIndex(szPath, PathParseIconLocation(szPath), 0);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int IEMapPIDLToSystemImageListIndex(IShellFolder *psfParent, LPCITEMIDLIST pidlChild, int *piSelectedImage)
|
|
{
|
|
int nIndex;
|
|
int nIcon = SHMapPIDLToSystemImageListIndex(psfParent, pidlChild, piSelectedImage);
|
|
|
|
if (-1 == g_IEIcons[0].nDefaultIcon)
|
|
_GenerateIEIcons();
|
|
|
|
for (nIndex = 0; nIndex < ARRAYSIZE(g_IEIcons); nIndex++)
|
|
{
|
|
if ((nIcon == g_IEIcons[nIndex].nDefaultIcon) ||
|
|
(piSelectedImage && *piSelectedImage == g_IEIcons[nIndex].nDefaultIcon))
|
|
{
|
|
nIcon = g_IEIcons[nIndex].nIEIcon;
|
|
if (piSelectedImage)
|
|
*piSelectedImage = nIcon;
|
|
break;
|
|
}
|
|
}
|
|
return nIcon;
|
|
}
|
|
|
|
void IEInvalidateImageList(void)
|
|
{
|
|
g_IEIcons[0].nDefaultIcon = -1;
|
|
}
|
|
|
|
int _GetIEHTMLImageIndex()
|
|
{
|
|
if (-1 == g_IEIcons[0].nDefaultIcon)
|
|
_GenerateIEIcons();
|
|
|
|
return g_IEIcons[0].nIEIcon;
|
|
}
|
|
|
|
// Checks to see if any process at all
|
|
// has loaded wininet
|
|
static BOOL g_fWininetLoadedSomeplace = FALSE;
|
|
BOOL IsWininetLoadedAnywhere()
|
|
{
|
|
HANDLE hMutex = NULL;
|
|
BOOL fRet;
|
|
|
|
if (g_fWininetLoadedSomeplace)
|
|
return TRUE;
|
|
|
|
//
|
|
// Use OpenMutexA so it works on W95.
|
|
// wininet is ansi and created this mutex with CreateMutexA
|
|
hMutex = OpenMutexA(SYNCHRONIZE, FALSE, WININET_STARTUP_MUTEX);
|
|
|
|
if (hMutex)
|
|
{
|
|
fRet = TRUE;
|
|
g_fWininetLoadedSomeplace = TRUE;
|
|
CloseHandle(hMutex);
|
|
}
|
|
else
|
|
{
|
|
fRet = FALSE;
|
|
}
|
|
return fRet;
|
|
}
|
|
|
|
|
|
|
|
// Checks if global state is offline
|
|
BOOL SHIsGlobalOffline(void)
|
|
{
|
|
DWORD dwState = 0, dwSize = sizeof(DWORD);
|
|
BOOL fRet = FALSE;
|
|
|
|
if (!IsWininetLoadedAnywhere())
|
|
return FALSE;
|
|
|
|
// Since wininet is already loaded someplace
|
|
// We have to load wininet to check if offline
|
|
|
|
if (InternetQueryOptionA(NULL, INTERNET_OPTION_CONNECTED_STATE, &dwState,
|
|
&dwSize))
|
|
{
|
|
if (dwState & INTERNET_STATE_DISCONNECTED_BY_USER)
|
|
fRet = TRUE;
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
void SetGlobalOffline(BOOL fOffline)
|
|
{
|
|
INTERNET_CONNECTED_INFO ci;
|
|
|
|
memset(&ci, 0, sizeof(ci));
|
|
if (fOffline) {
|
|
ci.dwConnectedState = INTERNET_STATE_DISCONNECTED_BY_USER;
|
|
ci.dwFlags = ISO_FORCE_DISCONNECTED;
|
|
} else {
|
|
ci.dwConnectedState = INTERNET_STATE_CONNECTED;
|
|
}
|
|
|
|
InternetSetOption(NULL, INTERNET_OPTION_CONNECTED_STATE, &ci, sizeof(ci));
|
|
}
|
|
|
|
// This API is documented and is called by apps outside
|
|
// the shell such as OE
|
|
STDAPI_(void) SetShellOfflineState(BOOL fPutOffline)
|
|
{
|
|
BOOL fWasOffline = SHIsGlobalOffline();
|
|
if (fWasOffline != fPutOffline)
|
|
{
|
|
SetGlobalOffline(fPutOffline); // Set the state
|
|
// Tell all browser windows to update their title
|
|
SendShellIEBroadcastMessage(WM_WININICHANGE,0,0, 1000);
|
|
}
|
|
}
|
|
|
|
|
|
BOOL GetHistoryFolderPath(LPTSTR pszPath, int cchPath)
|
|
{
|
|
INTERNET_CACHE_CONFIG_INFO cci;
|
|
DWORD cbcci = sizeof(INTERNET_CACHE_CONFIG_INFO);
|
|
|
|
if (GetUrlCacheConfigInfo(&cci, &cbcci, CACHE_CONFIG_HISTORY_PATHS_FC))
|
|
{
|
|
StrCpyN(pszPath, cci.CachePaths[0].CachePath, cchPath);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// in:
|
|
// pidlRoot root part of pidl.
|
|
// pidl equal to or child below pidlRoot
|
|
// pszKey root key to store stuff under, should match pidlRoot
|
|
// grfMode read/write
|
|
//
|
|
// example:
|
|
// pidlRoot = c:\win\favorites
|
|
// pidl = c:\win\favorites\channels
|
|
// pszKey = "MenuOrder\Favorites"
|
|
// result -> stream comes from HKCU\...\MenuOrder\Favorites\channels
|
|
//
|
|
|
|
IStream * OpenPidlOrderStream(LPCITEMIDLIST pidlRoot, LPCITEMIDLIST pidl, LPCSTR pszKey, DWORD grfMode)
|
|
{
|
|
LPITEMIDLIST pidlAlloc = NULL;
|
|
TCHAR szRegPath[MAX_URL_STRING];
|
|
TCHAR szKey[MAXIMUM_SUB_KEY_LENGTH];
|
|
|
|
SHAnsiToTChar(pszKey, szKey, ARRAYSIZE(szKey));
|
|
StrCpyN(szRegPath, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"), ARRAYSIZE(szRegPath));
|
|
StrCatBuff(szRegPath, szKey, ARRAYSIZE(szRegPath));
|
|
|
|
// deal with ordinal vs true pidls
|
|
if (HIWORD(pidlRoot) == 0)
|
|
{
|
|
// Sundown: coercion to int since we are assuming ordinal pidl
|
|
SHGetSpecialFolderLocation(NULL, PtrToLong(pidlRoot), &pidlAlloc);
|
|
pidlRoot = pidlAlloc;
|
|
}
|
|
|
|
// build a reg key from the names of the items below the pidlRoot folder. we do
|
|
// this because IEGetDisplayName(SFGAO_FORPARSING) has a bug for file system
|
|
// junctions (channel contents) that returns garbage path names.
|
|
|
|
if (pidlRoot)
|
|
{
|
|
LPITEMIDLIST pidlCopy = ILClone(pidl);
|
|
if (pidlCopy)
|
|
{
|
|
LPCITEMIDLIST pidlTail = ILFindChild(pidlRoot, pidlCopy);
|
|
if (pidlTail)
|
|
{
|
|
LPITEMIDLIST pidlNext;
|
|
for (pidlNext = ILGetNext(pidlTail); pidlNext; pidlNext = ILGetNext(pidlNext))
|
|
{
|
|
WORD cbSave = pidlNext->mkid.cb;
|
|
pidlNext->mkid.cb = 0;
|
|
|
|
IShellFolder *psf;
|
|
LPCITEMIDLIST pidlChild;
|
|
|
|
// we do a full bind every time, we could skip this for sub items
|
|
// and bind from this point down but this code is simpler and binds
|
|
// aren't that bad...
|
|
|
|
if (SUCCEEDED(IEBindToParentFolder(pidlCopy, &psf, &pidlChild)))
|
|
{
|
|
LPWSTR pszName;
|
|
if (SUCCEEDED(DisplayNameOfAsOLESTR(psf, pidlChild, SHGDN_NORMAL, &pszName)))
|
|
{
|
|
StrCatBuff(szRegPath, TEXT("\\"), ARRAYSIZE(szRegPath));
|
|
StrCatBuff(szRegPath, pszName, ARRAYSIZE(szRegPath));
|
|
CoTaskMemFree(pszName);
|
|
}
|
|
psf->Release();
|
|
}
|
|
pidlNext->mkid.cb = cbSave;
|
|
}
|
|
}
|
|
ILFree(pidlCopy);
|
|
}
|
|
if (pidlAlloc)
|
|
ILFree(pidlAlloc);
|
|
return SHOpenRegStream(HKEY_CURRENT_USER, szRegPath, TEXT("Order"), grfMode);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
HRESULT GetHTMLElementID(IHTMLElement *pielem, LPTSTR pszName, DWORD cchSize)
|
|
{
|
|
// only do this persistence thing if we're in ( or completing ) an operation
|
|
BSTR bstrID = NULL;
|
|
HRESULT hr;
|
|
|
|
if (!pielem)
|
|
hr = E_INVALIDARG;
|
|
else if (SUCCEEDED(hr = pielem->get_id(&bstrID)))
|
|
{
|
|
SHUnicodeToTChar(bstrID, pszName, cchSize);
|
|
SysFreeString(bstrID);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/**********************************************************************
|
|
* SHRestricted2
|
|
*
|
|
* These are new restrictions that apply to browser only and integrated
|
|
* mode. (Since we're not changing shell32 in browser only mode, we
|
|
* need to duplicate the functionality.)
|
|
*
|
|
* FEATURE: What window will listen to the WM_WININICHANGE
|
|
* lParam="Policy" message and invalidate the cache?
|
|
* Remember not to cache the per zone values.
|
|
\**********************************************************************/
|
|
|
|
// The ZAW compliant policy location.
|
|
const TCHAR c_szInfodeliveryBase[] = TEXT("Software\\Policies\\Microsoft\\Internet Explorer\\Infodelivery");
|
|
const TCHAR c_szInfodeliveryKey[] = TEXT("Restrictions");
|
|
|
|
// The normal policy location.
|
|
const TCHAR c_szExplorerBase[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies");
|
|
const TCHAR c_szExplorerKey[] = TEXT("Explorer");
|
|
|
|
// The browser policy location that SP2 used
|
|
const TCHAR c_szBrowserBase[] = TEXT("Software\\Policies\\Microsoft\\Internet Explorer");
|
|
const TCHAR c_szBrowserKey[] = TEXT("Restrictions");
|
|
const TCHAR c_szToolbarKey[] = TEXT("Toolbars\\Restrictions");
|
|
|
|
const SHRESTRICTIONITEMS c_rgRestrictionItems[] =
|
|
{
|
|
// explorer restrictions
|
|
{ REST_NOTOOLBARCUSTOMIZE, c_szExplorerKey, TEXT("NoToolbarCustomize") },
|
|
{ REST_NOBANDCUSTOMIZE, c_szExplorerKey, TEXT("NoBandCustomize") },
|
|
{ REST_SMALLICONS, c_szExplorerKey, TEXT("SmallIcons") },
|
|
{ REST_LOCKICONSIZE, c_szExplorerKey, TEXT("LockIconSize") },
|
|
{ REST_SPECIFYDEFAULTBUTTONS, c_szExplorerKey, TEXT("SpecifyDefaultButtons") },
|
|
{ REST_BTN_BACK, c_szExplorerKey, TEXT("Btn_Back") },
|
|
{ REST_BTN_FORWARD, c_szExplorerKey, TEXT("Btn_Forward") },
|
|
{ REST_BTN_STOPDOWNLOAD, c_szExplorerKey, TEXT("Btn_Stop") },
|
|
{ REST_BTN_REFRESH, c_szExplorerKey, TEXT("Btn_Refresh") },
|
|
{ REST_BTN_HOME, c_szExplorerKey, TEXT("Btn_Home") },
|
|
{ REST_BTN_SEARCH, c_szExplorerKey, TEXT("Btn_Search") },
|
|
{ REST_BTN_HISTORY, c_szExplorerKey, TEXT("Btn_History") },
|
|
{ REST_BTN_FAVORITES, c_szExplorerKey, TEXT("Btn_Favorites") },
|
|
{ REST_BTN_ALLFOLDERS, c_szExplorerKey, TEXT("Btn_Folders") },
|
|
{ REST_BTN_THEATER, c_szExplorerKey, TEXT("Btn_Fullscreen") },
|
|
{ REST_BTN_TOOLS, c_szExplorerKey, TEXT("Btn_Tools") },
|
|
{ REST_BTN_MAIL, c_szExplorerKey, TEXT("Btn_MailNews") },
|
|
{ REST_BTN_FONTS, c_szExplorerKey, TEXT("Btn_Size") },
|
|
{ REST_BTN_PRINT, c_szExplorerKey, TEXT("Btn_Print") },
|
|
{ REST_BTN_EDIT, c_szExplorerKey, TEXT("Btn_Edit") },
|
|
{ REST_BTN_DISCUSSIONS, c_szExplorerKey, TEXT("Btn_Discussions") },
|
|
{ REST_BTN_CUT, c_szExplorerKey, TEXT("Btn_Cut") },
|
|
{ REST_BTN_COPY, c_szExplorerKey, TEXT("Btn_Copy") },
|
|
{ REST_BTN_PASTE, c_szExplorerKey, TEXT("Btn_Paste") },
|
|
{ REST_BTN_ENCODING, c_szExplorerKey, TEXT("Btn_Encoding") },
|
|
{ REST_BTN_PRINTPREVIEW, c_szExplorerKey, TEXT("Btn_PrintPreview") },
|
|
{ REST_NoUserAssist, c_szExplorerKey, TEXT("NoInstrumentation"), },
|
|
{ REST_NoWindowsUpdate, c_szExplorerKey, TEXT("NoWindowsUpdate"), },
|
|
{ REST_NoExpandedNewMenu, c_szExplorerKey, TEXT("NoExpandedNewMenu"), },
|
|
{ REST_BTN_MEDIABAR, c_szExplorerKey, TEXT("Btn_Media"), },
|
|
// ported from SP1
|
|
{ REST_NOFILEURL, c_szExplorerKey, TEXT("NoFileUrl"), },
|
|
// infodelivery restrictions
|
|
{ REST_NoChannelUI, c_szInfodeliveryKey, TEXT("NoChannelUI") },
|
|
{ REST_NoAddingChannels, c_szInfodeliveryKey, TEXT("NoAddingChannels") },
|
|
{ REST_NoEditingChannels, c_szInfodeliveryKey, TEXT("NoEditingChannels") },
|
|
{ REST_NoRemovingChannels, c_szInfodeliveryKey, TEXT("NoRemovingChannels") },
|
|
{ REST_NoAddingSubscriptions, c_szInfodeliveryKey, TEXT("NoAddingSubscriptions") },
|
|
{ REST_NoEditingSubscriptions, c_szInfodeliveryKey, TEXT("NoEditingSubscriptions") },
|
|
{ REST_NoRemovingSubscriptions, c_szInfodeliveryKey, TEXT("NoRemovingSubscriptions") },
|
|
{ REST_NoChannelLogging, c_szInfodeliveryKey, TEXT("NoChannelLogging") },
|
|
{ REST_NoManualUpdates, c_szInfodeliveryKey, TEXT("NoManualUpdates") },
|
|
{ REST_NoScheduledUpdates, c_szInfodeliveryKey, TEXT("NoScheduledUpdates") },
|
|
{ REST_NoUnattendedDialing, c_szInfodeliveryKey, TEXT("NoUnattendedDialing") },
|
|
{ REST_NoChannelContent, c_szInfodeliveryKey, TEXT("NoChannelContent") },
|
|
{ REST_NoSubscriptionContent, c_szInfodeliveryKey, TEXT("NoSubscriptionContent") },
|
|
{ REST_NoEditingScheduleGroups, c_szInfodeliveryKey, TEXT("NoEditingScheduleGroups") },
|
|
{ REST_MaxChannelSize, c_szInfodeliveryKey, TEXT("MaxChannelSize") },
|
|
{ REST_MaxSubscriptionSize, c_szInfodeliveryKey, TEXT("MaxSubscriptionSize") },
|
|
{ REST_MaxChannelCount, c_szInfodeliveryKey, TEXT("MaxChannelCount") },
|
|
{ REST_MaxSubscriptionCount, c_szInfodeliveryKey, TEXT("MaxSubscriptionCount") },
|
|
{ REST_MinUpdateInterval, c_szInfodeliveryKey, TEXT("MinUpdateInterval") },
|
|
{ REST_UpdateExcludeBegin, c_szInfodeliveryKey, TEXT("UpdateExcludeBegin") },
|
|
{ REST_UpdateExcludeEnd, c_szInfodeliveryKey, TEXT("UpdateExcludeEnd") },
|
|
{ REST_UpdateInNewProcess, c_szInfodeliveryKey, TEXT("UpdateInNewProcess") },
|
|
{ REST_MaxWebcrawlLevels, c_szInfodeliveryKey, TEXT("MaxWebcrawlLevels") },
|
|
{ REST_MaxChannelLevels, c_szInfodeliveryKey, TEXT("MaxChannelLevels") },
|
|
{ REST_NoSubscriptionPasswords, c_szInfodeliveryKey, TEXT("NoSubscriptionPasswords")},
|
|
{ REST_NoBrowserSaveWebComplete,c_szInfodeliveryKey, TEXT("NoBrowserSaveWebComplete") },
|
|
{ REST_NoSearchCustomization, c_szInfodeliveryKey, TEXT("NoSearchCustomization"), },
|
|
{ REST_NoSplash, c_szInfodeliveryKey, TEXT("NoSplash"), },
|
|
|
|
// browser restrictions ported from SP2
|
|
{ REST_NoFileOpen, c_szBrowserKey, TEXT("NoFileOpen"), },
|
|
{ REST_NoFileNew, c_szBrowserKey, TEXT("NoFileNew"), },
|
|
{ REST_NoBrowserSaveAs , c_szBrowserKey, TEXT("NoBrowserSaveAs"), },
|
|
{ REST_NoBrowserOptions, c_szBrowserKey, TEXT("NoBrowserOptions"), },
|
|
{ REST_NoFavorites, c_szBrowserKey, TEXT("NoFavorites"), },
|
|
{ REST_NoSelectDownloadDir, c_szBrowserKey, TEXT("NoSelectDownloadDir"), },
|
|
{ REST_NoBrowserContextMenu, c_szBrowserKey, TEXT("NoBrowserContextMenu"), },
|
|
{ REST_NoBrowserClose, c_szBrowserKey, TEXT("NoBrowserClose"), },
|
|
{ REST_NoOpeninNewWnd, c_szBrowserKey, TEXT("NoOpeninNewWnd"), },
|
|
{ REST_NoTheaterMode, c_szBrowserKey, TEXT("NoTheaterMode"), },
|
|
{ REST_NoFindFiles, c_szBrowserKey, TEXT("NoFindFiles"), },
|
|
{ REST_NoViewSource, c_szBrowserKey, TEXT("NoViewSource"), },
|
|
{ REST_GoMenu, c_szBrowserKey, TEXT("RestGoMenu"), },
|
|
{ REST_NoToolbarOptions, c_szToolbarKey, TEXT("NoToolbarOptions"), },
|
|
{ REST_AlwaysPromptWhenDownload,c_szBrowserKey, TEXT("AlwaysPromptWhenDownload"),},
|
|
|
|
{ REST_NoHelpItem_TipOfTheDay, c_szBrowserKey, TEXT("NoHelpItemTipOfTheDay"), },
|
|
{ REST_NoHelpItem_NetscapeHelp, c_szBrowserKey, TEXT("NoHelpItemNetscapeHelp"), },
|
|
{ REST_NoHelpItem_Tutorial, c_szBrowserKey, TEXT("NoHelpItemTutorial"), },
|
|
{ REST_NoHelpItem_SendFeedback, c_szBrowserKey, TEXT("NoHelpItemSendFeedback"), },
|
|
|
|
{ REST_NoNavButtons, c_szBrowserKey, TEXT("NoNavButtons"), },
|
|
{ REST_NoHelpMenu, c_szBrowserKey, TEXT("NoHelpMenu"), },
|
|
{ REST_NoBrowserBars, c_szBrowserKey, TEXT("NoBrowserBars"), },
|
|
{ REST_NoToolBar, c_szToolbarKey, TEXT("NoToolBar"), },
|
|
{ REST_NoAddressBar, c_szToolbarKey, TEXT("NoAddressBar"), },
|
|
{ REST_NoLinksBar, c_szToolbarKey, TEXT("NoLinksBar"), },
|
|
|
|
{ REST_NoPrinting, c_szBrowserKey, TEXT("NoPrinting") },
|
|
|
|
{ REST_No_LaunchMediaBar, c_szBrowserKey, TEXT("No_LaunchMediaBar") },
|
|
{ REST_No_MediaBarOnlineContent, c_szBrowserKey, TEXT("No_MediaBarOnlineContent") },
|
|
|
|
{0, NULL, NULL},
|
|
};
|
|
|
|
typedef struct {
|
|
BROWSER_RESTRICTIONS rest;
|
|
DWORD dwAction;
|
|
} ACTIONITEM;
|
|
|
|
const ACTIONITEM c_ActionItems[] = {
|
|
{ REST_NoAddingChannels, URLACTION_INFODELIVERY_NO_ADDING_CHANNELS },
|
|
{ REST_NoEditingChannels, URLACTION_INFODELIVERY_NO_EDITING_CHANNELS },
|
|
{ REST_NoRemovingChannels, URLACTION_INFODELIVERY_NO_REMOVING_CHANNELS },
|
|
{ REST_NoAddingSubscriptions, URLACTION_INFODELIVERY_NO_ADDING_SUBSCRIPTIONS },
|
|
{ REST_NoEditingSubscriptions, URLACTION_INFODELIVERY_NO_EDITING_SUBSCRIPTIONS },
|
|
{ REST_NoRemovingSubscriptions, URLACTION_INFODELIVERY_NO_REMOVING_SUBSCRIPTIONS },
|
|
{ REST_NoChannelLogging, URLACTION_INFODELIVERY_NO_CHANNEL_LOGGING },
|
|
};
|
|
|
|
#define REST_WITHACTION_FIRST REST_NoAddingChannels
|
|
#define REST_WITHACTION_LAST REST_NoChannelLogging
|
|
|
|
#define RESTRICTIONMAX (c_rgRestrictionItems[ARRAYSIZE(c_rgRestrictionItems) - 1].rest)
|
|
|
|
DWORD g_rgRestrictionItemValues[ARRAYSIZE(c_rgRestrictionItems)];
|
|
|
|
DWORD SHRestricted2W(BROWSER_RESTRICTIONS rest, LPCWSTR pwzUrl, DWORD dwReserved)
|
|
{
|
|
// Validate restriction and dwReserved
|
|
if (dwReserved)
|
|
{
|
|
RIPMSG(0, "SHRestricted2W: Invalid dwReserved");
|
|
return 0;
|
|
}
|
|
|
|
if (!(InRange(rest, REST_EXPLORER_FIRST, REST_EXPLORER_LAST))
|
|
&& !(InRange(rest, REST_INFO_FIRST, REST_INFO_LAST))
|
|
&& !(InRange(rest, REST_BROWSER_FIRST, REST_BROWSER_LAST)))
|
|
{
|
|
RIPMSG(0, "SHRestricted2W: Invalid browser restriction");
|
|
return 0;
|
|
}
|
|
|
|
// See if the restriction is in place in the URL zone
|
|
// FEATURE: Should we assert on NULL URLs if the restriction is per zone?
|
|
// It might be reasonable to query the global setting.
|
|
if (pwzUrl && InRange(rest, REST_WITHACTION_FIRST, REST_WITHACTION_LAST))
|
|
{
|
|
// Compute the index into the table
|
|
int index = rest - REST_WITHACTION_FIRST;
|
|
|
|
ASSERT(c_ActionItems[index].dwAction);
|
|
|
|
IInternetSecurityManager *pism = NULL;
|
|
HRESULT hr;
|
|
hr = CoCreateInstance(CLSID_InternetSecurityManager, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IInternetSecurityManager, (void**)&pism);
|
|
if (SUCCEEDED(hr) && pism)
|
|
{
|
|
DWORD dwPolicy = 0;
|
|
DWORD dwContext = 0;
|
|
hr = pism->ProcessUrlAction(pwzUrl,
|
|
c_ActionItems[index].dwAction,
|
|
(BYTE *)&dwPolicy,
|
|
sizeof(dwPolicy),
|
|
(BYTE *)&dwContext,
|
|
sizeof(dwContext),
|
|
PUAF_NOUI,
|
|
0);
|
|
pism->Release();
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (GetUrlPolicyPermissions(dwPolicy) == URLPOLICY_ALLOW)
|
|
return 0;
|
|
else
|
|
return 1; // restrict for query and disallow
|
|
}
|
|
}
|
|
}
|
|
|
|
// The cache may be invalid. Check first! We have to use
|
|
// a global named semaphore in case this function is called
|
|
// from a process other than the shell process. (And we're
|
|
// sharing the same count between shell32 and shdocvw.)
|
|
static HANDLE hRestrictions = NULL;
|
|
static long lRestrictionCount = -1;
|
|
if (hRestrictions == NULL)
|
|
hRestrictions = SHGlobalCounterCreate(GUID_Restrictions);
|
|
long lGlobalCount = SHGlobalCounterGetValue(hRestrictions);
|
|
if (lGlobalCount != lRestrictionCount)
|
|
{
|
|
memset((LPBYTE)g_rgRestrictionItemValues, (BYTE)-1, SIZEOF(g_rgRestrictionItemValues));
|
|
|
|
lRestrictionCount = lGlobalCount;
|
|
}
|
|
|
|
LPCWSTR pszBaseKey;
|
|
if (InRange(rest, REST_EXPLORER_FIRST, REST_EXPLORER_LAST))
|
|
pszBaseKey = c_szExplorerBase;
|
|
else
|
|
{
|
|
if (InRange(rest, REST_BROWSER_FIRST, REST_BROWSER_LAST))
|
|
pszBaseKey = c_szBrowserBase;
|
|
else
|
|
pszBaseKey = c_szInfodeliveryBase;
|
|
}
|
|
|
|
return SHRestrictionLookup(rest, pszBaseKey, c_rgRestrictionItems, g_rgRestrictionItemValues);
|
|
}
|
|
|
|
DWORD SHRestricted2A(BROWSER_RESTRICTIONS rest, LPCSTR pszUrl, DWORD dwReserved)
|
|
{
|
|
if (pszUrl)
|
|
{
|
|
WCHAR wzUrl[MAX_URL_STRING];
|
|
|
|
ASSERT(ARRAYSIZE(wzUrl) > lstrlenA(pszUrl)); // We only work for Urls of MAX_URL_STRING or shorter.
|
|
AnsiToUnicode(pszUrl, wzUrl, ARRAYSIZE(wzUrl));
|
|
|
|
return SHRestricted2W(rest, wzUrl, dwReserved);
|
|
}
|
|
else
|
|
{
|
|
return SHRestricted2W(rest, NULL, dwReserved);
|
|
}
|
|
}
|
|
|
|
/**********************************************************************
|
|
*
|
|
\**********************************************************************/
|
|
|
|
#define MAX_SUBSTR_SIZE 100
|
|
typedef struct tagURLSub
|
|
{
|
|
LPCTSTR szTag;
|
|
DWORD dwType;
|
|
} URLSUB;
|
|
|
|
const static URLSUB c_UrlSub[] = {
|
|
{TEXT("{SUB_PRD}"), URLSUB_PRD},
|
|
{TEXT("{SUB_PVER}"), URLSUB_PVER},
|
|
{TEXT("{SUB_OS}"), URLSUB_OS},
|
|
{TEXT("{SUB_OVER}"), URLSUB_OVER},
|
|
{TEXT("{SUB_OLCID}"), URLSUB_OLCID},
|
|
{TEXT("{SUB_CLCID}"), URLSUB_CLCID},
|
|
{TEXT("{SUB_CLSID}"), URLSUB_CLCID}, // legacy support (do NOT use "SUB_CLSID" in new URLs)
|
|
{TEXT("{SUB_RFC1766}"), URLSUB_RFC1766}
|
|
};
|
|
|
|
void GetWebLocaleAsRFC1766(LPTSTR pszLocale, int cchLocale)
|
|
{
|
|
LCID lcid;
|
|
TCHAR szValue[MAX_PATH];
|
|
|
|
DWORD cbVal = sizeof(szValue);
|
|
DWORD dwType;
|
|
|
|
ASSERT(NULL != pszLocale);
|
|
|
|
*pszLocale = TEXT('\0');
|
|
|
|
if ((SHGetValue(HKEY_CURRENT_USER, REGSTR_PATH_INTERNATIONAL,
|
|
REGSTR_VAL_ACCEPT_LANGUAGE,
|
|
&dwType, szValue, &cbVal) == ERROR_SUCCESS) &&
|
|
(REG_SZ == dwType))
|
|
{
|
|
TCHAR *psz = szValue;
|
|
|
|
// Use the first one we find so terminate at the comma or semicolon
|
|
while (*psz && (*psz != TEXT(',')) && (*psz != TEXT(';')))
|
|
{
|
|
psz = CharNext(psz);
|
|
}
|
|
*psz = TEXT('\0');
|
|
|
|
// If it's user defined, this will fail and we will fall back
|
|
// to the system default.
|
|
if (SUCCEEDED(Rfc1766ToLcid(&lcid, szValue)))
|
|
{
|
|
StrCpyN(pszLocale, szValue, cchLocale);
|
|
}
|
|
}
|
|
|
|
if (TEXT('\0') == *pszLocale)
|
|
{
|
|
// No entry in the registry or it's a user defined header.
|
|
// Either way we fall back to the system default.
|
|
|
|
LcidToRfc1766(GetUserDefaultLCID(), pszLocale, cchLocale);
|
|
}
|
|
}
|
|
|
|
HRESULT URLSubstitution(LPCWSTR pszUrlIn, LPWSTR pszUrlOut, DWORD cchSize, DWORD dwSubstitutions)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwIndex;
|
|
WCHAR szTempUrl[MAX_URL_STRING];
|
|
ASSERT(cchSize <= ARRAYSIZE(szTempUrl)); // We will truncate anything longer than MAX_URL_STRING
|
|
|
|
StrCpyNW(szTempUrl, pszUrlIn, ARRAYSIZE(szTempUrl));
|
|
|
|
for (dwIndex = 0; dwIndex < ARRAYSIZE(c_UrlSub); dwIndex++)
|
|
{
|
|
while (IsFlagSet(dwSubstitutions, c_UrlSub[dwIndex].dwType))
|
|
{
|
|
LPWSTR pszTag = StrStr(szTempUrl, c_UrlSub[dwIndex].szTag);
|
|
|
|
if (pszTag)
|
|
{
|
|
TCHAR szCopyUrl[MAX_URL_STRING];
|
|
TCHAR szSubStr[MAX_SUBSTR_SIZE]; // The Substitution
|
|
|
|
// Copy URL Before Substitution.
|
|
StrCpyN(szCopyUrl, szTempUrl, (int)(pszTag-szTempUrl+1));
|
|
pszTag += lstrlen(c_UrlSub[dwIndex].szTag);
|
|
|
|
switch (c_UrlSub[dwIndex].dwType)
|
|
{
|
|
case URLSUB_PRD:
|
|
MLLoadString(IDS_SUBSTR_PRD, szSubStr, ARRAYSIZE(szSubStr));
|
|
break;
|
|
|
|
case URLSUB_PVER:
|
|
MLLoadString(IDS_SUBSTR_PVER, szSubStr, ARRAYSIZE(szSubStr));
|
|
break;
|
|
|
|
case URLSUB_OS:
|
|
{
|
|
LPCTSTR pszWin95 = _T("95"); // Windows 95
|
|
LPCTSTR pszWin98 = _T("98"); // Windows 98 (Memphis)
|
|
LPCTSTR pszWinME = _T("ME"); // Windows Millenium
|
|
LPCTSTR pszWinNT4 = _T("N4"); // Windows NT 4
|
|
LPCTSTR pszWinNT5 = _T("N5"); // Windows 2000
|
|
LPCTSTR pszWinNT6 = _T("N6"); // Windows XP (Whistler)
|
|
LPCTSTR pszUnknown = _T(""); // error
|
|
LPCTSTR psz = pszUnknown;
|
|
|
|
if (IsOS(OS_WINDOWS))
|
|
{
|
|
if (IsOS(OS_MILLENNIUMORGREATER))
|
|
psz = pszWinME;
|
|
else if (IsOS(OS_WIN98ORGREATER))
|
|
psz = pszWin98;
|
|
else if (IsOS(OS_WIN95ORGREATER))
|
|
psz = pszWin95;
|
|
else
|
|
{
|
|
ASSERT(FALSE); // What OS is this?
|
|
}
|
|
}
|
|
else if (IsOS(OS_NT))
|
|
{
|
|
if (IsOS(OS_WHISTLERORGREATER))
|
|
psz = pszWinNT6;
|
|
else if (IsOS(OS_WIN2000ORGREATER))
|
|
psz = pszWinNT5;
|
|
else if (IsOS(OS_NT4ORGREATER))
|
|
psz = pszWinNT4;
|
|
else
|
|
{
|
|
ASSERT(FALSE); // What OS is this?
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASSERT(FALSE); // What OS is this?
|
|
}
|
|
|
|
StrCpyN(szSubStr, psz, ARRAYSIZE(szSubStr));
|
|
}
|
|
break;
|
|
|
|
case URLSUB_OVER:
|
|
{
|
|
LPCTSTR pszVersion_5_1 = _T("5.1"); // Version 5.1 (Whistler)
|
|
LPCTSTR pszUnknown = _T(""); // error
|
|
LPCTSTR psz = pszUnknown;
|
|
|
|
if (IsOS(OS_WINDOWS))
|
|
{
|
|
ASSERT(FALSE); // Not supported under Windows Millenium or lesser.
|
|
}
|
|
else if (IsOS(OS_NT))
|
|
{
|
|
if (IsOS(OS_WHISTLERORGREATER))
|
|
psz = pszVersion_5_1;
|
|
else
|
|
{
|
|
ASSERT(FALSE); // Not supported under Windows 2000 or lesser.
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASSERT(FALSE); // What OS is this?
|
|
}
|
|
|
|
StrCpyN(szSubStr, psz, ARRAYSIZE(szSubStr));
|
|
}
|
|
break;
|
|
|
|
case URLSUB_OLCID:
|
|
wnsprintf(szSubStr, ARRAYSIZE(szSubStr), _T("%#04lx"), GetSystemDefaultLCID());
|
|
break;
|
|
|
|
case URLSUB_CLCID:
|
|
wnsprintf(szSubStr, ARRAYSIZE(szSubStr), _T("%#04lx"), GetUserDefaultLCID());
|
|
break;
|
|
|
|
case URLSUB_RFC1766:
|
|
GetWebLocaleAsRFC1766(szSubStr, ARRAYSIZE(szSubStr));
|
|
break;
|
|
|
|
default:
|
|
szSubStr[0] = TEXT('\0');
|
|
ASSERT(FALSE); // Not Impl.
|
|
hr = E_NOTIMPL;
|
|
break;
|
|
}
|
|
// Add the Substitution String to the end (will become the middle)
|
|
StrCatBuff(szCopyUrl, szSubStr, ARRAYSIZE(szCopyUrl));
|
|
// Add the rest of the URL after the substitution substring.
|
|
StrCatBuff(szCopyUrl, pszTag, ARRAYSIZE(szCopyUrl));
|
|
StrCpyN(szTempUrl, szCopyUrl, ARRAYSIZE(szTempUrl));
|
|
}
|
|
else
|
|
break; // This will allow us to replace all the occurances of this string.
|
|
}
|
|
}
|
|
StrCpyN(pszUrlOut, szTempUrl, cchSize);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
// inetcpl.cpl uses this.
|
|
STDAPI URLSubRegQueryA(LPCSTR pszKey, LPCSTR pszValue, BOOL fUseHKCU,
|
|
LPSTR pszUrlOut, DWORD cchSizeOut, DWORD dwSubstitutions)
|
|
{
|
|
HRESULT hr;
|
|
TCHAR szKey[MAX_PATH];
|
|
TCHAR szValue[MAX_PATH];
|
|
TCHAR szUrlOut[MAX_URL_STRING];
|
|
|
|
AnsiToTChar(pszKey, szKey, ARRAYSIZE(szKey));
|
|
AnsiToTChar(pszValue, szValue, ARRAYSIZE(szValue));
|
|
hr = URLSubRegQueryW(szKey, szValue, fUseHKCU, szUrlOut, ARRAYSIZE(szUrlOut), dwSubstitutions);
|
|
TCharToAnsi(szUrlOut, pszUrlOut, cchSizeOut);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT URLSubRegQueryW(LPCWSTR pszKey, LPCWSTR pszValue, BOOL fUseHKCU,
|
|
LPWSTR pszUrlOut, DWORD cchSizeOut, DWORD dwSubstitutions)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
WCHAR szTempUrl[MAX_URL_STRING];
|
|
DWORD ccbSize = sizeof(szTempUrl);
|
|
if (ERROR_SUCCESS == SHRegGetUSValueW(pszKey, pszValue, NULL, szTempUrl,
|
|
&ccbSize, !fUseHKCU, NULL, NULL))
|
|
{
|
|
hr = URLSubstitution(szTempUrl, pszUrlOut, cchSizeOut, dwSubstitutions);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
// note that anyone inside shdocvw should pass hInst==NULL to
|
|
// ensure that pluggable UI works correctly. anyone outside of shdocvw
|
|
// must pass an hInst for their appropriate resource dll
|
|
HRESULT URLSubLoadString(HINSTANCE hInst, UINT idRes, LPWSTR pszUrlOut,
|
|
DWORD cchSizeOut, DWORD dwSubstitutions)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
WCHAR szTempUrl[MAX_URL_STRING];
|
|
int nStrLen;
|
|
|
|
nStrLen = 0;
|
|
|
|
if (hInst == NULL)
|
|
{
|
|
// this is for internal users who want pluggable UI to work
|
|
nStrLen = MLLoadStringW(idRes, szTempUrl, ARRAYSIZE(szTempUrl));
|
|
}
|
|
else
|
|
{
|
|
// this is for external users who use us to load some
|
|
// of their own resources but whom we can't change (like shell32)
|
|
nStrLen = LoadStringWrap(hInst, idRes, szTempUrl, ARRAYSIZE(szTempUrl));
|
|
}
|
|
|
|
if (nStrLen > 0)
|
|
{
|
|
hr = URLSubstitution(szTempUrl, pszUrlOut, cchSizeOut, dwSubstitutions);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/**********************************************************************\
|
|
ILIsUrlChild() will find pidls that exist under "Desktop\The Internet"
|
|
section of the Shell Name Space. This function includes those items
|
|
and file system items that have a "txt/html.
|
|
\**********************************************************************/
|
|
BOOL ILIsWeb(LPCITEMIDLIST pidl)
|
|
{
|
|
BOOL fIsWeb = FALSE;
|
|
|
|
if (pidl)
|
|
{
|
|
if (IsURLChild(pidl, TRUE))
|
|
fIsWeb = TRUE;
|
|
else
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
|
|
fIsWeb = (!ILIsRooted(pidl)
|
|
&& SUCCEEDED(SHGetPathFromIDList(pidl, szPath))
|
|
&& (PathIsHTMLFile(szPath) ||
|
|
PathIsContentType(szPath, TEXT("text/xml"))));
|
|
}
|
|
}
|
|
|
|
return fIsWeb;
|
|
}
|
|
|
|
//
|
|
// in:
|
|
// pidlTo
|
|
|
|
STDAPI CreateLinkToPidl(LPCITEMIDLIST pidlTo, LPCTSTR pszDir, LPCTSTR pszTitle, LPTSTR pszOut, int cchOut)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
TCHAR szPathDest[MAX_URL_STRING];
|
|
BOOL fCopyLnk;
|
|
|
|
if (SHGetNewLinkInfo((LPCTSTR)pidlTo, pszDir, szPathDest, &fCopyLnk, SHGNLI_PIDL))
|
|
{
|
|
IShellLinkA *pslA; // Use A version for W95.
|
|
if (SUCCEEDED(CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellLinkA, &pslA))))
|
|
{
|
|
TCHAR szPathSrc[MAX_URL_STRING];
|
|
DWORD dwAttributes = SFGAO_FILESYSTEM | SFGAO_FOLDER;
|
|
SHGetNameAndFlags(pidlTo, SHGDN_FORPARSING | SHGDN_FORADDRESSBAR, szPathSrc, ARRAYSIZE(szPathSrc), &dwAttributes);
|
|
|
|
if (fCopyLnk)
|
|
{
|
|
if (((dwAttributes & (SFGAO_FILESYSTEM | SFGAO_FOLDER)) == SFGAO_FILESYSTEM) && CopyFile(szPathSrc, szPathDest, TRUE))
|
|
{
|
|
SHChangeNotify(SHCNE_CREATE, SHCNF_PATH, szPathDest, NULL);
|
|
SHChangeNotify(SHCNE_FREESPACE, SHCNF_PATH, szPathDest, NULL);
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
// load the source object that will be "copied" below (with the ::Save call)
|
|
SAFERELEASE(pslA);
|
|
hr = SHGetUIObjectFromFullPIDL(pidlTo, NULL, IID_PPV_ARG(IShellLinkA, &pslA));
|
|
// this pslA is released at the end of the topmost if
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IPersistFile *ppf;
|
|
hr = pslA->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = ppf->Save(szPathDest, TRUE);
|
|
ppf->Release();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pslA->SetIDList(pidlTo);
|
|
|
|
// make sure the working directory is set to the same
|
|
// directory as the app (or document).
|
|
//
|
|
// dont do this for non-FS pidls (ie control panel)
|
|
|
|
if (SFGAO_FILESYSTEM == (dwAttributes & SFGAO_FILESYSTEM | SFGAO_FOLDER))
|
|
{
|
|
ASSERT(!PathIsRelative(szPathSrc));
|
|
PathRemoveFileSpec(szPathSrc);
|
|
// Try to get the W version.
|
|
IShellLinkW* pslW;
|
|
if (SUCCEEDED(pslA->QueryInterface(IID_PPV_ARG(IShellLinkW, &pslW))))
|
|
{
|
|
pslW->SetWorkingDirectory(szPathSrc);
|
|
pslW->Release();
|
|
}
|
|
else
|
|
{
|
|
CHAR szPathSrcA[MAX_URL_STRING];
|
|
SHUnicodeToAnsi(szPathSrc, szPathSrcA, ARRAYSIZE(szPathSrcA));
|
|
pslA->SetWorkingDirectory(szPathSrcA);
|
|
}
|
|
}
|
|
|
|
IPersistFile *ppf;
|
|
hr = pslA->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (pszTitle && pszTitle[0])
|
|
{
|
|
PathRemoveFileSpec(szPathDest);
|
|
PathAppend(szPathDest, pszTitle);
|
|
StrCatBuff(szPathDest, TEXT(".lnk"), ARRAYSIZE(szPathDest));
|
|
}
|
|
hr = ppf->Save(szPathDest, TRUE);
|
|
if (pszOut)
|
|
{
|
|
StrCpyN(pszOut, szPathDest, cchOut);
|
|
}
|
|
ppf->Release();
|
|
}
|
|
}
|
|
|
|
SAFERELEASE(pslA);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
int GetColorComponent(LPTSTR *ppsz)
|
|
{
|
|
int iColor = 0;
|
|
if (*ppsz) {
|
|
LPTSTR pBuf = *ppsz;
|
|
iColor = StrToInt(pBuf);
|
|
|
|
// find the next comma
|
|
while(pBuf && *pBuf && *pBuf!=TEXT(','))
|
|
pBuf++;
|
|
|
|
// if valid and not NULL...
|
|
if (pBuf && *pBuf)
|
|
pBuf++; // increment
|
|
|
|
*ppsz = pBuf;
|
|
}
|
|
return iColor;
|
|
}
|
|
|
|
// Read the registry for a string (REG_SZ) of comma separated RGB values
|
|
COLORREF RegGetColorRefString( HKEY hkey, LPTSTR RegValue, COLORREF Value)
|
|
{
|
|
TCHAR SmallBuf[80];
|
|
TCHAR *pBuf;
|
|
int iRed, iGreen, iBlue;
|
|
|
|
DWORD cb = ARRAYSIZE(SmallBuf);
|
|
if (RegQueryValueEx(hkey, RegValue, NULL, NULL, (LPBYTE)&SmallBuf, &cb)
|
|
== ERROR_SUCCESS)
|
|
{
|
|
pBuf = SmallBuf;
|
|
|
|
iRed = GetColorComponent(&pBuf);
|
|
iGreen = GetColorComponent(&pBuf);
|
|
iBlue = GetColorComponent(&pBuf);
|
|
|
|
// make sure all values are valid
|
|
iRed %= 256;
|
|
iGreen %= 256;
|
|
iBlue %= 256;
|
|
|
|
Value = RGB(iRed, iGreen, iBlue);
|
|
}
|
|
|
|
return Value;
|
|
}
|
|
|
|
#ifdef DEBUG // {
|
|
//*** SearchDW -- scan for DWORD in buffer
|
|
// ENTRY/EXIT
|
|
// pdwBuf buffer
|
|
// cbBuf size of buffer in *bytes* (*not* DWORDs)
|
|
// dwVal DWORD we're looking for
|
|
// dOff (return) byte offset in buffer; o.w. -1 if not found
|
|
//
|
|
int SearchDW(DWORD *pdwBuf, int cbBuf, DWORD dwVal)
|
|
{
|
|
int dOff;
|
|
|
|
for (dOff = 0; dOff < cbBuf; dOff += SIZEOF(DWORD), pdwBuf++) {
|
|
if (*pdwBuf == dwVal)
|
|
return dOff;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
#endif // }
|
|
|
|
// NOTE: These are directly copied from fsnotify.c in shell32. Please make sure
|
|
// NOTE: any changes are reflected there also.
|
|
|
|
// this is the NEW SHCNE_UPDATEIMAGE stuff, it passes renough data so that the recieving process
|
|
// has a vague chance that it can find the right index to refresh.
|
|
STDAPI_(void) _SHUpdateImageA( LPCSTR pszHashItem, int iIndex, UINT uFlags, int iImageIndex )
|
|
{
|
|
WCHAR szWHash[MAX_PATH];
|
|
|
|
MultiByteToWideChar( CP_ACP, 0, pszHashItem, -1, szWHash, MAX_PATH );
|
|
|
|
_SHUpdateImageW( szWHash, iIndex, uFlags, iImageIndex );
|
|
}
|
|
|
|
STDAPI_(void) _SHUpdateImageW( LPCWSTR pszHashItem, int iIndex, UINT uFlags, int iImageIndex )
|
|
{
|
|
SHChangeUpdateImageIDList rgPidl;
|
|
SHChangeDWORDAsIDList rgDWord;
|
|
|
|
int cLen = MAX_PATH - (lstrlenW( pszHashItem ) + 1);
|
|
cLen *= sizeof( WCHAR );
|
|
|
|
if ( cLen < 0 )
|
|
cLen = 0;
|
|
|
|
// make sure we send a valid index
|
|
if ( iImageIndex == -1 )
|
|
iImageIndex = II_DOCUMENT;
|
|
|
|
rgPidl.dwProcessID = GetCurrentProcessId();
|
|
rgPidl.iIconIndex = iIndex;
|
|
rgPidl.iCurIndex = iImageIndex;
|
|
rgPidl.uFlags = uFlags;
|
|
StrCpyNW( rgPidl.szName, pszHashItem, MAX_PATH );
|
|
rgPidl.cb = (USHORT)(sizeof( rgPidl ) - cLen);
|
|
_ILNext( (LPITEMIDLIST) &rgPidl )->mkid.cb = 0;
|
|
|
|
rgDWord.cb = (unsigned short) PtrDiff(&rgDWord.cbZero, &rgDWord);
|
|
rgDWord.dwItem1 = (DWORD) iImageIndex;
|
|
rgDWord.dwItem2 = 0;
|
|
rgDWord.cbZero = 0;
|
|
|
|
// pump it as an extended event
|
|
SHChangeNotify( SHCNE_UPDATEIMAGE, SHCNF_IDLIST, &rgDWord, &rgPidl );
|
|
}
|
|
|
|
STDAPI_(int) _SHHandleUpdateImage( LPCITEMIDLIST pidlExtra )
|
|
{
|
|
SHChangeUpdateImageIDList * pUs = (SHChangeUpdateImageIDList*) pidlExtra;
|
|
|
|
if ( !pUs )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
// if in the same process, or an old style notification
|
|
if ( pUs->dwProcessID == GetCurrentProcessId())
|
|
{
|
|
return (int) pUs->iCurIndex;
|
|
}
|
|
else
|
|
{
|
|
WCHAR szBuffer[MAX_PATH];
|
|
int iIconIndex = *(int UNALIGNED *)((BYTE *)&pUs->iIconIndex);
|
|
UINT uFlags = *(UINT UNALIGNED *)((BYTE *)&pUs->uFlags);
|
|
|
|
ualstrcpynW( szBuffer, pUs->szName, ARRAYSIZE(szBuffer) );
|
|
|
|
// we are in a different process, look up the hash in our index to get the right one...
|
|
|
|
return Shell_GetCachedImageIndex( szBuffer, iIconIndex, uFlags );
|
|
}
|
|
}
|
|
|
|
VOID CleanExploits(PWSTR psz)
|
|
{
|
|
while (*psz)
|
|
{
|
|
if (*psz<L' ')
|
|
{
|
|
*psz = L' ';
|
|
}
|
|
psz++;
|
|
}
|
|
}
|
|
|
|
HRESULT FormatUrlForDisplay(LPWSTR pwzURL, LPWSTR pwzFriendly, UINT cchBuf, LPWSTR pwzFrom, UINT cbFrom, BOOL fSeperate, DWORD dwCodePage, PWSTR pwzCachedFileName)
|
|
{
|
|
const DWORD dwMaxPathLen = 32;
|
|
const DWORD dwMaxHostLen = 32;
|
|
const DWORD dwMaxTemplateLen = 64;
|
|
const DWORD dwElipsisLen = 3;
|
|
const CHAR rgchElipsis[] = "...";
|
|
const WCHAR rgwchElipsis[] = L"...";
|
|
|
|
HRESULT hrRC = E_FAIL;
|
|
HRESULT hr;
|
|
|
|
if (pwzURL==NULL || pwzFriendly==NULL)
|
|
return E_POINTER;
|
|
|
|
*pwzFriendly = '\0';
|
|
|
|
if (!*pwzURL)
|
|
return S_OK;
|
|
|
|
if (!cchBuf)
|
|
return E_FAIL;
|
|
|
|
// Wininet can't deal with code pages other than CP_ACP so convert the URL ourself and call InterCrackUrlA
|
|
URL_COMPONENTSA urlComp;
|
|
CHAR rgchScheme[INTERNET_MAX_SCHEME_LENGTH];
|
|
CHAR rgchHostName[INTERNET_MAX_HOST_NAME_LENGTH];
|
|
CHAR rgchUrlPath[MAX_PATH];
|
|
CHAR rgchCanonicalUrl[MAX_URL_STRING];
|
|
LPSTR pszURL;
|
|
DWORD dwLen;
|
|
|
|
dwLen = MAX_URL_STRING * 2;
|
|
if ((pszURL = (LPSTR)LocalAlloc(LPTR, dwLen * sizeof(CHAR))) != NULL)
|
|
{
|
|
SHUnicodeToAnsiCP(dwCodePage, pwzURL, pszURL, dwLen);
|
|
|
|
dwLen = ARRAYSIZE(rgchCanonicalUrl);
|
|
hr = UrlCanonicalizeA(pszURL, rgchCanonicalUrl, &dwLen, 0);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ZeroMemory(&urlComp, sizeof(urlComp));
|
|
|
|
urlComp.dwStructSize = sizeof(urlComp);
|
|
urlComp.lpszHostName = rgchHostName;
|
|
urlComp.dwHostNameLength = ARRAYSIZE(rgchHostName);
|
|
urlComp.lpszUrlPath = rgchUrlPath;
|
|
urlComp.dwUrlPathLength = ARRAYSIZE(rgchUrlPath);
|
|
urlComp.lpszScheme = rgchScheme;
|
|
urlComp.dwSchemeLength = ARRAYSIZE(rgchScheme);
|
|
|
|
hr = InternetCrackUrlA(rgchCanonicalUrl, lstrlenA(rgchCanonicalUrl), 0, &urlComp);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
DWORD dwPathLen = lstrlenA(rgchUrlPath);
|
|
DWORD dwHostLen = lstrlenA(rgchHostName);
|
|
DWORD dwSchemeLen = lstrlenA(rgchScheme);
|
|
|
|
CHAR rgchHostForDisplay[INTERNET_MAX_HOST_NAME_LENGTH];
|
|
CHAR rgchPathForDisplay[MAX_PATH];
|
|
|
|
ZeroMemory(rgchHostForDisplay, sizeof(rgchHostForDisplay));
|
|
ZeroMemory(rgchPathForDisplay, sizeof(rgchPathForDisplay));
|
|
|
|
if (dwHostLen>dwMaxHostLen)
|
|
{
|
|
DWORD dwOverFlow = dwHostLen - dwMaxHostLen + dwElipsisLen + 1;
|
|
wnsprintfA(rgchHostForDisplay, ARRAYSIZE(rgchHostForDisplay), "%s%s", rgchElipsis, rgchHostName+dwOverFlow);
|
|
dwHostLen = dwMaxHostLen;
|
|
}
|
|
else
|
|
StrCpyNA(rgchHostForDisplay, rgchHostName, ARRAYSIZE(rgchHostForDisplay));
|
|
|
|
if (dwPathLen>dwMaxPathLen)
|
|
{
|
|
DWORD dwOverFlow = dwPathLen - dwMaxPathLen + dwElipsisLen;
|
|
wnsprintfA(rgchPathForDisplay, ARRAYSIZE(rgchPathForDisplay), "/%s%s", rgchElipsis, rgchUrlPath+dwOverFlow);
|
|
dwPathLen = dwMaxPathLen;
|
|
}
|
|
else
|
|
StrCpyNA(rgchPathForDisplay, rgchUrlPath, ARRAYSIZE(rgchPathForDisplay));
|
|
|
|
WCHAR rgwchScheme[INTERNET_MAX_SCHEME_LENGTH];
|
|
WCHAR rgwchHostForDisplay[INTERNET_MAX_HOST_NAME_LENGTH];
|
|
WCHAR rgwchPathForDisplay[MAX_PATH];
|
|
WCHAR rgwchUrlPath[MAX_PATH];
|
|
|
|
SHAnsiToUnicodeCP(dwCodePage, rgchScheme, rgwchScheme, ARRAYSIZE(rgwchScheme));
|
|
SHAnsiToUnicodeCP(dwCodePage, rgchHostForDisplay, rgwchHostForDisplay, ARRAYSIZE(rgwchHostForDisplay));
|
|
SHAnsiToUnicodeCP(dwCodePage, rgchPathForDisplay, rgwchPathForDisplay, ARRAYSIZE(rgwchPathForDisplay));
|
|
SHAnsiToUnicodeCP(dwCodePage, rgchUrlPath, rgwchUrlPath, ARRAYSIZE(rgwchUrlPath));
|
|
|
|
if (pwzCachedFileName && *pwzCachedFileName)
|
|
{
|
|
WCHAR szUrlPath[MAX_PATH];
|
|
DWORD cc = ARRAYSIZE(rgchUrlPath);
|
|
if (FAILED(_PrepareURLForDisplayUTF8W(pwzCachedFileName, szUrlPath, &cc, TRUE, dwCodePage)))
|
|
{
|
|
StrCpyNW(szUrlPath, pwzCachedFileName, ARRAYSIZE(szUrlPath));
|
|
}
|
|
CleanExploits(szUrlPath);
|
|
|
|
dwPathLen = lstrlenW(szUrlPath);
|
|
if (dwPathLen>dwMaxPathLen)
|
|
{
|
|
DWORD dwOverFlow = dwPathLen - dwMaxPathLen + dwElipsisLen;
|
|
wnsprintfW(rgwchPathForDisplay, ARRAYSIZE(rgwchPathForDisplay), L"/%s%s", rgwchElipsis, szUrlPath+dwOverFlow);
|
|
dwPathLen = dwMaxPathLen;
|
|
}
|
|
else
|
|
StrCpyNW(rgwchPathForDisplay, szUrlPath, ARRAYSIZE(rgwchPathForDisplay));
|
|
}
|
|
|
|
if (fSeperate)
|
|
{
|
|
// Format string as "X from Y"
|
|
WCHAR rgwchTemplate[dwMaxTemplateLen];
|
|
WCHAR *pwzFileName = PathFindFileNameW(rgwchPathForDisplay);
|
|
DWORD dwCount;
|
|
|
|
//
|
|
// remove cache decoration goop to map ie5setup[1].exe to ie5setup.exe
|
|
//
|
|
PathUndecorateW(pwzFileName);
|
|
|
|
ZeroMemory(rgwchTemplate, sizeof(rgwchTemplate));
|
|
dwCount = MLLoadString(IDS_TARGETFILE, rgwchTemplate, ARRAYSIZE(rgwchTemplate));
|
|
if (dwCount > 0)
|
|
{
|
|
if (urlComp.nScheme == INTERNET_SCHEME_FILE)
|
|
{
|
|
StrCpyNW(rgwchHostForDisplay, rgwchUrlPath, ARRAYSIZE(rgwchPathForDisplay));
|
|
PathRemoveFileSpecW(rgwchHostForDisplay);
|
|
}
|
|
|
|
if (dwPathLen+lstrlenW(rgwchTemplate)+dwHostLen <= cchBuf)
|
|
{
|
|
//avoid formatting the string as "X from " in the event internetcrackurl fails us
|
|
if (rgwchHostForDisplay[0] != TEXT('\0'))
|
|
{
|
|
// if necessary return host separately
|
|
if (pwzFrom && cbFrom)
|
|
{
|
|
StrCpyNW(pwzFriendly, pwzFileName, cchBuf);
|
|
StrCpyNW(pwzFrom, rgwchHostForDisplay, cbFrom);
|
|
}
|
|
else
|
|
_FormatMessage(rgwchTemplate, pwzFriendly, cchBuf, pwzFileName, rgwchHostForDisplay);
|
|
}
|
|
else //hostname is blank, just use filename
|
|
StrCpyNW(pwzFriendly, pwzFileName, cchBuf);
|
|
hrRC = S_OK;
|
|
}
|
|
}
|
|
}
|
|
else // !fSeperate
|
|
{
|
|
if (3+dwPathLen+dwHostLen+dwSchemeLen < cchBuf)
|
|
{
|
|
wnsprintf(pwzFriendly, cchBuf, TEXT("%ws://%ws%ws"), rgwchScheme, rgwchHostForDisplay, rgwchPathForDisplay);
|
|
hrRC = S_OK;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
LocalFree(pszURL);
|
|
pszURL = NULL;
|
|
}
|
|
|
|
return(hrRC);
|
|
}
|
|
|
|
BOOL __cdecl _FormatMessage(LPCWSTR szTemplate, LPWSTR szBuf, UINT cchBuf, ...)
|
|
{
|
|
BOOL fRet;
|
|
va_list ArgList;
|
|
va_start(ArgList, cchBuf);
|
|
|
|
fRet = FormatMessage(FORMAT_MESSAGE_FROM_STRING, szTemplate, 0, 0, szBuf, cchBuf, &ArgList);
|
|
|
|
va_end(ArgList);
|
|
return fRet;
|
|
}
|
|
|
|
|
|
// Navigate to a given Url (wszUrl) using IE. Returns an error if IE does not exist.
|
|
// fNewWindow = TRUE ==> A new window is compulsory
|
|
// fNewWindow = FALSE ==> Do not launch a new window if one already is open.
|
|
HRESULT NavToUrlUsingIEW(LPCWSTR wszUrl, BOOL fNewWindow)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!EVAL(wszUrl))
|
|
return E_INVALIDARG;
|
|
|
|
if (IsIEDefaultBrowser() && !fNewWindow)
|
|
{
|
|
// ShellExecute navigates to the Url using the same browser window,
|
|
// if one is already open.
|
|
|
|
SHELLEXECUTEINFOW sei = {0};
|
|
|
|
sei.cbSize = sizeof(sei);
|
|
sei.lpFile = wszUrl;
|
|
sei.nShow = SW_SHOWNORMAL;
|
|
|
|
ShellExecuteExW(&sei);
|
|
|
|
}
|
|
else
|
|
{
|
|
IWebBrowser2 *pwb2;
|
|
hr = CoCreateInstance(CLSID_InternetExplorer, NULL,
|
|
CLSCTX_LOCAL_SERVER, IID_PPV_ARG(IWebBrowser2, &pwb2));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LBSTR::CString strUrl( wszUrl );
|
|
|
|
VARIANT varURL;
|
|
varURL.vt = VT_BSTR;
|
|
varURL.bstrVal = strUrl;
|
|
|
|
VARIANT varFlags;
|
|
varFlags.vt = VT_I4;
|
|
varFlags.lVal = 0;
|
|
|
|
hr = pwb2->Navigate2(&varURL, &varFlags, PVAREMPTY, PVAREMPTY, PVAREMPTY);
|
|
ASSERT(SUCCEEDED(hr)); // mikesh sez there's no way for Navigate2 to fail
|
|
hr = pwb2->put_Visible( TRUE );
|
|
pwb2->Release();
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT NavToUrlUsingIEA(LPCSTR szUrl, BOOL fNewWindow)
|
|
{
|
|
WCHAR wszUrl[INTERNET_MAX_URL_LENGTH];
|
|
|
|
AnsiToUnicode(szUrl, wszUrl, ARRAYSIZE(wszUrl));
|
|
|
|
return NavToUrlUsingIEW(wszUrl, fNewWindow);
|
|
}
|
|
|
|
|
|
// MultiByteToWideChar doesn't truncate if the buffer is too small.
|
|
// these utils do.
|
|
// returns:
|
|
// # of chars converted (WIDE chars) into out buffer (pwstr)
|
|
|
|
int _AnsiToUnicode(UINT uiCP, LPCSTR pstr, LPWSTR pwstr, int cch)
|
|
{
|
|
int cchDst = 0;
|
|
|
|
ASSERT(IS_VALID_STRING_PTRA(pstr, -1));
|
|
ASSERT(NULL == pwstr || IS_VALID_WRITE_BUFFER(pwstr, WCHAR, cch));
|
|
|
|
if (cch && pwstr)
|
|
pwstr[0] = 0;
|
|
|
|
switch (uiCP)
|
|
{
|
|
case 1200: // UCS-2 (Unicode)
|
|
uiCP = 65001;
|
|
// fall through
|
|
case 50000: // "User Defined"
|
|
case 65000: // UTF-7
|
|
case 65001: // UTF-8
|
|
{
|
|
INT cchSrc, cchSrcOriginal;
|
|
|
|
cchSrc = cchSrcOriginal = lstrlenA(pstr) + 1;
|
|
cchDst = cch;
|
|
|
|
if (SUCCEEDED(ConvertINetMultiByteToUnicode(NULL, uiCP, pstr,
|
|
&cchSrc, pwstr, &cchDst)) &&
|
|
cchSrc < cchSrcOriginal)
|
|
{
|
|
LPWSTR pwsz = (LPWSTR)LocalAlloc(LPTR, cchDst * SIZEOF(WCHAR));
|
|
if (pwsz)
|
|
{
|
|
if (SUCCEEDED(ConvertINetMultiByteToUnicode( NULL, uiCP, pstr,
|
|
&cchSrcOriginal, pwsz, &cchDst )))
|
|
{
|
|
StrCpyNW( pwstr, pwsz, cch );
|
|
cchDst = cch;
|
|
}
|
|
|
|
LocalFree(pwsz);
|
|
pwsz = NULL;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
cchDst = MultiByteToWideChar(uiCP, 0, pstr, -1, pwstr, cch);
|
|
if (!cchDst) {
|
|
|
|
// failed.
|
|
|
|
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
|
int cchNeeded = MultiByteToWideChar(uiCP, 0, pstr, -1, NULL, 0);
|
|
|
|
if (cchNeeded) {
|
|
LPWSTR pwsz = (LPWSTR)LocalAlloc(LPTR, cchNeeded * SIZEOF(WCHAR));
|
|
if (pwsz) {
|
|
cchDst = MultiByteToWideChar(uiCP, 0, pstr, -1, pwsz, cchNeeded);
|
|
if (cchDst) {
|
|
StrCpyNW(pwstr, pwsz, cch);
|
|
cchDst = cch;
|
|
}
|
|
|
|
LocalFree(pwsz);
|
|
pwsz = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
return cchDst;
|
|
}
|
|
|
|
UINT g_cfURL = 0;
|
|
UINT g_cfURLW = 0;
|
|
UINT g_cfFileDescA = 0;
|
|
UINT g_cfFileContents = 0;
|
|
UINT g_cfPreferredEffect = 0;
|
|
UINT g_cfPerformedEffect = 0;
|
|
UINT g_cfTargetCLSID = 0;
|
|
|
|
UINT g_cfHIDA = 0;
|
|
UINT g_cfFileDescW = 0;
|
|
|
|
void InitClipboardFormats()
|
|
{
|
|
if (g_cfURL == 0)
|
|
{
|
|
g_cfURL = RegisterClipboardFormat(CFSTR_SHELLURL);
|
|
g_cfURLW = RegisterClipboardFormat(CFSTR_INETURLW);
|
|
g_cfFileDescA = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORA);
|
|
g_cfFileContents = RegisterClipboardFormat(CFSTR_FILECONTENTS);
|
|
g_cfPreferredEffect = RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT);
|
|
g_cfPerformedEffect = RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT);
|
|
g_cfTargetCLSID = RegisterClipboardFormat(CFSTR_TARGETCLSID);
|
|
g_cfHIDA = RegisterClipboardFormat(CFSTR_SHELLIDLIST);
|
|
g_cfFileDescW = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW);
|
|
}
|
|
}
|
|
|
|
|
|
// FEATURE [raymondc] use SHGlobalCounter
|
|
|
|
// We need to use a cross process browser count.
|
|
// We use a named semaphore.
|
|
//
|
|
EXTERN_C HANDLE g_hSemBrowserCount = NULL;
|
|
|
|
#define SESSION_COUNT_SEMAPHORE_NAME _T("_ie_sessioncount")
|
|
|
|
HANDLE GetSessionCountSemaphoreHandle()
|
|
{
|
|
if (!g_hSemBrowserCount)
|
|
{
|
|
g_hSemBrowserCount = SHGlobalCounterCreateNamed( SESSION_COUNT_SEMAPHORE_NAME, 0 );
|
|
}
|
|
|
|
ASSERT( g_hSemBrowserCount );
|
|
|
|
return g_hSemBrowserCount;
|
|
}
|
|
|
|
LONG GetSessionCount()
|
|
{
|
|
LONG lPrevCount = 0x7FFFFFFF;
|
|
HANDLE hSem = GetSessionCountSemaphoreHandle();
|
|
|
|
ASSERT(hSem);
|
|
if (hSem)
|
|
{
|
|
ReleaseSemaphore(hSem, 1, &lPrevCount);
|
|
WaitForSingleObject(hSem, 0);
|
|
}
|
|
return lPrevCount;
|
|
|
|
|
|
}
|
|
|
|
LONG IncrementSessionCount()
|
|
{
|
|
LONG lPrevCount = 0x7FFFFFFF;
|
|
HANDLE hSem = GetSessionCountSemaphoreHandle();
|
|
|
|
ASSERT(hSem);
|
|
if (hSem)
|
|
{
|
|
ReleaseSemaphore(hSem, 1, &lPrevCount);
|
|
}
|
|
return lPrevCount;
|
|
}
|
|
|
|
LONG DecrementSessionCount()
|
|
{
|
|
LONG lPrevCount = 0x7FFFFFFF;
|
|
HANDLE hSem = GetSessionCountSemaphoreHandle();
|
|
ASSERT(hSem);
|
|
if (hSem)
|
|
{
|
|
ReleaseSemaphore(hSem, 1, &lPrevCount); // increment first to make sure deadlock
|
|
// never occurs
|
|
ASSERT(lPrevCount > 0);
|
|
if (lPrevCount > 0)
|
|
{
|
|
WaitForSingleObject(hSem, 0);
|
|
WaitForSingleObject(hSem, 0);
|
|
lPrevCount--;
|
|
}
|
|
else
|
|
{
|
|
// Oops - Looks like a bug !
|
|
// Just return it back to normal and leave
|
|
WaitForSingleObject(hSem, 0);
|
|
}
|
|
}
|
|
return lPrevCount;
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// The following is the message that autodial monitors expect to receive
|
|
// when it's a good time to hang up
|
|
//
|
|
#define WM_IEXPLORER_EXITING (WM_USER + 103)
|
|
|
|
long SetQueryNetSessionCount(enum SessionOp Op)
|
|
{
|
|
long lCount = 0;
|
|
|
|
switch(Op) {
|
|
case SESSION_QUERY:
|
|
lCount = GetSessionCount();
|
|
TraceMsg(DM_SESSIONCOUNT, "SetQueryNetSessionCount SessionCount=%d (query)", lCount);
|
|
break;
|
|
|
|
case SESSION_INCREMENT_NODEFAULTBROWSERCHECK:
|
|
case SESSION_INCREMENT:
|
|
lCount = IncrementSessionCount();
|
|
TraceMsg(DM_SESSIONCOUNT, "SetQueryNetSessionCount SessionCount=%d (incr)", lCount);
|
|
|
|
|
|
if ((PLATFORM_INTEGRATED == WhichPlatform()))
|
|
{
|
|
// Weird name here... But in integrated mode we make every new browser window
|
|
// look like a new session wrt how we use the cache. Basically this is the way things appear to the
|
|
// user. This effects the way we look for new pages vs doing an if modified
|
|
// since. The ie3/ie4 switch says "look for new pages on each session start"
|
|
// but wininet folks implemented this as a end session name. Woops.
|
|
// Note that things like authentication etc aren't reset by this, but rather
|
|
// only when all browsers are closed via the INTERNET_OPTION_END_BROWSER_SESSION option.
|
|
InternetSetOption(NULL, INTERNET_OPTION_RESET_URLCACHE_SESSION, NULL, 0);
|
|
}
|
|
|
|
if (!lCount && (Op == SESSION_INCREMENT))
|
|
{
|
|
// this forces a reload of the title
|
|
DetectAndFixAssociations();
|
|
}
|
|
break;
|
|
|
|
case SESSION_DECREMENT:
|
|
lCount = DecrementSessionCount();
|
|
TraceMsg(DM_SESSIONCOUNT, "SetQueryNetSessionCount SessionCount=%d (decr)", lCount);
|
|
|
|
if (!lCount) {
|
|
// if we've closed all the net browsers, we need to flush the cache
|
|
InternetSetOption(NULL, INTERNET_OPTION_END_BROWSER_SESSION, NULL, 0);
|
|
InternetSetOption(NULL, INTERNET_OPTION_RESET_URLCACHE_SESSION, NULL, 0);
|
|
|
|
// flush the Java VM cache too (if the Java VM is loaded in this process
|
|
// and we're in integrated mode)
|
|
if (WhichPlatform() == PLATFORM_INTEGRATED)
|
|
{
|
|
HMODULE hmod = GetModuleHandle(TEXT("msjava.dll"));
|
|
if (hmod)
|
|
{
|
|
typedef HRESULT (*PFNNOTIFYBROWSERSHUTDOWN)(void *);
|
|
FARPROC fp = GetProcAddress(hmod, "NotifyBrowserShutdown");
|
|
if (fp)
|
|
{
|
|
HRESULT hr = ((PFNNOTIFYBROWSERSHUTDOWN)fp)(NULL);
|
|
ASSERT(SUCCEEDED(hr));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Inform dial monitor that it's a good time to hang up
|
|
HWND hwndMonitorWnd = FindWindow(TEXT("MS_AutodialMonitor"),NULL);
|
|
if (hwndMonitorWnd) {
|
|
PostMessage(hwndMonitorWnd,WM_IEXPLORER_EXITING,0,0);
|
|
}
|
|
hwndMonitorWnd = FindWindow(TEXT("MS_WebcheckMonitor"),NULL);
|
|
if (hwndMonitorWnd) {
|
|
PostMessage(hwndMonitorWnd,WM_IEXPLORER_EXITING,0,0);
|
|
}
|
|
|
|
// reset offline mode on all platforms except Win2K.
|
|
OSVERSIONINFOA vi;
|
|
vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
|
|
GetVersionExA(&vi);
|
|
if ( vi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS ||
|
|
vi.dwMajorVersion < 5)
|
|
{
|
|
// wininet is loaded - tell it to go online
|
|
INTERNET_CONNECTED_INFO ci;
|
|
memset(&ci, 0, sizeof(ci));
|
|
ci.dwConnectedState = INTERNET_STATE_CONNECTED;
|
|
InternetSetOption(NULL, INTERNET_OPTION_CONNECTED_STATE, &ci, sizeof(ci));
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return lCount;
|
|
}
|
|
|
|
|
|
#ifdef DEBUG
|
|
//---------------------------------------------------------------------------
|
|
// Copy the exception info so we can get debug info for Raised exceptions
|
|
// which don't go through the debugger.
|
|
void _CopyExceptionInfo(LPEXCEPTION_POINTERS pep)
|
|
{
|
|
PEXCEPTION_RECORD per;
|
|
|
|
per = pep->ExceptionRecord;
|
|
TraceMsg(DM_ERROR, "Exception %x at %#08x.", per->ExceptionCode, per->ExceptionAddress);
|
|
|
|
if (per->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
|
|
{
|
|
// If the first param is 1 then this was a write.
|
|
// If the first param is 0 then this was a read.
|
|
if (per->ExceptionInformation[0])
|
|
{
|
|
TraceMsg(DM_ERROR, "Invalid write to %#08x.", per->ExceptionInformation[1]);
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(DM_ERROR, "Invalid read of %#08x.", per->ExceptionInformation[1]);
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
#define _CopyExceptionInfo(x) TRUE
|
|
#endif
|
|
|
|
|
|
int WELCallback(void * p, void * pData)
|
|
{
|
|
STATURL* pstat = (STATURL*)p;
|
|
if (pstat->pwcsUrl) {
|
|
OleFree(pstat->pwcsUrl);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int CALLBACK WELCompare(void * p1, void * p2, LPARAM lParam)
|
|
{
|
|
HDSA hdsa = (HDSA)lParam;
|
|
// Sundown: coercion to long because parameter is an index
|
|
STATURL* pstat1 = (STATURL*)DSA_GetItemPtr(hdsa, PtrToLong(p1));
|
|
STATURL* pstat2 = (STATURL*)DSA_GetItemPtr(hdsa, PtrToLong(p2));
|
|
if (pstat1 && pstat2) {
|
|
return CompareFileTime(&pstat2->ftLastVisited, &pstat1->ftLastVisited);
|
|
}
|
|
|
|
ASSERT(0);
|
|
return 0;
|
|
}
|
|
|
|
#define MACRO_STR(x) #x
|
|
#define VERSION_HEADER_STR "Microsoft Internet Explorer 5.0 Error Log -- " \
|
|
MACRO_STR(VER_MAJOR_PRODUCTVER) "." \
|
|
MACRO_STR(VER_MINOR_PRODUCTVER) "." \
|
|
MACRO_STR(VER_PRODUCTBUILD) "." \
|
|
MACRO_STR(VER_PRODUCTBUILD_QFE) "\r\n"
|
|
|
|
SHDOCAPI_(void) IEWriteErrorLog(const EXCEPTION_RECORD* pexr)
|
|
{
|
|
HANDLE hfile = INVALID_HANDLE_VALUE;
|
|
_try
|
|
{
|
|
TCHAR szWindows[MAX_PATH];
|
|
GetWindowsDirectory(szWindows, ARRAYSIZE(szWindows));
|
|
PathAppend(szWindows, TEXT("IE4 Error Log.txt"));
|
|
HANDLE hfile = CreateFile(szWindows, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if (hfile != INVALID_HANDLE_VALUE)
|
|
{
|
|
const static CHAR c_szCRLF[] = "\r\n";
|
|
DWORD cbWritten;
|
|
CHAR szBuf[MAX_URL_STRING];
|
|
|
|
// Write the title and product version.
|
|
WriteFile(hfile, VERSION_HEADER_STR, lstrlenA(VERSION_HEADER_STR), &cbWritten, NULL);
|
|
|
|
// Write the current time.
|
|
SYSTEMTIME st;
|
|
FILETIME ft;
|
|
GetSystemTime(&st);
|
|
SystemTimeToFileTime(&st, &ft);
|
|
SHFormatDateTimeA(&ft, NULL, szBuf, SIZECHARS(szBuf));
|
|
const static CHAR c_szCurrentTime[] = "CurrentTime: ";
|
|
WriteFile(hfile, c_szCurrentTime, SIZEOF(c_szCurrentTime)-1, &cbWritten, NULL);
|
|
WriteFile(hfile, szBuf, lstrlenA(szBuf), &cbWritten, NULL);
|
|
WriteFile(hfile, c_szCRLF, SIZEOF(c_szCRLF)-1, &cbWritten, NULL);
|
|
|
|
if (pexr) {
|
|
const static CHAR c_szExcCode[] = "Exception Info: Code=%x Flags=%x Address=%x\r\n";
|
|
const static CHAR c_szExcParam[] = "Exception Param:";
|
|
wnsprintfA(szBuf, ARRAYSIZE(szBuf), c_szExcCode, pexr->ExceptionCode, pexr->ExceptionFlags, pexr->ExceptionAddress);
|
|
WriteFile(hfile, szBuf, lstrlenA(szBuf), &cbWritten, NULL);
|
|
|
|
if (pexr->NumberParameters) {
|
|
WriteFile(hfile, c_szExcParam, SIZEOF(c_szExcParam)-1, &cbWritten, NULL);
|
|
for (UINT iParam=0; iParam<pexr->NumberParameters; iParam++) {
|
|
wnsprintfA(szBuf, ARRAYSIZE(szBuf), " %x", pexr->ExceptionInformation[iParam]);
|
|
WriteFile(hfile, szBuf, lstrlenA(szBuf), &cbWritten, NULL);
|
|
}
|
|
}
|
|
|
|
WriteFile(hfile, c_szCRLF, SIZEOF(c_szCRLF)-1, &cbWritten, NULL);
|
|
WriteFile(hfile, c_szCRLF, SIZEOF(c_szCRLF)-1, &cbWritten, NULL);
|
|
}
|
|
|
|
IUrlHistoryStg* pUrlHistStg;
|
|
HRESULT hres = CoCreateInstance(CLSID_CUrlHistory, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_PPV_ARG(IUrlHistoryStg, &pUrlHistStg));
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
IEnumSTATURL* penum;
|
|
hres = pUrlHistStg->EnumUrls(&penum);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
// Allocate DSA for an array of STATURL
|
|
HDSA hdsa = DSA_Create(SIZEOF(STATURL), 32);
|
|
if (hdsa)
|
|
{
|
|
// Allocate DPA for sorting
|
|
HDPA hdpa = DPA_Create(32);
|
|
if (hdpa)
|
|
{
|
|
STATURL stat;
|
|
stat.cbSize = SIZEOF(stat.cbSize);
|
|
while(penum->Next(1, &stat, NULL)==S_OK && stat.pwcsUrl)
|
|
{
|
|
DSA_AppendItem(hdsa, &stat);
|
|
DPA_AppendPtr(hdpa, IntToPtr(DSA_GetItemCount(hdsa)-1));
|
|
}
|
|
|
|
DPA_Sort(hdpa, WELCompare, (LPARAM)hdsa);
|
|
for (int i=0; i<10 && i<DPA_GetPtrCount(hdpa) ; i++)
|
|
{
|
|
// Sundown: typecast to long is OK
|
|
STATURL* pstat = (STATURL*)DSA_GetItemPtr(hdsa, PtrToLong(DPA_GetPtr(hdpa, i)));
|
|
if (pstat && pstat->pwcsUrl)
|
|
{
|
|
SHFormatDateTimeA(&pstat->ftLastVisited, NULL, szBuf, SIZECHARS(szBuf));
|
|
WriteFile(hfile, szBuf, lstrlenA(szBuf), &cbWritten, NULL);
|
|
const static TCHAR c_szColumn[] = TEXT(" -- ");
|
|
WriteFile(hfile, c_szColumn, SIZEOF(c_szColumn)-1, &cbWritten, NULL);
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, pstat->pwcsUrl, -1,
|
|
szBuf, ARRAYSIZE(szBuf), NULL, NULL);
|
|
WriteFile(hfile, szBuf, lstrlenA(szBuf), &cbWritten, NULL);
|
|
|
|
WriteFile(hfile, c_szCRLF, SIZEOF(c_szCRLF)-1, &cbWritten, NULL);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(0);
|
|
}
|
|
}
|
|
|
|
DPA_Destroy(hdpa);
|
|
hdpa = NULL;
|
|
}
|
|
|
|
DSA_DestroyCallback(hdsa, WELCallback, NULL);
|
|
hdsa = NULL;
|
|
}
|
|
penum->Release();
|
|
}
|
|
else
|
|
{
|
|
ASSERT(0);
|
|
}
|
|
pUrlHistStg->Release();
|
|
}
|
|
else
|
|
{
|
|
ASSERT(0);
|
|
}
|
|
|
|
CloseHandle( hfile );
|
|
hfile = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
_except((SetErrorMode(SEM_NOGPFAULTERRORBOX),
|
|
_CopyExceptionInfo(GetExceptionInformation()),
|
|
UnhandledExceptionFilter(GetExceptionInformation())
|
|
))
|
|
{
|
|
// We hit an exception while handling an exception.
|
|
// Do nothing; we have already displayed the error dialog box.
|
|
if (hfile != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(hfile);
|
|
}
|
|
}
|
|
__endexcept
|
|
}
|
|
|
|
IStream* SHGetViewStream(LPCITEMIDLIST pidl, DWORD grfMode, LPCTSTR pszName, LPCTSTR pszStreamMRU, LPCTSTR pszStreams)
|
|
{
|
|
IStream *pstm = NULL;
|
|
static DWORD s_dwMRUSize = 0;
|
|
DWORD dwSize = sizeof(s_dwMRUSize);
|
|
|
|
if ((0 == s_dwMRUSize) &&
|
|
(ERROR_SUCCESS != SHGetValue(HKEY_CURRENT_USER, pszStreamMRU, TEXT("MRU Size"), NULL, (void *) &s_dwMRUSize, &dwSize)))
|
|
{
|
|
s_dwMRUSize = 200; // The default.
|
|
}
|
|
|
|
ASSERT(pidl);
|
|
|
|
// should be checked by caller - if this is not true we'll flush the
|
|
// MRU cache with internet pidls! FTP and other URL Shell Extension PIDLs
|
|
// that act like a folder and need similar persistence and fine. This
|
|
// is especially true because recently the cache size was increased from
|
|
// 30 or so to 200.
|
|
ASSERT(ILIsEqual(pidl, c_pidlURLRoot) || !IsBrowserFrameOptionsPidlSet(pidl, BFO_BROWSER_PERSIST_SETTINGS));
|
|
|
|
// Now lets try to save away the other information associated with view.
|
|
IMruDataList *pmru;
|
|
if (SUCCEEDED(SHCoCreateInstance(NULL, &CLSID_MruLongList, NULL, IID_PPV_ARG(IMruDataList, &pmru))))
|
|
{
|
|
if (SUCCEEDED(pmru->InitData(s_dwMRUSize, MRULISTF_USE_ILISEQUAL, HKEY_CURRENT_USER, pszStreamMRU, NULL)))
|
|
{
|
|
DWORD cbPidl = ILGetSize(pidl);
|
|
// need to walk the list
|
|
// and find this guy
|
|
int iIndex;
|
|
BOOL fFoundPidl = SUCCEEDED(pmru->FindData((const BYTE *)pidl, cbPidl, &iIndex));
|
|
|
|
// Did we find the item?
|
|
if (!fFoundPidl && ((grfMode & (STGM_READ|STGM_WRITE|STGM_READWRITE)) == STGM_READ))
|
|
{
|
|
// Do not create the stream if it does not exist and we are
|
|
// only reading
|
|
}
|
|
else
|
|
{
|
|
// Note that we always create the key here, since we have
|
|
// already checked whether we are just reading and the MRU
|
|
// thing does not exist
|
|
HKEY hkCabStreams = SHGetShellKey(SHELLKEY_HKCU_EXPLORER, pszStreams, TRUE);
|
|
if (hkCabStreams )
|
|
{
|
|
DWORD dwSlot;
|
|
if (SUCCEEDED(pmru->AddData((const BYTE *)pidl, cbPidl, &dwSlot)))
|
|
{
|
|
HKEY hkValues;
|
|
TCHAR szValue[32], szSubVal[64];
|
|
wnsprintf(szValue, ARRAYSIZE(szValue), TEXT("%d"), dwSlot);
|
|
|
|
if (!fFoundPidl && RegOpenKey(hkCabStreams, szValue, &hkValues) == ERROR_SUCCESS)
|
|
{
|
|
// This means that we have created a new MRU
|
|
// item for this PIDL, so clear out any
|
|
// information residing at this slot
|
|
// Note that we do not just delete the key,
|
|
// since that could fail if it has any sub-keys
|
|
DWORD dwType, dwSize = ARRAYSIZE(szSubVal);
|
|
|
|
while (RegEnumValue(hkValues, 0, szSubVal, &dwSize, NULL, &dwType, NULL, NULL) == ERROR_SUCCESS)
|
|
{
|
|
if (RegDeleteValue(hkValues, szSubVal) != ERROR_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hkValues);
|
|
}
|
|
pstm = OpenRegStream(hkCabStreams, szValue, pszName, grfMode);
|
|
}
|
|
|
|
RegCloseKey(hkCabStreams);
|
|
}
|
|
}
|
|
}
|
|
|
|
pmru->Release();
|
|
}
|
|
|
|
|
|
return pstm;
|
|
}
|
|
|
|
|
|
#define c_szExploreClass TEXT("ExploreWClass")
|
|
#define c_szIExploreClass TEXT("IEFrame")
|
|
#ifdef IE3CLASSNAME
|
|
#define c_szCabinetClass TEXT("IEFrame")
|
|
#else
|
|
#define c_szCabinetClass TEXT("CabinetWClass")
|
|
#endif
|
|
|
|
|
|
BOOL IsNamedWindow(HWND hwnd, LPCTSTR pszClass)
|
|
{
|
|
TCHAR szClass[32];
|
|
|
|
GetClassName(hwnd, szClass, ARRAYSIZE(szClass));
|
|
return StrCmp(szClass, pszClass) == 0;
|
|
}
|
|
|
|
BOOL IsTrayWindow(HWND hwnd)
|
|
{
|
|
return IsNamedWindow(hwnd, TEXT(WNDCLASS_TRAYNOTIFY));
|
|
}
|
|
|
|
BOOL IsExplorerWindow(HWND hwnd)
|
|
{
|
|
return IsNamedWindow(hwnd, c_szExploreClass);
|
|
}
|
|
|
|
BOOL IsFolderWindow(HWND hwnd)
|
|
{
|
|
TCHAR szClass[32];
|
|
|
|
GetClassName(hwnd, szClass, ARRAYSIZE(szClass));
|
|
return (StrCmp(szClass, c_szCabinetClass) == 0) || (StrCmp(szClass, c_szIExploreClass) == 0);
|
|
}
|
|
|
|
HRESULT _SendOrPostDispatchMessage(HWND hwnd, WPARAM wParam, LPARAM lParam, BOOL fPostMessage, BOOL fCheckFirst)
|
|
{
|
|
HRESULT hr = HRESULT_FROM_WIN32(ERROR_BUSY);
|
|
DWORD idProcess;
|
|
|
|
// in case of wParam = DSID_NAVIGATEIEBROWSER, lParam is LocalAlloced structure
|
|
// so we better make sure we are in process 'coz otherwise will fault
|
|
GetWindowThreadProcessId(hwnd, &idProcess);
|
|
if (idProcess == GetCurrentProcessId() && IsWindowEnabled(hwnd) && IsWindowVisible(hwnd))
|
|
{
|
|
if (!fPostMessage || fCheckFirst)
|
|
{
|
|
// sync or we are querying the windows readiness
|
|
ULONG_PTR result;
|
|
if (SendMessageTimeoutA(hwnd, WMC_DISPATCH, (fCheckFirst ? DSID_NOACTION : wParam),
|
|
lParam, SMTO_ABORTIFHUNG, 400, &result))
|
|
hr = (HRESULT) result;
|
|
}
|
|
|
|
// handle the post only if the window was ready
|
|
if (fPostMessage && (!fCheckFirst || SUCCEEDED(hr)))
|
|
hr = (PostMessage(hwnd, WMC_DISPATCH, wParam, lParam) ? S_OK : E_FAIL);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
HRESULT FindBrowserWindowOfClass(LPCTSTR pszClass, WPARAM wParam, LPARAM lParam, BOOL fPostMessage, HWND* phwnd)
|
|
{
|
|
//If there is no window, assume the user is in the process of shutting down IE, and return E_FAIL
|
|
|
|
//Otherwise, if there is at least one window, start cycling through the windows until you find
|
|
//one that's not busy, and give it our message. If all are busy, return
|
|
//HRESULT_FROM_WIN32(ERROR_BUSY)
|
|
HWND hwnd = NULL;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
while (FAILED(hr)
|
|
&& (hwnd = FindWindowEx(NULL, hwnd, pszClass, NULL)) != NULL)
|
|
{
|
|
hr = _SendOrPostDispatchMessage(hwnd, wParam, lParam, fPostMessage, fPostMessage);
|
|
}
|
|
|
|
*phwnd = hwnd;
|
|
return hr;
|
|
}
|
|
|
|
//This common function gets called when the DDE engine doesn't seem to care in which window something
|
|
//happens. It returns in which window that something happened. 0 means all windows are busy.
|
|
//
|
|
//phwnd: a pointer the hwnd to which to send the message. <= 0 means any window will do.
|
|
// this is also an out parameter that specifies in which window it happened.
|
|
//fPostMessage: when doing navigations, we have to do a PostMessage instead of a SendMessageTimeout
|
|
// or a CoCreateInstance later on in CDocObjectHost::_BindFileMoniker will fail. So when
|
|
// this function is called from CDDEAuto_Navigate, we make this flag TRUE
|
|
HRESULT CDDEAuto_Common(WPARAM wParam, LPARAM lParam, HWND *phwnd, BOOL fPostMessage)
|
|
{
|
|
HRESULT hr = HRESULT_FROM_WIN32(ERROR_BUSY);
|
|
HWND hwnd;
|
|
|
|
//if we're told to go to a specific window
|
|
if (phwnd && (*phwnd != (HWND)-1))
|
|
{
|
|
hr = _SendOrPostDispatchMessage(*phwnd, wParam, lParam, fPostMessage, FALSE);
|
|
}
|
|
|
|
if (HRESULT_FROM_WIN32(ERROR_BUSY) == hr)
|
|
{
|
|
hr = FindBrowserWindowOfClass(c_szIExploreClass, wParam, lParam, fPostMessage, &hwnd);
|
|
if (!hwnd)
|
|
hr = FindBrowserWindowOfClass(c_szCabinetClass, wParam, lParam, fPostMessage, &hwnd);
|
|
|
|
if (phwnd)
|
|
*phwnd = hwnd;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Before changing the behavior of this function look at itemmenu.cpp in
|
|
// cdfview.
|
|
//
|
|
HRESULT CDDEAuto_Navigate(BSTR str, HWND *phwnd, long lLaunchNewWindow) // the long used to be for lTransID, but it was always ignored...
|
|
{ // so I am using it to tell us if we want to absolutely create an new window or not...
|
|
DDENAVIGATESTRUCT *pddens = NULL;
|
|
HRESULT hres = E_FAIL;
|
|
|
|
if (phwnd == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
pddens = new DDENAVIGATESTRUCT;
|
|
if (!pddens)
|
|
hres = E_OUTOFMEMORY;
|
|
else
|
|
{
|
|
pddens->wszUrl = StrDupW(str);
|
|
if (!pddens->wszUrl)
|
|
{
|
|
hres = E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
// Don't do the navigate if *phwnd == 0, in that case we want to either
|
|
// create a new window or activate an existing one that already is viewing
|
|
// this URL.
|
|
|
|
if ((*phwnd != NULL) && !lLaunchNewWindow)
|
|
{
|
|
BOOL fForceWindowReuse = FALSE;
|
|
BSTR bstrUrl = NULL;
|
|
// If there is even a single window with a location
|
|
// you are basically assured that you cannot force a
|
|
// reuse of windows. essentially
|
|
|
|
// case 1 : only iexplore -nohome windows implies we want to force reuse
|
|
// case 2 : only windows that have a location - we don't want to force reuse
|
|
// just follow user's preference
|
|
// case 3: mix of iexplore -nohome windows and windows with location. we don't
|
|
// know what state we are in - don't force reuse
|
|
hres = CDDEAuto_get_LocationURL(&bstrUrl, *phwnd);
|
|
|
|
if (FAILED(hres) ||
|
|
(!bstrUrl) ||
|
|
(SUCCEEDED(hres) && (*bstrUrl == L'\0')))
|
|
{
|
|
fForceWindowReuse = TRUE;
|
|
}
|
|
if (bstrUrl)
|
|
SysFreeString(bstrUrl);
|
|
|
|
if ( !(GetAsyncKeyState(VK_SHIFT) < 0)
|
|
&& (fForceWindowReuse || SHRegGetBoolUSValue(REGSTR_PATH_MAIN, TEXT("AllowWindowReuse"), FALSE, TRUE)))
|
|
{
|
|
hres = CDDEAuto_Common(DSID_NAVIGATEIEBROWSER, (LPARAM)pddens, phwnd, FALSE);
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hres) && (*phwnd != 0) && (*phwnd != (HWND)-1))
|
|
{
|
|
// We found an existing browser window and successfully sent the
|
|
// navigate message to it. Make the window foreground.
|
|
SetForegroundWindow(*phwnd);
|
|
|
|
if (IsIconic(*phwnd))
|
|
ShowWindowAsync(*phwnd, SW_RESTORE);
|
|
}
|
|
|
|
//
|
|
// If we are using whatever window and all the browser windows are busy
|
|
// (*phwnd == 0), or if there's no browser window opened (*phwnd == -1)
|
|
// or we are asked to create a new one, then take the official OLE automation
|
|
// route to start a new window.
|
|
//
|
|
if ((*phwnd == 0) ||
|
|
(*phwnd == (HWND)-1))
|
|
{
|
|
//WARNING: this route doesn't give us the ability to return the hwnd of the window
|
|
//in which the navigation took place (while we could - it's too hard and not worth it)
|
|
LPITEMIDLIST pidlNew;
|
|
hres = IECreateFromPathW(str, &pidlNew);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
if (!lLaunchNewWindow)
|
|
{
|
|
// See if there is already a browser viewing this URL, if so just
|
|
// make him foreground otherwise create a new browser.
|
|
hres = WinList_FindFolderWindow(pidlNew, NULL, phwnd, NULL);
|
|
}
|
|
else
|
|
{
|
|
// we don't look in the winlist if the caller explicitly wants a new window
|
|
hres = S_FALSE;
|
|
}
|
|
|
|
if (S_OK == hres)
|
|
{
|
|
ILFree(pidlNew);
|
|
SetForegroundWindow(*phwnd);
|
|
ShowWindow(*phwnd, SW_SHOWNORMAL);
|
|
}
|
|
else
|
|
{
|
|
SHOpenNewFrame(pidlNew, NULL, 0, COF_IEXPLORE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// It will be set to NULL if we don't need to free it.
|
|
if (pddens)
|
|
{
|
|
if (pddens->wszUrl)
|
|
{
|
|
LocalFree(pddens->wszUrl);
|
|
pddens->wszUrl = NULL;
|
|
}
|
|
|
|
delete pddens;
|
|
}
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CDDEAuto_get_LocationURL(BSTR * pstr, HWND hwnd)
|
|
{
|
|
return CDDEAuto_Common(DSID_GETLOCATIONURL, (LPARAM)pstr, &hwnd, FALSE);
|
|
}
|
|
|
|
HRESULT CDDEAuto_get_LocationTitle(BSTR * pstr, HWND hwnd)
|
|
{
|
|
return CDDEAuto_Common(DSID_GETLOCATIONTITLE, (LPARAM)pstr, &hwnd, FALSE);
|
|
}
|
|
|
|
HRESULT CDDEAuto_get_HWND(long * phwnd)
|
|
{
|
|
return CDDEAuto_Common(DSID_GETHWND, (LPARAM)phwnd, NULL, FALSE);
|
|
}
|
|
|
|
HRESULT CDDEAuto_Exit()
|
|
{
|
|
return CDDEAuto_Common(DSID_EXIT, (LPARAM)NULL, NULL, FALSE);
|
|
}
|
|
|
|
#define DXTRACK 1
|
|
void FrameTrack(HDC hdc, LPRECT prc, UINT uFlags)
|
|
{
|
|
COLORREF clrSave, clr;
|
|
RECT rc;
|
|
|
|
// upperleft
|
|
switch (uFlags)
|
|
{
|
|
case TRACKHOT:
|
|
clr = GetSysColor(COLOR_BTNHILIGHT);
|
|
break;
|
|
case TRACKNOCHILD:
|
|
case TRACKEXPAND:
|
|
clr = GetSysColor(COLOR_BTNSHADOW);
|
|
break;
|
|
default:
|
|
ASSERT(FALSE);
|
|
clr = GetSysColor(COLOR_BTNSHADOW);
|
|
break;
|
|
}
|
|
clrSave = SetBkColor(hdc, clr);
|
|
rc = *prc;
|
|
rc.bottom = rc.top + DXTRACK;
|
|
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
|
|
rc.bottom = prc->bottom;
|
|
rc.right = rc.left + DXTRACK;
|
|
rc.top = prc->top + DXTRACK;
|
|
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
|
|
// lowerright
|
|
switch (uFlags)
|
|
{
|
|
case TRACKHOT:
|
|
clr = GetSysColor(COLOR_BTNSHADOW);
|
|
break;
|
|
case TRACKNOCHILD:
|
|
case TRACKEXPAND:
|
|
clr = GetSysColor(COLOR_BTNHILIGHT);
|
|
break;
|
|
default:
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
SetBkColor(hdc, clr);
|
|
if (uFlags & (TRACKHOT | TRACKNOCHILD))
|
|
{
|
|
rc.right = prc->right;
|
|
rc.top = rc.bottom - DXTRACK;
|
|
rc.left = prc->left;
|
|
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
|
|
}
|
|
rc.right = prc->right;
|
|
rc.left = prc->right - DXTRACK;
|
|
rc.top = prc->top;
|
|
rc.bottom = prc->bottom;
|
|
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
|
|
SetBkColor(hdc, clrSave);
|
|
return;
|
|
}
|
|
|
|
|
|
#undef new // Hack!! Need to remove this (edwardp)
|
|
|
|
class CDelagateMalloc : public IMalloc
|
|
{
|
|
public:
|
|
// IUnknown
|
|
virtual STDMETHODIMP QueryInterface(REFIID,void **);
|
|
virtual STDMETHODIMP_(ULONG) AddRef(void);
|
|
virtual STDMETHODIMP_(ULONG) Release(void);
|
|
|
|
// IMalloc
|
|
virtual STDMETHODIMP_(void *) Alloc(SIZE_T cb);
|
|
virtual STDMETHODIMP_(void *) Realloc(void *pv, SIZE_T cb);
|
|
virtual STDMETHODIMP_(void) Free(void *pv);
|
|
virtual STDMETHODIMP_(SIZE_T) GetSize(void *pv);
|
|
virtual STDMETHODIMP_(int) DidAlloc(void *pv);
|
|
virtual STDMETHODIMP_(void) HeapMinimize();
|
|
|
|
private:
|
|
CDelagateMalloc(void *pv, SIZE_T cbSize, WORD wOuter);
|
|
~CDelagateMalloc() {}
|
|
void* operator new(size_t cbClass, SIZE_T cbSize)
|
|
{
|
|
return ::operator new(cbClass + cbSize);
|
|
}
|
|
|
|
|
|
friend HRESULT CDelegateMalloc_Create(void *pv, SIZE_T cbSize, WORD wOuter, IMalloc **ppmalloc);
|
|
|
|
protected:
|
|
LONG _cRef;
|
|
WORD _wOuter; // delegate item outer signature
|
|
WORD _wUnused; // to allign
|
|
#ifdef DEBUG
|
|
UINT _cAllocs;
|
|
#endif
|
|
SIZE_T _cb;
|
|
BYTE _data[EMPTY_SIZE];
|
|
};
|
|
|
|
CDelagateMalloc::CDelagateMalloc(void *pv, SIZE_T cbSize, WORD wOuter)
|
|
{
|
|
_cRef = 1;
|
|
_wOuter = wOuter;
|
|
_cb = cbSize;
|
|
|
|
memcpy(_data, pv, _cb);
|
|
}
|
|
|
|
HRESULT CDelagateMalloc::QueryInterface(REFIID riid, void **ppvObj)
|
|
{
|
|
static const QITAB qit[] = {
|
|
QITABENT(CDelagateMalloc, IMalloc),
|
|
{ 0 },
|
|
};
|
|
return QISearch(this, qit, riid, ppvObj);
|
|
}
|
|
|
|
ULONG CDelagateMalloc::AddRef()
|
|
{
|
|
return InterlockedIncrement(&_cRef);
|
|
}
|
|
|
|
ULONG CDelagateMalloc::Release()
|
|
{
|
|
if (InterlockedDecrement(&_cRef))
|
|
return _cRef;
|
|
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
void *CDelagateMalloc::Alloc(SIZE_T cb)
|
|
{
|
|
WORD cbActualSize = (WORD)(
|
|
SIZEOF(DELEGATEITEMID) - 1 + // header (-1 sizeof(rgb[0])
|
|
cb + // inner
|
|
_cb); // outer data
|
|
|
|
PDELEGATEITEMID pidl = (PDELEGATEITEMID)SHAlloc(cbActualSize + 2); // +2 for pidl term
|
|
if (pidl)
|
|
{
|
|
pidl->cbSize = cbActualSize;
|
|
pidl->wOuter = _wOuter;
|
|
pidl->cbInner = (WORD)cb;
|
|
memcpy(&pidl->rgb[cb], _data, _cb);
|
|
*(UNALIGNED WORD *)&(((BYTE *)pidl)[cbActualSize]) = 0;
|
|
#ifdef DEBUG
|
|
_cAllocs++;
|
|
#endif
|
|
}
|
|
return pidl;
|
|
}
|
|
|
|
void *CDelagateMalloc::Realloc(void *pv, SIZE_T cb)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
void CDelagateMalloc::Free(void *pv)
|
|
{
|
|
SHFree(pv);
|
|
}
|
|
|
|
SIZE_T CDelagateMalloc::GetSize(void *pv)
|
|
{
|
|
return (SIZE_T)-1;
|
|
}
|
|
|
|
int CDelagateMalloc::DidAlloc(void *pv)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
void CDelagateMalloc::HeapMinimize()
|
|
{
|
|
}
|
|
|
|
STDAPI CDelegateMalloc_Create(void *pv, SIZE_T cbSize, WORD wOuter, IMalloc **ppmalloc)
|
|
{
|
|
CDelagateMalloc *pdm = new(cbSize) CDelagateMalloc(pv, cbSize, wOuter);
|
|
if (pdm)
|
|
{
|
|
HRESULT hres = pdm->QueryInterface(IID_PPV_ARG(IMalloc, ppmalloc));
|
|
pdm->Release();
|
|
return hres;
|
|
}
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// This function scans the head of an html document for the desired element
|
|
// with a particular attribute. If a match is found, the first occurance
|
|
// of that element is returned in punkDesired and S_OK is returned.
|
|
// Otherwise, E_FAIL is returned.
|
|
//
|
|
// Example: Find the first meta element with name="ProgID":
|
|
//
|
|
// SearchForElementInHead(pHTMLDoc, OLESTR("Name"), OLESTR("ProgId"),
|
|
// IID_IHTMLMetaElement, (IUnknown**)&pMetaElement);
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HRESULT SearchForElementInHead
|
|
(
|
|
IHTMLDocument2* pHTMLDocument, // [in] document to search
|
|
LPOLESTR pszAttribName, // [in] attribute to check for
|
|
LPOLESTR pszAttrib, // [in] value the attribute must have
|
|
REFIID iidDesired, // [in] element interface to return
|
|
IUnknown** ppunkDesired // [out] returned interface
|
|
)
|
|
{
|
|
ASSERT(NULL != pHTMLDocument);
|
|
ASSERT(NULL != pszAttribName);
|
|
ASSERT(NULL != pszAttrib);
|
|
ASSERT(NULL != ppunkDesired);
|
|
|
|
HRESULT hr = E_FAIL;
|
|
*ppunkDesired = NULL;
|
|
|
|
BSTR bstrAttribName = SysAllocString(pszAttribName);
|
|
if (NULL == bstrAttribName)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// First get all document elements. Note that this is very fast in
|
|
// ie5 because the collection directly accesses the internal tree.
|
|
//
|
|
IHTMLElementCollection * pAllCollection;
|
|
if (SUCCEEDED(pHTMLDocument->get_all(&pAllCollection)))
|
|
{
|
|
IUnknown* punk;
|
|
IHTMLBodyElement* pBodyElement;
|
|
IHTMLFrameSetElement* pFrameSetElement;
|
|
IDispatch* pDispItem;
|
|
|
|
//
|
|
// Now we scan the document for the desired tags. Since we're only
|
|
// searching the head, and since Trident always creates a body tag
|
|
// (unless there is a frameset), we can stop looking when we hit the
|
|
// body or frameset.
|
|
//
|
|
// Note, the alternative of using pAllCollection->tags to return the
|
|
// collection of desired tags is likely more expensive because it will
|
|
// walk the whole tree (unless Trident optimizes this).
|
|
//
|
|
long lItemCnt;
|
|
VARIANT vEmpty;
|
|
V_VT(&vEmpty) = VT_EMPTY;
|
|
|
|
VARIANT vIndex;
|
|
V_VT(&vIndex) = VT_I4;
|
|
|
|
EVAL(SUCCEEDED(pAllCollection->get_length(&lItemCnt)));
|
|
|
|
for (long lItem = 0; lItem < lItemCnt; lItem++)
|
|
{
|
|
V_I4(&vIndex) = lItem;
|
|
|
|
if (S_OK == pAllCollection->item(vIndex, vEmpty, &pDispItem))
|
|
{
|
|
//
|
|
// First see if it's the desired element type
|
|
//
|
|
if (SUCCEEDED(pDispItem->QueryInterface(iidDesired, (void **)&punk)))
|
|
{
|
|
//
|
|
// Next see if it has the desired attribute
|
|
//
|
|
IHTMLElement* pElement;
|
|
|
|
if (SUCCEEDED(pDispItem->QueryInterface(IID_PPV_ARG(IHTMLElement, &pElement))))
|
|
{
|
|
VARIANT varAttrib;
|
|
V_VT(&varAttrib) = VT_EMPTY;
|
|
|
|
if (SUCCEEDED(pElement->getAttribute(bstrAttribName, FALSE, &varAttrib)) &&
|
|
(V_VT(&varAttrib) == VT_BSTR) && varAttrib.bstrVal &&
|
|
(StrCmpIW(varAttrib.bstrVal, pszAttrib) == 0) )
|
|
{
|
|
// Found it!
|
|
*ppunkDesired = punk;
|
|
punk = NULL;
|
|
hr = S_OK;
|
|
|
|
// Terminate the search;
|
|
lItem = lItemCnt;
|
|
}
|
|
pElement->Release();
|
|
|
|
VariantClear(&varAttrib);
|
|
}
|
|
|
|
if (punk)
|
|
punk->Release();
|
|
}
|
|
//
|
|
// Next check for the body tag
|
|
//
|
|
else if (SUCCEEDED(pDispItem->QueryInterface(IID_PPV_ARG(IHTMLBodyElement,&pBodyElement))))
|
|
{
|
|
// Found a body tag, so terminate the search
|
|
lItem = lItemCnt;
|
|
pBodyElement->Release();
|
|
}
|
|
//
|
|
// Finally, check for a frameset tag
|
|
//
|
|
else if (SUCCEEDED(pDispItem->QueryInterface(IID_PPV_ARG(IHTMLFrameSetElement, &pFrameSetElement))))
|
|
{
|
|
// Found a frameset tag, so terminate the search
|
|
lItem = lItemCnt;
|
|
pFrameSetElement->Release();
|
|
}
|
|
|
|
pDispItem->Release();
|
|
}
|
|
}
|
|
// Make sure that these don't have to be cleared (should not have been modified)
|
|
ASSERT(vEmpty.vt == VT_EMPTY);
|
|
ASSERT(vIndex.vt == VT_I4);
|
|
|
|
pAllCollection->Release();
|
|
}
|
|
|
|
SysFreeString(bstrAttribName);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
// JITCoCreateInstance
|
|
//
|
|
// This function makes sure that the Option pack which
|
|
// has this class id is installed.
|
|
// It attempts to make sure that the Option pack corresponding
|
|
// to the current IE Build.
|
|
// If the feature does get installed correctly, it will
|
|
// attempt to CoCreate the specified CLSID
|
|
//
|
|
//+------------------------------------------------------------------
|
|
HRESULT JITCoCreateInstance(REFCLSID rclsid, IUnknown *pUnkOuter, DWORD dwClsContext, REFIID riid, void ** ppv, HWND hwndParent, DWORD dwJitFlags)
|
|
{
|
|
uCLSSPEC ucs;
|
|
QUERYCONTEXT qc = { 0 };
|
|
ucs.tyspec = TYSPEC_CLSID;
|
|
ucs.tagged_union.clsid = rclsid;
|
|
|
|
ASSERT((dwJitFlags & ~(FIEF_FLAG_FORCE_JITUI | FIEF_FLAG_PEEK)) == 0);
|
|
|
|
HRESULT hr = FaultInIEFeature(hwndParent, &ucs, &qc, dwJitFlags);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
BOOL IsFeaturePotentiallyAvailable(REFCLSID rclsid)
|
|
{
|
|
uCLSSPEC ucs;
|
|
QUERYCONTEXT qc = { 0 };
|
|
|
|
ucs.tyspec = TYSPEC_CLSID;
|
|
ucs.tagged_union.clsid = rclsid;
|
|
|
|
return (FaultInIEFeature(NULL, &ucs, &qc, FIEF_FLAG_FORCE_JITUI | FIEF_FLAG_PEEK) != E_ACCESSDENIED);
|
|
}
|
|
|
|
BOOL CreateFromDesktop(PNEWFOLDERINFO pfi)
|
|
{
|
|
//
|
|
// APPCOMPAT:HACKHACK - we need to handle differences in the way we parse the command line
|
|
// on IE4 integrated. we should not be called by anybody but IE4's Explorer.exe
|
|
//
|
|
ASSERT(GetUIVersion() == 4);
|
|
if (!pfi->pidl)
|
|
{
|
|
if ((pfi->uFlags & (COF_ROOTCLASS | COF_NEWROOT)) || pfi->pidlRoot)
|
|
{
|
|
pfi->pidl = ILRootedCreateIDList(pfi->uFlags & COF_ROOTCLASS ? &pfi->clsid : NULL, pfi->pidlRoot);
|
|
pfi->uFlags &= ~(COF_ROOTCLASS | COF_NEWROOT);
|
|
ILFree(pfi->pidlRoot);
|
|
pfi->pidlRoot = NULL;
|
|
pfi->clsid = CLSID_NULL;
|
|
}
|
|
else if (!PathIsURLA(pfi->pszPath))
|
|
{
|
|
CHAR szTemp[MAX_PATH];
|
|
GetCurrentDirectoryA(ARRAYSIZE(szTemp), szTemp);
|
|
PathCombineA(szTemp, szTemp, pfi->pszPath);
|
|
Str_SetPtrA(&(pfi->pszPath), szTemp);
|
|
}
|
|
}
|
|
|
|
ASSERT(!(pfi->uFlags & (COF_ROOTCLASS | COF_NEWROOT)));
|
|
|
|
return SHCreateFromDesktop(pfi);
|
|
}
|
|
|
|
//*** IsVK_TABCycler -- is key a TAB-equivalent
|
|
// ENTRY/EXIT
|
|
// dir 0 if not a TAB, non-0 if a TAB
|
|
// NOTES
|
|
// NYI: -1 for shift+tab, 1 for tab
|
|
//
|
|
int IsVK_TABCycler(MSG *pMsg)
|
|
{
|
|
if (!pMsg)
|
|
return 0;
|
|
|
|
if (pMsg->message != WM_KEYDOWN)
|
|
return 0;
|
|
if (! (pMsg->wParam == VK_TAB || pMsg->wParam == VK_F6))
|
|
return 0;
|
|
|
|
return (GetKeyState(VK_SHIFT) < 0) ? -1 : 1;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
//
|
|
// This function fully fills the input buffer, trashing stuff so we fault
|
|
// when the size is wrong :-)
|
|
//
|
|
// We should hopefully catch people passing buffers that are too small here by
|
|
// having a reproable stack corruption.
|
|
//
|
|
#define CH_BADCHARA ((CHAR)0xCC)
|
|
#define CH_BADCHARW ((WCHAR)0xCCCC)
|
|
|
|
#ifdef UNICODE
|
|
#define CH_BADCHAR CH_BADCHARW
|
|
#else // UNICODE
|
|
#define CH_BADCHAR CH_BADCHARA
|
|
#endif // UNICODE
|
|
|
|
void DebugFillInputString(LPTSTR pszBuffer, DWORD cchSize)
|
|
{
|
|
while (cchSize--)
|
|
{
|
|
pszBuffer[0] = CH_BADCHAR;
|
|
pszBuffer++;
|
|
}
|
|
}
|
|
|
|
void DebugFillInputStringA(LPSTR pszBuffer, DWORD cchSize)
|
|
{
|
|
while (cchSize--)
|
|
{
|
|
pszBuffer[0] = CH_BADCHARA;
|
|
pszBuffer++;
|
|
}
|
|
}
|
|
|
|
|
|
#endif // DEBUG
|
|
|
|
// Review chrisny: this can be moved into an object easily to handle generic droptarget, dropcursor
|
|
// , autoscrool, etc. . .
|
|
void _DragEnter(HWND hwndTarget, const POINTL ptStart, IDataObject *pdtObject)
|
|
{
|
|
RECT rc;
|
|
POINT pt;
|
|
|
|
GetWindowRect(hwndTarget, &rc);
|
|
if (IS_WINDOW_RTL_MIRRORED(hwndTarget))
|
|
pt.x = rc.right - ptStart.x;
|
|
else
|
|
pt.x = ptStart.x - rc.left;
|
|
pt.y = ptStart.y - rc.top;
|
|
DAD_DragEnterEx2(hwndTarget, pt, pdtObject);
|
|
return;
|
|
}
|
|
|
|
void _DragMove(HWND hwndTarget, const POINTL ptStart)
|
|
{
|
|
RECT rc;
|
|
POINT pt;
|
|
|
|
GetWindowRect(hwndTarget, &rc);
|
|
if (IS_WINDOW_RTL_MIRRORED(hwndTarget))
|
|
pt.x = rc.right - ptStart.x;
|
|
else
|
|
pt.x = ptStart.x - rc.left;
|
|
pt.y = ptStart.y - rc.top;
|
|
DAD_DragMove(pt);
|
|
return;
|
|
}
|
|
|
|
STDAPI_(IBindCtx *) CreateBindCtxForUI(IUnknown * punkSite)
|
|
{
|
|
IBindCtx * pbc = NULL;
|
|
|
|
if (EVAL(punkSite && SUCCEEDED(CreateBindCtx(0, &pbc))))
|
|
{
|
|
if (FAILED(pbc->RegisterObjectParam(STR_DISPLAY_UI_DURING_BINDING, punkSite)))
|
|
{
|
|
// It failed
|
|
ATOMICRELEASE(pbc);
|
|
}
|
|
}
|
|
|
|
return pbc;
|
|
}
|
|
|
|
//
|
|
// Return the location of the internet cache
|
|
// HRESULT GetCacheLocation(
|
|
// dwSize no. of chars in pszCacheLocation
|
|
|
|
STDAPI GetCacheLocation(LPTSTR pszCacheLocation, DWORD dwSize)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwLastErr;
|
|
LPINTERNET_CACHE_CONFIG_INFO lpCCI = NULL; // init to suppress bogus C4701 warning
|
|
DWORD dwCCISize = sizeof(INTERNET_CACHE_CONFIG_INFO);
|
|
BOOL fOnceErrored = FALSE;
|
|
|
|
while (TRUE)
|
|
{
|
|
if ((lpCCI = (LPINTERNET_CACHE_CONFIG_INFO) LocalAlloc(LPTR,
|
|
dwCCISize)) == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto cleanup;
|
|
}
|
|
|
|
if (!GetUrlCacheConfigInfo(lpCCI, &dwCCISize,
|
|
CACHE_CONFIG_CONTENT_PATHS_FC))
|
|
{
|
|
if ((dwLastErr = GetLastError()) != ERROR_INSUFFICIENT_BUFFER ||
|
|
fOnceErrored)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(dwLastErr);
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// We have insufficient buffer size; reallocate a buffer with the
|
|
// new dwCCISize set by GetUrlCacheConfigInfo
|
|
// Set fOnceErrored to TRUE so that we don't loop indefinitely
|
|
//
|
|
fOnceErrored = TRUE;
|
|
}
|
|
else
|
|
{
|
|
LPTSTR pszPath = lpCCI->CachePaths[0].CachePath;
|
|
INT iLen;
|
|
|
|
PathRemoveBackslash(pszPath);
|
|
iLen = lstrlen(pszPath) + 1; // + 1 is for the null char
|
|
|
|
if ((DWORD) iLen < dwSize)
|
|
{
|
|
StrCpyN(pszCacheLocation, pszPath, iLen);
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
LocalFree(lpCCI);
|
|
lpCCI = NULL;
|
|
}
|
|
|
|
cleanup:
|
|
if (lpCCI != NULL)
|
|
{
|
|
LocalFree(lpCCI);
|
|
lpCCI = NULL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDAPI_(UINT) GetWheelMsg()
|
|
{
|
|
static UINT s_msgMSWheel = 0;
|
|
if (s_msgMSWheel == 0)
|
|
s_msgMSWheel = RegisterWindowMessage(TEXT("MSWHEEL_ROLLMSG"));
|
|
return s_msgMSWheel;
|
|
}
|
|
|
|
STDAPI StringToStrRet(LPCTSTR pString, STRRET *pstrret)
|
|
{
|
|
HRESULT hr = SHStrDup(pString, &pstrret->pOleStr);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
pstrret->uType = STRRET_WSTR;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
// these two functions are duplicated from browseui
|
|
HINSTANCE GetComctl32Hinst()
|
|
{
|
|
static HINSTANCE s_hinst = NULL;
|
|
if (!s_hinst)
|
|
s_hinst = GetModuleHandle(TEXT("comctl32.dll"));
|
|
return s_hinst;
|
|
}
|
|
|
|
// since we don't define the proper WINVER we do this ourselves
|
|
#ifndef IDC_HAND
|
|
#define IDC_HAND MAKEINTRESOURCE(32649)
|
|
#endif
|
|
|
|
STDAPI_(HCURSOR) LoadHandCursor(DWORD dwRes)
|
|
{
|
|
if (g_bRunOnNT5 || g_bRunOnMemphis)
|
|
{
|
|
HCURSOR hcur = LoadCursor(NULL, IDC_HAND); // from USER, system supplied
|
|
if (hcur)
|
|
return hcur;
|
|
}
|
|
return LoadCursor(GetComctl32Hinst(), IDC_HAND_INTERNAL);
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Returns true if this type of url may not be available when offline unless
|
|
// it is cached by wininet
|
|
//--------------------------------------------------------------------------
|
|
BOOL MayBeUnavailableOffline(LPTSTR pszUrl)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
URL_COMPONENTS uc = {0};
|
|
uc.dwStructSize = sizeof(uc);
|
|
|
|
if (SUCCEEDED(InternetCrackUrl(pszUrl, 0, 0, &uc)))
|
|
{
|
|
fRet = uc.nScheme == INTERNET_SCHEME_HTTP ||
|
|
uc.nScheme == INTERNET_SCHEME_HTTPS ||
|
|
uc.nScheme == INTERNET_SCHEME_FTP ||
|
|
uc.nScheme == INTERNET_SCHEME_GOPHER;
|
|
}
|
|
return fRet;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// If the folder is a link, the associated URL is returned.
|
|
//--------------------------------------------------------------------------
|
|
HRESULT GetNavTargetName(IShellFolder* psf, LPCITEMIDLIST pidl, LPTSTR pszUrl, UINT cMaxChars)
|
|
{
|
|
LPITEMIDLIST pidlTarget;
|
|
HRESULT hr = SHGetNavigateTarget(psf, pidl, &pidlTarget, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Get the URL
|
|
// NOTE (andrewgu): ie5.5 b#109391 - if SHGDN_FORPARSING is used the result will be
|
|
// consitently the fully qualified path regardless of the protocol
|
|
hr = IEGetNameAndFlags(pidlTarget, SHGDN_FORPARSING, pszUrl, cMaxChars, NULL);
|
|
ILFree(pidlTarget);
|
|
}
|
|
else
|
|
*pszUrl = 0;
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Returns info about whether this item is available offline. Returns E_FAIL
|
|
// if the item is not a link.
|
|
// if we navigate to this item
|
|
// (true if we're online, items in the cache or otherwise available)
|
|
// if item is a sticky cache entry
|
|
//--------------------------------------------------------------------------
|
|
// FEATURE: this should use an interface to bind to this information abstractly
|
|
// psf->GetUIObjectOf(IID_IAvailablility, ...);
|
|
HRESULT GetLinkInfo(IShellFolder* psf, LPCITEMIDLIST pidlItem, BOOL* pfAvailable, BOOL* pfSticky)
|
|
{
|
|
if (pfAvailable)
|
|
*pfAvailable = TRUE;
|
|
|
|
if (pfSticky)
|
|
*pfSticky = FALSE;
|
|
//
|
|
// See if it is a link. If it is not, then it can't be in the wininet cache and can't
|
|
// be pinned (sticky cache entry) or greyed (unavailable when offline)
|
|
//
|
|
WCHAR szUrl[MAX_URL_STRING];
|
|
DWORD dwFlags = 0;
|
|
|
|
HRESULT hr = GetNavTargetName(psf, pidlItem, szUrl, ARRAYSIZE(szUrl));
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
CHAR szUrlAnsi[MAX_URL_STRING];
|
|
|
|
//
|
|
// Get the cache info for this item. Note that we use GetUrlCacheEntryInfoEx instead
|
|
// of GetUrlCacheEntryInfo because it follows any redirects that occured. This wacky
|
|
// api uses a variable length buffer, so we have to guess the size and retry if the
|
|
// call fails.
|
|
//
|
|
BOOL fInCache = FALSE;
|
|
WCHAR szBuf[512];
|
|
LPINTERNET_CACHE_ENTRY_INFOA pCE = (LPINTERNET_CACHE_ENTRY_INFOA)szBuf;
|
|
DWORD dwEntrySize = ARRAYSIZE(szBuf);
|
|
|
|
SHTCharToAnsi(szUrl, szUrlAnsi, ARRAYSIZE(szUrlAnsi));
|
|
if (!(fInCache = GetUrlCacheEntryInfoExA(szUrlAnsi, pCE, &dwEntrySize, NULL, NULL, NULL, 0)))
|
|
{
|
|
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
// We guessed too small for the buffer so allocate the correct size & retry
|
|
pCE = (LPINTERNET_CACHE_ENTRY_INFOA)LocalAlloc(LPTR, dwEntrySize);
|
|
if (pCE)
|
|
{
|
|
fInCache = GetUrlCacheEntryInfoExA(szUrlAnsi, pCE, &dwEntrySize, NULL, NULL, NULL, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we are offline, see if the item is in the cache.
|
|
//
|
|
if (pfAvailable && SHIsGlobalOffline() && MayBeUnavailableOffline(szUrl) && !fInCache)
|
|
{
|
|
// Not available
|
|
*pfAvailable = FALSE;
|
|
}
|
|
|
|
//
|
|
// See if it's a sticky cache entry
|
|
//
|
|
if (pCE)
|
|
{
|
|
if (pfSticky && fInCache && (pCE->CacheEntryType & STICKY_CACHE_ENTRY))
|
|
{
|
|
*pfSticky = TRUE;
|
|
}
|
|
|
|
if ((TCHAR*)pCE != szBuf)
|
|
{
|
|
LocalFree(pCE);
|
|
pCE = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Somebody is obviously interested in in the offline availability so listen
|
|
// to wininet for changes to the cache and rebroadcast as a SHChangeNotify
|
|
//
|
|
CWinInetNotify::GlobalEnable();
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Get the avg char width given an hwnd
|
|
//
|
|
|
|
int GetAvgCharWidth(HWND hwnd)
|
|
{
|
|
ASSERT(hwnd);
|
|
|
|
int nWidth = 0;
|
|
|
|
HFONT hfont = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0);
|
|
|
|
if (hfont)
|
|
{
|
|
HDC hdc = GetDC(NULL);
|
|
|
|
if (hdc)
|
|
{
|
|
HFONT hfontOld = (HFONT)SelectObject(hdc, hfont);
|
|
|
|
TEXTMETRIC tm;
|
|
|
|
if (GetTextMetrics(hdc, &tm))
|
|
nWidth = tm.tmAveCharWidth;
|
|
|
|
SelectObject(hdc, hfontOld);
|
|
|
|
ReleaseDC(NULL, hdc);
|
|
}
|
|
}
|
|
|
|
return nWidth;
|
|
}
|
|
|
|
//
|
|
// Converts all "&" into "&&" so that they show up
|
|
// in menus
|
|
//
|
|
void FixAmpersands(LPWSTR pszToFix, UINT cchMax)
|
|
{
|
|
ASSERT(pszToFix && cchMax > 0);
|
|
|
|
WCHAR szBuf[MAX_URL_STRING];
|
|
LPWSTR pszBuf = szBuf;
|
|
LPWSTR pszSrc = pszToFix;
|
|
UINT cch = 0;
|
|
|
|
while (*pszSrc && cch < ARRAYSIZE(szBuf)-2)
|
|
{
|
|
if (*pszSrc == '&')
|
|
{
|
|
*pszBuf++ = '&';
|
|
++cch;
|
|
}
|
|
*pszBuf++ = *pszSrc++;
|
|
++cch;
|
|
}
|
|
*pszBuf = 0;
|
|
|
|
StrCpyN(pszToFix, szBuf, cchMax);
|
|
}
|
|
|
|
BOOL IsInetcplRestricted(LPCWSTR pszCommand)
|
|
{
|
|
BOOL fDisabled = FALSE;
|
|
DWORD dwData, dwType;
|
|
DWORD dwSize = sizeof(dwData);
|
|
|
|
if (ERROR_SUCCESS == SHRegGetUSValue(TEXT("Software\\Policies\\Microsoft\\Internet Explorer\\Control Panel"),
|
|
pszCommand, &dwType, (void *)&dwData, &dwSize, FALSE, NULL, 0))
|
|
{
|
|
fDisabled = dwData;
|
|
}
|
|
return fDisabled;
|
|
}
|
|
|
|
BOOL HasExtendedChar(LPCWSTR pszQuery)
|
|
{
|
|
BOOL fNonAscii = FALSE;
|
|
for (LPCWSTR psz = pszQuery; *psz; psz++)
|
|
{
|
|
if (*psz > 0x7f)
|
|
{
|
|
fNonAscii = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
return fNonAscii;
|
|
}
|
|
|
|
void ConvertToUtf8Escaped(LPWSTR pszUrl, int cch)
|
|
{
|
|
// Convert to utf8
|
|
char szBuf[MAX_URL_STRING];
|
|
SHUnicodeToAnsiCP(CP_UTF8, pszUrl, szBuf, ARRAYSIZE(szBuf));
|
|
|
|
// Escape the string into the original buffer
|
|
LPSTR pchIn;
|
|
LPWSTR pchOut = pszUrl;
|
|
WCHAR ch;
|
|
static const WCHAR hex[] = L"0123456789ABCDEF";
|
|
|
|
for (pchIn = szBuf; *pchIn && cch > 3; pchIn++)
|
|
{
|
|
ch = *pchIn;
|
|
|
|
if (ch > 0x7f)
|
|
{
|
|
cch -= 3;
|
|
*pchOut++ = L'%';
|
|
*pchOut++ = hex[(ch >> 4) & 15];
|
|
*pchOut++ = hex[ch & 15];
|
|
}
|
|
else
|
|
{
|
|
--cch;
|
|
*pchOut++ = *pchIn;
|
|
}
|
|
}
|
|
|
|
*pchOut = L'\0';
|
|
}
|
|
|
|
|
|
|
|
|
|
HRESULT IExtractIcon_GetIconLocation(
|
|
IUnknown *punk,
|
|
IN UINT uInFlags,
|
|
OUT LPTSTR pszIconFile,
|
|
IN UINT cchIconFile,
|
|
OUT PINT pniIcon,
|
|
OUT PUINT puOutFlags)
|
|
{
|
|
ASSERT(punk);
|
|
HRESULT hr;
|
|
|
|
if (g_fRunningOnNT)
|
|
{
|
|
IExtractIcon *pxi;
|
|
hr = punk->QueryInterface(IID_PPV_ARG(IExtractIcon, &pxi));
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pxi->GetIconLocation(uInFlags, pszIconFile, cchIconFile, pniIcon, puOutFlags);
|
|
|
|
pxi->Release();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
IExtractIconA *pxi;
|
|
hr = punk->QueryInterface(IID_PPV_ARG(IExtractIconA, &pxi));
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
CHAR sz[MAX_PATH];
|
|
hr = pxi->GetIconLocation(uInFlags, sz, SIZECHARS(sz), pniIcon, puOutFlags);
|
|
|
|
if (SUCCEEDED(hr))
|
|
SHAnsiToTChar(sz, pszIconFile, cchIconFile);
|
|
|
|
pxi->Release();
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT IExtractIcon_Extract(
|
|
IUnknown *punk,
|
|
IN LPCTSTR pszIconFile,
|
|
IN UINT iIcon,
|
|
OUT HICON * phiconLarge,
|
|
OUT HICON * phiconSmall,
|
|
IN UINT ucIconSize)
|
|
{
|
|
ASSERT(punk);
|
|
HRESULT hr;
|
|
|
|
if (g_fRunningOnNT)
|
|
{
|
|
IExtractIcon *pxi;
|
|
hr = punk->QueryInterface(IID_PPV_ARG(IExtractIcon, &pxi));
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pxi->Extract(pszIconFile, iIcon, phiconLarge, phiconSmall, ucIconSize);
|
|
|
|
pxi->Release();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
IExtractIconA *pxi;
|
|
hr = punk->QueryInterface(IID_PPV_ARG(IExtractIconA, &pxi));
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
CHAR sz[MAX_PATH];
|
|
SHTCharToAnsi(pszIconFile, sz, SIZECHARS(sz));
|
|
hr = pxi->Extract(sz, iIcon, phiconLarge, phiconSmall, ucIconSize);
|
|
|
|
pxi->Release();
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
typedef EXECUTION_STATE (__stdcall *PFNSTES) (EXECUTION_STATE);
|
|
|
|
EXECUTION_STATE _SetThreadExecutionState(EXECUTION_STATE esFlags)
|
|
{
|
|
static PFNSTES _pfnSetThreadExecutionState = (PFNSTES)-1;
|
|
|
|
if (_pfnSetThreadExecutionState == (PFNSTES)-1)
|
|
_pfnSetThreadExecutionState = (PFNSTES)GetProcAddress(GetModuleHandleA("kernel32.dll"), "SetThreadExecutionState");
|
|
|
|
if (_pfnSetThreadExecutionState != (PFNSTES)NULL)
|
|
return(_pfnSetThreadExecutionState(esFlags));
|
|
else
|
|
return((EXECUTION_STATE)NULL);
|
|
}
|
|
|
|
|
|
HRESULT SHPathPrepareForWriteWrap(HWND hwnd, IUnknown *punkEnableModless, LPCTSTR pszPath, UINT wFunc, DWORD dwFlags)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (g_bRunOnNT5)
|
|
{
|
|
// NT5's version of the API is better.
|
|
hr = SHPathPrepareForWriteW(hwnd, punkEnableModless, pszPath, dwFlags);
|
|
}
|
|
else
|
|
{
|
|
hr = SHCheckDiskForMedia(hwnd, punkEnableModless, pszPath, wFunc);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
void GetPathOtherFormA(LPSTR lpszPath, LPSTR lpszNewPath, DWORD dwSize)
|
|
{
|
|
BOOL bQuotes = FALSE;
|
|
LPSTR szStart = lpszPath;
|
|
LPSTR szEnd = NULL;
|
|
LPSTR szNewStart = lpszNewPath;
|
|
|
|
ZeroMemory(lpszNewPath, dwSize);
|
|
|
|
// Cull out the starting and ending " because GetShortPathName does not
|
|
// like it.
|
|
if (*lpszPath == '"')
|
|
{
|
|
bQuotes = TRUE;
|
|
|
|
szStart = lpszPath + 1;
|
|
szEnd = lpszPath + lstrlenA(lpszPath) - 1; // Point to the last "
|
|
*szEnd = '\0';
|
|
|
|
szNewStart = lpszNewPath + 1; // So that we can insert the " in it.
|
|
dwSize = dwSize - 2; // for the two double quotes to be added.
|
|
}
|
|
|
|
if (GetShortPathNameA(szStart, szNewStart, dwSize) != 0)
|
|
{
|
|
if (StrCmpIA(szStart, szNewStart) == 0)
|
|
{ // The original Path is a SFN. So NewPath needs to be LFN.
|
|
GetLongPathNameA((LPCSTR)szStart, szNewStart, dwSize);
|
|
}
|
|
}
|
|
|
|
// Now add the " to the NewPath so that it is in the expected form
|
|
if (bQuotes)
|
|
{
|
|
int len = 0;
|
|
|
|
// Fix the Original path.
|
|
*szEnd = '"';
|
|
|
|
// Fix the New path.
|
|
*lpszNewPath = '"'; // Insert " in the beginning.
|
|
len = lstrlenA(lpszNewPath);
|
|
*(lpszNewPath + len) = '"'; // Add the " in the end.
|
|
*(lpszNewPath + len + 1) = '\0'; // Terminate the string.
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
int GetUrlSchemeFromPidl(LPCITEMIDLIST pidl)
|
|
{
|
|
ASSERT(pidl);
|
|
ASSERT(IsURLChild(pidl, FALSE));
|
|
|
|
int nRet = URL_SCHEME_INVALID;
|
|
|
|
WCHAR szUrl[MAX_URL_STRING];
|
|
|
|
if (SUCCEEDED(IEGetNameAndFlags(pidl, SHGDN_FORPARSING, szUrl,
|
|
ARRAYSIZE(szUrl), NULL)))
|
|
{
|
|
nRet = GetUrlScheme(szUrl);
|
|
}
|
|
|
|
return nRet;
|
|
}
|
|
|
|
//
|
|
// Check if it is safe to create a shortcut for the given url. Used by add
|
|
// to favorites code.
|
|
//
|
|
BOOL IEIsLinkSafe(HWND hwnd, LPCITEMIDLIST pidl, ILS_ACTION ilsFlag)
|
|
{
|
|
ASSERT(pidl);
|
|
|
|
BOOL fRet = TRUE;
|
|
|
|
if (IsURLChild(pidl, FALSE))
|
|
{
|
|
int nScheme = GetUrlSchemeFromPidl(pidl);
|
|
|
|
if (URL_SCHEME_JAVASCRIPT == nScheme || URL_SCHEME_VBSCRIPT == nScheme)
|
|
{
|
|
WCHAR szTitle[MAX_PATH];
|
|
WCHAR szText[MAX_PATH];
|
|
|
|
MLLoadString(IDS_SECURITYALERT, szTitle, ARRAYSIZE(szTitle));
|
|
MLLoadString(IDS_ADDTOFAV_WARNING + ilsFlag, szText,
|
|
ARRAYSIZE(szText));
|
|
|
|
ULONG_PTR uCookie = 0;
|
|
SHActivateContext(&uCookie);
|
|
fRet = (IDYES == MLShellMessageBox(hwnd, szText, szTitle, MB_YESNO |
|
|
MB_ICONWARNING | MB_APPLMODAL |
|
|
MB_DEFBUTTON2));
|
|
if (uCookie)
|
|
{
|
|
SHDeactivateContext(uCookie);
|
|
}
|
|
}
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
HRESULT GetSearchStyle(IServiceProvider * psp, LPDWORD pdwSearchStyle)
|
|
{
|
|
RIP(pdwSearchStyle != NULL);
|
|
|
|
HRESULT hr = E_FAIL;
|
|
|
|
// first see if there is an ISearchContext to get this information from
|
|
if (psp != NULL)
|
|
{
|
|
ISearchContext * pSC = NULL;
|
|
hr = psp->QueryService(SID_STopWindow, IID_PPV_ARG(ISearchContext, &pSC));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
RIP(pSC != NULL);
|
|
|
|
hr = pSC->GetSearchStyle(pdwSearchStyle);
|
|
pSC->Release();
|
|
}
|
|
}
|
|
|
|
// there wasn't a viable search context, so try the reg key
|
|
if (FAILED(hr))
|
|
{
|
|
DWORD dwType;
|
|
DWORD dwAutoSearch;
|
|
DWORD cb = sizeof(dwAutoSearch);
|
|
|
|
if (ERROR_SUCCESS == SHRegGetUSValue(REGSTR_PATH_MAIN, L"AutoSearch", &dwType, &dwAutoSearch, &cb, FALSE, NULL, 0))
|
|
{
|
|
*pdwSearchStyle = dwAutoSearch;
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
// return a default value
|
|
if (FAILED(hr))
|
|
{
|
|
hr = S_FALSE;
|
|
|
|
// Default to "display results in search pane and go to most likely site"
|
|
*pdwSearchStyle = 3;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
BOOL AccessAllowed(LPCWSTR pwszURL1, LPCWSTR pwszURL2)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
IInternetSecurityManager *pSecMgr = NULL;
|
|
|
|
if (pwszURL1 && pwszURL2 && SUCCEEDED(CoCreateInstance(CLSID_InternetSecurityManager,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_PPV_ARG(IInternetSecurityManager, &pSecMgr))))
|
|
{
|
|
BYTE reqSid[MAX_SIZE_SECURITY_ID], docSid[MAX_SIZE_SECURITY_ID];
|
|
DWORD cbReqSid = ARRAYSIZE(reqSid);
|
|
DWORD cbDocSid = ARRAYSIZE(docSid);
|
|
|
|
if ( SUCCEEDED(pSecMgr->GetSecurityId(pwszURL1, reqSid, &cbReqSid, 0))
|
|
&& SUCCEEDED(pSecMgr->GetSecurityId(pwszURL2, docSid, &cbDocSid, 0))
|
|
&& (cbReqSid == cbDocSid)
|
|
&& (memcmp(reqSid, docSid, cbReqSid) == 0))
|
|
{
|
|
fRet = TRUE;
|
|
}
|
|
pSecMgr->Release();
|
|
}
|
|
return fRet;
|
|
}
|
|
|
|
BOOL IsFrameWindow(IHTMLWindow2 * pHTMLWindow)
|
|
{
|
|
BOOL fIsFrame = FALSE;
|
|
|
|
HRESULT hr = E_FAIL;
|
|
|
|
IHTMLWindow2 * pParentWindow = NULL;
|
|
IHTMLWindow2 * pSelfWindow = NULL;
|
|
|
|
ASSERT(pHTMLWindow);
|
|
|
|
hr = pHTMLWindow->get_self(&pSelfWindow);
|
|
|
|
if (FAILED(hr) || (pSelfWindow == NULL))
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
hr = pHTMLWindow->get_parent(&pParentWindow);
|
|
|
|
if (FAILED(hr) || (pParentWindow == NULL))
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
if (!IsSameObject(pSelfWindow, pParentWindow))
|
|
{
|
|
fIsFrame = TRUE;
|
|
}
|
|
|
|
cleanup:
|
|
|
|
if (pSelfWindow)
|
|
{
|
|
pSelfWindow->Release();
|
|
}
|
|
|
|
if (pParentWindow)
|
|
{
|
|
pParentWindow->Release();
|
|
}
|
|
|
|
return fIsFrame;
|
|
}
|
|
|
|
// For compatability with the Win2k debug SHELL32.DLL, this function needs to exist at ordinal 161.
|
|
// It's fine for it to return FALSE.
|
|
STDAPI_(BOOL) GetLeakDetectionFunctionTable(void *pTable)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
STDAPI_(BOOL) IsCSIDLFolder(UINT csidl, LPCITEMIDLIST pidl)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
TCHAR szPath[MAX_PATH];
|
|
if (SUCCEEDED(SHGetFolderPathD(NULL, csidl, NULL, 0, szPath)))
|
|
{
|
|
PathRemoveBackslash(szPath); // some platforms return version with slash on the end
|
|
TCHAR szFolder[MAX_PATH];
|
|
if (SUCCEEDED(SHGetNameAndFlags(pidl, SHGDN_FORPARSING, szFolder, ARRAYSIZE(szFolder), NULL)))
|
|
{
|
|
bRet = (StrCmpI(szFolder, szPath) == 0);
|
|
}
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
// Determines if the classic toolbar strips should be used, or the new
|
|
// Whistler toolbar strips.
|
|
//
|
|
// To use the new Whistler strips, the user must be running Whistler or later
|
|
// and have a display with greater than 256 colors.
|
|
|
|
STDAPI_(BOOL) SHUseClassicToolbarGlyphs (void)
|
|
{
|
|
BOOL bRet = TRUE;
|
|
|
|
if (SHGetCurColorRes() > 8)
|
|
{
|
|
if (GetUIVersion() > 5)
|
|
{
|
|
bRet = FALSE;
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|