Release 1.5.29.
[wine] / dlls / wshom.ocx / shell.c
1 /*
2  * Copyright 2011 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include "wshom_private.h"
20 #include "wshom.h"
21
22 #include "shellapi.h"
23 #include "shlobj.h"
24
25 #include "wine/debug.h"
26 #include "wine/unicode.h"
27
28 WINE_DEFAULT_DEBUG_CHANNEL(wshom);
29
30 static const char *debugstr_variant(const VARIANT *v)
31 {
32     if(!v)
33         return "(null)";
34
35     switch(V_VT(v)) {
36     case VT_EMPTY:
37         return "{VT_EMPTY}";
38     case VT_NULL:
39         return "{VT_NULL}";
40     case VT_I4:
41         return wine_dbg_sprintf("{VT_I4: %d}", V_I4(v));
42     case VT_R8:
43         return wine_dbg_sprintf("{VT_R8: %lf}", V_R8(v));
44     case VT_BSTR:
45         return wine_dbg_sprintf("{VT_BSTR: %s}", debugstr_w(V_BSTR(v)));
46     case VT_DISPATCH:
47         return wine_dbg_sprintf("{VT_DISPATCH: %p}", V_DISPATCH(v));
48     case VT_BOOL:
49         return wine_dbg_sprintf("{VT_BOOL: %x}", V_BOOL(v));
50     case VT_UNKNOWN:
51         return wine_dbg_sprintf("{VT_UNKNOWN: %p}", V_UNKNOWN(v));
52     case VT_UINT:
53         return wine_dbg_sprintf("{VT_UINT: %u}", V_UINT(v));
54     case VT_BSTR|VT_BYREF:
55         return wine_dbg_sprintf("{VT_BSTR|VT_BYREF: ptr %p, data %s}",
56             V_BSTRREF(v), debugstr_w(V_BSTRREF(v) ? *V_BSTRREF(v) : NULL));
57     default:
58         return wine_dbg_sprintf("{vt %d}", V_VT(v));
59     }
60 }
61
62 static IWshShell3 WshShell3;
63
64 typedef struct
65 {
66     IWshCollection IWshCollection_iface;
67     LONG ref;
68 } WshCollection;
69
70 typedef struct
71 {
72     IWshShortcut IWshShortcut_iface;
73     LONG ref;
74
75     IShellLinkW *link;
76     BSTR path_link;
77 } WshShortcut;
78
79 static inline WshCollection *impl_from_IWshCollection( IWshCollection *iface )
80 {
81     return CONTAINING_RECORD(iface, WshCollection, IWshCollection_iface);
82 }
83
84 static inline WshShortcut *impl_from_IWshShortcut( IWshShortcut *iface )
85 {
86     return CONTAINING_RECORD(iface, WshShortcut, IWshShortcut_iface);
87 }
88
89 static HRESULT WINAPI WshCollection_QueryInterface(IWshCollection *iface, REFIID riid, void **ppv)
90 {
91     WshCollection *This = impl_from_IWshCollection(iface);
92
93     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
94
95     if (IsEqualGUID(riid, &IID_IUnknown)  ||
96         IsEqualGUID(riid, &IID_IDispatch) ||
97         IsEqualGUID(riid, &IID_IWshCollection))
98     {
99         *ppv = iface;
100     }else {
101         FIXME("Unknown iface %s\n", debugstr_guid(riid));
102         *ppv = NULL;
103         return E_NOINTERFACE;
104     }
105
106     IUnknown_AddRef((IUnknown*)*ppv);
107     return S_OK;
108 }
109
110 static ULONG WINAPI WshCollection_AddRef(IWshCollection *iface)
111 {
112     WshCollection *This = impl_from_IWshCollection(iface);
113     LONG ref = InterlockedIncrement(&This->ref);
114     TRACE("(%p) ref = %d\n", This, ref);
115     return ref;
116 }
117
118 static ULONG WINAPI WshCollection_Release(IWshCollection *iface)
119 {
120     WshCollection *This = impl_from_IWshCollection(iface);
121     LONG ref = InterlockedDecrement(&This->ref);
122     TRACE("(%p) ref = %d\n", This, ref);
123
124     if (!ref)
125         HeapFree(GetProcessHeap(), 0, This);
126
127     return ref;
128 }
129
130 static HRESULT WINAPI WshCollection_GetTypeInfoCount(IWshCollection *iface, UINT *pctinfo)
131 {
132     WshCollection *This = impl_from_IWshCollection(iface);
133     TRACE("(%p)->(%p)\n", This, pctinfo);
134     *pctinfo = 1;
135     return S_OK;
136 }
137
138 static HRESULT WINAPI WshCollection_GetTypeInfo(IWshCollection *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
139 {
140     WshCollection *This = impl_from_IWshCollection(iface);
141     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
142     return get_typeinfo(IWshCollection_tid, ppTInfo);
143 }
144
145 static HRESULT WINAPI WshCollection_GetIDsOfNames(IWshCollection *iface, REFIID riid, LPOLESTR *rgszNames,
146         UINT cNames, LCID lcid, DISPID *rgDispId)
147 {
148     WshCollection *This = impl_from_IWshCollection(iface);
149     ITypeInfo *typeinfo;
150     HRESULT hr;
151
152     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
153
154     hr = get_typeinfo(IWshCollection_tid, &typeinfo);
155     if(SUCCEEDED(hr))
156     {
157         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
158         ITypeInfo_Release(typeinfo);
159     }
160
161     return hr;
162 }
163
164 static HRESULT WINAPI WshCollection_Invoke(IWshCollection *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
165         WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
166 {
167     WshCollection *This = impl_from_IWshCollection(iface);
168     ITypeInfo *typeinfo;
169     HRESULT hr;
170
171     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
172           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
173
174     hr = get_typeinfo(IWshCollection_tid, &typeinfo);
175     if(SUCCEEDED(hr))
176     {
177         hr = ITypeInfo_Invoke(typeinfo, &This->IWshCollection_iface, dispIdMember, wFlags,
178                 pDispParams, pVarResult, pExcepInfo, puArgErr);
179         ITypeInfo_Release(typeinfo);
180     }
181
182     return hr;
183 }
184
185 static HRESULT WINAPI WshCollection_Item(IWshCollection *iface, VARIANT *index, VARIANT *value)
186 {
187     WshCollection *This = impl_from_IWshCollection(iface);
188     static const WCHAR allusersdesktopW[] = {'A','l','l','U','s','e','r','s','D','e','s','k','t','o','p',0};
189     static const WCHAR allusersprogramsW[] = {'A','l','l','U','s','e','r','s','P','r','o','g','r','a','m','s',0};
190     static const WCHAR desktopW[] = {'D','e','s','k','t','o','p',0};
191     PIDLIST_ABSOLUTE pidl;
192     WCHAR pathW[MAX_PATH];
193     int kind = 0;
194     BSTR folder;
195     HRESULT hr;
196
197     TRACE("(%p)->(%s %p)\n", This, debugstr_variant(index), value);
198
199     if (V_VT(index) != VT_BSTR)
200     {
201         FIXME("only BSTR index supported, got %d\n", V_VT(index));
202         return E_NOTIMPL;
203     }
204
205     folder = V_BSTR(index);
206     if (!strcmpiW(folder, desktopW))
207         kind = CSIDL_DESKTOP;
208     else if (!strcmpiW(folder, allusersdesktopW))
209         kind = CSIDL_COMMON_DESKTOPDIRECTORY;
210     else if (!strcmpiW(folder, allusersprogramsW))
211         kind = CSIDL_COMMON_PROGRAMS;
212     else
213     {
214         FIXME("folder kind %s not supported\n", debugstr_w(folder));
215         return E_NOTIMPL;
216     }
217
218     hr = SHGetSpecialFolderLocation(NULL, kind, &pidl);
219     if (hr != S_OK) return hr;
220
221     if (SHGetPathFromIDListW(pidl, pathW))
222     {
223         V_VT(value) = VT_BSTR;
224         V_BSTR(value) = SysAllocString(pathW);
225         hr = V_BSTR(value) ? S_OK : E_OUTOFMEMORY;
226     }
227     else
228         hr = E_FAIL;
229
230     CoTaskMemFree(pidl);
231
232     return hr;
233 }
234
235 static HRESULT WINAPI WshCollection_Count(IWshCollection *iface, LONG *count)
236 {
237     WshCollection *This = impl_from_IWshCollection(iface);
238     FIXME("(%p)->(%p): stub\n", This, count);
239     return E_NOTIMPL;
240 }
241
242 static HRESULT WINAPI WshCollection_get_length(IWshCollection *iface, LONG *count)
243 {
244     WshCollection *This = impl_from_IWshCollection(iface);
245     FIXME("(%p)->(%p): stub\n", This, count);
246     return E_NOTIMPL;
247 }
248
249 static HRESULT WINAPI WshCollection__NewEnum(IWshCollection *iface, IUnknown *Enum)
250 {
251     WshCollection *This = impl_from_IWshCollection(iface);
252     FIXME("(%p)->(%p): stub\n", This, Enum);
253     return E_NOTIMPL;
254 }
255
256 static const IWshCollectionVtbl WshCollectionVtbl = {
257     WshCollection_QueryInterface,
258     WshCollection_AddRef,
259     WshCollection_Release,
260     WshCollection_GetTypeInfoCount,
261     WshCollection_GetTypeInfo,
262     WshCollection_GetIDsOfNames,
263     WshCollection_Invoke,
264     WshCollection_Item,
265     WshCollection_Count,
266     WshCollection_get_length,
267     WshCollection__NewEnum
268 };
269
270 static HRESULT WshCollection_Create(IWshCollection **collection)
271 {
272     WshCollection *This;
273
274     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
275     if (!This) return E_OUTOFMEMORY;
276
277     This->IWshCollection_iface.lpVtbl = &WshCollectionVtbl;
278     This->ref = 1;
279
280     *collection = &This->IWshCollection_iface;
281
282     return S_OK;
283 }
284
285 /* IWshShortcut */
286 static HRESULT WINAPI WshShortcut_QueryInterface(IWshShortcut *iface, REFIID riid, void **ppv)
287 {
288     WshShortcut *This = impl_from_IWshShortcut(iface);
289
290     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
291
292     if (IsEqualGUID(riid, &IID_IUnknown)  ||
293         IsEqualGUID(riid, &IID_IDispatch) ||
294         IsEqualGUID(riid, &IID_IWshShortcut))
295     {
296         *ppv = iface;
297     }else {
298         FIXME("Unknown iface %s\n", debugstr_guid(riid));
299         *ppv = NULL;
300         return E_NOINTERFACE;
301     }
302
303     IUnknown_AddRef((IUnknown*)*ppv);
304     return S_OK;
305 }
306
307 static ULONG WINAPI WshShortcut_AddRef(IWshShortcut *iface)
308 {
309     WshShortcut *This = impl_from_IWshShortcut(iface);
310     LONG ref = InterlockedIncrement(&This->ref);
311     TRACE("(%p) ref = %d\n", This, ref);
312     return ref;
313 }
314
315 static ULONG WINAPI WshShortcut_Release(IWshShortcut *iface)
316 {
317     WshShortcut *This = impl_from_IWshShortcut(iface);
318     LONG ref = InterlockedDecrement(&This->ref);
319     TRACE("(%p) ref = %d\n", This, ref);
320
321     if (!ref)
322     {
323         SysFreeString(This->path_link);
324         IShellLinkW_Release(This->link);
325         HeapFree(GetProcessHeap(), 0, This);
326     }
327
328     return ref;
329 }
330
331 static HRESULT WINAPI WshShortcut_GetTypeInfoCount(IWshShortcut *iface, UINT *pctinfo)
332 {
333     WshShortcut *This = impl_from_IWshShortcut(iface);
334     TRACE("(%p)->(%p)\n", This, pctinfo);
335     *pctinfo = 1;
336     return S_OK;
337 }
338
339 static HRESULT WINAPI WshShortcut_GetTypeInfo(IWshShortcut *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
340 {
341     WshShortcut *This = impl_from_IWshShortcut(iface);
342     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
343     return get_typeinfo(IWshShortcut_tid, ppTInfo);
344 }
345
346 static HRESULT WINAPI WshShortcut_GetIDsOfNames(IWshShortcut *iface, REFIID riid, LPOLESTR *rgszNames,
347         UINT cNames, LCID lcid, DISPID *rgDispId)
348 {
349     WshShortcut *This = impl_from_IWshShortcut(iface);
350     ITypeInfo *typeinfo;
351     HRESULT hr;
352
353     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
354
355     hr = get_typeinfo(IWshShortcut_tid, &typeinfo);
356     if(SUCCEEDED(hr))
357     {
358         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
359         ITypeInfo_Release(typeinfo);
360     }
361
362     return hr;
363 }
364
365 static HRESULT WINAPI WshShortcut_Invoke(IWshShortcut *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
366         WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
367 {
368     WshShortcut *This = impl_from_IWshShortcut(iface);
369     ITypeInfo *typeinfo;
370     HRESULT hr;
371
372     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
373           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
374
375     hr = get_typeinfo(IWshShortcut_tid, &typeinfo);
376     if(SUCCEEDED(hr))
377     {
378         hr = ITypeInfo_Invoke(typeinfo, &This->IWshShortcut_iface, dispIdMember, wFlags,
379                 pDispParams, pVarResult, pExcepInfo, puArgErr);
380         ITypeInfo_Release(typeinfo);
381     }
382
383     return hr;
384 }
385
386 static HRESULT WINAPI WshShortcut_get_FullName(IWshShortcut *iface, BSTR *name)
387 {
388     WshShortcut *This = impl_from_IWshShortcut(iface);
389     FIXME("(%p)->(%p): stub\n", This, name);
390     return E_NOTIMPL;
391 }
392
393 static HRESULT WINAPI WshShortcut_get_Arguments(IWshShortcut *iface, BSTR *Arguments)
394 {
395     WshShortcut *This = impl_from_IWshShortcut(iface);
396     FIXME("(%p)->(%p): stub\n", This, Arguments);
397     return E_NOTIMPL;
398 }
399
400 static HRESULT WINAPI WshShortcut_put_Arguments(IWshShortcut *iface, BSTR Arguments)
401 {
402     WshShortcut *This = impl_from_IWshShortcut(iface);
403     FIXME("(%p)->(%s): stub\n", This, debugstr_w(Arguments));
404     return E_NOTIMPL;
405 }
406
407 static HRESULT WINAPI WshShortcut_get_Description(IWshShortcut *iface, BSTR *Description)
408 {
409     WshShortcut *This = impl_from_IWshShortcut(iface);
410     FIXME("(%p)->(%p): stub\n", This, Description);
411     return E_NOTIMPL;
412 }
413
414 static HRESULT WINAPI WshShortcut_put_Description(IWshShortcut *iface, BSTR Description)
415 {
416     WshShortcut *This = impl_from_IWshShortcut(iface);
417     TRACE("(%p)->(%s)\n", This, debugstr_w(Description));
418     return IShellLinkW_SetDescription(This->link, Description);
419 }
420
421 static HRESULT WINAPI WshShortcut_get_Hotkey(IWshShortcut *iface, BSTR *Hotkey)
422 {
423     WshShortcut *This = impl_from_IWshShortcut(iface);
424     FIXME("(%p)->(%p): stub\n", This, Hotkey);
425     return E_NOTIMPL;
426 }
427
428 static HRESULT WINAPI WshShortcut_put_Hotkey(IWshShortcut *iface, BSTR Hotkey)
429 {
430     WshShortcut *This = impl_from_IWshShortcut(iface);
431     FIXME("(%p)->(%s): stub\n", This, debugstr_w(Hotkey));
432     return E_NOTIMPL;
433 }
434
435 static HRESULT WINAPI WshShortcut_get_IconLocation(IWshShortcut *iface, BSTR *IconPath)
436 {
437     WshShortcut *This = impl_from_IWshShortcut(iface);
438     FIXME("(%p)->(%p): stub\n", This, IconPath);
439     return E_NOTIMPL;
440 }
441
442 static HRESULT WINAPI WshShortcut_put_IconLocation(IWshShortcut *iface, BSTR IconPath)
443 {
444     WshShortcut *This = impl_from_IWshShortcut(iface);
445     FIXME("(%p)->(%s): stub\n", This, debugstr_w(IconPath));
446     return E_NOTIMPL;
447 }
448
449 static HRESULT WINAPI WshShortcut_put_RelativePath(IWshShortcut *iface, BSTR rhs)
450 {
451     WshShortcut *This = impl_from_IWshShortcut(iface);
452     FIXME("(%p)->(%s): stub\n", This, debugstr_w(rhs));
453     return E_NOTIMPL;
454 }
455
456 static HRESULT WINAPI WshShortcut_get_TargetPath(IWshShortcut *iface, BSTR *Path)
457 {
458     WshShortcut *This = impl_from_IWshShortcut(iface);
459     FIXME("(%p)->(%p): stub\n", This, Path);
460     return E_NOTIMPL;
461 }
462
463 static HRESULT WINAPI WshShortcut_put_TargetPath(IWshShortcut *iface, BSTR Path)
464 {
465     WshShortcut *This = impl_from_IWshShortcut(iface);
466     TRACE("(%p)->(%s)\n", This, debugstr_w(Path));
467     return IShellLinkW_SetPath(This->link, Path);
468 }
469
470 static HRESULT WINAPI WshShortcut_get_WindowStyle(IWshShortcut *iface, int *ShowCmd)
471 {
472     WshShortcut *This = impl_from_IWshShortcut(iface);
473     TRACE("(%p)->(%p)\n", This, ShowCmd);
474     return IShellLinkW_GetShowCmd(This->link, ShowCmd);
475 }
476
477 static HRESULT WINAPI WshShortcut_put_WindowStyle(IWshShortcut *iface, int ShowCmd)
478 {
479     WshShortcut *This = impl_from_IWshShortcut(iface);
480     TRACE("(%p)->(%d)\n", This, ShowCmd);
481     return IShellLinkW_SetShowCmd(This->link, ShowCmd);
482 }
483
484 static HRESULT WINAPI WshShortcut_get_WorkingDirectory(IWshShortcut *iface, BSTR *WorkingDirectory)
485 {
486     WshShortcut *This = impl_from_IWshShortcut(iface);
487     FIXME("(%p)->(%p): stub\n", This, WorkingDirectory);
488     return E_NOTIMPL;
489 }
490
491 static HRESULT WINAPI WshShortcut_put_WorkingDirectory(IWshShortcut *iface, BSTR WorkingDirectory)
492 {
493     WshShortcut *This = impl_from_IWshShortcut(iface);
494     TRACE("(%p)->(%s): stub\n", This, debugstr_w(WorkingDirectory));
495     return IShellLinkW_SetWorkingDirectory(This->link, WorkingDirectory);
496 }
497
498 static HRESULT WINAPI WshShortcut_Load(IWshShortcut *iface, BSTR PathLink)
499 {
500     WshShortcut *This = impl_from_IWshShortcut(iface);
501     FIXME("(%p)->(%s): stub\n", This, debugstr_w(PathLink));
502     return E_NOTIMPL;
503 }
504
505 static HRESULT WINAPI WshShortcut_Save(IWshShortcut *iface)
506 {
507     WshShortcut *This = impl_from_IWshShortcut(iface);
508     IPersistFile *file;
509     HRESULT hr;
510
511     TRACE("(%p)\n", This);
512
513     IShellLinkW_QueryInterface(This->link, &IID_IPersistFile, (void**)&file);
514     hr = IPersistFile_Save(file, This->path_link, TRUE);
515     IPersistFile_Release(file);
516
517     return hr;
518 }
519
520 static const IWshShortcutVtbl WshShortcutVtbl = {
521     WshShortcut_QueryInterface,
522     WshShortcut_AddRef,
523     WshShortcut_Release,
524     WshShortcut_GetTypeInfoCount,
525     WshShortcut_GetTypeInfo,
526     WshShortcut_GetIDsOfNames,
527     WshShortcut_Invoke,
528     WshShortcut_get_FullName,
529     WshShortcut_get_Arguments,
530     WshShortcut_put_Arguments,
531     WshShortcut_get_Description,
532     WshShortcut_put_Description,
533     WshShortcut_get_Hotkey,
534     WshShortcut_put_Hotkey,
535     WshShortcut_get_IconLocation,
536     WshShortcut_put_IconLocation,
537     WshShortcut_put_RelativePath,
538     WshShortcut_get_TargetPath,
539     WshShortcut_put_TargetPath,
540     WshShortcut_get_WindowStyle,
541     WshShortcut_put_WindowStyle,
542     WshShortcut_get_WorkingDirectory,
543     WshShortcut_put_WorkingDirectory,
544     WshShortcut_Load,
545     WshShortcut_Save
546 };
547
548 static HRESULT WshShortcut_Create(const WCHAR *path, IDispatch **shortcut)
549 {
550     WshShortcut *This;
551     HRESULT hr;
552
553     *shortcut = NULL;
554
555     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
556     if (!This) return E_OUTOFMEMORY;
557
558     This->IWshShortcut_iface.lpVtbl = &WshShortcutVtbl;
559     This->ref = 1;
560
561     hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
562             &IID_IShellLinkW, (void**)&This->link);
563     if (FAILED(hr))
564     {
565         HeapFree(GetProcessHeap(), 0, This);
566         return hr;
567     }
568
569     This->path_link = SysAllocString(path);
570     *shortcut = (IDispatch*)&This->IWshShortcut_iface;
571
572     return S_OK;
573 }
574
575 static HRESULT WINAPI WshShell3_QueryInterface(IWshShell3 *iface, REFIID riid, void **ppv)
576 {
577     TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
578
579     if(IsEqualGUID(riid, &IID_IUnknown)  ||
580        IsEqualGUID(riid, &IID_IDispatch) ||
581        IsEqualGUID(riid, &IID_IWshShell3))
582     {
583         *ppv = iface;
584     }else {
585         FIXME("Unknown iface %s\n", debugstr_guid(riid));
586         *ppv = NULL;
587         return E_NOINTERFACE;
588     }
589
590     IWshShell3_AddRef(iface);
591     return S_OK;
592 }
593
594 static ULONG WINAPI WshShell3_AddRef(IWshShell3 *iface)
595 {
596     TRACE("()\n");
597     return 2;
598 }
599
600 static ULONG WINAPI WshShell3_Release(IWshShell3 *iface)
601 {
602     TRACE("()\n");
603     return 2;
604 }
605
606 static HRESULT WINAPI WshShell3_GetTypeInfoCount(IWshShell3 *iface, UINT *pctinfo)
607 {
608     TRACE("(%p)\n", pctinfo);
609     *pctinfo = 1;
610     return S_OK;
611 }
612
613 static HRESULT WINAPI WshShell3_GetTypeInfo(IWshShell3 *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
614 {
615     TRACE("(%u %u %p)\n", iTInfo, lcid, ppTInfo);
616     return get_typeinfo(IWshShell3_tid, ppTInfo);
617 }
618
619 static HRESULT WINAPI WshShell3_GetIDsOfNames(IWshShell3 *iface, REFIID riid, LPOLESTR *rgszNames,
620         UINT cNames, LCID lcid, DISPID *rgDispId)
621 {
622     ITypeInfo *typeinfo;
623     HRESULT hr;
624
625     TRACE("(%s %p %u %u %p)\n", debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
626
627     hr = get_typeinfo(IWshShell3_tid, &typeinfo);
628     if(SUCCEEDED(hr))
629     {
630         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
631         ITypeInfo_Release(typeinfo);
632     }
633
634     return hr;
635 }
636
637 static HRESULT WINAPI WshShell3_Invoke(IWshShell3 *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
638         WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
639 {
640     ITypeInfo *typeinfo;
641     HRESULT hr;
642
643     TRACE("(%d %s %d %d %p %p %p %p)\n", dispIdMember, debugstr_guid(riid),
644           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
645
646     hr = get_typeinfo(IWshShell3_tid, &typeinfo);
647     if(SUCCEEDED(hr))
648     {
649         hr = ITypeInfo_Invoke(typeinfo, &WshShell3, dispIdMember, wFlags,
650                 pDispParams, pVarResult, pExcepInfo, puArgErr);
651         ITypeInfo_Release(typeinfo);
652     }
653
654     return hr;
655 }
656
657 static HRESULT WINAPI WshShell3_get_SpecialFolders(IWshShell3 *iface, IWshCollection **folders)
658 {
659     TRACE("(%p)\n", folders);
660     return WshCollection_Create(folders);
661 }
662
663 static HRESULT WINAPI WshShell3_get_Environment(IWshShell3 *iface, VARIANT *Type, IWshEnvironment **out_Env)
664 {
665     FIXME("(%p %p): stub\n", Type, out_Env);
666     return E_NOTIMPL;
667 }
668
669 static HRESULT WINAPI WshShell3_Run(IWshShell3 *iface, BSTR cmd, VARIANT *style, VARIANT *WaitOnReturn, int *exit_code)
670 {
671     SHELLEXECUTEINFOW info;
672     int waitforprocess;
673     VARIANT s, w;
674     HRESULT hr;
675
676     TRACE("(%s %s %s %p)\n", debugstr_w(cmd), debugstr_variant(style), debugstr_variant(WaitOnReturn), exit_code);
677
678     VariantInit(&s);
679     hr = VariantChangeType(&s, style, 0, VT_I4);
680     if (FAILED(hr))
681     {
682         ERR("failed to convert style argument, 0x%08x\n", hr);
683         return hr;
684     }
685
686     VariantInit(&w);
687     hr = VariantChangeType(&w, WaitOnReturn, 0, VT_I4);
688     if (FAILED(hr))
689     {
690         ERR("failed to convert wait argument, 0x%08x\n", hr);
691         return hr;
692     }
693
694     memset(&info, 0, sizeof(info));
695     info.cbSize = sizeof(info);
696
697     waitforprocess = V_I4(&w);
698
699     info.fMask = waitforprocess ? SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS : SEE_MASK_DEFAULT;
700     info.lpFile = cmd;
701     info.nShow = V_I4(&s);
702
703     if (!ShellExecuteExW(&info))
704     {
705         TRACE("ShellExecute failed, %d\n", GetLastError());
706         return HRESULT_FROM_WIN32(GetLastError());
707     }
708     else
709     {
710         if (waitforprocess)
711         {
712             if (exit_code)
713             {
714                 DWORD code;
715                 GetExitCodeProcess(info.hProcess, &code);
716                 *exit_code = code;
717             }
718             CloseHandle(info.hProcess);
719         }
720         else
721             if (exit_code) *exit_code = 0;
722
723         return S_OK;
724     }
725 }
726
727 static HRESULT WINAPI WshShell3_Popup(IWshShell3 *iface, BSTR Text, VARIANT* SecondsToWait, VARIANT *Title, VARIANT *Type, int *button)
728 {
729     FIXME("(%s %s %s %s %p): stub\n", debugstr_w(Text), debugstr_variant(SecondsToWait),
730         debugstr_variant(Title), debugstr_variant(Type), button);
731     return E_NOTIMPL;
732 }
733
734 static HRESULT WINAPI WshShell3_CreateShortcut(IWshShell3 *iface, BSTR PathLink, IDispatch** Shortcut)
735 {
736     TRACE("(%s %p)\n", debugstr_w(PathLink), Shortcut);
737     return WshShortcut_Create(PathLink, Shortcut);
738 }
739
740 static HRESULT WINAPI WshShell3_ExpandEnvironmentStrings(IWshShell3 *iface, BSTR Src, BSTR* out_Dst)
741 {
742     FIXME("(%s %p): stub\n", debugstr_w(Src), out_Dst);
743     return E_NOTIMPL;
744 }
745
746 static HRESULT WINAPI WshShell3_RegRead(IWshShell3 *iface, BSTR Name, VARIANT* out_Value)
747 {
748     FIXME("(%s %p): stub\n", debugstr_w(Name), out_Value);
749     return E_NOTIMPL;
750 }
751
752 static HRESULT WINAPI WshShell3_RegWrite(IWshShell3 *iface, BSTR Name, VARIANT *Value, VARIANT *Type)
753 {
754     FIXME("(%s %s %s): stub\n", debugstr_w(Name), debugstr_variant(Value), debugstr_variant(Type));
755     return E_NOTIMPL;
756 }
757
758 static HRESULT WINAPI WshShell3_RegDelete(IWshShell3 *iface, BSTR Name)
759 {
760     FIXME("(%s): stub\n", debugstr_w(Name));
761     return E_NOTIMPL;
762 }
763
764 static HRESULT WINAPI WshShell3_LogEvent(IWshShell3 *iface, VARIANT *Type, BSTR Message, BSTR Target, VARIANT_BOOL *out_Success)
765 {
766     FIXME("(%s %s %s %p): stub\n", debugstr_variant(Type), debugstr_w(Message), debugstr_w(Target), out_Success);
767     return E_NOTIMPL;
768 }
769
770 static HRESULT WINAPI WshShell3_AppActivate(IWshShell3 *iface, VARIANT *App, VARIANT *Wait, VARIANT_BOOL *out_Success)
771 {
772     FIXME("(%s %s %p): stub\n", debugstr_variant(App), debugstr_variant(Wait), out_Success);
773     return E_NOTIMPL;
774 }
775
776 static HRESULT WINAPI WshShell3_SendKeys(IWshShell3 *iface, BSTR Keys, VARIANT *Wait)
777 {
778     FIXME("(%s %p): stub\n", debugstr_w(Keys), Wait);
779     return E_NOTIMPL;
780 }
781
782 static const IWshShell3Vtbl WshShell3Vtbl = {
783     WshShell3_QueryInterface,
784     WshShell3_AddRef,
785     WshShell3_Release,
786     WshShell3_GetTypeInfoCount,
787     WshShell3_GetTypeInfo,
788     WshShell3_GetIDsOfNames,
789     WshShell3_Invoke,
790     WshShell3_get_SpecialFolders,
791     WshShell3_get_Environment,
792     WshShell3_Run,
793     WshShell3_Popup,
794     WshShell3_CreateShortcut,
795     WshShell3_ExpandEnvironmentStrings,
796     WshShell3_RegRead,
797     WshShell3_RegWrite,
798     WshShell3_RegDelete,
799     WshShell3_LogEvent,
800     WshShell3_AppActivate,
801     WshShell3_SendKeys
802 };
803
804 static IWshShell3 WshShell3 = { &WshShell3Vtbl };
805
806 HRESULT WINAPI WshShellFactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
807 {
808     TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
809
810     return IWshShell3_QueryInterface(&WshShell3, riid, ppv);
811 }