| /* |
| * Copyright 2011 Jacek Caban for CodeWeavers |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #include "wshom_private.h" |
| #include "wshom.h" |
| |
| #include "shellapi.h" |
| #include "shlobj.h" |
| #include "dispex.h" |
| |
| #include "wine/debug.h" |
| #include "wine/unicode.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(wshom); |
| |
| typedef struct |
| { |
| struct provideclassinfo classinfo; |
| IWshShell3 IWshShell3_iface; |
| } WshShellImpl; |
| static WshShellImpl WshShell3; |
| |
| typedef struct |
| { |
| struct provideclassinfo classinfo; |
| IWshCollection IWshCollection_iface; |
| LONG ref; |
| } WshCollection; |
| |
| typedef struct |
| { |
| struct provideclassinfo classinfo; |
| IWshShortcut IWshShortcut_iface; |
| LONG ref; |
| |
| IShellLinkW *link; |
| BSTR path_link; |
| } WshShortcut; |
| |
| typedef struct |
| { |
| struct provideclassinfo classinfo; |
| IWshEnvironment IWshEnvironment_iface; |
| LONG ref; |
| } WshEnvironment; |
| |
| typedef struct |
| { |
| struct provideclassinfo classinfo; |
| IWshExec IWshExec_iface; |
| LONG ref; |
| PROCESS_INFORMATION info; |
| } WshExecImpl; |
| |
| static inline WshCollection *impl_from_IWshCollection( IWshCollection *iface ) |
| { |
| return CONTAINING_RECORD(iface, WshCollection, IWshCollection_iface); |
| } |
| |
| static inline WshShortcut *impl_from_IWshShortcut( IWshShortcut *iface ) |
| { |
| return CONTAINING_RECORD(iface, WshShortcut, IWshShortcut_iface); |
| } |
| |
| static inline WshEnvironment *impl_from_IWshEnvironment( IWshEnvironment *iface ) |
| { |
| return CONTAINING_RECORD(iface, WshEnvironment, IWshEnvironment_iface); |
| } |
| |
| static inline WshExecImpl *impl_from_IWshExec( IWshExec *iface ) |
| { |
| return CONTAINING_RECORD(iface, WshExecImpl, IWshExec_iface); |
| } |
| |
| static HRESULT WINAPI WshExec_QueryInterface(IWshExec *iface, REFIID riid, void **obj) |
| { |
| WshExecImpl *This = impl_from_IWshExec(iface); |
| |
| TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), obj); |
| |
| if (IsEqualGUID(riid, &IID_IDispatch) || |
| IsEqualGUID(riid, &IID_IWshExec) || |
| IsEqualGUID(riid, &IID_IUnknown)) |
| { |
| *obj = iface; |
| } |
| else if (IsEqualIID(riid, &IID_IProvideClassInfo)) |
| { |
| *obj = &This->classinfo.IProvideClassInfo_iface; |
| } |
| else { |
| FIXME("Unknown iface %s\n", debugstr_guid(riid)); |
| *obj = NULL; |
| return E_NOINTERFACE; |
| } |
| |
| IUnknown_AddRef((IUnknown *)*obj); |
| return S_OK; |
| } |
| |
| static ULONG WINAPI WshExec_AddRef(IWshExec *iface) |
| { |
| WshExecImpl *This = impl_from_IWshExec(iface); |
| LONG ref = InterlockedIncrement(&This->ref); |
| TRACE("(%p) ref = %d\n", This, ref); |
| return ref; |
| } |
| |
| static ULONG WINAPI WshExec_Release(IWshExec *iface) |
| { |
| WshExecImpl *This = impl_from_IWshExec(iface); |
| LONG ref = InterlockedDecrement(&This->ref); |
| TRACE("(%p) ref = %d\n", This, ref); |
| |
| if (!ref) { |
| CloseHandle(This->info.hThread); |
| CloseHandle(This->info.hProcess); |
| HeapFree(GetProcessHeap(), 0, This); |
| } |
| |
| return ref; |
| } |
| |
| static HRESULT WINAPI WshExec_GetTypeInfoCount(IWshExec *iface, UINT *pctinfo) |
| { |
| WshExecImpl *This = impl_from_IWshExec(iface); |
| TRACE("(%p)->(%p)\n", This, pctinfo); |
| *pctinfo = 1; |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI WshExec_GetTypeInfo(IWshExec *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) |
| { |
| WshExecImpl *This = impl_from_IWshExec(iface); |
| TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo); |
| return get_typeinfo(IWshExec_tid, ppTInfo); |
| } |
| |
| static HRESULT WINAPI WshExec_GetIDsOfNames(IWshExec *iface, REFIID riid, LPOLESTR *rgszNames, |
| UINT cNames, LCID lcid, DISPID *rgDispId) |
| { |
| WshExecImpl *This = impl_from_IWshExec(iface); |
| ITypeInfo *typeinfo; |
| HRESULT hr; |
| |
| TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId); |
| |
| hr = get_typeinfo(IWshExec_tid, &typeinfo); |
| if(SUCCEEDED(hr)) |
| { |
| hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId); |
| ITypeInfo_Release(typeinfo); |
| } |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI WshExec_Invoke(IWshExec *iface, DISPID dispIdMember, REFIID riid, LCID lcid, |
| WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) |
| { |
| WshExecImpl *This = impl_from_IWshExec(iface); |
| ITypeInfo *typeinfo; |
| HRESULT hr; |
| |
| TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid), |
| lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); |
| |
| hr = get_typeinfo(IWshExec_tid, &typeinfo); |
| if(SUCCEEDED(hr)) |
| { |
| hr = ITypeInfo_Invoke(typeinfo, &This->IWshExec_iface, dispIdMember, wFlags, |
| pDispParams, pVarResult, pExcepInfo, puArgErr); |
| ITypeInfo_Release(typeinfo); |
| } |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI WshExec_get_Status(IWshExec *iface, WshExecStatus *status) |
| { |
| WshExecImpl *This = impl_from_IWshExec(iface); |
| DWORD code; |
| |
| TRACE("(%p)->(%p)\n", This, status); |
| |
| if (!status) |
| return E_INVALIDARG; |
| |
| if (!GetExitCodeProcess(This->info.hProcess, &code)) |
| return HRESULT_FROM_WIN32(GetLastError()); |
| |
| switch (code) |
| { |
| case 0: |
| *status = WshFinished; |
| break; |
| case STILL_ACTIVE: |
| *status = WshRunning; |
| break; |
| default: |
| *status = WshFailed; |
| } |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI WshExec_get_StdIn(IWshExec *iface, ITextStream **stream) |
| { |
| WshExecImpl *This = impl_from_IWshExec(iface); |
| |
| FIXME("(%p)->(%p): stub\n", This, stream); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI WshExec_get_StdOut(IWshExec *iface, ITextStream **stream) |
| { |
| WshExecImpl *This = impl_from_IWshExec(iface); |
| |
| FIXME("(%p)->(%p): stub\n", This, stream); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI WshExec_get_StdErr(IWshExec *iface, ITextStream **stream) |
| { |
| WshExecImpl *This = impl_from_IWshExec(iface); |
| |
| FIXME("(%p)->(%p): stub\n", This, stream); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI WshExec_get_ProcessID(IWshExec *iface, DWORD *pid) |
| { |
| WshExecImpl *This = impl_from_IWshExec(iface); |
| |
| TRACE("(%p)->(%p)\n", This, pid); |
| |
| if (!pid) |
| return E_INVALIDARG; |
| |
| *pid = This->info.dwProcessId; |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI WshExec_get_ExitCode(IWshExec *iface, DWORD *code) |
| { |
| WshExecImpl *This = impl_from_IWshExec(iface); |
| |
| FIXME("(%p)->(%p): stub\n", This, code); |
| |
| return E_NOTIMPL; |
| } |
| |
| static BOOL CALLBACK enum_thread_wnd_proc(HWND hwnd, LPARAM lParam) |
| { |
| INT *count = (INT*)lParam; |
| |
| (*count)++; |
| PostMessageW(hwnd, WM_CLOSE, 0, 0); |
| /* try to send it to all windows, even if failed for some */ |
| return TRUE; |
| } |
| |
| static HRESULT WINAPI WshExec_Terminate(IWshExec *iface) |
| { |
| WshExecImpl *This = impl_from_IWshExec(iface); |
| BOOL ret, kill = FALSE; |
| INT count = 0; |
| |
| TRACE("(%p)\n", This); |
| |
| ret = EnumThreadWindows(This->info.dwThreadId, enum_thread_wnd_proc, (LPARAM)&count); |
| if (ret && count) { |
| /* manual testing shows that it waits 2 seconds before forcing termination */ |
| if (WaitForSingleObject(This->info.hProcess, 2000) != WAIT_OBJECT_0) |
| kill = TRUE; |
| } |
| else |
| kill = TRUE; |
| |
| if (kill) |
| TerminateProcess(This->info.hProcess, 0); |
| |
| return S_OK; |
| } |
| |
| static const IWshExecVtbl WshExecVtbl = { |
| WshExec_QueryInterface, |
| WshExec_AddRef, |
| WshExec_Release, |
| WshExec_GetTypeInfoCount, |
| WshExec_GetTypeInfo, |
| WshExec_GetIDsOfNames, |
| WshExec_Invoke, |
| WshExec_get_Status, |
| WshExec_get_StdIn, |
| WshExec_get_StdOut, |
| WshExec_get_StdErr, |
| WshExec_get_ProcessID, |
| WshExec_get_ExitCode, |
| WshExec_Terminate |
| }; |
| |
| static HRESULT WshExec_create(BSTR command, IWshExec **ret) |
| { |
| STARTUPINFOW si = {0}; |
| WshExecImpl *This; |
| |
| *ret = NULL; |
| |
| This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); |
| if (!This) |
| return E_OUTOFMEMORY; |
| |
| This->IWshExec_iface.lpVtbl = &WshExecVtbl; |
| This->ref = 1; |
| |
| if (!CreateProcessW(NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &This->info)) { |
| HeapFree(GetProcessHeap(), 0, This); |
| return HRESULT_FROM_WIN32(GetLastError()); |
| } |
| |
| init_classinfo(&CLSID_WshExec, (IUnknown *)&This->IWshExec_iface, &This->classinfo); |
| *ret = &This->IWshExec_iface; |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI WshEnvironment_QueryInterface(IWshEnvironment *iface, REFIID riid, void **obj) |
| { |
| WshEnvironment *This = impl_from_IWshEnvironment(iface); |
| |
| TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), obj); |
| |
| if (IsEqualGUID(riid, &IID_IUnknown) || |
| IsEqualGUID(riid, &IID_IDispatch) || |
| IsEqualGUID(riid, &IID_IWshEnvironment)) |
| { |
| *obj = iface; |
| } |
| else if (IsEqualIID(riid, &IID_IProvideClassInfo)) |
| { |
| *obj = &This->classinfo.IProvideClassInfo_iface; |
| } |
| else { |
| FIXME("Unknown iface %s\n", debugstr_guid(riid)); |
| *obj = NULL; |
| return E_NOINTERFACE; |
| } |
| |
| IUnknown_AddRef((IUnknown*)*obj); |
| return S_OK; |
| } |
| |
| static ULONG WINAPI WshEnvironment_AddRef(IWshEnvironment *iface) |
| { |
| WshEnvironment *This = impl_from_IWshEnvironment(iface); |
| LONG ref = InterlockedIncrement(&This->ref); |
| TRACE("(%p) ref = %d\n", This, ref); |
| return ref; |
| } |
| |
| static ULONG WINAPI WshEnvironment_Release(IWshEnvironment *iface) |
| { |
| WshEnvironment *This = impl_from_IWshEnvironment(iface); |
| LONG ref = InterlockedDecrement(&This->ref); |
| TRACE("(%p) ref = %d\n", This, ref); |
| |
| if (!ref) |
| HeapFree(GetProcessHeap(), 0, This); |
| |
| return ref; |
| } |
| |
| static HRESULT WINAPI WshEnvironment_GetTypeInfoCount(IWshEnvironment *iface, UINT *pctinfo) |
| { |
| WshEnvironment *This = impl_from_IWshEnvironment(iface); |
| TRACE("(%p)->(%p)\n", This, pctinfo); |
| *pctinfo = 1; |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI WshEnvironment_GetTypeInfo(IWshEnvironment *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) |
| { |
| WshEnvironment *This = impl_from_IWshEnvironment(iface); |
| TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo); |
| return get_typeinfo(IWshEnvironment_tid, ppTInfo); |
| } |
| |
| static HRESULT WINAPI WshEnvironment_GetIDsOfNames(IWshEnvironment *iface, REFIID riid, LPOLESTR *rgszNames, |
| UINT cNames, LCID lcid, DISPID *rgDispId) |
| { |
| WshEnvironment *This = impl_from_IWshEnvironment(iface); |
| ITypeInfo *typeinfo; |
| HRESULT hr; |
| |
| TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId); |
| |
| hr = get_typeinfo(IWshEnvironment_tid, &typeinfo); |
| if(SUCCEEDED(hr)) |
| { |
| hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId); |
| ITypeInfo_Release(typeinfo); |
| } |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI WshEnvironment_Invoke(IWshEnvironment *iface, DISPID dispIdMember, REFIID riid, LCID lcid, |
| WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) |
| { |
| WshEnvironment *This = impl_from_IWshEnvironment(iface); |
| ITypeInfo *typeinfo; |
| HRESULT hr; |
| |
| TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid), |
| lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); |
| |
| hr = get_typeinfo(IWshEnvironment_tid, &typeinfo); |
| if(SUCCEEDED(hr)) |
| { |
| hr = ITypeInfo_Invoke(typeinfo, &This->IWshEnvironment_iface, dispIdMember, wFlags, |
| pDispParams, pVarResult, pExcepInfo, puArgErr); |
| ITypeInfo_Release(typeinfo); |
| } |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI WshEnvironment_get_Item(IWshEnvironment *iface, BSTR name, BSTR *value) |
| { |
| WshEnvironment *This = impl_from_IWshEnvironment(iface); |
| DWORD len; |
| |
| TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), value); |
| |
| if (!value) |
| return E_POINTER; |
| |
| len = GetEnvironmentVariableW(name, NULL, 0); |
| *value = SysAllocStringLen(NULL, len); |
| if (!*value) |
| return E_OUTOFMEMORY; |
| |
| if (len) |
| GetEnvironmentVariableW(name, *value, len+1); |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI WshEnvironment_put_Item(IWshEnvironment *iface, BSTR name, BSTR value) |
| { |
| WshEnvironment *This = impl_from_IWshEnvironment(iface); |
| FIXME("(%p)->(%s %s): stub\n", This, debugstr_w(name), debugstr_w(value)); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI WshEnvironment_Count(IWshEnvironment *iface, LONG *count) |
| { |
| WshEnvironment *This = impl_from_IWshEnvironment(iface); |
| FIXME("(%p)->(%p): stub\n", This, count); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI WshEnvironment_get_length(IWshEnvironment *iface, LONG *len) |
| { |
| WshEnvironment *This = impl_from_IWshEnvironment(iface); |
| FIXME("(%p)->(%p): stub\n", This, len); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI WshEnvironment__NewEnum(IWshEnvironment *iface, IUnknown **penum) |
| { |
| WshEnvironment *This = impl_from_IWshEnvironment(iface); |
| FIXME("(%p)->(%p): stub\n", This, penum); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI WshEnvironment_Remove(IWshEnvironment *iface, BSTR name) |
| { |
| WshEnvironment *This = impl_from_IWshEnvironment(iface); |
| FIXME("(%p)->(%s): stub\n", This, debugstr_w(name)); |
| return E_NOTIMPL; |
| } |
| |
| static const IWshEnvironmentVtbl WshEnvironmentVtbl = { |
| WshEnvironment_QueryInterface, |
| WshEnvironment_AddRef, |
| WshEnvironment_Release, |
| WshEnvironment_GetTypeInfoCount, |
| WshEnvironment_GetTypeInfo, |
| WshEnvironment_GetIDsOfNames, |
| WshEnvironment_Invoke, |
| WshEnvironment_get_Item, |
| WshEnvironment_put_Item, |
| WshEnvironment_Count, |
| WshEnvironment_get_length, |
| WshEnvironment__NewEnum, |
| WshEnvironment_Remove |
| }; |
| |
| static HRESULT WshEnvironment_Create(IWshEnvironment **env) |
| { |
| WshEnvironment *This; |
| |
| This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); |
| if (!This) return E_OUTOFMEMORY; |
| |
| This->IWshEnvironment_iface.lpVtbl = &WshEnvironmentVtbl; |
| This->ref = 1; |
| |
| init_classinfo(&IID_IWshEnvironment, (IUnknown *)&This->IWshEnvironment_iface, &This->classinfo); |
| *env = &This->IWshEnvironment_iface; |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI WshCollection_QueryInterface(IWshCollection *iface, REFIID riid, void **ppv) |
| { |
| WshCollection *This = impl_from_IWshCollection(iface); |
| |
| TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv); |
| |
| if (IsEqualGUID(riid, &IID_IUnknown) || |
| IsEqualGUID(riid, &IID_IDispatch) || |
| IsEqualGUID(riid, &IID_IWshCollection)) |
| { |
| *ppv = iface; |
| } |
| else if (IsEqualIID(riid, &IID_IProvideClassInfo)) |
| { |
| *ppv = &This->classinfo.IProvideClassInfo_iface; |
| } |
| else { |
| FIXME("Unknown iface %s\n", debugstr_guid(riid)); |
| *ppv = NULL; |
| return E_NOINTERFACE; |
| } |
| |
| IUnknown_AddRef((IUnknown*)*ppv); |
| return S_OK; |
| } |
| |
| static ULONG WINAPI WshCollection_AddRef(IWshCollection *iface) |
| { |
| WshCollection *This = impl_from_IWshCollection(iface); |
| LONG ref = InterlockedIncrement(&This->ref); |
| TRACE("(%p) ref = %d\n", This, ref); |
| return ref; |
| } |
| |
| static ULONG WINAPI WshCollection_Release(IWshCollection *iface) |
| { |
| WshCollection *This = impl_from_IWshCollection(iface); |
| LONG ref = InterlockedDecrement(&This->ref); |
| TRACE("(%p) ref = %d\n", This, ref); |
| |
| if (!ref) |
| HeapFree(GetProcessHeap(), 0, This); |
| |
| return ref; |
| } |
| |
| static HRESULT WINAPI WshCollection_GetTypeInfoCount(IWshCollection *iface, UINT *pctinfo) |
| { |
| WshCollection *This = impl_from_IWshCollection(iface); |
| TRACE("(%p)->(%p)\n", This, pctinfo); |
| *pctinfo = 1; |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI WshCollection_GetTypeInfo(IWshCollection *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) |
| { |
| WshCollection *This = impl_from_IWshCollection(iface); |
| TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo); |
| return get_typeinfo(IWshCollection_tid, ppTInfo); |
| } |
| |
| static HRESULT WINAPI WshCollection_GetIDsOfNames(IWshCollection *iface, REFIID riid, LPOLESTR *rgszNames, |
| UINT cNames, LCID lcid, DISPID *rgDispId) |
| { |
| WshCollection *This = impl_from_IWshCollection(iface); |
| ITypeInfo *typeinfo; |
| HRESULT hr; |
| |
| TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId); |
| |
| hr = get_typeinfo(IWshCollection_tid, &typeinfo); |
| if(SUCCEEDED(hr)) |
| { |
| hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId); |
| ITypeInfo_Release(typeinfo); |
| } |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI WshCollection_Invoke(IWshCollection *iface, DISPID dispIdMember, REFIID riid, LCID lcid, |
| WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) |
| { |
| WshCollection *This = impl_from_IWshCollection(iface); |
| ITypeInfo *typeinfo; |
| HRESULT hr; |
| |
| TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid), |
| lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); |
| |
| hr = get_typeinfo(IWshCollection_tid, &typeinfo); |
| if(SUCCEEDED(hr)) |
| { |
| hr = ITypeInfo_Invoke(typeinfo, &This->IWshCollection_iface, dispIdMember, wFlags, |
| pDispParams, pVarResult, pExcepInfo, puArgErr); |
| ITypeInfo_Release(typeinfo); |
| } |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI WshCollection_Item(IWshCollection *iface, VARIANT *index, VARIANT *value) |
| { |
| WshCollection *This = impl_from_IWshCollection(iface); |
| static const WCHAR allusersdesktopW[] = {'A','l','l','U','s','e','r','s','D','e','s','k','t','o','p',0}; |
| static const WCHAR allusersprogramsW[] = {'A','l','l','U','s','e','r','s','P','r','o','g','r','a','m','s',0}; |
| static const WCHAR desktopW[] = {'D','e','s','k','t','o','p',0}; |
| PIDLIST_ABSOLUTE pidl; |
| WCHAR pathW[MAX_PATH]; |
| int kind = 0; |
| BSTR folder; |
| HRESULT hr; |
| |
| TRACE("(%p)->(%s %p)\n", This, debugstr_variant(index), value); |
| |
| if (V_VT(index) != VT_BSTR) |
| { |
| FIXME("only BSTR index supported, got %d\n", V_VT(index)); |
| return E_NOTIMPL; |
| } |
| |
| folder = V_BSTR(index); |
| if (!strcmpiW(folder, desktopW)) |
| kind = CSIDL_DESKTOP; |
| else if (!strcmpiW(folder, allusersdesktopW)) |
| kind = CSIDL_COMMON_DESKTOPDIRECTORY; |
| else if (!strcmpiW(folder, allusersprogramsW)) |
| kind = CSIDL_COMMON_PROGRAMS; |
| else |
| { |
| FIXME("folder kind %s not supported\n", debugstr_w(folder)); |
| return E_NOTIMPL; |
| } |
| |
| hr = SHGetSpecialFolderLocation(NULL, kind, &pidl); |
| if (hr != S_OK) return hr; |
| |
| if (SHGetPathFromIDListW(pidl, pathW)) |
| { |
| V_VT(value) = VT_BSTR; |
| V_BSTR(value) = SysAllocString(pathW); |
| hr = V_BSTR(value) ? S_OK : E_OUTOFMEMORY; |
| } |
| else |
| hr = E_FAIL; |
| |
| CoTaskMemFree(pidl); |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI WshCollection_Count(IWshCollection *iface, LONG *count) |
| { |
| WshCollection *This = impl_from_IWshCollection(iface); |
| FIXME("(%p)->(%p): stub\n", This, count); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI WshCollection_get_length(IWshCollection *iface, LONG *count) |
| { |
| WshCollection *This = impl_from_IWshCollection(iface); |
| FIXME("(%p)->(%p): stub\n", This, count); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI WshCollection__NewEnum(IWshCollection *iface, IUnknown *Enum) |
| { |
| WshCollection *This = impl_from_IWshCollection(iface); |
| FIXME("(%p)->(%p): stub\n", This, Enum); |
| return E_NOTIMPL; |
| } |
| |
| static const IWshCollectionVtbl WshCollectionVtbl = { |
| WshCollection_QueryInterface, |
| WshCollection_AddRef, |
| WshCollection_Release, |
| WshCollection_GetTypeInfoCount, |
| WshCollection_GetTypeInfo, |
| WshCollection_GetIDsOfNames, |
| WshCollection_Invoke, |
| WshCollection_Item, |
| WshCollection_Count, |
| WshCollection_get_length, |
| WshCollection__NewEnum |
| }; |
| |
| static HRESULT WshCollection_Create(IWshCollection **collection) |
| { |
| WshCollection *This; |
| |
| This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); |
| if (!This) return E_OUTOFMEMORY; |
| |
| This->IWshCollection_iface.lpVtbl = &WshCollectionVtbl; |
| This->ref = 1; |
| |
| init_classinfo(&IID_IWshCollection, (IUnknown *)&This->IWshCollection_iface, &This->classinfo); |
| *collection = &This->IWshCollection_iface; |
| |
| return S_OK; |
| } |
| |
| /* IWshShortcut */ |
| static HRESULT WINAPI WshShortcut_QueryInterface(IWshShortcut *iface, REFIID riid, void **ppv) |
| { |
| WshShortcut *This = impl_from_IWshShortcut(iface); |
| |
| TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv); |
| |
| if (IsEqualGUID(riid, &IID_IUnknown) || |
| IsEqualGUID(riid, &IID_IDispatch) || |
| IsEqualGUID(riid, &IID_IWshShortcut)) |
| { |
| *ppv = iface; |
| } |
| else if (IsEqualIID(riid, &IID_IProvideClassInfo)) |
| { |
| *ppv = &This->classinfo.IProvideClassInfo_iface; |
| } |
| else { |
| FIXME("Unknown iface %s\n", debugstr_guid(riid)); |
| *ppv = NULL; |
| return E_NOINTERFACE; |
| } |
| |
| IUnknown_AddRef((IUnknown*)*ppv); |
| return S_OK; |
| } |
| |
| static ULONG WINAPI WshShortcut_AddRef(IWshShortcut *iface) |
| { |
| WshShortcut *This = impl_from_IWshShortcut(iface); |
| LONG ref = InterlockedIncrement(&This->ref); |
| TRACE("(%p) ref = %d\n", This, ref); |
| return ref; |
| } |
| |
| static ULONG WINAPI WshShortcut_Release(IWshShortcut *iface) |
| { |
| WshShortcut *This = impl_from_IWshShortcut(iface); |
| LONG ref = InterlockedDecrement(&This->ref); |
| TRACE("(%p) ref = %d\n", This, ref); |
| |
| if (!ref) |
| { |
| SysFreeString(This->path_link); |
| IShellLinkW_Release(This->link); |
| HeapFree(GetProcessHeap(), 0, This); |
| } |
| |
| return ref; |
| } |
| |
| static HRESULT WINAPI WshShortcut_GetTypeInfoCount(IWshShortcut *iface, UINT *pctinfo) |
| { |
| WshShortcut *This = impl_from_IWshShortcut(iface); |
| TRACE("(%p)->(%p)\n", This, pctinfo); |
| *pctinfo = 1; |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI WshShortcut_GetTypeInfo(IWshShortcut *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) |
| { |
| WshShortcut *This = impl_from_IWshShortcut(iface); |
| TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo); |
| return get_typeinfo(IWshShortcut_tid, ppTInfo); |
| } |
| |
| static HRESULT WINAPI WshShortcut_GetIDsOfNames(IWshShortcut *iface, REFIID riid, LPOLESTR *rgszNames, |
| UINT cNames, LCID lcid, DISPID *rgDispId) |
| { |
| WshShortcut *This = impl_from_IWshShortcut(iface); |
| ITypeInfo *typeinfo; |
| HRESULT hr; |
| |
| TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId); |
| |
| hr = get_typeinfo(IWshShortcut_tid, &typeinfo); |
| if(SUCCEEDED(hr)) |
| { |
| hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId); |
| ITypeInfo_Release(typeinfo); |
| } |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI WshShortcut_Invoke(IWshShortcut *iface, DISPID dispIdMember, REFIID riid, LCID lcid, |
| WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) |
| { |
| WshShortcut *This = impl_from_IWshShortcut(iface); |
| ITypeInfo *typeinfo; |
| HRESULT hr; |
| |
| TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid), |
| lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); |
| |
| hr = get_typeinfo(IWshShortcut_tid, &typeinfo); |
| if(SUCCEEDED(hr)) |
| { |
| hr = ITypeInfo_Invoke(typeinfo, &This->IWshShortcut_iface, dispIdMember, wFlags, |
| pDispParams, pVarResult, pExcepInfo, puArgErr); |
| ITypeInfo_Release(typeinfo); |
| } |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI WshShortcut_get_FullName(IWshShortcut *iface, BSTR *name) |
| { |
| WshShortcut *This = impl_from_IWshShortcut(iface); |
| FIXME("(%p)->(%p): stub\n", This, name); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI WshShortcut_get_Arguments(IWshShortcut *iface, BSTR *Arguments) |
| { |
| WshShortcut *This = impl_from_IWshShortcut(iface); |
| WCHAR buffW[INFOTIPSIZE]; |
| HRESULT hr; |
| |
| TRACE("(%p)->(%p)\n", This, Arguments); |
| |
| if (!Arguments) |
| return E_POINTER; |
| |
| *Arguments = NULL; |
| |
| hr = IShellLinkW_GetArguments(This->link, buffW, sizeof(buffW)/sizeof(WCHAR)); |
| if (FAILED(hr)) |
| return hr; |
| |
| *Arguments = SysAllocString(buffW); |
| return *Arguments ? S_OK : E_OUTOFMEMORY; |
| } |
| |
| static HRESULT WINAPI WshShortcut_put_Arguments(IWshShortcut *iface, BSTR Arguments) |
| { |
| WshShortcut *This = impl_from_IWshShortcut(iface); |
| |
| TRACE("(%p)->(%s)\n", This, debugstr_w(Arguments)); |
| |
| return IShellLinkW_SetArguments(This->link, Arguments); |
| } |
| |
| static HRESULT WINAPI WshShortcut_get_Description(IWshShortcut *iface, BSTR *Description) |
| { |
| WshShortcut *This = impl_from_IWshShortcut(iface); |
| FIXME("(%p)->(%p): stub\n", This, Description); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI WshShortcut_put_Description(IWshShortcut *iface, BSTR Description) |
| { |
| WshShortcut *This = impl_from_IWshShortcut(iface); |
| TRACE("(%p)->(%s)\n", This, debugstr_w(Description)); |
| return IShellLinkW_SetDescription(This->link, Description); |
| } |
| |
| static HRESULT WINAPI WshShortcut_get_Hotkey(IWshShortcut *iface, BSTR *Hotkey) |
| { |
| WshShortcut *This = impl_from_IWshShortcut(iface); |
| FIXME("(%p)->(%p): stub\n", This, Hotkey); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI WshShortcut_put_Hotkey(IWshShortcut *iface, BSTR Hotkey) |
| { |
| WshShortcut *This = impl_from_IWshShortcut(iface); |
| FIXME("(%p)->(%s): stub\n", This, debugstr_w(Hotkey)); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI WshShortcut_get_IconLocation(IWshShortcut *iface, BSTR *IconPath) |
| { |
| static const WCHAR fmtW[] = {'%','s',',',' ','%','d',0}; |
| WshShortcut *This = impl_from_IWshShortcut(iface); |
| WCHAR buffW[MAX_PATH], pathW[MAX_PATH]; |
| INT icon = 0; |
| HRESULT hr; |
| |
| TRACE("(%p)->(%p)\n", This, IconPath); |
| |
| if (!IconPath) |
| return E_POINTER; |
| |
| hr = IShellLinkW_GetIconLocation(This->link, buffW, sizeof(buffW)/sizeof(WCHAR), &icon); |
| if (FAILED(hr)) return hr; |
| |
| sprintfW(pathW, fmtW, buffW, icon); |
| *IconPath = SysAllocString(pathW); |
| if (!*IconPath) return E_OUTOFMEMORY; |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI WshShortcut_put_IconLocation(IWshShortcut *iface, BSTR IconPath) |
| { |
| WshShortcut *This = impl_from_IWshShortcut(iface); |
| HRESULT hr; |
| WCHAR *ptr; |
| BSTR path; |
| INT icon; |
| |
| TRACE("(%p)->(%s)\n", This, debugstr_w(IconPath)); |
| |
| /* scan for icon id */ |
| ptr = strrchrW(IconPath, ','); |
| if (!ptr) |
| { |
| WARN("icon index not found\n"); |
| return E_FAIL; |
| } |
| |
| path = SysAllocStringLen(IconPath, ptr-IconPath); |
| |
| /* skip spaces if any */ |
| while (isspaceW(*++ptr)) |
| ; |
| |
| icon = atoiW(ptr); |
| |
| hr = IShellLinkW_SetIconLocation(This->link, path, icon); |
| SysFreeString(path); |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI WshShortcut_put_RelativePath(IWshShortcut *iface, BSTR rhs) |
| { |
| WshShortcut *This = impl_from_IWshShortcut(iface); |
| FIXME("(%p)->(%s): stub\n", This, debugstr_w(rhs)); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI WshShortcut_get_TargetPath(IWshShortcut *iface, BSTR *Path) |
| { |
| WshShortcut *This = impl_from_IWshShortcut(iface); |
| FIXME("(%p)->(%p): stub\n", This, Path); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI WshShortcut_put_TargetPath(IWshShortcut *iface, BSTR Path) |
| { |
| WshShortcut *This = impl_from_IWshShortcut(iface); |
| TRACE("(%p)->(%s)\n", This, debugstr_w(Path)); |
| return IShellLinkW_SetPath(This->link, Path); |
| } |
| |
| static HRESULT WINAPI WshShortcut_get_WindowStyle(IWshShortcut *iface, int *ShowCmd) |
| { |
| WshShortcut *This = impl_from_IWshShortcut(iface); |
| TRACE("(%p)->(%p)\n", This, ShowCmd); |
| return IShellLinkW_GetShowCmd(This->link, ShowCmd); |
| } |
| |
| static HRESULT WINAPI WshShortcut_put_WindowStyle(IWshShortcut *iface, int ShowCmd) |
| { |
| WshShortcut *This = impl_from_IWshShortcut(iface); |
| TRACE("(%p)->(%d)\n", This, ShowCmd); |
| return IShellLinkW_SetShowCmd(This->link, ShowCmd); |
| } |
| |
| static HRESULT WINAPI WshShortcut_get_WorkingDirectory(IWshShortcut *iface, BSTR *WorkingDirectory) |
| { |
| WshShortcut *This = impl_from_IWshShortcut(iface); |
| WCHAR buffW[MAX_PATH]; |
| HRESULT hr; |
| |
| TRACE("(%p)->(%p)\n", This, WorkingDirectory); |
| |
| if (!WorkingDirectory) |
| return E_POINTER; |
| |
| *WorkingDirectory = NULL; |
| hr = IShellLinkW_GetWorkingDirectory(This->link, buffW, sizeof(buffW)/sizeof(WCHAR)); |
| if (FAILED(hr)) return hr; |
| |
| *WorkingDirectory = SysAllocString(buffW); |
| return *WorkingDirectory ? S_OK : E_OUTOFMEMORY; |
| } |
| |
| static HRESULT WINAPI WshShortcut_put_WorkingDirectory(IWshShortcut *iface, BSTR WorkingDirectory) |
| { |
| WshShortcut *This = impl_from_IWshShortcut(iface); |
| TRACE("(%p)->(%s)\n", This, debugstr_w(WorkingDirectory)); |
| return IShellLinkW_SetWorkingDirectory(This->link, WorkingDirectory); |
| } |
| |
| static HRESULT WINAPI WshShortcut_Load(IWshShortcut *iface, BSTR PathLink) |
| { |
| WshShortcut *This = impl_from_IWshShortcut(iface); |
| FIXME("(%p)->(%s): stub\n", This, debugstr_w(PathLink)); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI WshShortcut_Save(IWshShortcut *iface) |
| { |
| WshShortcut *This = impl_from_IWshShortcut(iface); |
| IPersistFile *file; |
| HRESULT hr; |
| |
| TRACE("(%p)\n", This); |
| |
| IShellLinkW_QueryInterface(This->link, &IID_IPersistFile, (void**)&file); |
| hr = IPersistFile_Save(file, This->path_link, TRUE); |
| IPersistFile_Release(file); |
| |
| return hr; |
| } |
| |
| static const IWshShortcutVtbl WshShortcutVtbl = { |
| WshShortcut_QueryInterface, |
| WshShortcut_AddRef, |
| WshShortcut_Release, |
| WshShortcut_GetTypeInfoCount, |
| WshShortcut_GetTypeInfo, |
| WshShortcut_GetIDsOfNames, |
| WshShortcut_Invoke, |
| WshShortcut_get_FullName, |
| WshShortcut_get_Arguments, |
| WshShortcut_put_Arguments, |
| WshShortcut_get_Description, |
| WshShortcut_put_Description, |
| WshShortcut_get_Hotkey, |
| WshShortcut_put_Hotkey, |
| WshShortcut_get_IconLocation, |
| WshShortcut_put_IconLocation, |
| WshShortcut_put_RelativePath, |
| WshShortcut_get_TargetPath, |
| WshShortcut_put_TargetPath, |
| WshShortcut_get_WindowStyle, |
| WshShortcut_put_WindowStyle, |
| WshShortcut_get_WorkingDirectory, |
| WshShortcut_put_WorkingDirectory, |
| WshShortcut_Load, |
| WshShortcut_Save |
| }; |
| |
| static HRESULT WshShortcut_Create(const WCHAR *path, IDispatch **shortcut) |
| { |
| WshShortcut *This; |
| HRESULT hr; |
| |
| *shortcut = NULL; |
| |
| This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); |
| if (!This) return E_OUTOFMEMORY; |
| |
| This->IWshShortcut_iface.lpVtbl = &WshShortcutVtbl; |
| This->ref = 1; |
| |
| hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, |
| &IID_IShellLinkW, (void**)&This->link); |
| if (FAILED(hr)) |
| { |
| HeapFree(GetProcessHeap(), 0, This); |
| return hr; |
| } |
| |
| This->path_link = SysAllocString(path); |
| if (!This->path_link) |
| { |
| IShellLinkW_Release(This->link); |
| HeapFree(GetProcessHeap(), 0, This); |
| return E_OUTOFMEMORY; |
| } |
| |
| init_classinfo(&IID_IWshShortcut, (IUnknown *)&This->IWshShortcut_iface, &This->classinfo); |
| *shortcut = (IDispatch*)&This->IWshShortcut_iface; |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI WshShell3_QueryInterface(IWshShell3 *iface, REFIID riid, void **ppv) |
| { |
| TRACE("(%s, %p)\n", debugstr_guid(riid), ppv); |
| |
| *ppv = NULL; |
| |
| if (IsEqualGUID(riid, &IID_IDispatch) || |
| IsEqualGUID(riid, &IID_IWshShell3) || |
| IsEqualGUID(riid, &IID_IWshShell2) || |
| IsEqualGUID(riid, &IID_IWshShell) || |
| IsEqualGUID(riid, &IID_IUnknown)) |
| { |
| *ppv = iface; |
| } |
| else if (IsEqualGUID(riid, &IID_IDispatchEx)) |
| { |
| return E_NOINTERFACE; |
| } |
| else if (IsEqualIID(riid, &IID_IProvideClassInfo)) |
| { |
| *ppv = &WshShell3.classinfo.IProvideClassInfo_iface; |
| } |
| else |
| { |
| WARN("unknown iface %s\n", debugstr_guid(riid)); |
| return E_NOINTERFACE; |
| } |
| |
| IUnknown_AddRef((IUnknown *)*ppv); |
| return S_OK; |
| } |
| |
| static ULONG WINAPI WshShell3_AddRef(IWshShell3 *iface) |
| { |
| TRACE("()\n"); |
| return 2; |
| } |
| |
| static ULONG WINAPI WshShell3_Release(IWshShell3 *iface) |
| { |
| TRACE("()\n"); |
| return 2; |
| } |
| |
| static HRESULT WINAPI WshShell3_GetTypeInfoCount(IWshShell3 *iface, UINT *pctinfo) |
| { |
| TRACE("(%p)\n", pctinfo); |
| *pctinfo = 1; |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI WshShell3_GetTypeInfo(IWshShell3 *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) |
| { |
| TRACE("(%u %u %p)\n", iTInfo, lcid, ppTInfo); |
| return get_typeinfo(IWshShell3_tid, ppTInfo); |
| } |
| |
| static HRESULT WINAPI WshShell3_GetIDsOfNames(IWshShell3 *iface, REFIID riid, LPOLESTR *rgszNames, |
| UINT cNames, LCID lcid, DISPID *rgDispId) |
| { |
| ITypeInfo *typeinfo; |
| HRESULT hr; |
| |
| TRACE("(%s %p %u %u %p)\n", debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId); |
| |
| hr = get_typeinfo(IWshShell3_tid, &typeinfo); |
| if(SUCCEEDED(hr)) |
| { |
| hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId); |
| ITypeInfo_Release(typeinfo); |
| } |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI WshShell3_Invoke(IWshShell3 *iface, DISPID dispIdMember, REFIID riid, LCID lcid, |
| WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) |
| { |
| ITypeInfo *typeinfo; |
| HRESULT hr; |
| |
| TRACE("(%d %s %d %d %p %p %p %p)\n", dispIdMember, debugstr_guid(riid), |
| lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); |
| |
| hr = get_typeinfo(IWshShell3_tid, &typeinfo); |
| if(SUCCEEDED(hr)) |
| { |
| hr = ITypeInfo_Invoke(typeinfo, &WshShell3.IWshShell3_iface, dispIdMember, wFlags, |
| pDispParams, pVarResult, pExcepInfo, puArgErr); |
| ITypeInfo_Release(typeinfo); |
| } |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI WshShell3_get_SpecialFolders(IWshShell3 *iface, IWshCollection **folders) |
| { |
| TRACE("(%p)\n", folders); |
| return WshCollection_Create(folders); |
| } |
| |
| static HRESULT WINAPI WshShell3_get_Environment(IWshShell3 *iface, VARIANT *type, IWshEnvironment **env) |
| { |
| FIXME("(%s %p): semi-stub\n", debugstr_variant(type), env); |
| return WshEnvironment_Create(env); |
| } |
| |
| static inline BOOL is_optional_argument(const VARIANT *arg) |
| { |
| return V_VT(arg) == VT_ERROR && V_ERROR(arg) == DISP_E_PARAMNOTFOUND; |
| } |
| |
| static HRESULT WINAPI WshShell3_Run(IWshShell3 *iface, BSTR cmd, VARIANT *style, VARIANT *wait, DWORD *exit_code) |
| { |
| SHELLEXECUTEINFOW info; |
| int waitforprocess; |
| VARIANT s; |
| HRESULT hr; |
| |
| TRACE("(%s %s %s %p)\n", debugstr_w(cmd), debugstr_variant(style), debugstr_variant(wait), exit_code); |
| |
| if (!style || !wait || !exit_code) |
| return E_POINTER; |
| |
| VariantInit(&s); |
| hr = VariantChangeType(&s, style, 0, VT_I4); |
| if (FAILED(hr)) |
| { |
| ERR("failed to convert style argument, 0x%08x\n", hr); |
| return hr; |
| } |
| |
| if (is_optional_argument(wait)) |
| waitforprocess = 0; |
| else { |
| VARIANT w; |
| |
| VariantInit(&w); |
| hr = VariantChangeType(&w, wait, 0, VT_I4); |
| if (FAILED(hr)) |
| return hr; |
| |
| waitforprocess = V_I4(&w); |
| } |
| |
| memset(&info, 0, sizeof(info)); |
| info.cbSize = sizeof(info); |
| info.fMask = waitforprocess ? SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS : SEE_MASK_DEFAULT; |
| info.lpFile = cmd; |
| info.nShow = V_I4(&s); |
| |
| if (!ShellExecuteExW(&info)) |
| { |
| TRACE("ShellExecute failed, %d\n", GetLastError()); |
| return HRESULT_FROM_WIN32(GetLastError()); |
| } |
| else |
| { |
| if (waitforprocess) |
| { |
| GetExitCodeProcess(info.hProcess, exit_code); |
| CloseHandle(info.hProcess); |
| } |
| else |
| *exit_code = 0; |
| |
| return S_OK; |
| } |
| } |
| |
| static HRESULT WINAPI WshShell3_Popup(IWshShell3 *iface, BSTR Text, VARIANT* SecondsToWait, VARIANT *Title, VARIANT *Type, int *button) |
| { |
| FIXME("(%s %s %s %s %p): stub\n", debugstr_w(Text), debugstr_variant(SecondsToWait), |
| debugstr_variant(Title), debugstr_variant(Type), button); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI WshShell3_CreateShortcut(IWshShell3 *iface, BSTR PathLink, IDispatch** Shortcut) |
| { |
| TRACE("(%s %p)\n", debugstr_w(PathLink), Shortcut); |
| return WshShortcut_Create(PathLink, Shortcut); |
| } |
| |
| static HRESULT WINAPI WshShell3_ExpandEnvironmentStrings(IWshShell3 *iface, BSTR Src, BSTR* Dst) |
| { |
| DWORD ret; |
| |
| TRACE("(%s %p)\n", debugstr_w(Src), Dst); |
| |
| if (!Src || !Dst) return E_POINTER; |
| |
| ret = ExpandEnvironmentStringsW(Src, NULL, 0); |
| *Dst = SysAllocStringLen(NULL, ret); |
| if (!*Dst) return E_OUTOFMEMORY; |
| |
| if (ExpandEnvironmentStringsW(Src, *Dst, ret)) |
| return S_OK; |
| else |
| { |
| SysFreeString(*Dst); |
| *Dst = NULL; |
| return HRESULT_FROM_WIN32(GetLastError()); |
| } |
| } |
| |
| static HKEY get_root_key(const WCHAR *path) |
| { |
| static const struct { |
| const WCHAR full[20]; |
| const WCHAR abbrev[5]; |
| HKEY hkey; |
| } rootkeys[] = { |
| { {'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R',0}, {'H','K','C','U',0}, HKEY_CURRENT_USER }, |
| { {'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 }, |
| { {'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T',0}, {'H','K','C','R',0}, HKEY_CLASSES_ROOT }, |
| { {'H','K','E','Y','_','U','S','E','R','S',0}, {0}, HKEY_USERS }, |
| { {'H','K','E','Y','_','C','U','R','R','E','N','T','_','C','O','N','F','I','G',0}, {0}, HKEY_CURRENT_CONFIG } |
| }; |
| int i; |
| |
| for (i = 0; i < sizeof(rootkeys)/sizeof(rootkeys[0]); i++) { |
| if (!strncmpW(path, rootkeys[i].full, strlenW(rootkeys[i].full))) |
| return rootkeys[i].hkey; |
| if (rootkeys[i].abbrev[0] && !strncmpW(path, rootkeys[i].abbrev, strlenW(rootkeys[i].abbrev))) |
| return rootkeys[i].hkey; |
| } |
| |
| return NULL; |
| } |
| |
| /* Caller is responsible to free 'subkey' if 'value' is not NULL */ |
| static HRESULT split_reg_path(const WCHAR *path, WCHAR **subkey, WCHAR **value) |
| { |
| *value = NULL; |
| |
| /* at least one separator should be present */ |
| *subkey = strchrW(path, '\\'); |
| if (!*subkey) |
| return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); |
| |
| /* default value or not */ |
| if ((*subkey)[strlenW(*subkey)-1] == '\\') { |
| (*subkey)++; |
| *value = NULL; |
| } |
| else { |
| *value = strrchrW(*subkey, '\\'); |
| if (*value - *subkey > 1) { |
| unsigned int len = *value - *subkey - 1; |
| WCHAR *ret; |
| |
| ret = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR)); |
| if (!ret) |
| return E_OUTOFMEMORY; |
| |
| memcpy(ret, *subkey + 1, len*sizeof(WCHAR)); |
| ret[len] = 0; |
| *subkey = ret; |
| } |
| (*value)++; |
| } |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI WshShell3_RegRead(IWshShell3 *iface, BSTR name, VARIANT *value) |
| { |
| DWORD type, datalen, ret; |
| WCHAR *subkey, *val; |
| HRESULT hr; |
| HKEY root; |
| |
| TRACE("(%s %p)\n", debugstr_w(name), value); |
| |
| if (!name || !value) |
| return E_POINTER; |
| |
| root = get_root_key(name); |
| if (!root) |
| return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); |
| |
| hr = split_reg_path(name, &subkey, &val); |
| if (FAILED(hr)) |
| return hr; |
| |
| type = REG_NONE; |
| datalen = 0; |
| ret = RegGetValueW(root, subkey, val, RRF_RT_ANY, &type, NULL, &datalen); |
| if (ret == ERROR_SUCCESS) { |
| void *data; |
| |
| data = HeapAlloc(GetProcessHeap(), 0, datalen); |
| if (!data) { |
| hr = E_OUTOFMEMORY; |
| goto fail; |
| } |
| |
| ret = RegGetValueW(root, subkey, val, RRF_RT_ANY, &type, data, &datalen); |
| if (ret) { |
| HeapFree(GetProcessHeap(), 0, data); |
| hr = HRESULT_FROM_WIN32(ret); |
| goto fail; |
| } |
| |
| switch (type) { |
| case REG_SZ: |
| case REG_EXPAND_SZ: |
| V_VT(value) = VT_BSTR; |
| V_BSTR(value) = SysAllocString((WCHAR*)data); |
| if (!V_BSTR(value)) |
| hr = E_OUTOFMEMORY; |
| break; |
| case REG_DWORD: |
| V_VT(value) = VT_I4; |
| V_I4(value) = *(DWORD*)data; |
| break; |
| case REG_BINARY: |
| { |
| BYTE *ptr = (BYTE*)data; |
| SAFEARRAYBOUND bound; |
| unsigned int i; |
| SAFEARRAY *sa; |
| VARIANT *v; |
| |
| bound.lLbound = 0; |
| bound.cElements = datalen; |
| sa = SafeArrayCreate(VT_VARIANT, 1, &bound); |
| if (!sa) |
| break; |
| |
| hr = SafeArrayAccessData(sa, (void**)&v); |
| if (FAILED(hr)) { |
| SafeArrayDestroy(sa); |
| break; |
| } |
| |
| for (i = 0; i < datalen; i++) { |
| V_VT(&v[i]) = VT_UI1; |
| V_UI1(&v[i]) = ptr[i]; |
| } |
| SafeArrayUnaccessData(sa); |
| |
| V_VT(value) = VT_ARRAY|VT_VARIANT; |
| V_ARRAY(value) = sa; |
| break; |
| } |
| case REG_MULTI_SZ: |
| { |
| WCHAR *ptr = (WCHAR*)data; |
| SAFEARRAYBOUND bound; |
| SAFEARRAY *sa; |
| VARIANT *v; |
| |
| /* get element count first */ |
| bound.lLbound = 0; |
| bound.cElements = 0; |
| while (*ptr) { |
| bound.cElements++; |
| ptr += strlenW(ptr)+1; |
| } |
| |
| sa = SafeArrayCreate(VT_VARIANT, 1, &bound); |
| if (!sa) |
| break; |
| |
| hr = SafeArrayAccessData(sa, (void**)&v); |
| if (FAILED(hr)) { |
| SafeArrayDestroy(sa); |
| break; |
| } |
| |
| ptr = (WCHAR*)data; |
| while (*ptr) { |
| V_VT(v) = VT_BSTR; |
| V_BSTR(v) = SysAllocString(ptr); |
| ptr += strlenW(ptr)+1; |
| v++; |
| } |
| |
| SafeArrayUnaccessData(sa); |
| V_VT(value) = VT_ARRAY|VT_VARIANT; |
| V_ARRAY(value) = sa; |
| break; |
| } |
| default: |
| FIXME("value type %d not supported\n", type); |
| hr = E_FAIL; |
| }; |
| |
| HeapFree(GetProcessHeap(), 0, data); |
| if (FAILED(hr)) |
| VariantInit(value); |
| } |
| else |
| hr = HRESULT_FROM_WIN32(ret); |
| |
| fail: |
| if (val) |
| HeapFree(GetProcessHeap(), 0, subkey); |
| return hr; |
| } |
| |
| static HRESULT WINAPI WshShell3_RegWrite(IWshShell3 *iface, BSTR name, VARIANT *value, VARIANT *type) |
| { |
| static const WCHAR regexpandszW[] = {'R','E','G','_','E','X','P','A','N','D','_','S','Z',0}; |
| static const WCHAR regszW[] = {'R','E','G','_','S','Z',0}; |
| static const WCHAR regdwordW[] = {'R','E','G','_','D','W','O','R','D',0}; |
| static const WCHAR regbinaryW[] = {'R','E','G','_','B','I','N','A','R','Y',0}; |
| |
| DWORD regtype, data_len; |
| WCHAR *subkey, *val; |
| const BYTE *data; |
| HRESULT hr; |
| HKEY root; |
| VARIANT v; |
| LONG ret; |
| |
| TRACE("(%s %s %s)\n", debugstr_w(name), debugstr_variant(value), debugstr_variant(type)); |
| |
| if (!name || !value || !type) |
| return E_POINTER; |
| |
| root = get_root_key(name); |
| if (!root) |
| return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); |
| |
| /* value type */ |
| if (is_optional_argument(type)) |
| regtype = REG_SZ; |
| else { |
| if (V_VT(type) != VT_BSTR) |
| return E_INVALIDARG; |
| |
| if (!strcmpW(V_BSTR(type), regszW)) |
| regtype = REG_SZ; |
| else if (!strcmpW(V_BSTR(type), regdwordW)) |
| regtype = REG_DWORD; |
| else if (!strcmpW(V_BSTR(type), regexpandszW)) |
| regtype = REG_EXPAND_SZ; |
| else if (!strcmpW(V_BSTR(type), regbinaryW)) |
| regtype = REG_BINARY; |
| else { |
| FIXME("unrecognized value type %s\n", debugstr_w(V_BSTR(type))); |
| return E_FAIL; |
| } |
| } |
| |
| /* it's always a string or a DWORD */ |
| VariantInit(&v); |
| switch (regtype) |
| { |
| case REG_SZ: |
| case REG_EXPAND_SZ: |
| hr = VariantChangeType(&v, value, 0, VT_BSTR); |
| if (hr == S_OK) { |
| data = (BYTE*)V_BSTR(&v); |
| data_len = SysStringByteLen(V_BSTR(&v)) + sizeof(WCHAR); |
| } |
| break; |
| case REG_DWORD: |
| case REG_BINARY: |
| hr = VariantChangeType(&v, value, 0, VT_I4); |
| data = (BYTE*)&V_I4(&v); |
| data_len = sizeof(DWORD); |
| break; |
| default: |
| FIXME("unexpected regtype %d\n", regtype); |
| return E_FAIL; |
| }; |
| |
| if (FAILED(hr)) { |
| FIXME("failed to convert value, regtype %d, 0x%08x\n", regtype, hr); |
| return hr; |
| } |
| |
| hr = split_reg_path(name, &subkey, &val); |
| if (FAILED(hr)) |
| goto fail; |
| |
| ret = RegSetKeyValueW(root, subkey, val, regtype, data, data_len); |
| if (ret) |
| hr = HRESULT_FROM_WIN32(ret); |
| |
| fail: |
| VariantClear(&v); |
| if (val) |
| HeapFree(GetProcessHeap(), 0, subkey); |
| return hr; |
| } |
| |
| static HRESULT WINAPI WshShell3_RegDelete(IWshShell3 *iface, BSTR Name) |
| { |
| FIXME("(%s): stub\n", debugstr_w(Name)); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI WshShell3_LogEvent(IWshShell3 *iface, VARIANT *Type, BSTR Message, BSTR Target, VARIANT_BOOL *out_Success) |
| { |
| FIXME("(%s %s %s %p): stub\n", debugstr_variant(Type), debugstr_w(Message), debugstr_w(Target), out_Success); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI WshShell3_AppActivate(IWshShell3 *iface, VARIANT *App, VARIANT *Wait, VARIANT_BOOL *out_Success) |
| { |
| FIXME("(%s %s %p): stub\n", debugstr_variant(App), debugstr_variant(Wait), out_Success); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI WshShell3_SendKeys(IWshShell3 *iface, BSTR Keys, VARIANT *Wait) |
| { |
| FIXME("(%s %p): stub\n", debugstr_w(Keys), Wait); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI WshShell3_Exec(IWshShell3 *iface, BSTR command, IWshExec **ret) |
| { |
| TRACE("(%s %p)\n", debugstr_w(command), ret); |
| |
| if (!ret) |
| return E_POINTER; |
| |
| if (!command) |
| return DISP_E_EXCEPTION; |
| |
| return WshExec_create(command, ret); |
| } |
| |
| static HRESULT WINAPI WshShell3_get_CurrentDirectory(IWshShell3 *iface, BSTR *dir) |
| { |
| DWORD ret; |
| |
| TRACE("(%p)\n", dir); |
| |
| ret = GetCurrentDirectoryW(0, NULL); |
| if (!ret) |
| return HRESULT_FROM_WIN32(GetLastError()); |
| |
| *dir = SysAllocStringLen(NULL, ret-1); |
| if (!*dir) |
| return E_OUTOFMEMORY; |
| |
| ret = GetCurrentDirectoryW(ret, *dir); |
| if (!ret) { |
| SysFreeString(*dir); |
| *dir = NULL; |
| return HRESULT_FROM_WIN32(GetLastError()); |
| } |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI WshShell3_put_CurrentDirectory(IWshShell3 *iface, BSTR dir) |
| { |
| TRACE("(%s)\n", debugstr_w(dir)); |
| |
| if (!dir) |
| return E_INVALIDARG; |
| |
| if (!SetCurrentDirectoryW(dir)) |
| return HRESULT_FROM_WIN32(GetLastError()); |
| |
| return S_OK; |
| } |
| |
| static const IWshShell3Vtbl WshShell3Vtbl = { |
| WshShell3_QueryInterface, |
| WshShell3_AddRef, |
| WshShell3_Release, |
| WshShell3_GetTypeInfoCount, |
| WshShell3_GetTypeInfo, |
| WshShell3_GetIDsOfNames, |
| WshShell3_Invoke, |
| WshShell3_get_SpecialFolders, |
| WshShell3_get_Environment, |
| WshShell3_Run, |
| WshShell3_Popup, |
| WshShell3_CreateShortcut, |
| WshShell3_ExpandEnvironmentStrings, |
| WshShell3_RegRead, |
| WshShell3_RegWrite, |
| WshShell3_RegDelete, |
| WshShell3_LogEvent, |
| WshShell3_AppActivate, |
| WshShell3_SendKeys, |
| WshShell3_Exec, |
| WshShell3_get_CurrentDirectory, |
| WshShell3_put_CurrentDirectory |
| }; |
| |
| HRESULT WINAPI WshShellFactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv) |
| { |
| TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv); |
| |
| WshShell3.IWshShell3_iface.lpVtbl = &WshShell3Vtbl; |
| init_classinfo(&IID_IWshShell3, (IUnknown *)&WshShell3.IWshShell3_iface, &WshShell3.classinfo); |
| return IWshShell3_QueryInterface(&WshShell3.IWshShell3_iface, riid, ppv); |
| } |