d2d1: Add a helper to set error state.
[wine.git] / dlls / wshom.ocx / shell.c
blob1aa353a17a381d2e6d7ca7b0a5c51eea265506bb
1 /*
2 * Copyright 2011 Jacek Caban for CodeWeavers
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.
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.
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
19 #include "wshom_private.h"
20 #include "wshom.h"
22 #include "shellapi.h"
23 #include "shlobj.h"
24 #include "dispex.h"
26 #include "wine/debug.h"
27 #include "wine/heap.h"
28 #include "wine/unicode.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(wshom);
32 typedef struct
34 struct provideclassinfo classinfo;
35 IWshShell3 IWshShell3_iface;
36 } WshShellImpl;
37 static WshShellImpl WshShell3;
39 typedef struct
41 struct provideclassinfo classinfo;
42 IWshCollection IWshCollection_iface;
43 LONG ref;
44 } WshCollection;
46 typedef struct
48 struct provideclassinfo classinfo;
49 IWshShortcut IWshShortcut_iface;
50 LONG ref;
52 IShellLinkW *link;
53 BSTR path_link;
54 } WshShortcut;
56 typedef struct
58 struct provideclassinfo classinfo;
59 IWshEnvironment IWshEnvironment_iface;
60 LONG ref;
61 } WshEnvironment;
63 typedef struct
65 struct provideclassinfo classinfo;
66 IWshExec IWshExec_iface;
67 LONG ref;
68 PROCESS_INFORMATION info;
69 } WshExecImpl;
71 static inline WshCollection *impl_from_IWshCollection( IWshCollection *iface )
73 return CONTAINING_RECORD(iface, WshCollection, IWshCollection_iface);
76 static inline WshShortcut *impl_from_IWshShortcut( IWshShortcut *iface )
78 return CONTAINING_RECORD(iface, WshShortcut, IWshShortcut_iface);
81 static inline WshEnvironment *impl_from_IWshEnvironment( IWshEnvironment *iface )
83 return CONTAINING_RECORD(iface, WshEnvironment, IWshEnvironment_iface);
86 static inline WshExecImpl *impl_from_IWshExec( IWshExec *iface )
88 return CONTAINING_RECORD(iface, WshExecImpl, IWshExec_iface);
91 static HRESULT WINAPI WshExec_QueryInterface(IWshExec *iface, REFIID riid, void **obj)
93 WshExecImpl *This = impl_from_IWshExec(iface);
95 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), obj);
97 if (IsEqualGUID(riid, &IID_IDispatch) ||
98 IsEqualGUID(riid, &IID_IWshExec) ||
99 IsEqualGUID(riid, &IID_IUnknown))
101 *obj = iface;
103 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
105 *obj = &This->classinfo.IProvideClassInfo_iface;
107 else {
108 FIXME("Unknown iface %s\n", debugstr_guid(riid));
109 *obj = NULL;
110 return E_NOINTERFACE;
113 IUnknown_AddRef((IUnknown *)*obj);
114 return S_OK;
117 static ULONG WINAPI WshExec_AddRef(IWshExec *iface)
119 WshExecImpl *This = impl_from_IWshExec(iface);
120 LONG ref = InterlockedIncrement(&This->ref);
121 TRACE("(%p) ref = %d\n", This, ref);
122 return ref;
125 static ULONG WINAPI WshExec_Release(IWshExec *iface)
127 WshExecImpl *This = impl_from_IWshExec(iface);
128 LONG ref = InterlockedDecrement(&This->ref);
129 TRACE("(%p) ref = %d\n", This, ref);
131 if (!ref) {
132 CloseHandle(This->info.hThread);
133 CloseHandle(This->info.hProcess);
134 heap_free(This);
137 return ref;
140 static HRESULT WINAPI WshExec_GetTypeInfoCount(IWshExec *iface, UINT *pctinfo)
142 WshExecImpl *This = impl_from_IWshExec(iface);
143 TRACE("(%p)->(%p)\n", This, pctinfo);
144 *pctinfo = 1;
145 return S_OK;
148 static HRESULT WINAPI WshExec_GetTypeInfo(IWshExec *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
150 WshExecImpl *This = impl_from_IWshExec(iface);
151 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
152 return get_typeinfo(IWshExec_tid, ppTInfo);
155 static HRESULT WINAPI WshExec_GetIDsOfNames(IWshExec *iface, REFIID riid, LPOLESTR *rgszNames,
156 UINT cNames, LCID lcid, DISPID *rgDispId)
158 WshExecImpl *This = impl_from_IWshExec(iface);
159 ITypeInfo *typeinfo;
160 HRESULT hr;
162 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
164 hr = get_typeinfo(IWshExec_tid, &typeinfo);
165 if(SUCCEEDED(hr))
167 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
168 ITypeInfo_Release(typeinfo);
171 return hr;
174 static HRESULT WINAPI WshExec_Invoke(IWshExec *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
175 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
177 WshExecImpl *This = impl_from_IWshExec(iface);
178 ITypeInfo *typeinfo;
179 HRESULT hr;
181 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
182 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
184 hr = get_typeinfo(IWshExec_tid, &typeinfo);
185 if(SUCCEEDED(hr))
187 hr = ITypeInfo_Invoke(typeinfo, &This->IWshExec_iface, dispIdMember, wFlags,
188 pDispParams, pVarResult, pExcepInfo, puArgErr);
189 ITypeInfo_Release(typeinfo);
192 return hr;
195 static HRESULT WINAPI WshExec_get_Status(IWshExec *iface, WshExecStatus *status)
197 WshExecImpl *This = impl_from_IWshExec(iface);
198 DWORD code;
200 TRACE("(%p)->(%p)\n", This, status);
202 if (!status)
203 return E_INVALIDARG;
205 if (!GetExitCodeProcess(This->info.hProcess, &code))
206 return HRESULT_FROM_WIN32(GetLastError());
208 switch (code)
210 case 0:
211 *status = WshFinished;
212 break;
213 case STILL_ACTIVE:
214 *status = WshRunning;
215 break;
216 default:
217 *status = WshFailed;
220 return S_OK;
223 static HRESULT WINAPI WshExec_get_StdIn(IWshExec *iface, ITextStream **stream)
225 WshExecImpl *This = impl_from_IWshExec(iface);
227 FIXME("(%p)->(%p): stub\n", This, stream);
229 return E_NOTIMPL;
232 static HRESULT WINAPI WshExec_get_StdOut(IWshExec *iface, ITextStream **stream)
234 WshExecImpl *This = impl_from_IWshExec(iface);
236 FIXME("(%p)->(%p): stub\n", This, stream);
238 return E_NOTIMPL;
241 static HRESULT WINAPI WshExec_get_StdErr(IWshExec *iface, ITextStream **stream)
243 WshExecImpl *This = impl_from_IWshExec(iface);
245 FIXME("(%p)->(%p): stub\n", This, stream);
247 return E_NOTIMPL;
250 static HRESULT WINAPI WshExec_get_ProcessID(IWshExec *iface, DWORD *pid)
252 WshExecImpl *This = impl_from_IWshExec(iface);
254 TRACE("(%p)->(%p)\n", This, pid);
256 if (!pid)
257 return E_INVALIDARG;
259 *pid = This->info.dwProcessId;
260 return S_OK;
263 static HRESULT WINAPI WshExec_get_ExitCode(IWshExec *iface, DWORD *code)
265 WshExecImpl *This = impl_from_IWshExec(iface);
267 FIXME("(%p)->(%p): stub\n", This, code);
269 return E_NOTIMPL;
272 static BOOL CALLBACK enum_thread_wnd_proc(HWND hwnd, LPARAM lParam)
274 INT *count = (INT*)lParam;
276 (*count)++;
277 PostMessageW(hwnd, WM_CLOSE, 0, 0);
278 /* try to send it to all windows, even if failed for some */
279 return TRUE;
282 static HRESULT WINAPI WshExec_Terminate(IWshExec *iface)
284 WshExecImpl *This = impl_from_IWshExec(iface);
285 BOOL ret, kill = FALSE;
286 INT count = 0;
288 TRACE("(%p)\n", This);
290 ret = EnumThreadWindows(This->info.dwThreadId, enum_thread_wnd_proc, (LPARAM)&count);
291 if (ret && count) {
292 /* manual testing shows that it waits 2 seconds before forcing termination */
293 if (WaitForSingleObject(This->info.hProcess, 2000) != WAIT_OBJECT_0)
294 kill = TRUE;
296 else
297 kill = TRUE;
299 if (kill)
300 TerminateProcess(This->info.hProcess, 0);
302 return S_OK;
305 static const IWshExecVtbl WshExecVtbl = {
306 WshExec_QueryInterface,
307 WshExec_AddRef,
308 WshExec_Release,
309 WshExec_GetTypeInfoCount,
310 WshExec_GetTypeInfo,
311 WshExec_GetIDsOfNames,
312 WshExec_Invoke,
313 WshExec_get_Status,
314 WshExec_get_StdIn,
315 WshExec_get_StdOut,
316 WshExec_get_StdErr,
317 WshExec_get_ProcessID,
318 WshExec_get_ExitCode,
319 WshExec_Terminate
322 static HRESULT WshExec_create(BSTR command, IWshExec **ret)
324 STARTUPINFOW si = {0};
325 WshExecImpl *This;
327 *ret = NULL;
329 This = heap_alloc(sizeof(*This));
330 if (!This)
331 return E_OUTOFMEMORY;
333 This->IWshExec_iface.lpVtbl = &WshExecVtbl;
334 This->ref = 1;
336 if (!CreateProcessW(NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &This->info)) {
337 heap_free(This);
338 return HRESULT_FROM_WIN32(GetLastError());
341 init_classinfo(&CLSID_WshExec, (IUnknown *)&This->IWshExec_iface, &This->classinfo);
342 *ret = &This->IWshExec_iface;
343 return S_OK;
346 static HRESULT WINAPI WshEnvironment_QueryInterface(IWshEnvironment *iface, REFIID riid, void **obj)
348 WshEnvironment *This = impl_from_IWshEnvironment(iface);
350 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), obj);
352 if (IsEqualGUID(riid, &IID_IUnknown) ||
353 IsEqualGUID(riid, &IID_IDispatch) ||
354 IsEqualGUID(riid, &IID_IWshEnvironment))
356 *obj = iface;
358 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
360 *obj = &This->classinfo.IProvideClassInfo_iface;
362 else {
363 FIXME("Unknown iface %s\n", debugstr_guid(riid));
364 *obj = NULL;
365 return E_NOINTERFACE;
368 IUnknown_AddRef((IUnknown*)*obj);
369 return S_OK;
372 static ULONG WINAPI WshEnvironment_AddRef(IWshEnvironment *iface)
374 WshEnvironment *This = impl_from_IWshEnvironment(iface);
375 LONG ref = InterlockedIncrement(&This->ref);
376 TRACE("(%p) ref = %d\n", This, ref);
377 return ref;
380 static ULONG WINAPI WshEnvironment_Release(IWshEnvironment *iface)
382 WshEnvironment *This = impl_from_IWshEnvironment(iface);
383 LONG ref = InterlockedDecrement(&This->ref);
384 TRACE("(%p) ref = %d\n", This, ref);
386 if (!ref)
387 heap_free(This);
389 return ref;
392 static HRESULT WINAPI WshEnvironment_GetTypeInfoCount(IWshEnvironment *iface, UINT *pctinfo)
394 WshEnvironment *This = impl_from_IWshEnvironment(iface);
395 TRACE("(%p)->(%p)\n", This, pctinfo);
396 *pctinfo = 1;
397 return S_OK;
400 static HRESULT WINAPI WshEnvironment_GetTypeInfo(IWshEnvironment *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
402 WshEnvironment *This = impl_from_IWshEnvironment(iface);
403 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
404 return get_typeinfo(IWshEnvironment_tid, ppTInfo);
407 static HRESULT WINAPI WshEnvironment_GetIDsOfNames(IWshEnvironment *iface, REFIID riid, LPOLESTR *rgszNames,
408 UINT cNames, LCID lcid, DISPID *rgDispId)
410 WshEnvironment *This = impl_from_IWshEnvironment(iface);
411 ITypeInfo *typeinfo;
412 HRESULT hr;
414 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
416 hr = get_typeinfo(IWshEnvironment_tid, &typeinfo);
417 if(SUCCEEDED(hr))
419 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
420 ITypeInfo_Release(typeinfo);
423 return hr;
426 static HRESULT WINAPI WshEnvironment_Invoke(IWshEnvironment *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
427 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
429 WshEnvironment *This = impl_from_IWshEnvironment(iface);
430 ITypeInfo *typeinfo;
431 HRESULT hr;
433 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
434 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
436 hr = get_typeinfo(IWshEnvironment_tid, &typeinfo);
437 if(SUCCEEDED(hr))
439 hr = ITypeInfo_Invoke(typeinfo, &This->IWshEnvironment_iface, dispIdMember, wFlags,
440 pDispParams, pVarResult, pExcepInfo, puArgErr);
441 ITypeInfo_Release(typeinfo);
444 return hr;
447 static HRESULT WINAPI WshEnvironment_get_Item(IWshEnvironment *iface, BSTR name, BSTR *value)
449 WshEnvironment *This = impl_from_IWshEnvironment(iface);
450 DWORD len;
452 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), value);
454 if (!value)
455 return E_POINTER;
457 len = GetEnvironmentVariableW(name, NULL, 0);
458 *value = SysAllocStringLen(NULL, len);
459 if (!*value)
460 return E_OUTOFMEMORY;
462 if (len)
463 GetEnvironmentVariableW(name, *value, len+1);
465 return S_OK;
468 static HRESULT WINAPI WshEnvironment_put_Item(IWshEnvironment *iface, BSTR name, BSTR value)
470 WshEnvironment *This = impl_from_IWshEnvironment(iface);
471 FIXME("(%p)->(%s %s): stub\n", This, debugstr_w(name), debugstr_w(value));
472 return E_NOTIMPL;
475 static HRESULT WINAPI WshEnvironment_Count(IWshEnvironment *iface, LONG *count)
477 WshEnvironment *This = impl_from_IWshEnvironment(iface);
478 FIXME("(%p)->(%p): stub\n", This, count);
479 return E_NOTIMPL;
482 static HRESULT WINAPI WshEnvironment_get_length(IWshEnvironment *iface, LONG *len)
484 WshEnvironment *This = impl_from_IWshEnvironment(iface);
485 FIXME("(%p)->(%p): stub\n", This, len);
486 return E_NOTIMPL;
489 static HRESULT WINAPI WshEnvironment__NewEnum(IWshEnvironment *iface, IUnknown **penum)
491 WshEnvironment *This = impl_from_IWshEnvironment(iface);
492 FIXME("(%p)->(%p): stub\n", This, penum);
493 return E_NOTIMPL;
496 static HRESULT WINAPI WshEnvironment_Remove(IWshEnvironment *iface, BSTR name)
498 WshEnvironment *This = impl_from_IWshEnvironment(iface);
499 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
500 return E_NOTIMPL;
503 static const IWshEnvironmentVtbl WshEnvironmentVtbl = {
504 WshEnvironment_QueryInterface,
505 WshEnvironment_AddRef,
506 WshEnvironment_Release,
507 WshEnvironment_GetTypeInfoCount,
508 WshEnvironment_GetTypeInfo,
509 WshEnvironment_GetIDsOfNames,
510 WshEnvironment_Invoke,
511 WshEnvironment_get_Item,
512 WshEnvironment_put_Item,
513 WshEnvironment_Count,
514 WshEnvironment_get_length,
515 WshEnvironment__NewEnum,
516 WshEnvironment_Remove
519 static HRESULT WshEnvironment_Create(IWshEnvironment **env)
521 WshEnvironment *This;
523 This = heap_alloc(sizeof(*This));
524 if (!This) return E_OUTOFMEMORY;
526 This->IWshEnvironment_iface.lpVtbl = &WshEnvironmentVtbl;
527 This->ref = 1;
529 init_classinfo(&IID_IWshEnvironment, (IUnknown *)&This->IWshEnvironment_iface, &This->classinfo);
530 *env = &This->IWshEnvironment_iface;
532 return S_OK;
535 static HRESULT WINAPI WshCollection_QueryInterface(IWshCollection *iface, REFIID riid, void **ppv)
537 WshCollection *This = impl_from_IWshCollection(iface);
539 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
541 if (IsEqualGUID(riid, &IID_IUnknown) ||
542 IsEqualGUID(riid, &IID_IDispatch) ||
543 IsEqualGUID(riid, &IID_IWshCollection))
545 *ppv = iface;
547 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
549 *ppv = &This->classinfo.IProvideClassInfo_iface;
551 else {
552 FIXME("Unknown iface %s\n", debugstr_guid(riid));
553 *ppv = NULL;
554 return E_NOINTERFACE;
557 IUnknown_AddRef((IUnknown*)*ppv);
558 return S_OK;
561 static ULONG WINAPI WshCollection_AddRef(IWshCollection *iface)
563 WshCollection *This = impl_from_IWshCollection(iface);
564 LONG ref = InterlockedIncrement(&This->ref);
565 TRACE("(%p) ref = %d\n", This, ref);
566 return ref;
569 static ULONG WINAPI WshCollection_Release(IWshCollection *iface)
571 WshCollection *This = impl_from_IWshCollection(iface);
572 LONG ref = InterlockedDecrement(&This->ref);
573 TRACE("(%p) ref = %d\n", This, ref);
575 if (!ref)
576 heap_free(This);
578 return ref;
581 static HRESULT WINAPI WshCollection_GetTypeInfoCount(IWshCollection *iface, UINT *pctinfo)
583 WshCollection *This = impl_from_IWshCollection(iface);
584 TRACE("(%p)->(%p)\n", This, pctinfo);
585 *pctinfo = 1;
586 return S_OK;
589 static HRESULT WINAPI WshCollection_GetTypeInfo(IWshCollection *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
591 WshCollection *This = impl_from_IWshCollection(iface);
592 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
593 return get_typeinfo(IWshCollection_tid, ppTInfo);
596 static HRESULT WINAPI WshCollection_GetIDsOfNames(IWshCollection *iface, REFIID riid, LPOLESTR *rgszNames,
597 UINT cNames, LCID lcid, DISPID *rgDispId)
599 WshCollection *This = impl_from_IWshCollection(iface);
600 ITypeInfo *typeinfo;
601 HRESULT hr;
603 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
605 hr = get_typeinfo(IWshCollection_tid, &typeinfo);
606 if(SUCCEEDED(hr))
608 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
609 ITypeInfo_Release(typeinfo);
612 return hr;
615 static HRESULT WINAPI WshCollection_Invoke(IWshCollection *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
616 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
618 WshCollection *This = impl_from_IWshCollection(iface);
619 ITypeInfo *typeinfo;
620 HRESULT hr;
622 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
623 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
625 hr = get_typeinfo(IWshCollection_tid, &typeinfo);
626 if(SUCCEEDED(hr))
628 hr = ITypeInfo_Invoke(typeinfo, &This->IWshCollection_iface, dispIdMember, wFlags,
629 pDispParams, pVarResult, pExcepInfo, puArgErr);
630 ITypeInfo_Release(typeinfo);
633 return hr;
636 static HRESULT WINAPI WshCollection_Item(IWshCollection *iface, VARIANT *index, VARIANT *value)
638 WshCollection *This = impl_from_IWshCollection(iface);
639 static const WCHAR allusersdesktopW[] = {'A','l','l','U','s','e','r','s','D','e','s','k','t','o','p',0};
640 static const WCHAR allusersprogramsW[] = {'A','l','l','U','s','e','r','s','P','r','o','g','r','a','m','s',0};
641 static const WCHAR desktopW[] = {'D','e','s','k','t','o','p',0};
642 PIDLIST_ABSOLUTE pidl;
643 WCHAR pathW[MAX_PATH];
644 int kind = 0;
645 BSTR folder;
646 HRESULT hr;
648 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(index), value);
650 if (V_VT(index) != VT_BSTR)
652 FIXME("only BSTR index supported, got %d\n", V_VT(index));
653 return E_NOTIMPL;
656 folder = V_BSTR(index);
657 if (!strcmpiW(folder, desktopW))
658 kind = CSIDL_DESKTOP;
659 else if (!strcmpiW(folder, allusersdesktopW))
660 kind = CSIDL_COMMON_DESKTOPDIRECTORY;
661 else if (!strcmpiW(folder, allusersprogramsW))
662 kind = CSIDL_COMMON_PROGRAMS;
663 else
665 FIXME("folder kind %s not supported\n", debugstr_w(folder));
666 return E_NOTIMPL;
669 hr = SHGetSpecialFolderLocation(NULL, kind, &pidl);
670 if (hr != S_OK) return hr;
672 if (SHGetPathFromIDListW(pidl, pathW))
674 V_VT(value) = VT_BSTR;
675 V_BSTR(value) = SysAllocString(pathW);
676 hr = V_BSTR(value) ? S_OK : E_OUTOFMEMORY;
678 else
679 hr = E_FAIL;
681 CoTaskMemFree(pidl);
683 return hr;
686 static HRESULT WINAPI WshCollection_Count(IWshCollection *iface, LONG *count)
688 WshCollection *This = impl_from_IWshCollection(iface);
689 FIXME("(%p)->(%p): stub\n", This, count);
690 return E_NOTIMPL;
693 static HRESULT WINAPI WshCollection_get_length(IWshCollection *iface, LONG *count)
695 WshCollection *This = impl_from_IWshCollection(iface);
696 FIXME("(%p)->(%p): stub\n", This, count);
697 return E_NOTIMPL;
700 static HRESULT WINAPI WshCollection__NewEnum(IWshCollection *iface, IUnknown *Enum)
702 WshCollection *This = impl_from_IWshCollection(iface);
703 FIXME("(%p)->(%p): stub\n", This, Enum);
704 return E_NOTIMPL;
707 static const IWshCollectionVtbl WshCollectionVtbl = {
708 WshCollection_QueryInterface,
709 WshCollection_AddRef,
710 WshCollection_Release,
711 WshCollection_GetTypeInfoCount,
712 WshCollection_GetTypeInfo,
713 WshCollection_GetIDsOfNames,
714 WshCollection_Invoke,
715 WshCollection_Item,
716 WshCollection_Count,
717 WshCollection_get_length,
718 WshCollection__NewEnum
721 static HRESULT WshCollection_Create(IWshCollection **collection)
723 WshCollection *This;
725 This = heap_alloc(sizeof(*This));
726 if (!This) return E_OUTOFMEMORY;
728 This->IWshCollection_iface.lpVtbl = &WshCollectionVtbl;
729 This->ref = 1;
731 init_classinfo(&IID_IWshCollection, (IUnknown *)&This->IWshCollection_iface, &This->classinfo);
732 *collection = &This->IWshCollection_iface;
734 return S_OK;
737 /* IWshShortcut */
738 static HRESULT WINAPI WshShortcut_QueryInterface(IWshShortcut *iface, REFIID riid, void **ppv)
740 WshShortcut *This = impl_from_IWshShortcut(iface);
742 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
744 if (IsEqualGUID(riid, &IID_IUnknown) ||
745 IsEqualGUID(riid, &IID_IDispatch) ||
746 IsEqualGUID(riid, &IID_IWshShortcut))
748 *ppv = iface;
750 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
752 *ppv = &This->classinfo.IProvideClassInfo_iface;
754 else {
755 FIXME("Unknown iface %s\n", debugstr_guid(riid));
756 *ppv = NULL;
757 return E_NOINTERFACE;
760 IUnknown_AddRef((IUnknown*)*ppv);
761 return S_OK;
764 static ULONG WINAPI WshShortcut_AddRef(IWshShortcut *iface)
766 WshShortcut *This = impl_from_IWshShortcut(iface);
767 LONG ref = InterlockedIncrement(&This->ref);
768 TRACE("(%p) ref = %d\n", This, ref);
769 return ref;
772 static ULONG WINAPI WshShortcut_Release(IWshShortcut *iface)
774 WshShortcut *This = impl_from_IWshShortcut(iface);
775 LONG ref = InterlockedDecrement(&This->ref);
776 TRACE("(%p) ref = %d\n", This, ref);
778 if (!ref)
780 SysFreeString(This->path_link);
781 IShellLinkW_Release(This->link);
782 heap_free(This);
785 return ref;
788 static HRESULT WINAPI WshShortcut_GetTypeInfoCount(IWshShortcut *iface, UINT *pctinfo)
790 WshShortcut *This = impl_from_IWshShortcut(iface);
791 TRACE("(%p)->(%p)\n", This, pctinfo);
792 *pctinfo = 1;
793 return S_OK;
796 static HRESULT WINAPI WshShortcut_GetTypeInfo(IWshShortcut *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
798 WshShortcut *This = impl_from_IWshShortcut(iface);
799 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
800 return get_typeinfo(IWshShortcut_tid, ppTInfo);
803 static HRESULT WINAPI WshShortcut_GetIDsOfNames(IWshShortcut *iface, REFIID riid, LPOLESTR *rgszNames,
804 UINT cNames, LCID lcid, DISPID *rgDispId)
806 WshShortcut *This = impl_from_IWshShortcut(iface);
807 ITypeInfo *typeinfo;
808 HRESULT hr;
810 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
812 hr = get_typeinfo(IWshShortcut_tid, &typeinfo);
813 if(SUCCEEDED(hr))
815 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
816 ITypeInfo_Release(typeinfo);
819 return hr;
822 static HRESULT WINAPI WshShortcut_Invoke(IWshShortcut *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
823 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
825 WshShortcut *This = impl_from_IWshShortcut(iface);
826 ITypeInfo *typeinfo;
827 HRESULT hr;
829 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
830 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
832 hr = get_typeinfo(IWshShortcut_tid, &typeinfo);
833 if(SUCCEEDED(hr))
835 hr = ITypeInfo_Invoke(typeinfo, &This->IWshShortcut_iface, dispIdMember, wFlags,
836 pDispParams, pVarResult, pExcepInfo, puArgErr);
837 ITypeInfo_Release(typeinfo);
840 return hr;
843 static HRESULT WINAPI WshShortcut_get_FullName(IWshShortcut *iface, BSTR *name)
845 WshShortcut *This = impl_from_IWshShortcut(iface);
846 FIXME("(%p)->(%p): stub\n", This, name);
847 return E_NOTIMPL;
850 static HRESULT WINAPI WshShortcut_get_Arguments(IWshShortcut *iface, BSTR *Arguments)
852 WshShortcut *This = impl_from_IWshShortcut(iface);
853 WCHAR buffW[INFOTIPSIZE];
854 HRESULT hr;
856 TRACE("(%p)->(%p)\n", This, Arguments);
858 if (!Arguments)
859 return E_POINTER;
861 *Arguments = NULL;
863 hr = IShellLinkW_GetArguments(This->link, buffW, ARRAY_SIZE(buffW));
864 if (FAILED(hr))
865 return hr;
867 *Arguments = SysAllocString(buffW);
868 return *Arguments ? S_OK : E_OUTOFMEMORY;
871 static HRESULT WINAPI WshShortcut_put_Arguments(IWshShortcut *iface, BSTR Arguments)
873 WshShortcut *This = impl_from_IWshShortcut(iface);
875 TRACE("(%p)->(%s)\n", This, debugstr_w(Arguments));
877 return IShellLinkW_SetArguments(This->link, Arguments);
880 static HRESULT WINAPI WshShortcut_get_Description(IWshShortcut *iface, BSTR *Description)
882 WshShortcut *This = impl_from_IWshShortcut(iface);
883 FIXME("(%p)->(%p): stub\n", This, Description);
884 return E_NOTIMPL;
887 static HRESULT WINAPI WshShortcut_put_Description(IWshShortcut *iface, BSTR Description)
889 WshShortcut *This = impl_from_IWshShortcut(iface);
890 TRACE("(%p)->(%s)\n", This, debugstr_w(Description));
891 return IShellLinkW_SetDescription(This->link, Description);
894 static HRESULT WINAPI WshShortcut_get_Hotkey(IWshShortcut *iface, BSTR *Hotkey)
896 WshShortcut *This = impl_from_IWshShortcut(iface);
897 FIXME("(%p)->(%p): stub\n", This, Hotkey);
898 return E_NOTIMPL;
901 static HRESULT WINAPI WshShortcut_put_Hotkey(IWshShortcut *iface, BSTR Hotkey)
903 WshShortcut *This = impl_from_IWshShortcut(iface);
904 FIXME("(%p)->(%s): stub\n", This, debugstr_w(Hotkey));
905 return E_NOTIMPL;
908 static HRESULT WINAPI WshShortcut_get_IconLocation(IWshShortcut *iface, BSTR *IconPath)
910 static const WCHAR fmtW[] = {'%','s',',',' ','%','d',0};
911 WshShortcut *This = impl_from_IWshShortcut(iface);
912 WCHAR buffW[MAX_PATH], pathW[MAX_PATH];
913 INT icon = 0;
914 HRESULT hr;
916 TRACE("(%p)->(%p)\n", This, IconPath);
918 if (!IconPath)
919 return E_POINTER;
921 hr = IShellLinkW_GetIconLocation(This->link, buffW, ARRAY_SIZE(buffW), &icon);
922 if (FAILED(hr)) return hr;
924 sprintfW(pathW, fmtW, buffW, icon);
925 *IconPath = SysAllocString(pathW);
926 if (!*IconPath) return E_OUTOFMEMORY;
928 return S_OK;
931 static HRESULT WINAPI WshShortcut_put_IconLocation(IWshShortcut *iface, BSTR IconPath)
933 WshShortcut *This = impl_from_IWshShortcut(iface);
934 HRESULT hr;
935 WCHAR *ptr;
936 BSTR path;
937 INT icon;
939 TRACE("(%p)->(%s)\n", This, debugstr_w(IconPath));
941 /* scan for icon id */
942 ptr = strrchrW(IconPath, ',');
943 if (!ptr)
945 WARN("icon index not found\n");
946 return E_FAIL;
949 path = SysAllocStringLen(IconPath, ptr-IconPath);
951 /* skip spaces if any */
952 while (isspaceW(*++ptr))
955 icon = atoiW(ptr);
957 hr = IShellLinkW_SetIconLocation(This->link, path, icon);
958 SysFreeString(path);
960 return hr;
963 static HRESULT WINAPI WshShortcut_put_RelativePath(IWshShortcut *iface, BSTR rhs)
965 WshShortcut *This = impl_from_IWshShortcut(iface);
966 FIXME("(%p)->(%s): stub\n", This, debugstr_w(rhs));
967 return E_NOTIMPL;
970 static HRESULT WINAPI WshShortcut_get_TargetPath(IWshShortcut *iface, BSTR *Path)
972 WshShortcut *This = impl_from_IWshShortcut(iface);
973 FIXME("(%p)->(%p): stub\n", This, Path);
974 return E_NOTIMPL;
977 static HRESULT WINAPI WshShortcut_put_TargetPath(IWshShortcut *iface, BSTR Path)
979 WshShortcut *This = impl_from_IWshShortcut(iface);
980 TRACE("(%p)->(%s)\n", This, debugstr_w(Path));
981 return IShellLinkW_SetPath(This->link, Path);
984 static HRESULT WINAPI WshShortcut_get_WindowStyle(IWshShortcut *iface, int *ShowCmd)
986 WshShortcut *This = impl_from_IWshShortcut(iface);
987 TRACE("(%p)->(%p)\n", This, ShowCmd);
988 return IShellLinkW_GetShowCmd(This->link, ShowCmd);
991 static HRESULT WINAPI WshShortcut_put_WindowStyle(IWshShortcut *iface, int ShowCmd)
993 WshShortcut *This = impl_from_IWshShortcut(iface);
994 TRACE("(%p)->(%d)\n", This, ShowCmd);
995 return IShellLinkW_SetShowCmd(This->link, ShowCmd);
998 static HRESULT WINAPI WshShortcut_get_WorkingDirectory(IWshShortcut *iface, BSTR *WorkingDirectory)
1000 WshShortcut *This = impl_from_IWshShortcut(iface);
1001 WCHAR buffW[MAX_PATH];
1002 HRESULT hr;
1004 TRACE("(%p)->(%p)\n", This, WorkingDirectory);
1006 if (!WorkingDirectory)
1007 return E_POINTER;
1009 *WorkingDirectory = NULL;
1010 hr = IShellLinkW_GetWorkingDirectory(This->link, buffW, ARRAY_SIZE(buffW));
1011 if (FAILED(hr)) return hr;
1013 *WorkingDirectory = SysAllocString(buffW);
1014 return *WorkingDirectory ? S_OK : E_OUTOFMEMORY;
1017 static HRESULT WINAPI WshShortcut_put_WorkingDirectory(IWshShortcut *iface, BSTR WorkingDirectory)
1019 WshShortcut *This = impl_from_IWshShortcut(iface);
1020 TRACE("(%p)->(%s)\n", This, debugstr_w(WorkingDirectory));
1021 return IShellLinkW_SetWorkingDirectory(This->link, WorkingDirectory);
1024 static HRESULT WINAPI WshShortcut_Load(IWshShortcut *iface, BSTR PathLink)
1026 WshShortcut *This = impl_from_IWshShortcut(iface);
1027 FIXME("(%p)->(%s): stub\n", This, debugstr_w(PathLink));
1028 return E_NOTIMPL;
1031 static HRESULT WINAPI WshShortcut_Save(IWshShortcut *iface)
1033 WshShortcut *This = impl_from_IWshShortcut(iface);
1034 IPersistFile *file;
1035 HRESULT hr;
1037 TRACE("(%p)\n", This);
1039 IShellLinkW_QueryInterface(This->link, &IID_IPersistFile, (void**)&file);
1040 hr = IPersistFile_Save(file, This->path_link, TRUE);
1041 IPersistFile_Release(file);
1043 return hr;
1046 static const IWshShortcutVtbl WshShortcutVtbl = {
1047 WshShortcut_QueryInterface,
1048 WshShortcut_AddRef,
1049 WshShortcut_Release,
1050 WshShortcut_GetTypeInfoCount,
1051 WshShortcut_GetTypeInfo,
1052 WshShortcut_GetIDsOfNames,
1053 WshShortcut_Invoke,
1054 WshShortcut_get_FullName,
1055 WshShortcut_get_Arguments,
1056 WshShortcut_put_Arguments,
1057 WshShortcut_get_Description,
1058 WshShortcut_put_Description,
1059 WshShortcut_get_Hotkey,
1060 WshShortcut_put_Hotkey,
1061 WshShortcut_get_IconLocation,
1062 WshShortcut_put_IconLocation,
1063 WshShortcut_put_RelativePath,
1064 WshShortcut_get_TargetPath,
1065 WshShortcut_put_TargetPath,
1066 WshShortcut_get_WindowStyle,
1067 WshShortcut_put_WindowStyle,
1068 WshShortcut_get_WorkingDirectory,
1069 WshShortcut_put_WorkingDirectory,
1070 WshShortcut_Load,
1071 WshShortcut_Save
1074 static HRESULT WshShortcut_Create(const WCHAR *path, IDispatch **shortcut)
1076 WshShortcut *This;
1077 HRESULT hr;
1079 *shortcut = NULL;
1081 This = heap_alloc(sizeof(*This));
1082 if (!This) return E_OUTOFMEMORY;
1084 This->IWshShortcut_iface.lpVtbl = &WshShortcutVtbl;
1085 This->ref = 1;
1087 hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
1088 &IID_IShellLinkW, (void**)&This->link);
1089 if (FAILED(hr))
1091 heap_free(This);
1092 return hr;
1095 This->path_link = SysAllocString(path);
1096 if (!This->path_link)
1098 IShellLinkW_Release(This->link);
1099 heap_free(This);
1100 return E_OUTOFMEMORY;
1103 init_classinfo(&IID_IWshShortcut, (IUnknown *)&This->IWshShortcut_iface, &This->classinfo);
1104 *shortcut = (IDispatch*)&This->IWshShortcut_iface;
1106 return S_OK;
1109 static HRESULT WINAPI WshShell3_QueryInterface(IWshShell3 *iface, REFIID riid, void **ppv)
1111 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
1113 *ppv = NULL;
1115 if (IsEqualGUID(riid, &IID_IDispatch) ||
1116 IsEqualGUID(riid, &IID_IWshShell3) ||
1117 IsEqualGUID(riid, &IID_IWshShell2) ||
1118 IsEqualGUID(riid, &IID_IWshShell) ||
1119 IsEqualGUID(riid, &IID_IUnknown))
1121 *ppv = iface;
1123 else if (IsEqualGUID(riid, &IID_IDispatchEx))
1125 return E_NOINTERFACE;
1127 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
1129 *ppv = &WshShell3.classinfo.IProvideClassInfo_iface;
1131 else
1133 WARN("unknown iface %s\n", debugstr_guid(riid));
1134 return E_NOINTERFACE;
1137 IUnknown_AddRef((IUnknown *)*ppv);
1138 return S_OK;
1141 static ULONG WINAPI WshShell3_AddRef(IWshShell3 *iface)
1143 TRACE("()\n");
1144 return 2;
1147 static ULONG WINAPI WshShell3_Release(IWshShell3 *iface)
1149 TRACE("()\n");
1150 return 2;
1153 static HRESULT WINAPI WshShell3_GetTypeInfoCount(IWshShell3 *iface, UINT *pctinfo)
1155 TRACE("(%p)\n", pctinfo);
1156 *pctinfo = 1;
1157 return S_OK;
1160 static HRESULT WINAPI WshShell3_GetTypeInfo(IWshShell3 *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
1162 TRACE("(%u %u %p)\n", iTInfo, lcid, ppTInfo);
1163 return get_typeinfo(IWshShell3_tid, ppTInfo);
1166 static HRESULT WINAPI WshShell3_GetIDsOfNames(IWshShell3 *iface, REFIID riid, LPOLESTR *rgszNames,
1167 UINT cNames, LCID lcid, DISPID *rgDispId)
1169 ITypeInfo *typeinfo;
1170 HRESULT hr;
1172 TRACE("(%s %p %u %u %p)\n", debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1174 hr = get_typeinfo(IWshShell3_tid, &typeinfo);
1175 if(SUCCEEDED(hr))
1177 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1178 ITypeInfo_Release(typeinfo);
1181 return hr;
1184 static HRESULT WINAPI WshShell3_Invoke(IWshShell3 *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
1185 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
1187 ITypeInfo *typeinfo;
1188 HRESULT hr;
1190 TRACE("(%d %s %d %d %p %p %p %p)\n", dispIdMember, debugstr_guid(riid),
1191 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1193 hr = get_typeinfo(IWshShell3_tid, &typeinfo);
1194 if(SUCCEEDED(hr))
1196 hr = ITypeInfo_Invoke(typeinfo, &WshShell3.IWshShell3_iface, dispIdMember, wFlags,
1197 pDispParams, pVarResult, pExcepInfo, puArgErr);
1198 ITypeInfo_Release(typeinfo);
1201 return hr;
1204 static HRESULT WINAPI WshShell3_get_SpecialFolders(IWshShell3 *iface, IWshCollection **folders)
1206 TRACE("(%p)\n", folders);
1207 return WshCollection_Create(folders);
1210 static HRESULT WINAPI WshShell3_get_Environment(IWshShell3 *iface, VARIANT *type, IWshEnvironment **env)
1212 FIXME("(%s %p): semi-stub\n", debugstr_variant(type), env);
1213 return WshEnvironment_Create(env);
1216 static inline BOOL is_optional_argument(const VARIANT *arg)
1218 return V_VT(arg) == VT_ERROR && V_ERROR(arg) == DISP_E_PARAMNOTFOUND;
1221 static HRESULT WINAPI WshShell3_Run(IWshShell3 *iface, BSTR cmd, VARIANT *style, VARIANT *wait, DWORD *exit_code)
1223 SHELLEXECUTEINFOW info;
1224 int waitforprocess;
1225 VARIANT s;
1226 HRESULT hr;
1228 TRACE("(%s %s %s %p)\n", debugstr_w(cmd), debugstr_variant(style), debugstr_variant(wait), exit_code);
1230 if (!style || !wait || !exit_code)
1231 return E_POINTER;
1233 VariantInit(&s);
1234 hr = VariantChangeType(&s, style, 0, VT_I4);
1235 if (FAILED(hr))
1237 ERR("failed to convert style argument, 0x%08x\n", hr);
1238 return hr;
1241 if (is_optional_argument(wait))
1242 waitforprocess = 0;
1243 else {
1244 VARIANT w;
1246 VariantInit(&w);
1247 hr = VariantChangeType(&w, wait, 0, VT_I4);
1248 if (FAILED(hr))
1249 return hr;
1251 waitforprocess = V_I4(&w);
1254 memset(&info, 0, sizeof(info));
1255 info.cbSize = sizeof(info);
1256 info.fMask = waitforprocess ? SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS : SEE_MASK_DEFAULT;
1257 info.lpFile = cmd;
1258 info.nShow = V_I4(&s);
1260 if (!ShellExecuteExW(&info))
1262 TRACE("ShellExecute failed, %d\n", GetLastError());
1263 return HRESULT_FROM_WIN32(GetLastError());
1265 else
1267 if (waitforprocess)
1269 GetExitCodeProcess(info.hProcess, exit_code);
1270 CloseHandle(info.hProcess);
1272 else
1273 *exit_code = 0;
1275 return S_OK;
1279 struct popup_thread_param
1281 WCHAR *text;
1282 VARIANT title;
1283 VARIANT type;
1284 INT button;
1287 static DWORD WINAPI popup_thread_proc(void *arg)
1289 static const WCHAR defaulttitleW[] = {'W','i','n','d','o','w','s',' ','S','c','r','i','p','t',' ','H','o','s','t',0};
1290 struct popup_thread_param *param = (struct popup_thread_param *)arg;
1292 param->button = MessageBoxW(NULL, param->text, is_optional_argument(&param->title) ?
1293 defaulttitleW : V_BSTR(&param->title), V_I4(&param->type));
1294 return 0;
1297 static HRESULT WINAPI WshShell3_Popup(IWshShell3 *iface, BSTR text, VARIANT *seconds_to_wait, VARIANT *title,
1298 VARIANT *type, int *button)
1300 struct popup_thread_param param;
1301 DWORD tid, status;
1302 VARIANT timeout;
1303 HANDLE hthread;
1304 HRESULT hr;
1306 TRACE("(%s %s %s %s %p)\n", debugstr_w(text), debugstr_variant(seconds_to_wait), debugstr_variant(title),
1307 debugstr_variant(type), button);
1309 if (!seconds_to_wait || !title || !type || !button)
1310 return E_POINTER;
1312 VariantInit(&timeout);
1313 if (!is_optional_argument(seconds_to_wait))
1315 hr = VariantChangeType(&timeout, seconds_to_wait, 0, VT_I4);
1316 if (FAILED(hr))
1317 return hr;
1320 VariantInit(&param.type);
1321 if (!is_optional_argument(type))
1323 hr = VariantChangeType(&param.type, type, 0, VT_I4);
1324 if (FAILED(hr))
1325 return hr;
1328 if (is_optional_argument(title))
1329 param.title = *title;
1330 else
1332 VariantInit(&param.title);
1333 hr = VariantChangeType(&param.title, title, 0, VT_BSTR);
1334 if (FAILED(hr))
1335 return hr;
1338 param.text = text;
1339 param.button = -1;
1340 hthread = CreateThread(NULL, 0, popup_thread_proc, &param, 0, &tid);
1341 status = MsgWaitForMultipleObjects(1, &hthread, FALSE, V_I4(&timeout) ? V_I4(&timeout) * 1000: INFINITE, 0);
1342 if (status == WAIT_TIMEOUT)
1344 PostThreadMessageW(tid, WM_QUIT, 0, 0);
1345 MsgWaitForMultipleObjects(1, &hthread, FALSE, INFINITE, 0);
1346 param.button = -1;
1348 *button = param.button;
1350 VariantClear(&param.title);
1351 CloseHandle(hthread);
1353 return S_OK;
1356 static HRESULT WINAPI WshShell3_CreateShortcut(IWshShell3 *iface, BSTR PathLink, IDispatch** Shortcut)
1358 TRACE("(%s %p)\n", debugstr_w(PathLink), Shortcut);
1359 return WshShortcut_Create(PathLink, Shortcut);
1362 static HRESULT WINAPI WshShell3_ExpandEnvironmentStrings(IWshShell3 *iface, BSTR Src, BSTR* Dst)
1364 DWORD ret;
1366 TRACE("(%s %p)\n", debugstr_w(Src), Dst);
1368 if (!Src || !Dst) return E_POINTER;
1370 ret = ExpandEnvironmentStringsW(Src, NULL, 0);
1371 *Dst = SysAllocStringLen(NULL, ret);
1372 if (!*Dst) return E_OUTOFMEMORY;
1374 if (ExpandEnvironmentStringsW(Src, *Dst, ret))
1375 return S_OK;
1376 else
1378 SysFreeString(*Dst);
1379 *Dst = NULL;
1380 return HRESULT_FROM_WIN32(GetLastError());
1384 static HKEY get_root_key(const WCHAR *path)
1386 static const struct {
1387 const WCHAR full[20];
1388 const WCHAR abbrev[5];
1389 HKEY hkey;
1390 } rootkeys[] = {
1391 { {'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R',0}, {'H','K','C','U',0}, HKEY_CURRENT_USER },
1392 { {'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 },
1393 { {'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T',0}, {'H','K','C','R',0}, HKEY_CLASSES_ROOT },
1394 { {'H','K','E','Y','_','U','S','E','R','S',0}, {0}, HKEY_USERS },
1395 { {'H','K','E','Y','_','C','U','R','R','E','N','T','_','C','O','N','F','I','G',0}, {0}, HKEY_CURRENT_CONFIG }
1397 int i;
1399 for (i = 0; i < ARRAY_SIZE(rootkeys); i++) {
1400 if (!strncmpW(path, rootkeys[i].full, strlenW(rootkeys[i].full)))
1401 return rootkeys[i].hkey;
1402 if (rootkeys[i].abbrev[0] && !strncmpW(path, rootkeys[i].abbrev, strlenW(rootkeys[i].abbrev)))
1403 return rootkeys[i].hkey;
1406 return NULL;
1409 /* Caller is responsible to free 'subkey' if 'value' is not NULL */
1410 static HRESULT split_reg_path(const WCHAR *path, WCHAR **subkey, WCHAR **value)
1412 *value = NULL;
1414 /* at least one separator should be present */
1415 *subkey = strchrW(path, '\\');
1416 if (!*subkey)
1417 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1419 /* default value or not */
1420 if ((*subkey)[strlenW(*subkey)-1] == '\\') {
1421 (*subkey)++;
1422 *value = NULL;
1424 else {
1425 *value = strrchrW(*subkey, '\\');
1426 if (*value - *subkey > 1) {
1427 unsigned int len = *value - *subkey - 1;
1428 WCHAR *ret;
1430 ret = heap_alloc((len + 1)*sizeof(WCHAR));
1431 if (!ret)
1432 return E_OUTOFMEMORY;
1434 memcpy(ret, *subkey + 1, len*sizeof(WCHAR));
1435 ret[len] = 0;
1436 *subkey = ret;
1438 (*value)++;
1441 return S_OK;
1444 static HRESULT WINAPI WshShell3_RegRead(IWshShell3 *iface, BSTR name, VARIANT *value)
1446 DWORD type, datalen, ret;
1447 WCHAR *subkey, *val;
1448 HRESULT hr;
1449 HKEY root;
1451 TRACE("(%s %p)\n", debugstr_w(name), value);
1453 if (!name || !value)
1454 return E_POINTER;
1456 root = get_root_key(name);
1457 if (!root)
1458 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1460 hr = split_reg_path(name, &subkey, &val);
1461 if (FAILED(hr))
1462 return hr;
1464 type = REG_NONE;
1465 datalen = 0;
1466 ret = RegGetValueW(root, subkey, val, RRF_RT_ANY, &type, NULL, &datalen);
1467 if (ret == ERROR_SUCCESS) {
1468 void *data;
1470 data = heap_alloc(datalen);
1471 if (!data) {
1472 hr = E_OUTOFMEMORY;
1473 goto fail;
1476 ret = RegGetValueW(root, subkey, val, RRF_RT_ANY, &type, data, &datalen);
1477 if (ret) {
1478 heap_free(data);
1479 hr = HRESULT_FROM_WIN32(ret);
1480 goto fail;
1483 switch (type) {
1484 case REG_SZ:
1485 case REG_EXPAND_SZ:
1486 V_VT(value) = VT_BSTR;
1487 V_BSTR(value) = SysAllocString((WCHAR*)data);
1488 if (!V_BSTR(value))
1489 hr = E_OUTOFMEMORY;
1490 break;
1491 case REG_DWORD:
1492 V_VT(value) = VT_I4;
1493 V_I4(value) = *(DWORD*)data;
1494 break;
1495 case REG_BINARY:
1497 BYTE *ptr = (BYTE*)data;
1498 SAFEARRAYBOUND bound;
1499 unsigned int i;
1500 SAFEARRAY *sa;
1501 VARIANT *v;
1503 bound.lLbound = 0;
1504 bound.cElements = datalen;
1505 sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
1506 if (!sa)
1507 break;
1509 hr = SafeArrayAccessData(sa, (void**)&v);
1510 if (FAILED(hr)) {
1511 SafeArrayDestroy(sa);
1512 break;
1515 for (i = 0; i < datalen; i++) {
1516 V_VT(&v[i]) = VT_UI1;
1517 V_UI1(&v[i]) = ptr[i];
1519 SafeArrayUnaccessData(sa);
1521 V_VT(value) = VT_ARRAY|VT_VARIANT;
1522 V_ARRAY(value) = sa;
1523 break;
1525 case REG_MULTI_SZ:
1527 WCHAR *ptr = (WCHAR*)data;
1528 SAFEARRAYBOUND bound;
1529 SAFEARRAY *sa;
1530 VARIANT *v;
1532 /* get element count first */
1533 bound.lLbound = 0;
1534 bound.cElements = 0;
1535 while (*ptr) {
1536 bound.cElements++;
1537 ptr += strlenW(ptr)+1;
1540 sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
1541 if (!sa)
1542 break;
1544 hr = SafeArrayAccessData(sa, (void**)&v);
1545 if (FAILED(hr)) {
1546 SafeArrayDestroy(sa);
1547 break;
1550 ptr = (WCHAR*)data;
1551 while (*ptr) {
1552 V_VT(v) = VT_BSTR;
1553 V_BSTR(v) = SysAllocString(ptr);
1554 ptr += strlenW(ptr)+1;
1555 v++;
1558 SafeArrayUnaccessData(sa);
1559 V_VT(value) = VT_ARRAY|VT_VARIANT;
1560 V_ARRAY(value) = sa;
1561 break;
1563 default:
1564 FIXME("value type %d not supported\n", type);
1565 hr = E_FAIL;
1568 heap_free(data);
1569 if (FAILED(hr))
1570 VariantInit(value);
1572 else
1573 hr = HRESULT_FROM_WIN32(ret);
1575 fail:
1576 if (val)
1577 heap_free(subkey);
1578 return hr;
1581 static HRESULT WINAPI WshShell3_RegWrite(IWshShell3 *iface, BSTR name, VARIANT *value, VARIANT *type)
1583 static const WCHAR regexpandszW[] = {'R','E','G','_','E','X','P','A','N','D','_','S','Z',0};
1584 static const WCHAR regszW[] = {'R','E','G','_','S','Z',0};
1585 static const WCHAR regdwordW[] = {'R','E','G','_','D','W','O','R','D',0};
1586 static const WCHAR regbinaryW[] = {'R','E','G','_','B','I','N','A','R','Y',0};
1588 DWORD regtype, data_len;
1589 WCHAR *subkey, *val;
1590 const BYTE *data;
1591 HRESULT hr;
1592 HKEY root;
1593 VARIANT v;
1594 LONG ret;
1596 TRACE("(%s %s %s)\n", debugstr_w(name), debugstr_variant(value), debugstr_variant(type));
1598 if (!name || !value || !type)
1599 return E_POINTER;
1601 root = get_root_key(name);
1602 if (!root)
1603 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1605 /* value type */
1606 if (is_optional_argument(type))
1607 regtype = REG_SZ;
1608 else {
1609 if (V_VT(type) != VT_BSTR)
1610 return E_INVALIDARG;
1612 if (!strcmpW(V_BSTR(type), regszW))
1613 regtype = REG_SZ;
1614 else if (!strcmpW(V_BSTR(type), regdwordW))
1615 regtype = REG_DWORD;
1616 else if (!strcmpW(V_BSTR(type), regexpandszW))
1617 regtype = REG_EXPAND_SZ;
1618 else if (!strcmpW(V_BSTR(type), regbinaryW))
1619 regtype = REG_BINARY;
1620 else {
1621 FIXME("unrecognized value type %s\n", debugstr_w(V_BSTR(type)));
1622 return E_FAIL;
1626 /* it's always a string or a DWORD */
1627 VariantInit(&v);
1628 switch (regtype)
1630 case REG_SZ:
1631 case REG_EXPAND_SZ:
1632 hr = VariantChangeType(&v, value, 0, VT_BSTR);
1633 if (hr == S_OK) {
1634 data = (BYTE*)V_BSTR(&v);
1635 data_len = SysStringByteLen(V_BSTR(&v)) + sizeof(WCHAR);
1637 break;
1638 case REG_DWORD:
1639 case REG_BINARY:
1640 hr = VariantChangeType(&v, value, 0, VT_I4);
1641 data = (BYTE*)&V_I4(&v);
1642 data_len = sizeof(DWORD);
1643 break;
1644 default:
1645 FIXME("unexpected regtype %d\n", regtype);
1646 return E_FAIL;
1649 if (FAILED(hr)) {
1650 FIXME("failed to convert value, regtype %d, 0x%08x\n", regtype, hr);
1651 return hr;
1654 hr = split_reg_path(name, &subkey, &val);
1655 if (FAILED(hr))
1656 goto fail;
1658 ret = RegSetKeyValueW(root, subkey, val, regtype, data, data_len);
1659 if (ret)
1660 hr = HRESULT_FROM_WIN32(ret);
1662 fail:
1663 VariantClear(&v);
1664 if (val)
1665 heap_free(subkey);
1666 return hr;
1669 static HRESULT WINAPI WshShell3_RegDelete(IWshShell3 *iface, BSTR Name)
1671 FIXME("(%s): stub\n", debugstr_w(Name));
1672 return E_NOTIMPL;
1675 static HRESULT WINAPI WshShell3_LogEvent(IWshShell3 *iface, VARIANT *Type, BSTR Message, BSTR Target, VARIANT_BOOL *out_Success)
1677 FIXME("(%s %s %s %p): stub\n", debugstr_variant(Type), debugstr_w(Message), debugstr_w(Target), out_Success);
1678 return E_NOTIMPL;
1681 static HRESULT WINAPI WshShell3_AppActivate(IWshShell3 *iface, VARIANT *App, VARIANT *Wait, VARIANT_BOOL *out_Success)
1683 FIXME("(%s %s %p): stub\n", debugstr_variant(App), debugstr_variant(Wait), out_Success);
1684 return E_NOTIMPL;
1687 static HRESULT WINAPI WshShell3_SendKeys(IWshShell3 *iface, BSTR Keys, VARIANT *Wait)
1689 FIXME("(%s %p): stub\n", debugstr_w(Keys), Wait);
1690 return E_NOTIMPL;
1693 static HRESULT WINAPI WshShell3_Exec(IWshShell3 *iface, BSTR command, IWshExec **ret)
1695 TRACE("(%s %p)\n", debugstr_w(command), ret);
1697 if (!ret)
1698 return E_POINTER;
1700 if (!command)
1701 return DISP_E_EXCEPTION;
1703 return WshExec_create(command, ret);
1706 static HRESULT WINAPI WshShell3_get_CurrentDirectory(IWshShell3 *iface, BSTR *dir)
1708 DWORD ret;
1710 TRACE("(%p)\n", dir);
1712 ret = GetCurrentDirectoryW(0, NULL);
1713 if (!ret)
1714 return HRESULT_FROM_WIN32(GetLastError());
1716 *dir = SysAllocStringLen(NULL, ret-1);
1717 if (!*dir)
1718 return E_OUTOFMEMORY;
1720 ret = GetCurrentDirectoryW(ret, *dir);
1721 if (!ret) {
1722 SysFreeString(*dir);
1723 *dir = NULL;
1724 return HRESULT_FROM_WIN32(GetLastError());
1727 return S_OK;
1730 static HRESULT WINAPI WshShell3_put_CurrentDirectory(IWshShell3 *iface, BSTR dir)
1732 TRACE("(%s)\n", debugstr_w(dir));
1734 if (!dir)
1735 return E_INVALIDARG;
1737 if (!SetCurrentDirectoryW(dir))
1738 return HRESULT_FROM_WIN32(GetLastError());
1740 return S_OK;
1743 static const IWshShell3Vtbl WshShell3Vtbl = {
1744 WshShell3_QueryInterface,
1745 WshShell3_AddRef,
1746 WshShell3_Release,
1747 WshShell3_GetTypeInfoCount,
1748 WshShell3_GetTypeInfo,
1749 WshShell3_GetIDsOfNames,
1750 WshShell3_Invoke,
1751 WshShell3_get_SpecialFolders,
1752 WshShell3_get_Environment,
1753 WshShell3_Run,
1754 WshShell3_Popup,
1755 WshShell3_CreateShortcut,
1756 WshShell3_ExpandEnvironmentStrings,
1757 WshShell3_RegRead,
1758 WshShell3_RegWrite,
1759 WshShell3_RegDelete,
1760 WshShell3_LogEvent,
1761 WshShell3_AppActivate,
1762 WshShell3_SendKeys,
1763 WshShell3_Exec,
1764 WshShell3_get_CurrentDirectory,
1765 WshShell3_put_CurrentDirectory
1768 HRESULT WINAPI WshShellFactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
1770 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
1772 WshShell3.IWshShell3_iface.lpVtbl = &WshShell3Vtbl;
1773 init_classinfo(&IID_IWshShell3, (IUnknown *)&WshShell3.IWshShell3_iface, &WshShell3.classinfo);
1774 return IWshShell3_QueryInterface(&WshShell3.IWshShell3_iface, riid, ppv);