42310e2a7e18c24587d0472a11ef8d0df1d0a428
[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 #include "wshom.h"
21
22 #include "shellapi.h"
23 #include "shlobj.h"
24 #include "dispex.h"
25
26 #include "wine/debug.h"
27 #include "wine/heap.h"
28 #include "wine/unicode.h"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(wshom);
31
32 typedef struct
33 {
34 struct provideclassinfo classinfo;
35 IWshShell3 IWshShell3_iface;
36 } WshShellImpl;
37 static WshShellImpl WshShell3;
38
39 typedef struct
40 {
41 struct provideclassinfo classinfo;
42 IWshCollection IWshCollection_iface;
43 LONG ref;
44 } WshCollection;
45
46 typedef struct
47 {
48 struct provideclassinfo classinfo;
49 IWshShortcut IWshShortcut_iface;
50 LONG ref;
51
52 IShellLinkW *link;
53 BSTR path_link;
54 } WshShortcut;
55
56 typedef struct
57 {
58 struct provideclassinfo classinfo;
59 IWshEnvironment IWshEnvironment_iface;
60 LONG ref;
61 } WshEnvironment;
62
63 typedef struct
64 {
65 struct provideclassinfo classinfo;
66 IWshExec IWshExec_iface;
67 LONG ref;
68 PROCESS_INFORMATION info;
69 } WshExecImpl;
70
71 static inline WshCollection *impl_from_IWshCollection( IWshCollection *iface )
72 {
73 return CONTAINING_RECORD(iface, WshCollection, IWshCollection_iface);
74 }
75
76 static inline WshShortcut *impl_from_IWshShortcut( IWshShortcut *iface )
77 {
78 return CONTAINING_RECORD(iface, WshShortcut, IWshShortcut_iface);
79 }
80
81 static inline WshEnvironment *impl_from_IWshEnvironment( IWshEnvironment *iface )
82 {
83 return CONTAINING_RECORD(iface, WshEnvironment, IWshEnvironment_iface);
84 }
85
86 static inline WshExecImpl *impl_from_IWshExec( IWshExec *iface )
87 {
88 return CONTAINING_RECORD(iface, WshExecImpl, IWshExec_iface);
89 }
90
91 static HRESULT WINAPI WshExec_QueryInterface(IWshExec *iface, REFIID riid, void **obj)
92 {
93 WshExecImpl *This = impl_from_IWshExec(iface);
94
95 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), obj);
96
97 if (IsEqualGUID(riid, &IID_IDispatch) ||
98 IsEqualGUID(riid, &IID_IWshExec) ||
99 IsEqualGUID(riid, &IID_IUnknown))
100 {
101 *obj = iface;
102 }
103 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
104 {
105 *obj = &This->classinfo.IProvideClassInfo_iface;
106 }
107 else {
108 FIXME("Unknown iface %s\n", debugstr_guid(riid));
109 *obj = NULL;
110 return E_NOINTERFACE;
111 }
112
113 IUnknown_AddRef((IUnknown *)*obj);
114 return S_OK;
115 }
116
117 static ULONG WINAPI WshExec_AddRef(IWshExec *iface)
118 {
119 WshExecImpl *This = impl_from_IWshExec(iface);
120 LONG ref = InterlockedIncrement(&This->ref);
121 TRACE("(%p) ref = %d\n", This, ref);
122 return ref;
123 }
124
125 static ULONG WINAPI WshExec_Release(IWshExec *iface)
126 {
127 WshExecImpl *This = impl_from_IWshExec(iface);
128 LONG ref = InterlockedDecrement(&This->ref);
129 TRACE("(%p) ref = %d\n", This, ref);
130
131 if (!ref) {
132 CloseHandle(This->info.hThread);
133 CloseHandle(This->info.hProcess);
134 heap_free(This);
135 }
136
137 return ref;
138 }
139
140 static HRESULT WINAPI WshExec_GetTypeInfoCount(IWshExec *iface, UINT *pctinfo)
141 {
142 WshExecImpl *This = impl_from_IWshExec(iface);
143 TRACE("(%p)->(%p)\n", This, pctinfo);
144 *pctinfo = 1;
145 return S_OK;
146 }
147
148 static HRESULT WINAPI WshExec_GetTypeInfo(IWshExec *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
149 {
150 WshExecImpl *This = impl_from_IWshExec(iface);
151 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
152 return get_typeinfo(IWshExec_tid, ppTInfo);
153 }
154
155 static HRESULT WINAPI WshExec_GetIDsOfNames(IWshExec *iface, REFIID riid, LPOLESTR *rgszNames,
156 UINT cNames, LCID lcid, DISPID *rgDispId)
157 {
158 WshExecImpl *This = impl_from_IWshExec(iface);
159 ITypeInfo *typeinfo;
160 HRESULT hr;
161
162 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
163
164 hr = get_typeinfo(IWshExec_tid, &typeinfo);
165 if(SUCCEEDED(hr))
166 {
167 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
168 ITypeInfo_Release(typeinfo);
169 }
170
171 return hr;
172 }
173
174 static HRESULT WINAPI WshExec_Invoke(IWshExec *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
175 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
176 {
177 WshExecImpl *This = impl_from_IWshExec(iface);
178 ITypeInfo *typeinfo;
179 HRESULT hr;
180
181 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
182 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
183
184 hr = get_typeinfo(IWshExec_tid, &typeinfo);
185 if(SUCCEEDED(hr))
186 {
187 hr = ITypeInfo_Invoke(typeinfo, &This->IWshExec_iface, dispIdMember, wFlags,
188 pDispParams, pVarResult, pExcepInfo, puArgErr);
189 ITypeInfo_Release(typeinfo);
190 }
191
192 return hr;
193 }
194
195 static HRESULT WINAPI WshExec_get_Status(IWshExec *iface, WshExecStatus *status)
196 {
197 WshExecImpl *This = impl_from_IWshExec(iface);
198 DWORD code;
199
200 TRACE("(%p)->(%p)\n", This, status);
201
202 if (!status)
203 return E_INVALIDARG;
204
205 if (!GetExitCodeProcess(This->info.hProcess, &code))
206 return HRESULT_FROM_WIN32(GetLastError());
207
208 switch (code)
209 {
210 case 0:
211 *status = WshFinished;
212 break;
213 case STILL_ACTIVE:
214 *status = WshRunning;
215 break;
216 default:
217 *status = WshFailed;
218 }
219
220 return S_OK;
221 }
222
223 static HRESULT WINAPI WshExec_get_StdIn(IWshExec *iface, ITextStream **stream)
224 {
225 WshExecImpl *This = impl_from_IWshExec(iface);
226
227 FIXME("(%p)->(%p): stub\n", This, stream);
228
229 return E_NOTIMPL;
230 }
231
232 static HRESULT WINAPI WshExec_get_StdOut(IWshExec *iface, ITextStream **stream)
233 {
234 WshExecImpl *This = impl_from_IWshExec(iface);
235
236 FIXME("(%p)->(%p): stub\n", This, stream);
237
238 return E_NOTIMPL;
239 }
240
241 static HRESULT WINAPI WshExec_get_StdErr(IWshExec *iface, ITextStream **stream)
242 {
243 WshExecImpl *This = impl_from_IWshExec(iface);
244
245 FIXME("(%p)->(%p): stub\n", This, stream);
246
247 return E_NOTIMPL;
248 }
249
250 static HRESULT WINAPI WshExec_get_ProcessID(IWshExec *iface, DWORD *pid)
251 {
252 WshExecImpl *This = impl_from_IWshExec(iface);
253
254 TRACE("(%p)->(%p)\n", This, pid);
255
256 if (!pid)
257 return E_INVALIDARG;
258
259 *pid = This->info.dwProcessId;
260 return S_OK;
261 }
262
263 static HRESULT WINAPI WshExec_get_ExitCode(IWshExec *iface, DWORD *code)
264 {
265 WshExecImpl *This = impl_from_IWshExec(iface);
266
267 FIXME("(%p)->(%p): stub\n", This, code);
268
269 return E_NOTIMPL;
270 }
271
272 static BOOL CALLBACK enum_thread_wnd_proc(HWND hwnd, LPARAM lParam)
273 {
274 INT *count = (INT*)lParam;
275
276 (*count)++;
277 PostMessageW(hwnd, WM_CLOSE, 0, 0);
278 /* try to send it to all windows, even if failed for some */
279 return TRUE;
280 }
281
282 static HRESULT WINAPI WshExec_Terminate(IWshExec *iface)
283 {
284 WshExecImpl *This = impl_from_IWshExec(iface);
285 BOOL ret, kill = FALSE;
286 INT count = 0;
287
288 TRACE("(%p)\n", This);
289
290 ret = EnumThreadWindows(This->info.dwThreadId, enum_thread_wnd_proc, (LPARAM)&count);
291 if (ret && count) {
292 /* manual testing shows that it waits 2 seconds before forcing termination */
293 if (WaitForSingleObject(This->info.hProcess, 2000) != WAIT_OBJECT_0)
294 kill = TRUE;
295 }
296 else
297 kill = TRUE;
298
299 if (kill)
300 TerminateProcess(This->info.hProcess, 0);
301
302 return S_OK;
303 }
304
305 static const IWshExecVtbl WshExecVtbl = {
306 WshExec_QueryInterface,
307 WshExec_AddRef,
308 WshExec_Release,
309 WshExec_GetTypeInfoCount,
310 WshExec_GetTypeInfo,
311 WshExec_GetIDsOfNames,
312 WshExec_Invoke,
313 WshExec_get_Status,
314 WshExec_get_StdIn,
315 WshExec_get_StdOut,
316 WshExec_get_StdErr,
317 WshExec_get_ProcessID,
318 WshExec_get_ExitCode,
319 WshExec_Terminate
320 };
321
322 static HRESULT WshExec_create(BSTR command, IWshExec **ret)
323 {
324 STARTUPINFOW si = {0};
325 WshExecImpl *This;
326
327 *ret = NULL;
328
329 This = heap_alloc(sizeof(*This));
330 if (!This)
331 return E_OUTOFMEMORY;
332
333 This->IWshExec_iface.lpVtbl = &WshExecVtbl;
334 This->ref = 1;
335
336 if (!CreateProcessW(NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &This->info)) {
337 heap_free(This);
338 return HRESULT_FROM_WIN32(GetLastError());
339 }
340
341 init_classinfo(&CLSID_WshExec, (IUnknown *)&This->IWshExec_iface, &This->classinfo);
342 *ret = &This->IWshExec_iface;
343 return S_OK;
344 }
345
346 static HRESULT WINAPI WshEnvironment_QueryInterface(IWshEnvironment *iface, REFIID riid, void **obj)
347 {
348 WshEnvironment *This = impl_from_IWshEnvironment(iface);
349
350 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), obj);
351
352 if (IsEqualGUID(riid, &IID_IUnknown) ||
353 IsEqualGUID(riid, &IID_IDispatch) ||
354 IsEqualGUID(riid, &IID_IWshEnvironment))
355 {
356 *obj = iface;
357 }
358 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
359 {
360 *obj = &This->classinfo.IProvideClassInfo_iface;
361 }
362 else {
363 FIXME("Unknown iface %s\n", debugstr_guid(riid));
364 *obj = NULL;
365 return E_NOINTERFACE;
366 }
367
368 IUnknown_AddRef((IUnknown*)*obj);
369 return S_OK;
370 }
371
372 static ULONG WINAPI WshEnvironment_AddRef(IWshEnvironment *iface)
373 {
374 WshEnvironment *This = impl_from_IWshEnvironment(iface);
375 LONG ref = InterlockedIncrement(&This->ref);
376 TRACE("(%p) ref = %d\n", This, ref);
377 return ref;
378 }
379
380 static ULONG WINAPI WshEnvironment_Release(IWshEnvironment *iface)
381 {
382 WshEnvironment *This = impl_from_IWshEnvironment(iface);
383 LONG ref = InterlockedDecrement(&This->ref);
384 TRACE("(%p) ref = %d\n", This, ref);
385
386 if (!ref)
387 heap_free(This);
388
389 return ref;
390 }
391
392 static HRESULT WINAPI WshEnvironment_GetTypeInfoCount(IWshEnvironment *iface, UINT *pctinfo)
393 {
394 WshEnvironment *This = impl_from_IWshEnvironment(iface);
395 TRACE("(%p)->(%p)\n", This, pctinfo);
396 *pctinfo = 1;
397 return S_OK;
398 }
399
400 static HRESULT WINAPI WshEnvironment_GetTypeInfo(IWshEnvironment *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
401 {
402 WshEnvironment *This = impl_from_IWshEnvironment(iface);
403 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
404 return get_typeinfo(IWshEnvironment_tid, ppTInfo);
405 }
406
407 static HRESULT WINAPI WshEnvironment_GetIDsOfNames(IWshEnvironment *iface, REFIID riid, LPOLESTR *rgszNames,
408 UINT cNames, LCID lcid, DISPID *rgDispId)
409 {
410 WshEnvironment *This = impl_from_IWshEnvironment(iface);
411 ITypeInfo *typeinfo;
412 HRESULT hr;
413
414 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
415
416 hr = get_typeinfo(IWshEnvironment_tid, &typeinfo);
417 if(SUCCEEDED(hr))
418 {
419 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
420 ITypeInfo_Release(typeinfo);
421 }
422
423 return hr;
424 }
425
426 static HRESULT WINAPI WshEnvironment_Invoke(IWshEnvironment *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
427 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
428 {
429 WshEnvironment *This = impl_from_IWshEnvironment(iface);
430 ITypeInfo *typeinfo;
431 HRESULT hr;
432
433 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
434 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
435
436 hr = get_typeinfo(IWshEnvironment_tid, &typeinfo);
437 if(SUCCEEDED(hr))
438 {
439 hr = ITypeInfo_Invoke(typeinfo, &This->IWshEnvironment_iface, dispIdMember, wFlags,
440 pDispParams, pVarResult, pExcepInfo, puArgErr);
441 ITypeInfo_Release(typeinfo);
442 }
443
444 return hr;
445 }
446
447 static HRESULT WINAPI WshEnvironment_get_Item(IWshEnvironment *iface, BSTR name, BSTR *value)
448 {
449 WshEnvironment *This = impl_from_IWshEnvironment(iface);
450 DWORD len;
451
452 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), value);
453
454 if (!value)
455 return E_POINTER;
456
457 len = GetEnvironmentVariableW(name, NULL, 0);
458 *value = SysAllocStringLen(NULL, len);
459 if (!*value)
460 return E_OUTOFMEMORY;
461
462 if (len)
463 GetEnvironmentVariableW(name, *value, len+1);
464
465 return S_OK;
466 }
467
468 static HRESULT WINAPI WshEnvironment_put_Item(IWshEnvironment *iface, BSTR name, BSTR value)
469 {
470 WshEnvironment *This = impl_from_IWshEnvironment(iface);
471 FIXME("(%p)->(%s %s): stub\n", This, debugstr_w(name), debugstr_w(value));
472 return E_NOTIMPL;
473 }
474
475 static HRESULT WINAPI WshEnvironment_Count(IWshEnvironment *iface, LONG *count)
476 {
477 WshEnvironment *This = impl_from_IWshEnvironment(iface);
478 FIXME("(%p)->(%p): stub\n", This, count);
479 return E_NOTIMPL;
480 }
481
482 static HRESULT WINAPI WshEnvironment_get_length(IWshEnvironment *iface, LONG *len)
483 {
484 WshEnvironment *This = impl_from_IWshEnvironment(iface);
485 FIXME("(%p)->(%p): stub\n", This, len);
486 return E_NOTIMPL;
487 }
488
489 static HRESULT WINAPI WshEnvironment__NewEnum(IWshEnvironment *iface, IUnknown **penum)
490 {
491 WshEnvironment *This = impl_from_IWshEnvironment(iface);
492 FIXME("(%p)->(%p): stub\n", This, penum);
493 return E_NOTIMPL;
494 }
495
496 static HRESULT WINAPI WshEnvironment_Remove(IWshEnvironment *iface, BSTR name)
497 {
498 WshEnvironment *This = impl_from_IWshEnvironment(iface);
499 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
500 return E_NOTIMPL;
501 }
502
503 static const IWshEnvironmentVtbl WshEnvironmentVtbl = {
504 WshEnvironment_QueryInterface,
505 WshEnvironment_AddRef,
506 WshEnvironment_Release,
507 WshEnvironment_GetTypeInfoCount,
508 WshEnvironment_GetTypeInfo,
509 WshEnvironment_GetIDsOfNames,
510 WshEnvironment_Invoke,
511 WshEnvironment_get_Item,
512 WshEnvironment_put_Item,
513 WshEnvironment_Count,
514 WshEnvironment_get_length,
515 WshEnvironment__NewEnum,
516 WshEnvironment_Remove
517 };
518
519 static HRESULT WshEnvironment_Create(IWshEnvironment **env)
520 {
521 WshEnvironment *This;
522
523 This = heap_alloc(sizeof(*This));
524 if (!This) return E_OUTOFMEMORY;
525
526 This->IWshEnvironment_iface.lpVtbl = &WshEnvironmentVtbl;
527 This->ref = 1;
528
529 init_classinfo(&IID_IWshEnvironment, (IUnknown *)&This->IWshEnvironment_iface, &This->classinfo);
530 *env = &This->IWshEnvironment_iface;
531
532 return S_OK;
533 }
534
535 static HRESULT WINAPI WshCollection_QueryInterface(IWshCollection *iface, REFIID riid, void **ppv)
536 {
537 WshCollection *This = impl_from_IWshCollection(iface);
538
539 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
540
541 if (IsEqualGUID(riid, &IID_IUnknown) ||
542 IsEqualGUID(riid, &IID_IDispatch) ||
543 IsEqualGUID(riid, &IID_IWshCollection))
544 {
545 *ppv = iface;
546 }
547 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
548 {
549 *ppv = &This->classinfo.IProvideClassInfo_iface;
550 }
551 else {
552 FIXME("Unknown iface %s\n", debugstr_guid(riid));
553 *ppv = NULL;
554 return E_NOINTERFACE;
555 }
556
557 IUnknown_AddRef((IUnknown*)*ppv);
558 return S_OK;
559 }
560
561 static ULONG WINAPI WshCollection_AddRef(IWshCollection *iface)
562 {
563 WshCollection *This = impl_from_IWshCollection(iface);
564 LONG ref = InterlockedIncrement(&This->ref);
565 TRACE("(%p) ref = %d\n", This, ref);
566 return ref;
567 }
568
569 static ULONG WINAPI WshCollection_Release(IWshCollection *iface)
570 {
571 WshCollection *This = impl_from_IWshCollection(iface);
572 LONG ref = InterlockedDecrement(&This->ref);
573 TRACE("(%p) ref = %d\n", This, ref);
574
575 if (!ref)
576 heap_free(This);
577
578 return ref;
579 }
580
581 static HRESULT WINAPI WshCollection_GetTypeInfoCount(IWshCollection *iface, UINT *pctinfo)
582 {
583 WshCollection *This = impl_from_IWshCollection(iface);
584 TRACE("(%p)->(%p)\n", This, pctinfo);
585 *pctinfo = 1;
586 return S_OK;
587 }
588
589 static HRESULT WINAPI WshCollection_GetTypeInfo(IWshCollection *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
590 {
591 WshCollection *This = impl_from_IWshCollection(iface);
592 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
593 return get_typeinfo(IWshCollection_tid, ppTInfo);
594 }
595
596 static HRESULT WINAPI WshCollection_GetIDsOfNames(IWshCollection *iface, REFIID riid, LPOLESTR *rgszNames,
597 UINT cNames, LCID lcid, DISPID *rgDispId)
598 {
599 WshCollection *This = impl_from_IWshCollection(iface);
600 ITypeInfo *typeinfo;
601 HRESULT hr;
602
603 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
604
605 hr = get_typeinfo(IWshCollection_tid, &typeinfo);
606 if(SUCCEEDED(hr))
607 {
608 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
609 ITypeInfo_Release(typeinfo);
610 }
611
612 return hr;
613 }
614
615 static HRESULT WINAPI WshCollection_Invoke(IWshCollection *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
616 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
617 {
618 WshCollection *This = impl_from_IWshCollection(iface);
619 ITypeInfo *typeinfo;
620 HRESULT hr;
621
622 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
623 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
624
625 hr = get_typeinfo(IWshCollection_tid, &typeinfo);
626 if(SUCCEEDED(hr))
627 {
628 hr = ITypeInfo_Invoke(typeinfo, &This->IWshCollection_iface, dispIdMember, wFlags,
629 pDispParams, pVarResult, pExcepInfo, puArgErr);
630 ITypeInfo_Release(typeinfo);
631 }
632
633 return hr;
634 }
635
636 static HRESULT WINAPI WshCollection_Item(IWshCollection *iface, VARIANT *index, VARIANT *value)
637 {
638 WshCollection *This = impl_from_IWshCollection(iface);
639 static const WCHAR allusersdesktopW[] = {'A','l','l','U','s','e','r','s','D','e','s','k','t','o','p',0};
640 static const WCHAR allusersprogramsW[] = {'A','l','l','U','s','e','r','s','P','r','o','g','r','a','m','s',0};
641 static const WCHAR desktopW[] = {'D','e','s','k','t','o','p',0};
642 PIDLIST_ABSOLUTE pidl;
643 WCHAR pathW[MAX_PATH];
644 int kind = 0;
645 BSTR folder;
646 HRESULT hr;
647
648 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(index), value);
649
650 if (V_VT(index) != VT_BSTR)
651 {
652 FIXME("only BSTR index supported, got %d\n", V_VT(index));
653 return E_NOTIMPL;
654 }
655
656 folder = V_BSTR(index);
657 if (!strcmpiW(folder, desktopW))
658 kind = CSIDL_DESKTOP;
659 else if (!strcmpiW(folder, allusersdesktopW))
660 kind = CSIDL_COMMON_DESKTOPDIRECTORY;
661 else if (!strcmpiW(folder, allusersprogramsW))
662 kind = CSIDL_COMMON_PROGRAMS;
663 else
664 {
665 FIXME("folder kind %s not supported\n", debugstr_w(folder));
666 return E_NOTIMPL;
667 }
668
669 hr = SHGetSpecialFolderLocation(NULL, kind, &pidl);
670 if (hr != S_OK) return hr;
671
672 if (SHGetPathFromIDListW(pidl, pathW))
673 {
674 V_VT(value) = VT_BSTR;
675 V_BSTR(value) = SysAllocString(pathW);
676 hr = V_BSTR(value) ? S_OK : E_OUTOFMEMORY;
677 }
678 else
679 hr = E_FAIL;
680
681 CoTaskMemFree(pidl);
682
683 return hr;
684 }
685
686 static HRESULT WINAPI WshCollection_Count(IWshCollection *iface, LONG *count)
687 {
688 WshCollection *This = impl_from_IWshCollection(iface);
689 FIXME("(%p)->(%p): stub\n", This, count);
690 return E_NOTIMPL;
691 }
692
693 static HRESULT WINAPI WshCollection_get_length(IWshCollection *iface, LONG *count)
694 {
695 WshCollection *This = impl_from_IWshCollection(iface);
696 FIXME("(%p)->(%p): stub\n", This, count);
697 return E_NOTIMPL;
698 }
699
700 static HRESULT WINAPI WshCollection__NewEnum(IWshCollection *iface, IUnknown *Enum)
701 {
702 WshCollection *This = impl_from_IWshCollection(iface);
703 FIXME("(%p)->(%p): stub\n", This, Enum);
704 return E_NOTIMPL;
705 }
706
707 static const IWshCollectionVtbl WshCollectionVtbl = {
708 WshCollection_QueryInterface,
709 WshCollection_AddRef,
710 WshCollection_Release,
711 WshCollection_GetTypeInfoCount,
712 WshCollection_GetTypeInfo,
713 WshCollection_GetIDsOfNames,
714 WshCollection_Invoke,
715 WshCollection_Item,
716 WshCollection_Count,
717 WshCollection_get_length,
718 WshCollection__NewEnum
719 };
720
721 static HRESULT WshCollection_Create(IWshCollection **collection)
722 {
723 WshCollection *This;
724
725 This = heap_alloc(sizeof(*This));
726 if (!This) return E_OUTOFMEMORY;
727
728 This->IWshCollection_iface.lpVtbl = &WshCollectionVtbl;
729 This->ref = 1;
730
731 init_classinfo(&IID_IWshCollection, (IUnknown *)&This->IWshCollection_iface, &This->classinfo);
732 *collection = &This->IWshCollection_iface;
733
734 return S_OK;
735 }
736
737 /* IWshShortcut */
738 static HRESULT WINAPI WshShortcut_QueryInterface(IWshShortcut *iface, REFIID riid, void **ppv)
739 {
740 WshShortcut *This = impl_from_IWshShortcut(iface);
741
742 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
743
744 if (IsEqualGUID(riid, &IID_IUnknown) ||
745 IsEqualGUID(riid, &IID_IDispatch) ||
746 IsEqualGUID(riid, &IID_IWshShortcut))
747 {
748 *ppv = iface;
749 }
750 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
751 {
752 *ppv = &This->classinfo.IProvideClassInfo_iface;
753 }
754 else {
755 FIXME("Unknown iface %s\n", debugstr_guid(riid));
756 *ppv = NULL;
757 return E_NOINTERFACE;
758 }
759
760 IUnknown_AddRef((IUnknown*)*ppv);
761 return S_OK;
762 }
763
764 static ULONG WINAPI WshShortcut_AddRef(IWshShortcut *iface)
765 {
766 WshShortcut *This = impl_from_IWshShortcut(iface);
767 LONG ref = InterlockedIncrement(&This->ref);
768 TRACE("(%p) ref = %d\n", This, ref);
769 return ref;
770 }
771
772 static ULONG WINAPI WshShortcut_Release(IWshShortcut *iface)
773 {
774 WshShortcut *This = impl_from_IWshShortcut(iface);
775 LONG ref = InterlockedDecrement(&This->ref);
776 TRACE("(%p) ref = %d\n", This, ref);
777
778 if (!ref)
779 {
780 SysFreeString(This->path_link);
781 IShellLinkW_Release(This->link);
782 heap_free(This);
783 }
784
785 return ref;
786 }
787
788 static HRESULT WINAPI WshShortcut_GetTypeInfoCount(IWshShortcut *iface, UINT *pctinfo)
789 {
790 WshShortcut *This = impl_from_IWshShortcut(iface);
791 TRACE("(%p)->(%p)\n", This, pctinfo);
792 *pctinfo = 1;
793 return S_OK;
794 }
795
796 static HRESULT WINAPI WshShortcut_GetTypeInfo(IWshShortcut *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
797 {
798 WshShortcut *This = impl_from_IWshShortcut(iface);
799 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
800 return get_typeinfo(IWshShortcut_tid, ppTInfo);
801 }
802
803 static HRESULT WINAPI WshShortcut_GetIDsOfNames(IWshShortcut *iface, REFIID riid, LPOLESTR *rgszNames,
804 UINT cNames, LCID lcid, DISPID *rgDispId)
805 {
806 WshShortcut *This = impl_from_IWshShortcut(iface);
807 ITypeInfo *typeinfo;
808 HRESULT hr;
809
810 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
811
812 hr = get_typeinfo(IWshShortcut_tid, &typeinfo);
813 if(SUCCEEDED(hr))
814 {
815 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
816 ITypeInfo_Release(typeinfo);
817 }
818
819 return hr;
820 }
821
822 static HRESULT WINAPI WshShortcut_Invoke(IWshShortcut *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
823 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
824 {
825 WshShortcut *This = impl_from_IWshShortcut(iface);
826 ITypeInfo *typeinfo;
827 HRESULT hr;
828
829 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
830 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
831
832 hr = get_typeinfo(IWshShortcut_tid, &typeinfo);
833 if(SUCCEEDED(hr))
834 {
835 hr = ITypeInfo_Invoke(typeinfo, &This->IWshShortcut_iface, dispIdMember, wFlags,
836 pDispParams, pVarResult, pExcepInfo, puArgErr);
837 ITypeInfo_Release(typeinfo);
838 }
839
840 return hr;
841 }
842
843 static HRESULT WINAPI WshShortcut_get_FullName(IWshShortcut *iface, BSTR *name)
844 {
845 WshShortcut *This = impl_from_IWshShortcut(iface);
846 FIXME("(%p)->(%p): stub\n", This, name);
847 return E_NOTIMPL;
848 }
849
850 static HRESULT WINAPI WshShortcut_get_Arguments(IWshShortcut *iface, BSTR *Arguments)
851 {
852 WshShortcut *This = impl_from_IWshShortcut(iface);
853 WCHAR buffW[INFOTIPSIZE];
854 HRESULT hr;
855
856 TRACE("(%p)->(%p)\n", This, Arguments);
857
858 if (!Arguments)
859 return E_POINTER;
860
861 *Arguments = NULL;
862
863 hr = IShellLinkW_GetArguments(This->link, buffW, ARRAY_SIZE(buffW));
864 if (FAILED(hr))
865 return hr;
866
867 *Arguments = SysAllocString(buffW);
868 return *Arguments ? S_OK : E_OUTOFMEMORY;
869 }
870
871 static HRESULT WINAPI WshShortcut_put_Arguments(IWshShortcut *iface, BSTR Arguments)
872 {
873 WshShortcut *This = impl_from_IWshShortcut(iface);
874
875 TRACE("(%p)->(%s)\n", This, debugstr_w(Arguments));
876
877 return IShellLinkW_SetArguments(This->link, Arguments);
878 }
879
880 static HRESULT WINAPI WshShortcut_get_Description(IWshShortcut *iface, BSTR *Description)
881 {
882 WshShortcut *This = impl_from_IWshShortcut(iface);
883 FIXME("(%p)->(%p): stub\n", This, Description);
884 return E_NOTIMPL;
885 }
886
887 static HRESULT WINAPI WshShortcut_put_Description(IWshShortcut *iface, BSTR Description)
888 {
889 WshShortcut *This = impl_from_IWshShortcut(iface);
890 TRACE("(%p)->(%s)\n", This, debugstr_w(Description));
891 return IShellLinkW_SetDescription(This->link, Description);
892 }
893
894 static HRESULT WINAPI WshShortcut_get_Hotkey(IWshShortcut *iface, BSTR *Hotkey)
895 {
896 WshShortcut *This = impl_from_IWshShortcut(iface);
897 FIXME("(%p)->(%p): stub\n", This, Hotkey);
898 return E_NOTIMPL;
899 }
900
901 static HRESULT WINAPI WshShortcut_put_Hotkey(IWshShortcut *iface, BSTR Hotkey)
902 {
903 WshShortcut *This = impl_from_IWshShortcut(iface);
904 FIXME("(%p)->(%s): stub\n", This, debugstr_w(Hotkey));
905 return E_NOTIMPL;
906 }
907
908 static HRESULT WINAPI WshShortcut_get_IconLocation(IWshShortcut *iface, BSTR *IconPath)
909 {
910 static const WCHAR fmtW[] = {'%','s',',',' ','%','d',0};
911 WshShortcut *This = impl_from_IWshShortcut(iface);
912 WCHAR buffW[MAX_PATH], pathW[MAX_PATH];
913 INT icon = 0;
914 HRESULT hr;
915
916 TRACE("(%p)->(%p)\n", This, IconPath);
917
918 if (!IconPath)
919 return E_POINTER;
920
921 hr = IShellLinkW_GetIconLocation(This->link, buffW, ARRAY_SIZE(buffW), &icon);
922 if (FAILED(hr)) return hr;
923
924 sprintfW(pathW, fmtW, buffW, icon);
925 *IconPath = SysAllocString(pathW);
926 if (!*IconPath) return E_OUTOFMEMORY;
927
928 return S_OK;
929 }
930
931 static HRESULT WINAPI WshShortcut_put_IconLocation(IWshShortcut *iface, BSTR IconPath)
932 {
933 WshShortcut *This = impl_from_IWshShortcut(iface);
934 HRESULT hr;
935 WCHAR *ptr;
936 BSTR path;
937 INT icon;
938
939 TRACE("(%p)->(%s)\n", This, debugstr_w(IconPath));
940
941 /* scan for icon id */
942 ptr = strrchrW(IconPath, ',');
943 if (!ptr)
944 {
945 WARN("icon index not found\n");
946 return E_FAIL;
947 }
948
949 path = SysAllocStringLen(IconPath, ptr-IconPath);
950
951 /* skip spaces if any */
952 while (isspaceW(*++ptr))
953 ;
954
955 icon = atoiW(ptr);
956
957 hr = IShellLinkW_SetIconLocation(This->link, path, icon);
958 SysFreeString(path);
959
960 return hr;
961 }
962
963 static HRESULT WINAPI WshShortcut_put_RelativePath(IWshShortcut *iface, BSTR rhs)
964 {
965 WshShortcut *This = impl_from_IWshShortcut(iface);
966 FIXME("(%p)->(%s): stub\n", This, debugstr_w(rhs));
967 return E_NOTIMPL;
968 }
969
970 static HRESULT WINAPI WshShortcut_get_TargetPath(IWshShortcut *iface, BSTR *Path)
971 {
972 WshShortcut *This = impl_from_IWshShortcut(iface);
973 FIXME("(%p)->(%p): stub\n", This, Path);
974 return E_NOTIMPL;
975 }
976
977 static HRESULT WINAPI WshShortcut_put_TargetPath(IWshShortcut *iface, BSTR Path)
978 {
979 WshShortcut *This = impl_from_IWshShortcut(iface);
980 TRACE("(%p)->(%s)\n", This, debugstr_w(Path));
981 return IShellLinkW_SetPath(This->link, Path);
982 }
983
984 static HRESULT WINAPI WshShortcut_get_WindowStyle(IWshShortcut *iface, int *ShowCmd)
985 {
986 WshShortcut *This = impl_from_IWshShortcut(iface);
987 TRACE("(%p)->(%p)\n", This, ShowCmd);
988 return IShellLinkW_GetShowCmd(This->link, ShowCmd);
989 }
990
991 static HRESULT WINAPI WshShortcut_put_WindowStyle(IWshShortcut *iface, int ShowCmd)
992 {
993 WshShortcut *This = impl_from_IWshShortcut(iface);
994 TRACE("(%p)->(%d)\n", This, ShowCmd);
995 return IShellLinkW_SetShowCmd(This->link, ShowCmd);
996 }
997
998 static HRESULT WINAPI WshShortcut_get_WorkingDirectory(IWshShortcut *iface, BSTR *WorkingDirectory)
999 {
1000 WshShortcut *This = impl_from_IWshShortcut(iface);
1001 WCHAR buffW[MAX_PATH];
1002 HRESULT hr;
1003
1004 TRACE("(%p)->(%p)\n", This, WorkingDirectory);
1005
1006 if (!WorkingDirectory)
1007 return E_POINTER;
1008
1009 *WorkingDirectory = NULL;
1010 hr = IShellLinkW_GetWorkingDirectory(This->link, buffW, ARRAY_SIZE(buffW));
1011 if (FAILED(hr)) return hr;
1012
1013 *WorkingDirectory = SysAllocString(buffW);
1014 return *WorkingDirectory ? S_OK : E_OUTOFMEMORY;
1015 }
1016
1017 static HRESULT WINAPI WshShortcut_put_WorkingDirectory(IWshShortcut *iface, BSTR WorkingDirectory)
1018 {
1019 WshShortcut *This = impl_from_IWshShortcut(iface);
1020 TRACE("(%p)->(%s)\n", This, debugstr_w(WorkingDirectory));
1021 return IShellLinkW_SetWorkingDirectory(This->link, WorkingDirectory);
1022 }
1023
1024 static HRESULT WINAPI WshShortcut_Load(IWshShortcut *iface, BSTR PathLink)
1025 {
1026 WshShortcut *This = impl_from_IWshShortcut(iface);
1027 FIXME("(%p)->(%s): stub\n", This, debugstr_w(PathLink));
1028 return E_NOTIMPL;
1029 }
1030
1031 static HRESULT WINAPI WshShortcut_Save(IWshShortcut *iface)
1032 {
1033 WshShortcut *This = impl_from_IWshShortcut(iface);
1034 IPersistFile *file;
1035 HRESULT hr;
1036
1037 TRACE("(%p)\n", This);
1038
1039 IShellLinkW_QueryInterface(This->link, &IID_IPersistFile, (void**)&file);
1040 hr = IPersistFile_Save(file, This->path_link, TRUE);
1041 IPersistFile_Release(file);
1042
1043 return hr;
1044 }
1045
1046 static const IWshShortcutVtbl WshShortcutVtbl = {
1047 WshShortcut_QueryInterface,
1048 WshShortcut_AddRef,
1049 WshShortcut_Release,
1050 WshShortcut_GetTypeInfoCount,
1051 WshShortcut_GetTypeInfo,
1052 WshShortcut_GetIDsOfNames,
1053 WshShortcut_Invoke,
1054 WshShortcut_get_FullName,
1055 WshShortcut_get_Arguments,
1056 WshShortcut_put_Arguments,
1057 WshShortcut_get_Description,
1058 WshShortcut_put_Description,
1059 WshShortcut_get_Hotkey,
1060 WshShortcut_put_Hotkey,
1061 WshShortcut_get_IconLocation,
1062 WshShortcut_put_IconLocation,
1063 WshShortcut_put_RelativePath,
1064 WshShortcut_get_TargetPath,
1065 WshShortcut_put_TargetPath,
1066 WshShortcut_get_WindowStyle,
1067 WshShortcut_put_WindowStyle,
1068 WshShortcut_get_WorkingDirectory,
1069 WshShortcut_put_WorkingDirectory,
1070 WshShortcut_Load,
1071 WshShortcut_Save
1072 };
1073
1074 static HRESULT WshShortcut_Create(const WCHAR *path, IDispatch **shortcut)
1075 {
1076 WshShortcut *This;
1077 HRESULT hr;
1078
1079 *shortcut = NULL;
1080
1081 This = heap_alloc(sizeof(*This));
1082 if (!This) return E_OUTOFMEMORY;
1083
1084 This->IWshShortcut_iface.lpVtbl = &WshShortcutVtbl;
1085 This->ref = 1;
1086
1087 hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
1088 &IID_IShellLinkW, (void**)&This->link);
1089 if (FAILED(hr))
1090 {
1091 heap_free(This);
1092 return hr;
1093 }
1094
1095 This->path_link = SysAllocString(path);
1096 if (!This->path_link)
1097 {
1098 IShellLinkW_Release(This->link);
1099 heap_free(This);
1100 return E_OUTOFMEMORY;
1101 }
1102
1103 init_classinfo(&IID_IWshShortcut, (IUnknown *)&This->IWshShortcut_iface, &This->classinfo);
1104 *shortcut = (IDispatch*)&This->IWshShortcut_iface;
1105
1106 return S_OK;
1107 }
1108
1109 static HRESULT WINAPI WshShell3_QueryInterface(IWshShell3 *iface, REFIID riid, void **ppv)
1110 {
1111 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
1112
1113 *ppv = NULL;
1114
1115 if (IsEqualGUID(riid, &IID_IDispatch) ||
1116 IsEqualGUID(riid, &IID_IWshShell3) ||
1117 IsEqualGUID(riid, &IID_IWshShell2) ||
1118 IsEqualGUID(riid, &IID_IWshShell) ||
1119 IsEqualGUID(riid, &IID_IUnknown))
1120 {
1121 *ppv = iface;
1122 }
1123 else if (IsEqualGUID(riid, &IID_IDispatchEx))
1124 {
1125 return E_NOINTERFACE;
1126 }
1127 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
1128 {
1129 *ppv = &WshShell3.classinfo.IProvideClassInfo_iface;
1130 }
1131 else
1132 {
1133 WARN("unknown iface %s\n", debugstr_guid(riid));
1134 return E_NOINTERFACE;
1135 }
1136
1137 IUnknown_AddRef((IUnknown *)*ppv);
1138 return S_OK;
1139 }
1140
1141 static ULONG WINAPI WshShell3_AddRef(IWshShell3 *iface)
1142 {
1143 TRACE("()\n");
1144 return 2;
1145 }
1146
1147 static ULONG WINAPI WshShell3_Release(IWshShell3 *iface)
1148 {
1149 TRACE("()\n");
1150 return 2;
1151 }
1152
1153 static HRESULT WINAPI WshShell3_GetTypeInfoCount(IWshShell3 *iface, UINT *pctinfo)
1154 {
1155 TRACE("(%p)\n", pctinfo);
1156 *pctinfo = 1;
1157 return S_OK;
1158 }
1159
1160 static HRESULT WINAPI WshShell3_GetTypeInfo(IWshShell3 *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
1161 {
1162 TRACE("(%u %u %p)\n", iTInfo, lcid, ppTInfo);
1163 return get_typeinfo(IWshShell3_tid, ppTInfo);
1164 }
1165
1166 static HRESULT WINAPI WshShell3_GetIDsOfNames(IWshShell3 *iface, REFIID riid, LPOLESTR *rgszNames,
1167 UINT cNames, LCID lcid, DISPID *rgDispId)
1168 {
1169 ITypeInfo *typeinfo;
1170 HRESULT hr;
1171
1172 TRACE("(%s %p %u %u %p)\n", debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1173
1174 hr = get_typeinfo(IWshShell3_tid, &typeinfo);
1175 if(SUCCEEDED(hr))
1176 {
1177 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1178 ITypeInfo_Release(typeinfo);
1179 }
1180
1181 return hr;
1182 }
1183
1184 static HRESULT WINAPI WshShell3_Invoke(IWshShell3 *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
1185 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
1186 {
1187 ITypeInfo *typeinfo;
1188 HRESULT hr;
1189
1190 TRACE("(%d %s %d %d %p %p %p %p)\n", dispIdMember, debugstr_guid(riid),
1191 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1192
1193 hr = get_typeinfo(IWshShell3_tid, &typeinfo);
1194 if(SUCCEEDED(hr))
1195 {
1196 hr = ITypeInfo_Invoke(typeinfo, &WshShell3.IWshShell3_iface, dispIdMember, wFlags,
1197 pDispParams, pVarResult, pExcepInfo, puArgErr);
1198 ITypeInfo_Release(typeinfo);
1199 }
1200
1201 return hr;
1202 }
1203
1204 static HRESULT WINAPI WshShell3_get_SpecialFolders(IWshShell3 *iface, IWshCollection **folders)
1205 {
1206 TRACE("(%p)\n", folders);
1207 return WshCollection_Create(folders);
1208 }
1209
1210 static HRESULT WINAPI WshShell3_get_Environment(IWshShell3 *iface, VARIANT *type, IWshEnvironment **env)
1211 {
1212 FIXME("(%s %p): semi-stub\n", debugstr_variant(type), env);
1213 return WshEnvironment_Create(env);
1214 }
1215
1216 static inline BOOL is_optional_argument(const VARIANT *arg)
1217 {
1218 return V_VT(arg) == VT_ERROR && V_ERROR(arg) == DISP_E_PARAMNOTFOUND;
1219 }
1220
1221 static HRESULT WINAPI WshShell3_Run(IWshShell3 *iface, BSTR cmd, VARIANT *style, VARIANT *wait, DWORD *exit_code)
1222 {
1223 SHELLEXECUTEINFOW info;
1224 int waitforprocess;
1225 VARIANT s;
1226 HRESULT hr;
1227
1228 TRACE("(%s %s %s %p)\n", debugstr_w(cmd), debugstr_variant(style), debugstr_variant(wait), exit_code);
1229
1230 if (!style || !wait || !exit_code)
1231 return E_POINTER;
1232
1233 VariantInit(&s);
1234 hr = VariantChangeType(&s, style, 0, VT_I4);
1235 if (FAILED(hr))
1236 {
1237 ERR("failed to convert style argument, 0x%08x\n", hr);
1238 return hr;
1239 }
1240
1241 if (is_optional_argument(wait))
1242 waitforprocess = 0;
1243 else {
1244 VARIANT w;
1245
1246 VariantInit(&w);
1247 hr = VariantChangeType(&w, wait, 0, VT_I4);
1248 if (FAILED(hr))
1249 return hr;
1250
1251 waitforprocess = V_I4(&w);
1252 }
1253
1254 memset(&info, 0, sizeof(info));
1255 info.cbSize = sizeof(info);
1256 info.fMask = waitforprocess ? SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS : SEE_MASK_DEFAULT;
1257 info.lpFile = cmd;
1258 info.nShow = V_I4(&s);
1259
1260 if (!ShellExecuteExW(&info))
1261 {
1262 TRACE("ShellExecute failed, %d\n", GetLastError());
1263 return HRESULT_FROM_WIN32(GetLastError());
1264 }
1265 else
1266 {
1267 if (waitforprocess)
1268 {
1269 GetExitCodeProcess(info.hProcess, exit_code);
1270 CloseHandle(info.hProcess);
1271 }
1272 else
1273 *exit_code = 0;
1274
1275 return S_OK;
1276 }
1277 }
1278
1279 struct popup_thread_param
1280 {
1281 WCHAR *text;
1282 VARIANT title;
1283 VARIANT type;
1284 INT button;
1285 };
1286
1287 static DWORD WINAPI popup_thread_proc(void *arg)
1288 {
1289 static const WCHAR defaulttitleW[] = {'W','i','n','d','o','w','s',' ','S','c','r','i','p','t',' ','H','o','s','t',0};
1290 struct popup_thread_param *param = (struct popup_thread_param *)arg;
1291
1292 param->button = MessageBoxW(NULL, param->text, is_optional_argument(&param->title) ?
1293 defaulttitleW : V_BSTR(&param->title), V_I4(&param->type));
1294 return 0;
1295 }
1296
1297 static HRESULT WINAPI WshShell3_Popup(IWshShell3 *iface, BSTR text, VARIANT *seconds_to_wait, VARIANT *title,
1298 VARIANT *type, int *button)
1299 {
1300 struct popup_thread_param param;
1301 DWORD tid, status;
1302 VARIANT timeout;
1303 HANDLE hthread;
1304 HRESULT hr;
1305
1306 TRACE("(%s %s %s %s %p)\n", debugstr_w(text), debugstr_variant(seconds_to_wait), debugstr_variant(title),
1307 debugstr_variant(type), button);
1308
1309 if (!seconds_to_wait || !title || !type || !button)
1310 return E_POINTER;
1311
1312 VariantInit(&timeout);
1313 if (!is_optional_argument(seconds_to_wait))
1314 {
1315 hr = VariantChangeType(&timeout, seconds_to_wait, 0, VT_I4);
1316 if (FAILED(hr))
1317 return hr;
1318 }
1319 #ifdef __REACTOS__
1320 else
1321 {
1322 VariantChangeType(&timeout, &timeout, 0, VT_I4);
1323 }
1324 #endif
1325
1326 VariantInit(&param.type);
1327 if (!is_optional_argument(type))
1328 {
1329 hr = VariantChangeType(&param.type, type, 0, VT_I4);
1330 if (FAILED(hr))
1331 return hr;
1332 }
1333 #ifdef __REACTOS__
1334 else
1335 {
1336 VariantChangeType(&param.type, &param.type, 0, VT_I4);
1337 }
1338 #endif
1339
1340 if (is_optional_argument(title))
1341 param.title = *title;
1342 else
1343 {
1344 VariantInit(&param.title);
1345 hr = VariantChangeType(&param.title, title, 0, VT_BSTR);
1346 if (FAILED(hr))
1347 return hr;
1348 }
1349
1350 param.text = text;
1351 param.button = -1;
1352 hthread = CreateThread(NULL, 0, popup_thread_proc, &param, 0, &tid);
1353 status = MsgWaitForMultipleObjects(1, &hthread, FALSE, V_I4(&timeout) ? V_I4(&timeout) * 1000: INFINITE, 0);
1354 if (status == WAIT_TIMEOUT)
1355 {
1356 PostThreadMessageW(tid, WM_QUIT, 0, 0);
1357 MsgWaitForMultipleObjects(1, &hthread, FALSE, INFINITE, 0);
1358 param.button = -1;
1359 }
1360 *button = param.button;
1361
1362 VariantClear(&param.title);
1363 CloseHandle(hthread);
1364
1365 return S_OK;
1366 }
1367
1368 static HRESULT WINAPI WshShell3_CreateShortcut(IWshShell3 *iface, BSTR PathLink, IDispatch** Shortcut)
1369 {
1370 TRACE("(%s %p)\n", debugstr_w(PathLink), Shortcut);
1371 return WshShortcut_Create(PathLink, Shortcut);
1372 }
1373
1374 static HRESULT WINAPI WshShell3_ExpandEnvironmentStrings(IWshShell3 *iface, BSTR Src, BSTR* Dst)
1375 {
1376 DWORD ret;
1377
1378 TRACE("(%s %p)\n", debugstr_w(Src), Dst);
1379
1380 if (!Src || !Dst) return E_POINTER;
1381
1382 ret = ExpandEnvironmentStringsW(Src, NULL, 0);
1383 *Dst = SysAllocStringLen(NULL, ret);
1384 if (!*Dst) return E_OUTOFMEMORY;
1385
1386 if (ExpandEnvironmentStringsW(Src, *Dst, ret))
1387 return S_OK;
1388 else
1389 {
1390 SysFreeString(*Dst);
1391 *Dst = NULL;
1392 return HRESULT_FROM_WIN32(GetLastError());
1393 }
1394 }
1395
1396 static HKEY get_root_key(const WCHAR *path)
1397 {
1398 static const struct {
1399 const WCHAR full[20];
1400 const WCHAR abbrev[5];
1401 HKEY hkey;
1402 } rootkeys[] = {
1403 { {'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R',0}, {'H','K','C','U',0}, HKEY_CURRENT_USER },
1404 { {'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 },
1405 { {'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T',0}, {'H','K','C','R',0}, HKEY_CLASSES_ROOT },
1406 { {'H','K','E','Y','_','U','S','E','R','S',0}, {0}, HKEY_USERS },
1407 { {'H','K','E','Y','_','C','U','R','R','E','N','T','_','C','O','N','F','I','G',0}, {0}, HKEY_CURRENT_CONFIG }
1408 };
1409 int i;
1410
1411 for (i = 0; i < ARRAY_SIZE(rootkeys); i++) {
1412 if (!strncmpW(path, rootkeys[i].full, strlenW(rootkeys[i].full)))
1413 return rootkeys[i].hkey;
1414 if (rootkeys[i].abbrev[0] && !strncmpW(path, rootkeys[i].abbrev, strlenW(rootkeys[i].abbrev)))
1415 return rootkeys[i].hkey;
1416 }
1417
1418 return NULL;
1419 }
1420
1421 /* Caller is responsible to free 'subkey' if 'value' is not NULL */
1422 static HRESULT split_reg_path(const WCHAR *path, WCHAR **subkey, WCHAR **value)
1423 {
1424 *value = NULL;
1425
1426 /* at least one separator should be present */
1427 *subkey = strchrW(path, '\\');
1428 if (!*subkey)
1429 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1430
1431 /* default value or not */
1432 if ((*subkey)[strlenW(*subkey)-1] == '\\') {
1433 (*subkey)++;
1434 *value = NULL;
1435 }
1436 else {
1437 *value = strrchrW(*subkey, '\\');
1438 if (*value - *subkey > 1) {
1439 unsigned int len = *value - *subkey - 1;
1440 WCHAR *ret;
1441
1442 ret = heap_alloc((len + 1)*sizeof(WCHAR));
1443 if (!ret)
1444 return E_OUTOFMEMORY;
1445
1446 memcpy(ret, *subkey + 1, len*sizeof(WCHAR));
1447 ret[len] = 0;
1448 *subkey = ret;
1449 }
1450 (*value)++;
1451 }
1452
1453 return S_OK;
1454 }
1455
1456 static HRESULT WINAPI WshShell3_RegRead(IWshShell3 *iface, BSTR name, VARIANT *value)
1457 {
1458 DWORD type, datalen, ret;
1459 WCHAR *subkey, *val;
1460 HRESULT hr;
1461 HKEY root;
1462
1463 TRACE("(%s %p)\n", debugstr_w(name), value);
1464
1465 if (!name || !value)
1466 return E_POINTER;
1467
1468 root = get_root_key(name);
1469 if (!root)
1470 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1471
1472 hr = split_reg_path(name, &subkey, &val);
1473 if (FAILED(hr))
1474 return hr;
1475
1476 type = REG_NONE;
1477 datalen = 0;
1478 ret = RegGetValueW(root, subkey, val, RRF_RT_ANY, &type, NULL, &datalen);
1479 if (ret == ERROR_SUCCESS) {
1480 void *data;
1481
1482 data = heap_alloc(datalen);
1483 if (!data) {
1484 hr = E_OUTOFMEMORY;
1485 goto fail;
1486 }
1487
1488 ret = RegGetValueW(root, subkey, val, RRF_RT_ANY, &type, data, &datalen);
1489 if (ret) {
1490 heap_free(data);
1491 hr = HRESULT_FROM_WIN32(ret);
1492 goto fail;
1493 }
1494
1495 switch (type) {
1496 case REG_SZ:
1497 case REG_EXPAND_SZ:
1498 V_VT(value) = VT_BSTR;
1499 V_BSTR(value) = SysAllocString((WCHAR*)data);
1500 if (!V_BSTR(value))
1501 hr = E_OUTOFMEMORY;
1502 break;
1503 case REG_DWORD:
1504 V_VT(value) = VT_I4;
1505 V_I4(value) = *(DWORD*)data;
1506 break;
1507 case REG_BINARY:
1508 {
1509 BYTE *ptr = (BYTE*)data;
1510 SAFEARRAYBOUND bound;
1511 unsigned int i;
1512 SAFEARRAY *sa;
1513 VARIANT *v;
1514
1515 bound.lLbound = 0;
1516 bound.cElements = datalen;
1517 sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
1518 if (!sa)
1519 break;
1520
1521 hr = SafeArrayAccessData(sa, (void**)&v);
1522 if (FAILED(hr)) {
1523 SafeArrayDestroy(sa);
1524 break;
1525 }
1526
1527 for (i = 0; i < datalen; i++) {
1528 V_VT(&v[i]) = VT_UI1;
1529 V_UI1(&v[i]) = ptr[i];
1530 }
1531 SafeArrayUnaccessData(sa);
1532
1533 V_VT(value) = VT_ARRAY|VT_VARIANT;
1534 V_ARRAY(value) = sa;
1535 break;
1536 }
1537 case REG_MULTI_SZ:
1538 {
1539 WCHAR *ptr = (WCHAR*)data;
1540 SAFEARRAYBOUND bound;
1541 SAFEARRAY *sa;
1542 VARIANT *v;
1543
1544 /* get element count first */
1545 bound.lLbound = 0;
1546 bound.cElements = 0;
1547 while (*ptr) {
1548 bound.cElements++;
1549 ptr += strlenW(ptr)+1;
1550 }
1551
1552 sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
1553 if (!sa)
1554 break;
1555
1556 hr = SafeArrayAccessData(sa, (void**)&v);
1557 if (FAILED(hr)) {
1558 SafeArrayDestroy(sa);
1559 break;
1560 }
1561
1562 ptr = (WCHAR*)data;
1563 while (*ptr) {
1564 V_VT(v) = VT_BSTR;
1565 V_BSTR(v) = SysAllocString(ptr);
1566 ptr += strlenW(ptr)+1;
1567 v++;
1568 }
1569
1570 SafeArrayUnaccessData(sa);
1571 V_VT(value) = VT_ARRAY|VT_VARIANT;
1572 V_ARRAY(value) = sa;
1573 break;
1574 }
1575 default:
1576 FIXME("value type %d not supported\n", type);
1577 hr = E_FAIL;
1578 };
1579
1580 heap_free(data);
1581 if (FAILED(hr))
1582 VariantInit(value);
1583 }
1584 else
1585 hr = HRESULT_FROM_WIN32(ret);
1586
1587 fail:
1588 if (val)
1589 heap_free(subkey);
1590 return hr;
1591 }
1592
1593 static HRESULT WINAPI WshShell3_RegWrite(IWshShell3 *iface, BSTR name, VARIANT *value, VARIANT *type)
1594 {
1595 static const WCHAR regexpandszW[] = {'R','E','G','_','E','X','P','A','N','D','_','S','Z',0};
1596 static const WCHAR regszW[] = {'R','E','G','_','S','Z',0};
1597 static const WCHAR regdwordW[] = {'R','E','G','_','D','W','O','R','D',0};
1598 static const WCHAR regbinaryW[] = {'R','E','G','_','B','I','N','A','R','Y',0};
1599
1600 DWORD regtype, data_len;
1601 WCHAR *subkey, *val;
1602 const BYTE *data;
1603 HRESULT hr;
1604 HKEY root;
1605 VARIANT v;
1606 LONG ret;
1607
1608 TRACE("(%s %s %s)\n", debugstr_w(name), debugstr_variant(value), debugstr_variant(type));
1609
1610 if (!name || !value || !type)
1611 return E_POINTER;
1612
1613 root = get_root_key(name);
1614 if (!root)
1615 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1616
1617 /* value type */
1618 if (is_optional_argument(type))
1619 regtype = REG_SZ;
1620 else {
1621 if (V_VT(type) != VT_BSTR)
1622 return E_INVALIDARG;
1623
1624 if (!strcmpW(V_BSTR(type), regszW))
1625 regtype = REG_SZ;
1626 else if (!strcmpW(V_BSTR(type), regdwordW))
1627 regtype = REG_DWORD;
1628 else if (!strcmpW(V_BSTR(type), regexpandszW))
1629 regtype = REG_EXPAND_SZ;
1630 else if (!strcmpW(V_BSTR(type), regbinaryW))
1631 regtype = REG_BINARY;
1632 else {
1633 FIXME("unrecognized value type %s\n", debugstr_w(V_BSTR(type)));
1634 return E_FAIL;
1635 }
1636 }
1637
1638 /* it's always a string or a DWORD */
1639 VariantInit(&v);
1640 switch (regtype)
1641 {
1642 case REG_SZ:
1643 case REG_EXPAND_SZ:
1644 hr = VariantChangeType(&v, value, 0, VT_BSTR);
1645 if (hr == S_OK) {
1646 data = (BYTE*)V_BSTR(&v);
1647 data_len = SysStringByteLen(V_BSTR(&v)) + sizeof(WCHAR);
1648 }
1649 break;
1650 case REG_DWORD:
1651 case REG_BINARY:
1652 hr = VariantChangeType(&v, value, 0, VT_I4);
1653 data = (BYTE*)&V_I4(&v);
1654 data_len = sizeof(DWORD);
1655 break;
1656 default:
1657 FIXME("unexpected regtype %d\n", regtype);
1658 return E_FAIL;
1659 };
1660
1661 if (FAILED(hr)) {
1662 FIXME("failed to convert value, regtype %d, 0x%08x\n", regtype, hr);
1663 return hr;
1664 }
1665
1666 hr = split_reg_path(name, &subkey, &val);
1667 if (FAILED(hr))
1668 goto fail;
1669
1670 ret = RegSetKeyValueW(root, subkey, val, regtype, data, data_len);
1671 if (ret)
1672 hr = HRESULT_FROM_WIN32(ret);
1673
1674 fail:
1675 VariantClear(&v);
1676 if (val)
1677 heap_free(subkey);
1678 return hr;
1679 }
1680
1681 static HRESULT WINAPI WshShell3_RegDelete(IWshShell3 *iface, BSTR Name)
1682 {
1683 FIXME("(%s): stub\n", debugstr_w(Name));
1684 return E_NOTIMPL;
1685 }
1686
1687 static HRESULT WINAPI WshShell3_LogEvent(IWshShell3 *iface, VARIANT *Type, BSTR Message, BSTR Target, VARIANT_BOOL *out_Success)
1688 {
1689 FIXME("(%s %s %s %p): stub\n", debugstr_variant(Type), debugstr_w(Message), debugstr_w(Target), out_Success);
1690 return E_NOTIMPL;
1691 }
1692
1693 static HRESULT WINAPI WshShell3_AppActivate(IWshShell3 *iface, VARIANT *App, VARIANT *Wait, VARIANT_BOOL *out_Success)
1694 {
1695 FIXME("(%s %s %p): stub\n", debugstr_variant(App), debugstr_variant(Wait), out_Success);
1696 return E_NOTIMPL;
1697 }
1698
1699 static HRESULT WINAPI WshShell3_SendKeys(IWshShell3 *iface, BSTR Keys, VARIANT *Wait)
1700 {
1701 FIXME("(%s %p): stub\n", debugstr_w(Keys), Wait);
1702 return E_NOTIMPL;
1703 }
1704
1705 static HRESULT WINAPI WshShell3_Exec(IWshShell3 *iface, BSTR command, IWshExec **ret)
1706 {
1707 TRACE("(%s %p)\n", debugstr_w(command), ret);
1708
1709 if (!ret)
1710 return E_POINTER;
1711
1712 if (!command)
1713 return DISP_E_EXCEPTION;
1714
1715 return WshExec_create(command, ret);
1716 }
1717
1718 static HRESULT WINAPI WshShell3_get_CurrentDirectory(IWshShell3 *iface, BSTR *dir)
1719 {
1720 DWORD ret;
1721
1722 TRACE("(%p)\n", dir);
1723
1724 ret = GetCurrentDirectoryW(0, NULL);
1725 if (!ret)
1726 return HRESULT_FROM_WIN32(GetLastError());
1727
1728 *dir = SysAllocStringLen(NULL, ret-1);
1729 if (!*dir)
1730 return E_OUTOFMEMORY;
1731
1732 ret = GetCurrentDirectoryW(ret, *dir);
1733 if (!ret) {
1734 SysFreeString(*dir);
1735 *dir = NULL;
1736 return HRESULT_FROM_WIN32(GetLastError());
1737 }
1738
1739 return S_OK;
1740 }
1741
1742 static HRESULT WINAPI WshShell3_put_CurrentDirectory(IWshShell3 *iface, BSTR dir)
1743 {
1744 TRACE("(%s)\n", debugstr_w(dir));
1745
1746 if (!dir)
1747 return E_INVALIDARG;
1748
1749 if (!SetCurrentDirectoryW(dir))
1750 return HRESULT_FROM_WIN32(GetLastError());
1751
1752 return S_OK;
1753 }
1754
1755 static const IWshShell3Vtbl WshShell3Vtbl = {
1756 WshShell3_QueryInterface,
1757 WshShell3_AddRef,
1758 WshShell3_Release,
1759 WshShell3_GetTypeInfoCount,
1760 WshShell3_GetTypeInfo,
1761 WshShell3_GetIDsOfNames,
1762 WshShell3_Invoke,
1763 WshShell3_get_SpecialFolders,
1764 WshShell3_get_Environment,
1765 WshShell3_Run,
1766 WshShell3_Popup,
1767 WshShell3_CreateShortcut,
1768 WshShell3_ExpandEnvironmentStrings,
1769 WshShell3_RegRead,
1770 WshShell3_RegWrite,
1771 WshShell3_RegDelete,
1772 WshShell3_LogEvent,
1773 WshShell3_AppActivate,
1774 WshShell3_SendKeys,
1775 WshShell3_Exec,
1776 WshShell3_get_CurrentDirectory,
1777 WshShell3_put_CurrentDirectory
1778 };
1779
1780 HRESULT WINAPI WshShellFactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
1781 {
1782 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
1783
1784 WshShell3.IWshShell3_iface.lpVtbl = &WshShell3Vtbl;
1785 init_classinfo(&IID_IWshShell3, (IUnknown *)&WshShell3.IWshShell3_iface, &WshShell3.classinfo);
1786 return IWshShell3_QueryInterface(&WshShell3.IWshShell3_iface, riid, ppv);
1787 }