shell32/tests: Add PathResolve tests.
[wine.git] / dlls / wshom.ocx / shell.c
blob543d951ea05d445fce4f9b41be598bd63afce3f4
1 /*
2 * Copyright 2011 Jacek Caban for CodeWeavers
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.
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.
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
19 #include "wshom_private.h"
20 #include "wshom.h"
22 #include "shellapi.h"
23 #include "shlobj.h"
24 #include "dispex.h"
26 #include "wine/debug.h"
27 #include "wine/heap.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(wshom);
31 typedef struct
33 struct provideclassinfo classinfo;
34 IWshShell3 IWshShell3_iface;
35 } WshShellImpl;
36 static WshShellImpl WshShell3;
38 typedef struct
40 struct provideclassinfo classinfo;
41 IWshCollection IWshCollection_iface;
42 LONG ref;
43 } WshCollection;
45 typedef struct
47 struct provideclassinfo classinfo;
48 IWshShortcut IWshShortcut_iface;
49 LONG ref;
51 IShellLinkW *link;
52 BSTR path_link;
53 } WshShortcut;
55 typedef struct
57 struct provideclassinfo classinfo;
58 IWshEnvironment IWshEnvironment_iface;
59 LONG ref;
60 } WshEnvironment;
62 typedef struct
64 struct provideclassinfo classinfo;
65 IWshExec IWshExec_iface;
66 LONG ref;
67 PROCESS_INFORMATION info;
68 } WshExecImpl;
70 static inline WshCollection *impl_from_IWshCollection( IWshCollection *iface )
72 return CONTAINING_RECORD(iface, WshCollection, IWshCollection_iface);
75 static inline WshShortcut *impl_from_IWshShortcut( IWshShortcut *iface )
77 return CONTAINING_RECORD(iface, WshShortcut, IWshShortcut_iface);
80 static inline WshEnvironment *impl_from_IWshEnvironment( IWshEnvironment *iface )
82 return CONTAINING_RECORD(iface, WshEnvironment, IWshEnvironment_iface);
85 static inline WshExecImpl *impl_from_IWshExec( IWshExec *iface )
87 return CONTAINING_RECORD(iface, WshExecImpl, IWshExec_iface);
90 static HRESULT WINAPI WshExec_QueryInterface(IWshExec *iface, REFIID riid, void **obj)
92 WshExecImpl *This = impl_from_IWshExec(iface);
94 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), obj);
96 if (IsEqualGUID(riid, &IID_IDispatch) ||
97 IsEqualGUID(riid, &IID_IWshExec) ||
98 IsEqualGUID(riid, &IID_IUnknown))
100 *obj = iface;
102 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
104 *obj = &This->classinfo.IProvideClassInfo_iface;
106 else {
107 FIXME("Unknown iface %s\n", debugstr_guid(riid));
108 *obj = NULL;
109 return E_NOINTERFACE;
112 IUnknown_AddRef((IUnknown *)*obj);
113 return S_OK;
116 static ULONG WINAPI WshExec_AddRef(IWshExec *iface)
118 WshExecImpl *This = impl_from_IWshExec(iface);
119 LONG ref = InterlockedIncrement(&This->ref);
120 TRACE("(%p) ref = %d\n", This, ref);
121 return ref;
124 static ULONG WINAPI WshExec_Release(IWshExec *iface)
126 WshExecImpl *This = impl_from_IWshExec(iface);
127 LONG ref = InterlockedDecrement(&This->ref);
128 TRACE("(%p) ref = %d\n", This, ref);
130 if (!ref) {
131 CloseHandle(This->info.hThread);
132 CloseHandle(This->info.hProcess);
133 heap_free(This);
136 return ref;
139 static HRESULT WINAPI WshExec_GetTypeInfoCount(IWshExec *iface, UINT *pctinfo)
141 WshExecImpl *This = impl_from_IWshExec(iface);
142 TRACE("(%p)->(%p)\n", This, pctinfo);
143 *pctinfo = 1;
144 return S_OK;
147 static HRESULT WINAPI WshExec_GetTypeInfo(IWshExec *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
149 WshExecImpl *This = impl_from_IWshExec(iface);
150 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
151 return get_typeinfo(IWshExec_tid, ppTInfo);
154 static HRESULT WINAPI WshExec_GetIDsOfNames(IWshExec *iface, REFIID riid, LPOLESTR *rgszNames,
155 UINT cNames, LCID lcid, DISPID *rgDispId)
157 WshExecImpl *This = impl_from_IWshExec(iface);
158 ITypeInfo *typeinfo;
159 HRESULT hr;
161 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
163 hr = get_typeinfo(IWshExec_tid, &typeinfo);
164 if(SUCCEEDED(hr))
166 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
167 ITypeInfo_Release(typeinfo);
170 return hr;
173 static HRESULT WINAPI WshExec_Invoke(IWshExec *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
174 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
176 WshExecImpl *This = impl_from_IWshExec(iface);
177 ITypeInfo *typeinfo;
178 HRESULT hr;
180 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
181 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
183 hr = get_typeinfo(IWshExec_tid, &typeinfo);
184 if(SUCCEEDED(hr))
186 hr = ITypeInfo_Invoke(typeinfo, &This->IWshExec_iface, dispIdMember, wFlags,
187 pDispParams, pVarResult, pExcepInfo, puArgErr);
188 ITypeInfo_Release(typeinfo);
191 return hr;
194 static HRESULT WINAPI WshExec_get_Status(IWshExec *iface, WshExecStatus *status)
196 WshExecImpl *This = impl_from_IWshExec(iface);
197 DWORD code;
199 TRACE("(%p)->(%p)\n", This, status);
201 if (!status)
202 return E_INVALIDARG;
204 if (!GetExitCodeProcess(This->info.hProcess, &code))
205 return HRESULT_FROM_WIN32(GetLastError());
207 switch (code)
209 case 0:
210 *status = WshFinished;
211 break;
212 case STILL_ACTIVE:
213 *status = WshRunning;
214 break;
215 default:
216 *status = WshFailed;
219 return S_OK;
222 static HRESULT WINAPI WshExec_get_StdIn(IWshExec *iface, ITextStream **stream)
224 WshExecImpl *This = impl_from_IWshExec(iface);
226 FIXME("(%p)->(%p): stub\n", This, stream);
228 return E_NOTIMPL;
231 static HRESULT WINAPI WshExec_get_StdOut(IWshExec *iface, ITextStream **stream)
233 WshExecImpl *This = impl_from_IWshExec(iface);
235 FIXME("(%p)->(%p): stub\n", This, stream);
237 return E_NOTIMPL;
240 static HRESULT WINAPI WshExec_get_StdErr(IWshExec *iface, ITextStream **stream)
242 WshExecImpl *This = impl_from_IWshExec(iface);
244 FIXME("(%p)->(%p): stub\n", This, stream);
246 return E_NOTIMPL;
249 static HRESULT WINAPI WshExec_get_ProcessID(IWshExec *iface, DWORD *pid)
251 WshExecImpl *This = impl_from_IWshExec(iface);
253 TRACE("(%p)->(%p)\n", This, pid);
255 if (!pid)
256 return E_INVALIDARG;
258 *pid = This->info.dwProcessId;
259 return S_OK;
262 static HRESULT WINAPI WshExec_get_ExitCode(IWshExec *iface, DWORD *code)
264 WshExecImpl *This = impl_from_IWshExec(iface);
266 FIXME("(%p)->(%p): stub\n", This, code);
268 return E_NOTIMPL;
271 static BOOL CALLBACK enum_thread_wnd_proc(HWND hwnd, LPARAM lParam)
273 INT *count = (INT*)lParam;
275 (*count)++;
276 PostMessageW(hwnd, WM_CLOSE, 0, 0);
277 /* try to send it to all windows, even if failed for some */
278 return TRUE;
281 static HRESULT WINAPI WshExec_Terminate(IWshExec *iface)
283 WshExecImpl *This = impl_from_IWshExec(iface);
284 BOOL ret, kill = FALSE;
285 INT count = 0;
287 TRACE("(%p)\n", This);
289 ret = EnumThreadWindows(This->info.dwThreadId, enum_thread_wnd_proc, (LPARAM)&count);
290 if (ret && count) {
291 /* manual testing shows that it waits 2 seconds before forcing termination */
292 if (WaitForSingleObject(This->info.hProcess, 2000) != WAIT_OBJECT_0)
293 kill = TRUE;
295 else
296 kill = TRUE;
298 if (kill)
299 TerminateProcess(This->info.hProcess, 0);
301 return S_OK;
304 static const IWshExecVtbl WshExecVtbl = {
305 WshExec_QueryInterface,
306 WshExec_AddRef,
307 WshExec_Release,
308 WshExec_GetTypeInfoCount,
309 WshExec_GetTypeInfo,
310 WshExec_GetIDsOfNames,
311 WshExec_Invoke,
312 WshExec_get_Status,
313 WshExec_get_StdIn,
314 WshExec_get_StdOut,
315 WshExec_get_StdErr,
316 WshExec_get_ProcessID,
317 WshExec_get_ExitCode,
318 WshExec_Terminate
321 static HRESULT WshExec_create(BSTR command, IWshExec **ret)
323 STARTUPINFOW si = {0};
324 WshExecImpl *This;
326 *ret = NULL;
328 This = heap_alloc(sizeof(*This));
329 if (!This)
330 return E_OUTOFMEMORY;
332 This->IWshExec_iface.lpVtbl = &WshExecVtbl;
333 This->ref = 1;
335 if (!CreateProcessW(NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &This->info)) {
336 heap_free(This);
337 return HRESULT_FROM_WIN32(GetLastError());
340 init_classinfo(&CLSID_WshExec, (IUnknown *)&This->IWshExec_iface, &This->classinfo);
341 *ret = &This->IWshExec_iface;
342 return S_OK;
345 static HRESULT WINAPI WshEnvironment_QueryInterface(IWshEnvironment *iface, REFIID riid, void **obj)
347 WshEnvironment *This = impl_from_IWshEnvironment(iface);
349 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), obj);
351 if (IsEqualGUID(riid, &IID_IUnknown) ||
352 IsEqualGUID(riid, &IID_IDispatch) ||
353 IsEqualGUID(riid, &IID_IWshEnvironment))
355 *obj = iface;
357 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
359 *obj = &This->classinfo.IProvideClassInfo_iface;
361 else {
362 FIXME("Unknown iface %s\n", debugstr_guid(riid));
363 *obj = NULL;
364 return E_NOINTERFACE;
367 IUnknown_AddRef((IUnknown*)*obj);
368 return S_OK;
371 static ULONG WINAPI WshEnvironment_AddRef(IWshEnvironment *iface)
373 WshEnvironment *This = impl_from_IWshEnvironment(iface);
374 LONG ref = InterlockedIncrement(&This->ref);
375 TRACE("(%p) ref = %d\n", This, ref);
376 return ref;
379 static ULONG WINAPI WshEnvironment_Release(IWshEnvironment *iface)
381 WshEnvironment *This = impl_from_IWshEnvironment(iface);
382 LONG ref = InterlockedDecrement(&This->ref);
383 TRACE("(%p) ref = %d\n", This, ref);
385 if (!ref)
386 heap_free(This);
388 return ref;
391 static HRESULT WINAPI WshEnvironment_GetTypeInfoCount(IWshEnvironment *iface, UINT *pctinfo)
393 WshEnvironment *This = impl_from_IWshEnvironment(iface);
394 TRACE("(%p)->(%p)\n", This, pctinfo);
395 *pctinfo = 1;
396 return S_OK;
399 static HRESULT WINAPI WshEnvironment_GetTypeInfo(IWshEnvironment *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
401 WshEnvironment *This = impl_from_IWshEnvironment(iface);
402 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
403 return get_typeinfo(IWshEnvironment_tid, ppTInfo);
406 static HRESULT WINAPI WshEnvironment_GetIDsOfNames(IWshEnvironment *iface, REFIID riid, LPOLESTR *rgszNames,
407 UINT cNames, LCID lcid, DISPID *rgDispId)
409 WshEnvironment *This = impl_from_IWshEnvironment(iface);
410 ITypeInfo *typeinfo;
411 HRESULT hr;
413 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
415 hr = get_typeinfo(IWshEnvironment_tid, &typeinfo);
416 if(SUCCEEDED(hr))
418 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
419 ITypeInfo_Release(typeinfo);
422 return hr;
425 static HRESULT WINAPI WshEnvironment_Invoke(IWshEnvironment *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
426 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
428 WshEnvironment *This = impl_from_IWshEnvironment(iface);
429 ITypeInfo *typeinfo;
430 HRESULT hr;
432 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
433 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
435 hr = get_typeinfo(IWshEnvironment_tid, &typeinfo);
436 if(SUCCEEDED(hr))
438 hr = ITypeInfo_Invoke(typeinfo, &This->IWshEnvironment_iface, dispIdMember, wFlags,
439 pDispParams, pVarResult, pExcepInfo, puArgErr);
440 ITypeInfo_Release(typeinfo);
443 return hr;
446 static HRESULT WINAPI WshEnvironment_get_Item(IWshEnvironment *iface, BSTR name, BSTR *value)
448 WshEnvironment *This = impl_from_IWshEnvironment(iface);
449 DWORD len;
451 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), value);
453 if (!value)
454 return E_POINTER;
456 len = GetEnvironmentVariableW(name, NULL, 0);
457 if (len)
459 *value = SysAllocStringLen(NULL, len - 1);
460 if (*value)
461 GetEnvironmentVariableW(name, *value, len);
463 else
464 *value = SysAllocStringLen(NULL, 0);
466 return *value ? S_OK : E_OUTOFMEMORY;
469 static HRESULT WINAPI WshEnvironment_put_Item(IWshEnvironment *iface, BSTR name, BSTR value)
471 WshEnvironment *This = impl_from_IWshEnvironment(iface);
472 FIXME("(%p)->(%s %s): stub\n", This, debugstr_w(name), debugstr_w(value));
473 return E_NOTIMPL;
476 static HRESULT WINAPI WshEnvironment_Count(IWshEnvironment *iface, LONG *count)
478 WshEnvironment *This = impl_from_IWshEnvironment(iface);
479 FIXME("(%p)->(%p): stub\n", This, count);
480 return E_NOTIMPL;
483 static HRESULT WINAPI WshEnvironment_get_length(IWshEnvironment *iface, LONG *len)
485 WshEnvironment *This = impl_from_IWshEnvironment(iface);
486 FIXME("(%p)->(%p): stub\n", This, len);
487 return E_NOTIMPL;
490 static HRESULT WINAPI WshEnvironment__NewEnum(IWshEnvironment *iface, IUnknown **penum)
492 WshEnvironment *This = impl_from_IWshEnvironment(iface);
493 FIXME("(%p)->(%p): stub\n", This, penum);
494 return E_NOTIMPL;
497 static HRESULT WINAPI WshEnvironment_Remove(IWshEnvironment *iface, BSTR name)
499 WshEnvironment *This = impl_from_IWshEnvironment(iface);
500 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
501 return E_NOTIMPL;
504 static const IWshEnvironmentVtbl WshEnvironmentVtbl = {
505 WshEnvironment_QueryInterface,
506 WshEnvironment_AddRef,
507 WshEnvironment_Release,
508 WshEnvironment_GetTypeInfoCount,
509 WshEnvironment_GetTypeInfo,
510 WshEnvironment_GetIDsOfNames,
511 WshEnvironment_Invoke,
512 WshEnvironment_get_Item,
513 WshEnvironment_put_Item,
514 WshEnvironment_Count,
515 WshEnvironment_get_length,
516 WshEnvironment__NewEnum,
517 WshEnvironment_Remove
520 static HRESULT WshEnvironment_Create(IWshEnvironment **env)
522 WshEnvironment *This;
524 This = heap_alloc(sizeof(*This));
525 if (!This) return E_OUTOFMEMORY;
527 This->IWshEnvironment_iface.lpVtbl = &WshEnvironmentVtbl;
528 This->ref = 1;
530 init_classinfo(&IID_IWshEnvironment, (IUnknown *)&This->IWshEnvironment_iface, &This->classinfo);
531 *env = &This->IWshEnvironment_iface;
533 return S_OK;
536 static HRESULT WINAPI WshCollection_QueryInterface(IWshCollection *iface, REFIID riid, void **ppv)
538 WshCollection *This = impl_from_IWshCollection(iface);
540 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
542 if (IsEqualGUID(riid, &IID_IUnknown) ||
543 IsEqualGUID(riid, &IID_IDispatch) ||
544 IsEqualGUID(riid, &IID_IWshCollection))
546 *ppv = iface;
548 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
550 *ppv = &This->classinfo.IProvideClassInfo_iface;
552 else {
553 FIXME("Unknown iface %s\n", debugstr_guid(riid));
554 *ppv = NULL;
555 return E_NOINTERFACE;
558 IUnknown_AddRef((IUnknown*)*ppv);
559 return S_OK;
562 static ULONG WINAPI WshCollection_AddRef(IWshCollection *iface)
564 WshCollection *This = impl_from_IWshCollection(iface);
565 LONG ref = InterlockedIncrement(&This->ref);
566 TRACE("(%p) ref = %d\n", This, ref);
567 return ref;
570 static ULONG WINAPI WshCollection_Release(IWshCollection *iface)
572 WshCollection *This = impl_from_IWshCollection(iface);
573 LONG ref = InterlockedDecrement(&This->ref);
574 TRACE("(%p) ref = %d\n", This, ref);
576 if (!ref)
577 heap_free(This);
579 return ref;
582 static HRESULT WINAPI WshCollection_GetTypeInfoCount(IWshCollection *iface, UINT *pctinfo)
584 WshCollection *This = impl_from_IWshCollection(iface);
585 TRACE("(%p)->(%p)\n", This, pctinfo);
586 *pctinfo = 1;
587 return S_OK;
590 static HRESULT WINAPI WshCollection_GetTypeInfo(IWshCollection *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
592 WshCollection *This = impl_from_IWshCollection(iface);
593 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
594 return get_typeinfo(IWshCollection_tid, ppTInfo);
597 static HRESULT WINAPI WshCollection_GetIDsOfNames(IWshCollection *iface, REFIID riid, LPOLESTR *rgszNames,
598 UINT cNames, LCID lcid, DISPID *rgDispId)
600 WshCollection *This = impl_from_IWshCollection(iface);
601 ITypeInfo *typeinfo;
602 HRESULT hr;
604 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
606 hr = get_typeinfo(IWshCollection_tid, &typeinfo);
607 if(SUCCEEDED(hr))
609 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
610 ITypeInfo_Release(typeinfo);
613 return hr;
616 static HRESULT WINAPI WshCollection_Invoke(IWshCollection *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
617 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
619 WshCollection *This = impl_from_IWshCollection(iface);
620 ITypeInfo *typeinfo;
621 HRESULT hr;
623 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
624 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
626 hr = get_typeinfo(IWshCollection_tid, &typeinfo);
627 if(SUCCEEDED(hr))
629 hr = ITypeInfo_Invoke(typeinfo, &This->IWshCollection_iface, dispIdMember, wFlags,
630 pDispParams, pVarResult, pExcepInfo, puArgErr);
631 ITypeInfo_Release(typeinfo);
634 return hr;
637 static HRESULT WINAPI WshCollection_Item(IWshCollection *iface, VARIANT *index, VARIANT *value)
639 WshCollection *This = impl_from_IWshCollection(iface);
640 static const WCHAR allusersdesktopW[] = {'A','l','l','U','s','e','r','s','D','e','s','k','t','o','p',0};
641 static const WCHAR allusersprogramsW[] = {'A','l','l','U','s','e','r','s','P','r','o','g','r','a','m','s',0};
642 static const WCHAR desktopW[] = {'D','e','s','k','t','o','p',0};
643 PIDLIST_ABSOLUTE pidl;
644 WCHAR pathW[MAX_PATH];
645 int kind = 0;
646 BSTR folder;
647 HRESULT hr;
649 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(index), value);
651 if (V_VT(index) != VT_BSTR)
653 FIXME("only BSTR index supported, got %d\n", V_VT(index));
654 return E_NOTIMPL;
657 folder = V_BSTR(index);
658 if (!wcsicmp(folder, desktopW))
659 kind = CSIDL_DESKTOP;
660 else if (!wcsicmp(folder, allusersdesktopW))
661 kind = CSIDL_COMMON_DESKTOPDIRECTORY;
662 else if (!wcsicmp(folder, allusersprogramsW))
663 kind = CSIDL_COMMON_PROGRAMS;
664 else
666 FIXME("folder kind %s not supported\n", debugstr_w(folder));
667 return E_NOTIMPL;
670 hr = SHGetSpecialFolderLocation(NULL, kind, &pidl);
671 if (hr != S_OK) return hr;
673 if (SHGetPathFromIDListW(pidl, pathW))
675 V_VT(value) = VT_BSTR;
676 V_BSTR(value) = SysAllocString(pathW);
677 hr = V_BSTR(value) ? S_OK : E_OUTOFMEMORY;
679 else
680 hr = E_FAIL;
682 CoTaskMemFree(pidl);
684 return hr;
687 static HRESULT WINAPI WshCollection_Count(IWshCollection *iface, LONG *count)
689 WshCollection *This = impl_from_IWshCollection(iface);
690 FIXME("(%p)->(%p): stub\n", This, count);
691 return E_NOTIMPL;
694 static HRESULT WINAPI WshCollection_get_length(IWshCollection *iface, LONG *count)
696 WshCollection *This = impl_from_IWshCollection(iface);
697 FIXME("(%p)->(%p): stub\n", This, count);
698 return E_NOTIMPL;
701 static HRESULT WINAPI WshCollection__NewEnum(IWshCollection *iface, IUnknown **Enum)
703 WshCollection *This = impl_from_IWshCollection(iface);
704 FIXME("(%p)->(%p): stub\n", This, Enum);
705 return E_NOTIMPL;
708 static const IWshCollectionVtbl WshCollectionVtbl = {
709 WshCollection_QueryInterface,
710 WshCollection_AddRef,
711 WshCollection_Release,
712 WshCollection_GetTypeInfoCount,
713 WshCollection_GetTypeInfo,
714 WshCollection_GetIDsOfNames,
715 WshCollection_Invoke,
716 WshCollection_Item,
717 WshCollection_Count,
718 WshCollection_get_length,
719 WshCollection__NewEnum
722 static HRESULT WshCollection_Create(IWshCollection **collection)
724 WshCollection *This;
726 This = heap_alloc(sizeof(*This));
727 if (!This) return E_OUTOFMEMORY;
729 This->IWshCollection_iface.lpVtbl = &WshCollectionVtbl;
730 This->ref = 1;
732 init_classinfo(&IID_IWshCollection, (IUnknown *)&This->IWshCollection_iface, &This->classinfo);
733 *collection = &This->IWshCollection_iface;
735 return S_OK;
738 /* IWshShortcut */
739 static HRESULT WINAPI WshShortcut_QueryInterface(IWshShortcut *iface, REFIID riid, void **ppv)
741 WshShortcut *This = impl_from_IWshShortcut(iface);
743 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
745 if (IsEqualGUID(riid, &IID_IUnknown) ||
746 IsEqualGUID(riid, &IID_IDispatch) ||
747 IsEqualGUID(riid, &IID_IWshShortcut))
749 *ppv = iface;
751 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
753 *ppv = &This->classinfo.IProvideClassInfo_iface;
755 else {
756 FIXME("Unknown iface %s\n", debugstr_guid(riid));
757 *ppv = NULL;
758 return E_NOINTERFACE;
761 IUnknown_AddRef((IUnknown*)*ppv);
762 return S_OK;
765 static ULONG WINAPI WshShortcut_AddRef(IWshShortcut *iface)
767 WshShortcut *This = impl_from_IWshShortcut(iface);
768 LONG ref = InterlockedIncrement(&This->ref);
769 TRACE("(%p) ref = %d\n", This, ref);
770 return ref;
773 static ULONG WINAPI WshShortcut_Release(IWshShortcut *iface)
775 WshShortcut *This = impl_from_IWshShortcut(iface);
776 LONG ref = InterlockedDecrement(&This->ref);
777 TRACE("(%p) ref = %d\n", This, ref);
779 if (!ref)
781 SysFreeString(This->path_link);
782 IShellLinkW_Release(This->link);
783 heap_free(This);
786 return ref;
789 static HRESULT WINAPI WshShortcut_GetTypeInfoCount(IWshShortcut *iface, UINT *pctinfo)
791 WshShortcut *This = impl_from_IWshShortcut(iface);
792 TRACE("(%p)->(%p)\n", This, pctinfo);
793 *pctinfo = 1;
794 return S_OK;
797 static HRESULT WINAPI WshShortcut_GetTypeInfo(IWshShortcut *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
799 WshShortcut *This = impl_from_IWshShortcut(iface);
800 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
801 return get_typeinfo(IWshShortcut_tid, ppTInfo);
804 static HRESULT WINAPI WshShortcut_GetIDsOfNames(IWshShortcut *iface, REFIID riid, LPOLESTR *rgszNames,
805 UINT cNames, LCID lcid, DISPID *rgDispId)
807 WshShortcut *This = impl_from_IWshShortcut(iface);
808 ITypeInfo *typeinfo;
809 HRESULT hr;
811 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
813 hr = get_typeinfo(IWshShortcut_tid, &typeinfo);
814 if(SUCCEEDED(hr))
816 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
817 ITypeInfo_Release(typeinfo);
820 return hr;
823 static HRESULT WINAPI WshShortcut_Invoke(IWshShortcut *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
824 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
826 WshShortcut *This = impl_from_IWshShortcut(iface);
827 ITypeInfo *typeinfo;
828 HRESULT hr;
830 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
831 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
833 hr = get_typeinfo(IWshShortcut_tid, &typeinfo);
834 if(SUCCEEDED(hr))
836 hr = ITypeInfo_Invoke(typeinfo, &This->IWshShortcut_iface, dispIdMember, wFlags,
837 pDispParams, pVarResult, pExcepInfo, puArgErr);
838 ITypeInfo_Release(typeinfo);
841 return hr;
844 static HRESULT WINAPI WshShortcut_get_FullName(IWshShortcut *iface, BSTR *name)
846 WshShortcut *This = impl_from_IWshShortcut(iface);
847 FIXME("(%p)->(%p): stub\n", This, name);
848 return E_NOTIMPL;
851 static HRESULT WINAPI WshShortcut_get_Arguments(IWshShortcut *iface, BSTR *Arguments)
853 WshShortcut *This = impl_from_IWshShortcut(iface);
854 WCHAR buffW[INFOTIPSIZE];
855 HRESULT hr;
857 TRACE("(%p)->(%p)\n", This, Arguments);
859 if (!Arguments)
860 return E_POINTER;
862 *Arguments = NULL;
864 hr = IShellLinkW_GetArguments(This->link, buffW, ARRAY_SIZE(buffW));
865 if (FAILED(hr))
866 return hr;
868 *Arguments = SysAllocString(buffW);
869 return *Arguments ? S_OK : E_OUTOFMEMORY;
872 static HRESULT WINAPI WshShortcut_put_Arguments(IWshShortcut *iface, BSTR Arguments)
874 WshShortcut *This = impl_from_IWshShortcut(iface);
876 TRACE("(%p)->(%s)\n", This, debugstr_w(Arguments));
878 return IShellLinkW_SetArguments(This->link, Arguments);
881 static HRESULT WINAPI WshShortcut_get_Description(IWshShortcut *iface, BSTR *Description)
883 WshShortcut *This = impl_from_IWshShortcut(iface);
884 FIXME("(%p)->(%p): stub\n", This, Description);
885 return E_NOTIMPL;
888 static HRESULT WINAPI WshShortcut_put_Description(IWshShortcut *iface, BSTR Description)
890 WshShortcut *This = impl_from_IWshShortcut(iface);
891 TRACE("(%p)->(%s)\n", This, debugstr_w(Description));
892 return IShellLinkW_SetDescription(This->link, Description);
895 static HRESULT WINAPI WshShortcut_get_Hotkey(IWshShortcut *iface, BSTR *Hotkey)
897 WshShortcut *This = impl_from_IWshShortcut(iface);
898 FIXME("(%p)->(%p): stub\n", This, Hotkey);
899 return E_NOTIMPL;
902 static HRESULT WINAPI WshShortcut_put_Hotkey(IWshShortcut *iface, BSTR Hotkey)
904 WshShortcut *This = impl_from_IWshShortcut(iface);
905 FIXME("(%p)->(%s): stub\n", This, debugstr_w(Hotkey));
906 return E_NOTIMPL;
909 static HRESULT WINAPI WshShortcut_get_IconLocation(IWshShortcut *iface, BSTR *IconPath)
911 static const WCHAR fmtW[] = {'%','s',',',' ','%','d',0};
912 WshShortcut *This = impl_from_IWshShortcut(iface);
913 WCHAR buffW[MAX_PATH], pathW[MAX_PATH];
914 INT icon = 0;
915 HRESULT hr;
917 TRACE("(%p)->(%p)\n", This, IconPath);
919 if (!IconPath)
920 return E_POINTER;
922 hr = IShellLinkW_GetIconLocation(This->link, buffW, ARRAY_SIZE(buffW), &icon);
923 if (FAILED(hr)) return hr;
925 swprintf(pathW, ARRAY_SIZE(pathW), fmtW, buffW, icon);
926 *IconPath = SysAllocString(pathW);
927 if (!*IconPath) return E_OUTOFMEMORY;
929 return S_OK;
932 static HRESULT WINAPI WshShortcut_put_IconLocation(IWshShortcut *iface, BSTR IconPath)
934 WshShortcut *This = impl_from_IWshShortcut(iface);
935 HRESULT hr;
936 WCHAR *ptr;
937 BSTR path;
938 INT icon;
940 TRACE("(%p)->(%s)\n", This, debugstr_w(IconPath));
942 /* scan for icon id */
943 ptr = wcsrchr(IconPath, ',');
944 if (!ptr)
946 WARN("icon index not found\n");
947 return E_FAIL;
950 path = SysAllocStringLen(IconPath, ptr-IconPath);
952 /* skip spaces if any */
953 while (iswspace(*++ptr))
956 icon = wcstol(ptr, NULL, 10);
958 hr = IShellLinkW_SetIconLocation(This->link, path, icon);
959 SysFreeString(path);
961 return hr;
964 static HRESULT WINAPI WshShortcut_put_RelativePath(IWshShortcut *iface, BSTR rhs)
966 WshShortcut *This = impl_from_IWshShortcut(iface);
967 FIXME("(%p)->(%s): stub\n", This, debugstr_w(rhs));
968 return E_NOTIMPL;
971 static HRESULT WINAPI WshShortcut_get_TargetPath(IWshShortcut *iface, BSTR *Path)
973 WshShortcut *This = impl_from_IWshShortcut(iface);
974 FIXME("(%p)->(%p): stub\n", This, Path);
975 return E_NOTIMPL;
978 static HRESULT WINAPI WshShortcut_put_TargetPath(IWshShortcut *iface, BSTR Path)
980 WshShortcut *This = impl_from_IWshShortcut(iface);
981 TRACE("(%p)->(%s)\n", This, debugstr_w(Path));
982 return IShellLinkW_SetPath(This->link, Path);
985 static HRESULT WINAPI WshShortcut_get_WindowStyle(IWshShortcut *iface, int *ShowCmd)
987 WshShortcut *This = impl_from_IWshShortcut(iface);
988 TRACE("(%p)->(%p)\n", This, ShowCmd);
989 return IShellLinkW_GetShowCmd(This->link, ShowCmd);
992 static HRESULT WINAPI WshShortcut_put_WindowStyle(IWshShortcut *iface, int ShowCmd)
994 WshShortcut *This = impl_from_IWshShortcut(iface);
995 TRACE("(%p)->(%d)\n", This, ShowCmd);
996 return IShellLinkW_SetShowCmd(This->link, ShowCmd);
999 static HRESULT WINAPI WshShortcut_get_WorkingDirectory(IWshShortcut *iface, BSTR *WorkingDirectory)
1001 WshShortcut *This = impl_from_IWshShortcut(iface);
1002 WCHAR buffW[MAX_PATH];
1003 HRESULT hr;
1005 TRACE("(%p)->(%p)\n", This, WorkingDirectory);
1007 if (!WorkingDirectory)
1008 return E_POINTER;
1010 *WorkingDirectory = NULL;
1011 hr = IShellLinkW_GetWorkingDirectory(This->link, buffW, ARRAY_SIZE(buffW));
1012 if (FAILED(hr)) return hr;
1014 *WorkingDirectory = SysAllocString(buffW);
1015 return *WorkingDirectory ? S_OK : E_OUTOFMEMORY;
1018 static HRESULT WINAPI WshShortcut_put_WorkingDirectory(IWshShortcut *iface, BSTR WorkingDirectory)
1020 WshShortcut *This = impl_from_IWshShortcut(iface);
1021 TRACE("(%p)->(%s)\n", This, debugstr_w(WorkingDirectory));
1022 return IShellLinkW_SetWorkingDirectory(This->link, WorkingDirectory);
1025 static HRESULT WINAPI WshShortcut_Load(IWshShortcut *iface, BSTR PathLink)
1027 WshShortcut *This = impl_from_IWshShortcut(iface);
1028 FIXME("(%p)->(%s): stub\n", This, debugstr_w(PathLink));
1029 return E_NOTIMPL;
1032 static HRESULT WINAPI WshShortcut_Save(IWshShortcut *iface)
1034 WshShortcut *This = impl_from_IWshShortcut(iface);
1035 IPersistFile *file;
1036 HRESULT hr;
1038 TRACE("(%p)\n", This);
1040 IShellLinkW_QueryInterface(This->link, &IID_IPersistFile, (void**)&file);
1041 hr = IPersistFile_Save(file, This->path_link, TRUE);
1042 IPersistFile_Release(file);
1044 return hr;
1047 static const IWshShortcutVtbl WshShortcutVtbl = {
1048 WshShortcut_QueryInterface,
1049 WshShortcut_AddRef,
1050 WshShortcut_Release,
1051 WshShortcut_GetTypeInfoCount,
1052 WshShortcut_GetTypeInfo,
1053 WshShortcut_GetIDsOfNames,
1054 WshShortcut_Invoke,
1055 WshShortcut_get_FullName,
1056 WshShortcut_get_Arguments,
1057 WshShortcut_put_Arguments,
1058 WshShortcut_get_Description,
1059 WshShortcut_put_Description,
1060 WshShortcut_get_Hotkey,
1061 WshShortcut_put_Hotkey,
1062 WshShortcut_get_IconLocation,
1063 WshShortcut_put_IconLocation,
1064 WshShortcut_put_RelativePath,
1065 WshShortcut_get_TargetPath,
1066 WshShortcut_put_TargetPath,
1067 WshShortcut_get_WindowStyle,
1068 WshShortcut_put_WindowStyle,
1069 WshShortcut_get_WorkingDirectory,
1070 WshShortcut_put_WorkingDirectory,
1071 WshShortcut_Load,
1072 WshShortcut_Save
1075 static HRESULT WshShortcut_Create(const WCHAR *path, IDispatch **shortcut)
1077 WshShortcut *This;
1078 HRESULT hr;
1080 *shortcut = NULL;
1082 This = heap_alloc(sizeof(*This));
1083 if (!This) return E_OUTOFMEMORY;
1085 This->IWshShortcut_iface.lpVtbl = &WshShortcutVtbl;
1086 This->ref = 1;
1088 hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
1089 &IID_IShellLinkW, (void**)&This->link);
1090 if (FAILED(hr))
1092 heap_free(This);
1093 return hr;
1096 This->path_link = SysAllocString(path);
1097 if (!This->path_link)
1099 IShellLinkW_Release(This->link);
1100 heap_free(This);
1101 return E_OUTOFMEMORY;
1104 init_classinfo(&IID_IWshShortcut, (IUnknown *)&This->IWshShortcut_iface, &This->classinfo);
1105 *shortcut = (IDispatch*)&This->IWshShortcut_iface;
1107 return S_OK;
1110 static HRESULT WINAPI WshShell3_QueryInterface(IWshShell3 *iface, REFIID riid, void **ppv)
1112 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
1114 *ppv = NULL;
1116 if (IsEqualGUID(riid, &IID_IDispatch) ||
1117 IsEqualGUID(riid, &IID_IWshShell3) ||
1118 IsEqualGUID(riid, &IID_IWshShell2) ||
1119 IsEqualGUID(riid, &IID_IWshShell) ||
1120 IsEqualGUID(riid, &IID_IUnknown))
1122 *ppv = iface;
1124 else if (IsEqualGUID(riid, &IID_IDispatchEx))
1126 return E_NOINTERFACE;
1128 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
1130 *ppv = &WshShell3.classinfo.IProvideClassInfo_iface;
1132 else
1134 WARN("unknown iface %s\n", debugstr_guid(riid));
1135 return E_NOINTERFACE;
1138 IUnknown_AddRef((IUnknown *)*ppv);
1139 return S_OK;
1142 static ULONG WINAPI WshShell3_AddRef(IWshShell3 *iface)
1144 TRACE("()\n");
1145 return 2;
1148 static ULONG WINAPI WshShell3_Release(IWshShell3 *iface)
1150 TRACE("()\n");
1151 return 2;
1154 static HRESULT WINAPI WshShell3_GetTypeInfoCount(IWshShell3 *iface, UINT *pctinfo)
1156 TRACE("(%p)\n", pctinfo);
1157 *pctinfo = 1;
1158 return S_OK;
1161 static HRESULT WINAPI WshShell3_GetTypeInfo(IWshShell3 *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
1163 TRACE("(%u %u %p)\n", iTInfo, lcid, ppTInfo);
1164 return get_typeinfo(IWshShell3_tid, ppTInfo);
1167 static HRESULT WINAPI WshShell3_GetIDsOfNames(IWshShell3 *iface, REFIID riid, LPOLESTR *rgszNames,
1168 UINT cNames, LCID lcid, DISPID *rgDispId)
1170 ITypeInfo *typeinfo;
1171 HRESULT hr;
1173 TRACE("(%s %p %u %u %p)\n", debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1175 hr = get_typeinfo(IWshShell3_tid, &typeinfo);
1176 if(SUCCEEDED(hr))
1178 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1179 ITypeInfo_Release(typeinfo);
1182 return hr;
1185 static HRESULT WINAPI WshShell3_Invoke(IWshShell3 *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
1186 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
1188 ITypeInfo *typeinfo;
1189 HRESULT hr;
1191 TRACE("(%d %s %d %d %p %p %p %p)\n", dispIdMember, debugstr_guid(riid),
1192 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1194 hr = get_typeinfo(IWshShell3_tid, &typeinfo);
1195 if(SUCCEEDED(hr))
1197 hr = ITypeInfo_Invoke(typeinfo, &WshShell3.IWshShell3_iface, dispIdMember, wFlags,
1198 pDispParams, pVarResult, pExcepInfo, puArgErr);
1199 ITypeInfo_Release(typeinfo);
1202 return hr;
1205 static HRESULT WINAPI WshShell3_get_SpecialFolders(IWshShell3 *iface, IWshCollection **folders)
1207 TRACE("(%p)\n", folders);
1208 return WshCollection_Create(folders);
1211 static HRESULT WINAPI WshShell3_get_Environment(IWshShell3 *iface, VARIANT *type, IWshEnvironment **env)
1213 FIXME("(%s %p): semi-stub\n", debugstr_variant(type), env);
1214 return WshEnvironment_Create(env);
1217 static inline BOOL is_optional_argument(const VARIANT *arg)
1219 return V_VT(arg) == VT_ERROR && V_ERROR(arg) == DISP_E_PARAMNOTFOUND;
1222 static WCHAR *split_command( BSTR cmd, WCHAR **params )
1224 WCHAR *ret, *ptr;
1225 BOOL in_quotes = FALSE;
1227 if (!(ret = heap_alloc((lstrlenW(cmd) + 1) * sizeof(WCHAR)))) return NULL;
1228 lstrcpyW( ret, cmd );
1230 *params = NULL;
1231 for (ptr = ret; *ptr; ptr++)
1233 if (*ptr == '"') in_quotes = !in_quotes;
1234 else if (*ptr == ' ' && !in_quotes)
1236 *ptr = 0;
1237 *params = ptr + 1;
1238 break;
1242 return ret;
1245 static HRESULT WINAPI WshShell3_Run(IWshShell3 *iface, BSTR cmd, VARIANT *style, VARIANT *wait, DWORD *exit_code)
1247 SHELLEXECUTEINFOW info;
1248 int waitforprocess;
1249 WCHAR *file, *params;
1250 VARIANT s;
1251 HRESULT hr;
1252 BOOL ret;
1254 TRACE("(%s %s %s %p)\n", debugstr_w(cmd), debugstr_variant(style), debugstr_variant(wait), exit_code);
1256 if (!style || !wait || !exit_code)
1257 return E_POINTER;
1259 VariantInit(&s);
1260 hr = VariantChangeType(&s, style, 0, VT_I4);
1261 if (FAILED(hr))
1263 ERR("failed to convert style argument, 0x%08x\n", hr);
1264 return hr;
1267 if (is_optional_argument(wait))
1268 waitforprocess = 0;
1269 else {
1270 VARIANT w;
1272 VariantInit(&w);
1273 hr = VariantChangeType(&w, wait, 0, VT_I4);
1274 if (FAILED(hr))
1275 return hr;
1277 waitforprocess = V_I4(&w);
1280 if (!(file = split_command(cmd, &params))) return E_OUTOFMEMORY;
1282 memset(&info, 0, sizeof(info));
1283 info.cbSize = sizeof(info);
1284 info.fMask = waitforprocess ? SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS : SEE_MASK_DEFAULT;
1285 info.lpFile = file;
1286 info.lpParameters = params;
1287 info.nShow = V_I4(&s);
1289 ret = ShellExecuteExW(&info);
1290 heap_free( file );
1291 if (!ret)
1293 TRACE("ShellExecute failed, %d\n", GetLastError());
1294 return HRESULT_FROM_WIN32(GetLastError());
1296 else
1298 if (waitforprocess)
1300 WaitForSingleObject(info.hProcess, INFINITE);
1301 GetExitCodeProcess(info.hProcess, exit_code);
1302 CloseHandle(info.hProcess);
1304 else
1305 *exit_code = 0;
1307 return S_OK;
1311 struct popup_thread_param
1313 WCHAR *text;
1314 VARIANT title;
1315 VARIANT type;
1316 INT button;
1319 static DWORD WINAPI popup_thread_proc(void *arg)
1321 static const WCHAR defaulttitleW[] = {'W','i','n','d','o','w','s',' ','S','c','r','i','p','t',' ','H','o','s','t',0};
1322 struct popup_thread_param *param = (struct popup_thread_param *)arg;
1324 param->button = MessageBoxW(NULL, param->text, is_optional_argument(&param->title) ?
1325 defaulttitleW : V_BSTR(&param->title), V_I4(&param->type));
1326 return 0;
1329 static HRESULT WINAPI WshShell3_Popup(IWshShell3 *iface, BSTR text, VARIANT *seconds_to_wait, VARIANT *title,
1330 VARIANT *type, int *button)
1332 struct popup_thread_param param;
1333 DWORD tid, status;
1334 VARIANT timeout;
1335 HANDLE hthread;
1336 HRESULT hr;
1338 TRACE("(%s %s %s %s %p)\n", debugstr_w(text), debugstr_variant(seconds_to_wait), debugstr_variant(title),
1339 debugstr_variant(type), button);
1341 if (!seconds_to_wait || !title || !type || !button)
1342 return E_POINTER;
1344 VariantInit(&timeout);
1345 if (!is_optional_argument(seconds_to_wait))
1347 hr = VariantChangeType(&timeout, seconds_to_wait, 0, VT_I4);
1348 if (FAILED(hr))
1349 return hr;
1352 VariantInit(&param.type);
1353 if (!is_optional_argument(type))
1355 hr = VariantChangeType(&param.type, type, 0, VT_I4);
1356 if (FAILED(hr))
1357 return hr;
1360 if (is_optional_argument(title))
1361 param.title = *title;
1362 else
1364 VariantInit(&param.title);
1365 hr = VariantChangeType(&param.title, title, 0, VT_BSTR);
1366 if (FAILED(hr))
1367 return hr;
1370 param.text = text;
1371 param.button = -1;
1372 hthread = CreateThread(NULL, 0, popup_thread_proc, &param, 0, &tid);
1373 status = MsgWaitForMultipleObjects(1, &hthread, FALSE, V_I4(&timeout) ? V_I4(&timeout) * 1000: INFINITE, 0);
1374 if (status == WAIT_TIMEOUT)
1376 PostThreadMessageW(tid, WM_QUIT, 0, 0);
1377 MsgWaitForMultipleObjects(1, &hthread, FALSE, INFINITE, 0);
1378 param.button = -1;
1380 *button = param.button;
1382 VariantClear(&param.title);
1383 CloseHandle(hthread);
1385 return S_OK;
1388 static HRESULT WINAPI WshShell3_CreateShortcut(IWshShell3 *iface, BSTR PathLink, IDispatch** Shortcut)
1390 TRACE("(%s %p)\n", debugstr_w(PathLink), Shortcut);
1391 return WshShortcut_Create(PathLink, Shortcut);
1394 static HRESULT WINAPI WshShell3_ExpandEnvironmentStrings(IWshShell3 *iface, BSTR Src, BSTR* Dst)
1396 DWORD ret;
1398 TRACE("(%s %p)\n", debugstr_w(Src), Dst);
1400 if (!Src || !Dst) return E_POINTER;
1402 ret = ExpandEnvironmentStringsW(Src, NULL, 0);
1403 *Dst = SysAllocStringLen(NULL, ret);
1404 if (!*Dst) return E_OUTOFMEMORY;
1406 if (ExpandEnvironmentStringsW(Src, *Dst, ret))
1407 return S_OK;
1408 else
1410 SysFreeString(*Dst);
1411 *Dst = NULL;
1412 return HRESULT_FROM_WIN32(GetLastError());
1416 static HKEY get_root_key(const WCHAR *path)
1418 static const struct {
1419 const WCHAR full[20];
1420 const WCHAR abbrev[5];
1421 HKEY hkey;
1422 } rootkeys[] = {
1423 { {'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R',0}, {'H','K','C','U',0}, HKEY_CURRENT_USER },
1424 { {'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 },
1425 { {'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T',0}, {'H','K','C','R',0}, HKEY_CLASSES_ROOT },
1426 { {'H','K','E','Y','_','U','S','E','R','S',0}, {0}, HKEY_USERS },
1427 { {'H','K','E','Y','_','C','U','R','R','E','N','T','_','C','O','N','F','I','G',0}, {0}, HKEY_CURRENT_CONFIG }
1429 int i;
1431 for (i = 0; i < ARRAY_SIZE(rootkeys); i++) {
1432 if (!wcsncmp(path, rootkeys[i].full, lstrlenW(rootkeys[i].full)))
1433 return rootkeys[i].hkey;
1434 if (rootkeys[i].abbrev[0] && !wcsncmp(path, rootkeys[i].abbrev, lstrlenW(rootkeys[i].abbrev)))
1435 return rootkeys[i].hkey;
1438 return NULL;
1441 /* Caller is responsible to free 'subkey' if 'value' is not NULL */
1442 static HRESULT split_reg_path(const WCHAR *path, WCHAR **subkey, WCHAR **value)
1444 *value = NULL;
1446 /* at least one separator should be present */
1447 *subkey = wcschr(path, '\\');
1448 if (!*subkey)
1449 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1451 /* default value or not */
1452 if ((*subkey)[lstrlenW(*subkey)-1] == '\\') {
1453 (*subkey)++;
1454 *value = NULL;
1456 else {
1457 *value = wcsrchr(*subkey, '\\');
1458 if (*value - *subkey > 1) {
1459 unsigned int len = *value - *subkey - 1;
1460 WCHAR *ret;
1462 ret = heap_alloc((len + 1)*sizeof(WCHAR));
1463 if (!ret)
1464 return E_OUTOFMEMORY;
1466 memcpy(ret, *subkey + 1, len*sizeof(WCHAR));
1467 ret[len] = 0;
1468 *subkey = ret;
1470 (*value)++;
1473 return S_OK;
1476 static HRESULT WINAPI WshShell3_RegRead(IWshShell3 *iface, BSTR name, VARIANT *value)
1478 DWORD type, datalen, ret;
1479 WCHAR *subkey, *val;
1480 HRESULT hr;
1481 HKEY root;
1483 TRACE("(%s %p)\n", debugstr_w(name), value);
1485 if (!name || !value)
1486 return E_POINTER;
1488 root = get_root_key(name);
1489 if (!root)
1490 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1492 hr = split_reg_path(name, &subkey, &val);
1493 if (FAILED(hr))
1494 return hr;
1496 type = REG_NONE;
1497 datalen = 0;
1498 ret = RegGetValueW(root, subkey, val, RRF_RT_ANY, &type, NULL, &datalen);
1499 if (ret == ERROR_SUCCESS) {
1500 void *data;
1502 data = heap_alloc(datalen);
1503 if (!data) {
1504 hr = E_OUTOFMEMORY;
1505 goto fail;
1508 ret = RegGetValueW(root, subkey, val, RRF_RT_ANY, &type, data, &datalen);
1509 if (ret) {
1510 heap_free(data);
1511 hr = HRESULT_FROM_WIN32(ret);
1512 goto fail;
1515 switch (type) {
1516 case REG_SZ:
1517 case REG_EXPAND_SZ:
1518 V_VT(value) = VT_BSTR;
1519 V_BSTR(value) = SysAllocString((WCHAR*)data);
1520 if (!V_BSTR(value))
1521 hr = E_OUTOFMEMORY;
1522 break;
1523 case REG_DWORD:
1524 V_VT(value) = VT_I4;
1525 V_I4(value) = *(DWORD*)data;
1526 break;
1527 case REG_BINARY:
1529 BYTE *ptr = (BYTE*)data;
1530 SAFEARRAYBOUND bound;
1531 unsigned int i;
1532 SAFEARRAY *sa;
1533 VARIANT *v;
1535 bound.lLbound = 0;
1536 bound.cElements = datalen;
1537 sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
1538 if (!sa)
1539 break;
1541 hr = SafeArrayAccessData(sa, (void**)&v);
1542 if (FAILED(hr)) {
1543 SafeArrayDestroy(sa);
1544 break;
1547 for (i = 0; i < datalen; i++) {
1548 V_VT(&v[i]) = VT_UI1;
1549 V_UI1(&v[i]) = ptr[i];
1551 SafeArrayUnaccessData(sa);
1553 V_VT(value) = VT_ARRAY|VT_VARIANT;
1554 V_ARRAY(value) = sa;
1555 break;
1557 case REG_MULTI_SZ:
1559 WCHAR *ptr = (WCHAR*)data;
1560 SAFEARRAYBOUND bound;
1561 SAFEARRAY *sa;
1562 VARIANT *v;
1564 /* get element count first */
1565 bound.lLbound = 0;
1566 bound.cElements = 0;
1567 while (*ptr) {
1568 bound.cElements++;
1569 ptr += lstrlenW(ptr)+1;
1572 sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
1573 if (!sa)
1574 break;
1576 hr = SafeArrayAccessData(sa, (void**)&v);
1577 if (FAILED(hr)) {
1578 SafeArrayDestroy(sa);
1579 break;
1582 ptr = (WCHAR*)data;
1583 while (*ptr) {
1584 V_VT(v) = VT_BSTR;
1585 V_BSTR(v) = SysAllocString(ptr);
1586 ptr += lstrlenW(ptr)+1;
1587 v++;
1590 SafeArrayUnaccessData(sa);
1591 V_VT(value) = VT_ARRAY|VT_VARIANT;
1592 V_ARRAY(value) = sa;
1593 break;
1595 default:
1596 FIXME("value type %d not supported\n", type);
1597 hr = E_FAIL;
1600 heap_free(data);
1601 if (FAILED(hr))
1602 VariantInit(value);
1604 else
1605 hr = HRESULT_FROM_WIN32(ret);
1607 fail:
1608 if (val)
1609 heap_free(subkey);
1610 return hr;
1613 static HRESULT WINAPI WshShell3_RegWrite(IWshShell3 *iface, BSTR name, VARIANT *value, VARIANT *type)
1615 static const WCHAR regexpandszW[] = {'R','E','G','_','E','X','P','A','N','D','_','S','Z',0};
1616 static const WCHAR regszW[] = {'R','E','G','_','S','Z',0};
1617 static const WCHAR regdwordW[] = {'R','E','G','_','D','W','O','R','D',0};
1618 static const WCHAR regbinaryW[] = {'R','E','G','_','B','I','N','A','R','Y',0};
1620 DWORD regtype, data_len;
1621 WCHAR *subkey, *val;
1622 const BYTE *data;
1623 HRESULT hr;
1624 HKEY root;
1625 VARIANT v;
1626 LONG ret;
1628 TRACE("(%s %s %s)\n", debugstr_w(name), debugstr_variant(value), debugstr_variant(type));
1630 if (!name || !value || !type)
1631 return E_POINTER;
1633 root = get_root_key(name);
1634 if (!root)
1635 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1637 /* value type */
1638 if (is_optional_argument(type))
1639 regtype = REG_SZ;
1640 else {
1641 if (V_VT(type) != VT_BSTR)
1642 return E_INVALIDARG;
1644 if (!wcscmp(V_BSTR(type), regszW))
1645 regtype = REG_SZ;
1646 else if (!wcscmp(V_BSTR(type), regdwordW))
1647 regtype = REG_DWORD;
1648 else if (!wcscmp(V_BSTR(type), regexpandszW))
1649 regtype = REG_EXPAND_SZ;
1650 else if (!wcscmp(V_BSTR(type), regbinaryW))
1651 regtype = REG_BINARY;
1652 else {
1653 FIXME("unrecognized value type %s\n", debugstr_w(V_BSTR(type)));
1654 return E_FAIL;
1658 /* it's always a string or a DWORD */
1659 VariantInit(&v);
1660 switch (regtype)
1662 case REG_SZ:
1663 case REG_EXPAND_SZ:
1664 hr = VariantChangeType(&v, value, 0, VT_BSTR);
1665 if (hr == S_OK) {
1666 data = (BYTE*)V_BSTR(&v);
1667 data_len = SysStringByteLen(V_BSTR(&v)) + sizeof(WCHAR);
1669 break;
1670 case REG_DWORD:
1671 case REG_BINARY:
1672 hr = VariantChangeType(&v, value, 0, VT_I4);
1673 data = (BYTE*)&V_I4(&v);
1674 data_len = sizeof(DWORD);
1675 break;
1676 default:
1677 FIXME("unexpected regtype %d\n", regtype);
1678 return E_FAIL;
1681 if (FAILED(hr)) {
1682 FIXME("failed to convert value, regtype %d, 0x%08x\n", regtype, hr);
1683 return hr;
1686 hr = split_reg_path(name, &subkey, &val);
1687 if (FAILED(hr))
1688 goto fail;
1690 ret = RegSetKeyValueW(root, subkey, val, regtype, data, data_len);
1691 if (ret)
1692 hr = HRESULT_FROM_WIN32(ret);
1694 fail:
1695 VariantClear(&v);
1696 if (val)
1697 heap_free(subkey);
1698 return hr;
1701 static HRESULT WINAPI WshShell3_RegDelete(IWshShell3 *iface, BSTR Name)
1703 FIXME("(%s): stub\n", debugstr_w(Name));
1704 return E_NOTIMPL;
1707 static HRESULT WINAPI WshShell3_LogEvent(IWshShell3 *iface, VARIANT *Type, BSTR Message, BSTR Target, VARIANT_BOOL *out_Success)
1709 FIXME("(%s %s %s %p): stub\n", debugstr_variant(Type), debugstr_w(Message), debugstr_w(Target), out_Success);
1710 return E_NOTIMPL;
1713 static HRESULT WINAPI WshShell3_AppActivate(IWshShell3 *iface, VARIANT *App, VARIANT *Wait, VARIANT_BOOL *out_Success)
1715 FIXME("(%s %s %p): stub\n", debugstr_variant(App), debugstr_variant(Wait), out_Success);
1716 return E_NOTIMPL;
1719 static HRESULT WINAPI WshShell3_SendKeys(IWshShell3 *iface, BSTR Keys, VARIANT *Wait)
1721 FIXME("(%s %p): stub\n", debugstr_w(Keys), Wait);
1722 return E_NOTIMPL;
1725 static HRESULT WINAPI WshShell3_Exec(IWshShell3 *iface, BSTR command, IWshExec **ret)
1727 TRACE("(%s %p)\n", debugstr_w(command), ret);
1729 if (!ret)
1730 return E_POINTER;
1732 if (!command)
1733 return DISP_E_EXCEPTION;
1735 return WshExec_create(command, ret);
1738 static HRESULT WINAPI WshShell3_get_CurrentDirectory(IWshShell3 *iface, BSTR *dir)
1740 DWORD ret;
1742 TRACE("(%p)\n", dir);
1744 ret = GetCurrentDirectoryW(0, NULL);
1745 if (!ret)
1746 return HRESULT_FROM_WIN32(GetLastError());
1748 *dir = SysAllocStringLen(NULL, ret-1);
1749 if (!*dir)
1750 return E_OUTOFMEMORY;
1752 ret = GetCurrentDirectoryW(ret, *dir);
1753 if (!ret) {
1754 SysFreeString(*dir);
1755 *dir = NULL;
1756 return HRESULT_FROM_WIN32(GetLastError());
1759 return S_OK;
1762 static HRESULT WINAPI WshShell3_put_CurrentDirectory(IWshShell3 *iface, BSTR dir)
1764 TRACE("(%s)\n", debugstr_w(dir));
1766 if (!dir)
1767 return E_INVALIDARG;
1769 if (!SetCurrentDirectoryW(dir))
1770 return HRESULT_FROM_WIN32(GetLastError());
1772 return S_OK;
1775 static const IWshShell3Vtbl WshShell3Vtbl = {
1776 WshShell3_QueryInterface,
1777 WshShell3_AddRef,
1778 WshShell3_Release,
1779 WshShell3_GetTypeInfoCount,
1780 WshShell3_GetTypeInfo,
1781 WshShell3_GetIDsOfNames,
1782 WshShell3_Invoke,
1783 WshShell3_get_SpecialFolders,
1784 WshShell3_get_Environment,
1785 WshShell3_Run,
1786 WshShell3_Popup,
1787 WshShell3_CreateShortcut,
1788 WshShell3_ExpandEnvironmentStrings,
1789 WshShell3_RegRead,
1790 WshShell3_RegWrite,
1791 WshShell3_RegDelete,
1792 WshShell3_LogEvent,
1793 WshShell3_AppActivate,
1794 WshShell3_SendKeys,
1795 WshShell3_Exec,
1796 WshShell3_get_CurrentDirectory,
1797 WshShell3_put_CurrentDirectory
1800 HRESULT WINAPI WshShellFactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
1802 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
1804 WshShell3.IWshShell3_iface.lpVtbl = &WshShell3Vtbl;
1805 init_classinfo(&IID_IWshShell3, (IUnknown *)&WshShell3.IWshShell3_iface, &WshShell3.classinfo);
1806 return IWshShell3_QueryInterface(&WshShell3.IWshShell3_iface, riid, ppv);