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 #ifdef __REACTOS__ 1265 if (is_optional_argument(style)) 1266 { 1267 V_VT(&s) = VT_I4; 1268 V_I4(&s) = SW_SHOW; 1269 hr = S_OK; 1270 } 1271 else 1272 #endif 1273 hr = VariantChangeType(&s, style, 0, VT_I4); 1274 if (FAILED(hr)) 1275 { 1276 ERR("failed to convert style argument, 0x%08x\n", hr); 1277 return hr; 1278 } 1279 1280 if (is_optional_argument(wait)) 1281 waitforprocess = 0; 1282 else { 1283 VARIANT w; 1284 1285 VariantInit(&w); 1286 hr = VariantChangeType(&w, wait, 0, VT_I4); 1287 if (FAILED(hr)) 1288 return hr; 1289 1290 waitforprocess = V_I4(&w); 1291 } 1292 1293 if (!(file = split_command(cmd, ¶ms))) return E_OUTOFMEMORY; 1294 1295 memset(&info, 0, sizeof(info)); 1296 info.cbSize = sizeof(info); 1297 info.fMask = waitforprocess ? SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS : SEE_MASK_DEFAULT; 1298 info.lpFile = file; 1299 info.lpParameters = params; 1300 info.nShow = V_I4(&s); 1301 1302 ret = ShellExecuteExW(&info); 1303 heap_free( file ); 1304 if (!ret) 1305 { 1306 TRACE("ShellExecute failed, %d\n", GetLastError()); 1307 return HRESULT_FROM_WIN32(GetLastError()); 1308 } 1309 else 1310 { 1311 if (waitforprocess) 1312 { 1313 WaitForSingleObject(info.hProcess, INFINITE); 1314 GetExitCodeProcess(info.hProcess, exit_code); 1315 CloseHandle(info.hProcess); 1316 } 1317 else 1318 *exit_code = 0; 1319 1320 return S_OK; 1321 } 1322 } 1323 1324 struct popup_thread_param 1325 { 1326 WCHAR *text; 1327 VARIANT title; 1328 VARIANT type; 1329 INT button; 1330 }; 1331 1332 static DWORD WINAPI popup_thread_proc(void *arg) 1333 { 1334 static const WCHAR defaulttitleW[] = {'W','i','n','d','o','w','s',' ','S','c','r','i','p','t',' ','H','o','s','t',0}; 1335 struct popup_thread_param *param = (struct popup_thread_param *)arg; 1336 1337 param->button = MessageBoxW(NULL, param->text, is_optional_argument(¶m->title) ? 1338 defaulttitleW : V_BSTR(¶m->title), V_I4(¶m->type)); 1339 return 0; 1340 } 1341 1342 static HRESULT WINAPI WshShell3_Popup(IWshShell3 *iface, BSTR text, VARIANT *seconds_to_wait, VARIANT *title, 1343 VARIANT *type, int *button) 1344 { 1345 struct popup_thread_param param; 1346 DWORD tid, status; 1347 VARIANT timeout; 1348 HANDLE hthread; 1349 HRESULT hr; 1350 1351 TRACE("(%s %s %s %s %p)\n", debugstr_w(text), debugstr_variant(seconds_to_wait), debugstr_variant(title), 1352 debugstr_variant(type), button); 1353 1354 if (!seconds_to_wait || !title || !type || !button) 1355 return E_POINTER; 1356 1357 VariantInit(&timeout); 1358 if (!is_optional_argument(seconds_to_wait)) 1359 { 1360 hr = VariantChangeType(&timeout, seconds_to_wait, 0, VT_I4); 1361 if (FAILED(hr)) 1362 return hr; 1363 } 1364 #ifdef __REACTOS__ 1365 else 1366 { 1367 VariantChangeType(&timeout, &timeout, 0, VT_I4); 1368 } 1369 #endif 1370 1371 VariantInit(¶m.type); 1372 if (!is_optional_argument(type)) 1373 { 1374 hr = VariantChangeType(¶m.type, type, 0, VT_I4); 1375 if (FAILED(hr)) 1376 return hr; 1377 } 1378 #ifdef __REACTOS__ 1379 else 1380 { 1381 VariantChangeType(¶m.type, ¶m.type, 0, VT_I4); 1382 } 1383 #endif 1384 1385 if (is_optional_argument(title)) 1386 param.title = *title; 1387 else 1388 { 1389 VariantInit(¶m.title); 1390 hr = VariantChangeType(¶m.title, title, 0, VT_BSTR); 1391 if (FAILED(hr)) 1392 return hr; 1393 } 1394 1395 param.text = text; 1396 param.button = -1; 1397 hthread = CreateThread(NULL, 0, popup_thread_proc, ¶m, 0, &tid); 1398 status = MsgWaitForMultipleObjects(1, &hthread, FALSE, V_I4(&timeout) ? V_I4(&timeout) * 1000: INFINITE, 0); 1399 if (status == WAIT_TIMEOUT) 1400 { 1401 PostThreadMessageW(tid, WM_QUIT, 0, 0); 1402 MsgWaitForMultipleObjects(1, &hthread, FALSE, INFINITE, 0); 1403 param.button = -1; 1404 } 1405 *button = param.button; 1406 1407 VariantClear(¶m.title); 1408 CloseHandle(hthread); 1409 1410 return S_OK; 1411 } 1412 1413 static HRESULT WINAPI WshShell3_CreateShortcut(IWshShell3 *iface, BSTR PathLink, IDispatch** Shortcut) 1414 { 1415 TRACE("(%s %p)\n", debugstr_w(PathLink), Shortcut); 1416 return WshShortcut_Create(PathLink, Shortcut); 1417 } 1418 1419 static HRESULT WINAPI WshShell3_ExpandEnvironmentStrings(IWshShell3 *iface, BSTR Src, BSTR* Dst) 1420 { 1421 DWORD ret; 1422 1423 TRACE("(%s %p)\n", debugstr_w(Src), Dst); 1424 1425 if (!Src || !Dst) return E_POINTER; 1426 1427 ret = ExpandEnvironmentStringsW(Src, NULL, 0); 1428 *Dst = SysAllocStringLen(NULL, ret); 1429 if (!*Dst) return E_OUTOFMEMORY; 1430 1431 if (ExpandEnvironmentStringsW(Src, *Dst, ret)) 1432 return S_OK; 1433 else 1434 { 1435 SysFreeString(*Dst); 1436 *Dst = NULL; 1437 return HRESULT_FROM_WIN32(GetLastError()); 1438 } 1439 } 1440 1441 static HKEY get_root_key(const WCHAR *path) 1442 { 1443 static const struct { 1444 const WCHAR full[20]; 1445 const WCHAR abbrev[5]; 1446 HKEY hkey; 1447 } rootkeys[] = { 1448 { {'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R',0}, {'H','K','C','U',0}, HKEY_CURRENT_USER }, 1449 { {'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 }, 1450 { {'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T',0}, {'H','K','C','R',0}, HKEY_CLASSES_ROOT }, 1451 { {'H','K','E','Y','_','U','S','E','R','S',0}, {0}, HKEY_USERS }, 1452 { {'H','K','E','Y','_','C','U','R','R','E','N','T','_','C','O','N','F','I','G',0}, {0}, HKEY_CURRENT_CONFIG } 1453 }; 1454 int i; 1455 1456 for (i = 0; i < ARRAY_SIZE(rootkeys); i++) { 1457 if (!wcsncmp(path, rootkeys[i].full, lstrlenW(rootkeys[i].full))) 1458 return rootkeys[i].hkey; 1459 if (rootkeys[i].abbrev[0] && !wcsncmp(path, rootkeys[i].abbrev, lstrlenW(rootkeys[i].abbrev))) 1460 return rootkeys[i].hkey; 1461 } 1462 1463 return NULL; 1464 } 1465 1466 /* Caller is responsible to free 'subkey' if 'value' is not NULL */ 1467 static HRESULT split_reg_path(const WCHAR *path, WCHAR **subkey, WCHAR **value) 1468 { 1469 *value = NULL; 1470 1471 /* at least one separator should be present */ 1472 *subkey = wcschr(path, '\\'); 1473 if (!*subkey) 1474 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); 1475 1476 /* default value or not */ 1477 if ((*subkey)[lstrlenW(*subkey)-1] == '\\') { 1478 (*subkey)++; 1479 *value = NULL; 1480 } 1481 else { 1482 *value = wcsrchr(*subkey, '\\'); 1483 if (*value - *subkey > 1) { 1484 unsigned int len = *value - *subkey - 1; 1485 WCHAR *ret; 1486 1487 ret = heap_alloc((len + 1)*sizeof(WCHAR)); 1488 if (!ret) 1489 return E_OUTOFMEMORY; 1490 1491 memcpy(ret, *subkey + 1, len*sizeof(WCHAR)); 1492 ret[len] = 0; 1493 *subkey = ret; 1494 } 1495 (*value)++; 1496 } 1497 1498 return S_OK; 1499 } 1500 1501 static HRESULT WINAPI WshShell3_RegRead(IWshShell3 *iface, BSTR name, VARIANT *value) 1502 { 1503 DWORD type, datalen, ret; 1504 WCHAR *subkey, *val; 1505 HRESULT hr; 1506 HKEY root; 1507 1508 TRACE("(%s %p)\n", debugstr_w(name), value); 1509 1510 if (!name || !value) 1511 return E_POINTER; 1512 1513 root = get_root_key(name); 1514 if (!root) 1515 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); 1516 1517 hr = split_reg_path(name, &subkey, &val); 1518 if (FAILED(hr)) 1519 return hr; 1520 1521 type = REG_NONE; 1522 datalen = 0; 1523 ret = RegGetValueW(root, subkey, val, RRF_RT_ANY, &type, NULL, &datalen); 1524 if (ret == ERROR_SUCCESS) { 1525 void *data; 1526 1527 data = heap_alloc(datalen); 1528 if (!data) { 1529 hr = E_OUTOFMEMORY; 1530 goto fail; 1531 } 1532 1533 ret = RegGetValueW(root, subkey, val, RRF_RT_ANY, &type, data, &datalen); 1534 if (ret) { 1535 heap_free(data); 1536 hr = HRESULT_FROM_WIN32(ret); 1537 goto fail; 1538 } 1539 1540 switch (type) { 1541 case REG_SZ: 1542 case REG_EXPAND_SZ: 1543 V_VT(value) = VT_BSTR; 1544 V_BSTR(value) = SysAllocString((WCHAR*)data); 1545 if (!V_BSTR(value)) 1546 hr = E_OUTOFMEMORY; 1547 break; 1548 case REG_DWORD: 1549 V_VT(value) = VT_I4; 1550 V_I4(value) = *(DWORD*)data; 1551 break; 1552 case REG_BINARY: 1553 { 1554 BYTE *ptr = (BYTE*)data; 1555 SAFEARRAYBOUND bound; 1556 unsigned int i; 1557 SAFEARRAY *sa; 1558 VARIANT *v; 1559 1560 bound.lLbound = 0; 1561 bound.cElements = datalen; 1562 sa = SafeArrayCreate(VT_VARIANT, 1, &bound); 1563 if (!sa) 1564 break; 1565 1566 hr = SafeArrayAccessData(sa, (void**)&v); 1567 if (FAILED(hr)) { 1568 SafeArrayDestroy(sa); 1569 break; 1570 } 1571 1572 for (i = 0; i < datalen; i++) { 1573 V_VT(&v[i]) = VT_UI1; 1574 V_UI1(&v[i]) = ptr[i]; 1575 } 1576 SafeArrayUnaccessData(sa); 1577 1578 V_VT(value) = VT_ARRAY|VT_VARIANT; 1579 V_ARRAY(value) = sa; 1580 break; 1581 } 1582 case REG_MULTI_SZ: 1583 { 1584 WCHAR *ptr = (WCHAR*)data; 1585 SAFEARRAYBOUND bound; 1586 SAFEARRAY *sa; 1587 VARIANT *v; 1588 1589 /* get element count first */ 1590 bound.lLbound = 0; 1591 bound.cElements = 0; 1592 while (*ptr) { 1593 bound.cElements++; 1594 ptr += lstrlenW(ptr)+1; 1595 } 1596 1597 sa = SafeArrayCreate(VT_VARIANT, 1, &bound); 1598 if (!sa) 1599 break; 1600 1601 hr = SafeArrayAccessData(sa, (void**)&v); 1602 if (FAILED(hr)) { 1603 SafeArrayDestroy(sa); 1604 break; 1605 } 1606 1607 ptr = (WCHAR*)data; 1608 while (*ptr) { 1609 V_VT(v) = VT_BSTR; 1610 V_BSTR(v) = SysAllocString(ptr); 1611 ptr += lstrlenW(ptr)+1; 1612 v++; 1613 } 1614 1615 SafeArrayUnaccessData(sa); 1616 V_VT(value) = VT_ARRAY|VT_VARIANT; 1617 V_ARRAY(value) = sa; 1618 break; 1619 } 1620 default: 1621 FIXME("value type %d not supported\n", type); 1622 hr = E_FAIL; 1623 }; 1624 1625 heap_free(data); 1626 if (FAILED(hr)) 1627 VariantInit(value); 1628 } 1629 else 1630 hr = HRESULT_FROM_WIN32(ret); 1631 1632 fail: 1633 if (val) 1634 heap_free(subkey); 1635 return hr; 1636 } 1637 1638 static HRESULT WINAPI WshShell3_RegWrite(IWshShell3 *iface, BSTR name, VARIANT *value, VARIANT *type) 1639 { 1640 static const WCHAR regexpandszW[] = {'R','E','G','_','E','X','P','A','N','D','_','S','Z',0}; 1641 static const WCHAR regszW[] = {'R','E','G','_','S','Z',0}; 1642 static const WCHAR regdwordW[] = {'R','E','G','_','D','W','O','R','D',0}; 1643 static const WCHAR regbinaryW[] = {'R','E','G','_','B','I','N','A','R','Y',0}; 1644 1645 DWORD regtype, data_len; 1646 WCHAR *subkey, *val; 1647 const BYTE *data; 1648 HRESULT hr; 1649 HKEY root; 1650 VARIANT v; 1651 LONG ret; 1652 1653 TRACE("(%s %s %s)\n", debugstr_w(name), debugstr_variant(value), debugstr_variant(type)); 1654 1655 if (!name || !value || !type) 1656 return E_POINTER; 1657 1658 root = get_root_key(name); 1659 if (!root) 1660 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); 1661 1662 /* value type */ 1663 if (is_optional_argument(type)) 1664 regtype = REG_SZ; 1665 else { 1666 if (V_VT(type) != VT_BSTR) 1667 return E_INVALIDARG; 1668 1669 if (!wcscmp(V_BSTR(type), regszW)) 1670 regtype = REG_SZ; 1671 else if (!wcscmp(V_BSTR(type), regdwordW)) 1672 regtype = REG_DWORD; 1673 else if (!wcscmp(V_BSTR(type), regexpandszW)) 1674 regtype = REG_EXPAND_SZ; 1675 else if (!wcscmp(V_BSTR(type), regbinaryW)) 1676 regtype = REG_BINARY; 1677 else { 1678 FIXME("unrecognized value type %s\n", debugstr_w(V_BSTR(type))); 1679 return E_FAIL; 1680 } 1681 } 1682 1683 /* it's always a string or a DWORD */ 1684 VariantInit(&v); 1685 switch (regtype) 1686 { 1687 case REG_SZ: 1688 case REG_EXPAND_SZ: 1689 hr = VariantChangeType(&v, value, 0, VT_BSTR); 1690 if (hr == S_OK) { 1691 data = (BYTE*)V_BSTR(&v); 1692 data_len = SysStringByteLen(V_BSTR(&v)) + sizeof(WCHAR); 1693 } 1694 break; 1695 case REG_DWORD: 1696 case REG_BINARY: 1697 hr = VariantChangeType(&v, value, 0, VT_I4); 1698 data = (BYTE*)&V_I4(&v); 1699 data_len = sizeof(DWORD); 1700 break; 1701 default: 1702 FIXME("unexpected regtype %d\n", regtype); 1703 return E_FAIL; 1704 }; 1705 1706 if (FAILED(hr)) { 1707 FIXME("failed to convert value, regtype %d, 0x%08x\n", regtype, hr); 1708 return hr; 1709 } 1710 1711 hr = split_reg_path(name, &subkey, &val); 1712 if (FAILED(hr)) 1713 goto fail; 1714 1715 ret = RegSetKeyValueW(root, subkey, val, regtype, data, data_len); 1716 if (ret) 1717 hr = HRESULT_FROM_WIN32(ret); 1718 1719 fail: 1720 VariantClear(&v); 1721 if (val) 1722 heap_free(subkey); 1723 return hr; 1724 } 1725 1726 static HRESULT WINAPI WshShell3_RegDelete(IWshShell3 *iface, BSTR Name) 1727 { 1728 FIXME("(%s): stub\n", debugstr_w(Name)); 1729 return E_NOTIMPL; 1730 } 1731 1732 static HRESULT WINAPI WshShell3_LogEvent(IWshShell3 *iface, VARIANT *Type, BSTR Message, BSTR Target, VARIANT_BOOL *out_Success) 1733 { 1734 FIXME("(%s %s %s %p): stub\n", debugstr_variant(Type), debugstr_w(Message), debugstr_w(Target), out_Success); 1735 return E_NOTIMPL; 1736 } 1737 1738 static HRESULT WINAPI WshShell3_AppActivate(IWshShell3 *iface, VARIANT *App, VARIANT *Wait, VARIANT_BOOL *out_Success) 1739 { 1740 FIXME("(%s %s %p): stub\n", debugstr_variant(App), debugstr_variant(Wait), out_Success); 1741 return E_NOTIMPL; 1742 } 1743 1744 static HRESULT WINAPI WshShell3_SendKeys(IWshShell3 *iface, BSTR Keys, VARIANT *Wait) 1745 { 1746 FIXME("(%s %p): stub\n", debugstr_w(Keys), Wait); 1747 return E_NOTIMPL; 1748 } 1749 1750 static HRESULT WINAPI WshShell3_Exec(IWshShell3 *iface, BSTR command, IWshExec **ret) 1751 { 1752 TRACE("(%s %p)\n", debugstr_w(command), ret); 1753 1754 if (!ret) 1755 return E_POINTER; 1756 1757 if (!command) 1758 return DISP_E_EXCEPTION; 1759 1760 return WshExec_create(command, ret); 1761 } 1762 1763 static HRESULT WINAPI WshShell3_get_CurrentDirectory(IWshShell3 *iface, BSTR *dir) 1764 { 1765 DWORD ret; 1766 1767 TRACE("(%p)\n", dir); 1768 1769 ret = GetCurrentDirectoryW(0, NULL); 1770 if (!ret) 1771 return HRESULT_FROM_WIN32(GetLastError()); 1772 1773 *dir = SysAllocStringLen(NULL, ret-1); 1774 if (!*dir) 1775 return E_OUTOFMEMORY; 1776 1777 ret = GetCurrentDirectoryW(ret, *dir); 1778 if (!ret) { 1779 SysFreeString(*dir); 1780 *dir = NULL; 1781 return HRESULT_FROM_WIN32(GetLastError()); 1782 } 1783 1784 return S_OK; 1785 } 1786 1787 static HRESULT WINAPI WshShell3_put_CurrentDirectory(IWshShell3 *iface, BSTR dir) 1788 { 1789 TRACE("(%s)\n", debugstr_w(dir)); 1790 1791 if (!dir) 1792 return E_INVALIDARG; 1793 1794 if (!SetCurrentDirectoryW(dir)) 1795 return HRESULT_FROM_WIN32(GetLastError()); 1796 1797 return S_OK; 1798 } 1799 1800 static const IWshShell3Vtbl WshShell3Vtbl = { 1801 WshShell3_QueryInterface, 1802 WshShell3_AddRef, 1803 WshShell3_Release, 1804 WshShell3_GetTypeInfoCount, 1805 WshShell3_GetTypeInfo, 1806 WshShell3_GetIDsOfNames, 1807 WshShell3_Invoke, 1808 WshShell3_get_SpecialFolders, 1809 WshShell3_get_Environment, 1810 WshShell3_Run, 1811 WshShell3_Popup, 1812 WshShell3_CreateShortcut, 1813 WshShell3_ExpandEnvironmentStrings, 1814 WshShell3_RegRead, 1815 WshShell3_RegWrite, 1816 WshShell3_RegDelete, 1817 WshShell3_LogEvent, 1818 WshShell3_AppActivate, 1819 WshShell3_SendKeys, 1820 WshShell3_Exec, 1821 WshShell3_get_CurrentDirectory, 1822 WshShell3_put_CurrentDirectory 1823 }; 1824 1825 HRESULT WINAPI WshShellFactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv) 1826 { 1827 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv); 1828 1829 WshShell3.IWshShell3_iface.lpVtbl = &WshShell3Vtbl; 1830 init_classinfo(&IID_IWshShell3, (IUnknown *)&WshShell3.IWshShell3_iface, &WshShell3.classinfo); 1831 return IWshShell3_QueryInterface(&WshShell3.IWshShell3_iface, riid, ppv); 1832 } 1833