From 628ce75acd9cd5e63616983113e3c4bc09cd4c63 Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Mon, 18 May 2026 16:54:55 +0300 Subject: [PATCH] [SHCORE] Import from Wine-10.0 --- dll/win32/CMakeLists.txt | 1 + dll/win32/shcore/CMakeLists.txt | 24 + dll/win32/shcore/main.c | 2555 ++++++++++++++++++++++++++ dll/win32/shcore/shcore.spec | 198 ++ sdk/include/psdk/featurestagingapi.h | 49 + sdk/include/psdk/shcore.h | 32 + 6 files changed, 2859 insertions(+) create mode 100644 dll/win32/shcore/CMakeLists.txt create mode 100644 dll/win32/shcore/main.c create mode 100644 dll/win32/shcore/shcore.spec create mode 100644 sdk/include/psdk/featurestagingapi.h create mode 100644 sdk/include/psdk/shcore.h diff --git a/dll/win32/CMakeLists.txt b/dll/win32/CMakeLists.txt index 1246065de9a..0bb72219f5f 100644 --- a/dll/win32/CMakeLists.txt +++ b/dll/win32/CMakeLists.txt @@ -193,6 +193,7 @@ add_subdirectory(setupapi) add_subdirectory(sfc) add_subdirectory(sfc_os) add_subdirectory(sfcfiles) +add_subdirectory(shcore) add_subdirectory(shdoclc) add_subdirectory(shdocvw) add_subdirectory(shell32) diff --git a/dll/win32/shcore/CMakeLists.txt b/dll/win32/shcore/CMakeLists.txt new file mode 100644 index 00000000000..0845dddb3ee --- /dev/null +++ b/dll/win32/shcore/CMakeLists.txt @@ -0,0 +1,24 @@ + +remove_definitions(-D_WIN32_WINNT=0x502) +add_definitions(-D_WIN32_WINNT=0x600) + +spec2def(shcore.dll shcore.spec ADD_IMPORTLIB) + +add_definitions(-DCONST_VTABLE) + +list(APPEND SOURCE + main.c + ${CMAKE_CURRENT_BINARY_DIR}/shcore.def + ${CMAKE_CURRENT_BINARY_DIR}/shcore_stubs.c +) + +add_library(shcore MODULE ${SOURCE}) +set_module_type(shcore win32dll ENTRYPOINT 0) +if(MSVC) + target_compile_options(shcore PRIVATE /wd4267) # warning C4267: '=': conversion from 'size_t' to 'ULONG', possible loss of data +endif() +target_link_libraries(shcore crtheap wine wine_dll_canunload) +add_importlibs(shcore combase advapi32 advapi32_vista kernel32 ntdll) +add_dependencies(shcore psdk) +add_cd_file(TARGET shcore DESTINATION reactos/system32 FOR all) +set_wine_module(shcore) diff --git a/dll/win32/shcore/main.c b/dll/win32/shcore/main.c new file mode 100644 index 00000000000..ecfd5693134 --- /dev/null +++ b/dll/win32/shcore/main.c @@ -0,0 +1,2555 @@ +/* + * Copyright 2002 Jon Griffiths + * Copyright 2016 Sebastian Lackner + * + * 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 + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "initguid.h" +#include "ocidl.h" +#include "featurestagingapi.h" +#include "shellscalingapi.h" +#include "shcore.h" +#define WINSHLWAPI +#include "shlwapi.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(shcore); + +static DWORD shcore_tls; +static IUnknown *process_ref; + +BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) +{ + TRACE("%p, %lu, %p.\n", instance, reason, reserved); + + switch (reason) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(instance); + shcore_tls = TlsAlloc(); + break; + case DLL_PROCESS_DETACH: + if (reserved) break; + if (shcore_tls != TLS_OUT_OF_INDEXES) + TlsFree(shcore_tls); + break; + } + + return TRUE; +} + +#ifndef __REACTOS__ +HRESULT WINAPI GetProcessDpiAwareness(HANDLE process, PROCESS_DPI_AWARENESS *value) +{ + if (GetProcessDpiAwarenessInternal( process, (DPI_AWARENESS *)value )) return S_OK; + return HRESULT_FROM_WIN32( GetLastError() ); +} + +HRESULT WINAPI SetProcessDpiAwareness(PROCESS_DPI_AWARENESS value) +{ + if (SetProcessDpiAwarenessInternal( (DPI_AWARENESS)value )) return S_OK; + return HRESULT_FROM_WIN32( GetLastError() ); +} + +HRESULT WINAPI GetDpiForMonitor(HMONITOR monitor, MONITOR_DPI_TYPE type, UINT *x, UINT *y) +{ + if (GetDpiForMonitorInternal( monitor, type, x, y )) return S_OK; + return HRESULT_FROM_WIN32( GetLastError() ); +} +#endif /* __REACTOS__ */ + +HRESULT WINAPI GetScaleFactorForMonitor(HMONITOR monitor, DEVICE_SCALE_FACTOR *scale) +{ + FIXME("(%p %p): stub\n", monitor, scale); + + *scale = SCALE_100_PERCENT; + return S_OK; +} + +DEVICE_SCALE_FACTOR WINAPI GetScaleFactorForDevice(DISPLAY_DEVICE_TYPE device_type) +{ + FIXME("%d\n", device_type); + + return SCALE_100_PERCENT; +} + +HRESULT WINAPI _IStream_Read(IStream *stream, void *dest, ULONG size) +{ + ULONG read; + HRESULT hr; + + TRACE("%p, %p, %lu.\n", stream, dest, size); + + hr = IStream_Read(stream, dest, size, &read); + if (SUCCEEDED(hr) && read != size) + hr = E_FAIL; + return hr; +} + +HRESULT WINAPI IStream_Reset(IStream *stream) +{ + static const LARGE_INTEGER zero; + + TRACE("(%p)\n", stream); + + return IStream_Seek(stream, zero, 0, NULL); +} + +HRESULT WINAPI IStream_Size(IStream *stream, ULARGE_INTEGER *size) +{ + STATSTG statstg; + HRESULT hr; + + TRACE("(%p, %p)\n", stream, size); + + memset(&statstg, 0, sizeof(statstg)); + + hr = IStream_Stat(stream, &statstg, STATFLAG_NONAME); + + if (SUCCEEDED(hr) && size) + *size = statstg.cbSize; + return hr; +} + +HRESULT WINAPI _IStream_Write(IStream *stream, const void *src, ULONG size) +{ + ULONG written; + HRESULT hr; + + TRACE("%p, %p, %lu.\n", stream, src, size); + + hr = IStream_Write(stream, src, size, &written); + if (SUCCEEDED(hr) && written != size) + hr = E_FAIL; + + return hr; +} + +void WINAPI IUnknown_AtomicRelease(IUnknown **obj) +{ + TRACE("(%p)\n", obj); + + if (!obj || !*obj) + return; + + IUnknown_Release(*obj); + *obj = NULL; +} + +HRESULT WINAPI IUnknown_GetSite(IUnknown *unk, REFIID iid, void **site) +{ + IObjectWithSite *obj = NULL; + HRESULT hr = E_INVALIDARG; + + TRACE("(%p, %s, %p)\n", unk, debugstr_guid(iid), site); + + if (unk && iid && site) + { + hr = IUnknown_QueryInterface(unk, &IID_IObjectWithSite, (void **)&obj); + if (SUCCEEDED(hr) && obj) + { + hr = IObjectWithSite_GetSite(obj, iid, site); + IObjectWithSite_Release(obj); + } + } + + return hr; +} + +HRESULT WINAPI IUnknown_QueryService(IUnknown *obj, REFGUID sid, REFIID iid, void **out) +{ + IServiceProvider *provider = NULL; + HRESULT hr; + + if (!out) + return E_FAIL; + + *out = NULL; + + if (!obj) + return E_FAIL; + + hr = IUnknown_QueryInterface(obj, &IID_IServiceProvider, (void **)&provider); + if (hr == S_OK && provider) + { + TRACE("Using provider %p.\n", provider); + + hr = IServiceProvider_QueryService(provider, sid, iid, out); + + TRACE("Provider %p returned %p.\n", provider, *out); + + IServiceProvider_Release(provider); + } + + return hr; +} + +void WINAPI IUnknown_Set(IUnknown **dest, IUnknown *src) +{ + TRACE("(%p, %p)\n", dest, src); + + IUnknown_AtomicRelease(dest); + + if (src) + { + IUnknown_AddRef(src); + *dest = src; + } +} + +HRESULT WINAPI IUnknown_SetSite(IUnknown *obj, IUnknown *site) +{ + IInternetSecurityManager *sec_manager; + IObjectWithSite *objwithsite; + HRESULT hr; + + if (!obj) + return E_FAIL; + + hr = IUnknown_QueryInterface(obj, &IID_IObjectWithSite, (void **)&objwithsite); + TRACE("ObjectWithSite %p, hr %#lx.\n", objwithsite, hr); + if (SUCCEEDED(hr)) + { + hr = IObjectWithSite_SetSite(objwithsite, site); + TRACE("SetSite() hr %#lx.\n", hr); + IObjectWithSite_Release(objwithsite); + } + else + { + hr = IUnknown_QueryInterface(obj, &IID_IInternetSecurityManager, (void **)&sec_manager); + TRACE("InternetSecurityManager %p, hr %#lx.\n", sec_manager, hr); + if (FAILED(hr)) + return hr; + + hr = IInternetSecurityManager_SetSecuritySite(sec_manager, (IInternetSecurityMgrSite *)site); + TRACE("SetSecuritySite() hr %#lx.\n", hr); + IInternetSecurityManager_Release(sec_manager); + } + + return hr; +} + +HRESULT WINAPI SetCurrentProcessExplicitAppUserModelID(const WCHAR *appid) +{ + FIXME("%s: stub\n", debugstr_w(appid)); + return S_OK; +} + +HRESULT WINAPI GetCurrentProcessExplicitAppUserModelID(const WCHAR **appid) +{ + FIXME("%p: stub\n", appid); + *appid = NULL; + return E_NOTIMPL; +} + +/************************************************************************* + * CommandLineToArgvW [SHCORE.@] + * + * We must interpret the quotes in the command line to rebuild the argv + * array correctly: + * - arguments are separated by spaces or tabs + * - quotes serve as optional argument delimiters + * '"a b"' -> 'a b' + * - escaped quotes must be converted back to '"' + * '\"' -> '"' + * - consecutive backslashes preceding a quote see their number halved with + * the remainder escaping the quote: + * 2n backslashes + quote -> n backslashes + quote as an argument delimiter + * 2n+1 backslashes + quote -> n backslashes + literal quote + * - backslashes that are not followed by a quote are copied literally: + * 'a\b' -> 'a\b' + * 'a\\b' -> 'a\\b' + * - in quoted strings, consecutive quotes see their number divided by three + * with the remainder modulo 3 deciding whether to close the string or not. + * Note that the opening quote must be counted in the consecutive quotes, + * that's the (1+) below: + * (1+) 3n quotes -> n quotes + * (1+) 3n+1 quotes -> n quotes plus closes the quoted string + * (1+) 3n+2 quotes -> n+1 quotes plus closes the quoted string + * - in unquoted strings, the first quote opens the quoted string and the + * remaining consecutive quotes follow the above rule. + */ +WCHAR** WINAPI CommandLineToArgvW(const WCHAR *cmdline, int *numargs) +{ + int qcount, bcount; + const WCHAR *s; + WCHAR **argv; + DWORD argc; + WCHAR *d; + + if (!numargs) + { + SetLastError(ERROR_INVALID_PARAMETER); + return NULL; + } + + if (*cmdline == 0) + { + /* Return the path to the executable */ + DWORD len, deslen = MAX_PATH, size; + + size = sizeof(WCHAR *) * 2 + deslen * sizeof(WCHAR); + for (;;) + { + if (!(argv = LocalAlloc(LMEM_FIXED, size))) return NULL; + len = GetModuleFileNameW(0, (WCHAR *)(argv + 2), deslen); + if (!len) + { + LocalFree(argv); + return NULL; + } + if (len < deslen) break; + deslen *= 2; + size = sizeof(WCHAR *) * 2 + deslen * sizeof(WCHAR); + LocalFree(argv); + } + argv[0] = (WCHAR *)(argv + 2); + argv[1] = NULL; + *numargs = 1; + + return argv; + } + + /* --- First count the arguments */ + argc = 1; + s = cmdline; + /* The first argument, the executable path, follows special rules */ + if (*s == '"') + { + /* The executable path ends at the next quote, no matter what */ + s++; + while (*s) + if (*s++ == '"') + break; + } + else + { + /* The executable path ends at the next space, no matter what */ + while (*s && *s != ' ' && *s != '\t') + s++; + } + /* skip to the first argument, if any */ + while (*s == ' ' || *s == '\t') + s++; + if (*s) + argc++; + + /* Analyze the remaining arguments */ + qcount = bcount = 0; + while (*s) + { + if ((*s == ' ' || *s == '\t') && qcount == 0) + { + /* skip to the next argument and count it if any */ + while (*s == ' ' || *s == '\t') + s++; + if (*s) + argc++; + bcount = 0; + } + else if (*s == '\\') + { + /* '\', count them */ + bcount++; + s++; + } + else if (*s == '"') + { + /* '"' */ + if ((bcount & 1) == 0) + qcount++; /* unescaped '"' */ + s++; + bcount = 0; + /* consecutive quotes, see comment in copying code below */ + while (*s == '"') + { + qcount++; + s++; + } + qcount = qcount % 3; + if (qcount == 2) + qcount = 0; + } + else + { + /* a regular character */ + bcount = 0; + s++; + } + } + + /* Allocate in a single lump, the string array, and the strings that go + * with it. This way the caller can make a single LocalFree() call to free + * both, as per MSDN. + */ + argv = LocalAlloc(LMEM_FIXED, (argc + 1) * sizeof(WCHAR *) + (lstrlenW(cmdline) + 1) * sizeof(WCHAR)); + if (!argv) + return NULL; + + /* --- Then split and copy the arguments */ + argv[0] = d = lstrcpyW((WCHAR *)(argv + argc + 1), cmdline); + argc = 1; + /* The first argument, the executable path, follows special rules */ + if (*d == '"') + { + /* The executable path ends at the next quote, no matter what */ + s = d + 1; + while (*s) + { + if (*s == '"') + { + s++; + break; + } + *d++ = *s++; + } + } + else + { + /* The executable path ends at the next space, no matter what */ + while (*d && *d != ' ' && *d != '\t') + d++; + s = d; + if (*s) + s++; + } + /* close the executable path */ + *d++ = 0; + /* skip to the first argument and initialize it if any */ + while (*s == ' ' || *s == '\t') + s++; + if (!*s) + { + /* There are no parameters so we are all done */ + argv[argc] = NULL; + *numargs = argc; + return argv; + } + + /* Split and copy the remaining arguments */ + argv[argc++] = d; + qcount = bcount = 0; + while (*s) + { + if ((*s == ' ' || *s == '\t') && qcount == 0) + { + /* close the argument */ + *d++ = 0; + bcount = 0; + + /* skip to the next one and initialize it if any */ + do { + s++; + } while (*s == ' ' || *s == '\t'); + if (*s) + argv[argc++] = d; + } + else if (*s=='\\') + { + *d++ = *s++; + bcount++; + } + else if (*s == '"') + { + if ((bcount & 1) == 0) + { + /* Preceded by an even number of '\', this is half that + * number of '\', plus a quote which we erase. + */ + d -= bcount / 2; + qcount++; + } + else + { + /* Preceded by an odd number of '\', this is half that + * number of '\' followed by a '"' + */ + d = d - bcount / 2 - 1; + *d++ = '"'; + } + s++; + bcount = 0; + /* Now count the number of consecutive quotes. Note that qcount + * already takes into account the opening quote if any, as well as + * the quote that lead us here. + */ + while (*s == '"') + { + if (++qcount == 3) + { + *d++ = '"'; + qcount = 0; + } + s++; + } + if (qcount == 2) + qcount = 0; + } + else + { + /* a regular character */ + *d++ = *s++; + bcount = 0; + } + } + *d = '\0'; + argv[argc] = NULL; + *numargs = argc; + + return argv; +} + +struct shstream +{ + IStream IStream_iface; + LONG refcount; + + union + { + struct + { + BYTE *buffer; + DWORD length; + DWORD position; + + HKEY hkey; + WCHAR *valuename; + } mem; + struct + { + HANDLE handle; + DWORD mode; + WCHAR *path; + } file; + } u; +}; + +static inline struct shstream *impl_from_IStream(IStream *iface) +{ + return CONTAINING_RECORD(iface, struct shstream, IStream_iface); +} + +static HRESULT WINAPI shstream_QueryInterface(IStream *iface, REFIID riid, void **out) +{ + struct shstream *stream = impl_from_IStream(iface); + + TRACE("(%p)->(%s, %p)\n", stream, debugstr_guid(riid), out); + + if (IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_IStream) || + IsEqualIID(riid, &IID_ISequentialStream)) + { + *out = iface; + IStream_AddRef(iface); + return S_OK; + } + + *out = NULL; + WARN("Unsupported interface %s.\n", debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI shstream_AddRef(IStream *iface) +{ + struct shstream *stream = impl_from_IStream(iface); + ULONG refcount = InterlockedIncrement(&stream->refcount); + + TRACE("%p, refcount %lu.\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI memstream_Release(IStream *iface) +{ + struct shstream *stream = impl_from_IStream(iface); + ULONG refcount = InterlockedDecrement(&stream->refcount); + + TRACE("%p, refcount %lu.\n", iface, refcount); + + if (!refcount) + { + free(stream->u.mem.buffer); + free(stream); + } + + return refcount; +} + +static HRESULT WINAPI memstream_Read(IStream *iface, void *buff, ULONG buff_size, ULONG *read_len) +{ + struct shstream *stream = impl_from_IStream(iface); + DWORD length; + + TRACE("%p, %p, %lu, %p.\n", iface, buff, buff_size, read_len); + + if (stream->u.mem.position >= stream->u.mem.length) + { + if (read_len) + *read_len = 0; + return S_FALSE; + } + + length = stream->u.mem.length - stream->u.mem.position; + if (buff_size < length) + length = buff_size; + + memmove(buff, stream->u.mem.buffer + stream->u.mem.position, length); + stream->u.mem.position += length; + + if (read_len) + *read_len = length; + + return S_OK; +} + +static HRESULT WINAPI memstream_Write(IStream *iface, const void *buff, ULONG buff_size, ULONG *written) +{ + struct shstream *stream = impl_from_IStream(iface); + DWORD length = stream->u.mem.position + buff_size; + + TRACE("%p, %p, %lu, %p.\n", iface, buff, buff_size, written); + + if (length < stream->u.mem.position) /* overflow */ + return STG_E_INSUFFICIENTMEMORY; + + if (length > stream->u.mem.length) + { + BYTE *buffer = _recalloc(stream->u.mem.buffer, 1, length); + if (!buffer) + return STG_E_INSUFFICIENTMEMORY; + + stream->u.mem.length = length; + stream->u.mem.buffer = buffer; + } + memmove(stream->u.mem.buffer + stream->u.mem.position, buff, buff_size); + stream->u.mem.position += buff_size; /* adjust pointer */ + + if (written) + *written = buff_size; + + return S_OK; +} + +static HRESULT WINAPI memstream_Seek(IStream *iface, LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER*new_pos) +{ + struct shstream *stream = impl_from_IStream(iface); + LARGE_INTEGER tmp; + + TRACE("%p, %s, %ld, %p.\n", iface, wine_dbgstr_longlong(move.QuadPart), origin, new_pos); + + if (origin == STREAM_SEEK_SET) + tmp = move; + else if (origin == STREAM_SEEK_CUR) + tmp.QuadPart = stream->u.mem.position + move.QuadPart; + else if (origin == STREAM_SEEK_END) + tmp.QuadPart = stream->u.mem.length + move.QuadPart; + else + return STG_E_INVALIDPARAMETER; + + if (tmp.QuadPart < 0) + return STG_E_INVALIDFUNCTION; + + /* we cut off the high part here */ + stream->u.mem.position = tmp.u.LowPart; + + if (new_pos) + new_pos->QuadPart = stream->u.mem.position; + return S_OK; +} + +static HRESULT WINAPI memstream_SetSize(IStream *iface, ULARGE_INTEGER new_size) +{ + struct shstream *stream = impl_from_IStream(iface); + DWORD length; + BYTE *buffer; + + TRACE("(%p, %s)\n", stream, wine_dbgstr_longlong(new_size.QuadPart)); + + /* we cut off the high part here */ + length = new_size.u.LowPart; + buffer = _recalloc(stream->u.mem.buffer, 1, length); + if (!buffer) + return STG_E_INSUFFICIENTMEMORY; + + stream->u.mem.buffer = buffer; + stream->u.mem.length = length; + + return S_OK; +} + +static HRESULT WINAPI shstream_CopyTo(IStream *iface, IStream *dest, ULARGE_INTEGER size, + ULARGE_INTEGER *read_len, ULARGE_INTEGER *written) +{ + struct shstream *stream = impl_from_IStream(iface); + ULARGE_INTEGER total_read, total_written; + HRESULT hr = S_OK; + BYTE buffer[0x400]; + + TRACE("(%p, %p, %s, %p, %p)\n", stream, dest, wine_dbgstr_longlong(size.QuadPart), read_len, written); + + if (!dest) + return E_POINTER; + + total_read.QuadPart = 0; + total_written.QuadPart = 0; + + while (size.QuadPart > 0) + { + ULONG chunk_size = size.QuadPart >= sizeof(buffer) ? sizeof(buffer) : size.u.LowPart; + ULONG chunk_read, chunk_written; + + hr = IStream_Read(iface, buffer, chunk_size, &chunk_read); + if (FAILED(hr)) + break; + + total_read.QuadPart += chunk_read; + + if (chunk_read) + { + hr = IStream_Write(dest, buffer, chunk_read, &chunk_written); + if (FAILED(hr)) + break; + + total_written.QuadPart += chunk_written; + } + + if (chunk_read != chunk_size) + size.QuadPart = 0; + else + size.QuadPart -= chunk_read; + } + + if (read_len) + read_len->QuadPart = total_read.QuadPart; + if (written) + written->QuadPart = total_written.QuadPart; + + return hr; +} + +static HRESULT WINAPI shstream_Commit(IStream *iface, DWORD flags) +{ + TRACE("%p, %#lx.\n", iface, flags); + + /* Commit is not supported by this stream */ + return E_NOTIMPL; +} + +static HRESULT WINAPI shstream_Revert(IStream *iface) +{ + struct shstream *stream = impl_from_IStream(iface); + + TRACE("(%p)\n", stream); + + /* revert not supported by this stream */ + return E_NOTIMPL; +} + +static HRESULT WINAPI shstream_LockRegion(IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER size, DWORD lock_type) +{ + struct shstream *stream = impl_from_IStream(iface); + + TRACE("(%p)\n", stream); + + /* lock/unlock not supported by this stream */ + return E_NOTIMPL; +} + +static HRESULT WINAPI shstream_UnlockRegion(IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER size, DWORD lock_type) +{ + struct shstream *stream = impl_from_IStream(iface); + + TRACE("(%p)\n", stream); + + /* lock/unlock not supported by this stream */ + return E_NOTIMPL; +} + +static HRESULT WINAPI memstream_Stat(IStream *iface, STATSTG *statstg, DWORD flags) +{ + struct shstream *stream = impl_from_IStream(iface); + + TRACE("%p, %p, %#lx.\n", iface, statstg, flags); + + memset(statstg, 0, sizeof(*statstg)); + statstg->type = STGTY_STREAM; + statstg->cbSize.QuadPart = stream->u.mem.length; + statstg->grfMode = STGM_READWRITE; + + return S_OK; +} + +static HRESULT WINAPI shstream_Clone(IStream *iface, IStream **dest) +{ + struct shstream *stream = impl_from_IStream(iface); + + TRACE("(%p, %p)\n", stream, dest); + + *dest = NULL; + + /* clone not supported by this stream */ + return E_NOTIMPL; +} + +static const IStreamVtbl memstreamvtbl = +{ + shstream_QueryInterface, + shstream_AddRef, + memstream_Release, + memstream_Read, + memstream_Write, + memstream_Seek, + memstream_SetSize, + shstream_CopyTo, + shstream_Commit, + shstream_Revert, + shstream_LockRegion, + shstream_UnlockRegion, + memstream_Stat, + shstream_Clone, +}; + +static struct shstream *shstream_create(const IStreamVtbl *vtbl, const BYTE *data, UINT data_len) +{ + struct shstream *stream; + + if (!data) + data_len = 0; + + stream = malloc(sizeof(*stream)); + stream->IStream_iface.lpVtbl = vtbl; + stream->refcount = 1; + stream->u.mem.buffer = malloc(data_len); + if (!stream->u.mem.buffer) + { + free(stream); + return NULL; + } + memcpy(stream->u.mem.buffer, data, data_len); + stream->u.mem.length = data_len; + stream->u.mem.position = 0; + + return stream; +} + +/************************************************************************* + * SHCreateMemStream [SHCORE.@] + * + * Create an IStream object on a block of memory. + * + * PARAMS + * data [I] Memory block to create the IStream object on + * data_len [I] Length of data block + * + * RETURNS + * Success: A pointer to the IStream object. + * Failure: NULL, if any parameters are invalid or an error occurs. + * + * NOTES + * A copy of the memory block is made, it's freed when the stream is released. + */ +IStream * WINAPI SHCreateMemStream(const BYTE *data, UINT data_len) +{ + struct shstream *stream; + + TRACE("(%p, %u)\n", data, data_len); + + stream = shstream_create(&memstreamvtbl, data, data_len); + return stream ? &stream->IStream_iface : NULL; +} + +static ULONG WINAPI filestream_Release(IStream *iface) +{ + struct shstream *stream = impl_from_IStream(iface); + ULONG refcount = InterlockedDecrement(&stream->refcount); + + TRACE("%p, refcount %lu.\n", iface, refcount); + + if (!refcount) + { + CloseHandle(stream->u.file.handle); + free(stream->u.file.path); + free(stream); + } + + return refcount; +} + +static HRESULT WINAPI filestream_Read(IStream *iface, void *buff, ULONG size, ULONG *read_len) +{ + struct shstream *stream = impl_from_IStream(iface); + DWORD read = 0; + + TRACE("%p, %p, %lu, %p.\n", iface, buff, size, read_len); + + if (!ReadFile(stream->u.file.handle, buff, size, &read, NULL)) + { + WARN("error %ld reading file\n", GetLastError()); + return S_FALSE; + } + + if (read_len) + *read_len = read; + + return read == size ? S_OK : S_FALSE; +} + +static HRESULT WINAPI filestream_Write(IStream *iface, const void *buff, ULONG size, ULONG *written) +{ + struct shstream *stream = impl_from_IStream(iface); + DWORD written_len = 0; + + TRACE("%p, %p, %lu, %p.\n", iface, buff, size, written); + + switch (stream->u.file.mode & 0xf) + { + case STGM_WRITE: + case STGM_READWRITE: + break; + default: + return STG_E_ACCESSDENIED; + } + + if (!WriteFile(stream->u.file.handle, buff, size, &written_len, NULL)) + return HRESULT_FROM_WIN32(GetLastError()); + + if (written) + *written = written_len; + + return S_OK; +} + +static HRESULT WINAPI filestream_Seek(IStream *iface, LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER *new_pos) +{ + struct shstream *stream = impl_from_IStream(iface); + DWORD position; + + TRACE("%p, %s, %ld, %p.\n", iface, wine_dbgstr_longlong(move.QuadPart), origin, new_pos); + + position = SetFilePointer(stream->u.file.handle, move.u.LowPart, NULL, origin); + if (position == INVALID_SET_FILE_POINTER) + return HRESULT_FROM_WIN32(GetLastError()); + + if (new_pos) + { + new_pos->u.HighPart = 0; + new_pos->u.LowPart = position; + } + + return S_OK; +} + +static HRESULT WINAPI filestream_SetSize(IStream *iface, ULARGE_INTEGER size) +{ + struct shstream *stream = impl_from_IStream(iface); + LARGE_INTEGER origin, move; + + TRACE("(%p, %s)\n", stream, wine_dbgstr_longlong(size.QuadPart)); + + move.QuadPart = 0; + if (!SetFilePointerEx(stream->u.file.handle, move, &origin, FILE_CURRENT)) + return E_FAIL; + + move.QuadPart = size.QuadPart; + if (!SetFilePointerEx(stream->u.file.handle, move, NULL, FILE_BEGIN)) + return E_FAIL; + + if (stream->u.file.mode != STGM_READ) + { + if (!SetEndOfFile(stream->u.file.handle)) + return E_FAIL; + if (!SetFilePointerEx(stream->u.file.handle, origin, NULL, FILE_BEGIN)) + return E_FAIL; + } + + return S_OK; +} + +static HRESULT WINAPI filestream_CopyTo(IStream *iface, IStream *dest, ULARGE_INTEGER size, + ULARGE_INTEGER *read_len, ULARGE_INTEGER *written) +{ + struct shstream *stream = impl_from_IStream(iface); + HRESULT hr = S_OK; + char buff[1024]; + + TRACE("(%p, %p, %s, %p, %p)\n", stream, dest, wine_dbgstr_longlong(size.QuadPart), read_len, written); + + if (read_len) + read_len->QuadPart = 0; + if (written) + written->QuadPart = 0; + + if (!dest) + return S_OK; + + while (size.QuadPart) + { + ULONG left, read_chunk, written_chunk; + + left = size.QuadPart > sizeof(buff) ? sizeof(buff) : size.QuadPart; + + /* Read */ + hr = IStream_Read(iface, buff, left, &read_chunk); + if (FAILED(hr) || read_chunk == 0) + break; + if (read_len) + read_len->QuadPart += read_chunk; + + /* Write */ + hr = IStream_Write(dest, buff, read_chunk, &written_chunk); + if (written) + written->QuadPart += written_chunk; + if (FAILED(hr) || written_chunk != left) + break; + + size.QuadPart -= left; + } + + return hr; +} + +static HRESULT WINAPI filestream_Commit(IStream *iface, DWORD flags) +{ + TRACE("%p, %#lx.\n", iface, flags); + + return S_OK; +} + +static HRESULT WINAPI filestream_Stat(IStream *iface, STATSTG *statstg, DWORD flags) +{ + struct shstream *stream = impl_from_IStream(iface); + BY_HANDLE_FILE_INFORMATION fi; + + TRACE("%p, %p, %#lx.\n", iface, statstg, flags); + + if (!statstg) + return STG_E_INVALIDPOINTER; + + memset(&fi, 0, sizeof(fi)); + GetFileInformationByHandle(stream->u.file.handle, &fi); + + if (flags & STATFLAG_NONAME) + statstg->pwcsName = NULL; + else + { + int len = lstrlenW(stream->u.file.path); + if ((statstg->pwcsName = CoTaskMemAlloc((len + 1) * sizeof(WCHAR)))) + memcpy(statstg->pwcsName, stream->u.file.path, (len + 1) * sizeof(WCHAR)); + } + statstg->type = 0; + statstg->cbSize.u.LowPart = fi.nFileSizeLow; + statstg->cbSize.u.HighPart = fi.nFileSizeHigh; + statstg->mtime = fi.ftLastWriteTime; + statstg->ctime = fi.ftCreationTime; + statstg->atime = fi.ftLastAccessTime; + statstg->grfMode = stream->u.file.mode; + statstg->grfLocksSupported = 0; + memcpy(&statstg->clsid, &IID_IStream, sizeof(CLSID)); + statstg->grfStateBits = 0; + statstg->reserved = 0; + + return S_OK; +} + +static const IStreamVtbl filestreamvtbl = +{ + shstream_QueryInterface, + shstream_AddRef, + filestream_Release, + filestream_Read, + filestream_Write, + filestream_Seek, + filestream_SetSize, + filestream_CopyTo, + filestream_Commit, + shstream_Revert, + shstream_LockRegion, + shstream_UnlockRegion, + filestream_Stat, + shstream_Clone, +}; + +/************************************************************************* + * SHCreateStreamOnFileEx [SHCORE.@] + */ +HRESULT WINAPI SHCreateStreamOnFileEx(const WCHAR *path, DWORD mode, DWORD attributes, + BOOL create, IStream *template, IStream **ret) +{ + DWORD access, share, creation_disposition, len; + struct shstream *stream; + HANDLE hFile; + + TRACE("%s, %ld, %#lx, %d, %p, %p)\n", debugstr_w(path), mode, attributes, + create, template, ret); + + if (!path || !ret || template) + return E_INVALIDARG; + + *ret = NULL; + + /* Access */ + switch (mode & 0xf) + { + case STGM_WRITE: + case STGM_READWRITE: + access = GENERIC_READ | GENERIC_WRITE; + break; + case STGM_READ: + access = GENERIC_READ; + break; + default: + return E_INVALIDARG; + } + + /* Sharing */ + switch (mode & 0xf0) + { + case 0: + case STGM_SHARE_DENY_NONE: + share = FILE_SHARE_READ | FILE_SHARE_WRITE; + break; + case STGM_SHARE_DENY_READ: + share = FILE_SHARE_WRITE; + break; + case STGM_SHARE_DENY_WRITE: + share = FILE_SHARE_READ; + break; + case STGM_SHARE_EXCLUSIVE: + share = 0; + break; + default: + return E_INVALIDARG; + } + + switch (mode & 0xf000) + { + case STGM_FAILIFTHERE: + creation_disposition = create ? CREATE_NEW : OPEN_EXISTING; + break; + case STGM_CREATE: + creation_disposition = CREATE_ALWAYS; + break; + default: + return E_INVALIDARG; + } + + hFile = CreateFileW(path, access, share, NULL, creation_disposition, attributes, 0); + if (hFile == INVALID_HANDLE_VALUE) + return HRESULT_FROM_WIN32(GetLastError()); + + stream = malloc(sizeof(*stream)); + stream->IStream_iface.lpVtbl = &filestreamvtbl; + stream->refcount = 1; + stream->u.file.handle = hFile; + stream->u.file.mode = mode; + + len = lstrlenW(path); + stream->u.file.path = malloc((len + 1) * sizeof(WCHAR)); + memcpy(stream->u.file.path, path, (len + 1) * sizeof(WCHAR)); + + *ret = &stream->IStream_iface; + + return S_OK; +} + +/************************************************************************* + * SHCreateStreamOnFileW [SHCORE.@] + */ +HRESULT WINAPI SHCreateStreamOnFileW(const WCHAR *path, DWORD mode, IStream **stream) +{ + TRACE("%s, %#lx, %p.\n", debugstr_w(path), mode, stream); + + if (!path || !stream) + return E_INVALIDARG; + + if ((mode & (STGM_CONVERT | STGM_DELETEONRELEASE | STGM_TRANSACTED)) != 0) + return E_INVALIDARG; + + return SHCreateStreamOnFileEx(path, mode, 0, FALSE, NULL, stream); +} + +/************************************************************************* + * SHCreateStreamOnFileA [SHCORE.@] + */ +HRESULT WINAPI SHCreateStreamOnFileA(const char *path, DWORD mode, IStream **stream) +{ + WCHAR *pathW; + HRESULT hr; + DWORD len; + + TRACE("%s, %#lx, %p.\n", debugstr_a(path), mode, stream); + + if (!path) + return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); + + len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0); + pathW = malloc(len * sizeof(WCHAR)); + if (!pathW) + return E_OUTOFMEMORY; + + MultiByteToWideChar(CP_ACP, 0, path, -1, pathW, len); + hr = SHCreateStreamOnFileW(pathW, mode, stream); + free(pathW); + + return hr; +} + +static ULONG WINAPI regstream_Release(IStream *iface) +{ + struct shstream *stream = impl_from_IStream(iface); + ULONG refcount = InterlockedDecrement(&stream->refcount); + + TRACE("%p, refcount %lu.\n", iface, refcount); + + if (!refcount) + { + if (stream->u.mem.hkey) + { + if (stream->u.mem.length) + RegSetValueExW(stream->u.mem.hkey, stream->u.mem.valuename, 0, REG_BINARY, + (const BYTE *)stream->u.mem.buffer, stream->u.mem.length); + else + RegDeleteValueW(stream->u.mem.hkey, stream->u.mem.valuename); + RegCloseKey(stream->u.mem.hkey); + } + CoTaskMemFree(stream->u.mem.valuename); + free(stream->u.mem.buffer); + free(stream); + } + + return refcount; +} + +static const IStreamVtbl regstreamvtbl = +{ + shstream_QueryInterface, + shstream_AddRef, + regstream_Release, + memstream_Read, + memstream_Write, + memstream_Seek, + memstream_SetSize, + shstream_CopyTo, + shstream_Commit, + shstream_Revert, + shstream_LockRegion, + shstream_UnlockRegion, + memstream_Stat, + shstream_Clone, +}; + +/************************************************************************* + * SHOpenRegStream2W [SHCORE.@] + */ +IStream * WINAPI SHOpenRegStream2W(HKEY hKey, const WCHAR *subkey, const WCHAR *value, DWORD mode) +{ + struct shstream *stream; + HKEY hStrKey = NULL; + BYTE *buff = NULL; + DWORD length = 0; + LONG ret; + + TRACE("%p, %s, %s, %#lx.\n", hKey, debugstr_w(subkey), debugstr_w(value), mode); + + if (mode == STGM_READ) + ret = RegOpenKeyExW(hKey, subkey, 0, KEY_READ, &hStrKey); + else /* in write mode we make sure the subkey exits */ + ret = RegCreateKeyExW(hKey, subkey, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &hStrKey, NULL); + + if (ret == ERROR_SUCCESS) + { + if (mode == STGM_READ || mode == STGM_READWRITE) + { + /* read initial data */ + ret = RegQueryValueExW(hStrKey, value, 0, 0, 0, &length); + if (ret == ERROR_SUCCESS && length) + { + buff = malloc(length); + RegQueryValueExW(hStrKey, value, 0, 0, buff, &length); + } + } + + if (!length) + buff = malloc(length); + + stream = shstream_create(®streamvtbl, buff, length); + free(buff); + if (stream) + { + stream->u.mem.hkey = hStrKey; + SHStrDupW(value, &stream->u.mem.valuename); + return &stream->IStream_iface; + } + } + + if (hStrKey) + RegCloseKey(hStrKey); + + return NULL; +} + +/************************************************************************* + * SHOpenRegStream2A [SHCORE.@] + */ +IStream * WINAPI SHOpenRegStream2A(HKEY hKey, const char *subkey, const char *value, DWORD mode) +{ + WCHAR *subkeyW = NULL, *valueW = NULL; + IStream *stream; + + TRACE("%p, %s, %s, %#lx.\n", hKey, debugstr_a(subkey), debugstr_a(value), mode); + + if (subkey && FAILED(SHStrDupA(subkey, &subkeyW))) + return NULL; + if (value && FAILED(SHStrDupA(value, &valueW))) + { + CoTaskMemFree(subkeyW); + return NULL; + } + + stream = SHOpenRegStream2W(hKey, subkeyW, valueW, mode); + CoTaskMemFree(subkeyW); + CoTaskMemFree(valueW); + return stream; +} + +/************************************************************************* + * SHOpenRegStreamA [SHCORE.@] + */ +IStream * WINAPI SHOpenRegStreamA(HKEY hkey, const char *subkey, const char *value, DWORD mode) +{ + WCHAR *subkeyW = NULL, *valueW = NULL; + IStream *stream; + + TRACE("%p, %s, %s, %#lx.\n", hkey, debugstr_a(subkey), debugstr_a(value), mode); + + if (subkey && FAILED(SHStrDupA(subkey, &subkeyW))) + return NULL; + if (value && FAILED(SHStrDupA(value, &valueW))) + { + CoTaskMemFree(subkeyW); + return NULL; + } + + stream = SHOpenRegStreamW(hkey, subkeyW, valueW, mode); + CoTaskMemFree(subkeyW); + CoTaskMemFree(valueW); + return stream; +} + +static ULONG WINAPI dummystream_AddRef(IStream *iface) +{ + TRACE("()\n"); + return 2; +} + +static ULONG WINAPI dummystream_Release(IStream *iface) +{ + TRACE("()\n"); + return 1; +} + +static HRESULT WINAPI dummystream_Read(IStream *iface, void *buff, ULONG buff_size, ULONG *read_len) +{ + if (read_len) + *read_len = 0; + + return E_NOTIMPL; +} + +static const IStreamVtbl dummystreamvtbl = +{ + shstream_QueryInterface, + dummystream_AddRef, + dummystream_Release, + dummystream_Read, + memstream_Write, + memstream_Seek, + memstream_SetSize, + shstream_CopyTo, + shstream_Commit, + shstream_Revert, + shstream_LockRegion, + shstream_UnlockRegion, + memstream_Stat, + shstream_Clone, +}; + +static struct shstream dummyregstream = { { &dummystreamvtbl } }; + +/************************************************************************* + * SHOpenRegStreamW [SHCORE.@] + */ +IStream * WINAPI SHOpenRegStreamW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, DWORD mode) +{ + IStream *stream; + + TRACE("%p, %s, %s, %#lx.\n", hkey, debugstr_w(subkey), debugstr_w(value), mode); + stream = SHOpenRegStream2W(hkey, subkey, value, mode); + return stream ? stream : &dummyregstream.IStream_iface; +} + +struct threadref +{ + IUnknown IUnknown_iface; + LONG *refcount; +}; + +static inline struct threadref *threadref_impl_from_IUnknown(IUnknown *iface) +{ + return CONTAINING_RECORD(iface, struct threadref, IUnknown_iface); +} + +static HRESULT WINAPI threadref_QueryInterface(IUnknown *iface, REFIID riid, void **out) +{ + struct threadref *threadref = threadref_impl_from_IUnknown(iface); + + TRACE("(%p, %s, %p)\n", threadref, debugstr_guid(riid), out); + + if (out == NULL) + return E_POINTER; + + if (IsEqualGUID(&IID_IUnknown, riid)) + { + *out = iface; + IUnknown_AddRef(iface); + return S_OK; + } + + *out = NULL; + WARN("Interface %s not supported.\n", debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI threadref_AddRef(IUnknown *iface) +{ + struct threadref *threadref = threadref_impl_from_IUnknown(iface); + LONG refcount = InterlockedIncrement(threadref->refcount); + + TRACE("%p, refcount %ld.\n", threadref, refcount); + + return refcount; +} + +static ULONG WINAPI threadref_Release(IUnknown *iface) +{ + struct threadref *threadref = threadref_impl_from_IUnknown(iface); + LONG refcount = InterlockedDecrement(threadref->refcount); + + TRACE("%p, refcount %ld.\n", threadref, refcount); + + if (!refcount) + free(threadref); + + return refcount; +} + +static const IUnknownVtbl threadrefvtbl = +{ + threadref_QueryInterface, + threadref_AddRef, + threadref_Release, +}; + +/************************************************************************* + * SHCreateThreadRef [SHCORE.@] + */ +HRESULT WINAPI SHCreateThreadRef(LONG *refcount, IUnknown **out) +{ + struct threadref *threadref; + + TRACE("(%p, %p)\n", refcount, out); + + if (!refcount || !out) + return E_INVALIDARG; + + *out = NULL; + + threadref = malloc(sizeof(*threadref)); + if (!threadref) + return E_OUTOFMEMORY; + threadref->IUnknown_iface.lpVtbl = &threadrefvtbl; + threadref->refcount = refcount; + + *refcount = 1; + *out = &threadref->IUnknown_iface; + + TRACE("Created %p.\n", threadref); + return S_OK; +} + +/************************************************************************* + * SHGetThreadRef [SHCORE.@] + */ +HRESULT WINAPI SHGetThreadRef(IUnknown **out) +{ + TRACE("(%p)\n", out); + + if (shcore_tls == TLS_OUT_OF_INDEXES) + return E_NOINTERFACE; + + *out = TlsGetValue(shcore_tls); + if (!*out) + return E_NOINTERFACE; + + IUnknown_AddRef(*out); + return S_OK; +} + +/************************************************************************* + * SHSetThreadRef [SHCORE.@] + */ +HRESULT WINAPI SHSetThreadRef(IUnknown *obj) +{ + TRACE("(%p)\n", obj); + + if (shcore_tls == TLS_OUT_OF_INDEXES) + return E_NOINTERFACE; + + TlsSetValue(shcore_tls, obj); + return S_OK; +} + +/************************************************************************* + * SHReleaseThreadRef [SHCORE.@] + */ +HRESULT WINAPI SHReleaseThreadRef(void) +{ + FIXME("() - stub!\n"); + return S_OK; +} + +/************************************************************************* + * GetProcessReference [SHCORE.@] + */ +HRESULT WINAPI GetProcessReference(IUnknown **obj) +{ + TRACE("(%p)\n", obj); + + *obj = process_ref; + + if (!process_ref) + return E_FAIL; + + if (*obj) + IUnknown_AddRef(*obj); + + return S_OK; +} + +/************************************************************************* + * SetProcessReference [SHCORE.@] + */ +void WINAPI SetProcessReference(IUnknown *obj) +{ + TRACE("(%p)\n", obj); + + process_ref = obj; +} + +struct thread_data +{ + LPTHREAD_START_ROUTINE thread_proc; + LPTHREAD_START_ROUTINE callback; + void *data; + DWORD flags; + HANDLE hEvent; + IUnknown *thread_ref; + IUnknown *process_ref; +}; + +static DWORD WINAPI shcore_thread_wrapper(void *data) +{ + struct thread_data thread_data; + HRESULT hr = E_FAIL; + DWORD retval; + + TRACE("(%p)\n", data); + + /* We are now executing in the context of the newly created thread. + * So we copy the data passed to us (it is on the stack of the function + * that called us, which is waiting for us to signal an event before + * returning). */ + thread_data = *(struct thread_data *)data; + + if (thread_data.flags & CTF_COINIT) + { + hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); + if (FAILED(hr)) + hr = CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE); + } + + if (thread_data.callback) + thread_data.callback(thread_data.data); + + /* Signal the thread that created us; it can return now. */ + SetEvent(thread_data.hEvent); + + /* Execute the callers start code. */ + retval = thread_data.thread_proc(thread_data.data); + + /* Release thread and process references. */ + if (thread_data.thread_ref) + IUnknown_Release(thread_data.thread_ref); + + if (thread_data.process_ref) + IUnknown_Release(thread_data.process_ref); + + if (SUCCEEDED(hr)) + CoUninitialize(); + + return retval; +} + +/************************************************************************* + * SHCreateThread [SHCORE.@] + */ +BOOL WINAPI SHCreateThread(LPTHREAD_START_ROUTINE thread_proc, void *data, DWORD flags, LPTHREAD_START_ROUTINE callback) +{ + struct thread_data thread_data; + BOOL called = FALSE; + + TRACE("%p, %p, %#lx, %p.\n", thread_proc, data, flags, callback); + + thread_data.thread_proc = thread_proc; + thread_data.callback = callback; + thread_data.data = data; + thread_data.flags = flags; + thread_data.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL); + + if (flags & CTF_THREAD_REF) + SHGetThreadRef(&thread_data.thread_ref); + else + thread_data.thread_ref = NULL; + + if (flags & CTF_PROCESS_REF) + GetProcessReference(&thread_data.process_ref); + else + thread_data.process_ref = NULL; + + /* Create the thread */ + if (thread_data.hEvent) + { + HANDLE hThread; + DWORD retval; + + hThread = CreateThread(NULL, 0, shcore_thread_wrapper, &thread_data, 0, &retval); + if (hThread) + { + /* Wait for the thread to signal us to continue */ + WaitForSingleObject(thread_data.hEvent, INFINITE); + CloseHandle(hThread); + called = TRUE; + } + CloseHandle(thread_data.hEvent); + } + + if (!called) + { + if (!thread_data.callback && flags & CTF_INSIST) + { + /* Couldn't call, call synchronously */ + thread_data.thread_proc(data); + called = TRUE; + } + else + { + if (thread_data.thread_ref) + IUnknown_Release(thread_data.thread_ref); + + if (thread_data.process_ref) + IUnknown_Release(thread_data.process_ref); + } + } + + return called; +} + +/************************************************************************* + * SHStrDupW [SHCORE.@] + */ +HRESULT WINAPI SHStrDupW(const WCHAR *src, WCHAR **dest) +{ + size_t len; + + TRACE("(%s, %p)\n", debugstr_w(src), dest); + + *dest = NULL; + + if (!src) + return E_INVALIDARG; + + len = (lstrlenW(src) + 1) * sizeof(WCHAR); + *dest = CoTaskMemAlloc(len); + if (!*dest) + return E_OUTOFMEMORY; + + memcpy(*dest, src, len); + + return S_OK; +} + +/************************************************************************* + * SHStrDupA [SHCORE.@] + */ +HRESULT WINAPI SHStrDupA(const char *src, WCHAR **dest) +{ + DWORD len; + + *dest = NULL; + + if (!src) + return E_INVALIDARG; + + len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0); + *dest = CoTaskMemAlloc(len * sizeof(WCHAR)); + if (!*dest) + return E_OUTOFMEMORY; + + MultiByteToWideChar(CP_ACP, 0, src, -1, *dest, len); + + return S_OK; +} + +/************************************************************************* + * SHAnsiToAnsi [SHCORE.@] + */ +DWORD WINAPI SHAnsiToAnsi(const char *src, char *dest, int dest_len) +{ + DWORD ret; + + TRACE("(%s, %p, %d)\n", debugstr_a(src), dest, dest_len); + + if (!src || !dest || dest_len <= 0) + return 0; + + lstrcpynA(dest, src, dest_len); + ret = strlen(dest); + + return src[ret] ? 0 : ret + 1; +} + +/************************************************************************* + * SHUnicodeToAnsi [SHCORE.@] + */ +DWORD WINAPI SHUnicodeToAnsi(const WCHAR *src, char *dest, int dest_len) +{ + int ret = 1; + + TRACE("(%s, %p, %d)\n", debugstr_w(src), dest, dest_len); + + if (!dest || !dest_len) + return 0; + + if (src) + { + ret = WideCharToMultiByte(CP_ACP, 0, src, -1, dest, dest_len, NULL, NULL); + if (!ret) + { + dest[dest_len - 1] = 0; + ret = dest_len; + } + } + else + dest[0] = 0; + + return ret; +} + +/************************************************************************* + * SHUnicodeToUnicode [SHCORE.@] + */ +DWORD WINAPI SHUnicodeToUnicode(const WCHAR *src, WCHAR *dest, int dest_len) +{ + DWORD ret; + + TRACE("(%s, %p, %d)\n", debugstr_w(src), dest, dest_len); + + if (!src || !dest || dest_len <= 0) + return 0; + + lstrcpynW(dest, src, dest_len); + ret = lstrlenW(dest); + + return src[ret] ? 0 : ret + 1; +} + +/************************************************************************* + * SHAnsiToUnicode [SHCORE.@] + */ +DWORD WINAPI SHAnsiToUnicode(const char *src, WCHAR *dest, int dest_len) +{ + int ret = 1; + + TRACE("(%s, %p, %d)\n", debugstr_a(src), dest, dest_len); + + if (!dest || !dest_len) + return 0; + + if (src) + { + ret = MultiByteToWideChar(CP_ACP, 0, src, -1, dest, dest_len); + if (!ret) + { + dest[dest_len - 1] = 0; + ret = dest_len; + } + } + else + dest[0] = 0; + + return ret; +} + +/************************************************************************* + * SHRegDuplicateHKey [SHCORE.@] + */ +HKEY WINAPI SHRegDuplicateHKey(HKEY hKey) +{ + HKEY newKey = 0; + + RegOpenKeyExW(hKey, 0, 0, MAXIMUM_ALLOWED, &newKey); + TRACE("new key is %p\n", newKey); + return newKey; +} + +/************************************************************************* + * SHDeleteEmptyKeyW [SHCORE.@] + */ +DWORD WINAPI SHDeleteEmptyKeyW(HKEY hkey, const WCHAR *subkey) +{ + DWORD ret, count = 0; + HKEY hsubkey = 0; + + TRACE("(%p, %s)\n", hkey, debugstr_w(subkey)); + + ret = RegOpenKeyExW(hkey, subkey, 0, KEY_READ, &hsubkey); + if (!ret) + { + ret = RegQueryInfoKeyW(hsubkey, NULL, NULL, NULL, &count, + NULL, NULL, NULL, NULL, NULL, NULL, NULL); + RegCloseKey(hsubkey); + if (!ret) + { + if (count) + ret = ERROR_KEY_HAS_CHILDREN; + else + ret = RegDeleteKeyW(hkey, subkey); + } + } + + return ret; +} + +/************************************************************************* + * SHDeleteEmptyKeyA [SHCORE.@] + */ +DWORD WINAPI SHDeleteEmptyKeyA(HKEY hkey, const char *subkey) +{ + WCHAR *subkeyW = NULL; + DWORD ret; + + TRACE("(%p, %s)\n", hkey, debugstr_a(subkey)); + + if (subkey && FAILED(SHStrDupA(subkey, &subkeyW))) + return ERROR_OUTOFMEMORY; + + ret = SHDeleteEmptyKeyW(hkey, subkeyW); + CoTaskMemFree(subkeyW); + return ret; +} + +/************************************************************************* + * SHDeleteKeyW [SHCORE.@] + */ +DWORD WINAPI SHDeleteKeyW(HKEY hkey, const WCHAR *subkey) +{ + TRACE("(%p, %s)\n", hkey, debugstr_w(subkey)); + + return RegDeleteTreeW(hkey, subkey); +} + +/************************************************************************* + * SHDeleteKeyA [SHCORE.@] + */ +DWORD WINAPI SHDeleteKeyA(HKEY hkey, const char *subkey) +{ + TRACE("(%p, %s)\n", hkey, debugstr_a(subkey)); + + return RegDeleteTreeA(hkey, subkey); +} + +/************************************************************************* + * SHDeleteValueW [SHCORE.@] + */ +DWORD WINAPI SHDeleteValueW(HKEY hkey, const WCHAR *subkey, const WCHAR *value) +{ + HKEY hsubkey; + DWORD ret; + + TRACE("(%p, %s, %s)\n", hkey, debugstr_w(subkey), debugstr_w(value)); + + ret = RegOpenKeyExW(hkey, subkey, 0, KEY_SET_VALUE, &hsubkey); + if (!ret) + { + ret = RegDeleteValueW(hsubkey, value); + RegCloseKey(hsubkey); + } + + return ret; +} + +/************************************************************************* + * SHDeleteValueA [SHCORE.@] + */ +DWORD WINAPI SHDeleteValueA(HKEY hkey, const char *subkey, const char *value) +{ + WCHAR *subkeyW = NULL, *valueW = NULL; + DWORD ret; + + TRACE("(%p, %s, %s)\n", hkey, debugstr_a(subkey), debugstr_a(value)); + + if (subkey && FAILED(SHStrDupA(subkey, &subkeyW))) + return ERROR_OUTOFMEMORY; + if (value && FAILED(SHStrDupA(value, &valueW))) + { + CoTaskMemFree(subkeyW); + return ERROR_OUTOFMEMORY; + } + + ret = SHDeleteValueW(hkey, subkeyW, valueW); + CoTaskMemFree(subkeyW); + CoTaskMemFree(valueW); + return ret; +} + +/************************************************************************* + * SHCopyKeyA [SHCORE.@] + */ +DWORD WINAPI SHCopyKeyA(HKEY hkey_src, const char *subkey, HKEY hkey_dst, DWORD reserved) +{ + WCHAR *subkeyW = NULL; + DWORD ret; + + TRACE("%p, %s, %p, %ld.\n", hkey_src, debugstr_a(subkey), hkey_dst, reserved); + + if (subkey && FAILED(SHStrDupA(subkey, &subkeyW))) + return 0; + + ret = SHCopyKeyW(hkey_src, subkeyW, hkey_dst, reserved); + CoTaskMemFree(subkeyW); + return ret; +} + +/************************************************************************* + * SHCopyKeyW [SHCORE.@] + */ +DWORD WINAPI SHCopyKeyW(HKEY hkey_src, const WCHAR *subkey, HKEY hkey_dst, DWORD reserved) +{ + DWORD key_count = 0, value_count = 0, max_key_len = 0; + WCHAR name[MAX_PATH], *ptr_name = name; + BYTE buff[1024], *ptr = buff; + DWORD max_data_len = 0, i; + DWORD ret = 0; + + TRACE("%p, %s, %p, %ld.\n", hkey_src, debugstr_w(subkey), hkey_dst, reserved); + + if (!hkey_dst || !hkey_src) + return ERROR_INVALID_PARAMETER; + + if (subkey) + ret = RegOpenKeyExW(hkey_src, subkey, 0, KEY_ALL_ACCESS, &hkey_src); + + if (ret) + hkey_src = NULL; /* Don't close this key since we didn't open it */ + else + { + DWORD max_value_len; + + ret = RegQueryInfoKeyW(hkey_src, NULL, NULL, NULL, &key_count, &max_key_len, + NULL, &value_count, &max_value_len, &max_data_len, NULL, NULL); + if (!ret) + { + /* Get max size for key/value names */ + max_key_len = max(max_key_len, max_value_len); + + if (max_key_len++ > MAX_PATH - 1) + ptr_name = malloc(max_key_len * sizeof(WCHAR)); + + if (max_data_len > sizeof(buff)) + ptr = malloc(max_data_len); + + if (!ptr_name || !ptr) + ret = ERROR_NOT_ENOUGH_MEMORY; + } + } + + for (i = 0; i < key_count && !ret; i++) + { + HKEY hsubkey_src, hsubkey_dst; + DWORD length = max_key_len; + + ret = RegEnumKeyExW(hkey_src, i, ptr_name, &length, NULL, NULL, NULL, NULL); + if (!ret) + { + ret = RegOpenKeyExW(hkey_src, ptr_name, 0, KEY_READ, &hsubkey_src); + if (!ret) + { + /* Create destination sub key */ + ret = RegCreateKeyW(hkey_dst, ptr_name, &hsubkey_dst); + if (!ret) + { + /* Recursively copy keys and values from the sub key */ + ret = SHCopyKeyW(hsubkey_src, NULL, hsubkey_dst, 0); + RegCloseKey(hsubkey_dst); + } + } + RegCloseKey(hsubkey_src); + } + } + + /* Copy all the values in this key */ + for (i = 0; i < value_count && !ret; i++) + { + DWORD length = max_key_len, type, data_len = max_data_len; + + ret = RegEnumValueW(hkey_src, i, ptr_name, &length, NULL, &type, ptr, &data_len); + if (!ret) { + ret = SHSetValueW(hkey_dst, NULL, ptr_name, type, ptr, data_len); + } + } + + /* Free buffers if allocated */ + if (ptr_name != name) + free(ptr_name); + if (ptr != buff) + free(ptr); + + if (subkey && hkey_src) + RegCloseKey(hkey_src); + + return ret; +} + + +/************************************************************************* + * SHEnumKeyExA [SHCORE.@] + */ +LONG WINAPI SHEnumKeyExA(HKEY hkey, DWORD index, char *subkey, DWORD *length) +{ + TRACE("%p, %ld, %s, %p.\n", hkey, index, debugstr_a(subkey), length); + + return RegEnumKeyExA(hkey, index, subkey, length, NULL, NULL, NULL, NULL); +} + +/************************************************************************* + * SHEnumKeyExW [SHCORE.@] + */ +LONG WINAPI SHEnumKeyExW(HKEY hkey, DWORD index, WCHAR *subkey, DWORD *length) +{ + TRACE("%p, %ld, %s, %p.\n", hkey, index, debugstr_w(subkey), length); + + return RegEnumKeyExW(hkey, index, subkey, length, NULL, NULL, NULL, NULL); +} + +/************************************************************************* + * SHEnumValueA [SHCORE.@] + */ +LONG WINAPI SHEnumValueA(HKEY hkey, DWORD index, char *value, DWORD *length, DWORD *type, + void *data, DWORD *data_len) +{ + TRACE("%p, %ld, %s, %p, %p, %p, %p.\n", hkey, index, debugstr_a(value), length, type, data, data_len); + + return RegEnumValueA(hkey, index, value, length, NULL, type, data, data_len); +} + +/************************************************************************* + * SHEnumValueW [SHCORE.@] + */ +LONG WINAPI SHEnumValueW(HKEY hkey, DWORD index, WCHAR *value, DWORD *length, DWORD *type, + void *data, DWORD *data_len) +{ + TRACE("%p, %ld, %s, %p, %p, %p, %p.\n", hkey, index, debugstr_w(value), length, type, data, data_len); + + return RegEnumValueW(hkey, index, value, length, NULL, type, data, data_len); +} + +/************************************************************************* + * SHQueryValueExW [SHCORE.@] + */ +DWORD WINAPI SHQueryValueExW(HKEY hkey, const WCHAR *name, DWORD *reserved, DWORD *type, + void *buff, DWORD *buff_len) +{ + DWORD ret, value_type, data_len = 0; + + TRACE("(%p, %s, %p, %p, %p, %p)\n", hkey, debugstr_w(name), reserved, type, buff, buff_len); + + if (buff_len) + data_len = *buff_len; + + ret = RegQueryValueExW(hkey, name, reserved, &value_type, buff, &data_len); + if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) + return ret; + + if (buff_len && value_type == REG_EXPAND_SZ) + { + DWORD length; + WCHAR *value; + + if (!buff || ret == ERROR_MORE_DATA) + { + length = data_len; + value = malloc(length); + RegQueryValueExW(hkey, name, reserved, NULL, (BYTE *)value, &length); + length = ExpandEnvironmentStringsW(value, NULL, 0); + } + else + { + length = (lstrlenW(buff) + 1) * sizeof(WCHAR); + value = malloc(length); + memcpy(value, buff, length); + length = ExpandEnvironmentStringsW(value, buff, *buff_len / sizeof(WCHAR)); + if (length > *buff_len) ret = ERROR_MORE_DATA; + } + data_len = max(data_len, length); + free(value); + } + + if (type) + *type = value_type == REG_EXPAND_SZ ? REG_SZ : value_type; + if (buff_len) + *buff_len = data_len; + return ret; +} + +/************************************************************************* + * SHQueryValueExA [SHCORE.@] + */ +DWORD WINAPI SHQueryValueExA(HKEY hkey, const char *name, DWORD *reserved, DWORD *type, + void *buff, DWORD *buff_len) +{ + DWORD ret, value_type, data_len = 0; + + TRACE("(%p, %s, %p, %p, %p, %p)\n", hkey, debugstr_a(name), reserved, type, buff, buff_len); + + if (buff_len) + data_len = *buff_len; + + ret = RegQueryValueExA(hkey, name, reserved, &value_type, buff, &data_len); + if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) + return ret; + + if (buff_len && value_type == REG_EXPAND_SZ) + { + DWORD length; + char *value; + + if (!buff || ret == ERROR_MORE_DATA) + { + length = data_len; + value = malloc(length); + RegQueryValueExA(hkey, name, reserved, NULL, (BYTE *)value, &length); + length = ExpandEnvironmentStringsA(value, NULL, 0); + } + else + { + length = strlen(buff) + 1; + value = malloc(length); + memcpy(value, buff, length); + length = ExpandEnvironmentStringsA(value, buff, *buff_len); + if (length > *buff_len) ret = ERROR_MORE_DATA; + } + data_len = max(data_len, length); + free(value); + } + + if (type) + *type = value_type == REG_EXPAND_SZ ? REG_SZ : value_type; + if (buff_len) + *buff_len = data_len; + return ret; +} + +/************************************************************************* + * SHGetValueA [SHCORE.@] + */ +DWORD WINAPI SHGetValueA(HKEY hkey, const char *subkey, const char *value, + DWORD *type, void *data, DWORD *data_len) +{ + HKEY hsubkey = 0; + DWORD ret = 0; + + TRACE("(%p, %s, %s, %p, %p, %p)\n", hkey, debugstr_a(subkey), debugstr_a(value), + type, data, data_len); + + if (subkey) + ret = RegOpenKeyExA(hkey, subkey, 0, KEY_QUERY_VALUE, &hsubkey); + + if (!ret) + { + ret = SHQueryValueExA(hsubkey ? hsubkey : hkey, value, 0, type, data, data_len); + if (subkey) + RegCloseKey(hsubkey); + } + + return ret; +} + +/************************************************************************* + * SHGetValueW [SHCORE.@] + */ +DWORD WINAPI SHGetValueW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, + DWORD *type, void *data, DWORD *data_len) +{ + HKEY hsubkey = 0; + DWORD ret = 0; + + TRACE("(%p, %s, %s, %p, %p, %p)\n", hkey, debugstr_w(subkey), debugstr_w(value), + type, data, data_len); + + if (subkey) + ret = RegOpenKeyExW(hkey, subkey, 0, KEY_QUERY_VALUE, &hsubkey); + + if (!ret) + { + ret = SHQueryValueExW(hsubkey ? hsubkey : hkey, value, 0, type, data, data_len); + if (subkey) + RegCloseKey(hsubkey); + } + + return ret; +} + +/************************************************************************* + * SHRegGetIntW [SHCORE.280] + */ +int WINAPI SHRegGetIntW(HKEY hkey, const WCHAR *value, int default_value) +{ + WCHAR buff[32]; + DWORD buff_len; + + TRACE("(%p, %s, %d)\n", hkey, debugstr_w(value), default_value); + + buff[0] = 0; + buff_len = sizeof(buff); + if (SHQueryValueExW(hkey, value, 0, 0, buff, &buff_len)) + return default_value; + + if (*buff >= '0' && *buff <= '9') + return wcstol(buff, NULL, 10); + + return default_value; +} + +/************************************************************************* + * SHRegGetPathA [SHCORE.@] + */ +DWORD WINAPI SHRegGetPathA(HKEY hkey, const char *subkey, const char *value, char *path, DWORD flags) +{ + DWORD length = MAX_PATH; + + TRACE("%p, %s, %s, %p, %#lx.\n", hkey, debugstr_a(subkey), debugstr_a(value), path, flags); + + return SHGetValueA(hkey, subkey, value, 0, path, &length); +} + +/************************************************************************* + * SHRegGetPathW [SHCORE.@] + */ +DWORD WINAPI SHRegGetPathW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, WCHAR *path, DWORD flags) +{ + DWORD length = MAX_PATH; + + TRACE("%p, %s, %s, %p, %#lx.\n", hkey, debugstr_w(subkey), debugstr_w(value), path, flags); + + return SHGetValueW(hkey, subkey, value, 0, path, &length); +} + +/************************************************************************* + * SHSetValueW [SHCORE.@] + */ +DWORD WINAPI SHSetValueW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, DWORD type, + const void *data, DWORD data_len) +{ + DWORD ret = ERROR_SUCCESS, dummy; + HKEY hsubkey; + + TRACE("%p, %s, %s, %ld, %p, %ld.\n", hkey, debugstr_w(subkey), debugstr_w(value), + type, data, data_len); + + if (subkey && *subkey) + ret = RegCreateKeyExW(hkey, subkey, 0, NULL, 0, KEY_SET_VALUE, NULL, &hsubkey, &dummy); + else + hsubkey = hkey; + + if (!ret) + { + ret = RegSetValueExW(hsubkey, value, 0, type, data, data_len); + if (hsubkey != hkey) + RegCloseKey(hsubkey); + } + + return ret; +} + +/************************************************************************* + * SHSetValueA [SHCORE.@] + */ +DWORD WINAPI SHSetValueA(HKEY hkey, const char *subkey, const char *value, + DWORD type, const void *data, DWORD data_len) +{ + DWORD ret = ERROR_SUCCESS, dummy; + HKEY hsubkey; + + TRACE("%p, %s, %s, %ld, %p, %ld.\n", hkey, debugstr_a(subkey), debugstr_a(value), + type, data, data_len); + + if (subkey && *subkey) + ret = RegCreateKeyExA(hkey, subkey, 0, NULL, 0, KEY_SET_VALUE, NULL, &hsubkey, &dummy); + else + hsubkey = hkey; + + if (!ret) + { + ret = RegSetValueExA(hsubkey, value, 0, type, data, data_len); + if (hsubkey != hkey) + RegCloseKey(hsubkey); + } + + return ret; +} + +/************************************************************************* + * SHRegSetPathA [SHCORE.@] + */ +DWORD WINAPI SHRegSetPathA(HKEY hkey, const char *subkey, const char *value, const char *path, DWORD flags) +{ + FIXME("%p, %s, %s, %s, %#lx - semi-stub\n", hkey, debugstr_a(subkey), + debugstr_a(value), debugstr_a(path), flags); + + /* FIXME: PathUnExpandEnvStringsA() */ + + return SHSetValueA(hkey, subkey, value, REG_SZ, path, lstrlenA(path)); +} + +/************************************************************************* + * SHRegSetPathW [SHCORE.@] + */ +DWORD WINAPI SHRegSetPathW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, const WCHAR *path, DWORD flags) +{ + FIXME("%p, %s, %s, %s, %#lx semi-stub\n", hkey, debugstr_w(subkey), + debugstr_w(value), debugstr_w(path), flags); + + /* FIXME: PathUnExpandEnvStringsW(); */ + + return SHSetValueW(hkey, subkey, value, REG_SZ, path, lstrlenW(path)); +} + +/************************************************************************* + * SHQueryInfoKeyA [SHCORE.@] + */ +LONG WINAPI SHQueryInfoKeyA(HKEY hkey, DWORD *subkeys, DWORD *subkey_max, DWORD *values, DWORD *value_max) +{ + TRACE("(%p, %p, %p, %p, %p)\n", hkey, subkeys, subkey_max, values, value_max); + + return RegQueryInfoKeyA(hkey, NULL, NULL, NULL, subkeys, subkey_max, NULL, values, value_max, NULL, NULL, NULL); +} + +/************************************************************************* + * SHQueryInfoKeyW [SHCORE.@] + */ +LONG WINAPI SHQueryInfoKeyW(HKEY hkey, DWORD *subkeys, DWORD *subkey_max, DWORD *values, DWORD *value_max) +{ + TRACE("(%p, %p, %p, %p, %p)\n", hkey, subkeys, subkey_max, values, value_max); + + return RegQueryInfoKeyW(hkey, NULL, NULL, NULL, subkeys, subkey_max, NULL, values, value_max, NULL, NULL, NULL); +} + +/************************************************************************* + * IsOS [SHCORE.@] + */ +BOOL WINAPI IsOS(DWORD feature) +{ + DWORD platform, majorv, minorv; + OSVERSIONINFOA osvi; + + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); + if (!GetVersionExA(&osvi)) + return FALSE; + + majorv = osvi.dwMajorVersion; + minorv = osvi.dwMinorVersion; + platform = osvi.dwPlatformId; + +#define ISOS_RETURN(x) \ + TRACE("(%#lx) ret %d\n",feature,(x)); \ + return (x) + + switch(feature) { + case OS_WIN32SORGREATER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32s + || platform == VER_PLATFORM_WIN32_WINDOWS); + case OS_NT: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT); + case OS_WIN95ORGREATER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS); + case OS_NT4ORGREATER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 4); + case OS_WIN2000ORGREATER_ALT: + case OS_WIN2000ORGREATER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5); + case OS_WIN98ORGREATER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 10); + case OS_WIN98_GOLD: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 10); + case OS_WIN2000PRO: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5); + case OS_WIN2000SERVER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1)); + case OS_WIN2000ADVSERVER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1)); + case OS_WIN2000DATACENTER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1)); + case OS_WIN2000TERMINAL: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1)); + case OS_EMBEDDED: + FIXME("(OS_EMBEDDED) What should we return here?\n"); + return FALSE; + case OS_TERMINALCLIENT: + FIXME("(OS_TERMINALCLIENT) What should we return here?\n"); + return FALSE; + case OS_TERMINALREMOTEADMIN: + FIXME("(OS_TERMINALREMOTEADMIN) What should we return here?\n"); + return FALSE; + case OS_WIN95_GOLD: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 0); + case OS_MEORGREATER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 90); + case OS_XPORGREATER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1); + case OS_HOME: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1); + case OS_PROFESSIONAL: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT); + case OS_DATACENTER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT); + case OS_ADVSERVER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5); + case OS_SERVER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT); + case OS_TERMINALSERVER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT); + case OS_PERSONALTERMINALSERVER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && minorv >= 1 && majorv >= 5); + case OS_FASTUSERSWITCHING: + FIXME("(OS_FASTUSERSWITCHING) What should we return here?\n"); + return TRUE; + case OS_WELCOMELOGONUI: + FIXME("(OS_WELCOMELOGONUI) What should we return here?\n"); + return FALSE; + case OS_DOMAINMEMBER: + FIXME("(OS_DOMAINMEMBER) What should we return here?\n"); + return TRUE; + case OS_ANYSERVER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT); + case OS_WOW6432: + { + BOOL is_wow64; + IsWow64Process(GetCurrentProcess(), &is_wow64); + return is_wow64; + } + case OS_WEBSERVER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT); + case OS_SMALLBUSINESSSERVER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT); + case OS_TABLETPC: + FIXME("(OS_TABLETPC) What should we return here?\n"); + return FALSE; + case OS_SERVERADMINUI: + FIXME("(OS_SERVERADMINUI) What should we return here?\n"); + return FALSE; + case OS_MEDIACENTER: + FIXME("(OS_MEDIACENTER) What should we return here?\n"); + return FALSE; + case OS_APPLIANCE: + FIXME("(OS_APPLIANCE) What should we return here?\n"); + return FALSE; + case 0x25: /*OS_VISTAORGREATER*/ + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 6); + } + +#undef ISOS_RETURN + + WARN("(%#lx) unknown parameter\n", feature); + + return FALSE; +} + +/************************************************************************* + * SubscribeFeatureStateChangeNotification [SHCORE.@] + */ +void WINAPI SubscribeFeatureStateChangeNotification(FEATURE_STATE_CHANGE_SUBSCRIPTION *subscription, + FEATURE_STATE_CHANGE_CALLBACK *callback, void *context) +{ + FIXME("(%p, %p, %p) stub\n", subscription, callback, context); +} + +/************************************************************************* + * GetFeatureEnabledState [SHCORE.@] + */ +FEATURE_ENABLED_STATE WINAPI GetFeatureEnabledState(UINT32 feature, FEATURE_CHANGE_TIME change_time) +{ + FIXME("(%u, %u) stub\n", feature, change_time); + return FEATURE_ENABLED_STATE_DEFAULT; +} + +/************************************************************************* + * RegisterScaleChangeEvent [SHCORE.@] + */ +HRESULT WINAPI RegisterScaleChangeEvent(HANDLE handle, DWORD_PTR *cookie) +{ + FIXME("(%p, %p) stub\n", handle, cookie); + return E_NOTIMPL; +} + +/************************************************************************* + * RegisterScaleChangeNotifications [SHCORE.@] + */ +HRESULT WINAPI RegisterScaleChangeNotifications(DISPLAY_DEVICE_TYPE display_device, HWND hwnd, UINT msg, DWORD *cookie) +{ + FIXME("(%d, %p, %u, %p) stub\n", display_device, hwnd, msg, cookie); + + if (cookie) *cookie = 0; + + return E_NOTIMPL; +} + +/************************************************************************* + * CreateRandomAccessStreamOverStream [SHCORE.@] + */ +HRESULT WINAPI CreateRandomAccessStreamOverStream(IStream *stream, BSOS_OPTIONS options, REFIID riid, void **ppv) +{ + FIXME("(%p, %d, %s, %p) stub\n", stream, options, debugstr_guid(riid), ppv); + return E_NOTIMPL; +} diff --git a/dll/win32/shcore/shcore.spec b/dll/win32/shcore/shcore.spec new file mode 100644 index 00000000000..8aea90e6116 --- /dev/null +++ b/dll/win32/shcore/shcore.spec @@ -0,0 +1,198 @@ +1 stub -noname SHCreateReadOnlySharedMemoryStream +@ stdcall CommandLineToArgvW(wstr ptr) +@ stub CreateRandomAccessStreamOnFile +@ stdcall CreateRandomAccessStreamOverStream(ptr long ptr ptr) +@ stub CreateStreamOverRandomAccessStream +@ stdcall -private DllCanUnloadNow() +@ stub DllGetActivationFactory +@ stub -private DllGetClassObject +@ stdcall GetCurrentProcessExplicitAppUserModelID(ptr) +@ stdcall -stub GetDpiForMonitor(long long ptr ptr) +@ stub GetDpiForShellUIComponent +@ stdcall GetFeatureEnabledState(long long) +# @ stub GetFeatureVariant +@ stdcall -stub GetProcessDpiAwareness(long ptr) +@ stdcall GetProcessReference(ptr) +@ stdcall GetScaleFactorForDevice(long) +@ stdcall GetScaleFactorForMonitor(long ptr) +@ stub IStream_Copy +@ stdcall IStream_Read(ptr ptr long) _IStream_Read +@ stub IStream_ReadStr +@ stdcall IStream_Reset(ptr) +@ stdcall IStream_Size(ptr ptr) +@ stdcall IStream_Write(ptr ptr long) _IStream_Write +@ stub IStream_WriteStr +@ stdcall IUnknown_AtomicRelease(ptr) +@ stdcall IUnknown_GetSite(ptr ptr ptr) +@ stdcall IUnknown_QueryService(ptr ptr ptr ptr) +@ stdcall IUnknown_Set(ptr ptr) +@ stdcall IUnknown_SetSite(ptr ptr) +@ stdcall IsOS(long) +# @ stub IsProcessInIsolatedContainer +# @ stub IsProcessInWDAGContainer +# @ stub RecordFeatureError +# @ stub RecordFeatureUsage +@ stdcall RegisterScaleChangeEvent(ptr ptr) +@ stdcall RegisterScaleChangeNotifications(long ptr long ptr) +@ stub RevokeScaleChangeNotifications +@ stdcall SHAnsiToAnsi(str ptr long) +@ stdcall SHAnsiToUnicode(str ptr long) +@ stdcall SHCopyKeyA(long str long long) +@ stdcall SHCopyKeyW(long wstr long long) +@ stdcall SHCreateMemStream(ptr long) +@ stdcall SHCreateStreamOnFileA(str long ptr) +@ stdcall SHCreateStreamOnFileEx(wstr long long long ptr ptr) +@ stdcall SHCreateStreamOnFileW(wstr long ptr) +@ stdcall SHCreateThread(ptr ptr long ptr) +@ stdcall SHCreateThreadRef(ptr ptr) +@ stub SHCreateThreadWithHandle +@ stdcall SHDeleteEmptyKeyA(long str) +@ stdcall SHDeleteEmptyKeyW(long wstr) +@ stdcall SHDeleteKeyA(long str) +@ stdcall SHDeleteKeyW(long wstr) +@ stdcall SHDeleteValueA(long str str) +@ stdcall SHDeleteValueW(long wstr wstr) +@ stdcall SHEnumKeyExA(long long str ptr) +@ stdcall SHEnumKeyExW(long long wstr ptr) +@ stdcall SHEnumValueA(long long str ptr ptr ptr ptr) +@ stdcall SHEnumValueW(long long wstr ptr ptr ptr ptr) +@ stdcall SHGetThreadRef(ptr) +@ stdcall SHGetValueA(long str str ptr ptr ptr) +@ stdcall SHGetValueW(long wstr wstr ptr ptr ptr) +@ stdcall SHOpenRegStream2A(long str str long) +@ stdcall SHOpenRegStream2W(long wstr wstr long) +@ stdcall SHOpenRegStreamA(long str str long) +@ stdcall SHOpenRegStreamW(long wstr wstr long) +@ stdcall SHQueryInfoKeyA(long ptr ptr ptr ptr) +@ stdcall SHQueryInfoKeyW(long ptr ptr ptr ptr) +@ stdcall SHQueryValueExA(long str ptr ptr ptr ptr) +@ stdcall SHQueryValueExW(long wstr ptr ptr ptr ptr) +@ stdcall SHRegDuplicateHKey(long) +@ stdcall SHRegGetIntW(ptr wstr long) +@ stdcall SHRegGetPathA(long str str ptr long) +@ stdcall SHRegGetPathW(long wstr wstr ptr long) +@ stdcall SHRegGetValueA(long str str long ptr ptr ptr) advapi32.RegGetValueA +@ stdcall SHRegGetValueW(long wstr wstr long ptr ptr ptr) advapi32.RegGetValueW +@ stdcall SHRegSetPathA(long str str str long) +@ stdcall SHRegSetPathW(long wstr wstr wstr long) +@ stdcall SHReleaseThreadRef() +@ stdcall SHSetThreadRef(ptr) +@ stdcall SHSetValueA(long str str long ptr long) +@ stdcall SHSetValueW(long wstr wstr long ptr long) +@ stdcall SHStrDupA(str ptr) +@ stdcall SHStrDupW(wstr ptr) +# @ stub SHTaskPoolAllowThreadReuse +# @ stub SHTaskPoolDoNotWaitForMoreTasks +# @ stub SHTaskPoolGetCurrentThreadLifetime +# @ stub SHTaskPoolGetUniqueContext +# @ stub SHTaskPoolQueueTask +# @ stub SHTaskPoolSetThreadReuseAllowed +@ stdcall SHUnicodeToAnsi(wstr ptr ptr) +@ stdcall SHUnicodeToUnicode(wstr ptr long) +@ stdcall SetCurrentProcessExplicitAppUserModelID(wstr) +@ stdcall -stub SetProcessDpiAwareness(long) +@ stdcall SetProcessReference(ptr) +@ stdcall SubscribeFeatureStateChangeNotification(ptr ptr ptr) +@ stub UnregisterScaleChangeEvent +# @ stub UnsubscribeFeatureStateChangeNotification + +100 stub -noname SHManagedCreateStreamOnFile +101 stub -noname SHManagedCreateFile +102 stub -noname SHIsEmptyStream +103 stub -noname MapWin32ErrorToSTG +104 stub -noname ModeToCreateFileFlags +105 stub -noname CreateTempStreamName +106 stub -noname StreamCopyTo +107 stub -noname IStream_ReadStrLong +108 stub -noname IStream_WriteStrLong +109 stub -noname SHCreateStreamOnModuleResourceW +110 stub -noname SHCreateStreamOnDllResourceW +111 stub -noname CreateWritableSharedMemoryStream +115 stub -noname CreateRandomAccessStreamOnFileWithOptions +116 stub -noname RandomAccessStreamCopyAsync +117 stub -noname CreateRandomAccessStreamOnPlaceholderFile +120 stub -noname SHRegGetCLSIDKey +121 stub -noname SHRegSetValue +122 stub SHRegGetValueFromHKCUHKLM +123 stub -noname SHRegGetBoolValueFromHKCUHKLM +124 stub -noname SHGetValueGoodBootA +125 stub -noname SHGetValueGoodBootW +126 stub -noname SHLoadRegUIStringW +127 stub -noname QuerySourceCreateFromKeyEx +130 stub -noname SHGlobalCounterGetValue +131 stub -noname SHGlobalCounterIncrement +132 stub -noname SHGlobalCounterDecrement +133 stub -noname SHGlobalCounterSetValue +140 stub -noname IUnknown_ProfferService +141 stub -noname IUnknown_RemoveBackReferences +142 stub -noname IUnknown_GetClassID +143 stub -noname StrRetToStrW +144 stub -noname StrRetToBSTR +145 stub -noname StrRetToBufW +150 stub -noname SHAnsiToUnicodeCP +151 stub -noname SHUnicodeToAnsiCP +152 stub -noname SHUnicodeToAnsiCPAlloc +153 stub -noname SHAnsiToUnicodeCPAlloc +160 stub -noname SHWaitForSendMessageThread +161 stub -noname SHWaitForThreadWithWakeMask +162 stub -noname SHQueueUserWorkItem +170 stub -noname PathIsNetworkPathW +171 stub -noname PathIsNetworkPathA +172 stub -noname PathBuildRootW +173 stub -noname PathBuildRootA +174 stub -noname DriveType +175 stub -noname IsNetDrive +181 stub -noname SHMapHandle +182 stub -noname SHAllocShared +183 stub -noname SHLockSharedEx +184 stub -noname SHLockShared +185 stub -noname SHGetSizeShared +186 stub -noname SHUnlockShared +187 stub -noname SHFreeShared +188 stub -noname SHCreateWorkerWindowW +189 stub -noname SHCreateOplockProvider +190 stub -noname SHWindowsPolicy +191 stub -noname SHWindowsPolicyGetValue +192 stub -noname IsAppCompatModeEnabled +193 stub -noname SHGetObjectCompatFlags +200 stub -noname GUIDFromStringW +220 stub -noname GetPhysicalDpiForDevice +222 stub -noname ScaleRelativePixelsForDevice +223 stub -noname PhysicalRectFromScaledRect +224 stub -noname ScaleAndMapRelativeRectForDevice +225 stub -noname CanOverrideScaleFactor +226 stub -noname GetScalingOverride +227 stub -noname RegisterScaleChangeSink +228 stub -noname SetDesignModeScaleFactor +229 stub -noname GetProposedScaleFactorForWindow +230 stub -noname SHSetWindowSubclass +231 stub -noname SHGetWindowSubclassData +232 stub -noname SHRemoveWindowSubclass +233 stub -noname SHDefSubclassProc +234 stub -noname SHRegisterClassW +240 stub -noname RegisterScaleChangeSinkForWindow +241 stub -noname ScaleAndMapRelativeRect +242 stub -noname RelativeRectFromPhysicalRectWithScale +244 stub -noname GetScaleFactorForWindow +245 stub -noname RegisterScaleChangeNotificationsForWindow +246 stub -noname RevokeScaleChangeNotificationsForWindow +247 stub -noname GetOverrideScaleFactorForWindow +248 stub -noname GetSystemScaleFactorForWindow +249 stub -noname UpdateScalingInfoCache +250 stub -noname RegisterCurrentWindowChangeListener +251 stub -noname RegisterWindowMonitorChangeListener +252 stub -noname UnregisterCurrentWindowChangeListener +253 stub -noname UnregisterWindowMonitorChangeListener +254 stub -noname AddCurrentWindowCandidate +255 stub -noname GetCurrentWindow +260 stub -noname PhysicalRectFromRelativeRectWithScales +261 stub -noname RelativeRectFromPhysicalRectWithScales +270 stub -noname SHCreateMemoryStreamOnSharedBuffer +280 stub -noname _CreateDirectoryHelper +281 stub -noname Win32CreateDirectory +282 stub -noname SuspendSHNotify +283 stub -noname ResumeSHNotify +284 stub -noname IsNotifySuspended +290 stub -noname SHCreateDirectoryExW +291 stub -noname SHCreateDirectoryExA +292 stub -noname SHCreateDirectory diff --git a/sdk/include/psdk/featurestagingapi.h b/sdk/include/psdk/featurestagingapi.h new file mode 100644 index 00000000000..9a9237eb13c --- /dev/null +++ b/sdk/include/psdk/featurestagingapi.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2021 Alex Henrie + * + * 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 + */ + +#ifndef _FEATURESTAGINGAPI_H_ +#define _FEATURESTAGINGAPI_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +DECLARE_HANDLE(FEATURE_STATE_CHANGE_SUBSCRIPTION); + +typedef void WINAPI FEATURE_STATE_CHANGE_CALLBACK(void*); + +typedef enum FEATURE_CHANGE_TIME +{ + FEATURE_CHANGE_TIME_READ, + FEATURE_CHANGE_TIME_MODULE_RELOAD, + FEATURE_CHANGE_TIME_SESSION, + FEATURE_CHANGE_TIME_REBOOT +} FEATURE_CHANGE_TIME; + +typedef enum FEATURE_ENABLED_STATE +{ + FEATURE_ENABLED_STATE_DEFAULT, + FEATURE_ENABLED_STATE_DISABLED, + FEATURE_ENABLED_STATE_ENABLED +} FEATURE_ENABLED_STATE; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sdk/include/psdk/shcore.h b/sdk/include/psdk/shcore.h new file mode 100644 index 00000000000..7893261b953 --- /dev/null +++ b/sdk/include/psdk/shcore.h @@ -0,0 +1,32 @@ +/* + * Copyright 2023 Louis Lenders + * + * 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 + */ + +#ifndef SHCORE_H +#define SHCORE_H + +#include + +typedef enum BSOS_OPTIONS +{ + BSOS_DEFAULT, + BSOS_PREFERDESTINATIONSTREAM +} BSOS_OPTIONS; + +HRESULT WINAPI CreateRandomAccessStreamOverStream(IStream *stream, BSOS_OPTIONS options, REFIID riid, void **ppv); + +#endif