Fixed gcc 4.0 warnings.
[wine] / dlls / mshtml / protocol.c
1 /*
2  * Copyright 2005 Jacek Caban
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19 #include "config.h"
20
21 #include <stdarg.h>
22 #include <stdio.h>
23
24 #define COBJMACROS
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "ole2.h"
30
31 #include "wine/debug.h"
32 #include "wine/unicode.h"
33
34 #include "mshtml_private.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
37
38 /********************************************************************
39  * common ProtocolFactory implementation
40  */
41
42 #define PROTOCOLINFO(x) ((IInternetProtocolInfo*) &(x)->lpInternetProtocolInfoVtbl)
43 #define CLASSFACTORY(x) ((IClassFactory*)         &(x)->lpClassFactoryVtbl)
44 #define PROTOCOL(x)     ((IInternetProtocol*)     &(x)->lpInternetProtocolVtbl)
45
46 typedef struct {
47     const IInternetProtocolInfoVtbl *lpInternetProtocolInfoVtbl;
48     const IClassFactoryVtbl         *lpClassFactoryVtbl;
49 } ProtocolFactory;
50
51 #define PROTOCOLINFO_THIS(iface) DEFINE_THIS(ProtocolFactory, InternetProtocolInfo, iface)
52
53 static HRESULT WINAPI InternetProtocolInfo_QueryInterface(IInternetProtocolInfo *iface, REFIID riid, void **ppv)
54 {
55     ProtocolFactory *This = PROTOCOLINFO_THIS(iface);
56
57     *ppv = NULL;
58     if(IsEqualGUID(&IID_IUnknown, riid)) {
59         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
60         *ppv = PROTOCOLINFO(This);
61     }else if(IsEqualGUID(&IID_IInternetProtocolInfo, riid)) {
62         TRACE("(%p)->(IID_IInternetProtocolInfo %p)\n", This, ppv);
63         *ppv = PROTOCOLINFO(This);
64     }else if(IsEqualGUID(&IID_IClassFactory, riid)) {
65         TRACE("(%p)->(IID_IClassFactory %p)\n", This, ppv);
66         *ppv = CLASSFACTORY(This);
67     }
68
69     if(!*ppv) {
70         WARN("unknown interface %s\n", debugstr_guid(riid));
71         return E_NOINTERFACE;
72     }
73
74     IInternetProtocolInfo_AddRef(iface);
75     return S_OK;
76 }
77
78 static ULONG WINAPI InternetProtocolInfo_AddRef(IInternetProtocolInfo *iface)
79 {
80     ProtocolFactory *This = PROTOCOLINFO_THIS(iface);
81     TRACE("(%p)\n", This);
82     LOCK_MODULE();
83     return 2;
84 }
85
86 static ULONG WINAPI InternetProtocolInfo_Release(IInternetProtocolInfo *iface)
87 {
88     ProtocolFactory *This = PROTOCOLINFO_THIS(iface);
89     TRACE("(%p)\n", This);
90     UNLOCK_MODULE();
91     return 1;
92 }
93
94 #undef PROTOCOLINFO_THIS
95
96 #define CLASSFACTORY_THIS(iface) DEFINE_THIS(ProtocolFactory, ClassFactory, iface)
97
98 static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
99 {
100     ProtocolFactory *This = CLASSFACTORY_THIS(iface);
101     return IInternetProtocolInfo_QueryInterface(PROTOCOLINFO(This), riid, ppv);
102 }
103
104 static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface)
105 {
106     ProtocolFactory *This = CLASSFACTORY_THIS(iface);
107     return IInternetProtocolInfo_AddRef(PROTOCOLINFO(This));
108 }
109
110 static ULONG WINAPI ClassFactory_Release(IClassFactory *iface)
111 {
112     ProtocolFactory *This = CLASSFACTORY_THIS(iface);
113     return IInternetProtocolInfo_Release(PROTOCOLINFO(This));
114 }
115
116 static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL dolock)
117 {
118     ProtocolFactory *This = CLASSFACTORY_THIS(iface);
119
120     TRACE("(%p)->(%x)\n", This, dolock);
121
122     if(dolock)
123         LOCK_MODULE();
124     else
125         UNLOCK_MODULE();
126
127     return S_OK;
128 }
129
130 #undef CLASSFACTORY_THIS
131
132 /********************************************************************
133  * AboutProtocol implementation
134  */
135
136 typedef struct {
137     const IInternetProtocolVtbl *lpInternetProtocolVtbl;
138
139     LONG ref;
140
141     BYTE *data;
142     ULONG data_len;
143     ULONG cur;
144
145     IUnknown *pUnkOuter;
146 } AboutProtocol;
147
148 #define PROTOCOL_THIS(iface) DEFINE_THIS(AboutProtocol, InternetProtocol, iface)
149
150 static HRESULT WINAPI AboutProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
151 {
152     AboutProtocol *This = PROTOCOL_THIS(iface);
153
154     *ppv = NULL;
155
156     if(IsEqualGUID(&IID_IUnknown, riid)) {
157         TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv);
158         if(This->pUnkOuter)
159             return IUnknown_QueryInterface(This->pUnkOuter, riid, ppv);
160         *ppv = PROTOCOL(This);
161     }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
162         TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", iface, ppv);
163         *ppv = PROTOCOL(This);
164     }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
165         TRACE("(%p)->(IID_IInternetProtocol %p)\n", iface, ppv);
166         *ppv = PROTOCOL(This);
167     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
168         FIXME("IServiceProvider is not implemented\n");
169         return E_NOINTERFACE;
170     }
171
172     if(!*ppv) {
173         TRACE("unknown interface %s\n", debugstr_guid(riid));
174         return E_NOINTERFACE;
175     }
176
177     IInternetProtocol_AddRef(iface);
178     return S_OK;
179 }
180
181 static ULONG WINAPI AboutProtocol_AddRef(IInternetProtocol *iface)
182 {
183     AboutProtocol *This = PROTOCOL_THIS(iface);
184     ULONG ref = InterlockedIncrement(&This->ref);
185     TRACE("(%p) ref=%ld\n", iface, ref);
186     return This->pUnkOuter ? IUnknown_AddRef(This->pUnkOuter) : ref;
187 }
188
189 static ULONG WINAPI AboutProtocol_Release(IInternetProtocol *iface)
190 {
191     AboutProtocol *This = PROTOCOL_THIS(iface);
192     IUnknown *pUnkOuter = This->pUnkOuter;
193     ULONG ref = InterlockedDecrement(&This->ref);
194
195     TRACE("(%p) ref=%lx\n", iface, ref);
196
197     if(!ref) {
198         HeapFree(GetProcessHeap(), 0, This->data);
199         HeapFree(GetProcessHeap(), 0, This);
200         UNLOCK_MODULE();
201     }
202
203     return pUnkOuter ? IUnknown_Release(pUnkOuter) : ref;
204 }
205
206 static HRESULT WINAPI AboutProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
207         IInternetProtocolSink* pOIProtSink, IInternetBindInfo* pOIBindInfo,
208         DWORD grfPI, DWORD dwReserved)
209 {
210     AboutProtocol *This = PROTOCOL_THIS(iface);
211     BINDINFO bindinfo;
212     DWORD grfBINDF = 0;
213     LPCWSTR text = NULL;
214
215     static const WCHAR html_begin[] = {0xfeff,'<','H','T','M','L','>',0};
216     static const WCHAR html_end[] = {'<','/','H','T','M','L','>',0};
217     static const WCHAR wszBlank[] = {'b','l','a','n','k',0};
218     static const WCHAR wszAbout[] = {'a','b','o','u','t',':'};
219     static const WCHAR wszTextHtml[] = {'t','e','x','t','/','h','t','m','l',0};
220
221     /* NOTE:
222      * the about protocol seems not to work as I would expect. It creates html document
223      * for a given url, eg. about:some_text -> <HTML>some_text</HTML> except for the case when
224      * some_text = "blank", when document is blank (<HTML></HMTL>). The same happens
225      * when the url does not have "about:" in the beginning.
226      */
227
228     TRACE("(%p)->(%s %p %p %08lx %ld)\n", This, debugstr_w(szUrl), pOIProtSink,
229             pOIBindInfo, grfPI, dwReserved);
230
231     memset(&bindinfo, 0, sizeof(bindinfo));
232     bindinfo.cbSize = sizeof(BINDINFO);
233     IInternetBindInfo_GetBindInfo(pOIBindInfo, &grfBINDF, &bindinfo);
234     ReleaseBindInfo(&bindinfo);
235
236     if(strlenW(szUrl)>=sizeof(wszAbout)/sizeof(WCHAR) && !memcmp(wszAbout, szUrl, sizeof(wszAbout))) {
237         text = szUrl + sizeof(wszAbout)/sizeof(WCHAR);
238         if(!strcmpW(wszBlank, text))
239             text = NULL;
240     }
241
242     This->data_len = sizeof(html_begin)+sizeof(html_end)-sizeof(WCHAR) 
243         + (text ? strlenW(text)*sizeof(WCHAR) : 0);
244     This->data = HeapAlloc(GetProcessHeap(), 0, This->data_len);
245
246     memcpy(This->data, html_begin, sizeof(html_begin));
247     if(text)
248         strcatW((LPWSTR)This->data, text);
249     strcatW((LPWSTR)This->data, html_end);
250     
251     This->cur = 0;
252
253     IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_MIMETYPEAVAILABLE, wszTextHtml);
254
255     IInternetProtocolSink_ReportData(pOIProtSink,
256             BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE,
257             This->data_len, This->data_len);
258
259     IInternetProtocolSink_ReportResult(pOIProtSink, S_OK, 0, NULL);
260
261     return S_OK;
262 }
263
264 static HRESULT WINAPI AboutProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA* pProtocolData)
265 {
266     AboutProtocol *This = PROTOCOL_THIS(iface);
267     FIXME("(%p)->(%p)\n", This, pProtocolData);
268     return E_NOTIMPL;
269 }
270
271 static HRESULT WINAPI AboutProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
272         DWORD dwOptions)
273 {
274     AboutProtocol *This = PROTOCOL_THIS(iface);
275     FIXME("(%p)->(%08lx %08lx)\n", This, hrReason, dwOptions);
276     return E_NOTIMPL;
277 }
278
279 static HRESULT WINAPI AboutProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
280 {
281     AboutProtocol *This = PROTOCOL_THIS(iface);
282     TRACE("(%p)->(%08lx)\n", This, dwOptions);
283     return S_OK;
284 }
285
286 static HRESULT WINAPI AboutProtocol_Suspend(IInternetProtocol *iface)
287 {
288     AboutProtocol *This = PROTOCOL_THIS(iface);
289     FIXME("(%p)\n", This);
290     return E_NOTIMPL;
291 }
292
293 static HRESULT WINAPI AboutProtocol_Resume(IInternetProtocol *iface)
294 {
295     AboutProtocol *This = PROTOCOL_THIS(iface);
296     FIXME("(%p)\n", This);
297     return E_NOTIMPL;
298 }
299
300 static HRESULT WINAPI AboutProtocol_Read(IInternetProtocol *iface, void* pv, ULONG cb, ULONG* pcbRead)
301 {
302     AboutProtocol *This = PROTOCOL_THIS(iface);
303
304     TRACE("(%p)->(%p %lu %p)\n", This, pv, cb, pcbRead);
305
306     if(!This->data)
307         return E_FAIL;
308
309     *pcbRead = (cb > This->data_len-This->cur ? This->data_len-This->cur : cb);
310
311     if(!*pcbRead)
312         return S_FALSE;
313
314     memcpy(pv, This->data, *pcbRead);
315     This->cur += *pcbRead;
316
317     return S_OK;
318 }
319
320 static HRESULT WINAPI AboutProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
321         DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition)
322 {
323     AboutProtocol *This = PROTOCOL_THIS(iface);
324     FIXME("(%p)->(%ld %ld %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
325     return E_NOTIMPL;
326 }
327
328 static HRESULT WINAPI AboutProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
329 {
330     AboutProtocol *This = PROTOCOL_THIS(iface);
331
332     TRACE("(%p)->(%ld)\n", This, dwOptions);
333
334     return S_OK;
335 }
336
337 static HRESULT WINAPI AboutProtocol_UnlockRequest(IInternetProtocol *iface)
338 {
339     AboutProtocol *This = PROTOCOL_THIS(iface);
340
341     TRACE("(%p)\n", This);
342
343     return S_OK;
344 }
345
346 #undef PROTOCOL_THIS
347
348 static const IInternetProtocolVtbl AboutProtocolVtbl = {
349     AboutProtocol_QueryInterface,
350     AboutProtocol_AddRef,
351     AboutProtocol_Release,
352     AboutProtocol_Start,
353     AboutProtocol_Continue,
354     AboutProtocol_Abort,
355     AboutProtocol_Terminate,
356     AboutProtocol_Suspend,
357     AboutProtocol_Resume,
358     AboutProtocol_Read,
359     AboutProtocol_Seek,
360     AboutProtocol_LockRequest,
361     AboutProtocol_UnlockRequest
362 };
363
364 static HRESULT WINAPI AboutProtocolFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter,
365         REFIID riid, void **ppv)
366 {
367     AboutProtocol *ret;
368     HRESULT hres = S_OK;
369
370     TRACE("(%p)->(%p %s %p)\n", iface, pUnkOuter, debugstr_guid(riid), ppv);
371
372     ret = HeapAlloc(GetProcessHeap(), 0, sizeof(AboutProtocol));
373     ret->lpInternetProtocolVtbl = &AboutProtocolVtbl;
374     ret->ref = 0;
375
376     ret->data = NULL;
377     ret->data_len = 0;
378     ret->cur = 0;
379     ret->pUnkOuter = pUnkOuter;
380
381     if(pUnkOuter) {
382         ret->ref = 1;
383         if(IsEqualGUID(&IID_IUnknown, riid))
384             *ppv = PROTOCOL(ret);
385         else
386             hres = E_INVALIDARG;
387     }else {
388         hres = IInternetProtocol_QueryInterface(PROTOCOL(ret), riid, ppv);
389     }
390
391     if(SUCCEEDED(hres))
392         LOCK_MODULE();
393     else
394         HeapFree(GetProcessHeap(), 0, ret);
395
396     return hres;
397 }
398
399 static HRESULT WINAPI AboutProtocolInfo_ParseUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
400         PARSEACTION ParseAction, DWORD dwParseFlags, LPWSTR pwzResult, DWORD cchResult,
401         DWORD* pcchResult, DWORD dwReserved)
402 {
403     TRACE("%p)->(%s %08x %08lx %p %ld %p %ld)\n", iface, debugstr_w(pwzUrl), ParseAction,
404             dwParseFlags, pwzResult, cchResult, pcchResult, dwReserved);
405
406     if(ParseAction == PARSE_SECURITY_URL) {
407         int len = lstrlenW(pwzUrl);
408
409         if(len >= cchResult)
410             return S_FALSE;
411
412         memcpy(pwzResult, pwzUrl, (len+1)*sizeof(WCHAR));
413         return S_OK;
414     }
415
416     if(ParseAction == PARSE_DOMAIN) {
417         /* Tests show that we don't have to do anything here */
418         return S_OK;
419     }
420
421     return INET_E_DEFAULT_ACTION;
422 }
423
424 static HRESULT WINAPI AboutProtocolInfo_CombineUrl(IInternetProtocolInfo *iface, LPCWSTR pwzBaseUrl,
425         LPCWSTR pwzRelativeUrl, DWORD dwCombineFlags, LPWSTR pwzResult, DWORD cchResult,
426         DWORD* pcchResult, DWORD dwReserved)
427 {
428     FIXME("%p)->(%s %s %08lx %p %ld %p %ld)\n", iface, debugstr_w(pwzBaseUrl), debugstr_w(pwzRelativeUrl),
429             dwCombineFlags, pwzResult, cchResult, pcchResult, dwReserved);
430     return E_NOTIMPL;
431 }
432
433 static HRESULT WINAPI AboutProtocolInfo_CompareUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl1,
434         LPCWSTR pwzUrl2, DWORD dwCompareFlags)
435 {
436     FIXME("%p)->(%s %s %08lx)\n", iface, debugstr_w(pwzUrl1), debugstr_w(pwzUrl2), dwCompareFlags);
437     return E_NOTIMPL;
438 }
439
440 static HRESULT WINAPI AboutProtocolInfo_QueryInfo(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
441         QUERYOPTION QueryOption, DWORD dwQueryFlags, LPVOID pBuffer, DWORD cbBuffer, DWORD* pcbBuf,
442         DWORD dwReserved)
443 {
444     FIXME("%p)->(%s %08x %08lx %p %ld %p %ld)\n", iface, debugstr_w(pwzUrl), QueryOption, dwQueryFlags, pBuffer,
445             cbBuffer, pcbBuf, dwReserved);
446     return E_NOTIMPL;
447 }
448
449 static const IInternetProtocolInfoVtbl AboutProtocolInfoVtbl = {
450     InternetProtocolInfo_QueryInterface,
451     InternetProtocolInfo_AddRef,
452     InternetProtocolInfo_Release,
453     AboutProtocolInfo_ParseUrl,
454     AboutProtocolInfo_CombineUrl,
455     AboutProtocolInfo_CompareUrl,
456     AboutProtocolInfo_QueryInfo
457 };
458
459 static const IClassFactoryVtbl AboutProtocolFactoryVtbl = {
460     ClassFactory_QueryInterface,
461     ClassFactory_AddRef,
462     ClassFactory_Release,
463     AboutProtocolFactory_CreateInstance,
464     ClassFactory_LockServer
465 };
466
467 static ProtocolFactory AboutProtocolFactory = {
468     &AboutProtocolInfoVtbl,
469     &AboutProtocolFactoryVtbl
470 };
471
472 /********************************************************************
473  * ResProtocol implementation
474  */
475
476 typedef struct {
477     const IInternetProtocolVtbl *lpInternetProtocolVtbl;
478     LONG ref;
479
480     BYTE *data;
481     ULONG data_len;
482     ULONG cur;
483
484     IUnknown *pUnkOuter;
485 } ResProtocol;
486
487 #define PROTOCOL_THIS(iface) DEFINE_THIS(ResProtocol, InternetProtocol, iface)
488
489 static HRESULT WINAPI ResProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
490 {
491     ResProtocol *This = PROTOCOL_THIS(iface);
492
493     *ppv = NULL;
494
495     if(IsEqualGUID(&IID_IUnknown, riid)) {
496         TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv);
497         if(This->pUnkOuter)
498             return IUnknown_QueryInterface(This->pUnkOuter, &IID_IUnknown, ppv);
499         *ppv = PROTOCOL(This);
500     }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
501         TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", iface, ppv);
502         *ppv = PROTOCOL(This);
503     }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
504         TRACE("(%p)->(IID_IInternetProtocol %p)\n", iface, ppv);
505         *ppv = PROTOCOL(This);
506     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
507         FIXME("IServiceProvider is not implemented\n");
508         return E_NOINTERFACE;
509     }
510
511     if(!*ppv) {
512         TRACE("unknown interface %s\n", debugstr_guid(riid));
513         return E_NOINTERFACE;
514     }
515
516     IInternetProtocol_AddRef(iface);
517     return S_OK;
518 }
519
520 static ULONG WINAPI ResProtocol_AddRef(IInternetProtocol *iface)
521 {
522     ResProtocol *This = PROTOCOL_THIS(iface);
523     ULONG ref = InterlockedIncrement(&This->ref);
524     TRACE("(%p) ref=%ld\n", iface, ref);
525     return This->pUnkOuter ? IUnknown_AddRef(This->pUnkOuter) : ref;
526 }
527
528 static ULONG WINAPI ResProtocol_Release(IInternetProtocol *iface)
529 {
530     ResProtocol *This = (ResProtocol*)iface;
531     IUnknown *pUnkOuter = This->pUnkOuter;
532     ULONG ref = InterlockedDecrement(&This->ref);
533
534     TRACE("(%p) ref=%lx\n", iface, ref);
535
536     if(!ref) {
537         HeapFree(GetProcessHeap(), 0, This->data);
538         HeapFree(GetProcessHeap(), 0, This);
539         UNLOCK_MODULE();
540     }
541
542     return pUnkOuter ? IUnknown_Release(pUnkOuter) : ref;
543 }
544
545 static HRESULT WINAPI ResProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
546         IInternetProtocolSink* pOIProtSink, IInternetBindInfo* pOIBindInfo,
547         DWORD grfPI, DWORD dwReserved)
548 {
549     ResProtocol *This = PROTOCOL_THIS(iface);
550     DWORD grfBINDF = 0;
551     BINDINFO bindinfo;
552     int len;
553     WCHAR dll[MAX_PATH];
554     LPCWSTR url_dll, url_file;
555     HMODULE hdll;
556     HRSRC src;
557
558     static const WCHAR wszRes[] = {'r','e','s',':','/','/'};
559
560     TRACE("(%p)->(%s %p %p %08lx %ld)\n", This, debugstr_w(szUrl), pOIProtSink,
561             pOIBindInfo, grfPI, dwReserved);
562
563     memset(&bindinfo, 0, sizeof(bindinfo));
564     bindinfo.cbSize = sizeof(BINDINFO);
565     IInternetBindInfo_GetBindInfo(pOIBindInfo, &grfBINDF, &bindinfo);
566     ReleaseBindInfo(&bindinfo);
567
568     /* FIXME:
569      * Implement MIME type checking
570      * Use CoInternetParseUrl (not implemented yet)
571      */
572
573     len = strlenW(szUrl);
574     if(len < sizeof(wszRes)/sizeof(wszRes[0]) || memcmp(szUrl, wszRes, sizeof(wszRes))) {
575         WARN("Wrong protocol of url: %s\n", debugstr_w(szUrl));
576         IInternetProtocolSink_ReportResult(pOIProtSink, MK_E_SYNTAX, 0, NULL);
577         return MK_E_SYNTAX;
578     }
579
580     url_dll = szUrl + sizeof(wszRes)/sizeof(wszRes[0]);
581     if(!(url_file = strchrW(url_dll, '/'))) {
582         WARN("wrong url: %s\n", debugstr_w(szUrl));
583         IInternetProtocolSink_ReportResult(pOIProtSink, MK_E_SYNTAX, 0, NULL);
584         return MK_E_SYNTAX;
585     }
586
587     memcpy(dll, url_dll, (url_file-url_dll)*sizeof(WCHAR));
588     dll[url_file-url_dll] = 0;
589
590     hdll = LoadLibraryExW(dll, NULL, LOAD_LIBRARY_AS_DATAFILE);
591     if(!hdll) {
592         WARN("Could not open dll: %s\n", debugstr_w(dll));
593         IInternetProtocolSink_ReportResult(pOIProtSink, HRESULT_FROM_WIN32(GetLastError()), 0, NULL);
594         return HRESULT_FROM_WIN32(GetLastError());
595     }
596
597     src = FindResourceW(hdll, ++url_file, (LPCWSTR)RT_HTML);
598     if(!src) {
599         WARN("Could not find resource: %s\n", debugstr_w(url_file));
600         IInternetProtocolSink_ReportResult(pOIProtSink, HRESULT_FROM_WIN32(GetLastError()), 0, NULL);
601         return HRESULT_FROM_WIN32(GetLastError());
602     }
603
604     if(This->data) {
605         WARN("data already loaded\n");
606         HeapFree(GetProcessHeap(), 0, This->data);
607     }
608
609     This->data_len = SizeofResource(hdll, src);
610     This->data = HeapAlloc(GetProcessHeap(), 0, This->data_len);
611     memcpy(This->data, LoadResource(hdll, src), This->data_len);
612     This->cur = 0;
613
614     FreeLibrary(hdll);
615
616     IInternetProtocolSink_ReportData(pOIProtSink,
617             BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE,
618             This->data_len, This->data_len);
619
620     IInternetProtocolSink_ReportResult(pOIProtSink, S_OK, 0, NULL);
621     
622     return S_OK;
623 }
624
625 static HRESULT WINAPI ResProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA* pProtocolData)
626 {
627     ResProtocol *This = PROTOCOL_THIS(iface);
628     FIXME("(%p)->(%p)\n", This, pProtocolData);
629     return E_NOTIMPL;
630 }
631
632 static HRESULT WINAPI ResProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
633         DWORD dwOptions)
634 {
635     ResProtocol *This = PROTOCOL_THIS(iface);
636     FIXME("(%p)->(%08lx %08lx)\n", This, hrReason, dwOptions);
637     return E_NOTIMPL;
638 }
639
640 static HRESULT WINAPI ResProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
641 {
642     ResProtocol *This = PROTOCOL_THIS(iface);
643
644     TRACE("(%p)->(%08lx)\n", This, dwOptions);
645
646     /* test show that we don't have to do anything here */
647     return S_OK;
648 }
649
650 static HRESULT WINAPI ResProtocol_Suspend(IInternetProtocol *iface)
651 {
652     ResProtocol *This = PROTOCOL_THIS(iface);
653     FIXME("(%p)\n", This);
654     return E_NOTIMPL;
655 }
656
657 static HRESULT WINAPI ResProtocol_Resume(IInternetProtocol *iface)
658 {
659     ResProtocol *This = PROTOCOL_THIS(iface);
660     FIXME("(%p)\n", This);
661     return E_NOTIMPL;
662 }
663
664 static HRESULT WINAPI ResProtocol_Read(IInternetProtocol *iface, void* pv, ULONG cb, ULONG* pcbRead)
665 {
666     ResProtocol *This = PROTOCOL_THIS(iface);
667
668     TRACE("(%p)->(%p %lu %p)\n", This, pv, cb, pcbRead);
669
670     if(!This->data)
671         return E_FAIL;
672
673     *pcbRead = (cb > This->data_len-This->cur ? This->data_len-This->cur : cb);
674
675     if(!*pcbRead)
676         return S_FALSE;
677
678     memcpy(pv, This->data, *pcbRead);
679     This->cur += *pcbRead;
680
681     return S_OK;
682 }
683
684 static HRESULT WINAPI ResProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
685         DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition)
686 {
687     ResProtocol *This = PROTOCOL_THIS(iface);
688     FIXME("(%p)->(%ld %ld %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
689     return E_NOTIMPL;
690 }
691
692 static HRESULT WINAPI ResProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
693 {
694     ResProtocol *This = PROTOCOL_THIS(iface);
695
696     TRACE("(%p)->(%ld)\n", This, dwOptions);
697
698     /* test show that we don't have to do anything here */
699     return S_OK;
700 }
701
702 static HRESULT WINAPI ResProtocol_UnlockRequest(IInternetProtocol *iface)
703 {
704     ResProtocol *This = PROTOCOL_THIS(iface);
705
706     TRACE("(%p)\n", This);
707
708     /* test show that we don't have to do anything here */
709     return S_OK;
710 }
711
712 #undef PROTOCOL_THIS
713
714 static const IInternetProtocolVtbl ResProtocolVtbl = {
715     ResProtocol_QueryInterface,
716     ResProtocol_AddRef,
717     ResProtocol_Release,
718     ResProtocol_Start,
719     ResProtocol_Continue,
720     ResProtocol_Abort,
721     ResProtocol_Terminate,
722     ResProtocol_Suspend,
723     ResProtocol_Resume,
724     ResProtocol_Read,
725     ResProtocol_Seek,
726     ResProtocol_LockRequest,
727     ResProtocol_UnlockRequest
728 };
729
730 static HRESULT WINAPI ResProtocolFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter,
731         REFIID riid, void **ppv)
732 {
733     ResProtocol *ret;
734     HRESULT hres = S_OK;
735
736     TRACE("(%p)->(%p %s %p)\n", iface, pUnkOuter, debugstr_guid(riid), ppv);
737
738     ret = HeapAlloc(GetProcessHeap(), 0, sizeof(ResProtocol));
739     ret->lpInternetProtocolVtbl = &ResProtocolVtbl;
740     ret->ref = 0;
741     ret->data = NULL;
742     ret->data_len = 0;
743     ret->cur = 0;
744     ret->pUnkOuter = pUnkOuter;
745
746     if(pUnkOuter) {
747         ret->ref = 1;
748         if(IsEqualGUID(&IID_IUnknown, riid))
749             *ppv = PROTOCOL(ret);
750         else
751             hres = E_FAIL;
752     }else {
753         hres = IInternetProtocol_QueryInterface(PROTOCOL(ret), riid, ppv);
754     }
755
756     if(SUCCEEDED(hres))
757         LOCK_MODULE();
758     else
759         HeapFree(GetProcessHeap(), 0, ret);
760
761     return hres;
762 }
763
764 static HRESULT WINAPI ResProtocolInfo_ParseUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
765         PARSEACTION ParseAction, DWORD dwParseFlags, LPWSTR pwzResult, DWORD cchResult,
766         DWORD* pcchResult, DWORD dwReserved)
767 {
768     TRACE("%p)->(%s %d %lx %p %ld %p %ld)\n", iface, debugstr_w(pwzUrl), ParseAction,
769             dwParseFlags, pwzResult, cchResult, pcchResult, dwReserved);
770
771     if(ParseAction == PARSE_SECURITY_URL) {
772         WCHAR *ptr;
773         DWORD size;
774
775         static const WCHAR wszFile[] = {'f','i','l','e',':','/','/'};
776         static const WCHAR wszRes[] = {'r','e','s',':','/','/'};
777
778         if(strlenW(pwzUrl) <= sizeof(wszRes)/sizeof(WCHAR) || memcmp(pwzUrl, wszRes, sizeof(wszRes)))
779             return MK_E_SYNTAX;
780
781         ptr = strchrW(pwzUrl + sizeof(wszRes)/sizeof(WCHAR), '/');
782         if(!ptr)
783             return MK_E_SYNTAX;
784
785         size = ptr-pwzUrl + sizeof(wszFile)/sizeof(WCHAR) - sizeof(wszRes)/sizeof(WCHAR);
786         if(size >= cchResult)
787             return S_FALSE;
788
789         /* FIXME: return full path */
790         memcpy(pwzResult, wszFile, sizeof(wszFile));
791         memcpy(pwzResult + sizeof(wszFile)/sizeof(WCHAR),
792                 pwzUrl + sizeof(wszRes)/sizeof(WCHAR),
793                 size*sizeof(WCHAR) - sizeof(wszFile));
794         pwzResult[size] = 0;
795
796         if(pcchResult)
797             *pcchResult = size;
798         return S_OK;
799     }
800
801     if(ParseAction == PARSE_DOMAIN) {
802         /* Tests show that we don't have to do anything here */
803         return S_OK;
804     }
805
806     return INET_E_DEFAULT_ACTION;
807 }
808
809 static HRESULT WINAPI ResProtocolInfo_CombineUrl(IInternetProtocolInfo *iface, LPCWSTR pwzBaseUrl,
810         LPCWSTR pwzRelativeUrl, DWORD dwCombineFlags, LPWSTR pwzResult, DWORD cchResult,
811         DWORD* pcchResult, DWORD dwReserved)
812 {
813     FIXME("%p)->(%s %s %08lx %p %ld %p %ld)\n", iface, debugstr_w(pwzBaseUrl), debugstr_w(pwzRelativeUrl),
814             dwCombineFlags, pwzResult, cchResult, pcchResult, dwReserved);
815     return E_NOTIMPL;
816 }
817
818 static HRESULT WINAPI ResProtocolInfo_CompareUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl1,
819         LPCWSTR pwzUrl2, DWORD dwCompareFlags)
820 {
821     FIXME("%p)->(%s %s %08lx)\n", iface, debugstr_w(pwzUrl1), debugstr_w(pwzUrl2), dwCompareFlags);
822     return E_NOTIMPL;
823 }
824
825 static HRESULT WINAPI ResProtocolInfo_QueryInfo(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
826         QUERYOPTION QueryOption, DWORD dwQueryFlags, LPVOID pBuffer, DWORD cbBuffer, DWORD* pcbBuf,
827         DWORD dwReserved)
828 {
829     FIXME("%p)->(%s %08x %08lx %p %ld %p %ld)\n", iface, debugstr_w(pwzUrl), QueryOption, dwQueryFlags, pBuffer,
830             cbBuffer, pcbBuf, dwReserved);
831     return E_NOTIMPL;
832 }
833
834 static const IInternetProtocolInfoVtbl ResProtocolInfoVtbl = {
835     InternetProtocolInfo_QueryInterface,
836     InternetProtocolInfo_AddRef,
837     InternetProtocolInfo_Release,
838     ResProtocolInfo_ParseUrl,
839     ResProtocolInfo_CombineUrl,
840     ResProtocolInfo_CompareUrl,
841     ResProtocolInfo_QueryInfo
842 };
843
844 static const IClassFactoryVtbl ResProtocolFactoryVtbl = {
845     ClassFactory_QueryInterface,
846     ClassFactory_AddRef,
847     ClassFactory_Release,
848     ResProtocolFactory_CreateInstance,
849     ClassFactory_LockServer
850 };
851
852 static ProtocolFactory ResProtocolFactory = {
853     &ResProtocolInfoVtbl,
854     &ResProtocolFactoryVtbl
855 };
856
857 HRESULT ProtocolFactory_Create(REFCLSID rclsid, REFIID riid, void **ppv)
858 {
859     ProtocolFactory *cf = NULL;
860
861     if(IsEqualGUID(&CLSID_AboutProtocol, rclsid))
862         cf = &AboutProtocolFactory;
863     else if(IsEqualGUID(&CLSID_ResProtocol, rclsid))
864         cf = &ResProtocolFactory;
865
866     if(!cf) {
867         FIXME("not implemented protocol %s\n", debugstr_guid(rclsid));
868         return CLASS_E_CLASSNOTAVAILABLE;
869     }
870  
871     return IUnknown_QueryInterface((IUnknown*)cf, riid, ppv);
872 }