wmc: Move WineHQ URLs to https.
[wine.git] / dlls / wshom.ocx / shell.c
blobb00bc1060e8471de37d90588cf2144a308675471
1 /*
2 * Copyright 2011 Jacek Caban for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "wshom_private.h"
20 #include "wshom.h"
22 #include "shellapi.h"
23 #include "shlobj.h"
24 #include "dispex.h"
26 #include "wine/debug.h"
27 #include "wine/unicode.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(wshom);
31 typedef struct
33 struct provideclassinfo classinfo;
34 IWshShell3 IWshShell3_iface;
35 } WshShellImpl;
36 static WshShellImpl WshShell3;
38 typedef struct
40 struct provideclassinfo classinfo;
41 IWshCollection IWshCollection_iface;
42 LONG ref;
43 } WshCollection;
45 typedef struct
47 struct provideclassinfo classinfo;
48 IWshShortcut IWshShortcut_iface;
49 LONG ref;
51 IShellLinkW *link;
52 BSTR path_link;
53 } WshShortcut;
55 typedef struct
57 struct provideclassinfo classinfo;
58 IWshEnvironment IWshEnvironment_iface;
59 LONG ref;
60 } WshEnvironment;
62 typedef struct
64 struct provideclassinfo classinfo;
65 IWshExec IWshExec_iface;
66 LONG ref;
67 PROCESS_INFORMATION info;
68 } WshExecImpl;
70 static inline WshCollection *impl_from_IWshCollection( IWshCollection *iface )
72 return CONTAINING_RECORD(iface, WshCollection, IWshCollection_iface);
75 static inline WshShortcut *impl_from_IWshShortcut( IWshShortcut *iface )
77 return CONTAINING_RECORD(iface, WshShortcut, IWshShortcut_iface);
80 static inline WshEnvironment *impl_from_IWshEnvironment( IWshEnvironment *iface )
82 return CONTAINING_RECORD(iface, WshEnvironment, IWshEnvironment_iface);
85 static inline WshExecImpl *impl_from_IWshExec( IWshExec *iface )
87 return CONTAINING_RECORD(iface, WshExecImpl, IWshExec_iface);
90 static HRESULT WINAPI WshExec_QueryInterface(IWshExec *iface, REFIID riid, void **obj)
92 WshExecImpl *This = impl_from_IWshExec(iface);
94 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), obj);
96 if (IsEqualGUID(riid, &IID_IDispatch) ||
97 IsEqualGUID(riid, &IID_IWshExec) ||
98 IsEqualGUID(riid, &IID_IUnknown))
100 *obj = iface;
102 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
104 *obj = &This->classinfo.IProvideClassInfo_iface;
106 else {
107 FIXME("Unknown iface %s\n", debugstr_guid(riid));
108 *obj = NULL;
109 return E_NOINTERFACE;
112 IUnknown_AddRef((IUnknown *)*obj);
113 return S_OK;
116 static ULONG WINAPI WshExec_AddRef(IWshExec *iface)
118 WshExecImpl *This = impl_from_IWshExec(iface);
119 LONG ref = InterlockedIncrement(&This->ref);
120 TRACE("(%p) ref = %d\n", This, ref);
121 return ref;
124 static ULONG WINAPI WshExec_Release(IWshExec *iface)
126 WshExecImpl *This = impl_from_IWshExec(iface);
127 LONG ref = InterlockedDecrement(&This->ref);
128 TRACE("(%p) ref = %d\n", This, ref);
130 if (!ref) {
131 CloseHandle(This->info.hThread);
132 CloseHandle(This->info.hProcess);
133 HeapFree(GetProcessHeap(), 0, This);
136 return ref;
139 static HRESULT WINAPI WshExec_GetTypeInfoCount(IWshExec *iface, UINT *pctinfo)
141 WshExecImpl *This = impl_from_IWshExec(iface);
142 TRACE("(%p)->(%p)\n", This, pctinfo);
143 *pctinfo = 1;
144 return S_OK;
147 static HRESULT WINAPI WshExec_GetTypeInfo(IWshExec *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
149 WshExecImpl *This = impl_from_IWshExec(iface);
150 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
151 return get_typeinfo(IWshExec_tid, ppTInfo);
154 static HRESULT WINAPI WshExec_GetIDsOfNames(IWshExec *iface, REFIID riid, LPOLESTR *rgszNames,
155 UINT cNames, LCID lcid, DISPID *rgDispId)
157 WshExecImpl *This = impl_from_IWshExec(iface);
158 ITypeInfo *typeinfo;
159 HRESULT hr;
161 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
163 hr = get_typeinfo(IWshExec_tid, &typeinfo);
164 if(SUCCEEDED(hr))
166 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
167 ITypeInfo_Release(typeinfo);
170 return hr;
173 static HRESULT WINAPI WshExec_Invoke(IWshExec *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
174 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
176 WshExecImpl *This = impl_from_IWshExec(iface);
177 ITypeInfo *typeinfo;
178 HRESULT hr;
180 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
181 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
183 hr = get_typeinfo(IWshExec_tid, &typeinfo);
184 if(SUCCEEDED(hr))
186 hr = ITypeInfo_Invoke(typeinfo, &This->IWshExec_iface, dispIdMember, wFlags,
187 pDispParams, pVarResult, pExcepInfo, puArgErr);
188 ITypeInfo_Release(typeinfo);
191 return hr;
194 static HRESULT WINAPI WshExec_get_Status(IWshExec *iface, WshExecStatus *status)
196 WshExecImpl *This = impl_from_IWshExec(iface);
197 DWORD code;
199 TRACE("(%p)->(%p)\n", This, status);
201 if (!status)
202 return E_INVALIDARG;
204 if (!GetExitCodeProcess(This->info.hProcess, &code))
205 return HRESULT_FROM_WIN32(GetLastError());
207 switch (code)
209 case 0:
210 *status = WshFinished;
211 break;
212 case STILL_ACTIVE:
213 *status = WshRunning;
214 break;
215 default:
216 *status = WshFailed;
219 return S_OK;
222 static HRESULT WINAPI WshExec_get_StdIn(IWshExec *iface, ITextStream **stream)
224 WshExecImpl *This = impl_from_IWshExec(iface);
226 FIXME("(%p)->(%p): stub\n", This, stream);
228 return E_NOTIMPL;
231 static HRESULT WINAPI WshExec_get_StdOut(IWshExec *iface, ITextStream **stream)
233 WshExecImpl *This = impl_from_IWshExec(iface);
235 FIXME("(%p)->(%p): stub\n", This, stream);
237 return E_NOTIMPL;
240 static HRESULT WINAPI WshExec_get_StdErr(IWshExec *iface, ITextStream **stream)
242 WshExecImpl *This = impl_from_IWshExec(iface);
244 FIXME("(%p)->(%p): stub\n", This, stream);
246 return E_NOTIMPL;
249 static HRESULT WINAPI WshExec_get_ProcessID(IWshExec *iface, DWORD *pid)
251 WshExecImpl *This = impl_from_IWshExec(iface);
253 TRACE("(%p)->(%p)\n", This, pid);
255 if (!pid)
256 return E_INVALIDARG;
258 *pid = This->info.dwProcessId;
259 return S_OK;
262 static HRESULT WINAPI WshExec_get_ExitCode(IWshExec *iface, DWORD *code)
264 WshExecImpl *This = impl_from_IWshExec(iface);
266 FIXME("(%p)->(%p): stub\n", This, code);
268 return E_NOTIMPL;
271 static BOOL CALLBACK enum_thread_wnd_proc(HWND hwnd, LPARAM lParam)
273 INT *count = (INT*)lParam;
275 (*count)++;
276 PostMessageW(hwnd, WM_CLOSE, 0, 0);
277 /* try to send it to all windows, even if failed for some */
278 return TRUE;
281 static HRESULT WINAPI WshExec_Terminate(IWshExec *iface)
283 WshExecImpl *This = impl_from_IWshExec(iface);
284 BOOL ret, kill = FALSE;
285 INT count = 0;
287 TRACE("(%p)\n", This);
289 ret = EnumThreadWindows(This->info.dwThreadId, enum_thread_wnd_proc, (LPARAM)&count);
290 if (ret && count) {
291 /* manual testing shows that it waits 2 seconds before forcing termination */
292 if (WaitForSingleObject(This->info.hProcess, 2000) != WAIT_OBJECT_0)
293 kill = TRUE;
295 else
296 kill = TRUE;
298 if (kill)
299 TerminateProcess(This->info.hProcess, 0);
301 return S_OK;
304 static const IWshExecVtbl WshExecVtbl = {
305 WshExec_QueryInterface,
306 WshExec_AddRef,
307 WshExec_Release,
308 WshExec_GetTypeInfoCount,
309 WshExec_GetTypeInfo,
310 WshExec_GetIDsOfNames,
311 WshExec_Invoke,
312 WshExec_get_Status,
313 WshExec_get_StdIn,
314 WshExec_get_StdOut,
315 WshExec_get_StdErr,
316 WshExec_get_ProcessID,
317 WshExec_get_ExitCode,
318 WshExec_Terminate
321 static HRESULT WshExec_create(BSTR command, IWshExec **ret)
323 STARTUPINFOW si = {0};
324 WshExecImpl *This;
326 *ret = NULL;
328 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
329 if (!This)
330 return E_OUTOFMEMORY;
332 This->IWshExec_iface.lpVtbl = &WshExecVtbl;
333 This->ref = 1;
335 if (!CreateProcessW(NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &This->info)) {
336 HeapFree(GetProcessHeap(), 0, This);
337 return HRESULT_FROM_WIN32(GetLastError());
340 init_classinfo(&CLSID_WshExec, (IUnknown *)&This->IWshExec_iface, &This->classinfo);
341 *ret = &This->IWshExec_iface;
342 return S_OK;
345 static HRESULT WINAPI WshEnvironment_QueryInterface(IWshEnvironment *iface, REFIID riid, void **obj)
347 WshEnvironment *This = impl_from_IWshEnvironment(iface);
349 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), obj);
351 if (IsEqualGUID(riid, &IID_IUnknown) ||
352 IsEqualGUID(riid, &IID_IDispatch) ||
353 IsEqualGUID(riid, &IID_IWshEnvironment))
355 *obj = iface;
357 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
359 *obj = &This->classinfo.IProvideClassInfo_iface;
361 else {
362 FIXME("Unknown iface %s\n", debugstr_guid(riid));
363 *obj = NULL;
364 return E_NOINTERFACE;
367 IUnknown_AddRef((IUnknown*)*obj);
368 return S_OK;
371 static ULONG WINAPI WshEnvironment_AddRef(IWshEnvironment *iface)
373 WshEnvironment *This = impl_from_IWshEnvironment(iface);
374 LONG ref = InterlockedIncrement(&This->ref);
375 TRACE("(%p) ref = %d\n", This, ref);
376 return ref;
379 static ULONG WINAPI WshEnvironment_Release(IWshEnvironment *iface)
381 WshEnvironment *This = impl_from_IWshEnvironment(iface);
382 LONG ref = InterlockedDecrement(&This->ref);
383 TRACE("(%p) ref = %d\n", This, ref);
385 if (!ref)
386 HeapFree(GetProcessHeap(), 0, This);
388 return ref;
391 static HRESULT WINAPI WshEnvironment_GetTypeInfoCount(IWshEnvironment *iface, UINT *pctinfo)
393 WshEnvironment *This = impl_from_IWshEnvironment(iface);
394 TRACE("(%p)->(%p)\n", This, pctinfo);
395 *pctinfo = 1;
396 return S_OK;
399 static HRESULT WINAPI WshEnvironment_GetTypeInfo(IWshEnvironment *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
401 WshEnvironment *This = impl_from_IWshEnvironment(iface);
402 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
403 return get_typeinfo(IWshEnvironment_tid, ppTInfo);
406 static HRESULT WINAPI WshEnvironment_GetIDsOfNames(IWshEnvironment *iface, REFIID riid, LPOLESTR *rgszNames,
407 UINT cNames, LCID lcid, DISPID *rgDispId)
409 WshEnvironment *This = impl_from_IWshEnvironment(iface);
410 ITypeInfo *typeinfo;
411 HRESULT hr;
413 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
415 hr = get_typeinfo(IWshEnvironment_tid, &typeinfo);
416 if(SUCCEEDED(hr))
418 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
419 ITypeInfo_Release(typeinfo);
422 return hr;
425 static HRESULT WINAPI WshEnvironment_Invoke(IWshEnvironment *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
426 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
428 WshEnvironment *This = impl_from_IWshEnvironment(iface);
429 ITypeInfo *typeinfo;
430 HRESULT hr;
432 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
433 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
435 hr = get_typeinfo(IWshEnvironment_tid, &typeinfo);
436 if(SUCCEEDED(hr))
438 hr = ITypeInfo_Invoke(typeinfo, &This->IWshEnvironment_iface, dispIdMember, wFlags,
439 pDispParams, pVarResult, pExcepInfo, puArgErr);
440 ITypeInfo_Release(typeinfo);
443 return hr;
446 static HRESULT WINAPI WshEnvironment_get_Item(IWshEnvironment *iface, BSTR name, BSTR *value)
448 WshEnvironment *This = impl_from_IWshEnvironment(iface);
449 DWORD len;
451 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), value);
453 if (!value)
454 return E_POINTER;
456 len = GetEnvironmentVariableW(name, NULL, 0);
457 *value = SysAllocStringLen(NULL, len);
458 if (!*value)
459 return E_OUTOFMEMORY;
461 if (len)
462 GetEnvironmentVariableW(name, *value, len+1);
464 return S_OK;
467 static HRESULT WINAPI WshEnvironment_put_Item(IWshEnvironment *iface, BSTR name, BSTR value)
469 WshEnvironment *This = impl_from_IWshEnvironment(iface);
470 FIXME("(%p)->(%s %s): stub\n", This, debugstr_w(name), debugstr_w(value));
471 return E_NOTIMPL;
474 static HRESULT WINAPI WshEnvironment_Count(IWshEnvironment *iface, LONG *count)
476 WshEnvironment *This = impl_from_IWshEnvironment(iface);
477 FIXME("(%p)->(%p): stub\n", This, count);
478 return E_NOTIMPL;
481 static HRESULT WINAPI WshEnvironment_get_length(IWshEnvironment *iface, LONG *len)
483 WshEnvironment *This = impl_from_IWshEnvironment(iface);
484 FIXME("(%p)->(%p): stub\n", This, len);
485 return E_NOTIMPL;
488 static HRESULT WINAPI WshEnvironment__NewEnum(IWshEnvironment *iface, IUnknown **penum)
490 WshEnvironment *This = impl_from_IWshEnvironment(iface);
491 FIXME("(%p)->(%p): stub\n", This, penum);
492 return E_NOTIMPL;
495 static HRESULT WINAPI WshEnvironment_Remove(IWshEnvironment *iface, BSTR name)
497 WshEnvironment *This = impl_from_IWshEnvironment(iface);
498 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
499 return E_NOTIMPL;
502 static const IWshEnvironmentVtbl WshEnvironmentVtbl = {
503 WshEnvironment_QueryInterface,
504 WshEnvironment_AddRef,
505 WshEnvironment_Release,
506 WshEnvironment_GetTypeInfoCount,
507 WshEnvironment_GetTypeInfo,
508 WshEnvironment_GetIDsOfNames,
509 WshEnvironment_Invoke,
510 WshEnvironment_get_Item,
511 WshEnvironment_put_Item,
512 WshEnvironment_Count,
513 WshEnvironment_get_length,
514 WshEnvironment__NewEnum,
515 WshEnvironment_Remove
518 static HRESULT WshEnvironment_Create(IWshEnvironment **env)
520 WshEnvironment *This;
522 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
523 if (!This) return E_OUTOFMEMORY;
525 This->IWshEnvironment_iface.lpVtbl = &WshEnvironmentVtbl;
526 This->ref = 1;
528 init_classinfo(&IID_IWshEnvironment, (IUnknown *)&This->IWshEnvironment_iface, &This->classinfo);
529 *env = &This->IWshEnvironment_iface;
531 return S_OK;
534 static HRESULT WINAPI WshCollection_QueryInterface(IWshCollection *iface, REFIID riid, void **ppv)
536 WshCollection *This = impl_from_IWshCollection(iface);
538 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
540 if (IsEqualGUID(riid, &IID_IUnknown) ||
541 IsEqualGUID(riid, &IID_IDispatch) ||
542 IsEqualGUID(riid, &IID_IWshCollection))
544 *ppv = iface;
546 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
548 *ppv = &This->classinfo.IProvideClassInfo_iface;
550 else {
551 FIXME("Unknown iface %s\n", debugstr_guid(riid));
552 *ppv = NULL;
553 return E_NOINTERFACE;
556 IUnknown_AddRef((IUnknown*)*ppv);
557 return S_OK;
560 static ULONG WINAPI WshCollection_AddRef(IWshCollection *iface)
562 WshCollection *This = impl_from_IWshCollection(iface);
563 LONG ref = InterlockedIncrement(&This->ref);
564 TRACE("(%p) ref = %d\n", This, ref);
565 return ref;
568 static ULONG WINAPI WshCollection_Release(IWshCollection *iface)
570 WshCollection *This = impl_from_IWshCollection(iface);
571 LONG ref = InterlockedDecrement(&This->ref);
572 TRACE("(%p) ref = %d\n", This, ref);
574 if (!ref)
575 HeapFree(GetProcessHeap(), 0, This);
577 return ref;
580 static HRESULT WINAPI WshCollection_GetTypeInfoCount(IWshCollection *iface, UINT *pctinfo)
582 WshCollection *This = impl_from_IWshCollection(iface);
583 TRACE("(%p)->(%p)\n", This, pctinfo);
584 *pctinfo = 1;
585 return S_OK;
588 static HRESULT WINAPI WshCollection_GetTypeInfo(IWshCollection *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
590 WshCollection *This = impl_from_IWshCollection(iface);
591 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
592 return get_typeinfo(IWshCollection_tid, ppTInfo);
595 static HRESULT WINAPI WshCollection_GetIDsOfNames(IWshCollection *iface, REFIID riid, LPOLESTR *rgszNames,
596 UINT cNames, LCID lcid, DISPID *rgDispId)
598 WshCollection *This = impl_from_IWshCollection(iface);
599 ITypeInfo *typeinfo;
600 HRESULT hr;
602 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
604 hr = get_typeinfo(IWshCollection_tid, &typeinfo);
605 if(SUCCEEDED(hr))
607 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
608 ITypeInfo_Release(typeinfo);
611 return hr;
614 static HRESULT WINAPI WshCollection_Invoke(IWshCollection *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
615 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
617 WshCollection *This = impl_from_IWshCollection(iface);
618 ITypeInfo *typeinfo;
619 HRESULT hr;
621 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
622 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
624 hr = get_typeinfo(IWshCollection_tid, &typeinfo);
625 if(SUCCEEDED(hr))
627 hr = ITypeInfo_Invoke(typeinfo, &This->IWshCollection_iface, dispIdMember, wFlags,
628 pDispParams, pVarResult, pExcepInfo, puArgErr);
629 ITypeInfo_Release(typeinfo);
632 return hr;
635 static HRESULT WINAPI WshCollection_Item(IWshCollection *iface, VARIANT *index, VARIANT *value)
637 WshCollection *This = impl_from_IWshCollection(iface);
638 static const WCHAR allusersdesktopW[] = {'A','l','l','U','s','e','r','s','D','e','s','k','t','o','p',0};
639 static const WCHAR allusersprogramsW[] = {'A','l','l','U','s','e','r','s','P','r','o','g','r','a','m','s',0};
640 static const WCHAR desktopW[] = {'D','e','s','k','t','o','p',0};
641 PIDLIST_ABSOLUTE pidl;
642 WCHAR pathW[MAX_PATH];
643 int kind = 0;
644 BSTR folder;
645 HRESULT hr;
647 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(index), value);
649 if (V_VT(index) != VT_BSTR)
651 FIXME("only BSTR index supported, got %d\n", V_VT(index));
652 return E_NOTIMPL;
655 folder = V_BSTR(index);
656 if (!strcmpiW(folder, desktopW))
657 kind = CSIDL_DESKTOP;
658 else if (!strcmpiW(folder, allusersdesktopW))
659 kind = CSIDL_COMMON_DESKTOPDIRECTORY;
660 else if (!strcmpiW(folder, allusersprogramsW))
661 kind = CSIDL_COMMON_PROGRAMS;
662 else
664 FIXME("folder kind %s not supported\n", debugstr_w(folder));
665 return E_NOTIMPL;
668 hr = SHGetSpecialFolderLocation(NULL, kind, &pidl);
669 if (hr != S_OK) return hr;
671 if (SHGetPathFromIDListW(pidl, pathW))
673 V_VT(value) = VT_BSTR;
674 V_BSTR(value) = SysAllocString(pathW);
675 hr = V_BSTR(value) ? S_OK : E_OUTOFMEMORY;
677 else
678 hr = E_FAIL;
680 CoTaskMemFree(pidl);
682 return hr;
685 static HRESULT WINAPI WshCollection_Count(IWshCollection *iface, LONG *count)
687 WshCollection *This = impl_from_IWshCollection(iface);
688 FIXME("(%p)->(%p): stub\n", This, count);
689 return E_NOTIMPL;
692 static HRESULT WINAPI WshCollection_get_length(IWshCollection *iface, LONG *count)
694 WshCollection *This = impl_from_IWshCollection(iface);
695 FIXME("(%p)->(%p): stub\n", This, count);
696 return E_NOTIMPL;
699 static HRESULT WINAPI WshCollection__NewEnum(IWshCollection *iface, IUnknown *Enum)
701 WshCollection *This = impl_from_IWshCollection(iface);
702 FIXME("(%p)->(%p): stub\n", This, Enum);
703 return E_NOTIMPL;
706 static const IWshCollectionVtbl WshCollectionVtbl = {
707 WshCollection_QueryInterface,
708 WshCollection_AddRef,
709 WshCollection_Release,
710 WshCollection_GetTypeInfoCount,
711 WshCollection_GetTypeInfo,
712 WshCollection_GetIDsOfNames,
713 WshCollection_Invoke,
714 WshCollection_Item,
715 WshCollection_Count,
716 WshCollection_get_length,
717 WshCollection__NewEnum
720 static HRESULT WshCollection_Create(IWshCollection **collection)
722 WshCollection *This;
724 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
725 if (!This) return E_OUTOFMEMORY;
727 This->IWshCollection_iface.lpVtbl = &WshCollectionVtbl;
728 This->ref = 1;
730 init_classinfo(&IID_IWshCollection, (IUnknown *)&This->IWshCollection_iface, &This->classinfo);
731 *collection = &This->IWshCollection_iface;
733 return S_OK;
736 /* IWshShortcut */
737 static HRESULT WINAPI WshShortcut_QueryInterface(IWshShortcut *iface, REFIID riid, void **ppv)
739 WshShortcut *This = impl_from_IWshShortcut(iface);
741 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
743 if (IsEqualGUID(riid, &IID_IUnknown) ||
744 IsEqualGUID(riid, &IID_IDispatch) ||
745 IsEqualGUID(riid, &IID_IWshShortcut))
747 *ppv = iface;
749 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
751 *ppv = &This->classinfo.IProvideClassInfo_iface;
753 else {
754 FIXME("Unknown iface %s\n", debugstr_guid(riid));
755 *ppv = NULL;
756 return E_NOINTERFACE;
759 IUnknown_AddRef((IUnknown*)*ppv);
760 return S_OK;
763 static ULONG WINAPI WshShortcut_AddRef(IWshShortcut *iface)
765 WshShortcut *This = impl_from_IWshShortcut(iface);
766 LONG ref = InterlockedIncrement(&This->ref);
767 TRACE("(%p) ref = %d\n", This, ref);
768 return ref;
771 static ULONG WINAPI WshShortcut_Release(IWshShortcut *iface)
773 WshShortcut *This = impl_from_IWshShortcut(iface);
774 LONG ref = InterlockedDecrement(&This->ref);
775 TRACE("(%p) ref = %d\n", This, ref);
777 if (!ref)
779 SysFreeString(This->path_link);
780 IShellLinkW_Release(This->link);
781 HeapFree(GetProcessHeap(), 0, This);
784 return ref;
787 static HRESULT WINAPI WshShortcut_GetTypeInfoCount(IWshShortcut *iface, UINT *pctinfo)
789 WshShortcut *This = impl_from_IWshShortcut(iface);
790 TRACE("(%p)->(%p)\n", This, pctinfo);
791 *pctinfo = 1;
792 return S_OK;
795 static HRESULT WINAPI WshShortcut_GetTypeInfo(IWshShortcut *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
797 WshShortcut *This = impl_from_IWshShortcut(iface);
798 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
799 return get_typeinfo(IWshShortcut_tid, ppTInfo);
802 static HRESULT WINAPI WshShortcut_GetIDsOfNames(IWshShortcut *iface, REFIID riid, LPOLESTR *rgszNames,
803 UINT cNames, LCID lcid, DISPID *rgDispId)
805 WshShortcut *This = impl_from_IWshShortcut(iface);
806 ITypeInfo *typeinfo;
807 HRESULT hr;
809 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
811 hr = get_typeinfo(IWshShortcut_tid, &typeinfo);
812 if(SUCCEEDED(hr))
814 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
815 ITypeInfo_Release(typeinfo);
818 return hr;
821 static HRESULT WINAPI WshShortcut_Invoke(IWshShortcut *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
822 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
824 WshShortcut *This = impl_from_IWshShortcut(iface);
825 ITypeInfo *typeinfo;
826 HRESULT hr;
828 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
829 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
831 hr = get_typeinfo(IWshShortcut_tid, &typeinfo);
832 if(SUCCEEDED(hr))
834 hr = ITypeInfo_Invoke(typeinfo, &This->IWshShortcut_iface, dispIdMember, wFlags,
835 pDispParams, pVarResult, pExcepInfo, puArgErr);
836 ITypeInfo_Release(typeinfo);
839 return hr;
842 static HRESULT WINAPI WshShortcut_get_FullName(IWshShortcut *iface, BSTR *name)
844 WshShortcut *This = impl_from_IWshShortcut(iface);
845 FIXME("(%p)->(%p): stub\n", This, name);
846 return E_NOTIMPL;
849 static HRESULT WINAPI WshShortcut_get_Arguments(IWshShortcut *iface, BSTR *Arguments)
851 WshShortcut *This = impl_from_IWshShortcut(iface);
852 WCHAR buffW[INFOTIPSIZE];
853 HRESULT hr;
855 TRACE("(%p)->(%p)\n", This, Arguments);
857 if (!Arguments)
858 return E_POINTER;
860 *Arguments = NULL;
862 hr = IShellLinkW_GetArguments(This->link, buffW, sizeof(buffW)/sizeof(WCHAR));
863 if (FAILED(hr))
864 return hr;
866 *Arguments = SysAllocString(buffW);
867 return *Arguments ? S_OK : E_OUTOFMEMORY;
870 static HRESULT WINAPI WshShortcut_put_Arguments(IWshShortcut *iface, BSTR Arguments)
872 WshShortcut *This = impl_from_IWshShortcut(iface);
874 TRACE("(%p)->(%s)\n", This, debugstr_w(Arguments));
876 return IShellLinkW_SetArguments(This->link, Arguments);
879 static HRESULT WINAPI WshShortcut_get_Description(IWshShortcut *iface, BSTR *Description)
881 WshShortcut *This = impl_from_IWshShortcut(iface);
882 FIXME("(%p)->(%p): stub\n", This, Description);
883 return E_NOTIMPL;
886 static HRESULT WINAPI WshShortcut_put_Description(IWshShortcut *iface, BSTR Description)
888 WshShortcut *This = impl_from_IWshShortcut(iface);
889 TRACE("(%p)->(%s)\n", This, debugstr_w(Description));
890 return IShellLinkW_SetDescription(This->link, Description);
893 static HRESULT WINAPI WshShortcut_get_Hotkey(IWshShortcut *iface, BSTR *Hotkey)
895 WshShortcut *This = impl_from_IWshShortcut(iface);
896 FIXME("(%p)->(%p): stub\n", This, Hotkey);
897 return E_NOTIMPL;
900 static HRESULT WINAPI WshShortcut_put_Hotkey(IWshShortcut *iface, BSTR Hotkey)
902 WshShortcut *This = impl_from_IWshShortcut(iface);
903 FIXME("(%p)->(%s): stub\n", This, debugstr_w(Hotkey));
904 return E_NOTIMPL;
907 static HRESULT WINAPI WshShortcut_get_IconLocation(IWshShortcut *iface, BSTR *IconPath)
909 static const WCHAR fmtW[] = {'%','s',',',' ','%','d',0};
910 WshShortcut *This = impl_from_IWshShortcut(iface);
911 WCHAR buffW[MAX_PATH], pathW[MAX_PATH];
912 INT icon = 0;
913 HRESULT hr;
915 TRACE("(%p)->(%p)\n", This, IconPath);
917 if (!IconPath)
918 return E_POINTER;
920 hr = IShellLinkW_GetIconLocation(This->link, buffW, sizeof(buffW)/sizeof(WCHAR), &icon);
921 if (FAILED(hr)) return hr;
923 sprintfW(pathW, fmtW, buffW, icon);
924 *IconPath = SysAllocString(pathW);
925 if (!*IconPath) return E_OUTOFMEMORY;
927 return S_OK;
930 static HRESULT WINAPI WshShortcut_put_IconLocation(IWshShortcut *iface, BSTR IconPath)
932 WshShortcut *This = impl_from_IWshShortcut(iface);
933 HRESULT hr;
934 WCHAR *ptr;
935 BSTR path;
936 INT icon;
938 TRACE("(%p)->(%s)\n", This, debugstr_w(IconPath));
940 /* scan for icon id */
941 ptr = strrchrW(IconPath, ',');
942 if (!ptr)
944 WARN("icon index not found\n");
945 return E_FAIL;
948 path = SysAllocStringLen(IconPath, ptr-IconPath);
950 /* skip spaces if any */
951 while (isspaceW(*++ptr))
954 icon = atoiW(ptr);
956 hr = IShellLinkW_SetIconLocation(This->link, path, icon);
957 SysFreeString(path);
959 return hr;
962 static HRESULT WINAPI WshShortcut_put_RelativePath(IWshShortcut *iface, BSTR rhs)
964 WshShortcut *This = impl_from_IWshShortcut(iface);
965 FIXME("(%p)->(%s): stub\n", This, debugstr_w(rhs));
966 return E_NOTIMPL;
969 static HRESULT WINAPI WshShortcut_get_TargetPath(IWshShortcut *iface, BSTR *Path)
971 WshShortcut *This = impl_from_IWshShortcut(iface);
972 FIXME("(%p)->(%p): stub\n", This, Path);
973 return E_NOTIMPL;
976 static HRESULT WINAPI WshShortcut_put_TargetPath(IWshShortcut *iface, BSTR Path)
978 WshShortcut *This = impl_from_IWshShortcut(iface);
979 TRACE("(%p)->(%s)\n", This, debugstr_w(Path));
980 return IShellLinkW_SetPath(This->link, Path);
983 static HRESULT WINAPI WshShortcut_get_WindowStyle(IWshShortcut *iface, int *ShowCmd)
985 WshShortcut *This = impl_from_IWshShortcut(iface);
986 TRACE("(%p)->(%p)\n", This, ShowCmd);
987 return IShellLinkW_GetShowCmd(This->link, ShowCmd);
990 static HRESULT WINAPI WshShortcut_put_WindowStyle(IWshShortcut *iface, int ShowCmd)
992 WshShortcut *This = impl_from_IWshShortcut(iface);
993 TRACE("(%p)->(%d)\n", This, ShowCmd);
994 return IShellLinkW_SetShowCmd(This->link, ShowCmd);
997 static HRESULT WINAPI WshShortcut_get_WorkingDirectory(IWshShortcut *iface, BSTR *WorkingDirectory)
999 WshShortcut *This = impl_from_IWshShortcut(iface);
1000 WCHAR buffW[MAX_PATH];
1001 HRESULT hr;
1003 TRACE("(%p)->(%p)\n", This, WorkingDirectory);
1005 if (!WorkingDirectory)
1006 return E_POINTER;
1008 *WorkingDirectory = NULL;
1009 hr = IShellLinkW_GetWorkingDirectory(This->link, buffW, sizeof(buffW)/sizeof(WCHAR));
1010 if (FAILED(hr)) return hr;
1012 *WorkingDirectory = SysAllocString(buffW);
1013 return *WorkingDirectory ? S_OK : E_OUTOFMEMORY;
1016 static HRESULT WINAPI WshShortcut_put_WorkingDirectory(IWshShortcut *iface, BSTR WorkingDirectory)
1018 WshShortcut *This = impl_from_IWshShortcut(iface);
1019 TRACE("(%p)->(%s)\n", This, debugstr_w(WorkingDirectory));
1020 return IShellLinkW_SetWorkingDirectory(This->link, WorkingDirectory);
1023 static HRESULT WINAPI WshShortcut_Load(IWshShortcut *iface, BSTR PathLink)
1025 WshShortcut *This = impl_from_IWshShortcut(iface);
1026 FIXME("(%p)->(%s): stub\n", This, debugstr_w(PathLink));
1027 return E_NOTIMPL;
1030 static HRESULT WINAPI WshShortcut_Save(IWshShortcut *iface)
1032 WshShortcut *This = impl_from_IWshShortcut(iface);
1033 IPersistFile *file;
1034 HRESULT hr;
1036 TRACE("(%p)\n", This);
1038 IShellLinkW_QueryInterface(This->link, &IID_IPersistFile, (void**)&file);
1039 hr = IPersistFile_Save(file, This->path_link, TRUE);
1040 IPersistFile_Release(file);
1042 return hr;
1045 static const IWshShortcutVtbl WshShortcutVtbl = {
1046 WshShortcut_QueryInterface,
1047 WshShortcut_AddRef,
1048 WshShortcut_Release,
1049 WshShortcut_GetTypeInfoCount,
1050 WshShortcut_GetTypeInfo,
1051 WshShortcut_GetIDsOfNames,
1052 WshShortcut_Invoke,
1053 WshShortcut_get_FullName,
1054 WshShortcut_get_Arguments,
1055 WshShortcut_put_Arguments,
1056 WshShortcut_get_Description,
1057 WshShortcut_put_Description,
1058 WshShortcut_get_Hotkey,
1059 WshShortcut_put_Hotkey,
1060 WshShortcut_get_IconLocation,
1061 WshShortcut_put_IconLocation,
1062 WshShortcut_put_RelativePath,
1063 WshShortcut_get_TargetPath,
1064 WshShortcut_put_TargetPath,
1065 WshShortcut_get_WindowStyle,
1066 WshShortcut_put_WindowStyle,
1067 WshShortcut_get_WorkingDirectory,
1068 WshShortcut_put_WorkingDirectory,
1069 WshShortcut_Load,
1070 WshShortcut_Save
1073 static HRESULT WshShortcut_Create(const WCHAR *path, IDispatch **shortcut)
1075 WshShortcut *This;
1076 HRESULT hr;
1078 *shortcut = NULL;
1080 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1081 if (!This) return E_OUTOFMEMORY;
1083 This->IWshShortcut_iface.lpVtbl = &WshShortcutVtbl;
1084 This->ref = 1;
1086 hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
1087 &IID_IShellLinkW, (void**)&This->link);
1088 if (FAILED(hr))
1090 HeapFree(GetProcessHeap(), 0, This);
1091 return hr;
1094 This->path_link = SysAllocString(path);
1095 if (!This->path_link)
1097 IShellLinkW_Release(This->link);
1098 HeapFree(GetProcessHeap(), 0, This);
1099 return E_OUTOFMEMORY;
1102 init_classinfo(&IID_IWshShortcut, (IUnknown *)&This->IWshShortcut_iface, &This->classinfo);
1103 *shortcut = (IDispatch*)&This->IWshShortcut_iface;
1105 return S_OK;
1108 static HRESULT WINAPI WshShell3_QueryInterface(IWshShell3 *iface, REFIID riid, void **ppv)
1110 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
1112 *ppv = NULL;
1114 if (IsEqualGUID(riid, &IID_IDispatch) ||
1115 IsEqualGUID(riid, &IID_IWshShell3) ||
1116 IsEqualGUID(riid, &IID_IWshShell2) ||
1117 IsEqualGUID(riid, &IID_IWshShell) ||
1118 IsEqualGUID(riid, &IID_IUnknown))
1120 *ppv = iface;
1122 else if (IsEqualGUID(riid, &IID_IDispatchEx))
1124 return E_NOINTERFACE;
1126 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
1128 *ppv = &WshShell3.classinfo.IProvideClassInfo_iface;
1130 else
1132 WARN("unknown iface %s\n", debugstr_guid(riid));
1133 return E_NOINTERFACE;
1136 IUnknown_AddRef((IUnknown *)*ppv);
1137 return S_OK;
1140 static ULONG WINAPI WshShell3_AddRef(IWshShell3 *iface)
1142 TRACE("()\n");
1143 return 2;
1146 static ULONG WINAPI WshShell3_Release(IWshShell3 *iface)
1148 TRACE("()\n");
1149 return 2;
1152 static HRESULT WINAPI WshShell3_GetTypeInfoCount(IWshShell3 *iface, UINT *pctinfo)
1154 TRACE("(%p)\n", pctinfo);
1155 *pctinfo = 1;
1156 return S_OK;
1159 static HRESULT WINAPI WshShell3_GetTypeInfo(IWshShell3 *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
1161 TRACE("(%u %u %p)\n", iTInfo, lcid, ppTInfo);
1162 return get_typeinfo(IWshShell3_tid, ppTInfo);
1165 static HRESULT WINAPI WshShell3_GetIDsOfNames(IWshShell3 *iface, REFIID riid, LPOLESTR *rgszNames,
1166 UINT cNames, LCID lcid, DISPID *rgDispId)
1168 ITypeInfo *typeinfo;
1169 HRESULT hr;
1171 TRACE("(%s %p %u %u %p)\n", debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1173 hr = get_typeinfo(IWshShell3_tid, &typeinfo);
1174 if(SUCCEEDED(hr))
1176 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1177 ITypeInfo_Release(typeinfo);
1180 return hr;
1183 static HRESULT WINAPI WshShell3_Invoke(IWshShell3 *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
1184 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
1186 ITypeInfo *typeinfo;
1187 HRESULT hr;
1189 TRACE("(%d %s %d %d %p %p %p %p)\n", dispIdMember, debugstr_guid(riid),
1190 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1192 hr = get_typeinfo(IWshShell3_tid, &typeinfo);
1193 if(SUCCEEDED(hr))
1195 hr = ITypeInfo_Invoke(typeinfo, &WshShell3.IWshShell3_iface, dispIdMember, wFlags,
1196 pDispParams, pVarResult, pExcepInfo, puArgErr);
1197 ITypeInfo_Release(typeinfo);
1200 return hr;
1203 static HRESULT WINAPI WshShell3_get_SpecialFolders(IWshShell3 *iface, IWshCollection **folders)
1205 TRACE("(%p)\n", folders);
1206 return WshCollection_Create(folders);
1209 static HRESULT WINAPI WshShell3_get_Environment(IWshShell3 *iface, VARIANT *type, IWshEnvironment **env)
1211 FIXME("(%s %p): semi-stub\n", debugstr_variant(type), env);
1212 return WshEnvironment_Create(env);
1215 static inline BOOL is_optional_argument(const VARIANT *arg)
1217 return V_VT(arg) == VT_ERROR && V_ERROR(arg) == DISP_E_PARAMNOTFOUND;
1220 static HRESULT WINAPI WshShell3_Run(IWshShell3 *iface, BSTR cmd, VARIANT *style, VARIANT *wait, DWORD *exit_code)
1222 SHELLEXECUTEINFOW info;
1223 int waitforprocess;
1224 VARIANT s;
1225 HRESULT hr;
1227 TRACE("(%s %s %s %p)\n", debugstr_w(cmd), debugstr_variant(style), debugstr_variant(wait), exit_code);
1229 if (!style || !wait || !exit_code)
1230 return E_POINTER;
1232 VariantInit(&s);
1233 hr = VariantChangeType(&s, style, 0, VT_I4);
1234 if (FAILED(hr))
1236 ERR("failed to convert style argument, 0x%08x\n", hr);
1237 return hr;
1240 if (is_optional_argument(wait))
1241 waitforprocess = 0;
1242 else {
1243 VARIANT w;
1245 VariantInit(&w);
1246 hr = VariantChangeType(&w, wait, 0, VT_I4);
1247 if (FAILED(hr))
1248 return hr;
1250 waitforprocess = V_I4(&w);
1253 memset(&info, 0, sizeof(info));
1254 info.cbSize = sizeof(info);
1255 info.fMask = waitforprocess ? SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS : SEE_MASK_DEFAULT;
1256 info.lpFile = cmd;
1257 info.nShow = V_I4(&s);
1259 if (!ShellExecuteExW(&info))
1261 TRACE("ShellExecute failed, %d\n", GetLastError());
1262 return HRESULT_FROM_WIN32(GetLastError());
1264 else
1266 if (waitforprocess)
1268 GetExitCodeProcess(info.hProcess, exit_code);
1269 CloseHandle(info.hProcess);
1271 else
1272 *exit_code = 0;
1274 return S_OK;
1278 static HRESULT WINAPI WshShell3_Popup(IWshShell3 *iface, BSTR Text, VARIANT* SecondsToWait, VARIANT *Title, VARIANT *Type, int *button)
1280 FIXME("(%s %s %s %s %p): stub\n", debugstr_w(Text), debugstr_variant(SecondsToWait),
1281 debugstr_variant(Title), debugstr_variant(Type), button);
1282 return E_NOTIMPL;
1285 static HRESULT WINAPI WshShell3_CreateShortcut(IWshShell3 *iface, BSTR PathLink, IDispatch** Shortcut)
1287 TRACE("(%s %p)\n", debugstr_w(PathLink), Shortcut);
1288 return WshShortcut_Create(PathLink, Shortcut);
1291 static HRESULT WINAPI WshShell3_ExpandEnvironmentStrings(IWshShell3 *iface, BSTR Src, BSTR* Dst)
1293 DWORD ret;
1295 TRACE("(%s %p)\n", debugstr_w(Src), Dst);
1297 if (!Src || !Dst) return E_POINTER;
1299 ret = ExpandEnvironmentStringsW(Src, NULL, 0);
1300 *Dst = SysAllocStringLen(NULL, ret);
1301 if (!*Dst) return E_OUTOFMEMORY;
1303 if (ExpandEnvironmentStringsW(Src, *Dst, ret))
1304 return S_OK;
1305 else
1307 SysFreeString(*Dst);
1308 *Dst = NULL;
1309 return HRESULT_FROM_WIN32(GetLastError());
1313 static HKEY get_root_key(const WCHAR *path)
1315 static const struct {
1316 const WCHAR full[20];
1317 const WCHAR abbrev[5];
1318 HKEY hkey;
1319 } rootkeys[] = {
1320 { {'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R',0}, {'H','K','C','U',0}, HKEY_CURRENT_USER },
1321 { {'H','K','E','Y','_','L','O','C','A','L','_','M','A','C','H','I','N','E',0}, {'H','K','L','M',0}, HKEY_LOCAL_MACHINE },
1322 { {'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T',0}, {'H','K','C','R',0}, HKEY_CLASSES_ROOT },
1323 { {'H','K','E','Y','_','U','S','E','R','S',0}, {0}, HKEY_USERS },
1324 { {'H','K','E','Y','_','C','U','R','R','E','N','T','_','C','O','N','F','I','G',0}, {0}, HKEY_CURRENT_CONFIG }
1326 int i;
1328 for (i = 0; i < sizeof(rootkeys)/sizeof(rootkeys[0]); i++) {
1329 if (!strncmpW(path, rootkeys[i].full, strlenW(rootkeys[i].full)))
1330 return rootkeys[i].hkey;
1331 if (rootkeys[i].abbrev[0] && !strncmpW(path, rootkeys[i].abbrev, strlenW(rootkeys[i].abbrev)))
1332 return rootkeys[i].hkey;
1335 return NULL;
1338 /* Caller is responsible to free 'subkey' if 'value' is not NULL */
1339 static HRESULT split_reg_path(const WCHAR *path, WCHAR **subkey, WCHAR **value)
1341 *value = NULL;
1343 /* at least one separator should be present */
1344 *subkey = strchrW(path, '\\');
1345 if (!*subkey)
1346 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1348 /* default value or not */
1349 if ((*subkey)[strlenW(*subkey)-1] == '\\') {
1350 (*subkey)++;
1351 *value = NULL;
1353 else {
1354 *value = strrchrW(*subkey, '\\');
1355 if (*value - *subkey > 1) {
1356 unsigned int len = *value - *subkey - 1;
1357 WCHAR *ret;
1359 ret = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR));
1360 if (!ret)
1361 return E_OUTOFMEMORY;
1363 memcpy(ret, *subkey + 1, len*sizeof(WCHAR));
1364 ret[len] = 0;
1365 *subkey = ret;
1367 (*value)++;
1370 return S_OK;
1373 static HRESULT WINAPI WshShell3_RegRead(IWshShell3 *iface, BSTR name, VARIANT *value)
1375 DWORD type, datalen, ret;
1376 WCHAR *subkey, *val;
1377 HRESULT hr;
1378 HKEY root;
1380 TRACE("(%s %p)\n", debugstr_w(name), value);
1382 if (!name || !value)
1383 return E_POINTER;
1385 root = get_root_key(name);
1386 if (!root)
1387 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1389 hr = split_reg_path(name, &subkey, &val);
1390 if (FAILED(hr))
1391 return hr;
1393 type = REG_NONE;
1394 datalen = 0;
1395 ret = RegGetValueW(root, subkey, val, RRF_RT_ANY, &type, NULL, &datalen);
1396 if (ret == ERROR_SUCCESS) {
1397 void *data;
1399 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1400 if (!data) {
1401 hr = E_OUTOFMEMORY;
1402 goto fail;
1405 ret = RegGetValueW(root, subkey, val, RRF_RT_ANY, &type, data, &datalen);
1406 if (ret) {
1407 HeapFree(GetProcessHeap(), 0, data);
1408 hr = HRESULT_FROM_WIN32(ret);
1409 goto fail;
1412 switch (type) {
1413 case REG_SZ:
1414 case REG_EXPAND_SZ:
1415 V_VT(value) = VT_BSTR;
1416 V_BSTR(value) = SysAllocString((WCHAR*)data);
1417 if (!V_BSTR(value))
1418 hr = E_OUTOFMEMORY;
1419 break;
1420 case REG_DWORD:
1421 V_VT(value) = VT_I4;
1422 V_I4(value) = *(DWORD*)data;
1423 break;
1424 case REG_BINARY:
1426 BYTE *ptr = (BYTE*)data;
1427 SAFEARRAYBOUND bound;
1428 unsigned int i;
1429 SAFEARRAY *sa;
1430 VARIANT *v;
1432 bound.lLbound = 0;
1433 bound.cElements = datalen;
1434 sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
1435 if (!sa)
1436 break;
1438 hr = SafeArrayAccessData(sa, (void**)&v);
1439 if (FAILED(hr)) {
1440 SafeArrayDestroy(sa);
1441 break;
1444 for (i = 0; i < datalen; i++) {
1445 V_VT(&v[i]) = VT_UI1;
1446 V_UI1(&v[i]) = ptr[i];
1448 SafeArrayUnaccessData(sa);
1450 V_VT(value) = VT_ARRAY|VT_VARIANT;
1451 V_ARRAY(value) = sa;
1452 break;
1454 case REG_MULTI_SZ:
1456 WCHAR *ptr = (WCHAR*)data;
1457 SAFEARRAYBOUND bound;
1458 SAFEARRAY *sa;
1459 VARIANT *v;
1461 /* get element count first */
1462 bound.lLbound = 0;
1463 bound.cElements = 0;
1464 while (*ptr) {
1465 bound.cElements++;
1466 ptr += strlenW(ptr)+1;
1469 sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
1470 if (!sa)
1471 break;
1473 hr = SafeArrayAccessData(sa, (void**)&v);
1474 if (FAILED(hr)) {
1475 SafeArrayDestroy(sa);
1476 break;
1479 ptr = (WCHAR*)data;
1480 while (*ptr) {
1481 V_VT(v) = VT_BSTR;
1482 V_BSTR(v) = SysAllocString(ptr);
1483 ptr += strlenW(ptr)+1;
1484 v++;
1487 SafeArrayUnaccessData(sa);
1488 V_VT(value) = VT_ARRAY|VT_VARIANT;
1489 V_ARRAY(value) = sa;
1490 break;
1492 default:
1493 FIXME("value type %d not supported\n", type);
1494 hr = E_FAIL;
1497 HeapFree(GetProcessHeap(), 0, data);
1498 if (FAILED(hr))
1499 VariantInit(value);
1501 else
1502 hr = HRESULT_FROM_WIN32(ret);
1504 fail:
1505 if (val)
1506 HeapFree(GetProcessHeap(), 0, subkey);
1507 return hr;
1510 static HRESULT WINAPI WshShell3_RegWrite(IWshShell3 *iface, BSTR name, VARIANT *value, VARIANT *type)
1512 static const WCHAR regexpandszW[] = {'R','E','G','_','E','X','P','A','N','D','_','S','Z',0};
1513 static const WCHAR regszW[] = {'R','E','G','_','S','Z',0};
1514 static const WCHAR regdwordW[] = {'R','E','G','_','D','W','O','R','D',0};
1515 static const WCHAR regbinaryW[] = {'R','E','G','_','B','I','N','A','R','Y',0};
1517 DWORD regtype, data_len;
1518 WCHAR *subkey, *val;
1519 const BYTE *data;
1520 HRESULT hr;
1521 HKEY root;
1522 VARIANT v;
1523 LONG ret;
1525 TRACE("(%s %s %s)\n", debugstr_w(name), debugstr_variant(value), debugstr_variant(type));
1527 if (!name || !value || !type)
1528 return E_POINTER;
1530 root = get_root_key(name);
1531 if (!root)
1532 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1534 /* value type */
1535 if (is_optional_argument(type))
1536 regtype = REG_SZ;
1537 else {
1538 if (V_VT(type) != VT_BSTR)
1539 return E_INVALIDARG;
1541 if (!strcmpW(V_BSTR(type), regszW))
1542 regtype = REG_SZ;
1543 else if (!strcmpW(V_BSTR(type), regdwordW))
1544 regtype = REG_DWORD;
1545 else if (!strcmpW(V_BSTR(type), regexpandszW))
1546 regtype = REG_EXPAND_SZ;
1547 else if (!strcmpW(V_BSTR(type), regbinaryW))
1548 regtype = REG_BINARY;
1549 else {
1550 FIXME("unrecognized value type %s\n", debugstr_w(V_BSTR(type)));
1551 return E_FAIL;
1555 /* it's always a string or a DWORD */
1556 VariantInit(&v);
1557 switch (regtype)
1559 case REG_SZ:
1560 case REG_EXPAND_SZ:
1561 hr = VariantChangeType(&v, value, 0, VT_BSTR);
1562 if (hr == S_OK) {
1563 data = (BYTE*)V_BSTR(&v);
1564 data_len = SysStringByteLen(V_BSTR(&v)) + sizeof(WCHAR);
1566 break;
1567 case REG_DWORD:
1568 case REG_BINARY:
1569 hr = VariantChangeType(&v, value, 0, VT_I4);
1570 data = (BYTE*)&V_I4(&v);
1571 data_len = sizeof(DWORD);
1572 break;
1573 default:
1574 FIXME("unexpected regtype %d\n", regtype);
1575 return E_FAIL;
1578 if (FAILED(hr)) {
1579 FIXME("failed to convert value, regtype %d, 0x%08x\n", regtype, hr);
1580 return hr;
1583 hr = split_reg_path(name, &subkey, &val);
1584 if (FAILED(hr))
1585 goto fail;
1587 ret = RegSetKeyValueW(root, subkey, val, regtype, data, data_len);
1588 if (ret)
1589 hr = HRESULT_FROM_WIN32(ret);
1591 fail:
1592 VariantClear(&v);
1593 if (val)
1594 HeapFree(GetProcessHeap(), 0, subkey);
1595 return hr;
1598 static HRESULT WINAPI WshShell3_RegDelete(IWshShell3 *iface, BSTR Name)
1600 FIXME("(%s): stub\n", debugstr_w(Name));
1601 return E_NOTIMPL;
1604 static HRESULT WINAPI WshShell3_LogEvent(IWshShell3 *iface, VARIANT *Type, BSTR Message, BSTR Target, VARIANT_BOOL *out_Success)
1606 FIXME("(%s %s %s %p): stub\n", debugstr_variant(Type), debugstr_w(Message), debugstr_w(Target), out_Success);
1607 return E_NOTIMPL;
1610 static HRESULT WINAPI WshShell3_AppActivate(IWshShell3 *iface, VARIANT *App, VARIANT *Wait, VARIANT_BOOL *out_Success)
1612 FIXME("(%s %s %p): stub\n", debugstr_variant(App), debugstr_variant(Wait), out_Success);
1613 return E_NOTIMPL;
1616 static HRESULT WINAPI WshShell3_SendKeys(IWshShell3 *iface, BSTR Keys, VARIANT *Wait)
1618 FIXME("(%s %p): stub\n", debugstr_w(Keys), Wait);
1619 return E_NOTIMPL;
1622 static HRESULT WINAPI WshShell3_Exec(IWshShell3 *iface, BSTR command, IWshExec **ret)
1624 TRACE("(%s %p)\n", debugstr_w(command), ret);
1626 if (!ret)
1627 return E_POINTER;
1629 if (!command)
1630 return DISP_E_EXCEPTION;
1632 return WshExec_create(command, ret);
1635 static HRESULT WINAPI WshShell3_get_CurrentDirectory(IWshShell3 *iface, BSTR *dir)
1637 DWORD ret;
1639 TRACE("(%p)\n", dir);
1641 ret = GetCurrentDirectoryW(0, NULL);
1642 if (!ret)
1643 return HRESULT_FROM_WIN32(GetLastError());
1645 *dir = SysAllocStringLen(NULL, ret-1);
1646 if (!*dir)
1647 return E_OUTOFMEMORY;
1649 ret = GetCurrentDirectoryW(ret, *dir);
1650 if (!ret) {
1651 SysFreeString(*dir);
1652 *dir = NULL;
1653 return HRESULT_FROM_WIN32(GetLastError());
1656 return S_OK;
1659 static HRESULT WINAPI WshShell3_put_CurrentDirectory(IWshShell3 *iface, BSTR dir)
1661 TRACE("(%s)\n", debugstr_w(dir));
1663 if (!dir)
1664 return E_INVALIDARG;
1666 if (!SetCurrentDirectoryW(dir))
1667 return HRESULT_FROM_WIN32(GetLastError());
1669 return S_OK;
1672 static const IWshShell3Vtbl WshShell3Vtbl = {
1673 WshShell3_QueryInterface,
1674 WshShell3_AddRef,
1675 WshShell3_Release,
1676 WshShell3_GetTypeInfoCount,
1677 WshShell3_GetTypeInfo,
1678 WshShell3_GetIDsOfNames,
1679 WshShell3_Invoke,
1680 WshShell3_get_SpecialFolders,
1681 WshShell3_get_Environment,
1682 WshShell3_Run,
1683 WshShell3_Popup,
1684 WshShell3_CreateShortcut,
1685 WshShell3_ExpandEnvironmentStrings,
1686 WshShell3_RegRead,
1687 WshShell3_RegWrite,
1688 WshShell3_RegDelete,
1689 WshShell3_LogEvent,
1690 WshShell3_AppActivate,
1691 WshShell3_SendKeys,
1692 WshShell3_Exec,
1693 WshShell3_get_CurrentDirectory,
1694 WshShell3_put_CurrentDirectory
1697 HRESULT WINAPI WshShellFactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
1699 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
1701 WshShell3.IWshShell3_iface.lpVtbl = &WshShell3Vtbl;
1702 init_classinfo(&IID_IWshShell3, (IUnknown *)&WshShell3.IWshShell3_iface, &WshShell3.classinfo);
1703 return IWshShell3_QueryInterface(&WshShell3.IWshShell3_iface, riid, ppv);