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