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