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