mshtml: Implement MediaQueryList's matches prop.
[wine.git] / dlls / wshom.ocx / shell.c
blobe04844458b10f9c41e5487f2e661f1c65887f722
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, DWORD *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, DWORD *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 static HRESULT WINAPI WshEnvironment_get_Item(IWshEnvironment *iface, BSTR name, BSTR *value)
543 WshEnvironment *This = impl_from_IWshEnvironment(iface);
544 DWORD len;
546 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), value);
548 if (!value)
549 return E_POINTER;
551 len = GetEnvironmentVariableW(name, NULL, 0);
552 if (len)
554 *value = SysAllocStringLen(NULL, len - 1);
555 if (*value)
556 GetEnvironmentVariableW(name, *value, len);
558 else
559 *value = SysAllocStringLen(NULL, 0);
561 return *value ? S_OK : E_OUTOFMEMORY;
564 static HRESULT WINAPI WshEnvironment_put_Item(IWshEnvironment *iface, BSTR name, BSTR value)
566 WshEnvironment *This = impl_from_IWshEnvironment(iface);
567 FIXME("(%p)->(%s %s): stub\n", This, debugstr_w(name), debugstr_w(value));
568 return E_NOTIMPL;
571 static HRESULT WINAPI WshEnvironment_Count(IWshEnvironment *iface, LONG *count)
573 WshEnvironment *This = impl_from_IWshEnvironment(iface);
574 FIXME("(%p)->(%p): stub\n", This, count);
575 return E_NOTIMPL;
578 static HRESULT WINAPI WshEnvironment_get_length(IWshEnvironment *iface, LONG *len)
580 WshEnvironment *This = impl_from_IWshEnvironment(iface);
581 FIXME("(%p)->(%p): stub\n", This, len);
582 return E_NOTIMPL;
585 static HRESULT WINAPI WshEnvironment__NewEnum(IWshEnvironment *iface, IUnknown **penum)
587 WshEnvironment *This = impl_from_IWshEnvironment(iface);
588 FIXME("(%p)->(%p): stub\n", This, penum);
589 return E_NOTIMPL;
592 static HRESULT WINAPI WshEnvironment_Remove(IWshEnvironment *iface, BSTR name)
594 WshEnvironment *This = impl_from_IWshEnvironment(iface);
595 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
596 return E_NOTIMPL;
599 static const IWshEnvironmentVtbl WshEnvironmentVtbl = {
600 WshEnvironment_QueryInterface,
601 WshEnvironment_AddRef,
602 WshEnvironment_Release,
603 WshEnvironment_GetTypeInfoCount,
604 WshEnvironment_GetTypeInfo,
605 WshEnvironment_GetIDsOfNames,
606 WshEnvironment_Invoke,
607 WshEnvironment_get_Item,
608 WshEnvironment_put_Item,
609 WshEnvironment_Count,
610 WshEnvironment_get_length,
611 WshEnvironment__NewEnum,
612 WshEnvironment_Remove
615 static HRESULT WshEnvironment_Create(IWshEnvironment **env)
617 WshEnvironment *object;
619 if (!(object = calloc(1, sizeof(*object))))
620 return E_OUTOFMEMORY;
622 object->IWshEnvironment_iface.lpVtbl = &WshEnvironmentVtbl;
623 object->ref = 1;
625 init_classinfo(&IID_IWshEnvironment, (IUnknown *)&object->IWshEnvironment_iface, &object->classinfo);
626 *env = &object->IWshEnvironment_iface;
628 return S_OK;
631 static HRESULT WINAPI WshCollection_QueryInterface(IWshCollection *iface, REFIID riid, void **ppv)
633 WshCollection *This = impl_from_IWshCollection(iface);
635 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
637 if (IsEqualGUID(riid, &IID_IUnknown) ||
638 IsEqualGUID(riid, &IID_IDispatch) ||
639 IsEqualGUID(riid, &IID_IWshCollection))
641 *ppv = iface;
643 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
645 *ppv = &This->classinfo.IProvideClassInfo_iface;
647 else {
648 FIXME("Unknown iface %s\n", debugstr_guid(riid));
649 *ppv = NULL;
650 return E_NOINTERFACE;
653 IUnknown_AddRef((IUnknown*)*ppv);
654 return S_OK;
657 static ULONG WINAPI WshCollection_AddRef(IWshCollection *iface)
659 WshCollection *collection = impl_from_IWshCollection(iface);
660 LONG ref = InterlockedIncrement(&collection->ref);
662 TRACE("%p, refcount %ld.\n", iface, ref);
664 return ref;
667 static ULONG WINAPI WshCollection_Release(IWshCollection *iface)
669 WshCollection *collection = impl_from_IWshCollection(iface);
670 LONG ref = InterlockedDecrement(&collection->ref);
671 TRACE("%p, refcount %ld.\n", iface, ref);
673 if (!ref)
674 free(collection);
676 return ref;
679 static HRESULT WINAPI WshCollection_GetTypeInfoCount(IWshCollection *iface, UINT *pctinfo)
681 WshCollection *This = impl_from_IWshCollection(iface);
682 TRACE("(%p)->(%p)\n", This, pctinfo);
683 *pctinfo = 1;
684 return S_OK;
687 static HRESULT WINAPI WshCollection_GetTypeInfo(IWshCollection *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
689 TRACE("%p, %u, %lx, %p.\n", iface, iTInfo, lcid, ppTInfo);
691 return get_typeinfo(IWshCollection_tid, ppTInfo);
694 static HRESULT WINAPI WshCollection_GetIDsOfNames(IWshCollection *iface, REFIID riid, LPOLESTR *rgszNames,
695 UINT cNames, LCID lcid, DISPID *rgDispId)
697 ITypeInfo *typeinfo;
698 HRESULT hr;
700 TRACE("%p, %s, %p, %u, %lx, %p.\n", iface, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
702 hr = get_typeinfo(IWshCollection_tid, &typeinfo);
703 if(SUCCEEDED(hr))
705 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
706 ITypeInfo_Release(typeinfo);
709 return hr;
712 static HRESULT WINAPI WshCollection_Invoke(IWshCollection *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
713 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
715 ITypeInfo *typeinfo;
716 HRESULT hr;
718 TRACE("%p, %ld, %s, %lx, %d, %p, %p, %p, %p.\n", iface, dispIdMember, debugstr_guid(riid),
719 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
721 hr = get_typeinfo(IWshCollection_tid, &typeinfo);
722 if(SUCCEEDED(hr))
724 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
725 ITypeInfo_Release(typeinfo);
728 return hr;
731 static HRESULT WINAPI WshCollection_Item(IWshCollection *iface, VARIANT *index, VARIANT *value)
733 WshCollection *This = impl_from_IWshCollection(iface);
734 PIDLIST_ABSOLUTE pidl;
735 WCHAR pathW[MAX_PATH];
736 int kind = 0;
737 BSTR folder;
738 HRESULT hr;
740 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(index), value);
742 if (V_VT(index) != VT_BSTR)
744 FIXME("only BSTR index supported, got %d\n", V_VT(index));
745 return E_NOTIMPL;
748 folder = V_BSTR(index);
749 if (!wcsicmp(folder, L"Desktop"))
750 kind = CSIDL_DESKTOP;
751 else if (!wcsicmp(folder, L"AllUsersDesktop"))
752 kind = CSIDL_COMMON_DESKTOPDIRECTORY;
753 else if (!wcsicmp(folder, L"AllUsersPrograms"))
754 kind = CSIDL_COMMON_PROGRAMS;
755 else
757 FIXME("folder kind %s not supported\n", debugstr_w(folder));
758 return E_NOTIMPL;
761 hr = SHGetSpecialFolderLocation(NULL, kind, &pidl);
762 if (hr != S_OK) return hr;
764 if (SHGetPathFromIDListW(pidl, pathW))
766 V_VT(value) = VT_BSTR;
767 V_BSTR(value) = SysAllocString(pathW);
768 hr = V_BSTR(value) ? S_OK : E_OUTOFMEMORY;
770 else
771 hr = E_FAIL;
773 CoTaskMemFree(pidl);
775 return hr;
778 static HRESULT WINAPI WshCollection_Count(IWshCollection *iface, LONG *count)
780 WshCollection *This = impl_from_IWshCollection(iface);
781 FIXME("(%p)->(%p): stub\n", This, count);
782 return E_NOTIMPL;
785 static HRESULT WINAPI WshCollection_get_length(IWshCollection *iface, LONG *count)
787 WshCollection *This = impl_from_IWshCollection(iface);
788 FIXME("(%p)->(%p): stub\n", This, count);
789 return E_NOTIMPL;
792 static HRESULT WINAPI WshCollection__NewEnum(IWshCollection *iface, IUnknown **Enum)
794 WshCollection *This = impl_from_IWshCollection(iface);
795 FIXME("(%p)->(%p): stub\n", This, Enum);
796 return E_NOTIMPL;
799 static const IWshCollectionVtbl WshCollectionVtbl = {
800 WshCollection_QueryInterface,
801 WshCollection_AddRef,
802 WshCollection_Release,
803 WshCollection_GetTypeInfoCount,
804 WshCollection_GetTypeInfo,
805 WshCollection_GetIDsOfNames,
806 WshCollection_Invoke,
807 WshCollection_Item,
808 WshCollection_Count,
809 WshCollection_get_length,
810 WshCollection__NewEnum
813 static HRESULT WshCollection_Create(IWshCollection **collection)
815 WshCollection *object;
817 if (!(object = calloc(1, sizeof(*object))))
818 return E_OUTOFMEMORY;
820 object->IWshCollection_iface.lpVtbl = &WshCollectionVtbl;
821 object->ref = 1;
823 init_classinfo(&IID_IWshCollection, (IUnknown *)&object->IWshCollection_iface, &object->classinfo);
824 *collection = &object->IWshCollection_iface;
826 return S_OK;
829 /* IWshShortcut */
830 static HRESULT WINAPI WshShortcut_QueryInterface(IWshShortcut *iface, REFIID riid, void **ppv)
832 WshShortcut *This = impl_from_IWshShortcut(iface);
834 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
836 if (IsEqualGUID(riid, &IID_IUnknown) ||
837 IsEqualGUID(riid, &IID_IDispatch) ||
838 IsEqualGUID(riid, &IID_IWshShortcut))
840 *ppv = iface;
842 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
844 *ppv = &This->classinfo.IProvideClassInfo_iface;
846 else {
847 FIXME("Unknown iface %s\n", debugstr_guid(riid));
848 *ppv = NULL;
849 return E_NOINTERFACE;
852 IUnknown_AddRef((IUnknown*)*ppv);
853 return S_OK;
856 static ULONG WINAPI WshShortcut_AddRef(IWshShortcut *iface)
858 WshShortcut *This = impl_from_IWshShortcut(iface);
859 LONG ref = InterlockedIncrement(&This->ref);
860 TRACE("%p, refcount %ld.\n", iface, ref);
861 return ref;
864 static ULONG WINAPI WshShortcut_Release(IWshShortcut *iface)
866 WshShortcut *This = impl_from_IWshShortcut(iface);
867 LONG ref = InterlockedDecrement(&This->ref);
868 TRACE("%p, refcount %ld.\n", iface, ref);
870 if (!ref)
872 IShellLinkW_Release(This->link);
873 free(This->path_link);
874 free(This);
877 return ref;
880 static HRESULT WINAPI WshShortcut_GetTypeInfoCount(IWshShortcut *iface, UINT *pctinfo)
882 WshShortcut *This = impl_from_IWshShortcut(iface);
883 TRACE("(%p)->(%p)\n", This, pctinfo);
884 *pctinfo = 1;
885 return S_OK;
888 static HRESULT WINAPI WshShortcut_GetTypeInfo(IWshShortcut *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
890 TRACE("%p, %u, %lx, %p.\n", iface, iTInfo, lcid, ppTInfo);
892 return get_typeinfo(IWshShortcut_tid, ppTInfo);
895 static HRESULT WINAPI WshShortcut_GetIDsOfNames(IWshShortcut *iface, REFIID riid, LPOLESTR *rgszNames,
896 UINT cNames, LCID lcid, DISPID *rgDispId)
898 ITypeInfo *typeinfo;
899 HRESULT hr;
901 TRACE("%p, %s, %p, %u, %lx, %p.\n", iface, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
903 hr = get_typeinfo(IWshShortcut_tid, &typeinfo);
904 if(SUCCEEDED(hr))
906 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
907 ITypeInfo_Release(typeinfo);
910 return hr;
913 static HRESULT WINAPI WshShortcut_Invoke(IWshShortcut *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
914 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
916 ITypeInfo *typeinfo;
917 HRESULT hr;
919 TRACE("%p, %ld, %s, %lx, %d, %p, %p, %p, %p.\n", iface, dispIdMember, debugstr_guid(riid),
920 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
922 hr = get_typeinfo(IWshShortcut_tid, &typeinfo);
923 if(SUCCEEDED(hr))
925 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
926 ITypeInfo_Release(typeinfo);
929 return hr;
932 static HRESULT WINAPI WshShortcut_get_FullName(IWshShortcut *iface, BSTR *name)
934 WshShortcut *This = impl_from_IWshShortcut(iface);
935 FIXME("(%p)->(%p): stub\n", This, name);
936 return E_NOTIMPL;
939 static HRESULT WINAPI WshShortcut_get_Arguments(IWshShortcut *iface, BSTR *Arguments)
941 WshShortcut *This = impl_from_IWshShortcut(iface);
942 WCHAR buffW[INFOTIPSIZE];
943 HRESULT hr;
945 TRACE("(%p)->(%p)\n", This, Arguments);
947 if (!Arguments)
948 return E_POINTER;
950 *Arguments = NULL;
952 hr = IShellLinkW_GetArguments(This->link, buffW, ARRAY_SIZE(buffW));
953 if (FAILED(hr))
954 return hr;
956 *Arguments = SysAllocString(buffW);
957 return *Arguments ? S_OK : E_OUTOFMEMORY;
960 static HRESULT WINAPI WshShortcut_put_Arguments(IWshShortcut *iface, BSTR Arguments)
962 WshShortcut *This = impl_from_IWshShortcut(iface);
964 TRACE("(%p)->(%s)\n", This, debugstr_w(Arguments));
966 return IShellLinkW_SetArguments(This->link, Arguments);
969 static HRESULT WINAPI WshShortcut_get_Description(IWshShortcut *iface, BSTR *Description)
971 WshShortcut *This = impl_from_IWshShortcut(iface);
972 FIXME("(%p)->(%p): stub\n", This, Description);
973 return E_NOTIMPL;
976 static HRESULT WINAPI WshShortcut_put_Description(IWshShortcut *iface, BSTR Description)
978 WshShortcut *This = impl_from_IWshShortcut(iface);
979 TRACE("(%p)->(%s)\n", This, debugstr_w(Description));
980 return IShellLinkW_SetDescription(This->link, Description);
983 static HRESULT WINAPI WshShortcut_get_Hotkey(IWshShortcut *iface, BSTR *Hotkey)
985 WshShortcut *This = impl_from_IWshShortcut(iface);
986 FIXME("(%p)->(%p): stub\n", This, Hotkey);
987 return E_NOTIMPL;
990 static HRESULT WINAPI WshShortcut_put_Hotkey(IWshShortcut *iface, BSTR Hotkey)
992 WshShortcut *This = impl_from_IWshShortcut(iface);
993 FIXME("(%p)->(%s): stub\n", This, debugstr_w(Hotkey));
994 return E_NOTIMPL;
997 static HRESULT WINAPI WshShortcut_get_IconLocation(IWshShortcut *iface, BSTR *IconPath)
999 WshShortcut *This = impl_from_IWshShortcut(iface);
1000 WCHAR buffW[MAX_PATH], pathW[MAX_PATH];
1001 INT icon = 0;
1002 HRESULT hr;
1004 TRACE("(%p)->(%p)\n", This, IconPath);
1006 if (!IconPath)
1007 return E_POINTER;
1009 hr = IShellLinkW_GetIconLocation(This->link, buffW, ARRAY_SIZE(buffW), &icon);
1010 if (FAILED(hr)) return hr;
1012 swprintf(pathW, ARRAY_SIZE(pathW), L"%s, %d", buffW, icon);
1013 *IconPath = SysAllocString(pathW);
1014 if (!*IconPath) return E_OUTOFMEMORY;
1016 return S_OK;
1019 static HRESULT WINAPI WshShortcut_put_IconLocation(IWshShortcut *iface, BSTR IconPath)
1021 WshShortcut *This = impl_from_IWshShortcut(iface);
1022 HRESULT hr;
1023 WCHAR *ptr;
1024 BSTR path;
1025 INT icon;
1027 TRACE("(%p)->(%s)\n", This, debugstr_w(IconPath));
1029 /* scan for icon id */
1030 ptr = wcsrchr(IconPath, ',');
1031 if (!ptr)
1033 WARN("icon index not found\n");
1034 return E_FAIL;
1037 path = SysAllocStringLen(IconPath, ptr-IconPath);
1039 /* skip spaces if any */
1040 while (iswspace(*++ptr))
1043 icon = wcstol(ptr, NULL, 10);
1045 hr = IShellLinkW_SetIconLocation(This->link, path, icon);
1046 SysFreeString(path);
1048 return hr;
1051 static HRESULT WINAPI WshShortcut_put_RelativePath(IWshShortcut *iface, BSTR rhs)
1053 WshShortcut *This = impl_from_IWshShortcut(iface);
1054 FIXME("(%p)->(%s): stub\n", This, debugstr_w(rhs));
1055 return E_NOTIMPL;
1058 static HRESULT WINAPI WshShortcut_get_TargetPath(IWshShortcut *iface, BSTR *Path)
1060 WshShortcut *This = impl_from_IWshShortcut(iface);
1061 FIXME("(%p)->(%p): stub\n", This, Path);
1062 return E_NOTIMPL;
1065 static HRESULT WINAPI WshShortcut_put_TargetPath(IWshShortcut *iface, BSTR Path)
1067 WshShortcut *This = impl_from_IWshShortcut(iface);
1068 TRACE("(%p)->(%s)\n", This, debugstr_w(Path));
1069 return IShellLinkW_SetPath(This->link, Path);
1072 static HRESULT WINAPI WshShortcut_get_WindowStyle(IWshShortcut *iface, int *ShowCmd)
1074 WshShortcut *This = impl_from_IWshShortcut(iface);
1075 TRACE("(%p)->(%p)\n", This, ShowCmd);
1076 return IShellLinkW_GetShowCmd(This->link, ShowCmd);
1079 static HRESULT WINAPI WshShortcut_put_WindowStyle(IWshShortcut *iface, int ShowCmd)
1081 WshShortcut *This = impl_from_IWshShortcut(iface);
1082 TRACE("(%p)->(%d)\n", This, ShowCmd);
1083 return IShellLinkW_SetShowCmd(This->link, ShowCmd);
1086 static HRESULT WINAPI WshShortcut_get_WorkingDirectory(IWshShortcut *iface, BSTR *WorkingDirectory)
1088 WshShortcut *This = impl_from_IWshShortcut(iface);
1089 WCHAR buffW[MAX_PATH];
1090 HRESULT hr;
1092 TRACE("(%p)->(%p)\n", This, WorkingDirectory);
1094 if (!WorkingDirectory)
1095 return E_POINTER;
1097 *WorkingDirectory = NULL;
1098 hr = IShellLinkW_GetWorkingDirectory(This->link, buffW, ARRAY_SIZE(buffW));
1099 if (FAILED(hr)) return hr;
1101 *WorkingDirectory = SysAllocString(buffW);
1102 return *WorkingDirectory ? S_OK : E_OUTOFMEMORY;
1105 static HRESULT WINAPI WshShortcut_put_WorkingDirectory(IWshShortcut *iface, BSTR WorkingDirectory)
1107 WshShortcut *This = impl_from_IWshShortcut(iface);
1108 TRACE("(%p)->(%s)\n", This, debugstr_w(WorkingDirectory));
1109 return IShellLinkW_SetWorkingDirectory(This->link, WorkingDirectory);
1112 static HRESULT WINAPI WshShortcut_Load(IWshShortcut *iface, BSTR PathLink)
1114 WshShortcut *This = impl_from_IWshShortcut(iface);
1115 FIXME("(%p)->(%s): stub\n", This, debugstr_w(PathLink));
1116 return E_NOTIMPL;
1119 static HRESULT WINAPI WshShortcut_Save(IWshShortcut *iface)
1121 WshShortcut *This = impl_from_IWshShortcut(iface);
1122 IPersistFile *file;
1123 HRESULT hr;
1125 TRACE("(%p)\n", This);
1127 IShellLinkW_QueryInterface(This->link, &IID_IPersistFile, (void**)&file);
1128 hr = IPersistFile_Save(file, This->path_link, TRUE);
1129 IPersistFile_Release(file);
1131 return hr;
1134 static const IWshShortcutVtbl WshShortcutVtbl = {
1135 WshShortcut_QueryInterface,
1136 WshShortcut_AddRef,
1137 WshShortcut_Release,
1138 WshShortcut_GetTypeInfoCount,
1139 WshShortcut_GetTypeInfo,
1140 WshShortcut_GetIDsOfNames,
1141 WshShortcut_Invoke,
1142 WshShortcut_get_FullName,
1143 WshShortcut_get_Arguments,
1144 WshShortcut_put_Arguments,
1145 WshShortcut_get_Description,
1146 WshShortcut_put_Description,
1147 WshShortcut_get_Hotkey,
1148 WshShortcut_put_Hotkey,
1149 WshShortcut_get_IconLocation,
1150 WshShortcut_put_IconLocation,
1151 WshShortcut_put_RelativePath,
1152 WshShortcut_get_TargetPath,
1153 WshShortcut_put_TargetPath,
1154 WshShortcut_get_WindowStyle,
1155 WshShortcut_put_WindowStyle,
1156 WshShortcut_get_WorkingDirectory,
1157 WshShortcut_put_WorkingDirectory,
1158 WshShortcut_Load,
1159 WshShortcut_Save
1162 static HRESULT WshShortcut_Create(const WCHAR *path, IDispatch **shortcut)
1164 WshShortcut *object;
1165 HRESULT hr;
1167 *shortcut = NULL;
1169 if (!(object = calloc(1, sizeof(*object))))
1170 return E_OUTOFMEMORY;
1172 object->IWshShortcut_iface.lpVtbl = &WshShortcutVtbl;
1173 object->ref = 1;
1175 hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (void **)&object->link);
1176 if (FAILED(hr))
1178 free(object);
1179 return hr;
1182 object->path_link = wcsdup(path);
1183 if (!object->path_link)
1185 IShellLinkW_Release(object->link);
1186 free(object);
1187 return E_OUTOFMEMORY;
1190 init_classinfo(&IID_IWshShortcut, (IUnknown *)&object->IWshShortcut_iface, &object->classinfo);
1191 *shortcut = (IDispatch *)&object->IWshShortcut_iface;
1193 return S_OK;
1196 static HRESULT WINAPI WshShell3_QueryInterface(IWshShell3 *iface, REFIID riid, void **ppv)
1198 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
1200 *ppv = NULL;
1202 if (IsEqualGUID(riid, &IID_IDispatch) ||
1203 IsEqualGUID(riid, &IID_IWshShell3) ||
1204 IsEqualGUID(riid, &IID_IWshShell2) ||
1205 IsEqualGUID(riid, &IID_IWshShell) ||
1206 IsEqualGUID(riid, &IID_IUnknown))
1208 *ppv = iface;
1210 else if (IsEqualGUID(riid, &IID_IDispatchEx))
1212 return E_NOINTERFACE;
1214 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
1216 *ppv = &WshShell3.classinfo.IProvideClassInfo_iface;
1218 else
1220 WARN("unknown iface %s\n", debugstr_guid(riid));
1221 return E_NOINTERFACE;
1224 IUnknown_AddRef((IUnknown *)*ppv);
1225 return S_OK;
1228 static ULONG WINAPI WshShell3_AddRef(IWshShell3 *iface)
1230 TRACE("()\n");
1231 return 2;
1234 static ULONG WINAPI WshShell3_Release(IWshShell3 *iface)
1236 TRACE("()\n");
1237 return 2;
1240 static HRESULT WINAPI WshShell3_GetTypeInfoCount(IWshShell3 *iface, UINT *pctinfo)
1242 TRACE("(%p)\n", pctinfo);
1243 *pctinfo = 1;
1244 return S_OK;
1247 static HRESULT WINAPI WshShell3_GetTypeInfo(IWshShell3 *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
1249 TRACE("%u, %lx, %p.\n", iTInfo, lcid, ppTInfo);
1251 return get_typeinfo(IWshShell3_tid, ppTInfo);
1254 static HRESULT WINAPI WshShell3_GetIDsOfNames(IWshShell3 *iface, REFIID riid, LPOLESTR *rgszNames,
1255 UINT cNames, LCID lcid, DISPID *rgDispId)
1257 ITypeInfo *typeinfo;
1258 HRESULT hr;
1260 TRACE("%s, %p, %u, %lx, %p.\n", debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1262 hr = get_typeinfo(IWshShell3_tid, &typeinfo);
1263 if(SUCCEEDED(hr))
1265 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1266 ITypeInfo_Release(typeinfo);
1269 return hr;
1272 static HRESULT WINAPI WshShell3_Invoke(IWshShell3 *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
1273 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
1275 ITypeInfo *typeinfo;
1276 HRESULT hr;
1278 TRACE("%ld, %s, %lx, %d, %p, %p, %p, %p.\n", dispIdMember, debugstr_guid(riid),
1279 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1281 hr = get_typeinfo(IWshShell3_tid, &typeinfo);
1282 if(SUCCEEDED(hr))
1284 hr = ITypeInfo_Invoke(typeinfo, &WshShell3.IWshShell3_iface, dispIdMember, wFlags,
1285 pDispParams, pVarResult, pExcepInfo, puArgErr);
1286 ITypeInfo_Release(typeinfo);
1289 return hr;
1292 static HRESULT WINAPI WshShell3_get_SpecialFolders(IWshShell3 *iface, IWshCollection **folders)
1294 TRACE("(%p)\n", folders);
1295 return WshCollection_Create(folders);
1298 static HRESULT WINAPI WshShell3_get_Environment(IWshShell3 *iface, VARIANT *type, IWshEnvironment **env)
1300 FIXME("(%s %p): semi-stub\n", debugstr_variant(type), env);
1301 return WshEnvironment_Create(env);
1304 static inline BOOL is_optional_argument(const VARIANT *arg)
1306 return V_VT(arg) == VT_ERROR && V_ERROR(arg) == DISP_E_PARAMNOTFOUND;
1309 static WCHAR *split_command( BSTR cmd, WCHAR **params )
1311 WCHAR *ret, *ptr;
1312 BOOL in_quotes = FALSE;
1314 if (!(ret = malloc((lstrlenW(cmd) + 1) * sizeof(WCHAR)))) return NULL;
1315 lstrcpyW( ret, cmd );
1317 *params = NULL;
1318 for (ptr = ret; *ptr; ptr++)
1320 if (*ptr == '"') in_quotes = !in_quotes;
1321 else if (*ptr == ' ' && !in_quotes)
1323 *ptr = 0;
1324 *params = ptr + 1;
1325 break;
1329 return ret;
1332 static HRESULT WINAPI WshShell3_Run(IWshShell3 *iface, BSTR cmd, VARIANT *style, VARIANT *wait, DWORD *exit_code)
1334 SHELLEXECUTEINFOW info;
1335 int waitforprocess;
1336 WCHAR *file, *params;
1337 VARIANT s;
1338 HRESULT hr;
1339 BOOL ret;
1341 TRACE("(%s %s %s %p)\n", debugstr_w(cmd), debugstr_variant(style), debugstr_variant(wait), exit_code);
1343 if (!style || !wait || !exit_code)
1344 return E_POINTER;
1346 VariantInit(&s);
1347 hr = VariantChangeType(&s, style, 0, VT_I4);
1348 if (FAILED(hr))
1350 ERR("failed to convert style argument, %#lx\n", hr);
1351 return hr;
1354 if (is_optional_argument(wait))
1355 waitforprocess = 0;
1356 else {
1357 VARIANT w;
1359 VariantInit(&w);
1360 hr = VariantChangeType(&w, wait, 0, VT_I4);
1361 if (FAILED(hr))
1362 return hr;
1364 waitforprocess = V_I4(&w);
1367 if (!(file = split_command(cmd, &params))) return E_OUTOFMEMORY;
1369 memset(&info, 0, sizeof(info));
1370 info.cbSize = sizeof(info);
1371 info.fMask = waitforprocess ? SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS : SEE_MASK_DEFAULT;
1372 info.lpFile = file;
1373 info.lpParameters = params;
1374 info.nShow = V_I4(&s);
1376 ret = ShellExecuteExW(&info);
1377 free(file);
1378 if (!ret)
1380 TRACE("ShellExecute failed, %ld\n", GetLastError());
1381 return HRESULT_FROM_WIN32(GetLastError());
1383 else
1385 if (waitforprocess)
1387 WaitForSingleObject(info.hProcess, INFINITE);
1388 GetExitCodeProcess(info.hProcess, exit_code);
1389 CloseHandle(info.hProcess);
1391 else
1392 *exit_code = 0;
1394 return S_OK;
1398 struct popup_thread_param
1400 WCHAR *text;
1401 VARIANT title;
1402 VARIANT type;
1403 INT button;
1406 static DWORD WINAPI popup_thread_proc(void *arg)
1408 struct popup_thread_param *param = (struct popup_thread_param *)arg;
1410 param->button = MessageBoxW(NULL, param->text, is_optional_argument(&param->title) ?
1411 L"Windows Script Host" : V_BSTR(&param->title), V_I4(&param->type));
1412 return 0;
1415 static HRESULT WINAPI WshShell3_Popup(IWshShell3 *iface, BSTR text, VARIANT *seconds_to_wait, VARIANT *title,
1416 VARIANT *type, int *button)
1418 struct popup_thread_param param;
1419 DWORD tid, status;
1420 VARIANT timeout;
1421 HANDLE hthread;
1422 HRESULT hr;
1424 TRACE("(%s %s %s %s %p)\n", debugstr_w(text), debugstr_variant(seconds_to_wait), debugstr_variant(title),
1425 debugstr_variant(type), button);
1427 if (!seconds_to_wait || !title || !type || !button)
1428 return E_POINTER;
1430 VariantInit(&timeout);
1431 if (!is_optional_argument(seconds_to_wait))
1433 hr = VariantChangeType(&timeout, seconds_to_wait, 0, VT_I4);
1434 if (FAILED(hr))
1435 return hr;
1438 VariantInit(&param.type);
1439 if (!is_optional_argument(type))
1441 hr = VariantChangeType(&param.type, type, 0, VT_I4);
1442 if (FAILED(hr))
1443 return hr;
1446 if (is_optional_argument(title))
1447 param.title = *title;
1448 else
1450 VariantInit(&param.title);
1451 hr = VariantChangeType(&param.title, title, 0, VT_BSTR);
1452 if (FAILED(hr))
1453 return hr;
1456 param.text = text;
1457 param.button = -1;
1458 hthread = CreateThread(NULL, 0, popup_thread_proc, &param, 0, &tid);
1459 status = MsgWaitForMultipleObjects(1, &hthread, FALSE, V_I4(&timeout) ? V_I4(&timeout) * 1000: INFINITE, 0);
1460 if (status == WAIT_TIMEOUT)
1462 PostThreadMessageW(tid, WM_QUIT, 0, 0);
1463 MsgWaitForMultipleObjects(1, &hthread, FALSE, INFINITE, 0);
1464 param.button = -1;
1466 *button = param.button;
1468 VariantClear(&param.title);
1469 CloseHandle(hthread);
1471 return S_OK;
1474 static HRESULT WINAPI WshShell3_CreateShortcut(IWshShell3 *iface, BSTR PathLink, IDispatch** Shortcut)
1476 TRACE("(%s %p)\n", debugstr_w(PathLink), Shortcut);
1477 return WshShortcut_Create(PathLink, Shortcut);
1480 static HRESULT WINAPI WshShell3_ExpandEnvironmentStrings(IWshShell3 *iface, BSTR Src, BSTR* Dst)
1482 DWORD ret;
1484 TRACE("(%s %p)\n", debugstr_w(Src), Dst);
1486 if (!Src || !Dst) return E_POINTER;
1488 ret = ExpandEnvironmentStringsW(Src, NULL, 0);
1489 *Dst = SysAllocStringLen(NULL, ret);
1490 if (!*Dst) return E_OUTOFMEMORY;
1492 if (ExpandEnvironmentStringsW(Src, *Dst, ret))
1493 return S_OK;
1494 else
1496 SysFreeString(*Dst);
1497 *Dst = NULL;
1498 return HRESULT_FROM_WIN32(GetLastError());
1502 static HKEY get_root_key(const WCHAR *path)
1504 static const struct {
1505 const WCHAR full[20];
1506 const WCHAR abbrev[5];
1507 HKEY hkey;
1508 } rootkeys[] = {
1509 { L"HKEY_CURRENT_USER", L"HKCU", HKEY_CURRENT_USER },
1510 { L"HKEY_LOCAL_MACHINE", L"HKLM", HKEY_LOCAL_MACHINE },
1511 { L"HKEY_CLASSES_ROOT", L"HKCR", HKEY_CLASSES_ROOT },
1512 { L"HKEY_USERS", {0}, HKEY_USERS },
1513 { L"HKEY_CURRENT_CONFIG", {0}, HKEY_CURRENT_CONFIG }
1515 int i;
1517 for (i = 0; i < ARRAY_SIZE(rootkeys); i++) {
1518 if (!wcsncmp(path, rootkeys[i].full, lstrlenW(rootkeys[i].full)))
1519 return rootkeys[i].hkey;
1520 if (rootkeys[i].abbrev[0] && !wcsncmp(path, rootkeys[i].abbrev, lstrlenW(rootkeys[i].abbrev)))
1521 return rootkeys[i].hkey;
1524 return NULL;
1527 /* Caller is responsible to free 'subkey' if 'value' is not NULL */
1528 static HRESULT split_reg_path(const WCHAR *path, WCHAR **subkey, WCHAR **value)
1530 *value = NULL;
1532 /* at least one separator should be present */
1533 *subkey = wcschr(path, '\\');
1534 if (!*subkey)
1535 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1537 /* default value or not */
1538 if ((*subkey)[lstrlenW(*subkey)-1] == '\\') {
1539 (*subkey)++;
1540 *value = NULL;
1542 else {
1543 *value = wcsrchr(*subkey, '\\');
1544 if (*value - *subkey > 1) {
1545 unsigned int len = *value - *subkey - 1;
1546 WCHAR *ret;
1548 ret = malloc((len + 1)*sizeof(WCHAR));
1549 if (!ret)
1550 return E_OUTOFMEMORY;
1552 memcpy(ret, *subkey + 1, len*sizeof(WCHAR));
1553 ret[len] = 0;
1554 *subkey = ret;
1556 (*value)++;
1559 return S_OK;
1562 static HRESULT WINAPI WshShell3_RegRead(IWshShell3 *iface, BSTR name, VARIANT *value)
1564 DWORD type, datalen, ret;
1565 WCHAR *subkey, *val;
1566 HRESULT hr;
1567 HKEY root;
1569 TRACE("(%s %p)\n", debugstr_w(name), value);
1571 if (!name || !value)
1572 return E_POINTER;
1574 root = get_root_key(name);
1575 if (!root)
1576 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1578 hr = split_reg_path(name, &subkey, &val);
1579 if (FAILED(hr))
1580 return hr;
1582 type = REG_NONE;
1583 datalen = 0;
1584 ret = RegGetValueW(root, subkey, val, RRF_RT_ANY, &type, NULL, &datalen);
1585 if (ret == ERROR_SUCCESS) {
1586 void *data;
1588 data = malloc(datalen);
1589 if (!data) {
1590 hr = E_OUTOFMEMORY;
1591 goto fail;
1594 ret = RegGetValueW(root, subkey, val, RRF_RT_ANY, &type, data, &datalen);
1595 if (ret) {
1596 free(data);
1597 hr = HRESULT_FROM_WIN32(ret);
1598 goto fail;
1601 switch (type) {
1602 case REG_SZ:
1603 case REG_EXPAND_SZ:
1604 V_VT(value) = VT_BSTR;
1605 V_BSTR(value) = SysAllocString((WCHAR*)data);
1606 if (!V_BSTR(value))
1607 hr = E_OUTOFMEMORY;
1608 break;
1609 case REG_DWORD:
1610 V_VT(value) = VT_I4;
1611 V_I4(value) = *(DWORD*)data;
1612 break;
1613 case REG_BINARY:
1615 BYTE *ptr = (BYTE*)data;
1616 SAFEARRAYBOUND bound;
1617 unsigned int i;
1618 SAFEARRAY *sa;
1619 VARIANT *v;
1621 bound.lLbound = 0;
1622 bound.cElements = datalen;
1623 sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
1624 if (!sa)
1625 break;
1627 hr = SafeArrayAccessData(sa, (void**)&v);
1628 if (FAILED(hr)) {
1629 SafeArrayDestroy(sa);
1630 break;
1633 for (i = 0; i < datalen; i++) {
1634 V_VT(&v[i]) = VT_UI1;
1635 V_UI1(&v[i]) = ptr[i];
1637 SafeArrayUnaccessData(sa);
1639 V_VT(value) = VT_ARRAY|VT_VARIANT;
1640 V_ARRAY(value) = sa;
1641 break;
1643 case REG_MULTI_SZ:
1645 WCHAR *ptr = (WCHAR*)data;
1646 SAFEARRAYBOUND bound;
1647 SAFEARRAY *sa;
1648 VARIANT *v;
1650 /* get element count first */
1651 bound.lLbound = 0;
1652 bound.cElements = 0;
1653 while (*ptr) {
1654 bound.cElements++;
1655 ptr += lstrlenW(ptr)+1;
1658 sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
1659 if (!sa)
1660 break;
1662 hr = SafeArrayAccessData(sa, (void**)&v);
1663 if (FAILED(hr)) {
1664 SafeArrayDestroy(sa);
1665 break;
1668 ptr = (WCHAR*)data;
1669 while (*ptr) {
1670 V_VT(v) = VT_BSTR;
1671 V_BSTR(v) = SysAllocString(ptr);
1672 ptr += lstrlenW(ptr)+1;
1673 v++;
1676 SafeArrayUnaccessData(sa);
1677 V_VT(value) = VT_ARRAY|VT_VARIANT;
1678 V_ARRAY(value) = sa;
1679 break;
1681 default:
1682 FIXME("value type %ld not supported\n", type);
1683 hr = E_FAIL;
1686 free(data);
1687 if (FAILED(hr))
1688 VariantInit(value);
1690 else
1691 hr = HRESULT_FROM_WIN32(ret);
1693 fail:
1694 if (val)
1695 free(subkey);
1696 return hr;
1699 static HRESULT WINAPI WshShell3_RegWrite(IWshShell3 *iface, BSTR name, VARIANT *value, VARIANT *type)
1701 DWORD regtype, data_len;
1702 WCHAR *subkey, *val;
1703 const BYTE *data;
1704 HRESULT hr;
1705 HKEY root;
1706 VARIANT v;
1707 LONG ret;
1709 TRACE("(%s %s %s)\n", debugstr_w(name), debugstr_variant(value), debugstr_variant(type));
1711 if (!name || !value || !type)
1712 return E_POINTER;
1714 root = get_root_key(name);
1715 if (!root)
1716 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1718 /* value type */
1719 if (is_optional_argument(type))
1720 regtype = REG_SZ;
1721 else {
1722 if (V_VT(type) != VT_BSTR)
1723 return E_INVALIDARG;
1725 if (!wcscmp(V_BSTR(type), L"REG_SZ"))
1726 regtype = REG_SZ;
1727 else if (!wcscmp(V_BSTR(type), L"REG_DWORD"))
1728 regtype = REG_DWORD;
1729 else if (!wcscmp(V_BSTR(type), L"REG_EXPAND_SZ"))
1730 regtype = REG_EXPAND_SZ;
1731 else if (!wcscmp(V_BSTR(type), L"REG_BINARY"))
1732 regtype = REG_BINARY;
1733 else {
1734 FIXME("unrecognized value type %s\n", debugstr_w(V_BSTR(type)));
1735 return E_FAIL;
1739 /* it's always a string or a DWORD */
1740 VariantInit(&v);
1741 switch (regtype)
1743 case REG_SZ:
1744 case REG_EXPAND_SZ:
1745 hr = VariantChangeType(&v, value, 0, VT_BSTR);
1746 if (hr == S_OK) {
1747 data = (BYTE*)V_BSTR(&v);
1748 data_len = SysStringByteLen(V_BSTR(&v)) + sizeof(WCHAR);
1750 break;
1751 case REG_DWORD:
1752 case REG_BINARY:
1753 hr = VariantChangeType(&v, value, 0, VT_I4);
1754 data = (BYTE*)&V_I4(&v);
1755 data_len = sizeof(DWORD);
1756 break;
1757 default:
1758 FIXME("unexpected regtype %ld\n", regtype);
1759 return E_FAIL;
1762 if (FAILED(hr)) {
1763 FIXME("failed to convert value, regtype %ld, %#lx.\n", regtype, hr);
1764 return hr;
1767 hr = split_reg_path(name, &subkey, &val);
1768 if (FAILED(hr))
1769 goto fail;
1771 ret = RegSetKeyValueW(root, subkey, val, regtype, data, data_len);
1772 if (ret)
1773 hr = HRESULT_FROM_WIN32(ret);
1775 fail:
1776 VariantClear(&v);
1777 if (val)
1778 free(subkey);
1779 return hr;
1782 static HRESULT WINAPI WshShell3_RegDelete(IWshShell3 *iface, BSTR Name)
1784 FIXME("(%s): stub\n", debugstr_w(Name));
1785 return E_NOTIMPL;
1788 static HRESULT WINAPI WshShell3_LogEvent(IWshShell3 *iface, VARIANT *Type, BSTR Message, BSTR Target, VARIANT_BOOL *out_Success)
1790 FIXME("(%s %s %s %p): stub\n", debugstr_variant(Type), debugstr_w(Message), debugstr_w(Target), out_Success);
1791 return E_NOTIMPL;
1794 static HRESULT WINAPI WshShell3_AppActivate(IWshShell3 *iface, VARIANT *App, VARIANT *Wait, VARIANT_BOOL *out_Success)
1796 FIXME("(%s %s %p): stub\n", debugstr_variant(App), debugstr_variant(Wait), out_Success);
1797 return E_NOTIMPL;
1800 static HRESULT WINAPI WshShell3_SendKeys(IWshShell3 *iface, BSTR Keys, VARIANT *Wait)
1802 FIXME("(%s %p): stub\n", debugstr_w(Keys), Wait);
1803 return E_NOTIMPL;
1806 static HRESULT WINAPI WshShell3_Exec(IWshShell3 *iface, BSTR command, IWshExec **ret)
1808 BSTR expandedcmd;
1809 HRESULT hr;
1811 TRACE("(%s %p)\n", debugstr_w(command), ret);
1813 if (!ret)
1814 return E_POINTER;
1816 if (!command)
1817 return DISP_E_EXCEPTION;
1819 hr = WshShell3_ExpandEnvironmentStrings(iface, command, &expandedcmd);
1820 if (FAILED(hr))
1821 return hr;
1823 hr = WshExec_create(expandedcmd, ret);
1824 SysFreeString(expandedcmd);
1825 return hr;
1828 static HRESULT WINAPI WshShell3_get_CurrentDirectory(IWshShell3 *iface, BSTR *dir)
1830 DWORD ret;
1832 TRACE("(%p)\n", dir);
1834 ret = GetCurrentDirectoryW(0, NULL);
1835 if (!ret)
1836 return HRESULT_FROM_WIN32(GetLastError());
1838 *dir = SysAllocStringLen(NULL, ret-1);
1839 if (!*dir)
1840 return E_OUTOFMEMORY;
1842 ret = GetCurrentDirectoryW(ret, *dir);
1843 if (!ret) {
1844 SysFreeString(*dir);
1845 *dir = NULL;
1846 return HRESULT_FROM_WIN32(GetLastError());
1849 return S_OK;
1852 static HRESULT WINAPI WshShell3_put_CurrentDirectory(IWshShell3 *iface, BSTR dir)
1854 TRACE("(%s)\n", debugstr_w(dir));
1856 if (!dir)
1857 return E_INVALIDARG;
1859 if (!SetCurrentDirectoryW(dir))
1860 return HRESULT_FROM_WIN32(GetLastError());
1862 return S_OK;
1865 static const IWshShell3Vtbl WshShell3Vtbl = {
1866 WshShell3_QueryInterface,
1867 WshShell3_AddRef,
1868 WshShell3_Release,
1869 WshShell3_GetTypeInfoCount,
1870 WshShell3_GetTypeInfo,
1871 WshShell3_GetIDsOfNames,
1872 WshShell3_Invoke,
1873 WshShell3_get_SpecialFolders,
1874 WshShell3_get_Environment,
1875 WshShell3_Run,
1876 WshShell3_Popup,
1877 WshShell3_CreateShortcut,
1878 WshShell3_ExpandEnvironmentStrings,
1879 WshShell3_RegRead,
1880 WshShell3_RegWrite,
1881 WshShell3_RegDelete,
1882 WshShell3_LogEvent,
1883 WshShell3_AppActivate,
1884 WshShell3_SendKeys,
1885 WshShell3_Exec,
1886 WshShell3_get_CurrentDirectory,
1887 WshShell3_put_CurrentDirectory
1890 HRESULT WINAPI WshShellFactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
1892 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
1894 WshShell3.IWshShell3_iface.lpVtbl = &WshShell3Vtbl;
1895 init_classinfo(&IID_IWshShell3, (IUnknown *)&WshShell3.IWshShell3_iface, &WshShell3.classinfo);
1896 return IWshShell3_QueryInterface(&WshShell3.IWshShell3_iface, riid, ppv);