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