mf/tests: Clobber the alignment and bytes per second, to test if the DMO fixes it.
[wine.git] / dlls / vbscript / global.c
blob058ddabcde1ae6e54fa0632c1e7cc824e65df4e7
1 /*
2 * Copyright 2011 Jacek Caban for CodeWeavers
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.
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.
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
19 #include <assert.h>
20 #include <math.h>
22 #include "vbscript.h"
23 #include "vbscript_defs.h"
25 #include "mshtmhst.h"
26 #include "objsafe.h"
27 #include "wchar.h"
29 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
33 #define VB_E_CANNOT_CREATE_OBJ 0x800a01ad
34 #define VB_E_MK_PARSE_ERROR 0x800a01b0
36 /* Defined as extern in urlmon.idl, but not exported by uuid.lib */
37 const GUID GUID_CUSTOM_CONFIRMOBJECTSAFETY =
38 {0x10200490,0xfa38,0x11d0,{0xac,0x0e,0x00,0xa0,0xc9,0xf,0xff,0xc0}};
40 #define BP_GET 1
41 #define BP_GETPUT 2
43 typedef struct {
44 UINT16 len;
45 WCHAR buf[7];
46 } string_constant_t;
48 struct _builtin_prop_t {
49 const WCHAR *name;
50 HRESULT (*proc)(BuiltinDisp*,VARIANT*,unsigned,VARIANT*);
51 DWORD flags;
52 unsigned min_args;
53 UINT_PTR max_args;
56 static inline BuiltinDisp *impl_from_IDispatch(IDispatch *iface)
58 return CONTAINING_RECORD(iface, BuiltinDisp, IDispatch_iface);
61 static HRESULT WINAPI Builtin_QueryInterface(IDispatch *iface, REFIID riid, void **ppv)
63 BuiltinDisp *This = impl_from_IDispatch(iface);
65 if(IsEqualGUID(&IID_IUnknown, riid)) {
66 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
67 *ppv = &This->IDispatch_iface;
68 }else if(IsEqualGUID(&IID_IDispatch, riid)) {
69 TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
70 *ppv = &This->IDispatch_iface;
71 }else {
72 if(!IsEqualGUID(riid, &IID_IDispatchEx))
73 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
74 *ppv = NULL;
75 return E_NOINTERFACE;
78 IUnknown_AddRef((IUnknown*)*ppv);
79 return S_OK;
82 static ULONG WINAPI Builtin_AddRef(IDispatch *iface)
84 BuiltinDisp *This = impl_from_IDispatch(iface);
85 LONG ref = InterlockedIncrement(&This->ref);
87 TRACE("(%p) ref=%ld\n", This, ref);
89 return ref;
92 static ULONG WINAPI Builtin_Release(IDispatch *iface)
94 BuiltinDisp *This = impl_from_IDispatch(iface);
95 LONG ref = InterlockedDecrement(&This->ref);
97 TRACE("(%p) ref=%ld\n", This, ref);
99 if(!ref) {
100 assert(!This->ctx);
101 free(This);
104 return ref;
107 static HRESULT WINAPI Builtin_GetTypeInfoCount(IDispatch *iface, UINT *pctinfo)
109 BuiltinDisp *This = impl_from_IDispatch(iface);
110 TRACE("(%p)->(%p)\n", This, pctinfo);
111 *pctinfo = 0;
112 return S_OK;
115 static HRESULT WINAPI Builtin_GetTypeInfo(IDispatch *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
117 BuiltinDisp *This = impl_from_IDispatch(iface);
118 TRACE("(%p)->(%u %lu %p)\n", This, iTInfo, lcid, ppTInfo);
119 return DISP_E_BADINDEX;
122 HRESULT get_builtin_id(BuiltinDisp *disp, const WCHAR *name, DISPID *id)
124 size_t min = 1, max = disp->member_cnt - 1, i;
125 int r;
127 while(min <= max) {
128 i = (min + max) / 2;
129 r = wcsicmp(disp->members[i].name, name);
130 if(!r) {
131 *id = i;
132 return S_OK;
134 if(r < 0)
135 min = i+1;
136 else
137 max = i-1;
140 return DISP_E_MEMBERNOTFOUND;
144 static HRESULT WINAPI Builtin_GetIDsOfNames(IDispatch *iface, REFIID riid, LPOLESTR *names, UINT name_cnt,
145 LCID lcid, DISPID *ids)
147 BuiltinDisp *This = impl_from_IDispatch(iface);
148 unsigned i;
149 HRESULT hres;
151 TRACE("(%p)->(%s %p %u %lu %p)\n", This, debugstr_guid(riid), names, name_cnt, lcid, ids);
153 if(!This->ctx) {
154 FIXME("NULL context\n");
155 return E_UNEXPECTED;
158 for(i = 0; i < name_cnt; i++) {
159 hres = get_builtin_id(This, names[i], &ids[i]);
160 if(FAILED(hres))
161 return hres;
164 return S_OK;
167 static HRESULT WINAPI Builtin_Invoke(IDispatch *iface, DISPID id, REFIID riid, LCID lcid, WORD flags,
168 DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei, UINT *err)
170 BuiltinDisp *This = impl_from_IDispatch(iface);
171 const builtin_prop_t *prop;
172 VARIANT args_buf[8], *args;
173 unsigned argn, i;
174 HRESULT hres;
176 TRACE("(%p)->(%ld %s %ld %d %p %p %p %p)\n", This, id, debugstr_guid(riid), lcid, flags, dp, res, ei, err);
178 if(!This->ctx) {
179 FIXME("NULL context\n");
180 return E_UNEXPECTED;
183 if(id >= This->member_cnt || (!This->members[id].proc && !This->members[id].flags))
184 return DISP_E_MEMBERNOTFOUND;
185 prop = This->members + id;
187 switch(flags) {
188 case DISPATCH_PROPERTYGET:
189 if(!(prop->flags & (BP_GET|BP_GETPUT))) {
190 FIXME("property does not support DISPATCH_PROPERTYGET\n");
191 return E_FAIL;
193 break;
194 case DISPATCH_PROPERTYGET|DISPATCH_METHOD:
195 if(!prop->proc && prop->flags == BP_GET) {
196 const int vt = prop->min_args, val = prop->max_args;
197 switch(vt) {
198 case VT_I2:
199 V_VT(res) = VT_I2;
200 V_I2(res) = val;
201 break;
202 case VT_I4:
203 V_VT(res) = VT_I4;
204 V_I4(res) = val;
205 break;
206 case VT_BSTR: {
207 const string_constant_t *str = (const string_constant_t*)prop->max_args;
208 BSTR ret;
210 ret = SysAllocStringLen(str->buf, str->len);
211 if(!ret)
212 return E_OUTOFMEMORY;
214 V_VT(res) = VT_BSTR;
215 V_BSTR(res) = ret;
216 break;
218 DEFAULT_UNREACHABLE;
220 return S_OK;
222 break;
223 case DISPATCH_METHOD:
224 if(prop->flags & (BP_GET|BP_GETPUT)) {
225 FIXME("Call on property\n");
226 return E_FAIL;
228 break;
229 case DISPATCH_PROPERTYPUT:
230 if(!(prop->flags & BP_GETPUT)) {
231 FIXME("property does not support DISPATCH_PROPERTYPUT\n");
232 return E_FAIL;
235 FIXME("call put\n");
236 return E_NOTIMPL;
237 default:
238 FIXME("unsupported flags %x\n", flags);
239 return E_NOTIMPL;
242 argn = arg_cnt(dp);
244 if(argn < prop->min_args || argn > (prop->max_args ? prop->max_args : prop->min_args)) {
245 WARN("invalid number of arguments\n");
246 return MAKE_VBSERROR(VBSE_FUNC_ARITY_MISMATCH);
249 if(argn <= ARRAY_SIZE(args_buf)) {
250 args = args_buf;
251 }else {
252 args = malloc(argn * sizeof(*args));
253 if(!args)
254 return E_OUTOFMEMORY;
257 for(i=0; i < argn; i++) {
258 if(V_VT(dp->rgvarg+dp->cArgs-i-1) == (VT_BYREF|VT_VARIANT))
259 args[i] = *V_VARIANTREF(dp->rgvarg+dp->cArgs-i-1);
260 else
261 args[i] = dp->rgvarg[dp->cArgs-i-1];
264 hres = prop->proc(This, args, dp->cArgs, res);
265 if(args != args_buf)
266 free(args);
267 return hres;
270 static const IDispatchVtbl BuiltinDispVtbl = {
271 Builtin_QueryInterface,
272 Builtin_AddRef,
273 Builtin_Release,
274 Builtin_GetTypeInfoCount,
275 Builtin_GetTypeInfo,
276 Builtin_GetIDsOfNames,
277 Builtin_Invoke
280 static HRESULT create_builtin_dispatch(script_ctx_t *ctx, const builtin_prop_t *members, size_t member_cnt, BuiltinDisp **ret)
282 BuiltinDisp *disp;
284 if(!(disp = malloc(sizeof(*disp))))
285 return E_OUTOFMEMORY;
287 disp->IDispatch_iface.lpVtbl = &BuiltinDispVtbl;
288 disp->ref = 1;
289 disp->members = members;
290 disp->member_cnt = member_cnt;
291 disp->ctx = ctx;
293 *ret = disp;
294 return S_OK;
297 static IInternetHostSecurityManager *get_sec_mgr(script_ctx_t *ctx)
299 IInternetHostSecurityManager *secmgr;
300 IServiceProvider *sp;
301 HRESULT hres;
303 if(!ctx->site)
304 return NULL;
306 if(ctx->secmgr)
307 return ctx->secmgr;
309 hres = IActiveScriptSite_QueryInterface(ctx->site, &IID_IServiceProvider, (void**)&sp);
310 if(FAILED(hres))
311 return NULL;
313 hres = IServiceProvider_QueryService(sp, &SID_SInternetHostSecurityManager, &IID_IInternetHostSecurityManager,
314 (void**)&secmgr);
315 IServiceProvider_Release(sp);
316 if(FAILED(hres))
317 return NULL;
319 return ctx->secmgr = secmgr;
322 static HRESULT return_string(VARIANT *res, const WCHAR *str)
324 BSTR ret;
326 if(!res)
327 return S_OK;
329 ret = SysAllocString(str);
330 if(!ret)
331 return E_OUTOFMEMORY;
333 V_VT(res) = VT_BSTR;
334 V_BSTR(res) = ret;
335 return S_OK;
338 static HRESULT return_bstr(VARIANT *res, BSTR str)
340 if(res) {
341 V_VT(res) = VT_BSTR;
342 V_BSTR(res) = str;
343 }else {
344 SysFreeString(str);
346 return S_OK;
349 static HRESULT return_bool(VARIANT *res, BOOL val)
351 if(res) {
352 V_VT(res) = VT_BOOL;
353 V_BOOL(res) = val ? VARIANT_TRUE : VARIANT_FALSE;
355 return S_OK;
358 static HRESULT return_short(VARIANT *res, short val)
360 if(res) {
361 V_VT(res) = VT_I2;
362 V_I2(res) = val;
365 return S_OK;
368 static HRESULT return_int(VARIANT *res, int val)
370 if(res) {
371 V_VT(res) = VT_I4;
372 V_I4(res) = val;
375 return S_OK;
378 static inline HRESULT return_double(VARIANT *res, double val)
380 if(res) {
381 V_VT(res) = VT_R8;
382 V_R8(res) = val;
385 return S_OK;
388 static inline HRESULT return_float(VARIANT *res, float val)
390 if(res) {
391 V_VT(res) = VT_R4;
392 V_R4(res) = val;
395 return S_OK;
398 static inline HRESULT return_null(VARIANT *res)
400 if(res)
401 V_VT(res) = VT_NULL;
402 return S_OK;
405 static inline HRESULT return_date(VARIANT *res, double date)
407 if(res) {
408 V_VT(res) = VT_DATE;
409 V_DATE(res) = date;
411 return S_OK;
414 HRESULT to_int(VARIANT *v, int *ret)
416 VARIANT r;
417 HRESULT hres;
419 V_VT(&r) = VT_EMPTY;
420 hres = VariantChangeType(&r, v, 0, VT_I4);
421 if(FAILED(hres))
422 return hres;
424 *ret = V_I4(&r);
425 return S_OK;
428 static HRESULT to_double(VARIANT *v, double *ret)
430 VARIANT dst;
431 HRESULT hres;
433 V_VT(&dst) = VT_EMPTY;
434 hres = VariantChangeType(&dst, v, 0, VT_R8);
435 if(FAILED(hres))
436 return hres;
438 *ret = V_R8(&dst);
439 return S_OK;
442 static HRESULT to_float(VARIANT *v, float *ret)
444 VARIANT dst;
445 HRESULT hres;
447 V_VT(&dst) = VT_EMPTY;
448 hres = VariantChangeType(&dst, v, 0, VT_R4);
449 if(FAILED(hres))
450 return hres;
452 *ret = V_R4(&dst);
453 return S_OK;
456 static HRESULT to_string(VARIANT *v, BSTR *ret)
458 VARIANT dst;
459 HRESULT hres;
461 V_VT(&dst) = VT_EMPTY;
462 hres = VariantChangeType(&dst, v, VARIANT_LOCALBOOL, VT_BSTR);
463 if(FAILED(hres))
464 return hres;
466 *ret = V_BSTR(&dst);
467 return S_OK;
470 static HRESULT to_system_time(VARIANT *v, SYSTEMTIME *st)
472 VARIANT date;
473 HRESULT hres;
475 V_VT(&date) = VT_EMPTY;
476 hres = VariantChangeType(&date, v, 0, VT_DATE);
477 if(FAILED(hres))
478 return hres;
480 return VariantTimeToSystemTime(V_DATE(&date), st);
483 static HRESULT set_object_site(script_ctx_t *ctx, IUnknown *obj)
485 IObjectWithSite *obj_site;
486 IUnknown *ax_site;
487 HRESULT hres;
489 hres = IUnknown_QueryInterface(obj, &IID_IObjectWithSite, (void**)&obj_site);
490 if(FAILED(hres))
491 return S_OK;
493 ax_site = create_ax_site(ctx);
494 if(ax_site) {
495 hres = IObjectWithSite_SetSite(obj_site, ax_site);
496 IUnknown_Release(ax_site);
498 else
499 hres = E_OUTOFMEMORY;
500 IObjectWithSite_Release(obj_site);
501 return hres;
504 static IUnknown *create_object(script_ctx_t *ctx, const WCHAR *progid)
506 IInternetHostSecurityManager *secmgr = NULL;
507 struct CONFIRMSAFETY cs;
508 IClassFactoryEx *cfex;
509 IClassFactory *cf;
510 DWORD policy_size;
511 BYTE *bpolicy;
512 IUnknown *obj;
513 DWORD policy;
514 GUID guid;
515 HRESULT hres;
517 hres = CLSIDFromProgID(progid, &guid);
518 if(FAILED(hres))
519 return NULL;
521 TRACE("GUID %s\n", debugstr_guid(&guid));
523 if(ctx->safeopt & INTERFACE_USES_SECURITY_MANAGER) {
524 secmgr = get_sec_mgr(ctx);
525 if(!secmgr)
526 return NULL;
528 policy = 0;
529 hres = IInternetHostSecurityManager_ProcessUrlAction(secmgr, URLACTION_ACTIVEX_RUN,
530 (BYTE*)&policy, sizeof(policy), (BYTE*)&guid, sizeof(GUID), 0, 0);
531 if(FAILED(hres) || policy != URLPOLICY_ALLOW)
532 return NULL;
535 hres = CoGetClassObject(&guid, CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER, NULL, &IID_IClassFactory, (void**)&cf);
536 if(FAILED(hres))
537 return NULL;
539 hres = IClassFactory_QueryInterface(cf, &IID_IClassFactoryEx, (void**)&cfex);
540 if(SUCCEEDED(hres)) {
541 FIXME("Use IClassFactoryEx\n");
542 IClassFactoryEx_Release(cfex);
545 hres = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void**)&obj);
546 if(FAILED(hres))
547 return NULL;
549 if(secmgr) {
550 cs.clsid = guid;
551 cs.pUnk = obj;
552 cs.dwFlags = 0;
553 hres = IInternetHostSecurityManager_QueryCustomPolicy(secmgr, &GUID_CUSTOM_CONFIRMOBJECTSAFETY,
554 &bpolicy, &policy_size, (BYTE*)&cs, sizeof(cs), 0);
555 if(SUCCEEDED(hres)) {
556 policy = policy_size >= sizeof(DWORD) ? *(DWORD*)bpolicy : URLPOLICY_DISALLOW;
557 CoTaskMemFree(bpolicy);
560 if(FAILED(hres) || policy != URLPOLICY_ALLOW) {
561 IUnknown_Release(obj);
562 return NULL;
566 hres = set_object_site(ctx, obj);
567 if(FAILED(hres)) {
568 IUnknown_Release(obj);
569 return NULL;
572 return obj;
575 static HRESULT show_msgbox(script_ctx_t *ctx, BSTR prompt, unsigned type, BSTR orig_title, VARIANT *res)
577 SCRIPTUICHANDLING uic_handling = SCRIPTUICHANDLING_ALLOW;
578 IActiveScriptSiteUIControl *ui_control;
579 IActiveScriptSiteWindow *acts_window;
580 WCHAR *title_buf = NULL;
581 const WCHAR *title;
582 HWND hwnd = NULL;
583 int ret = 0;
584 HRESULT hres;
586 hres = IActiveScriptSite_QueryInterface(ctx->site, &IID_IActiveScriptSiteUIControl, (void**)&ui_control);
587 if(SUCCEEDED(hres)) {
588 hres = IActiveScriptSiteUIControl_GetUIBehavior(ui_control, SCRIPTUICITEM_MSGBOX, &uic_handling);
589 IActiveScriptSiteUIControl_Release(ui_control);
590 if(FAILED(hres))
591 uic_handling = SCRIPTUICHANDLING_ALLOW;
594 switch(uic_handling) {
595 case SCRIPTUICHANDLING_ALLOW:
596 break;
597 case SCRIPTUICHANDLING_NOUIDEFAULT:
598 return return_short(res, 0);
599 default:
600 FIXME("blocked\n");
601 return E_FAIL;
604 hres = IActiveScriptSite_QueryInterface(ctx->site, &IID_IActiveScriptSiteWindow, (void**)&acts_window);
605 if(FAILED(hres)) {
606 FIXME("No IActiveScriptSiteWindow\n");
607 return hres;
610 if(ctx->safeopt & INTERFACE_USES_SECURITY_MANAGER) {
611 if(orig_title && *orig_title) {
612 WCHAR *ptr;
614 title = title_buf = malloc(sizeof(L"VBScript") + (lstrlenW(orig_title)+2)*sizeof(WCHAR));
615 if(!title)
616 return E_OUTOFMEMORY;
618 memcpy(title_buf, L"VBScript", sizeof(L"VBScript"));
619 ptr = title_buf + ARRAY_SIZE(L"VBScript")-1;
621 *ptr++ = ':';
622 *ptr++ = ' ';
623 lstrcpyW(ptr, orig_title);
624 }else {
625 title = L"VBScript";
627 }else {
628 title = orig_title ? orig_title : L"";
631 hres = IActiveScriptSiteWindow_GetWindow(acts_window, &hwnd);
632 if(SUCCEEDED(hres)) {
633 hres = IActiveScriptSiteWindow_EnableModeless(acts_window, FALSE);
634 if(SUCCEEDED(hres)) {
635 ret = MessageBoxW(hwnd, prompt, title, type);
636 hres = IActiveScriptSiteWindow_EnableModeless(acts_window, TRUE);
640 free(title_buf);
641 IActiveScriptSiteWindow_Release(acts_window);
642 if(FAILED(hres)) {
643 FIXME("failed: %08lx\n", hres);
644 return hres;
647 return return_short(res, ret);
650 static HRESULT Global_CCur(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
652 VARIANT v;
653 HRESULT hres;
655 TRACE("%s\n", debugstr_variant(arg));
657 assert(args_cnt == 1);
659 V_VT(&v) = VT_EMPTY;
660 hres = VariantChangeType(&v, arg, 0, VT_CY);
661 if(FAILED(hres))
662 return hres;
664 if(!res) {
665 VariantClear(&v);
666 return DISP_E_BADVARTYPE;
669 *res = v;
670 return S_OK;
673 static HRESULT Global_CInt(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
675 VARIANT v;
676 HRESULT hres;
678 TRACE("%s\n", debugstr_variant(arg));
680 assert(args_cnt == 1);
682 V_VT(&v) = VT_EMPTY;
683 hres = VariantChangeType(&v, arg, 0, VT_I2);
684 if(FAILED(hres))
685 return hres;
687 if(!res)
688 return DISP_E_BADVARTYPE;
689 else {
690 *res = v;
691 return S_OK;
695 static HRESULT Global_CLng(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
697 int i;
698 HRESULT hres;
700 TRACE("%s\n", debugstr_variant(arg));
702 assert(args_cnt == 1);
704 hres = to_int(arg, &i);
705 if(FAILED(hres))
706 return hres;
707 if(!res)
708 return DISP_E_BADVARTYPE;
710 return return_int(res, i);
713 static HRESULT Global_CBool(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
715 VARIANT v;
716 HRESULT hres;
718 TRACE("%s\n", debugstr_variant(arg));
720 assert(args_cnt == 1);
722 V_VT(&v) = VT_EMPTY;
723 hres = VariantChangeType(&v, arg, VARIANT_LOCALBOOL, VT_BOOL);
724 if(FAILED(hres))
725 return hres;
727 if(res)
728 *res = v;
729 else
730 VariantClear(&v);
731 return S_OK;
734 static HRESULT Global_CByte(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
736 VARIANT v;
737 HRESULT hres;
739 TRACE("%s\n", debugstr_variant(arg));
741 assert(args_cnt == 1);
743 V_VT(&v) = VT_EMPTY;
744 hres = VariantChangeType(&v, arg, VARIANT_LOCALBOOL, VT_UI1);
745 if(FAILED(hres))
746 return hres;
748 if(!res) {
749 VariantClear(&v);
750 return DISP_E_BADVARTYPE;
753 *res = v;
754 return S_OK;
757 static HRESULT Global_CDate(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
759 VARIANT v;
760 HRESULT hres;
762 TRACE("%s\n", debugstr_variant(arg));
764 assert(args_cnt == 1);
766 if(V_VT(arg) == VT_NULL)
767 return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE);
769 V_VT(&v) = VT_EMPTY;
770 hres = VariantChangeType(&v, arg, 0, VT_DATE);
771 if(FAILED(hres)) {
772 hres = VariantChangeType(&v, arg, 0, VT_R8);
773 if(FAILED(hres))
774 return hres;
775 hres = VariantChangeType(&v, &v, 0, VT_DATE);
776 if(FAILED(hres))
777 return hres;
780 if(!res)
781 return DISP_E_BADVARTYPE;
782 *res = v;
783 return S_OK;
786 static HRESULT Global_CDbl(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
788 VARIANT v;
789 HRESULT hres;
791 TRACE("%s\n", debugstr_variant(arg));
793 assert(args_cnt == 1);
795 V_VT(&v) = VT_EMPTY;
796 hres = VariantChangeType(&v, arg, 0, VT_R8);
797 if(FAILED(hres))
798 return hres;
800 if(!res)
801 return DISP_E_BADVARTYPE;
802 else {
803 *res = v;
804 return S_OK;
808 static HRESULT Global_CSng(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
810 VARIANT v;
811 HRESULT hres;
813 TRACE("%s\n", debugstr_variant(arg));
815 assert(args_cnt == 1);
817 V_VT(&v) = VT_EMPTY;
818 hres = VariantChangeType(&v, arg, 0, VT_R4);
819 if(FAILED(hres))
820 return hres;
822 if(!res)
823 return DISP_E_BADVARTYPE;
825 *res = v;
826 return S_OK;
829 static HRESULT Global_CStr(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
831 BSTR str;
832 HRESULT hres;
834 TRACE("%s\n", debugstr_variant(arg));
836 if(V_VT(arg) == VT_NULL)
837 return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE);
839 hres = to_string(arg, &str);
840 if(FAILED(hres))
841 return hres;
843 return return_bstr(res, str);
846 static inline WCHAR hex_char(unsigned n)
848 return n < 10 ? '0'+n : 'A'+n-10;
851 static HRESULT Global_Hex(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
853 WCHAR buf[17], *ptr;
854 DWORD n;
855 HRESULT hres;
856 int ret;
858 TRACE("%s\n", debugstr_variant(arg));
860 switch(V_VT(arg)) {
861 case VT_I2:
862 n = (WORD)V_I2(arg);
863 break;
864 case VT_NULL:
865 return return_null(res);
866 default:
867 hres = to_int(arg, &ret);
868 if(FAILED(hres))
869 return hres;
870 else
871 n = ret;
874 buf[16] = 0;
875 ptr = buf+15;
877 if(n) {
878 do {
879 *ptr-- = hex_char(n & 0xf);
880 n >>= 4;
881 }while(n);
882 ptr++;
883 }else {
884 *ptr = '0';
887 return return_string(res, ptr);
890 static HRESULT Global_Oct(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
892 HRESULT hres;
893 WCHAR buf[23], *ptr;
894 DWORD n;
895 int ret;
897 TRACE("%s\n", debugstr_variant(arg));
899 switch(V_VT(arg)) {
900 case VT_I2:
901 n = (WORD)V_I2(arg);
902 break;
903 case VT_NULL:
904 return return_null(res);
905 default:
906 hres = to_int(arg, &ret);
907 if(FAILED(hres))
908 return hres;
909 else
910 n = ret;
913 buf[22] = 0;
914 ptr = buf + 21;
916 if(n) {
917 do {
918 *ptr-- = '0' + (n & 0x7);
919 n >>= 3;
920 }while(n);
921 ptr++;
922 }else {
923 *ptr = '0';
926 return return_string(res, ptr);
929 static HRESULT Global_VarType(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
931 VARTYPE vt;
933 TRACE("(%s)\n", debugstr_variant(arg));
935 assert(args_cnt == 1);
937 vt = V_VT(arg) & ~VT_BYREF;
938 if(vt & ~(VT_TYPEMASK | VT_ARRAY)) {
939 FIXME("not supported %s\n", debugstr_variant(arg));
940 return E_NOTIMPL;
943 return return_short(res, vt);
946 static HRESULT Global_IsDate(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
948 TRACE("%s\n", debugstr_variant(arg));
950 return return_bool(res, V_VT(arg) == VT_DATE);
953 static HRESULT Global_IsEmpty(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
955 TRACE("(%s)\n", debugstr_variant(arg));
957 assert(args_cnt == 1);
958 return return_bool(res, V_VT(arg) == VT_EMPTY);
961 static HRESULT Global_IsNull(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
963 TRACE("(%s)\n", debugstr_variant(arg));
965 assert(args_cnt == 1);
967 return return_bool(res, V_VT(arg) == VT_NULL);
970 static HRESULT Global_IsNumeric(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
972 HRESULT hres;
973 double d;
975 TRACE("(%s)\n", debugstr_variant(arg));
977 assert(args_cnt == 1);
979 hres = to_double(arg, &d);
981 return return_bool(res, SUCCEEDED(hres));
984 static HRESULT Global_IsArray(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
986 TRACE("(%s)\n", debugstr_variant(arg));
988 assert(args_cnt == 1);
990 return return_bool(res, V_ISARRAY(arg));
993 static HRESULT Global_IsObject(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
995 TRACE("(%s)\n", debugstr_variant(arg));
997 assert(args_cnt == 1);
999 return return_bool(res, V_VT(arg) == VT_DISPATCH);
1002 static HRESULT Global_Atn(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1004 HRESULT hres;
1005 double d;
1007 hres = to_double(arg, &d);
1008 if(FAILED(hres))
1009 return hres;
1011 return return_double(res, atan(d));
1014 static HRESULT Global_Cos(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1016 HRESULT hres;
1017 double d;
1019 hres = to_double(arg, &d);
1020 if(FAILED(hres))
1021 return hres;
1023 return return_double(res, cos(d));
1026 static HRESULT Global_Sin(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1028 HRESULT hres;
1029 double d;
1031 hres = to_double(arg, &d);
1032 if(FAILED(hres))
1033 return hres;
1035 return return_double(res, sin(d));
1038 static HRESULT Global_Tan(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1040 HRESULT hres;
1041 double d;
1043 hres = to_double(arg, &d);
1044 if(FAILED(hres))
1045 return hres;
1047 return return_double(res, tan(d));
1050 static HRESULT Global_Exp(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1052 HRESULT hres;
1053 double d;
1055 hres = to_double(arg, &d);
1056 if(FAILED(hres))
1057 return hres;
1059 return return_double(res, exp(d));
1062 static HRESULT Global_Log(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1064 HRESULT hres;
1065 double d;
1067 hres = to_double(arg, &d);
1068 if(FAILED(hres))
1069 return hres;
1071 if(d <= 0)
1072 return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
1073 else
1074 return return_double(res, log(d));
1077 static HRESULT Global_Sqr(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1079 HRESULT hres;
1080 double d;
1082 hres = to_double(arg, &d);
1083 if(FAILED(hres))
1084 return hres;
1086 if(d < 0)
1087 return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
1088 else
1089 return return_double(res, sqrt(d));
1092 static unsigned int get_next_rnd(int value)
1094 return (value * 0x43fd43fd + 0xc39ec3) & 0xffffff;
1097 static HRESULT Global_Randomize(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1099 union
1101 double d;
1102 unsigned int i[2];
1103 } dtoi;
1104 unsigned int seed;
1105 HRESULT hres;
1107 assert(args_cnt == 0 || args_cnt == 1);
1108 if (args_cnt == 1) {
1109 hres = to_double(arg, &dtoi.d);
1110 if (FAILED(hres))
1111 return hres;
1113 else
1114 dtoi.d = GetTickCount() * 0.001;
1116 seed = dtoi.i[1];
1117 seed ^= (seed >> 16);
1118 seed = ((seed & 0xffff) << 8) | (This->ctx->script_obj->rnd & 0xff);
1119 This->ctx->script_obj->rnd = seed;
1121 return res ? DISP_E_TYPEMISMATCH : S_OK;
1124 static HRESULT Global_Rnd(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1126 static const float modulus = 16777216.0f;
1127 unsigned int value;
1128 HRESULT hres;
1129 float f;
1131 assert(args_cnt == 0 || args_cnt == 1);
1133 value = This->ctx->script_obj->rnd;
1134 if (args_cnt == 1)
1136 hres = to_float(arg, &f);
1137 if (FAILED(hres))
1138 return hres;
1140 if (f < 0.0f)
1142 value = *(unsigned int *)&f;
1143 This->ctx->script_obj->rnd = value = get_next_rnd(value + (value >> 24));
1145 else if (f == 0.0f)
1146 value = This->ctx->script_obj->rnd;
1147 else
1148 This->ctx->script_obj->rnd = value = get_next_rnd(value);
1150 else
1152 This->ctx->script_obj->rnd = value = get_next_rnd(value);
1155 return return_float(res, (float)value / modulus);
1158 static HRESULT Global_Timer(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1160 SYSTEMTIME lt;
1161 double sec;
1163 GetLocalTime(&lt);
1164 sec = lt.wHour * 3600 + lt.wMinute * 60 + lt.wSecond + lt.wMilliseconds / 1000.0;
1165 return return_float(res, sec);
1169 static HRESULT Global_LBound(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1171 SAFEARRAY *sa;
1172 HRESULT hres;
1173 LONG lbound;
1174 int dim;
1176 assert(args_cnt == 1 || args_cnt == 2);
1178 TRACE("%s %s\n", debugstr_variant(arg), args_cnt == 2 ? debugstr_variant(arg + 1) : "1");
1180 switch(V_VT(arg)) {
1181 case VT_VARIANT|VT_ARRAY:
1182 sa = V_ARRAY(arg);
1183 break;
1184 case VT_VARIANT|VT_ARRAY|VT_BYREF:
1185 sa = *V_ARRAYREF(arg);
1186 break;
1187 case VT_EMPTY:
1188 case VT_NULL:
1189 return MAKE_VBSERROR(VBSE_TYPE_MISMATCH);
1190 default:
1191 FIXME("arg %s not supported\n", debugstr_variant(arg));
1192 return E_NOTIMPL;
1195 if(args_cnt == 2) {
1196 hres = to_int(arg + 1, &dim);
1197 if(FAILED(hres))
1198 return hres;
1199 }else {
1200 dim = 1;
1203 hres = SafeArrayGetLBound(sa, dim, &lbound);
1204 if(FAILED(hres))
1205 return hres;
1207 return return_int(res, lbound);
1210 static HRESULT Global_UBound(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1212 SAFEARRAY *sa;
1213 HRESULT hres;
1214 LONG ubound;
1215 int dim;
1217 assert(args_cnt == 1 || args_cnt == 2);
1219 TRACE("%s %s\n", debugstr_variant(arg), args_cnt == 2 ? debugstr_variant(arg + 1) : "1");
1221 switch(V_VT(arg)) {
1222 case VT_VARIANT|VT_ARRAY:
1223 sa = V_ARRAY(arg);
1224 break;
1225 case VT_VARIANT|VT_ARRAY|VT_BYREF:
1226 sa = *V_ARRAYREF(arg);
1227 break;
1228 case VT_EMPTY:
1229 case VT_NULL:
1230 return MAKE_VBSERROR(VBSE_TYPE_MISMATCH);
1231 default:
1232 FIXME("arg %s not supported\n", debugstr_variant(arg));
1233 return E_NOTIMPL;
1236 if(args_cnt == 2) {
1237 hres = to_int(arg + 1, &dim);
1238 if(FAILED(hres))
1239 return hres;
1240 }else {
1241 dim = 1;
1244 hres = SafeArrayGetUBound(sa, dim, &ubound);
1245 if(FAILED(hres))
1246 return hres;
1248 return return_int(res, ubound);
1251 static HRESULT Global_RGB(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1253 HRESULT hres;
1254 int i, color[3];
1256 TRACE("%s %s %s\n", debugstr_variant(arg), debugstr_variant(arg + 1), debugstr_variant(arg + 2));
1258 assert(args_cnt == 3);
1260 for(i = 0; i < 3; i++) {
1261 hres = to_int(arg + i, color + i);
1262 if(FAILED(hres))
1263 return hres;
1264 if(color[i] > 255)
1265 color[i] = 255;
1266 if(color[i] < 0)
1267 return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
1270 return return_int(res, RGB(color[0], color[1], color[2]));
1273 static HRESULT Global_Len(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1275 DWORD len;
1276 HRESULT hres;
1278 TRACE("%s\n", debugstr_variant(arg));
1280 if(V_VT(arg) == VT_NULL)
1281 return return_null(res);
1283 if(V_VT(arg) != VT_BSTR) {
1284 BSTR str;
1286 hres = to_string(arg, &str);
1287 if(FAILED(hres))
1288 return hres;
1290 len = SysStringLen(str);
1291 SysFreeString(str);
1292 }else {
1293 len = SysStringLen(V_BSTR(arg));
1296 return return_int(res, len);
1299 static HRESULT Global_LenB(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1301 FIXME("\n");
1302 return E_NOTIMPL;
1305 static HRESULT Global_Left(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
1307 BSTR str, ret, conv_str = NULL;
1308 int len, str_len;
1309 HRESULT hres;
1311 TRACE("(%s %s)\n", debugstr_variant(args+1), debugstr_variant(args));
1313 if(V_VT(args) == VT_BSTR) {
1314 str = V_BSTR(args);
1315 }else {
1316 hres = to_string(args, &conv_str);
1317 if(FAILED(hres))
1318 return hres;
1319 str = conv_str;
1322 hres = to_int(args+1, &len);
1323 if(FAILED(hres))
1324 return hres;
1326 if(len < 0) {
1327 FIXME("len = %d\n", len);
1328 return E_FAIL;
1331 str_len = SysStringLen(str);
1332 if(len > str_len)
1333 len = str_len;
1335 ret = SysAllocStringLen(str, len);
1336 SysFreeString(conv_str);
1337 if(!ret)
1338 return E_OUTOFMEMORY;
1340 return return_bstr(res, ret);
1343 static HRESULT Global_LeftB(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1345 FIXME("\n");
1346 return E_NOTIMPL;
1349 static HRESULT Global_Right(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
1351 BSTR str, ret, conv_str = NULL;
1352 int len, str_len;
1353 HRESULT hres;
1355 TRACE("(%s %s)\n", debugstr_variant(args), debugstr_variant(args+1));
1357 if(V_VT(args+1) == VT_NULL)
1358 return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE);
1360 hres = to_int(args+1, &len);
1361 if(FAILED(hres))
1362 return hres;
1364 if(len < 0)
1365 return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
1367 if(V_VT(args) == VT_NULL)
1368 return return_null(res);
1370 if(V_VT(args) == VT_BSTR) {
1371 str = V_BSTR(args);
1372 }else {
1373 hres = to_string(args, &conv_str);
1374 if(FAILED(hres))
1375 return hres;
1376 str = conv_str;
1379 str_len = SysStringLen(str);
1380 if(len > str_len)
1381 len = str_len;
1383 ret = SysAllocStringLen(str+str_len-len, len);
1384 SysFreeString(conv_str);
1385 if(!ret)
1386 return E_OUTOFMEMORY;
1388 return return_bstr(res, ret);
1391 static HRESULT Global_RightB(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1393 FIXME("\n");
1394 return E_NOTIMPL;
1397 static HRESULT Global_Mid(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
1399 int len = -1, start, str_len;
1400 BSTR str, conv_str = NULL;
1401 HRESULT hres;
1403 TRACE("(%s %s ...)\n", debugstr_variant(args), debugstr_variant(args+1));
1405 assert(args_cnt == 2 || args_cnt == 3);
1407 if(V_VT(args) == VT_EMPTY)
1408 return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
1410 if(V_VT(args+1) == VT_NULL || (args_cnt == 3 && V_VT(args+2) == VT_NULL))
1411 return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE);
1413 if(V_VT(args+1) == VT_EMPTY)
1414 return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
1416 hres = to_int(args+1, &start);
1417 if(FAILED(hres))
1418 return hres;
1420 if(start < 0)
1421 return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
1423 if(args_cnt == 3) {
1424 if(V_VT(args+2) == VT_EMPTY)
1425 return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
1427 hres = to_int(args+2, &len);
1428 if(FAILED(hres))
1429 return hres;
1431 if(len < 0)
1432 return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
1435 if(V_VT(args) == VT_BSTR) {
1436 str = V_BSTR(args);
1437 }else {
1438 hres = to_string(args, &conv_str);
1439 if(FAILED(hres))
1440 return hres;
1441 str = conv_str;
1444 str_len = SysStringLen(str);
1445 start--;
1446 if(start > str_len)
1447 start = str_len;
1449 if(len == -1)
1450 len = str_len-start;
1451 else if(len > str_len-start)
1452 len = str_len-start;
1454 if(res) {
1455 V_VT(res) = VT_BSTR;
1456 V_BSTR(res) = SysAllocStringLen(str+start, len);
1457 if(!V_BSTR(res))
1458 hres = E_OUTOFMEMORY;
1461 SysFreeString(conv_str);
1463 return hres;
1466 static HRESULT Global_MidB(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1468 FIXME("\n");
1469 return E_NOTIMPL;
1472 static HRESULT Global_StrComp(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
1474 BSTR left, right;
1475 int mode, ret;
1476 HRESULT hres;
1477 short val;
1479 TRACE("(%s %s ...)\n", debugstr_variant(args), debugstr_variant(args+1));
1481 assert(args_cnt == 2 || args_cnt == 3);
1483 if (args_cnt == 3) {
1484 hres = to_int(args+2, &mode);
1485 if(FAILED(hres))
1486 return hres;
1488 if (mode != 0 && mode != 1) {
1489 FIXME("unknown compare mode = %d\n", mode);
1490 return E_FAIL;
1493 else
1494 mode = 0;
1496 hres = to_string(args, &left);
1497 if(FAILED(hres))
1498 return hres;
1500 hres = to_string(args+1, &right);
1501 if(FAILED(hres))
1503 SysFreeString(left);
1504 return hres;
1507 ret = mode ? wcsicmp(left, right) : wcscmp(left, right);
1508 val = ret < 0 ? -1 : (ret > 0 ? 1 : 0);
1510 SysFreeString(left);
1511 SysFreeString(right);
1512 return return_short(res, val);
1515 static HRESULT Global_LCase(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1517 BSTR str;
1518 HRESULT hres;
1520 TRACE("%s\n", debugstr_variant(arg));
1522 if(V_VT(arg) == VT_NULL) {
1523 return return_null(res);
1526 hres = to_string(arg, &str);
1527 if(FAILED(hres))
1528 return hres;
1530 if(res) {
1531 WCHAR *ptr;
1533 for(ptr = str; *ptr; ptr++)
1534 *ptr = towlower(*ptr);
1536 V_VT(res) = VT_BSTR;
1537 V_BSTR(res) = str;
1538 }else {
1539 SysFreeString(str);
1541 return S_OK;
1544 static HRESULT Global_UCase(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1546 BSTR str;
1547 HRESULT hres;
1549 TRACE("%s\n", debugstr_variant(arg));
1551 if(V_VT(arg) == VT_NULL) {
1552 return return_null(res);
1555 hres = to_string(arg, &str);
1556 if(FAILED(hres))
1557 return hres;
1559 if(res) {
1560 WCHAR *ptr;
1562 for(ptr = str; *ptr; ptr++)
1563 *ptr = towupper(*ptr);
1565 V_VT(res) = VT_BSTR;
1566 V_BSTR(res) = str;
1567 }else {
1568 SysFreeString(str);
1570 return S_OK;
1573 static HRESULT Global_LTrim(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1575 BSTR str, conv_str = NULL;
1576 WCHAR *ptr;
1577 HRESULT hres;
1579 TRACE("%s\n", debugstr_variant(arg));
1581 if(V_VT(arg) == VT_BSTR) {
1582 str = V_BSTR(arg);
1583 }else {
1584 hres = to_string(arg, &conv_str);
1585 if(FAILED(hres))
1586 return hres;
1587 str = conv_str;
1590 for(ptr = str; *ptr && iswspace(*ptr); ptr++);
1592 str = SysAllocString(ptr);
1593 SysFreeString(conv_str);
1594 if(!str)
1595 return E_OUTOFMEMORY;
1597 return return_bstr(res, str);
1600 static HRESULT Global_RTrim(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1602 BSTR str, conv_str = NULL;
1603 WCHAR *ptr;
1604 HRESULT hres;
1606 TRACE("%s\n", debugstr_variant(arg));
1608 if(V_VT(arg) == VT_BSTR) {
1609 str = V_BSTR(arg);
1610 }else {
1611 hres = to_string(arg, &conv_str);
1612 if(FAILED(hres))
1613 return hres;
1614 str = conv_str;
1617 for(ptr = str+SysStringLen(str); ptr-1 > str && iswspace(*(ptr-1)); ptr--);
1619 str = SysAllocStringLen(str, ptr-str);
1620 SysFreeString(conv_str);
1621 if(!str)
1622 return E_OUTOFMEMORY;
1624 return return_bstr(res, str);
1627 static HRESULT Global_Trim(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1629 BSTR str, conv_str = NULL;
1630 WCHAR *begin_ptr, *end_ptr;
1631 HRESULT hres;
1633 TRACE("%s\n", debugstr_variant(arg));
1635 if(V_VT(arg) == VT_BSTR) {
1636 str = V_BSTR(arg);
1637 }else {
1638 hres = to_string(arg, &conv_str);
1639 if(FAILED(hres))
1640 return hres;
1641 str = conv_str;
1644 for(begin_ptr = str; *begin_ptr && iswspace(*begin_ptr); begin_ptr++);
1645 for(end_ptr = str+SysStringLen(str); end_ptr-1 > begin_ptr && iswspace(*(end_ptr-1)); end_ptr--);
1647 str = SysAllocStringLen(begin_ptr, end_ptr-begin_ptr);
1648 SysFreeString(conv_str);
1649 if(!str)
1650 return E_OUTOFMEMORY;
1652 return return_bstr(res, str);
1655 static HRESULT Global_Space(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1657 BSTR str;
1658 int n, i;
1659 HRESULT hres;
1661 TRACE("%s\n", debugstr_variant(arg));
1663 assert(args_cnt == 1);
1665 if(V_VT(arg) == VT_NULL)
1666 return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE);
1668 hres = to_int(arg, &n);
1669 if(FAILED(hres))
1670 return hres;
1672 if(n < 0)
1673 return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
1675 if(!res)
1676 return S_OK;
1678 str = SysAllocStringLen(NULL, n);
1679 if(!str)
1680 return E_OUTOFMEMORY;
1682 for(i=0; i<n; i++)
1683 str[i] = ' ';
1685 V_VT(res) = VT_BSTR;
1686 V_BSTR(res) = str;
1687 return S_OK;
1690 static HRESULT Global_String(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
1692 WCHAR ch;
1693 int cnt;
1694 HRESULT hres;
1696 TRACE("%s %s\n", debugstr_variant(args), debugstr_variant(args + 1));
1698 hres = to_int(args, &cnt);
1699 if(FAILED(hres))
1700 return hres;
1701 if(cnt < 0)
1702 return E_INVALIDARG;
1704 if(V_VT(args + 1) != VT_BSTR) {
1705 FIXME("Unsupported argument %s\n", debugstr_variant(args+1));
1706 return E_NOTIMPL;
1708 if(!SysStringLen(V_BSTR(args + 1)))
1709 return E_INVALIDARG;
1710 ch = V_BSTR(args + 1)[0];
1712 if(res) {
1713 BSTR str = SysAllocStringLen(NULL, cnt);
1714 if(!str)
1715 return E_OUTOFMEMORY;
1716 wmemset(str, ch, cnt);
1717 V_VT(res) = VT_BSTR;
1718 V_BSTR(res) = str;
1720 return S_OK;
1723 static HRESULT Global_InStr(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
1725 VARIANT *startv, *str1v, *str2v;
1726 BSTR str1, str2;
1727 int ret = -1, start = 0, mode = 0;
1728 HRESULT hres;
1730 TRACE("args_cnt=%u\n", args_cnt);
1732 assert(2 <= args_cnt && args_cnt <= 4);
1734 switch(args_cnt) {
1735 case 2:
1736 startv = NULL;
1737 str1v = args;
1738 str2v = args+1;
1739 break;
1740 case 3:
1741 startv = args;
1742 str1v = args+1;
1743 str2v = args+2;
1744 break;
1745 case 4:
1746 startv = args;
1747 str1v = args+1;
1748 str2v = args+2;
1750 if(V_VT(args+3) == VT_NULL)
1751 return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE);
1753 hres = to_int(args+3, &mode);
1754 if(FAILED(hres))
1755 return hres;
1757 if (mode != 0 && mode != 1)
1758 return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
1760 break;
1761 DEFAULT_UNREACHABLE;
1764 if(startv) {
1765 if(V_VT(startv) == VT_NULL)
1766 return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE);
1768 hres = to_int(startv, &start);
1769 if(FAILED(hres))
1770 return hres;
1771 if(--start < 0)
1772 return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
1775 if(V_VT(str1v) == VT_NULL || V_VT(str2v) == VT_NULL)
1776 return return_null(res);
1778 if(V_VT(str1v) != VT_BSTR) {
1779 hres = to_string(str1v, &str1);
1780 if(FAILED(hres))
1781 return hres;
1783 else
1784 str1 = V_BSTR(str1v);
1786 if(V_VT(str2v) != VT_BSTR) {
1787 hres = to_string(str2v, &str2);
1788 if(FAILED(hres)){
1789 if(V_VT(str1v) != VT_BSTR)
1790 SysFreeString(str1);
1791 return hres;
1794 else
1795 str2 = V_BSTR(str2v);
1797 if(start < SysStringLen(str1)) {
1798 ret = FindStringOrdinal(FIND_FROMSTART, str1 + start, SysStringLen(str1)-start,
1799 str2, SysStringLen(str2), mode);
1802 if(V_VT(str1v) != VT_BSTR)
1803 SysFreeString(str1);
1804 if(V_VT(str2v) != VT_BSTR)
1805 SysFreeString(str2);
1806 return return_int(res, ++ret ? ret+start : 0);
1809 static HRESULT Global_InStrB(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1811 FIXME("\n");
1812 return E_NOTIMPL;
1815 static HRESULT Global_AscB(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1817 FIXME("\n");
1818 return E_NOTIMPL;
1821 static HRESULT Global_ChrB(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1823 FIXME("\n");
1824 return E_NOTIMPL;
1827 static HRESULT Global_Asc(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1829 BSTR conv_str = NULL, str;
1830 HRESULT hres = S_OK;
1832 TRACE("(%s)\n", debugstr_variant(arg));
1834 switch(V_VT(arg)) {
1835 case VT_NULL:
1836 return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE);
1837 case VT_EMPTY:
1838 return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
1839 case VT_BSTR:
1840 str = V_BSTR(arg);
1841 break;
1842 default:
1843 hres = to_string(arg, &conv_str);
1844 if(FAILED(hres))
1845 return hres;
1846 str = conv_str;
1849 if(!SysStringLen(str))
1850 hres = MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
1851 else if (This->ctx->codepage == CP_UTF8)
1852 hres = return_short(res, *str);
1853 else {
1854 unsigned char buf[2];
1855 short val = 0;
1856 int n = WideCharToMultiByte(This->ctx->codepage, 0, str, 1, (char*)buf, sizeof(buf), NULL, NULL);
1857 switch(n) {
1858 case 1:
1859 val = buf[0];
1860 break;
1861 case 2:
1862 val = (buf[0] << 8) | buf[1];
1863 break;
1864 default:
1865 WARN("Failed to convert %x\n", *str);
1866 hres = MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
1868 if(SUCCEEDED(hres))
1869 hres = return_short(res, val);
1872 SysFreeString(conv_str);
1873 return hres;
1876 static HRESULT Global_Chr(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1878 int cp, c, len = 0;
1879 CPINFO cpi;
1880 WCHAR ch;
1881 char buf[2];
1882 HRESULT hres;
1884 TRACE("%s\n", debugstr_variant(arg));
1886 hres = to_int(arg, &c);
1887 if(FAILED(hres))
1888 return hres;
1890 cp = This->ctx->codepage;
1891 if(!GetCPInfo(cp, &cpi))
1892 cpi.MaxCharSize = 1;
1894 if((c!=(short)c && c!=(unsigned short)c) ||
1895 (unsigned short)c>=(cpi.MaxCharSize>1 ? 0x10000 : 0x100)) {
1896 WARN("invalid arg %d\n", c);
1897 return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
1900 if (cp == CP_UTF8)
1902 ch = c;
1904 else
1906 if(c>>8)
1907 buf[len++] = c>>8;
1908 if(!len || IsDBCSLeadByteEx(cp, buf[0]))
1909 buf[len++] = c;
1910 if(!MultiByteToWideChar(cp, 0, buf, len, &ch, 1)) {
1911 WARN("invalid arg %d, cp %d\n", c, cp);
1912 return E_FAIL;
1916 if(res) {
1917 V_VT(res) = VT_BSTR;
1918 V_BSTR(res) = SysAllocStringLen(&ch, 1);
1919 if(!V_BSTR(res))
1920 return E_OUTOFMEMORY;
1922 return S_OK;
1925 static HRESULT Global_AscW(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1927 FIXME("\n");
1928 return E_NOTIMPL;
1931 static HRESULT Global_ChrW(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1933 FIXME("\n");
1934 return E_NOTIMPL;
1937 static HRESULT Global_Abs(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1939 HRESULT hres;
1940 VARIANT dst;
1942 TRACE("(%s)\n", debugstr_variant(arg));
1944 assert(args_cnt == 1);
1946 hres = VarAbs(arg, &dst);
1947 if(FAILED(hres))
1948 return hres;
1950 if (res)
1951 *res = dst;
1952 else
1953 VariantClear(&dst);
1955 return S_OK;
1958 static HRESULT Global_Fix(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1960 HRESULT hres;
1961 VARIANT dst;
1963 TRACE("(%s)\n", debugstr_variant(arg));
1965 assert(args_cnt == 1);
1967 hres = VarFix(arg, &dst);
1968 if(FAILED(hres))
1969 return hres;
1971 if (res)
1972 *res = dst;
1973 else
1974 VariantClear(&dst);
1976 return S_OK;
1979 static HRESULT Global_Int(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
1981 HRESULT hres;
1982 VARIANT dst;
1984 TRACE("(%s)\n", debugstr_variant(arg));
1986 assert(args_cnt == 1);
1988 hres = VarInt(arg, &dst);
1989 if(FAILED(hres))
1990 return hres;
1992 if (res)
1993 *res = dst;
1994 else
1995 VariantClear(&dst);
1997 return S_OK;
2000 static HRESULT Global_Sgn(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2002 double v;
2003 short val;
2004 HRESULT hres;
2006 TRACE("(%s)\n", debugstr_variant(arg));
2008 assert(args_cnt == 1);
2010 if(V_VT(arg) == VT_NULL)
2011 return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE);
2013 hres = to_double(arg, &v);
2014 if (FAILED(hres))
2015 return hres;
2017 val = v == 0 ? 0 : (v > 0 ? 1 : -1);
2018 return return_short(res, val);
2021 static HRESULT Global_Now(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2023 SYSTEMTIME lt;
2024 double date;
2026 TRACE("\n");
2028 GetLocalTime(&lt);
2029 SystemTimeToVariantTime(&lt, &date);
2030 return return_date(res, date);
2033 static HRESULT Global_Date(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2035 SYSTEMTIME lt;
2036 UDATE ud;
2037 DATE date;
2038 HRESULT hres;
2040 TRACE("\n");
2042 GetLocalTime(&lt);
2043 ud.st = lt;
2044 ud.wDayOfYear = 0;
2045 hres = VarDateFromUdateEx(&ud, 0, VAR_DATEVALUEONLY, &date);
2046 if(FAILED(hres))
2047 return hres;
2048 return return_date(res, date);
2051 static HRESULT Global_Time(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2053 SYSTEMTIME lt;
2054 UDATE ud;
2055 DATE time;
2056 HRESULT hres;
2058 TRACE("\n");
2060 GetLocalTime(&lt);
2061 ud.st = lt;
2062 ud.wDayOfYear = 0;
2063 hres = VarDateFromUdateEx(&ud, 0, VAR_TIMEVALUEONLY, &time);
2064 if(FAILED(hres))
2065 return hres;
2066 return return_date(res, time);
2069 static HRESULT Global_Day(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2071 SYSTEMTIME st;
2072 HRESULT hres;
2074 TRACE("(%s)\n", debugstr_variant(arg));
2076 hres = to_system_time(arg, &st);
2077 return FAILED(hres) ? hres : return_short(res, st.wDay);
2080 static HRESULT Global_Month(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2082 SYSTEMTIME st;
2083 HRESULT hres;
2085 TRACE("(%s)\n", debugstr_variant(arg));
2087 hres = to_system_time(arg, &st);
2088 return FAILED(hres) ? hres : return_short(res, st.wMonth);
2091 static HRESULT Global_Weekday(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
2093 HRESULT hres = S_OK;
2094 int first_day = 0;
2095 SYSTEMTIME st;
2097 TRACE("(%s)\n", debugstr_variant(args));
2099 assert(args_cnt == 1 || args_cnt == 2);
2101 /* [vbSunday = 1, vbSaturday = 7] -> wDayOfWeek [0, 6] */
2102 if (args_cnt == 2)
2104 if (V_VT(args + 1) == VT_NULL)
2105 return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE);
2107 hres = to_int(args + 1, &first_day);
2108 if (SUCCEEDED(hres))
2110 if (!first_day)
2112 /* vbUseSystemDayOfWeek */
2113 GetLocaleInfoW(This->ctx->lcid, LOCALE_RETURN_NUMBER | LOCALE_IFIRSTDAYOFWEEK, (LPWSTR)&first_day,
2114 sizeof(first_day) / sizeof(WCHAR));
2115 first_day = (first_day + 1) % 7;
2117 else if (first_day >= 1 && first_day <= 7)
2119 first_day--;
2121 else
2122 return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
2126 if (FAILED(hres))
2127 return hres;
2129 if (V_VT(args) == VT_NULL)
2130 return return_null(res);
2132 if (FAILED(hres = to_system_time(args, &st))) return hres;
2134 return return_short(res, 1 + (7 - first_day + st.wDayOfWeek) % 7);
2137 static HRESULT Global_Year(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2139 SYSTEMTIME st;
2140 HRESULT hres;
2142 TRACE("(%s)\n", debugstr_variant(arg));
2144 hres = to_system_time(arg, &st);
2145 return FAILED(hres) ? hres : return_short(res, st.wYear);
2148 static HRESULT Global_Hour(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2150 SYSTEMTIME st;
2151 HRESULT hres;
2153 TRACE("(%s)\n", debugstr_variant(arg));
2155 hres = to_system_time(arg, &st);
2156 return FAILED(hres) ? hres : return_short(res, st.wHour);
2159 static HRESULT Global_Minute(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2161 SYSTEMTIME st;
2162 HRESULT hres;
2164 TRACE("(%s)\n", debugstr_variant(arg));
2166 hres = to_system_time(arg, &st);
2167 return FAILED(hres) ? hres : return_short(res, st.wMinute);
2170 static HRESULT Global_Second(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2172 SYSTEMTIME st;
2173 HRESULT hres;
2175 TRACE("(%s)\n", debugstr_variant(arg));
2177 hres = to_system_time(arg, &st);
2178 return FAILED(hres) ? hres : return_short(res, st.wSecond);
2181 static HRESULT Global_SetLocale(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
2183 FIXME("\n");
2184 return E_NOTIMPL;
2187 static HRESULT Global_DateValue(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2189 FIXME("\n");
2190 return E_NOTIMPL;
2193 static HRESULT Global_TimeValue(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2195 FIXME("\n");
2196 return E_NOTIMPL;
2199 static HRESULT Global_DateSerial(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
2201 int year, month, day;
2202 UDATE ud = {{ 0 }};
2203 HRESULT hres;
2204 double date;
2206 TRACE("\n");
2208 assert(args_cnt == 3);
2210 if (V_VT(args) == VT_NULL || V_VT(args + 1) == VT_NULL || V_VT(args + 2) == VT_NULL)
2211 return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE);
2213 hres = to_int(args, &year);
2214 if (SUCCEEDED(hres))
2215 hres = to_int(args + 1, &month);
2216 if (SUCCEEDED(hres))
2217 hres = to_int(args + 2, &day);
2219 if (SUCCEEDED(hres))
2221 ud.st.wYear = year;
2222 ud.st.wMonth = month;
2223 ud.st.wDay = day;
2224 hres = VarDateFromUdateEx(&ud, 0, 0, &date);
2227 if (SUCCEEDED(hres))
2228 hres = return_date(res, date);
2230 return hres;
2233 static HRESULT Global_TimeSerial(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
2235 int hour, minute, second;
2236 UDATE ud = {{ 0 }};
2237 HRESULT hres;
2238 double date;
2240 TRACE("\n");
2242 assert(args_cnt == 3);
2244 if (V_VT(args) == VT_NULL || V_VT(args + 1) == VT_NULL || V_VT(args + 2) == VT_NULL)
2245 return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE);
2247 hres = to_int(args, &hour);
2248 if (SUCCEEDED(hres))
2249 hres = to_int(args + 1, &minute);
2250 if (SUCCEEDED(hres))
2251 hres = to_int(args + 2, &second);
2253 if (SUCCEEDED(hres))
2255 ud.st.wYear = 1899;
2256 ud.st.wMonth = 12;
2257 ud.st.wDay = 30;
2258 ud.st.wHour = hour;
2259 ud.st.wMinute = minute;
2260 ud.st.wSecond = second;
2261 hres = VarDateFromUdateEx(&ud, 0, 0, &date);
2264 if (SUCCEEDED(hres))
2265 hres = return_date(res, date);
2267 return hres;
2270 static HRESULT Global_InputBox(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2272 FIXME("\n");
2273 return E_NOTIMPL;
2276 static HRESULT Global_MsgBox(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
2278 BSTR prompt, title = NULL;
2279 int type = MB_OK;
2280 HRESULT hres;
2282 TRACE("\n");
2284 assert(1 <= args_cnt && args_cnt <= 5);
2286 hres = to_string(args, &prompt);
2287 if(FAILED(hres))
2288 return hres;
2290 if(args_cnt > 1)
2291 hres = to_int(args+1, &type);
2293 if(SUCCEEDED(hres) && args_cnt > 2)
2294 hres = to_string(args+2, &title);
2296 if(SUCCEEDED(hres) && args_cnt > 3) {
2297 FIXME("unsupported arg_cnt %d\n", args_cnt);
2298 hres = E_NOTIMPL;
2301 if(SUCCEEDED(hres))
2302 hres = show_msgbox(This->ctx, prompt, type, title, res);
2304 SysFreeString(prompt);
2305 SysFreeString(title);
2306 return hres;
2309 static HRESULT Global_CreateObject(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2311 IUnknown *obj;
2312 HRESULT hres;
2314 TRACE("(%s)\n", debugstr_variant(arg));
2316 if(V_VT(arg) != VT_BSTR) {
2317 FIXME("non-bstr arg\n");
2318 return E_INVALIDARG;
2321 obj = create_object(This->ctx, V_BSTR(arg));
2322 if(!obj)
2323 return VB_E_CANNOT_CREATE_OBJ;
2325 if(res) {
2326 hres = IUnknown_QueryInterface(obj, &IID_IDispatch, (void**)&V_DISPATCH(res));
2327 if(FAILED(hres))
2328 return hres;
2330 V_VT(res) = VT_DISPATCH;
2333 IUnknown_Release(obj);
2334 return S_OK;
2337 static HRESULT Global_GetObject(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
2339 IBindCtx *bind_ctx;
2340 IUnknown *obj_unk;
2341 IDispatch *disp;
2342 ULONG eaten = 0;
2343 IMoniker *mon;
2344 HRESULT hres;
2346 TRACE("%s %s\n", args_cnt ? debugstr_variant(args) : "", args_cnt > 1 ? debugstr_variant(args+1) : "");
2348 if(args_cnt != 1 || V_VT(args) != VT_BSTR) {
2349 FIXME("unsupported args\n");
2350 return E_NOTIMPL;
2353 if(This->ctx->safeopt & (INTERFACE_USES_SECURITY_MANAGER|INTERFACESAFE_FOR_UNTRUSTED_DATA)) {
2354 WARN("blocked in current safety mode\n");
2355 return VB_E_CANNOT_CREATE_OBJ;
2358 hres = CreateBindCtx(0, &bind_ctx);
2359 if(FAILED(hres))
2360 return hres;
2362 hres = MkParseDisplayName(bind_ctx, V_BSTR(args), &eaten, &mon);
2363 if(SUCCEEDED(hres)) {
2364 hres = IMoniker_BindToObject(mon, bind_ctx, NULL, &IID_IUnknown, (void**)&obj_unk);
2365 IMoniker_Release(mon);
2366 }else {
2367 hres = MK_E_SYNTAX;
2369 IBindCtx_Release(bind_ctx);
2370 if(FAILED(hres))
2371 return hres;
2373 hres = set_object_site(This->ctx, obj_unk);
2374 if(FAILED(hres)) {
2375 IUnknown_Release(obj_unk);
2376 return hres;
2379 hres = IUnknown_QueryInterface(obj_unk, &IID_IDispatch, (void**)&disp);
2380 if(SUCCEEDED(hres)) {
2381 if(res) {
2382 V_VT(res) = VT_DISPATCH;
2383 V_DISPATCH(res) = disp;
2384 }else {
2385 IDispatch_Release(disp);
2387 }else {
2388 FIXME("object does not support IDispatch\n");
2391 return hres;
2394 static HRESULT Global_DateAdd(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
2396 BSTR interval = NULL;
2397 UDATE ud = {{ 0 }};
2398 HRESULT hres;
2399 double date;
2400 int count;
2402 TRACE("\n");
2404 assert(args_cnt == 3);
2406 if (V_VT(args) == VT_NULL || V_VT(args + 1) == VT_NULL)
2407 return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE);
2409 if (V_VT(args + 2) == VT_NULL)
2410 return return_null(res);
2412 hres = to_string(args, &interval);
2413 if (SUCCEEDED(hres))
2414 hres = to_int(args + 1, &count);
2415 if (SUCCEEDED(hres))
2416 hres = to_system_time(args + 2, &ud.st);
2417 if (SUCCEEDED(hres))
2419 if (!wcsicmp(interval, L"yyyy"))
2420 ud.st.wYear += count;
2421 else if (!wcsicmp(interval, L"q"))
2422 ud.st.wMonth += 3 * count;
2423 else if (!wcsicmp(interval, L"m"))
2424 ud.st.wMonth += count;
2425 else if (!wcsicmp(interval, L"y")
2426 || !wcsicmp(interval, L"d")
2427 || !wcsicmp(interval, L"w"))
2429 ud.st.wDay += count;
2431 else if (!wcsicmp(interval, L"ww"))
2432 ud.st.wDay += 7 * count;
2433 else if (!wcsicmp(interval, L"h"))
2434 ud.st.wHour += count;
2435 else if (!wcsicmp(interval, L"n"))
2436 ud.st.wMinute += count;
2437 else if (!wcsicmp(interval, L"s"))
2438 ud.st.wSecond += count;
2439 else
2441 WARN("Unrecognized interval %s.\n", debugstr_w(interval));
2442 hres = MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
2446 SysFreeString(interval);
2448 if (SUCCEEDED(hres))
2449 hres = VarDateFromUdateEx(&ud, 0, 0, &date);
2451 if (SUCCEEDED(hres))
2452 hres = return_date(res, date);
2454 return hres;
2457 static HRESULT Global_DateDiff(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2459 FIXME("\n");
2460 return E_NOTIMPL;
2463 static HRESULT Global_DatePart(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2465 FIXME("\n");
2466 return E_NOTIMPL;
2469 static HRESULT Global_TypeName(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2471 ITypeInfo *typeinfo;
2472 BSTR name = NULL;
2473 HRESULT hres;
2475 TRACE("(%s)\n", debugstr_variant(arg));
2477 assert(args_cnt == 1);
2479 if (V_ISARRAY(arg))
2480 return return_string(res, L"Variant()");
2482 switch(V_VT(arg)) {
2483 case VT_UI1:
2484 return return_string(res, L"Byte");
2485 case VT_I2:
2486 return return_string(res, L"Integer");
2487 case VT_I4:
2488 return return_string(res, L"Long");
2489 case VT_R4:
2490 return return_string(res, L"Single");
2491 case VT_R8:
2492 return return_string(res, L"Double");
2493 case VT_CY:
2494 return return_string(res, L"Currency");
2495 case VT_DECIMAL:
2496 return return_string(res, L"Decimal");
2497 case VT_DATE:
2498 return return_string(res, L"Date");
2499 case VT_BSTR:
2500 return return_string(res, L"String");
2501 case VT_BOOL:
2502 return return_string(res, L"Boolean");
2503 case VT_EMPTY:
2504 return return_string(res, L"Empty");
2505 case VT_NULL:
2506 return return_string(res, L"Null");
2507 case VT_DISPATCH:
2508 if (!V_DISPATCH(arg))
2509 return return_string(res, L"Nothing");
2510 if (SUCCEEDED(IDispatch_GetTypeInfo(V_DISPATCH(arg), 0, GetUserDefaultLCID(), &typeinfo)))
2512 hres = ITypeInfo_GetDocumentation(typeinfo, MEMBERID_NIL, &name, NULL, NULL, NULL);
2513 ITypeInfo_Release(typeinfo);
2515 if (SUCCEEDED(hres) && name && *name)
2516 return return_bstr(res, name);
2518 SysFreeString(name);
2520 return return_string(res, L"Object");
2521 default:
2522 FIXME("arg %s not supported\n", debugstr_variant(arg));
2523 return E_NOTIMPL;
2527 static HRESULT Global_Array(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2529 SAFEARRAYBOUND bounds;
2530 SAFEARRAY *sa;
2531 VARIANT *data;
2532 HRESULT hres;
2533 unsigned i;
2535 TRACE("arg_cnt=%u\n", args_cnt);
2537 bounds.lLbound = 0;
2538 bounds.cElements = args_cnt;
2539 sa = SafeArrayCreate(VT_VARIANT, 1, &bounds);
2540 if(!sa)
2541 return E_OUTOFMEMORY;
2543 hres = SafeArrayAccessData(sa, (void**)&data);
2544 if(FAILED(hres)) {
2545 SafeArrayDestroy(sa);
2546 return hres;
2549 for(i=0; i<args_cnt; i++) {
2550 hres = VariantCopyInd(data+i, arg+i);
2551 if(FAILED(hres)) {
2552 SafeArrayUnaccessData(sa);
2553 SafeArrayDestroy(sa);
2554 return hres;
2557 SafeArrayUnaccessData(sa);
2559 if(res) {
2560 V_VT(res) = VT_ARRAY|VT_VARIANT;
2561 V_ARRAY(res) = sa;
2562 }else {
2563 SafeArrayDestroy(sa);
2566 return S_OK;
2569 static HRESULT Global_Erase(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2571 FIXME("\n");
2572 return E_NOTIMPL;
2575 static HRESULT Global_Filter(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2577 FIXME("\n");
2578 return E_NOTIMPL;
2581 static HRESULT Global_Join(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2583 FIXME("\n");
2584 return E_NOTIMPL;
2587 static HRESULT Global_Split(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
2589 BSTR string, delimiter = NULL;
2590 int count, max, mode, len, start, end, ret, delimiterlen = 1;
2591 int i, *indices = NULL, *new_indices, indices_max = 8;
2592 SAFEARRAYBOUND bounds;
2593 SAFEARRAY *sa = NULL;
2594 VARIANT *data;
2595 HRESULT hres = S_OK;
2597 TRACE("%s %u...\n", debugstr_variant(args), args_cnt);
2599 assert(1 <= args_cnt && args_cnt <= 4);
2601 if(V_VT(args) == VT_NULL || (args_cnt > 1 && V_VT(args+1) == VT_NULL) || (args_cnt > 2 && V_VT(args+2) == VT_NULL)
2602 || (args_cnt == 4 && V_VT(args+3) == VT_NULL))
2603 return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE);
2605 if(V_VT(args) != VT_BSTR) {
2606 hres = to_string(args, &string);
2607 if(FAILED(hres))
2608 return hres;
2609 }else {
2610 string = V_BSTR(args);
2613 if(args_cnt > 1) {
2614 if(V_VT(args+1) != VT_BSTR) {
2615 hres = to_string(args+1, &delimiter);
2616 if(FAILED(hres))
2617 goto error;
2618 }else {
2619 delimiter = V_BSTR(args+1);
2621 delimiterlen = SysStringLen(delimiter);
2624 if(args_cnt > 2) {
2625 hres = to_int(args+2, &max);
2626 if(FAILED(hres))
2627 goto error;
2628 if (max < -1) {
2629 hres = MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
2630 goto error;
2632 }else {
2633 max = -1;
2636 if(args_cnt == 4) {
2637 hres = to_int(args+3, &mode);
2638 if(FAILED(hres))
2639 goto error;
2640 if (mode != 0 && mode != 1) {
2641 hres = MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
2642 goto error;
2644 }else {
2645 mode = 0;
2648 start = 0;
2650 len = SysStringLen(string);
2651 count = 0;
2653 indices = malloc( indices_max * sizeof(int));
2654 if(!indices) {
2655 hres = E_OUTOFMEMORY;
2656 goto error;
2659 while(1) {
2660 ret = -1;
2661 if (delimiterlen) {
2662 ret = FindStringOrdinal(FIND_FROMSTART, string + start, len - start,
2663 delimiter ? delimiter : L" ", delimiterlen, mode);
2666 if (ret == -1) {
2667 end = len;
2668 }else {
2669 end = start + ret;
2672 if (count == indices_max) {
2673 new_indices = realloc(indices, indices_max * 2 * sizeof(int));
2674 if(!new_indices) {
2675 hres = E_OUTOFMEMORY;
2676 goto error;
2678 indices = new_indices;
2679 indices_max *= 2;
2681 indices[count++] = end;
2683 if (ret == -1 || count == max) break;
2684 start = start + ret + delimiterlen;
2685 if (start > len) break;
2688 bounds.lLbound = 0;
2689 bounds.cElements = count;
2690 sa = SafeArrayCreate( VT_VARIANT, 1, &bounds);
2691 if (!sa) {
2692 hres = E_OUTOFMEMORY;
2693 goto error;
2695 hres = SafeArrayAccessData(sa, (void**)&data);
2696 if(FAILED(hres)) {
2697 goto error;
2700 start = 0;
2701 for (i = 0; i < count; i++) {
2702 V_VT(&data[i]) = VT_BSTR;
2703 V_BSTR(&data[i]) = SysAllocStringLen(string + start, indices[i] - start);
2705 if (!V_BSTR(&data[i])) {
2706 hres = E_OUTOFMEMORY;
2707 break;
2709 start = indices[i]+delimiterlen;
2711 SafeArrayUnaccessData(sa);
2713 error:
2714 if(SUCCEEDED(hres) && res) {
2715 V_VT(res) = VT_ARRAY|VT_VARIANT;
2716 V_ARRAY(res) = sa;
2717 }else {
2718 SafeArrayDestroy(sa);
2721 free(indices);
2722 if(V_VT(args) != VT_BSTR)
2723 SysFreeString(string);
2724 if(args_cnt > 1 && V_VT(args+1) != VT_BSTR)
2725 SysFreeString(delimiter);
2726 return hres;
2729 static HRESULT Global_Replace(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
2731 BSTR string, find = NULL, replace = NULL, ret;
2732 int from = 1, cnt = -1, mode = 0;
2733 HRESULT hres = S_OK;
2735 TRACE("%s %s %s %u...\n", debugstr_variant(args), debugstr_variant(args+1), debugstr_variant(args+2), args_cnt);
2737 assert(3 <= args_cnt && args_cnt <= 6);
2739 if(V_VT(args) == VT_NULL || V_VT(args+1) == VT_NULL || (V_VT(args+2) == VT_NULL)
2740 || (args_cnt >= 4 && V_VT(args+3) == VT_NULL) || (args_cnt >= 5 && V_VT(args+4) == VT_NULL)
2741 || (args_cnt == 6 && V_VT(args+5) == VT_NULL))
2742 return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE);
2745 if(V_VT(args) != VT_BSTR) {
2746 hres = to_string(args, &string);
2747 if(FAILED(hres))
2748 return hres;
2749 }else {
2750 string = V_BSTR(args);
2753 if(V_VT(args+1) != VT_BSTR) {
2754 hres = to_string(args+1, &find);
2755 if(FAILED(hres))
2756 goto error;
2757 }else {
2758 find = V_BSTR(args+1);
2761 if(V_VT(args+2) != VT_BSTR) {
2762 hres = to_string(args+2, &replace);
2763 if(FAILED(hres))
2764 goto error;
2765 }else {
2766 replace = V_BSTR(args+2);
2769 if(args_cnt >= 4) {
2770 hres = to_int(args+3, &from);
2771 if(FAILED(hres))
2772 goto error;
2773 if(from < 1) {
2774 hres = E_INVALIDARG;
2775 goto error;
2779 if(args_cnt >= 5) {
2780 hres = to_int(args+4, &cnt);
2781 if(FAILED(hres))
2782 goto error;
2783 if(cnt < -1) {
2784 hres = E_INVALIDARG;
2785 goto error;
2789 if(args_cnt == 6) {
2790 hres = to_int(args+5, &mode);
2791 if(FAILED(hres))
2792 goto error;
2793 if (mode != 0 && mode != 1) {
2794 hres = MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
2795 goto error;
2799 ret = string_replace(string, find, replace, from - 1, cnt, mode);
2800 if(!ret) {
2801 hres = E_OUTOFMEMORY;
2802 }else if(res) {
2803 V_VT(res) = VT_BSTR;
2804 V_BSTR(res) = ret;
2805 }else {
2806 SysFreeString(ret);
2809 error:
2810 if(V_VT(args) != VT_BSTR)
2811 SysFreeString(string);
2812 if(V_VT(args+1) != VT_BSTR)
2813 SysFreeString(find);
2814 if(V_VT(args+2) != VT_BSTR)
2815 SysFreeString(replace);
2816 return hres;
2819 static HRESULT Global_StrReverse(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2821 WCHAR *ptr1, *ptr2, ch;
2822 BSTR ret;
2823 HRESULT hres;
2825 TRACE("%s\n", debugstr_variant(arg));
2827 hres = to_string(arg, &ret);
2828 if(FAILED(hres))
2829 return hres;
2831 ptr1 = ret;
2832 ptr2 = ret + SysStringLen(ret)-1;
2833 while(ptr1 < ptr2) {
2834 ch = *ptr1;
2835 *ptr1++ = *ptr2;
2836 *ptr2-- = ch;
2839 return return_bstr(res, ret);
2842 static HRESULT Global_InStrRev(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
2844 int start = -1, ret = -1, mode = 0;
2845 BSTR str1, str2;
2846 size_t len1, len2;
2847 HRESULT hres;
2849 TRACE("%s %s arg_cnt=%u\n", debugstr_variant(args), debugstr_variant(args+1), args_cnt);
2851 assert(2 <= args_cnt && args_cnt <= 4);
2853 if(V_VT(args) == VT_NULL || V_VT(args+1) == VT_NULL || (args_cnt > 2 && V_VT(args+2) == VT_NULL)
2854 || (args_cnt == 4 && V_VT(args+3) == VT_NULL))
2855 return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE);
2857 if(args_cnt == 4) {
2858 hres = to_int(args+3, &mode);
2859 if(FAILED(hres))
2860 return hres;
2861 if (mode != 0 && mode != 1)
2862 return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
2865 if(args_cnt >= 3) {
2866 hres = to_int(args+2, &start);
2867 if(FAILED(hres))
2868 return hres;
2869 if(!start || start < -1)
2870 return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
2873 if(V_VT(args) != VT_BSTR) {
2874 hres = to_string(args, &str1);
2875 if(FAILED(hres))
2876 return hres;
2878 else
2879 str1 = V_BSTR(args);
2881 if(V_VT(args+1) != VT_BSTR) {
2882 hres = to_string(args+1, &str2);
2883 if(FAILED(hres)) {
2884 if(V_VT(args) != VT_BSTR)
2885 SysFreeString(str1);
2886 return hres;
2889 else
2890 str2 = V_BSTR(args+1);
2892 len1 = SysStringLen(str1);
2893 if(!len1) {
2894 ret = 0;
2895 goto end;
2898 if(start == -1)
2899 start = len1;
2901 len2 = SysStringLen(str2);
2902 if(!len2) {
2903 ret = start;
2904 goto end;
2907 if(start >= len2 && start <= len1) {
2908 ret = FindStringOrdinal(FIND_FROMEND, str1, start,
2909 str2, len2, mode);
2911 ret++;
2913 end:
2914 if(V_VT(args) != VT_BSTR)
2915 SysFreeString(str1);
2916 if(V_VT(args+1) != VT_BSTR)
2917 SysFreeString(str2);
2918 return return_int(res, ret);
2921 static HRESULT Global_LoadPicture(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2923 FIXME("\n");
2924 return E_NOTIMPL;
2927 static HRESULT Global_ScriptEngine(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2929 TRACE("%s\n", debugstr_variant(arg));
2931 assert(args_cnt == 0);
2933 return return_string(res, L"VBScript");
2936 static HRESULT Global_ScriptEngineMajorVersion(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2938 TRACE("%s\n", debugstr_variant(arg));
2940 assert(args_cnt == 0);
2942 return return_int(res, VBSCRIPT_MAJOR_VERSION);
2945 static HRESULT Global_ScriptEngineMinorVersion(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2947 TRACE("%s\n", debugstr_variant(arg));
2949 assert(args_cnt == 0);
2951 return return_int(res, VBSCRIPT_MINOR_VERSION);
2954 static HRESULT Global_ScriptEngineBuildVersion(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
2956 TRACE("%s\n", debugstr_variant(arg));
2958 assert(args_cnt == 0);
2960 return return_int(res, VBSCRIPT_BUILD_VERSION);
2963 static HRESULT Global_FormatNumber(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
2965 union
2967 struct
2969 int num_dig, inc_lead, use_parens, group;
2970 } s;
2971 int val[4];
2972 } int_args = { .s.num_dig = -1, .s.inc_lead = -2, .s.use_parens = -2, .s.group = -2 };
2973 HRESULT hres;
2974 BSTR str;
2975 int i;
2977 TRACE("\n");
2979 assert(1 <= args_cnt && args_cnt <= 5);
2981 for (i = 1; i < args_cnt; ++i)
2983 if (V_VT(args+i) == VT_ERROR) continue;
2984 if (V_VT(args+i) == VT_NULL) return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE);
2985 if (FAILED(hres = to_int(args+i, &int_args.val[i-1]))) return hres;
2988 hres = VarFormatNumber(args, int_args.s.num_dig, int_args.s.inc_lead, int_args.s.use_parens,
2989 int_args.s.group, 0, &str);
2990 if (FAILED(hres)) return hres;
2992 return return_bstr(res, str);
2995 static HRESULT Global_FormatCurrency(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
2997 union
2999 struct
3001 int num_dig, inc_lead, use_parens, group;
3002 } s;
3003 int val[4];
3004 } int_args = { .s.num_dig = -1, .s.inc_lead = -2, .s.use_parens = -2, .s.group = -2 };
3005 HRESULT hres;
3006 BSTR str;
3007 int i;
3009 TRACE("\n");
3011 assert(1 <= args_cnt && args_cnt <= 5);
3013 for (i = 1; i < args_cnt; ++i)
3015 if (V_VT(args+i) == VT_ERROR) continue;
3016 if (V_VT(args+i) == VT_NULL) return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE);
3017 if (FAILED(hres = to_int(args+i, &int_args.val[i-1]))) return hres;
3020 hres = VarFormatCurrency(args, int_args.s.num_dig, int_args.s.inc_lead, int_args.s.use_parens,
3021 int_args.s.group, 0, &str);
3022 if (FAILED(hres)) return hres;
3024 return return_bstr(res, str);
3027 static HRESULT Global_FormatPercent(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
3029 union
3031 struct
3033 int num_dig, inc_lead, use_parens, group;
3034 } s;
3035 int val[4];
3036 } int_args = { .s.num_dig = -1, .s.inc_lead = -2, .s.use_parens = -2, .s.group = -2 };
3037 HRESULT hres;
3038 BSTR str;
3039 int i;
3041 TRACE("\n");
3043 assert(1 <= args_cnt && args_cnt <= 5);
3045 for (i = 1; i < args_cnt; ++i)
3047 if (V_VT(args+i) == VT_ERROR) continue;
3048 if (V_VT(args+i) == VT_NULL) return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE);
3049 if (FAILED(hres = to_int(args+i, &int_args.val[i-1]))) return hres;
3052 hres = VarFormatPercent(args, int_args.s.num_dig, int_args.s.inc_lead, int_args.s.use_parens,
3053 int_args.s.group, 0, &str);
3054 if (FAILED(hres)) return hres;
3056 return return_bstr(res, str);
3059 static HRESULT Global_GetLocale(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
3061 FIXME("\n");
3062 return E_NOTIMPL;
3065 static HRESULT Global_FormatDateTime(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
3067 int format = 0;
3068 HRESULT hres;
3069 BSTR str;
3071 TRACE("\n");
3073 assert(1 <= args_cnt && args_cnt <= 2);
3075 if (V_VT(args) == VT_NULL)
3076 return MAKE_VBSERROR(VBSE_TYPE_MISMATCH);
3078 if (args_cnt == 2)
3080 if (V_VT(args+1) == VT_NULL) return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE);
3081 if (V_VT(args+1) != VT_ERROR)
3083 if (FAILED(hres = to_int(args+1, &format))) return hres;
3087 hres = VarFormatDateTime(args, format, 0, &str);
3088 if (FAILED(hres)) return hres;
3090 return return_bstr(res, str);
3093 static HRESULT Global_WeekdayName(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
3095 int weekday, first_day = 1, abbrev = 0;
3096 BSTR ret;
3097 HRESULT hres;
3099 TRACE("\n");
3101 assert(1 <= args_cnt && args_cnt <= 3);
3103 hres = to_int(args, &weekday);
3104 if(FAILED(hres))
3105 return hres;
3107 if(args_cnt > 1) {
3108 hres = to_int(args+1, &abbrev);
3109 if(FAILED(hres))
3110 return hres;
3112 if(args_cnt == 3) {
3113 hres = to_int(args+2, &first_day);
3114 if(FAILED(hres))
3115 return hres;
3119 hres = VarWeekdayName(weekday, abbrev, first_day, 0, &ret);
3120 if(FAILED(hres))
3121 return hres;
3123 return return_bstr(res, ret);
3126 static HRESULT Global_MonthName(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
3128 int month, abbrev = 0;
3129 BSTR ret;
3130 HRESULT hres;
3132 TRACE("\n");
3134 assert(args_cnt == 1 || args_cnt == 2);
3136 if(V_VT(args) == VT_NULL || (args_cnt == 2 && V_VT(args+1) == VT_NULL))
3137 return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE);
3139 hres = to_int(args, &month);
3140 if(FAILED(hres))
3141 return hres;
3143 if(args_cnt == 2) {
3144 hres = to_int(args+1, &abbrev);
3145 if(FAILED(hres))
3146 return hres;
3149 hres = VarMonthName(month, abbrev, 0, &ret);
3150 if(FAILED(hres))
3151 return hres;
3153 return return_bstr(res, ret);
3156 static HRESULT Global_Round(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
3158 int decimal_places = 0;
3159 double d;
3160 HRESULT hres;
3162 TRACE("%s %s\n", debugstr_variant(args), args_cnt == 2 ? debugstr_variant(args + 1) : "0");
3164 assert(args_cnt == 1 || args_cnt == 2);
3166 if(!res)
3167 return S_OK;
3169 if(args_cnt == 2) {
3170 if (V_VT(args + 1) != VT_ERROR) {
3171 hres = to_int(args + 1, &decimal_places);
3172 if (FAILED(hres))
3173 return hres;
3177 switch(V_VT(args)) {
3178 case VT_I2:
3179 case VT_I4:
3180 case VT_BOOL:
3181 *res = *args;
3182 return S_OK;
3183 case VT_R8:
3184 d = V_R8(args);
3185 break;
3186 default:
3187 hres = to_double(args, &d);
3188 if(FAILED(hres))
3189 return hres;
3192 hres = VarR8Round(d, decimal_places, &d);
3193 if(FAILED(hres))
3194 return hres;
3196 return return_double(res, d);
3199 static HRESULT Global_Escape(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
3201 FIXME("\n");
3202 return E_NOTIMPL;
3205 static HRESULT Global_Unescape(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
3207 FIXME("\n");
3208 return E_NOTIMPL;
3211 static HRESULT Global_Eval(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
3213 FIXME("\n");
3214 return E_NOTIMPL;
3217 static HRESULT Global_Execute(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
3219 FIXME("\n");
3220 return E_NOTIMPL;
3223 static HRESULT Global_ExecuteGlobal(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
3225 FIXME("\n");
3226 return E_NOTIMPL;
3229 static HRESULT Global_GetRef(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
3231 FIXME("\n");
3232 return E_NOTIMPL;
3235 static HRESULT Global_Err(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
3237 TRACE("\n");
3239 if(args_cnt) {
3240 FIXME("Setter not supported\n");
3241 return E_NOTIMPL;
3244 V_VT(res) = VT_DISPATCH;
3245 V_DISPATCH(res) = &This->ctx->err_obj->IDispatch_iface;
3246 IDispatch_AddRef(V_DISPATCH(res));
3247 return S_OK;
3250 static const string_constant_t vbCr = {1, {'\r'}};
3251 static const string_constant_t vbCrLf = {2, {'\r','\n'}};
3252 static const string_constant_t vbNewLine = {2, {'\r','\n'}};
3253 static const string_constant_t vbFormFeed = {1, {0xc}};
3254 static const string_constant_t vbLf = {1, {'\n'}};
3255 static const string_constant_t vbNullChar = {1};
3256 static const string_constant_t vbNullString = {0};
3257 static const string_constant_t vbTab = {1, {'\t'}};
3258 static const string_constant_t vbVerticalTab = {1, {0xb}};
3260 static const builtin_prop_t global_props[] = {
3261 {NULL}, /* no default value */
3262 {L"Abs", Global_Abs, 0, 1},
3263 {L"Array", Global_Array, 0, 0, MAXDWORD},
3264 {L"Asc", Global_Asc, 0, 1},
3265 {L"AscB", Global_AscB, 0, 1},
3266 {L"AscW", Global_AscW, 0, 1},
3267 {L"Atn", Global_Atn, 0, 1},
3268 {L"CBool", Global_CBool, 0, 1},
3269 {L"CByte", Global_CByte, 0, 1},
3270 {L"CCur", Global_CCur, 0, 1},
3271 {L"CDate", Global_CDate, 0, 1},
3272 {L"CDbl", Global_CDbl, 0, 1},
3273 {L"Chr", Global_Chr, 0, 1},
3274 {L"ChrB", Global_ChrB, 0, 1},
3275 {L"ChrW", Global_ChrW, 0, 1},
3276 {L"CInt", Global_CInt, 0, 1},
3277 {L"CLng", Global_CLng, 0, 1},
3278 {L"Cos", Global_Cos, 0, 1},
3279 {L"CreateObject", Global_CreateObject, 0, 1},
3280 {L"CSng", Global_CSng, 0, 1},
3281 {L"CStr", Global_CStr, 0, 1},
3282 {L"Date", Global_Date, 0, 0},
3283 {L"DateAdd", Global_DateAdd, 0, 3},
3284 {L"DateDiff", Global_DateDiff, 0, 3, 5},
3285 {L"DatePart", Global_DatePart, 0, 2, 4},
3286 {L"DateSerial", Global_DateSerial, 0, 3},
3287 {L"DateValue", Global_DateValue, 0, 1},
3288 {L"Day", Global_Day, 0, 1},
3289 {L"Erase", Global_Erase, 0, 1},
3290 {L"Err", Global_Err, BP_GETPUT},
3291 {L"Escape", Global_Escape, 0, 1},
3292 {L"Eval", Global_Eval, 0, 1},
3293 {L"Execute", Global_Execute, 0, 1},
3294 {L"ExecuteGlobal", Global_ExecuteGlobal, 0, 1},
3295 {L"Exp", Global_Exp, 0, 1},
3296 {L"Filter", Global_Filter, 0, 2, 4},
3297 {L"Fix", Global_Fix, 0, 1},
3298 {L"FormatCurrency", Global_FormatCurrency, 0, 1, 5},
3299 {L"FormatDateTime", Global_FormatDateTime, 0, 1, 2},
3300 {L"FormatNumber", Global_FormatNumber, 0, 1, 5},
3301 {L"FormatPercent", Global_FormatPercent, 0, 1, 5},
3302 {L"GetLocale", Global_GetLocale, 0, 0},
3303 {L"GetObject", Global_GetObject, 0, 0, 2},
3304 {L"GetRef", Global_GetRef, 0, 1},
3305 {L"Hex", Global_Hex, 0, 1},
3306 {L"Hour", Global_Hour, 0, 1},
3307 {L"InputBox", Global_InputBox, 0, 1, 7},
3308 {L"InStr", Global_InStr, 0, 2, 4},
3309 {L"InStrB", Global_InStrB, 0, 3, 4},
3310 {L"InStrRev", Global_InStrRev, 0, 2, 4},
3311 {L"Int", Global_Int, 0, 1},
3312 {L"IsArray", Global_IsArray, 0, 1},
3313 {L"IsDate", Global_IsDate, 0, 1},
3314 {L"IsEmpty", Global_IsEmpty, 0, 1},
3315 {L"IsNull", Global_IsNull, 0, 1},
3316 {L"IsNumeric", Global_IsNumeric, 0, 1},
3317 {L"IsObject", Global_IsObject, 0, 1},
3318 {L"Join", Global_Join, 0, 1, 2},
3319 {L"LBound", Global_LBound, 0, 1, 2},
3320 {L"LCase", Global_LCase, 0, 1},
3321 {L"Left", Global_Left, 0, 2},
3322 {L"LeftB", Global_LeftB, 0, 2},
3323 {L"Len", Global_Len, 0, 1},
3324 {L"LenB", Global_LenB, 0, 1},
3325 {L"LoadPicture", Global_LoadPicture, 0, 1},
3326 {L"Log", Global_Log, 0, 1},
3327 {L"LTrim", Global_LTrim, 0, 1},
3328 {L"Mid", Global_Mid, 0, 2, 3},
3329 {L"MidB", Global_MidB, 0, 2, 3},
3330 {L"Minute", Global_Minute, 0, 1},
3331 {L"Month", Global_Month, 0, 1},
3332 {L"MonthName", Global_MonthName, 0, 1, 2},
3333 {L"MsgBox", Global_MsgBox, 0, 1, 5},
3334 {L"Now", Global_Now, 0, 0},
3335 {L"Oct", Global_Oct, 0, 1},
3336 {L"Randomize", Global_Randomize, 0, 0, 1},
3337 {L"Replace", Global_Replace, 0, 3, 6},
3338 {L"RGB", Global_RGB, 0, 3},
3339 {L"Right", Global_Right, 0, 2},
3340 {L"RightB", Global_RightB, 0, 2},
3341 {L"Rnd", Global_Rnd, 0, 0, 1},
3342 {L"Round", Global_Round, 0, 1, 2},
3343 {L"RTrim", Global_RTrim, 0, 1},
3344 {L"ScriptEngine", Global_ScriptEngine, 0, 0},
3345 {L"ScriptEngineBuildVersion", Global_ScriptEngineBuildVersion, 0, 0},
3346 {L"ScriptEngineMajorVersion", Global_ScriptEngineMajorVersion, 0, 0},
3347 {L"ScriptEngineMinorVersion", Global_ScriptEngineMinorVersion, 0, 0},
3348 {L"Second", Global_Second, 0, 1},
3349 {L"SetLocale", Global_SetLocale, 0, 0, 1},
3350 {L"Sgn", Global_Sgn, 0, 1},
3351 {L"Sin", Global_Sin, 0, 1},
3352 {L"Space", Global_Space, 0, 1},
3353 {L"Split", Global_Split, 0, 1, 4},
3354 {L"Sqr", Global_Sqr, 0, 1},
3355 {L"StrComp", Global_StrComp, 0, 2, 3},
3356 {L"String", Global_String, 0, 0, 2},
3357 {L"StrReverse", Global_StrReverse, 0, 1},
3358 {L"Tan", Global_Tan, 0, 1},
3359 {L"Time", Global_Time, 0, 0},
3360 {L"Timer", Global_Timer, 0, 0},
3361 {L"TimeSerial", Global_TimeSerial, 0, 3},
3362 {L"TimeValue", Global_TimeValue, 0, 1},
3363 {L"Trim", Global_Trim, 0, 1},
3364 {L"TypeName", Global_TypeName, 0, 1},
3365 {L"UBound", Global_UBound, 0, 1, 2},
3366 {L"UCase", Global_UCase, 0, 1},
3367 {L"Unescape", Global_Unescape, 0, 1},
3368 {L"VarType", Global_VarType, 0, 1},
3369 {L"vbAbort", NULL, BP_GET, VT_I2, IDABORT},
3370 {L"vbAbortRetryIgnore", NULL, BP_GET, VT_I2, MB_ABORTRETRYIGNORE},
3371 {L"vbApplicationModal", NULL, BP_GET, VT_I2, MB_APPLMODAL},
3372 {L"vbArray", NULL, BP_GET, VT_I2, VT_ARRAY},
3373 {L"vbBinaryCompare", NULL, BP_GET, VT_I2, 0},
3374 {L"vbBlack", NULL, BP_GET, VT_I4, 0x000000},
3375 {L"vbBlue", NULL, BP_GET, VT_I4, 0xff0000},
3376 {L"vbBoolean", NULL, BP_GET, VT_I2, VT_BOOL},
3377 {L"vbByte", NULL, BP_GET, VT_I2, VT_UI1},
3378 {L"vbCancel", NULL, BP_GET, VT_I2, IDCANCEL},
3379 {L"vbCr", NULL, BP_GET, VT_BSTR, (UINT_PTR)&vbCr},
3380 {L"vbCritical", NULL, BP_GET, VT_I2, MB_ICONHAND},
3381 {L"vbCrLf", NULL, BP_GET, VT_BSTR, (UINT_PTR)&vbCrLf},
3382 {L"vbCurrency", NULL, BP_GET, VT_I2, VT_CY},
3383 {L"vbCyan", NULL, BP_GET, VT_I4, 0xffff00},
3384 {L"vbDatabaseCompare", NULL, BP_GET, VT_I2, 2},
3385 {L"vbDataObject", NULL, BP_GET, VT_I2, VT_UNKNOWN},
3386 {L"vbDate", NULL, BP_GET, VT_I2, VT_DATE},
3387 {L"vbDecimal", NULL, BP_GET, VT_I2, VT_DECIMAL},
3388 {L"vbDefaultButton1", NULL, BP_GET, VT_I2, MB_DEFBUTTON1},
3389 {L"vbDefaultButton2", NULL, BP_GET, VT_I2, MB_DEFBUTTON2},
3390 {L"vbDefaultButton3", NULL, BP_GET, VT_I2, MB_DEFBUTTON3},
3391 {L"vbDefaultButton4", NULL, BP_GET, VT_I2, MB_DEFBUTTON4},
3392 {L"vbDouble", NULL, BP_GET, VT_I2, VT_R8},
3393 {L"vbEmpty", NULL, BP_GET, VT_I2, VT_EMPTY},
3394 {L"vbError", NULL, BP_GET, VT_I2, VT_ERROR},
3395 {L"vbExclamation", NULL, BP_GET, VT_I2, MB_ICONEXCLAMATION},
3396 {L"vbFalse", NULL, BP_GET, VT_I2, VARIANT_FALSE},
3397 {L"vbFirstFourDays", NULL, BP_GET, VT_I2, 2},
3398 {L"vbFirstFullWeek", NULL, BP_GET, VT_I2, 3},
3399 {L"vbFirstJan1", NULL, BP_GET, VT_I2, 1},
3400 {L"vbFormFeed", NULL, BP_GET, VT_BSTR, (UINT_PTR)&vbFormFeed},
3401 {L"vbFriday", NULL, BP_GET, VT_I2, 6},
3402 {L"vbGeneralDate", NULL, BP_GET, VT_I2, 0},
3403 {L"vbGreen", NULL, BP_GET, VT_I4, 0x00ff00},
3404 {L"vbIgnore", NULL, BP_GET, VT_I2, IDIGNORE},
3405 {L"vbInformation", NULL, BP_GET, VT_I2, MB_ICONASTERISK},
3406 {L"vbInteger", NULL, BP_GET, VT_I2, VT_I2},
3407 {L"vbLf", NULL, BP_GET, VT_BSTR, (UINT_PTR)&vbLf},
3408 {L"vbLong", NULL, BP_GET, VT_I2, VT_I4},
3409 {L"vbLongDate", NULL, BP_GET, VT_I2, 1},
3410 {L"vbLongTime", NULL, BP_GET, VT_I2, 3},
3411 {L"vbMagenta", NULL, BP_GET, VT_I4, 0xff00ff},
3412 {L"vbMonday", NULL, BP_GET, VT_I2, 2},
3413 {L"vbMsgBoxHelpButton", NULL, BP_GET, VT_I4, MB_HELP},
3414 {L"vbMsgBoxRight", NULL, BP_GET, VT_I4, MB_RIGHT},
3415 {L"vbMsgBoxRtlReading", NULL, BP_GET, VT_I4, MB_RTLREADING},
3416 {L"vbMsgBoxSetForeground", NULL, BP_GET, VT_I4, MB_SETFOREGROUND},
3417 {L"vbNewLine", NULL, BP_GET, VT_BSTR, (UINT_PTR)&vbNewLine},
3418 {L"vbNo", NULL, BP_GET, VT_I2, IDNO},
3419 {L"vbNull", NULL, BP_GET, VT_I2, VT_NULL},
3420 {L"vbNullChar", NULL, BP_GET, VT_BSTR, (UINT_PTR)&vbNullChar},
3421 {L"vbNullString", NULL, BP_GET, VT_BSTR, (UINT_PTR)&vbNullString},
3422 {L"vbObject", NULL, BP_GET, VT_I2, VT_DISPATCH},
3423 {L"vbObjectError", NULL, BP_GET, VT_I4, 0x80040000},
3424 {L"vbOK", NULL, BP_GET, VT_I2, IDOK},
3425 {L"vbOKCancel", NULL, BP_GET, VT_I2, MB_OKCANCEL},
3426 {L"vbOKOnly", NULL, BP_GET, VT_I2, MB_OK},
3427 {L"vbQuestion", NULL, BP_GET, VT_I2, MB_ICONQUESTION},
3428 {L"vbRed", NULL, BP_GET, VT_I4, 0x0000ff},
3429 {L"vbRetry", NULL, BP_GET, VT_I2, IDRETRY},
3430 {L"vbRetryCancel", NULL, BP_GET, VT_I2, MB_RETRYCANCEL},
3431 {L"vbSaturday", NULL, BP_GET, VT_I2, 7},
3432 {L"vbShortDate", NULL, BP_GET, VT_I2, 2},
3433 {L"vbShortTime", NULL, BP_GET, VT_I2, 4},
3434 {L"vbSingle", NULL, BP_GET, VT_I2, VT_R4},
3435 {L"vbString", NULL, BP_GET, VT_I2, VT_BSTR},
3436 {L"vbSunday", NULL, BP_GET, VT_I2, 1},
3437 {L"vbSystemModal", NULL, BP_GET, VT_I2, MB_SYSTEMMODAL},
3438 {L"vbTab", NULL, BP_GET, VT_BSTR, (UINT_PTR)&vbTab},
3439 {L"vbTextCompare", NULL, BP_GET, VT_I2, 1},
3440 {L"vbThursday", NULL, BP_GET, VT_I2, 5},
3441 {L"vbTrue", NULL, BP_GET, VT_I2, VARIANT_TRUE},
3442 {L"vbTuesday", NULL, BP_GET, VT_I2, 3},
3443 {L"vbUseDefault", NULL, BP_GET, VT_I2, -2},
3444 {L"vbUseSystem", NULL, BP_GET, VT_I2, 0},
3445 {L"vbUseSystemDayOfWeek", NULL, BP_GET, VT_I2, 0},
3446 {L"vbVariant", NULL, BP_GET, VT_I2, VT_VARIANT},
3447 {L"vbVerticalTab", NULL, BP_GET, VT_BSTR, (UINT_PTR)&vbVerticalTab},
3448 {L"vbWednesday", NULL, BP_GET, VT_I2, 4},
3449 {L"vbWhite", NULL, BP_GET, VT_I4, 0xffffff},
3450 {L"vbYellow", NULL, BP_GET, VT_I4, 0x00ffff},
3451 {L"vbYes", NULL, BP_GET, VT_I2, IDYES},
3452 {L"vbYesNo", NULL, BP_GET, VT_I2, MB_YESNO},
3453 {L"vbYesNoCancel", NULL, BP_GET, VT_I2, MB_YESNOCANCEL},
3454 {L"Weekday", Global_Weekday, 0, 1, 2},
3455 {L"WeekdayName", Global_WeekdayName, 0, 1, 3},
3456 {L"Year", Global_Year, 0, 1}
3459 static HRESULT err_string_prop(BSTR *prop, VARIANT *args, unsigned args_cnt, VARIANT *res)
3461 BSTR str;
3462 HRESULT hres;
3464 if(!args_cnt)
3465 return return_string(res, *prop ? *prop : L"");
3467 hres = to_string(args, &str);
3468 if(FAILED(hres))
3469 return hres;
3471 SysFreeString(*prop);
3472 *prop = str;
3473 return S_OK;
3476 static HRESULT Err_Description(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
3478 TRACE("\n");
3479 return err_string_prop(&This->ctx->ei.bstrDescription, args, args_cnt, res);
3482 static HRESULT Err_HelpContext(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
3484 TRACE("\n");
3486 if(args_cnt) {
3487 FIXME("setter not implemented\n");
3488 return E_NOTIMPL;
3491 return return_int(res, This->ctx->ei.dwHelpContext);
3494 static HRESULT Err_HelpFile(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
3496 TRACE("\n");
3497 return err_string_prop(&This->ctx->ei.bstrHelpFile, args, args_cnt, res);
3500 static HRESULT Err_Number(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
3502 HRESULT hres;
3504 TRACE("\n");
3506 if(args_cnt) {
3507 FIXME("setter not implemented\n");
3508 return E_NOTIMPL;
3511 hres = This->ctx->ei.scode;
3512 return return_int(res, HRESULT_FACILITY(hres) == FACILITY_VBS ? HRESULT_CODE(hres) : hres);
3515 static HRESULT Err_Source(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
3517 TRACE("\n");
3518 return err_string_prop(&This->ctx->ei.bstrSource, args, args_cnt, res);
3521 static HRESULT Err_Clear(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
3523 TRACE("\n");
3525 clear_ei(&This->ctx->ei);
3526 return S_OK;
3529 static HRESULT Err_Raise(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
3531 BSTR source = NULL, description = NULL, helpfile = NULL;
3532 int code, helpcontext = 0;
3533 HRESULT hres;
3535 TRACE("%s %u...\n", debugstr_variant(args), args_cnt);
3537 hres = to_int(args, &code);
3538 if(FAILED(hres))
3539 return hres;
3540 if(code == 0 || code > 0xffff)
3541 return E_INVALIDARG;
3543 if(args_cnt >= 2)
3544 hres = to_string(args + 1, &source);
3545 if(args_cnt >= 3 && SUCCEEDED(hres))
3546 hres = to_string(args + 2, &description);
3547 if(args_cnt >= 4 && SUCCEEDED(hres))
3548 hres = to_string(args + 3, &helpfile);
3549 if(args_cnt >= 5 && SUCCEEDED(hres))
3550 hres = to_int(args + 4, &helpcontext);
3552 if(SUCCEEDED(hres)) {
3553 script_ctx_t *ctx = This->ctx;
3555 if(source) {
3556 SysFreeString(ctx->ei.bstrSource);
3557 ctx->ei.bstrSource = source;
3559 if(description) {
3560 SysFreeString(ctx->ei.bstrDescription);
3561 ctx->ei.bstrDescription = description;
3563 if(helpfile) {
3564 SysFreeString(ctx->ei.bstrHelpFile);
3565 ctx->ei.bstrHelpFile = helpfile;
3567 if(args_cnt >= 5)
3568 ctx->ei.dwHelpContext = helpcontext;
3570 ctx->ei.scode = (code & ~0xffff) ? code : MAKE_VBSERROR(code);
3571 map_vbs_exception(&ctx->ei);
3573 hres = SCRIPT_E_RECORDED;
3574 }else {
3575 SysFreeString(source);
3576 SysFreeString(description);
3577 SysFreeString(helpfile);
3580 return hres;
3583 static const builtin_prop_t err_props[] = {
3584 {NULL, Err_Number, BP_GETPUT},
3585 {L"Clear", Err_Clear},
3586 {L"Description", Err_Description, BP_GETPUT},
3587 {L"HelpContext", Err_HelpContext, BP_GETPUT},
3588 {L"HelpFile", Err_HelpFile, BP_GETPUT},
3589 {L"Number", Err_Number, BP_GETPUT},
3590 {L"Raise", Err_Raise, 0, 1, 5},
3591 {L"Source", Err_Source, BP_GETPUT}
3594 void detach_global_objects(script_ctx_t *ctx)
3596 if(ctx->err_obj) {
3597 ctx->err_obj->ctx = NULL;
3598 IDispatch_Release(&ctx->err_obj->IDispatch_iface);
3599 ctx->err_obj = NULL;
3602 if(ctx->global_obj) {
3603 ctx->global_obj->ctx = NULL;
3604 IDispatch_Release(&ctx->global_obj->IDispatch_iface);
3605 ctx->global_obj = NULL;
3609 HRESULT init_global(script_ctx_t *ctx)
3611 HRESULT hres;
3613 hres = create_builtin_dispatch(ctx, global_props, ARRAY_SIZE(global_props), &ctx->global_obj);
3614 if(FAILED(hres))
3615 return hres;
3617 return create_builtin_dispatch(ctx, err_props, ARRAY_SIZE(err_props), &ctx->err_obj);