Use a more portable scheme for storing the name of a critical
[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     FIXME("%p)->(%s %08x %08lx %p %ld %p %ld)\n", iface, debugstr_w(pwzUrl), ParseAction,
404             dwParseFlags, pwzResult, cchResult, pcchResult, dwReserved);
405     return E_NOTIMPL;
406 }
407
408 static HRESULT WINAPI AboutProtocolInfo_CombineUrl(IInternetProtocolInfo *iface, LPCWSTR pwzBaseUrl,
409         LPCWSTR pwzRelativeUrl, DWORD dwCombineFlags, LPWSTR pwzResult, DWORD cchResult,
410         DWORD* pcchResult, DWORD dwReserved)
411 {
412     FIXME("%p)->(%s %s %08lx %p %ld %p %ld)\n", iface, debugstr_w(pwzBaseUrl), debugstr_w(pwzRelativeUrl),
413             dwCombineFlags, pwzResult, cchResult, pcchResult, dwReserved);
414     return E_NOTIMPL;
415 }
416
417 static HRESULT WINAPI AboutProtocolInfo_CompareUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl1,
418         LPCWSTR pwzUrl2, DWORD dwCompareFlags)
419 {
420     FIXME("%p)->(%s %s %08lx)\n", iface, debugstr_w(pwzUrl1), debugstr_w(pwzUrl2), dwCompareFlags);
421     return E_NOTIMPL;
422 }
423
424 static HRESULT WINAPI AboutProtocolInfo_QueryInfo(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
425         QUERYOPTION QueryOption, DWORD dwQueryFlags, LPVOID pBuffer, DWORD cbBuffer, DWORD* pcbBuf,
426         DWORD dwReserved)
427 {
428     FIXME("%p)->(%s %08x %08lx %p %ld %p %ld)\n", iface, debugstr_w(pwzUrl), QueryOption, dwQueryFlags, pBuffer,
429             cbBuffer, pcbBuf, dwReserved);
430     return E_NOTIMPL;
431 }
432
433 static const IInternetProtocolInfoVtbl AboutProtocolInfoVtbl = {
434     InternetProtocolInfo_QueryInterface,
435     InternetProtocolInfo_AddRef,
436     InternetProtocolInfo_Release,
437     AboutProtocolInfo_ParseUrl,
438     AboutProtocolInfo_CombineUrl,
439     AboutProtocolInfo_CompareUrl,
440     AboutProtocolInfo_QueryInfo
441 };
442
443 static const IClassFactoryVtbl AboutProtocolFactoryVtbl = {
444     ClassFactory_QueryInterface,
445     ClassFactory_AddRef,
446     ClassFactory_Release,
447     AboutProtocolFactory_CreateInstance,
448     ClassFactory_LockServer
449 };
450
451 static ProtocolFactory AboutProtocolFactory = {
452     &AboutProtocolInfoVtbl,
453     &AboutProtocolFactoryVtbl
454 };
455
456 /********************************************************************
457  * ResProtocol implementation
458  */
459
460 typedef struct {
461     const IInternetProtocolVtbl *lpInternetProtocolVtbl;
462     LONG ref;
463
464     BYTE *data;
465     ULONG data_len;
466     ULONG cur;
467
468     IUnknown *pUnkOuter;
469 } ResProtocol;
470
471 #define PROTOCOL_THIS(iface) DEFINE_THIS(ResProtocol, InternetProtocol, iface)
472
473 static HRESULT WINAPI ResProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
474 {
475     ResProtocol *This = PROTOCOL_THIS(iface);
476
477     *ppv = NULL;
478
479     if(IsEqualGUID(&IID_IUnknown, riid)) {
480         TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv);
481         if(This->pUnkOuter)
482             return IUnknown_QueryInterface(This->pUnkOuter, &IID_IUnknown, ppv);
483         *ppv = PROTOCOL(This);
484     }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
485         TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", iface, ppv);
486         *ppv = PROTOCOL(This);
487     }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
488         TRACE("(%p)->(IID_IInternetProtocol %p)\n", iface, ppv);
489         *ppv = PROTOCOL(This);
490     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
491         FIXME("IServiceProvider is not implemented\n");
492         return E_NOINTERFACE;
493     }
494
495     if(!*ppv) {
496         TRACE("unknown interface %s\n", debugstr_guid(riid));
497         return E_NOINTERFACE;
498     }
499
500     IInternetProtocol_AddRef(iface);
501     return S_OK;
502 }
503
504 static ULONG WINAPI ResProtocol_AddRef(IInternetProtocol *iface)
505 {
506     ResProtocol *This = PROTOCOL_THIS(iface);
507     ULONG ref = InterlockedIncrement(&This->ref);
508     TRACE("(%p) ref=%ld\n", iface, ref);
509     return This->pUnkOuter ? IUnknown_AddRef(This->pUnkOuter) : ref;
510 }
511
512 static ULONG WINAPI ResProtocol_Release(IInternetProtocol *iface)
513 {
514     ResProtocol *This = (ResProtocol*)iface;
515     IUnknown *pUnkOuter = This->pUnkOuter;
516     ULONG ref = InterlockedDecrement(&This->ref);
517
518     TRACE("(%p) ref=%lx\n", iface, ref);
519
520     if(!ref) {
521         HeapFree(GetProcessHeap(), 0, This->data);
522         HeapFree(GetProcessHeap(), 0, This);
523         UNLOCK_MODULE();
524     }
525
526     return pUnkOuter ? IUnknown_Release(pUnkOuter) : ref;
527 }
528
529 static HRESULT WINAPI ResProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
530         IInternetProtocolSink* pOIProtSink, IInternetBindInfo* pOIBindInfo,
531         DWORD grfPI, DWORD dwReserved)
532 {
533     ResProtocol *This = PROTOCOL_THIS(iface);
534     DWORD grfBINDF = 0;
535     BINDINFO bindinfo;
536     int len;
537     WCHAR dll[MAX_PATH];
538     LPCWSTR url_dll, url_file;
539     HMODULE hdll;
540     HRSRC src;
541
542     static const WCHAR wszRes[] = {'r','e','s',':','/','/'};
543
544     TRACE("(%p)->(%s %p %p %08lx %ld)\n", This, debugstr_w(szUrl), pOIProtSink,
545             pOIBindInfo, grfPI, dwReserved);
546
547     memset(&bindinfo, 0, sizeof(bindinfo));
548     bindinfo.cbSize = sizeof(BINDINFO);
549     IInternetBindInfo_GetBindInfo(pOIBindInfo, &grfBINDF, &bindinfo);
550     ReleaseBindInfo(&bindinfo);
551
552     /* FIXME:
553      * Implement MIME type checking
554      * Use CoInternetParseUrl (not implemented yet)
555      */
556
557     len = strlenW(szUrl);
558     if(len < sizeof(wszRes)/sizeof(wszRes[0]) || memcmp(szUrl, wszRes, sizeof(wszRes))) {
559         WARN("Wrong protocol of url: %s\n", debugstr_w(szUrl));
560         IInternetProtocolSink_ReportResult(pOIProtSink, MK_E_SYNTAX, 0, NULL);
561         return MK_E_SYNTAX;
562     }
563
564     url_dll = szUrl + sizeof(wszRes)/sizeof(wszRes[0]);
565     if(!(url_file = strchrW(url_dll, '/'))) {
566         WARN("wrong url: %s\n", debugstr_w(szUrl));
567         IInternetProtocolSink_ReportResult(pOIProtSink, MK_E_SYNTAX, 0, NULL);
568         return MK_E_SYNTAX;
569     }
570
571     memcpy(dll, url_dll, (url_file-url_dll)*sizeof(WCHAR));
572     dll[url_file-url_dll] = 0;
573
574     hdll = LoadLibraryExW(dll, NULL, LOAD_LIBRARY_AS_DATAFILE);
575     if(!hdll) {
576         WARN("Could not open dll: %s\n", debugstr_w(dll));
577         IInternetProtocolSink_ReportResult(pOIProtSink, HRESULT_FROM_WIN32(GetLastError()), 0, NULL);
578         return HRESULT_FROM_WIN32(GetLastError());
579     }
580
581     src = FindResourceW(hdll, ++url_file, (LPCWSTR)RT_HTML);
582     if(!src) {
583         WARN("Could not find resource: %s\n", debugstr_w(url_file));
584         IInternetProtocolSink_ReportResult(pOIProtSink, HRESULT_FROM_WIN32(GetLastError()), 0, NULL);
585         return HRESULT_FROM_WIN32(GetLastError());
586     }
587
588     if(This->data) {
589         WARN("data already loaded\n");
590         HeapFree(GetProcessHeap(), 0, This->data);
591     }
592
593     This->data_len = SizeofResource(hdll, src);
594     This->data = HeapAlloc(GetProcessHeap(), 0, This->data_len);
595     memcpy(This->data, LoadResource(hdll, src), This->data_len);
596     This->cur = 0;
597
598     FreeLibrary(hdll);
599
600     IInternetProtocolSink_ReportData(pOIProtSink,
601             BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE,
602             This->data_len, This->data_len);
603
604     IInternetProtocolSink_ReportResult(pOIProtSink, S_OK, 0, NULL);
605     
606     return S_OK;
607 }
608
609 static HRESULT WINAPI ResProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA* pProtocolData)
610 {
611     ResProtocol *This = PROTOCOL_THIS(iface);
612     FIXME("(%p)->(%p)\n", This, pProtocolData);
613     return E_NOTIMPL;
614 }
615
616 static HRESULT WINAPI ResProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
617         DWORD dwOptions)
618 {
619     ResProtocol *This = PROTOCOL_THIS(iface);
620     FIXME("(%p)->(%08lx %08lx)\n", This, hrReason, dwOptions);
621     return E_NOTIMPL;
622 }
623
624 static HRESULT WINAPI ResProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
625 {
626     ResProtocol *This = PROTOCOL_THIS(iface);
627
628     TRACE("(%p)->(%08lx)\n", This, dwOptions);
629
630     /* test show that we don't have to do anything here */
631     return S_OK;
632 }
633
634 static HRESULT WINAPI ResProtocol_Suspend(IInternetProtocol *iface)
635 {
636     ResProtocol *This = PROTOCOL_THIS(iface);
637     FIXME("(%p)\n", This);
638     return E_NOTIMPL;
639 }
640
641 static HRESULT WINAPI ResProtocol_Resume(IInternetProtocol *iface)
642 {
643     ResProtocol *This = PROTOCOL_THIS(iface);
644     FIXME("(%p)\n", This);
645     return E_NOTIMPL;
646 }
647
648 static HRESULT WINAPI ResProtocol_Read(IInternetProtocol *iface, void* pv, ULONG cb, ULONG* pcbRead)
649 {
650     ResProtocol *This = PROTOCOL_THIS(iface);
651
652     TRACE("(%p)->(%p %lu %p)\n", This, pv, cb, pcbRead);
653
654     if(!This->data)
655         return E_FAIL;
656
657     *pcbRead = (cb > This->data_len-This->cur ? This->data_len-This->cur : cb);
658
659     if(!*pcbRead)
660         return S_FALSE;
661
662     memcpy(pv, This->data, *pcbRead);
663     This->cur += *pcbRead;
664
665     return S_OK;
666 }
667
668 static HRESULT WINAPI ResProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
669         DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition)
670 {
671     ResProtocol *This = PROTOCOL_THIS(iface);
672     FIXME("(%p)->(%ld %ld %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
673     return E_NOTIMPL;
674 }
675
676 static HRESULT WINAPI ResProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
677 {
678     ResProtocol *This = PROTOCOL_THIS(iface);
679
680     TRACE("(%p)->(%ld)\n", This, dwOptions);
681
682     /* test show that we don't have to do anything here */
683     return S_OK;
684 }
685
686 static HRESULT WINAPI ResProtocol_UnlockRequest(IInternetProtocol *iface)
687 {
688     ResProtocol *This = PROTOCOL_THIS(iface);
689
690     TRACE("(%p)\n", This);
691
692     /* test show that we don't have to do anything here */
693     return S_OK;
694 }
695
696 #undef PROTOCOL_THIS
697
698 static const IInternetProtocolVtbl ResProtocolVtbl = {
699     ResProtocol_QueryInterface,
700     ResProtocol_AddRef,
701     ResProtocol_Release,
702     ResProtocol_Start,
703     ResProtocol_Continue,
704     ResProtocol_Abort,
705     ResProtocol_Terminate,
706     ResProtocol_Suspend,
707     ResProtocol_Resume,
708     ResProtocol_Read,
709     ResProtocol_Seek,
710     ResProtocol_LockRequest,
711     ResProtocol_UnlockRequest
712 };
713
714 static HRESULT WINAPI ResProtocolFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter,
715         REFIID riid, void **ppv)
716 {
717     ResProtocol *ret;
718     HRESULT hres = S_OK;
719
720     TRACE("(%p)->(%p %s %p)\n", iface, pUnkOuter, debugstr_guid(riid), ppv);
721
722     ret = HeapAlloc(GetProcessHeap(), 0, sizeof(ResProtocol));
723     ret->lpInternetProtocolVtbl = &ResProtocolVtbl;
724     ret->ref = 0;
725     ret->data = NULL;
726     ret->data_len = 0;
727     ret->cur = 0;
728     ret->pUnkOuter = pUnkOuter;
729
730     if(pUnkOuter) {
731         ret->ref = 1;
732         if(IsEqualGUID(&IID_IUnknown, riid))
733             *ppv = PROTOCOL(ret);
734         else
735             hres = E_FAIL;
736     }else {
737         hres = IInternetProtocol_QueryInterface(PROTOCOL(ret), riid, ppv);
738     }
739
740     if(SUCCEEDED(hres))
741         LOCK_MODULE();
742     else
743         HeapFree(GetProcessHeap(), 0, ret);
744
745     return hres;
746 }
747
748 static HRESULT WINAPI ResProtocolInfo_ParseUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
749         PARSEACTION ParseAction, DWORD dwParseFlags, LPWSTR pwzResult, DWORD cchResult,
750         DWORD* pcchResult, DWORD dwReserved)
751 {
752     FIXME("%p)->(%s %08x %08lx %p %ld %p %ld)\n", iface, debugstr_w(pwzUrl), ParseAction,
753             dwParseFlags, pwzResult, cchResult, pcchResult, dwReserved);
754     return E_NOTIMPL;
755 }
756
757 static HRESULT WINAPI ResProtocolInfo_CombineUrl(IInternetProtocolInfo *iface, LPCWSTR pwzBaseUrl,
758         LPCWSTR pwzRelativeUrl, DWORD dwCombineFlags, LPWSTR pwzResult, DWORD cchResult,
759         DWORD* pcchResult, DWORD dwReserved)
760 {
761     FIXME("%p)->(%s %s %08lx %p %ld %p %ld)\n", iface, debugstr_w(pwzBaseUrl), debugstr_w(pwzRelativeUrl),
762             dwCombineFlags, pwzResult, cchResult, pcchResult, dwReserved);
763     return E_NOTIMPL;
764 }
765
766 static HRESULT WINAPI ResProtocolInfo_CompareUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl1,
767         LPCWSTR pwzUrl2, DWORD dwCompareFlags)
768 {
769     FIXME("%p)->(%s %s %08lx)\n", iface, debugstr_w(pwzUrl1), debugstr_w(pwzUrl2), dwCompareFlags);
770     return E_NOTIMPL;
771 }
772
773 static HRESULT WINAPI ResProtocolInfo_QueryInfo(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
774         QUERYOPTION QueryOption, DWORD dwQueryFlags, LPVOID pBuffer, DWORD cbBuffer, DWORD* pcbBuf,
775         DWORD dwReserved)
776 {
777     FIXME("%p)->(%s %08x %08lx %p %ld %p %ld)\n", iface, debugstr_w(pwzUrl), QueryOption, dwQueryFlags, pBuffer,
778             cbBuffer, pcbBuf, dwReserved);
779     return E_NOTIMPL;
780 }
781
782 static const IInternetProtocolInfoVtbl ResProtocolInfoVtbl = {
783     InternetProtocolInfo_QueryInterface,
784     InternetProtocolInfo_AddRef,
785     InternetProtocolInfo_Release,
786     ResProtocolInfo_ParseUrl,
787     ResProtocolInfo_CombineUrl,
788     ResProtocolInfo_CompareUrl,
789     ResProtocolInfo_QueryInfo
790 };
791
792 static const IClassFactoryVtbl ResProtocolFactoryVtbl = {
793     ClassFactory_QueryInterface,
794     ClassFactory_AddRef,
795     ClassFactory_Release,
796     ResProtocolFactory_CreateInstance,
797     ClassFactory_LockServer
798 };
799
800 static ProtocolFactory ResProtocolFactory = {
801     &ResProtocolInfoVtbl,
802     &ResProtocolFactoryVtbl
803 };
804
805 HRESULT ProtocolFactory_Create(REFCLSID rclsid, REFIID riid, void **ppv)
806 {
807     ProtocolFactory *cf = NULL;
808
809     if(IsEqualGUID(&CLSID_AboutProtocol, rclsid))
810         cf = &AboutProtocolFactory;
811     else if(IsEqualGUID(&CLSID_ResProtocol, rclsid))
812         cf = &ResProtocolFactory;
813
814     if(!cf) {
815         FIXME("not implemented protocol %s\n", debugstr_guid(rclsid));
816         return CLASS_E_CLASSNOTAVAILABLE;
817     }
818  
819     return IUnknown_QueryInterface((IUnknown*)cf, riid, ppv);
820 }