xref: /reactos/dll/win32/urlmon/session.c (revision 6c3c2e33)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * Copyright 2005-2006 Jacek Caban for CodeWeavers
3c2c66affSColin Finck  *
4c2c66affSColin Finck  * This library is free software; you can redistribute it and/or
5c2c66affSColin Finck  * modify it under the terms of the GNU Lesser General Public
6c2c66affSColin Finck  * License as published by the Free Software Foundation; either
7c2c66affSColin Finck  * version 2.1 of the License, or (at your option) any later version.
8c2c66affSColin Finck  *
9c2c66affSColin Finck  * This library is distributed in the hope that it will be useful,
10c2c66affSColin Finck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11c2c66affSColin Finck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12c2c66affSColin Finck  * Lesser General Public License for more details.
13c2c66affSColin Finck  *
14c2c66affSColin Finck  * You should have received a copy of the GNU Lesser General Public
15c2c66affSColin Finck  * License along with this library; if not, write to the Free Software
16c2c66affSColin Finck  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17c2c66affSColin Finck  */
18c2c66affSColin Finck 
19c2c66affSColin Finck #include "urlmon_main.h"
20143d4fdbSAmine Khaldi #include "winreg.h"
21143d4fdbSAmine Khaldi 
22143d4fdbSAmine Khaldi #include "wine/debug.h"
23143d4fdbSAmine Khaldi 
24143d4fdbSAmine Khaldi WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
25c2c66affSColin Finck 
26c2c66affSColin Finck typedef struct {
27c2c66affSColin Finck     LPWSTR protocol;
28c2c66affSColin Finck     IClassFactory *cf;
29c2c66affSColin Finck     CLSID clsid;
30c2c66affSColin Finck     BOOL urlmon;
31c2c66affSColin Finck 
32c2c66affSColin Finck     struct list entry;
33c2c66affSColin Finck } name_space;
34c2c66affSColin Finck 
35c2c66affSColin Finck typedef struct {
36c2c66affSColin Finck     IClassFactory *cf;
37c2c66affSColin Finck     CLSID clsid;
38c2c66affSColin Finck     LPWSTR mime;
39c2c66affSColin Finck 
40c2c66affSColin Finck     struct list entry;
41c2c66affSColin Finck } mime_filter;
42c2c66affSColin Finck 
43c2c66affSColin Finck static struct list name_space_list = LIST_INIT(name_space_list);
44c2c66affSColin Finck static struct list mime_filter_list = LIST_INIT(mime_filter_list);
45c2c66affSColin Finck 
46c2c66affSColin Finck static CRITICAL_SECTION session_cs;
47c2c66affSColin Finck static CRITICAL_SECTION_DEBUG session_cs_dbg =
48c2c66affSColin Finck {
49c2c66affSColin Finck     0, 0, &session_cs,
50c2c66affSColin Finck     { &session_cs_dbg.ProcessLocksList, &session_cs_dbg.ProcessLocksList },
51c2c66affSColin Finck       0, 0, { (DWORD_PTR)(__FILE__ ": session") }
52c2c66affSColin Finck };
53c2c66affSColin Finck static CRITICAL_SECTION session_cs = { &session_cs_dbg, -1, 0, 0, 0, 0 };
54c2c66affSColin Finck 
55c2c66affSColin Finck static const WCHAR internet_settings_keyW[] =
56c2c66affSColin Finck     {'S','O','F','T','W','A','R','E',
57c2c66affSColin Finck      '\\','M','i','c','r','o','s','o','f','t',
58c2c66affSColin Finck      '\\','W','i','n','d','o','w','s',
59c2c66affSColin Finck      '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n',
60c2c66affSColin Finck      '\\','I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0};
61c2c66affSColin Finck 
find_name_space(LPCWSTR protocol)62c2c66affSColin Finck static name_space *find_name_space(LPCWSTR protocol)
63c2c66affSColin Finck {
64c2c66affSColin Finck     name_space *iter;
65c2c66affSColin Finck 
66c2c66affSColin Finck     LIST_FOR_EACH_ENTRY(iter, &name_space_list, name_space, entry) {
67*6c3c2e33SAmine Khaldi         if(!wcsicmp(iter->protocol, protocol))
68c2c66affSColin Finck             return iter;
69c2c66affSColin Finck     }
70c2c66affSColin Finck 
71c2c66affSColin Finck     return NULL;
72c2c66affSColin Finck }
73c2c66affSColin Finck 
get_protocol_cf(LPCWSTR schema,DWORD schema_len,CLSID * pclsid,IClassFactory ** ret)74c2c66affSColin Finck static HRESULT get_protocol_cf(LPCWSTR schema, DWORD schema_len, CLSID *pclsid, IClassFactory **ret)
75c2c66affSColin Finck {
76c2c66affSColin Finck     WCHAR str_clsid[64];
77c2c66affSColin Finck     HKEY hkey = NULL;
78c2c66affSColin Finck     DWORD res, type, size;
79c2c66affSColin Finck     CLSID clsid;
80c2c66affSColin Finck     LPWSTR wszKey;
81c2c66affSColin Finck     HRESULT hres;
82c2c66affSColin Finck 
83c2c66affSColin Finck     static const WCHAR wszProtocolsKey[] =
84c2c66affSColin Finck         {'P','R','O','T','O','C','O','L','S','\\','H','a','n','d','l','e','r','\\'};
85c2c66affSColin Finck     static const WCHAR wszCLSID[] = {'C','L','S','I','D',0};
86c2c66affSColin Finck 
87c2c66affSColin Finck     wszKey = heap_alloc(sizeof(wszProtocolsKey)+(schema_len+1)*sizeof(WCHAR));
88c2c66affSColin Finck     memcpy(wszKey, wszProtocolsKey, sizeof(wszProtocolsKey));
89ad73c0a0SAmine Khaldi     memcpy(wszKey + ARRAY_SIZE(wszProtocolsKey), schema, (schema_len+1)*sizeof(WCHAR));
90c2c66affSColin Finck 
91c2c66affSColin Finck     res = RegOpenKeyW(HKEY_CLASSES_ROOT, wszKey, &hkey);
92c2c66affSColin Finck     heap_free(wszKey);
93c2c66affSColin Finck     if(res != ERROR_SUCCESS) {
94c2c66affSColin Finck         TRACE("Could not open protocol handler key\n");
95c2c66affSColin Finck         return MK_E_SYNTAX;
96c2c66affSColin Finck     }
97c2c66affSColin Finck 
98c2c66affSColin Finck     size = sizeof(str_clsid);
99c2c66affSColin Finck     res = RegQueryValueExW(hkey, wszCLSID, NULL, &type, (LPBYTE)str_clsid, &size);
100c2c66affSColin Finck     RegCloseKey(hkey);
101c2c66affSColin Finck     if(res != ERROR_SUCCESS || type != REG_SZ) {
102c2c66affSColin Finck         WARN("Could not get protocol CLSID res=%d\n", res);
103c2c66affSColin Finck         return MK_E_SYNTAX;
104c2c66affSColin Finck     }
105c2c66affSColin Finck 
106c2c66affSColin Finck     hres = CLSIDFromString(str_clsid, &clsid);
107c2c66affSColin Finck     if(FAILED(hres)) {
108c2c66affSColin Finck         WARN("CLSIDFromString failed: %08x\n", hres);
109c2c66affSColin Finck         return hres;
110c2c66affSColin Finck     }
111c2c66affSColin Finck 
112c2c66affSColin Finck     if(pclsid)
113c2c66affSColin Finck         *pclsid = clsid;
114c2c66affSColin Finck 
115c2c66affSColin Finck     if(!ret)
116c2c66affSColin Finck         return S_OK;
117c2c66affSColin Finck 
118c2c66affSColin Finck     hres = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IClassFactory, (void**)ret);
119c2c66affSColin Finck     return SUCCEEDED(hres) ? S_OK : MK_E_SYNTAX;
120c2c66affSColin Finck }
121c2c66affSColin Finck 
register_namespace(IClassFactory * cf,REFIID clsid,LPCWSTR protocol,BOOL urlmon_protocol)122c2c66affSColin Finck HRESULT register_namespace(IClassFactory *cf, REFIID clsid, LPCWSTR protocol, BOOL urlmon_protocol)
123c2c66affSColin Finck {
124c2c66affSColin Finck     name_space *new_name_space;
125c2c66affSColin Finck 
126c2c66affSColin Finck     new_name_space = heap_alloc(sizeof(name_space));
127c2c66affSColin Finck 
128c2c66affSColin Finck     if(!urlmon_protocol)
129c2c66affSColin Finck         IClassFactory_AddRef(cf);
130c2c66affSColin Finck     new_name_space->cf = cf;
131c2c66affSColin Finck     new_name_space->clsid = *clsid;
132c2c66affSColin Finck     new_name_space->urlmon = urlmon_protocol;
133c2c66affSColin Finck     new_name_space->protocol = heap_strdupW(protocol);
134c2c66affSColin Finck 
135c2c66affSColin Finck     EnterCriticalSection(&session_cs);
136c2c66affSColin Finck 
137c2c66affSColin Finck     list_add_head(&name_space_list, &new_name_space->entry);
138c2c66affSColin Finck 
139c2c66affSColin Finck     LeaveCriticalSection(&session_cs);
140c2c66affSColin Finck 
141c2c66affSColin Finck     return S_OK;
142c2c66affSColin Finck }
143c2c66affSColin Finck 
unregister_namespace(IClassFactory * cf,LPCWSTR protocol)144c2c66affSColin Finck static HRESULT unregister_namespace(IClassFactory *cf, LPCWSTR protocol)
145c2c66affSColin Finck {
146c2c66affSColin Finck     name_space *iter;
147c2c66affSColin Finck 
148c2c66affSColin Finck     EnterCriticalSection(&session_cs);
149c2c66affSColin Finck 
150c2c66affSColin Finck     LIST_FOR_EACH_ENTRY(iter, &name_space_list, name_space, entry) {
151*6c3c2e33SAmine Khaldi         if(iter->cf == cf && !wcsicmp(iter->protocol, protocol)) {
152c2c66affSColin Finck             list_remove(&iter->entry);
153c2c66affSColin Finck 
154c2c66affSColin Finck             LeaveCriticalSection(&session_cs);
155c2c66affSColin Finck 
156c2c66affSColin Finck             if(!iter->urlmon)
157c2c66affSColin Finck                 IClassFactory_Release(iter->cf);
158c2c66affSColin Finck             heap_free(iter->protocol);
159c2c66affSColin Finck             heap_free(iter);
160c2c66affSColin Finck             return S_OK;
161c2c66affSColin Finck         }
162c2c66affSColin Finck     }
163c2c66affSColin Finck 
164c2c66affSColin Finck     LeaveCriticalSection(&session_cs);
165c2c66affSColin Finck     return S_OK;
166c2c66affSColin Finck }
167c2c66affSColin Finck 
is_registered_protocol(LPCWSTR url)168c2c66affSColin Finck BOOL is_registered_protocol(LPCWSTR url)
169c2c66affSColin Finck {
170c2c66affSColin Finck     DWORD schema_len;
171c2c66affSColin Finck     WCHAR schema[64];
172c2c66affSColin Finck     HRESULT hres;
173c2c66affSColin Finck 
174ad73c0a0SAmine Khaldi     hres = CoInternetParseUrl(url, PARSE_SCHEMA, 0, schema, ARRAY_SIZE(schema), &schema_len, 0);
175c2c66affSColin Finck     if(FAILED(hres))
176c2c66affSColin Finck         return FALSE;
177c2c66affSColin Finck 
178c2c66affSColin Finck     return get_protocol_cf(schema, schema_len, NULL, NULL) == S_OK;
179c2c66affSColin Finck }
180c2c66affSColin Finck 
get_protocol_info(LPCWSTR url)181c2c66affSColin Finck IInternetProtocolInfo *get_protocol_info(LPCWSTR url)
182c2c66affSColin Finck {
183c2c66affSColin Finck     IInternetProtocolInfo *ret = NULL;
184c2c66affSColin Finck     IClassFactory *cf;
185c2c66affSColin Finck     name_space *ns;
186c2c66affSColin Finck     WCHAR schema[64];
187c2c66affSColin Finck     DWORD schema_len;
188c2c66affSColin Finck     HRESULT hres;
189c2c66affSColin Finck 
190ad73c0a0SAmine Khaldi     hres = CoInternetParseUrl(url, PARSE_SCHEMA, 0, schema, ARRAY_SIZE(schema), &schema_len, 0);
191c2c66affSColin Finck     if(FAILED(hres) || !schema_len)
192c2c66affSColin Finck         return NULL;
193c2c66affSColin Finck 
194c2c66affSColin Finck     EnterCriticalSection(&session_cs);
195c2c66affSColin Finck 
196c2c66affSColin Finck     ns = find_name_space(schema);
197c2c66affSColin Finck     if(ns && !ns->urlmon) {
198c2c66affSColin Finck         hres = IClassFactory_QueryInterface(ns->cf, &IID_IInternetProtocolInfo, (void**)&ret);
199c2c66affSColin Finck         if(FAILED(hres))
200c2c66affSColin Finck             hres = IClassFactory_CreateInstance(ns->cf, NULL, &IID_IInternetProtocolInfo, (void**)&ret);
201c2c66affSColin Finck     }
202c2c66affSColin Finck 
203c2c66affSColin Finck     LeaveCriticalSection(&session_cs);
204c2c66affSColin Finck 
205c2c66affSColin Finck     if(ns && SUCCEEDED(hres))
206c2c66affSColin Finck         return ret;
207c2c66affSColin Finck 
208c2c66affSColin Finck     hres = get_protocol_cf(schema, schema_len, NULL, &cf);
209c2c66affSColin Finck     if(FAILED(hres))
210c2c66affSColin Finck         return NULL;
211c2c66affSColin Finck 
212c2c66affSColin Finck     hres = IClassFactory_QueryInterface(cf, &IID_IInternetProtocolInfo, (void**)&ret);
213c2c66affSColin Finck     if(FAILED(hres))
214c2c66affSColin Finck         IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocolInfo, (void**)&ret);
215c2c66affSColin Finck     IClassFactory_Release(cf);
216c2c66affSColin Finck 
217c2c66affSColin Finck     return ret;
218c2c66affSColin Finck }
219c2c66affSColin Finck 
get_protocol_handler(IUri * uri,CLSID * clsid,IClassFactory ** ret)220d0eebfbdSAmine Khaldi HRESULT get_protocol_handler(IUri *uri, CLSID *clsid, IClassFactory **ret)
221c2c66affSColin Finck {
222c2c66affSColin Finck     name_space *ns;
223c2c66affSColin Finck     BSTR scheme;
224c2c66affSColin Finck     HRESULT hres;
225c2c66affSColin Finck 
226c2c66affSColin Finck     *ret = NULL;
227c2c66affSColin Finck 
228c2c66affSColin Finck     /* FIXME: Avoid GetSchemeName call for known schemes */
229c2c66affSColin Finck     hres = IUri_GetSchemeName(uri, &scheme);
230c2c66affSColin Finck     if(FAILED(hres))
231c2c66affSColin Finck         return hres;
232c2c66affSColin Finck 
233c2c66affSColin Finck     EnterCriticalSection(&session_cs);
234c2c66affSColin Finck 
235c2c66affSColin Finck     ns = find_name_space(scheme);
236c2c66affSColin Finck     if(ns) {
237c2c66affSColin Finck         *ret = ns->cf;
238c2c66affSColin Finck         IClassFactory_AddRef(*ret);
239c2c66affSColin Finck         if(clsid)
240c2c66affSColin Finck             *clsid = ns->clsid;
241c2c66affSColin Finck     }
242c2c66affSColin Finck 
243c2c66affSColin Finck     LeaveCriticalSection(&session_cs);
244c2c66affSColin Finck 
245d0eebfbdSAmine Khaldi     hres = *ret ? S_OK : get_protocol_cf(scheme, SysStringLen(scheme), clsid, ret);
246c2c66affSColin Finck     SysFreeString(scheme);
247c2c66affSColin Finck     return hres;
248c2c66affSColin Finck }
249c2c66affSColin Finck 
get_mime_filter(LPCWSTR mime)250c2c66affSColin Finck IInternetProtocol *get_mime_filter(LPCWSTR mime)
251c2c66affSColin Finck {
252c2c66affSColin Finck     static const WCHAR filtersW[] = {'P','r','o','t','o','c','o','l','s',
253c2c66affSColin Finck         '\\','F','i','l','t','e','r',0 };
254c2c66affSColin Finck     static const WCHAR CLSIDW[] = {'C','L','S','I','D',0};
255c2c66affSColin Finck 
256c2c66affSColin Finck     IClassFactory *cf = NULL;
257c2c66affSColin Finck     IInternetProtocol *ret;
258c2c66affSColin Finck     mime_filter *iter;
259c2c66affSColin Finck     HKEY hlist, hfilter;
260c2c66affSColin Finck     WCHAR clsidw[64];
261c2c66affSColin Finck     CLSID clsid;
262c2c66affSColin Finck     DWORD res, type, size;
263c2c66affSColin Finck     HRESULT hres;
264c2c66affSColin Finck 
265c2c66affSColin Finck     EnterCriticalSection(&session_cs);
266c2c66affSColin Finck 
267c2c66affSColin Finck     LIST_FOR_EACH_ENTRY(iter, &mime_filter_list, mime_filter, entry) {
268*6c3c2e33SAmine Khaldi         if(!wcscmp(iter->mime, mime)) {
269c2c66affSColin Finck             cf = iter->cf;
270c2c66affSColin Finck             break;
271c2c66affSColin Finck         }
272c2c66affSColin Finck     }
273c2c66affSColin Finck 
274c2c66affSColin Finck     LeaveCriticalSection(&session_cs);
275c2c66affSColin Finck 
276c2c66affSColin Finck     if(cf) {
277c2c66affSColin Finck         hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&ret);
278c2c66affSColin Finck         if(FAILED(hres)) {
279c2c66affSColin Finck             WARN("CreateInstance failed: %08x\n", hres);
280c2c66affSColin Finck             return NULL;
281c2c66affSColin Finck         }
282c2c66affSColin Finck 
283c2c66affSColin Finck         return ret;
284c2c66affSColin Finck     }
285c2c66affSColin Finck 
286c2c66affSColin Finck     res = RegOpenKeyW(HKEY_CLASSES_ROOT, filtersW, &hlist);
287c2c66affSColin Finck     if(res != ERROR_SUCCESS) {
288c2c66affSColin Finck         TRACE("Could not open MIME filters key\n");
289c2c66affSColin Finck         return NULL;
290c2c66affSColin Finck     }
291c2c66affSColin Finck 
292c2c66affSColin Finck     res = RegOpenKeyW(hlist, mime, &hfilter);
293c2c66affSColin Finck     CloseHandle(hlist);
294c2c66affSColin Finck     if(res != ERROR_SUCCESS)
295c2c66affSColin Finck         return NULL;
296c2c66affSColin Finck 
297c2c66affSColin Finck     size = sizeof(clsidw);
298c2c66affSColin Finck     res = RegQueryValueExW(hfilter, CLSIDW, NULL, &type, (LPBYTE)clsidw, &size);
299c2c66affSColin Finck     CloseHandle(hfilter);
300c2c66affSColin Finck     if(res!=ERROR_SUCCESS || type!=REG_SZ) {
301c2c66affSColin Finck         WARN("Could not get filter CLSID for %s\n", debugstr_w(mime));
302c2c66affSColin Finck         return NULL;
303c2c66affSColin Finck     }
304c2c66affSColin Finck 
305c2c66affSColin Finck     hres = CLSIDFromString(clsidw, &clsid);
306c2c66affSColin Finck     if(FAILED(hres)) {
307c2c66affSColin Finck         WARN("CLSIDFromString failed for %s (%x)\n", debugstr_w(mime), hres);
308c2c66affSColin Finck         return NULL;
309c2c66affSColin Finck     }
310c2c66affSColin Finck 
311c2c66affSColin Finck     hres = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IInternetProtocol, (void**)&ret);
312c2c66affSColin Finck     if(FAILED(hres)) {
313c2c66affSColin Finck         WARN("CoCreateInstance failed: %08x\n", hres);
314c2c66affSColin Finck         return NULL;
315c2c66affSColin Finck     }
316c2c66affSColin Finck 
317c2c66affSColin Finck     return ret;
318c2c66affSColin Finck }
319c2c66affSColin Finck 
InternetSession_QueryInterface(IInternetSession * iface,REFIID riid,void ** ppv)320c2c66affSColin Finck static HRESULT WINAPI InternetSession_QueryInterface(IInternetSession *iface,
321c2c66affSColin Finck         REFIID riid, void **ppv)
322c2c66affSColin Finck {
323c2c66affSColin Finck     TRACE("(%s %p)\n", debugstr_guid(riid), ppv);
324c2c66affSColin Finck 
325c2c66affSColin Finck     if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetSession, riid)) {
326c2c66affSColin Finck         *ppv = iface;
327c2c66affSColin Finck         IInternetSession_AddRef(iface);
328c2c66affSColin Finck         return S_OK;
329c2c66affSColin Finck     }
330c2c66affSColin Finck 
331c2c66affSColin Finck     *ppv = NULL;
332c2c66affSColin Finck     return E_NOINTERFACE;
333c2c66affSColin Finck }
334c2c66affSColin Finck 
InternetSession_AddRef(IInternetSession * iface)335c2c66affSColin Finck static ULONG WINAPI InternetSession_AddRef(IInternetSession *iface)
336c2c66affSColin Finck {
337c2c66affSColin Finck     TRACE("()\n");
338c2c66affSColin Finck     URLMON_LockModule();
339c2c66affSColin Finck     return 2;
340c2c66affSColin Finck }
341c2c66affSColin Finck 
InternetSession_Release(IInternetSession * iface)342c2c66affSColin Finck static ULONG WINAPI InternetSession_Release(IInternetSession *iface)
343c2c66affSColin Finck {
344c2c66affSColin Finck     TRACE("()\n");
345c2c66affSColin Finck     URLMON_UnlockModule();
346c2c66affSColin Finck     return 1;
347c2c66affSColin Finck }
348c2c66affSColin Finck 
InternetSession_RegisterNameSpace(IInternetSession * iface,IClassFactory * pCF,REFCLSID rclsid,LPCWSTR pwzProtocol,ULONG cPatterns,const LPCWSTR * ppwzPatterns,DWORD dwReserved)349c2c66affSColin Finck static HRESULT WINAPI InternetSession_RegisterNameSpace(IInternetSession *iface,
350c2c66affSColin Finck         IClassFactory *pCF, REFCLSID rclsid, LPCWSTR pwzProtocol, ULONG cPatterns,
351c2c66affSColin Finck         const LPCWSTR *ppwzPatterns, DWORD dwReserved)
352c2c66affSColin Finck {
353c2c66affSColin Finck     TRACE("(%p %s %s %d %p %d)\n", pCF, debugstr_guid(rclsid), debugstr_w(pwzProtocol),
354c2c66affSColin Finck           cPatterns, ppwzPatterns, dwReserved);
355c2c66affSColin Finck 
356c2c66affSColin Finck     if(cPatterns || ppwzPatterns)
357c2c66affSColin Finck         FIXME("patterns not supported\n");
358c2c66affSColin Finck     if(dwReserved)
359c2c66affSColin Finck         WARN("dwReserved = %d\n", dwReserved);
360c2c66affSColin Finck 
361c2c66affSColin Finck     if(!pCF || !pwzProtocol)
362c2c66affSColin Finck         return E_INVALIDARG;
363c2c66affSColin Finck 
364c2c66affSColin Finck     return register_namespace(pCF, rclsid, pwzProtocol, FALSE);
365c2c66affSColin Finck }
366c2c66affSColin Finck 
InternetSession_UnregisterNameSpace(IInternetSession * iface,IClassFactory * pCF,LPCWSTR pszProtocol)367c2c66affSColin Finck static HRESULT WINAPI InternetSession_UnregisterNameSpace(IInternetSession *iface,
368c2c66affSColin Finck         IClassFactory *pCF, LPCWSTR pszProtocol)
369c2c66affSColin Finck {
370c2c66affSColin Finck     TRACE("(%p %s)\n", pCF, debugstr_w(pszProtocol));
371c2c66affSColin Finck 
372c2c66affSColin Finck     if(!pCF || !pszProtocol)
373c2c66affSColin Finck         return E_INVALIDARG;
374c2c66affSColin Finck 
375c2c66affSColin Finck     return unregister_namespace(pCF, pszProtocol);
376c2c66affSColin Finck }
377c2c66affSColin Finck 
InternetSession_RegisterMimeFilter(IInternetSession * iface,IClassFactory * pCF,REFCLSID rclsid,LPCWSTR pwzType)378c2c66affSColin Finck static HRESULT WINAPI InternetSession_RegisterMimeFilter(IInternetSession *iface,
379c2c66affSColin Finck         IClassFactory *pCF, REFCLSID rclsid, LPCWSTR pwzType)
380c2c66affSColin Finck {
381c2c66affSColin Finck     mime_filter *filter;
382c2c66affSColin Finck 
383c2c66affSColin Finck     TRACE("(%p %s %s)\n", pCF, debugstr_guid(rclsid), debugstr_w(pwzType));
384c2c66affSColin Finck 
385c2c66affSColin Finck     filter = heap_alloc(sizeof(mime_filter));
386c2c66affSColin Finck 
387c2c66affSColin Finck     IClassFactory_AddRef(pCF);
388c2c66affSColin Finck     filter->cf = pCF;
389c2c66affSColin Finck     filter->clsid = *rclsid;
390c2c66affSColin Finck     filter->mime = heap_strdupW(pwzType);
391c2c66affSColin Finck 
392c2c66affSColin Finck     EnterCriticalSection(&session_cs);
393c2c66affSColin Finck 
394c2c66affSColin Finck     list_add_head(&mime_filter_list, &filter->entry);
395c2c66affSColin Finck 
396c2c66affSColin Finck     LeaveCriticalSection(&session_cs);
397c2c66affSColin Finck 
398c2c66affSColin Finck     return S_OK;
399c2c66affSColin Finck }
400c2c66affSColin Finck 
InternetSession_UnregisterMimeFilter(IInternetSession * iface,IClassFactory * pCF,LPCWSTR pwzType)401c2c66affSColin Finck static HRESULT WINAPI InternetSession_UnregisterMimeFilter(IInternetSession *iface,
402c2c66affSColin Finck         IClassFactory *pCF, LPCWSTR pwzType)
403c2c66affSColin Finck {
404c2c66affSColin Finck     mime_filter *iter;
405c2c66affSColin Finck 
406c2c66affSColin Finck     TRACE("(%p %s)\n", pCF, debugstr_w(pwzType));
407c2c66affSColin Finck 
408c2c66affSColin Finck     EnterCriticalSection(&session_cs);
409c2c66affSColin Finck 
410c2c66affSColin Finck     LIST_FOR_EACH_ENTRY(iter, &mime_filter_list, mime_filter, entry) {
411*6c3c2e33SAmine Khaldi         if(iter->cf == pCF && !wcscmp(iter->mime, pwzType)) {
412c2c66affSColin Finck             list_remove(&iter->entry);
413c2c66affSColin Finck 
414c2c66affSColin Finck             LeaveCriticalSection(&session_cs);
415c2c66affSColin Finck 
416c2c66affSColin Finck             IClassFactory_Release(iter->cf);
417c2c66affSColin Finck             heap_free(iter->mime);
418c2c66affSColin Finck             heap_free(iter);
419c2c66affSColin Finck             return S_OK;
420c2c66affSColin Finck         }
421c2c66affSColin Finck     }
422c2c66affSColin Finck 
423c2c66affSColin Finck     LeaveCriticalSection(&session_cs);
424c2c66affSColin Finck     return S_OK;
425c2c66affSColin Finck }
426c2c66affSColin Finck 
InternetSession_CreateBinding(IInternetSession * iface,LPBC pBC,LPCWSTR szUrl,IUnknown * pUnkOuter,IUnknown ** ppUnk,IInternetProtocol ** ppOInetProt,DWORD dwOption)427c2c66affSColin Finck static HRESULT WINAPI InternetSession_CreateBinding(IInternetSession *iface,
428c2c66affSColin Finck         LPBC pBC, LPCWSTR szUrl, IUnknown *pUnkOuter, IUnknown **ppUnk,
429c2c66affSColin Finck         IInternetProtocol **ppOInetProt, DWORD dwOption)
430c2c66affSColin Finck {
431c2c66affSColin Finck     BindProtocol *protocol;
432c2c66affSColin Finck     HRESULT hres;
433c2c66affSColin Finck 
434c2c66affSColin Finck     TRACE("(%p %s %p %p %p %08x)\n", pBC, debugstr_w(szUrl), pUnkOuter, ppUnk,
435c2c66affSColin Finck             ppOInetProt, dwOption);
436c2c66affSColin Finck 
437c2c66affSColin Finck     if(pBC || pUnkOuter || ppUnk || dwOption)
438c2c66affSColin Finck         FIXME("Unsupported arguments\n");
439c2c66affSColin Finck 
440d0eebfbdSAmine Khaldi     hres = create_binding_protocol(&protocol);
441c2c66affSColin Finck     if(FAILED(hres))
442c2c66affSColin Finck         return hres;
443c2c66affSColin Finck 
444c2c66affSColin Finck     *ppOInetProt = (IInternetProtocol*)&protocol->IInternetProtocolEx_iface;
445c2c66affSColin Finck     return S_OK;
446c2c66affSColin Finck }
447c2c66affSColin Finck 
InternetSession_SetSessionOption(IInternetSession * iface,DWORD dwOption,LPVOID pBuffer,DWORD dwBufferLength,DWORD dwReserved)448c2c66affSColin Finck static HRESULT WINAPI InternetSession_SetSessionOption(IInternetSession *iface,
449c2c66affSColin Finck         DWORD dwOption, LPVOID pBuffer, DWORD dwBufferLength, DWORD dwReserved)
450c2c66affSColin Finck {
451c2c66affSColin Finck     FIXME("(%08x %p %d %d)\n", dwOption, pBuffer, dwBufferLength, dwReserved);
452c2c66affSColin Finck     return E_NOTIMPL;
453c2c66affSColin Finck }
454c2c66affSColin Finck 
455c2c66affSColin Finck static const IInternetSessionVtbl InternetSessionVtbl = {
456c2c66affSColin Finck     InternetSession_QueryInterface,
457c2c66affSColin Finck     InternetSession_AddRef,
458c2c66affSColin Finck     InternetSession_Release,
459c2c66affSColin Finck     InternetSession_RegisterNameSpace,
460c2c66affSColin Finck     InternetSession_UnregisterNameSpace,
461c2c66affSColin Finck     InternetSession_RegisterMimeFilter,
462c2c66affSColin Finck     InternetSession_UnregisterMimeFilter,
463c2c66affSColin Finck     InternetSession_CreateBinding,
464c2c66affSColin Finck     InternetSession_SetSessionOption
465c2c66affSColin Finck };
466c2c66affSColin Finck 
467c2c66affSColin Finck static IInternetSession InternetSession = { &InternetSessionVtbl };
468c2c66affSColin Finck 
469c2c66affSColin Finck /***********************************************************************
470c2c66affSColin Finck  *           CoInternetGetSession (URLMON.@)
471c2c66affSColin Finck  *
472c2c66affSColin Finck  * Create a new internet session and return an IInternetSession interface
473c2c66affSColin Finck  * representing it.
474c2c66affSColin Finck  *
475c2c66affSColin Finck  * PARAMS
476c2c66affSColin Finck  *    dwSessionMode      [I] Mode for the internet session
477c2c66affSColin Finck  *    ppIInternetSession [O] Destination for creates IInternetSession object
478c2c66affSColin Finck  *    dwReserved         [I] Reserved, must be 0.
479c2c66affSColin Finck  *
480c2c66affSColin Finck  * RETURNS
481c2c66affSColin Finck  *    Success: S_OK. ppIInternetSession contains the IInternetSession interface.
482c2c66affSColin Finck  *    Failure: E_INVALIDARG, if any argument is invalid, or
483c2c66affSColin Finck  *             E_OUTOFMEMORY if memory allocation fails.
484c2c66affSColin Finck  */
CoInternetGetSession(DWORD dwSessionMode,IInternetSession ** ppIInternetSession,DWORD dwReserved)485c2c66affSColin Finck HRESULT WINAPI CoInternetGetSession(DWORD dwSessionMode, IInternetSession **ppIInternetSession,
486c2c66affSColin Finck         DWORD dwReserved)
487c2c66affSColin Finck {
488c2c66affSColin Finck     TRACE("(%d %p %d)\n", dwSessionMode, ppIInternetSession, dwReserved);
489c2c66affSColin Finck 
490c2c66affSColin Finck     if(dwSessionMode)
491c2c66affSColin Finck         ERR("dwSessionMode=%d\n", dwSessionMode);
492c2c66affSColin Finck     if(dwReserved)
493c2c66affSColin Finck         ERR("dwReserved=%d\n", dwReserved);
494c2c66affSColin Finck 
495c2c66affSColin Finck     IInternetSession_AddRef(&InternetSession);
496c2c66affSColin Finck     *ppIInternetSession = &InternetSession;
497c2c66affSColin Finck     return S_OK;
498c2c66affSColin Finck }
499c2c66affSColin Finck 
500c2c66affSColin Finck /**************************************************************************
501c2c66affSColin Finck  *                 UrlMkGetSessionOption (URLMON.@)
502c2c66affSColin Finck  */
get_url_encoding(HKEY root,DWORD * encoding)503c2c66affSColin Finck static BOOL get_url_encoding(HKEY root, DWORD *encoding)
504c2c66affSColin Finck {
505c2c66affSColin Finck     DWORD size = sizeof(DWORD), res, type;
506c2c66affSColin Finck     HKEY hkey;
507c2c66affSColin Finck 
508c2c66affSColin Finck     static const WCHAR wszUrlEncoding[] = {'U','r','l','E','n','c','o','d','i','n','g',0};
509c2c66affSColin Finck 
510c2c66affSColin Finck     res = RegOpenKeyW(root, internet_settings_keyW, &hkey);
511c2c66affSColin Finck     if(res != ERROR_SUCCESS)
512c2c66affSColin Finck         return FALSE;
513c2c66affSColin Finck 
514c2c66affSColin Finck     res = RegQueryValueExW(hkey, wszUrlEncoding, NULL, &type, (LPBYTE)encoding, &size);
515c2c66affSColin Finck     RegCloseKey(hkey);
516c2c66affSColin Finck 
517c2c66affSColin Finck     return res == ERROR_SUCCESS;
518c2c66affSColin Finck }
519c2c66affSColin Finck 
520c2c66affSColin Finck static LPWSTR user_agent;
521c2c66affSColin Finck 
ensure_useragent(void)522c2c66affSColin Finck static void ensure_useragent(void)
523c2c66affSColin Finck {
524c2c66affSColin Finck     OSVERSIONINFOW info = {sizeof(info)};
525c2c66affSColin Finck     const WCHAR *os_type, *is_nt;
526c2c66affSColin Finck     WCHAR buf[512], *ret, *tmp;
527c2c66affSColin Finck     DWORD res, idx=0;
528c2c66affSColin Finck     size_t len, size;
529c2c66affSColin Finck     BOOL is_wow;
530c2c66affSColin Finck     HKEY key;
531c2c66affSColin Finck 
532c2c66affSColin Finck     static const WCHAR formatW[] =
533c2c66affSColin Finck         {'M','o','z','i','l','l','a','/','4','.','0',
534c2c66affSColin Finck          ' ','(','c','o','m','p','a','t','i','b','l','e',';',
535c2c66affSColin Finck          ' ','M','S','I','E',' ','8','.','0',';',
536c2c66affSColin Finck          ' ','W','i','n','d','o','w','s',' ','%','s','%','d','.','%','d',';',
537c2c66affSColin Finck          ' ','%','s','T','r','i','d','e','n','t','/','5','.','0',0};
538c2c66affSColin Finck     static const WCHAR post_platform_keyW[] =
539c2c66affSColin Finck         {'S','O','F','T','W','A','R','E',
540c2c66affSColin Finck          '\\','M','i','c','r','o','s','o','f','t',
541c2c66affSColin Finck          '\\','W','i','n','d','o','w','s',
542c2c66affSColin Finck          '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n',
543c2c66affSColin Finck          '\\','I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',
544c2c66affSColin Finck          '\\','5','.','0','\\','U','s','e','r',' ','A','g','e','n','t',
545c2c66affSColin Finck          '\\','P','o','s','t',' ','P','l','a','t','f','o','r','m',0};
546c2c66affSColin Finck     static const WCHAR ntW[] = {'N','T',' ',0};
547c2c66affSColin Finck     static const WCHAR win64W[] = {'W','i','n','6','4',';',' ','x','6','4',';',' ',0};
548c2c66affSColin Finck     static const WCHAR wow64W[] = {'W','O','W','6','4',';',' ',0};
549c2c66affSColin Finck     static const WCHAR emptyW[] = {0};
550c2c66affSColin Finck 
551c2c66affSColin Finck     if(user_agent)
552c2c66affSColin Finck         return;
553c2c66affSColin Finck 
554c2c66affSColin Finck     GetVersionExW(&info);
555c2c66affSColin Finck     is_nt = info.dwPlatformId == VER_PLATFORM_WIN32_NT ? ntW : emptyW;
556c2c66affSColin Finck 
557c2c66affSColin Finck     if(sizeof(void*) == 8)
558c2c66affSColin Finck         os_type = win64W;
559c2c66affSColin Finck     else if(IsWow64Process(GetCurrentProcess(), &is_wow) && is_wow)
560c2c66affSColin Finck         os_type = wow64W;
561c2c66affSColin Finck     else
562c2c66affSColin Finck         os_type = emptyW;
563c2c66affSColin Finck 
564*6c3c2e33SAmine Khaldi     swprintf(buf, formatW, is_nt, info.dwMajorVersion, info.dwMinorVersion, os_type);
565*6c3c2e33SAmine Khaldi     len = lstrlenW(buf);
566c2c66affSColin Finck 
567c2c66affSColin Finck     size = len+40;
568c2c66affSColin Finck     ret = heap_alloc(size * sizeof(WCHAR));
569c2c66affSColin Finck     if(!ret)
570c2c66affSColin Finck         return;
571c2c66affSColin Finck 
572c2c66affSColin Finck     memcpy(ret, buf, len*sizeof(WCHAR));
573c2c66affSColin Finck 
574c2c66affSColin Finck     res = RegOpenKeyW(HKEY_LOCAL_MACHINE, post_platform_keyW, &key);
575c2c66affSColin Finck     if(res == ERROR_SUCCESS) {
576c2c66affSColin Finck         DWORD value_len;
577c2c66affSColin Finck 
578c2c66affSColin Finck         while(1) {
579ad73c0a0SAmine Khaldi             value_len = ARRAY_SIZE(buf);
580c2c66affSColin Finck             res = RegEnumValueW(key, idx, buf, &value_len, NULL, NULL, NULL, NULL);
581c2c66affSColin Finck             if(res != ERROR_SUCCESS)
582c2c66affSColin Finck                 break;
583c2c66affSColin Finck             idx++;
584c2c66affSColin Finck 
585c2c66affSColin Finck             if(len + value_len + 2 /* strlen("; ") */ + 1 /* trailing ')' */ >= size) {
586c2c66affSColin Finck                 tmp = heap_realloc(ret, (size*2+value_len)*sizeof(WCHAR));
587c2c66affSColin Finck                 if(!tmp)
588c2c66affSColin Finck                     break;
589c2c66affSColin Finck                 ret = tmp;
590c2c66affSColin Finck                 size = size*2+value_len;
591c2c66affSColin Finck             }
592c2c66affSColin Finck 
593c2c66affSColin Finck             ret[len++] = ';';
594c2c66affSColin Finck             ret[len++] = ' ';
595c2c66affSColin Finck             memcpy(ret+len, buf, value_len*sizeof(WCHAR));
596c2c66affSColin Finck             len += value_len;
597c2c66affSColin Finck         }
598c2c66affSColin Finck 
599c2c66affSColin Finck         RegCloseKey(key);
600c2c66affSColin Finck     }
601c2c66affSColin Finck 
602c2c66affSColin Finck     ret[len++] = ')';
603c2c66affSColin Finck     ret[len++] = 0;
604c2c66affSColin Finck 
605c2c66affSColin Finck     user_agent = ret;
606c2c66affSColin Finck     TRACE("Using user agent %s\n", debugstr_w(user_agent));
607c2c66affSColin Finck }
608c2c66affSColin Finck 
get_useragent(void)609c2c66affSColin Finck LPWSTR get_useragent(void)
610c2c66affSColin Finck {
611c2c66affSColin Finck     LPWSTR ret;
612c2c66affSColin Finck 
613c2c66affSColin Finck     ensure_useragent();
614c2c66affSColin Finck 
615c2c66affSColin Finck     EnterCriticalSection(&session_cs);
616c2c66affSColin Finck     ret = heap_strdupW(user_agent);
617c2c66affSColin Finck     LeaveCriticalSection(&session_cs);
618c2c66affSColin Finck 
619c2c66affSColin Finck     return ret;
620c2c66affSColin Finck }
621c2c66affSColin Finck 
UrlMkGetSessionOption(DWORD dwOption,LPVOID pBuffer,DWORD dwBufferLength,DWORD * pdwBufferLength,DWORD dwReserved)622c2c66affSColin Finck HRESULT WINAPI UrlMkGetSessionOption(DWORD dwOption, LPVOID pBuffer, DWORD dwBufferLength,
623c2c66affSColin Finck                                      DWORD* pdwBufferLength, DWORD dwReserved)
624c2c66affSColin Finck {
625c2c66affSColin Finck     TRACE("(%x, %p, %d, %p)\n", dwOption, pBuffer, dwBufferLength, pdwBufferLength);
626c2c66affSColin Finck 
627c2c66affSColin Finck     if(dwReserved)
628c2c66affSColin Finck         WARN("dwReserved = %d\n", dwReserved);
629c2c66affSColin Finck 
630c2c66affSColin Finck     switch(dwOption) {
631c2c66affSColin Finck     case URLMON_OPTION_USERAGENT: {
632c2c66affSColin Finck         HRESULT hres = E_OUTOFMEMORY;
633c2c66affSColin Finck         DWORD size;
634c2c66affSColin Finck 
635c2c66affSColin Finck         if(!pdwBufferLength)
636c2c66affSColin Finck             return E_INVALIDARG;
637c2c66affSColin Finck 
638c2c66affSColin Finck         EnterCriticalSection(&session_cs);
639c2c66affSColin Finck 
640c2c66affSColin Finck         ensure_useragent();
641c2c66affSColin Finck         if(user_agent) {
642c2c66affSColin Finck             size = WideCharToMultiByte(CP_ACP, 0, user_agent, -1, NULL, 0, NULL, NULL);
643c2c66affSColin Finck             *pdwBufferLength = size;
644c2c66affSColin Finck             if(size <= dwBufferLength) {
645c2c66affSColin Finck                 if(pBuffer)
646c2c66affSColin Finck                     WideCharToMultiByte(CP_ACP, 0, user_agent, -1, pBuffer, size, NULL, NULL);
647c2c66affSColin Finck                 else
648c2c66affSColin Finck                     hres = E_INVALIDARG;
649c2c66affSColin Finck             }
650c2c66affSColin Finck         }
651c2c66affSColin Finck 
652c2c66affSColin Finck         LeaveCriticalSection(&session_cs);
653c2c66affSColin Finck 
654c2c66affSColin Finck         /* Tests prove that we have to return E_OUTOFMEMORY on success. */
655c2c66affSColin Finck         return hres;
656c2c66affSColin Finck     }
657c2c66affSColin Finck     case URLMON_OPTION_URL_ENCODING: {
658c2c66affSColin Finck         DWORD encoding = 0;
659c2c66affSColin Finck 
660c2c66affSColin Finck         if(!pBuffer || dwBufferLength < sizeof(DWORD) || !pdwBufferLength)
661c2c66affSColin Finck             return E_INVALIDARG;
662c2c66affSColin Finck 
663c2c66affSColin Finck         if(!get_url_encoding(HKEY_CURRENT_USER, &encoding))
664c2c66affSColin Finck             get_url_encoding(HKEY_LOCAL_MACHINE, &encoding);
665c2c66affSColin Finck 
666c2c66affSColin Finck         *pdwBufferLength = sizeof(DWORD);
667c2c66affSColin Finck         *(DWORD*)pBuffer = encoding ? URL_ENCODING_DISABLE_UTF8 : URL_ENCODING_ENABLE_UTF8;
668c2c66affSColin Finck         return S_OK;
669c2c66affSColin Finck     }
670c2c66affSColin Finck     default:
671c2c66affSColin Finck         FIXME("unsupported option %x\n", dwOption);
672c2c66affSColin Finck     }
673c2c66affSColin Finck 
674c2c66affSColin Finck     return E_INVALIDARG;
675c2c66affSColin Finck }
676c2c66affSColin Finck 
677c2c66affSColin Finck /**************************************************************************
678c2c66affSColin Finck  *                 UrlMkSetSessionOption (URLMON.@)
679c2c66affSColin Finck  */
UrlMkSetSessionOption(DWORD dwOption,LPVOID pBuffer,DWORD dwBufferLength,DWORD Reserved)680c2c66affSColin Finck HRESULT WINAPI UrlMkSetSessionOption(DWORD dwOption, LPVOID pBuffer, DWORD dwBufferLength,
681c2c66affSColin Finck         DWORD Reserved)
682c2c66affSColin Finck {
683c2c66affSColin Finck     TRACE("(%x %p %x)\n", dwOption, pBuffer, dwBufferLength);
684c2c66affSColin Finck 
685c2c66affSColin Finck     switch(dwOption) {
686c2c66affSColin Finck     case URLMON_OPTION_USERAGENT: {
687c2c66affSColin Finck         LPWSTR new_user_agent;
688c2c66affSColin Finck         char *buf = pBuffer;
689c2c66affSColin Finck         DWORD len, size;
690c2c66affSColin Finck 
691c2c66affSColin Finck         if(!pBuffer || !dwBufferLength)
692c2c66affSColin Finck             return E_INVALIDARG;
693c2c66affSColin Finck 
694c2c66affSColin Finck         for(len=0; len<dwBufferLength && buf[len]; len++);
695c2c66affSColin Finck 
696c2c66affSColin Finck         TRACE("Setting user agent %s\n", debugstr_an(buf, len));
697c2c66affSColin Finck 
698c2c66affSColin Finck         size = MultiByteToWideChar(CP_ACP, 0, buf, len, NULL, 0);
699c2c66affSColin Finck         new_user_agent = heap_alloc((size+1)*sizeof(WCHAR));
700c2c66affSColin Finck         if(!new_user_agent)
701c2c66affSColin Finck             return E_OUTOFMEMORY;
702c2c66affSColin Finck         MultiByteToWideChar(CP_ACP, 0, buf, len, new_user_agent, size);
703c2c66affSColin Finck         new_user_agent[size] = 0;
704c2c66affSColin Finck 
705c2c66affSColin Finck         EnterCriticalSection(&session_cs);
706c2c66affSColin Finck 
707c2c66affSColin Finck         heap_free(user_agent);
708c2c66affSColin Finck         user_agent = new_user_agent;
709c2c66affSColin Finck         update_user_agent(user_agent);
710c2c66affSColin Finck 
711c2c66affSColin Finck         LeaveCriticalSection(&session_cs);
712c2c66affSColin Finck         break;
713c2c66affSColin Finck     }
714c2c66affSColin Finck     default:
715c2c66affSColin Finck         FIXME("Unknown option %x\n", dwOption);
716c2c66affSColin Finck         return E_INVALIDARG;
717c2c66affSColin Finck     }
718c2c66affSColin Finck 
719c2c66affSColin Finck     return S_OK;
720c2c66affSColin Finck }
721c2c66affSColin Finck 
722c2c66affSColin Finck /**************************************************************************
723c2c66affSColin Finck  *                 ObtainUserAgentString (URLMON.@)
724c2c66affSColin Finck  */
ObtainUserAgentString(DWORD dwOption,LPSTR pcszUAOut,DWORD * cbSize)725c2c66affSColin Finck HRESULT WINAPI ObtainUserAgentString(DWORD dwOption, LPSTR pcszUAOut, DWORD *cbSize)
726c2c66affSColin Finck {
727c2c66affSColin Finck     DWORD size;
728c2c66affSColin Finck     HRESULT hres = E_FAIL;
729c2c66affSColin Finck 
730c2c66affSColin Finck     TRACE("(%d %p %p)\n", dwOption, pcszUAOut, cbSize);
731c2c66affSColin Finck 
732c2c66affSColin Finck     if(!pcszUAOut || !cbSize)
733c2c66affSColin Finck         return E_INVALIDARG;
734c2c66affSColin Finck 
735c2c66affSColin Finck     EnterCriticalSection(&session_cs);
736c2c66affSColin Finck 
737c2c66affSColin Finck     ensure_useragent();
738c2c66affSColin Finck     if(user_agent) {
739c2c66affSColin Finck         size = WideCharToMultiByte(CP_ACP, 0, user_agent, -1, NULL, 0, NULL, NULL);
740c2c66affSColin Finck 
741c2c66affSColin Finck         if(size <= *cbSize) {
742c2c66affSColin Finck             WideCharToMultiByte(CP_ACP, 0, user_agent, -1, pcszUAOut, *cbSize, NULL, NULL);
743c2c66affSColin Finck             hres = S_OK;
744c2c66affSColin Finck         }else {
745c2c66affSColin Finck             hres = E_OUTOFMEMORY;
746c2c66affSColin Finck         }
747c2c66affSColin Finck 
748c2c66affSColin Finck         *cbSize = size;
749c2c66affSColin Finck     }
750c2c66affSColin Finck 
751c2c66affSColin Finck     LeaveCriticalSection(&session_cs);
752c2c66affSColin Finck     return hres;
753c2c66affSColin Finck }
754c2c66affSColin Finck 
free_session(void)755c2c66affSColin Finck void free_session(void)
756c2c66affSColin Finck {
757c2c66affSColin Finck     name_space *ns_iter, *ns_last;
758c2c66affSColin Finck     mime_filter *mf_iter, *mf_last;
759c2c66affSColin Finck 
760c2c66affSColin Finck     LIST_FOR_EACH_ENTRY_SAFE(ns_iter, ns_last, &name_space_list, name_space, entry) {
761c2c66affSColin Finck             if(!ns_iter->urlmon)
762c2c66affSColin Finck                 IClassFactory_Release(ns_iter->cf);
763c2c66affSColin Finck             heap_free(ns_iter->protocol);
764c2c66affSColin Finck             heap_free(ns_iter);
765c2c66affSColin Finck     }
766c2c66affSColin Finck 
767c2c66affSColin Finck     LIST_FOR_EACH_ENTRY_SAFE(mf_iter, mf_last, &mime_filter_list, mime_filter, entry) {
768c2c66affSColin Finck             IClassFactory_Release(mf_iter->cf);
769c2c66affSColin Finck             heap_free(mf_iter->mime);
770c2c66affSColin Finck             heap_free(mf_iter);
771c2c66affSColin Finck     }
772c2c66affSColin Finck 
773c2c66affSColin Finck     heap_free(user_agent);
774c2c66affSColin Finck }
775