Fix protocol test on winxp.
[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 static HRESULT WINAPI AboutProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
149 {
150     AboutProtocol *This = (AboutProtocol*)iface;
151
152     *ppv = NULL;
153
154     if(IsEqualGUID(&IID_IUnknown, riid)) {
155         TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv);
156         if(This->pUnkOuter)
157             return IUnknown_QueryInterface(This->pUnkOuter, riid, ppv);
158         *ppv = PROTOCOL(This);
159     }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
160         TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", iface, ppv);
161         *ppv = PROTOCOL(This);
162     }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
163         TRACE("(%p)->(IID_IInternetProtocol %p)\n", iface, ppv);
164         *ppv = PROTOCOL(This);
165     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
166         FIXME("IServiceProvider is not implemented\n");
167         return E_NOINTERFACE;
168     }
169
170     if(!*ppv) {
171         TRACE("unknown interface %s\n", debugstr_guid(riid));
172         return E_NOINTERFACE;
173     }
174
175     IInternetProtocol_AddRef(iface);
176     return S_OK;
177 }
178
179 static ULONG WINAPI AboutProtocol_AddRef(IInternetProtocol *iface)
180 {
181     AboutProtocol *This = (AboutProtocol*)iface;
182     ULONG ref = InterlockedIncrement(&This->ref);
183     TRACE("(%p) ref=%ld\n", iface, ref);
184     return This->pUnkOuter ? IUnknown_AddRef(This->pUnkOuter) : ref;
185 }
186
187 static ULONG WINAPI AboutProtocol_Release(IInternetProtocol *iface)
188 {
189     AboutProtocol *This = (AboutProtocol*)iface;
190     ULONG ref = InterlockedDecrement(&This->ref);
191
192     TRACE("(%p) ref=%lx\n", iface, ref);
193
194     if(!ref) {
195         HeapFree(GetProcessHeap(), 0, This->data);
196         HeapFree(GetProcessHeap(), 0, This);
197         UNLOCK_MODULE();
198     }
199
200     return This->pUnkOuter ? IUnknown_Release(This->pUnkOuter) : ref;
201 }
202
203 static HRESULT WINAPI AboutProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
204         IInternetProtocolSink* pOIProtSink, IInternetBindInfo* pOIBindInfo,
205         DWORD grfPI, DWORD dwReserved)
206 {
207     AboutProtocol *This = (AboutProtocol*)iface;
208     BINDINFO bindinfo;
209     DWORD grfBINDF = 0;
210     LPCWSTR text = NULL;
211
212     static const WCHAR html_begin[] = {0xfeff,'<','H','T','M','L','>',0};
213     static const WCHAR html_end[] = {'<','/','H','T','M','L','>',0};
214     static const WCHAR wszBlank[] = {'b','l','a','n','k',0};
215     static const WCHAR wszAbout[] = {'a','b','o','u','t',':'};
216     static const WCHAR wszTextHtml[] = {'t','e','x','t','/','h','t','m','l',0};
217
218     /* NOTE:
219      * the about protocol seems not to work as I would expect. It creates html document
220      * for a given url, eg. about:some_text -> <HTML>some_text</HTML> except for the case when
221      * some_text = "blank", when document is blank (<HTML></HMTL>). The same happens
222      * when the url does not have "about:" in the beginning.
223      */
224
225     TRACE("(%p)->(%s %p %p %08lx %ld)\n", This, debugstr_w(szUrl), pOIProtSink,
226             pOIBindInfo, grfPI, dwReserved);
227
228     memset(&bindinfo, 0, sizeof(bindinfo));
229     bindinfo.cbSize = sizeof(BINDINFO);
230     IInternetBindInfo_GetBindInfo(pOIBindInfo, &grfBINDF, &bindinfo);
231
232     if(strlenW(szUrl)>=sizeof(wszAbout)/sizeof(WCHAR) && !memcmp(wszAbout, szUrl, sizeof(wszAbout))) {
233         text = szUrl + sizeof(wszAbout)/sizeof(WCHAR);
234         if(!strcmpW(wszBlank, text))
235             text = NULL;
236     }
237
238     This->data_len = sizeof(html_begin)+sizeof(html_end)-sizeof(WCHAR) 
239         + (text ? strlenW(text)*sizeof(WCHAR) : 0);
240     This->data = HeapAlloc(GetProcessHeap(), 0, This->data_len);
241
242     memcpy(This->data, html_begin, sizeof(html_begin));
243     if(text)
244         strcatW((LPWSTR)This->data, text);
245     strcatW((LPWSTR)This->data, html_end);
246     
247     This->cur = 0;
248
249     IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_MIMETYPEAVAILABLE, wszTextHtml);
250
251     IInternetProtocolSink_ReportData(pOIProtSink,
252             BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE,
253             This->data_len, This->data_len);
254
255     IInternetProtocolSink_ReportResult(pOIProtSink, S_OK, 0, NULL);
256
257     return S_OK;
258 }
259
260 static HRESULT WINAPI AboutProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA* pProtocolData)
261 {
262     AboutProtocol *This = (AboutProtocol*)iface;
263     FIXME("(%p)->(%p)\n", This, pProtocolData);
264     return E_NOTIMPL;
265 }
266
267 static HRESULT WINAPI AboutProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
268         DWORD dwOptions)
269 {
270     AboutProtocol *This = (AboutProtocol*)iface;
271     FIXME("(%p)->(%08lx %08lx)\n", This, hrReason, dwOptions);
272     return E_NOTIMPL;
273 }
274
275 static HRESULT WINAPI AboutProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
276 {
277     AboutProtocol *This = (AboutProtocol*)iface;
278     TRACE("(%p)->(%08lx)\n", This, dwOptions);
279     return S_OK;
280 }
281
282 static HRESULT WINAPI AboutProtocol_Suspend(IInternetProtocol *iface)
283 {
284     AboutProtocol *This = (AboutProtocol*)iface;
285     FIXME("(%p)\n", This);
286     return E_NOTIMPL;
287 }
288
289 static HRESULT WINAPI AboutProtocol_Resume(IInternetProtocol *iface)
290 {
291     AboutProtocol *This = (AboutProtocol*)iface;
292     FIXME("(%p)\n", This);
293     return E_NOTIMPL;
294 }
295
296 static HRESULT WINAPI AboutProtocol_Read(IInternetProtocol *iface, void* pv, ULONG cb, ULONG* pcbRead)
297 {
298     AboutProtocol *This = (AboutProtocol*)iface;
299
300     TRACE("(%p)->(%p %lu %p)\n", This, pv, cb, pcbRead);
301
302     if(!This->data)
303         return E_FAIL;
304
305     *pcbRead = (cb > This->data_len-This->cur ? This->data_len-This->cur : cb);
306
307     if(!*pcbRead)
308         return S_FALSE;
309
310     memcpy(pv, This->data, *pcbRead);
311     This->cur += *pcbRead;
312
313     return S_OK;
314 }
315
316 static HRESULT WINAPI AboutProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
317         DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition)
318 {
319     AboutProtocol *This = (AboutProtocol*)iface;
320     FIXME("(%p)->(%ld %ld %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
321     return E_NOTIMPL;
322 }
323
324 static HRESULT WINAPI AboutProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
325 {
326     AboutProtocol *This = (AboutProtocol*)iface;
327
328     TRACE("(%p)->(%ld)\n", This, dwOptions);
329
330     return S_OK;
331 }
332
333 static HRESULT WINAPI AboutProtocol_UnlockRequest(IInternetProtocol *iface)
334 {
335     AboutProtocol *This = (AboutProtocol*)iface;
336
337     TRACE("(%p)\n", This);
338
339     return S_OK;
340 }
341
342 static const IInternetProtocolVtbl AboutProtocolVtbl = {
343     AboutProtocol_QueryInterface,
344     AboutProtocol_AddRef,
345     AboutProtocol_Release,
346     AboutProtocol_Start,
347     AboutProtocol_Continue,
348     AboutProtocol_Abort,
349     AboutProtocol_Terminate,
350     AboutProtocol_Suspend,
351     AboutProtocol_Resume,
352     AboutProtocol_Read,
353     AboutProtocol_Seek,
354     AboutProtocol_LockRequest,
355     AboutProtocol_UnlockRequest
356 };
357
358 static HRESULT WINAPI AboutProtocolFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter,
359         REFIID riid, void **ppv)
360 {
361     AboutProtocol *ret;
362     HRESULT hres = S_OK;
363
364     TRACE("(%p)->(%p %s %p)\n", iface, pUnkOuter, debugstr_guid(riid), ppv);
365
366     ret = HeapAlloc(GetProcessHeap(), 0, sizeof(AboutProtocol));
367     ret->lpInternetProtocolVtbl = &AboutProtocolVtbl;
368     ret->ref = 0;
369
370     ret->data = NULL;
371     ret->data_len = 0;
372     ret->cur = 0;
373     ret->pUnkOuter = pUnkOuter;
374
375     if(pUnkOuter) {
376         ret->ref = 1;
377         if(IsEqualGUID(&IID_IUnknown, riid))
378             *ppv = PROTOCOL(ret);
379         else
380             hres = E_INVALIDARG;
381     }else {
382         hres = IInternetProtocol_QueryInterface(PROTOCOL(ret), riid, ppv);
383     }
384
385     if(SUCCEEDED(hres))
386         LOCK_MODULE();
387     else
388         HeapFree(GetProcessHeap(), 0, ret);
389
390     return hres;
391 }
392
393 static HRESULT WINAPI AboutProtocolInfo_ParseUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
394         PARSEACTION ParseAction, DWORD dwParseFlags, LPWSTR pwzResult, DWORD cchResult,
395         DWORD* pcchResult, DWORD dwReserved)
396 {
397     FIXME("%p)->(%s %08x %08lx %p %ld %p %ld)\n", iface, debugstr_w(pwzUrl), ParseAction,
398             dwParseFlags, pwzResult, cchResult, pcchResult, dwReserved);
399     return E_NOTIMPL;
400 }
401
402 static HRESULT WINAPI AboutProtocolInfo_CombineUrl(IInternetProtocolInfo *iface, LPCWSTR pwzBaseUrl,
403         LPCWSTR pwzRelativeUrl, DWORD dwCombineFlags, LPWSTR pwzResult, DWORD cchResult,
404         DWORD* pcchResult, DWORD dwReserved)
405 {
406     FIXME("%p)->(%s %s %08lx %p %ld %p %ld)\n", iface, debugstr_w(pwzBaseUrl), debugstr_w(pwzRelativeUrl),
407             dwCombineFlags, pwzResult, cchResult, pcchResult, dwReserved);
408     return E_NOTIMPL;
409 }
410
411 static HRESULT WINAPI AboutProtocolInfo_CompareUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl1,
412         LPCWSTR pwzUrl2, DWORD dwCompareFlags)
413 {
414     FIXME("%p)->(%s %s %08lx)\n", iface, debugstr_w(pwzUrl1), debugstr_w(pwzUrl2), dwCompareFlags);
415     return E_NOTIMPL;
416 }
417
418 static HRESULT WINAPI AboutProtocolInfo_QueryInfo(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
419         QUERYOPTION QueryOption, DWORD dwQueryFlags, LPVOID pBuffer, DWORD cbBuffer, DWORD* pcbBuf,
420         DWORD dwReserved)
421 {
422     FIXME("%p)->(%s %08x %08lx %p %ld %p %ld)\n", iface, debugstr_w(pwzUrl), QueryOption, dwQueryFlags, pBuffer,
423             cbBuffer, pcbBuf, dwReserved);
424     return E_NOTIMPL;
425 }
426
427 static const IInternetProtocolInfoVtbl AboutProtocolInfoVtbl = {
428     InternetProtocolInfo_QueryInterface,
429     InternetProtocolInfo_AddRef,
430     InternetProtocolInfo_Release,
431     AboutProtocolInfo_ParseUrl,
432     AboutProtocolInfo_CombineUrl,
433     AboutProtocolInfo_CompareUrl,
434     AboutProtocolInfo_QueryInfo
435 };
436
437 static const IClassFactoryVtbl AboutProtocolFactoryVtbl = {
438     ClassFactory_QueryInterface,
439     ClassFactory_AddRef,
440     ClassFactory_Release,
441     AboutProtocolFactory_CreateInstance,
442     ClassFactory_LockServer
443 };
444
445 static ProtocolFactory AboutProtocolFactory = {
446     &AboutProtocolInfoVtbl,
447     &AboutProtocolFactoryVtbl
448 };
449
450 /********************************************************************
451  * ResProtocol implementation
452  */
453
454 typedef struct {
455     const IInternetProtocolVtbl *lpInternetProtocolVtbl;
456     LONG ref;
457
458     BYTE *data;
459     ULONG data_len;
460     ULONG cur;
461 } ResProtocol;
462
463 static HRESULT WINAPI ResProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
464 {
465     *ppv = NULL;
466
467     if(IsEqualGUID(&IID_IUnknown, riid)) {
468         TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv);
469         *ppv = iface;
470     }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
471         TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", iface, ppv);
472         *ppv = iface;
473     }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
474         TRACE("(%p)->(IID_IInternetProtocol %p)\n", iface, ppv);
475         *ppv = iface;
476     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
477         FIXME("IServiceProvider is not implemented\n");
478         return E_NOINTERFACE;
479     }
480
481     if(!*ppv) {
482         TRACE("unknown interface %s\n", debugstr_guid(riid));
483         return E_NOINTERFACE;
484     }
485
486     IInternetProtocol_AddRef(iface);
487     return S_OK;
488 }
489
490 static ULONG WINAPI ResProtocol_AddRef(IInternetProtocol *iface)
491 {
492     ResProtocol *This = (ResProtocol*)iface;
493     ULONG ref = InterlockedIncrement(&This->ref);
494     TRACE("(%p) ref=%ld\n", iface, ref);
495     return ref;
496 }
497
498 static ULONG WINAPI ResProtocol_Release(IInternetProtocol *iface)
499 {
500     ResProtocol *This = (ResProtocol*)iface;
501     ULONG ref = InterlockedDecrement(&This->ref);
502
503     TRACE("(%p) ref=%lx\n", iface, ref);
504
505     if(!ref) {
506         HeapFree(GetProcessHeap(), 0, This->data);
507         HeapFree(GetProcessHeap(), 0, This);
508         UNLOCK_MODULE();
509     }
510
511     return ref;
512 }
513
514 static HRESULT WINAPI ResProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
515         IInternetProtocolSink* pOIProtSink, IInternetBindInfo* pOIBindInfo,
516         DWORD grfPI, DWORD dwReserved)
517 {
518     ResProtocol *This = (ResProtocol*)iface;
519     DWORD grfBINDF = 0;
520     BINDINFO bindinfo;
521     int len;
522     WCHAR dll[MAX_PATH];
523     LPCWSTR url_dll, url_file;
524     HMODULE hdll;
525     HRSRC src;
526
527     static const WCHAR wszRes[] = {'r','e','s',':','/','/'};
528
529     TRACE("(%p)->(%s %p %p %08lx %ld)\n", This, debugstr_w(szUrl), pOIProtSink,
530             pOIBindInfo, grfPI, dwReserved);
531
532     memset(&bindinfo, 0, sizeof(bindinfo));
533     bindinfo.cbSize = sizeof(BINDINFO);
534     IInternetBindInfo_GetBindInfo(pOIBindInfo, &grfBINDF, &bindinfo);
535
536     /* FIXME:
537      * Implement MIME type checking
538      * Use CoInternetParseUrl (not implemented yet)
539      */
540
541     len = strlenW(szUrl);
542     if(len < sizeof(wszRes)/sizeof(wszRes[0]) || memcmp(szUrl, wszRes, sizeof(wszRes))) {
543         WARN("Wrong protocol of url: %s\n", debugstr_w(szUrl));
544         IInternetProtocolSink_ReportResult(pOIProtSink, MK_E_SYNTAX, 0, NULL);
545         return MK_E_SYNTAX;
546     }
547
548     url_dll = szUrl + sizeof(wszRes)/sizeof(wszRes[0]);
549     if(!(url_file = strchrW(url_dll, '/'))) {
550         WARN("wrong url: %s\n", debugstr_w(szUrl));
551         IInternetProtocolSink_ReportResult(pOIProtSink, MK_E_SYNTAX, 0, NULL);
552         return MK_E_SYNTAX;
553     }
554
555     memcpy(dll, url_dll, (url_file-url_dll)*sizeof(WCHAR));
556     dll[url_file-url_dll] = 0;
557
558     hdll = LoadLibraryExW(dll, NULL, LOAD_LIBRARY_AS_DATAFILE);
559     if(!hdll) {
560         WARN("Could not open dll: %s\n", debugstr_w(dll));
561         IInternetProtocolSink_ReportResult(pOIProtSink, HRESULT_FROM_WIN32(GetLastError()), 0, NULL);
562         return HRESULT_FROM_WIN32(GetLastError());
563     }
564
565     src = FindResourceW(hdll, ++url_file, (LPCWSTR)RT_HTML);
566     if(!src) {
567         WARN("Could not find resource: %s\n", debugstr_w(url_file));
568         IInternetProtocolSink_ReportResult(pOIProtSink, HRESULT_FROM_WIN32(GetLastError()), 0, NULL);
569         return HRESULT_FROM_WIN32(GetLastError());
570     }
571
572     if(This->data) {
573         WARN("data already loaded\n");
574         HeapFree(GetProcessHeap(), 0, This->data);
575     }
576
577     This->data_len = SizeofResource(hdll, src);
578     This->data = HeapAlloc(GetProcessHeap(), 0, This->data_len);
579     memcpy(This->data, LoadResource(hdll, src), This->data_len);
580     This->cur = 0;
581
582     FreeLibrary(hdll);
583
584     IInternetProtocolSink_ReportData(pOIProtSink,
585             BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE,
586             This->data_len, This->data_len);
587
588     IInternetProtocolSink_ReportResult(pOIProtSink, S_OK, 0, NULL);
589     
590     return S_OK;
591 }
592
593 static HRESULT WINAPI ResProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA* pProtocolData)
594 {
595     ResProtocol *This = (ResProtocol*)iface;
596     FIXME("(%p)->(%p)\n", This, pProtocolData);
597     return E_NOTIMPL;
598 }
599
600 static HRESULT WINAPI ResProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
601         DWORD dwOptions)
602 {
603     ResProtocol *This = (ResProtocol*)iface;
604     FIXME("(%p)->(%08lx %08lx)\n", This, hrReason, dwOptions);
605     return E_NOTIMPL;
606 }
607
608 static HRESULT WINAPI ResProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
609 {
610     ResProtocol *This = (ResProtocol*)iface;
611
612     TRACE("(%p)->(%08lx)\n", This, dwOptions);
613
614     /* test show that we don't have to do anything here */
615     return S_OK;
616 }
617
618 static HRESULT WINAPI ResProtocol_Suspend(IInternetProtocol *iface)
619 {
620     ResProtocol *This = (ResProtocol*)iface;
621     FIXME("(%p)\n", This);
622     return E_NOTIMPL;
623 }
624
625 static HRESULT WINAPI ResProtocol_Resume(IInternetProtocol *iface)
626 {
627     ResProtocol *This = (ResProtocol*)iface;
628     FIXME("(%p)\n", This);
629     return E_NOTIMPL;
630 }
631
632 static HRESULT WINAPI ResProtocol_Read(IInternetProtocol *iface, void* pv, ULONG cb, ULONG* pcbRead)
633 {
634     ResProtocol *This = (ResProtocol*)iface;
635
636     TRACE("(%p)->(%p %lu %p)\n", This, pv, cb, pcbRead);
637
638     if(!This->data)
639         return E_FAIL;
640
641     *pcbRead = (cb > This->data_len-This->cur ? This->data_len-This->cur : cb);
642
643     if(!*pcbRead)
644         return S_FALSE;
645
646     memcpy(pv, This->data, *pcbRead);
647     This->cur += *pcbRead;
648
649     return S_OK;
650 }
651
652 static HRESULT WINAPI ResProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
653         DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition)
654 {
655     ResProtocol *This = (ResProtocol*)iface;
656     FIXME("(%p)->(%ld %ld %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
657     return E_NOTIMPL;
658 }
659
660 static HRESULT WINAPI ResProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
661 {
662     ResProtocol *This = (ResProtocol*)iface;
663
664     TRACE("(%p)->(%ld)\n", This, dwOptions);
665
666     /* test show that we don't have to do anything here */
667     return S_OK;
668 }
669
670 static HRESULT WINAPI ResProtocol_UnlockRequest(IInternetProtocol *iface)
671 {
672     ResProtocol *This = (ResProtocol*)iface;
673
674     TRACE("(%p)\n", This);
675
676     /* test show that we don't have to do anything here */
677     return S_OK;
678 }
679
680 static const IInternetProtocolVtbl ResProtocolVtbl = {
681     ResProtocol_QueryInterface,
682     ResProtocol_AddRef,
683     ResProtocol_Release,
684     ResProtocol_Start,
685     ResProtocol_Continue,
686     ResProtocol_Abort,
687     ResProtocol_Terminate,
688     ResProtocol_Suspend,
689     ResProtocol_Resume,
690     ResProtocol_Read,
691     ResProtocol_Seek,
692     ResProtocol_LockRequest,
693     ResProtocol_UnlockRequest
694 };
695
696 static HRESULT WINAPI ResProtocolFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter,
697         REFIID riid, void **ppv)
698 {
699     ResProtocol *ret;
700     HRESULT hres;
701
702     TRACE("(%p)->(%p %s %p)\n", iface, pUnkOuter, debugstr_guid(riid), ppv);
703
704     ret = HeapAlloc(GetProcessHeap(), 0, sizeof(ResProtocol));
705     ret->lpInternetProtocolVtbl = &ResProtocolVtbl;
706     ret->ref = 0;
707     ret->data = NULL;
708     ret->data_len = 0;
709     ret->cur = 0;
710
711     hres = IUnknown_QueryInterface((IUnknown*)ret, riid, ppv);
712
713     if(SUCCEEDED(hres))
714         LOCK_MODULE();
715     else
716         HeapFree(GetProcessHeap(), 0, ret);
717
718     return hres;
719 }
720
721 static HRESULT WINAPI ResProtocolInfo_ParseUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
722         PARSEACTION ParseAction, DWORD dwParseFlags, LPWSTR pwzResult, DWORD cchResult,
723         DWORD* pcchResult, DWORD dwReserved)
724 {
725     FIXME("%p)->(%s %08x %08lx %p %ld %p %ld)\n", iface, debugstr_w(pwzUrl), ParseAction,
726             dwParseFlags, pwzResult, cchResult, pcchResult, dwReserved);
727     return E_NOTIMPL;
728 }
729
730 static HRESULT WINAPI ResProtocolInfo_CombineUrl(IInternetProtocolInfo *iface, LPCWSTR pwzBaseUrl,
731         LPCWSTR pwzRelativeUrl, DWORD dwCombineFlags, LPWSTR pwzResult, DWORD cchResult,
732         DWORD* pcchResult, DWORD dwReserved)
733 {
734     FIXME("%p)->(%s %s %08lx %p %ld %p %ld)\n", iface, debugstr_w(pwzBaseUrl), debugstr_w(pwzRelativeUrl),
735             dwCombineFlags, pwzResult, cchResult, pcchResult, dwReserved);
736     return E_NOTIMPL;
737 }
738
739 static HRESULT WINAPI ResProtocolInfo_CompareUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl1,
740         LPCWSTR pwzUrl2, DWORD dwCompareFlags)
741 {
742     FIXME("%p)->(%s %s %08lx)\n", iface, debugstr_w(pwzUrl1), debugstr_w(pwzUrl2), dwCompareFlags);
743     return E_NOTIMPL;
744 }
745
746 static HRESULT WINAPI ResProtocolInfo_QueryInfo(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
747         QUERYOPTION QueryOption, DWORD dwQueryFlags, LPVOID pBuffer, DWORD cbBuffer, DWORD* pcbBuf,
748         DWORD dwReserved)
749 {
750     FIXME("%p)->(%s %08x %08lx %p %ld %p %ld)\n", iface, debugstr_w(pwzUrl), QueryOption, dwQueryFlags, pBuffer,
751             cbBuffer, pcbBuf, dwReserved);
752     return E_NOTIMPL;
753 }
754
755 static const IInternetProtocolInfoVtbl ResProtocolInfoVtbl = {
756     InternetProtocolInfo_QueryInterface,
757     InternetProtocolInfo_AddRef,
758     InternetProtocolInfo_Release,
759     ResProtocolInfo_ParseUrl,
760     ResProtocolInfo_CombineUrl,
761     ResProtocolInfo_CompareUrl,
762     ResProtocolInfo_QueryInfo
763 };
764
765 static const IClassFactoryVtbl ResProtocolFactoryVtbl = {
766     ClassFactory_QueryInterface,
767     ClassFactory_AddRef,
768     ClassFactory_Release,
769     ResProtocolFactory_CreateInstance,
770     ClassFactory_LockServer
771 };
772
773 static ProtocolFactory ResProtocolFactory = {
774     &ResProtocolInfoVtbl,
775     &ResProtocolFactoryVtbl
776 };
777
778 HRESULT ProtocolFactory_Create(REFCLSID rclsid, REFIID riid, void **ppv)
779 {
780     ProtocolFactory *cf = NULL;
781
782     if(IsEqualGUID(&CLSID_AboutProtocol, rclsid))
783         cf = &AboutProtocolFactory;
784     else if(IsEqualGUID(&CLSID_ResProtocol, rclsid))
785         cf = &ResProtocolFactory;
786
787     if(!cf) {
788         FIXME("not implemented protocol %s\n", debugstr_guid(rclsid));
789         return CLASS_E_CLASSNOTAVAILABLE;
790     }
791  
792     return IUnknown_QueryInterface((IUnknown*)cf, riid, ppv);
793 }