1 /* 2 * Copyright 2011 Jacek Caban for CodeWeavers 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 */ 18 19 #ifdef __REACTOS__ 20 #include <wchar.h> 21 #endif 22 23 #include "wshom_private.h" 24 #include "wshom.h" 25 26 #include "shellapi.h" 27 #include "shlobj.h" 28 #include "dispex.h" 29 30 #include "wine/debug.h" 31 #include "wine/heap.h" 32 33 WINE_DEFAULT_DEBUG_CHANNEL(wshom); 34 35 typedef struct 36 { 37 struct provideclassinfo classinfo; 38 IWshShell3 IWshShell3_iface; 39 } WshShellImpl; 40 static WshShellImpl WshShell3; 41 42 typedef struct 43 { 44 struct provideclassinfo classinfo; 45 IWshCollection IWshCollection_iface; 46 LONG ref; 47 } WshCollection; 48 49 typedef struct 50 { 51 struct provideclassinfo classinfo; 52 IWshShortcut IWshShortcut_iface; 53 LONG ref; 54 55 IShellLinkW *link; 56 BSTR path_link; 57 } WshShortcut; 58 59 typedef struct 60 { 61 struct provideclassinfo classinfo; 62 IWshEnvironment IWshEnvironment_iface; 63 LONG ref; 64 } WshEnvironment; 65 66 typedef struct 67 { 68 struct provideclassinfo classinfo; 69 IWshExec IWshExec_iface; 70 LONG ref; 71 PROCESS_INFORMATION info; 72 } WshExecImpl; 73 74 static inline WshCollection *impl_from_IWshCollection( IWshCollection *iface ) 75 { 76 return CONTAINING_RECORD(iface, WshCollection, IWshCollection_iface); 77 } 78 79 static inline WshShortcut *impl_from_IWshShortcut( IWshShortcut *iface ) 80 { 81 return CONTAINING_RECORD(iface, WshShortcut, IWshShortcut_iface); 82 } 83 84 static inline WshEnvironment *impl_from_IWshEnvironment( IWshEnvironment *iface ) 85 { 86 return CONTAINING_RECORD(iface, WshEnvironment, IWshEnvironment_iface); 87 } 88 89 static inline WshExecImpl *impl_from_IWshExec( IWshExec *iface ) 90 { 91 return CONTAINING_RECORD(iface, WshExecImpl, IWshExec_iface); 92 } 93 94 static HRESULT WINAPI WshExec_QueryInterface(IWshExec *iface, REFIID riid, void **obj) 95 { 96 WshExecImpl *This = impl_from_IWshExec(iface); 97 98 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), obj); 99 100 if (IsEqualGUID(riid, &IID_IDispatch) || 101 IsEqualGUID(riid, &IID_IWshExec) || 102 IsEqualGUID(riid, &IID_IUnknown)) 103 { 104 *obj = iface; 105 } 106 else if (IsEqualIID(riid, &IID_IProvideClassInfo)) 107 { 108 *obj = &This->classinfo.IProvideClassInfo_iface; 109 } 110 else { 111 FIXME("Unknown iface %s\n", debugstr_guid(riid)); 112 *obj = NULL; 113 return E_NOINTERFACE; 114 } 115 116 IUnknown_AddRef((IUnknown *)*obj); 117 return S_OK; 118 } 119 120 static ULONG WINAPI WshExec_AddRef(IWshExec *iface) 121 { 122 WshExecImpl *This = impl_from_IWshExec(iface); 123 LONG ref = InterlockedIncrement(&This->ref); 124 TRACE("(%p) ref = %d\n", This, ref); 125 return ref; 126 } 127 128 static ULONG WINAPI WshExec_Release(IWshExec *iface) 129 { 130 WshExecImpl *This = impl_from_IWshExec(iface); 131 LONG ref = InterlockedDecrement(&This->ref); 132 TRACE("(%p) ref = %d\n", This, ref); 133 134 if (!ref) { 135 CloseHandle(This->info.hThread); 136 CloseHandle(This->info.hProcess); 137 heap_free(This); 138 } 139 140 return ref; 141 } 142 143 static HRESULT WINAPI WshExec_GetTypeInfoCount(IWshExec *iface, UINT *pctinfo) 144 { 145 WshExecImpl *This = impl_from_IWshExec(iface); 146 TRACE("(%p)->(%p)\n", This, pctinfo); 147 *pctinfo = 1; 148 return S_OK; 149 } 150 151 static HRESULT WINAPI WshExec_GetTypeInfo(IWshExec *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) 152 { 153 WshExecImpl *This = impl_from_IWshExec(iface); 154 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo); 155 return get_typeinfo(IWshExec_tid, ppTInfo); 156 } 157 158 static HRESULT WINAPI WshExec_GetIDsOfNames(IWshExec *iface, REFIID riid, LPOLESTR *rgszNames, 159 UINT cNames, LCID lcid, DISPID *rgDispId) 160 { 161 WshExecImpl *This = impl_from_IWshExec(iface); 162 ITypeInfo *typeinfo; 163 HRESULT hr; 164 165 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId); 166 167 hr = get_typeinfo(IWshExec_tid, &typeinfo); 168 if(SUCCEEDED(hr)) 169 { 170 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId); 171 ITypeInfo_Release(typeinfo); 172 } 173 174 return hr; 175 } 176 177 static HRESULT WINAPI WshExec_Invoke(IWshExec *iface, DISPID dispIdMember, REFIID riid, LCID lcid, 178 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) 179 { 180 WshExecImpl *This = impl_from_IWshExec(iface); 181 ITypeInfo *typeinfo; 182 HRESULT hr; 183 184 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid), 185 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); 186 187 hr = get_typeinfo(IWshExec_tid, &typeinfo); 188 if(SUCCEEDED(hr)) 189 { 190 hr = ITypeInfo_Invoke(typeinfo, &This->IWshExec_iface, dispIdMember, wFlags, 191 pDispParams, pVarResult, pExcepInfo, puArgErr); 192 ITypeInfo_Release(typeinfo); 193 } 194 195 return hr; 196 } 197 198 static HRESULT WINAPI WshExec_get_Status(IWshExec *iface, WshExecStatus *status) 199 { 200 WshExecImpl *This = impl_from_IWshExec(iface); 201 DWORD code; 202 203 TRACE("(%p)->(%p)\n", This, status); 204 205 if (!status) 206 return E_INVALIDARG; 207 208 if (!GetExitCodeProcess(This->info.hProcess, &code)) 209 return HRESULT_FROM_WIN32(GetLastError()); 210 211 switch (code) 212 { 213 case 0: 214 *status = WshFinished; 215 break; 216 case STILL_ACTIVE: 217 *status = WshRunning; 218 break; 219 default: 220 *status = WshFailed; 221 } 222 223 return S_OK; 224 } 225 226 static HRESULT WINAPI WshExec_get_StdIn(IWshExec *iface, ITextStream **stream) 227 { 228 WshExecImpl *This = impl_from_IWshExec(iface); 229 230 FIXME("(%p)->(%p): stub\n", This, stream); 231 232 return E_NOTIMPL; 233 } 234 235 static HRESULT WINAPI WshExec_get_StdOut(IWshExec *iface, ITextStream **stream) 236 { 237 WshExecImpl *This = impl_from_IWshExec(iface); 238 239 FIXME("(%p)->(%p): stub\n", This, stream); 240 241 return E_NOTIMPL; 242 } 243 244 static HRESULT WINAPI WshExec_get_StdErr(IWshExec *iface, ITextStream **stream) 245 { 246 WshExecImpl *This = impl_from_IWshExec(iface); 247 248 FIXME("(%p)->(%p): stub\n", This, stream); 249 250 return E_NOTIMPL; 251 } 252 253 static HRESULT WINAPI WshExec_get_ProcessID(IWshExec *iface, DWORD *pid) 254 { 255 WshExecImpl *This = impl_from_IWshExec(iface); 256 257 TRACE("(%p)->(%p)\n", This, pid); 258 259 if (!pid) 260 return E_INVALIDARG; 261 262 *pid = This->info.dwProcessId; 263 return S_OK; 264 } 265 266 static HRESULT WINAPI WshExec_get_ExitCode(IWshExec *iface, DWORD *code) 267 { 268 WshExecImpl *This = impl_from_IWshExec(iface); 269 270 FIXME("(%p)->(%p): stub\n", This, code); 271 272 return E_NOTIMPL; 273 } 274 275 static BOOL CALLBACK enum_thread_wnd_proc(HWND hwnd, LPARAM lParam) 276 { 277 INT *count = (INT*)lParam; 278 279 (*count)++; 280 PostMessageW(hwnd, WM_CLOSE, 0, 0); 281 /* try to send it to all windows, even if failed for some */ 282 return TRUE; 283 } 284 285 static HRESULT WINAPI WshExec_Terminate(IWshExec *iface) 286 { 287 WshExecImpl *This = impl_from_IWshExec(iface); 288 BOOL ret, kill = FALSE; 289 INT count = 0; 290 291 TRACE("(%p)\n", This); 292 293 ret = EnumThreadWindows(This->info.dwThreadId, enum_thread_wnd_proc, (LPARAM)&count); 294 if (ret && count) { 295 /* manual testing shows that it waits 2 seconds before forcing termination */ 296 if (WaitForSingleObject(This->info.hProcess, 2000) != WAIT_OBJECT_0) 297 kill = TRUE; 298 } 299 else 300 kill = TRUE; 301 302 if (kill) 303 TerminateProcess(This->info.hProcess, 0); 304 305 return S_OK; 306 } 307 308 static const IWshExecVtbl WshExecVtbl = { 309 WshExec_QueryInterface, 310 WshExec_AddRef, 311 WshExec_Release, 312 WshExec_GetTypeInfoCount, 313 WshExec_GetTypeInfo, 314 WshExec_GetIDsOfNames, 315 WshExec_Invoke, 316 WshExec_get_Status, 317 WshExec_get_StdIn, 318 WshExec_get_StdOut, 319 WshExec_get_StdErr, 320 WshExec_get_ProcessID, 321 WshExec_get_ExitCode, 322 WshExec_Terminate 323 }; 324 325 static HRESULT WshExec_create(BSTR command, IWshExec **ret) 326 { 327 STARTUPINFOW si = {0}; 328 WshExecImpl *This; 329 330 *ret = NULL; 331 332 This = heap_alloc(sizeof(*This)); 333 if (!This) 334 return E_OUTOFMEMORY; 335 336 This->IWshExec_iface.lpVtbl = &WshExecVtbl; 337 This->ref = 1; 338 339 if (!CreateProcessW(NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &This->info)) { 340 heap_free(This); 341 return HRESULT_FROM_WIN32(GetLastError()); 342 } 343 344 init_classinfo(&CLSID_WshExec, (IUnknown *)&This->IWshExec_iface, &This->classinfo); 345 *ret = &This->IWshExec_iface; 346 return S_OK; 347 } 348 349 static HRESULT WINAPI WshEnvironment_QueryInterface(IWshEnvironment *iface, REFIID riid, void **obj) 350 { 351 WshEnvironment *This = impl_from_IWshEnvironment(iface); 352 353 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), obj); 354 355 if (IsEqualGUID(riid, &IID_IUnknown) || 356 IsEqualGUID(riid, &IID_IDispatch) || 357 IsEqualGUID(riid, &IID_IWshEnvironment)) 358 { 359 *obj = iface; 360 } 361 else if (IsEqualIID(riid, &IID_IProvideClassInfo)) 362 { 363 *obj = &This->classinfo.IProvideClassInfo_iface; 364 } 365 else { 366 FIXME("Unknown iface %s\n", debugstr_guid(riid)); 367 *obj = NULL; 368 return E_NOINTERFACE; 369 } 370 371 IUnknown_AddRef((IUnknown*)*obj); 372 return S_OK; 373 } 374 375 static ULONG WINAPI WshEnvironment_AddRef(IWshEnvironment *iface) 376 { 377 WshEnvironment *This = impl_from_IWshEnvironment(iface); 378 LONG ref = InterlockedIncrement(&This->ref); 379 TRACE("(%p) ref = %d\n", This, ref); 380 return ref; 381 } 382 383 static ULONG WINAPI WshEnvironment_Release(IWshEnvironment *iface) 384 { 385 WshEnvironment *This = impl_from_IWshEnvironment(iface); 386 LONG ref = InterlockedDecrement(&This->ref); 387 TRACE("(%p) ref = %d\n", This, ref); 388 389 if (!ref) 390 heap_free(This); 391 392 return ref; 393 } 394 395 static HRESULT WINAPI WshEnvironment_GetTypeInfoCount(IWshEnvironment *iface, UINT *pctinfo) 396 { 397 WshEnvironment *This = impl_from_IWshEnvironment(iface); 398 TRACE("(%p)->(%p)\n", This, pctinfo); 399 *pctinfo = 1; 400 return S_OK; 401 } 402 403 static HRESULT WINAPI WshEnvironment_GetTypeInfo(IWshEnvironment *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) 404 { 405 WshEnvironment *This = impl_from_IWshEnvironment(iface); 406 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo); 407 return get_typeinfo(IWshEnvironment_tid, ppTInfo); 408 } 409 410 static HRESULT WINAPI WshEnvironment_GetIDsOfNames(IWshEnvironment *iface, REFIID riid, LPOLESTR *rgszNames, 411 UINT cNames, LCID lcid, DISPID *rgDispId) 412 { 413 WshEnvironment *This = impl_from_IWshEnvironment(iface); 414 ITypeInfo *typeinfo; 415 HRESULT hr; 416 417 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId); 418 419 hr = get_typeinfo(IWshEnvironment_tid, &typeinfo); 420 if(SUCCEEDED(hr)) 421 { 422 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId); 423 ITypeInfo_Release(typeinfo); 424 } 425 426 return hr; 427 } 428 429 static HRESULT WINAPI WshEnvironment_Invoke(IWshEnvironment *iface, DISPID dispIdMember, REFIID riid, LCID lcid, 430 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) 431 { 432 WshEnvironment *This = impl_from_IWshEnvironment(iface); 433 ITypeInfo *typeinfo; 434 HRESULT hr; 435 436 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid), 437 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); 438 439 hr = get_typeinfo(IWshEnvironment_tid, &typeinfo); 440 if(SUCCEEDED(hr)) 441 { 442 hr = ITypeInfo_Invoke(typeinfo, &This->IWshEnvironment_iface, dispIdMember, wFlags, 443 pDispParams, pVarResult, pExcepInfo, puArgErr); 444 ITypeInfo_Release(typeinfo); 445 } 446 447 return hr; 448 } 449 450 static HRESULT WINAPI WshEnvironment_get_Item(IWshEnvironment *iface, BSTR name, BSTR *value) 451 { 452 WshEnvironment *This = impl_from_IWshEnvironment(iface); 453 DWORD len; 454 455 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), value); 456 457 if (!value) 458 return E_POINTER; 459 460 len = GetEnvironmentVariableW(name, NULL, 0); 461 if (len) 462 { 463 *value = SysAllocStringLen(NULL, len - 1); 464 if (*value) 465 GetEnvironmentVariableW(name, *value, len); 466 } 467 else 468 *value = SysAllocStringLen(NULL, 0); 469 470 return *value ? S_OK : E_OUTOFMEMORY; 471 } 472 473 static HRESULT WINAPI WshEnvironment_put_Item(IWshEnvironment *iface, BSTR name, BSTR value) 474 { 475 WshEnvironment *This = impl_from_IWshEnvironment(iface); 476 FIXME("(%p)->(%s %s): stub\n", This, debugstr_w(name), debugstr_w(value)); 477 return E_NOTIMPL; 478 } 479 480 static HRESULT WINAPI WshEnvironment_Count(IWshEnvironment *iface, LONG *count) 481 { 482 WshEnvironment *This = impl_from_IWshEnvironment(iface); 483 FIXME("(%p)->(%p): stub\n", This, count); 484 return E_NOTIMPL; 485 } 486 487 static HRESULT WINAPI WshEnvironment_get_length(IWshEnvironment *iface, LONG *len) 488 { 489 WshEnvironment *This = impl_from_IWshEnvironment(iface); 490 FIXME("(%p)->(%p): stub\n", This, len); 491 return E_NOTIMPL; 492 } 493 494 static HRESULT WINAPI WshEnvironment__NewEnum(IWshEnvironment *iface, IUnknown **penum) 495 { 496 WshEnvironment *This = impl_from_IWshEnvironment(iface); 497 FIXME("(%p)->(%p): stub\n", This, penum); 498 return E_NOTIMPL; 499 } 500 501 static HRESULT WINAPI WshEnvironment_Remove(IWshEnvironment *iface, BSTR name) 502 { 503 WshEnvironment *This = impl_from_IWshEnvironment(iface); 504 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name)); 505 return E_NOTIMPL; 506 } 507 508 static const IWshEnvironmentVtbl WshEnvironmentVtbl = { 509 WshEnvironment_QueryInterface, 510 WshEnvironment_AddRef, 511 WshEnvironment_Release, 512 WshEnvironment_GetTypeInfoCount, 513 WshEnvironment_GetTypeInfo, 514 WshEnvironment_GetIDsOfNames, 515 WshEnvironment_Invoke, 516 WshEnvironment_get_Item, 517 WshEnvironment_put_Item, 518 WshEnvironment_Count, 519 WshEnvironment_get_length, 520 WshEnvironment__NewEnum, 521 WshEnvironment_Remove 522 }; 523 524 static HRESULT WshEnvironment_Create(IWshEnvironment **env) 525 { 526 WshEnvironment *This; 527 528 This = heap_alloc(sizeof(*This)); 529 if (!This) return E_OUTOFMEMORY; 530 531 This->IWshEnvironment_iface.lpVtbl = &WshEnvironmentVtbl; 532 This->ref = 1; 533 534 init_classinfo(&IID_IWshEnvironment, (IUnknown *)&This->IWshEnvironment_iface, &This->classinfo); 535 *env = &This->IWshEnvironment_iface; 536 537 return S_OK; 538 } 539 540 static HRESULT WINAPI WshCollection_QueryInterface(IWshCollection *iface, REFIID riid, void **ppv) 541 { 542 WshCollection *This = impl_from_IWshCollection(iface); 543 544 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv); 545 546 if (IsEqualGUID(riid, &IID_IUnknown) || 547 IsEqualGUID(riid, &IID_IDispatch) || 548 IsEqualGUID(riid, &IID_IWshCollection)) 549 { 550 *ppv = iface; 551 } 552 else if (IsEqualIID(riid, &IID_IProvideClassInfo)) 553 { 554 *ppv = &This->classinfo.IProvideClassInfo_iface; 555 } 556 else { 557 FIXME("Unknown iface %s\n", debugstr_guid(riid)); 558 *ppv = NULL; 559 return E_NOINTERFACE; 560 } 561 562 IUnknown_AddRef((IUnknown*)*ppv); 563 return S_OK; 564 } 565 566 static ULONG WINAPI WshCollection_AddRef(IWshCollection *iface) 567 { 568 WshCollection *This = impl_from_IWshCollection(iface); 569 LONG ref = InterlockedIncrement(&This->ref); 570 TRACE("(%p) ref = %d\n", This, ref); 571 return ref; 572 } 573 574 static ULONG WINAPI WshCollection_Release(IWshCollection *iface) 575 { 576 WshCollection *This = impl_from_IWshCollection(iface); 577 LONG ref = InterlockedDecrement(&This->ref); 578 TRACE("(%p) ref = %d\n", This, ref); 579 580 if (!ref) 581 heap_free(This); 582 583 return ref; 584 } 585 586 static HRESULT WINAPI WshCollection_GetTypeInfoCount(IWshCollection *iface, UINT *pctinfo) 587 { 588 WshCollection *This = impl_from_IWshCollection(iface); 589 TRACE("(%p)->(%p)\n", This, pctinfo); 590 *pctinfo = 1; 591 return S_OK; 592 } 593 594 static HRESULT WINAPI WshCollection_GetTypeInfo(IWshCollection *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) 595 { 596 WshCollection *This = impl_from_IWshCollection(iface); 597 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo); 598 return get_typeinfo(IWshCollection_tid, ppTInfo); 599 } 600 601 static HRESULT WINAPI WshCollection_GetIDsOfNames(IWshCollection *iface, REFIID riid, LPOLESTR *rgszNames, 602 UINT cNames, LCID lcid, DISPID *rgDispId) 603 { 604 WshCollection *This = impl_from_IWshCollection(iface); 605 ITypeInfo *typeinfo; 606 HRESULT hr; 607 608 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId); 609 610 hr = get_typeinfo(IWshCollection_tid, &typeinfo); 611 if(SUCCEEDED(hr)) 612 { 613 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId); 614 ITypeInfo_Release(typeinfo); 615 } 616 617 return hr; 618 } 619 620 static HRESULT WINAPI WshCollection_Invoke(IWshCollection *iface, DISPID dispIdMember, REFIID riid, LCID lcid, 621 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) 622 { 623 WshCollection *This = impl_from_IWshCollection(iface); 624 ITypeInfo *typeinfo; 625 HRESULT hr; 626 627 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid), 628 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); 629 630 hr = get_typeinfo(IWshCollection_tid, &typeinfo); 631 if(SUCCEEDED(hr)) 632 { 633 hr = ITypeInfo_Invoke(typeinfo, &This->IWshCollection_iface, dispIdMember, wFlags, 634 pDispParams, pVarResult, pExcepInfo, puArgErr); 635 ITypeInfo_Release(typeinfo); 636 } 637 638 return hr; 639 } 640 641 static HRESULT WINAPI WshCollection_Item(IWshCollection *iface, VARIANT *index, VARIANT *value) 642 { 643 WshCollection *This = impl_from_IWshCollection(iface); 644 static const WCHAR allusersdesktopW[] = {'A','l','l','U','s','e','r','s','D','e','s','k','t','o','p',0}; 645 static const WCHAR allusersprogramsW[] = {'A','l','l','U','s','e','r','s','P','r','o','g','r','a','m','s',0}; 646 static const WCHAR desktopW[] = {'D','e','s','k','t','o','p',0}; 647 PIDLIST_ABSOLUTE pidl; 648 WCHAR pathW[MAX_PATH]; 649 int kind = 0; 650 BSTR folder; 651 HRESULT hr; 652 653 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(index), value); 654 655 if (V_VT(index) != VT_BSTR) 656 { 657 FIXME("only BSTR index supported, got %d\n", V_VT(index)); 658 return E_NOTIMPL; 659 } 660 661 folder = V_BSTR(index); 662 if (!wcsicmp(folder, desktopW)) 663 kind = CSIDL_DESKTOP; 664 else if (!wcsicmp(folder, allusersdesktopW)) 665 kind = CSIDL_COMMON_DESKTOPDIRECTORY; 666 else if (!wcsicmp(folder, allusersprogramsW)) 667 kind = CSIDL_COMMON_PROGRAMS; 668 else 669 { 670 FIXME("folder kind %s not supported\n", debugstr_w(folder)); 671 return E_NOTIMPL; 672 } 673 674 hr = SHGetSpecialFolderLocation(NULL, kind, &pidl); 675 if (hr != S_OK) return hr; 676 677 if (SHGetPathFromIDListW(pidl, pathW)) 678 { 679 V_VT(value) = VT_BSTR; 680 V_BSTR(value) = SysAllocString(pathW); 681 hr = V_BSTR(value) ? S_OK : E_OUTOFMEMORY; 682 } 683 else 684 hr = E_FAIL; 685 686 CoTaskMemFree(pidl); 687 688 return hr; 689 } 690 691 static HRESULT WINAPI WshCollection_Count(IWshCollection *iface, LONG *count) 692 { 693 WshCollection *This = impl_from_IWshCollection(iface); 694 FIXME("(%p)->(%p): stub\n", This, count); 695 return E_NOTIMPL; 696 } 697 698 static HRESULT WINAPI WshCollection_get_length(IWshCollection *iface, LONG *count) 699 { 700 WshCollection *This = impl_from_IWshCollection(iface); 701 FIXME("(%p)->(%p): stub\n", This, count); 702 return E_NOTIMPL; 703 } 704 705 static HRESULT WINAPI WshCollection__NewEnum(IWshCollection *iface, IUnknown **Enum) 706 { 707 WshCollection *This = impl_from_IWshCollection(iface); 708 FIXME("(%p)->(%p): stub\n", This, Enum); 709 return E_NOTIMPL; 710 } 711 712 static const IWshCollectionVtbl WshCollectionVtbl = { 713 WshCollection_QueryInterface, 714 WshCollection_AddRef, 715 WshCollection_Release, 716 WshCollection_GetTypeInfoCount, 717 WshCollection_GetTypeInfo, 718 WshCollection_GetIDsOfNames, 719 WshCollection_Invoke, 720 WshCollection_Item, 721 WshCollection_Count, 722 WshCollection_get_length, 723 WshCollection__NewEnum 724 }; 725 726 static HRESULT WshCollection_Create(IWshCollection **collection) 727 { 728 WshCollection *This; 729 730 This = heap_alloc(sizeof(*This)); 731 if (!This) return E_OUTOFMEMORY; 732 733 This->IWshCollection_iface.lpVtbl = &WshCollectionVtbl; 734 This->ref = 1; 735 736 init_classinfo(&IID_IWshCollection, (IUnknown *)&This->IWshCollection_iface, &This->classinfo); 737 *collection = &This->IWshCollection_iface; 738 739 return S_OK; 740 } 741 742 /* IWshShortcut */ 743 static HRESULT WINAPI WshShortcut_QueryInterface(IWshShortcut *iface, REFIID riid, void **ppv) 744 { 745 WshShortcut *This = impl_from_IWshShortcut(iface); 746 747 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv); 748 749 if (IsEqualGUID(riid, &IID_IUnknown) || 750 IsEqualGUID(riid, &IID_IDispatch) || 751 IsEqualGUID(riid, &IID_IWshShortcut)) 752 { 753 *ppv = iface; 754 } 755 else if (IsEqualIID(riid, &IID_IProvideClassInfo)) 756 { 757 *ppv = &This->classinfo.IProvideClassInfo_iface; 758 } 759 else { 760 FIXME("Unknown iface %s\n", debugstr_guid(riid)); 761 *ppv = NULL; 762 return E_NOINTERFACE; 763 } 764 765 IUnknown_AddRef((IUnknown*)*ppv); 766 return S_OK; 767 } 768 769 static ULONG WINAPI WshShortcut_AddRef(IWshShortcut *iface) 770 { 771 WshShortcut *This = impl_from_IWshShortcut(iface); 772 LONG ref = InterlockedIncrement(&This->ref); 773 TRACE("(%p) ref = %d\n", This, ref); 774 return ref; 775 } 776 777 static ULONG WINAPI WshShortcut_Release(IWshShortcut *iface) 778 { 779 WshShortcut *This = impl_from_IWshShortcut(iface); 780 LONG ref = InterlockedDecrement(&This->ref); 781 TRACE("(%p) ref = %d\n", This, ref); 782 783 if (!ref) 784 { 785 SysFreeString(This->path_link); 786 IShellLinkW_Release(This->link); 787 heap_free(This); 788 } 789 790 return ref; 791 } 792 793 static HRESULT WINAPI WshShortcut_GetTypeInfoCount(IWshShortcut *iface, UINT *pctinfo) 794 { 795 WshShortcut *This = impl_from_IWshShortcut(iface); 796 TRACE("(%p)->(%p)\n", This, pctinfo); 797 *pctinfo = 1; 798 return S_OK; 799 } 800 801 static HRESULT WINAPI WshShortcut_GetTypeInfo(IWshShortcut *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) 802 { 803 WshShortcut *This = impl_from_IWshShortcut(iface); 804 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo); 805 return get_typeinfo(IWshShortcut_tid, ppTInfo); 806 } 807 808 static HRESULT WINAPI WshShortcut_GetIDsOfNames(IWshShortcut *iface, REFIID riid, LPOLESTR *rgszNames, 809 UINT cNames, LCID lcid, DISPID *rgDispId) 810 { 811 WshShortcut *This = impl_from_IWshShortcut(iface); 812 ITypeInfo *typeinfo; 813 HRESULT hr; 814 815 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId); 816 817 hr = get_typeinfo(IWshShortcut_tid, &typeinfo); 818 if(SUCCEEDED(hr)) 819 { 820 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId); 821 ITypeInfo_Release(typeinfo); 822 } 823 824 return hr; 825 } 826 827 static HRESULT WINAPI WshShortcut_Invoke(IWshShortcut *iface, DISPID dispIdMember, REFIID riid, LCID lcid, 828 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) 829 { 830 WshShortcut *This = impl_from_IWshShortcut(iface); 831 ITypeInfo *typeinfo; 832 HRESULT hr; 833 834 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid), 835 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); 836 837 hr = get_typeinfo(IWshShortcut_tid, &typeinfo); 838 if(SUCCEEDED(hr)) 839 { 840 hr = ITypeInfo_Invoke(typeinfo, &This->IWshShortcut_iface, dispIdMember, wFlags, 841 pDispParams, pVarResult, pExcepInfo, puArgErr); 842 ITypeInfo_Release(typeinfo); 843 } 844 845 return hr; 846 } 847 848 static HRESULT WINAPI WshShortcut_get_FullName(IWshShortcut *iface, BSTR *name) 849 { 850 WshShortcut *This = impl_from_IWshShortcut(iface); 851 FIXME("(%p)->(%p): stub\n", This, name); 852 return E_NOTIMPL; 853 } 854 855 static HRESULT WINAPI WshShortcut_get_Arguments(IWshShortcut *iface, BSTR *Arguments) 856 { 857 WshShortcut *This = impl_from_IWshShortcut(iface); 858 WCHAR buffW[INFOTIPSIZE]; 859 HRESULT hr; 860 861 TRACE("(%p)->(%p)\n", This, Arguments); 862 863 if (!Arguments) 864 return E_POINTER; 865 866 *Arguments = NULL; 867 868 hr = IShellLinkW_GetArguments(This->link, buffW, ARRAY_SIZE(buffW)); 869 if (FAILED(hr)) 870 return hr; 871 872 *Arguments = SysAllocString(buffW); 873 return *Arguments ? S_OK : E_OUTOFMEMORY; 874 } 875 876 static HRESULT WINAPI WshShortcut_put_Arguments(IWshShortcut *iface, BSTR Arguments) 877 { 878 WshShortcut *This = impl_from_IWshShortcut(iface); 879 880 TRACE("(%p)->(%s)\n", This, debugstr_w(Arguments)); 881 882 return IShellLinkW_SetArguments(This->link, Arguments); 883 } 884 885 static HRESULT WINAPI WshShortcut_get_Description(IWshShortcut *iface, BSTR *Description) 886 { 887 WshShortcut *This = impl_from_IWshShortcut(iface); 888 FIXME("(%p)->(%p): stub\n", This, Description); 889 return E_NOTIMPL; 890 } 891 892 static HRESULT WINAPI WshShortcut_put_Description(IWshShortcut *iface, BSTR Description) 893 { 894 WshShortcut *This = impl_from_IWshShortcut(iface); 895 TRACE("(%p)->(%s)\n", This, debugstr_w(Description)); 896 return IShellLinkW_SetDescription(This->link, Description); 897 } 898 899 static HRESULT WINAPI WshShortcut_get_Hotkey(IWshShortcut *iface, BSTR *Hotkey) 900 { 901 WshShortcut *This = impl_from_IWshShortcut(iface); 902 FIXME("(%p)->(%p): stub\n", This, Hotkey); 903 return E_NOTIMPL; 904 } 905 906 static HRESULT WINAPI WshShortcut_put_Hotkey(IWshShortcut *iface, BSTR Hotkey) 907 { 908 WshShortcut *This = impl_from_IWshShortcut(iface); 909 FIXME("(%p)->(%s): stub\n", This, debugstr_w(Hotkey)); 910 return E_NOTIMPL; 911 } 912 913 static HRESULT WINAPI WshShortcut_get_IconLocation(IWshShortcut *iface, BSTR *IconPath) 914 { 915 static const WCHAR fmtW[] = {'%','s',',',' ','%','d',0}; 916 WshShortcut *This = impl_from_IWshShortcut(iface); 917 WCHAR buffW[MAX_PATH], pathW[MAX_PATH]; 918 INT icon = 0; 919 HRESULT hr; 920 921 TRACE("(%p)->(%p)\n", This, IconPath); 922 923 if (!IconPath) 924 return E_POINTER; 925 926 hr = IShellLinkW_GetIconLocation(This->link, buffW, ARRAY_SIZE(buffW), &icon); 927 if (FAILED(hr)) return hr; 928 929 swprintf(pathW, fmtW, buffW, icon); 930 *IconPath = SysAllocString(pathW); 931 if (!*IconPath) return E_OUTOFMEMORY; 932 933 return S_OK; 934 } 935 936 static HRESULT WINAPI WshShortcut_put_IconLocation(IWshShortcut *iface, BSTR IconPath) 937 { 938 WshShortcut *This = impl_from_IWshShortcut(iface); 939 HRESULT hr; 940 WCHAR *ptr; 941 BSTR path; 942 INT icon; 943 944 TRACE("(%p)->(%s)\n", This, debugstr_w(IconPath)); 945 946 /* scan for icon id */ 947 ptr = wcsrchr(IconPath, ','); 948 if (!ptr) 949 { 950 WARN("icon index not found\n"); 951 return E_FAIL; 952 } 953 954 path = SysAllocStringLen(IconPath, ptr-IconPath); 955 956 /* skip spaces if any */ 957 while (iswspace(*++ptr)) 958 ; 959 960 icon = wcstol(ptr, NULL, 10); 961 962 hr = IShellLinkW_SetIconLocation(This->link, path, icon); 963 SysFreeString(path); 964 965 return hr; 966 } 967 968 static HRESULT WINAPI WshShortcut_put_RelativePath(IWshShortcut *iface, BSTR rhs) 969 { 970 WshShortcut *This = impl_from_IWshShortcut(iface); 971 FIXME("(%p)->(%s): stub\n", This, debugstr_w(rhs)); 972 return E_NOTIMPL; 973 } 974 975 static HRESULT WINAPI WshShortcut_get_TargetPath(IWshShortcut *iface, BSTR *Path) 976 { 977 WshShortcut *This = impl_from_IWshShortcut(iface); 978 FIXME("(%p)->(%p): stub\n", This, Path); 979 return E_NOTIMPL; 980 } 981 982 static HRESULT WINAPI WshShortcut_put_TargetPath(IWshShortcut *iface, BSTR Path) 983 { 984 WshShortcut *This = impl_from_IWshShortcut(iface); 985 TRACE("(%p)->(%s)\n", This, debugstr_w(Path)); 986 return IShellLinkW_SetPath(This->link, Path); 987 } 988 989 static HRESULT WINAPI WshShortcut_get_WindowStyle(IWshShortcut *iface, int *ShowCmd) 990 { 991 WshShortcut *This = impl_from_IWshShortcut(iface); 992 TRACE("(%p)->(%p)\n", This, ShowCmd); 993 return IShellLinkW_GetShowCmd(This->link, ShowCmd); 994 } 995 996 static HRESULT WINAPI WshShortcut_put_WindowStyle(IWshShortcut *iface, int ShowCmd) 997 { 998 WshShortcut *This = impl_from_IWshShortcut(iface); 999 TRACE("(%p)->(%d)\n", This, ShowCmd); 1000 return IShellLinkW_SetShowCmd(This->link, ShowCmd); 1001 } 1002 1003 static HRESULT WINAPI WshShortcut_get_WorkingDirectory(IWshShortcut *iface, BSTR *WorkingDirectory) 1004 { 1005 WshShortcut *This = impl_from_IWshShortcut(iface); 1006 WCHAR buffW[MAX_PATH]; 1007 HRESULT hr; 1008 1009 TRACE("(%p)->(%p)\n", This, WorkingDirectory); 1010 1011 if (!WorkingDirectory) 1012 return E_POINTER; 1013 1014 *WorkingDirectory = NULL; 1015 hr = IShellLinkW_GetWorkingDirectory(This->link, buffW, ARRAY_SIZE(buffW)); 1016 if (FAILED(hr)) return hr; 1017 1018 *WorkingDirectory = SysAllocString(buffW); 1019 return *WorkingDirectory ? S_OK : E_OUTOFMEMORY; 1020 } 1021 1022 static HRESULT WINAPI WshShortcut_put_WorkingDirectory(IWshShortcut *iface, BSTR WorkingDirectory) 1023 { 1024 WshShortcut *This = impl_from_IWshShortcut(iface); 1025 TRACE("(%p)->(%s)\n", This, debugstr_w(WorkingDirectory)); 1026 return IShellLinkW_SetWorkingDirectory(This->link, WorkingDirectory); 1027 } 1028 1029 static HRESULT WINAPI WshShortcut_Load(IWshShortcut *iface, BSTR PathLink) 1030 { 1031 WshShortcut *This = impl_from_IWshShortcut(iface); 1032 FIXME("(%p)->(%s): stub\n", This, debugstr_w(PathLink)); 1033 return E_NOTIMPL; 1034 } 1035 1036 static HRESULT WINAPI WshShortcut_Save(IWshShortcut *iface) 1037 { 1038 WshShortcut *This = impl_from_IWshShortcut(iface); 1039 IPersistFile *file; 1040 HRESULT hr; 1041 1042 TRACE("(%p)\n", This); 1043 1044 IShellLinkW_QueryInterface(This->link, &IID_IPersistFile, (void**)&file); 1045 hr = IPersistFile_Save(file, This->path_link, TRUE); 1046 IPersistFile_Release(file); 1047 1048 return hr; 1049 } 1050 1051 static const IWshShortcutVtbl WshShortcutVtbl = { 1052 WshShortcut_QueryInterface, 1053 WshShortcut_AddRef, 1054 WshShortcut_Release, 1055 WshShortcut_GetTypeInfoCount, 1056 WshShortcut_GetTypeInfo, 1057 WshShortcut_GetIDsOfNames, 1058 WshShortcut_Invoke, 1059 WshShortcut_get_FullName, 1060 WshShortcut_get_Arguments, 1061 WshShortcut_put_Arguments, 1062 WshShortcut_get_Description, 1063 WshShortcut_put_Description, 1064 WshShortcut_get_Hotkey, 1065 WshShortcut_put_Hotkey, 1066 WshShortcut_get_IconLocation, 1067 WshShortcut_put_IconLocation, 1068 WshShortcut_put_RelativePath, 1069 WshShortcut_get_TargetPath, 1070 WshShortcut_put_TargetPath, 1071 WshShortcut_get_WindowStyle, 1072 WshShortcut_put_WindowStyle, 1073 WshShortcut_get_WorkingDirectory, 1074 WshShortcut_put_WorkingDirectory, 1075 WshShortcut_Load, 1076 WshShortcut_Save 1077 }; 1078 1079 static HRESULT WshShortcut_Create(const WCHAR *path, IDispatch **shortcut) 1080 { 1081 WshShortcut *This; 1082 HRESULT hr; 1083 1084 *shortcut = NULL; 1085 1086 This = heap_alloc(sizeof(*This)); 1087 if (!This) return E_OUTOFMEMORY; 1088 1089 This->IWshShortcut_iface.lpVtbl = &WshShortcutVtbl; 1090 This->ref = 1; 1091 1092 hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, 1093 &IID_IShellLinkW, (void**)&This->link); 1094 if (FAILED(hr)) 1095 { 1096 heap_free(This); 1097 return hr; 1098 } 1099 1100 This->path_link = SysAllocString(path); 1101 if (!This->path_link) 1102 { 1103 IShellLinkW_Release(This->link); 1104 heap_free(This); 1105 return E_OUTOFMEMORY; 1106 } 1107 1108 init_classinfo(&IID_IWshShortcut, (IUnknown *)&This->IWshShortcut_iface, &This->classinfo); 1109 *shortcut = (IDispatch*)&This->IWshShortcut_iface; 1110 1111 return S_OK; 1112 } 1113 1114 static HRESULT WINAPI WshShell3_QueryInterface(IWshShell3 *iface, REFIID riid, void **ppv) 1115 { 1116 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv); 1117 1118 *ppv = NULL; 1119 1120 if (IsEqualGUID(riid, &IID_IDispatch) || 1121 IsEqualGUID(riid, &IID_IWshShell3) || 1122 IsEqualGUID(riid, &IID_IWshShell2) || 1123 IsEqualGUID(riid, &IID_IWshShell) || 1124 IsEqualGUID(riid, &IID_IUnknown)) 1125 { 1126 *ppv = iface; 1127 } 1128 else if (IsEqualGUID(riid, &IID_IDispatchEx)) 1129 { 1130 return E_NOINTERFACE; 1131 } 1132 else if (IsEqualIID(riid, &IID_IProvideClassInfo)) 1133 { 1134 *ppv = &WshShell3.classinfo.IProvideClassInfo_iface; 1135 } 1136 else 1137 { 1138 WARN("unknown iface %s\n", debugstr_guid(riid)); 1139 return E_NOINTERFACE; 1140 } 1141 1142 IUnknown_AddRef((IUnknown *)*ppv); 1143 return S_OK; 1144 } 1145 1146 static ULONG WINAPI WshShell3_AddRef(IWshShell3 *iface) 1147 { 1148 TRACE("()\n"); 1149 return 2; 1150 } 1151 1152 static ULONG WINAPI WshShell3_Release(IWshShell3 *iface) 1153 { 1154 TRACE("()\n"); 1155 return 2; 1156 } 1157 1158 static HRESULT WINAPI WshShell3_GetTypeInfoCount(IWshShell3 *iface, UINT *pctinfo) 1159 { 1160 TRACE("(%p)\n", pctinfo); 1161 *pctinfo = 1; 1162 return S_OK; 1163 } 1164 1165 static HRESULT WINAPI WshShell3_GetTypeInfo(IWshShell3 *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) 1166 { 1167 TRACE("(%u %u %p)\n", iTInfo, lcid, ppTInfo); 1168 return get_typeinfo(IWshShell3_tid, ppTInfo); 1169 } 1170 1171 static HRESULT WINAPI WshShell3_GetIDsOfNames(IWshShell3 *iface, REFIID riid, LPOLESTR *rgszNames, 1172 UINT cNames, LCID lcid, DISPID *rgDispId) 1173 { 1174 ITypeInfo *typeinfo; 1175 HRESULT hr; 1176 1177 TRACE("(%s %p %u %u %p)\n", debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId); 1178 1179 hr = get_typeinfo(IWshShell3_tid, &typeinfo); 1180 if(SUCCEEDED(hr)) 1181 { 1182 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId); 1183 ITypeInfo_Release(typeinfo); 1184 } 1185 1186 return hr; 1187 } 1188 1189 static HRESULT WINAPI WshShell3_Invoke(IWshShell3 *iface, DISPID dispIdMember, REFIID riid, LCID lcid, 1190 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) 1191 { 1192 ITypeInfo *typeinfo; 1193 HRESULT hr; 1194 1195 TRACE("(%d %s %d %d %p %p %p %p)\n", dispIdMember, debugstr_guid(riid), 1196 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); 1197 1198 hr = get_typeinfo(IWshShell3_tid, &typeinfo); 1199 if(SUCCEEDED(hr)) 1200 { 1201 hr = ITypeInfo_Invoke(typeinfo, &WshShell3.IWshShell3_iface, dispIdMember, wFlags, 1202 pDispParams, pVarResult, pExcepInfo, puArgErr); 1203 ITypeInfo_Release(typeinfo); 1204 } 1205 1206 return hr; 1207 } 1208 1209 static HRESULT WINAPI WshShell3_get_SpecialFolders(IWshShell3 *iface, IWshCollection **folders) 1210 { 1211 TRACE("(%p)\n", folders); 1212 return WshCollection_Create(folders); 1213 } 1214 1215 static HRESULT WINAPI WshShell3_get_Environment(IWshShell3 *iface, VARIANT *type, IWshEnvironment **env) 1216 { 1217 FIXME("(%s %p): semi-stub\n", debugstr_variant(type), env); 1218 return WshEnvironment_Create(env); 1219 } 1220 1221 static inline BOOL is_optional_argument(const VARIANT *arg) 1222 { 1223 return V_VT(arg) == VT_ERROR && V_ERROR(arg) == DISP_E_PARAMNOTFOUND; 1224 } 1225 1226 static WCHAR *split_command( BSTR cmd, WCHAR **params ) 1227 { 1228 WCHAR *ret, *ptr; 1229 BOOL in_quotes = FALSE; 1230 1231 if (!(ret = heap_alloc((lstrlenW(cmd) + 1) * sizeof(WCHAR)))) return NULL; 1232 lstrcpyW( ret, cmd ); 1233 1234 *params = NULL; 1235 for (ptr = ret; *ptr; ptr++) 1236 { 1237 if (*ptr == '"') in_quotes = !in_quotes; 1238 else if (*ptr == ' ' && !in_quotes) 1239 { 1240 *ptr = 0; 1241 *params = ptr + 1; 1242 break; 1243 } 1244 } 1245 1246 return ret; 1247 } 1248 1249 static HRESULT WINAPI WshShell3_Run(IWshShell3 *iface, BSTR cmd, VARIANT *style, VARIANT *wait, DWORD *exit_code) 1250 { 1251 SHELLEXECUTEINFOW info; 1252 int waitforprocess; 1253 WCHAR *file, *params; 1254 VARIANT s; 1255 HRESULT hr; 1256 BOOL ret; 1257 1258 TRACE("(%s %s %s %p)\n", debugstr_w(cmd), debugstr_variant(style), debugstr_variant(wait), exit_code); 1259 1260 if (!style || !wait || !exit_code) 1261 return E_POINTER; 1262 1263 VariantInit(&s); 1264 hr = VariantChangeType(&s, style, 0, VT_I4); 1265 if (FAILED(hr)) 1266 { 1267 ERR("failed to convert style argument, 0x%08x\n", hr); 1268 return hr; 1269 } 1270 1271 if (is_optional_argument(wait)) 1272 waitforprocess = 0; 1273 else { 1274 VARIANT w; 1275 1276 VariantInit(&w); 1277 hr = VariantChangeType(&w, wait, 0, VT_I4); 1278 if (FAILED(hr)) 1279 return hr; 1280 1281 waitforprocess = V_I4(&w); 1282 } 1283 1284 if (!(file = split_command(cmd, ¶ms))) return E_OUTOFMEMORY; 1285 1286 memset(&info, 0, sizeof(info)); 1287 info.cbSize = sizeof(info); 1288 info.fMask = waitforprocess ? SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS : SEE_MASK_DEFAULT; 1289 info.lpFile = file; 1290 info.lpParameters = params; 1291 info.nShow = V_I4(&s); 1292 1293 ret = ShellExecuteExW(&info); 1294 heap_free( file ); 1295 if (!ret) 1296 { 1297 TRACE("ShellExecute failed, %d\n", GetLastError()); 1298 return HRESULT_FROM_WIN32(GetLastError()); 1299 } 1300 else 1301 { 1302 if (waitforprocess) 1303 { 1304 WaitForSingleObject(info.hProcess, INFINITE); 1305 GetExitCodeProcess(info.hProcess, exit_code); 1306 CloseHandle(info.hProcess); 1307 } 1308 else 1309 *exit_code = 0; 1310 1311 return S_OK; 1312 } 1313 } 1314 1315 struct popup_thread_param 1316 { 1317 WCHAR *text; 1318 VARIANT title; 1319 VARIANT type; 1320 INT button; 1321 }; 1322 1323 static DWORD WINAPI popup_thread_proc(void *arg) 1324 { 1325 static const WCHAR defaulttitleW[] = {'W','i','n','d','o','w','s',' ','S','c','r','i','p','t',' ','H','o','s','t',0}; 1326 struct popup_thread_param *param = (struct popup_thread_param *)arg; 1327 1328 param->button = MessageBoxW(NULL, param->text, is_optional_argument(¶m->title) ? 1329 defaulttitleW : V_BSTR(¶m->title), V_I4(¶m->type)); 1330 return 0; 1331 } 1332 1333 static HRESULT WINAPI WshShell3_Popup(IWshShell3 *iface, BSTR text, VARIANT *seconds_to_wait, VARIANT *title, 1334 VARIANT *type, int *button) 1335 { 1336 struct popup_thread_param param; 1337 DWORD tid, status; 1338 VARIANT timeout; 1339 HANDLE hthread; 1340 HRESULT hr; 1341 1342 TRACE("(%s %s %s %s %p)\n", debugstr_w(text), debugstr_variant(seconds_to_wait), debugstr_variant(title), 1343 debugstr_variant(type), button); 1344 1345 if (!seconds_to_wait || !title || !type || !button) 1346 return E_POINTER; 1347 1348 VariantInit(&timeout); 1349 if (!is_optional_argument(seconds_to_wait)) 1350 { 1351 hr = VariantChangeType(&timeout, seconds_to_wait, 0, VT_I4); 1352 if (FAILED(hr)) 1353 return hr; 1354 } 1355 #ifdef __REACTOS__ 1356 else 1357 { 1358 VariantChangeType(&timeout, &timeout, 0, VT_I4); 1359 } 1360 #endif 1361 1362 VariantInit(¶m.type); 1363 if (!is_optional_argument(type)) 1364 { 1365 hr = VariantChangeType(¶m.type, type, 0, VT_I4); 1366 if (FAILED(hr)) 1367 return hr; 1368 } 1369 #ifdef __REACTOS__ 1370 else 1371 { 1372 VariantChangeType(¶m.type, ¶m.type, 0, VT_I4); 1373 } 1374 #endif 1375 1376 if (is_optional_argument(title)) 1377 param.title = *title; 1378 else 1379 { 1380 VariantInit(¶m.title); 1381 hr = VariantChangeType(¶m.title, title, 0, VT_BSTR); 1382 if (FAILED(hr)) 1383 return hr; 1384 } 1385 1386 param.text = text; 1387 param.button = -1; 1388 hthread = CreateThread(NULL, 0, popup_thread_proc, ¶m, 0, &tid); 1389 status = MsgWaitForMultipleObjects(1, &hthread, FALSE, V_I4(&timeout) ? V_I4(&timeout) * 1000: INFINITE, 0); 1390 if (status == WAIT_TIMEOUT) 1391 { 1392 PostThreadMessageW(tid, WM_QUIT, 0, 0); 1393 MsgWaitForMultipleObjects(1, &hthread, FALSE, INFINITE, 0); 1394 param.button = -1; 1395 } 1396 *button = param.button; 1397 1398 VariantClear(¶m.title); 1399 CloseHandle(hthread); 1400 1401 return S_OK; 1402 } 1403 1404 static HRESULT WINAPI WshShell3_CreateShortcut(IWshShell3 *iface, BSTR PathLink, IDispatch** Shortcut) 1405 { 1406 TRACE("(%s %p)\n", debugstr_w(PathLink), Shortcut); 1407 return WshShortcut_Create(PathLink, Shortcut); 1408 } 1409 1410 static HRESULT WINAPI WshShell3_ExpandEnvironmentStrings(IWshShell3 *iface, BSTR Src, BSTR* Dst) 1411 { 1412 DWORD ret; 1413 1414 TRACE("(%s %p)\n", debugstr_w(Src), Dst); 1415 1416 if (!Src || !Dst) return E_POINTER; 1417 1418 ret = ExpandEnvironmentStringsW(Src, NULL, 0); 1419 *Dst = SysAllocStringLen(NULL, ret); 1420 if (!*Dst) return E_OUTOFMEMORY; 1421 1422 if (ExpandEnvironmentStringsW(Src, *Dst, ret)) 1423 return S_OK; 1424 else 1425 { 1426 SysFreeString(*Dst); 1427 *Dst = NULL; 1428 return HRESULT_FROM_WIN32(GetLastError()); 1429 } 1430 } 1431 1432 static HKEY get_root_key(const WCHAR *path) 1433 { 1434 static const struct { 1435 const WCHAR full[20]; 1436 const WCHAR abbrev[5]; 1437 HKEY hkey; 1438 } rootkeys[] = { 1439 { {'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R',0}, {'H','K','C','U',0}, HKEY_CURRENT_USER }, 1440 { {'H','K','E','Y','_','L','O','C','A','L','_','M','A','C','H','I','N','E',0}, {'H','K','L','M',0}, HKEY_LOCAL_MACHINE }, 1441 { {'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T',0}, {'H','K','C','R',0}, HKEY_CLASSES_ROOT }, 1442 { {'H','K','E','Y','_','U','S','E','R','S',0}, {0}, HKEY_USERS }, 1443 { {'H','K','E','Y','_','C','U','R','R','E','N','T','_','C','O','N','F','I','G',0}, {0}, HKEY_CURRENT_CONFIG } 1444 }; 1445 int i; 1446 1447 for (i = 0; i < ARRAY_SIZE(rootkeys); i++) { 1448 if (!wcsncmp(path, rootkeys[i].full, lstrlenW(rootkeys[i].full))) 1449 return rootkeys[i].hkey; 1450 if (rootkeys[i].abbrev[0] && !wcsncmp(path, rootkeys[i].abbrev, lstrlenW(rootkeys[i].abbrev))) 1451 return rootkeys[i].hkey; 1452 } 1453 1454 return NULL; 1455 } 1456 1457 /* Caller is responsible to free 'subkey' if 'value' is not NULL */ 1458 static HRESULT split_reg_path(const WCHAR *path, WCHAR **subkey, WCHAR **value) 1459 { 1460 *value = NULL; 1461 1462 /* at least one separator should be present */ 1463 *subkey = wcschr(path, '\\'); 1464 if (!*subkey) 1465 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); 1466 1467 /* default value or not */ 1468 if ((*subkey)[lstrlenW(*subkey)-1] == '\\') { 1469 (*subkey)++; 1470 *value = NULL; 1471 } 1472 else { 1473 *value = wcsrchr(*subkey, '\\'); 1474 if (*value - *subkey > 1) { 1475 unsigned int len = *value - *subkey - 1; 1476 WCHAR *ret; 1477 1478 ret = heap_alloc((len + 1)*sizeof(WCHAR)); 1479 if (!ret) 1480 return E_OUTOFMEMORY; 1481 1482 memcpy(ret, *subkey + 1, len*sizeof(WCHAR)); 1483 ret[len] = 0; 1484 *subkey = ret; 1485 } 1486 (*value)++; 1487 } 1488 1489 return S_OK; 1490 } 1491 1492 static HRESULT WINAPI WshShell3_RegRead(IWshShell3 *iface, BSTR name, VARIANT *value) 1493 { 1494 DWORD type, datalen, ret; 1495 WCHAR *subkey, *val; 1496 HRESULT hr; 1497 HKEY root; 1498 1499 TRACE("(%s %p)\n", debugstr_w(name), value); 1500 1501 if (!name || !value) 1502 return E_POINTER; 1503 1504 root = get_root_key(name); 1505 if (!root) 1506 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); 1507 1508 hr = split_reg_path(name, &subkey, &val); 1509 if (FAILED(hr)) 1510 return hr; 1511 1512 type = REG_NONE; 1513 datalen = 0; 1514 ret = RegGetValueW(root, subkey, val, RRF_RT_ANY, &type, NULL, &datalen); 1515 if (ret == ERROR_SUCCESS) { 1516 void *data; 1517 1518 data = heap_alloc(datalen); 1519 if (!data) { 1520 hr = E_OUTOFMEMORY; 1521 goto fail; 1522 } 1523 1524 ret = RegGetValueW(root, subkey, val, RRF_RT_ANY, &type, data, &datalen); 1525 if (ret) { 1526 heap_free(data); 1527 hr = HRESULT_FROM_WIN32(ret); 1528 goto fail; 1529 } 1530 1531 switch (type) { 1532 case REG_SZ: 1533 case REG_EXPAND_SZ: 1534 V_VT(value) = VT_BSTR; 1535 V_BSTR(value) = SysAllocString((WCHAR*)data); 1536 if (!V_BSTR(value)) 1537 hr = E_OUTOFMEMORY; 1538 break; 1539 case REG_DWORD: 1540 V_VT(value) = VT_I4; 1541 V_I4(value) = *(DWORD*)data; 1542 break; 1543 case REG_BINARY: 1544 { 1545 BYTE *ptr = (BYTE*)data; 1546 SAFEARRAYBOUND bound; 1547 unsigned int i; 1548 SAFEARRAY *sa; 1549 VARIANT *v; 1550 1551 bound.lLbound = 0; 1552 bound.cElements = datalen; 1553 sa = SafeArrayCreate(VT_VARIANT, 1, &bound); 1554 if (!sa) 1555 break; 1556 1557 hr = SafeArrayAccessData(sa, (void**)&v); 1558 if (FAILED(hr)) { 1559 SafeArrayDestroy(sa); 1560 break; 1561 } 1562 1563 for (i = 0; i < datalen; i++) { 1564 V_VT(&v[i]) = VT_UI1; 1565 V_UI1(&v[i]) = ptr[i]; 1566 } 1567 SafeArrayUnaccessData(sa); 1568 1569 V_VT(value) = VT_ARRAY|VT_VARIANT; 1570 V_ARRAY(value) = sa; 1571 break; 1572 } 1573 case REG_MULTI_SZ: 1574 { 1575 WCHAR *ptr = (WCHAR*)data; 1576 SAFEARRAYBOUND bound; 1577 SAFEARRAY *sa; 1578 VARIANT *v; 1579 1580 /* get element count first */ 1581 bound.lLbound = 0; 1582 bound.cElements = 0; 1583 while (*ptr) { 1584 bound.cElements++; 1585 ptr += lstrlenW(ptr)+1; 1586 } 1587 1588 sa = SafeArrayCreate(VT_VARIANT, 1, &bound); 1589 if (!sa) 1590 break; 1591 1592 hr = SafeArrayAccessData(sa, (void**)&v); 1593 if (FAILED(hr)) { 1594 SafeArrayDestroy(sa); 1595 break; 1596 } 1597 1598 ptr = (WCHAR*)data; 1599 while (*ptr) { 1600 V_VT(v) = VT_BSTR; 1601 V_BSTR(v) = SysAllocString(ptr); 1602 ptr += lstrlenW(ptr)+1; 1603 v++; 1604 } 1605 1606 SafeArrayUnaccessData(sa); 1607 V_VT(value) = VT_ARRAY|VT_VARIANT; 1608 V_ARRAY(value) = sa; 1609 break; 1610 } 1611 default: 1612 FIXME("value type %d not supported\n", type); 1613 hr = E_FAIL; 1614 }; 1615 1616 heap_free(data); 1617 if (FAILED(hr)) 1618 VariantInit(value); 1619 } 1620 else 1621 hr = HRESULT_FROM_WIN32(ret); 1622 1623 fail: 1624 if (val) 1625 heap_free(subkey); 1626 return hr; 1627 } 1628 1629 static HRESULT WINAPI WshShell3_RegWrite(IWshShell3 *iface, BSTR name, VARIANT *value, VARIANT *type) 1630 { 1631 static const WCHAR regexpandszW[] = {'R','E','G','_','E','X','P','A','N','D','_','S','Z',0}; 1632 static const WCHAR regszW[] = {'R','E','G','_','S','Z',0}; 1633 static const WCHAR regdwordW[] = {'R','E','G','_','D','W','O','R','D',0}; 1634 static const WCHAR regbinaryW[] = {'R','E','G','_','B','I','N','A','R','Y',0}; 1635 1636 DWORD regtype, data_len; 1637 WCHAR *subkey, *val; 1638 const BYTE *data; 1639 HRESULT hr; 1640 HKEY root; 1641 VARIANT v; 1642 LONG ret; 1643 1644 TRACE("(%s %s %s)\n", debugstr_w(name), debugstr_variant(value), debugstr_variant(type)); 1645 1646 if (!name || !value || !type) 1647 return E_POINTER; 1648 1649 root = get_root_key(name); 1650 if (!root) 1651 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); 1652 1653 /* value type */ 1654 if (is_optional_argument(type)) 1655 regtype = REG_SZ; 1656 else { 1657 if (V_VT(type) != VT_BSTR) 1658 return E_INVALIDARG; 1659 1660 if (!wcscmp(V_BSTR(type), regszW)) 1661 regtype = REG_SZ; 1662 else if (!wcscmp(V_BSTR(type), regdwordW)) 1663 regtype = REG_DWORD; 1664 else if (!wcscmp(V_BSTR(type), regexpandszW)) 1665 regtype = REG_EXPAND_SZ; 1666 else if (!wcscmp(V_BSTR(type), regbinaryW)) 1667 regtype = REG_BINARY; 1668 else { 1669 FIXME("unrecognized value type %s\n", debugstr_w(V_BSTR(type))); 1670 return E_FAIL; 1671 } 1672 } 1673 1674 /* it's always a string or a DWORD */ 1675 VariantInit(&v); 1676 switch (regtype) 1677 { 1678 case REG_SZ: 1679 case REG_EXPAND_SZ: 1680 hr = VariantChangeType(&v, value, 0, VT_BSTR); 1681 if (hr == S_OK) { 1682 data = (BYTE*)V_BSTR(&v); 1683 data_len = SysStringByteLen(V_BSTR(&v)) + sizeof(WCHAR); 1684 } 1685 break; 1686 case REG_DWORD: 1687 case REG_BINARY: 1688 hr = VariantChangeType(&v, value, 0, VT_I4); 1689 data = (BYTE*)&V_I4(&v); 1690 data_len = sizeof(DWORD); 1691 break; 1692 default: 1693 FIXME("unexpected regtype %d\n", regtype); 1694 return E_FAIL; 1695 }; 1696 1697 if (FAILED(hr)) { 1698 FIXME("failed to convert value, regtype %d, 0x%08x\n", regtype, hr); 1699 return hr; 1700 } 1701 1702 hr = split_reg_path(name, &subkey, &val); 1703 if (FAILED(hr)) 1704 goto fail; 1705 1706 ret = RegSetKeyValueW(root, subkey, val, regtype, data, data_len); 1707 if (ret) 1708 hr = HRESULT_FROM_WIN32(ret); 1709 1710 fail: 1711 VariantClear(&v); 1712 if (val) 1713 heap_free(subkey); 1714 return hr; 1715 } 1716 1717 static HRESULT WINAPI WshShell3_RegDelete(IWshShell3 *iface, BSTR Name) 1718 { 1719 FIXME("(%s): stub\n", debugstr_w(Name)); 1720 return E_NOTIMPL; 1721 } 1722 1723 static HRESULT WINAPI WshShell3_LogEvent(IWshShell3 *iface, VARIANT *Type, BSTR Message, BSTR Target, VARIANT_BOOL *out_Success) 1724 { 1725 FIXME("(%s %s %s %p): stub\n", debugstr_variant(Type), debugstr_w(Message), debugstr_w(Target), out_Success); 1726 return E_NOTIMPL; 1727 } 1728 1729 static HRESULT WINAPI WshShell3_AppActivate(IWshShell3 *iface, VARIANT *App, VARIANT *Wait, VARIANT_BOOL *out_Success) 1730 { 1731 FIXME("(%s %s %p): stub\n", debugstr_variant(App), debugstr_variant(Wait), out_Success); 1732 return E_NOTIMPL; 1733 } 1734 1735 static HRESULT WINAPI WshShell3_SendKeys(IWshShell3 *iface, BSTR Keys, VARIANT *Wait) 1736 { 1737 FIXME("(%s %p): stub\n", debugstr_w(Keys), Wait); 1738 return E_NOTIMPL; 1739 } 1740 1741 static HRESULT WINAPI WshShell3_Exec(IWshShell3 *iface, BSTR command, IWshExec **ret) 1742 { 1743 TRACE("(%s %p)\n", debugstr_w(command), ret); 1744 1745 if (!ret) 1746 return E_POINTER; 1747 1748 if (!command) 1749 return DISP_E_EXCEPTION; 1750 1751 return WshExec_create(command, ret); 1752 } 1753 1754 static HRESULT WINAPI WshShell3_get_CurrentDirectory(IWshShell3 *iface, BSTR *dir) 1755 { 1756 DWORD ret; 1757 1758 TRACE("(%p)\n", dir); 1759 1760 ret = GetCurrentDirectoryW(0, NULL); 1761 if (!ret) 1762 return HRESULT_FROM_WIN32(GetLastError()); 1763 1764 *dir = SysAllocStringLen(NULL, ret-1); 1765 if (!*dir) 1766 return E_OUTOFMEMORY; 1767 1768 ret = GetCurrentDirectoryW(ret, *dir); 1769 if (!ret) { 1770 SysFreeString(*dir); 1771 *dir = NULL; 1772 return HRESULT_FROM_WIN32(GetLastError()); 1773 } 1774 1775 return S_OK; 1776 } 1777 1778 static HRESULT WINAPI WshShell3_put_CurrentDirectory(IWshShell3 *iface, BSTR dir) 1779 { 1780 TRACE("(%s)\n", debugstr_w(dir)); 1781 1782 if (!dir) 1783 return E_INVALIDARG; 1784 1785 if (!SetCurrentDirectoryW(dir)) 1786 return HRESULT_FROM_WIN32(GetLastError()); 1787 1788 return S_OK; 1789 } 1790 1791 static const IWshShell3Vtbl WshShell3Vtbl = { 1792 WshShell3_QueryInterface, 1793 WshShell3_AddRef, 1794 WshShell3_Release, 1795 WshShell3_GetTypeInfoCount, 1796 WshShell3_GetTypeInfo, 1797 WshShell3_GetIDsOfNames, 1798 WshShell3_Invoke, 1799 WshShell3_get_SpecialFolders, 1800 WshShell3_get_Environment, 1801 WshShell3_Run, 1802 WshShell3_Popup, 1803 WshShell3_CreateShortcut, 1804 WshShell3_ExpandEnvironmentStrings, 1805 WshShell3_RegRead, 1806 WshShell3_RegWrite, 1807 WshShell3_RegDelete, 1808 WshShell3_LogEvent, 1809 WshShell3_AppActivate, 1810 WshShell3_SendKeys, 1811 WshShell3_Exec, 1812 WshShell3_get_CurrentDirectory, 1813 WshShell3_put_CurrentDirectory 1814 }; 1815 1816 HRESULT WINAPI WshShellFactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv) 1817 { 1818 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv); 1819 1820 WshShell3.IWshShell3_iface.lpVtbl = &WshShell3Vtbl; 1821 init_classinfo(&IID_IWshShell3, (IUnknown *)&WshShell3.IWshShell3_iface, &WshShell3.classinfo); 1822 return IWshShell3_QueryInterface(&WshShell3.IWshShell3_iface, riid, ppv); 1823 } 1824