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