include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / wshom.ocx / shell.c
blobc538a6b4a74fb4f1c4b93f74982289863d78e97d
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"
28 extern HRESULT WINAPI DoOpenPipeStream(HANDLE pipe, IOMode mode, ITextStream **stream);
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 WCHAR *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 ITextStream *stdin_stream;
70 ITextStream *stdout_stream;
71 ITextStream *stderr_stream;
72 } WshExecImpl;
74 static inline WshCollection *impl_from_IWshCollection( IWshCollection *iface )
76 return CONTAINING_RECORD(iface, WshCollection, IWshCollection_iface);
79 static inline WshShortcut *impl_from_IWshShortcut( IWshShortcut *iface )
81 return CONTAINING_RECORD(iface, WshShortcut, IWshShortcut_iface);
84 static inline WshEnvironment *impl_from_IWshEnvironment( IWshEnvironment *iface )
86 return CONTAINING_RECORD(iface, WshEnvironment, IWshEnvironment_iface);
89 static inline WshExecImpl *impl_from_IWshExec( IWshExec *iface )
91 return CONTAINING_RECORD(iface, WshExecImpl, IWshExec_iface);
94 static HRESULT WINAPI WshExec_QueryInterface(IWshExec *iface, REFIID riid, void **obj)
96 WshExecImpl *This = impl_from_IWshExec(iface);
98 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), obj);
100 if (IsEqualGUID(riid, &IID_IDispatch) ||
101 IsEqualGUID(riid, &IID_IWshExec) ||
102 IsEqualGUID(riid, &IID_IUnknown))
104 *obj = iface;
106 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
108 *obj = &This->classinfo.IProvideClassInfo_iface;
110 else {
111 FIXME("Unknown iface %s\n", debugstr_guid(riid));
112 *obj = NULL;
113 return E_NOINTERFACE;
116 IUnknown_AddRef((IUnknown *)*obj);
117 return S_OK;
120 static ULONG WINAPI WshExec_AddRef(IWshExec *iface)
122 WshExecImpl *This = impl_from_IWshExec(iface);
123 LONG ref = InterlockedIncrement(&This->ref);
124 TRACE("%p, refcount %ld.\n", iface, ref);
125 return ref;
128 static ULONG WINAPI WshExec_Release(IWshExec *iface)
130 WshExecImpl *exec = impl_from_IWshExec(iface);
131 LONG ref = InterlockedDecrement(&exec->ref);
133 TRACE("%p, refcount %ld.\n", iface, ref);
135 if (!ref)
137 CloseHandle(exec->info.hThread);
138 CloseHandle(exec->info.hProcess);
139 if (exec->stdin_stream)
140 ITextStream_Release(exec->stdin_stream);
141 if (exec->stdout_stream)
142 ITextStream_Release(exec->stdout_stream);
143 if (exec->stderr_stream)
144 ITextStream_Release(exec->stderr_stream);
145 free(exec);
148 return ref;
151 static HRESULT WINAPI WshExec_GetTypeInfoCount(IWshExec *iface, UINT *pctinfo)
153 WshExecImpl *This = impl_from_IWshExec(iface);
154 TRACE("(%p)->(%p)\n", This, pctinfo);
155 *pctinfo = 1;
156 return S_OK;
159 static HRESULT WINAPI WshExec_GetTypeInfo(IWshExec *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
161 TRACE("%p, %u, %lx, %p.\n", iface, iTInfo, lcid, ppTInfo);
163 return get_typeinfo(IWshExec_tid, ppTInfo);
166 static HRESULT WINAPI WshExec_GetIDsOfNames(IWshExec *iface, REFIID riid, LPOLESTR *rgszNames,
167 UINT cNames, LCID lcid, DISPID *rgDispId)
169 ITypeInfo *typeinfo;
170 HRESULT hr;
172 TRACE("%p, %s, %p, %u, %lx, %p.\n", iface, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
174 hr = get_typeinfo(IWshExec_tid, &typeinfo);
175 if(SUCCEEDED(hr))
177 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
178 ITypeInfo_Release(typeinfo);
181 return hr;
184 static HRESULT WINAPI WshExec_Invoke(IWshExec *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
185 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
187 ITypeInfo *typeinfo;
188 HRESULT hr;
190 TRACE("%p, %ld, %s, %lx, %d, %p, %p, %p, %p.\n", iface, dispIdMember, debugstr_guid(riid),
191 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
193 hr = get_typeinfo(IWshExec_tid, &typeinfo);
194 if(SUCCEEDED(hr))
196 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
197 ITypeInfo_Release(typeinfo);
200 return hr;
203 static HRESULT WINAPI WshExec_get_Status(IWshExec *iface, WshExecStatus *status)
205 WshExecImpl *This = impl_from_IWshExec(iface);
206 DWORD code;
208 TRACE("(%p)->(%p)\n", This, status);
210 if (!status)
211 return E_INVALIDARG;
213 if (!GetExitCodeProcess(This->info.hProcess, &code))
214 return HRESULT_FROM_WIN32(GetLastError());
216 switch (code)
218 case 0:
219 *status = WshFinished;
220 break;
221 case STILL_ACTIVE:
222 *status = WshRunning;
223 break;
224 default:
225 *status = WshFailed;
228 return S_OK;
231 static HRESULT WINAPI WshExec_get_StdIn(IWshExec *iface, ITextStream **stream)
233 WshExecImpl *exec = impl_from_IWshExec(iface);
235 TRACE("%p, %p.\n", iface, stream);
237 *stream = exec->stdin_stream;
238 ITextStream_AddRef(*stream);
240 return S_OK;
243 static HRESULT WINAPI WshExec_get_StdOut(IWshExec *iface, ITextStream **stream)
245 WshExecImpl *exec = impl_from_IWshExec(iface);
247 TRACE("%p, %p.\n", iface, stream);
249 *stream = exec->stdout_stream;
250 ITextStream_AddRef(*stream);
252 return S_OK;
255 static HRESULT WINAPI WshExec_get_StdErr(IWshExec *iface, ITextStream **stream)
257 WshExecImpl *exec = impl_from_IWshExec(iface);
259 TRACE("%p, %p.\n", iface, stream);
261 *stream = exec->stderr_stream;
262 ITextStream_AddRef(*stream);
264 return S_OK;
267 static HRESULT WINAPI WshExec_get_ProcessID(IWshExec *iface, int *pid)
269 WshExecImpl *This = impl_from_IWshExec(iface);
271 TRACE("(%p)->(%p)\n", This, pid);
273 if (!pid)
274 return E_INVALIDARG;
276 *pid = This->info.dwProcessId;
277 return S_OK;
280 static HRESULT WINAPI WshExec_get_ExitCode(IWshExec *iface, int *code)
282 WshExecImpl *This = impl_from_IWshExec(iface);
284 FIXME("(%p)->(%p): stub\n", This, code);
286 return E_NOTIMPL;
289 static BOOL CALLBACK enum_thread_wnd_proc(HWND hwnd, LPARAM lParam)
291 INT *count = (INT*)lParam;
293 (*count)++;
294 PostMessageW(hwnd, WM_CLOSE, 0, 0);
295 /* try to send it to all windows, even if failed for some */
296 return TRUE;
299 static HRESULT WINAPI WshExec_Terminate(IWshExec *iface)
301 WshExecImpl *This = impl_from_IWshExec(iface);
302 BOOL ret, kill = FALSE;
303 INT count = 0;
305 TRACE("(%p)\n", This);
307 ret = EnumThreadWindows(This->info.dwThreadId, enum_thread_wnd_proc, (LPARAM)&count);
308 if (ret && count) {
309 /* manual testing shows that it waits 2 seconds before forcing termination */
310 if (WaitForSingleObject(This->info.hProcess, 2000) != WAIT_OBJECT_0)
311 kill = TRUE;
313 else
314 kill = TRUE;
316 if (kill)
317 TerminateProcess(This->info.hProcess, 0);
319 return S_OK;
322 static const IWshExecVtbl WshExecVtbl = {
323 WshExec_QueryInterface,
324 WshExec_AddRef,
325 WshExec_Release,
326 WshExec_GetTypeInfoCount,
327 WshExec_GetTypeInfo,
328 WshExec_GetIDsOfNames,
329 WshExec_Invoke,
330 WshExec_get_Status,
331 WshExec_get_StdIn,
332 WshExec_get_StdOut,
333 WshExec_get_StdErr,
334 WshExec_get_ProcessID,
335 WshExec_get_ExitCode,
336 WshExec_Terminate
339 static HRESULT create_pipe(HANDLE *hread, HANDLE *hwrite)
341 SECURITY_ATTRIBUTES sa;
343 sa.nLength = sizeof(sa);
344 sa.bInheritHandle = TRUE;
345 sa.lpSecurityDescriptor = NULL;
347 *hread = *hwrite = NULL;
348 if (!CreatePipe(hread, hwrite, &sa, 0))
349 return HRESULT_FROM_WIN32(GetLastError());
350 return S_OK;
353 static void close_pipe(HANDLE *hread, HANDLE *hwrite)
355 CloseHandle(*hread);
356 CloseHandle(*hwrite);
357 *hread = *hwrite = NULL;
360 static HRESULT WshExec_create(BSTR command, IWshExec **ret)
362 HANDLE stdout_read, stdout_write;
363 HANDLE stderr_read, stderr_write;
364 HANDLE stdin_read, stdin_write;
365 STARTUPINFOW si = {0};
366 WshExecImpl *object;
367 HRESULT hr;
369 *ret = NULL;
371 if (!(object = calloc(1, sizeof(*object))))
372 return E_OUTOFMEMORY;
374 object->IWshExec_iface.lpVtbl = &WshExecVtbl;
375 object->ref = 1;
376 init_classinfo(&CLSID_WshExec, (IUnknown *)&object->IWshExec_iface, &object->classinfo);
378 if (FAILED(hr = create_pipe(&stdin_read, &stdin_write)))
380 WARN("Failed to create stdin pipe.\n");
381 goto failed;
384 if (FAILED(hr = create_pipe(&stdout_read, &stdout_write)))
386 close_pipe(&stdin_read, &stdin_write);
387 WARN("Failed to create stdout pipe.\n");
388 goto failed;
391 if (FAILED(hr = create_pipe(&stderr_read, &stderr_write)))
393 close_pipe(&stdin_read, &stdin_write);
394 close_pipe(&stdout_read, &stdout_write);
395 WARN("Failed to create stderr pipe.\n");
396 goto failed;
399 if (SUCCEEDED(hr))
401 SetHandleInformation(stdin_write, HANDLE_FLAG_INHERIT, 0);
402 SetHandleInformation(stdout_read, HANDLE_FLAG_INHERIT, 0);
403 SetHandleInformation(stderr_read, HANDLE_FLAG_INHERIT, 0);
406 if (SUCCEEDED(hr))
407 hr = DoOpenPipeStream(stdin_write, ForWriting, &object->stdin_stream);
408 if (SUCCEEDED(hr))
409 hr = DoOpenPipeStream(stdout_read, ForReading, &object->stdout_stream);
410 if (SUCCEEDED(hr))
411 hr = DoOpenPipeStream(stderr_read, ForReading, &object->stderr_stream);
413 si.cb = sizeof(si);
414 si.hStdError = stderr_write;
415 si.hStdOutput = stdout_write;
416 si.hStdInput = stdin_read;
417 si.dwFlags = STARTF_USESTDHANDLES;
419 if (SUCCEEDED(hr))
421 if (!CreateProcessW(NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &object->info))
422 hr = HRESULT_FROM_WIN32(GetLastError());
425 CloseHandle(stderr_write);
426 CloseHandle(stdout_write);
427 CloseHandle(stdin_read);
429 if (SUCCEEDED(hr))
431 *ret = &object->IWshExec_iface;
433 return S_OK;
436 failed:
438 IWshExec_Release(&object->IWshExec_iface);
440 return hr;
443 static HRESULT WINAPI WshEnvironment_QueryInterface(IWshEnvironment *iface, REFIID riid, void **obj)
445 WshEnvironment *This = impl_from_IWshEnvironment(iface);
447 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), obj);
449 if (IsEqualGUID(riid, &IID_IUnknown) ||
450 IsEqualGUID(riid, &IID_IDispatch) ||
451 IsEqualGUID(riid, &IID_IWshEnvironment))
453 *obj = iface;
455 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
457 *obj = &This->classinfo.IProvideClassInfo_iface;
459 else {
460 FIXME("Unknown iface %s\n", debugstr_guid(riid));
461 *obj = NULL;
462 return E_NOINTERFACE;
465 IUnknown_AddRef((IUnknown*)*obj);
466 return S_OK;
469 static ULONG WINAPI WshEnvironment_AddRef(IWshEnvironment *iface)
471 WshEnvironment *This = impl_from_IWshEnvironment(iface);
472 LONG ref = InterlockedIncrement(&This->ref);
473 TRACE("%p, refcount %ld.\n", iface, ref);
474 return ref;
477 static ULONG WINAPI WshEnvironment_Release(IWshEnvironment *iface)
479 WshEnvironment *This = impl_from_IWshEnvironment(iface);
480 LONG ref = InterlockedDecrement(&This->ref);
481 TRACE("%p, refcount %ld.\n", iface, ref);
483 if (!ref)
484 free(This);
486 return ref;
489 static HRESULT WINAPI WshEnvironment_GetTypeInfoCount(IWshEnvironment *iface, UINT *pctinfo)
491 WshEnvironment *This = impl_from_IWshEnvironment(iface);
492 TRACE("(%p)->(%p)\n", This, pctinfo);
493 *pctinfo = 1;
494 return S_OK;
497 static HRESULT WINAPI WshEnvironment_GetTypeInfo(IWshEnvironment *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
499 TRACE("%p, %u, %lx, %p.\n", iface, iTInfo, lcid, ppTInfo);
501 return get_typeinfo(IWshEnvironment_tid, ppTInfo);
504 static HRESULT WINAPI WshEnvironment_GetIDsOfNames(IWshEnvironment *iface, REFIID riid, LPOLESTR *rgszNames,
505 UINT cNames, LCID lcid, DISPID *rgDispId)
507 ITypeInfo *typeinfo;
508 HRESULT hr;
510 TRACE("%p, %s, %p, %u, %lx, %p.\n", iface, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
512 hr = get_typeinfo(IWshEnvironment_tid, &typeinfo);
513 if(SUCCEEDED(hr))
515 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
516 ITypeInfo_Release(typeinfo);
519 return hr;
522 static HRESULT WINAPI WshEnvironment_Invoke(IWshEnvironment *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
523 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
525 ITypeInfo *typeinfo;
526 HRESULT hr;
528 TRACE("%p, %ld, %s, %lx, %d, %p, %p, %p, %p.\n", iface, dispIdMember, debugstr_guid(riid),
529 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
531 hr = get_typeinfo(IWshEnvironment_tid, &typeinfo);
532 if(SUCCEEDED(hr))
534 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
535 ITypeInfo_Release(typeinfo);
538 return hr;
541 HRESULT get_env_var(const WCHAR *name, BSTR *value)
543 DWORD len;
545 len = GetEnvironmentVariableW(name, NULL, 0);
546 if (len)
548 *value = SysAllocStringLen(NULL, len - 1);
549 if (*value)
550 GetEnvironmentVariableW(name, *value, len);
552 else
553 *value = SysAllocStringLen(NULL, 0);
555 return *value ? S_OK : E_OUTOFMEMORY;
558 static HRESULT WINAPI WshEnvironment_get_Item(IWshEnvironment *iface, BSTR name, BSTR *value)
560 WshEnvironment *This = impl_from_IWshEnvironment(iface);
562 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), value);
564 if (!value)
565 return E_POINTER;
567 return get_env_var(name, value);
570 static HRESULT WINAPI WshEnvironment_put_Item(IWshEnvironment *iface, BSTR name, BSTR value)
572 WshEnvironment *This = impl_from_IWshEnvironment(iface);
573 FIXME("(%p)->(%s %s): stub\n", This, debugstr_w(name), debugstr_w(value));
574 return E_NOTIMPL;
577 static HRESULT WINAPI WshEnvironment_Count(IWshEnvironment *iface, LONG *count)
579 WshEnvironment *This = impl_from_IWshEnvironment(iface);
580 FIXME("(%p)->(%p): stub\n", This, count);
581 return E_NOTIMPL;
584 static HRESULT WINAPI WshEnvironment_get_length(IWshEnvironment *iface, LONG *len)
586 WshEnvironment *This = impl_from_IWshEnvironment(iface);
587 FIXME("(%p)->(%p): stub\n", This, len);
588 return E_NOTIMPL;
591 static HRESULT WINAPI WshEnvironment__NewEnum(IWshEnvironment *iface, IUnknown **penum)
593 WshEnvironment *This = impl_from_IWshEnvironment(iface);
594 FIXME("(%p)->(%p): stub\n", This, penum);
595 return E_NOTIMPL;
598 static HRESULT WINAPI WshEnvironment_Remove(IWshEnvironment *iface, BSTR name)
600 WshEnvironment *This = impl_from_IWshEnvironment(iface);
601 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
602 return E_NOTIMPL;
605 static const IWshEnvironmentVtbl WshEnvironmentVtbl = {
606 WshEnvironment_QueryInterface,
607 WshEnvironment_AddRef,
608 WshEnvironment_Release,
609 WshEnvironment_GetTypeInfoCount,
610 WshEnvironment_GetTypeInfo,
611 WshEnvironment_GetIDsOfNames,
612 WshEnvironment_Invoke,
613 WshEnvironment_get_Item,
614 WshEnvironment_put_Item,
615 WshEnvironment_Count,
616 WshEnvironment_get_length,
617 WshEnvironment__NewEnum,
618 WshEnvironment_Remove
621 static HRESULT WshEnvironment_Create(IWshEnvironment **env)
623 WshEnvironment *object;
625 if (!(object = calloc(1, sizeof(*object))))
626 return E_OUTOFMEMORY;
628 object->IWshEnvironment_iface.lpVtbl = &WshEnvironmentVtbl;
629 object->ref = 1;
631 init_classinfo(&IID_IWshEnvironment, (IUnknown *)&object->IWshEnvironment_iface, &object->classinfo);
632 *env = &object->IWshEnvironment_iface;
634 return S_OK;
637 static HRESULT WINAPI WshCollection_QueryInterface(IWshCollection *iface, REFIID riid, void **ppv)
639 WshCollection *This = impl_from_IWshCollection(iface);
641 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
643 if (IsEqualGUID(riid, &IID_IUnknown) ||
644 IsEqualGUID(riid, &IID_IDispatch) ||
645 IsEqualGUID(riid, &IID_IWshCollection))
647 *ppv = iface;
649 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
651 *ppv = &This->classinfo.IProvideClassInfo_iface;
653 else {
654 FIXME("Unknown iface %s\n", debugstr_guid(riid));
655 *ppv = NULL;
656 return E_NOINTERFACE;
659 IUnknown_AddRef((IUnknown*)*ppv);
660 return S_OK;
663 static ULONG WINAPI WshCollection_AddRef(IWshCollection *iface)
665 WshCollection *collection = impl_from_IWshCollection(iface);
666 LONG ref = InterlockedIncrement(&collection->ref);
668 TRACE("%p, refcount %ld.\n", iface, ref);
670 return ref;
673 static ULONG WINAPI WshCollection_Release(IWshCollection *iface)
675 WshCollection *collection = impl_from_IWshCollection(iface);
676 LONG ref = InterlockedDecrement(&collection->ref);
677 TRACE("%p, refcount %ld.\n", iface, ref);
679 if (!ref)
680 free(collection);
682 return ref;
685 static HRESULT WINAPI WshCollection_GetTypeInfoCount(IWshCollection *iface, UINT *pctinfo)
687 WshCollection *This = impl_from_IWshCollection(iface);
688 TRACE("(%p)->(%p)\n", This, pctinfo);
689 *pctinfo = 1;
690 return S_OK;
693 static HRESULT WINAPI WshCollection_GetTypeInfo(IWshCollection *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
695 TRACE("%p, %u, %lx, %p.\n", iface, iTInfo, lcid, ppTInfo);
697 return get_typeinfo(IWshCollection_tid, ppTInfo);
700 static HRESULT WINAPI WshCollection_GetIDsOfNames(IWshCollection *iface, REFIID riid, LPOLESTR *rgszNames,
701 UINT cNames, LCID lcid, DISPID *rgDispId)
703 ITypeInfo *typeinfo;
704 HRESULT hr;
706 TRACE("%p, %s, %p, %u, %lx, %p.\n", iface, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
708 hr = get_typeinfo(IWshCollection_tid, &typeinfo);
709 if(SUCCEEDED(hr))
711 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
712 ITypeInfo_Release(typeinfo);
715 return hr;
718 static HRESULT WINAPI WshCollection_Invoke(IWshCollection *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
719 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
721 ITypeInfo *typeinfo;
722 HRESULT hr;
724 TRACE("%p, %ld, %s, %lx, %d, %p, %p, %p, %p.\n", iface, dispIdMember, debugstr_guid(riid),
725 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
727 hr = get_typeinfo(IWshCollection_tid, &typeinfo);
728 if(SUCCEEDED(hr))
730 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
731 ITypeInfo_Release(typeinfo);
734 return hr;
737 static HRESULT WINAPI WshCollection_Item(IWshCollection *iface, VARIANT *index, VARIANT *value)
739 WshCollection *This = impl_from_IWshCollection(iface);
740 PIDLIST_ABSOLUTE pidl;
741 WCHAR pathW[MAX_PATH];
742 int kind = 0;
743 BSTR folder;
744 HRESULT hr;
746 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(index), value);
748 if (V_VT(index) != VT_BSTR)
750 FIXME("only BSTR index supported, got %d\n", V_VT(index));
751 return E_NOTIMPL;
754 folder = V_BSTR(index);
755 if (!wcsicmp(folder, L"Desktop"))
756 kind = CSIDL_DESKTOP;
757 else if (!wcsicmp(folder, L"AllUsersDesktop"))
758 kind = CSIDL_COMMON_DESKTOPDIRECTORY;
759 else if (!wcsicmp(folder, L"AllUsersPrograms"))
760 kind = CSIDL_COMMON_PROGRAMS;
761 else
763 FIXME("folder kind %s not supported\n", debugstr_w(folder));
764 return E_NOTIMPL;
767 hr = SHGetSpecialFolderLocation(NULL, kind, &pidl);
768 if (hr != S_OK) return hr;
770 if (SHGetPathFromIDListW(pidl, pathW))
772 V_VT(value) = VT_BSTR;
773 V_BSTR(value) = SysAllocString(pathW);
774 hr = V_BSTR(value) ? S_OK : E_OUTOFMEMORY;
776 else
777 hr = E_FAIL;
779 CoTaskMemFree(pidl);
781 return hr;
784 static HRESULT WINAPI WshCollection_Count(IWshCollection *iface, LONG *count)
786 WshCollection *This = impl_from_IWshCollection(iface);
787 FIXME("(%p)->(%p): stub\n", This, count);
788 return E_NOTIMPL;
791 static HRESULT WINAPI WshCollection_get_length(IWshCollection *iface, LONG *count)
793 WshCollection *This = impl_from_IWshCollection(iface);
794 FIXME("(%p)->(%p): stub\n", This, count);
795 return E_NOTIMPL;
798 static HRESULT WINAPI WshCollection__NewEnum(IWshCollection *iface, IUnknown **Enum)
800 WshCollection *This = impl_from_IWshCollection(iface);
801 FIXME("(%p)->(%p): stub\n", This, Enum);
802 return E_NOTIMPL;
805 static const IWshCollectionVtbl WshCollectionVtbl = {
806 WshCollection_QueryInterface,
807 WshCollection_AddRef,
808 WshCollection_Release,
809 WshCollection_GetTypeInfoCount,
810 WshCollection_GetTypeInfo,
811 WshCollection_GetIDsOfNames,
812 WshCollection_Invoke,
813 WshCollection_Item,
814 WshCollection_Count,
815 WshCollection_get_length,
816 WshCollection__NewEnum
819 static HRESULT WshCollection_Create(IWshCollection **collection)
821 WshCollection *object;
823 if (!(object = calloc(1, sizeof(*object))))
824 return E_OUTOFMEMORY;
826 object->IWshCollection_iface.lpVtbl = &WshCollectionVtbl;
827 object->ref = 1;
829 init_classinfo(&IID_IWshCollection, (IUnknown *)&object->IWshCollection_iface, &object->classinfo);
830 *collection = &object->IWshCollection_iface;
832 return S_OK;
835 /* IWshShortcut */
836 static HRESULT WINAPI WshShortcut_QueryInterface(IWshShortcut *iface, REFIID riid, void **ppv)
838 WshShortcut *This = impl_from_IWshShortcut(iface);
840 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
842 if (IsEqualGUID(riid, &IID_IUnknown) ||
843 IsEqualGUID(riid, &IID_IDispatch) ||
844 IsEqualGUID(riid, &IID_IWshShortcut))
846 *ppv = iface;
848 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
850 *ppv = &This->classinfo.IProvideClassInfo_iface;
852 else {
853 FIXME("Unknown iface %s\n", debugstr_guid(riid));
854 *ppv = NULL;
855 return E_NOINTERFACE;
858 IUnknown_AddRef((IUnknown*)*ppv);
859 return S_OK;
862 static ULONG WINAPI WshShortcut_AddRef(IWshShortcut *iface)
864 WshShortcut *This = impl_from_IWshShortcut(iface);
865 LONG ref = InterlockedIncrement(&This->ref);
866 TRACE("%p, refcount %ld.\n", iface, ref);
867 return ref;
870 static ULONG WINAPI WshShortcut_Release(IWshShortcut *iface)
872 WshShortcut *This = impl_from_IWshShortcut(iface);
873 LONG ref = InterlockedDecrement(&This->ref);
874 TRACE("%p, refcount %ld.\n", iface, ref);
876 if (!ref)
878 IShellLinkW_Release(This->link);
879 free(This->path_link);
880 free(This);
883 return ref;
886 static HRESULT WINAPI WshShortcut_GetTypeInfoCount(IWshShortcut *iface, UINT *pctinfo)
888 WshShortcut *This = impl_from_IWshShortcut(iface);
889 TRACE("(%p)->(%p)\n", This, pctinfo);
890 *pctinfo = 1;
891 return S_OK;
894 static HRESULT WINAPI WshShortcut_GetTypeInfo(IWshShortcut *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
896 TRACE("%p, %u, %lx, %p.\n", iface, iTInfo, lcid, ppTInfo);
898 return get_typeinfo(IWshShortcut_tid, ppTInfo);
901 static HRESULT WINAPI WshShortcut_GetIDsOfNames(IWshShortcut *iface, REFIID riid, LPOLESTR *rgszNames,
902 UINT cNames, LCID lcid, DISPID *rgDispId)
904 ITypeInfo *typeinfo;
905 HRESULT hr;
907 TRACE("%p, %s, %p, %u, %lx, %p.\n", iface, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
909 hr = get_typeinfo(IWshShortcut_tid, &typeinfo);
910 if(SUCCEEDED(hr))
912 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
913 ITypeInfo_Release(typeinfo);
916 return hr;
919 static HRESULT WINAPI WshShortcut_Invoke(IWshShortcut *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
920 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
922 ITypeInfo *typeinfo;
923 HRESULT hr;
925 TRACE("%p, %ld, %s, %lx, %d, %p, %p, %p, %p.\n", iface, dispIdMember, debugstr_guid(riid),
926 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
928 hr = get_typeinfo(IWshShortcut_tid, &typeinfo);
929 if(SUCCEEDED(hr))
931 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
932 ITypeInfo_Release(typeinfo);
935 return hr;
938 static HRESULT WINAPI WshShortcut_get_FullName(IWshShortcut *iface, BSTR *name)
940 WshShortcut *This = impl_from_IWshShortcut(iface);
941 FIXME("(%p)->(%p): stub\n", This, name);
942 return E_NOTIMPL;
945 static HRESULT WINAPI WshShortcut_get_Arguments(IWshShortcut *iface, BSTR *Arguments)
947 WshShortcut *This = impl_from_IWshShortcut(iface);
948 WCHAR buffW[INFOTIPSIZE];
949 HRESULT hr;
951 TRACE("(%p)->(%p)\n", This, Arguments);
953 if (!Arguments)
954 return E_POINTER;
956 *Arguments = NULL;
958 hr = IShellLinkW_GetArguments(This->link, buffW, ARRAY_SIZE(buffW));
959 if (FAILED(hr))
960 return hr;
962 *Arguments = SysAllocString(buffW);
963 return *Arguments ? S_OK : E_OUTOFMEMORY;
966 static HRESULT WINAPI WshShortcut_put_Arguments(IWshShortcut *iface, BSTR Arguments)
968 WshShortcut *This = impl_from_IWshShortcut(iface);
970 TRACE("(%p)->(%s)\n", This, debugstr_w(Arguments));
972 return IShellLinkW_SetArguments(This->link, Arguments);
975 static HRESULT WINAPI WshShortcut_get_Description(IWshShortcut *iface, BSTR *Description)
977 WshShortcut *This = impl_from_IWshShortcut(iface);
978 FIXME("(%p)->(%p): stub\n", This, Description);
979 return E_NOTIMPL;
982 static HRESULT WINAPI WshShortcut_put_Description(IWshShortcut *iface, BSTR Description)
984 WshShortcut *This = impl_from_IWshShortcut(iface);
985 TRACE("(%p)->(%s)\n", This, debugstr_w(Description));
986 return IShellLinkW_SetDescription(This->link, Description);
989 static HRESULT WINAPI WshShortcut_get_Hotkey(IWshShortcut *iface, BSTR *Hotkey)
991 WshShortcut *This = impl_from_IWshShortcut(iface);
992 FIXME("(%p)->(%p): stub\n", This, Hotkey);
993 return E_NOTIMPL;
996 static HRESULT WINAPI WshShortcut_put_Hotkey(IWshShortcut *iface, BSTR Hotkey)
998 WshShortcut *This = impl_from_IWshShortcut(iface);
999 FIXME("(%p)->(%s): stub\n", This, debugstr_w(Hotkey));
1000 return E_NOTIMPL;
1003 static HRESULT WINAPI WshShortcut_get_IconLocation(IWshShortcut *iface, BSTR *IconPath)
1005 WshShortcut *This = impl_from_IWshShortcut(iface);
1006 WCHAR buffW[MAX_PATH], pathW[MAX_PATH];
1007 INT icon = 0;
1008 HRESULT hr;
1010 TRACE("(%p)->(%p)\n", This, IconPath);
1012 if (!IconPath)
1013 return E_POINTER;
1015 hr = IShellLinkW_GetIconLocation(This->link, buffW, ARRAY_SIZE(buffW), &icon);
1016 if (FAILED(hr)) return hr;
1018 swprintf(pathW, ARRAY_SIZE(pathW), L"%s, %d", buffW, icon);
1019 *IconPath = SysAllocString(pathW);
1020 if (!*IconPath) return E_OUTOFMEMORY;
1022 return S_OK;
1025 static HRESULT WINAPI WshShortcut_put_IconLocation(IWshShortcut *iface, BSTR IconPath)
1027 WshShortcut *This = impl_from_IWshShortcut(iface);
1028 HRESULT hr;
1029 WCHAR *ptr;
1030 BSTR path;
1031 INT icon;
1033 TRACE("(%p)->(%s)\n", This, debugstr_w(IconPath));
1035 /* scan for icon id */
1036 ptr = wcsrchr(IconPath, ',');
1037 if (!ptr)
1039 WARN("icon index not found\n");
1040 return E_FAIL;
1043 path = SysAllocStringLen(IconPath, ptr-IconPath);
1045 /* skip spaces if any */
1046 while (iswspace(*++ptr))
1049 icon = wcstol(ptr, NULL, 10);
1051 hr = IShellLinkW_SetIconLocation(This->link, path, icon);
1052 SysFreeString(path);
1054 return hr;
1057 static HRESULT WINAPI WshShortcut_put_RelativePath(IWshShortcut *iface, BSTR rhs)
1059 WshShortcut *This = impl_from_IWshShortcut(iface);
1060 FIXME("(%p)->(%s): stub\n", This, debugstr_w(rhs));
1061 return E_NOTIMPL;
1064 static HRESULT WINAPI WshShortcut_get_TargetPath(IWshShortcut *iface, BSTR *Path)
1066 WshShortcut *This = impl_from_IWshShortcut(iface);
1067 FIXME("(%p)->(%p): stub\n", This, Path);
1068 return E_NOTIMPL;
1071 static HRESULT WINAPI WshShortcut_put_TargetPath(IWshShortcut *iface, BSTR Path)
1073 WshShortcut *This = impl_from_IWshShortcut(iface);
1074 TRACE("(%p)->(%s)\n", This, debugstr_w(Path));
1075 return IShellLinkW_SetPath(This->link, Path);
1078 static HRESULT WINAPI WshShortcut_get_WindowStyle(IWshShortcut *iface, int *ShowCmd)
1080 WshShortcut *This = impl_from_IWshShortcut(iface);
1081 TRACE("(%p)->(%p)\n", This, ShowCmd);
1082 return IShellLinkW_GetShowCmd(This->link, ShowCmd);
1085 static HRESULT WINAPI WshShortcut_put_WindowStyle(IWshShortcut *iface, int ShowCmd)
1087 WshShortcut *This = impl_from_IWshShortcut(iface);
1088 TRACE("(%p)->(%d)\n", This, ShowCmd);
1089 return IShellLinkW_SetShowCmd(This->link, ShowCmd);
1092 static HRESULT WINAPI WshShortcut_get_WorkingDirectory(IWshShortcut *iface, BSTR *WorkingDirectory)
1094 WshShortcut *This = impl_from_IWshShortcut(iface);
1095 WCHAR buffW[MAX_PATH];
1096 HRESULT hr;
1098 TRACE("(%p)->(%p)\n", This, WorkingDirectory);
1100 if (!WorkingDirectory)
1101 return E_POINTER;
1103 *WorkingDirectory = NULL;
1104 hr = IShellLinkW_GetWorkingDirectory(This->link, buffW, ARRAY_SIZE(buffW));
1105 if (FAILED(hr)) return hr;
1107 *WorkingDirectory = SysAllocString(buffW);
1108 return *WorkingDirectory ? S_OK : E_OUTOFMEMORY;
1111 static HRESULT WINAPI WshShortcut_put_WorkingDirectory(IWshShortcut *iface, BSTR WorkingDirectory)
1113 WshShortcut *This = impl_from_IWshShortcut(iface);
1114 TRACE("(%p)->(%s)\n", This, debugstr_w(WorkingDirectory));
1115 return IShellLinkW_SetWorkingDirectory(This->link, WorkingDirectory);
1118 static HRESULT WINAPI WshShortcut_Load(IWshShortcut *iface, BSTR PathLink)
1120 WshShortcut *This = impl_from_IWshShortcut(iface);
1121 FIXME("(%p)->(%s): stub\n", This, debugstr_w(PathLink));
1122 return E_NOTIMPL;
1125 static HRESULT WINAPI WshShortcut_Save(IWshShortcut *iface)
1127 WshShortcut *This = impl_from_IWshShortcut(iface);
1128 IPersistFile *file;
1129 HRESULT hr;
1131 TRACE("(%p)\n", This);
1133 IShellLinkW_QueryInterface(This->link, &IID_IPersistFile, (void**)&file);
1134 hr = IPersistFile_Save(file, This->path_link, TRUE);
1135 IPersistFile_Release(file);
1137 return hr;
1140 static const IWshShortcutVtbl WshShortcutVtbl = {
1141 WshShortcut_QueryInterface,
1142 WshShortcut_AddRef,
1143 WshShortcut_Release,
1144 WshShortcut_GetTypeInfoCount,
1145 WshShortcut_GetTypeInfo,
1146 WshShortcut_GetIDsOfNames,
1147 WshShortcut_Invoke,
1148 WshShortcut_get_FullName,
1149 WshShortcut_get_Arguments,
1150 WshShortcut_put_Arguments,
1151 WshShortcut_get_Description,
1152 WshShortcut_put_Description,
1153 WshShortcut_get_Hotkey,
1154 WshShortcut_put_Hotkey,
1155 WshShortcut_get_IconLocation,
1156 WshShortcut_put_IconLocation,
1157 WshShortcut_put_RelativePath,
1158 WshShortcut_get_TargetPath,
1159 WshShortcut_put_TargetPath,
1160 WshShortcut_get_WindowStyle,
1161 WshShortcut_put_WindowStyle,
1162 WshShortcut_get_WorkingDirectory,
1163 WshShortcut_put_WorkingDirectory,
1164 WshShortcut_Load,
1165 WshShortcut_Save
1168 static HRESULT WshShortcut_Create(const WCHAR *path, IDispatch **shortcut)
1170 WshShortcut *object;
1171 HRESULT hr;
1173 *shortcut = NULL;
1175 if (!(object = calloc(1, sizeof(*object))))
1176 return E_OUTOFMEMORY;
1178 object->IWshShortcut_iface.lpVtbl = &WshShortcutVtbl;
1179 object->ref = 1;
1181 hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (void **)&object->link);
1182 if (FAILED(hr))
1184 free(object);
1185 return hr;
1188 object->path_link = wcsdup(path);
1189 if (!object->path_link)
1191 IShellLinkW_Release(object->link);
1192 free(object);
1193 return E_OUTOFMEMORY;
1196 init_classinfo(&IID_IWshShortcut, (IUnknown *)&object->IWshShortcut_iface, &object->classinfo);
1197 *shortcut = (IDispatch *)&object->IWshShortcut_iface;
1199 return S_OK;
1202 static HRESULT WINAPI WshShell3_QueryInterface(IWshShell3 *iface, REFIID riid, void **ppv)
1204 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
1206 *ppv = NULL;
1208 if (IsEqualGUID(riid, &IID_IDispatch) ||
1209 IsEqualGUID(riid, &IID_IWshShell3) ||
1210 IsEqualGUID(riid, &IID_IWshShell2) ||
1211 IsEqualGUID(riid, &IID_IWshShell) ||
1212 IsEqualGUID(riid, &IID_IUnknown))
1214 *ppv = iface;
1216 else if (IsEqualGUID(riid, &IID_IDispatchEx))
1218 return E_NOINTERFACE;
1220 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
1222 *ppv = &WshShell3.classinfo.IProvideClassInfo_iface;
1224 else
1226 WARN("unknown iface %s\n", debugstr_guid(riid));
1227 return E_NOINTERFACE;
1230 IUnknown_AddRef((IUnknown *)*ppv);
1231 return S_OK;
1234 static ULONG WINAPI WshShell3_AddRef(IWshShell3 *iface)
1236 TRACE("()\n");
1237 return 2;
1240 static ULONG WINAPI WshShell3_Release(IWshShell3 *iface)
1242 TRACE("()\n");
1243 return 2;
1246 static HRESULT WINAPI WshShell3_GetTypeInfoCount(IWshShell3 *iface, UINT *pctinfo)
1248 TRACE("(%p)\n", pctinfo);
1249 *pctinfo = 1;
1250 return S_OK;
1253 static HRESULT WINAPI WshShell3_GetTypeInfo(IWshShell3 *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
1255 TRACE("%u, %lx, %p.\n", iTInfo, lcid, ppTInfo);
1257 return get_typeinfo(IWshShell3_tid, ppTInfo);
1260 static HRESULT WINAPI WshShell3_GetIDsOfNames(IWshShell3 *iface, REFIID riid, LPOLESTR *rgszNames,
1261 UINT cNames, LCID lcid, DISPID *rgDispId)
1263 ITypeInfo *typeinfo;
1264 HRESULT hr;
1266 TRACE("%s, %p, %u, %lx, %p.\n", debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1268 hr = get_typeinfo(IWshShell3_tid, &typeinfo);
1269 if(SUCCEEDED(hr))
1271 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1272 ITypeInfo_Release(typeinfo);
1275 return hr;
1278 static HRESULT WINAPI WshShell3_Invoke(IWshShell3 *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
1279 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
1281 ITypeInfo *typeinfo;
1282 HRESULT hr;
1284 TRACE("%ld, %s, %lx, %d, %p, %p, %p, %p.\n", dispIdMember, debugstr_guid(riid),
1285 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1287 hr = get_typeinfo(IWshShell3_tid, &typeinfo);
1288 if(SUCCEEDED(hr))
1290 hr = ITypeInfo_Invoke(typeinfo, &WshShell3.IWshShell3_iface, dispIdMember, wFlags,
1291 pDispParams, pVarResult, pExcepInfo, puArgErr);
1292 ITypeInfo_Release(typeinfo);
1295 return hr;
1298 static HRESULT WINAPI WshShell3_get_SpecialFolders(IWshShell3 *iface, IWshCollection **folders)
1300 TRACE("(%p)\n", folders);
1301 return WshCollection_Create(folders);
1304 static HRESULT WINAPI WshShell3_get_Environment(IWshShell3 *iface, VARIANT *type, IWshEnvironment **env)
1306 FIXME("(%s %p): semi-stub\n", debugstr_variant(type), env);
1307 return WshEnvironment_Create(env);
1310 static inline BOOL is_optional_argument(const VARIANT *arg)
1312 return V_VT(arg) == VT_ERROR && V_ERROR(arg) == DISP_E_PARAMNOTFOUND;
1315 static WCHAR *split_command( BSTR cmd, WCHAR **params )
1317 WCHAR *ret, *ptr;
1318 BOOL in_quotes = FALSE;
1320 if (!(ret = wcsdup(cmd))) return NULL;
1322 *params = NULL;
1323 for (ptr = ret; *ptr; ptr++)
1325 if (*ptr == '"') in_quotes = !in_quotes;
1326 else if (*ptr == ' ' && !in_quotes)
1328 *ptr = 0;
1329 *params = ptr + 1;
1330 break;
1334 return ret;
1337 static HRESULT WINAPI WshShell3_Run(IWshShell3 *iface, BSTR cmd, VARIANT *style, VARIANT *wait, int *exit_code)
1339 SHELLEXECUTEINFOW info;
1340 int waitforprocess, show;
1341 WCHAR *file, *params;
1342 VARIANT v;
1343 HRESULT hr;
1344 BOOL ret;
1346 TRACE("(%s %s %s %p)\n", debugstr_w(cmd), debugstr_variant(style), debugstr_variant(wait), exit_code);
1348 if (!style || !wait || !exit_code)
1349 return E_POINTER;
1351 if (is_optional_argument(style))
1352 show = SW_SHOWNORMAL;
1353 else {
1354 VariantInit(&v);
1355 hr = VariantChangeType(&v, style, 0, VT_I4);
1356 if (FAILED(hr))
1357 return hr;
1359 show = V_I4(&v);
1362 if (is_optional_argument(wait))
1363 waitforprocess = 0;
1364 else {
1365 VariantInit(&v);
1366 hr = VariantChangeType(&v, wait, 0, VT_I4);
1367 if (FAILED(hr))
1368 return hr;
1370 waitforprocess = V_I4(&v);
1373 if (!(file = split_command(cmd, &params))) return E_OUTOFMEMORY;
1375 memset(&info, 0, sizeof(info));
1376 info.cbSize = sizeof(info);
1377 info.fMask = SEE_MASK_FLAG_NO_UI;
1378 info.fMask |= waitforprocess ? SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS : SEE_MASK_DEFAULT;
1379 info.lpFile = file;
1380 info.lpParameters = params;
1381 info.nShow = show;
1383 ret = ShellExecuteExW(&info);
1384 free(file);
1385 if (!ret)
1387 TRACE("ShellExecute failed, %ld\n", GetLastError());
1388 *exit_code = GetLastError();
1390 else
1392 if (waitforprocess)
1394 DWORD code;
1395 WaitForSingleObject(info.hProcess, INFINITE);
1396 GetExitCodeProcess(info.hProcess, &code);
1397 CloseHandle(info.hProcess);
1398 *exit_code = code;
1400 else
1401 *exit_code = 0;
1404 return S_OK;
1407 struct popup_thread_param
1409 WCHAR *text;
1410 VARIANT title;
1411 VARIANT type;
1412 INT button;
1415 static DWORD WINAPI popup_thread_proc(void *arg)
1417 struct popup_thread_param *param = (struct popup_thread_param *)arg;
1419 param->button = MessageBoxW(NULL, param->text, is_optional_argument(&param->title) ?
1420 L"Windows Script Host" : V_BSTR(&param->title), V_I4(&param->type));
1421 return 0;
1424 static HRESULT WINAPI WshShell3_Popup(IWshShell3 *iface, BSTR text, VARIANT *seconds_to_wait, VARIANT *title,
1425 VARIANT *type, int *button)
1427 struct popup_thread_param param;
1428 DWORD tid, status;
1429 VARIANT timeout;
1430 HANDLE hthread;
1431 HRESULT hr;
1433 TRACE("(%s %s %s %s %p)\n", debugstr_w(text), debugstr_variant(seconds_to_wait), debugstr_variant(title),
1434 debugstr_variant(type), button);
1436 if (!seconds_to_wait || !title || !type || !button)
1437 return E_POINTER;
1439 VariantInit(&timeout);
1440 if (!is_optional_argument(seconds_to_wait))
1442 hr = VariantChangeType(&timeout, seconds_to_wait, 0, VT_I4);
1443 if (FAILED(hr))
1444 return hr;
1447 VariantInit(&param.type);
1448 if (!is_optional_argument(type))
1450 hr = VariantChangeType(&param.type, type, 0, VT_I4);
1451 if (FAILED(hr))
1452 return hr;
1455 if (is_optional_argument(title))
1456 param.title = *title;
1457 else
1459 VariantInit(&param.title);
1460 hr = VariantChangeType(&param.title, title, 0, VT_BSTR);
1461 if (FAILED(hr))
1462 return hr;
1465 param.text = text;
1466 param.button = -1;
1467 hthread = CreateThread(NULL, 0, popup_thread_proc, &param, 0, &tid);
1468 status = MsgWaitForMultipleObjects(1, &hthread, FALSE, V_I4(&timeout) ? V_I4(&timeout) * 1000: INFINITE, 0);
1469 if (status == WAIT_TIMEOUT)
1471 PostThreadMessageW(tid, WM_QUIT, 0, 0);
1472 MsgWaitForMultipleObjects(1, &hthread, FALSE, INFINITE, 0);
1473 param.button = -1;
1475 *button = param.button;
1477 VariantClear(&param.title);
1478 CloseHandle(hthread);
1480 return S_OK;
1483 static HRESULT WINAPI WshShell3_CreateShortcut(IWshShell3 *iface, BSTR PathLink, IDispatch** Shortcut)
1485 TRACE("(%s %p)\n", debugstr_w(PathLink), Shortcut);
1486 return WshShortcut_Create(PathLink, Shortcut);
1489 static HRESULT WINAPI WshShell3_ExpandEnvironmentStrings(IWshShell3 *iface, BSTR Src, BSTR* Dst)
1491 DWORD ret;
1493 TRACE("(%s %p)\n", debugstr_w(Src), Dst);
1495 if (!Src || !Dst) return E_POINTER;
1497 ret = ExpandEnvironmentStringsW(Src, NULL, 0);
1498 *Dst = SysAllocStringLen(NULL, ret);
1499 if (!*Dst) return E_OUTOFMEMORY;
1501 if (ExpandEnvironmentStringsW(Src, *Dst, ret))
1502 return S_OK;
1503 else
1505 SysFreeString(*Dst);
1506 *Dst = NULL;
1507 return HRESULT_FROM_WIN32(GetLastError());
1511 static HKEY get_root_key(const WCHAR *path)
1513 static const struct {
1514 const WCHAR full[20];
1515 const WCHAR abbrev[5];
1516 HKEY hkey;
1517 } rootkeys[] = {
1518 { L"HKEY_CURRENT_USER", L"HKCU", HKEY_CURRENT_USER },
1519 { L"HKEY_LOCAL_MACHINE", L"HKLM", HKEY_LOCAL_MACHINE },
1520 { L"HKEY_CLASSES_ROOT", L"HKCR", HKEY_CLASSES_ROOT },
1521 { L"HKEY_USERS", {0}, HKEY_USERS },
1522 { L"HKEY_CURRENT_CONFIG", {0}, HKEY_CURRENT_CONFIG }
1524 int i;
1526 for (i = 0; i < ARRAY_SIZE(rootkeys); i++) {
1527 if (!wcsncmp(path, rootkeys[i].full, lstrlenW(rootkeys[i].full)))
1528 return rootkeys[i].hkey;
1529 if (rootkeys[i].abbrev[0] && !wcsncmp(path, rootkeys[i].abbrev, lstrlenW(rootkeys[i].abbrev)))
1530 return rootkeys[i].hkey;
1533 return NULL;
1536 /* Caller is responsible to free 'subkey' if 'value' is not NULL */
1537 static HRESULT split_reg_path(const WCHAR *path, WCHAR **subkey, WCHAR **value)
1539 *value = NULL;
1541 /* at least one separator should be present */
1542 *subkey = wcschr(path, '\\');
1543 if (!*subkey)
1544 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1546 /* default value or not */
1547 if ((*subkey)[lstrlenW(*subkey)-1] == '\\') {
1548 (*subkey)++;
1549 *value = NULL;
1551 else {
1552 *value = wcsrchr(*subkey, '\\');
1553 if (*value - *subkey > 1) {
1554 unsigned int len = *value - *subkey - 1;
1555 WCHAR *ret;
1557 ret = malloc((len + 1)*sizeof(WCHAR));
1558 if (!ret)
1559 return E_OUTOFMEMORY;
1561 memcpy(ret, *subkey + 1, len*sizeof(WCHAR));
1562 ret[len] = 0;
1563 *subkey = ret;
1565 (*value)++;
1568 return S_OK;
1571 static HRESULT WINAPI WshShell3_RegRead(IWshShell3 *iface, BSTR name, VARIANT *value)
1573 DWORD type, datalen, ret;
1574 WCHAR *subkey, *val;
1575 HRESULT hr;
1576 HKEY root;
1578 TRACE("(%s %p)\n", debugstr_w(name), value);
1580 if (!name || !value)
1581 return E_POINTER;
1583 root = get_root_key(name);
1584 if (!root)
1585 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1587 hr = split_reg_path(name, &subkey, &val);
1588 if (FAILED(hr))
1589 return hr;
1591 type = REG_NONE;
1592 datalen = 0;
1593 ret = RegGetValueW(root, subkey, val, RRF_RT_ANY, &type, NULL, &datalen);
1594 if (ret == ERROR_SUCCESS) {
1595 void *data;
1597 data = malloc(datalen);
1598 if (!data) {
1599 hr = E_OUTOFMEMORY;
1600 goto fail;
1603 ret = RegGetValueW(root, subkey, val, RRF_RT_ANY, &type, data, &datalen);
1604 if (ret) {
1605 free(data);
1606 hr = HRESULT_FROM_WIN32(ret);
1607 goto fail;
1610 switch (type) {
1611 case REG_SZ:
1612 case REG_EXPAND_SZ:
1613 V_VT(value) = VT_BSTR;
1614 V_BSTR(value) = SysAllocString((WCHAR*)data);
1615 if (!V_BSTR(value))
1616 hr = E_OUTOFMEMORY;
1617 break;
1618 case REG_DWORD:
1619 V_VT(value) = VT_I4;
1620 V_I4(value) = *(DWORD*)data;
1621 break;
1622 case REG_BINARY:
1624 BYTE *ptr = (BYTE*)data;
1625 SAFEARRAYBOUND bound;
1626 unsigned int i;
1627 SAFEARRAY *sa;
1628 VARIANT *v;
1630 bound.lLbound = 0;
1631 bound.cElements = datalen;
1632 sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
1633 if (!sa)
1634 break;
1636 hr = SafeArrayAccessData(sa, (void**)&v);
1637 if (FAILED(hr)) {
1638 SafeArrayDestroy(sa);
1639 break;
1642 for (i = 0; i < datalen; i++) {
1643 V_VT(&v[i]) = VT_UI1;
1644 V_UI1(&v[i]) = ptr[i];
1646 SafeArrayUnaccessData(sa);
1648 V_VT(value) = VT_ARRAY|VT_VARIANT;
1649 V_ARRAY(value) = sa;
1650 break;
1652 case REG_MULTI_SZ:
1654 WCHAR *ptr = (WCHAR*)data;
1655 SAFEARRAYBOUND bound;
1656 SAFEARRAY *sa;
1657 VARIANT *v;
1659 /* get element count first */
1660 bound.lLbound = 0;
1661 bound.cElements = 0;
1662 while (*ptr) {
1663 bound.cElements++;
1664 ptr += lstrlenW(ptr)+1;
1667 sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
1668 if (!sa)
1669 break;
1671 hr = SafeArrayAccessData(sa, (void**)&v);
1672 if (FAILED(hr)) {
1673 SafeArrayDestroy(sa);
1674 break;
1677 ptr = (WCHAR*)data;
1678 while (*ptr) {
1679 V_VT(v) = VT_BSTR;
1680 V_BSTR(v) = SysAllocString(ptr);
1681 ptr += lstrlenW(ptr)+1;
1682 v++;
1685 SafeArrayUnaccessData(sa);
1686 V_VT(value) = VT_ARRAY|VT_VARIANT;
1687 V_ARRAY(value) = sa;
1688 break;
1690 default:
1691 FIXME("value type %ld not supported\n", type);
1692 hr = E_FAIL;
1695 free(data);
1696 if (FAILED(hr))
1697 VariantInit(value);
1699 else
1700 hr = HRESULT_FROM_WIN32(ret);
1702 fail:
1703 if (val)
1704 free(subkey);
1705 return hr;
1708 static HRESULT WINAPI WshShell3_RegWrite(IWshShell3 *iface, BSTR name, VARIANT *value, VARIANT *type)
1710 DWORD regtype, data_len;
1711 WCHAR *subkey, *val;
1712 const BYTE *data;
1713 HRESULT hr;
1714 HKEY root;
1715 VARIANT v;
1716 LONG ret;
1718 TRACE("(%s %s %s)\n", debugstr_w(name), debugstr_variant(value), debugstr_variant(type));
1720 if (!name || !value || !type)
1721 return E_POINTER;
1723 root = get_root_key(name);
1724 if (!root)
1725 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1727 /* value type */
1728 if (is_optional_argument(type))
1729 regtype = REG_SZ;
1730 else {
1731 if (V_VT(type) != VT_BSTR)
1732 return E_INVALIDARG;
1734 if (!wcscmp(V_BSTR(type), L"REG_SZ"))
1735 regtype = REG_SZ;
1736 else if (!wcscmp(V_BSTR(type), L"REG_DWORD"))
1737 regtype = REG_DWORD;
1738 else if (!wcscmp(V_BSTR(type), L"REG_EXPAND_SZ"))
1739 regtype = REG_EXPAND_SZ;
1740 else if (!wcscmp(V_BSTR(type), L"REG_BINARY"))
1741 regtype = REG_BINARY;
1742 else {
1743 FIXME("unrecognized value type %s\n", debugstr_w(V_BSTR(type)));
1744 return E_FAIL;
1748 /* it's always a string or a DWORD */
1749 VariantInit(&v);
1750 switch (regtype)
1752 case REG_SZ:
1753 case REG_EXPAND_SZ:
1754 hr = VariantChangeType(&v, value, 0, VT_BSTR);
1755 if (hr == S_OK) {
1756 data = (BYTE*)V_BSTR(&v);
1757 data_len = SysStringByteLen(V_BSTR(&v)) + sizeof(WCHAR);
1759 break;
1760 case REG_DWORD:
1761 case REG_BINARY:
1762 hr = VariantChangeType(&v, value, 0, VT_I4);
1763 data = (BYTE*)&V_I4(&v);
1764 data_len = sizeof(DWORD);
1765 break;
1766 default:
1767 FIXME("unexpected regtype %ld\n", regtype);
1768 return E_FAIL;
1771 if (FAILED(hr)) {
1772 FIXME("failed to convert value, regtype %ld, %#lx.\n", regtype, hr);
1773 return hr;
1776 hr = split_reg_path(name, &subkey, &val);
1777 if (FAILED(hr))
1778 goto fail;
1780 ret = RegSetKeyValueW(root, subkey, val, regtype, data, data_len);
1781 if (ret)
1782 hr = HRESULT_FROM_WIN32(ret);
1784 fail:
1785 VariantClear(&v);
1786 if (val)
1787 free(subkey);
1788 return hr;
1791 static HRESULT WINAPI WshShell3_RegDelete(IWshShell3 *iface, BSTR Name)
1793 FIXME("(%s): stub\n", debugstr_w(Name));
1794 return E_NOTIMPL;
1797 static HRESULT WINAPI WshShell3_LogEvent(IWshShell3 *iface, VARIANT *Type, BSTR Message, BSTR Target, VARIANT_BOOL *out_Success)
1799 FIXME("(%s %s %s %p): stub\n", debugstr_variant(Type), debugstr_w(Message), debugstr_w(Target), out_Success);
1800 return E_NOTIMPL;
1803 static HRESULT WINAPI WshShell3_AppActivate(IWshShell3 *iface, VARIANT *App, VARIANT *Wait, VARIANT_BOOL *out_Success)
1805 FIXME("(%s %s %p): stub\n", debugstr_variant(App), debugstr_variant(Wait), out_Success);
1806 return E_NOTIMPL;
1809 static HRESULT WINAPI WshShell3_SendKeys(IWshShell3 *iface, BSTR Keys, VARIANT *Wait)
1811 FIXME("(%s %p): stub\n", debugstr_w(Keys), Wait);
1812 return E_NOTIMPL;
1815 static HRESULT WINAPI WshShell3_Exec(IWshShell3 *iface, BSTR command, IWshExec **ret)
1817 BSTR expandedcmd;
1818 HRESULT hr;
1820 TRACE("(%s %p)\n", debugstr_w(command), ret);
1822 if (!ret)
1823 return E_POINTER;
1825 if (!command)
1826 return DISP_E_EXCEPTION;
1828 hr = WshShell3_ExpandEnvironmentStrings(iface, command, &expandedcmd);
1829 if (FAILED(hr))
1830 return hr;
1832 hr = WshExec_create(expandedcmd, ret);
1833 SysFreeString(expandedcmd);
1834 return hr;
1837 static HRESULT WINAPI WshShell3_get_CurrentDirectory(IWshShell3 *iface, BSTR *dir)
1839 DWORD ret;
1841 TRACE("(%p)\n", dir);
1843 ret = GetCurrentDirectoryW(0, NULL);
1844 if (!ret)
1845 return HRESULT_FROM_WIN32(GetLastError());
1847 *dir = SysAllocStringLen(NULL, ret-1);
1848 if (!*dir)
1849 return E_OUTOFMEMORY;
1851 ret = GetCurrentDirectoryW(ret, *dir);
1852 if (!ret) {
1853 SysFreeString(*dir);
1854 *dir = NULL;
1855 return HRESULT_FROM_WIN32(GetLastError());
1858 return S_OK;
1861 static HRESULT WINAPI WshShell3_put_CurrentDirectory(IWshShell3 *iface, BSTR dir)
1863 TRACE("(%s)\n", debugstr_w(dir));
1865 if (!dir)
1866 return E_INVALIDARG;
1868 if (!SetCurrentDirectoryW(dir))
1869 return HRESULT_FROM_WIN32(GetLastError());
1871 return S_OK;
1874 static const IWshShell3Vtbl WshShell3Vtbl = {
1875 WshShell3_QueryInterface,
1876 WshShell3_AddRef,
1877 WshShell3_Release,
1878 WshShell3_GetTypeInfoCount,
1879 WshShell3_GetTypeInfo,
1880 WshShell3_GetIDsOfNames,
1881 WshShell3_Invoke,
1882 WshShell3_get_SpecialFolders,
1883 WshShell3_get_Environment,
1884 WshShell3_Run,
1885 WshShell3_Popup,
1886 WshShell3_CreateShortcut,
1887 WshShell3_ExpandEnvironmentStrings,
1888 WshShell3_RegRead,
1889 WshShell3_RegWrite,
1890 WshShell3_RegDelete,
1891 WshShell3_LogEvent,
1892 WshShell3_AppActivate,
1893 WshShell3_SendKeys,
1894 WshShell3_Exec,
1895 WshShell3_get_CurrentDirectory,
1896 WshShell3_put_CurrentDirectory
1899 HRESULT WINAPI WshShellFactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
1901 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
1903 WshShell3.IWshShell3_iface.lpVtbl = &WshShell3Vtbl;
1904 init_classinfo(&IID_IWshShell3, (IUnknown *)&WshShell3.IWshShell3_iface, &WshShell3.classinfo);
1905 return IWshShell3_QueryInterface(&WshShell3.IWshShell3_iface, riid, ppv);