wined3d: Implement multisample resolve for typed resources.
[wine.git] / dlls / wshom.ocx / shell.c
bloba023786cc18dde48e08d3e1a87c2fb324e2f96ae
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/unicode.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 HeapFree(GetProcessHeap(), 0, 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 = HeapAlloc(GetProcessHeap(), 0, 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 HeapFree(GetProcessHeap(), 0, 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 HeapFree(GetProcessHeap(), 0, 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 *value = SysAllocStringLen(NULL, len);
458 if (!*value)
459 return E_OUTOFMEMORY;
461 if (len)
462 GetEnvironmentVariableW(name, *value, len+1);
464 return S_OK;
467 static HRESULT WINAPI WshEnvironment_put_Item(IWshEnvironment *iface, BSTR name, BSTR value)
469 WshEnvironment *This = impl_from_IWshEnvironment(iface);
470 FIXME("(%p)->(%s %s): stub\n", This, debugstr_w(name), debugstr_w(value));
471 return E_NOTIMPL;
474 static HRESULT WINAPI WshEnvironment_Count(IWshEnvironment *iface, LONG *count)
476 WshEnvironment *This = impl_from_IWshEnvironment(iface);
477 FIXME("(%p)->(%p): stub\n", This, count);
478 return E_NOTIMPL;
481 static HRESULT WINAPI WshEnvironment_get_length(IWshEnvironment *iface, LONG *len)
483 WshEnvironment *This = impl_from_IWshEnvironment(iface);
484 FIXME("(%p)->(%p): stub\n", This, len);
485 return E_NOTIMPL;
488 static HRESULT WINAPI WshEnvironment__NewEnum(IWshEnvironment *iface, IUnknown **penum)
490 WshEnvironment *This = impl_from_IWshEnvironment(iface);
491 FIXME("(%p)->(%p): stub\n", This, penum);
492 return E_NOTIMPL;
495 static HRESULT WINAPI WshEnvironment_Remove(IWshEnvironment *iface, BSTR name)
497 WshEnvironment *This = impl_from_IWshEnvironment(iface);
498 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
499 return E_NOTIMPL;
502 static const IWshEnvironmentVtbl WshEnvironmentVtbl = {
503 WshEnvironment_QueryInterface,
504 WshEnvironment_AddRef,
505 WshEnvironment_Release,
506 WshEnvironment_GetTypeInfoCount,
507 WshEnvironment_GetTypeInfo,
508 WshEnvironment_GetIDsOfNames,
509 WshEnvironment_Invoke,
510 WshEnvironment_get_Item,
511 WshEnvironment_put_Item,
512 WshEnvironment_Count,
513 WshEnvironment_get_length,
514 WshEnvironment__NewEnum,
515 WshEnvironment_Remove
518 static HRESULT WshEnvironment_Create(IWshEnvironment **env)
520 WshEnvironment *This;
522 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
523 if (!This) return E_OUTOFMEMORY;
525 This->IWshEnvironment_iface.lpVtbl = &WshEnvironmentVtbl;
526 This->ref = 1;
528 init_classinfo(&IID_IWshEnvironment, (IUnknown *)&This->IWshEnvironment_iface, &This->classinfo);
529 *env = &This->IWshEnvironment_iface;
531 return S_OK;
534 static HRESULT WINAPI WshCollection_QueryInterface(IWshCollection *iface, REFIID riid, void **ppv)
536 WshCollection *This = impl_from_IWshCollection(iface);
538 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
540 if (IsEqualGUID(riid, &IID_IUnknown) ||
541 IsEqualGUID(riid, &IID_IDispatch) ||
542 IsEqualGUID(riid, &IID_IWshCollection))
544 *ppv = iface;
546 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
548 *ppv = &This->classinfo.IProvideClassInfo_iface;
550 else {
551 FIXME("Unknown iface %s\n", debugstr_guid(riid));
552 *ppv = NULL;
553 return E_NOINTERFACE;
556 IUnknown_AddRef((IUnknown*)*ppv);
557 return S_OK;
560 static ULONG WINAPI WshCollection_AddRef(IWshCollection *iface)
562 WshCollection *This = impl_from_IWshCollection(iface);
563 LONG ref = InterlockedIncrement(&This->ref);
564 TRACE("(%p) ref = %d\n", This, ref);
565 return ref;
568 static ULONG WINAPI WshCollection_Release(IWshCollection *iface)
570 WshCollection *This = impl_from_IWshCollection(iface);
571 LONG ref = InterlockedDecrement(&This->ref);
572 TRACE("(%p) ref = %d\n", This, ref);
574 if (!ref)
575 HeapFree(GetProcessHeap(), 0, This);
577 return ref;
580 static HRESULT WINAPI WshCollection_GetTypeInfoCount(IWshCollection *iface, UINT *pctinfo)
582 WshCollection *This = impl_from_IWshCollection(iface);
583 TRACE("(%p)->(%p)\n", This, pctinfo);
584 *pctinfo = 1;
585 return S_OK;
588 static HRESULT WINAPI WshCollection_GetTypeInfo(IWshCollection *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
590 WshCollection *This = impl_from_IWshCollection(iface);
591 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
592 return get_typeinfo(IWshCollection_tid, ppTInfo);
595 static HRESULT WINAPI WshCollection_GetIDsOfNames(IWshCollection *iface, REFIID riid, LPOLESTR *rgszNames,
596 UINT cNames, LCID lcid, DISPID *rgDispId)
598 WshCollection *This = impl_from_IWshCollection(iface);
599 ITypeInfo *typeinfo;
600 HRESULT hr;
602 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
604 hr = get_typeinfo(IWshCollection_tid, &typeinfo);
605 if(SUCCEEDED(hr))
607 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
608 ITypeInfo_Release(typeinfo);
611 return hr;
614 static HRESULT WINAPI WshCollection_Invoke(IWshCollection *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
615 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
617 WshCollection *This = impl_from_IWshCollection(iface);
618 ITypeInfo *typeinfo;
619 HRESULT hr;
621 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
622 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
624 hr = get_typeinfo(IWshCollection_tid, &typeinfo);
625 if(SUCCEEDED(hr))
627 hr = ITypeInfo_Invoke(typeinfo, &This->IWshCollection_iface, dispIdMember, wFlags,
628 pDispParams, pVarResult, pExcepInfo, puArgErr);
629 ITypeInfo_Release(typeinfo);
632 return hr;
635 static HRESULT WINAPI WshCollection_Item(IWshCollection *iface, VARIANT *index, VARIANT *value)
637 WshCollection *This = impl_from_IWshCollection(iface);
638 static const WCHAR allusersdesktopW[] = {'A','l','l','U','s','e','r','s','D','e','s','k','t','o','p',0};
639 static const WCHAR allusersprogramsW[] = {'A','l','l','U','s','e','r','s','P','r','o','g','r','a','m','s',0};
640 static const WCHAR desktopW[] = {'D','e','s','k','t','o','p',0};
641 PIDLIST_ABSOLUTE pidl;
642 WCHAR pathW[MAX_PATH];
643 int kind = 0;
644 BSTR folder;
645 HRESULT hr;
647 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(index), value);
649 if (V_VT(index) != VT_BSTR)
651 FIXME("only BSTR index supported, got %d\n", V_VT(index));
652 return E_NOTIMPL;
655 folder = V_BSTR(index);
656 if (!strcmpiW(folder, desktopW))
657 kind = CSIDL_DESKTOP;
658 else if (!strcmpiW(folder, allusersdesktopW))
659 kind = CSIDL_COMMON_DESKTOPDIRECTORY;
660 else if (!strcmpiW(folder, allusersprogramsW))
661 kind = CSIDL_COMMON_PROGRAMS;
662 else
664 FIXME("folder kind %s not supported\n", debugstr_w(folder));
665 return E_NOTIMPL;
668 hr = SHGetSpecialFolderLocation(NULL, kind, &pidl);
669 if (hr != S_OK) return hr;
671 if (SHGetPathFromIDListW(pidl, pathW))
673 V_VT(value) = VT_BSTR;
674 V_BSTR(value) = SysAllocString(pathW);
675 hr = V_BSTR(value) ? S_OK : E_OUTOFMEMORY;
677 else
678 hr = E_FAIL;
680 CoTaskMemFree(pidl);
682 return hr;
685 static HRESULT WINAPI WshCollection_Count(IWshCollection *iface, LONG *count)
687 WshCollection *This = impl_from_IWshCollection(iface);
688 FIXME("(%p)->(%p): stub\n", This, count);
689 return E_NOTIMPL;
692 static HRESULT WINAPI WshCollection_get_length(IWshCollection *iface, LONG *count)
694 WshCollection *This = impl_from_IWshCollection(iface);
695 FIXME("(%p)->(%p): stub\n", This, count);
696 return E_NOTIMPL;
699 static HRESULT WINAPI WshCollection__NewEnum(IWshCollection *iface, IUnknown *Enum)
701 WshCollection *This = impl_from_IWshCollection(iface);
702 FIXME("(%p)->(%p): stub\n", This, Enum);
703 return E_NOTIMPL;
706 static const IWshCollectionVtbl WshCollectionVtbl = {
707 WshCollection_QueryInterface,
708 WshCollection_AddRef,
709 WshCollection_Release,
710 WshCollection_GetTypeInfoCount,
711 WshCollection_GetTypeInfo,
712 WshCollection_GetIDsOfNames,
713 WshCollection_Invoke,
714 WshCollection_Item,
715 WshCollection_Count,
716 WshCollection_get_length,
717 WshCollection__NewEnum
720 static HRESULT WshCollection_Create(IWshCollection **collection)
722 WshCollection *This;
724 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
725 if (!This) return E_OUTOFMEMORY;
727 This->IWshCollection_iface.lpVtbl = &WshCollectionVtbl;
728 This->ref = 1;
730 init_classinfo(&IID_IWshCollection, (IUnknown *)&This->IWshCollection_iface, &This->classinfo);
731 *collection = &This->IWshCollection_iface;
733 return S_OK;
736 /* IWshShortcut */
737 static HRESULT WINAPI WshShortcut_QueryInterface(IWshShortcut *iface, REFIID riid, void **ppv)
739 WshShortcut *This = impl_from_IWshShortcut(iface);
741 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
743 if (IsEqualGUID(riid, &IID_IUnknown) ||
744 IsEqualGUID(riid, &IID_IDispatch) ||
745 IsEqualGUID(riid, &IID_IWshShortcut))
747 *ppv = iface;
749 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
751 *ppv = &This->classinfo.IProvideClassInfo_iface;
753 else {
754 FIXME("Unknown iface %s\n", debugstr_guid(riid));
755 *ppv = NULL;
756 return E_NOINTERFACE;
759 IUnknown_AddRef((IUnknown*)*ppv);
760 return S_OK;
763 static ULONG WINAPI WshShortcut_AddRef(IWshShortcut *iface)
765 WshShortcut *This = impl_from_IWshShortcut(iface);
766 LONG ref = InterlockedIncrement(&This->ref);
767 TRACE("(%p) ref = %d\n", This, ref);
768 return ref;
771 static ULONG WINAPI WshShortcut_Release(IWshShortcut *iface)
773 WshShortcut *This = impl_from_IWshShortcut(iface);
774 LONG ref = InterlockedDecrement(&This->ref);
775 TRACE("(%p) ref = %d\n", This, ref);
777 if (!ref)
779 SysFreeString(This->path_link);
780 IShellLinkW_Release(This->link);
781 HeapFree(GetProcessHeap(), 0, This);
784 return ref;
787 static HRESULT WINAPI WshShortcut_GetTypeInfoCount(IWshShortcut *iface, UINT *pctinfo)
789 WshShortcut *This = impl_from_IWshShortcut(iface);
790 TRACE("(%p)->(%p)\n", This, pctinfo);
791 *pctinfo = 1;
792 return S_OK;
795 static HRESULT WINAPI WshShortcut_GetTypeInfo(IWshShortcut *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
797 WshShortcut *This = impl_from_IWshShortcut(iface);
798 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
799 return get_typeinfo(IWshShortcut_tid, ppTInfo);
802 static HRESULT WINAPI WshShortcut_GetIDsOfNames(IWshShortcut *iface, REFIID riid, LPOLESTR *rgszNames,
803 UINT cNames, LCID lcid, DISPID *rgDispId)
805 WshShortcut *This = impl_from_IWshShortcut(iface);
806 ITypeInfo *typeinfo;
807 HRESULT hr;
809 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
811 hr = get_typeinfo(IWshShortcut_tid, &typeinfo);
812 if(SUCCEEDED(hr))
814 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
815 ITypeInfo_Release(typeinfo);
818 return hr;
821 static HRESULT WINAPI WshShortcut_Invoke(IWshShortcut *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
822 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
824 WshShortcut *This = impl_from_IWshShortcut(iface);
825 ITypeInfo *typeinfo;
826 HRESULT hr;
828 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
829 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
831 hr = get_typeinfo(IWshShortcut_tid, &typeinfo);
832 if(SUCCEEDED(hr))
834 hr = ITypeInfo_Invoke(typeinfo, &This->IWshShortcut_iface, dispIdMember, wFlags,
835 pDispParams, pVarResult, pExcepInfo, puArgErr);
836 ITypeInfo_Release(typeinfo);
839 return hr;
842 static HRESULT WINAPI WshShortcut_get_FullName(IWshShortcut *iface, BSTR *name)
844 WshShortcut *This = impl_from_IWshShortcut(iface);
845 FIXME("(%p)->(%p): stub\n", This, name);
846 return E_NOTIMPL;
849 static HRESULT WINAPI WshShortcut_get_Arguments(IWshShortcut *iface, BSTR *Arguments)
851 WshShortcut *This = impl_from_IWshShortcut(iface);
852 WCHAR buffW[INFOTIPSIZE];
853 HRESULT hr;
855 TRACE("(%p)->(%p)\n", This, Arguments);
857 if (!Arguments)
858 return E_POINTER;
860 *Arguments = NULL;
862 hr = IShellLinkW_GetArguments(This->link, buffW, sizeof(buffW)/sizeof(WCHAR));
863 if (FAILED(hr))
864 return hr;
866 *Arguments = SysAllocString(buffW);
867 return *Arguments ? S_OK : E_OUTOFMEMORY;
870 static HRESULT WINAPI WshShortcut_put_Arguments(IWshShortcut *iface, BSTR Arguments)
872 WshShortcut *This = impl_from_IWshShortcut(iface);
874 TRACE("(%p)->(%s)\n", This, debugstr_w(Arguments));
876 return IShellLinkW_SetArguments(This->link, Arguments);
879 static HRESULT WINAPI WshShortcut_get_Description(IWshShortcut *iface, BSTR *Description)
881 WshShortcut *This = impl_from_IWshShortcut(iface);
882 FIXME("(%p)->(%p): stub\n", This, Description);
883 return E_NOTIMPL;
886 static HRESULT WINAPI WshShortcut_put_Description(IWshShortcut *iface, BSTR Description)
888 WshShortcut *This = impl_from_IWshShortcut(iface);
889 TRACE("(%p)->(%s)\n", This, debugstr_w(Description));
890 return IShellLinkW_SetDescription(This->link, Description);
893 static HRESULT WINAPI WshShortcut_get_Hotkey(IWshShortcut *iface, BSTR *Hotkey)
895 WshShortcut *This = impl_from_IWshShortcut(iface);
896 FIXME("(%p)->(%p): stub\n", This, Hotkey);
897 return E_NOTIMPL;
900 static HRESULT WINAPI WshShortcut_put_Hotkey(IWshShortcut *iface, BSTR Hotkey)
902 WshShortcut *This = impl_from_IWshShortcut(iface);
903 FIXME("(%p)->(%s): stub\n", This, debugstr_w(Hotkey));
904 return E_NOTIMPL;
907 static HRESULT WINAPI WshShortcut_get_IconLocation(IWshShortcut *iface, BSTR *IconPath)
909 static const WCHAR fmtW[] = {'%','s',',',' ','%','d',0};
910 WshShortcut *This = impl_from_IWshShortcut(iface);
911 WCHAR buffW[MAX_PATH], pathW[MAX_PATH];
912 INT icon = 0;
913 HRESULT hr;
915 TRACE("(%p)->(%p)\n", This, IconPath);
917 if (!IconPath)
918 return E_POINTER;
920 hr = IShellLinkW_GetIconLocation(This->link, buffW, sizeof(buffW)/sizeof(WCHAR), &icon);
921 if (FAILED(hr)) return hr;
923 sprintfW(pathW, fmtW, buffW, icon);
924 *IconPath = SysAllocString(pathW);
925 if (!*IconPath) return E_OUTOFMEMORY;
927 return S_OK;
930 static HRESULT WINAPI WshShortcut_put_IconLocation(IWshShortcut *iface, BSTR IconPath)
932 WshShortcut *This = impl_from_IWshShortcut(iface);
933 HRESULT hr;
934 WCHAR *ptr;
935 BSTR path;
936 INT icon;
938 TRACE("(%p)->(%s)\n", This, debugstr_w(IconPath));
940 /* scan for icon id */
941 ptr = strrchrW(IconPath, ',');
942 if (!ptr)
944 WARN("icon index not found\n");
945 return E_FAIL;
948 path = SysAllocStringLen(IconPath, ptr-IconPath);
950 /* skip spaces if any */
951 while (isspaceW(*++ptr))
954 icon = atoiW(ptr);
956 hr = IShellLinkW_SetIconLocation(This->link, path, icon);
957 SysFreeString(path);
959 return hr;
962 static HRESULT WINAPI WshShortcut_put_RelativePath(IWshShortcut *iface, BSTR rhs)
964 WshShortcut *This = impl_from_IWshShortcut(iface);
965 FIXME("(%p)->(%s): stub\n", This, debugstr_w(rhs));
966 return E_NOTIMPL;
969 static HRESULT WINAPI WshShortcut_get_TargetPath(IWshShortcut *iface, BSTR *Path)
971 WshShortcut *This = impl_from_IWshShortcut(iface);
972 FIXME("(%p)->(%p): stub\n", This, Path);
973 return E_NOTIMPL;
976 static HRESULT WINAPI WshShortcut_put_TargetPath(IWshShortcut *iface, BSTR Path)
978 WshShortcut *This = impl_from_IWshShortcut(iface);
979 TRACE("(%p)->(%s)\n", This, debugstr_w(Path));
980 return IShellLinkW_SetPath(This->link, Path);
983 static HRESULT WINAPI WshShortcut_get_WindowStyle(IWshShortcut *iface, int *ShowCmd)
985 WshShortcut *This = impl_from_IWshShortcut(iface);
986 TRACE("(%p)->(%p)\n", This, ShowCmd);
987 return IShellLinkW_GetShowCmd(This->link, ShowCmd);
990 static HRESULT WINAPI WshShortcut_put_WindowStyle(IWshShortcut *iface, int ShowCmd)
992 WshShortcut *This = impl_from_IWshShortcut(iface);
993 TRACE("(%p)->(%d)\n", This, ShowCmd);
994 return IShellLinkW_SetShowCmd(This->link, ShowCmd);
997 static HRESULT WINAPI WshShortcut_get_WorkingDirectory(IWshShortcut *iface, BSTR *WorkingDirectory)
999 WshShortcut *This = impl_from_IWshShortcut(iface);
1000 WCHAR buffW[MAX_PATH];
1001 HRESULT hr;
1003 TRACE("(%p)->(%p)\n", This, WorkingDirectory);
1005 if (!WorkingDirectory)
1006 return E_POINTER;
1008 *WorkingDirectory = NULL;
1009 hr = IShellLinkW_GetWorkingDirectory(This->link, buffW, sizeof(buffW)/sizeof(WCHAR));
1010 if (FAILED(hr)) return hr;
1012 *WorkingDirectory = SysAllocString(buffW);
1013 return *WorkingDirectory ? S_OK : E_OUTOFMEMORY;
1016 static HRESULT WINAPI WshShortcut_put_WorkingDirectory(IWshShortcut *iface, BSTR WorkingDirectory)
1018 WshShortcut *This = impl_from_IWshShortcut(iface);
1019 TRACE("(%p)->(%s)\n", This, debugstr_w(WorkingDirectory));
1020 return IShellLinkW_SetWorkingDirectory(This->link, WorkingDirectory);
1023 static HRESULT WINAPI WshShortcut_Load(IWshShortcut *iface, BSTR PathLink)
1025 WshShortcut *This = impl_from_IWshShortcut(iface);
1026 FIXME("(%p)->(%s): stub\n", This, debugstr_w(PathLink));
1027 return E_NOTIMPL;
1030 static HRESULT WINAPI WshShortcut_Save(IWshShortcut *iface)
1032 WshShortcut *This = impl_from_IWshShortcut(iface);
1033 IPersistFile *file;
1034 HRESULT hr;
1036 TRACE("(%p)\n", This);
1038 IShellLinkW_QueryInterface(This->link, &IID_IPersistFile, (void**)&file);
1039 hr = IPersistFile_Save(file, This->path_link, TRUE);
1040 IPersistFile_Release(file);
1042 return hr;
1045 static const IWshShortcutVtbl WshShortcutVtbl = {
1046 WshShortcut_QueryInterface,
1047 WshShortcut_AddRef,
1048 WshShortcut_Release,
1049 WshShortcut_GetTypeInfoCount,
1050 WshShortcut_GetTypeInfo,
1051 WshShortcut_GetIDsOfNames,
1052 WshShortcut_Invoke,
1053 WshShortcut_get_FullName,
1054 WshShortcut_get_Arguments,
1055 WshShortcut_put_Arguments,
1056 WshShortcut_get_Description,
1057 WshShortcut_put_Description,
1058 WshShortcut_get_Hotkey,
1059 WshShortcut_put_Hotkey,
1060 WshShortcut_get_IconLocation,
1061 WshShortcut_put_IconLocation,
1062 WshShortcut_put_RelativePath,
1063 WshShortcut_get_TargetPath,
1064 WshShortcut_put_TargetPath,
1065 WshShortcut_get_WindowStyle,
1066 WshShortcut_put_WindowStyle,
1067 WshShortcut_get_WorkingDirectory,
1068 WshShortcut_put_WorkingDirectory,
1069 WshShortcut_Load,
1070 WshShortcut_Save
1073 static HRESULT WshShortcut_Create(const WCHAR *path, IDispatch **shortcut)
1075 WshShortcut *This;
1076 HRESULT hr;
1078 *shortcut = NULL;
1080 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1081 if (!This) return E_OUTOFMEMORY;
1083 This->IWshShortcut_iface.lpVtbl = &WshShortcutVtbl;
1084 This->ref = 1;
1086 hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
1087 &IID_IShellLinkW, (void**)&This->link);
1088 if (FAILED(hr))
1090 HeapFree(GetProcessHeap(), 0, This);
1091 return hr;
1094 This->path_link = SysAllocString(path);
1095 if (!This->path_link)
1097 IShellLinkW_Release(This->link);
1098 HeapFree(GetProcessHeap(), 0, This);
1099 return E_OUTOFMEMORY;
1102 init_classinfo(&IID_IWshShortcut, (IUnknown *)&This->IWshShortcut_iface, &This->classinfo);
1103 *shortcut = (IDispatch*)&This->IWshShortcut_iface;
1105 return S_OK;
1108 static HRESULT WINAPI WshShell3_QueryInterface(IWshShell3 *iface, REFIID riid, void **ppv)
1110 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
1112 *ppv = NULL;
1114 if (IsEqualGUID(riid, &IID_IDispatch) ||
1115 IsEqualGUID(riid, &IID_IWshShell3) ||
1116 IsEqualGUID(riid, &IID_IWshShell2) ||
1117 IsEqualGUID(riid, &IID_IWshShell) ||
1118 IsEqualGUID(riid, &IID_IUnknown))
1120 *ppv = iface;
1122 else if (IsEqualGUID(riid, &IID_IDispatchEx))
1124 return E_NOINTERFACE;
1126 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
1128 *ppv = &WshShell3.classinfo.IProvideClassInfo_iface;
1130 else
1132 WARN("unknown iface %s\n", debugstr_guid(riid));
1133 return E_NOINTERFACE;
1136 IUnknown_AddRef((IUnknown *)*ppv);
1137 return S_OK;
1140 static ULONG WINAPI WshShell3_AddRef(IWshShell3 *iface)
1142 TRACE("()\n");
1143 return 2;
1146 static ULONG WINAPI WshShell3_Release(IWshShell3 *iface)
1148 TRACE("()\n");
1149 return 2;
1152 static HRESULT WINAPI WshShell3_GetTypeInfoCount(IWshShell3 *iface, UINT *pctinfo)
1154 TRACE("(%p)\n", pctinfo);
1155 *pctinfo = 1;
1156 return S_OK;
1159 static HRESULT WINAPI WshShell3_GetTypeInfo(IWshShell3 *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
1161 TRACE("(%u %u %p)\n", iTInfo, lcid, ppTInfo);
1162 return get_typeinfo(IWshShell3_tid, ppTInfo);
1165 static HRESULT WINAPI WshShell3_GetIDsOfNames(IWshShell3 *iface, REFIID riid, LPOLESTR *rgszNames,
1166 UINT cNames, LCID lcid, DISPID *rgDispId)
1168 ITypeInfo *typeinfo;
1169 HRESULT hr;
1171 TRACE("(%s %p %u %u %p)\n", debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1173 hr = get_typeinfo(IWshShell3_tid, &typeinfo);
1174 if(SUCCEEDED(hr))
1176 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1177 ITypeInfo_Release(typeinfo);
1180 return hr;
1183 static HRESULT WINAPI WshShell3_Invoke(IWshShell3 *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
1184 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
1186 ITypeInfo *typeinfo;
1187 HRESULT hr;
1189 TRACE("(%d %s %d %d %p %p %p %p)\n", dispIdMember, debugstr_guid(riid),
1190 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1192 hr = get_typeinfo(IWshShell3_tid, &typeinfo);
1193 if(SUCCEEDED(hr))
1195 hr = ITypeInfo_Invoke(typeinfo, &WshShell3.IWshShell3_iface, dispIdMember, wFlags,
1196 pDispParams, pVarResult, pExcepInfo, puArgErr);
1197 ITypeInfo_Release(typeinfo);
1200 return hr;
1203 static HRESULT WINAPI WshShell3_get_SpecialFolders(IWshShell3 *iface, IWshCollection **folders)
1205 TRACE("(%p)\n", folders);
1206 return WshCollection_Create(folders);
1209 static HRESULT WINAPI WshShell3_get_Environment(IWshShell3 *iface, VARIANT *type, IWshEnvironment **env)
1211 FIXME("(%s %p): semi-stub\n", debugstr_variant(type), env);
1212 return WshEnvironment_Create(env);
1215 static inline BOOL is_optional_argument(const VARIANT *arg)
1217 return V_VT(arg) == VT_ERROR && V_ERROR(arg) == DISP_E_PARAMNOTFOUND;
1220 static HRESULT WINAPI WshShell3_Run(IWshShell3 *iface, BSTR cmd, VARIANT *style, VARIANT *wait, DWORD *exit_code)
1222 SHELLEXECUTEINFOW info;
1223 int waitforprocess;
1224 VARIANT s;
1225 HRESULT hr;
1227 TRACE("(%s %s %s %p)\n", debugstr_w(cmd), debugstr_variant(style), debugstr_variant(wait), exit_code);
1229 if (!style || !wait || !exit_code)
1230 return E_POINTER;
1232 VariantInit(&s);
1233 hr = VariantChangeType(&s, style, 0, VT_I4);
1234 if (FAILED(hr))
1236 ERR("failed to convert style argument, 0x%08x\n", hr);
1237 return hr;
1240 if (is_optional_argument(wait))
1241 waitforprocess = 0;
1242 else {
1243 VARIANT w;
1245 VariantInit(&w);
1246 hr = VariantChangeType(&w, wait, 0, VT_I4);
1247 if (FAILED(hr))
1248 return hr;
1250 waitforprocess = V_I4(&w);
1253 memset(&info, 0, sizeof(info));
1254 info.cbSize = sizeof(info);
1255 info.fMask = waitforprocess ? SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS : SEE_MASK_DEFAULT;
1256 info.lpFile = cmd;
1257 info.nShow = V_I4(&s);
1259 if (!ShellExecuteExW(&info))
1261 TRACE("ShellExecute failed, %d\n", GetLastError());
1262 return HRESULT_FROM_WIN32(GetLastError());
1264 else
1266 if (waitforprocess)
1268 GetExitCodeProcess(info.hProcess, exit_code);
1269 CloseHandle(info.hProcess);
1271 else
1272 *exit_code = 0;
1274 return S_OK;
1278 struct popup_thread_param
1280 WCHAR *text;
1281 VARIANT title;
1282 VARIANT type;
1283 INT button;
1286 static DWORD WINAPI popup_thread_proc(void *arg)
1288 static const WCHAR defaulttitleW[] = {'W','i','n','d','o','w','s',' ','S','c','r','i','p','t',' ','H','o','s','t',0};
1289 struct popup_thread_param *param = (struct popup_thread_param *)arg;
1291 param->button = MessageBoxW(NULL, param->text, is_optional_argument(&param->title) ?
1292 defaulttitleW : V_BSTR(&param->title), V_I4(&param->type));
1293 return 0;
1296 static HRESULT WINAPI WshShell3_Popup(IWshShell3 *iface, BSTR text, VARIANT *seconds_to_wait, VARIANT *title,
1297 VARIANT *type, int *button)
1299 struct popup_thread_param param;
1300 DWORD tid, status;
1301 VARIANT timeout;
1302 HANDLE hthread;
1303 HRESULT hr;
1305 TRACE("(%s %s %s %s %p)\n", debugstr_w(text), debugstr_variant(seconds_to_wait), debugstr_variant(title),
1306 debugstr_variant(type), button);
1308 if (!seconds_to_wait || !title || !type || !button)
1309 return E_POINTER;
1311 VariantInit(&timeout);
1312 if (!is_optional_argument(seconds_to_wait))
1314 hr = VariantChangeType(&timeout, seconds_to_wait, 0, VT_I4);
1315 if (FAILED(hr))
1316 return hr;
1319 VariantInit(&param.type);
1320 if (!is_optional_argument(type))
1322 hr = VariantChangeType(&param.type, type, 0, VT_I4);
1323 if (FAILED(hr))
1324 return hr;
1327 if (is_optional_argument(title))
1328 param.title = *title;
1329 else
1331 VariantInit(&param.title);
1332 hr = VariantChangeType(&param.title, title, 0, VT_BSTR);
1333 if (FAILED(hr))
1334 return hr;
1337 param.text = text;
1338 param.button = -1;
1339 hthread = CreateThread(NULL, 0, popup_thread_proc, &param, 0, &tid);
1340 status = MsgWaitForMultipleObjects(1, &hthread, FALSE, V_I4(&timeout) ? V_I4(&timeout) * 1000: INFINITE, 0);
1341 if (status == WAIT_TIMEOUT)
1343 PostThreadMessageW(tid, WM_QUIT, 0, 0);
1344 MsgWaitForMultipleObjects(1, &hthread, FALSE, INFINITE, 0);
1345 param.button = -1;
1347 *button = param.button;
1349 VariantClear(&param.title);
1350 CloseHandle(hthread);
1352 return S_OK;
1355 static HRESULT WINAPI WshShell3_CreateShortcut(IWshShell3 *iface, BSTR PathLink, IDispatch** Shortcut)
1357 TRACE("(%s %p)\n", debugstr_w(PathLink), Shortcut);
1358 return WshShortcut_Create(PathLink, Shortcut);
1361 static HRESULT WINAPI WshShell3_ExpandEnvironmentStrings(IWshShell3 *iface, BSTR Src, BSTR* Dst)
1363 DWORD ret;
1365 TRACE("(%s %p)\n", debugstr_w(Src), Dst);
1367 if (!Src || !Dst) return E_POINTER;
1369 ret = ExpandEnvironmentStringsW(Src, NULL, 0);
1370 *Dst = SysAllocStringLen(NULL, ret);
1371 if (!*Dst) return E_OUTOFMEMORY;
1373 if (ExpandEnvironmentStringsW(Src, *Dst, ret))
1374 return S_OK;
1375 else
1377 SysFreeString(*Dst);
1378 *Dst = NULL;
1379 return HRESULT_FROM_WIN32(GetLastError());
1383 static HKEY get_root_key(const WCHAR *path)
1385 static const struct {
1386 const WCHAR full[20];
1387 const WCHAR abbrev[5];
1388 HKEY hkey;
1389 } rootkeys[] = {
1390 { {'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R',0}, {'H','K','C','U',0}, HKEY_CURRENT_USER },
1391 { {'H','K','E','Y','_','L','O','C','A','L','_','M','A','C','H','I','N','E',0}, {'H','K','L','M',0}, HKEY_LOCAL_MACHINE },
1392 { {'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T',0}, {'H','K','C','R',0}, HKEY_CLASSES_ROOT },
1393 { {'H','K','E','Y','_','U','S','E','R','S',0}, {0}, HKEY_USERS },
1394 { {'H','K','E','Y','_','C','U','R','R','E','N','T','_','C','O','N','F','I','G',0}, {0}, HKEY_CURRENT_CONFIG }
1396 int i;
1398 for (i = 0; i < sizeof(rootkeys)/sizeof(rootkeys[0]); i++) {
1399 if (!strncmpW(path, rootkeys[i].full, strlenW(rootkeys[i].full)))
1400 return rootkeys[i].hkey;
1401 if (rootkeys[i].abbrev[0] && !strncmpW(path, rootkeys[i].abbrev, strlenW(rootkeys[i].abbrev)))
1402 return rootkeys[i].hkey;
1405 return NULL;
1408 /* Caller is responsible to free 'subkey' if 'value' is not NULL */
1409 static HRESULT split_reg_path(const WCHAR *path, WCHAR **subkey, WCHAR **value)
1411 *value = NULL;
1413 /* at least one separator should be present */
1414 *subkey = strchrW(path, '\\');
1415 if (!*subkey)
1416 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1418 /* default value or not */
1419 if ((*subkey)[strlenW(*subkey)-1] == '\\') {
1420 (*subkey)++;
1421 *value = NULL;
1423 else {
1424 *value = strrchrW(*subkey, '\\');
1425 if (*value - *subkey > 1) {
1426 unsigned int len = *value - *subkey - 1;
1427 WCHAR *ret;
1429 ret = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR));
1430 if (!ret)
1431 return E_OUTOFMEMORY;
1433 memcpy(ret, *subkey + 1, len*sizeof(WCHAR));
1434 ret[len] = 0;
1435 *subkey = ret;
1437 (*value)++;
1440 return S_OK;
1443 static HRESULT WINAPI WshShell3_RegRead(IWshShell3 *iface, BSTR name, VARIANT *value)
1445 DWORD type, datalen, ret;
1446 WCHAR *subkey, *val;
1447 HRESULT hr;
1448 HKEY root;
1450 TRACE("(%s %p)\n", debugstr_w(name), value);
1452 if (!name || !value)
1453 return E_POINTER;
1455 root = get_root_key(name);
1456 if (!root)
1457 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1459 hr = split_reg_path(name, &subkey, &val);
1460 if (FAILED(hr))
1461 return hr;
1463 type = REG_NONE;
1464 datalen = 0;
1465 ret = RegGetValueW(root, subkey, val, RRF_RT_ANY, &type, NULL, &datalen);
1466 if (ret == ERROR_SUCCESS) {
1467 void *data;
1469 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1470 if (!data) {
1471 hr = E_OUTOFMEMORY;
1472 goto fail;
1475 ret = RegGetValueW(root, subkey, val, RRF_RT_ANY, &type, data, &datalen);
1476 if (ret) {
1477 HeapFree(GetProcessHeap(), 0, data);
1478 hr = HRESULT_FROM_WIN32(ret);
1479 goto fail;
1482 switch (type) {
1483 case REG_SZ:
1484 case REG_EXPAND_SZ:
1485 V_VT(value) = VT_BSTR;
1486 V_BSTR(value) = SysAllocString((WCHAR*)data);
1487 if (!V_BSTR(value))
1488 hr = E_OUTOFMEMORY;
1489 break;
1490 case REG_DWORD:
1491 V_VT(value) = VT_I4;
1492 V_I4(value) = *(DWORD*)data;
1493 break;
1494 case REG_BINARY:
1496 BYTE *ptr = (BYTE*)data;
1497 SAFEARRAYBOUND bound;
1498 unsigned int i;
1499 SAFEARRAY *sa;
1500 VARIANT *v;
1502 bound.lLbound = 0;
1503 bound.cElements = datalen;
1504 sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
1505 if (!sa)
1506 break;
1508 hr = SafeArrayAccessData(sa, (void**)&v);
1509 if (FAILED(hr)) {
1510 SafeArrayDestroy(sa);
1511 break;
1514 for (i = 0; i < datalen; i++) {
1515 V_VT(&v[i]) = VT_UI1;
1516 V_UI1(&v[i]) = ptr[i];
1518 SafeArrayUnaccessData(sa);
1520 V_VT(value) = VT_ARRAY|VT_VARIANT;
1521 V_ARRAY(value) = sa;
1522 break;
1524 case REG_MULTI_SZ:
1526 WCHAR *ptr = (WCHAR*)data;
1527 SAFEARRAYBOUND bound;
1528 SAFEARRAY *sa;
1529 VARIANT *v;
1531 /* get element count first */
1532 bound.lLbound = 0;
1533 bound.cElements = 0;
1534 while (*ptr) {
1535 bound.cElements++;
1536 ptr += strlenW(ptr)+1;
1539 sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
1540 if (!sa)
1541 break;
1543 hr = SafeArrayAccessData(sa, (void**)&v);
1544 if (FAILED(hr)) {
1545 SafeArrayDestroy(sa);
1546 break;
1549 ptr = (WCHAR*)data;
1550 while (*ptr) {
1551 V_VT(v) = VT_BSTR;
1552 V_BSTR(v) = SysAllocString(ptr);
1553 ptr += strlenW(ptr)+1;
1554 v++;
1557 SafeArrayUnaccessData(sa);
1558 V_VT(value) = VT_ARRAY|VT_VARIANT;
1559 V_ARRAY(value) = sa;
1560 break;
1562 default:
1563 FIXME("value type %d not supported\n", type);
1564 hr = E_FAIL;
1567 HeapFree(GetProcessHeap(), 0, data);
1568 if (FAILED(hr))
1569 VariantInit(value);
1571 else
1572 hr = HRESULT_FROM_WIN32(ret);
1574 fail:
1575 if (val)
1576 HeapFree(GetProcessHeap(), 0, subkey);
1577 return hr;
1580 static HRESULT WINAPI WshShell3_RegWrite(IWshShell3 *iface, BSTR name, VARIANT *value, VARIANT *type)
1582 static const WCHAR regexpandszW[] = {'R','E','G','_','E','X','P','A','N','D','_','S','Z',0};
1583 static const WCHAR regszW[] = {'R','E','G','_','S','Z',0};
1584 static const WCHAR regdwordW[] = {'R','E','G','_','D','W','O','R','D',0};
1585 static const WCHAR regbinaryW[] = {'R','E','G','_','B','I','N','A','R','Y',0};
1587 DWORD regtype, data_len;
1588 WCHAR *subkey, *val;
1589 const BYTE *data;
1590 HRESULT hr;
1591 HKEY root;
1592 VARIANT v;
1593 LONG ret;
1595 TRACE("(%s %s %s)\n", debugstr_w(name), debugstr_variant(value), debugstr_variant(type));
1597 if (!name || !value || !type)
1598 return E_POINTER;
1600 root = get_root_key(name);
1601 if (!root)
1602 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1604 /* value type */
1605 if (is_optional_argument(type))
1606 regtype = REG_SZ;
1607 else {
1608 if (V_VT(type) != VT_BSTR)
1609 return E_INVALIDARG;
1611 if (!strcmpW(V_BSTR(type), regszW))
1612 regtype = REG_SZ;
1613 else if (!strcmpW(V_BSTR(type), regdwordW))
1614 regtype = REG_DWORD;
1615 else if (!strcmpW(V_BSTR(type), regexpandszW))
1616 regtype = REG_EXPAND_SZ;
1617 else if (!strcmpW(V_BSTR(type), regbinaryW))
1618 regtype = REG_BINARY;
1619 else {
1620 FIXME("unrecognized value type %s\n", debugstr_w(V_BSTR(type)));
1621 return E_FAIL;
1625 /* it's always a string or a DWORD */
1626 VariantInit(&v);
1627 switch (regtype)
1629 case REG_SZ:
1630 case REG_EXPAND_SZ:
1631 hr = VariantChangeType(&v, value, 0, VT_BSTR);
1632 if (hr == S_OK) {
1633 data = (BYTE*)V_BSTR(&v);
1634 data_len = SysStringByteLen(V_BSTR(&v)) + sizeof(WCHAR);
1636 break;
1637 case REG_DWORD:
1638 case REG_BINARY:
1639 hr = VariantChangeType(&v, value, 0, VT_I4);
1640 data = (BYTE*)&V_I4(&v);
1641 data_len = sizeof(DWORD);
1642 break;
1643 default:
1644 FIXME("unexpected regtype %d\n", regtype);
1645 return E_FAIL;
1648 if (FAILED(hr)) {
1649 FIXME("failed to convert value, regtype %d, 0x%08x\n", regtype, hr);
1650 return hr;
1653 hr = split_reg_path(name, &subkey, &val);
1654 if (FAILED(hr))
1655 goto fail;
1657 ret = RegSetKeyValueW(root, subkey, val, regtype, data, data_len);
1658 if (ret)
1659 hr = HRESULT_FROM_WIN32(ret);
1661 fail:
1662 VariantClear(&v);
1663 if (val)
1664 HeapFree(GetProcessHeap(), 0, subkey);
1665 return hr;
1668 static HRESULT WINAPI WshShell3_RegDelete(IWshShell3 *iface, BSTR Name)
1670 FIXME("(%s): stub\n", debugstr_w(Name));
1671 return E_NOTIMPL;
1674 static HRESULT WINAPI WshShell3_LogEvent(IWshShell3 *iface, VARIANT *Type, BSTR Message, BSTR Target, VARIANT_BOOL *out_Success)
1676 FIXME("(%s %s %s %p): stub\n", debugstr_variant(Type), debugstr_w(Message), debugstr_w(Target), out_Success);
1677 return E_NOTIMPL;
1680 static HRESULT WINAPI WshShell3_AppActivate(IWshShell3 *iface, VARIANT *App, VARIANT *Wait, VARIANT_BOOL *out_Success)
1682 FIXME("(%s %s %p): stub\n", debugstr_variant(App), debugstr_variant(Wait), out_Success);
1683 return E_NOTIMPL;
1686 static HRESULT WINAPI WshShell3_SendKeys(IWshShell3 *iface, BSTR Keys, VARIANT *Wait)
1688 FIXME("(%s %p): stub\n", debugstr_w(Keys), Wait);
1689 return E_NOTIMPL;
1692 static HRESULT WINAPI WshShell3_Exec(IWshShell3 *iface, BSTR command, IWshExec **ret)
1694 TRACE("(%s %p)\n", debugstr_w(command), ret);
1696 if (!ret)
1697 return E_POINTER;
1699 if (!command)
1700 return DISP_E_EXCEPTION;
1702 return WshExec_create(command, ret);
1705 static HRESULT WINAPI WshShell3_get_CurrentDirectory(IWshShell3 *iface, BSTR *dir)
1707 DWORD ret;
1709 TRACE("(%p)\n", dir);
1711 ret = GetCurrentDirectoryW(0, NULL);
1712 if (!ret)
1713 return HRESULT_FROM_WIN32(GetLastError());
1715 *dir = SysAllocStringLen(NULL, ret-1);
1716 if (!*dir)
1717 return E_OUTOFMEMORY;
1719 ret = GetCurrentDirectoryW(ret, *dir);
1720 if (!ret) {
1721 SysFreeString(*dir);
1722 *dir = NULL;
1723 return HRESULT_FROM_WIN32(GetLastError());
1726 return S_OK;
1729 static HRESULT WINAPI WshShell3_put_CurrentDirectory(IWshShell3 *iface, BSTR dir)
1731 TRACE("(%s)\n", debugstr_w(dir));
1733 if (!dir)
1734 return E_INVALIDARG;
1736 if (!SetCurrentDirectoryW(dir))
1737 return HRESULT_FROM_WIN32(GetLastError());
1739 return S_OK;
1742 static const IWshShell3Vtbl WshShell3Vtbl = {
1743 WshShell3_QueryInterface,
1744 WshShell3_AddRef,
1745 WshShell3_Release,
1746 WshShell3_GetTypeInfoCount,
1747 WshShell3_GetTypeInfo,
1748 WshShell3_GetIDsOfNames,
1749 WshShell3_Invoke,
1750 WshShell3_get_SpecialFolders,
1751 WshShell3_get_Environment,
1752 WshShell3_Run,
1753 WshShell3_Popup,
1754 WshShell3_CreateShortcut,
1755 WshShell3_ExpandEnvironmentStrings,
1756 WshShell3_RegRead,
1757 WshShell3_RegWrite,
1758 WshShell3_RegDelete,
1759 WshShell3_LogEvent,
1760 WshShell3_AppActivate,
1761 WshShell3_SendKeys,
1762 WshShell3_Exec,
1763 WshShell3_get_CurrentDirectory,
1764 WshShell3_put_CurrentDirectory
1767 HRESULT WINAPI WshShellFactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
1769 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
1771 WshShell3.IWshShell3_iface.lpVtbl = &WshShell3Vtbl;
1772 init_classinfo(&IID_IWshShell3, (IUnknown *)&WshShell3.IWshShell3_iface, &WshShell3.classinfo);
1773 return IWshShell3_QueryInterface(&WshShell3.IWshShell3_iface, riid, ppv);