vbscript: Tweak enum macros to avoid confusing winapi_extract.
[wine] / dlls / vbscript / vbregexp.c
1 /*
2  * Copyright 2013 Piotr Caban for CodeWeavers
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include "vbscript.h"
20 #include "regexp.h"
21 #include "vbsregexp55.h"
22
23 #include "wine/debug.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
26
27 #define REGEXP_TID_LIST \
28     XDIID(RegExp2), \
29     XDIID(Match2), \
30     XDIID(MatchCollection2), \
31     XDIID(SubMatches)
32
33 typedef enum {
34 #define XDIID(iface) iface ## _tid
35     REGEXP_TID_LIST,
36 #undef XDIID
37     REGEXP_LAST_tid
38 } regexp_tid_t;
39
40 static REFIID tid_ids[] = {
41 #define XDIID(iface) &IID_I ## iface
42     REGEXP_TID_LIST
43 #undef XDIID
44 };
45
46 static ITypeLib *typelib;
47 static ITypeInfo *typeinfos[REGEXP_LAST_tid];
48
49 static HRESULT init_regexp_typeinfo(regexp_tid_t tid)
50 {
51     HRESULT hres;
52
53     if(!typelib) {
54         static const WCHAR vbscript_dll3W[] = {'v','b','s','c','r','i','p','t','.','d','l','l','\\','3',0};
55         ITypeLib *tl;
56
57         hres = LoadTypeLib(vbscript_dll3W, &tl);
58         if(FAILED(hres)) {
59             ERR("LoadRegTypeLib failed: %08x\n", hres);
60             return hres;
61         }
62
63         if(InterlockedCompareExchangePointer((void**)&typelib, tl, NULL))
64             ITypeLib_Release(tl);
65     }
66
67     if(!typeinfos[tid]) {
68         ITypeInfo *ti;
69
70         hres = ITypeLib_GetTypeInfoOfGuid(typelib, tid_ids[tid], &ti);
71         if(FAILED(hres)) {
72             ERR("GetTypeInfoOfGuid(%s) failed: %08x\n", debugstr_guid(tid_ids[tid]), hres);
73             return hres;
74         }
75
76         if(InterlockedCompareExchangePointer((void**)(typeinfos+tid), ti, NULL))
77             ITypeInfo_Release(ti);
78     }
79
80     return S_OK;
81 }
82
83 struct SubMatches {
84     ISubMatches ISubMatches_iface;
85
86     LONG ref;
87
88     WCHAR *match;
89     match_state_t *result;
90 };
91
92 typedef struct Match2 {
93     IMatch2 IMatch2_iface;
94
95     LONG ref;
96
97     DWORD index;
98     SubMatches *sub_matches;
99 } Match2;
100
101 typedef struct MatchCollectionEnum {
102     IEnumVARIANT IEnumVARIANT_iface;
103
104     LONG ref;
105
106     IMatchCollection2 *mc;
107     LONG pos;
108     LONG count;
109 } MatchCollectionEnum;
110
111 typedef struct MatchCollection2 {
112     IMatchCollection2 IMatchCollection2_iface;
113
114     LONG ref;
115
116     IMatch2 **matches;
117     DWORD count;
118     DWORD size;
119 } MatchCollection2;
120
121 typedef struct RegExp2 {
122     IRegExp2 IRegExp2_iface;
123     IRegExp IRegExp_iface;
124
125     LONG ref;
126
127     WCHAR *pattern;
128     regexp_t *regexp;
129     heap_pool_t pool;
130     WORD flags;
131 } RegExp2;
132
133 static inline SubMatches* impl_from_ISubMatches(ISubMatches *iface)
134 {
135     return CONTAINING_RECORD(iface, SubMatches, ISubMatches_iface);
136 }
137
138 static HRESULT WINAPI SubMatches_QueryInterface(
139         ISubMatches *iface, REFIID riid, void **ppv)
140 {
141     SubMatches *This = impl_from_ISubMatches(iface);
142
143     if(IsEqualGUID(riid, &IID_IUnknown)) {
144         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
145         *ppv = &This->ISubMatches_iface;
146     }else if(IsEqualGUID(riid, &IID_IDispatch)) {
147         TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
148         *ppv = &This->ISubMatches_iface;
149     }else if(IsEqualGUID(riid, &IID_ISubMatches)) {
150         TRACE("(%p)->(IID_ISubMatches %p)\n", This, ppv);
151         *ppv = &This->ISubMatches_iface;
152     }else if(IsEqualGUID(riid, &IID_IDispatchEx)) {
153         TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
154         *ppv = NULL;
155         return E_NOINTERFACE;
156     }else {
157         FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
158         *ppv = NULL;
159         return E_NOINTERFACE;
160     }
161
162     IUnknown_AddRef((IUnknown*)*ppv);
163     return S_OK;
164 }
165
166 static ULONG WINAPI SubMatches_AddRef(ISubMatches *iface)
167 {
168     SubMatches *This = impl_from_ISubMatches(iface);
169     LONG ref = InterlockedIncrement(&This->ref);
170
171     TRACE("(%p) ref=%d\n", This, ref);
172
173     return ref;
174 }
175
176 static ULONG WINAPI SubMatches_Release(ISubMatches *iface)
177 {
178     SubMatches *This = impl_from_ISubMatches(iface);
179     LONG ref = InterlockedDecrement(&This->ref);
180
181     TRACE("(%p) ref=%d\n", This, ref);
182
183     if(!ref) {
184         heap_free(This->match);
185         heap_free(This->result);
186         heap_free(This);
187     }
188
189     return ref;
190 }
191
192 static HRESULT WINAPI SubMatches_GetTypeInfoCount(ISubMatches *iface, UINT *pctinfo)
193 {
194     SubMatches *This = impl_from_ISubMatches(iface);
195
196     TRACE("(%p)->(%p)\n", This, pctinfo);
197
198     *pctinfo = 1;
199     return S_OK;
200 }
201
202 static HRESULT WINAPI SubMatches_GetTypeInfo(ISubMatches *iface,
203         UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
204 {
205     SubMatches *This = impl_from_ISubMatches(iface);
206     FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
207     return E_NOTIMPL;
208 }
209
210 static HRESULT WINAPI SubMatches_GetIDsOfNames(ISubMatches *iface,
211         REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
212 {
213     SubMatches *This = impl_from_ISubMatches(iface);
214
215     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid),
216             rgszNames, cNames, lcid, rgDispId);
217
218     return ITypeInfo_GetIDsOfNames(typeinfos[SubMatches_tid], rgszNames, cNames, rgDispId);
219 }
220
221 static HRESULT WINAPI SubMatches_Invoke(ISubMatches *iface, DISPID dispIdMember,
222         REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
223                         VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
224 {
225     SubMatches *This = impl_from_ISubMatches(iface);
226
227     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
228             lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
229
230     return ITypeInfo_Invoke(typeinfos[SubMatches_tid], iface, dispIdMember, wFlags,
231             pDispParams, pVarResult, pExcepInfo, puArgErr);
232 }
233
234 static HRESULT WINAPI SubMatches_get_Item(ISubMatches *iface,
235         LONG index, VARIANT *pSubMatch)
236 {
237     SubMatches *This = impl_from_ISubMatches(iface);
238
239     TRACE("(%p)->(%d %p)\n", This, index, pSubMatch);
240
241     if(!pSubMatch)
242         return E_POINTER;
243
244     if(!This->result || index<0 || index>=This->result->paren_count)
245         return E_INVALIDARG;
246
247     if(This->result->parens[index].index == -1) {
248         V_VT(pSubMatch) = VT_EMPTY;
249     }else {
250         V_VT(pSubMatch) = VT_BSTR;
251         V_BSTR(pSubMatch) = SysAllocStringLen(
252                 This->match+This->result->parens[index].index,
253                 This->result->parens[index].length);
254
255         if(!V_BSTR(pSubMatch))
256             return E_OUTOFMEMORY;
257     }
258
259     return S_OK;
260 }
261
262 static HRESULT WINAPI SubMatches_get_Count(ISubMatches *iface, LONG *pCount)
263 {
264     SubMatches *This = impl_from_ISubMatches(iface);
265
266     TRACE("(%p)->(%p)\n", This, pCount);
267
268     if(!pCount)
269         return E_POINTER;
270
271     if(!This->result)
272         *pCount = 0;
273     else
274         *pCount = This->result->paren_count;
275     return S_OK;
276 }
277
278 static HRESULT WINAPI SubMatches_get__NewEnum(ISubMatches *iface, IUnknown **ppEnum)
279 {
280     SubMatches *This = impl_from_ISubMatches(iface);
281     FIXME("(%p)->(%p)\n", This, ppEnum);
282     return E_NOTIMPL;
283 }
284
285 static const ISubMatchesVtbl SubMatchesVtbl = {
286     SubMatches_QueryInterface,
287     SubMatches_AddRef,
288     SubMatches_Release,
289     SubMatches_GetTypeInfoCount,
290     SubMatches_GetTypeInfo,
291     SubMatches_GetIDsOfNames,
292     SubMatches_Invoke,
293     SubMatches_get_Item,
294     SubMatches_get_Count,
295     SubMatches_get__NewEnum
296 };
297
298 static HRESULT create_sub_matches(DWORD pos, match_state_t *result, SubMatches **sub_matches)
299 {
300     SubMatches *ret;
301     DWORD i;
302     HRESULT hres;
303
304     hres = init_regexp_typeinfo(SubMatches_tid);
305     if(FAILED(hres))
306         return hres;
307
308     ret = heap_alloc_zero(sizeof(*ret));
309     if(!ret)
310         return E_OUTOFMEMORY;
311
312     ret->ISubMatches_iface.lpVtbl = &SubMatchesVtbl;
313
314     ret->result = result;
315     if(result) {
316         ret->match = heap_alloc((result->match_len+1) * sizeof(WCHAR));
317         if(!ret) {
318             heap_free(ret);
319             return E_OUTOFMEMORY;
320         }
321         memcpy(ret->match, result->cp-result->match_len, result->match_len*sizeof(WCHAR));
322         ret->match[result->match_len] = 0;
323
324         result->cp = NULL;
325         for(i=0; i<result->paren_count; i++)
326             if(result->parens[i].index != -1)
327                 result->parens[i].index -= pos;
328     }else {
329         ret->match = NULL;
330     }
331
332     ret->ref = 1;
333     *sub_matches = ret;
334     return hres;
335 }
336
337 static inline Match2* impl_from_IMatch2(IMatch2 *iface)
338 {
339     return CONTAINING_RECORD(iface, Match2, IMatch2_iface);
340 }
341
342 static HRESULT WINAPI Match2_QueryInterface(
343         IMatch2 *iface, REFIID riid, void **ppv)
344 {
345     Match2 *This = impl_from_IMatch2(iface);
346
347     if(IsEqualGUID(riid, &IID_IUnknown)) {
348         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
349         *ppv = &This->IMatch2_iface;
350     }else if(IsEqualGUID(riid, &IID_IDispatch)) {
351         TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
352         *ppv = &This->IMatch2_iface;
353     }else if(IsEqualGUID(riid, &IID_IMatch2)) {
354         TRACE("(%p)->(IID_IMatch2 %p)\n", This, ppv);
355         *ppv = &This->IMatch2_iface;
356     }else if(IsEqualGUID(riid, &IID_IDispatchEx)) {
357         TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
358         *ppv = NULL;
359         return E_NOINTERFACE;
360     }else {
361         FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
362         *ppv = NULL;
363         return E_NOINTERFACE;
364     }
365
366     IUnknown_AddRef((IUnknown*)*ppv);
367     return S_OK;
368 }
369
370 static ULONG WINAPI Match2_AddRef(IMatch2 *iface)
371 {
372     Match2 *This = impl_from_IMatch2(iface);
373     LONG ref = InterlockedIncrement(&This->ref);
374
375     TRACE("(%p) ref=%d\n", This, ref);
376
377     return ref;
378 }
379
380 static ULONG WINAPI Match2_Release(IMatch2 *iface)
381 {
382     Match2 *This = impl_from_IMatch2(iface);
383     LONG ref = InterlockedDecrement(&This->ref);
384
385     TRACE("(%p) ref=%d\n", This, ref);
386
387     if(!ref) {
388         ISubMatches_Release(&This->sub_matches->ISubMatches_iface);
389         heap_free(This);
390     }
391
392     return ref;
393 }
394
395 static HRESULT WINAPI Match2_GetTypeInfoCount(IMatch2 *iface, UINT *pctinfo)
396 {
397     Match2 *This = impl_from_IMatch2(iface);
398
399     TRACE("(%p)->(%p)\n", This, pctinfo);
400
401     *pctinfo = 1;
402     return S_OK;
403 }
404
405 static HRESULT WINAPI Match2_GetTypeInfo(IMatch2 *iface,
406         UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
407 {
408     Match2 *This = impl_from_IMatch2(iface);
409     FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
410     return E_NOTIMPL;
411 }
412
413 static HRESULT WINAPI Match2_GetIDsOfNames(IMatch2 *iface,
414         REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
415 {
416     Match2 *This = impl_from_IMatch2(iface);
417
418     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid),
419             rgszNames, cNames, lcid, rgDispId);
420
421     return ITypeInfo_GetIDsOfNames(typeinfos[Match2_tid], rgszNames, cNames, rgDispId);
422 }
423
424 static HRESULT WINAPI Match2_Invoke(IMatch2 *iface, DISPID dispIdMember,
425         REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
426                 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
427 {
428     Match2 *This = impl_from_IMatch2(iface);
429
430     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
431             lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
432
433     return ITypeInfo_Invoke(typeinfos[Match2_tid], iface, dispIdMember, wFlags,
434             pDispParams, pVarResult, pExcepInfo, puArgErr);
435 }
436
437 static HRESULT WINAPI Match2_get_Value(IMatch2 *iface, BSTR *pValue)
438 {
439     Match2 *This = impl_from_IMatch2(iface);
440
441     TRACE("(%p)->(%p)\n", This, pValue);
442
443     if(!pValue)
444         return E_POINTER;
445
446     if(!This->sub_matches->match) {
447         *pValue = NULL;
448         return S_OK;
449     }
450
451     *pValue = SysAllocString(This->sub_matches->match);
452     return *pValue ? S_OK : E_OUTOFMEMORY;
453 }
454
455 static HRESULT WINAPI Match2_get_FirstIndex(IMatch2 *iface, LONG *pFirstIndex)
456 {
457     Match2 *This = impl_from_IMatch2(iface);
458
459     TRACE("(%p)->(%p)\n", This, pFirstIndex);
460
461     if(!pFirstIndex)
462         return E_POINTER;
463
464     *pFirstIndex = This->index;
465     return S_OK;
466 }
467
468 static HRESULT WINAPI Match2_get_Length(IMatch2 *iface, LONG *pLength)
469 {
470     Match2 *This = impl_from_IMatch2(iface);
471
472     TRACE("(%p)->(%p)\n", This, pLength);
473
474     if(!pLength)
475         return E_POINTER;
476
477     if(This->sub_matches->result)
478         *pLength = This->sub_matches->result->match_len;
479     else
480         *pLength = 0;
481     return S_OK;
482 }
483
484 static HRESULT WINAPI Match2_get_SubMatches(IMatch2 *iface, IDispatch **ppSubMatches)
485 {
486     Match2 *This = impl_from_IMatch2(iface);
487
488     TRACE("(%p)->(%p)\n", This, ppSubMatches);
489
490     if(!ppSubMatches)
491         return E_POINTER;
492
493     *ppSubMatches = (IDispatch*)&This->sub_matches->ISubMatches_iface;
494     ISubMatches_AddRef(&This->sub_matches->ISubMatches_iface);
495     return S_OK;
496 }
497
498 static const IMatch2Vtbl Match2Vtbl = {
499     Match2_QueryInterface,
500     Match2_AddRef,
501     Match2_Release,
502     Match2_GetTypeInfoCount,
503     Match2_GetTypeInfo,
504     Match2_GetIDsOfNames,
505     Match2_Invoke,
506     Match2_get_Value,
507     Match2_get_FirstIndex,
508     Match2_get_Length,
509     Match2_get_SubMatches
510 };
511
512 static HRESULT create_match2(DWORD pos, match_state_t **result, IMatch2 **match)
513 {
514     Match2 *ret;
515     HRESULT hres;
516
517     hres = init_regexp_typeinfo(Match2_tid);
518     if(FAILED(hres))
519         return hres;
520
521     ret = heap_alloc_zero(sizeof(*ret));
522     if(!ret)
523         return E_OUTOFMEMORY;
524
525     ret->index = pos;
526     hres = create_sub_matches(pos, result ? *result : NULL, &ret->sub_matches);
527     if(FAILED(hres)) {
528         heap_free(ret);
529         return hres;
530     }
531     if(result)
532         *result = NULL;
533
534     ret->IMatch2_iface.lpVtbl = &Match2Vtbl;
535
536     ret->ref = 1;
537     *match = &ret->IMatch2_iface;
538     return hres;
539 }
540
541 static inline MatchCollectionEnum* impl_from_IMatchCollectionEnum(IEnumVARIANT *iface)
542 {
543     return CONTAINING_RECORD(iface, MatchCollectionEnum, IEnumVARIANT_iface);
544 }
545
546 static HRESULT WINAPI MatchCollectionEnum_QueryInterface(
547         IEnumVARIANT *iface, REFIID riid, void **ppv)
548 {
549     MatchCollectionEnum *This = impl_from_IMatchCollectionEnum(iface);
550
551     if(IsEqualGUID(riid, &IID_IUnknown)) {
552         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
553         *ppv = &This->IEnumVARIANT_iface;
554     }else if(IsEqualGUID(riid, &IID_IEnumVARIANT)) {
555         TRACE("(%p)->(IID_IEnumVARIANT %p)\n", This, ppv);
556         *ppv = &This->IEnumVARIANT_iface;
557     }else {
558         FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
559         *ppv = NULL;
560         return E_NOINTERFACE;
561     }
562
563     IUnknown_AddRef((IUnknown*)*ppv);
564     return S_OK;
565 }
566
567 static ULONG WINAPI MatchCollectionEnum_AddRef(IEnumVARIANT *iface)
568 {
569     MatchCollectionEnum *This = impl_from_IMatchCollectionEnum(iface);
570     LONG ref = InterlockedIncrement(&This->ref);
571
572     TRACE("(%p) ref=%d\n", This, ref);
573
574     return ref;
575 }
576
577 static ULONG WINAPI MatchCollectionEnum_Release(IEnumVARIANT *iface)
578 {
579     MatchCollectionEnum *This = impl_from_IMatchCollectionEnum(iface);
580     LONG ref = InterlockedDecrement(&This->ref);
581
582     TRACE("(%p) ref=%d\n", This, ref);
583
584     if(!ref) {
585         IMatchCollection2_Release(This->mc);
586         heap_free(This);
587     }
588
589     return ref;
590 }
591
592 static HRESULT WINAPI MatchCollectionEnum_Next(IEnumVARIANT *iface,
593         ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched)
594 {
595     MatchCollectionEnum *This = impl_from_IMatchCollectionEnum(iface);
596     DWORD i;
597     HRESULT hres = S_OK;
598
599     TRACE("(%p)->(%u %p %p)\n", This, celt, rgVar, pCeltFetched);
600
601     if(This->pos>=This->count) {
602         if(pCeltFetched)
603             *pCeltFetched = 0;
604         return S_FALSE;
605     }
606
607     for(i=0; i<celt && This->pos+i<This->count; i++) {
608         V_VT(rgVar+i) = VT_DISPATCH;
609         hres = IMatchCollection2_get_Item(This->mc, This->pos+i, &V_DISPATCH(rgVar+i));
610         if(FAILED(hres))
611             break;
612     }
613     if(FAILED(hres)) {
614         while(i--)
615             VariantClear(rgVar+i);
616         return hres;
617     }
618
619     if(pCeltFetched)
620         *pCeltFetched = i;
621     This->pos += i;
622     return S_OK;
623 }
624
625 static HRESULT WINAPI MatchCollectionEnum_Skip(IEnumVARIANT *iface, ULONG celt)
626 {
627     MatchCollectionEnum *This = impl_from_IMatchCollectionEnum(iface);
628
629     TRACE("(%p)->(%u)\n", This, celt);
630
631     if(This->pos+celt <= This->count)
632         This->pos += celt;
633     else
634         This->pos = This->count;
635     return S_OK;
636 }
637
638 static HRESULT WINAPI MatchCollectionEnum_Reset(IEnumVARIANT *iface)
639 {
640     MatchCollectionEnum *This = impl_from_IMatchCollectionEnum(iface);
641
642     TRACE("(%p)\n", This);
643
644     This->pos = 0;
645     return S_OK;
646 }
647
648 static HRESULT WINAPI MatchCollectionEnum_Clone(IEnumVARIANT *iface, IEnumVARIANT **ppEnum)
649 {
650     MatchCollectionEnum *This = impl_from_IMatchCollectionEnum(iface);
651     FIXME("(%p)->(%p)\n", This, ppEnum);
652     return E_NOTIMPL;
653 }
654
655 static const IEnumVARIANTVtbl MatchCollectionEnum_Vtbl = {
656     MatchCollectionEnum_QueryInterface,
657     MatchCollectionEnum_AddRef,
658     MatchCollectionEnum_Release,
659     MatchCollectionEnum_Next,
660     MatchCollectionEnum_Skip,
661     MatchCollectionEnum_Reset,
662     MatchCollectionEnum_Clone
663 };
664
665 static HRESULT create_enum_variant_mc2(IMatchCollection2 *mc, ULONG pos, IEnumVARIANT **enum_variant)
666 {
667     MatchCollectionEnum *ret;
668
669     ret = heap_alloc_zero(sizeof(*ret));
670     if(!ret)
671         return E_OUTOFMEMORY;
672
673     ret->IEnumVARIANT_iface.lpVtbl = &MatchCollectionEnum_Vtbl;
674     ret->ref = 1;
675     ret->pos = pos;
676     IMatchCollection2_get_Count(mc, &ret->count);
677     ret->mc = mc;
678     IMatchCollection2_AddRef(mc);
679
680     *enum_variant = &ret->IEnumVARIANT_iface;
681     return S_OK;
682 }
683
684 static inline MatchCollection2* impl_from_IMatchCollection2(IMatchCollection2 *iface)
685 {
686     return CONTAINING_RECORD(iface, MatchCollection2, IMatchCollection2_iface);
687 }
688
689 static HRESULT WINAPI MatchCollection2_QueryInterface(
690         IMatchCollection2 *iface, REFIID riid, void **ppv)
691 {
692     MatchCollection2 *This = impl_from_IMatchCollection2(iface);
693
694     if(IsEqualGUID(riid, &IID_IUnknown)) {
695         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
696         *ppv = &This->IMatchCollection2_iface;
697     }else if(IsEqualGUID(riid, &IID_IDispatch)) {
698         TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
699         *ppv = &This->IMatchCollection2_iface;
700     }else if(IsEqualGUID(riid, &IID_IMatchCollection2)) {
701         TRACE("(%p)->(IID_IMatchCollection2 %p)\n", This, ppv);
702         *ppv = &This->IMatchCollection2_iface;
703     }else if(IsEqualGUID(riid, &IID_IDispatchEx)) {
704         TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
705         *ppv = NULL;
706         return E_NOINTERFACE;
707     }else {
708         FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
709         *ppv = NULL;
710         return E_NOINTERFACE;
711     }
712
713     IUnknown_AddRef((IUnknown*)*ppv);
714     return S_OK;
715 }
716
717 static ULONG WINAPI MatchCollection2_AddRef(IMatchCollection2 *iface)
718 {
719     MatchCollection2 *This = impl_from_IMatchCollection2(iface);
720     LONG ref = InterlockedIncrement(&This->ref);
721
722     TRACE("(%p) ref=%d\n", This, ref);
723
724     return ref;
725 }
726
727 static ULONG WINAPI MatchCollection2_Release(IMatchCollection2 *iface)
728 {
729     MatchCollection2 *This = impl_from_IMatchCollection2(iface);
730     LONG ref = InterlockedDecrement(&This->ref);
731
732     TRACE("(%p) ref=%d\n", This, ref);
733
734     if(!ref) {
735         DWORD i;
736
737         for(i=0; i<This->count; i++)
738             IMatch2_Release(This->matches[i]);
739         heap_free(This->matches);
740
741         heap_free(This);
742     }
743
744     return ref;
745 }
746
747 static HRESULT WINAPI MatchCollection2_GetTypeInfoCount(IMatchCollection2 *iface, UINT *pctinfo)
748 {
749     MatchCollection2 *This = impl_from_IMatchCollection2(iface);
750
751     TRACE("(%p)->(%p)\n", This, pctinfo);
752
753     *pctinfo = 1;
754     return S_OK;
755 }
756
757 static HRESULT WINAPI MatchCollection2_GetTypeInfo(IMatchCollection2 *iface,
758         UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
759 {
760     MatchCollection2 *This = impl_from_IMatchCollection2(iface);
761     FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
762     return E_NOTIMPL;
763 }
764
765 static HRESULT WINAPI MatchCollection2_GetIDsOfNames(IMatchCollection2 *iface,
766         REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
767 {
768     MatchCollection2 *This = impl_from_IMatchCollection2(iface);
769
770     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid),
771             rgszNames, cNames, lcid, rgDispId);
772
773     return ITypeInfo_GetIDsOfNames(typeinfos[MatchCollection2_tid], rgszNames, cNames, rgDispId);
774 }
775
776 static HRESULT WINAPI MatchCollection2_Invoke(IMatchCollection2 *iface, DISPID dispIdMember,
777         REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
778         VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
779 {
780     MatchCollection2 *This = impl_from_IMatchCollection2(iface);
781
782     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
783             lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
784
785     return ITypeInfo_Invoke(typeinfos[MatchCollection2_tid], iface, dispIdMember, wFlags,
786             pDispParams, pVarResult, pExcepInfo, puArgErr);
787 }
788
789 static HRESULT WINAPI MatchCollection2_get_Item(IMatchCollection2 *iface,
790         LONG index, IDispatch **ppMatch)
791 {
792     MatchCollection2 *This = impl_from_IMatchCollection2(iface);
793
794     TRACE("(%p)->()\n", This);
795
796     if(!ppMatch)
797         return E_POINTER;
798
799     if(index<0 || index>=This->count)
800         return E_INVALIDARG;
801
802     *ppMatch = (IDispatch*)This->matches[index];
803     IMatch2_AddRef(This->matches[index]);
804     return S_OK;
805 }
806
807 static HRESULT WINAPI MatchCollection2_get_Count(IMatchCollection2 *iface, LONG *pCount)
808 {
809     MatchCollection2 *This = impl_from_IMatchCollection2(iface);
810
811     TRACE("(%p)->()\n", This);
812
813     if(!pCount)
814         return E_POINTER;
815
816     *pCount = This->count;
817     return S_OK;
818 }
819
820 static HRESULT WINAPI MatchCollection2_get__NewEnum(IMatchCollection2 *iface, IUnknown **ppEnum)
821 {
822     MatchCollection2 *This = impl_from_IMatchCollection2(iface);
823
824     TRACE("(%p)->(%p)\n", This, ppEnum);
825
826     if(!ppEnum)
827         return E_POINTER;
828
829     return create_enum_variant_mc2(&This->IMatchCollection2_iface, 0, (IEnumVARIANT**)ppEnum);
830 }
831
832 static const IMatchCollection2Vtbl MatchCollection2Vtbl = {
833     MatchCollection2_QueryInterface,
834     MatchCollection2_AddRef,
835     MatchCollection2_Release,
836     MatchCollection2_GetTypeInfoCount,
837     MatchCollection2_GetTypeInfo,
838     MatchCollection2_GetIDsOfNames,
839     MatchCollection2_Invoke,
840     MatchCollection2_get_Item,
841     MatchCollection2_get_Count,
842     MatchCollection2_get__NewEnum
843 };
844
845 static HRESULT add_match(IMatchCollection2 *iface, IMatch2 *add)
846 {
847     MatchCollection2 *This = impl_from_IMatchCollection2(iface);
848
849     TRACE("(%p)->(%p)\n", This, add);
850
851     if(!This->size) {
852         This->matches = heap_alloc(8*sizeof(IMatch*));
853         if(!This->matches)
854             return E_OUTOFMEMORY;
855         This->size = 8;
856     }else if(This->size == This->count) {
857         IMatch2 **new_matches = heap_realloc(This->matches, 2*This->size*sizeof(IMatch*));
858         if(!new_matches)
859             return E_OUTOFMEMORY;
860
861         This->matches = new_matches;
862         This->size <<= 1;
863     }
864
865     This->matches[This->count++] = add;
866     IMatch2_AddRef(add);
867     return S_OK;
868 }
869
870 static HRESULT create_match_collection2(IMatchCollection2 **match_collection)
871 {
872     MatchCollection2 *ret;
873     HRESULT hres;
874
875     hres = init_regexp_typeinfo(MatchCollection2_tid);
876     if(FAILED(hres))
877         return hres;
878
879     ret = heap_alloc_zero(sizeof(*ret));
880     if(!ret)
881         return E_OUTOFMEMORY;
882
883     ret->IMatchCollection2_iface.lpVtbl = &MatchCollection2Vtbl;
884
885     ret->ref = 1;
886     *match_collection = &ret->IMatchCollection2_iface;
887     return S_OK;
888 }
889
890 static inline RegExp2 *impl_from_IRegExp2(IRegExp2 *iface)
891 {
892     return CONTAINING_RECORD(iface, RegExp2, IRegExp2_iface);
893 }
894
895 static HRESULT WINAPI RegExp2_QueryInterface(IRegExp2 *iface, REFIID riid, void **ppv)
896 {
897     RegExp2 *This = impl_from_IRegExp2(iface);
898
899     if(IsEqualGUID(riid, &IID_IUnknown)) {
900         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
901         *ppv = &This->IRegExp2_iface;
902     }else if(IsEqualGUID(riid, &IID_IDispatch)) {
903         TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
904         *ppv = &This->IRegExp2_iface;
905     }else if(IsEqualGUID(riid, &IID_IRegExp2)) {
906         TRACE("(%p)->(IID_IRegExp2 %p)\n", This, ppv);
907         *ppv = &This->IRegExp2_iface;
908     }else if(IsEqualGUID(riid, &IID_IRegExp)) {
909         TRACE("(%p)->(IID_IRegExp %p)\n", This, ppv);
910         *ppv = &This->IRegExp_iface;
911     }else if(IsEqualGUID(riid, &IID_IDispatchEx)) {
912         TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
913         *ppv = NULL;
914         return E_NOINTERFACE;
915     }else {
916         FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
917         *ppv = NULL;
918         return E_NOINTERFACE;
919     }
920
921     IUnknown_AddRef((IUnknown*)*ppv);
922     return S_OK;
923 }
924
925 static ULONG WINAPI RegExp2_AddRef(IRegExp2 *iface)
926 {
927     RegExp2 *This = impl_from_IRegExp2(iface);
928     LONG ref = InterlockedIncrement(&This->ref);
929
930     TRACE("(%p) ref=%d\n", This, ref);
931
932     return ref;
933 }
934
935 static ULONG WINAPI RegExp2_Release(IRegExp2 *iface)
936 {
937     RegExp2 *This = impl_from_IRegExp2(iface);
938     LONG ref = InterlockedDecrement(&This->ref);
939
940     TRACE("(%p) ref=%d\n", This, ref);
941
942     if(!ref) {
943         heap_free(This->pattern);
944         if(This->regexp)
945             regexp_destroy(This->regexp);
946         heap_pool_free(&This->pool);
947         heap_free(This);
948     }
949
950     return ref;
951 }
952
953 static HRESULT WINAPI RegExp2_GetTypeInfoCount(IRegExp2 *iface, UINT *pctinfo)
954 {
955     RegExp2 *This = impl_from_IRegExp2(iface);
956
957     TRACE("(%p)->(%p)\n", This, pctinfo);
958
959     *pctinfo = 1;
960     return S_OK;
961 }
962
963 static HRESULT WINAPI RegExp2_GetTypeInfo(IRegExp2 *iface,
964         UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
965 {
966     RegExp2 *This = impl_from_IRegExp2(iface);
967     FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
968     return E_NOTIMPL;
969 }
970
971 static HRESULT WINAPI RegExp2_GetIDsOfNames(IRegExp2 *iface, REFIID riid,
972         LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
973 {
974     RegExp2 *This = impl_from_IRegExp2(iface);
975
976     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid),
977             rgszNames, cNames, lcid, rgDispId);
978
979     return ITypeInfo_GetIDsOfNames(typeinfos[RegExp2_tid], rgszNames, cNames, rgDispId);
980 }
981
982 static HRESULT WINAPI RegExp2_Invoke(IRegExp2 *iface, DISPID dispIdMember,
983         REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
984         VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
985 {
986     RegExp2 *This = impl_from_IRegExp2(iface);
987
988     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
989             lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
990
991     return ITypeInfo_Invoke(typeinfos[RegExp2_tid], iface, dispIdMember, wFlags,
992             pDispParams, pVarResult, pExcepInfo, puArgErr);
993 }
994
995 static HRESULT WINAPI RegExp2_get_Pattern(IRegExp2 *iface, BSTR *pPattern)
996 {
997     RegExp2 *This = impl_from_IRegExp2(iface);
998
999     TRACE("(%p)->(%p)\n", This, pPattern);
1000
1001     if(!pPattern)
1002         return E_POINTER;
1003
1004     if(!This->pattern) {
1005         *pPattern = NULL;
1006         return S_OK;
1007     }
1008
1009     *pPattern = SysAllocString(This->pattern);
1010     return *pPattern ? S_OK : E_OUTOFMEMORY;
1011 }
1012
1013 static HRESULT WINAPI RegExp2_put_Pattern(IRegExp2 *iface, BSTR pattern)
1014 {
1015     RegExp2 *This = impl_from_IRegExp2(iface);
1016     WCHAR *p;
1017     DWORD size;
1018
1019     TRACE("(%p)->(%s)\n", This, wine_dbgstr_w(pattern));
1020
1021     if(!pattern) {
1022         heap_free(This->pattern);
1023         if(This->regexp) {
1024             regexp_destroy(This->regexp);
1025             This->regexp = NULL;
1026         }
1027         This->pattern = NULL;
1028         return S_OK;
1029     }
1030
1031     size = (SysStringLen(pattern)+1) * sizeof(WCHAR);
1032     p = heap_alloc(size);
1033     if(!p)
1034         return E_OUTOFMEMORY;
1035
1036     heap_free(This->pattern);
1037     This->pattern = p;
1038     memcpy(p, pattern, size);
1039     if(This->regexp) {
1040         regexp_destroy(This->regexp);
1041         This->regexp = NULL;
1042     }
1043     return S_OK;
1044 }
1045
1046 static HRESULT WINAPI RegExp2_get_IgnoreCase(IRegExp2 *iface, VARIANT_BOOL *pIgnoreCase)
1047 {
1048     RegExp2 *This = impl_from_IRegExp2(iface);
1049
1050     TRACE("(%p)->(%p)\n", This, pIgnoreCase);
1051
1052     if(!pIgnoreCase)
1053         return E_POINTER;
1054
1055     *pIgnoreCase = This->flags & REG_FOLD ? VARIANT_TRUE : VARIANT_FALSE;
1056     return S_OK;
1057 }
1058
1059 static HRESULT WINAPI RegExp2_put_IgnoreCase(IRegExp2 *iface, VARIANT_BOOL ignoreCase)
1060 {
1061     RegExp2 *This = impl_from_IRegExp2(iface);
1062
1063     TRACE("(%p)->(%s)\n", This, ignoreCase ? "true" : "false");
1064
1065     if(ignoreCase)
1066         This->flags |= REG_FOLD;
1067     else
1068         This->flags &= ~REG_FOLD;
1069     return S_OK;
1070 }
1071
1072 static HRESULT WINAPI RegExp2_get_Global(IRegExp2 *iface, VARIANT_BOOL *pGlobal)
1073 {
1074     RegExp2 *This = impl_from_IRegExp2(iface);
1075
1076     TRACE("(%p)->(%p)\n", This, pGlobal);
1077
1078     if(!pGlobal)
1079         return E_POINTER;
1080
1081     *pGlobal = This->flags & REG_GLOB ? VARIANT_TRUE : VARIANT_FALSE;
1082     return S_OK;
1083 }
1084
1085 static HRESULT WINAPI RegExp2_put_Global(IRegExp2 *iface, VARIANT_BOOL global)
1086 {
1087     RegExp2 *This = impl_from_IRegExp2(iface);
1088
1089     TRACE("(%p)->(%s)\n", This, global ? "true" : "false");
1090
1091     if(global)
1092         This->flags |= REG_GLOB;
1093     else
1094         This->flags &= ~REG_GLOB;
1095     return S_OK;
1096 }
1097
1098 static HRESULT WINAPI RegExp2_get_Multiline(IRegExp2 *iface, VARIANT_BOOL *pMultiline)
1099 {
1100     RegExp2 *This = impl_from_IRegExp2(iface);
1101
1102     TRACE("(%p)->(%p)\n", This, pMultiline);
1103
1104     if(!pMultiline)
1105         return E_POINTER;
1106
1107     *pMultiline = This->flags & REG_MULTILINE ? VARIANT_TRUE : VARIANT_FALSE;
1108     return S_OK;
1109 }
1110
1111 static HRESULT WINAPI RegExp2_put_Multiline(IRegExp2 *iface, VARIANT_BOOL multiline)
1112 {
1113     RegExp2 *This = impl_from_IRegExp2(iface);
1114
1115     TRACE("(%p)->(%s)\n", This, multiline ? "true" : "false");
1116
1117     if(multiline)
1118         This->flags |= REG_MULTILINE;
1119     else
1120         This->flags &= ~REG_MULTILINE;
1121     return S_OK;
1122 }
1123
1124 static HRESULT WINAPI RegExp2_Execute(IRegExp2 *iface,
1125         BSTR sourceString, IDispatch **ppMatches)
1126 {
1127     RegExp2 *This = impl_from_IRegExp2(iface);
1128     match_state_t *result;
1129     const WCHAR *pos;
1130     IMatchCollection2 *match_collection;
1131     IMatch2 *add = NULL;
1132     HRESULT hres;
1133
1134     TRACE("(%p)->(%s %p)\n", This, debugstr_w(sourceString), ppMatches);
1135
1136     if(!This->pattern) {
1137         DWORD i, len = SysStringLen(sourceString);
1138
1139         hres = create_match_collection2(&match_collection);
1140         if(FAILED(hres))
1141             return hres;
1142
1143         for(i=0; i<=len; i++) {
1144             hres = create_match2(i, NULL, &add);
1145             if(FAILED(hres))
1146                 break;
1147
1148             hres = add_match(match_collection, add);
1149             if(FAILED(hres))
1150                 break;
1151             IMatch2_Release(add);
1152
1153             if(!(This->flags & REG_GLOB))
1154                 break;
1155         }
1156
1157         if(FAILED(hres)) {
1158             IMatchCollection2_Release(match_collection);
1159             return hres;
1160         }
1161
1162         *ppMatches = (IDispatch*)match_collection;
1163         return S_OK;
1164     }
1165
1166     if(!This->regexp) {
1167         This->regexp = regexp_new(NULL, &This->pool, This->pattern,
1168                 strlenW(This->pattern), This->flags, FALSE);
1169         if(!This->regexp)
1170             return E_FAIL;
1171     }else {
1172         hres = regexp_set_flags(&This->regexp, NULL, &This->pool, This->flags);
1173         if(FAILED(hres))
1174             return hres;
1175     }
1176
1177     hres = create_match_collection2(&match_collection);
1178     if(FAILED(hres))
1179         return hres;
1180
1181     pos = sourceString;
1182     while(1) {
1183         result = alloc_match_state(This->regexp, NULL, pos);
1184         if(!result) {
1185             hres = E_OUTOFMEMORY;
1186             break;
1187         }
1188
1189         hres = regexp_execute(This->regexp, NULL, &This->pool,
1190                 sourceString, SysStringLen(sourceString), result);
1191         if(hres != S_OK) {
1192             heap_free(result);
1193             break;
1194         }
1195         pos = result->cp;
1196
1197         hres = create_match2(result->cp-result->match_len-sourceString, &result, &add);
1198         heap_free(result);
1199         if(FAILED(hres))
1200             break;
1201         hres = add_match(match_collection, add);
1202         IMatch2_Release(add);
1203         if(FAILED(hres))
1204             break;
1205
1206         if(!(This->flags & REG_GLOB))
1207             break;
1208     }
1209
1210     if(FAILED(hres)) {
1211         IMatchCollection2_Release(match_collection);
1212         return hres;
1213     }
1214
1215     *ppMatches = (IDispatch*)match_collection;
1216     return S_OK;
1217 }
1218
1219 static HRESULT WINAPI RegExp2_Test(IRegExp2 *iface, BSTR sourceString, VARIANT_BOOL *pMatch)
1220 {
1221     RegExp2 *This = impl_from_IRegExp2(iface);
1222     match_state_t *result;
1223     heap_pool_t *mark;
1224     HRESULT hres;
1225
1226     TRACE("(%p)->(%s %p)\n", This, debugstr_w(sourceString), pMatch);
1227
1228     if(!This->pattern) {
1229         *pMatch = VARIANT_TRUE;
1230         return S_OK;
1231     }
1232
1233     if(!This->regexp) {
1234         This->regexp = regexp_new(NULL, &This->pool, This->pattern,
1235                 strlenW(This->pattern), This->flags, FALSE);
1236         if(!This->regexp)
1237             return E_FAIL;
1238     }else {
1239         hres = regexp_set_flags(&This->regexp, NULL, &This->pool, This->flags);
1240         if(FAILED(hres))
1241             return hres;
1242     }
1243
1244     mark = heap_pool_mark(&This->pool);
1245     result = alloc_match_state(This->regexp, &This->pool, sourceString);
1246     if(!result) {
1247         heap_pool_clear(mark);
1248         return E_OUTOFMEMORY;
1249     }
1250
1251     hres = regexp_execute(This->regexp, NULL, &This->pool,
1252             sourceString, SysStringLen(sourceString), result);
1253
1254     heap_pool_clear(mark);
1255
1256     if(hres == S_OK) {
1257         *pMatch = VARIANT_TRUE;
1258     }else if(hres == S_FALSE) {
1259         *pMatch = VARIANT_FALSE;
1260         hres = S_OK;
1261     }
1262     return hres;
1263 }
1264
1265 static HRESULT WINAPI RegExp2_Replace(IRegExp2 *iface, BSTR sourceString,
1266         VARIANT replaceVar, BSTR *pDestString)
1267 {
1268     RegExp2 *This = impl_from_IRegExp2(iface);
1269     FIXME("(%p)->(%s %s %p)\n", This, debugstr_w(sourceString),
1270             debugstr_variant(&replaceVar), pDestString);
1271     return E_NOTIMPL;
1272 }
1273
1274 static const IRegExp2Vtbl RegExp2Vtbl = {
1275     RegExp2_QueryInterface,
1276     RegExp2_AddRef,
1277     RegExp2_Release,
1278     RegExp2_GetTypeInfoCount,
1279     RegExp2_GetTypeInfo,
1280     RegExp2_GetIDsOfNames,
1281     RegExp2_Invoke,
1282     RegExp2_get_Pattern,
1283     RegExp2_put_Pattern,
1284     RegExp2_get_IgnoreCase,
1285     RegExp2_put_IgnoreCase,
1286     RegExp2_get_Global,
1287     RegExp2_put_Global,
1288     RegExp2_get_Multiline,
1289     RegExp2_put_Multiline,
1290     RegExp2_Execute,
1291     RegExp2_Test,
1292     RegExp2_Replace
1293 };
1294
1295 static inline RegExp2 *impl_from_IRegExp(IRegExp *iface)
1296 {
1297     return CONTAINING_RECORD(iface, RegExp2, IRegExp_iface);
1298 }
1299
1300 static HRESULT WINAPI RegExp_QueryInterface(IRegExp *iface, REFIID riid, void **ppv)
1301 {
1302     RegExp2 *This = impl_from_IRegExp(iface);
1303     return IRegExp2_QueryInterface(&This->IRegExp2_iface, riid, ppv);
1304 }
1305
1306 static ULONG WINAPI RegExp_AddRef(IRegExp *iface)
1307 {
1308     RegExp2 *This = impl_from_IRegExp(iface);
1309     return IRegExp2_AddRef(&This->IRegExp2_iface);
1310 }
1311
1312 static ULONG WINAPI RegExp_Release(IRegExp *iface)
1313 {
1314     RegExp2 *This = impl_from_IRegExp(iface);
1315     return IRegExp2_Release(&This->IRegExp2_iface);
1316 }
1317
1318 static HRESULT WINAPI RegExp_GetTypeInfoCount(IRegExp *iface, UINT *pctinfo)
1319 {
1320     RegExp2 *This = impl_from_IRegExp(iface);
1321     return IRegExp2_GetTypeInfoCount(&This->IRegExp2_iface, pctinfo);
1322 }
1323
1324 static HRESULT WINAPI RegExp_GetTypeInfo(IRegExp *iface,
1325         UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
1326 {
1327     RegExp2 *This = impl_from_IRegExp(iface);
1328     return IRegExp2_GetTypeInfo(&This->IRegExp2_iface, iTInfo, lcid, ppTInfo);
1329 }
1330
1331 static HRESULT WINAPI RegExp_GetIDsOfNames(IRegExp *iface, REFIID riid,
1332         LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
1333 {
1334     RegExp2 *This = impl_from_IRegExp(iface);
1335     return IRegExp2_GetIDsOfNames(&This->IRegExp2_iface, riid, rgszNames, cNames, lcid, rgDispId);
1336 }
1337
1338 static HRESULT WINAPI RegExp_Invoke(IRegExp *iface, DISPID dispIdMember,
1339         REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
1340                 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
1341 {
1342     RegExp2 *This = impl_from_IRegExp(iface);
1343     return IRegExp2_Invoke(&This->IRegExp2_iface, dispIdMember, riid, lcid,
1344             wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1345 }
1346
1347 static HRESULT WINAPI RegExp_get_Pattern(IRegExp *iface, BSTR *pPattern)
1348 {
1349     RegExp2 *This = impl_from_IRegExp(iface);
1350     return IRegExp2_get_Pattern(&This->IRegExp2_iface, pPattern);
1351 }
1352
1353 static HRESULT WINAPI RegExp_put_Pattern(IRegExp *iface, BSTR pPattern)
1354 {
1355     RegExp2 *This = impl_from_IRegExp(iface);
1356     return IRegExp2_put_Pattern(&This->IRegExp2_iface, pPattern);
1357 }
1358
1359 static HRESULT WINAPI RegExp_get_IgnoreCase(IRegExp *iface, VARIANT_BOOL *pIgnoreCase)
1360 {
1361     RegExp2 *This = impl_from_IRegExp(iface);
1362     return IRegExp2_get_IgnoreCase(&This->IRegExp2_iface, pIgnoreCase);
1363 }
1364
1365 static HRESULT WINAPI RegExp_put_IgnoreCase(IRegExp *iface, VARIANT_BOOL pIgnoreCase)
1366 {
1367     RegExp2 *This = impl_from_IRegExp(iface);
1368     return IRegExp2_put_IgnoreCase(&This->IRegExp2_iface, pIgnoreCase);
1369 }
1370
1371 static HRESULT WINAPI RegExp_get_Global(IRegExp *iface, VARIANT_BOOL *pGlobal)
1372 {
1373     RegExp2 *This = impl_from_IRegExp(iface);
1374     return IRegExp2_get_Global(&This->IRegExp2_iface, pGlobal);
1375 }
1376
1377 static HRESULT WINAPI RegExp_put_Global(IRegExp *iface, VARIANT_BOOL pGlobal)
1378 {
1379     RegExp2 *This = impl_from_IRegExp(iface);
1380     return IRegExp2_put_Global(&This->IRegExp2_iface, pGlobal);
1381 }
1382
1383 static HRESULT WINAPI RegExp_Execute(IRegExp *iface,
1384         BSTR sourceString, IDispatch **ppMatches)
1385 {
1386     RegExp2 *This = impl_from_IRegExp(iface);
1387     return IRegExp2_Execute(&This->IRegExp2_iface, sourceString, ppMatches);
1388 }
1389
1390 static HRESULT WINAPI RegExp_Test(IRegExp *iface, BSTR sourceString, VARIANT_BOOL *pMatch)
1391 {
1392     RegExp2 *This = impl_from_IRegExp(iface);
1393     return IRegExp2_Test(&This->IRegExp2_iface, sourceString, pMatch);
1394 }
1395
1396 static HRESULT WINAPI RegExp_Replace(IRegExp *iface, BSTR sourceString,
1397         BSTR replaceString, BSTR *pDestString)
1398 {
1399     RegExp2 *This = impl_from_IRegExp(iface);
1400     VARIANT replace;
1401
1402     V_VT(&replace) = VT_BSTR;
1403     V_BSTR(&replace) = replaceString;
1404     return IRegExp2_Replace(&This->IRegExp2_iface, sourceString, replace, pDestString);
1405 }
1406
1407 static IRegExpVtbl RegExpVtbl = {
1408     RegExp_QueryInterface,
1409     RegExp_AddRef,
1410     RegExp_Release,
1411     RegExp_GetTypeInfoCount,
1412     RegExp_GetTypeInfo,
1413     RegExp_GetIDsOfNames,
1414     RegExp_Invoke,
1415     RegExp_get_Pattern,
1416     RegExp_put_Pattern,
1417     RegExp_get_IgnoreCase,
1418     RegExp_put_IgnoreCase,
1419     RegExp_get_Global,
1420     RegExp_put_Global,
1421     RegExp_Execute,
1422     RegExp_Test,
1423     RegExp_Replace
1424 };
1425
1426 HRESULT WINAPI VBScriptRegExpFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter, REFIID riid, void **ppv)
1427 {
1428     RegExp2 *ret;
1429     HRESULT hres;
1430
1431     TRACE("(%p %s %p)\n", pUnkOuter, debugstr_guid(riid), ppv);
1432
1433     hres = init_regexp_typeinfo(RegExp2_tid);
1434     if(FAILED(hres))
1435         return hres;
1436
1437     ret = heap_alloc_zero(sizeof(*ret));
1438     if(!ret)
1439         return E_OUTOFMEMORY;
1440
1441     ret->IRegExp2_iface.lpVtbl = &RegExp2Vtbl;
1442     ret->IRegExp_iface.lpVtbl = &RegExpVtbl;
1443
1444     ret->ref = 1;
1445     heap_pool_init(&ret->pool);
1446
1447     hres = IRegExp2_QueryInterface(&ret->IRegExp2_iface, riid, ppv);
1448     IRegExp2_Release(&ret->IRegExp2_iface);
1449     return hres;
1450 }
1451
1452 void release_regexp_typelib(void)
1453 {
1454     DWORD i;
1455
1456     for(i=0; i<REGEXP_LAST_tid; i++) {
1457         if(typeinfos[i])
1458             ITypeInfo_Release(typeinfos[i]);
1459     }
1460     if(typelib)
1461         ITypeLib_Release(typelib);
1462 }