wined3d: Properly compare integers in wined3d_bo_slab_vk_compare().
[wine.git] / dlls / wshom.ocx / shell.c
blob1ee745773101d8564b9830df5f5bd3a68d6b2426
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"
28 WINE_DEFAULT_DEBUG_CHANNEL(wshom);
30 typedef struct
32 struct provideclassinfo classinfo;
33 IWshShell3 IWshShell3_iface;
34 } WshShellImpl;
35 static WshShellImpl WshShell3;
37 typedef struct
39 struct provideclassinfo classinfo;
40 IWshCollection IWshCollection_iface;
41 LONG ref;
42 } WshCollection;
44 typedef struct
46 struct provideclassinfo classinfo;
47 IWshShortcut IWshShortcut_iface;
48 LONG ref;
50 IShellLinkW *link;
51 WCHAR *path_link;
52 } WshShortcut;
54 typedef struct
56 struct provideclassinfo classinfo;
57 IWshEnvironment IWshEnvironment_iface;
58 LONG ref;
59 } WshEnvironment;
61 typedef struct
63 struct provideclassinfo classinfo;
64 IWshExec IWshExec_iface;
65 LONG ref;
66 PROCESS_INFORMATION info;
67 } WshExecImpl;
69 static inline WshCollection *impl_from_IWshCollection( IWshCollection *iface )
71 return CONTAINING_RECORD(iface, WshCollection, IWshCollection_iface);
74 static inline WshShortcut *impl_from_IWshShortcut( IWshShortcut *iface )
76 return CONTAINING_RECORD(iface, WshShortcut, IWshShortcut_iface);
79 static inline WshEnvironment *impl_from_IWshEnvironment( IWshEnvironment *iface )
81 return CONTAINING_RECORD(iface, WshEnvironment, IWshEnvironment_iface);
84 static inline WshExecImpl *impl_from_IWshExec( IWshExec *iface )
86 return CONTAINING_RECORD(iface, WshExecImpl, IWshExec_iface);
89 static HRESULT WINAPI WshExec_QueryInterface(IWshExec *iface, REFIID riid, void **obj)
91 WshExecImpl *This = impl_from_IWshExec(iface);
93 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), obj);
95 if (IsEqualGUID(riid, &IID_IDispatch) ||
96 IsEqualGUID(riid, &IID_IWshExec) ||
97 IsEqualGUID(riid, &IID_IUnknown))
99 *obj = iface;
101 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
103 *obj = &This->classinfo.IProvideClassInfo_iface;
105 else {
106 FIXME("Unknown iface %s\n", debugstr_guid(riid));
107 *obj = NULL;
108 return E_NOINTERFACE;
111 IUnknown_AddRef((IUnknown *)*obj);
112 return S_OK;
115 static ULONG WINAPI WshExec_AddRef(IWshExec *iface)
117 WshExecImpl *This = impl_from_IWshExec(iface);
118 LONG ref = InterlockedIncrement(&This->ref);
119 TRACE("(%p) ref = %d\n", This, ref);
120 return ref;
123 static ULONG WINAPI WshExec_Release(IWshExec *iface)
125 WshExecImpl *This = impl_from_IWshExec(iface);
126 LONG ref = InterlockedDecrement(&This->ref);
127 TRACE("(%p) ref = %d\n", This, ref);
129 if (!ref) {
130 CloseHandle(This->info.hThread);
131 CloseHandle(This->info.hProcess);
132 free(This);
135 return ref;
138 static HRESULT WINAPI WshExec_GetTypeInfoCount(IWshExec *iface, UINT *pctinfo)
140 WshExecImpl *This = impl_from_IWshExec(iface);
141 TRACE("(%p)->(%p)\n", This, pctinfo);
142 *pctinfo = 1;
143 return S_OK;
146 static HRESULT WINAPI WshExec_GetTypeInfo(IWshExec *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
148 WshExecImpl *This = impl_from_IWshExec(iface);
149 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
150 return get_typeinfo(IWshExec_tid, ppTInfo);
153 static HRESULT WINAPI WshExec_GetIDsOfNames(IWshExec *iface, REFIID riid, LPOLESTR *rgszNames,
154 UINT cNames, LCID lcid, DISPID *rgDispId)
156 WshExecImpl *This = impl_from_IWshExec(iface);
157 ITypeInfo *typeinfo;
158 HRESULT hr;
160 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
162 hr = get_typeinfo(IWshExec_tid, &typeinfo);
163 if(SUCCEEDED(hr))
165 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
166 ITypeInfo_Release(typeinfo);
169 return hr;
172 static HRESULT WINAPI WshExec_Invoke(IWshExec *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
173 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
175 WshExecImpl *This = impl_from_IWshExec(iface);
176 ITypeInfo *typeinfo;
177 HRESULT hr;
179 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
180 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
182 hr = get_typeinfo(IWshExec_tid, &typeinfo);
183 if(SUCCEEDED(hr))
185 hr = ITypeInfo_Invoke(typeinfo, &This->IWshExec_iface, dispIdMember, wFlags,
186 pDispParams, pVarResult, pExcepInfo, puArgErr);
187 ITypeInfo_Release(typeinfo);
190 return hr;
193 static HRESULT WINAPI WshExec_get_Status(IWshExec *iface, WshExecStatus *status)
195 WshExecImpl *This = impl_from_IWshExec(iface);
196 DWORD code;
198 TRACE("(%p)->(%p)\n", This, status);
200 if (!status)
201 return E_INVALIDARG;
203 if (!GetExitCodeProcess(This->info.hProcess, &code))
204 return HRESULT_FROM_WIN32(GetLastError());
206 switch (code)
208 case 0:
209 *status = WshFinished;
210 break;
211 case STILL_ACTIVE:
212 *status = WshRunning;
213 break;
214 default:
215 *status = WshFailed;
218 return S_OK;
221 static HRESULT WINAPI WshExec_get_StdIn(IWshExec *iface, ITextStream **stream)
223 WshExecImpl *This = impl_from_IWshExec(iface);
225 FIXME("(%p)->(%p): stub\n", This, stream);
227 return E_NOTIMPL;
230 static HRESULT WINAPI WshExec_get_StdOut(IWshExec *iface, ITextStream **stream)
232 WshExecImpl *This = impl_from_IWshExec(iface);
234 FIXME("(%p)->(%p): stub\n", This, stream);
236 return E_NOTIMPL;
239 static HRESULT WINAPI WshExec_get_StdErr(IWshExec *iface, ITextStream **stream)
241 WshExecImpl *This = impl_from_IWshExec(iface);
243 FIXME("(%p)->(%p): stub\n", This, stream);
245 return E_NOTIMPL;
248 static HRESULT WINAPI WshExec_get_ProcessID(IWshExec *iface, DWORD *pid)
250 WshExecImpl *This = impl_from_IWshExec(iface);
252 TRACE("(%p)->(%p)\n", This, pid);
254 if (!pid)
255 return E_INVALIDARG;
257 *pid = This->info.dwProcessId;
258 return S_OK;
261 static HRESULT WINAPI WshExec_get_ExitCode(IWshExec *iface, DWORD *code)
263 WshExecImpl *This = impl_from_IWshExec(iface);
265 FIXME("(%p)->(%p): stub\n", This, code);
267 return E_NOTIMPL;
270 static BOOL CALLBACK enum_thread_wnd_proc(HWND hwnd, LPARAM lParam)
272 INT *count = (INT*)lParam;
274 (*count)++;
275 PostMessageW(hwnd, WM_CLOSE, 0, 0);
276 /* try to send it to all windows, even if failed for some */
277 return TRUE;
280 static HRESULT WINAPI WshExec_Terminate(IWshExec *iface)
282 WshExecImpl *This = impl_from_IWshExec(iface);
283 BOOL ret, kill = FALSE;
284 INT count = 0;
286 TRACE("(%p)\n", This);
288 ret = EnumThreadWindows(This->info.dwThreadId, enum_thread_wnd_proc, (LPARAM)&count);
289 if (ret && count) {
290 /* manual testing shows that it waits 2 seconds before forcing termination */
291 if (WaitForSingleObject(This->info.hProcess, 2000) != WAIT_OBJECT_0)
292 kill = TRUE;
294 else
295 kill = TRUE;
297 if (kill)
298 TerminateProcess(This->info.hProcess, 0);
300 return S_OK;
303 static const IWshExecVtbl WshExecVtbl = {
304 WshExec_QueryInterface,
305 WshExec_AddRef,
306 WshExec_Release,
307 WshExec_GetTypeInfoCount,
308 WshExec_GetTypeInfo,
309 WshExec_GetIDsOfNames,
310 WshExec_Invoke,
311 WshExec_get_Status,
312 WshExec_get_StdIn,
313 WshExec_get_StdOut,
314 WshExec_get_StdErr,
315 WshExec_get_ProcessID,
316 WshExec_get_ExitCode,
317 WshExec_Terminate
320 static HRESULT WshExec_create(BSTR command, IWshExec **ret)
322 STARTUPINFOW si = {0};
323 WshExecImpl *object;
325 *ret = NULL;
327 if (!(object = calloc(1, sizeof(*object))))
328 return E_OUTOFMEMORY;
330 object->IWshExec_iface.lpVtbl = &WshExecVtbl;
331 object->ref = 1;
333 if (!CreateProcessW(NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &object->info))
335 free(object);
336 return HRESULT_FROM_WIN32(GetLastError());
339 init_classinfo(&CLSID_WshExec, (IUnknown *)&object->IWshExec_iface, &object->classinfo);
340 *ret = &object->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 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 *object;
524 if (!(object = calloc(1, sizeof(*object))))
525 return E_OUTOFMEMORY;
527 object->IWshEnvironment_iface.lpVtbl = &WshEnvironmentVtbl;
528 object->ref = 1;
530 init_classinfo(&IID_IWshEnvironment, (IUnknown *)&object->IWshEnvironment_iface, &object->classinfo);
531 *env = &object->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 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 *object;
723 if (!(object = calloc(1, sizeof(*object))))
724 return E_OUTOFMEMORY;
726 object->IWshCollection_iface.lpVtbl = &WshCollectionVtbl;
727 object->ref = 1;
729 init_classinfo(&IID_IWshCollection, (IUnknown *)&object->IWshCollection_iface, &object->classinfo);
730 *collection = &object->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 IShellLinkW_Release(This->link);
779 free(This->path_link);
780 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 *object;
1074 HRESULT hr;
1076 *shortcut = NULL;
1078 if (!(object = calloc(1, sizeof(*object))))
1079 return E_OUTOFMEMORY;
1081 object->IWshShortcut_iface.lpVtbl = &WshShortcutVtbl;
1082 object->ref = 1;
1084 hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (void **)&object->link);
1085 if (FAILED(hr))
1087 free(object);
1088 return hr;
1091 object->path_link = wcsdup(path);
1092 if (!object->path_link)
1094 IShellLinkW_Release(object->link);
1095 free(object);
1096 return E_OUTOFMEMORY;
1099 init_classinfo(&IID_IWshShortcut, (IUnknown *)&object->IWshShortcut_iface, &object->classinfo);
1100 *shortcut = (IDispatch *)&object->IWshShortcut_iface;
1102 return S_OK;
1105 static HRESULT WINAPI WshShell3_QueryInterface(IWshShell3 *iface, REFIID riid, void **ppv)
1107 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
1109 *ppv = NULL;
1111 if (IsEqualGUID(riid, &IID_IDispatch) ||
1112 IsEqualGUID(riid, &IID_IWshShell3) ||
1113 IsEqualGUID(riid, &IID_IWshShell2) ||
1114 IsEqualGUID(riid, &IID_IWshShell) ||
1115 IsEqualGUID(riid, &IID_IUnknown))
1117 *ppv = iface;
1119 else if (IsEqualGUID(riid, &IID_IDispatchEx))
1121 return E_NOINTERFACE;
1123 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
1125 *ppv = &WshShell3.classinfo.IProvideClassInfo_iface;
1127 else
1129 WARN("unknown iface %s\n", debugstr_guid(riid));
1130 return E_NOINTERFACE;
1133 IUnknown_AddRef((IUnknown *)*ppv);
1134 return S_OK;
1137 static ULONG WINAPI WshShell3_AddRef(IWshShell3 *iface)
1139 TRACE("()\n");
1140 return 2;
1143 static ULONG WINAPI WshShell3_Release(IWshShell3 *iface)
1145 TRACE("()\n");
1146 return 2;
1149 static HRESULT WINAPI WshShell3_GetTypeInfoCount(IWshShell3 *iface, UINT *pctinfo)
1151 TRACE("(%p)\n", pctinfo);
1152 *pctinfo = 1;
1153 return S_OK;
1156 static HRESULT WINAPI WshShell3_GetTypeInfo(IWshShell3 *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
1158 TRACE("(%u %u %p)\n", iTInfo, lcid, ppTInfo);
1159 return get_typeinfo(IWshShell3_tid, ppTInfo);
1162 static HRESULT WINAPI WshShell3_GetIDsOfNames(IWshShell3 *iface, REFIID riid, LPOLESTR *rgszNames,
1163 UINT cNames, LCID lcid, DISPID *rgDispId)
1165 ITypeInfo *typeinfo;
1166 HRESULT hr;
1168 TRACE("(%s %p %u %u %p)\n", debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1170 hr = get_typeinfo(IWshShell3_tid, &typeinfo);
1171 if(SUCCEEDED(hr))
1173 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1174 ITypeInfo_Release(typeinfo);
1177 return hr;
1180 static HRESULT WINAPI WshShell3_Invoke(IWshShell3 *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
1181 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
1183 ITypeInfo *typeinfo;
1184 HRESULT hr;
1186 TRACE("(%d %s %d %d %p %p %p %p)\n", dispIdMember, debugstr_guid(riid),
1187 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1189 hr = get_typeinfo(IWshShell3_tid, &typeinfo);
1190 if(SUCCEEDED(hr))
1192 hr = ITypeInfo_Invoke(typeinfo, &WshShell3.IWshShell3_iface, dispIdMember, wFlags,
1193 pDispParams, pVarResult, pExcepInfo, puArgErr);
1194 ITypeInfo_Release(typeinfo);
1197 return hr;
1200 static HRESULT WINAPI WshShell3_get_SpecialFolders(IWshShell3 *iface, IWshCollection **folders)
1202 TRACE("(%p)\n", folders);
1203 return WshCollection_Create(folders);
1206 static HRESULT WINAPI WshShell3_get_Environment(IWshShell3 *iface, VARIANT *type, IWshEnvironment **env)
1208 FIXME("(%s %p): semi-stub\n", debugstr_variant(type), env);
1209 return WshEnvironment_Create(env);
1212 static inline BOOL is_optional_argument(const VARIANT *arg)
1214 return V_VT(arg) == VT_ERROR && V_ERROR(arg) == DISP_E_PARAMNOTFOUND;
1217 static WCHAR *split_command( BSTR cmd, WCHAR **params )
1219 WCHAR *ret, *ptr;
1220 BOOL in_quotes = FALSE;
1222 if (!(ret = malloc((lstrlenW(cmd) + 1) * sizeof(WCHAR)))) return NULL;
1223 lstrcpyW( ret, cmd );
1225 *params = NULL;
1226 for (ptr = ret; *ptr; ptr++)
1228 if (*ptr == '"') in_quotes = !in_quotes;
1229 else if (*ptr == ' ' && !in_quotes)
1231 *ptr = 0;
1232 *params = ptr + 1;
1233 break;
1237 return ret;
1240 static HRESULT WINAPI WshShell3_Run(IWshShell3 *iface, BSTR cmd, VARIANT *style, VARIANT *wait, DWORD *exit_code)
1242 SHELLEXECUTEINFOW info;
1243 int waitforprocess;
1244 WCHAR *file, *params;
1245 VARIANT s;
1246 HRESULT hr;
1247 BOOL ret;
1249 TRACE("(%s %s %s %p)\n", debugstr_w(cmd), debugstr_variant(style), debugstr_variant(wait), exit_code);
1251 if (!style || !wait || !exit_code)
1252 return E_POINTER;
1254 VariantInit(&s);
1255 hr = VariantChangeType(&s, style, 0, VT_I4);
1256 if (FAILED(hr))
1258 ERR("failed to convert style argument, 0x%08x\n", hr);
1259 return hr;
1262 if (is_optional_argument(wait))
1263 waitforprocess = 0;
1264 else {
1265 VARIANT w;
1267 VariantInit(&w);
1268 hr = VariantChangeType(&w, wait, 0, VT_I4);
1269 if (FAILED(hr))
1270 return hr;
1272 waitforprocess = V_I4(&w);
1275 if (!(file = split_command(cmd, &params))) return E_OUTOFMEMORY;
1277 memset(&info, 0, sizeof(info));
1278 info.cbSize = sizeof(info);
1279 info.fMask = waitforprocess ? SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS : SEE_MASK_DEFAULT;
1280 info.lpFile = file;
1281 info.lpParameters = params;
1282 info.nShow = V_I4(&s);
1284 ret = ShellExecuteExW(&info);
1285 free(file);
1286 if (!ret)
1288 TRACE("ShellExecute failed, %d\n", GetLastError());
1289 return HRESULT_FROM_WIN32(GetLastError());
1291 else
1293 if (waitforprocess)
1295 WaitForSingleObject(info.hProcess, INFINITE);
1296 GetExitCodeProcess(info.hProcess, exit_code);
1297 CloseHandle(info.hProcess);
1299 else
1300 *exit_code = 0;
1302 return S_OK;
1306 struct popup_thread_param
1308 WCHAR *text;
1309 VARIANT title;
1310 VARIANT type;
1311 INT button;
1314 static DWORD WINAPI popup_thread_proc(void *arg)
1316 struct popup_thread_param *param = (struct popup_thread_param *)arg;
1318 param->button = MessageBoxW(NULL, param->text, is_optional_argument(&param->title) ?
1319 L"Windows Script Host" : V_BSTR(&param->title), V_I4(&param->type));
1320 return 0;
1323 static HRESULT WINAPI WshShell3_Popup(IWshShell3 *iface, BSTR text, VARIANT *seconds_to_wait, VARIANT *title,
1324 VARIANT *type, int *button)
1326 struct popup_thread_param param;
1327 DWORD tid, status;
1328 VARIANT timeout;
1329 HANDLE hthread;
1330 HRESULT hr;
1332 TRACE("(%s %s %s %s %p)\n", debugstr_w(text), debugstr_variant(seconds_to_wait), debugstr_variant(title),
1333 debugstr_variant(type), button);
1335 if (!seconds_to_wait || !title || !type || !button)
1336 return E_POINTER;
1338 VariantInit(&timeout);
1339 if (!is_optional_argument(seconds_to_wait))
1341 hr = VariantChangeType(&timeout, seconds_to_wait, 0, VT_I4);
1342 if (FAILED(hr))
1343 return hr;
1346 VariantInit(&param.type);
1347 if (!is_optional_argument(type))
1349 hr = VariantChangeType(&param.type, type, 0, VT_I4);
1350 if (FAILED(hr))
1351 return hr;
1354 if (is_optional_argument(title))
1355 param.title = *title;
1356 else
1358 VariantInit(&param.title);
1359 hr = VariantChangeType(&param.title, title, 0, VT_BSTR);
1360 if (FAILED(hr))
1361 return hr;
1364 param.text = text;
1365 param.button = -1;
1366 hthread = CreateThread(NULL, 0, popup_thread_proc, &param, 0, &tid);
1367 status = MsgWaitForMultipleObjects(1, &hthread, FALSE, V_I4(&timeout) ? V_I4(&timeout) * 1000: INFINITE, 0);
1368 if (status == WAIT_TIMEOUT)
1370 PostThreadMessageW(tid, WM_QUIT, 0, 0);
1371 MsgWaitForMultipleObjects(1, &hthread, FALSE, INFINITE, 0);
1372 param.button = -1;
1374 *button = param.button;
1376 VariantClear(&param.title);
1377 CloseHandle(hthread);
1379 return S_OK;
1382 static HRESULT WINAPI WshShell3_CreateShortcut(IWshShell3 *iface, BSTR PathLink, IDispatch** Shortcut)
1384 TRACE("(%s %p)\n", debugstr_w(PathLink), Shortcut);
1385 return WshShortcut_Create(PathLink, Shortcut);
1388 static HRESULT WINAPI WshShell3_ExpandEnvironmentStrings(IWshShell3 *iface, BSTR Src, BSTR* Dst)
1390 DWORD ret;
1392 TRACE("(%s %p)\n", debugstr_w(Src), Dst);
1394 if (!Src || !Dst) return E_POINTER;
1396 ret = ExpandEnvironmentStringsW(Src, NULL, 0);
1397 *Dst = SysAllocStringLen(NULL, ret);
1398 if (!*Dst) return E_OUTOFMEMORY;
1400 if (ExpandEnvironmentStringsW(Src, *Dst, ret))
1401 return S_OK;
1402 else
1404 SysFreeString(*Dst);
1405 *Dst = NULL;
1406 return HRESULT_FROM_WIN32(GetLastError());
1410 static HKEY get_root_key(const WCHAR *path)
1412 static const struct {
1413 const WCHAR full[20];
1414 const WCHAR abbrev[5];
1415 HKEY hkey;
1416 } rootkeys[] = {
1417 { L"HKEY_CURRENT_USER", L"HKCU", HKEY_CURRENT_USER },
1418 { L"HKEY_LOCAL_MACHINE", L"HKLM", HKEY_LOCAL_MACHINE },
1419 { L"HKEY_CLASSES_ROOT", L"HKCR", HKEY_CLASSES_ROOT },
1420 { L"HKEY_USERS", {0}, HKEY_USERS },
1421 { L"HKEY_CURRENT_CONFIG", {0}, HKEY_CURRENT_CONFIG }
1423 int i;
1425 for (i = 0; i < ARRAY_SIZE(rootkeys); i++) {
1426 if (!wcsncmp(path, rootkeys[i].full, lstrlenW(rootkeys[i].full)))
1427 return rootkeys[i].hkey;
1428 if (rootkeys[i].abbrev[0] && !wcsncmp(path, rootkeys[i].abbrev, lstrlenW(rootkeys[i].abbrev)))
1429 return rootkeys[i].hkey;
1432 return NULL;
1435 /* Caller is responsible to free 'subkey' if 'value' is not NULL */
1436 static HRESULT split_reg_path(const WCHAR *path, WCHAR **subkey, WCHAR **value)
1438 *value = NULL;
1440 /* at least one separator should be present */
1441 *subkey = wcschr(path, '\\');
1442 if (!*subkey)
1443 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1445 /* default value or not */
1446 if ((*subkey)[lstrlenW(*subkey)-1] == '\\') {
1447 (*subkey)++;
1448 *value = NULL;
1450 else {
1451 *value = wcsrchr(*subkey, '\\');
1452 if (*value - *subkey > 1) {
1453 unsigned int len = *value - *subkey - 1;
1454 WCHAR *ret;
1456 ret = malloc((len + 1)*sizeof(WCHAR));
1457 if (!ret)
1458 return E_OUTOFMEMORY;
1460 memcpy(ret, *subkey + 1, len*sizeof(WCHAR));
1461 ret[len] = 0;
1462 *subkey = ret;
1464 (*value)++;
1467 return S_OK;
1470 static HRESULT WINAPI WshShell3_RegRead(IWshShell3 *iface, BSTR name, VARIANT *value)
1472 DWORD type, datalen, ret;
1473 WCHAR *subkey, *val;
1474 HRESULT hr;
1475 HKEY root;
1477 TRACE("(%s %p)\n", debugstr_w(name), value);
1479 if (!name || !value)
1480 return E_POINTER;
1482 root = get_root_key(name);
1483 if (!root)
1484 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1486 hr = split_reg_path(name, &subkey, &val);
1487 if (FAILED(hr))
1488 return hr;
1490 type = REG_NONE;
1491 datalen = 0;
1492 ret = RegGetValueW(root, subkey, val, RRF_RT_ANY, &type, NULL, &datalen);
1493 if (ret == ERROR_SUCCESS) {
1494 void *data;
1496 data = malloc(datalen);
1497 if (!data) {
1498 hr = E_OUTOFMEMORY;
1499 goto fail;
1502 ret = RegGetValueW(root, subkey, val, RRF_RT_ANY, &type, data, &datalen);
1503 if (ret) {
1504 free(data);
1505 hr = HRESULT_FROM_WIN32(ret);
1506 goto fail;
1509 switch (type) {
1510 case REG_SZ:
1511 case REG_EXPAND_SZ:
1512 V_VT(value) = VT_BSTR;
1513 V_BSTR(value) = SysAllocString((WCHAR*)data);
1514 if (!V_BSTR(value))
1515 hr = E_OUTOFMEMORY;
1516 break;
1517 case REG_DWORD:
1518 V_VT(value) = VT_I4;
1519 V_I4(value) = *(DWORD*)data;
1520 break;
1521 case REG_BINARY:
1523 BYTE *ptr = (BYTE*)data;
1524 SAFEARRAYBOUND bound;
1525 unsigned int i;
1526 SAFEARRAY *sa;
1527 VARIANT *v;
1529 bound.lLbound = 0;
1530 bound.cElements = datalen;
1531 sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
1532 if (!sa)
1533 break;
1535 hr = SafeArrayAccessData(sa, (void**)&v);
1536 if (FAILED(hr)) {
1537 SafeArrayDestroy(sa);
1538 break;
1541 for (i = 0; i < datalen; i++) {
1542 V_VT(&v[i]) = VT_UI1;
1543 V_UI1(&v[i]) = ptr[i];
1545 SafeArrayUnaccessData(sa);
1547 V_VT(value) = VT_ARRAY|VT_VARIANT;
1548 V_ARRAY(value) = sa;
1549 break;
1551 case REG_MULTI_SZ:
1553 WCHAR *ptr = (WCHAR*)data;
1554 SAFEARRAYBOUND bound;
1555 SAFEARRAY *sa;
1556 VARIANT *v;
1558 /* get element count first */
1559 bound.lLbound = 0;
1560 bound.cElements = 0;
1561 while (*ptr) {
1562 bound.cElements++;
1563 ptr += lstrlenW(ptr)+1;
1566 sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
1567 if (!sa)
1568 break;
1570 hr = SafeArrayAccessData(sa, (void**)&v);
1571 if (FAILED(hr)) {
1572 SafeArrayDestroy(sa);
1573 break;
1576 ptr = (WCHAR*)data;
1577 while (*ptr) {
1578 V_VT(v) = VT_BSTR;
1579 V_BSTR(v) = SysAllocString(ptr);
1580 ptr += lstrlenW(ptr)+1;
1581 v++;
1584 SafeArrayUnaccessData(sa);
1585 V_VT(value) = VT_ARRAY|VT_VARIANT;
1586 V_ARRAY(value) = sa;
1587 break;
1589 default:
1590 FIXME("value type %d not supported\n", type);
1591 hr = E_FAIL;
1594 free(data);
1595 if (FAILED(hr))
1596 VariantInit(value);
1598 else
1599 hr = HRESULT_FROM_WIN32(ret);
1601 fail:
1602 if (val)
1603 free(subkey);
1604 return hr;
1607 static HRESULT WINAPI WshShell3_RegWrite(IWshShell3 *iface, BSTR name, VARIANT *value, VARIANT *type)
1609 DWORD regtype, data_len;
1610 WCHAR *subkey, *val;
1611 const BYTE *data;
1612 HRESULT hr;
1613 HKEY root;
1614 VARIANT v;
1615 LONG ret;
1617 TRACE("(%s %s %s)\n", debugstr_w(name), debugstr_variant(value), debugstr_variant(type));
1619 if (!name || !value || !type)
1620 return E_POINTER;
1622 root = get_root_key(name);
1623 if (!root)
1624 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1626 /* value type */
1627 if (is_optional_argument(type))
1628 regtype = REG_SZ;
1629 else {
1630 if (V_VT(type) != VT_BSTR)
1631 return E_INVALIDARG;
1633 if (!wcscmp(V_BSTR(type), L"REG_SZ"))
1634 regtype = REG_SZ;
1635 else if (!wcscmp(V_BSTR(type), L"REG_DWORD"))
1636 regtype = REG_DWORD;
1637 else if (!wcscmp(V_BSTR(type), L"REG_EXPAND_SZ"))
1638 regtype = REG_EXPAND_SZ;
1639 else if (!wcscmp(V_BSTR(type), L"REG_BINARY"))
1640 regtype = REG_BINARY;
1641 else {
1642 FIXME("unrecognized value type %s\n", debugstr_w(V_BSTR(type)));
1643 return E_FAIL;
1647 /* it's always a string or a DWORD */
1648 VariantInit(&v);
1649 switch (regtype)
1651 case REG_SZ:
1652 case REG_EXPAND_SZ:
1653 hr = VariantChangeType(&v, value, 0, VT_BSTR);
1654 if (hr == S_OK) {
1655 data = (BYTE*)V_BSTR(&v);
1656 data_len = SysStringByteLen(V_BSTR(&v)) + sizeof(WCHAR);
1658 break;
1659 case REG_DWORD:
1660 case REG_BINARY:
1661 hr = VariantChangeType(&v, value, 0, VT_I4);
1662 data = (BYTE*)&V_I4(&v);
1663 data_len = sizeof(DWORD);
1664 break;
1665 default:
1666 FIXME("unexpected regtype %d\n", regtype);
1667 return E_FAIL;
1670 if (FAILED(hr)) {
1671 FIXME("failed to convert value, regtype %d, 0x%08x\n", regtype, hr);
1672 return hr;
1675 hr = split_reg_path(name, &subkey, &val);
1676 if (FAILED(hr))
1677 goto fail;
1679 ret = RegSetKeyValueW(root, subkey, val, regtype, data, data_len);
1680 if (ret)
1681 hr = HRESULT_FROM_WIN32(ret);
1683 fail:
1684 VariantClear(&v);
1685 if (val)
1686 free(subkey);
1687 return hr;
1690 static HRESULT WINAPI WshShell3_RegDelete(IWshShell3 *iface, BSTR Name)
1692 FIXME("(%s): stub\n", debugstr_w(Name));
1693 return E_NOTIMPL;
1696 static HRESULT WINAPI WshShell3_LogEvent(IWshShell3 *iface, VARIANT *Type, BSTR Message, BSTR Target, VARIANT_BOOL *out_Success)
1698 FIXME("(%s %s %s %p): stub\n", debugstr_variant(Type), debugstr_w(Message), debugstr_w(Target), out_Success);
1699 return E_NOTIMPL;
1702 static HRESULT WINAPI WshShell3_AppActivate(IWshShell3 *iface, VARIANT *App, VARIANT *Wait, VARIANT_BOOL *out_Success)
1704 FIXME("(%s %s %p): stub\n", debugstr_variant(App), debugstr_variant(Wait), out_Success);
1705 return E_NOTIMPL;
1708 static HRESULT WINAPI WshShell3_SendKeys(IWshShell3 *iface, BSTR Keys, VARIANT *Wait)
1710 FIXME("(%s %p): stub\n", debugstr_w(Keys), Wait);
1711 return E_NOTIMPL;
1714 static HRESULT WINAPI WshShell3_Exec(IWshShell3 *iface, BSTR command, IWshExec **ret)
1716 BSTR expandedcmd;
1717 HRESULT hr;
1719 TRACE("(%s %p)\n", debugstr_w(command), ret);
1721 if (!ret)
1722 return E_POINTER;
1724 if (!command)
1725 return DISP_E_EXCEPTION;
1727 hr = WshShell3_ExpandEnvironmentStrings(iface, command, &expandedcmd);
1728 if (FAILED(hr))
1729 return hr;
1731 hr = WshExec_create(expandedcmd, ret);
1732 SysFreeString(expandedcmd);
1733 return hr;
1736 static HRESULT WINAPI WshShell3_get_CurrentDirectory(IWshShell3 *iface, BSTR *dir)
1738 DWORD ret;
1740 TRACE("(%p)\n", dir);
1742 ret = GetCurrentDirectoryW(0, NULL);
1743 if (!ret)
1744 return HRESULT_FROM_WIN32(GetLastError());
1746 *dir = SysAllocStringLen(NULL, ret-1);
1747 if (!*dir)
1748 return E_OUTOFMEMORY;
1750 ret = GetCurrentDirectoryW(ret, *dir);
1751 if (!ret) {
1752 SysFreeString(*dir);
1753 *dir = NULL;
1754 return HRESULT_FROM_WIN32(GetLastError());
1757 return S_OK;
1760 static HRESULT WINAPI WshShell3_put_CurrentDirectory(IWshShell3 *iface, BSTR dir)
1762 TRACE("(%s)\n", debugstr_w(dir));
1764 if (!dir)
1765 return E_INVALIDARG;
1767 if (!SetCurrentDirectoryW(dir))
1768 return HRESULT_FROM_WIN32(GetLastError());
1770 return S_OK;
1773 static const IWshShell3Vtbl WshShell3Vtbl = {
1774 WshShell3_QueryInterface,
1775 WshShell3_AddRef,
1776 WshShell3_Release,
1777 WshShell3_GetTypeInfoCount,
1778 WshShell3_GetTypeInfo,
1779 WshShell3_GetIDsOfNames,
1780 WshShell3_Invoke,
1781 WshShell3_get_SpecialFolders,
1782 WshShell3_get_Environment,
1783 WshShell3_Run,
1784 WshShell3_Popup,
1785 WshShell3_CreateShortcut,
1786 WshShell3_ExpandEnvironmentStrings,
1787 WshShell3_RegRead,
1788 WshShell3_RegWrite,
1789 WshShell3_RegDelete,
1790 WshShell3_LogEvent,
1791 WshShell3_AppActivate,
1792 WshShell3_SendKeys,
1793 WshShell3_Exec,
1794 WshShell3_get_CurrentDirectory,
1795 WshShell3_put_CurrentDirectory
1798 HRESULT WINAPI WshShellFactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
1800 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
1802 WshShell3.IWshShell3_iface.lpVtbl = &WshShell3Vtbl;
1803 init_classinfo(&IID_IWshShell3, (IUnknown *)&WshShell3.IWshShell3_iface, &WshShell3.classinfo);
1804 return IWshShell3_QueryInterface(&WshShell3.IWshShell3_iface, riid, ppv);