mfplay: Implement GetCharacteristics().
[wine/zf.git] / dlls / wshom.ocx / shell.c
blobe8fcba725054a3b6c58303a99b86143e9d6d3abf
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 PIDLIST_ABSOLUTE pidl;
641 WCHAR pathW[MAX_PATH];
642 int kind = 0;
643 BSTR folder;
644 HRESULT hr;
646 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(index), value);
648 if (V_VT(index) != VT_BSTR)
650 FIXME("only BSTR index supported, got %d\n", V_VT(index));
651 return E_NOTIMPL;
654 folder = V_BSTR(index);
655 if (!wcsicmp(folder, L"Desktop"))
656 kind = CSIDL_DESKTOP;
657 else if (!wcsicmp(folder, L"AllUsersDesktop"))
658 kind = CSIDL_COMMON_DESKTOPDIRECTORY;
659 else if (!wcsicmp(folder, L"AllUsersPrograms"))
660 kind = CSIDL_COMMON_PROGRAMS;
661 else
663 FIXME("folder kind %s not supported\n", debugstr_w(folder));
664 return E_NOTIMPL;
667 hr = SHGetSpecialFolderLocation(NULL, kind, &pidl);
668 if (hr != S_OK) return hr;
670 if (SHGetPathFromIDListW(pidl, pathW))
672 V_VT(value) = VT_BSTR;
673 V_BSTR(value) = SysAllocString(pathW);
674 hr = V_BSTR(value) ? S_OK : E_OUTOFMEMORY;
676 else
677 hr = E_FAIL;
679 CoTaskMemFree(pidl);
681 return hr;
684 static HRESULT WINAPI WshCollection_Count(IWshCollection *iface, LONG *count)
686 WshCollection *This = impl_from_IWshCollection(iface);
687 FIXME("(%p)->(%p): stub\n", This, count);
688 return E_NOTIMPL;
691 static HRESULT WINAPI WshCollection_get_length(IWshCollection *iface, LONG *count)
693 WshCollection *This = impl_from_IWshCollection(iface);
694 FIXME("(%p)->(%p): stub\n", This, count);
695 return E_NOTIMPL;
698 static HRESULT WINAPI WshCollection__NewEnum(IWshCollection *iface, IUnknown **Enum)
700 WshCollection *This = impl_from_IWshCollection(iface);
701 FIXME("(%p)->(%p): stub\n", This, Enum);
702 return E_NOTIMPL;
705 static const IWshCollectionVtbl WshCollectionVtbl = {
706 WshCollection_QueryInterface,
707 WshCollection_AddRef,
708 WshCollection_Release,
709 WshCollection_GetTypeInfoCount,
710 WshCollection_GetTypeInfo,
711 WshCollection_GetIDsOfNames,
712 WshCollection_Invoke,
713 WshCollection_Item,
714 WshCollection_Count,
715 WshCollection_get_length,
716 WshCollection__NewEnum
719 static HRESULT WshCollection_Create(IWshCollection **collection)
721 WshCollection *This;
723 This = heap_alloc(sizeof(*This));
724 if (!This) return E_OUTOFMEMORY;
726 This->IWshCollection_iface.lpVtbl = &WshCollectionVtbl;
727 This->ref = 1;
729 init_classinfo(&IID_IWshCollection, (IUnknown *)&This->IWshCollection_iface, &This->classinfo);
730 *collection = &This->IWshCollection_iface;
732 return S_OK;
735 /* IWshShortcut */
736 static HRESULT WINAPI WshShortcut_QueryInterface(IWshShortcut *iface, REFIID riid, void **ppv)
738 WshShortcut *This = impl_from_IWshShortcut(iface);
740 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
742 if (IsEqualGUID(riid, &IID_IUnknown) ||
743 IsEqualGUID(riid, &IID_IDispatch) ||
744 IsEqualGUID(riid, &IID_IWshShortcut))
746 *ppv = iface;
748 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
750 *ppv = &This->classinfo.IProvideClassInfo_iface;
752 else {
753 FIXME("Unknown iface %s\n", debugstr_guid(riid));
754 *ppv = NULL;
755 return E_NOINTERFACE;
758 IUnknown_AddRef((IUnknown*)*ppv);
759 return S_OK;
762 static ULONG WINAPI WshShortcut_AddRef(IWshShortcut *iface)
764 WshShortcut *This = impl_from_IWshShortcut(iface);
765 LONG ref = InterlockedIncrement(&This->ref);
766 TRACE("(%p) ref = %d\n", This, ref);
767 return ref;
770 static ULONG WINAPI WshShortcut_Release(IWshShortcut *iface)
772 WshShortcut *This = impl_from_IWshShortcut(iface);
773 LONG ref = InterlockedDecrement(&This->ref);
774 TRACE("(%p) ref = %d\n", This, ref);
776 if (!ref)
778 SysFreeString(This->path_link);
779 IShellLinkW_Release(This->link);
780 heap_free(This);
783 return ref;
786 static HRESULT WINAPI WshShortcut_GetTypeInfoCount(IWshShortcut *iface, UINT *pctinfo)
788 WshShortcut *This = impl_from_IWshShortcut(iface);
789 TRACE("(%p)->(%p)\n", This, pctinfo);
790 *pctinfo = 1;
791 return S_OK;
794 static HRESULT WINAPI WshShortcut_GetTypeInfo(IWshShortcut *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
796 WshShortcut *This = impl_from_IWshShortcut(iface);
797 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
798 return get_typeinfo(IWshShortcut_tid, ppTInfo);
801 static HRESULT WINAPI WshShortcut_GetIDsOfNames(IWshShortcut *iface, REFIID riid, LPOLESTR *rgszNames,
802 UINT cNames, LCID lcid, DISPID *rgDispId)
804 WshShortcut *This = impl_from_IWshShortcut(iface);
805 ITypeInfo *typeinfo;
806 HRESULT hr;
808 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
810 hr = get_typeinfo(IWshShortcut_tid, &typeinfo);
811 if(SUCCEEDED(hr))
813 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
814 ITypeInfo_Release(typeinfo);
817 return hr;
820 static HRESULT WINAPI WshShortcut_Invoke(IWshShortcut *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
821 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
823 WshShortcut *This = impl_from_IWshShortcut(iface);
824 ITypeInfo *typeinfo;
825 HRESULT hr;
827 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
828 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
830 hr = get_typeinfo(IWshShortcut_tid, &typeinfo);
831 if(SUCCEEDED(hr))
833 hr = ITypeInfo_Invoke(typeinfo, &This->IWshShortcut_iface, dispIdMember, wFlags,
834 pDispParams, pVarResult, pExcepInfo, puArgErr);
835 ITypeInfo_Release(typeinfo);
838 return hr;
841 static HRESULT WINAPI WshShortcut_get_FullName(IWshShortcut *iface, BSTR *name)
843 WshShortcut *This = impl_from_IWshShortcut(iface);
844 FIXME("(%p)->(%p): stub\n", This, name);
845 return E_NOTIMPL;
848 static HRESULT WINAPI WshShortcut_get_Arguments(IWshShortcut *iface, BSTR *Arguments)
850 WshShortcut *This = impl_from_IWshShortcut(iface);
851 WCHAR buffW[INFOTIPSIZE];
852 HRESULT hr;
854 TRACE("(%p)->(%p)\n", This, Arguments);
856 if (!Arguments)
857 return E_POINTER;
859 *Arguments = NULL;
861 hr = IShellLinkW_GetArguments(This->link, buffW, ARRAY_SIZE(buffW));
862 if (FAILED(hr))
863 return hr;
865 *Arguments = SysAllocString(buffW);
866 return *Arguments ? S_OK : E_OUTOFMEMORY;
869 static HRESULT WINAPI WshShortcut_put_Arguments(IWshShortcut *iface, BSTR Arguments)
871 WshShortcut *This = impl_from_IWshShortcut(iface);
873 TRACE("(%p)->(%s)\n", This, debugstr_w(Arguments));
875 return IShellLinkW_SetArguments(This->link, Arguments);
878 static HRESULT WINAPI WshShortcut_get_Description(IWshShortcut *iface, BSTR *Description)
880 WshShortcut *This = impl_from_IWshShortcut(iface);
881 FIXME("(%p)->(%p): stub\n", This, Description);
882 return E_NOTIMPL;
885 static HRESULT WINAPI WshShortcut_put_Description(IWshShortcut *iface, BSTR Description)
887 WshShortcut *This = impl_from_IWshShortcut(iface);
888 TRACE("(%p)->(%s)\n", This, debugstr_w(Description));
889 return IShellLinkW_SetDescription(This->link, Description);
892 static HRESULT WINAPI WshShortcut_get_Hotkey(IWshShortcut *iface, BSTR *Hotkey)
894 WshShortcut *This = impl_from_IWshShortcut(iface);
895 FIXME("(%p)->(%p): stub\n", This, Hotkey);
896 return E_NOTIMPL;
899 static HRESULT WINAPI WshShortcut_put_Hotkey(IWshShortcut *iface, BSTR Hotkey)
901 WshShortcut *This = impl_from_IWshShortcut(iface);
902 FIXME("(%p)->(%s): stub\n", This, debugstr_w(Hotkey));
903 return E_NOTIMPL;
906 static HRESULT WINAPI WshShortcut_get_IconLocation(IWshShortcut *iface, BSTR *IconPath)
908 WshShortcut *This = impl_from_IWshShortcut(iface);
909 WCHAR buffW[MAX_PATH], pathW[MAX_PATH];
910 INT icon = 0;
911 HRESULT hr;
913 TRACE("(%p)->(%p)\n", This, IconPath);
915 if (!IconPath)
916 return E_POINTER;
918 hr = IShellLinkW_GetIconLocation(This->link, buffW, ARRAY_SIZE(buffW), &icon);
919 if (FAILED(hr)) return hr;
921 swprintf(pathW, ARRAY_SIZE(pathW), L"%s, %d", buffW, icon);
922 *IconPath = SysAllocString(pathW);
923 if (!*IconPath) return E_OUTOFMEMORY;
925 return S_OK;
928 static HRESULT WINAPI WshShortcut_put_IconLocation(IWshShortcut *iface, BSTR IconPath)
930 WshShortcut *This = impl_from_IWshShortcut(iface);
931 HRESULT hr;
932 WCHAR *ptr;
933 BSTR path;
934 INT icon;
936 TRACE("(%p)->(%s)\n", This, debugstr_w(IconPath));
938 /* scan for icon id */
939 ptr = wcsrchr(IconPath, ',');
940 if (!ptr)
942 WARN("icon index not found\n");
943 return E_FAIL;
946 path = SysAllocStringLen(IconPath, ptr-IconPath);
948 /* skip spaces if any */
949 while (iswspace(*++ptr))
952 icon = wcstol(ptr, NULL, 10);
954 hr = IShellLinkW_SetIconLocation(This->link, path, icon);
955 SysFreeString(path);
957 return hr;
960 static HRESULT WINAPI WshShortcut_put_RelativePath(IWshShortcut *iface, BSTR rhs)
962 WshShortcut *This = impl_from_IWshShortcut(iface);
963 FIXME("(%p)->(%s): stub\n", This, debugstr_w(rhs));
964 return E_NOTIMPL;
967 static HRESULT WINAPI WshShortcut_get_TargetPath(IWshShortcut *iface, BSTR *Path)
969 WshShortcut *This = impl_from_IWshShortcut(iface);
970 FIXME("(%p)->(%p): stub\n", This, Path);
971 return E_NOTIMPL;
974 static HRESULT WINAPI WshShortcut_put_TargetPath(IWshShortcut *iface, BSTR Path)
976 WshShortcut *This = impl_from_IWshShortcut(iface);
977 TRACE("(%p)->(%s)\n", This, debugstr_w(Path));
978 return IShellLinkW_SetPath(This->link, Path);
981 static HRESULT WINAPI WshShortcut_get_WindowStyle(IWshShortcut *iface, int *ShowCmd)
983 WshShortcut *This = impl_from_IWshShortcut(iface);
984 TRACE("(%p)->(%p)\n", This, ShowCmd);
985 return IShellLinkW_GetShowCmd(This->link, ShowCmd);
988 static HRESULT WINAPI WshShortcut_put_WindowStyle(IWshShortcut *iface, int ShowCmd)
990 WshShortcut *This = impl_from_IWshShortcut(iface);
991 TRACE("(%p)->(%d)\n", This, ShowCmd);
992 return IShellLinkW_SetShowCmd(This->link, ShowCmd);
995 static HRESULT WINAPI WshShortcut_get_WorkingDirectory(IWshShortcut *iface, BSTR *WorkingDirectory)
997 WshShortcut *This = impl_from_IWshShortcut(iface);
998 WCHAR buffW[MAX_PATH];
999 HRESULT hr;
1001 TRACE("(%p)->(%p)\n", This, WorkingDirectory);
1003 if (!WorkingDirectory)
1004 return E_POINTER;
1006 *WorkingDirectory = NULL;
1007 hr = IShellLinkW_GetWorkingDirectory(This->link, buffW, ARRAY_SIZE(buffW));
1008 if (FAILED(hr)) return hr;
1010 *WorkingDirectory = SysAllocString(buffW);
1011 return *WorkingDirectory ? S_OK : E_OUTOFMEMORY;
1014 static HRESULT WINAPI WshShortcut_put_WorkingDirectory(IWshShortcut *iface, BSTR WorkingDirectory)
1016 WshShortcut *This = impl_from_IWshShortcut(iface);
1017 TRACE("(%p)->(%s)\n", This, debugstr_w(WorkingDirectory));
1018 return IShellLinkW_SetWorkingDirectory(This->link, WorkingDirectory);
1021 static HRESULT WINAPI WshShortcut_Load(IWshShortcut *iface, BSTR PathLink)
1023 WshShortcut *This = impl_from_IWshShortcut(iface);
1024 FIXME("(%p)->(%s): stub\n", This, debugstr_w(PathLink));
1025 return E_NOTIMPL;
1028 static HRESULT WINAPI WshShortcut_Save(IWshShortcut *iface)
1030 WshShortcut *This = impl_from_IWshShortcut(iface);
1031 IPersistFile *file;
1032 HRESULT hr;
1034 TRACE("(%p)\n", This);
1036 IShellLinkW_QueryInterface(This->link, &IID_IPersistFile, (void**)&file);
1037 hr = IPersistFile_Save(file, This->path_link, TRUE);
1038 IPersistFile_Release(file);
1040 return hr;
1043 static const IWshShortcutVtbl WshShortcutVtbl = {
1044 WshShortcut_QueryInterface,
1045 WshShortcut_AddRef,
1046 WshShortcut_Release,
1047 WshShortcut_GetTypeInfoCount,
1048 WshShortcut_GetTypeInfo,
1049 WshShortcut_GetIDsOfNames,
1050 WshShortcut_Invoke,
1051 WshShortcut_get_FullName,
1052 WshShortcut_get_Arguments,
1053 WshShortcut_put_Arguments,
1054 WshShortcut_get_Description,
1055 WshShortcut_put_Description,
1056 WshShortcut_get_Hotkey,
1057 WshShortcut_put_Hotkey,
1058 WshShortcut_get_IconLocation,
1059 WshShortcut_put_IconLocation,
1060 WshShortcut_put_RelativePath,
1061 WshShortcut_get_TargetPath,
1062 WshShortcut_put_TargetPath,
1063 WshShortcut_get_WindowStyle,
1064 WshShortcut_put_WindowStyle,
1065 WshShortcut_get_WorkingDirectory,
1066 WshShortcut_put_WorkingDirectory,
1067 WshShortcut_Load,
1068 WshShortcut_Save
1071 static HRESULT WshShortcut_Create(const WCHAR *path, IDispatch **shortcut)
1073 WshShortcut *This;
1074 HRESULT hr;
1076 *shortcut = NULL;
1078 This = heap_alloc(sizeof(*This));
1079 if (!This) return E_OUTOFMEMORY;
1081 This->IWshShortcut_iface.lpVtbl = &WshShortcutVtbl;
1082 This->ref = 1;
1084 hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
1085 &IID_IShellLinkW, (void**)&This->link);
1086 if (FAILED(hr))
1088 heap_free(This);
1089 return hr;
1092 This->path_link = SysAllocString(path);
1093 if (!This->path_link)
1095 IShellLinkW_Release(This->link);
1096 heap_free(This);
1097 return E_OUTOFMEMORY;
1100 init_classinfo(&IID_IWshShortcut, (IUnknown *)&This->IWshShortcut_iface, &This->classinfo);
1101 *shortcut = (IDispatch*)&This->IWshShortcut_iface;
1103 return S_OK;
1106 static HRESULT WINAPI WshShell3_QueryInterface(IWshShell3 *iface, REFIID riid, void **ppv)
1108 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
1110 *ppv = NULL;
1112 if (IsEqualGUID(riid, &IID_IDispatch) ||
1113 IsEqualGUID(riid, &IID_IWshShell3) ||
1114 IsEqualGUID(riid, &IID_IWshShell2) ||
1115 IsEqualGUID(riid, &IID_IWshShell) ||
1116 IsEqualGUID(riid, &IID_IUnknown))
1118 *ppv = iface;
1120 else if (IsEqualGUID(riid, &IID_IDispatchEx))
1122 return E_NOINTERFACE;
1124 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
1126 *ppv = &WshShell3.classinfo.IProvideClassInfo_iface;
1128 else
1130 WARN("unknown iface %s\n", debugstr_guid(riid));
1131 return E_NOINTERFACE;
1134 IUnknown_AddRef((IUnknown *)*ppv);
1135 return S_OK;
1138 static ULONG WINAPI WshShell3_AddRef(IWshShell3 *iface)
1140 TRACE("()\n");
1141 return 2;
1144 static ULONG WINAPI WshShell3_Release(IWshShell3 *iface)
1146 TRACE("()\n");
1147 return 2;
1150 static HRESULT WINAPI WshShell3_GetTypeInfoCount(IWshShell3 *iface, UINT *pctinfo)
1152 TRACE("(%p)\n", pctinfo);
1153 *pctinfo = 1;
1154 return S_OK;
1157 static HRESULT WINAPI WshShell3_GetTypeInfo(IWshShell3 *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
1159 TRACE("(%u %u %p)\n", iTInfo, lcid, ppTInfo);
1160 return get_typeinfo(IWshShell3_tid, ppTInfo);
1163 static HRESULT WINAPI WshShell3_GetIDsOfNames(IWshShell3 *iface, REFIID riid, LPOLESTR *rgszNames,
1164 UINT cNames, LCID lcid, DISPID *rgDispId)
1166 ITypeInfo *typeinfo;
1167 HRESULT hr;
1169 TRACE("(%s %p %u %u %p)\n", debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1171 hr = get_typeinfo(IWshShell3_tid, &typeinfo);
1172 if(SUCCEEDED(hr))
1174 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1175 ITypeInfo_Release(typeinfo);
1178 return hr;
1181 static HRESULT WINAPI WshShell3_Invoke(IWshShell3 *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
1182 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
1184 ITypeInfo *typeinfo;
1185 HRESULT hr;
1187 TRACE("(%d %s %d %d %p %p %p %p)\n", dispIdMember, debugstr_guid(riid),
1188 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1190 hr = get_typeinfo(IWshShell3_tid, &typeinfo);
1191 if(SUCCEEDED(hr))
1193 hr = ITypeInfo_Invoke(typeinfo, &WshShell3.IWshShell3_iface, dispIdMember, wFlags,
1194 pDispParams, pVarResult, pExcepInfo, puArgErr);
1195 ITypeInfo_Release(typeinfo);
1198 return hr;
1201 static HRESULT WINAPI WshShell3_get_SpecialFolders(IWshShell3 *iface, IWshCollection **folders)
1203 TRACE("(%p)\n", folders);
1204 return WshCollection_Create(folders);
1207 static HRESULT WINAPI WshShell3_get_Environment(IWshShell3 *iface, VARIANT *type, IWshEnvironment **env)
1209 FIXME("(%s %p): semi-stub\n", debugstr_variant(type), env);
1210 return WshEnvironment_Create(env);
1213 static inline BOOL is_optional_argument(const VARIANT *arg)
1215 return V_VT(arg) == VT_ERROR && V_ERROR(arg) == DISP_E_PARAMNOTFOUND;
1218 static WCHAR *split_command( BSTR cmd, WCHAR **params )
1220 WCHAR *ret, *ptr;
1221 BOOL in_quotes = FALSE;
1223 if (!(ret = heap_alloc((lstrlenW(cmd) + 1) * sizeof(WCHAR)))) return NULL;
1224 lstrcpyW( ret, cmd );
1226 *params = NULL;
1227 for (ptr = ret; *ptr; ptr++)
1229 if (*ptr == '"') in_quotes = !in_quotes;
1230 else if (*ptr == ' ' && !in_quotes)
1232 *ptr = 0;
1233 *params = ptr + 1;
1234 break;
1238 return ret;
1241 static HRESULT WINAPI WshShell3_Run(IWshShell3 *iface, BSTR cmd, VARIANT *style, VARIANT *wait, DWORD *exit_code)
1243 SHELLEXECUTEINFOW info;
1244 int waitforprocess;
1245 WCHAR *file, *params;
1246 VARIANT s;
1247 HRESULT hr;
1248 BOOL ret;
1250 TRACE("(%s %s %s %p)\n", debugstr_w(cmd), debugstr_variant(style), debugstr_variant(wait), exit_code);
1252 if (!style || !wait || !exit_code)
1253 return E_POINTER;
1255 VariantInit(&s);
1256 hr = VariantChangeType(&s, style, 0, VT_I4);
1257 if (FAILED(hr))
1259 ERR("failed to convert style argument, 0x%08x\n", hr);
1260 return hr;
1263 if (is_optional_argument(wait))
1264 waitforprocess = 0;
1265 else {
1266 VARIANT w;
1268 VariantInit(&w);
1269 hr = VariantChangeType(&w, wait, 0, VT_I4);
1270 if (FAILED(hr))
1271 return hr;
1273 waitforprocess = V_I4(&w);
1276 if (!(file = split_command(cmd, &params))) return E_OUTOFMEMORY;
1278 memset(&info, 0, sizeof(info));
1279 info.cbSize = sizeof(info);
1280 info.fMask = waitforprocess ? SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS : SEE_MASK_DEFAULT;
1281 info.lpFile = file;
1282 info.lpParameters = params;
1283 info.nShow = V_I4(&s);
1285 ret = ShellExecuteExW(&info);
1286 heap_free( file );
1287 if (!ret)
1289 TRACE("ShellExecute failed, %d\n", GetLastError());
1290 return HRESULT_FROM_WIN32(GetLastError());
1292 else
1294 if (waitforprocess)
1296 WaitForSingleObject(info.hProcess, INFINITE);
1297 GetExitCodeProcess(info.hProcess, exit_code);
1298 CloseHandle(info.hProcess);
1300 else
1301 *exit_code = 0;
1303 return S_OK;
1307 struct popup_thread_param
1309 WCHAR *text;
1310 VARIANT title;
1311 VARIANT type;
1312 INT button;
1315 static DWORD WINAPI popup_thread_proc(void *arg)
1317 struct popup_thread_param *param = (struct popup_thread_param *)arg;
1319 param->button = MessageBoxW(NULL, param->text, is_optional_argument(&param->title) ?
1320 L"Windows Script Host" : V_BSTR(&param->title), V_I4(&param->type));
1321 return 0;
1324 static HRESULT WINAPI WshShell3_Popup(IWshShell3 *iface, BSTR text, VARIANT *seconds_to_wait, VARIANT *title,
1325 VARIANT *type, int *button)
1327 struct popup_thread_param param;
1328 DWORD tid, status;
1329 VARIANT timeout;
1330 HANDLE hthread;
1331 HRESULT hr;
1333 TRACE("(%s %s %s %s %p)\n", debugstr_w(text), debugstr_variant(seconds_to_wait), debugstr_variant(title),
1334 debugstr_variant(type), button);
1336 if (!seconds_to_wait || !title || !type || !button)
1337 return E_POINTER;
1339 VariantInit(&timeout);
1340 if (!is_optional_argument(seconds_to_wait))
1342 hr = VariantChangeType(&timeout, seconds_to_wait, 0, VT_I4);
1343 if (FAILED(hr))
1344 return hr;
1347 VariantInit(&param.type);
1348 if (!is_optional_argument(type))
1350 hr = VariantChangeType(&param.type, type, 0, VT_I4);
1351 if (FAILED(hr))
1352 return hr;
1355 if (is_optional_argument(title))
1356 param.title = *title;
1357 else
1359 VariantInit(&param.title);
1360 hr = VariantChangeType(&param.title, title, 0, VT_BSTR);
1361 if (FAILED(hr))
1362 return hr;
1365 param.text = text;
1366 param.button = -1;
1367 hthread = CreateThread(NULL, 0, popup_thread_proc, &param, 0, &tid);
1368 status = MsgWaitForMultipleObjects(1, &hthread, FALSE, V_I4(&timeout) ? V_I4(&timeout) * 1000: INFINITE, 0);
1369 if (status == WAIT_TIMEOUT)
1371 PostThreadMessageW(tid, WM_QUIT, 0, 0);
1372 MsgWaitForMultipleObjects(1, &hthread, FALSE, INFINITE, 0);
1373 param.button = -1;
1375 *button = param.button;
1377 VariantClear(&param.title);
1378 CloseHandle(hthread);
1380 return S_OK;
1383 static HRESULT WINAPI WshShell3_CreateShortcut(IWshShell3 *iface, BSTR PathLink, IDispatch** Shortcut)
1385 TRACE("(%s %p)\n", debugstr_w(PathLink), Shortcut);
1386 return WshShortcut_Create(PathLink, Shortcut);
1389 static HRESULT WINAPI WshShell3_ExpandEnvironmentStrings(IWshShell3 *iface, BSTR Src, BSTR* Dst)
1391 DWORD ret;
1393 TRACE("(%s %p)\n", debugstr_w(Src), Dst);
1395 if (!Src || !Dst) return E_POINTER;
1397 ret = ExpandEnvironmentStringsW(Src, NULL, 0);
1398 *Dst = SysAllocStringLen(NULL, ret);
1399 if (!*Dst) return E_OUTOFMEMORY;
1401 if (ExpandEnvironmentStringsW(Src, *Dst, ret))
1402 return S_OK;
1403 else
1405 SysFreeString(*Dst);
1406 *Dst = NULL;
1407 return HRESULT_FROM_WIN32(GetLastError());
1411 static HKEY get_root_key(const WCHAR *path)
1413 static const struct {
1414 const WCHAR full[20];
1415 const WCHAR abbrev[5];
1416 HKEY hkey;
1417 } rootkeys[] = {
1418 { L"HKEY_CURRENT_USER", L"HKCU", HKEY_CURRENT_USER },
1419 { L"HKEY_LOCAL_MACHINE", L"HKLM", HKEY_LOCAL_MACHINE },
1420 { L"HKEY_CLASSES_ROOT", L"HKCR", HKEY_CLASSES_ROOT },
1421 { L"HKEY_USERS", {0}, HKEY_USERS },
1422 { L"HKEY_CURRENT_CONFIG", {0}, HKEY_CURRENT_CONFIG }
1424 int i;
1426 for (i = 0; i < ARRAY_SIZE(rootkeys); i++) {
1427 if (!wcsncmp(path, rootkeys[i].full, lstrlenW(rootkeys[i].full)))
1428 return rootkeys[i].hkey;
1429 if (rootkeys[i].abbrev[0] && !wcsncmp(path, rootkeys[i].abbrev, lstrlenW(rootkeys[i].abbrev)))
1430 return rootkeys[i].hkey;
1433 return NULL;
1436 /* Caller is responsible to free 'subkey' if 'value' is not NULL */
1437 static HRESULT split_reg_path(const WCHAR *path, WCHAR **subkey, WCHAR **value)
1439 *value = NULL;
1441 /* at least one separator should be present */
1442 *subkey = wcschr(path, '\\');
1443 if (!*subkey)
1444 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1446 /* default value or not */
1447 if ((*subkey)[lstrlenW(*subkey)-1] == '\\') {
1448 (*subkey)++;
1449 *value = NULL;
1451 else {
1452 *value = wcsrchr(*subkey, '\\');
1453 if (*value - *subkey > 1) {
1454 unsigned int len = *value - *subkey - 1;
1455 WCHAR *ret;
1457 ret = heap_alloc((len + 1)*sizeof(WCHAR));
1458 if (!ret)
1459 return E_OUTOFMEMORY;
1461 memcpy(ret, *subkey + 1, len*sizeof(WCHAR));
1462 ret[len] = 0;
1463 *subkey = ret;
1465 (*value)++;
1468 return S_OK;
1471 static HRESULT WINAPI WshShell3_RegRead(IWshShell3 *iface, BSTR name, VARIANT *value)
1473 DWORD type, datalen, ret;
1474 WCHAR *subkey, *val;
1475 HRESULT hr;
1476 HKEY root;
1478 TRACE("(%s %p)\n", debugstr_w(name), value);
1480 if (!name || !value)
1481 return E_POINTER;
1483 root = get_root_key(name);
1484 if (!root)
1485 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1487 hr = split_reg_path(name, &subkey, &val);
1488 if (FAILED(hr))
1489 return hr;
1491 type = REG_NONE;
1492 datalen = 0;
1493 ret = RegGetValueW(root, subkey, val, RRF_RT_ANY, &type, NULL, &datalen);
1494 if (ret == ERROR_SUCCESS) {
1495 void *data;
1497 data = heap_alloc(datalen);
1498 if (!data) {
1499 hr = E_OUTOFMEMORY;
1500 goto fail;
1503 ret = RegGetValueW(root, subkey, val, RRF_RT_ANY, &type, data, &datalen);
1504 if (ret) {
1505 heap_free(data);
1506 hr = HRESULT_FROM_WIN32(ret);
1507 goto fail;
1510 switch (type) {
1511 case REG_SZ:
1512 case REG_EXPAND_SZ:
1513 V_VT(value) = VT_BSTR;
1514 V_BSTR(value) = SysAllocString((WCHAR*)data);
1515 if (!V_BSTR(value))
1516 hr = E_OUTOFMEMORY;
1517 break;
1518 case REG_DWORD:
1519 V_VT(value) = VT_I4;
1520 V_I4(value) = *(DWORD*)data;
1521 break;
1522 case REG_BINARY:
1524 BYTE *ptr = (BYTE*)data;
1525 SAFEARRAYBOUND bound;
1526 unsigned int i;
1527 SAFEARRAY *sa;
1528 VARIANT *v;
1530 bound.lLbound = 0;
1531 bound.cElements = datalen;
1532 sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
1533 if (!sa)
1534 break;
1536 hr = SafeArrayAccessData(sa, (void**)&v);
1537 if (FAILED(hr)) {
1538 SafeArrayDestroy(sa);
1539 break;
1542 for (i = 0; i < datalen; i++) {
1543 V_VT(&v[i]) = VT_UI1;
1544 V_UI1(&v[i]) = ptr[i];
1546 SafeArrayUnaccessData(sa);
1548 V_VT(value) = VT_ARRAY|VT_VARIANT;
1549 V_ARRAY(value) = sa;
1550 break;
1552 case REG_MULTI_SZ:
1554 WCHAR *ptr = (WCHAR*)data;
1555 SAFEARRAYBOUND bound;
1556 SAFEARRAY *sa;
1557 VARIANT *v;
1559 /* get element count first */
1560 bound.lLbound = 0;
1561 bound.cElements = 0;
1562 while (*ptr) {
1563 bound.cElements++;
1564 ptr += lstrlenW(ptr)+1;
1567 sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
1568 if (!sa)
1569 break;
1571 hr = SafeArrayAccessData(sa, (void**)&v);
1572 if (FAILED(hr)) {
1573 SafeArrayDestroy(sa);
1574 break;
1577 ptr = (WCHAR*)data;
1578 while (*ptr) {
1579 V_VT(v) = VT_BSTR;
1580 V_BSTR(v) = SysAllocString(ptr);
1581 ptr += lstrlenW(ptr)+1;
1582 v++;
1585 SafeArrayUnaccessData(sa);
1586 V_VT(value) = VT_ARRAY|VT_VARIANT;
1587 V_ARRAY(value) = sa;
1588 break;
1590 default:
1591 FIXME("value type %d not supported\n", type);
1592 hr = E_FAIL;
1595 heap_free(data);
1596 if (FAILED(hr))
1597 VariantInit(value);
1599 else
1600 hr = HRESULT_FROM_WIN32(ret);
1602 fail:
1603 if (val)
1604 heap_free(subkey);
1605 return hr;
1608 static HRESULT WINAPI WshShell3_RegWrite(IWshShell3 *iface, BSTR name, VARIANT *value, VARIANT *type)
1610 DWORD regtype, data_len;
1611 WCHAR *subkey, *val;
1612 const BYTE *data;
1613 HRESULT hr;
1614 HKEY root;
1615 VARIANT v;
1616 LONG ret;
1618 TRACE("(%s %s %s)\n", debugstr_w(name), debugstr_variant(value), debugstr_variant(type));
1620 if (!name || !value || !type)
1621 return E_POINTER;
1623 root = get_root_key(name);
1624 if (!root)
1625 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1627 /* value type */
1628 if (is_optional_argument(type))
1629 regtype = REG_SZ;
1630 else {
1631 if (V_VT(type) != VT_BSTR)
1632 return E_INVALIDARG;
1634 if (!wcscmp(V_BSTR(type), L"REG_SZ"))
1635 regtype = REG_SZ;
1636 else if (!wcscmp(V_BSTR(type), L"REG_DWORD"))
1637 regtype = REG_DWORD;
1638 else if (!wcscmp(V_BSTR(type), L"REG_EXPAND_SZ"))
1639 regtype = REG_EXPAND_SZ;
1640 else if (!wcscmp(V_BSTR(type), L"REG_BINARY"))
1641 regtype = REG_BINARY;
1642 else {
1643 FIXME("unrecognized value type %s\n", debugstr_w(V_BSTR(type)));
1644 return E_FAIL;
1648 /* it's always a string or a DWORD */
1649 VariantInit(&v);
1650 switch (regtype)
1652 case REG_SZ:
1653 case REG_EXPAND_SZ:
1654 hr = VariantChangeType(&v, value, 0, VT_BSTR);
1655 if (hr == S_OK) {
1656 data = (BYTE*)V_BSTR(&v);
1657 data_len = SysStringByteLen(V_BSTR(&v)) + sizeof(WCHAR);
1659 break;
1660 case REG_DWORD:
1661 case REG_BINARY:
1662 hr = VariantChangeType(&v, value, 0, VT_I4);
1663 data = (BYTE*)&V_I4(&v);
1664 data_len = sizeof(DWORD);
1665 break;
1666 default:
1667 FIXME("unexpected regtype %d\n", regtype);
1668 return E_FAIL;
1671 if (FAILED(hr)) {
1672 FIXME("failed to convert value, regtype %d, 0x%08x\n", regtype, hr);
1673 return hr;
1676 hr = split_reg_path(name, &subkey, &val);
1677 if (FAILED(hr))
1678 goto fail;
1680 ret = RegSetKeyValueW(root, subkey, val, regtype, data, data_len);
1681 if (ret)
1682 hr = HRESULT_FROM_WIN32(ret);
1684 fail:
1685 VariantClear(&v);
1686 if (val)
1687 heap_free(subkey);
1688 return hr;
1691 static HRESULT WINAPI WshShell3_RegDelete(IWshShell3 *iface, BSTR Name)
1693 FIXME("(%s): stub\n", debugstr_w(Name));
1694 return E_NOTIMPL;
1697 static HRESULT WINAPI WshShell3_LogEvent(IWshShell3 *iface, VARIANT *Type, BSTR Message, BSTR Target, VARIANT_BOOL *out_Success)
1699 FIXME("(%s %s %s %p): stub\n", debugstr_variant(Type), debugstr_w(Message), debugstr_w(Target), out_Success);
1700 return E_NOTIMPL;
1703 static HRESULT WINAPI WshShell3_AppActivate(IWshShell3 *iface, VARIANT *App, VARIANT *Wait, VARIANT_BOOL *out_Success)
1705 FIXME("(%s %s %p): stub\n", debugstr_variant(App), debugstr_variant(Wait), out_Success);
1706 return E_NOTIMPL;
1709 static HRESULT WINAPI WshShell3_SendKeys(IWshShell3 *iface, BSTR Keys, VARIANT *Wait)
1711 FIXME("(%s %p): stub\n", debugstr_w(Keys), Wait);
1712 return E_NOTIMPL;
1715 static HRESULT WINAPI WshShell3_Exec(IWshShell3 *iface, BSTR command, IWshExec **ret)
1717 BSTR expandedcmd;
1718 HRESULT hr;
1720 TRACE("(%s %p)\n", debugstr_w(command), ret);
1722 if (!ret)
1723 return E_POINTER;
1725 if (!command)
1726 return DISP_E_EXCEPTION;
1728 hr = WshShell3_ExpandEnvironmentStrings(iface, command, &expandedcmd);
1729 if (FAILED(hr))
1730 return hr;
1732 hr = WshExec_create(expandedcmd, ret);
1733 SysFreeString(expandedcmd);
1734 return hr;
1737 static HRESULT WINAPI WshShell3_get_CurrentDirectory(IWshShell3 *iface, BSTR *dir)
1739 DWORD ret;
1741 TRACE("(%p)\n", dir);
1743 ret = GetCurrentDirectoryW(0, NULL);
1744 if (!ret)
1745 return HRESULT_FROM_WIN32(GetLastError());
1747 *dir = SysAllocStringLen(NULL, ret-1);
1748 if (!*dir)
1749 return E_OUTOFMEMORY;
1751 ret = GetCurrentDirectoryW(ret, *dir);
1752 if (!ret) {
1753 SysFreeString(*dir);
1754 *dir = NULL;
1755 return HRESULT_FROM_WIN32(GetLastError());
1758 return S_OK;
1761 static HRESULT WINAPI WshShell3_put_CurrentDirectory(IWshShell3 *iface, BSTR dir)
1763 TRACE("(%s)\n", debugstr_w(dir));
1765 if (!dir)
1766 return E_INVALIDARG;
1768 if (!SetCurrentDirectoryW(dir))
1769 return HRESULT_FROM_WIN32(GetLastError());
1771 return S_OK;
1774 static const IWshShell3Vtbl WshShell3Vtbl = {
1775 WshShell3_QueryInterface,
1776 WshShell3_AddRef,
1777 WshShell3_Release,
1778 WshShell3_GetTypeInfoCount,
1779 WshShell3_GetTypeInfo,
1780 WshShell3_GetIDsOfNames,
1781 WshShell3_Invoke,
1782 WshShell3_get_SpecialFolders,
1783 WshShell3_get_Environment,
1784 WshShell3_Run,
1785 WshShell3_Popup,
1786 WshShell3_CreateShortcut,
1787 WshShell3_ExpandEnvironmentStrings,
1788 WshShell3_RegRead,
1789 WshShell3_RegWrite,
1790 WshShell3_RegDelete,
1791 WshShell3_LogEvent,
1792 WshShell3_AppActivate,
1793 WshShell3_SendKeys,
1794 WshShell3_Exec,
1795 WshShell3_get_CurrentDirectory,
1796 WshShell3_put_CurrentDirectory
1799 HRESULT WINAPI WshShellFactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
1801 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
1803 WshShell3.IWshShell3_iface.lpVtbl = &WshShell3Vtbl;
1804 init_classinfo(&IID_IWshShell3, (IUnknown *)&WshShell3.IWshShell3_iface, &WshShell3.classinfo);
1805 return IWshShell3_QueryInterface(&WshShell3.IWshShell3_iface, riid, ppv);