304 lines
9.4 KiB
C++
304 lines
9.4 KiB
C++
|
#include "priv.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#include "objidl.h"
|
||
|
#include "urlmon.h"
|
||
|
#include "exdisp.h" // IWebBrowserApp
|
||
|
#include "shlobj.h" // IShellBrowser
|
||
|
#include "inetreg.h"
|
||
|
#include <mlang.h>
|
||
|
|
||
|
// Internal helper functions
|
||
|
HRESULT wrap_CreateFormatEnumerator( UINT cfmtetc, FORMATETC* rgfmtetc, IEnumFORMATETC** ppenumfmtetc);
|
||
|
HRESULT wrap_RegisterFormatEnumerator(LPBC pBC, IEnumFORMATETC *pEFetc, DWORD reserved);
|
||
|
STDAPI common_GetAcceptLanguages(CHAR *psz, LPDWORD pcch);
|
||
|
|
||
|
#define SETFMTETC(p, a) {(p)->cfFormat = (a); \
|
||
|
(p)->dwAspect = DVASPECT_CONTENT; \
|
||
|
(p)->lindex = -1; \
|
||
|
(p)->tymed = TYMED_ISTREAM; \
|
||
|
(p)->ptd = NULL;}
|
||
|
|
||
|
const SA_BSTRGUID s_sstrEFM = {
|
||
|
38 * sizeof(WCHAR),
|
||
|
L"{D0FCA420-D3F5-11CF-B211-00AA004AE837}"
|
||
|
};
|
||
|
|
||
|
|
||
|
STDAPI CreateDefaultAcceptHeaders(VARIANT* pvar, IWebBrowserApp* pdie)
|
||
|
{
|
||
|
IEnumFORMATETC* pEFM;
|
||
|
HKEY hkey;
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
if (RegOpenKey(HKEY_LOCAL_MACHINE,
|
||
|
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Accepted Documents"),
|
||
|
&hkey) == ERROR_SUCCESS)
|
||
|
{
|
||
|
DWORD iValue = 0;
|
||
|
DWORD iValidEntries = 0;
|
||
|
TCHAR szValueName[128];
|
||
|
DWORD cchValueName = ARRAYSIZE(szValueName);
|
||
|
DWORD dwType;
|
||
|
|
||
|
// Count the types in the registry
|
||
|
while (RegEnumValue(hkey, iValue++, szValueName, &cchValueName,
|
||
|
NULL, &dwType, NULL, NULL)==ERROR_SUCCESS)
|
||
|
{
|
||
|
// purpose is to increment iValue
|
||
|
cchValueName = ARRAYSIZE(szValueName);
|
||
|
}
|
||
|
|
||
|
// Previous loop ends +1, so no need to add +1 for CF_NULL
|
||
|
|
||
|
FORMATETC *prgfmtetc = (FORMATETC *)LocalAlloc(LPTR, iValue * sizeof(FORMATETC));
|
||
|
if (prgfmtetc)
|
||
|
{
|
||
|
FORMATETC *pcurfmtetc = prgfmtetc;
|
||
|
for (DWORD nValue=0; SUCCEEDED(hr) && (nValue < (iValue -1)); nValue++)
|
||
|
{
|
||
|
TCHAR szFormatName[128];
|
||
|
DWORD cchFormatName = ARRAYSIZE(szFormatName);
|
||
|
|
||
|
cchValueName = ARRAYSIZE(szValueName);
|
||
|
if (RegEnumValue(hkey, nValue, szValueName, &cchValueName, NULL,
|
||
|
&dwType, (LPBYTE) szFormatName, &cchFormatName)==ERROR_SUCCESS)
|
||
|
{
|
||
|
pcurfmtetc->cfFormat = (CLIPFORMAT) RegisterClipboardFormat(szFormatName);
|
||
|
if (pcurfmtetc->cfFormat)
|
||
|
{
|
||
|
SETFMTETC (pcurfmtetc, pcurfmtetc->cfFormat);
|
||
|
pcurfmtetc++; // move to next fmtetc
|
||
|
iValidEntries++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||
|
}
|
||
|
} // if RegEnum
|
||
|
} // for nValue
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// for the last pcurfmtetc, we fill in for CF_NULL
|
||
|
// no need to do RegisterClipboardFormat("*/*")
|
||
|
SETFMTETC(pcurfmtetc, CF_NULL);
|
||
|
iValidEntries++;
|
||
|
|
||
|
hr = wrap_CreateFormatEnumerator (iValidEntries, prgfmtetc, &pEFM);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
ASSERT(pvar->vt == VT_EMPTY);
|
||
|
pvar->vt = VT_UNKNOWN;
|
||
|
pvar->punkVal = (IUnknown *)pEFM;
|
||
|
hr = pdie->PutProperty((BSTR)s_sstrEFM.wsz, *pvar);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
pEFM->Release(); // if we failed to pass ownership on, free EFM
|
||
|
pvar->vt = VT_EMPTY;
|
||
|
pvar->punkVal = NULL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LocalFree (prgfmtetc);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
RegCloseKey(hkey);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DebugMsg(TF_ERROR, TEXT("RegOpenkey failed!"));
|
||
|
hr = E_FAIL;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
STDAPI RegisterDefaultAcceptHeaders(IBindCtx* pbc, LPSHELLBROWSER psb)
|
||
|
{
|
||
|
IEnumFORMATETC* pEFM;
|
||
|
IWebBrowserApp* pdie;
|
||
|
|
||
|
ASSERT(pbc);
|
||
|
ASSERT(psb);
|
||
|
HRESULT hres = IUnknown_QueryService(psb, IID_IWebBrowserApp, IID_IWebBrowserApp, (LPVOID*)&pdie);
|
||
|
if (SUCCEEDED(hres))
|
||
|
{
|
||
|
VARIANT var;
|
||
|
hres = pdie->GetProperty((BSTR)s_sstrEFM.wsz, &var);
|
||
|
if (SUCCEEDED(hres))
|
||
|
{
|
||
|
if (var.vt == VT_EMPTY)
|
||
|
{
|
||
|
#ifdef FULL_DEBUG
|
||
|
DebugMsg(DM_TRACE, TEXT("RegisterDefaultAcceptHeaders var.vt == VT_EMPTY"));
|
||
|
#endif
|
||
|
CreateDefaultAcceptHeaders(&var, pdie);
|
||
|
}
|
||
|
else if (var.vt == VT_UNKNOWN)
|
||
|
{
|
||
|
#ifdef FULL_DEBUG
|
||
|
DebugMsg(DM_TRACE, TEXT("RegisterDefaultAcceptHeaders var.vt == VT_UNKNOWN"));
|
||
|
#endif
|
||
|
hres = var.punkVal->QueryInterface(IID_IEnumFORMATETC, (LPVOID*)&pEFM);
|
||
|
if (SUCCEEDED(hres)) {
|
||
|
IEnumFORMATETC* pEFMClone = NULL;
|
||
|
hres = pEFM->Clone(&pEFMClone);
|
||
|
if (SUCCEEDED(hres)) {
|
||
|
#ifdef FULL_DEBUG
|
||
|
DebugMsg(DM_TRACE, TEXT("RegisterDefaultAcceptHeaders registering FormatEnum %x"), pEFMClone);
|
||
|
#endif
|
||
|
hres = wrap_RegisterFormatEnumerator(pbc, pEFMClone, 0);
|
||
|
pEFMClone->Release();
|
||
|
} else {
|
||
|
DebugMsg(TF_ERROR, TEXT("RegisterDefaultAcceptHeaders Clone failed %x"), hres);
|
||
|
}
|
||
|
pEFM->Release();
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DebugMsg(TF_ERROR, TEXT("GetProperty() returned illegal Variant Type: %x"), var.vt);
|
||
|
DebugMsg(TF_ERROR, TEXT("RegisterDefaultAcceptHeaders not registering FormatEnum"));
|
||
|
}
|
||
|
|
||
|
VariantClear(&var);
|
||
|
} else {
|
||
|
DebugMsg(TF_ERROR, TEXT("RegisterDefaultAcceptHeaders pdie->GetProperty() failed %x"), hres);
|
||
|
}
|
||
|
|
||
|
pdie->Release();
|
||
|
} else {
|
||
|
DebugMsg(TF_ERROR, TEXT("RegisterDefaultAcceptHeaders QueryService(ISP) failed %x"), hres);
|
||
|
}
|
||
|
|
||
|
return hres;
|
||
|
} // RegisterDefaultAcceptHeaders
|
||
|
|
||
|
STDAPI GetAcceptLanguagesA(LPSTR pszLanguages, LPDWORD pcchLanguages)
|
||
|
{
|
||
|
return common_GetAcceptLanguages(pszLanguages, pcchLanguages);
|
||
|
} // GetAcceptLanguagesA
|
||
|
|
||
|
STDAPI GetAcceptLanguagesW(LPWSTR pwzLanguages, LPDWORD pcchLanguages)
|
||
|
{
|
||
|
if (!pwzLanguages || !pcchLanguages || !*pcchLanguages)
|
||
|
return E_FAIL;
|
||
|
|
||
|
DWORD dwcchMaxOut = *pcchLanguages;
|
||
|
|
||
|
LPSTR psz = (LPSTR) LocalAlloc (LPTR, dwcchMaxOut);
|
||
|
if (!psz)
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
HRESULT hr = common_GetAcceptLanguages(psz, &dwcchMaxOut);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
*pcchLanguages = MultiByteToWideChar(CP_ACP, 0, psz, -1,
|
||
|
pwzLanguages, *pcchLanguages - 1);
|
||
|
|
||
|
pwzLanguages[*pcchLanguages] = 0;
|
||
|
}
|
||
|
|
||
|
LocalFree(psz);
|
||
|
return hr;
|
||
|
} // GetAcceptLanguagesW
|
||
|
|
||
|
STDAPI common_GetAcceptLanguages(CHAR *psz, LPDWORD pcch)
|
||
|
{
|
||
|
HKEY hk;
|
||
|
HRESULT hr = E_FAIL;
|
||
|
|
||
|
if (!psz || !pcch || !*pcch)
|
||
|
return hr;
|
||
|
|
||
|
if ((RegOpenKey (HKEY_CURRENT_USER, REGSTR_PATH_INTERNATIONAL, &hk) == ERROR_SUCCESS) && hk)
|
||
|
{
|
||
|
DWORD dwType;
|
||
|
|
||
|
if (RegQueryValueEx (hk, REGSTR_VAL_ACCEPT_LANGUAGE, NULL, &dwType, (UCHAR *)psz, pcch) != ERROR_SUCCESS)
|
||
|
{
|
||
|
|
||
|
// When there is no AcceptLanguage key, we have to default
|
||
|
DWORD LCID = GetUserDefaultLCID();
|
||
|
|
||
|
// Use MLang for RFC1766 language name
|
||
|
hr = LcidToRfc1766A(LCID, psz, *pcch);
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
*pcch = lstrlenA(psz);
|
||
|
else
|
||
|
{
|
||
|
*pcch = 0;
|
||
|
AssertMsg(FALSE, TEXT("We should add LCID 0x%lx to MLang RFC1766 table"), LCID);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = S_OK;
|
||
|
if (!*psz)
|
||
|
{
|
||
|
// A NULL AcceptLanguage means send no A-L: header
|
||
|
hr = S_FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
RegCloseKey (hk);
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
} // w_GetAcceptLanguages
|
||
|
|
||
|
|
||
|
//
|
||
|
// Both of these functions will be called only once per browser session - the
|
||
|
// first time we create the FormatEnumerator. After that, we will use the one
|
||
|
// we created, rather than needing to call these to allocate a new one.
|
||
|
//
|
||
|
|
||
|
HRESULT wrap_RegisterFormatEnumerator(LPBC pBC, IEnumFORMATETC *pEFetc, DWORD reserved)
|
||
|
{
|
||
|
HRESULT hr = E_FAIL;
|
||
|
HINSTANCE hurl = LoadLibrary(TEXT("URLMON.DLL"));
|
||
|
if (hurl)
|
||
|
{
|
||
|
HRESULT (*pfnRFE)(LPBC pBC, IEnumFORMATETC * pEFetc, DWORD reserved);
|
||
|
|
||
|
pfnRFE = (HRESULT (*)(LPBC, IEnumFORMATETC*, DWORD))GetProcAddress (hurl, "RegisterFormatEnumerator");
|
||
|
if (pfnRFE)
|
||
|
{
|
||
|
hr = pfnRFE(pBC, pEFetc, reserved);
|
||
|
}
|
||
|
|
||
|
FreeLibrary(hurl);
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT wrap_CreateFormatEnumerator(UINT cfmtetc, FORMATETC* rgfmtetc, IEnumFORMATETC** ppenumfmtetc)
|
||
|
{
|
||
|
HRESULT hr = E_FAIL;
|
||
|
HINSTANCE hurl = LoadLibrary(TEXT("URLMON.DLL"));
|
||
|
if (hurl)
|
||
|
{
|
||
|
HRESULT (*pfnCFE)(UINT cfmtetc, FORMATETC* rgfmtetc, IEnumFORMATETC **ppenumfmtetc);
|
||
|
|
||
|
pfnCFE = (HRESULT (*)(UINT, FORMATETC*, IEnumFORMATETC **))GetProcAddress (hurl, "CreateFormatEnumerator");
|
||
|
if (pfnCFE)
|
||
|
{
|
||
|
hr = pfnCFE(cfmtetc, rgfmtetc, ppenumfmtetc);
|
||
|
}
|
||
|
|
||
|
FreeLibrary(hurl);
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|