* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#ifdef __REACTOS__
+#include <wchar.h>
+#endif
+
#include "wshom_private.h"
+#include "wshom.h"
+
+#include "shellapi.h"
+#include "shlobj.h"
+#include "dispex.h"
-#include <shellapi.h>
-#include <shlobj.h>
-#include <dispex.h>
+#include "wine/debug.h"
+#include "wine/heap.h"
-#include <wine/unicode.h>
+WINE_DEFAULT_DEBUG_CHANNEL(wshom);
-static IWshShell3 WshShell3;
+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;
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);
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);
+ heap_free(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 = heap_alloc(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)) {
+ heap_free(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);
IsEqualGUID(riid, &IID_IWshEnvironment))
{
*obj = iface;
- }else {
+ }
+ 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;
TRACE("(%p) ref = %d\n", This, ref);
if (!ref)
- HeapFree(GetProcessHeap(), 0, This);
+ heap_free(This);
return ref;
}
return E_POINTER;
len = GetEnvironmentVariableW(name, NULL, 0);
- *value = SysAllocStringLen(NULL, len);
- if (!*value)
- return E_OUTOFMEMORY;
-
if (len)
- GetEnvironmentVariableW(name, *value, len+1);
+ {
+ *value = SysAllocStringLen(NULL, len - 1);
+ if (*value)
+ GetEnvironmentVariableW(name, *value, len);
+ }
+ else
+ *value = SysAllocStringLen(NULL, 0);
- return S_OK;
+ return *value ? S_OK : E_OUTOFMEMORY;
}
static HRESULT WINAPI WshEnvironment_put_Item(IWshEnvironment *iface, BSTR name, BSTR value)
{
WshEnvironment *This;
- This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
+ This = heap_alloc(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;
IsEqualGUID(riid, &IID_IWshCollection))
{
*ppv = iface;
- }else {
+ }
+ 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;
TRACE("(%p) ref = %d\n", This, ref);
if (!ref)
- HeapFree(GetProcessHeap(), 0, This);
+ heap_free(This);
return ref;
}
}
folder = V_BSTR(index);
- if (!strcmpiW(folder, desktopW))
+ if (!wcsicmp(folder, desktopW))
kind = CSIDL_DESKTOP;
- else if (!strcmpiW(folder, allusersdesktopW))
+ else if (!wcsicmp(folder, allusersdesktopW))
kind = CSIDL_COMMON_DESKTOPDIRECTORY;
- else if (!strcmpiW(folder, allusersprogramsW))
+ else if (!wcsicmp(folder, allusersprogramsW))
kind = CSIDL_COMMON_PROGRAMS;
else
{
return E_NOTIMPL;
}
-static HRESULT WINAPI WshCollection__NewEnum(IWshCollection *iface, IUnknown *Enum)
+static HRESULT WINAPI WshCollection__NewEnum(IWshCollection *iface, IUnknown **Enum)
{
WshCollection *This = impl_from_IWshCollection(iface);
FIXME("(%p)->(%p): stub\n", This, Enum);
{
WshCollection *This;
- This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
+ This = heap_alloc(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;
IsEqualGUID(riid, &IID_IWshShortcut))
{
*ppv = iface;
- }else {
+ }
+ 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;
{
SysFreeString(This->path_link);
IShellLinkW_Release(This->link);
- HeapFree(GetProcessHeap(), 0, This);
+ heap_free(This);
}
return ref;
*Arguments = NULL;
- hr = IShellLinkW_GetArguments(This->link, buffW, sizeof(buffW)/sizeof(WCHAR));
+ hr = IShellLinkW_GetArguments(This->link, buffW, ARRAY_SIZE(buffW));
if (FAILED(hr))
return hr;
if (!IconPath)
return E_POINTER;
- hr = IShellLinkW_GetIconLocation(This->link, buffW, sizeof(buffW)/sizeof(WCHAR), &icon);
+ hr = IShellLinkW_GetIconLocation(This->link, buffW, ARRAY_SIZE(buffW), &icon);
if (FAILED(hr)) return hr;
- sprintfW(pathW, fmtW, buffW, icon);
+ swprintf(pathW, fmtW, buffW, icon);
*IconPath = SysAllocString(pathW);
if (!*IconPath) return E_OUTOFMEMORY;
TRACE("(%p)->(%s)\n", This, debugstr_w(IconPath));
/* scan for icon id */
- ptr = strrchrW(IconPath, ',');
+ ptr = wcsrchr(IconPath, ',');
if (!ptr)
{
WARN("icon index not found\n");
path = SysAllocStringLen(IconPath, ptr-IconPath);
/* skip spaces if any */
- while (isspaceW(*++ptr))
+ while (iswspace(*++ptr))
;
- icon = atoiW(ptr);
+ icon = wcstol(ptr, NULL, 10);
hr = IShellLinkW_SetIconLocation(This->link, path, icon);
SysFreeString(path);
return E_POINTER;
*WorkingDirectory = NULL;
- hr = IShellLinkW_GetWorkingDirectory(This->link, buffW, sizeof(buffW)/sizeof(WCHAR));
+ hr = IShellLinkW_GetWorkingDirectory(This->link, buffW, ARRAY_SIZE(buffW));
if (FAILED(hr)) return hr;
*WorkingDirectory = SysAllocString(buffW);
*shortcut = NULL;
- This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
+ This = heap_alloc(sizeof(*This));
if (!This) return E_OUTOFMEMORY;
This->IWshShortcut_iface.lpVtbl = &WshShortcutVtbl;
&IID_IShellLinkW, (void**)&This->link);
if (FAILED(hr))
{
- HeapFree(GetProcessHeap(), 0, This);
+ heap_free(This);
return hr;
}
if (!This->path_link)
{
IShellLinkW_Release(This->link);
- HeapFree(GetProcessHeap(), 0, This);
+ heap_free(This);
return E_OUTOFMEMORY;
}
+ init_classinfo(&IID_IWshShortcut, (IUnknown *)&This->IWshShortcut_iface, &This->classinfo);
*shortcut = (IDispatch*)&This->IWshShortcut_iface;
return S_OK;
*ppv = NULL;
- if(IsEqualGUID(riid, &IID_IUnknown) ||
- IsEqualGUID(riid, &IID_IDispatch) ||
- IsEqualGUID(riid, &IID_IWshShell3))
+ if (IsEqualGUID(riid, &IID_IDispatch) ||
+ IsEqualGUID(riid, &IID_IWshShell3) ||
+ IsEqualGUID(riid, &IID_IWshShell2) ||
+ IsEqualGUID(riid, &IID_IWshShell) ||
+ IsEqualGUID(riid, &IID_IUnknown))
{
*ppv = iface;
}
{
return E_NOINTERFACE;
}
+ else if (IsEqualIID(riid, &IID_IProvideClassInfo))
+ {
+ *ppv = &WshShell3.classinfo.IProvideClassInfo_iface;
+ }
else
{
- FIXME("Unknown iface %s\n", debugstr_guid(riid));
+ WARN("unknown iface %s\n", debugstr_guid(riid));
return E_NOINTERFACE;
}
- IWshShell3_AddRef(iface);
+ IUnknown_AddRef((IUnknown *)*ppv);
return S_OK;
}
hr = get_typeinfo(IWshShell3_tid, &typeinfo);
if(SUCCEEDED(hr))
{
- hr = ITypeInfo_Invoke(typeinfo, &WshShell3, dispIdMember, wFlags,
+ hr = ITypeInfo_Invoke(typeinfo, &WshShell3.IWshShell3_iface, dispIdMember, wFlags,
pDispParams, pVarResult, pExcepInfo, puArgErr);
ITypeInfo_Release(typeinfo);
}
return WshEnvironment_Create(env);
}
-static HRESULT WINAPI WshShell3_Run(IWshShell3 *iface, BSTR cmd, VARIANT *style, VARIANT *WaitOnReturn, int *exit_code)
+static inline BOOL is_optional_argument(const VARIANT *arg)
+{
+ return V_VT(arg) == VT_ERROR && V_ERROR(arg) == DISP_E_PARAMNOTFOUND;
+}
+
+static WCHAR *split_command( BSTR cmd, WCHAR **params )
+{
+ WCHAR *ret, *ptr;
+ BOOL in_quotes = FALSE;
+
+ if (!(ret = heap_alloc((lstrlenW(cmd) + 1) * sizeof(WCHAR)))) return NULL;
+ lstrcpyW( ret, cmd );
+
+ *params = NULL;
+ for (ptr = ret; *ptr; ptr++)
+ {
+ if (*ptr == '"') in_quotes = !in_quotes;
+ else if (*ptr == ' ' && !in_quotes)
+ {
+ *ptr = 0;
+ *params = ptr + 1;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static HRESULT WINAPI WshShell3_Run(IWshShell3 *iface, BSTR cmd, VARIANT *style, VARIANT *wait, DWORD *exit_code)
{
SHELLEXECUTEINFOW info;
int waitforprocess;
- VARIANT s, w;
+ WCHAR *file, *params;
+ VARIANT s;
HRESULT hr;
+ BOOL ret;
+
+ TRACE("(%s %s %s %p)\n", debugstr_w(cmd), debugstr_variant(style), debugstr_variant(wait), exit_code);
- TRACE("(%s %s %s %p)\n", debugstr_w(cmd), debugstr_variant(style), debugstr_variant(WaitOnReturn), exit_code);
+ if (!style || !wait || !exit_code)
+ return E_POINTER;
VariantInit(&s);
hr = VariantChangeType(&s, style, 0, VT_I4);
return hr;
}
- VariantInit(&w);
- hr = VariantChangeType(&w, WaitOnReturn, 0, VT_I4);
- if (FAILED(hr))
- {
- ERR("failed to convert wait 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);
}
+ if (!(file = split_command(cmd, ¶ms))) return E_OUTOFMEMORY;
+
memset(&info, 0, sizeof(info));
info.cbSize = sizeof(info);
-
- waitforprocess = V_I4(&w);
-
info.fMask = waitforprocess ? SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS : SEE_MASK_DEFAULT;
- info.lpFile = cmd;
+ info.lpFile = file;
+ info.lpParameters = params;
info.nShow = V_I4(&s);
- if (!ShellExecuteExW(&info))
+ ret = ShellExecuteExW(&info);
+ heap_free( file );
+ if (!ret)
{
TRACE("ShellExecute failed, %d\n", GetLastError());
return HRESULT_FROM_WIN32(GetLastError());
{
if (waitforprocess)
{
- if (exit_code)
- {
- DWORD code;
- GetExitCodeProcess(info.hProcess, &code);
- *exit_code = code;
- }
+ WaitForSingleObject(info.hProcess, INFINITE);
+ GetExitCodeProcess(info.hProcess, exit_code);
CloseHandle(info.hProcess);
}
else
- if (exit_code) *exit_code = 0;
+ *exit_code = 0;
return S_OK;
}
}
-static HRESULT WINAPI WshShell3_Popup(IWshShell3 *iface, BSTR Text, VARIANT* SecondsToWait, VARIANT *Title, VARIANT *Type, int *button)
+struct popup_thread_param
{
- FIXME("(%s %s %s %s %p): stub\n", debugstr_w(Text), debugstr_variant(SecondsToWait),
- debugstr_variant(Title), debugstr_variant(Type), button);
- return E_NOTIMPL;
+ WCHAR *text;
+ VARIANT title;
+ VARIANT type;
+ INT button;
+};
+
+static DWORD WINAPI popup_thread_proc(void *arg)
+{
+ static const WCHAR defaulttitleW[] = {'W','i','n','d','o','w','s',' ','S','c','r','i','p','t',' ','H','o','s','t',0};
+ struct popup_thread_param *param = (struct popup_thread_param *)arg;
+
+ param->button = MessageBoxW(NULL, param->text, is_optional_argument(¶m->title) ?
+ defaulttitleW : V_BSTR(¶m->title), V_I4(¶m->type));
+ return 0;
+}
+
+static HRESULT WINAPI WshShell3_Popup(IWshShell3 *iface, BSTR text, VARIANT *seconds_to_wait, VARIANT *title,
+ VARIANT *type, int *button)
+{
+ struct popup_thread_param param;
+ DWORD tid, status;
+ VARIANT timeout;
+ HANDLE hthread;
+ HRESULT hr;
+
+ TRACE("(%s %s %s %s %p)\n", debugstr_w(text), debugstr_variant(seconds_to_wait), debugstr_variant(title),
+ debugstr_variant(type), button);
+
+ if (!seconds_to_wait || !title || !type || !button)
+ return E_POINTER;
+
+ VariantInit(&timeout);
+ if (!is_optional_argument(seconds_to_wait))
+ {
+ hr = VariantChangeType(&timeout, seconds_to_wait, 0, VT_I4);
+ if (FAILED(hr))
+ return hr;
+ }
+#ifdef __REACTOS__
+ else
+ {
+ VariantChangeType(&timeout, &timeout, 0, VT_I4);
+ }
+#endif
+
+ VariantInit(¶m.type);
+ if (!is_optional_argument(type))
+ {
+ hr = VariantChangeType(¶m.type, type, 0, VT_I4);
+ if (FAILED(hr))
+ return hr;
+ }
+#ifdef __REACTOS__
+ else
+ {
+ VariantChangeType(¶m.type, ¶m.type, 0, VT_I4);
+ }
+#endif
+
+ if (is_optional_argument(title))
+ param.title = *title;
+ else
+ {
+ VariantInit(¶m.title);
+ hr = VariantChangeType(¶m.title, title, 0, VT_BSTR);
+ if (FAILED(hr))
+ return hr;
+ }
+
+ param.text = text;
+ param.button = -1;
+ hthread = CreateThread(NULL, 0, popup_thread_proc, ¶m, 0, &tid);
+ status = MsgWaitForMultipleObjects(1, &hthread, FALSE, V_I4(&timeout) ? V_I4(&timeout) * 1000: INFINITE, 0);
+ if (status == WAIT_TIMEOUT)
+ {
+ PostThreadMessageW(tid, WM_QUIT, 0, 0);
+ MsgWaitForMultipleObjects(1, &hthread, FALSE, INFINITE, 0);
+ param.button = -1;
+ }
+ *button = param.button;
+
+ VariantClear(¶m.title);
+ CloseHandle(hthread);
+
+ return S_OK;
}
static HRESULT WINAPI WshShell3_CreateShortcut(IWshShell3 *iface, BSTR PathLink, IDispatch** Shortcut)
}
}
-static HRESULT WINAPI WshShell3_RegRead(IWshShell3 *iface, BSTR Name, VARIANT* out_Value)
+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 < ARRAY_SIZE(rootkeys); i++) {
+ if (!wcsncmp(path, rootkeys[i].full, lstrlenW(rootkeys[i].full)))
+ return rootkeys[i].hkey;
+ if (rootkeys[i].abbrev[0] && !wcsncmp(path, rootkeys[i].abbrev, lstrlenW(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)
{
- FIXME("(%s %p): stub\n", debugstr_w(Name), out_Value);
- return E_NOTIMPL;
+ *value = NULL;
+
+ /* at least one separator should be present */
+ *subkey = wcschr(path, '\\');
+ if (!*subkey)
+ return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
+
+ /* default value or not */
+ if ((*subkey)[lstrlenW(*subkey)-1] == '\\') {
+ (*subkey)++;
+ *value = NULL;
+ }
+ else {
+ *value = wcsrchr(*subkey, '\\');
+ if (*value - *subkey > 1) {
+ unsigned int len = *value - *subkey - 1;
+ WCHAR *ret;
+
+ ret = heap_alloc((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_RegWrite(IWshShell3 *iface, BSTR Name, VARIANT *Value, VARIANT *Type)
+static HRESULT WINAPI WshShell3_RegRead(IWshShell3 *iface, BSTR name, VARIANT *value)
{
- FIXME("(%s %s %s): stub\n", debugstr_w(Name), debugstr_variant(Value), debugstr_variant(Type));
- return E_NOTIMPL;
+ 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 = heap_alloc(datalen);
+ if (!data) {
+ hr = E_OUTOFMEMORY;
+ goto fail;
+ }
+
+ ret = RegGetValueW(root, subkey, val, RRF_RT_ANY, &type, data, &datalen);
+ if (ret) {
+ heap_free(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 += lstrlenW(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 += lstrlenW(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;
+ };
+
+ heap_free(data);
+ if (FAILED(hr))
+ VariantInit(value);
+ }
+ else
+ hr = HRESULT_FROM_WIN32(ret);
+
+fail:
+ if (val)
+ heap_free(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 (!wcscmp(V_BSTR(type), regszW))
+ regtype = REG_SZ;
+ else if (!wcscmp(V_BSTR(type), regdwordW))
+ regtype = REG_DWORD;
+ else if (!wcscmp(V_BSTR(type), regexpandszW))
+ regtype = REG_EXPAND_SZ;
+ else if (!wcscmp(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)
+ heap_free(subkey);
+ return hr;
}
static HRESULT WINAPI WshShell3_RegDelete(IWshShell3 *iface, BSTR Name)
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_RegDelete,
WshShell3_LogEvent,
WshShell3_AppActivate,
- WshShell3_SendKeys
+ WshShell3_SendKeys,
+ WshShell3_Exec,
+ WshShell3_get_CurrentDirectory,
+ WshShell3_put_CurrentDirectory
};
-static IWshShell3 WshShell3 = { &WshShell3Vtbl };
-
HRESULT WINAPI WshShellFactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
{
TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
- return IWshShell3_QueryInterface(&WshShell3, 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);
}