vbscipt: Added IActiveScript::Close 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
30 #include "vbscript.h"
31
32 #include "wine/debug.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
35
36 #ifdef _WIN64
37
38 #define CTXARG_T DWORDLONG
39 #define IActiveScriptParseVtbl IActiveScriptParse64Vtbl
40
41 #else
42
43 #define CTXARG_T DWORD
44 #define IActiveScriptParseVtbl IActiveScriptParse32Vtbl
45
46 #endif
47
48 struct VBScript {
49     IActiveScript IActiveScript_iface;
50     IActiveScriptParse IActiveScriptParse_iface;
51
52     LONG ref;
53
54     SCRIPTSTATE state;
55     IActiveScriptSite *site;
56     script_ctx_t *ctx;
57     LONG thread_id;
58     LCID lcid;
59 };
60
61 static void change_state(VBScript *This, SCRIPTSTATE state)
62 {
63     if(This->state == state)
64         return;
65
66     This->state = state;
67     if(This->site)
68         IActiveScriptSite_OnStateChange(This->site, state);
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 {
139         FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
140         *ppv = NULL;
141         return E_NOINTERFACE;
142     }
143
144     IUnknown_AddRef((IUnknown*)*ppv);
145     return S_OK;
146 }
147
148 static ULONG WINAPI VBScript_AddRef(IActiveScript *iface)
149 {
150     VBScript *This = impl_from_IActiveScript(iface);
151     LONG ref = InterlockedIncrement(&This->ref);
152
153     TRACE("(%p) ref=%d\n", This, ref);
154
155     return ref;
156 }
157
158 static ULONG WINAPI VBScript_Release(IActiveScript *iface)
159 {
160     VBScript *This = impl_from_IActiveScript(iface);
161     LONG ref = InterlockedDecrement(&This->ref);
162
163     TRACE("(%p) ref=%d\n", iface, ref);
164
165     if(!ref) {
166         if(This->site)
167             IActiveScriptSite_Release(This->site);
168         heap_free(This);
169     }
170
171     return ref;
172 }
173
174 static HRESULT WINAPI VBScript_SetScriptSite(IActiveScript *iface, IActiveScriptSite *pass)
175 {
176     VBScript *This = impl_from_IActiveScript(iface);
177     LCID lcid;
178     HRESULT hres;
179
180     TRACE("(%p)->(%p)\n", This, pass);
181
182     if(!pass)
183         return E_POINTER;
184
185     if(This->site)
186         return E_UNEXPECTED;
187
188     if(InterlockedCompareExchange(&This->thread_id, GetCurrentThreadId(), 0))
189         return E_UNEXPECTED;
190
191     This->site = pass;
192     IActiveScriptSite_AddRef(This->site);
193
194     hres = IActiveScriptSite_GetLCID(This->site, &lcid);
195     if(hres == S_OK)
196         This->lcid = lcid;
197
198     return This->ctx ? set_ctx_site(This) : S_OK;
199 }
200
201 static HRESULT WINAPI VBScript_GetScriptSite(IActiveScript *iface, REFIID riid,
202                                             void **ppvObject)
203 {
204     VBScript *This = impl_from_IActiveScript(iface);
205     FIXME("(%p)->()\n", This);
206     return E_NOTIMPL;
207 }
208
209 static HRESULT WINAPI VBScript_SetScriptState(IActiveScript *iface, SCRIPTSTATE ss)
210 {
211     VBScript *This = impl_from_IActiveScript(iface);
212     FIXME("(%p)->(%d)\n", This, ss);
213     return S_OK;
214 }
215
216 static HRESULT WINAPI VBScript_GetScriptState(IActiveScript *iface, SCRIPTSTATE *pssState)
217 {
218     VBScript *This = impl_from_IActiveScript(iface);
219     FIXME("(%p)->(%p)\n", This, pssState);
220     return E_NOTIMPL;
221 }
222
223 static HRESULT WINAPI VBScript_Close(IActiveScript *iface)
224 {
225     VBScript *This = impl_from_IActiveScript(iface);
226
227     TRACE("(%p)->()\n", This);
228
229     if(This->thread_id && This->thread_id != GetCurrentThreadId())
230         return E_UNEXPECTED;
231
232     decrease_state(This, SCRIPTSTATE_CLOSED);
233     return S_OK;
234 }
235
236 static HRESULT WINAPI VBScript_AddNamedItem(IActiveScript *iface, LPCOLESTR pstrName, DWORD dwFlags)
237 {
238     VBScript *This = impl_from_IActiveScript(iface);
239     FIXME("(%p)->(%s %x)\n", This, debugstr_w(pstrName), dwFlags);
240     return S_OK;
241 }
242
243 static HRESULT WINAPI VBScript_AddTypeLib(IActiveScript *iface, REFGUID rguidTypeLib,
244         DWORD dwMajor, DWORD dwMinor, DWORD dwFlags)
245 {
246     VBScript *This = impl_from_IActiveScript(iface);
247     FIXME("(%p)->()\n", This);
248     return E_NOTIMPL;
249 }
250
251 static HRESULT WINAPI VBScript_GetScriptDispatch(IActiveScript *iface, LPCOLESTR pstrItemName, IDispatch **ppdisp)
252 {
253     VBScript *This = impl_from_IActiveScript(iface);
254     FIXME("(%p)->(%p)\n", This, ppdisp);
255     return E_NOTIMPL;
256 }
257
258 static HRESULT WINAPI VBScript_GetCurrentScriptThreadID(IActiveScript *iface,
259                                                        SCRIPTTHREADID *pstridThread)
260 {
261     VBScript *This = impl_from_IActiveScript(iface);
262     FIXME("(%p)->()\n", This);
263     return E_NOTIMPL;
264 }
265
266 static HRESULT WINAPI VBScript_GetScriptThreadID(IActiveScript *iface,
267                                                 DWORD dwWin32ThreadId, SCRIPTTHREADID *pstidThread)
268 {
269     VBScript *This = impl_from_IActiveScript(iface);
270     FIXME("(%p)->()\n", This);
271     return E_NOTIMPL;
272 }
273
274 static HRESULT WINAPI VBScript_GetScriptThreadState(IActiveScript *iface,
275         SCRIPTTHREADID stidThread, SCRIPTTHREADSTATE *pstsState)
276 {
277     VBScript *This = impl_from_IActiveScript(iface);
278     FIXME("(%p)->()\n", This);
279     return E_NOTIMPL;
280 }
281
282 static HRESULT WINAPI VBScript_InterruptScriptThread(IActiveScript *iface,
283         SCRIPTTHREADID stidThread, const EXCEPINFO *pexcepinfo, DWORD dwFlags)
284 {
285     VBScript *This = impl_from_IActiveScript(iface);
286     FIXME("(%p)->()\n", This);
287     return E_NOTIMPL;
288 }
289
290 static HRESULT WINAPI VBScript_Clone(IActiveScript *iface, IActiveScript **ppscript)
291 {
292     VBScript *This = impl_from_IActiveScript(iface);
293     FIXME("(%p)->()\n", This);
294     return E_NOTIMPL;
295 }
296
297 static const IActiveScriptVtbl VBScriptVtbl = {
298     VBScript_QueryInterface,
299     VBScript_AddRef,
300     VBScript_Release,
301     VBScript_SetScriptSite,
302     VBScript_GetScriptSite,
303     VBScript_SetScriptState,
304     VBScript_GetScriptState,
305     VBScript_Close,
306     VBScript_AddNamedItem,
307     VBScript_AddTypeLib,
308     VBScript_GetScriptDispatch,
309     VBScript_GetCurrentScriptThreadID,
310     VBScript_GetScriptThreadID,
311     VBScript_GetScriptThreadState,
312     VBScript_InterruptScriptThread,
313     VBScript_Clone
314 };
315
316 static inline VBScript *impl_from_IActiveScriptParse(IActiveScriptParse *iface)
317 {
318     return CONTAINING_RECORD(iface, VBScript, IActiveScriptParse_iface);
319 }
320
321 static HRESULT WINAPI VBScriptParse_QueryInterface(IActiveScriptParse *iface, REFIID riid, void **ppv)
322 {
323     VBScript *This = impl_from_IActiveScriptParse(iface);
324     return IActiveScript_QueryInterface(&This->IActiveScript_iface, riid, ppv);
325 }
326
327 static ULONG WINAPI VBScriptParse_AddRef(IActiveScriptParse *iface)
328 {
329     VBScript *This = impl_from_IActiveScriptParse(iface);
330     return IActiveScript_AddRef(&This->IActiveScript_iface);
331 }
332
333 static ULONG WINAPI VBScriptParse_Release(IActiveScriptParse *iface)
334 {
335     VBScript *This = impl_from_IActiveScriptParse(iface);
336     return IActiveScript_Release(&This->IActiveScript_iface);
337 }
338
339 static HRESULT WINAPI VBScriptParse_InitNew(IActiveScriptParse *iface)
340 {
341     VBScript *This = impl_from_IActiveScriptParse(iface);
342     script_ctx_t *ctx;
343
344     TRACE("(%p)\n", This);
345
346     if(This->ctx)
347         return E_UNEXPECTED;
348
349     ctx = heap_alloc_zero(sizeof(script_ctx_t));
350     if(!ctx)
351         return E_OUTOFMEMORY;
352
353     ctx = InterlockedCompareExchangePointer((void**)&This->ctx, ctx, NULL);
354     if(ctx) {
355         destroy_script(ctx);
356         return E_UNEXPECTED;
357     }
358
359     return This->site ? set_ctx_site(This) : S_OK;
360 }
361
362 static HRESULT WINAPI VBScriptParse_AddScriptlet(IActiveScriptParse *iface,
363         LPCOLESTR pstrDefaultName, LPCOLESTR pstrCode, LPCOLESTR pstrItemName,
364         LPCOLESTR pstrSubItemName, LPCOLESTR pstrEventName, LPCOLESTR pstrDelimiter,
365         CTXARG_T dwSourceContextCookie, ULONG ulStartingLineNumber, DWORD dwFlags,
366         BSTR *pbstrName, EXCEPINFO *pexcepinfo)
367 {
368     VBScript *This = impl_from_IActiveScriptParse(iface);
369     FIXME("(%p)->(%s %s %s %s %s %s %s %u %x %p %p)\n", This, debugstr_w(pstrDefaultName),
370           debugstr_w(pstrCode), debugstr_w(pstrItemName), debugstr_w(pstrSubItemName),
371           debugstr_w(pstrEventName), debugstr_w(pstrDelimiter), wine_dbgstr_longlong(dwSourceContextCookie),
372           ulStartingLineNumber, dwFlags, pbstrName, pexcepinfo);
373     return E_NOTIMPL;
374 }
375
376 static HRESULT WINAPI VBScriptParse_ParseScriptText(IActiveScriptParse *iface,
377         LPCOLESTR pstrCode, LPCOLESTR pstrItemName, IUnknown *punkContext,
378         LPCOLESTR pstrDelimiter, CTXARG_T dwSourceContextCookie, ULONG ulStartingLine,
379         DWORD dwFlags, VARIANT *pvarResult, EXCEPINFO *pexcepinfo)
380 {
381     VBScript *This = impl_from_IActiveScriptParse(iface);
382     FIXME("(%p)->(%s %s %p %s %s %u %x %p %p)\n", This, debugstr_w(pstrCode),
383           debugstr_w(pstrItemName), punkContext, debugstr_w(pstrDelimiter),
384           wine_dbgstr_longlong(dwSourceContextCookie), ulStartingLine, dwFlags, pvarResult, pexcepinfo);
385     return E_NOTIMPL;
386 }
387
388 static const IActiveScriptParseVtbl VBScriptParseVtbl = {
389     VBScriptParse_QueryInterface,
390     VBScriptParse_AddRef,
391     VBScriptParse_Release,
392     VBScriptParse_InitNew,
393     VBScriptParse_AddScriptlet,
394     VBScriptParse_ParseScriptText
395 };
396
397 HRESULT WINAPI VBScriptFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter, REFIID riid, void **ppv)
398 {
399     VBScript *ret;
400     HRESULT hres;
401
402     TRACE("(%p %s %p)\n", pUnkOuter, debugstr_guid(riid), ppv);
403
404     ret = heap_alloc_zero(sizeof(*ret));
405     if(!ret)
406         return E_OUTOFMEMORY;
407
408     ret->IActiveScript_iface.lpVtbl = &VBScriptVtbl;
409     ret->IActiveScriptParse_iface.lpVtbl = &VBScriptParseVtbl;
410
411     ret->ref = 1;
412     ret->state = SCRIPTSTATE_UNINITIALIZED;
413
414     hres = IActiveScript_QueryInterface(&ret->IActiveScript_iface, riid, ppv);
415     IActiveScript_Release(&ret->IActiveScript_iface);
416     return hres;
417 }