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