ntdll: Set EH_NESTED_CALL flag in call_stack_handlers() on x64.
[wine.git] / programs / wscript / main.c
blob12571181491f841acf044b61042e0e1804914775
1 /*
2 * Copyright 2010 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 <stdarg.h>
21 #define COBJMACROS
23 #include <windef.h>
24 #include <winbase.h>
25 #include <winreg.h>
26 #include <ole2.h>
27 #include <shellapi.h>
28 #include <activscp.h>
29 #include <initguid.h>
31 #include "wscript.h"
33 #include <wine/debug.h>
35 #ifdef _WIN64
37 #define IActiveScriptParse_Release IActiveScriptParse64_Release
38 #define IActiveScriptParse_InitNew IActiveScriptParse64_InitNew
39 #define IActiveScriptParse_ParseScriptText IActiveScriptParse64_ParseScriptText
41 #else
43 #define IActiveScriptParse_Release IActiveScriptParse32_Release
44 #define IActiveScriptParse_InitNew IActiveScriptParse32_InitNew
45 #define IActiveScriptParse_ParseScriptText IActiveScriptParse32_ParseScriptText
47 #endif
49 WINE_DEFAULT_DEBUG_CHANNEL(wscript);
50 WCHAR scriptFullName[MAX_PATH];
52 ITypeInfo *host_ti;
53 ITypeInfo *arguments_ti;
55 static HRESULT query_interface(REFIID,void**);
57 static HRESULT WINAPI ActiveScriptSite_QueryInterface(IActiveScriptSite *iface,
58 REFIID riid, void **ppv)
60 return query_interface(riid, ppv);
63 static ULONG WINAPI ActiveScriptSite_AddRef(IActiveScriptSite *iface)
65 return 2;
68 static ULONG WINAPI ActiveScriptSite_Release(IActiveScriptSite *iface)
70 return 1;
73 static HRESULT WINAPI ActiveScriptSite_GetLCID(IActiveScriptSite *iface, LCID *plcid)
75 WINE_TRACE("()\n");
77 *plcid = GetUserDefaultLCID();
78 return S_OK;
81 static HRESULT WINAPI ActiveScriptSite_GetItemInfo(IActiveScriptSite *iface,
82 LPCOLESTR pstrName, DWORD dwReturnMask, IUnknown **ppunkItem, ITypeInfo **ppti)
84 WINE_TRACE("(%s %lx %p %p)\n", wine_dbgstr_w(pstrName), dwReturnMask, ppunkItem, ppti);
86 if(lstrcmpW(pstrName, L"WSH") && lstrcmpW(pstrName, L"WScript"))
87 return E_FAIL;
89 if(dwReturnMask & SCRIPTINFO_ITYPEINFO) {
90 ITypeInfo_AddRef(host_ti);
91 *ppti = host_ti;
94 if(dwReturnMask & SCRIPTINFO_IUNKNOWN) {
95 IHost_AddRef(&host_obj);
96 *ppunkItem = (IUnknown*)&host_obj;
99 return S_OK;
102 static HRESULT WINAPI ActiveScriptSite_GetDocVersionString(IActiveScriptSite *iface,
103 BSTR *pbstrVersion)
105 WINE_FIXME("()\n");
106 return E_NOTIMPL;
109 static HRESULT WINAPI ActiveScriptSite_OnScriptTerminate(IActiveScriptSite *iface,
110 const VARIANT *pvarResult, const EXCEPINFO *pexcepinfo)
112 WINE_FIXME("()\n");
113 return E_NOTIMPL;
116 static HRESULT WINAPI ActiveScriptSite_OnStateChange(IActiveScriptSite *iface,
117 SCRIPTSTATE ssScriptState)
119 WINE_TRACE("(%x)\n", ssScriptState);
120 return S_OK;
123 static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface,
124 IActiveScriptError *pscripterror)
126 WINE_FIXME("()\n");
127 return E_NOTIMPL;
130 static HRESULT WINAPI ActiveScriptSite_OnEnterScript(IActiveScriptSite *iface)
132 WINE_TRACE("()\n");
133 return S_OK;
136 static HRESULT WINAPI ActiveScriptSite_OnLeaveScript(IActiveScriptSite *iface)
138 WINE_TRACE("()\n");
139 return S_OK;
142 static IActiveScriptSiteVtbl ActiveScriptSiteVtbl = {
143 ActiveScriptSite_QueryInterface,
144 ActiveScriptSite_AddRef,
145 ActiveScriptSite_Release,
146 ActiveScriptSite_GetLCID,
147 ActiveScriptSite_GetItemInfo,
148 ActiveScriptSite_GetDocVersionString,
149 ActiveScriptSite_OnScriptTerminate,
150 ActiveScriptSite_OnStateChange,
151 ActiveScriptSite_OnScriptError,
152 ActiveScriptSite_OnEnterScript,
153 ActiveScriptSite_OnLeaveScript
156 static IActiveScriptSite script_site = { &ActiveScriptSiteVtbl };
158 static HRESULT WINAPI ActiveScriptSiteWindow_QueryInterface(IActiveScriptSiteWindow *iface, REFIID riid, void **ppv)
160 return query_interface(riid, ppv);
163 static ULONG WINAPI ActiveScriptSiteWindow_AddRef(IActiveScriptSiteWindow *iface)
165 return 2;
168 static ULONG WINAPI ActiveScriptSiteWindow_Release(IActiveScriptSiteWindow *iface)
170 return 1;
173 static HRESULT WINAPI ActiveScriptSiteWindow_GetWindow(IActiveScriptSiteWindow *iface, HWND *phwnd)
175 TRACE("(%p)\n", phwnd);
177 *phwnd = NULL;
178 return S_OK;
181 static HRESULT WINAPI ActiveScriptSiteWindow_EnableModeless(IActiveScriptSiteWindow *iface, BOOL fEnable)
183 TRACE("(%x)\n", fEnable);
184 return S_OK;
187 static const IActiveScriptSiteWindowVtbl ActiveScriptSiteWindowVtbl = {
188 ActiveScriptSiteWindow_QueryInterface,
189 ActiveScriptSiteWindow_AddRef,
190 ActiveScriptSiteWindow_Release,
191 ActiveScriptSiteWindow_GetWindow,
192 ActiveScriptSiteWindow_EnableModeless
195 static IActiveScriptSiteWindow script_site_window = { &ActiveScriptSiteWindowVtbl };
197 static HRESULT query_interface(REFIID riid, void **ppv)
199 if(IsEqualGUID(riid, &IID_IUnknown)) {
200 TRACE("(IID_IUnknown %p)\n", ppv);
201 *ppv = &script_site;
202 }else if(IsEqualGUID(riid, &IID_IActiveScriptSite)) {
203 TRACE("(IID_IActiveScriptSite %p)\n", ppv);
204 *ppv = &script_site;
205 }else if(IsEqualGUID(riid, &IID_IActiveScriptSiteWindow)) {
206 TRACE("(IID_IActiveScriptSiteWindow %p)\n", ppv);
207 *ppv = &script_site_window;
208 }else {
209 *ppv = NULL;
210 TRACE("(%s %p)\n", wine_dbgstr_guid(riid), ppv);
211 return E_NOINTERFACE;
214 IUnknown_AddRef((IUnknown*)*ppv);
215 return S_OK;
218 static BOOL load_typelib(void)
220 ITypeLib *typelib;
221 HRESULT hres;
223 hres = LoadTypeLib(L"wscript.exe", &typelib);
224 if(FAILED(hres))
225 return FALSE;
227 hres = ITypeLib_GetTypeInfoOfGuid(typelib, &IID_IHost, &host_ti);
228 if(SUCCEEDED(hres))
229 hres = ITypeLib_GetTypeInfoOfGuid(typelib, &IID_IArguments2, &arguments_ti);
231 ITypeLib_Release(typelib);
232 return SUCCEEDED(hres);
235 static BOOL get_engine_clsid(const WCHAR *ext, CLSID *clsid)
237 WCHAR fileid[64], progid[64];
238 DWORD res;
239 LONG size;
240 HKEY hkey;
241 HRESULT hres;
243 res = RegOpenKeyW(HKEY_CLASSES_ROOT, ext, &hkey);
244 if(res != ERROR_SUCCESS)
245 return FALSE;
247 size = ARRAY_SIZE(fileid);
248 res = RegQueryValueW(hkey, NULL, fileid, &size);
249 RegCloseKey(hkey);
250 if(res != ERROR_SUCCESS)
251 return FALSE;
253 WINE_TRACE("fileid is %s\n", wine_dbgstr_w(fileid));
255 lstrcatW(fileid, L"\\ScriptEngine");
256 res = RegOpenKeyW(HKEY_CLASSES_ROOT, fileid, &hkey);
257 if(res != ERROR_SUCCESS)
258 return FALSE;
260 size = ARRAY_SIZE(progid);
261 res = RegQueryValueW(hkey, NULL, progid, &size);
262 RegCloseKey(hkey);
263 if(res != ERROR_SUCCESS)
264 return FALSE;
266 WINE_TRACE("ProgID is %s\n", wine_dbgstr_w(progid));
268 hres = CLSIDFromProgID(progid, clsid);
269 return SUCCEEDED(hres);
272 static BOOL create_engine(CLSID *clsid, IActiveScript **script_ret,
273 IActiveScriptParse **parser)
275 IActiveScript *script;
276 IUnknown *unk;
277 HRESULT hres;
279 hres = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
280 &IID_IUnknown, (void**)&unk);
281 if(FAILED(hres))
282 return FALSE;
284 hres = IUnknown_QueryInterface(unk, &IID_IActiveScript, (void**)&script);
285 IUnknown_Release(unk);
286 if(FAILED(hres))
287 return FALSE;
289 hres = IActiveScript_QueryInterface(script, &IID_IActiveScriptParse, (void**)parser);
290 if(FAILED(hres)) {
291 IActiveScript_Release(script);
292 return FALSE;
295 *script_ret = script;
296 return TRUE;
299 static BOOL init_engine(IActiveScript *script, IActiveScriptParse *parser)
301 HRESULT hres;
303 if(!load_typelib())
304 return FALSE;
306 hres = IActiveScript_SetScriptSite(script, &script_site);
307 if(FAILED(hres))
308 return FALSE;
310 hres = IActiveScriptParse_InitNew(parser);
311 if(FAILED(hres))
312 return FALSE;
314 hres = IActiveScript_AddNamedItem(script, L"WScript", SCRIPTITEM_ISVISIBLE);
315 if(FAILED(hres))
316 return FALSE;
318 hres = IActiveScript_AddNamedItem(script, L"WSH", SCRIPTITEM_ISVISIBLE);
319 if(FAILED(hres))
320 return FALSE;
322 hres = IActiveScript_SetScriptState(script, SCRIPTSTATE_INITIALIZED);
323 return SUCCEEDED(hres);
326 static BSTR get_script_str(const WCHAR *filename)
328 const char *file_map;
329 HANDLE file, map;
330 DWORD size, len;
331 BSTR ret;
333 file = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
334 if(file == INVALID_HANDLE_VALUE)
335 return NULL;
337 size = GetFileSize(file, NULL);
338 map = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
339 CloseHandle(file);
340 if(map == INVALID_HANDLE_VALUE)
341 return NULL;
343 file_map = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
344 CloseHandle(map);
345 if(!file_map)
346 return NULL;
348 len = MultiByteToWideChar(CP_ACP, 0, file_map, size, NULL, 0);
349 ret = SysAllocStringLen(NULL, len);
350 MultiByteToWideChar(CP_ACP, 0, file_map, size, ret, len);
352 UnmapViewOfFile(file_map);
353 return ret;
356 static void run_script(const WCHAR *filename, IActiveScript *script, IActiveScriptParse *parser)
358 BSTR text;
359 HRESULT hres;
361 text = get_script_str(filename);
362 if(!text) {
363 WINE_FIXME("Could not get script text\n");
364 return;
367 hres = IActiveScriptParse_ParseScriptText(parser, text, NULL, NULL, NULL, 1, 1,
368 SCRIPTTEXT_HOSTMANAGESSOURCE|SCRIPTITEM_ISVISIBLE, NULL, NULL);
369 SysFreeString(text);
370 if(FAILED(hres)) {
371 WINE_FIXME("ParseScriptText failed: %08lx\n", hres);
372 return;
375 hres = IActiveScript_SetScriptState(script, SCRIPTSTATE_STARTED);
376 if(FAILED(hres))
377 WINE_FIXME("SetScriptState failed: %08lx\n", hres);
380 static BOOL set_host_properties(const WCHAR *prop)
382 if(*prop == '/') {
383 ++prop;
384 if(*prop == '/')
385 ++prop;
387 else
388 ++prop;
390 if(wcsicmp(prop, L"i") == 0)
391 wshInteractive = VARIANT_TRUE;
392 else if(wcsicmp(prop, L"b") == 0)
393 wshInteractive = VARIANT_FALSE;
394 else if(wcsicmp(prop, L"nologo") == 0)
395 WINE_FIXME("ignored %s switch\n", debugstr_w(L"nologo"));
396 else
398 WINE_FIXME("unsupported switch %s\n", debugstr_w(prop));
399 return FALSE;
401 return TRUE;
404 int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR cmdline, int cmdshow)
406 WCHAR *ext, *filepart, *filename = NULL;
407 IActiveScriptParse *parser;
408 IActiveScript *script;
409 WCHAR **argv;
410 CLSID clsid;
411 int argc, i;
412 DWORD res;
414 WINE_TRACE("(%p %p %s %x)\n", hInst, hPrevInst, wine_dbgstr_w(cmdline), cmdshow);
416 argv = CommandLineToArgvW(GetCommandLineW(), &argc);
417 if(!argv)
418 return 1;
420 for(i=1; i<argc; i++) {
421 if(*argv[i] == '/' || *argv[i] == '-') {
422 if(!set_host_properties(argv[i]))
423 return 1;
424 }else {
425 filename = argv[i];
426 argums = argv+i+1;
427 numOfArgs = argc-i-1;
428 break;
432 if(!filename) {
433 WINE_FIXME("No file name specified\n");
434 return 1;
436 res = GetFullPathNameW(filename, ARRAY_SIZE(scriptFullName), scriptFullName, &filepart);
437 if(!res || res > ARRAY_SIZE(scriptFullName))
438 return 1;
440 ext = wcsrchr(filepart, '.');
441 if(!ext || !get_engine_clsid(ext, &clsid)) {
442 WINE_FIXME("Could not find engine for %s\n", wine_dbgstr_w(ext));
443 return 1;
446 CoInitialize(NULL);
448 if(!create_engine(&clsid, &script, &parser)) {
449 WINE_FIXME("Could not create script engine\n");
450 CoUninitialize();
451 return 1;
454 if(init_engine(script, parser)) {
455 run_script(filename, script, parser);
456 IActiveScript_Close(script);
457 ITypeInfo_Release(host_ti);
458 }else {
459 WINE_FIXME("Script initialization failed\n");
462 IActiveScript_Release(script);
463 IActiveScriptParse_Release(parser);
465 CoUninitialize();
467 return 0;