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