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