[PATCH 1/3] urlmon: Add basic implementation of MapBrowserEmulationModeToUserAgent.

Gabriel Ivăncescu gabrielopcode at gmail.com
Fri Apr 8 09:35:50 CDT 2022


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 at gmail.com>
---

Unfortunately I was not able to find a public structure that starts with
such a field in urlmon.

Sending these to get some feedback if there's a better way...

 dlls/urlmon/session.c     | 40 +++++++++++++++++++++++++++++
 dlls/urlmon/tests/misc.c  | 53 +++++++++++++++++++++++++++++++++++++++
 dlls/urlmon/urlmon.spec   |  2 +-
 dlls/urlmon/urlmon_main.c | 10 --------
 4 files changed, 94 insertions(+), 11 deletions(-)

diff --git a/dlls/urlmon/session.c b/dlls/urlmon/session.c
index 052444d..671d74d 100644
--- a/dlls/urlmon/session.c
+++ b/dlls/urlmon/session.c
@@ -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];
+
+    FIXME("%p %p\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;
diff --git a/dlls/urlmon/tests/misc.c b/dlls/urlmon/tests/misc.c
index 0575a43..72b3442 100644
--- a/dlls/urlmon/tests/misc.c
+++ b/dlls/urlmon/tests/misc.c
@@ -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,55 @@ 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 random 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),
+           "[%d] MapBrowserEmulationModeToUserAgent%s returned %08lx\n", i, custom_ua_msg, hres);
+        if(hres != S_OK)
+            ok(ua == NULL, "[%d] ua%s = %p\n", i, custom_ua_msg, ua);
+        else {
+            char buf[1024];
+            DWORD size = sizeof(buf);
+            WCHAR *ua2;
+
+            hres = pObtainUserAgentString(custom_ua ? 0 : i, buf, &size);
+            ok(hres == S_OK, "[%d] ObtainUserAgentString%s failed: %08lx\n", i, custom_ua_msg, hres);
+            ua2 = a2co(buf);
+            ok(!lstrcmpW(ua, ua2), "[%d] 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 +2795,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 +2808,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 +2825,7 @@ START_TEST(misc)
         test_MkParseDisplayNameEx();
         test_IsValidURL();
         test_bsc_marshaling();
+        test_MapBrowserEmulationModeToUserAgent(TRUE);
     }
 
     test_internet_features();
diff --git a/dlls/urlmon/urlmon.spec b/dlls/urlmon/urlmon.spec
index ea3cd38..2fda69e 100644
--- a/dlls/urlmon/urlmon.spec
+++ b/dlls/urlmon/urlmon.spec
@@ -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
diff --git a/dlls/urlmon/urlmon_main.c b/dlls/urlmon/urlmon_main.c
index b540313..56c2257 100644
--- a/dlls/urlmon/urlmon_main.c
+++ b/dlls/urlmon/urlmon_main.c
@@ -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
-- 
2.34.1




More information about the wine-devel mailing list