vkd3d: Import upstream release 1.9.
[wine.git] / dlls / wshom.ocx / shell.c
blob69db995cd0d192829862ff5d93fdf489980a939a
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 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 = wcsdup(cmd))) return NULL;
1316 *params = NULL;
1317 for (ptr = ret; *ptr; ptr++)
1319 if (*ptr == '"') in_quotes = !in_quotes;
1320 else if (*ptr == ' ' && !in_quotes)
1322 *ptr = 0;
1323 *params = ptr + 1;
1324 break;
1328 return ret;
1331 static HRESULT WINAPI WshShell3_Run(IWshShell3 *iface, BSTR cmd, VARIANT *style, VARIANT *wait, int *exit_code)
1333 SHELLEXECUTEINFOW info;
1334 int waitforprocess, show;
1335 WCHAR *file, *params;
1336 VARIANT v;
1337 HRESULT hr;
1338 BOOL ret;
1340 TRACE("(%s %s %s %p)\n", debugstr_w(cmd), debugstr_variant(style), debugstr_variant(wait), exit_code);
1342 if (!style || !wait || !exit_code)
1343 return E_POINTER;
1345 if (is_optional_argument(style))
1346 show = SW_SHOWNORMAL;
1347 else {
1348 VariantInit(&v);
1349 hr = VariantChangeType(&v, style, 0, VT_I4);
1350 if (FAILED(hr))
1351 return hr;
1353 show = V_I4(&v);
1356 if (is_optional_argument(wait))
1357 waitforprocess = 0;
1358 else {
1359 VariantInit(&v);
1360 hr = VariantChangeType(&v, wait, 0, VT_I4);
1361 if (FAILED(hr))
1362 return hr;
1364 waitforprocess = V_I4(&v);
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 = show;
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 DWORD code;
1388 WaitForSingleObject(info.hProcess, INFINITE);
1389 GetExitCodeProcess(info.hProcess, &code);
1390 CloseHandle(info.hProcess);
1391 *exit_code = code;
1393 else
1394 *exit_code = 0;
1396 return S_OK;
1400 struct popup_thread_param
1402 WCHAR *text;
1403 VARIANT title;
1404 VARIANT type;
1405 INT button;
1408 static DWORD WINAPI popup_thread_proc(void *arg)
1410 struct popup_thread_param *param = (struct popup_thread_param *)arg;
1412 param->button = MessageBoxW(NULL, param->text, is_optional_argument(&param->title) ?
1413 L"Windows Script Host" : V_BSTR(&param->title), V_I4(&param->type));
1414 return 0;
1417 static HRESULT WINAPI WshShell3_Popup(IWshShell3 *iface, BSTR text, VARIANT *seconds_to_wait, VARIANT *title,
1418 VARIANT *type, int *button)
1420 struct popup_thread_param param;
1421 DWORD tid, status;
1422 VARIANT timeout;
1423 HANDLE hthread;
1424 HRESULT hr;
1426 TRACE("(%s %s %s %s %p)\n", debugstr_w(text), debugstr_variant(seconds_to_wait), debugstr_variant(title),
1427 debugstr_variant(type), button);
1429 if (!seconds_to_wait || !title || !type || !button)
1430 return E_POINTER;
1432 VariantInit(&timeout);
1433 if (!is_optional_argument(seconds_to_wait))
1435 hr = VariantChangeType(&timeout, seconds_to_wait, 0, VT_I4);
1436 if (FAILED(hr))
1437 return hr;
1440 VariantInit(&param.type);
1441 if (!is_optional_argument(type))
1443 hr = VariantChangeType(&param.type, type, 0, VT_I4);
1444 if (FAILED(hr))
1445 return hr;
1448 if (is_optional_argument(title))
1449 param.title = *title;
1450 else
1452 VariantInit(&param.title);
1453 hr = VariantChangeType(&param.title, title, 0, VT_BSTR);
1454 if (FAILED(hr))
1455 return hr;
1458 param.text = text;
1459 param.button = -1;
1460 hthread = CreateThread(NULL, 0, popup_thread_proc, &param, 0, &tid);
1461 status = MsgWaitForMultipleObjects(1, &hthread, FALSE, V_I4(&timeout) ? V_I4(&timeout) * 1000: INFINITE, 0);
1462 if (status == WAIT_TIMEOUT)
1464 PostThreadMessageW(tid, WM_QUIT, 0, 0);
1465 MsgWaitForMultipleObjects(1, &hthread, FALSE, INFINITE, 0);
1466 param.button = -1;
1468 *button = param.button;
1470 VariantClear(&param.title);
1471 CloseHandle(hthread);
1473 return S_OK;
1476 static HRESULT WINAPI WshShell3_CreateShortcut(IWshShell3 *iface, BSTR PathLink, IDispatch** Shortcut)
1478 TRACE("(%s %p)\n", debugstr_w(PathLink), Shortcut);
1479 return WshShortcut_Create(PathLink, Shortcut);
1482 static HRESULT WINAPI WshShell3_ExpandEnvironmentStrings(IWshShell3 *iface, BSTR Src, BSTR* Dst)
1484 DWORD ret;
1486 TRACE("(%s %p)\n", debugstr_w(Src), Dst);
1488 if (!Src || !Dst) return E_POINTER;
1490 ret = ExpandEnvironmentStringsW(Src, NULL, 0);
1491 *Dst = SysAllocStringLen(NULL, ret);
1492 if (!*Dst) return E_OUTOFMEMORY;
1494 if (ExpandEnvironmentStringsW(Src, *Dst, ret))
1495 return S_OK;
1496 else
1498 SysFreeString(*Dst);
1499 *Dst = NULL;
1500 return HRESULT_FROM_WIN32(GetLastError());
1504 static HKEY get_root_key(const WCHAR *path)
1506 static const struct {
1507 const WCHAR full[20];
1508 const WCHAR abbrev[5];
1509 HKEY hkey;
1510 } rootkeys[] = {
1511 { L"HKEY_CURRENT_USER", L"HKCU", HKEY_CURRENT_USER },
1512 { L"HKEY_LOCAL_MACHINE", L"HKLM", HKEY_LOCAL_MACHINE },
1513 { L"HKEY_CLASSES_ROOT", L"HKCR", HKEY_CLASSES_ROOT },
1514 { L"HKEY_USERS", {0}, HKEY_USERS },
1515 { L"HKEY_CURRENT_CONFIG", {0}, HKEY_CURRENT_CONFIG }
1517 int i;
1519 for (i = 0; i < ARRAY_SIZE(rootkeys); i++) {
1520 if (!wcsncmp(path, rootkeys[i].full, lstrlenW(rootkeys[i].full)))
1521 return rootkeys[i].hkey;
1522 if (rootkeys[i].abbrev[0] && !wcsncmp(path, rootkeys[i].abbrev, lstrlenW(rootkeys[i].abbrev)))
1523 return rootkeys[i].hkey;
1526 return NULL;
1529 /* Caller is responsible to free 'subkey' if 'value' is not NULL */
1530 static HRESULT split_reg_path(const WCHAR *path, WCHAR **subkey, WCHAR **value)
1532 *value = NULL;
1534 /* at least one separator should be present */
1535 *subkey = wcschr(path, '\\');
1536 if (!*subkey)
1537 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1539 /* default value or not */
1540 if ((*subkey)[lstrlenW(*subkey)-1] == '\\') {
1541 (*subkey)++;
1542 *value = NULL;
1544 else {
1545 *value = wcsrchr(*subkey, '\\');
1546 if (*value - *subkey > 1) {
1547 unsigned int len = *value - *subkey - 1;
1548 WCHAR *ret;
1550 ret = malloc((len + 1)*sizeof(WCHAR));
1551 if (!ret)
1552 return E_OUTOFMEMORY;
1554 memcpy(ret, *subkey + 1, len*sizeof(WCHAR));
1555 ret[len] = 0;
1556 *subkey = ret;
1558 (*value)++;
1561 return S_OK;
1564 static HRESULT WINAPI WshShell3_RegRead(IWshShell3 *iface, BSTR name, VARIANT *value)
1566 DWORD type, datalen, ret;
1567 WCHAR *subkey, *val;
1568 HRESULT hr;
1569 HKEY root;
1571 TRACE("(%s %p)\n", debugstr_w(name), value);
1573 if (!name || !value)
1574 return E_POINTER;
1576 root = get_root_key(name);
1577 if (!root)
1578 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1580 hr = split_reg_path(name, &subkey, &val);
1581 if (FAILED(hr))
1582 return hr;
1584 type = REG_NONE;
1585 datalen = 0;
1586 ret = RegGetValueW(root, subkey, val, RRF_RT_ANY, &type, NULL, &datalen);
1587 if (ret == ERROR_SUCCESS) {
1588 void *data;
1590 data = malloc(datalen);
1591 if (!data) {
1592 hr = E_OUTOFMEMORY;
1593 goto fail;
1596 ret = RegGetValueW(root, subkey, val, RRF_RT_ANY, &type, data, &datalen);
1597 if (ret) {
1598 free(data);
1599 hr = HRESULT_FROM_WIN32(ret);
1600 goto fail;
1603 switch (type) {
1604 case REG_SZ:
1605 case REG_EXPAND_SZ:
1606 V_VT(value) = VT_BSTR;
1607 V_BSTR(value) = SysAllocString((WCHAR*)data);
1608 if (!V_BSTR(value))
1609 hr = E_OUTOFMEMORY;
1610 break;
1611 case REG_DWORD:
1612 V_VT(value) = VT_I4;
1613 V_I4(value) = *(DWORD*)data;
1614 break;
1615 case REG_BINARY:
1617 BYTE *ptr = (BYTE*)data;
1618 SAFEARRAYBOUND bound;
1619 unsigned int i;
1620 SAFEARRAY *sa;
1621 VARIANT *v;
1623 bound.lLbound = 0;
1624 bound.cElements = datalen;
1625 sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
1626 if (!sa)
1627 break;
1629 hr = SafeArrayAccessData(sa, (void**)&v);
1630 if (FAILED(hr)) {
1631 SafeArrayDestroy(sa);
1632 break;
1635 for (i = 0; i < datalen; i++) {
1636 V_VT(&v[i]) = VT_UI1;
1637 V_UI1(&v[i]) = ptr[i];
1639 SafeArrayUnaccessData(sa);
1641 V_VT(value) = VT_ARRAY|VT_VARIANT;
1642 V_ARRAY(value) = sa;
1643 break;
1645 case REG_MULTI_SZ:
1647 WCHAR *ptr = (WCHAR*)data;
1648 SAFEARRAYBOUND bound;
1649 SAFEARRAY *sa;
1650 VARIANT *v;
1652 /* get element count first */
1653 bound.lLbound = 0;
1654 bound.cElements = 0;
1655 while (*ptr) {
1656 bound.cElements++;
1657 ptr += lstrlenW(ptr)+1;
1660 sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
1661 if (!sa)
1662 break;
1664 hr = SafeArrayAccessData(sa, (void**)&v);
1665 if (FAILED(hr)) {
1666 SafeArrayDestroy(sa);
1667 break;
1670 ptr = (WCHAR*)data;
1671 while (*ptr) {
1672 V_VT(v) = VT_BSTR;
1673 V_BSTR(v) = SysAllocString(ptr);
1674 ptr += lstrlenW(ptr)+1;
1675 v++;
1678 SafeArrayUnaccessData(sa);
1679 V_VT(value) = VT_ARRAY|VT_VARIANT;
1680 V_ARRAY(value) = sa;
1681 break;
1683 default:
1684 FIXME("value type %ld not supported\n", type);
1685 hr = E_FAIL;
1688 free(data);
1689 if (FAILED(hr))
1690 VariantInit(value);
1692 else
1693 hr = HRESULT_FROM_WIN32(ret);
1695 fail:
1696 if (val)
1697 free(subkey);
1698 return hr;
1701 static HRESULT WINAPI WshShell3_RegWrite(IWshShell3 *iface, BSTR name, VARIANT *value, VARIANT *type)
1703 DWORD regtype, data_len;
1704 WCHAR *subkey, *val;
1705 const BYTE *data;
1706 HRESULT hr;
1707 HKEY root;
1708 VARIANT v;
1709 LONG ret;
1711 TRACE("(%s %s %s)\n", debugstr_w(name), debugstr_variant(value), debugstr_variant(type));
1713 if (!name || !value || !type)
1714 return E_POINTER;
1716 root = get_root_key(name);
1717 if (!root)
1718 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1720 /* value type */
1721 if (is_optional_argument(type))
1722 regtype = REG_SZ;
1723 else {
1724 if (V_VT(type) != VT_BSTR)
1725 return E_INVALIDARG;
1727 if (!wcscmp(V_BSTR(type), L"REG_SZ"))
1728 regtype = REG_SZ;
1729 else if (!wcscmp(V_BSTR(type), L"REG_DWORD"))
1730 regtype = REG_DWORD;
1731 else if (!wcscmp(V_BSTR(type), L"REG_EXPAND_SZ"))
1732 regtype = REG_EXPAND_SZ;
1733 else if (!wcscmp(V_BSTR(type), L"REG_BINARY"))
1734 regtype = REG_BINARY;
1735 else {
1736 FIXME("unrecognized value type %s\n", debugstr_w(V_BSTR(type)));
1737 return E_FAIL;
1741 /* it's always a string or a DWORD */
1742 VariantInit(&v);
1743 switch (regtype)
1745 case REG_SZ:
1746 case REG_EXPAND_SZ:
1747 hr = VariantChangeType(&v, value, 0, VT_BSTR);
1748 if (hr == S_OK) {
1749 data = (BYTE*)V_BSTR(&v);
1750 data_len = SysStringByteLen(V_BSTR(&v)) + sizeof(WCHAR);
1752 break;
1753 case REG_DWORD:
1754 case REG_BINARY:
1755 hr = VariantChangeType(&v, value, 0, VT_I4);
1756 data = (BYTE*)&V_I4(&v);
1757 data_len = sizeof(DWORD);
1758 break;
1759 default:
1760 FIXME("unexpected regtype %ld\n", regtype);
1761 return E_FAIL;
1764 if (FAILED(hr)) {
1765 FIXME("failed to convert value, regtype %ld, %#lx.\n", regtype, hr);
1766 return hr;
1769 hr = split_reg_path(name, &subkey, &val);
1770 if (FAILED(hr))
1771 goto fail;
1773 ret = RegSetKeyValueW(root, subkey, val, regtype, data, data_len);
1774 if (ret)
1775 hr = HRESULT_FROM_WIN32(ret);
1777 fail:
1778 VariantClear(&v);
1779 if (val)
1780 free(subkey);
1781 return hr;
1784 static HRESULT WINAPI WshShell3_RegDelete(IWshShell3 *iface, BSTR Name)
1786 FIXME("(%s): stub\n", debugstr_w(Name));
1787 return E_NOTIMPL;
1790 static HRESULT WINAPI WshShell3_LogEvent(IWshShell3 *iface, VARIANT *Type, BSTR Message, BSTR Target, VARIANT_BOOL *out_Success)
1792 FIXME("(%s %s %s %p): stub\n", debugstr_variant(Type), debugstr_w(Message), debugstr_w(Target), out_Success);
1793 return E_NOTIMPL;
1796 static HRESULT WINAPI WshShell3_AppActivate(IWshShell3 *iface, VARIANT *App, VARIANT *Wait, VARIANT_BOOL *out_Success)
1798 FIXME("(%s %s %p): stub\n", debugstr_variant(App), debugstr_variant(Wait), out_Success);
1799 return E_NOTIMPL;
1802 static HRESULT WINAPI WshShell3_SendKeys(IWshShell3 *iface, BSTR Keys, VARIANT *Wait)
1804 FIXME("(%s %p): stub\n", debugstr_w(Keys), Wait);
1805 return E_NOTIMPL;
1808 static HRESULT WINAPI WshShell3_Exec(IWshShell3 *iface, BSTR command, IWshExec **ret)
1810 BSTR expandedcmd;
1811 HRESULT hr;
1813 TRACE("(%s %p)\n", debugstr_w(command), ret);
1815 if (!ret)
1816 return E_POINTER;
1818 if (!command)
1819 return DISP_E_EXCEPTION;
1821 hr = WshShell3_ExpandEnvironmentStrings(iface, command, &expandedcmd);
1822 if (FAILED(hr))
1823 return hr;
1825 hr = WshExec_create(expandedcmd, ret);
1826 SysFreeString(expandedcmd);
1827 return hr;
1830 static HRESULT WINAPI WshShell3_get_CurrentDirectory(IWshShell3 *iface, BSTR *dir)
1832 DWORD ret;
1834 TRACE("(%p)\n", dir);
1836 ret = GetCurrentDirectoryW(0, NULL);
1837 if (!ret)
1838 return HRESULT_FROM_WIN32(GetLastError());
1840 *dir = SysAllocStringLen(NULL, ret-1);
1841 if (!*dir)
1842 return E_OUTOFMEMORY;
1844 ret = GetCurrentDirectoryW(ret, *dir);
1845 if (!ret) {
1846 SysFreeString(*dir);
1847 *dir = NULL;
1848 return HRESULT_FROM_WIN32(GetLastError());
1851 return S_OK;
1854 static HRESULT WINAPI WshShell3_put_CurrentDirectory(IWshShell3 *iface, BSTR dir)
1856 TRACE("(%s)\n", debugstr_w(dir));
1858 if (!dir)
1859 return E_INVALIDARG;
1861 if (!SetCurrentDirectoryW(dir))
1862 return HRESULT_FROM_WIN32(GetLastError());
1864 return S_OK;
1867 static const IWshShell3Vtbl WshShell3Vtbl = {
1868 WshShell3_QueryInterface,
1869 WshShell3_AddRef,
1870 WshShell3_Release,
1871 WshShell3_GetTypeInfoCount,
1872 WshShell3_GetTypeInfo,
1873 WshShell3_GetIDsOfNames,
1874 WshShell3_Invoke,
1875 WshShell3_get_SpecialFolders,
1876 WshShell3_get_Environment,
1877 WshShell3_Run,
1878 WshShell3_Popup,
1879 WshShell3_CreateShortcut,
1880 WshShell3_ExpandEnvironmentStrings,
1881 WshShell3_RegRead,
1882 WshShell3_RegWrite,
1883 WshShell3_RegDelete,
1884 WshShell3_LogEvent,
1885 WshShell3_AppActivate,
1886 WshShell3_SendKeys,
1887 WshShell3_Exec,
1888 WshShell3_get_CurrentDirectory,
1889 WshShell3_put_CurrentDirectory
1892 HRESULT WINAPI WshShellFactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
1894 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
1896 WshShell3.IWshShell3_iface.lpVtbl = &WshShell3Vtbl;
1897 init_classinfo(&IID_IWshShell3, (IUnknown *)&WshShell3.IWshShell3_iface, &WshShell3.classinfo);
1898 return IWshShell3_QueryInterface(&WshShell3.IWshShell3_iface, riid, ppv);