1 /* 2 * Unit tests for misc shdocvw functions 3 * 4 * Copyright 2008 Detlef Riekenberg 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 22 #include <stdarg.h> 23 24 #include "windef.h" 25 #include "winbase.h" 26 #include "winreg.h" 27 #include "wininet.h" 28 #include "winnls.h" 29 30 #include "wine/test.h" 31 32 /* ################ */ 33 34 static HMODULE hshdocvw; 35 static HRESULT (WINAPI *pURLSubRegQueryA)(LPCSTR, LPCSTR, DWORD, LPVOID, DWORD, DWORD); 36 static DWORD (WINAPI *pParseURLFromOutsideSourceA)(LPCSTR, LPSTR, LPDWORD, LPDWORD); 37 static DWORD (WINAPI *pParseURLFromOutsideSourceW)(LPCWSTR, LPWSTR, LPDWORD, LPDWORD); 38 39 static const char appdata[] = "AppData"; 40 static const char common_appdata[] = "Common AppData"; 41 static const char default_page_url[] = "Default_Page_URL"; 42 static const char does_not_exist[] = "does_not_exist"; 43 static const char regpath_iemain[] = "Software\\Microsoft\\Internet Explorer\\Main"; 44 static const char regpath_shellfolders[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"; 45 static const char start_page[] = "Start Page"; 46 47 /* ################ */ 48 49 static const struct { 50 const char *url; 51 const char *newurl; 52 DWORD len; 53 } ParseURL_table[] = { 54 {"http://www.winehq.org", "http://www.winehq.org/", 22}, 55 {"www.winehq.org", "http://www.winehq.org/", 22}, 56 {"winehq.org", "http://winehq.org/", 18}, 57 {"ftp.winehq.org", "ftp://ftp.winehq.org/", 21}, 58 {"http://winehq.org", "http://winehq.org/", 18}, 59 {"https://winehq.org", "https://winehq.org/", 19}, 60 {"https://www.winehq.org", "https://www.winehq.org/", 23}, 61 {"ftp://winehq.org", "ftp://winehq.org/", 17}, 62 {"ftp://ftp.winehq.org", "ftp://ftp.winehq.org/", 21}, 63 {"about:blank", "about:blank", 11}, 64 {"about:home", "about:home", 10}, 65 {"about:mozilla", "about:mozilla", 13}, 66 /* a space at the start is not allowed */ 67 {" http://www.winehq.org", "http://%20http://www.winehq.org", 31} 68 69 }; 70 71 /* ################ */ 72 73 static void init_functions(void) 74 { 75 hshdocvw = LoadLibraryA("shdocvw.dll"); 76 pURLSubRegQueryA = (void *) GetProcAddress(hshdocvw, (LPSTR) 151); 77 pParseURLFromOutsideSourceA = (void *) GetProcAddress(hshdocvw, (LPSTR) 169); 78 pParseURLFromOutsideSourceW = (void *) GetProcAddress(hshdocvw, (LPSTR) 170); 79 } 80 81 /* ################ */ 82 83 static void test_URLSubRegQueryA(void) 84 { 85 CHAR buffer[INTERNET_MAX_URL_LENGTH]; 86 HRESULT hr; 87 DWORD used; 88 DWORD len; 89 90 if (!pURLSubRegQueryA) { 91 skip("URLSubRegQueryA not found\n"); 92 return; 93 } 94 95 memset(buffer, '#', sizeof(buffer)-1); 96 buffer[sizeof(buffer)-1] = '\0'; 97 /* called by inetcpl.cpl */ 98 hr = pURLSubRegQueryA(regpath_iemain, default_page_url, REG_SZ, buffer, INTERNET_MAX_URL_LENGTH, -1); 99 ok(hr == E_FAIL || hr == S_OK, "got 0x%x (expected E_FAIL or S_OK)\n", hr); 100 101 memset(buffer, '#', sizeof(buffer)-1); 102 buffer[sizeof(buffer)-1] = '\0'; 103 /* called by inetcpl.cpl */ 104 hr = pURLSubRegQueryA(regpath_iemain, start_page, REG_SZ, buffer, INTERNET_MAX_URL_LENGTH, -1); 105 len = lstrlenA(buffer); 106 /* respect privacy: do not dump the url */ 107 ok(hr == S_OK, "got 0x%x and %d (expected S_OK)\n", hr, len); 108 109 /* test buffer length: just large enough */ 110 memset(buffer, '#', sizeof(buffer)-1); 111 buffer[sizeof(buffer)-1] = '\0'; 112 hr = pURLSubRegQueryA(regpath_iemain, start_page, REG_SZ, buffer, len+1, -1); 113 used = lstrlenA(buffer); 114 /* respect privacy: do not dump the url */ 115 ok((hr == S_OK) && (used == len), 116 "got 0x%x and %d (expected S_OK and %d)\n", hr, used, len); 117 118 /* no space for terminating 0: result is truncated */ 119 memset(buffer, '#', sizeof(buffer)-1); 120 buffer[sizeof(buffer)-1] = '\0'; 121 hr = pURLSubRegQueryA(regpath_iemain, start_page, REG_SZ, buffer, len, -1); 122 used = lstrlenA(buffer); 123 ok((hr == S_OK) && (used == len - 1), 124 "got 0x%x and %d (expected S_OK and %d)\n", hr, used, len - 1); 125 126 /* no space for the complete result: truncate another char */ 127 if (len > 1) { 128 memset(buffer, '#', sizeof(buffer)-1); 129 buffer[sizeof(buffer)-1] = '\0'; 130 hr = pURLSubRegQueryA(regpath_iemain, start_page, REG_SZ, buffer, len-1, -1); 131 used = lstrlenA(buffer); 132 ok((hr == S_OK) && (used == (len - 2)), 133 "got 0x%x and %d (expected S_OK and %d)\n", hr, used, len - 2); 134 } 135 136 /* only space for the terminating 0: function still succeeded */ 137 memset(buffer, '#', sizeof(buffer)-1); 138 buffer[sizeof(buffer)-1] = '\0'; 139 hr = pURLSubRegQueryA(regpath_iemain, start_page, REG_SZ, buffer, 1, -1); 140 used = lstrlenA(buffer); 141 ok((hr == S_OK) && !used, 142 "got 0x%x and %d (expected S_OK and 0)\n", hr, used); 143 144 /* size of buffer is 0, but the function still succeed. 145 buffer[0] is cleared in IE 5.01 and IE 5.5 (Buffer Overflow) */ 146 memset(buffer, '#', sizeof(buffer)-1); 147 buffer[sizeof(buffer)-1] = '\0'; 148 hr = pURLSubRegQueryA(regpath_iemain, start_page, REG_SZ, buffer, 0, -1); 149 used = lstrlenA(buffer); 150 ok( (hr == S_OK) && 151 ((used == INTERNET_MAX_URL_LENGTH - 1) || broken(used == 0)) , 152 "got 0x%x and %d (expected S_OK and INTERNET_MAX_URL_LENGTH - 1)\n", 153 hr, used); 154 155 /* still succeed without a buffer for the result */ 156 hr = pURLSubRegQueryA(regpath_iemain, start_page, REG_SZ, NULL, 0, -1); 157 ok(hr == S_OK, "got 0x%x (expected S_OK)\n", hr); 158 159 /* still succeed, when a length is given without a buffer */ 160 hr = pURLSubRegQueryA(regpath_iemain, start_page, REG_SZ, NULL, INTERNET_MAX_URL_LENGTH, -1); 161 ok(hr == S_OK, "got 0x%x (expected S_OK)\n", hr); 162 163 /* this value does not exist */ 164 memset(buffer, '#', sizeof(buffer)-1); 165 buffer[sizeof(buffer)-1] = '\0'; 166 hr = pURLSubRegQueryA(regpath_iemain, does_not_exist, REG_SZ, buffer, INTERNET_MAX_URL_LENGTH, -1); 167 /* random bytes are copied to the buffer */ 168 ok((hr == E_FAIL), "got 0x%x (expected E_FAIL)\n", hr); 169 170 /* the third parameter is ignored. Is it really a type? (data is REG_SZ) */ 171 memset(buffer, '#', sizeof(buffer)-1); 172 buffer[sizeof(buffer)-1] = '\0'; 173 hr = pURLSubRegQueryA(regpath_iemain, start_page, REG_DWORD, buffer, INTERNET_MAX_URL_LENGTH, -1); 174 used = lstrlenA(buffer); 175 ok((hr == S_OK) && (used == len), 176 "got 0x%x and %d (expected S_OK and %d)\n", hr, used, len); 177 178 /* the function works for HKCU and HKLM */ 179 memset(buffer, '#', sizeof(buffer)-1); 180 buffer[sizeof(buffer)-1] = '\0'; 181 hr = pURLSubRegQueryA(regpath_shellfolders, appdata, REG_SZ, buffer, INTERNET_MAX_URL_LENGTH, -1); 182 used = lstrlenA(buffer); 183 ok(hr == S_OK, "got 0x%x and %d (expected S_OK)\n", hr, used); 184 185 memset(buffer, '#', sizeof(buffer)-1); 186 buffer[sizeof(buffer)-1] = '\0'; 187 hr = pURLSubRegQueryA(regpath_shellfolders, common_appdata, REG_SZ, buffer, INTERNET_MAX_URL_LENGTH, -1); 188 used = lstrlenA(buffer); 189 ok(hr == S_OK, "got 0x%x and %d (expected S_OK)\n", hr, used); 190 191 /* todo: what does the last parameter mean? */ 192 } 193 194 /* ################ */ 195 196 static void test_ParseURLFromOutsideSourceA(void) 197 { 198 CHAR buffer[INTERNET_MAX_URL_LENGTH]; 199 DWORD dummy; 200 DWORD maxlen; 201 DWORD len; 202 DWORD res; 203 int i; 204 205 if (!pParseURLFromOutsideSourceA) { 206 skip("ParseURLFromOutsideSourceA not found\n"); 207 return; 208 } 209 210 for(i = 0; i < ARRAY_SIZE(ParseURL_table); i++) { 211 memset(buffer, '#', sizeof(buffer)-1); 212 buffer[sizeof(buffer)-1] = '\0'; 213 len = sizeof(buffer); 214 dummy = 0; 215 /* on success, string size including terminating 0 is returned for ansi version */ 216 res = pParseURLFromOutsideSourceA(ParseURL_table[i].url, buffer, &len, &dummy); 217 /* len does not include the terminating 0, when buffer is large enough */ 218 ok( res == (ParseURL_table[i].len+1) && len == ParseURL_table[i].len && 219 !lstrcmpA(buffer, ParseURL_table[i].newurl), 220 "#%d: got %d and %d with '%s' (expected %d and %d with '%s')\n", 221 i, res, len, buffer, ParseURL_table[i].len+1, ParseURL_table[i].len, ParseURL_table[i].newurl); 222 223 224 /* use the size test only for the first examples */ 225 if (i > 4) continue; 226 227 maxlen = len; 228 229 memset(buffer, '#', sizeof(buffer)-1); 230 buffer[sizeof(buffer)-1] = '\0'; 231 len = maxlen + 1; 232 dummy = 0; 233 res = pParseURLFromOutsideSourceA(ParseURL_table[i].url, buffer, &len, &dummy); 234 ok( res != 0 && len == ParseURL_table[i].len && 235 !lstrcmpA(buffer, ParseURL_table[i].newurl), 236 "#%d (+1): got %d and %d with '%s' (expected '!=0' and %d with '%s')\n", 237 i, res, len, buffer, ParseURL_table[i].len, ParseURL_table[i].newurl); 238 239 memset(buffer, '#', sizeof(buffer)-1); 240 buffer[sizeof(buffer)-1] = '\0'; 241 len = maxlen; 242 dummy = 0; 243 res = pParseURLFromOutsideSourceA(ParseURL_table[i].url, buffer, &len, &dummy); 244 /* len includes the terminating 0, when the buffer is too small */ 245 ok( res == 0 && len == ParseURL_table[i].len + 1, 246 "#%d (==): got %d and %d (expected '0' and %d)\n", 247 i, res, len, ParseURL_table[i].len + 1); 248 249 memset(buffer, '#', sizeof(buffer)-1); 250 buffer[sizeof(buffer)-1] = '\0'; 251 len = maxlen-1; 252 dummy = 0; 253 res = pParseURLFromOutsideSourceA(ParseURL_table[i].url, buffer, &len, &dummy); 254 /* len includes the terminating 0 on XP SP1 and before, when the buffer is too small */ 255 ok( res == 0 && (len == ParseURL_table[i].len || len == ParseURL_table[i].len + 1), 256 "#%d (-1): got %d and %d (expected '0' and %d or %d)\n", 257 i, res, len, ParseURL_table[i].len, ParseURL_table[i].len + 1); 258 259 memset(buffer, '#', sizeof(buffer)-1); 260 buffer[sizeof(buffer)-1] = '\0'; 261 len = maxlen+1; 262 dummy = 0; 263 res = pParseURLFromOutsideSourceA(ParseURL_table[i].url, NULL, &len, &dummy); 264 /* len does not include the terminating 0, when buffer is NULL */ 265 ok( res == 0 && len == ParseURL_table[i].len, 266 "#%d (buffer): got %d and %d (expected '0' and %d)\n", 267 i, res, len, ParseURL_table[i].len); 268 269 if (0) { 270 /* that test crash on native shdocvw */ 271 pParseURLFromOutsideSourceA(ParseURL_table[i].url, buffer, NULL, &dummy); 272 } 273 274 memset(buffer, '#', sizeof(buffer)-1); 275 buffer[sizeof(buffer)-1] = '\0'; 276 len = maxlen+1; 277 dummy = 0; 278 res = pParseURLFromOutsideSourceA(ParseURL_table[i].url, buffer, &len, NULL); 279 ok( res != 0 && len == ParseURL_table[i].len && 280 !lstrcmpA(buffer, ParseURL_table[i].newurl), 281 "#%d (unknown): got %d and %d with '%s' (expected '!=0' and %d with '%s')\n", 282 i, res, len, buffer, ParseURL_table[i].len, ParseURL_table[i].newurl); 283 } 284 } 285 286 /* ################ */ 287 288 static void test_ParseURLFromOutsideSourceW(void) 289 { 290 WCHAR urlW[INTERNET_MAX_URL_LENGTH]; 291 WCHAR bufferW[INTERNET_MAX_URL_LENGTH]; 292 CHAR bufferA[INTERNET_MAX_URL_LENGTH]; 293 DWORD maxlen; 294 DWORD dummy; 295 DWORD len; 296 DWORD res; 297 298 if (!pParseURLFromOutsideSourceW) { 299 skip("ParseURLFromOutsideSourceW not found\n"); 300 return; 301 } 302 MultiByteToWideChar(CP_ACP, 0, ParseURL_table[0].url, -1, urlW, INTERNET_MAX_URL_LENGTH); 303 304 memset(bufferA, '#', sizeof(bufferA)-1); 305 bufferA[sizeof(bufferA) - 1] = '\0'; 306 MultiByteToWideChar(CP_ACP, 0, bufferA, -1, bufferW, INTERNET_MAX_URL_LENGTH); 307 308 /* len is in characters */ 309 len = ARRAY_SIZE(bufferW); 310 dummy = 0; 311 /* on success, 1 is returned for unicode version */ 312 res = pParseURLFromOutsideSourceW(urlW, bufferW, &len, &dummy); 313 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, bufferA, sizeof(bufferA), NULL, NULL); 314 ok( res == 1 && len == ParseURL_table[0].len && 315 !lstrcmpA(bufferA, ParseURL_table[0].newurl), 316 "got %d and %d with '%s' (expected 1 and %d with '%s')\n", 317 res, len, bufferA, ParseURL_table[0].len, ParseURL_table[0].newurl); 318 319 320 maxlen = len; 321 322 memset(bufferA, '#', sizeof(bufferA)-1); 323 bufferA[sizeof(bufferA) - 1] = '\0'; 324 MultiByteToWideChar(CP_ACP, 0, bufferA, -1, bufferW, INTERNET_MAX_URL_LENGTH); 325 len = maxlen+1; 326 dummy = 0; 327 res = pParseURLFromOutsideSourceW(urlW, bufferW, &len, &dummy); 328 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, bufferA, sizeof(bufferA), NULL, NULL); 329 /* len does not include the terminating 0, when buffer is large enough */ 330 ok( res != 0 && len == ParseURL_table[0].len && 331 !lstrcmpA(bufferA, ParseURL_table[0].newurl), 332 "+1: got %d and %d with '%s' (expected '!=0' and %d with '%s')\n", 333 res, len, bufferA, ParseURL_table[0].len, ParseURL_table[0].newurl); 334 335 len = maxlen; 336 dummy = 0; 337 res = pParseURLFromOutsideSourceW(urlW, bufferW, &len, &dummy); 338 /* len includes the terminating 0, when the buffer is too small */ 339 ok( res == 0 && len == ParseURL_table[0].len + 1, 340 "==: got %d and %d (expected '0' and %d)\n", 341 res, len, ParseURL_table[0].len + 1); 342 343 len = maxlen - 1; 344 dummy = 0; 345 res = pParseURLFromOutsideSourceW(urlW, bufferW, &len, &dummy); 346 /* len includes the terminating 0 on XP SP1 and before, when the buffer is too small */ 347 ok( res == 0 && (len == ParseURL_table[0].len || len == ParseURL_table[0].len + 1), 348 "-1: got %d and %d (expected '0' and %d or %d)\n", 349 res, len, ParseURL_table[0].len, ParseURL_table[0].len + 1); 350 351 } 352 353 /* ################ */ 354 355 START_TEST(shdocvw) 356 { 357 init_functions(); 358 test_URLSubRegQueryA(); 359 test_ParseURLFromOutsideSourceA(); 360 test_ParseURLFromOutsideSourceW(); 361 FreeLibrary(hshdocvw); 362 } 363