1 /* 2 * Copyright 2010 Jacek Caban for CodeWeavers 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 */ 18 19 #include <stdarg.h> 20 21 #define COBJMACROS 22 #ifdef __REACTOS__ 23 #define CONST_VTABLE 24 #endif 25 26 #include <windef.h> 27 #include <winbase.h> 28 #include <winreg.h> 29 #include <ole2.h> 30 #include <shellapi.h> 31 #include <activscp.h> 32 #include <initguid.h> 33 34 #include "wscript.h" 35 36 #include <wine/debug.h> 37 38 #ifdef _WIN64 39 40 #define IActiveScriptParse_Release IActiveScriptParse64_Release 41 #define IActiveScriptParse_InitNew IActiveScriptParse64_InitNew 42 #define IActiveScriptParse_ParseScriptText IActiveScriptParse64_ParseScriptText 43 44 #else 45 46 #define IActiveScriptParse_Release IActiveScriptParse32_Release 47 #define IActiveScriptParse_InitNew IActiveScriptParse32_InitNew 48 #define IActiveScriptParse_ParseScriptText IActiveScriptParse32_ParseScriptText 49 50 #endif 51 52 WINE_DEFAULT_DEBUG_CHANNEL(wscript); 53 54 static const WCHAR wscriptW[] = {'W','S','c','r','i','p','t',0}; 55 static const WCHAR wshW[] = {'W','S','H',0}; 56 WCHAR scriptFullName[MAX_PATH]; 57 58 ITypeInfo *host_ti; 59 ITypeInfo *arguments_ti; 60 61 static HRESULT query_interface(REFIID,void**); 62 63 static HRESULT WINAPI ActiveScriptSite_QueryInterface(IActiveScriptSite *iface, 64 REFIID riid, void **ppv) 65 { 66 return query_interface(riid, ppv); 67 } 68 69 static ULONG WINAPI ActiveScriptSite_AddRef(IActiveScriptSite *iface) 70 { 71 return 2; 72 } 73 74 static ULONG WINAPI ActiveScriptSite_Release(IActiveScriptSite *iface) 75 { 76 return 1; 77 } 78 79 static HRESULT WINAPI ActiveScriptSite_GetLCID(IActiveScriptSite *iface, LCID *plcid) 80 { 81 WINE_TRACE("()\n"); 82 83 *plcid = GetUserDefaultLCID(); 84 return S_OK; 85 } 86 87 static HRESULT WINAPI ActiveScriptSite_GetItemInfo(IActiveScriptSite *iface, 88 LPCOLESTR pstrName, DWORD dwReturnMask, IUnknown **ppunkItem, ITypeInfo **ppti) 89 { 90 WINE_TRACE("(%s %x %p %p)\n", wine_dbgstr_w(pstrName), dwReturnMask, ppunkItem, ppti); 91 92 if(lstrcmpW(pstrName, wshW) && lstrcmpW(pstrName, wscriptW)) 93 return E_FAIL; 94 95 if(dwReturnMask & SCRIPTINFO_ITYPEINFO) { 96 ITypeInfo_AddRef(host_ti); 97 *ppti = host_ti; 98 } 99 100 if(dwReturnMask & SCRIPTINFO_IUNKNOWN) { 101 IHost_AddRef(&host_obj); 102 *ppunkItem = (IUnknown*)&host_obj; 103 } 104 105 return S_OK; 106 } 107 108 static HRESULT WINAPI ActiveScriptSite_GetDocVersionString(IActiveScriptSite *iface, 109 BSTR *pbstrVersion) 110 { 111 WINE_FIXME("()\n"); 112 return E_NOTIMPL; 113 } 114 115 static HRESULT WINAPI ActiveScriptSite_OnScriptTerminate(IActiveScriptSite *iface, 116 const VARIANT *pvarResult, const EXCEPINFO *pexcepinfo) 117 { 118 WINE_FIXME("()\n"); 119 return E_NOTIMPL; 120 } 121 122 static HRESULT WINAPI ActiveScriptSite_OnStateChange(IActiveScriptSite *iface, 123 SCRIPTSTATE ssScriptState) 124 { 125 WINE_TRACE("(%x)\n", ssScriptState); 126 return S_OK; 127 } 128 129 static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface, 130 IActiveScriptError *pscripterror) 131 { 132 WINE_FIXME("()\n"); 133 return E_NOTIMPL; 134 } 135 136 static HRESULT WINAPI ActiveScriptSite_OnEnterScript(IActiveScriptSite *iface) 137 { 138 WINE_TRACE("()\n"); 139 return S_OK; 140 } 141 142 static HRESULT WINAPI ActiveScriptSite_OnLeaveScript(IActiveScriptSite *iface) 143 { 144 WINE_TRACE("()\n"); 145 return S_OK; 146 } 147 148 static IActiveScriptSiteVtbl ActiveScriptSiteVtbl = { 149 ActiveScriptSite_QueryInterface, 150 ActiveScriptSite_AddRef, 151 ActiveScriptSite_Release, 152 ActiveScriptSite_GetLCID, 153 ActiveScriptSite_GetItemInfo, 154 ActiveScriptSite_GetDocVersionString, 155 ActiveScriptSite_OnScriptTerminate, 156 ActiveScriptSite_OnStateChange, 157 ActiveScriptSite_OnScriptError, 158 ActiveScriptSite_OnEnterScript, 159 ActiveScriptSite_OnLeaveScript 160 }; 161 162 static IActiveScriptSite script_site = { &ActiveScriptSiteVtbl }; 163 164 static HRESULT WINAPI ActiveScriptSiteWindow_QueryInterface(IActiveScriptSiteWindow *iface, REFIID riid, void **ppv) 165 { 166 return query_interface(riid, ppv); 167 } 168 169 static ULONG WINAPI ActiveScriptSiteWindow_AddRef(IActiveScriptSiteWindow *iface) 170 { 171 return 2; 172 } 173 174 static ULONG WINAPI ActiveScriptSiteWindow_Release(IActiveScriptSiteWindow *iface) 175 { 176 return 1; 177 } 178 179 static HRESULT WINAPI ActiveScriptSiteWindow_GetWindow(IActiveScriptSiteWindow *iface, HWND *phwnd) 180 { 181 TRACE("(%p)\n", phwnd); 182 183 *phwnd = NULL; 184 return S_OK; 185 } 186 187 static HRESULT WINAPI ActiveScriptSiteWindow_EnableModeless(IActiveScriptSiteWindow *iface, BOOL fEnable) 188 { 189 TRACE("(%x)\n", fEnable); 190 return S_OK; 191 } 192 193 static const IActiveScriptSiteWindowVtbl ActiveScriptSiteWindowVtbl = { 194 ActiveScriptSiteWindow_QueryInterface, 195 ActiveScriptSiteWindow_AddRef, 196 ActiveScriptSiteWindow_Release, 197 ActiveScriptSiteWindow_GetWindow, 198 ActiveScriptSiteWindow_EnableModeless 199 }; 200 201 static IActiveScriptSiteWindow script_site_window = { &ActiveScriptSiteWindowVtbl }; 202 203 static HRESULT query_interface(REFIID riid, void **ppv) 204 { 205 if(IsEqualGUID(riid, &IID_IUnknown)) { 206 TRACE("(IID_IUnknown %p)\n", ppv); 207 *ppv = &script_site; 208 }else if(IsEqualGUID(riid, &IID_IActiveScriptSite)) { 209 TRACE("(IID_IActiveScriptSite %p)\n", ppv); 210 *ppv = &script_site; 211 }else if(IsEqualGUID(riid, &IID_IActiveScriptSiteWindow)) { 212 TRACE("(IID_IActiveScriptSiteWindow %p)\n", ppv); 213 *ppv = &script_site_window; 214 }else { 215 *ppv = NULL; 216 TRACE("(%s %p)\n", wine_dbgstr_guid(riid), ppv); 217 return E_NOINTERFACE; 218 } 219 220 IUnknown_AddRef((IUnknown*)*ppv); 221 return S_OK; 222 } 223 224 static BOOL load_typelib(void) 225 { 226 ITypeLib *typelib; 227 HRESULT hres; 228 229 static const WCHAR wscript_exeW[] = {'w','s','c','r','i','p','t','.','e','x','e',0}; 230 231 hres = LoadTypeLib(wscript_exeW, &typelib); 232 if(FAILED(hres)) 233 return FALSE; 234 235 hres = ITypeLib_GetTypeInfoOfGuid(typelib, &IID_IHost, &host_ti); 236 if(SUCCEEDED(hres)) 237 hres = ITypeLib_GetTypeInfoOfGuid(typelib, &IID_IArguments2, &arguments_ti); 238 239 ITypeLib_Release(typelib); 240 return SUCCEEDED(hres); 241 } 242 243 static BOOL get_engine_clsid(const WCHAR *ext, CLSID *clsid) 244 { 245 WCHAR fileid[64], progid[64]; 246 DWORD res; 247 LONG size; 248 HKEY hkey; 249 HRESULT hres; 250 251 static const WCHAR script_engineW[] = 252 {'\\','S','c','r','i','p','t','E','n','g','i','n','e',0}; 253 254 res = RegOpenKeyW(HKEY_CLASSES_ROOT, ext, &hkey); 255 if(res != ERROR_SUCCESS) 256 return FALSE; 257 258 size = ARRAY_SIZE(fileid); 259 res = RegQueryValueW(hkey, NULL, fileid, &size); 260 RegCloseKey(hkey); 261 if(res != ERROR_SUCCESS) 262 return FALSE; 263 264 WINE_TRACE("fileid is %s\n", wine_dbgstr_w(fileid)); 265 266 lstrcatW(fileid, script_engineW); 267 res = RegOpenKeyW(HKEY_CLASSES_ROOT, fileid, &hkey); 268 if(res != ERROR_SUCCESS) 269 return FALSE; 270 271 size = ARRAY_SIZE(progid); 272 res = RegQueryValueW(hkey, NULL, progid, &size); 273 RegCloseKey(hkey); 274 if(res != ERROR_SUCCESS) 275 return FALSE; 276 277 WINE_TRACE("ProgID is %s\n", wine_dbgstr_w(progid)); 278 279 hres = CLSIDFromProgID(progid, clsid); 280 return SUCCEEDED(hres); 281 } 282 283 static BOOL create_engine(CLSID *clsid, IActiveScript **script_ret, 284 IActiveScriptParse **parser) 285 { 286 IActiveScript *script; 287 IUnknown *unk; 288 HRESULT hres; 289 290 hres = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, 291 &IID_IUnknown, (void**)&unk); 292 if(FAILED(hres)) 293 return FALSE; 294 295 hres = IUnknown_QueryInterface(unk, &IID_IActiveScript, (void**)&script); 296 IUnknown_Release(unk); 297 if(FAILED(hres)) 298 return FALSE; 299 300 hres = IActiveScript_QueryInterface(script, &IID_IActiveScriptParse, (void**)parser); 301 if(FAILED(hres)) { 302 IActiveScript_Release(script); 303 return FALSE; 304 } 305 306 *script_ret = script; 307 return TRUE; 308 } 309 310 static BOOL init_engine(IActiveScript *script, IActiveScriptParse *parser) 311 { 312 HRESULT hres; 313 314 if(!load_typelib()) 315 return FALSE; 316 317 hres = IActiveScript_SetScriptSite(script, &script_site); 318 if(FAILED(hres)) 319 return FALSE; 320 321 hres = IActiveScriptParse_InitNew(parser); 322 if(FAILED(hres)) 323 return FALSE; 324 325 hres = IActiveScript_AddNamedItem(script, wscriptW, SCRIPTITEM_ISVISIBLE); 326 if(FAILED(hres)) 327 return FALSE; 328 329 hres = IActiveScript_AddNamedItem(script, wshW, SCRIPTITEM_ISVISIBLE); 330 if(FAILED(hres)) 331 return FALSE; 332 333 hres = IActiveScript_SetScriptState(script, SCRIPTSTATE_INITIALIZED); 334 return SUCCEEDED(hres); 335 } 336 337 static BSTR get_script_str(const WCHAR *filename) 338 { 339 const char *file_map; 340 HANDLE file, map; 341 DWORD size, len; 342 BSTR ret; 343 344 file = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); 345 if(file == INVALID_HANDLE_VALUE) 346 return NULL; 347 348 size = GetFileSize(file, NULL); 349 map = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL); 350 CloseHandle(file); 351 if(map == INVALID_HANDLE_VALUE) 352 return NULL; 353 354 file_map = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0); 355 CloseHandle(map); 356 if(!file_map) 357 return NULL; 358 359 len = MultiByteToWideChar(CP_ACP, 0, file_map, size, NULL, 0); 360 ret = SysAllocStringLen(NULL, len); 361 MultiByteToWideChar(CP_ACP, 0, file_map, size, ret, len); 362 363 UnmapViewOfFile(file_map); 364 return ret; 365 } 366 367 static void run_script(const WCHAR *filename, IActiveScript *script, IActiveScriptParse *parser) 368 { 369 BSTR text; 370 HRESULT hres; 371 372 text = get_script_str(filename); 373 if(!text) { 374 WINE_FIXME("Could not get script text\n"); 375 return; 376 } 377 378 hres = IActiveScriptParse_ParseScriptText(parser, text, NULL, NULL, NULL, 1, 1, 379 SCRIPTTEXT_HOSTMANAGESSOURCE|SCRIPTITEM_ISVISIBLE, NULL, NULL); 380 SysFreeString(text); 381 if(FAILED(hres)) { 382 WINE_FIXME("ParseScriptText failed: %08x\n", hres); 383 return; 384 } 385 386 hres = IActiveScript_SetScriptState(script, SCRIPTSTATE_STARTED); 387 if(FAILED(hres)) 388 WINE_FIXME("SetScriptState failed: %08x\n", hres); 389 } 390 391 static BOOL set_host_properties(const WCHAR *prop) 392 { 393 static const WCHAR nologoW[] = {'n','o','l','o','g','o',0}; 394 static const WCHAR iactive[] = {'i',0}; 395 static const WCHAR batch[] = {'b',0}; 396 397 if(*prop == '/') { 398 ++prop; 399 if(*prop == '/') 400 ++prop; 401 } 402 else 403 ++prop; 404 405 if(wcsicmp(prop, iactive) == 0) 406 wshInteractive = VARIANT_TRUE; 407 else if(wcsicmp(prop, batch) == 0) 408 wshInteractive = VARIANT_FALSE; 409 else if(wcsicmp(prop, nologoW) == 0) 410 WINE_FIXME("ignored %s switch\n", debugstr_w(nologoW)); 411 else 412 { 413 WINE_FIXME("unsupported switch %s\n", debugstr_w(prop)); 414 return FALSE; 415 } 416 return TRUE; 417 } 418 419 int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR cmdline, int cmdshow) 420 { 421 WCHAR *ext, *filepart, *filename = NULL; 422 IActiveScriptParse *parser; 423 IActiveScript *script; 424 WCHAR **argv; 425 CLSID clsid; 426 int argc, i; 427 DWORD res; 428 429 WINE_TRACE("(%p %p %s %x)\n", hInst, hPrevInst, wine_dbgstr_w(cmdline), cmdshow); 430 431 argv = CommandLineToArgvW(GetCommandLineW(), &argc); 432 if(!argv) 433 return 1; 434 435 for(i=1; i<argc; i++) { 436 if(*argv[i] == '/' || *argv[i] == '-') { 437 if(!set_host_properties(argv[i])) 438 return 1; 439 }else { 440 filename = argv[i]; 441 argums = argv+i+1; 442 numOfArgs = argc-i-1; 443 break; 444 } 445 } 446 447 if(!filename) { 448 WINE_FIXME("No file name specified\n"); 449 return 1; 450 } 451 res = GetFullPathNameW(filename, ARRAY_SIZE(scriptFullName), scriptFullName, &filepart); 452 if(!res || res > ARRAY_SIZE(scriptFullName)) 453 return 1; 454 455 ext = wcsrchr(filepart, '.'); 456 if(!ext || !get_engine_clsid(ext, &clsid)) { 457 WINE_FIXME("Could not find engine for %s\n", wine_dbgstr_w(ext)); 458 return 1; 459 } 460 461 CoInitialize(NULL); 462 463 if(!create_engine(&clsid, &script, &parser)) { 464 WINE_FIXME("Could not create script engine\n"); 465 CoUninitialize(); 466 return 1; 467 } 468 469 if(init_engine(script, parser)) { 470 run_script(filename, script, parser); 471 IActiveScript_Close(script); 472 ITypeInfo_Release(host_ti); 473 }else { 474 WINE_FIXME("Script initialization failed\n"); 475 } 476 477 IActiveScript_Release(script); 478 IActiveScriptParse_Release(parser); 479 480 CoUninitialize(); 481 482 return 0; 483 } 484