* Sync up to trunk head (r65481).
[reactos.git] / dll / win32 / 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
21 #include <shellapi.h>
22 #include <shlobj.h>
23 #include <dispex.h>
24
25 #include <wine/unicode.h>
26
27 static IWshShell3 WshShell3;
28
29 typedef struct
30 {
31 IWshCollection IWshCollection_iface;
32 LONG ref;
33 } WshCollection;
34
35 typedef struct
36 {
37 IWshShortcut IWshShortcut_iface;
38 LONG ref;
39
40 IShellLinkW *link;
41 BSTR path_link;
42 } WshShortcut;
43
44 typedef struct
45 {
46 IWshEnvironment IWshEnvironment_iface;
47 LONG ref;
48 } WshEnvironment;
49
50 static inline WshCollection *impl_from_IWshCollection( IWshCollection *iface )
51 {
52 return CONTAINING_RECORD(iface, WshCollection, IWshCollection_iface);
53 }
54
55 static inline WshShortcut *impl_from_IWshShortcut( IWshShortcut *iface )
56 {
57 return CONTAINING_RECORD(iface, WshShortcut, IWshShortcut_iface);
58 }
59
60 static inline WshEnvironment *impl_from_IWshEnvironment( IWshEnvironment *iface )
61 {
62 return CONTAINING_RECORD(iface, WshEnvironment, IWshEnvironment_iface);
63 }
64
65 static HRESULT WINAPI WshEnvironment_QueryInterface(IWshEnvironment *iface, REFIID riid, void **obj)
66 {
67 WshEnvironment *This = impl_from_IWshEnvironment(iface);
68
69 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), obj);
70
71 if (IsEqualGUID(riid, &IID_IUnknown) ||
72 IsEqualGUID(riid, &IID_IDispatch) ||
73 IsEqualGUID(riid, &IID_IWshEnvironment))
74 {
75 *obj = iface;
76 }else {
77 FIXME("Unknown iface %s\n", debugstr_guid(riid));
78 *obj = NULL;
79 return E_NOINTERFACE;
80 }
81
82 IUnknown_AddRef((IUnknown*)*obj);
83 return S_OK;
84 }
85
86 static ULONG WINAPI WshEnvironment_AddRef(IWshEnvironment *iface)
87 {
88 WshEnvironment *This = impl_from_IWshEnvironment(iface);
89 LONG ref = InterlockedIncrement(&This->ref);
90 TRACE("(%p) ref = %d\n", This, ref);
91 return ref;
92 }
93
94 static ULONG WINAPI WshEnvironment_Release(IWshEnvironment *iface)
95 {
96 WshEnvironment *This = impl_from_IWshEnvironment(iface);
97 LONG ref = InterlockedDecrement(&This->ref);
98 TRACE("(%p) ref = %d\n", This, ref);
99
100 if (!ref)
101 HeapFree(GetProcessHeap(), 0, This);
102
103 return ref;
104 }
105
106 static HRESULT WINAPI WshEnvironment_GetTypeInfoCount(IWshEnvironment *iface, UINT *pctinfo)
107 {
108 WshEnvironment *This = impl_from_IWshEnvironment(iface);
109 TRACE("(%p)->(%p)\n", This, pctinfo);
110 *pctinfo = 1;
111 return S_OK;
112 }
113
114 static HRESULT WINAPI WshEnvironment_GetTypeInfo(IWshEnvironment *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
115 {
116 WshEnvironment *This = impl_from_IWshEnvironment(iface);
117 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
118 return get_typeinfo(IWshEnvironment_tid, ppTInfo);
119 }
120
121 static HRESULT WINAPI WshEnvironment_GetIDsOfNames(IWshEnvironment *iface, REFIID riid, LPOLESTR *rgszNames,
122 UINT cNames, LCID lcid, DISPID *rgDispId)
123 {
124 WshEnvironment *This = impl_from_IWshEnvironment(iface);
125 ITypeInfo *typeinfo;
126 HRESULT hr;
127
128 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
129
130 hr = get_typeinfo(IWshEnvironment_tid, &typeinfo);
131 if(SUCCEEDED(hr))
132 {
133 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
134 ITypeInfo_Release(typeinfo);
135 }
136
137 return hr;
138 }
139
140 static HRESULT WINAPI WshEnvironment_Invoke(IWshEnvironment *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
141 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
142 {
143 WshEnvironment *This = impl_from_IWshEnvironment(iface);
144 ITypeInfo *typeinfo;
145 HRESULT hr;
146
147 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
148 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
149
150 hr = get_typeinfo(IWshEnvironment_tid, &typeinfo);
151 if(SUCCEEDED(hr))
152 {
153 hr = ITypeInfo_Invoke(typeinfo, &This->IWshEnvironment_iface, dispIdMember, wFlags,
154 pDispParams, pVarResult, pExcepInfo, puArgErr);
155 ITypeInfo_Release(typeinfo);
156 }
157
158 return hr;
159 }
160
161 static HRESULT WINAPI WshEnvironment_get_Item(IWshEnvironment *iface, BSTR name, BSTR *value)
162 {
163 WshEnvironment *This = impl_from_IWshEnvironment(iface);
164 DWORD len;
165
166 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), value);
167
168 if (!value)
169 return E_POINTER;
170
171 len = GetEnvironmentVariableW(name, NULL, 0);
172 *value = SysAllocStringLen(NULL, len);
173 if (!*value)
174 return E_OUTOFMEMORY;
175
176 if (len)
177 GetEnvironmentVariableW(name, *value, len+1);
178
179 return S_OK;
180 }
181
182 static HRESULT WINAPI WshEnvironment_put_Item(IWshEnvironment *iface, BSTR name, BSTR value)
183 {
184 WshEnvironment *This = impl_from_IWshEnvironment(iface);
185 FIXME("(%p)->(%s %s): stub\n", This, debugstr_w(name), debugstr_w(value));
186 return E_NOTIMPL;
187 }
188
189 static HRESULT WINAPI WshEnvironment_Count(IWshEnvironment *iface, LONG *count)
190 {
191 WshEnvironment *This = impl_from_IWshEnvironment(iface);
192 FIXME("(%p)->(%p): stub\n", This, count);
193 return E_NOTIMPL;
194 }
195
196 static HRESULT WINAPI WshEnvironment_get_length(IWshEnvironment *iface, LONG *len)
197 {
198 WshEnvironment *This = impl_from_IWshEnvironment(iface);
199 FIXME("(%p)->(%p): stub\n", This, len);
200 return E_NOTIMPL;
201 }
202
203 static HRESULT WINAPI WshEnvironment__NewEnum(IWshEnvironment *iface, IUnknown **penum)
204 {
205 WshEnvironment *This = impl_from_IWshEnvironment(iface);
206 FIXME("(%p)->(%p): stub\n", This, penum);
207 return E_NOTIMPL;
208 }
209
210 static HRESULT WINAPI WshEnvironment_Remove(IWshEnvironment *iface, BSTR name)
211 {
212 WshEnvironment *This = impl_from_IWshEnvironment(iface);
213 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
214 return E_NOTIMPL;
215 }
216
217 static const IWshEnvironmentVtbl WshEnvironmentVtbl = {
218 WshEnvironment_QueryInterface,
219 WshEnvironment_AddRef,
220 WshEnvironment_Release,
221 WshEnvironment_GetTypeInfoCount,
222 WshEnvironment_GetTypeInfo,
223 WshEnvironment_GetIDsOfNames,
224 WshEnvironment_Invoke,
225 WshEnvironment_get_Item,
226 WshEnvironment_put_Item,
227 WshEnvironment_Count,
228 WshEnvironment_get_length,
229 WshEnvironment__NewEnum,
230 WshEnvironment_Remove
231 };
232
233 static HRESULT WshEnvironment_Create(IWshEnvironment **env)
234 {
235 WshEnvironment *This;
236
237 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
238 if (!This) return E_OUTOFMEMORY;
239
240 This->IWshEnvironment_iface.lpVtbl = &WshEnvironmentVtbl;
241 This->ref = 1;
242
243 *env = &This->IWshEnvironment_iface;
244
245 return S_OK;
246 }
247
248 static HRESULT WINAPI WshCollection_QueryInterface(IWshCollection *iface, REFIID riid, void **ppv)
249 {
250 WshCollection *This = impl_from_IWshCollection(iface);
251
252 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
253
254 if (IsEqualGUID(riid, &IID_IUnknown) ||
255 IsEqualGUID(riid, &IID_IDispatch) ||
256 IsEqualGUID(riid, &IID_IWshCollection))
257 {
258 *ppv = iface;
259 }else {
260 FIXME("Unknown iface %s\n", debugstr_guid(riid));
261 *ppv = NULL;
262 return E_NOINTERFACE;
263 }
264
265 IUnknown_AddRef((IUnknown*)*ppv);
266 return S_OK;
267 }
268
269 static ULONG WINAPI WshCollection_AddRef(IWshCollection *iface)
270 {
271 WshCollection *This = impl_from_IWshCollection(iface);
272 LONG ref = InterlockedIncrement(&This->ref);
273 TRACE("(%p) ref = %d\n", This, ref);
274 return ref;
275 }
276
277 static ULONG WINAPI WshCollection_Release(IWshCollection *iface)
278 {
279 WshCollection *This = impl_from_IWshCollection(iface);
280 LONG ref = InterlockedDecrement(&This->ref);
281 TRACE("(%p) ref = %d\n", This, ref);
282
283 if (!ref)
284 HeapFree(GetProcessHeap(), 0, This);
285
286 return ref;
287 }
288
289 static HRESULT WINAPI WshCollection_GetTypeInfoCount(IWshCollection *iface, UINT *pctinfo)
290 {
291 WshCollection *This = impl_from_IWshCollection(iface);
292 TRACE("(%p)->(%p)\n", This, pctinfo);
293 *pctinfo = 1;
294 return S_OK;
295 }
296
297 static HRESULT WINAPI WshCollection_GetTypeInfo(IWshCollection *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
298 {
299 WshCollection *This = impl_from_IWshCollection(iface);
300 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
301 return get_typeinfo(IWshCollection_tid, ppTInfo);
302 }
303
304 static HRESULT WINAPI WshCollection_GetIDsOfNames(IWshCollection *iface, REFIID riid, LPOLESTR *rgszNames,
305 UINT cNames, LCID lcid, DISPID *rgDispId)
306 {
307 WshCollection *This = impl_from_IWshCollection(iface);
308 ITypeInfo *typeinfo;
309 HRESULT hr;
310
311 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
312
313 hr = get_typeinfo(IWshCollection_tid, &typeinfo);
314 if(SUCCEEDED(hr))
315 {
316 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
317 ITypeInfo_Release(typeinfo);
318 }
319
320 return hr;
321 }
322
323 static HRESULT WINAPI WshCollection_Invoke(IWshCollection *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
324 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
325 {
326 WshCollection *This = impl_from_IWshCollection(iface);
327 ITypeInfo *typeinfo;
328 HRESULT hr;
329
330 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
331 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
332
333 hr = get_typeinfo(IWshCollection_tid, &typeinfo);
334 if(SUCCEEDED(hr))
335 {
336 hr = ITypeInfo_Invoke(typeinfo, &This->IWshCollection_iface, dispIdMember, wFlags,
337 pDispParams, pVarResult, pExcepInfo, puArgErr);
338 ITypeInfo_Release(typeinfo);
339 }
340
341 return hr;
342 }
343
344 static HRESULT WINAPI WshCollection_Item(IWshCollection *iface, VARIANT *index, VARIANT *value)
345 {
346 WshCollection *This = impl_from_IWshCollection(iface);
347 static const WCHAR allusersdesktopW[] = {'A','l','l','U','s','e','r','s','D','e','s','k','t','o','p',0};
348 static const WCHAR allusersprogramsW[] = {'A','l','l','U','s','e','r','s','P','r','o','g','r','a','m','s',0};
349 static const WCHAR desktopW[] = {'D','e','s','k','t','o','p',0};
350 PIDLIST_ABSOLUTE pidl;
351 WCHAR pathW[MAX_PATH];
352 int kind = 0;
353 BSTR folder;
354 HRESULT hr;
355
356 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(index), value);
357
358 if (V_VT(index) != VT_BSTR)
359 {
360 FIXME("only BSTR index supported, got %d\n", V_VT(index));
361 return E_NOTIMPL;
362 }
363
364 folder = V_BSTR(index);
365 if (!strcmpiW(folder, desktopW))
366 kind = CSIDL_DESKTOP;
367 else if (!strcmpiW(folder, allusersdesktopW))
368 kind = CSIDL_COMMON_DESKTOPDIRECTORY;
369 else if (!strcmpiW(folder, allusersprogramsW))
370 kind = CSIDL_COMMON_PROGRAMS;
371 else
372 {
373 FIXME("folder kind %s not supported\n", debugstr_w(folder));
374 return E_NOTIMPL;
375 }
376
377 hr = SHGetSpecialFolderLocation(NULL, kind, &pidl);
378 if (hr != S_OK) return hr;
379
380 if (SHGetPathFromIDListW(pidl, pathW))
381 {
382 V_VT(value) = VT_BSTR;
383 V_BSTR(value) = SysAllocString(pathW);
384 hr = V_BSTR(value) ? S_OK : E_OUTOFMEMORY;
385 }
386 else
387 hr = E_FAIL;
388
389 CoTaskMemFree(pidl);
390
391 return hr;
392 }
393
394 static HRESULT WINAPI WshCollection_Count(IWshCollection *iface, LONG *count)
395 {
396 WshCollection *This = impl_from_IWshCollection(iface);
397 FIXME("(%p)->(%p): stub\n", This, count);
398 return E_NOTIMPL;
399 }
400
401 static HRESULT WINAPI WshCollection_get_length(IWshCollection *iface, LONG *count)
402 {
403 WshCollection *This = impl_from_IWshCollection(iface);
404 FIXME("(%p)->(%p): stub\n", This, count);
405 return E_NOTIMPL;
406 }
407
408 static HRESULT WINAPI WshCollection__NewEnum(IWshCollection *iface, IUnknown *Enum)
409 {
410 WshCollection *This = impl_from_IWshCollection(iface);
411 FIXME("(%p)->(%p): stub\n", This, Enum);
412 return E_NOTIMPL;
413 }
414
415 static const IWshCollectionVtbl WshCollectionVtbl = {
416 WshCollection_QueryInterface,
417 WshCollection_AddRef,
418 WshCollection_Release,
419 WshCollection_GetTypeInfoCount,
420 WshCollection_GetTypeInfo,
421 WshCollection_GetIDsOfNames,
422 WshCollection_Invoke,
423 WshCollection_Item,
424 WshCollection_Count,
425 WshCollection_get_length,
426 WshCollection__NewEnum
427 };
428
429 static HRESULT WshCollection_Create(IWshCollection **collection)
430 {
431 WshCollection *This;
432
433 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
434 if (!This) return E_OUTOFMEMORY;
435
436 This->IWshCollection_iface.lpVtbl = &WshCollectionVtbl;
437 This->ref = 1;
438
439 *collection = &This->IWshCollection_iface;
440
441 return S_OK;
442 }
443
444 /* IWshShortcut */
445 static HRESULT WINAPI WshShortcut_QueryInterface(IWshShortcut *iface, REFIID riid, void **ppv)
446 {
447 WshShortcut *This = impl_from_IWshShortcut(iface);
448
449 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
450
451 if (IsEqualGUID(riid, &IID_IUnknown) ||
452 IsEqualGUID(riid, &IID_IDispatch) ||
453 IsEqualGUID(riid, &IID_IWshShortcut))
454 {
455 *ppv = iface;
456 }else {
457 FIXME("Unknown iface %s\n", debugstr_guid(riid));
458 *ppv = NULL;
459 return E_NOINTERFACE;
460 }
461
462 IUnknown_AddRef((IUnknown*)*ppv);
463 return S_OK;
464 }
465
466 static ULONG WINAPI WshShortcut_AddRef(IWshShortcut *iface)
467 {
468 WshShortcut *This = impl_from_IWshShortcut(iface);
469 LONG ref = InterlockedIncrement(&This->ref);
470 TRACE("(%p) ref = %d\n", This, ref);
471 return ref;
472 }
473
474 static ULONG WINAPI WshShortcut_Release(IWshShortcut *iface)
475 {
476 WshShortcut *This = impl_from_IWshShortcut(iface);
477 LONG ref = InterlockedDecrement(&This->ref);
478 TRACE("(%p) ref = %d\n", This, ref);
479
480 if (!ref)
481 {
482 SysFreeString(This->path_link);
483 IShellLinkW_Release(This->link);
484 HeapFree(GetProcessHeap(), 0, This);
485 }
486
487 return ref;
488 }
489
490 static HRESULT WINAPI WshShortcut_GetTypeInfoCount(IWshShortcut *iface, UINT *pctinfo)
491 {
492 WshShortcut *This = impl_from_IWshShortcut(iface);
493 TRACE("(%p)->(%p)\n", This, pctinfo);
494 *pctinfo = 1;
495 return S_OK;
496 }
497
498 static HRESULT WINAPI WshShortcut_GetTypeInfo(IWshShortcut *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
499 {
500 WshShortcut *This = impl_from_IWshShortcut(iface);
501 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
502 return get_typeinfo(IWshShortcut_tid, ppTInfo);
503 }
504
505 static HRESULT WINAPI WshShortcut_GetIDsOfNames(IWshShortcut *iface, REFIID riid, LPOLESTR *rgszNames,
506 UINT cNames, LCID lcid, DISPID *rgDispId)
507 {
508 WshShortcut *This = impl_from_IWshShortcut(iface);
509 ITypeInfo *typeinfo;
510 HRESULT hr;
511
512 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
513
514 hr = get_typeinfo(IWshShortcut_tid, &typeinfo);
515 if(SUCCEEDED(hr))
516 {
517 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
518 ITypeInfo_Release(typeinfo);
519 }
520
521 return hr;
522 }
523
524 static HRESULT WINAPI WshShortcut_Invoke(IWshShortcut *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
525 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
526 {
527 WshShortcut *This = impl_from_IWshShortcut(iface);
528 ITypeInfo *typeinfo;
529 HRESULT hr;
530
531 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
532 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
533
534 hr = get_typeinfo(IWshShortcut_tid, &typeinfo);
535 if(SUCCEEDED(hr))
536 {
537 hr = ITypeInfo_Invoke(typeinfo, &This->IWshShortcut_iface, dispIdMember, wFlags,
538 pDispParams, pVarResult, pExcepInfo, puArgErr);
539 ITypeInfo_Release(typeinfo);
540 }
541
542 return hr;
543 }
544
545 static HRESULT WINAPI WshShortcut_get_FullName(IWshShortcut *iface, BSTR *name)
546 {
547 WshShortcut *This = impl_from_IWshShortcut(iface);
548 FIXME("(%p)->(%p): stub\n", This, name);
549 return E_NOTIMPL;
550 }
551
552 static HRESULT WINAPI WshShortcut_get_Arguments(IWshShortcut *iface, BSTR *Arguments)
553 {
554 WshShortcut *This = impl_from_IWshShortcut(iface);
555 WCHAR buffW[INFOTIPSIZE];
556 HRESULT hr;
557
558 TRACE("(%p)->(%p)\n", This, Arguments);
559
560 if (!Arguments)
561 return E_POINTER;
562
563 *Arguments = NULL;
564
565 hr = IShellLinkW_GetArguments(This->link, buffW, sizeof(buffW)/sizeof(WCHAR));
566 if (FAILED(hr))
567 return hr;
568
569 *Arguments = SysAllocString(buffW);
570 return *Arguments ? S_OK : E_OUTOFMEMORY;
571 }
572
573 static HRESULT WINAPI WshShortcut_put_Arguments(IWshShortcut *iface, BSTR Arguments)
574 {
575 WshShortcut *This = impl_from_IWshShortcut(iface);
576
577 TRACE("(%p)->(%s)\n", This, debugstr_w(Arguments));
578
579 return IShellLinkW_SetArguments(This->link, Arguments);
580 }
581
582 static HRESULT WINAPI WshShortcut_get_Description(IWshShortcut *iface, BSTR *Description)
583 {
584 WshShortcut *This = impl_from_IWshShortcut(iface);
585 FIXME("(%p)->(%p): stub\n", This, Description);
586 return E_NOTIMPL;
587 }
588
589 static HRESULT WINAPI WshShortcut_put_Description(IWshShortcut *iface, BSTR Description)
590 {
591 WshShortcut *This = impl_from_IWshShortcut(iface);
592 TRACE("(%p)->(%s)\n", This, debugstr_w(Description));
593 return IShellLinkW_SetDescription(This->link, Description);
594 }
595
596 static HRESULT WINAPI WshShortcut_get_Hotkey(IWshShortcut *iface, BSTR *Hotkey)
597 {
598 WshShortcut *This = impl_from_IWshShortcut(iface);
599 FIXME("(%p)->(%p): stub\n", This, Hotkey);
600 return E_NOTIMPL;
601 }
602
603 static HRESULT WINAPI WshShortcut_put_Hotkey(IWshShortcut *iface, BSTR Hotkey)
604 {
605 WshShortcut *This = impl_from_IWshShortcut(iface);
606 FIXME("(%p)->(%s): stub\n", This, debugstr_w(Hotkey));
607 return E_NOTIMPL;
608 }
609
610 static HRESULT WINAPI WshShortcut_get_IconLocation(IWshShortcut *iface, BSTR *IconPath)
611 {
612 static const WCHAR fmtW[] = {'%','s',',',' ','%','d',0};
613 WshShortcut *This = impl_from_IWshShortcut(iface);
614 WCHAR buffW[MAX_PATH], pathW[MAX_PATH];
615 INT icon = 0;
616 HRESULT hr;
617
618 TRACE("(%p)->(%p)\n", This, IconPath);
619
620 if (!IconPath)
621 return E_POINTER;
622
623 hr = IShellLinkW_GetIconLocation(This->link, buffW, sizeof(buffW)/sizeof(WCHAR), &icon);
624 if (FAILED(hr)) return hr;
625
626 sprintfW(pathW, fmtW, buffW, icon);
627 *IconPath = SysAllocString(pathW);
628 if (!*IconPath) return E_OUTOFMEMORY;
629
630 return S_OK;
631 }
632
633 static HRESULT WINAPI WshShortcut_put_IconLocation(IWshShortcut *iface, BSTR IconPath)
634 {
635 WshShortcut *This = impl_from_IWshShortcut(iface);
636 HRESULT hr;
637 WCHAR *ptr;
638 BSTR path;
639 INT icon;
640
641 TRACE("(%p)->(%s)\n", This, debugstr_w(IconPath));
642
643 /* scan for icon id */
644 ptr = strrchrW(IconPath, ',');
645 if (!ptr)
646 {
647 WARN("icon index not found\n");
648 return E_FAIL;
649 }
650
651 path = SysAllocStringLen(IconPath, ptr-IconPath);
652
653 /* skip spaces if any */
654 while (isspaceW(*++ptr))
655 ;
656
657 icon = atoiW(ptr);
658
659 hr = IShellLinkW_SetIconLocation(This->link, path, icon);
660 SysFreeString(path);
661
662 return hr;
663 }
664
665 static HRESULT WINAPI WshShortcut_put_RelativePath(IWshShortcut *iface, BSTR rhs)
666 {
667 WshShortcut *This = impl_from_IWshShortcut(iface);
668 FIXME("(%p)->(%s): stub\n", This, debugstr_w(rhs));
669 return E_NOTIMPL;
670 }
671
672 static HRESULT WINAPI WshShortcut_get_TargetPath(IWshShortcut *iface, BSTR *Path)
673 {
674 WshShortcut *This = impl_from_IWshShortcut(iface);
675 FIXME("(%p)->(%p): stub\n", This, Path);
676 return E_NOTIMPL;
677 }
678
679 static HRESULT WINAPI WshShortcut_put_TargetPath(IWshShortcut *iface, BSTR Path)
680 {
681 WshShortcut *This = impl_from_IWshShortcut(iface);
682 TRACE("(%p)->(%s)\n", This, debugstr_w(Path));
683 return IShellLinkW_SetPath(This->link, Path);
684 }
685
686 static HRESULT WINAPI WshShortcut_get_WindowStyle(IWshShortcut *iface, int *ShowCmd)
687 {
688 WshShortcut *This = impl_from_IWshShortcut(iface);
689 TRACE("(%p)->(%p)\n", This, ShowCmd);
690 return IShellLinkW_GetShowCmd(This->link, ShowCmd);
691 }
692
693 static HRESULT WINAPI WshShortcut_put_WindowStyle(IWshShortcut *iface, int ShowCmd)
694 {
695 WshShortcut *This = impl_from_IWshShortcut(iface);
696 TRACE("(%p)->(%d)\n", This, ShowCmd);
697 return IShellLinkW_SetShowCmd(This->link, ShowCmd);
698 }
699
700 static HRESULT WINAPI WshShortcut_get_WorkingDirectory(IWshShortcut *iface, BSTR *WorkingDirectory)
701 {
702 WshShortcut *This = impl_from_IWshShortcut(iface);
703 WCHAR buffW[MAX_PATH];
704 HRESULT hr;
705
706 TRACE("(%p)->(%p)\n", This, WorkingDirectory);
707
708 if (!WorkingDirectory)
709 return E_POINTER;
710
711 *WorkingDirectory = NULL;
712 hr = IShellLinkW_GetWorkingDirectory(This->link, buffW, sizeof(buffW)/sizeof(WCHAR));
713 if (FAILED(hr)) return hr;
714
715 *WorkingDirectory = SysAllocString(buffW);
716 return *WorkingDirectory ? S_OK : E_OUTOFMEMORY;
717 }
718
719 static HRESULT WINAPI WshShortcut_put_WorkingDirectory(IWshShortcut *iface, BSTR WorkingDirectory)
720 {
721 WshShortcut *This = impl_from_IWshShortcut(iface);
722 TRACE("(%p)->(%s)\n", This, debugstr_w(WorkingDirectory));
723 return IShellLinkW_SetWorkingDirectory(This->link, WorkingDirectory);
724 }
725
726 static HRESULT WINAPI WshShortcut_Load(IWshShortcut *iface, BSTR PathLink)
727 {
728 WshShortcut *This = impl_from_IWshShortcut(iface);
729 FIXME("(%p)->(%s): stub\n", This, debugstr_w(PathLink));
730 return E_NOTIMPL;
731 }
732
733 static HRESULT WINAPI WshShortcut_Save(IWshShortcut *iface)
734 {
735 WshShortcut *This = impl_from_IWshShortcut(iface);
736 IPersistFile *file;
737 HRESULT hr;
738
739 TRACE("(%p)\n", This);
740
741 IShellLinkW_QueryInterface(This->link, &IID_IPersistFile, (void**)&file);
742 hr = IPersistFile_Save(file, This->path_link, TRUE);
743 IPersistFile_Release(file);
744
745 return hr;
746 }
747
748 static const IWshShortcutVtbl WshShortcutVtbl = {
749 WshShortcut_QueryInterface,
750 WshShortcut_AddRef,
751 WshShortcut_Release,
752 WshShortcut_GetTypeInfoCount,
753 WshShortcut_GetTypeInfo,
754 WshShortcut_GetIDsOfNames,
755 WshShortcut_Invoke,
756 WshShortcut_get_FullName,
757 WshShortcut_get_Arguments,
758 WshShortcut_put_Arguments,
759 WshShortcut_get_Description,
760 WshShortcut_put_Description,
761 WshShortcut_get_Hotkey,
762 WshShortcut_put_Hotkey,
763 WshShortcut_get_IconLocation,
764 WshShortcut_put_IconLocation,
765 WshShortcut_put_RelativePath,
766 WshShortcut_get_TargetPath,
767 WshShortcut_put_TargetPath,
768 WshShortcut_get_WindowStyle,
769 WshShortcut_put_WindowStyle,
770 WshShortcut_get_WorkingDirectory,
771 WshShortcut_put_WorkingDirectory,
772 WshShortcut_Load,
773 WshShortcut_Save
774 };
775
776 static HRESULT WshShortcut_Create(const WCHAR *path, IDispatch **shortcut)
777 {
778 WshShortcut *This;
779 HRESULT hr;
780
781 *shortcut = NULL;
782
783 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
784 if (!This) return E_OUTOFMEMORY;
785
786 This->IWshShortcut_iface.lpVtbl = &WshShortcutVtbl;
787 This->ref = 1;
788
789 hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
790 &IID_IShellLinkW, (void**)&This->link);
791 if (FAILED(hr))
792 {
793 HeapFree(GetProcessHeap(), 0, This);
794 return hr;
795 }
796
797 This->path_link = SysAllocString(path);
798 if (!This->path_link)
799 {
800 IShellLinkW_Release(This->link);
801 HeapFree(GetProcessHeap(), 0, This);
802 return E_OUTOFMEMORY;
803 }
804
805 *shortcut = (IDispatch*)&This->IWshShortcut_iface;
806
807 return S_OK;
808 }
809
810 static HRESULT WINAPI WshShell3_QueryInterface(IWshShell3 *iface, REFIID riid, void **ppv)
811 {
812 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
813
814 *ppv = NULL;
815
816 if(IsEqualGUID(riid, &IID_IUnknown) ||
817 IsEqualGUID(riid, &IID_IDispatch) ||
818 IsEqualGUID(riid, &IID_IWshShell3))
819 {
820 *ppv = iface;
821 }
822 else if (IsEqualGUID(riid, &IID_IDispatchEx))
823 {
824 return E_NOINTERFACE;
825 }
826 else
827 {
828 FIXME("Unknown iface %s\n", debugstr_guid(riid));
829 return E_NOINTERFACE;
830 }
831
832 IWshShell3_AddRef(iface);
833 return S_OK;
834 }
835
836 static ULONG WINAPI WshShell3_AddRef(IWshShell3 *iface)
837 {
838 TRACE("()\n");
839 return 2;
840 }
841
842 static ULONG WINAPI WshShell3_Release(IWshShell3 *iface)
843 {
844 TRACE("()\n");
845 return 2;
846 }
847
848 static HRESULT WINAPI WshShell3_GetTypeInfoCount(IWshShell3 *iface, UINT *pctinfo)
849 {
850 TRACE("(%p)\n", pctinfo);
851 *pctinfo = 1;
852 return S_OK;
853 }
854
855 static HRESULT WINAPI WshShell3_GetTypeInfo(IWshShell3 *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
856 {
857 TRACE("(%u %u %p)\n", iTInfo, lcid, ppTInfo);
858 return get_typeinfo(IWshShell3_tid, ppTInfo);
859 }
860
861 static HRESULT WINAPI WshShell3_GetIDsOfNames(IWshShell3 *iface, REFIID riid, LPOLESTR *rgszNames,
862 UINT cNames, LCID lcid, DISPID *rgDispId)
863 {
864 ITypeInfo *typeinfo;
865 HRESULT hr;
866
867 TRACE("(%s %p %u %u %p)\n", debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
868
869 hr = get_typeinfo(IWshShell3_tid, &typeinfo);
870 if(SUCCEEDED(hr))
871 {
872 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
873 ITypeInfo_Release(typeinfo);
874 }
875
876 return hr;
877 }
878
879 static HRESULT WINAPI WshShell3_Invoke(IWshShell3 *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
880 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
881 {
882 ITypeInfo *typeinfo;
883 HRESULT hr;
884
885 TRACE("(%d %s %d %d %p %p %p %p)\n", dispIdMember, debugstr_guid(riid),
886 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
887
888 hr = get_typeinfo(IWshShell3_tid, &typeinfo);
889 if(SUCCEEDED(hr))
890 {
891 hr = ITypeInfo_Invoke(typeinfo, &WshShell3, dispIdMember, wFlags,
892 pDispParams, pVarResult, pExcepInfo, puArgErr);
893 ITypeInfo_Release(typeinfo);
894 }
895
896 return hr;
897 }
898
899 static HRESULT WINAPI WshShell3_get_SpecialFolders(IWshShell3 *iface, IWshCollection **folders)
900 {
901 TRACE("(%p)\n", folders);
902 return WshCollection_Create(folders);
903 }
904
905 static HRESULT WINAPI WshShell3_get_Environment(IWshShell3 *iface, VARIANT *type, IWshEnvironment **env)
906 {
907 FIXME("(%s %p): semi-stub\n", debugstr_variant(type), env);
908 return WshEnvironment_Create(env);
909 }
910
911 static HRESULT WINAPI WshShell3_Run(IWshShell3 *iface, BSTR cmd, VARIANT *style, VARIANT *WaitOnReturn, int *exit_code)
912 {
913 SHELLEXECUTEINFOW info;
914 int waitforprocess;
915 VARIANT s, w;
916 HRESULT hr;
917
918 TRACE("(%s %s %s %p)\n", debugstr_w(cmd), debugstr_variant(style), debugstr_variant(WaitOnReturn), exit_code);
919
920 VariantInit(&s);
921 hr = VariantChangeType(&s, style, 0, VT_I4);
922 if (FAILED(hr))
923 {
924 ERR("failed to convert style argument, 0x%08x\n", hr);
925 return hr;
926 }
927
928 VariantInit(&w);
929 hr = VariantChangeType(&w, WaitOnReturn, 0, VT_I4);
930 if (FAILED(hr))
931 {
932 ERR("failed to convert wait argument, 0x%08x\n", hr);
933 return hr;
934 }
935
936 memset(&info, 0, sizeof(info));
937 info.cbSize = sizeof(info);
938
939 waitforprocess = V_I4(&w);
940
941 info.fMask = waitforprocess ? SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS : SEE_MASK_DEFAULT;
942 info.lpFile = cmd;
943 info.nShow = V_I4(&s);
944
945 if (!ShellExecuteExW(&info))
946 {
947 TRACE("ShellExecute failed, %d\n", GetLastError());
948 return HRESULT_FROM_WIN32(GetLastError());
949 }
950 else
951 {
952 if (waitforprocess)
953 {
954 if (exit_code)
955 {
956 DWORD code;
957 GetExitCodeProcess(info.hProcess, &code);
958 *exit_code = code;
959 }
960 CloseHandle(info.hProcess);
961 }
962 else
963 if (exit_code) *exit_code = 0;
964
965 return S_OK;
966 }
967 }
968
969 static HRESULT WINAPI WshShell3_Popup(IWshShell3 *iface, BSTR Text, VARIANT* SecondsToWait, VARIANT *Title, VARIANT *Type, int *button)
970 {
971 FIXME("(%s %s %s %s %p): stub\n", debugstr_w(Text), debugstr_variant(SecondsToWait),
972 debugstr_variant(Title), debugstr_variant(Type), button);
973 return E_NOTIMPL;
974 }
975
976 static HRESULT WINAPI WshShell3_CreateShortcut(IWshShell3 *iface, BSTR PathLink, IDispatch** Shortcut)
977 {
978 TRACE("(%s %p)\n", debugstr_w(PathLink), Shortcut);
979 return WshShortcut_Create(PathLink, Shortcut);
980 }
981
982 static HRESULT WINAPI WshShell3_ExpandEnvironmentStrings(IWshShell3 *iface, BSTR Src, BSTR* Dst)
983 {
984 DWORD ret;
985
986 TRACE("(%s %p)\n", debugstr_w(Src), Dst);
987
988 if (!Src || !Dst) return E_POINTER;
989
990 ret = ExpandEnvironmentStringsW(Src, NULL, 0);
991 *Dst = SysAllocStringLen(NULL, ret);
992 if (!*Dst) return E_OUTOFMEMORY;
993
994 if (ExpandEnvironmentStringsW(Src, *Dst, ret))
995 return S_OK;
996 else
997 {
998 SysFreeString(*Dst);
999 *Dst = NULL;
1000 return HRESULT_FROM_WIN32(GetLastError());
1001 }
1002 }
1003
1004 static HRESULT WINAPI WshShell3_RegRead(IWshShell3 *iface, BSTR Name, VARIANT* out_Value)
1005 {
1006 FIXME("(%s %p): stub\n", debugstr_w(Name), out_Value);
1007 return E_NOTIMPL;
1008 }
1009
1010 static HRESULT WINAPI WshShell3_RegWrite(IWshShell3 *iface, BSTR Name, VARIANT *Value, VARIANT *Type)
1011 {
1012 FIXME("(%s %s %s): stub\n", debugstr_w(Name), debugstr_variant(Value), debugstr_variant(Type));
1013 return E_NOTIMPL;
1014 }
1015
1016 static HRESULT WINAPI WshShell3_RegDelete(IWshShell3 *iface, BSTR Name)
1017 {
1018 FIXME("(%s): stub\n", debugstr_w(Name));
1019 return E_NOTIMPL;
1020 }
1021
1022 static HRESULT WINAPI WshShell3_LogEvent(IWshShell3 *iface, VARIANT *Type, BSTR Message, BSTR Target, VARIANT_BOOL *out_Success)
1023 {
1024 FIXME("(%s %s %s %p): stub\n", debugstr_variant(Type), debugstr_w(Message), debugstr_w(Target), out_Success);
1025 return E_NOTIMPL;
1026 }
1027
1028 static HRESULT WINAPI WshShell3_AppActivate(IWshShell3 *iface, VARIANT *App, VARIANT *Wait, VARIANT_BOOL *out_Success)
1029 {
1030 FIXME("(%s %s %p): stub\n", debugstr_variant(App), debugstr_variant(Wait), out_Success);
1031 return E_NOTIMPL;
1032 }
1033
1034 static HRESULT WINAPI WshShell3_SendKeys(IWshShell3 *iface, BSTR Keys, VARIANT *Wait)
1035 {
1036 FIXME("(%s %p): stub\n", debugstr_w(Keys), Wait);
1037 return E_NOTIMPL;
1038 }
1039
1040 static const IWshShell3Vtbl WshShell3Vtbl = {
1041 WshShell3_QueryInterface,
1042 WshShell3_AddRef,
1043 WshShell3_Release,
1044 WshShell3_GetTypeInfoCount,
1045 WshShell3_GetTypeInfo,
1046 WshShell3_GetIDsOfNames,
1047 WshShell3_Invoke,
1048 WshShell3_get_SpecialFolders,
1049 WshShell3_get_Environment,
1050 WshShell3_Run,
1051 WshShell3_Popup,
1052 WshShell3_CreateShortcut,
1053 WshShell3_ExpandEnvironmentStrings,
1054 WshShell3_RegRead,
1055 WshShell3_RegWrite,
1056 WshShell3_RegDelete,
1057 WshShell3_LogEvent,
1058 WshShell3_AppActivate,
1059 WshShell3_SendKeys
1060 };
1061
1062 static IWshShell3 WshShell3 = { &WshShell3Vtbl };
1063
1064 HRESULT WINAPI WshShellFactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
1065 {
1066 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
1067
1068 return IWshShell3_QueryInterface(&WshShell3, riid, ppv);
1069 }