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"
26 #include "wine/debug.h"
28 extern HRESULT WINAPI
DoOpenPipeStream(HANDLE pipe
, IOMode mode
, ITextStream
**stream
);
30 WINE_DEFAULT_DEBUG_CHANNEL(wshom
);
34 struct provideclassinfo classinfo
;
35 IWshShell3 IWshShell3_iface
;
37 static WshShellImpl WshShell3
;
41 struct provideclassinfo classinfo
;
42 IWshCollection IWshCollection_iface
;
48 struct provideclassinfo classinfo
;
49 IWshShortcut IWshShortcut_iface
;
58 struct provideclassinfo classinfo
;
59 IWshEnvironment IWshEnvironment_iface
;
65 struct provideclassinfo classinfo
;
66 IWshExec IWshExec_iface
;
68 PROCESS_INFORMATION info
;
69 ITextStream
*stdin_stream
;
70 ITextStream
*stdout_stream
;
71 ITextStream
*stderr_stream
;
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
))
106 else if (IsEqualIID(riid
, &IID_IProvideClassInfo
))
108 *obj
= &This
->classinfo
.IProvideClassInfo_iface
;
111 FIXME("Unknown iface %s\n", debugstr_guid(riid
));
113 return E_NOINTERFACE
;
116 IUnknown_AddRef((IUnknown
*)*obj
);
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
);
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
);
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
);
151 static HRESULT WINAPI
WshExec_GetTypeInfoCount(IWshExec
*iface
, UINT
*pctinfo
)
153 WshExecImpl
*This
= impl_from_IWshExec(iface
);
154 TRACE("(%p)->(%p)\n", This
, pctinfo
);
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
)
172 TRACE("%p, %s, %p, %u, %lx, %p.\n", iface
, debugstr_guid(riid
), rgszNames
, cNames
, lcid
, rgDispId
);
174 hr
= get_typeinfo(IWshExec_tid
, &typeinfo
);
177 hr
= ITypeInfo_GetIDsOfNames(typeinfo
, rgszNames
, cNames
, rgDispId
);
178 ITypeInfo_Release(typeinfo
);
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
)
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
);
196 hr
= ITypeInfo_Invoke(typeinfo
, iface
, dispIdMember
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
197 ITypeInfo_Release(typeinfo
);
203 static HRESULT WINAPI
WshExec_get_Status(IWshExec
*iface
, WshExecStatus
*status
)
205 WshExecImpl
*This
= impl_from_IWshExec(iface
);
208 TRACE("(%p)->(%p)\n", This
, status
);
213 if (!GetExitCodeProcess(This
->info
.hProcess
, &code
))
214 return HRESULT_FROM_WIN32(GetLastError());
219 *status
= WshFinished
;
222 *status
= WshRunning
;
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
);
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
);
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
);
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
);
276 *pid
= This
->info
.dwProcessId
;
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
);
289 static BOOL CALLBACK
enum_thread_wnd_proc(HWND hwnd
, LPARAM lParam
)
291 INT
*count
= (INT
*)lParam
;
294 PostMessageW(hwnd
, WM_CLOSE
, 0, 0);
295 /* try to send it to all windows, even if failed for some */
299 static HRESULT WINAPI
WshExec_Terminate(IWshExec
*iface
)
301 WshExecImpl
*This
= impl_from_IWshExec(iface
);
302 BOOL ret
, kill
= FALSE
;
305 TRACE("(%p)\n", This
);
307 ret
= EnumThreadWindows(This
->info
.dwThreadId
, enum_thread_wnd_proc
, (LPARAM
)&count
);
309 /* manual testing shows that it waits 2 seconds before forcing termination */
310 if (WaitForSingleObject(This
->info
.hProcess
, 2000) != WAIT_OBJECT_0
)
317 TerminateProcess(This
->info
.hProcess
, 0);
322 static const IWshExecVtbl WshExecVtbl
= {
323 WshExec_QueryInterface
,
326 WshExec_GetTypeInfoCount
,
328 WshExec_GetIDsOfNames
,
334 WshExec_get_ProcessID
,
335 WshExec_get_ExitCode
,
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());
353 static void close_pipe(HANDLE
*hread
, HANDLE
*hwrite
)
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};
371 if (!(object
= calloc(1, sizeof(*object
))))
372 return E_OUTOFMEMORY
;
374 object
->IWshExec_iface
.lpVtbl
= &WshExecVtbl
;
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");
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");
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");
401 SetHandleInformation(stdin_write
, HANDLE_FLAG_INHERIT
, 0);
402 SetHandleInformation(stdout_read
, HANDLE_FLAG_INHERIT
, 0);
403 SetHandleInformation(stderr_read
, HANDLE_FLAG_INHERIT
, 0);
407 hr
= DoOpenPipeStream(stdin_write
, ForWriting
, &object
->stdin_stream
);
409 hr
= DoOpenPipeStream(stdout_read
, ForReading
, &object
->stdout_stream
);
411 hr
= DoOpenPipeStream(stderr_read
, ForReading
, &object
->stderr_stream
);
414 si
.hStdError
= stderr_write
;
415 si
.hStdOutput
= stdout_write
;
416 si
.hStdInput
= stdin_read
;
417 si
.dwFlags
= STARTF_USESTDHANDLES
;
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
);
431 *ret
= &object
->IWshExec_iface
;
438 IWshExec_Release(&object
->IWshExec_iface
);
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
))
455 else if (IsEqualIID(riid
, &IID_IProvideClassInfo
))
457 *obj
= &This
->classinfo
.IProvideClassInfo_iface
;
460 FIXME("Unknown iface %s\n", debugstr_guid(riid
));
462 return E_NOINTERFACE
;
465 IUnknown_AddRef((IUnknown
*)*obj
);
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
);
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
);
489 static HRESULT WINAPI
WshEnvironment_GetTypeInfoCount(IWshEnvironment
*iface
, UINT
*pctinfo
)
491 WshEnvironment
*This
= impl_from_IWshEnvironment(iface
);
492 TRACE("(%p)->(%p)\n", This
, pctinfo
);
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
)
510 TRACE("%p, %s, %p, %u, %lx, %p.\n", iface
, debugstr_guid(riid
), rgszNames
, cNames
, lcid
, rgDispId
);
512 hr
= get_typeinfo(IWshEnvironment_tid
, &typeinfo
);
515 hr
= ITypeInfo_GetIDsOfNames(typeinfo
, rgszNames
, cNames
, rgDispId
);
516 ITypeInfo_Release(typeinfo
);
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
)
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
);
534 hr
= ITypeInfo_Invoke(typeinfo
, iface
, dispIdMember
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
535 ITypeInfo_Release(typeinfo
);
541 static HRESULT WINAPI
WshEnvironment_get_Item(IWshEnvironment
*iface
, BSTR name
, BSTR
*value
)
543 WshEnvironment
*This
= impl_from_IWshEnvironment(iface
);
546 TRACE("(%p)->(%s %p)\n", This
, debugstr_w(name
), value
);
551 len
= GetEnvironmentVariableW(name
, NULL
, 0);
554 *value
= SysAllocStringLen(NULL
, len
- 1);
556 GetEnvironmentVariableW(name
, *value
, len
);
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
));
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
);
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
);
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
);
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
));
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
;
625 init_classinfo(&IID_IWshEnvironment
, (IUnknown
*)&object
->IWshEnvironment_iface
, &object
->classinfo
);
626 *env
= &object
->IWshEnvironment_iface
;
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
))
643 else if (IsEqualIID(riid
, &IID_IProvideClassInfo
))
645 *ppv
= &This
->classinfo
.IProvideClassInfo_iface
;
648 FIXME("Unknown iface %s\n", debugstr_guid(riid
));
650 return E_NOINTERFACE
;
653 IUnknown_AddRef((IUnknown
*)*ppv
);
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
);
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
);
679 static HRESULT WINAPI
WshCollection_GetTypeInfoCount(IWshCollection
*iface
, UINT
*pctinfo
)
681 WshCollection
*This
= impl_from_IWshCollection(iface
);
682 TRACE("(%p)->(%p)\n", This
, pctinfo
);
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
)
700 TRACE("%p, %s, %p, %u, %lx, %p.\n", iface
, debugstr_guid(riid
), rgszNames
, cNames
, lcid
, rgDispId
);
702 hr
= get_typeinfo(IWshCollection_tid
, &typeinfo
);
705 hr
= ITypeInfo_GetIDsOfNames(typeinfo
, rgszNames
, cNames
, rgDispId
);
706 ITypeInfo_Release(typeinfo
);
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
)
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
);
724 hr
= ITypeInfo_Invoke(typeinfo
, iface
, dispIdMember
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
725 ITypeInfo_Release(typeinfo
);
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
];
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
));
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
;
757 FIXME("folder kind %s not supported\n", debugstr_w(folder
));
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
;
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
);
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
);
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
);
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
,
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
;
823 init_classinfo(&IID_IWshCollection
, (IUnknown
*)&object
->IWshCollection_iface
, &object
->classinfo
);
824 *collection
= &object
->IWshCollection_iface
;
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
))
842 else if (IsEqualIID(riid
, &IID_IProvideClassInfo
))
844 *ppv
= &This
->classinfo
.IProvideClassInfo_iface
;
847 FIXME("Unknown iface %s\n", debugstr_guid(riid
));
849 return E_NOINTERFACE
;
852 IUnknown_AddRef((IUnknown
*)*ppv
);
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
);
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
);
872 IShellLinkW_Release(This
->link
);
873 free(This
->path_link
);
880 static HRESULT WINAPI
WshShortcut_GetTypeInfoCount(IWshShortcut
*iface
, UINT
*pctinfo
)
882 WshShortcut
*This
= impl_from_IWshShortcut(iface
);
883 TRACE("(%p)->(%p)\n", This
, pctinfo
);
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
)
901 TRACE("%p, %s, %p, %u, %lx, %p.\n", iface
, debugstr_guid(riid
), rgszNames
, cNames
, lcid
, rgDispId
);
903 hr
= get_typeinfo(IWshShortcut_tid
, &typeinfo
);
906 hr
= ITypeInfo_GetIDsOfNames(typeinfo
, rgszNames
, cNames
, rgDispId
);
907 ITypeInfo_Release(typeinfo
);
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
)
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
);
925 hr
= ITypeInfo_Invoke(typeinfo
, iface
, dispIdMember
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
926 ITypeInfo_Release(typeinfo
);
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
);
939 static HRESULT WINAPI
WshShortcut_get_Arguments(IWshShortcut
*iface
, BSTR
*Arguments
)
941 WshShortcut
*This
= impl_from_IWshShortcut(iface
);
942 WCHAR buffW
[INFOTIPSIZE
];
945 TRACE("(%p)->(%p)\n", This
, Arguments
);
952 hr
= IShellLinkW_GetArguments(This
->link
, buffW
, ARRAY_SIZE(buffW
));
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
);
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
);
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
));
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
];
1004 TRACE("(%p)->(%p)\n", This
, IconPath
);
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
;
1019 static HRESULT WINAPI
WshShortcut_put_IconLocation(IWshShortcut
*iface
, BSTR IconPath
)
1021 WshShortcut
*This
= impl_from_IWshShortcut(iface
);
1027 TRACE("(%p)->(%s)\n", This
, debugstr_w(IconPath
));
1029 /* scan for icon id */
1030 ptr
= wcsrchr(IconPath
, ',');
1033 WARN("icon index not found\n");
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
);
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
));
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
);
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
];
1092 TRACE("(%p)->(%p)\n", This
, WorkingDirectory
);
1094 if (!WorkingDirectory
)
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
));
1119 static HRESULT WINAPI
WshShortcut_Save(IWshShortcut
*iface
)
1121 WshShortcut
*This
= impl_from_IWshShortcut(iface
);
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
);
1134 static const IWshShortcutVtbl WshShortcutVtbl
= {
1135 WshShortcut_QueryInterface
,
1137 WshShortcut_Release
,
1138 WshShortcut_GetTypeInfoCount
,
1139 WshShortcut_GetTypeInfo
,
1140 WshShortcut_GetIDsOfNames
,
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
,
1162 static HRESULT
WshShortcut_Create(const WCHAR
*path
, IDispatch
**shortcut
)
1164 WshShortcut
*object
;
1169 if (!(object
= calloc(1, sizeof(*object
))))
1170 return E_OUTOFMEMORY
;
1172 object
->IWshShortcut_iface
.lpVtbl
= &WshShortcutVtbl
;
1175 hr
= CoCreateInstance(&CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IShellLinkW
, (void **)&object
->link
);
1182 object
->path_link
= wcsdup(path
);
1183 if (!object
->path_link
)
1185 IShellLinkW_Release(object
->link
);
1187 return E_OUTOFMEMORY
;
1190 init_classinfo(&IID_IWshShortcut
, (IUnknown
*)&object
->IWshShortcut_iface
, &object
->classinfo
);
1191 *shortcut
= (IDispatch
*)&object
->IWshShortcut_iface
;
1196 static HRESULT WINAPI
WshShell3_QueryInterface(IWshShell3
*iface
, REFIID riid
, void **ppv
)
1198 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
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
))
1210 else if (IsEqualGUID(riid
, &IID_IDispatchEx
))
1212 return E_NOINTERFACE
;
1214 else if (IsEqualIID(riid
, &IID_IProvideClassInfo
))
1216 *ppv
= &WshShell3
.classinfo
.IProvideClassInfo_iface
;
1220 WARN("unknown iface %s\n", debugstr_guid(riid
));
1221 return E_NOINTERFACE
;
1224 IUnknown_AddRef((IUnknown
*)*ppv
);
1228 static ULONG WINAPI
WshShell3_AddRef(IWshShell3
*iface
)
1234 static ULONG WINAPI
WshShell3_Release(IWshShell3
*iface
)
1240 static HRESULT WINAPI
WshShell3_GetTypeInfoCount(IWshShell3
*iface
, UINT
*pctinfo
)
1242 TRACE("(%p)\n", pctinfo
);
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
;
1260 TRACE("%s, %p, %u, %lx, %p.\n", debugstr_guid(riid
), rgszNames
, cNames
, lcid
, rgDispId
);
1262 hr
= get_typeinfo(IWshShell3_tid
, &typeinfo
);
1265 hr
= ITypeInfo_GetIDsOfNames(typeinfo
, rgszNames
, cNames
, rgDispId
);
1266 ITypeInfo_Release(typeinfo
);
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
;
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
);
1284 hr
= ITypeInfo_Invoke(typeinfo
, &WshShell3
.IWshShell3_iface
, dispIdMember
, wFlags
,
1285 pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
1286 ITypeInfo_Release(typeinfo
);
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
)
1312 BOOL in_quotes
= FALSE
;
1314 if (!(ret
= malloc((lstrlenW(cmd
) + 1) * sizeof(WCHAR
)))) return NULL
;
1315 lstrcpyW( ret
, cmd
);
1318 for (ptr
= ret
; *ptr
; ptr
++)
1320 if (*ptr
== '"') in_quotes
= !in_quotes
;
1321 else if (*ptr
== ' ' && !in_quotes
)
1332 static HRESULT WINAPI
WshShell3_Run(IWshShell3
*iface
, BSTR cmd
, VARIANT
*style
, VARIANT
*wait
, int *exit_code
)
1334 SHELLEXECUTEINFOW info
;
1335 int waitforprocess
, show
;
1336 WCHAR
*file
, *params
;
1341 TRACE("(%s %s %s %p)\n", debugstr_w(cmd
), debugstr_variant(style
), debugstr_variant(wait
), exit_code
);
1343 if (!style
|| !wait
|| !exit_code
)
1346 if (is_optional_argument(style
))
1347 show
= SW_SHOWNORMAL
;
1350 hr
= VariantChangeType(&v
, style
, 0, VT_I4
);
1357 if (is_optional_argument(wait
))
1361 hr
= VariantChangeType(&v
, wait
, 0, VT_I4
);
1365 waitforprocess
= V_I4(&v
);
1368 if (!(file
= split_command(cmd
, ¶ms
))) return E_OUTOFMEMORY
;
1370 memset(&info
, 0, sizeof(info
));
1371 info
.cbSize
= sizeof(info
);
1372 info
.fMask
= waitforprocess
? SEE_MASK_NOASYNC
| SEE_MASK_NOCLOSEPROCESS
: SEE_MASK_DEFAULT
;
1374 info
.lpParameters
= params
;
1377 ret
= ShellExecuteExW(&info
);
1381 TRACE("ShellExecute failed, %ld\n", GetLastError());
1382 return HRESULT_FROM_WIN32(GetLastError());
1389 WaitForSingleObject(info
.hProcess
, INFINITE
);
1390 GetExitCodeProcess(info
.hProcess
, &code
);
1391 CloseHandle(info
.hProcess
);
1401 struct popup_thread_param
1409 static DWORD WINAPI
popup_thread_proc(void *arg
)
1411 struct popup_thread_param
*param
= (struct popup_thread_param
*)arg
;
1413 param
->button
= MessageBoxW(NULL
, param
->text
, is_optional_argument(¶m
->title
) ?
1414 L
"Windows Script Host" : V_BSTR(¶m
->title
), V_I4(¶m
->type
));
1418 static HRESULT WINAPI
WshShell3_Popup(IWshShell3
*iface
, BSTR text
, VARIANT
*seconds_to_wait
, VARIANT
*title
,
1419 VARIANT
*type
, int *button
)
1421 struct popup_thread_param param
;
1427 TRACE("(%s %s %s %s %p)\n", debugstr_w(text
), debugstr_variant(seconds_to_wait
), debugstr_variant(title
),
1428 debugstr_variant(type
), button
);
1430 if (!seconds_to_wait
|| !title
|| !type
|| !button
)
1433 VariantInit(&timeout
);
1434 if (!is_optional_argument(seconds_to_wait
))
1436 hr
= VariantChangeType(&timeout
, seconds_to_wait
, 0, VT_I4
);
1441 VariantInit(¶m
.type
);
1442 if (!is_optional_argument(type
))
1444 hr
= VariantChangeType(¶m
.type
, type
, 0, VT_I4
);
1449 if (is_optional_argument(title
))
1450 param
.title
= *title
;
1453 VariantInit(¶m
.title
);
1454 hr
= VariantChangeType(¶m
.title
, title
, 0, VT_BSTR
);
1461 hthread
= CreateThread(NULL
, 0, popup_thread_proc
, ¶m
, 0, &tid
);
1462 status
= MsgWaitForMultipleObjects(1, &hthread
, FALSE
, V_I4(&timeout
) ? V_I4(&timeout
) * 1000: INFINITE
, 0);
1463 if (status
== WAIT_TIMEOUT
)
1465 PostThreadMessageW(tid
, WM_QUIT
, 0, 0);
1466 MsgWaitForMultipleObjects(1, &hthread
, FALSE
, INFINITE
, 0);
1469 *button
= param
.button
;
1471 VariantClear(¶m
.title
);
1472 CloseHandle(hthread
);
1477 static HRESULT WINAPI
WshShell3_CreateShortcut(IWshShell3
*iface
, BSTR PathLink
, IDispatch
** Shortcut
)
1479 TRACE("(%s %p)\n", debugstr_w(PathLink
), Shortcut
);
1480 return WshShortcut_Create(PathLink
, Shortcut
);
1483 static HRESULT WINAPI
WshShell3_ExpandEnvironmentStrings(IWshShell3
*iface
, BSTR Src
, BSTR
* Dst
)
1487 TRACE("(%s %p)\n", debugstr_w(Src
), Dst
);
1489 if (!Src
|| !Dst
) return E_POINTER
;
1491 ret
= ExpandEnvironmentStringsW(Src
, NULL
, 0);
1492 *Dst
= SysAllocStringLen(NULL
, ret
);
1493 if (!*Dst
) return E_OUTOFMEMORY
;
1495 if (ExpandEnvironmentStringsW(Src
, *Dst
, ret
))
1499 SysFreeString(*Dst
);
1501 return HRESULT_FROM_WIN32(GetLastError());
1505 static HKEY
get_root_key(const WCHAR
*path
)
1507 static const struct {
1508 const WCHAR full
[20];
1509 const WCHAR abbrev
[5];
1512 { L
"HKEY_CURRENT_USER", L
"HKCU", HKEY_CURRENT_USER
},
1513 { L
"HKEY_LOCAL_MACHINE", L
"HKLM", HKEY_LOCAL_MACHINE
},
1514 { L
"HKEY_CLASSES_ROOT", L
"HKCR", HKEY_CLASSES_ROOT
},
1515 { L
"HKEY_USERS", {0}, HKEY_USERS
},
1516 { L
"HKEY_CURRENT_CONFIG", {0}, HKEY_CURRENT_CONFIG
}
1520 for (i
= 0; i
< ARRAY_SIZE(rootkeys
); i
++) {
1521 if (!wcsncmp(path
, rootkeys
[i
].full
, lstrlenW(rootkeys
[i
].full
)))
1522 return rootkeys
[i
].hkey
;
1523 if (rootkeys
[i
].abbrev
[0] && !wcsncmp(path
, rootkeys
[i
].abbrev
, lstrlenW(rootkeys
[i
].abbrev
)))
1524 return rootkeys
[i
].hkey
;
1530 /* Caller is responsible to free 'subkey' if 'value' is not NULL */
1531 static HRESULT
split_reg_path(const WCHAR
*path
, WCHAR
**subkey
, WCHAR
**value
)
1535 /* at least one separator should be present */
1536 *subkey
= wcschr(path
, '\\');
1538 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND
);
1540 /* default value or not */
1541 if ((*subkey
)[lstrlenW(*subkey
)-1] == '\\') {
1546 *value
= wcsrchr(*subkey
, '\\');
1547 if (*value
- *subkey
> 1) {
1548 unsigned int len
= *value
- *subkey
- 1;
1551 ret
= malloc((len
+ 1)*sizeof(WCHAR
));
1553 return E_OUTOFMEMORY
;
1555 memcpy(ret
, *subkey
+ 1, len
*sizeof(WCHAR
));
1565 static HRESULT WINAPI
WshShell3_RegRead(IWshShell3
*iface
, BSTR name
, VARIANT
*value
)
1567 DWORD type
, datalen
, ret
;
1568 WCHAR
*subkey
, *val
;
1572 TRACE("(%s %p)\n", debugstr_w(name
), value
);
1574 if (!name
|| !value
)
1577 root
= get_root_key(name
);
1579 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND
);
1581 hr
= split_reg_path(name
, &subkey
, &val
);
1587 ret
= RegGetValueW(root
, subkey
, val
, RRF_RT_ANY
, &type
, NULL
, &datalen
);
1588 if (ret
== ERROR_SUCCESS
) {
1591 data
= malloc(datalen
);
1597 ret
= RegGetValueW(root
, subkey
, val
, RRF_RT_ANY
, &type
, data
, &datalen
);
1600 hr
= HRESULT_FROM_WIN32(ret
);
1607 V_VT(value
) = VT_BSTR
;
1608 V_BSTR(value
) = SysAllocString((WCHAR
*)data
);
1613 V_VT(value
) = VT_I4
;
1614 V_I4(value
) = *(DWORD
*)data
;
1618 BYTE
*ptr
= (BYTE
*)data
;
1619 SAFEARRAYBOUND bound
;
1625 bound
.cElements
= datalen
;
1626 sa
= SafeArrayCreate(VT_VARIANT
, 1, &bound
);
1630 hr
= SafeArrayAccessData(sa
, (void**)&v
);
1632 SafeArrayDestroy(sa
);
1636 for (i
= 0; i
< datalen
; i
++) {
1637 V_VT(&v
[i
]) = VT_UI1
;
1638 V_UI1(&v
[i
]) = ptr
[i
];
1640 SafeArrayUnaccessData(sa
);
1642 V_VT(value
) = VT_ARRAY
|VT_VARIANT
;
1643 V_ARRAY(value
) = sa
;
1648 WCHAR
*ptr
= (WCHAR
*)data
;
1649 SAFEARRAYBOUND bound
;
1653 /* get element count first */
1655 bound
.cElements
= 0;
1658 ptr
+= lstrlenW(ptr
)+1;
1661 sa
= SafeArrayCreate(VT_VARIANT
, 1, &bound
);
1665 hr
= SafeArrayAccessData(sa
, (void**)&v
);
1667 SafeArrayDestroy(sa
);
1674 V_BSTR(v
) = SysAllocString(ptr
);
1675 ptr
+= lstrlenW(ptr
)+1;
1679 SafeArrayUnaccessData(sa
);
1680 V_VT(value
) = VT_ARRAY
|VT_VARIANT
;
1681 V_ARRAY(value
) = sa
;
1685 FIXME("value type %ld not supported\n", type
);
1694 hr
= HRESULT_FROM_WIN32(ret
);
1702 static HRESULT WINAPI
WshShell3_RegWrite(IWshShell3
*iface
, BSTR name
, VARIANT
*value
, VARIANT
*type
)
1704 DWORD regtype
, data_len
;
1705 WCHAR
*subkey
, *val
;
1712 TRACE("(%s %s %s)\n", debugstr_w(name
), debugstr_variant(value
), debugstr_variant(type
));
1714 if (!name
|| !value
|| !type
)
1717 root
= get_root_key(name
);
1719 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND
);
1722 if (is_optional_argument(type
))
1725 if (V_VT(type
) != VT_BSTR
)
1726 return E_INVALIDARG
;
1728 if (!wcscmp(V_BSTR(type
), L
"REG_SZ"))
1730 else if (!wcscmp(V_BSTR(type
), L
"REG_DWORD"))
1731 regtype
= REG_DWORD
;
1732 else if (!wcscmp(V_BSTR(type
), L
"REG_EXPAND_SZ"))
1733 regtype
= REG_EXPAND_SZ
;
1734 else if (!wcscmp(V_BSTR(type
), L
"REG_BINARY"))
1735 regtype
= REG_BINARY
;
1737 FIXME("unrecognized value type %s\n", debugstr_w(V_BSTR(type
)));
1742 /* it's always a string or a DWORD */
1748 hr
= VariantChangeType(&v
, value
, 0, VT_BSTR
);
1750 data
= (BYTE
*)V_BSTR(&v
);
1751 data_len
= SysStringByteLen(V_BSTR(&v
)) + sizeof(WCHAR
);
1756 hr
= VariantChangeType(&v
, value
, 0, VT_I4
);
1757 data
= (BYTE
*)&V_I4(&v
);
1758 data_len
= sizeof(DWORD
);
1761 FIXME("unexpected regtype %ld\n", regtype
);
1766 FIXME("failed to convert value, regtype %ld, %#lx.\n", regtype
, hr
);
1770 hr
= split_reg_path(name
, &subkey
, &val
);
1774 ret
= RegSetKeyValueW(root
, subkey
, val
, regtype
, data
, data_len
);
1776 hr
= HRESULT_FROM_WIN32(ret
);
1785 static HRESULT WINAPI
WshShell3_RegDelete(IWshShell3
*iface
, BSTR Name
)
1787 FIXME("(%s): stub\n", debugstr_w(Name
));
1791 static HRESULT WINAPI
WshShell3_LogEvent(IWshShell3
*iface
, VARIANT
*Type
, BSTR Message
, BSTR Target
, VARIANT_BOOL
*out_Success
)
1793 FIXME("(%s %s %s %p): stub\n", debugstr_variant(Type
), debugstr_w(Message
), debugstr_w(Target
), out_Success
);
1797 static HRESULT WINAPI
WshShell3_AppActivate(IWshShell3
*iface
, VARIANT
*App
, VARIANT
*Wait
, VARIANT_BOOL
*out_Success
)
1799 FIXME("(%s %s %p): stub\n", debugstr_variant(App
), debugstr_variant(Wait
), out_Success
);
1803 static HRESULT WINAPI
WshShell3_SendKeys(IWshShell3
*iface
, BSTR Keys
, VARIANT
*Wait
)
1805 FIXME("(%s %p): stub\n", debugstr_w(Keys
), Wait
);
1809 static HRESULT WINAPI
WshShell3_Exec(IWshShell3
*iface
, BSTR command
, IWshExec
**ret
)
1814 TRACE("(%s %p)\n", debugstr_w(command
), ret
);
1820 return DISP_E_EXCEPTION
;
1822 hr
= WshShell3_ExpandEnvironmentStrings(iface
, command
, &expandedcmd
);
1826 hr
= WshExec_create(expandedcmd
, ret
);
1827 SysFreeString(expandedcmd
);
1831 static HRESULT WINAPI
WshShell3_get_CurrentDirectory(IWshShell3
*iface
, BSTR
*dir
)
1835 TRACE("(%p)\n", dir
);
1837 ret
= GetCurrentDirectoryW(0, NULL
);
1839 return HRESULT_FROM_WIN32(GetLastError());
1841 *dir
= SysAllocStringLen(NULL
, ret
-1);
1843 return E_OUTOFMEMORY
;
1845 ret
= GetCurrentDirectoryW(ret
, *dir
);
1847 SysFreeString(*dir
);
1849 return HRESULT_FROM_WIN32(GetLastError());
1855 static HRESULT WINAPI
WshShell3_put_CurrentDirectory(IWshShell3
*iface
, BSTR dir
)
1857 TRACE("(%s)\n", debugstr_w(dir
));
1860 return E_INVALIDARG
;
1862 if (!SetCurrentDirectoryW(dir
))
1863 return HRESULT_FROM_WIN32(GetLastError());
1868 static const IWshShell3Vtbl WshShell3Vtbl
= {
1869 WshShell3_QueryInterface
,
1872 WshShell3_GetTypeInfoCount
,
1873 WshShell3_GetTypeInfo
,
1874 WshShell3_GetIDsOfNames
,
1876 WshShell3_get_SpecialFolders
,
1877 WshShell3_get_Environment
,
1880 WshShell3_CreateShortcut
,
1881 WshShell3_ExpandEnvironmentStrings
,
1884 WshShell3_RegDelete
,
1886 WshShell3_AppActivate
,
1889 WshShell3_get_CurrentDirectory
,
1890 WshShell3_put_CurrentDirectory
1893 HRESULT WINAPI
WshShellFactory_CreateInstance(IClassFactory
*iface
, IUnknown
*outer
, REFIID riid
, void **ppv
)
1895 TRACE("(%p %s %p)\n", outer
, debugstr_guid(riid
), ppv
);
1897 WshShell3
.IWshShell3_iface
.lpVtbl
= &WshShell3Vtbl
;
1898 init_classinfo(&IID_IWshShell3
, (IUnknown
*)&WshShell3
.IWshShell3_iface
, &WshShell3
.classinfo
);
1899 return IWshShell3_QueryInterface(&WshShell3
.IWshShell3_iface
, riid
, ppv
);