vbscript: Added GetScriptDispatch implementation.
[wine] / dlls / vbscript / vbscript.c
1 /*
2  * Copyright 2011 Jacek 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
20 #include <assert.h>
21
22 #include "vbscript.h"
23 #include "objsafe.h"
24
25 #include "wine/debug.h"
26
27 WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
28
29 #ifdef _WIN64
30
31 #define CTXARG_T DWORDLONG
32 #define IActiveScriptParseVtbl IActiveScriptParse64Vtbl
33
34 #else
35
36 #define CTXARG_T DWORD
37 #define IActiveScriptParseVtbl IActiveScriptParse32Vtbl
38
39 #endif
40
41 struct VBScript {
42     IActiveScript IActiveScript_iface;
43     IActiveScriptParse IActiveScriptParse_iface;
44     IObjectSafety IObjectSafety_iface;
45
46     LONG ref;
47
48     DWORD safeopt;
49     SCRIPTSTATE state;
50     IActiveScriptSite *site;
51     script_ctx_t *ctx;
52     LONG thread_id;
53     LCID lcid;
54 };
55
56 static void change_state(VBScript *This, SCRIPTSTATE state)
57 {
58     if(This->state == state)
59         return;
60
61     This->state = state;
62     if(This->site)
63         IActiveScriptSite_OnStateChange(This->site, state);
64 }
65
66 static void exec_queued_code(VBScript *This)
67 {
68     FIXME("\n");
69 }
70
71 static HRESULT set_ctx_site(VBScript *This)
72 {
73     HRESULT hres;
74
75     This->ctx->lcid = This->lcid;
76
77     hres = init_global(This->ctx);
78     if(FAILED(hres))
79         return hres;
80
81     IActiveScriptSite_AddRef(This->site);
82     This->ctx->site = This->site;
83
84     change_state(This, SCRIPTSTATE_INITIALIZED);
85     return S_OK;
86 }
87
88 static void destroy_script(script_ctx_t *ctx)
89 {
90     if(ctx->site)
91         IActiveScriptSite_Release(ctx->site);
92     if(ctx->script_obj)
93         IDispatchEx_Release(&ctx->script_obj->IDispatchEx_iface);
94     heap_free(ctx);
95 }
96
97 static void decrease_state(VBScript *This, SCRIPTSTATE state)
98 {
99     switch(This->state) {
100     case SCRIPTSTATE_CONNECTED:
101     case SCRIPTSTATE_STARTED:
102     case SCRIPTSTATE_DISCONNECTED:
103         FIXME("unimplemented state %d\n", This->state);
104         if(state == SCRIPTSTATE_INITIALIZED)
105             break;
106         /* FALLTHROUGH */
107     case SCRIPTSTATE_INITIALIZED:
108         destroy_script(This->ctx);
109         This->ctx = NULL;
110         This->thread_id = 0;
111
112         change_state(This, state);
113         if(state == SCRIPTSTATE_UNINITIALIZED)
114             break;
115         /* FALLTHROUGH */
116     case SCRIPTSTATE_UNINITIALIZED:
117         if(This->site) {
118             IActiveScriptSite_Release(This->site);
119             This->site = NULL;
120         }
121
122         break;
123     default:
124         assert(0);
125     }
126 }
127
128 static inline VBScript *impl_from_IActiveScript(IActiveScript *iface)
129 {
130     return CONTAINING_RECORD(iface, VBScript, IActiveScript_iface);
131 }
132
133 static HRESULT WINAPI VBScript_QueryInterface(IActiveScript *iface, REFIID riid, void **ppv)
134 {
135     VBScript *This = impl_from_IActiveScript(iface);
136
137     if(IsEqualGUID(riid, &IID_IUnknown)) {
138         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
139         *ppv = &This->IActiveScript_iface;
140     }else if(IsEqualGUID(riid, &IID_IActiveScript)) {
141         TRACE("(%p)->(IID_IActiveScript %p)\n", This, ppv);
142         *ppv = &This->IActiveScript_iface;
143     }else if(IsEqualGUID(riid, &IID_IActiveScriptParse)) {
144         TRACE("(%p)->(IID_IActiveScriptParse %p)\n", This, ppv);
145         *ppv = &This->IActiveScriptParse_iface;
146     }else if(IsEqualGUID(riid, &IID_IObjectSafety)) {
147         TRACE("(%p)->(IID_IObjectSafety %p)\n", This, ppv);
148         *ppv = &This->IObjectSafety_iface;
149     }else {
150         FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
151         *ppv = NULL;
152         return E_NOINTERFACE;
153     }
154
155     IUnknown_AddRef((IUnknown*)*ppv);
156     return S_OK;
157 }
158
159 static ULONG WINAPI VBScript_AddRef(IActiveScript *iface)
160 {
161     VBScript *This = impl_from_IActiveScript(iface);
162     LONG ref = InterlockedIncrement(&This->ref);
163
164     TRACE("(%p) ref=%d\n", This, ref);
165
166     return ref;
167 }
168
169 static ULONG WINAPI VBScript_Release(IActiveScript *iface)
170 {
171     VBScript *This = impl_from_IActiveScript(iface);
172     LONG ref = InterlockedDecrement(&This->ref);
173
174     TRACE("(%p) ref=%d\n", iface, ref);
175
176     if(!ref) {
177         if(This->site)
178             IActiveScriptSite_Release(This->site);
179         heap_free(This);
180     }
181
182     return ref;
183 }
184
185 static HRESULT WINAPI VBScript_SetScriptSite(IActiveScript *iface, IActiveScriptSite *pass)
186 {
187     VBScript *This = impl_from_IActiveScript(iface);
188     LCID lcid;
189     HRESULT hres;
190
191     TRACE("(%p)->(%p)\n", This, pass);
192
193     if(!pass)
194         return E_POINTER;
195
196     if(This->site)
197         return E_UNEXPECTED;
198
199     if(InterlockedCompareExchange(&This->thread_id, GetCurrentThreadId(), 0))
200         return E_UNEXPECTED;
201
202     This->site = pass;
203     IActiveScriptSite_AddRef(This->site);
204
205     hres = IActiveScriptSite_GetLCID(This->site, &lcid);
206     if(hres == S_OK)
207         This->lcid = lcid;
208
209     return This->ctx ? set_ctx_site(This) : S_OK;
210 }
211
212 static HRESULT WINAPI VBScript_GetScriptSite(IActiveScript *iface, REFIID riid,
213                                             void **ppvObject)
214 {
215     VBScript *This = impl_from_IActiveScript(iface);
216     FIXME("(%p)->()\n", This);
217     return E_NOTIMPL;
218 }
219
220 static HRESULT WINAPI VBScript_SetScriptState(IActiveScript *iface, SCRIPTSTATE ss)
221 {
222     VBScript *This = impl_from_IActiveScript(iface);
223
224     TRACE("(%p)->(%d)\n", This, ss);
225
226     if(This->thread_id && GetCurrentThreadId() != This->thread_id)
227         return E_UNEXPECTED;
228
229     if(ss == SCRIPTSTATE_UNINITIALIZED) {
230         if(This->state == SCRIPTSTATE_CLOSED)
231             return E_UNEXPECTED;
232
233         decrease_state(This, SCRIPTSTATE_UNINITIALIZED);
234         return S_OK;
235     }
236
237     if(!This->ctx)
238         return E_UNEXPECTED;
239
240     switch(ss) {
241     case SCRIPTSTATE_STARTED:
242     case SCRIPTSTATE_CONNECTED: /* FIXME */
243         if(This->state == SCRIPTSTATE_CLOSED)
244             return E_UNEXPECTED;
245
246         exec_queued_code(This);
247         break;
248     case SCRIPTSTATE_INITIALIZED:
249         FIXME("unimplemented SCRIPTSTATE_INITIALIZED\n");
250         return S_OK;
251     default:
252         FIXME("unimplemented state %d\n", ss);
253         return E_NOTIMPL;
254     }
255
256     change_state(This, ss);
257     return S_OK;
258 }
259
260 static HRESULT WINAPI VBScript_GetScriptState(IActiveScript *iface, SCRIPTSTATE *pssState)
261 {
262     VBScript *This = impl_from_IActiveScript(iface);
263
264     TRACE("(%p)->(%p)\n", This, pssState);
265
266     if(!pssState)
267         return E_POINTER;
268
269     if(This->thread_id && This->thread_id != GetCurrentThreadId())
270         return E_UNEXPECTED;
271
272     *pssState = This->state;
273     return S_OK;
274 }
275
276 static HRESULT WINAPI VBScript_Close(IActiveScript *iface)
277 {
278     VBScript *This = impl_from_IActiveScript(iface);
279
280     TRACE("(%p)->()\n", This);
281
282     if(This->thread_id && This->thread_id != GetCurrentThreadId())
283         return E_UNEXPECTED;
284
285     decrease_state(This, SCRIPTSTATE_CLOSED);
286     return S_OK;
287 }
288
289 static HRESULT WINAPI VBScript_AddNamedItem(IActiveScript *iface, LPCOLESTR pstrName, DWORD dwFlags)
290 {
291     VBScript *This = impl_from_IActiveScript(iface);
292     FIXME("(%p)->(%s %x)\n", This, debugstr_w(pstrName), dwFlags);
293     return S_OK;
294 }
295
296 static HRESULT WINAPI VBScript_AddTypeLib(IActiveScript *iface, REFGUID rguidTypeLib,
297         DWORD dwMajor, DWORD dwMinor, DWORD dwFlags)
298 {
299     VBScript *This = impl_from_IActiveScript(iface);
300     FIXME("(%p)->()\n", This);
301     return E_NOTIMPL;
302 }
303
304 static HRESULT WINAPI VBScript_GetScriptDispatch(IActiveScript *iface, LPCOLESTR pstrItemName, IDispatch **ppdisp)
305 {
306     VBScript *This = impl_from_IActiveScript(iface);
307
308     TRACE("(%p)->(%p)\n", This, ppdisp);
309
310     if(!ppdisp)
311         return E_POINTER;
312
313     if(This->thread_id != GetCurrentThreadId() || !This->ctx->script_obj) {
314         *ppdisp = NULL;
315         return E_UNEXPECTED;
316     }
317
318     *ppdisp = (IDispatch*)&This->ctx->script_obj->IDispatchEx_iface;
319     IDispatch_AddRef(*ppdisp);
320     return S_OK;
321 }
322
323 static HRESULT WINAPI VBScript_GetCurrentScriptThreadID(IActiveScript *iface,
324                                                        SCRIPTTHREADID *pstridThread)
325 {
326     VBScript *This = impl_from_IActiveScript(iface);
327     FIXME("(%p)->()\n", This);
328     return E_NOTIMPL;
329 }
330
331 static HRESULT WINAPI VBScript_GetScriptThreadID(IActiveScript *iface,
332                                                 DWORD dwWin32ThreadId, SCRIPTTHREADID *pstidThread)
333 {
334     VBScript *This = impl_from_IActiveScript(iface);
335     FIXME("(%p)->()\n", This);
336     return E_NOTIMPL;
337 }
338
339 static HRESULT WINAPI VBScript_GetScriptThreadState(IActiveScript *iface,
340         SCRIPTTHREADID stidThread, SCRIPTTHREADSTATE *pstsState)
341 {
342     VBScript *This = impl_from_IActiveScript(iface);
343     FIXME("(%p)->()\n", This);
344     return E_NOTIMPL;
345 }
346
347 static HRESULT WINAPI VBScript_InterruptScriptThread(IActiveScript *iface,
348         SCRIPTTHREADID stidThread, const EXCEPINFO *pexcepinfo, DWORD dwFlags)
349 {
350     VBScript *This = impl_from_IActiveScript(iface);
351     FIXME("(%p)->()\n", This);
352     return E_NOTIMPL;
353 }
354
355 static HRESULT WINAPI VBScript_Clone(IActiveScript *iface, IActiveScript **ppscript)
356 {
357     VBScript *This = impl_from_IActiveScript(iface);
358     FIXME("(%p)->()\n", This);
359     return E_NOTIMPL;
360 }
361
362 static const IActiveScriptVtbl VBScriptVtbl = {
363     VBScript_QueryInterface,
364     VBScript_AddRef,
365     VBScript_Release,
366     VBScript_SetScriptSite,
367     VBScript_GetScriptSite,
368     VBScript_SetScriptState,
369     VBScript_GetScriptState,
370     VBScript_Close,
371     VBScript_AddNamedItem,
372     VBScript_AddTypeLib,
373     VBScript_GetScriptDispatch,
374     VBScript_GetCurrentScriptThreadID,
375     VBScript_GetScriptThreadID,
376     VBScript_GetScriptThreadState,
377     VBScript_InterruptScriptThread,
378     VBScript_Clone
379 };
380
381 static inline VBScript *impl_from_IActiveScriptParse(IActiveScriptParse *iface)
382 {
383     return CONTAINING_RECORD(iface, VBScript, IActiveScriptParse_iface);
384 }
385
386 static HRESULT WINAPI VBScriptParse_QueryInterface(IActiveScriptParse *iface, REFIID riid, void **ppv)
387 {
388     VBScript *This = impl_from_IActiveScriptParse(iface);
389     return IActiveScript_QueryInterface(&This->IActiveScript_iface, riid, ppv);
390 }
391
392 static ULONG WINAPI VBScriptParse_AddRef(IActiveScriptParse *iface)
393 {
394     VBScript *This = impl_from_IActiveScriptParse(iface);
395     return IActiveScript_AddRef(&This->IActiveScript_iface);
396 }
397
398 static ULONG WINAPI VBScriptParse_Release(IActiveScriptParse *iface)
399 {
400     VBScript *This = impl_from_IActiveScriptParse(iface);
401     return IActiveScript_Release(&This->IActiveScript_iface);
402 }
403
404 static HRESULT WINAPI VBScriptParse_InitNew(IActiveScriptParse *iface)
405 {
406     VBScript *This = impl_from_IActiveScriptParse(iface);
407     script_ctx_t *ctx, *old_ctx;
408
409     TRACE("(%p)\n", This);
410
411     if(This->ctx)
412         return E_UNEXPECTED;
413
414     ctx = heap_alloc_zero(sizeof(script_ctx_t));
415     if(!ctx)
416         return E_OUTOFMEMORY;
417
418     old_ctx = InterlockedCompareExchangePointer((void**)&This->ctx, ctx, NULL);
419     if(old_ctx) {
420         destroy_script(ctx);
421         return E_UNEXPECTED;
422     }
423
424     return This->site ? set_ctx_site(This) : S_OK;
425 }
426
427 static HRESULT WINAPI VBScriptParse_AddScriptlet(IActiveScriptParse *iface,
428         LPCOLESTR pstrDefaultName, LPCOLESTR pstrCode, LPCOLESTR pstrItemName,
429         LPCOLESTR pstrSubItemName, LPCOLESTR pstrEventName, LPCOLESTR pstrDelimiter,
430         CTXARG_T dwSourceContextCookie, ULONG ulStartingLineNumber, DWORD dwFlags,
431         BSTR *pbstrName, EXCEPINFO *pexcepinfo)
432 {
433     VBScript *This = impl_from_IActiveScriptParse(iface);
434     FIXME("(%p)->(%s %s %s %s %s %s %s %u %x %p %p)\n", This, debugstr_w(pstrDefaultName),
435           debugstr_w(pstrCode), debugstr_w(pstrItemName), debugstr_w(pstrSubItemName),
436           debugstr_w(pstrEventName), debugstr_w(pstrDelimiter), wine_dbgstr_longlong(dwSourceContextCookie),
437           ulStartingLineNumber, dwFlags, pbstrName, pexcepinfo);
438     return E_NOTIMPL;
439 }
440
441 static HRESULT WINAPI VBScriptParse_ParseScriptText(IActiveScriptParse *iface,
442         LPCOLESTR pstrCode, LPCOLESTR pstrItemName, IUnknown *punkContext,
443         LPCOLESTR pstrDelimiter, CTXARG_T dwSourceContextCookie, ULONG ulStartingLine,
444         DWORD dwFlags, VARIANT *pvarResult, EXCEPINFO *pexcepinfo)
445 {
446     VBScript *This = impl_from_IActiveScriptParse(iface);
447     FIXME("(%p)->(%s %s %p %s %s %u %x %p %p)\n", This, debugstr_w(pstrCode),
448           debugstr_w(pstrItemName), punkContext, debugstr_w(pstrDelimiter),
449           wine_dbgstr_longlong(dwSourceContextCookie), ulStartingLine, dwFlags, pvarResult, pexcepinfo);
450     return E_NOTIMPL;
451 }
452
453 static const IActiveScriptParseVtbl VBScriptParseVtbl = {
454     VBScriptParse_QueryInterface,
455     VBScriptParse_AddRef,
456     VBScriptParse_Release,
457     VBScriptParse_InitNew,
458     VBScriptParse_AddScriptlet,
459     VBScriptParse_ParseScriptText
460 };
461
462 static inline VBScript *impl_from_IObjectSafety(IObjectSafety *iface)
463 {
464     return CONTAINING_RECORD(iface, VBScript, IObjectSafety_iface);
465 }
466
467 static HRESULT WINAPI VBScriptSafety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
468 {
469     VBScript *This = impl_from_IObjectSafety(iface);
470     return IActiveScript_QueryInterface(&This->IActiveScript_iface, riid, ppv);
471 }
472
473 static ULONG WINAPI VBScriptSafety_AddRef(IObjectSafety *iface)
474 {
475     VBScript *This = impl_from_IObjectSafety(iface);
476     return IActiveScript_AddRef(&This->IActiveScript_iface);
477 }
478
479 static ULONG WINAPI VBScriptSafety_Release(IObjectSafety *iface)
480 {
481     VBScript *This = impl_from_IObjectSafety(iface);
482     return IActiveScript_Release(&This->IActiveScript_iface);
483 }
484
485 #define SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER)
486
487 static HRESULT WINAPI VBScriptSafety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
488         DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions)
489 {
490     VBScript *This = impl_from_IObjectSafety(iface);
491
492     TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), pdwSupportedOptions, pdwEnabledOptions);
493
494     if(!pdwSupportedOptions || !pdwEnabledOptions)
495         return E_POINTER;
496
497     *pdwSupportedOptions = SUPPORTED_OPTIONS;
498     *pdwEnabledOptions = This->safeopt;
499     return S_OK;
500 }
501
502 static HRESULT WINAPI VBScriptSafety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
503         DWORD dwOptionSetMask, DWORD dwEnabledOptions)
504 {
505     VBScript *This = impl_from_IObjectSafety(iface);
506
507     TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), dwOptionSetMask, dwEnabledOptions);
508
509     if(dwOptionSetMask & ~SUPPORTED_OPTIONS)
510         return E_FAIL;
511
512     This->safeopt = (dwEnabledOptions & dwOptionSetMask) | (This->safeopt & ~dwOptionSetMask) | INTERFACE_USES_DISPEX;
513     return S_OK;
514 }
515
516 static const IObjectSafetyVtbl VBScriptSafetyVtbl = {
517     VBScriptSafety_QueryInterface,
518     VBScriptSafety_AddRef,
519     VBScriptSafety_Release,
520     VBScriptSafety_GetInterfaceSafetyOptions,
521     VBScriptSafety_SetInterfaceSafetyOptions
522 };
523
524 HRESULT WINAPI VBScriptFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter, REFIID riid, void **ppv)
525 {
526     VBScript *ret;
527     HRESULT hres;
528
529     TRACE("(%p %s %p)\n", pUnkOuter, debugstr_guid(riid), ppv);
530
531     ret = heap_alloc_zero(sizeof(*ret));
532     if(!ret)
533         return E_OUTOFMEMORY;
534
535     ret->IActiveScript_iface.lpVtbl = &VBScriptVtbl;
536     ret->IActiveScriptParse_iface.lpVtbl = &VBScriptParseVtbl;
537     ret->IObjectSafety_iface.lpVtbl = &VBScriptSafetyVtbl;
538
539     ret->ref = 1;
540     ret->state = SCRIPTSTATE_UNINITIALIZED;
541     ret->safeopt = INTERFACE_USES_DISPEX;
542
543     hres = IActiveScript_QueryInterface(&ret->IActiveScript_iface, riid, ppv);
544     IActiveScript_Release(&ret->IActiveScript_iface);
545     return hres;
546 }