urlmon: Add basic implementation of MapBrowserEmulationModeToUserAgent.

This is necessary for mshtml's navigator userAgent to work properly, since
some apps expect it.

The second argument seems to be output pointer that gets allocated (by
CoTaskMemAlloc, or something compatible with it), but the first argument
seems to be a pointer to an unknown struct, which makes it almost impossible
to guess reliably what it does by just inspecting its behavior...

Thankfully, it seems only the first DWORD field is necessary for
this. Changing it returns the user agent for that given mode, if the rest
is zeros.

Signed-off-by: Gabriel Ivăncescu <gabrielopcode@gmail.com>
Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Gabriel Ivăncescu 2022-04-11 18:58:47 +03:00 committed by Alexandre Julliard
parent d4a2f4d44b
commit 735ac6eb8f
4 changed files with 98 additions and 11 deletions

View File

@ -504,6 +504,7 @@ static BOOL get_url_encoding(HKEY root, DWORD *encoding)
}
static LPWSTR user_agent;
static BOOL user_agent_set;
static size_t obtain_user_agent(unsigned int version, WCHAR *ret, size_t size)
{
@ -710,6 +711,7 @@ HRESULT WINAPI UrlMkSetSessionOption(DWORD dwOption, LPVOID pBuffer, DWORD dwBuf
heap_free(user_agent);
user_agent = new_user_agent;
user_agent_set = TRUE;
update_user_agent(user_agent);
LeaveCriticalSection(&session_cs);
@ -748,6 +750,44 @@ HRESULT WINAPI ObtainUserAgentString(DWORD option, char *ret, DWORD *ret_size)
return hres;
}
/***********************************************************************
* MapBrowserEmulationModeToUserAgent (URLMON.445)
* Undocumented, added in IE8
*/
HRESULT WINAPI MapBrowserEmulationModeToUserAgent(const void *arg, WCHAR **ret)
{
DWORD size, version;
const WCHAR *ua;
WCHAR buf[1024];
TRACE("%p %p: semi-stub\n", arg, ret);
if(user_agent_set) {
/* Native ignores first arg if custom user agent has been set, doesn't crash even if NULL */
size = (wcslen(user_agent) + 1) * sizeof(WCHAR);
ua = user_agent;
}else {
*ret = NULL;
/* First arg seems to be a pointer to a structure of unknown size, and crashes
if it's too small (or filled with arbitrary values from the stack). For our
purposes, we only check first field which seems to be the requested version. */
version = *(DWORD*)arg;
if(version == 5)
version = 7;
if(version < 7 || version > 11)
return E_FAIL;
size = obtain_user_agent(version, buf, ARRAY_SIZE(buf)) * sizeof(WCHAR);
ua = buf;
}
if(!(*ret = CoTaskMemAlloc(size)))
return E_OUTOFMEMORY;
memcpy(*ret, ua, size);
return S_OK;
}
void free_session(void)
{
name_space *ns_iter, *ns_last;

View File

@ -83,6 +83,7 @@ static HRESULT (WINAPI *pCompareSecurityIds)(BYTE*,DWORD,BYTE*,DWORD,DWORD);
static HRESULT (WINAPI *pCoInternetIsFeatureEnabled)(INTERNETFEATURELIST,DWORD);
static HRESULT (WINAPI *pCoInternetSetFeatureEnabled)(INTERNETFEATURELIST,DWORD,BOOL);
static HRESULT (WINAPI *pIEInstallScope)(DWORD*);
static HRESULT (WINAPI *pMapBrowserEmulationModeToUserAgent)(const void*,WCHAR**);
static WCHAR *a2co(const char *str)
{
@ -2721,6 +2722,59 @@ static void test_bsc_marshaling(void)
TerminateThread(thread, 0);
}
static void test_MapBrowserEmulationModeToUserAgent(BOOL custom_ua)
{
/* Undocumented structure of unknown size, crashes if it's too small (with arbitrary values from stack) */
struct
{
DWORD version;
char unknown[252];
} arg;
static char test_str[] = "test";
const char *custom_ua_msg = "";
HRESULT hres;
unsigned i;
WCHAR *ua;
if(!pMapBrowserEmulationModeToUserAgent) {
win_skip("MapBrowserEmulationModeToUserAgent not available\n");
return;
}
memset(&arg, 0, sizeof(arg));
if(custom_ua) {
hres = UrlMkSetSessionOption(URLMON_OPTION_USERAGENT, test_str, sizeof(test_str), 0);
ok(hres == S_OK, "UrlMkSetSessionOption failed: %08lx\n", hres);
custom_ua_msg = " (with custom ua)";
}
for(i = 0; i < 12; i++) {
arg.version = i;
ua = (WCHAR*)0xdeadbeef;
hres = pMapBrowserEmulationModeToUserAgent(&arg, &ua);
ok(hres == (i == 5 || i >= 7 || custom_ua ? S_OK : E_FAIL),
"[%u] MapBrowserEmulationModeToUserAgent%s returned %08lx\n", i, custom_ua_msg, hres);
if(hres != S_OK)
ok(ua == NULL, "[%u] ua%s = %p\n", i, custom_ua_msg, ua);
else {
char buf[1024];
DWORD size = sizeof(buf);
WCHAR *ua2;
if(custom_ua)
ua2 = a2co(test_str);
else {
hres = pObtainUserAgentString(i, buf, &size);
ok(hres == S_OK, "[%u] ObtainUserAgentString%s failed: %08lx\n", i, custom_ua_msg, hres);
ua2 = a2co(buf);
}
ok(!lstrcmpW(ua, ua2), "[%u] ua%s = %s, expected %s\n", i, custom_ua_msg, wine_dbgstr_w(ua), wine_dbgstr_w(ua2));
CoTaskMemFree(ua2);
CoTaskMemFree(ua);
}
}
}
START_TEST(misc)
{
HMODULE hurlmon;
@ -2745,6 +2799,7 @@ START_TEST(misc)
pCoInternetIsFeatureEnabled = (void*) GetProcAddress(hurlmon, "CoInternetIsFeatureEnabled");
pCoInternetSetFeatureEnabled = (void*) GetProcAddress(hurlmon, "CoInternetSetFeatureEnabled");
pIEInstallScope = (void*) GetProcAddress(hurlmon, "IEInstallScope");
pMapBrowserEmulationModeToUserAgent = (void*) GetProcAddress(hurlmon, (const char*)445);
if (!pCoInternetCompareUrl || !pCoInternetGetSecurityUrl ||
!pCoInternetGetSession || !pCoInternetParseUrl || !pCompareSecurityIds) {
@ -2757,6 +2812,7 @@ START_TEST(misc)
if(argc <= 2 || strcmp(argv[2], "internet_features")) {
register_protocols();
test_MapBrowserEmulationModeToUserAgent(FALSE);
test_CreateFormatEnum();
test_RegisterFormatEnumerator();
test_CoInternetParseUrl();
@ -2773,6 +2829,7 @@ START_TEST(misc)
test_MkParseDisplayNameEx();
test_IsValidURL();
test_bsc_marshaling();
test_MapBrowserEmulationModeToUserAgent(TRUE);
}
test_internet_features();

View File

@ -110,6 +110,6 @@
410 stdcall @(long long) LogSqmBits
423 stdcall @(long long long long) LogSqmUXCommandOffsetInternal
444 stdcall @(long long long) MapUriToBrowserEmulationState
445 stdcall @(long long) MapBrowserEmulationModeToUserAgent
445 stdcall @(ptr ptr) MapBrowserEmulationModeToUserAgent
446 stdcall @(long) CoInternetGetBrowserProfile
455 stdcall @() FlushUrlmonZonesCache

View File

@ -791,16 +791,6 @@ int WINAPI MapUriToBrowserEmulationState(DWORD unk1, DWORD unk2, DWORD unk3)
return 0;
}
/***********************************************************************
* MapBrowserEmulationModeToUserAgent (URLMON.445)
* Undocumented, added in IE8
*/
int WINAPI MapBrowserEmulationModeToUserAgent(DWORD unk1, DWORD unk2)
{
FIXME("stub: %ld %ld\n", unk1, unk2);
return 0;
}
/***********************************************************************
* CoInternetGetBrowserProfile (URLMON.446)
* Undocumented, added in IE8