xref: /reactos/dll/win32/vbscript/global.c (revision 9a0ddc13)
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 <assert.h>
20 #include <math.h>
21 
22 #include "vbscript.h"
23 #include "vbscript_defs.h"
24 
25 #include "mshtmhst.h"
26 #include "objsafe.h"
27 
28 #include "wine/debug.h"
29 
30 #ifdef __REACTOS__
31 #include <wingdi.h>
32 #include <winnls.h>
33 #endif
34 
35 WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
36 
37 #define VB_E_CANNOT_CREATE_OBJ 0x800a01ad
38 #define VB_E_MK_PARSE_ERROR    0x800a01b0
39 
40 /* Defined as extern in urlmon.idl, but not exported by uuid.lib */
41 const GUID GUID_CUSTOM_CONFIRMOBJECTSAFETY =
42     {0x10200490,0xfa38,0x11d0,{0xac,0x0e,0x00,0xa0,0xc9,0xf,0xff,0xc0}};
43 
44 static const WCHAR emptyW[] = {0};
45 static const WCHAR vbscriptW[] = {'V','B','S','c','r','i','p','t',0};
46 
47 #define BP_GET      1
48 #define BP_GETPUT   2
49 
50 typedef struct {
51     UINT16 len;
52     WCHAR buf[7];
53 } string_constant_t;
54 
55 struct _builtin_prop_t {
56     const WCHAR *name;
57     HRESULT (*proc)(BuiltinDisp*,VARIANT*,unsigned,VARIANT*);
58     DWORD flags;
59     unsigned min_args;
60     UINT_PTR max_args;
61 };
62 
impl_from_IDispatch(IDispatch * iface)63 static inline BuiltinDisp *impl_from_IDispatch(IDispatch *iface)
64 {
65     return CONTAINING_RECORD(iface, BuiltinDisp, IDispatch_iface);
66 }
67 
Builtin_QueryInterface(IDispatch * iface,REFIID riid,void ** ppv)68 static HRESULT WINAPI Builtin_QueryInterface(IDispatch *iface, REFIID riid, void **ppv)
69 {
70     BuiltinDisp *This = impl_from_IDispatch(iface);
71 
72     if(IsEqualGUID(&IID_IUnknown, riid)) {
73         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
74         *ppv = &This->IDispatch_iface;
75     }else if(IsEqualGUID(&IID_IDispatch, riid)) {
76         TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
77         *ppv = &This->IDispatch_iface;
78     }else {
79         WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
80         *ppv = NULL;
81         return E_NOINTERFACE;
82     }
83 
84     IUnknown_AddRef((IUnknown*)*ppv);
85     return S_OK;
86 }
87 
Builtin_AddRef(IDispatch * iface)88 static ULONG WINAPI Builtin_AddRef(IDispatch *iface)
89 {
90     BuiltinDisp *This = impl_from_IDispatch(iface);
91     LONG ref = InterlockedIncrement(&This->ref);
92 
93     TRACE("(%p) ref=%d\n", This, ref);
94 
95     return ref;
96 }
97 
Builtin_Release(IDispatch * iface)98 static ULONG WINAPI Builtin_Release(IDispatch *iface)
99 {
100     BuiltinDisp *This = impl_from_IDispatch(iface);
101     LONG ref = InterlockedDecrement(&This->ref);
102 
103     TRACE("(%p) ref=%d\n", This, ref);
104 
105     if(!ref) {
106         assert(!This->ctx);
107         heap_free(This);
108     }
109 
110     return ref;
111 }
112 
Builtin_GetTypeInfoCount(IDispatch * iface,UINT * pctinfo)113 static HRESULT WINAPI Builtin_GetTypeInfoCount(IDispatch *iface, UINT *pctinfo)
114 {
115     BuiltinDisp *This = impl_from_IDispatch(iface);
116     TRACE("(%p)->(%p)\n", This, pctinfo);
117     *pctinfo = 0;
118     return S_OK;
119 }
120 
Builtin_GetTypeInfo(IDispatch * iface,UINT iTInfo,LCID lcid,ITypeInfo ** ppTInfo)121 static HRESULT WINAPI Builtin_GetTypeInfo(IDispatch *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
122 {
123     BuiltinDisp *This = impl_from_IDispatch(iface);
124     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
125     return DISP_E_BADINDEX;
126 }
127 
get_builtin_id(BuiltinDisp * disp,const WCHAR * name,DISPID * id)128 HRESULT get_builtin_id(BuiltinDisp *disp, const WCHAR *name, DISPID *id)
129 {
130     size_t min = 1, max = disp->member_cnt - 1, i;
131     int r;
132 
133     while(min <= max) {
134         i = (min + max) / 2;
135         r = wcsicmp(disp->members[i].name, name);
136         if(!r) {
137             *id = i;
138             return S_OK;
139         }
140         if(r < 0)
141             min = i+1;
142         else
143             max = i-1;
144     }
145 
146     return DISP_E_MEMBERNOTFOUND;
147 
148 }
149 
Builtin_GetIDsOfNames(IDispatch * iface,REFIID riid,LPOLESTR * names,UINT name_cnt,LCID lcid,DISPID * ids)150 static HRESULT WINAPI Builtin_GetIDsOfNames(IDispatch *iface, REFIID riid, LPOLESTR *names, UINT name_cnt,
151                                             LCID lcid, DISPID *ids)
152 {
153     BuiltinDisp *This = impl_from_IDispatch(iface);
154     unsigned i;
155     HRESULT hres;
156 
157     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), names, name_cnt, lcid, ids);
158 
159     if(!This->ctx) {
160         FIXME("NULL context\n");
161         return E_UNEXPECTED;
162     }
163 
164     for(i = 0; i < name_cnt; i++) {
165         hres = get_builtin_id(This, names[i], &ids[i]);
166         if(FAILED(hres))
167             return hres;
168     }
169 
170     return S_OK;
171 }
172 
Builtin_Invoke(IDispatch * iface,DISPID id,REFIID riid,LCID lcid,WORD flags,DISPPARAMS * dp,VARIANT * res,EXCEPINFO * ei,UINT * err)173 static HRESULT WINAPI Builtin_Invoke(IDispatch *iface, DISPID id, REFIID riid, LCID lcid, WORD flags,
174                                      DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei, UINT *err)
175 {
176     BuiltinDisp *This = impl_from_IDispatch(iface);
177     const builtin_prop_t *prop;
178     VARIANT args[8];
179     unsigned argn, i;
180 
181     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, id, debugstr_guid(riid), lcid, flags, dp, res, ei, err);
182 
183     if(!This->ctx) {
184         FIXME("NULL context\n");
185         return E_UNEXPECTED;
186     }
187 
188     if(id >= This->member_cnt || (!This->members[id].proc && !This->members[id].flags))
189         return DISP_E_MEMBERNOTFOUND;
190     prop = This->members + id;
191 
192     switch(flags) {
193     case DISPATCH_PROPERTYGET:
194         if(!(prop->flags & (BP_GET|BP_GETPUT))) {
195             FIXME("property does not support DISPATCH_PROPERTYGET\n");
196             return E_FAIL;
197         }
198         break;
199     case DISPATCH_PROPERTYGET|DISPATCH_METHOD:
200         if(!prop->proc && prop->flags == BP_GET) {
201             const int vt = prop->min_args, val = prop->max_args;
202             switch(vt) {
203             case VT_I2:
204                 V_VT(res) = VT_I2;
205                 V_I2(res) = val;
206                 break;
207             case VT_I4:
208                 V_VT(res) = VT_I4;
209                 V_I4(res) = val;
210                 break;
211             case VT_BSTR: {
212                 const string_constant_t *str = (const string_constant_t*)prop->max_args;
213                 BSTR ret;
214 
215                 ret = SysAllocStringLen(str->buf, str->len);
216                 if(!ret)
217                     return E_OUTOFMEMORY;
218 
219                 V_VT(res) = VT_BSTR;
220                 V_BSTR(res) = ret;
221                 break;
222             }
223             DEFAULT_UNREACHABLE;
224             }
225             return S_OK;
226         }
227         break;
228     case DISPATCH_METHOD:
229         if(prop->flags & (BP_GET|BP_GETPUT)) {
230             FIXME("Call on property\n");
231             return E_FAIL;
232         }
233         break;
234     case DISPATCH_PROPERTYPUT:
235         if(!(prop->flags & BP_GETPUT)) {
236             FIXME("property does not support DISPATCH_PROPERTYPUT\n");
237             return E_FAIL;
238         }
239 
240         FIXME("call put\n");
241         return E_NOTIMPL;
242     default:
243         FIXME("unsupported flags %x\n", flags);
244         return E_NOTIMPL;
245     }
246 
247     argn = arg_cnt(dp);
248 
249     if(argn < prop->min_args || argn > (prop->max_args ? prop->max_args : prop->min_args)) {
250         WARN("invalid number of arguments\n");
251         return MAKE_VBSERROR(VBSE_FUNC_ARITY_MISMATCH);
252     }
253 
254     assert(argn < ARRAY_SIZE(args));
255 
256     for(i=0; i < argn; i++) {
257         if(V_VT(dp->rgvarg+dp->cArgs-i-1) == (VT_BYREF|VT_VARIANT))
258             args[i] = *V_VARIANTREF(dp->rgvarg+dp->cArgs-i-1);
259         else
260             args[i] = dp->rgvarg[dp->cArgs-i-1];
261     }
262 
263     return prop->proc(This, args, dp->cArgs, res);
264 }
265 
266 static const IDispatchVtbl BuiltinDispVtbl = {
267     Builtin_QueryInterface,
268     Builtin_AddRef,
269     Builtin_Release,
270     Builtin_GetTypeInfoCount,
271     Builtin_GetTypeInfo,
272     Builtin_GetIDsOfNames,
273     Builtin_Invoke
274 };
275 
create_builtin_dispatch(script_ctx_t * ctx,const builtin_prop_t * members,size_t member_cnt,BuiltinDisp ** ret)276 static HRESULT create_builtin_dispatch(script_ctx_t *ctx, const builtin_prop_t *members, size_t member_cnt, BuiltinDisp **ret)
277 {
278     BuiltinDisp *disp;
279 
280     if(!(disp = heap_alloc(sizeof(*disp))))
281         return E_OUTOFMEMORY;
282 
283     disp->IDispatch_iface.lpVtbl = &BuiltinDispVtbl;
284     disp->ref = 1;
285     disp->members = members;
286     disp->member_cnt = member_cnt;
287     disp->ctx = ctx;
288 
289     *ret = disp;
290     return S_OK;
291 }
292 
get_sec_mgr(script_ctx_t * ctx)293 static IInternetHostSecurityManager *get_sec_mgr(script_ctx_t *ctx)
294 {
295     IInternetHostSecurityManager *secmgr;
296     IServiceProvider *sp;
297     HRESULT hres;
298 
299     if(!ctx->site)
300         return NULL;
301 
302     if(ctx->secmgr)
303         return ctx->secmgr;
304 
305     hres = IActiveScriptSite_QueryInterface(ctx->site, &IID_IServiceProvider, (void**)&sp);
306     if(FAILED(hres))
307         return NULL;
308 
309     hres = IServiceProvider_QueryService(sp, &SID_SInternetHostSecurityManager, &IID_IInternetHostSecurityManager,
310             (void**)&secmgr);
311     IServiceProvider_Release(sp);
312     if(FAILED(hres))
313         return NULL;
314 
315     return ctx->secmgr = secmgr;
316 }
317 
return_string(VARIANT * res,const WCHAR * str)318 static HRESULT return_string(VARIANT *res, const WCHAR *str)
319 {
320     BSTR ret;
321 
322     if(!res)
323         return S_OK;
324 
325     ret = SysAllocString(str);
326     if(!ret)
327         return E_OUTOFMEMORY;
328 
329     V_VT(res) = VT_BSTR;
330     V_BSTR(res) = ret;
331     return S_OK;
332 }
333 
return_bstr(VARIANT * res,BSTR str)334 static HRESULT return_bstr(VARIANT *res, BSTR str)
335 {
336     if(res) {
337         V_VT(res) = VT_BSTR;
338         V_BSTR(res) = str;
339     }else {
340         SysFreeString(str);
341     }
342     return S_OK;
343 }
344 
return_bool(VARIANT * res,BOOL val)345 static HRESULT return_bool(VARIANT *res, BOOL val)
346 {
347     if(res) {
348         V_VT(res) = VT_BOOL;
349         V_BOOL(res) = val ? VARIANT_TRUE : VARIANT_FALSE;
350     }
351     return S_OK;
352 }
353 
return_short(VARIANT * res,short val)354 static HRESULT return_short(VARIANT *res, short val)
355 {
356     if(res) {
357         V_VT(res) = VT_I2;
358         V_I2(res) = val;
359     }
360 
361     return S_OK;
362 }
363 
return_int(VARIANT * res,int val)364 static HRESULT return_int(VARIANT *res, int val)
365 {
366     if(res) {
367         V_VT(res) = VT_I4;
368         V_I4(res) = val;
369     }
370 
371     return S_OK;
372 }
373 
return_double(VARIANT * res,double val)374 static inline HRESULT return_double(VARIANT *res, double val)
375 {
376     if(res) {
377         V_VT(res) = VT_R8;
378         V_R8(res) = val;
379     }
380 
381     return S_OK;
382 }
383 
return_float(VARIANT * res,float val)384 static inline HRESULT return_float(VARIANT *res, float val)
385 {
386     if(res) {
387         V_VT(res) = VT_R4;
388         V_R4(res) = val;
389     }
390 
391     return S_OK;
392 }
393 
return_null(VARIANT * res)394 static inline HRESULT return_null(VARIANT *res)
395 {
396     if(res)
397         V_VT(res) = VT_NULL;
398     return S_OK;
399 }
400 
return_date(VARIANT * res,double date)401 static inline HRESULT return_date(VARIANT *res, double date)
402 {
403     if(res) {
404         V_VT(res) = VT_DATE;
405         V_DATE(res) = date;
406     }
407     return S_OK;
408 }
409 
to_int(VARIANT * v,int * ret)410 HRESULT to_int(VARIANT *v, int *ret)
411 {
412     VARIANT r;
413     HRESULT hres;
414 
415     V_VT(&r) = VT_EMPTY;
416     hres = VariantChangeType(&r, v, 0, VT_I4);
417     if(FAILED(hres))
418         return hres;
419 
420     *ret = V_I4(&r);
421     return S_OK;
422 }
423 
to_double(VARIANT * v,double * ret)424 static HRESULT to_double(VARIANT *v, double *ret)
425 {
426     VARIANT dst;
427     HRESULT hres;
428 
429     V_VT(&dst) = VT_EMPTY;
430     hres = VariantChangeType(&dst, v, 0, VT_R8);
431     if(FAILED(hres))
432         return hres;
433 
434     *ret = V_R8(&dst);
435     return S_OK;
436 }
437 
to_string(VARIANT * v,BSTR * ret)438 static HRESULT to_string(VARIANT *v, BSTR *ret)
439 {
440     VARIANT dst;
441     HRESULT hres;
442 
443     V_VT(&dst) = VT_EMPTY;
444     hres = VariantChangeType(&dst, v, VARIANT_LOCALBOOL, VT_BSTR);
445     if(FAILED(hres))
446         return hres;
447 
448     *ret = V_BSTR(&dst);
449     return S_OK;
450 }
451 
to_system_time(VARIANT * v,SYSTEMTIME * st)452 static HRESULT to_system_time(VARIANT *v, SYSTEMTIME *st)
453 {
454     VARIANT date;
455     HRESULT hres;
456 
457     V_VT(&date) = VT_EMPTY;
458     hres = VariantChangeType(&date, v, 0, VT_DATE);
459     if(FAILED(hres))
460         return hres;
461 
462     return VariantTimeToSystemTime(V_DATE(&date), st);
463 }
464 
set_object_site(script_ctx_t * ctx,IUnknown * obj)465 static HRESULT set_object_site(script_ctx_t *ctx, IUnknown *obj)
466 {
467     IObjectWithSite *obj_site;
468     IUnknown *ax_site;
469     HRESULT hres;
470 
471     hres = IUnknown_QueryInterface(obj, &IID_IObjectWithSite, (void**)&obj_site);
472     if(FAILED(hres))
473         return S_OK;
474 
475     ax_site = create_ax_site(ctx);
476     if(ax_site) {
477         hres = IObjectWithSite_SetSite(obj_site, ax_site);
478         IUnknown_Release(ax_site);
479     }
480     else
481         hres = E_OUTOFMEMORY;
482     IObjectWithSite_Release(obj_site);
483     return hres;
484 }
485 
create_object(script_ctx_t * ctx,const WCHAR * progid)486 static IUnknown *create_object(script_ctx_t *ctx, const WCHAR *progid)
487 {
488     IInternetHostSecurityManager *secmgr = NULL;
489     struct CONFIRMSAFETY cs;
490     IClassFactoryEx *cfex;
491     IClassFactory *cf;
492     DWORD policy_size;
493     BYTE *bpolicy;
494     IUnknown *obj;
495     DWORD policy;
496     GUID guid;
497     HRESULT hres;
498 
499     hres = CLSIDFromProgID(progid, &guid);
500     if(FAILED(hres))
501         return NULL;
502 
503     TRACE("GUID %s\n", debugstr_guid(&guid));
504 
505     if(ctx->safeopt & INTERFACE_USES_SECURITY_MANAGER) {
506         secmgr = get_sec_mgr(ctx);
507         if(!secmgr)
508             return NULL;
509 
510         policy = 0;
511         hres = IInternetHostSecurityManager_ProcessUrlAction(secmgr, URLACTION_ACTIVEX_RUN,
512                 (BYTE*)&policy, sizeof(policy), (BYTE*)&guid, sizeof(GUID), 0, 0);
513         if(FAILED(hres) || policy != URLPOLICY_ALLOW)
514             return NULL;
515     }
516 
517     hres = CoGetClassObject(&guid, CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER, NULL, &IID_IClassFactory, (void**)&cf);
518     if(FAILED(hres))
519         return NULL;
520 
521     hres = IClassFactory_QueryInterface(cf, &IID_IClassFactoryEx, (void**)&cfex);
522     if(SUCCEEDED(hres)) {
523         FIXME("Use IClassFactoryEx\n");
524         IClassFactoryEx_Release(cfex);
525     }
526 
527     hres = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void**)&obj);
528     if(FAILED(hres))
529         return NULL;
530 
531     if(secmgr) {
532         cs.clsid = guid;
533         cs.pUnk = obj;
534         cs.dwFlags = 0;
535         hres = IInternetHostSecurityManager_QueryCustomPolicy(secmgr, &GUID_CUSTOM_CONFIRMOBJECTSAFETY,
536                 &bpolicy, &policy_size, (BYTE*)&cs, sizeof(cs), 0);
537         if(SUCCEEDED(hres)) {
538             policy = policy_size >= sizeof(DWORD) ? *(DWORD*)bpolicy : URLPOLICY_DISALLOW;
539             CoTaskMemFree(bpolicy);
540         }
541 
542         if(FAILED(hres) || policy != URLPOLICY_ALLOW) {
543             IUnknown_Release(obj);
544             return NULL;
545         }
546     }
547 
548     hres = set_object_site(ctx, obj);
549     if(FAILED(hres)) {
550         IUnknown_Release(obj);
551         return NULL;
552     }
553 
554     return obj;
555 }
556 
show_msgbox(script_ctx_t * ctx,BSTR prompt,unsigned type,BSTR orig_title,VARIANT * res)557 static HRESULT show_msgbox(script_ctx_t *ctx, BSTR prompt, unsigned type, BSTR orig_title, VARIANT *res)
558 {
559     SCRIPTUICHANDLING uic_handling = SCRIPTUICHANDLING_ALLOW;
560     IActiveScriptSiteUIControl *ui_control;
561     IActiveScriptSiteWindow *acts_window;
562     WCHAR *title_buf = NULL;
563     const WCHAR *title;
564     HWND hwnd = NULL;
565     int ret = 0;
566     HRESULT hres;
567 
568     hres = IActiveScriptSite_QueryInterface(ctx->site, &IID_IActiveScriptSiteUIControl, (void**)&ui_control);
569     if(SUCCEEDED(hres)) {
570         hres = IActiveScriptSiteUIControl_GetUIBehavior(ui_control, SCRIPTUICITEM_MSGBOX, &uic_handling);
571         IActiveScriptSiteUIControl_Release(ui_control);
572         if(FAILED(hres))
573             uic_handling = SCRIPTUICHANDLING_ALLOW;
574     }
575 
576     switch(uic_handling) {
577     case SCRIPTUICHANDLING_ALLOW:
578         break;
579     case SCRIPTUICHANDLING_NOUIDEFAULT:
580         return return_short(res, 0);
581     default:
582         FIXME("blocked\n");
583         return E_FAIL;
584     }
585 
586     hres = IActiveScriptSite_QueryInterface(ctx->site, &IID_IActiveScriptSiteWindow, (void**)&acts_window);
587     if(FAILED(hres)) {
588         FIXME("No IActiveScriptSiteWindow\n");
589         return hres;
590     }
591 
592     if(ctx->safeopt & INTERFACE_USES_SECURITY_MANAGER) {
593         if(orig_title && *orig_title) {
594             WCHAR *ptr;
595 
596             title = title_buf = heap_alloc(sizeof(vbscriptW) + (lstrlenW(orig_title)+2)*sizeof(WCHAR));
597             if(!title)
598                 return E_OUTOFMEMORY;
599 
600             memcpy(title_buf, vbscriptW, sizeof(vbscriptW));
601             ptr = title_buf + ARRAY_SIZE(vbscriptW)-1;
602 
603             *ptr++ = ':';
604             *ptr++ = ' ';
605             lstrcpyW(ptr, orig_title);
606         }else {
607             title = vbscriptW;
608         }
609     }else {
610         title = orig_title ? orig_title : emptyW;
611     }
612 
613     hres = IActiveScriptSiteWindow_GetWindow(acts_window, &hwnd);
614     if(SUCCEEDED(hres)) {
615         hres = IActiveScriptSiteWindow_EnableModeless(acts_window, FALSE);
616         if(SUCCEEDED(hres)) {
617             ret = MessageBoxW(hwnd, prompt, title, type);
618             hres = IActiveScriptSiteWindow_EnableModeless(acts_window, TRUE);
619         }
620     }
621 
622     heap_free(title_buf);
623     IActiveScriptSiteWindow_Release(acts_window);
624     if(FAILED(hres)) {
625         FIXME("failed: %08x\n", hres);
626         return hres;
627     }
628 
629     return return_short(res, ret);
630 }
631 
Global_CCur(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)632 static HRESULT Global_CCur(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
633 {
634     VARIANT v;
635     HRESULT hres;
636 
637     TRACE("%s\n", debugstr_variant(arg));
638 
639     assert(args_cnt == 1);
640 
641     V_VT(&v) = VT_EMPTY;
642     hres = VariantChangeType(&v, arg, 0, VT_CY);
643     if(FAILED(hres))
644         return hres;
645 
646     if(!res) {
647         VariantClear(&v);
648         return DISP_E_BADVARTYPE;
649     }
650 
651     *res = v;
652     return S_OK;
653 }
654 
Global_CInt(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)655 static HRESULT Global_CInt(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
656 {
657     VARIANT v;
658     HRESULT hres;
659 
660     TRACE("%s\n", debugstr_variant(arg));
661 
662     assert(args_cnt == 1);
663 
664     V_VT(&v) = VT_EMPTY;
665     hres = VariantChangeType(&v, arg, 0, VT_I2);
666     if(FAILED(hres))
667         return hres;
668 
669     if(!res)
670         return DISP_E_BADVARTYPE;
671     else {
672         *res = v;
673         return S_OK;
674     }
675 }
676 
Global_CLng(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)677 static HRESULT Global_CLng(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
678 {
679     int i;
680     HRESULT hres;
681 
682     TRACE("%s\n", debugstr_variant(arg));
683 
684     assert(args_cnt == 1);
685 
686     hres = to_int(arg, &i);
687     if(FAILED(hres))
688         return hres;
689     if(!res)
690         return DISP_E_BADVARTYPE;
691 
692     return return_int(res, i);
693 }
694 
Global_CBool(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)695 static HRESULT Global_CBool(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
696 {
697     VARIANT v;
698     HRESULT hres;
699 
700     TRACE("%s\n", debugstr_variant(arg));
701 
702     assert(args_cnt == 1);
703 
704     V_VT(&v) = VT_EMPTY;
705     hres = VariantChangeType(&v, arg, VARIANT_LOCALBOOL, VT_BOOL);
706     if(FAILED(hres))
707         return hres;
708 
709     if(res)
710         *res = v;
711     else
712         VariantClear(&v);
713     return S_OK;
714 }
715 
Global_CByte(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)716 static HRESULT Global_CByte(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
717 {
718     VARIANT v;
719     HRESULT hres;
720 
721     TRACE("%s\n", debugstr_variant(arg));
722 
723     assert(args_cnt == 1);
724 
725     V_VT(&v) = VT_EMPTY;
726     hres = VariantChangeType(&v, arg, VARIANT_LOCALBOOL, VT_UI1);
727     if(FAILED(hres))
728         return hres;
729 
730     if(!res) {
731         VariantClear(&v);
732         return DISP_E_BADVARTYPE;
733     }
734 
735     *res = v;
736     return S_OK;
737 }
738 
Global_CDate(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)739 static HRESULT Global_CDate(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
740 {
741     FIXME("\n");
742     return E_NOTIMPL;
743 }
744 
Global_CDbl(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)745 static HRESULT Global_CDbl(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
746 {
747     VARIANT v;
748     HRESULT hres;
749 
750     TRACE("%s\n", debugstr_variant(arg));
751 
752     assert(args_cnt == 1);
753 
754     V_VT(&v) = VT_EMPTY;
755     hres = VariantChangeType(&v, arg, 0, VT_R8);
756     if(FAILED(hres))
757         return hres;
758 
759     if(!res)
760         return DISP_E_BADVARTYPE;
761     else {
762         *res = v;
763         return S_OK;
764     }
765 }
766 
Global_CSng(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)767 static HRESULT Global_CSng(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
768 {
769     VARIANT v;
770     HRESULT hres;
771 
772     TRACE("%s\n", debugstr_variant(arg));
773 
774     assert(args_cnt == 1);
775 
776     V_VT(&v) = VT_EMPTY;
777     hres = VariantChangeType(&v, arg, 0, VT_R4);
778     if(FAILED(hres))
779         return hres;
780 
781     if(!res)
782         return DISP_E_BADVARTYPE;
783 
784    *res = v;
785    return S_OK;
786 }
787 
Global_CStr(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)788 static HRESULT Global_CStr(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
789 {
790     BSTR str;
791     HRESULT hres;
792 
793     TRACE("%s\n", debugstr_variant(arg));
794 
795     if(V_VT(arg) == VT_NULL)
796         return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE);
797 
798     hres = to_string(arg, &str);
799     if(FAILED(hres))
800         return hres;
801 
802     return return_bstr(res, str);
803 }
804 
hex_char(unsigned n)805 static inline WCHAR hex_char(unsigned n)
806 {
807     return n < 10 ? '0'+n : 'A'+n-10;
808 }
809 
Global_Hex(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)810 static HRESULT Global_Hex(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
811 {
812     WCHAR buf[17], *ptr;
813     DWORD n;
814     HRESULT hres;
815     int ret;
816 
817     TRACE("%s\n", debugstr_variant(arg));
818 
819     switch(V_VT(arg)) {
820     case VT_I2:
821         n = (WORD)V_I2(arg);
822         break;
823     case VT_NULL:
824         if(res)
825             V_VT(res) = VT_NULL;
826         return S_OK;
827     default:
828         hres = to_int(arg, &ret);
829         if(FAILED(hres))
830             return hres;
831         else
832             n = ret;
833     }
834 
835     buf[16] = 0;
836     ptr = buf+15;
837 
838     if(n) {
839         do {
840             *ptr-- = hex_char(n & 0xf);
841             n >>= 4;
842         }while(n);
843         ptr++;
844     }else {
845         *ptr = '0';
846     }
847 
848     return return_string(res, ptr);
849 }
850 
Global_Oct(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)851 static HRESULT Global_Oct(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
852 {
853     HRESULT hres;
854     WCHAR buf[23], *ptr;
855     DWORD n;
856     int ret;
857 
858     TRACE("%s\n", debugstr_variant(arg));
859 
860     switch(V_VT(arg)) {
861     case VT_I2:
862         n = (WORD)V_I2(arg);
863         break;
864     case VT_NULL:
865         if(res)
866             V_VT(res) = VT_NULL;
867         return S_OK;
868     default:
869         hres = to_int(arg, &ret);
870         if(FAILED(hres))
871             return hres;
872         else
873             n = ret;
874     }
875 
876     buf[22] = 0;
877     ptr = buf + 21;
878 
879     if(n) {
880         do {
881             *ptr-- = '0' + (n & 0x7);
882             n >>= 3;
883         }while(n);
884         ptr++;
885     }else {
886         *ptr = '0';
887     }
888 
889     return return_string(res, ptr);
890 }
891 
Global_VarType(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)892 static HRESULT Global_VarType(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
893 {
894     VARTYPE vt;
895 
896     TRACE("(%s)\n", debugstr_variant(arg));
897 
898     assert(args_cnt == 1);
899 
900     vt = V_VT(arg) & ~VT_BYREF;
901     if(vt & ~(VT_TYPEMASK | VT_ARRAY)) {
902         FIXME("not supported %s\n", debugstr_variant(arg));
903         return E_NOTIMPL;
904     }
905 
906     return return_short(res, vt);
907 }
908 
Global_IsDate(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)909 static HRESULT Global_IsDate(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
910 {
911     FIXME("\n");
912     return E_NOTIMPL;
913 }
914 
Global_IsEmpty(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)915 static HRESULT Global_IsEmpty(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
916 {
917     TRACE("(%s)\n", debugstr_variant(arg));
918 
919     assert(args_cnt == 1);
920 
921     if(res) {
922         V_VT(res) = VT_BOOL;
923         V_BOOL(res) = V_VT(arg) == VT_EMPTY ? VARIANT_TRUE : VARIANT_FALSE;
924     }
925     return S_OK;
926 }
927 
Global_IsNull(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)928 static HRESULT Global_IsNull(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
929 {
930     TRACE("(%s)\n", debugstr_variant(arg));
931 
932     assert(args_cnt == 1);
933 
934     if(res) {
935         V_VT(res) = VT_BOOL;
936         V_BOOL(res) = V_VT(arg) == VT_NULL ? VARIANT_TRUE : VARIANT_FALSE;
937     }
938     return S_OK;
939 }
940 
Global_IsNumeric(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)941 static HRESULT Global_IsNumeric(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
942 {
943     HRESULT hres;
944     double d;
945 
946     TRACE("(%s)\n", debugstr_variant(arg));
947 
948     assert(args_cnt == 1);
949 
950     hres = to_double(arg, &d);
951 
952     return return_bool(res, SUCCEEDED(hres));
953 }
954 
Global_IsArray(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)955 static HRESULT Global_IsArray(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
956 {
957     FIXME("\n");
958     return E_NOTIMPL;
959 }
960 
Global_IsObject(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)961 static HRESULT Global_IsObject(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
962 {
963     TRACE("(%s)\n", debugstr_variant(arg));
964 
965     assert(args_cnt == 1);
966 
967     if(res) {
968         V_VT(res) = VT_BOOL;
969         V_BOOL(res) = V_VT(arg) == VT_DISPATCH ? VARIANT_TRUE : VARIANT_FALSE;
970     }
971     return S_OK;
972 }
973 
Global_Atn(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)974 static HRESULT Global_Atn(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
975 {
976     HRESULT hres;
977     double d;
978 
979     hres = to_double(arg, &d);
980     if(FAILED(hres))
981         return hres;
982 
983     return return_double(res, atan(d));
984 }
985 
Global_Cos(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)986 static HRESULT Global_Cos(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
987 {
988     HRESULT hres;
989     double d;
990 
991     hres = to_double(arg, &d);
992     if(FAILED(hres))
993         return hres;
994 
995     return return_double(res, cos(d));
996 }
997 
Global_Sin(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)998 static HRESULT Global_Sin(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
999 {
1000     HRESULT hres;
1001     double d;
1002 
1003     hres = to_double(arg, &d);
1004     if(FAILED(hres))
1005         return hres;
1006 
1007     return return_double(res, sin(d));
1008 }
1009 
Global_Tan(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1010 static HRESULT Global_Tan(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1011 {
1012     HRESULT hres;
1013     double d;
1014 
1015     hres = to_double(arg, &d);
1016     if(FAILED(hres))
1017         return hres;
1018 
1019     return return_double(res, tan(d));
1020 }
1021 
Global_Exp(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1022 static HRESULT Global_Exp(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1023 {
1024     HRESULT hres;
1025     double d;
1026 
1027     hres = to_double(arg, &d);
1028     if(FAILED(hres))
1029         return hres;
1030 
1031     return return_double(res, exp(d));
1032 }
1033 
Global_Log(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1034 static HRESULT Global_Log(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1035 {
1036     HRESULT hres;
1037     double d;
1038 
1039     hres = to_double(arg, &d);
1040     if(FAILED(hres))
1041         return hres;
1042 
1043     if(d <= 0)
1044         return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
1045     else
1046         return return_double(res, log(d));
1047 }
1048 
Global_Sqr(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1049 static HRESULT Global_Sqr(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1050 {
1051     HRESULT hres;
1052     double d;
1053 
1054     hres = to_double(arg, &d);
1055     if(FAILED(hres))
1056         return hres;
1057 
1058     if(d < 0)
1059         return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
1060     else
1061         return return_double(res, sqrt(d));
1062 }
1063 
Global_Randomize(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1064 static HRESULT Global_Randomize(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1065 {
1066     FIXME("\n");
1067     return E_NOTIMPL;
1068 }
1069 
Global_Rnd(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1070 static HRESULT Global_Rnd(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1071 {
1072     FIXME("\n");
1073     return E_NOTIMPL;
1074 }
1075 
Global_Timer(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1076 static HRESULT Global_Timer(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1077 {
1078     SYSTEMTIME lt;
1079     double sec;
1080 
1081     GetLocalTime(&lt);
1082     sec = lt.wHour * 3600 + lt.wMinute * 60 + lt.wSecond + lt.wMilliseconds / 1000.0;
1083     return return_float(res, sec);
1084 
1085 }
1086 
Global_LBound(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1087 static HRESULT Global_LBound(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1088 {
1089     FIXME("\n");
1090     return E_NOTIMPL;
1091 }
1092 
Global_UBound(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1093 static HRESULT Global_UBound(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1094 {
1095     SAFEARRAY *sa;
1096     HRESULT hres;
1097     LONG ubound;
1098     int dim;
1099 
1100     assert(args_cnt == 1 || args_cnt == 2);
1101 
1102     TRACE("%s %s\n", debugstr_variant(arg), args_cnt == 2 ? debugstr_variant(arg + 1) : "1");
1103 
1104     switch(V_VT(arg)) {
1105     case VT_VARIANT|VT_ARRAY:
1106         sa = V_ARRAY(arg);
1107         break;
1108     case VT_VARIANT|VT_ARRAY|VT_BYREF:
1109         sa = *V_ARRAYREF(arg);
1110         break;
1111     default:
1112         FIXME("arg %s not supported\n", debugstr_variant(arg));
1113         return E_NOTIMPL;
1114     }
1115 
1116     if(args_cnt == 2) {
1117         hres = to_int(arg + 1, &dim);
1118         if(FAILED(hres))
1119             return hres;
1120     }else {
1121         dim = 1;
1122     }
1123 
1124     hres = SafeArrayGetUBound(sa, dim, &ubound);
1125     if(FAILED(hres))
1126         return hres;
1127 
1128     return return_int(res, ubound);
1129 }
1130 
Global_RGB(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1131 static HRESULT Global_RGB(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1132 {
1133     HRESULT hres;
1134     int i, color[3];
1135 
1136     TRACE("%s %s %s\n", debugstr_variant(arg), debugstr_variant(arg + 1), debugstr_variant(arg + 2));
1137 
1138     assert(args_cnt == 3);
1139 
1140     for(i = 0; i < 3; i++) {
1141         hres = to_int(arg + i, color + i);
1142         if(FAILED(hres))
1143             return hres;
1144         if(color[i] > 255)
1145             color[i] = 255;
1146         if(color[i] < 0)
1147             return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
1148     }
1149 
1150     return return_int(res, RGB(color[0], color[1], color[2]));
1151 }
1152 
Global_Len(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1153 static HRESULT Global_Len(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1154 {
1155     DWORD len;
1156     HRESULT hres;
1157 
1158     TRACE("%s\n", debugstr_variant(arg));
1159 
1160     if(V_VT(arg) == VT_NULL)
1161         return return_null(res);
1162 
1163     if(V_VT(arg) != VT_BSTR) {
1164         BSTR str;
1165 
1166         hres = to_string(arg, &str);
1167         if(FAILED(hres))
1168             return hres;
1169 
1170         len = SysStringLen(str);
1171         SysFreeString(str);
1172     }else {
1173         len = SysStringLen(V_BSTR(arg));
1174     }
1175 
1176     return return_int(res, len);
1177 }
1178 
Global_LenB(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1179 static HRESULT Global_LenB(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1180 {
1181     FIXME("\n");
1182     return E_NOTIMPL;
1183 }
1184 
Global_Left(BuiltinDisp * This,VARIANT * args,unsigned args_cnt,VARIANT * res)1185 static HRESULT Global_Left(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
1186 {
1187     BSTR str, ret, conv_str = NULL;
1188     int len, str_len;
1189     HRESULT hres;
1190 
1191     TRACE("(%s %s)\n", debugstr_variant(args+1), debugstr_variant(args));
1192 
1193     if(V_VT(args) == VT_BSTR) {
1194         str = V_BSTR(args);
1195     }else {
1196         hres = to_string(args, &conv_str);
1197         if(FAILED(hres))
1198             return hres;
1199         str = conv_str;
1200     }
1201 
1202     hres = to_int(args+1, &len);
1203     if(FAILED(hres))
1204         return hres;
1205 
1206     if(len < 0) {
1207         FIXME("len = %d\n", len);
1208         return E_FAIL;
1209     }
1210 
1211     str_len = SysStringLen(str);
1212     if(len > str_len)
1213         len = str_len;
1214 
1215     ret = SysAllocStringLen(str, len);
1216     SysFreeString(conv_str);
1217     if(!ret)
1218         return E_OUTOFMEMORY;
1219 
1220     return return_bstr(res, ret);
1221 }
1222 
Global_LeftB(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1223 static HRESULT Global_LeftB(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1224 {
1225     FIXME("\n");
1226     return E_NOTIMPL;
1227 }
1228 
Global_Right(BuiltinDisp * This,VARIANT * args,unsigned args_cnt,VARIANT * res)1229 static HRESULT Global_Right(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
1230 {
1231     BSTR str, ret, conv_str = NULL;
1232     int len, str_len;
1233     HRESULT hres;
1234 
1235     TRACE("(%s %s)\n", debugstr_variant(args), debugstr_variant(args+1));
1236 
1237     if(V_VT(args+1) == VT_BSTR) {
1238         str = V_BSTR(args);
1239     }else {
1240         hres = to_string(args, &conv_str);
1241         if(FAILED(hres))
1242             return hres;
1243         str = conv_str;
1244     }
1245 
1246     hres = to_int(args+1, &len);
1247     if(FAILED(hres))
1248         return hres;
1249 
1250     if(len < 0) {
1251         FIXME("len = %d\n", len);
1252         return E_FAIL;
1253     }
1254 
1255     str_len = SysStringLen(str);
1256     if(len > str_len)
1257         len = str_len;
1258 
1259     ret = SysAllocStringLen(str+str_len-len, len);
1260     SysFreeString(conv_str);
1261     if(!ret)
1262         return E_OUTOFMEMORY;
1263 
1264     return return_bstr(res, ret);
1265 }
1266 
Global_RightB(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1267 static HRESULT Global_RightB(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1268 {
1269     FIXME("\n");
1270     return E_NOTIMPL;
1271 }
1272 
Global_Mid(BuiltinDisp * This,VARIANT * args,unsigned args_cnt,VARIANT * res)1273 static HRESULT Global_Mid(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
1274 {
1275     int len = -1, start, str_len;
1276     BSTR str;
1277     HRESULT hres;
1278 
1279     TRACE("(%s %s ...)\n", debugstr_variant(args), debugstr_variant(args+1));
1280 
1281     assert(args_cnt == 2 || args_cnt == 3);
1282 
1283     if(V_VT(args) != VT_BSTR) {
1284         FIXME("args[0] = %s\n", debugstr_variant(args));
1285         return E_NOTIMPL;
1286     }
1287 
1288     str = V_BSTR(args);
1289 
1290     hres = to_int(args+1, &start);
1291     if(FAILED(hres))
1292         return hres;
1293 
1294     if(args_cnt == 3) {
1295         hres = to_int(args+2, &len);
1296         if(FAILED(hres))
1297             return hres;
1298 
1299         if(len < 0) {
1300             FIXME("len = %d\n", len);
1301             return E_FAIL;
1302         }
1303     }
1304 
1305 
1306     str_len = SysStringLen(str);
1307     start--;
1308     if(start > str_len)
1309         start = str_len;
1310 
1311     if(len == -1)
1312         len = str_len-start;
1313     else if(len > str_len-start)
1314         len = str_len-start;
1315 
1316     if(res) {
1317         V_VT(res) = VT_BSTR;
1318         V_BSTR(res) = SysAllocStringLen(str+start, len);
1319         if(!V_BSTR(res))
1320             return E_OUTOFMEMORY;
1321     }
1322 
1323     return S_OK;
1324 }
1325 
Global_MidB(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1326 static HRESULT Global_MidB(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1327 {
1328     FIXME("\n");
1329     return E_NOTIMPL;
1330 }
1331 
Global_StrComp(BuiltinDisp * This,VARIANT * args,unsigned args_cnt,VARIANT * res)1332 static HRESULT Global_StrComp(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
1333 {
1334     BSTR left, right;
1335     int mode, ret;
1336     HRESULT hres;
1337     short val;
1338 
1339     TRACE("(%s %s ...)\n", debugstr_variant(args), debugstr_variant(args+1));
1340 
1341     assert(args_cnt == 2 || args_cnt == 3);
1342 
1343     if (args_cnt == 3) {
1344         hres = to_int(args+2, &mode);
1345         if(FAILED(hres))
1346             return hres;
1347 
1348         if (mode != 0 && mode != 1) {
1349             FIXME("unknown compare mode = %d\n", mode);
1350             return E_FAIL;
1351         }
1352     }
1353     else
1354         mode = 0;
1355 
1356     hres = to_string(args, &left);
1357     if(FAILED(hres))
1358         return hres;
1359 
1360     hres = to_string(args+1, &right);
1361     if(FAILED(hres))
1362     {
1363         SysFreeString(left);
1364         return hres;
1365     }
1366 
1367     ret = mode ? wcsicmp(left, right) : wcscmp(left, right);
1368     val = ret < 0 ? -1 : (ret > 0 ? 1 : 0);
1369 
1370     SysFreeString(left);
1371     SysFreeString(right);
1372     return return_short(res, val);
1373 }
1374 
Global_LCase(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1375 static HRESULT Global_LCase(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1376 {
1377     BSTR str;
1378     HRESULT hres;
1379 
1380     TRACE("%s\n", debugstr_variant(arg));
1381 
1382     if(V_VT(arg) == VT_NULL) {
1383         if(res)
1384             V_VT(res) = VT_NULL;
1385         return S_OK;
1386     }
1387 
1388     hres = to_string(arg, &str);
1389     if(FAILED(hres))
1390         return hres;
1391 
1392     if(res) {
1393         WCHAR *ptr;
1394 
1395         for(ptr = str; *ptr; ptr++)
1396             *ptr = towlower(*ptr);
1397 
1398         V_VT(res) = VT_BSTR;
1399         V_BSTR(res) = str;
1400     }else {
1401         SysFreeString(str);
1402     }
1403     return S_OK;
1404 }
1405 
Global_UCase(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1406 static HRESULT Global_UCase(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1407 {
1408     BSTR str;
1409     HRESULT hres;
1410 
1411     TRACE("%s\n", debugstr_variant(arg));
1412 
1413     if(V_VT(arg) == VT_NULL) {
1414         if(res)
1415             V_VT(res) = VT_NULL;
1416         return S_OK;
1417     }
1418 
1419     hres = to_string(arg, &str);
1420     if(FAILED(hres))
1421         return hres;
1422 
1423     if(res) {
1424         WCHAR *ptr;
1425 
1426         for(ptr = str; *ptr; ptr++)
1427             *ptr = towupper(*ptr);
1428 
1429         V_VT(res) = VT_BSTR;
1430         V_BSTR(res) = str;
1431     }else {
1432         SysFreeString(str);
1433     }
1434     return S_OK;
1435 }
1436 
Global_LTrim(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1437 static HRESULT Global_LTrim(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1438 {
1439     BSTR str, conv_str = NULL;
1440     WCHAR *ptr;
1441     HRESULT hres;
1442 
1443     TRACE("%s\n", debugstr_variant(arg));
1444 
1445     if(V_VT(arg) == VT_BSTR) {
1446         str = V_BSTR(arg);
1447     }else {
1448         hres = to_string(arg, &conv_str);
1449         if(FAILED(hres))
1450             return hres;
1451         str = conv_str;
1452     }
1453 
1454     for(ptr = str; *ptr && iswspace(*ptr); ptr++);
1455 
1456     str = SysAllocString(ptr);
1457     SysFreeString(conv_str);
1458     if(!str)
1459         return E_OUTOFMEMORY;
1460 
1461     return return_bstr(res, str);
1462 }
1463 
Global_RTrim(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1464 static HRESULT Global_RTrim(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1465 {
1466     BSTR str, conv_str = NULL;
1467     WCHAR *ptr;
1468     HRESULT hres;
1469 
1470     TRACE("%s\n", debugstr_variant(arg));
1471 
1472     if(V_VT(arg) == VT_BSTR) {
1473         str = V_BSTR(arg);
1474     }else {
1475         hres = to_string(arg, &conv_str);
1476         if(FAILED(hres))
1477             return hres;
1478         str = conv_str;
1479     }
1480 
1481     for(ptr = str+SysStringLen(str); ptr-1 > str && iswspace(*(ptr-1)); ptr--);
1482 
1483     str = SysAllocStringLen(str, ptr-str);
1484     SysFreeString(conv_str);
1485     if(!str)
1486         return E_OUTOFMEMORY;
1487 
1488     return return_bstr(res, str);
1489 }
1490 
Global_Trim(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1491 static HRESULT Global_Trim(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1492 {
1493     BSTR str, conv_str = NULL;
1494     WCHAR *begin_ptr, *end_ptr;
1495     HRESULT hres;
1496 
1497     TRACE("%s\n", debugstr_variant(arg));
1498 
1499     if(V_VT(arg) == VT_BSTR) {
1500         str = V_BSTR(arg);
1501     }else {
1502         hres = to_string(arg, &conv_str);
1503         if(FAILED(hres))
1504             return hres;
1505         str = conv_str;
1506     }
1507 
1508     for(begin_ptr = str; *begin_ptr && iswspace(*begin_ptr); begin_ptr++);
1509     for(end_ptr = str+SysStringLen(str); end_ptr-1 > begin_ptr && iswspace(*(end_ptr-1)); end_ptr--);
1510 
1511     str = SysAllocStringLen(begin_ptr, end_ptr-begin_ptr);
1512     SysFreeString(conv_str);
1513     if(!str)
1514         return E_OUTOFMEMORY;
1515 
1516     return return_bstr(res, str);
1517 }
1518 
Global_Space(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1519 static HRESULT Global_Space(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1520 {
1521     BSTR str;
1522     int n, i;
1523     HRESULT hres;
1524 
1525     TRACE("%s\n", debugstr_variant(arg));
1526 
1527     hres = to_int(arg, &n);
1528     if(FAILED(hres))
1529         return hres;
1530 
1531     if(n < 0) {
1532         FIXME("n = %d\n", n);
1533         return E_NOTIMPL;
1534     }
1535 
1536     if(!res)
1537         return S_OK;
1538 
1539     str = SysAllocStringLen(NULL, n);
1540     if(!str)
1541         return E_OUTOFMEMORY;
1542 
1543     for(i=0; i<n; i++)
1544         str[i] = ' ';
1545 
1546     V_VT(res) = VT_BSTR;
1547     V_BSTR(res) = str;
1548     return S_OK;
1549 }
1550 
Global_String(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1551 static HRESULT Global_String(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1552 {
1553     FIXME("\n");
1554     return E_NOTIMPL;
1555 }
1556 
Global_InStr(BuiltinDisp * This,VARIANT * args,unsigned args_cnt,VARIANT * res)1557 static HRESULT Global_InStr(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
1558 {
1559     VARIANT *startv, *str1v, *str2v;
1560     BSTR str1, str2;
1561     int start, ret;
1562     HRESULT hres;
1563 
1564     TRACE("\n");
1565 
1566     assert(2 <= args_cnt && args_cnt <= 4);
1567 
1568     switch(args_cnt) {
1569     case 2:
1570         startv = NULL;
1571         str1v = args;
1572         str2v = args+1;
1573         break;
1574     case 3:
1575         startv = args;
1576         str1v = args+1;
1577         str2v = args+2;
1578         break;
1579     case 4:
1580         FIXME("unsupported compare argument %s\n", debugstr_variant(args));
1581         return E_NOTIMPL;
1582     DEFAULT_UNREACHABLE;
1583     }
1584 
1585     if(startv) {
1586         hres = to_int(startv, &start);
1587         if(FAILED(hres))
1588             return hres;
1589         if(--start < 0) {
1590             FIXME("start %d\n", start);
1591             return E_FAIL;
1592         }
1593     }else {
1594         start = 0;
1595     }
1596 
1597     if(V_VT(str1v) == VT_NULL || V_VT(str2v) == VT_NULL)
1598         return return_null(res);
1599 
1600     if(V_VT(str1v) != VT_BSTR) {
1601         FIXME("Unsupported str1 type %s\n", debugstr_variant(str1v));
1602         return E_NOTIMPL;
1603     }
1604     str1 = V_BSTR(str1v);
1605 
1606     if(V_VT(str2v) != VT_BSTR) {
1607         FIXME("Unsupported str2 type %s\n", debugstr_variant(str2v));
1608         return E_NOTIMPL;
1609     }
1610     str2 = V_BSTR(str2v);
1611 
1612     if(start < SysStringLen(str1)) {
1613         WCHAR *ptr;
1614 
1615         ptr = wcsstr(str1+start, str2);
1616         ret = ptr ? ptr-str1+1 : 0;
1617     }else {
1618         ret = 0;
1619     }
1620 
1621     return return_int(res, ret);
1622 }
1623 
Global_InStrB(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1624 static HRESULT Global_InStrB(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1625 {
1626     FIXME("\n");
1627     return E_NOTIMPL;
1628 }
1629 
Global_AscB(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1630 static HRESULT Global_AscB(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1631 {
1632     FIXME("\n");
1633     return E_NOTIMPL;
1634 }
1635 
Global_ChrB(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1636 static HRESULT Global_ChrB(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1637 {
1638     FIXME("\n");
1639     return E_NOTIMPL;
1640 }
1641 
Global_Asc(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1642 static HRESULT Global_Asc(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1643 {
1644     BSTR conv_str = NULL, str;
1645     HRESULT hres = S_OK;
1646 
1647     TRACE("(%s)\n", debugstr_variant(arg));
1648 
1649     switch(V_VT(arg)) {
1650     case VT_NULL:
1651         return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE);
1652     case VT_EMPTY:
1653         return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
1654     case VT_BSTR:
1655         str = V_BSTR(arg);
1656         break;
1657     default:
1658         hres = to_string(arg, &conv_str);
1659         if(FAILED(hres))
1660             return hres;
1661         str = conv_str;
1662     }
1663 
1664     if(!SysStringLen(str) || *str >= 0x100)
1665         hres = MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
1666     else if(res)
1667         hres = return_short(res, *str);
1668     SysFreeString(conv_str);
1669     return hres;
1670 }
1671 
1672 /* The function supports only single-byte and double-byte character sets. It
1673  * ignores language specified by IActiveScriptSite::GetLCID. The argument needs
1674  * to be in range of short or unsigned short. */
Global_Chr(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1675 static HRESULT Global_Chr(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1676 {
1677     int cp, c, len = 0;
1678     CPINFO cpi;
1679     WCHAR ch;
1680     char buf[2];
1681     HRESULT hres;
1682 
1683     TRACE("%s\n", debugstr_variant(arg));
1684 
1685     hres = to_int(arg, &c);
1686     if(FAILED(hres))
1687         return hres;
1688 
1689     cp = GetACP();
1690     if(!GetCPInfo(cp, &cpi))
1691         cpi.MaxCharSize = 1;
1692 
1693     if((c!=(short)c && c!=(unsigned short)c) ||
1694             (unsigned short)c>=(cpi.MaxCharSize>1 ? 0x10000 : 0x100)) {
1695         WARN("invalid arg %d\n", c);
1696         return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
1697     }
1698 
1699     if(c>>8)
1700         buf[len++] = c>>8;
1701     if(!len || IsDBCSLeadByteEx(cp, buf[0]))
1702         buf[len++] = c;
1703     if(!MultiByteToWideChar(CP_ACP, 0, buf, len, &ch, 1)) {
1704         WARN("invalid arg %d, cp %d\n", c, cp);
1705         return E_FAIL;
1706     }
1707 
1708     if(res) {
1709         V_VT(res) = VT_BSTR;
1710         V_BSTR(res) = SysAllocStringLen(&ch, 1);
1711         if(!V_BSTR(res))
1712             return E_OUTOFMEMORY;
1713     }
1714     return S_OK;
1715 }
1716 
Global_AscW(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1717 static HRESULT Global_AscW(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1718 {
1719     FIXME("\n");
1720     return E_NOTIMPL;
1721 }
1722 
Global_ChrW(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1723 static HRESULT Global_ChrW(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1724 {
1725     FIXME("\n");
1726     return E_NOTIMPL;
1727 }
1728 
Global_Abs(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1729 static HRESULT Global_Abs(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1730 {
1731     HRESULT hres;
1732     VARIANT dst;
1733 
1734     TRACE("(%s)\n", debugstr_variant(arg));
1735 
1736     assert(args_cnt == 1);
1737 
1738     hres = VarAbs(arg, &dst);
1739     if(FAILED(hres))
1740         return hres;
1741 
1742     if (res)
1743         *res = dst;
1744     else
1745         VariantClear(&dst);
1746 
1747     return S_OK;
1748 }
1749 
Global_Fix(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1750 static HRESULT Global_Fix(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1751 {
1752     HRESULT hres;
1753     VARIANT dst;
1754 
1755     TRACE("(%s)\n", debugstr_variant(arg));
1756 
1757     assert(args_cnt == 1);
1758 
1759     hres = VarFix(arg, &dst);
1760     if(FAILED(hres))
1761         return hres;
1762 
1763     if (res)
1764         *res = dst;
1765     else
1766         VariantClear(&dst);
1767 
1768     return S_OK;
1769 }
1770 
Global_Int(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1771 static HRESULT Global_Int(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1772 {
1773     HRESULT hres;
1774     VARIANT dst;
1775 
1776     TRACE("(%s)\n", debugstr_variant(arg));
1777 
1778     assert(args_cnt == 1);
1779 
1780     hres = VarInt(arg, &dst);
1781     if(FAILED(hres))
1782         return hres;
1783 
1784     if (res)
1785         *res = dst;
1786     else
1787         VariantClear(&dst);
1788 
1789     return S_OK;
1790 }
1791 
Global_Sgn(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1792 static HRESULT Global_Sgn(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1793 {
1794     double v;
1795     short val;
1796     HRESULT hres;
1797 
1798     TRACE("(%s)\n", debugstr_variant(arg));
1799 
1800     assert(args_cnt == 1);
1801 
1802     if(V_VT(arg) == VT_NULL)
1803         return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE);
1804 
1805     hres = to_double(arg, &v);
1806     if (FAILED(hres))
1807         return hres;
1808 
1809     val = v == 0 ? 0 : (v > 0 ? 1 : -1);
1810     return return_short(res, val);
1811 }
1812 
Global_Now(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1813 static HRESULT Global_Now(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1814 {
1815     SYSTEMTIME lt;
1816     double date;
1817 
1818     TRACE("\n");
1819 
1820     GetLocalTime(&lt);
1821     SystemTimeToVariantTime(&lt, &date);
1822     return return_date(res, date);
1823 }
1824 
Global_Date(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1825 static HRESULT Global_Date(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1826 {
1827     SYSTEMTIME lt;
1828     UDATE ud;
1829     DATE date;
1830     HRESULT hres;
1831 
1832     TRACE("\n");
1833 
1834     GetLocalTime(&lt);
1835     ud.st = lt;
1836     ud.wDayOfYear = 0;
1837     hres = VarDateFromUdateEx(&ud, 0, VAR_DATEVALUEONLY, &date);
1838     if(FAILED(hres))
1839         return hres;
1840     return return_date(res, date);
1841 }
1842 
Global_Time(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1843 static HRESULT Global_Time(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1844 {
1845     SYSTEMTIME lt;
1846     UDATE ud;
1847     DATE time;
1848     HRESULT hres;
1849 
1850     TRACE("\n");
1851 
1852     GetLocalTime(&lt);
1853     ud.st = lt;
1854     ud.wDayOfYear = 0;
1855     hres = VarDateFromUdateEx(&ud, 0, VAR_TIMEVALUEONLY, &time);
1856     if(FAILED(hres))
1857         return hres;
1858     return return_date(res, time);
1859 }
1860 
Global_Day(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1861 static HRESULT Global_Day(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1862 {
1863     SYSTEMTIME st;
1864     HRESULT hres;
1865 
1866     TRACE("(%s)\n", debugstr_variant(arg));
1867 
1868     hres = to_system_time(arg, &st);
1869     return FAILED(hres) ? hres : return_short(res, st.wDay);
1870 }
1871 
Global_Month(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1872 static HRESULT Global_Month(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1873 {
1874     SYSTEMTIME st;
1875     HRESULT hres;
1876 
1877     TRACE("(%s)\n", debugstr_variant(arg));
1878 
1879     hres = to_system_time(arg, &st);
1880     return FAILED(hres) ? hres : return_short(res, st.wMonth);
1881 }
1882 
Global_Weekday(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1883 static HRESULT Global_Weekday(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1884 {
1885     FIXME("\n");
1886     return E_NOTIMPL;
1887 }
1888 
Global_Year(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1889 static HRESULT Global_Year(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1890 {
1891     SYSTEMTIME st;
1892     HRESULT hres;
1893 
1894     TRACE("(%s)\n", debugstr_variant(arg));
1895 
1896     hres = to_system_time(arg, &st);
1897     return FAILED(hres) ? hres : return_short(res, st.wYear);
1898 }
1899 
Global_Hour(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1900 static HRESULT Global_Hour(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1901 {
1902     SYSTEMTIME st;
1903     HRESULT hres;
1904 
1905     TRACE("(%s)\n", debugstr_variant(arg));
1906 
1907     hres = to_system_time(arg, &st);
1908     return FAILED(hres) ? hres : return_short(res, st.wHour);
1909 }
1910 
Global_Minute(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1911 static HRESULT Global_Minute(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1912 {
1913     SYSTEMTIME st;
1914     HRESULT hres;
1915 
1916     TRACE("(%s)\n", debugstr_variant(arg));
1917 
1918     hres = to_system_time(arg, &st);
1919     return FAILED(hres) ? hres : return_short(res, st.wMinute);
1920 }
1921 
Global_Second(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1922 static HRESULT Global_Second(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1923 {
1924     SYSTEMTIME st;
1925     HRESULT hres;
1926 
1927     TRACE("(%s)\n", debugstr_variant(arg));
1928 
1929     hres = to_system_time(arg, &st);
1930     return FAILED(hres) ? hres : return_short(res, st.wSecond);
1931 }
1932 
Global_DateValue(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1933 static HRESULT Global_DateValue(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1934 {
1935     FIXME("\n");
1936     return E_NOTIMPL;
1937 }
1938 
Global_TimeValue(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1939 static HRESULT Global_TimeValue(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1940 {
1941     FIXME("\n");
1942     return E_NOTIMPL;
1943 }
1944 
Global_DateSerial(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1945 static HRESULT Global_DateSerial(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1946 {
1947     FIXME("\n");
1948     return E_NOTIMPL;
1949 }
1950 
Global_TimeSerial(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1951 static HRESULT Global_TimeSerial(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1952 {
1953     FIXME("\n");
1954     return E_NOTIMPL;
1955 }
1956 
Global_InputBox(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1957 static HRESULT Global_InputBox(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1958 {
1959     FIXME("\n");
1960     return E_NOTIMPL;
1961 }
1962 
Global_MsgBox(BuiltinDisp * This,VARIANT * args,unsigned args_cnt,VARIANT * res)1963 static HRESULT Global_MsgBox(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
1964 {
1965     BSTR prompt, title = NULL;
1966     int type = MB_OK;
1967     HRESULT hres;
1968 
1969     TRACE("\n");
1970 
1971     assert(1 <= args_cnt && args_cnt <= 5);
1972 
1973     hres = to_string(args, &prompt);
1974     if(FAILED(hres))
1975         return hres;
1976 
1977     if(args_cnt > 1)
1978         hres = to_int(args+1, &type);
1979 
1980     if(SUCCEEDED(hres) && args_cnt > 2)
1981         hres = to_string(args+2, &title);
1982 
1983     if(SUCCEEDED(hres) && args_cnt > 3) {
1984         FIXME("unsupported arg_cnt %d\n", args_cnt);
1985         hres = E_NOTIMPL;
1986     }
1987 
1988     if(SUCCEEDED(hres))
1989         hres = show_msgbox(This->ctx, prompt, type, title, res);
1990 
1991     SysFreeString(prompt);
1992     SysFreeString(title);
1993     return hres;
1994 }
1995 
Global_CreateObject(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)1996 static HRESULT Global_CreateObject(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1997 {
1998     IUnknown *obj;
1999     HRESULT hres;
2000 
2001     TRACE("(%s)\n", debugstr_variant(arg));
2002 
2003     if(V_VT(arg) != VT_BSTR) {
2004         FIXME("non-bstr arg\n");
2005         return E_INVALIDARG;
2006     }
2007 
2008     obj = create_object(This->ctx, V_BSTR(arg));
2009     if(!obj)
2010         return VB_E_CANNOT_CREATE_OBJ;
2011 
2012     if(res) {
2013         hres = IUnknown_QueryInterface(obj, &IID_IDispatch, (void**)&V_DISPATCH(res));
2014         if(FAILED(hres))
2015             return hres;
2016 
2017         V_VT(res) = VT_DISPATCH;
2018     }
2019 
2020     IUnknown_Release(obj);
2021     return S_OK;
2022 }
2023 
Global_GetObject(BuiltinDisp * This,VARIANT * args,unsigned args_cnt,VARIANT * res)2024 static HRESULT Global_GetObject(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
2025 {
2026     IBindCtx *bind_ctx;
2027     IUnknown *obj_unk;
2028     IDispatch *disp;
2029     ULONG eaten = 0;
2030     IMoniker *mon;
2031     HRESULT hres;
2032 
2033     TRACE("%s %s\n", args_cnt ? debugstr_variant(args) : "", args_cnt > 1 ? debugstr_variant(args+1) : "");
2034 
2035     if(args_cnt != 1 || V_VT(args) != VT_BSTR) {
2036         FIXME("unsupported args\n");
2037         return E_NOTIMPL;
2038     }
2039 
2040     if(This->ctx->safeopt & (INTERFACE_USES_SECURITY_MANAGER|INTERFACESAFE_FOR_UNTRUSTED_DATA)) {
2041         WARN("blocked in current safety mode\n");
2042         return VB_E_CANNOT_CREATE_OBJ;
2043     }
2044 
2045     hres = CreateBindCtx(0, &bind_ctx);
2046     if(FAILED(hres))
2047         return hres;
2048 
2049     hres = MkParseDisplayName(bind_ctx, V_BSTR(args), &eaten, &mon);
2050     if(SUCCEEDED(hres)) {
2051         hres = IMoniker_BindToObject(mon, bind_ctx, NULL, &IID_IUnknown, (void**)&obj_unk);
2052         IMoniker_Release(mon);
2053     }else {
2054         hres = MK_E_SYNTAX;
2055     }
2056     IBindCtx_Release(bind_ctx);
2057     if(FAILED(hres))
2058         return hres;
2059 
2060     hres = set_object_site(This->ctx, obj_unk);
2061     if(FAILED(hres)) {
2062         IUnknown_Release(obj_unk);
2063         return hres;
2064     }
2065 
2066     hres = IUnknown_QueryInterface(obj_unk, &IID_IDispatch, (void**)&disp);
2067     if(SUCCEEDED(hres)) {
2068         if(res) {
2069             V_VT(res) = VT_DISPATCH;
2070             V_DISPATCH(res) = disp;
2071         }else {
2072             IDispatch_Release(disp);
2073         }
2074     }else {
2075         FIXME("object does not support IDispatch\n");
2076     }
2077 
2078     return hres;
2079 }
2080 
Global_DateAdd(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)2081 static HRESULT Global_DateAdd(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2082 {
2083     FIXME("\n");
2084     return E_NOTIMPL;
2085 }
2086 
Global_DateDiff(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)2087 static HRESULT Global_DateDiff(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2088 {
2089     FIXME("\n");
2090     return E_NOTIMPL;
2091 }
2092 
Global_DatePart(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)2093 static HRESULT Global_DatePart(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2094 {
2095     FIXME("\n");
2096     return E_NOTIMPL;
2097 }
2098 
Global_TypeName(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)2099 static HRESULT Global_TypeName(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2100 {
2101     static const WCHAR ByteW[]     = {'B', 'y', 't', 'e', 0};
2102     static const WCHAR IntegerW[]  = {'I', 'n', 't', 'e', 'g', 'e', 'r', 0};
2103     static const WCHAR LongW[]     = {'L', 'o', 'n', 'g', 0};
2104     static const WCHAR SingleW[]   = {'S', 'i', 'n', 'g', 'l', 'e', 0};
2105     static const WCHAR DoubleW[]   = {'D', 'o', 'u', 'b', 'l', 'e', 0};
2106     static const WCHAR CurrencyW[] = {'C', 'u', 'r', 'r', 'e', 'n', 'c', 'y', 0};
2107     static const WCHAR DecimalW[]  = {'D', 'e', 'c', 'i', 'm', 'a', 'l', 0};
2108     static const WCHAR DateW[]     = {'D', 'a', 't', 'e', 0};
2109     static const WCHAR StringW[]   = {'S', 't', 'r', 'i', 'n', 'g', 0};
2110     static const WCHAR BooleanW[]  = {'B', 'o', 'o', 'l', 'e', 'a', 'n', 0};
2111     static const WCHAR EmptyW[]    = {'E', 'm', 'p', 't', 'y', 0};
2112     static const WCHAR NullW[]     = {'N', 'u', 'l', 'l', 0};
2113 
2114     TRACE("(%s)\n", debugstr_variant(arg));
2115 
2116     assert(args_cnt == 1);
2117 
2118     switch(V_VT(arg)) {
2119         case VT_UI1:
2120             return return_string(res, ByteW);
2121         case VT_I2:
2122             return return_string(res, IntegerW);
2123         case VT_I4:
2124             return return_string(res, LongW);
2125         case VT_R4:
2126             return return_string(res, SingleW);
2127         case VT_R8:
2128             return return_string(res, DoubleW);
2129         case VT_CY:
2130             return return_string(res, CurrencyW);
2131         case VT_DECIMAL:
2132             return return_string(res, DecimalW);
2133         case VT_DATE:
2134             return return_string(res, DateW);
2135         case VT_BSTR:
2136             return return_string(res, StringW);
2137         case VT_BOOL:
2138             return return_string(res, BooleanW);
2139         case VT_EMPTY:
2140             return return_string(res, EmptyW);
2141         case VT_NULL:
2142             return return_string(res, NullW);
2143         default:
2144             FIXME("arg %s not supported\n", debugstr_variant(arg));
2145             return E_NOTIMPL;
2146         }
2147 }
2148 
Global_Array(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)2149 static HRESULT Global_Array(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2150 {
2151     SAFEARRAYBOUND bounds;
2152     SAFEARRAY *sa;
2153     VARIANT *data;
2154     HRESULT hres;
2155     unsigned i;
2156 
2157     TRACE("arg_cnt=%u\n", args_cnt);
2158 
2159     bounds.lLbound = 0;
2160     bounds.cElements = args_cnt;
2161     sa = SafeArrayCreate(VT_VARIANT, 1, &bounds);
2162     if(!sa)
2163         return E_OUTOFMEMORY;
2164 
2165     hres = SafeArrayAccessData(sa, (void**)&data);
2166     if(FAILED(hres)) {
2167         SafeArrayDestroy(sa);
2168         return hres;
2169     }
2170 
2171     for(i=0; i<args_cnt; i++) {
2172         hres = VariantCopyInd(data+i, arg+i);
2173         if(FAILED(hres)) {
2174             SafeArrayUnaccessData(sa);
2175             SafeArrayDestroy(sa);
2176             return hres;
2177         }
2178     }
2179     SafeArrayUnaccessData(sa);
2180 
2181     if(res) {
2182         V_VT(res) = VT_ARRAY|VT_VARIANT;
2183         V_ARRAY(res) = sa;
2184     }else {
2185         SafeArrayDestroy(sa);
2186     }
2187 
2188     return S_OK;
2189 }
2190 
Global_Erase(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)2191 static HRESULT Global_Erase(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2192 {
2193     FIXME("\n");
2194     return E_NOTIMPL;
2195 }
2196 
Global_Filter(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)2197 static HRESULT Global_Filter(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2198 {
2199     FIXME("\n");
2200     return E_NOTIMPL;
2201 }
2202 
Global_Join(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)2203 static HRESULT Global_Join(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2204 {
2205     FIXME("\n");
2206     return E_NOTIMPL;
2207 }
2208 
Global_Split(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)2209 static HRESULT Global_Split(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2210 {
2211     FIXME("\n");
2212     return E_NOTIMPL;
2213 }
2214 
Global_Replace(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)2215 static HRESULT Global_Replace(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2216 {
2217     FIXME("\n");
2218     return E_NOTIMPL;
2219 }
2220 
Global_StrReverse(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)2221 static HRESULT Global_StrReverse(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2222 {
2223     WCHAR *ptr1, *ptr2, ch;
2224     BSTR ret;
2225     HRESULT hres;
2226 
2227     TRACE("%s\n", debugstr_variant(arg));
2228 
2229     hres = to_string(arg, &ret);
2230     if(FAILED(hres))
2231         return hres;
2232 
2233     ptr1 = ret;
2234     ptr2 = ret + SysStringLen(ret)-1;
2235     while(ptr1 < ptr2) {
2236         ch = *ptr1;
2237         *ptr1++ = *ptr2;
2238         *ptr2-- = ch;
2239     }
2240 
2241     return return_bstr(res, ret);
2242 }
2243 
Global_InStrRev(BuiltinDisp * This,VARIANT * args,unsigned args_cnt,VARIANT * res)2244 static HRESULT Global_InStrRev(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
2245 {
2246     int start, ret = 0;
2247     BSTR str1, str2;
2248     HRESULT hres;
2249 
2250     TRACE("%s %s arg_cnt=%u\n", debugstr_variant(args), debugstr_variant(args+1), args_cnt);
2251 
2252     if(args_cnt > 3) {
2253         FIXME("Unsupported args\n");
2254         return E_NOTIMPL;
2255     }
2256 
2257     assert(2 <= args_cnt && args_cnt <= 4);
2258 
2259     if(V_VT(args) == VT_NULL || V_VT(args+1) == VT_NULL || (args_cnt > 2 && V_VT(args+2) == VT_NULL))
2260         return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE);
2261 
2262     hres = to_string(args, &str1);
2263     if(FAILED(hres))
2264         return hres;
2265 
2266     hres = to_string(args+1, &str2);
2267     if(SUCCEEDED(hres)) {
2268         if(args_cnt > 2) {
2269             hres = to_int(args+2, &start);
2270             if(SUCCEEDED(hres) && start <= 0) {
2271                 FIXME("Unsupported start %d\n", start);
2272                 hres = E_NOTIMPL;
2273             }
2274         }else {
2275             start = SysStringLen(str1);
2276         }
2277     } else {
2278         str2 = NULL;
2279     }
2280 
2281     if(SUCCEEDED(hres)) {
2282         const WCHAR *ptr;
2283         size_t len;
2284 
2285         len = SysStringLen(str2);
2286         if(start >= len && start <= SysStringLen(str1)) {
2287             for(ptr = str1+start-SysStringLen(str2); ptr >= str1; ptr--) {
2288                 if(!memcmp(ptr, str2, len*sizeof(WCHAR))) {
2289                     ret = ptr-str1+1;
2290                     break;
2291                 }
2292             }
2293         }
2294     }
2295 
2296     SysFreeString(str1);
2297     SysFreeString(str2);
2298     if(FAILED(hres))
2299         return hres;
2300 
2301     return return_int(res, ret);
2302 }
2303 
Global_LoadPicture(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)2304 static HRESULT Global_LoadPicture(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2305 {
2306     FIXME("\n");
2307     return E_NOTIMPL;
2308 }
2309 
Global_ScriptEngine(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)2310 static HRESULT Global_ScriptEngine(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2311 {
2312     TRACE("%s\n", debugstr_variant(arg));
2313 
2314     assert(args_cnt == 0);
2315 
2316     return return_string(res, vbscriptW);
2317 }
2318 
Global_ScriptEngineMajorVersion(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)2319 static HRESULT Global_ScriptEngineMajorVersion(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2320 {
2321     TRACE("%s\n", debugstr_variant(arg));
2322 
2323     assert(args_cnt == 0);
2324 
2325     return return_int(res, VBSCRIPT_MAJOR_VERSION);
2326 }
2327 
Global_ScriptEngineMinorVersion(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)2328 static HRESULT Global_ScriptEngineMinorVersion(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2329 {
2330     TRACE("%s\n", debugstr_variant(arg));
2331 
2332     assert(args_cnt == 0);
2333 
2334     return return_int(res, VBSCRIPT_MINOR_VERSION);
2335 }
2336 
Global_ScriptEngineBuildVersion(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)2337 static HRESULT Global_ScriptEngineBuildVersion(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2338 {
2339     TRACE("%s\n", debugstr_variant(arg));
2340 
2341     assert(args_cnt == 0);
2342 
2343     return return_int(res, VBSCRIPT_BUILD_VERSION);
2344 }
2345 
Global_FormatNumber(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)2346 static HRESULT Global_FormatNumber(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2347 {
2348     FIXME("\n");
2349     return E_NOTIMPL;
2350 }
2351 
Global_FormatCurrency(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)2352 static HRESULT Global_FormatCurrency(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2353 {
2354     FIXME("\n");
2355     return E_NOTIMPL;
2356 }
2357 
Global_FormatPercent(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)2358 static HRESULT Global_FormatPercent(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2359 {
2360     FIXME("\n");
2361     return E_NOTIMPL;
2362 }
2363 
Global_FormatDateTime(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)2364 static HRESULT Global_FormatDateTime(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2365 {
2366     FIXME("\n");
2367     return E_NOTIMPL;
2368 }
2369 
Global_WeekdayName(BuiltinDisp * This,VARIANT * args,unsigned args_cnt,VARIANT * res)2370 static HRESULT Global_WeekdayName(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
2371 {
2372     int weekday, first_day = 1, abbrev = 0;
2373     BSTR ret;
2374     HRESULT hres;
2375 
2376     TRACE("\n");
2377 
2378     assert(1 <= args_cnt && args_cnt <= 3);
2379 
2380     hres = to_int(args, &weekday);
2381     if(FAILED(hres))
2382         return hres;
2383 
2384     if(args_cnt > 1) {
2385         hres = to_int(args+1, &abbrev);
2386         if(FAILED(hres))
2387             return hres;
2388 
2389         if(args_cnt == 3) {
2390             hres = to_int(args+2, &first_day);
2391             if(FAILED(hres))
2392                 return hres;
2393         }
2394     }
2395 
2396     hres = VarWeekdayName(weekday, abbrev, first_day, 0, &ret);
2397     if(FAILED(hres))
2398         return hres;
2399 
2400     return return_bstr(res, ret);
2401 }
2402 
Global_MonthName(BuiltinDisp * This,VARIANT * args,unsigned args_cnt,VARIANT * res)2403 static HRESULT Global_MonthName(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
2404 {
2405     int month, abbrev = 0;
2406     BSTR ret;
2407     HRESULT hres;
2408 
2409     TRACE("\n");
2410 
2411     assert(args_cnt == 1 || args_cnt == 2);
2412 
2413     hres = to_int(args, &month);
2414     if(FAILED(hres))
2415         return hres;
2416 
2417     if(args_cnt == 2) {
2418         hres = to_int(args+1, &abbrev);
2419         if(FAILED(hres))
2420             return hres;
2421     }
2422 
2423     hres = VarMonthName(month, abbrev, 0, &ret);
2424     if(FAILED(hres))
2425         return hres;
2426 
2427     return return_bstr(res, ret);
2428 }
2429 
Global_Round(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)2430 static HRESULT Global_Round(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2431 {
2432     double n;
2433     HRESULT hres;
2434 
2435     TRACE("%s\n", debugstr_variant(arg));
2436 
2437     if(!res)
2438         return S_OK;
2439 
2440     switch(V_VT(arg)) {
2441     case VT_I2:
2442     case VT_I4:
2443     case VT_BOOL:
2444         *res = *arg;
2445         return S_OK;
2446     case VT_R8:
2447         n = V_R8(arg);
2448         break;
2449     default:
2450         hres = to_double(arg, &n);
2451         if(FAILED(hres))
2452             return hres;
2453     }
2454 
2455     return return_double(res, round(n));
2456 }
2457 
Global_Escape(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)2458 static HRESULT Global_Escape(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2459 {
2460     FIXME("\n");
2461     return E_NOTIMPL;
2462 }
2463 
Global_Unescape(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)2464 static HRESULT Global_Unescape(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2465 {
2466     FIXME("\n");
2467     return E_NOTIMPL;
2468 }
2469 
Global_Eval(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)2470 static HRESULT Global_Eval(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2471 {
2472     FIXME("\n");
2473     return E_NOTIMPL;
2474 }
2475 
Global_Execute(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)2476 static HRESULT Global_Execute(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2477 {
2478     FIXME("\n");
2479     return E_NOTIMPL;
2480 }
2481 
Global_ExecuteGlobal(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)2482 static HRESULT Global_ExecuteGlobal(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2483 {
2484     FIXME("\n");
2485     return E_NOTIMPL;
2486 }
2487 
Global_GetRef(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)2488 static HRESULT Global_GetRef(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2489 {
2490     FIXME("\n");
2491     return E_NOTIMPL;
2492 }
2493 
Global_Err(BuiltinDisp * This,VARIANT * arg,unsigned args_cnt,VARIANT * res)2494 static HRESULT Global_Err(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2495 {
2496     TRACE("\n");
2497 
2498     if(args_cnt) {
2499         FIXME("Setter not supported\n");
2500         return E_NOTIMPL;
2501     }
2502 
2503     V_VT(res) = VT_DISPATCH;
2504     V_DISPATCH(res) = &This->ctx->err_obj->IDispatch_iface;
2505     IDispatch_AddRef(V_DISPATCH(res));
2506     return S_OK;
2507 }
2508 
2509 static const string_constant_t vbCr          = {1, {'\r'}};
2510 static const string_constant_t vbCrLf        = {2, {'\r','\n'}};
2511 static const string_constant_t vbNewLine     = {2, {'\r','\n'}};
2512 static const string_constant_t vbFormFeed    = {1, {0xc}};
2513 static const string_constant_t vbLf          = {1, {'\n'}};
2514 static const string_constant_t vbNullChar    = {1};
2515 static const string_constant_t vbNullString  = {0};
2516 static const string_constant_t vbTab         = {1, {'\t'}};
2517 static const string_constant_t vbVerticalTab = {1, {0xb}};
2518 
2519 static const builtin_prop_t global_props[] = {
2520     {NULL}, /* no default value */
2521     {L"Abs",                       Global_Abs, 0, 1},
2522     {L"Array",                     Global_Array, 0, 0, MAXDWORD},
2523     {L"Asc",                       Global_Asc, 0, 1},
2524     {L"AscB",                      Global_AscB, 0, 1},
2525     {L"AscW",                      Global_AscW, 0, 1},
2526     {L"Atn",                       Global_Atn, 0, 1},
2527     {L"CBool",                     Global_CBool, 0, 1},
2528     {L"CByte",                     Global_CByte, 0, 1},
2529     {L"CCur",                      Global_CCur, 0, 1},
2530     {L"CDate",                     Global_CDate, 0, 1},
2531     {L"CDbl",                      Global_CDbl, 0, 1},
2532     {L"Chr",                       Global_Chr, 0, 1},
2533     {L"ChrB",                      Global_ChrB, 0, 1},
2534     {L"ChrW",                      Global_ChrW, 0, 1},
2535     {L"CInt",                      Global_CInt, 0, 1},
2536     {L"CLng",                      Global_CLng, 0, 1},
2537     {L"Cos",                       Global_Cos, 0, 1},
2538     {L"CreateObject",              Global_CreateObject, 0, 1},
2539     {L"CSng",                      Global_CSng, 0, 1},
2540     {L"CStr",                      Global_CStr, 0, 1},
2541     {L"Date",                      Global_Date, 0, 0},
2542     {L"DateAdd",                   Global_DateAdd, 0, 3},
2543     {L"DateDiff",                  Global_DateDiff, 0, 3, 5},
2544     {L"DatePart",                  Global_DatePart, 0, 2, 4},
2545     {L"DateSerial",                Global_DateSerial, 0, 3},
2546     {L"DateValue",                 Global_DateValue, 0, 1},
2547     {L"Day",                       Global_Day, 0, 1},
2548     {L"Erase",                     Global_Erase, 0, 1},
2549     {L"Err",                       Global_Err, BP_GETPUT},
2550     {L"Escape",                    Global_Escape, 0, 1},
2551     {L"Eval",                      Global_Eval, 0, 1},
2552     {L"Execute",                   Global_Execute, 0, 1},
2553     {L"ExecuteGlobal",             Global_ExecuteGlobal, 0, 1},
2554     {L"Exp",                       Global_Exp, 0, 1},
2555     {L"Filter",                    Global_Filter, 0, 2, 4},
2556     {L"Fix",                       Global_Fix, 0, 1},
2557     {L"FormatCurrency",            Global_FormatCurrency, 0, 1, 5},
2558     {L"FormatDateTime",            Global_FormatDateTime, 0, 1, 2},
2559     {L"FormatNumber",              Global_FormatNumber, 0, 1, 5},
2560     {L"FormatPercent",             Global_FormatPercent, 0, 1, 5},
2561     {L"GetObject",                 Global_GetObject, 0, 0, 2},
2562     {L"GetRef",                    Global_GetRef, 0, 1},
2563     {L"Hex",                       Global_Hex, 0, 1},
2564     {L"Hour",                      Global_Hour, 0, 1},
2565     {L"InputBox",                  Global_InputBox, 0, 1, 7},
2566     {L"InStr",                     Global_InStr, 0, 2, 4},
2567     {L"InStrB",                    Global_InStrB, 0, 3, 4},
2568     {L"InStrRev",                  Global_InStrRev, 0, 2, 4},
2569     {L"Int",                       Global_Int, 0, 1},
2570     {L"IsArray",                   Global_IsArray, 0, 1},
2571     {L"IsDate",                    Global_IsDate, 0, 1},
2572     {L"IsEmpty",                   Global_IsEmpty, 0, 1},
2573     {L"IsNull",                    Global_IsNull, 0, 1},
2574     {L"IsNumeric",                 Global_IsNumeric, 0, 1},
2575     {L"IsObject",                  Global_IsObject, 0, 1},
2576     {L"Join",                      Global_Join, 0, 1, 2},
2577     {L"LBound",                    Global_LBound, 0, 1},
2578     {L"LCase",                     Global_LCase, 0, 1},
2579     {L"Left",                      Global_Left, 0, 2},
2580     {L"LeftB",                     Global_LeftB, 0, 2},
2581     {L"Len",                       Global_Len, 0, 1},
2582     {L"LenB",                      Global_LenB, 0, 1},
2583     {L"LoadPicture",               Global_LoadPicture, 0, 1},
2584     {L"Log",                       Global_Log, 0, 1},
2585     {L"LTrim",                     Global_LTrim, 0, 1},
2586     {L"Mid",                       Global_Mid, 0, 2, 3},
2587     {L"MidB",                      Global_MidB, 0, 2, 3},
2588     {L"Minute",                    Global_Minute, 0, 1},
2589     {L"Month",                     Global_Month, 0, 1},
2590     {L"MonthName",                 Global_MonthName, 0, 1, 2},
2591     {L"MsgBox",                    Global_MsgBox, 0, 1, 5},
2592     {L"Now",                       Global_Now, 0, 0},
2593     {L"Oct",                       Global_Oct, 0, 1},
2594     {L"Randomize",                 Global_Randomize, 0, 1},
2595     {L"Replace",                   Global_Replace, 0, 3, 6},
2596     {L"RGB",                       Global_RGB, 0, 3},
2597     {L"Right",                     Global_Right, 0, 2},
2598     {L"RightB",                    Global_RightB, 0, 2},
2599     {L"Rnd",                       Global_Rnd, 0, 1},
2600     {L"Round",                     Global_Round, 0, 1, 2},
2601     {L"RTrim",                     Global_RTrim, 0, 1},
2602     {L"ScriptEngine",              Global_ScriptEngine, 0, 0},
2603     {L"ScriptEngineBuildVersion",  Global_ScriptEngineBuildVersion, 0, 0},
2604     {L"ScriptEngineMajorVersion",  Global_ScriptEngineMajorVersion, 0, 0},
2605     {L"ScriptEngineMinorVersion",  Global_ScriptEngineMinorVersion, 0, 0},
2606     {L"Second",                    Global_Second, 0, 1},
2607     {L"Sgn",                       Global_Sgn, 0, 1},
2608     {L"Sin",                       Global_Sin, 0, 1},
2609     {L"Space",                     Global_Space, 0, 1},
2610     {L"Split",                     Global_Split, 0, 1, 4},
2611     {L"Sqr",                       Global_Sqr, 0, 1},
2612     {L"StrComp",                   Global_StrComp, 0, 2, 3},
2613     {L"String",                    Global_String, 0, 0, 2},
2614     {L"StrReverse",                Global_StrReverse, 0, 1},
2615     {L"Tan",                       Global_Tan, 0, 1},
2616     {L"Time",                      Global_Time, 0, 0},
2617     {L"Timer",                     Global_Timer, 0, 0},
2618     {L"TimeSerial",                Global_TimeSerial, 0, 3},
2619     {L"TimeValue",                 Global_TimeValue, 0, 1},
2620     {L"Trim",                      Global_Trim, 0, 1},
2621     {L"TypeName",                  Global_TypeName, 0, 1},
2622     {L"UBound",                    Global_UBound, 0, 1, 2},
2623     {L"UCase",                     Global_UCase, 0, 1},
2624     {L"Unescape",                  Global_Unescape, 0, 1},
2625     {L"VarType",                   Global_VarType, 0, 1},
2626     {L"vbAbort",                   NULL, BP_GET, VT_I2, IDABORT},
2627     {L"vbAbortRetryIgnore",        NULL, BP_GET, VT_I2, MB_ABORTRETRYIGNORE},
2628     {L"vbApplicationModal",        NULL, BP_GET, VT_I2, MB_APPLMODAL},
2629     {L"vbArray",                   NULL, BP_GET, VT_I2, VT_ARRAY},
2630     {L"vbBinaryCompare",           NULL, BP_GET, VT_I2, 0},
2631     {L"vbBlack",                   NULL, BP_GET, VT_I4, 0x000000},
2632     {L"vbBlue",                    NULL, BP_GET, VT_I4, 0xff0000},
2633     {L"vbBoolean",                 NULL, BP_GET, VT_I2, VT_BOOL},
2634     {L"vbByte",                    NULL, BP_GET, VT_I2, VT_UI1},
2635     {L"vbCancel",                  NULL, BP_GET, VT_I2, IDCANCEL},
2636     {L"vbCr",                      NULL, BP_GET, VT_BSTR, (UINT_PTR)&vbCr},
2637     {L"vbCritical",                NULL, BP_GET, VT_I2, MB_ICONHAND},
2638     {L"vbCrLf",                    NULL, BP_GET, VT_BSTR, (UINT_PTR)&vbCrLf},
2639     {L"vbCurrency",                NULL, BP_GET, VT_I2, VT_CY},
2640     {L"vbCyan",                    NULL, BP_GET, VT_I4, 0xffff00},
2641     {L"vbDatabaseCompare",         NULL, BP_GET, VT_I2, 2},
2642     {L"vbDataObject",              NULL, BP_GET, VT_I2, VT_UNKNOWN},
2643     {L"vbDate",                    NULL, BP_GET, VT_I2, VT_DATE},
2644     {L"vbDecimal",                 NULL, BP_GET, VT_I2, VT_DECIMAL},
2645     {L"vbDefaultButton1",          NULL, BP_GET, VT_I2, MB_DEFBUTTON1},
2646     {L"vbDefaultButton2",          NULL, BP_GET, VT_I2, MB_DEFBUTTON2},
2647     {L"vbDefaultButton3",          NULL, BP_GET, VT_I2, MB_DEFBUTTON3},
2648     {L"vbDefaultButton4",          NULL, BP_GET, VT_I2, MB_DEFBUTTON4},
2649     {L"vbDouble",                  NULL, BP_GET, VT_I2, VT_R8},
2650     {L"vbEmpty",                   NULL, BP_GET, VT_I2, VT_EMPTY},
2651     {L"vbError",                   NULL, BP_GET, VT_I2, VT_ERROR},
2652     {L"vbExclamation",             NULL, BP_GET, VT_I2, MB_ICONEXCLAMATION},
2653     {L"vbFalse",                   NULL, BP_GET, VT_I2, VARIANT_FALSE},
2654     {L"vbFirstFourDays",           NULL, BP_GET, VT_I2, 2},
2655     {L"vbFirstFullWeek",           NULL, BP_GET, VT_I2, 3},
2656     {L"vbFirstJan1",               NULL, BP_GET, VT_I2, 1},
2657     {L"vbFormFeed",                NULL, BP_GET, VT_BSTR, (UINT_PTR)&vbFormFeed},
2658     {L"vbFriday",                  NULL, BP_GET, VT_I2, 6},
2659     {L"vbGeneralDate",             NULL, BP_GET, VT_I2, 0},
2660     {L"vbGreen",                   NULL, BP_GET, VT_I4, 0x00ff00},
2661     {L"vbIgnore",                  NULL, BP_GET, VT_I2, IDIGNORE},
2662     {L"vbInformation",             NULL, BP_GET, VT_I2, MB_ICONASTERISK},
2663     {L"vbInteger",                 NULL, BP_GET, VT_I2, VT_I2},
2664     {L"vbLf",                      NULL, BP_GET, VT_BSTR, (UINT_PTR)&vbLf},
2665     {L"vbLong",                    NULL, BP_GET, VT_I2, VT_I4},
2666     {L"vbLongDate",                NULL, BP_GET, VT_I2, 1},
2667     {L"vbLongTime",                NULL, BP_GET, VT_I2, 3},
2668     {L"vbMagenta",                 NULL, BP_GET, VT_I4, 0xff00ff},
2669     {L"vbMonday",                  NULL, BP_GET, VT_I2, 2},
2670     {L"vbMsgBoxHelpButton",        NULL, BP_GET, VT_I4, MB_HELP},
2671     {L"vbMsgBoxRight",             NULL, BP_GET, VT_I4, MB_RIGHT},
2672     {L"vbMsgBoxRtlReading",        NULL, BP_GET, VT_I4, MB_RTLREADING},
2673     {L"vbMsgBoxSetForeground",     NULL, BP_GET, VT_I4, MB_SETFOREGROUND},
2674     {L"vbNewLine",                 NULL, BP_GET, VT_BSTR, (UINT_PTR)&vbNewLine},
2675     {L"vbNo",                      NULL, BP_GET, VT_I2, IDNO},
2676     {L"vbNull",                    NULL, BP_GET, VT_I2, VT_NULL},
2677     {L"vbNullChar",                NULL, BP_GET, VT_BSTR, (UINT_PTR)&vbNullChar},
2678     {L"vbNullString",              NULL, BP_GET, VT_BSTR, (UINT_PTR)&vbNullString},
2679     {L"vbObject",                  NULL, BP_GET, VT_I2, VT_DISPATCH},
2680     {L"vbObjectError",             NULL, BP_GET, VT_I4, 0x80040000},
2681     {L"vbOK",                      NULL, BP_GET, VT_I2, IDOK},
2682     {L"vbOKCancel",                NULL, BP_GET, VT_I2, MB_OKCANCEL},
2683     {L"vbOKOnly",                  NULL, BP_GET, VT_I2, MB_OK},
2684     {L"vbQuestion",                NULL, BP_GET, VT_I2, MB_ICONQUESTION},
2685     {L"vbRed",                     NULL, BP_GET, VT_I4, 0x0000ff},
2686     {L"vbRetry",                   NULL, BP_GET, VT_I2, IDRETRY},
2687     {L"vbRetryCancel",             NULL, BP_GET, VT_I2, MB_RETRYCANCEL},
2688     {L"vbSaturday",                NULL, BP_GET, VT_I2, 7},
2689     {L"vbShortDate",               NULL, BP_GET, VT_I2, 2},
2690     {L"vbShortTime",               NULL, BP_GET, VT_I2, 4},
2691     {L"vbSingle",                  NULL, BP_GET, VT_I2, VT_R4},
2692     {L"vbString",                  NULL, BP_GET, VT_I2, VT_BSTR},
2693     {L"vbSunday",                  NULL, BP_GET, VT_I2, 1},
2694     {L"vbSystemModal",             NULL, BP_GET, VT_I2, MB_SYSTEMMODAL},
2695     {L"vbTab",                     NULL, BP_GET, VT_BSTR, (UINT_PTR)&vbTab},
2696     {L"vbTextCompare",             NULL, BP_GET, VT_I2, 1},
2697     {L"vbThursday",                NULL, BP_GET, VT_I2, 5},
2698     {L"vbTrue",                    NULL, BP_GET, VT_I2, VARIANT_TRUE},
2699     {L"vbTuesday",                 NULL, BP_GET, VT_I2, 3},
2700     {L"vbUseDefault",              NULL, BP_GET, VT_I2, -2},
2701     {L"vbUseSystem",               NULL, BP_GET, VT_I2, 0},
2702     {L"vbUseSystemDayOfWeek",      NULL, BP_GET, VT_I2, 0},
2703     {L"vbVariant",                 NULL, BP_GET, VT_I2, VT_VARIANT},
2704     {L"vbVerticalTab",             NULL, BP_GET, VT_BSTR, (UINT_PTR)&vbVerticalTab},
2705     {L"vbWednesday",               NULL, BP_GET, VT_I2, 4},
2706     {L"vbWhite",                   NULL, BP_GET, VT_I4, 0xffffff},
2707     {L"vbYellow",                  NULL, BP_GET, VT_I4, 0x00ffff},
2708     {L"vbYes",                     NULL, BP_GET, VT_I2, IDYES},
2709     {L"vbYesNo",                   NULL, BP_GET, VT_I2, MB_YESNO},
2710     {L"vbYesNoCancel",             NULL, BP_GET, VT_I2, MB_YESNOCANCEL},
2711     {L"Weekday",                   Global_Weekday, 0, 1, 2},
2712     {L"WeekdayName",               Global_WeekdayName, 0, 1, 3},
2713     {L"Year",                      Global_Year, 0, 1}
2714 };
2715 
err_string_prop(BSTR * prop,VARIANT * args,unsigned args_cnt,VARIANT * res)2716 static HRESULT err_string_prop(BSTR *prop, VARIANT *args, unsigned args_cnt, VARIANT *res)
2717 {
2718     BSTR str;
2719     HRESULT hres;
2720 
2721     if(!args_cnt)
2722         return return_string(res, *prop ? *prop : L"");
2723 
2724     hres = to_string(args, &str);
2725     if(FAILED(hres))
2726         return hres;
2727 
2728     SysFreeString(*prop);
2729     *prop = str;
2730     return S_OK;
2731 }
2732 
Err_Description(BuiltinDisp * This,VARIANT * args,unsigned args_cnt,VARIANT * res)2733 static HRESULT Err_Description(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
2734 {
2735     TRACE("\n");
2736     return err_string_prop(&This->ctx->ei.bstrDescription, args, args_cnt, res);
2737 }
2738 
Err_HelpContext(BuiltinDisp * This,VARIANT * args,unsigned args_cnt,VARIANT * res)2739 static HRESULT Err_HelpContext(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
2740 {
2741     TRACE("\n");
2742 
2743     if(args_cnt) {
2744         FIXME("setter not implemented\n");
2745         return E_NOTIMPL;
2746     }
2747 
2748     return return_int(res, This->ctx->ei.dwHelpContext);
2749 }
2750 
Err_HelpFile(BuiltinDisp * This,VARIANT * args,unsigned args_cnt,VARIANT * res)2751 static HRESULT Err_HelpFile(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
2752 {
2753     TRACE("\n");
2754     return err_string_prop(&This->ctx->ei.bstrHelpFile, args, args_cnt, res);
2755 }
2756 
Err_Number(BuiltinDisp * This,VARIANT * args,unsigned args_cnt,VARIANT * res)2757 static HRESULT Err_Number(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
2758 {
2759     HRESULT hres;
2760 
2761     TRACE("\n");
2762 
2763     if(args_cnt) {
2764         FIXME("setter not implemented\n");
2765         return E_NOTIMPL;
2766     }
2767 
2768     hres = This->ctx->ei.scode;
2769     return return_int(res, HRESULT_FACILITY(hres) == FACILITY_VBS ? HRESULT_CODE(hres) : hres);
2770 }
2771 
Err_Source(BuiltinDisp * This,VARIANT * args,unsigned args_cnt,VARIANT * res)2772 static HRESULT Err_Source(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
2773 {
2774     TRACE("\n");
2775     return err_string_prop(&This->ctx->ei.bstrSource, args, args_cnt, res);
2776 }
2777 
Err_Clear(BuiltinDisp * This,VARIANT * args,unsigned args_cnt,VARIANT * res)2778 static HRESULT Err_Clear(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
2779 {
2780     TRACE("\n");
2781 
2782     clear_ei(&This->ctx->ei);
2783     return S_OK;
2784 }
2785 
Err_Raise(BuiltinDisp * This,VARIANT * args,unsigned args_cnt,VARIANT * res)2786 static HRESULT Err_Raise(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
2787 {
2788     BSTR source = NULL, description = NULL, helpfile = NULL;
2789     int code,  helpcontext = 0;
2790     HRESULT hres, error;
2791 
2792     TRACE("%s %u...\n", debugstr_variant(args), args_cnt);
2793 
2794     hres = to_int(args, &code);
2795     if(FAILED(hres))
2796         return hres;
2797     if(code > 0 && code > 0xffff)
2798         return E_INVALIDARG;
2799 
2800     if(args_cnt >= 2)
2801         hres = to_string(args + 1, &source);
2802     if(args_cnt >= 3 && SUCCEEDED(hres))
2803         hres = to_string(args + 2, &description);
2804     if(args_cnt >= 4 && SUCCEEDED(hres))
2805         hres = to_string(args + 3, &helpfile);
2806     if(args_cnt >= 5 && SUCCEEDED(hres))
2807         hres = to_int(args + 4, &helpcontext);
2808 
2809     if(SUCCEEDED(hres)) {
2810         script_ctx_t *ctx = This->ctx;
2811 
2812         error = (code & ~0xffff) ? map_hres(code) : MAKE_VBSERROR(code);
2813 
2814         if(source) {
2815             if(ctx->ei.bstrSource) SysFreeString(ctx->ei.bstrSource);
2816             ctx->ei.bstrSource = source;
2817         }
2818         if(!ctx->ei.bstrSource)
2819             ctx->ei.bstrSource = get_vbscript_string(VBS_RUNTIME_ERROR);
2820         if(description) {
2821             if(ctx->ei.bstrDescription) SysFreeString(ctx->ei.bstrDescription);
2822             ctx->ei.bstrDescription = description;
2823         }
2824         if(!ctx->ei.bstrDescription)
2825             ctx->ei.bstrDescription = get_vbscript_error_string(error);
2826         if(helpfile) {
2827             if(ctx->ei.bstrHelpFile) SysFreeString(ctx->ei.bstrHelpFile);
2828             ctx->ei.bstrHelpFile = helpfile;
2829         }
2830         if(args_cnt >= 5)
2831             ctx->ei.dwHelpContext = helpcontext;
2832 
2833         ctx->ei.scode = error;
2834         hres = SCRIPT_E_RECORDED;
2835     }else {
2836         SysFreeString(source);
2837         SysFreeString(description);
2838         SysFreeString(helpfile);
2839     }
2840 
2841     return hres;
2842 }
2843 
2844 static const builtin_prop_t err_props[] = {
2845     {NULL,            Err_Number, BP_GETPUT},
2846     {L"Clear",        Err_Clear},
2847     {L"Description",  Err_Description, BP_GETPUT},
2848     {L"HelpContext",  Err_HelpContext, BP_GETPUT},
2849     {L"HelpFile",     Err_HelpFile, BP_GETPUT},
2850     {L"Number",       Err_Number, BP_GETPUT},
2851     {L"Raise",        Err_Raise, 0, 1, 5},
2852     {L"Source",       Err_Source, BP_GETPUT}
2853 };
2854 
detach_global_objects(script_ctx_t * ctx)2855 void detach_global_objects(script_ctx_t *ctx)
2856 {
2857     if(ctx->err_obj) {
2858         ctx->err_obj->ctx = NULL;
2859         IDispatch_Release(&ctx->err_obj->IDispatch_iface);
2860         ctx->err_obj = NULL;
2861     }
2862 
2863     if(ctx->global_obj) {
2864         ctx->global_obj->ctx = NULL;
2865         IDispatch_Release(&ctx->global_obj->IDispatch_iface);
2866         ctx->global_obj = NULL;
2867     }
2868 }
2869 
init_global(script_ctx_t * ctx)2870 HRESULT init_global(script_ctx_t *ctx)
2871 {
2872     HRESULT hres;
2873 
2874     hres = create_builtin_dispatch(ctx, global_props, ARRAY_SIZE(global_props), &ctx->global_obj);
2875     if(FAILED(hres))
2876         return hres;
2877 
2878     return create_builtin_dispatch(ctx, err_props, ARRAY_SIZE(err_props), &ctx->err_obj);
2879 }
2880