Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/shcore/main.c | 308 ++++++++++++++++++++++++++++++++++++++++ dlls/shcore/shcore.spec | 2 +- 2 files changed, 309 insertions(+), 1 deletion(-)
diff --git a/dlls/shcore/main.c b/dlls/shcore/main.c index 8f674a2edc..792f7c85b7 100644 --- a/dlls/shcore/main.c +++ b/dlls/shcore/main.c @@ -28,7 +28,9 @@ #include "initguid.h" #include "ocidl.h" #include "shellscalingapi.h" + #include "wine/debug.h" +#include "wine/heap.h" #include "wine/unicode.h"
WINE_DEFAULT_DEBUG_CHANNEL(shcore); @@ -492,3 +494,309 @@ WCHAR** WINAPI CommandLineToArgvW(const WCHAR *cmdline, int *numargs)
return argv; } + +struct shstream +{ + IStream IStream_iface; + LONG refcount; + + union + { + struct + { + BYTE *buffer; + DWORD length; + DWORD position; + } mem; + } 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)) + { + *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)->(%u)\n", stream, refcount); + + return refcount; +} + +static ULONG WINAPI memstream_Release(IStream *iface) +{ + struct shstream *stream = impl_from_IStream(iface); + ULONG refcount = InterlockedDecrement(&stream->refcount); + + TRACE("(%p)->(%u)\n", stream, refcount); + + if (!refcount) + { + heap_free(stream->u.mem.buffer); + heap_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, %u, %p)\n", stream, buff, buff_size, read_len); + + if (stream->u.mem.position >= stream->u.mem.length) + length = 0; + else + length = stream->u.mem.length - stream->u.mem.position; + + length = buff_size > length ? length : buff_size; + if (length != 0) /* not at end of buffer and we want to read something */ + { + memmove(buff, stream->u.mem.buffer + stream->u.mem.position, length); + stream->u.mem.position += length; /* adjust pointer */ + } + + 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, %u, %p)\n", stream, buff, buff_size, written); + + if (length < stream->u.mem.position) /* overflow */ + return STG_E_INSUFFICIENTMEMORY; + + if (length > stream->u.mem.length) + { + BYTE *buffer = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, stream->u.mem.buffer, 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, %d, %p)\n", stream, 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 = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, stream->u.mem.buffer, 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 *pstm, ULARGE_INTEGER size, ULARGE_INTEGER *read_len, ULARGE_INTEGER *written) +{ + struct shstream *stream = impl_from_IStream(iface); + + TRACE("(%p)\n", stream); + + if (read_len) + read_len->QuadPart = 0; + + if (written) + written->QuadPart = 0; + + /* TODO implement */ + return E_NOTIMPL; +} + +static HRESULT WINAPI shstream_Commit(IStream *iface, DWORD flags) +{ + struct shstream *stream = impl_from_IStream(iface); + + TRACE("(%p, %#x)\n", stream, 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, %#x)\n", stream, 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 shstreamvtbl = +{ + 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, +}; + +/************************************************************************* + * 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); + + if (!data) + data_len = 0; + + stream = heap_alloc(sizeof(*stream)); + stream->IStream_iface.lpVtbl = &shstreamvtbl; + stream->refcount = 1; + stream->u.mem.buffer = heap_alloc(data_len); + if (!stream->u.mem.buffer) + { + heap_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->IStream_iface; +} diff --git a/dlls/shcore/shcore.spec b/dlls/shcore/shcore.spec index 1266a02f69..e8643d8691 100644 --- a/dlls/shcore/shcore.spec +++ b/dlls/shcore/shcore.spec @@ -33,7 +33,7 @@ @ stdcall SHAnsiToUnicode(str ptr long) shlwapi.SHAnsiToUnicode @ stdcall SHCopyKeyA(long str long long) shlwapi.SHCopyKeyA @ stdcall SHCopyKeyW(long wstr long long) shlwapi.SHCopyKeyW -@ stdcall SHCreateMemStream(ptr long) shlwapi.SHCreateMemStream +@ stdcall SHCreateMemStream(ptr long) @ stdcall SHCreateStreamOnFileA(str long ptr) shlwapi.SHCreateStreamOnFileA @ stdcall SHCreateStreamOnFileEx(wstr long long long ptr ptr) shlwapi.SHCreateStreamOnFileEx @ stdcall SHCreateStreamOnFileW(wstr long ptr) shlwapi.SHCreateStreamOnFileW
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/shcore/Makefile.in | 2 +- dlls/shcore/main.c | 327 +++++++++++++++++++++++++++++++++++++++- dlls/shcore/shcore.spec | 6 +- 3 files changed, 329 insertions(+), 6 deletions(-)
diff --git a/dlls/shcore/Makefile.in b/dlls/shcore/Makefile.in index 8497198996..050be57804 100644 --- a/dlls/shcore/Makefile.in +++ b/dlls/shcore/Makefile.in @@ -1,5 +1,5 @@ MODULE = shcore.dll -IMPORTS = user32 gdi32 +IMPORTS = user32 gdi32 ole32
C_SRCS = \ main.c diff --git a/dlls/shcore/main.c b/dlls/shcore/main.c index 792f7c85b7..f99479d383 100644 --- a/dlls/shcore/main.c +++ b/dlls/shcore/main.c @@ -508,6 +508,12 @@ struct shstream DWORD length; DWORD position; } mem; + struct + { + HANDLE handle; + DWORD mode; + WCHAR *path; + } file; } u; };
@@ -742,7 +748,7 @@ static HRESULT WINAPI shstream_Clone(IStream *iface, IStream **dest) return E_NOTIMPL; }
-static const IStreamVtbl shstreamvtbl = +static const IStreamVtbl memstreamvtbl = { shstream_QueryInterface, shstream_AddRef, @@ -786,7 +792,7 @@ IStream * WINAPI SHCreateMemStream(const BYTE *data, UINT data_len) data_len = 0;
stream = heap_alloc(sizeof(*stream)); - stream->IStream_iface.lpVtbl = &shstreamvtbl; + stream->IStream_iface.lpVtbl = &memstreamvtbl; stream->refcount = 1; stream->u.mem.buffer = heap_alloc(data_len); if (!stream->u.mem.buffer) @@ -800,3 +806,320 @@ IStream * WINAPI SHCreateMemStream(const BYTE *data, UINT data_len)
return &stream->IStream_iface; } + +static ULONG WINAPI filestream_Release(IStream *iface) +{ + struct shstream *stream = impl_from_IStream(iface); + ULONG refcount = InterlockedDecrement(&stream->refcount); + + TRACE("(%p)->(%u)\n", stream, refcount); + + if (!refcount) + { + CloseHandle(stream->u.file.handle); + heap_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, %u, %p)\n", stream, buff, size, read_len); + + if (!ReadFile(stream->u.file.handle, buff, size, &read, NULL)) + { + WARN("error %d 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, %u, %p)\n", stream, 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, %d, %p)\n", stream, 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); + + TRACE("(%p, %s)\n", stream, wine_dbgstr_longlong(size.QuadPart)); + + if (!SetFilePointer(stream->u.file.handle, size.QuadPart, NULL, FILE_BEGIN)) + return E_FAIL; + + if (!SetEndOfFile(stream->u.file.handle)) + 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_chunk) + written->QuadPart += written_chunk; + if (FAILED(hr) || written_chunk != left) + break; + + size.QuadPart -= left; + } + + return hr; +} + +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, %#x)\n", stream, 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 = strlenW(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, + shstream_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, %d, 0x%08X, %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 = heap_alloc(sizeof(*stream)); + stream->IStream_iface.lpVtbl = &filestreamvtbl; + stream->refcount = 1; + stream->u.file.handle = hFile; + stream->u.file.mode = mode; + + len = strlenW(path); + stream->u.file.path = heap_alloc((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, %#x, %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, %#x, %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 = heap_alloc(len * sizeof(WCHAR)); + if (!pathW) + return E_OUTOFMEMORY; + + MultiByteToWideChar(CP_ACP, 0, path, -1, pathW, len); + hr = SHCreateStreamOnFileW(pathW, mode, stream); + heap_free(pathW); + + return hr; +} diff --git a/dlls/shcore/shcore.spec b/dlls/shcore/shcore.spec index e8643d8691..c3bb8d27e4 100644 --- a/dlls/shcore/shcore.spec +++ b/dlls/shcore/shcore.spec @@ -34,9 +34,9 @@ @ stdcall SHCopyKeyA(long str long long) shlwapi.SHCopyKeyA @ stdcall SHCopyKeyW(long wstr long long) shlwapi.SHCopyKeyW @ stdcall SHCreateMemStream(ptr long) -@ stdcall SHCreateStreamOnFileA(str long ptr) shlwapi.SHCreateStreamOnFileA -@ stdcall SHCreateStreamOnFileEx(wstr long long long ptr ptr) shlwapi.SHCreateStreamOnFileEx -@ stdcall SHCreateStreamOnFileW(wstr long ptr) shlwapi.SHCreateStreamOnFileW +@ stdcall SHCreateStreamOnFileA(str long ptr) +@ stdcall SHCreateStreamOnFileEx(wstr long long long ptr ptr) +@ stdcall SHCreateStreamOnFileW(wstr long ptr) @ stdcall SHCreateThread(ptr ptr long ptr) shlwapi.SHCreateThread @ stdcall SHCreateThreadRef(ptr ptr) shlwapi.SHCreateThreadRef @ stub SHCreateThreadWithHandle
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/shcore/main.c | 138 ++++++++++++++++++++++++++++++++++++++++ dlls/shcore/shcore.spec | 8 +-- 2 files changed, 142 insertions(+), 4 deletions(-)
diff --git a/dlls/shcore/main.c b/dlls/shcore/main.c index f99479d383..7f423c1edd 100644 --- a/dlls/shcore/main.c +++ b/dlls/shcore/main.c @@ -35,6 +35,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(shcore);
+static DWORD shcore_tls; + BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) { TRACE("(%p, %u, %p)\n", instance, reason, reserved); @@ -45,6 +47,12 @@ BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) return FALSE; /* prefer native version */ 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; }
@@ -1123,3 +1131,133 @@ HRESULT WINAPI SHCreateStreamOnFileA(const char *path, DWORD mode, IStream **str
return hr; } + +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, %d)\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, %d)\n", threadref, refcount); + + if (!refcount) + heap_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 = heap_alloc(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; +} diff --git a/dlls/shcore/shcore.spec b/dlls/shcore/shcore.spec index c3bb8d27e4..568cb20597 100644 --- a/dlls/shcore/shcore.spec +++ b/dlls/shcore/shcore.spec @@ -38,7 +38,7 @@ @ stdcall SHCreateStreamOnFileEx(wstr long long long ptr ptr) @ stdcall SHCreateStreamOnFileW(wstr long ptr) @ stdcall SHCreateThread(ptr ptr long ptr) shlwapi.SHCreateThread -@ stdcall SHCreateThreadRef(ptr ptr) shlwapi.SHCreateThreadRef +@ stdcall SHCreateThreadRef(ptr ptr) @ stub SHCreateThreadWithHandle @ stdcall SHDeleteEmptyKeyA(long ptr) shlwapi.SHDeleteEmptyKeyA @ stdcall SHDeleteEmptyKeyW(long ptr) shlwapi.SHDeleteEmptyKeyW @@ -50,7 +50,7 @@ @ stdcall SHEnumKeyExW(long long wstr ptr) shlwapi.SHEnumKeyExW @ stdcall SHEnumValueA(long long str ptr ptr ptr ptr) shlwapi.SHEnumValueA @ stdcall SHEnumValueW(long long wstr ptr ptr ptr ptr) shlwapi.SHEnumValueW -@ stdcall SHGetThreadRef(ptr) shlwapi.SHGetThreadRef +@ stdcall SHGetThreadRef(ptr) @ stdcall SHGetValueA( long str str ptr ptr ptr ) shlwapi.SHGetValueA @ stdcall SHGetValueW( long wstr wstr ptr ptr ptr ) shlwapi.SHGetValueW @ stdcall SHOpenRegStream2A(long str str long) shlwapi.SHOpenRegStream2A @@ -69,8 +69,8 @@ @ stdcall SHRegGetValueW( long wstr wstr long ptr ptr ptr ) shlwapi.SHRegGetValueW @ stdcall SHRegSetPathA(long str str str long) shlwapi.SHRegSetPathA @ stdcall SHRegSetPathW(long wstr wstr wstr long) shlwapi.SHRegSetPathW -@ stdcall SHReleaseThreadRef() shlwapi.SHReleaseThreadRef -@ stdcall SHSetThreadRef(ptr) shlwapi.SHSetThreadRef +@ stdcall SHReleaseThreadRef() +@ stdcall SHSetThreadRef(ptr) @ stdcall SHSetValueA(long str str long ptr long) shlwapi.SHSetValueA @ stdcall SHSetValueW(long wstr wstr long ptr long) shlwapi.SHSetValueW @ stdcall SHStrDupA(str ptr) shlwapi.SHStrDupA
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- configure | 1 + configure.ac | 1 + dlls/shcore/main.c | 29 +++++++ dlls/shcore/shcore.spec | 4 +- dlls/shcore/tests/Makefile.in | 4 + dlls/shcore/tests/shcore.c | 140 ++++++++++++++++++++++++++++++++++ 6 files changed, 177 insertions(+), 2 deletions(-) create mode 100644 dlls/shcore/tests/Makefile.in create mode 100644 dlls/shcore/tests/shcore.c
diff --git a/configure b/configure index bb2817c074..45d0bc8023 100755 --- a/configure +++ b/configure @@ -19799,6 +19799,7 @@ wine_fn_config_makefile dlls/setupx.dll16 enable_win16 wine_fn_config_makefile dlls/sfc enable_sfc wine_fn_config_makefile dlls/sfc_os enable_sfc_os wine_fn_config_makefile dlls/shcore enable_shcore +wine_fn_config_makefile dlls/shcore/tests enable_tests wine_fn_config_makefile dlls/shdoclc enable_shdoclc wine_fn_config_makefile dlls/shdocvw enable_shdocvw wine_fn_config_makefile dlls/shdocvw/tests enable_tests diff --git a/configure.ac b/configure.ac index 8bf5e109e6..7fce8ef35f 100644 --- a/configure.ac +++ b/configure.ac @@ -3654,6 +3654,7 @@ WINE_CONFIG_MAKEFILE(dlls/setupx.dll16,enable_win16) WINE_CONFIG_MAKEFILE(dlls/sfc) WINE_CONFIG_MAKEFILE(dlls/sfc_os) WINE_CONFIG_MAKEFILE(dlls/shcore) +WINE_CONFIG_MAKEFILE(dlls/shcore/tests) WINE_CONFIG_MAKEFILE(dlls/shdoclc) WINE_CONFIG_MAKEFILE(dlls/shdocvw) WINE_CONFIG_MAKEFILE(dlls/shdocvw/tests) diff --git a/dlls/shcore/main.c b/dlls/shcore/main.c index 7f423c1edd..488e78eb86 100644 --- a/dlls/shcore/main.c +++ b/dlls/shcore/main.c @@ -36,6 +36,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(shcore);
static DWORD shcore_tls; +static IUnknown *process_ref;
BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) { @@ -1261,3 +1262,31 @@ 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; +} diff --git a/dlls/shcore/shcore.spec b/dlls/shcore/shcore.spec index 568cb20597..c98f2db54a 100644 --- a/dlls/shcore/shcore.spec +++ b/dlls/shcore/shcore.spec @@ -10,7 +10,7 @@ @ stdcall GetDpiForMonitor(long long ptr ptr) @ stub GetDpiForShellUIComponent @ stdcall GetProcessDpiAwareness(long ptr) -@ stub GetProcessReference +@ stdcall GetProcessReference(ptr) @ stub GetScaleFactorForDevice @ stub GetScaleFactorForMonitor @ stub IStream_Copy @@ -79,7 +79,7 @@ @ stdcall SHUnicodeToUnicode(wstr ptr long) shlwapi.SHUnicodeToUnicode @ stdcall SetCurrentProcessExplicitAppUserModelID(wstr) @ stdcall SetProcessDpiAwareness(long) -@ stub SetProcessReference +@ stdcall SetProcessReference(ptr) @ stub UnregisterScaleChangeEvent
100 stub @ diff --git a/dlls/shcore/tests/Makefile.in b/dlls/shcore/tests/Makefile.in new file mode 100644 index 0000000000..0ea769a348 --- /dev/null +++ b/dlls/shcore/tests/Makefile.in @@ -0,0 +1,4 @@ +TESTDLL = shcore.dll + +C_SRCS = \ + shcore.c diff --git a/dlls/shcore/tests/shcore.c b/dlls/shcore/tests/shcore.c new file mode 100644 index 0000000000..de6a921fc2 --- /dev/null +++ b/dlls/shcore/tests/shcore.c @@ -0,0 +1,140 @@ +/* + * Copyright 2018 Nikolay Sivov for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define COBJMACROS + +#include <stdarg.h> + +#include <windows.h> +#include "initguid.h" +#include "objidl.h" + +#include "wine/test.h" + +static HRESULT (WINAPI *pGetProcessReference)(IUnknown **); +static void (WINAPI *pSetProcessReference)(IUnknown *); +static HRESULT (WINAPI *pSHGetInstanceExplorer)(IUnknown **); + +static void init(HMODULE hshcore) +{ +#define X(f) p##f = (void*)GetProcAddress(hshcore, #f) + X(GetProcessReference); + X(SetProcessReference); +#undef X +} + +static HRESULT WINAPI unk_QI(IUnknown *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IUnknown_AddRef(iface); + return S_OK; + } + + *obj = NULL; + return E_NOINTERFACE; +} + +struct test_unk +{ + IUnknown IUnknown_iface; + LONG refcount; +}; + +static struct test_unk *impl_from_IUnknown(IUnknown *iface) +{ + return CONTAINING_RECORD(iface, struct test_unk, IUnknown_iface); +} + +static ULONG WINAPI unk_AddRef(IUnknown *iface) +{ + struct test_unk *obj = impl_from_IUnknown(iface); + return InterlockedIncrement(&obj->refcount); +} + +static ULONG WINAPI unk_Release(IUnknown *iface) +{ + struct test_unk *obj = impl_from_IUnknown(iface); + return InterlockedDecrement(&obj->refcount); +} + +static const IUnknownVtbl testunkvtbl = +{ + unk_QI, + unk_AddRef, + unk_Release, +}; + +static void test_unk_init(struct test_unk *testunk) +{ + testunk->IUnknown_iface.lpVtbl = &testunkvtbl; + testunk->refcount = 1; +} + +static void test_process_reference(void) +{ + struct test_unk test_unk, test_unk2; + IUnknown *obj; + HMODULE hmod; + HRESULT hr; + + obj = (void *)0xdeadbeef; + hr = pGetProcessReference(&obj); + ok(hr == E_FAIL, "Unexpected hr %#x.\n", hr); + ok(obj == NULL, "Unexpected pointer.\n"); + + test_unk_init(&test_unk); + test_unk_init(&test_unk2); + + pSetProcessReference(&test_unk.IUnknown_iface); + ok(test_unk.refcount == 1, "Unexpected refcount %u.\n", test_unk.refcount); + pSetProcessReference(&test_unk2.IUnknown_iface); + ok(test_unk.refcount == 1, "Unexpected refcount %u.\n", test_unk.refcount); + ok(test_unk2.refcount == 1, "Unexpected refcount %u.\n", test_unk2.refcount); + + hr = pGetProcessReference(&obj); + ok(hr == S_OK, "Failed to get reference, hr %#x.\n", hr); + ok(obj == &test_unk2.IUnknown_iface, "Unexpected pointer.\n"); + ok(test_unk2.refcount == 2, "Unexpected refcount %u.\n", test_unk2.refcount); + + hmod = LoadLibraryA("shell32.dll"); + + pSHGetInstanceExplorer = (void *)GetProcAddress(hmod, "SHGetInstanceExplorer"); + hr = pSHGetInstanceExplorer(&obj); +todo_wine { + ok(hr == S_OK, "Failed to get reference, hr %#x.\n", hr); + ok(obj == &test_unk2.IUnknown_iface, "Unexpected pointer.\n"); + ok(test_unk2.refcount == 3, "Unexpected refcount %u.\n", test_unk2.refcount); +} +} + +START_TEST(shcore) +{ + HMODULE hshcore = LoadLibraryA("shcore.dll"); + + if (!hshcore) + { + win_skip("Shcore.dll is not available.\n"); + return; + } + + init(hshcore); + + test_process_reference(); +}
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/shcore/tests/shcore.c | 2 -- dlls/shell32/shell32.spec | 4 ++-- dlls/shell32/shellord.c | 28 ---------------------------- 3 files changed, 2 insertions(+), 32 deletions(-)
diff --git a/dlls/shcore/tests/shcore.c b/dlls/shcore/tests/shcore.c index de6a921fc2..904d8264cd 100644 --- a/dlls/shcore/tests/shcore.c +++ b/dlls/shcore/tests/shcore.c @@ -117,12 +117,10 @@ static void test_process_reference(void)
pSHGetInstanceExplorer = (void *)GetProcAddress(hmod, "SHGetInstanceExplorer"); hr = pSHGetInstanceExplorer(&obj); -todo_wine { ok(hr == S_OK, "Failed to get reference, hr %#x.\n", hr); ok(obj == &test_unk2.IUnknown_iface, "Unexpected pointer.\n"); ok(test_unk2.refcount == 3, "Unexpected refcount %u.\n", test_unk2.refcount); } -}
START_TEST(shcore) { diff --git a/dlls/shell32/shell32.spec b/dlls/shell32/shell32.spec index 23243e1f22..bf8b5121d7 100644 --- a/dlls/shell32/shell32.spec +++ b/dlls/shell32/shell32.spec @@ -165,7 +165,7 @@ 173 stdcall -ordinal SHValidateUNC(long wstr long) 174 stdcall -ordinal SHCreateShellFolderViewEx(ptr ptr) 175 stdcall -noname SHGetSpecialFolderPath(long long long long) SHGetSpecialFolderPathAW - 176 stdcall -ordinal SHSetInstanceExplorer(ptr) + 176 stdcall -ordinal SHSetInstanceExplorer(ptr) shcore.SetProcessReference 177 stub DAD_SetDragImageFromListView 178 stdcall -ordinal SHObjectProperties(long long wstr wstr) 179 stdcall -ordinal SHGetNewLinkInfoA(str str ptr ptr long) @@ -380,7 +380,7 @@ @ stdcall SHGetIconOverlayIndexA(str long) @ stdcall SHGetIconOverlayIndexW(wstr long) @ stdcall SHGetIDListFromObject(ptr ptr) -@ stdcall SHGetInstanceExplorer(ptr) +@ stdcall SHGetInstanceExplorer(ptr) shcore.GetProcessReference @ stdcall SHGetItemFromDataObject(ptr long ptr ptr) @ stdcall SHGetItemFromObject(ptr ptr ptr) @ stdcall SHGetKnownFolderIDList(ptr long ptr ptr) diff --git a/dlls/shell32/shellord.c b/dlls/shell32/shellord.c index 6fc49dcd59..6ed0c9000f 100644 --- a/dlls/shell32/shellord.c +++ b/dlls/shell32/shellord.c @@ -1103,34 +1103,6 @@ BOOL WINAPI SHRunControlPanel (LPCWSTR commandLine, HWND parent) return FALSE; }
-static LPUNKNOWN SHELL32_IExplorerInterface=0; -/************************************************************************* - * SHSetInstanceExplorer [SHELL32.176] - * - * NOTES - * Sets the interface - */ -VOID WINAPI SHSetInstanceExplorer (LPUNKNOWN lpUnknown) -{ TRACE("%p\n", lpUnknown); - SHELL32_IExplorerInterface = lpUnknown; -} -/************************************************************************* - * SHGetInstanceExplorer [SHELL32.@] - * - * NOTES - * gets the interface pointer of the explorer and a reference - */ -HRESULT WINAPI SHGetInstanceExplorer (IUnknown **lpUnknown) -{ TRACE("%p\n", lpUnknown); - - *lpUnknown = SHELL32_IExplorerInterface; - - if (!SHELL32_IExplorerInterface) - return E_FAIL; - - IUnknown_AddRef(SHELL32_IExplorerInterface); - return S_OK; -} /************************************************************************* * SHFreeUnusedLibraries [SHELL32.123] *