winegstreamer: Introduce new wg_sample_create_quartz helper for quartz_transform.c.
[wine.git] / dlls / shcore / main.c
blob6cc18ad147379cc176b8dafd4dbe15aa2dfd9cd7
1 /*
2 * Copyright 2002 Jon Griffiths
3 * Copyright 2016 Sebastian Lackner
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <stdarg.h>
22 #define COBJMACROS
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "initguid.h"
29 #include "ocidl.h"
30 #include "featurestagingapi.h"
31 #include "shellscalingapi.h"
32 #include "shlwapi.h"
34 #include "wine/debug.h"
35 #include "wine/heap.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(shcore);
39 static DWORD shcore_tls;
40 static IUnknown *process_ref;
42 BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved)
44 TRACE("%p, %lu, %p.\n", instance, reason, reserved);
46 switch (reason)
48 case DLL_PROCESS_ATTACH:
49 DisableThreadLibraryCalls(instance);
50 shcore_tls = TlsAlloc();
51 break;
52 case DLL_PROCESS_DETACH:
53 if (reserved) break;
54 if (shcore_tls != TLS_OUT_OF_INDEXES)
55 TlsFree(shcore_tls);
56 break;
59 return TRUE;
62 HRESULT WINAPI GetProcessDpiAwareness(HANDLE process, PROCESS_DPI_AWARENESS *value)
64 if (GetProcessDpiAwarenessInternal( process, (DPI_AWARENESS *)value )) return S_OK;
65 return HRESULT_FROM_WIN32( GetLastError() );
68 HRESULT WINAPI SetProcessDpiAwareness(PROCESS_DPI_AWARENESS value)
70 if (SetProcessDpiAwarenessInternal( value )) return S_OK;
71 return HRESULT_FROM_WIN32( GetLastError() );
74 HRESULT WINAPI GetDpiForMonitor(HMONITOR monitor, MONITOR_DPI_TYPE type, UINT *x, UINT *y)
76 if (GetDpiForMonitorInternal( monitor, type, x, y )) return S_OK;
77 return HRESULT_FROM_WIN32( GetLastError() );
80 HRESULT WINAPI GetScaleFactorForMonitor(HMONITOR monitor, DEVICE_SCALE_FACTOR *scale)
82 FIXME("(%p %p): stub\n", monitor, scale);
84 *scale = SCALE_100_PERCENT;
85 return S_OK;
88 DEVICE_SCALE_FACTOR WINAPI GetScaleFactorForDevice(DISPLAY_DEVICE_TYPE device_type)
90 FIXME("%d\n", device_type);
92 return SCALE_100_PERCENT;
95 HRESULT WINAPI _IStream_Read(IStream *stream, void *dest, ULONG size)
97 ULONG read;
98 HRESULT hr;
100 TRACE("%p, %p, %lu.\n", stream, dest, size);
102 hr = IStream_Read(stream, dest, size, &read);
103 if (SUCCEEDED(hr) && read != size)
104 hr = E_FAIL;
105 return hr;
108 HRESULT WINAPI IStream_Reset(IStream *stream)
110 static const LARGE_INTEGER zero;
112 TRACE("(%p)\n", stream);
114 return IStream_Seek(stream, zero, 0, NULL);
117 HRESULT WINAPI IStream_Size(IStream *stream, ULARGE_INTEGER *size)
119 STATSTG statstg;
120 HRESULT hr;
122 TRACE("(%p, %p)\n", stream, size);
124 memset(&statstg, 0, sizeof(statstg));
126 hr = IStream_Stat(stream, &statstg, STATFLAG_NONAME);
128 if (SUCCEEDED(hr) && size)
129 *size = statstg.cbSize;
130 return hr;
133 HRESULT WINAPI _IStream_Write(IStream *stream, const void *src, ULONG size)
135 ULONG written;
136 HRESULT hr;
138 TRACE("%p, %p, %lu.\n", stream, src, size);
140 hr = IStream_Write(stream, src, size, &written);
141 if (SUCCEEDED(hr) && written != size)
142 hr = E_FAIL;
144 return hr;
147 void WINAPI IUnknown_AtomicRelease(IUnknown **obj)
149 TRACE("(%p)\n", obj);
151 if (!obj || !*obj)
152 return;
154 IUnknown_Release(*obj);
155 *obj = NULL;
158 HRESULT WINAPI IUnknown_GetSite(IUnknown *unk, REFIID iid, void **site)
160 IObjectWithSite *obj = NULL;
161 HRESULT hr = E_INVALIDARG;
163 TRACE("(%p, %s, %p)\n", unk, debugstr_guid(iid), site);
165 if (unk && iid && site)
167 hr = IUnknown_QueryInterface(unk, &IID_IObjectWithSite, (void **)&obj);
168 if (SUCCEEDED(hr) && obj)
170 hr = IObjectWithSite_GetSite(obj, iid, site);
171 IObjectWithSite_Release(obj);
175 return hr;
178 HRESULT WINAPI IUnknown_QueryService(IUnknown *obj, REFGUID sid, REFIID iid, void **out)
180 IServiceProvider *provider = NULL;
181 HRESULT hr;
183 if (!out)
184 return E_FAIL;
186 *out = NULL;
188 if (!obj)
189 return E_FAIL;
191 hr = IUnknown_QueryInterface(obj, &IID_IServiceProvider, (void **)&provider);
192 if (hr == S_OK && provider)
194 TRACE("Using provider %p.\n", provider);
196 hr = IServiceProvider_QueryService(provider, sid, iid, out);
198 TRACE("Provider %p returned %p.\n", provider, *out);
200 IServiceProvider_Release(provider);
203 return hr;
206 void WINAPI IUnknown_Set(IUnknown **dest, IUnknown *src)
208 TRACE("(%p, %p)\n", dest, src);
210 IUnknown_AtomicRelease(dest);
212 if (src)
214 IUnknown_AddRef(src);
215 *dest = src;
219 HRESULT WINAPI IUnknown_SetSite(IUnknown *obj, IUnknown *site)
221 IInternetSecurityManager *sec_manager;
222 IObjectWithSite *objwithsite;
223 HRESULT hr;
225 if (!obj)
226 return E_FAIL;
228 hr = IUnknown_QueryInterface(obj, &IID_IObjectWithSite, (void **)&objwithsite);
229 TRACE("ObjectWithSite %p, hr %#lx.\n", objwithsite, hr);
230 if (SUCCEEDED(hr))
232 hr = IObjectWithSite_SetSite(objwithsite, site);
233 TRACE("SetSite() hr %#lx.\n", hr);
234 IObjectWithSite_Release(objwithsite);
236 else
238 hr = IUnknown_QueryInterface(obj, &IID_IInternetSecurityManager, (void **)&sec_manager);
239 TRACE("InternetSecurityManager %p, hr %#lx.\n", sec_manager, hr);
240 if (FAILED(hr))
241 return hr;
243 hr = IInternetSecurityManager_SetSecuritySite(sec_manager, (IInternetSecurityMgrSite *)site);
244 TRACE("SetSecuritySite() hr %#lx.\n", hr);
245 IInternetSecurityManager_Release(sec_manager);
248 return hr;
251 HRESULT WINAPI SetCurrentProcessExplicitAppUserModelID(const WCHAR *appid)
253 FIXME("%s: stub\n", debugstr_w(appid));
254 return S_OK;
257 HRESULT WINAPI GetCurrentProcessExplicitAppUserModelID(const WCHAR **appid)
259 FIXME("%p: stub\n", appid);
260 *appid = NULL;
261 return E_NOTIMPL;
264 /*************************************************************************
265 * CommandLineToArgvW [SHCORE.@]
267 * We must interpret the quotes in the command line to rebuild the argv
268 * array correctly:
269 * - arguments are separated by spaces or tabs
270 * - quotes serve as optional argument delimiters
271 * '"a b"' -> 'a b'
272 * - escaped quotes must be converted back to '"'
273 * '\"' -> '"'
274 * - consecutive backslashes preceding a quote see their number halved with
275 * the remainder escaping the quote:
276 * 2n backslashes + quote -> n backslashes + quote as an argument delimiter
277 * 2n+1 backslashes + quote -> n backslashes + literal quote
278 * - backslashes that are not followed by a quote are copied literally:
279 * 'a\b' -> 'a\b'
280 * 'a\\b' -> 'a\\b'
281 * - in quoted strings, consecutive quotes see their number divided by three
282 * with the remainder modulo 3 deciding whether to close the string or not.
283 * Note that the opening quote must be counted in the consecutive quotes,
284 * that's the (1+) below:
285 * (1+) 3n quotes -> n quotes
286 * (1+) 3n+1 quotes -> n quotes plus closes the quoted string
287 * (1+) 3n+2 quotes -> n+1 quotes plus closes the quoted string
288 * - in unquoted strings, the first quote opens the quoted string and the
289 * remaining consecutive quotes follow the above rule.
291 WCHAR** WINAPI CommandLineToArgvW(const WCHAR *cmdline, int *numargs)
293 int qcount, bcount;
294 const WCHAR *s;
295 WCHAR **argv;
296 DWORD argc;
297 WCHAR *d;
299 if (!numargs)
301 SetLastError(ERROR_INVALID_PARAMETER);
302 return NULL;
305 if (*cmdline == 0)
307 /* Return the path to the executable */
308 DWORD len, deslen = MAX_PATH, size;
310 size = sizeof(WCHAR *) * 2 + deslen * sizeof(WCHAR);
311 for (;;)
313 if (!(argv = LocalAlloc(LMEM_FIXED, size))) return NULL;
314 len = GetModuleFileNameW(0, (WCHAR *)(argv + 2), deslen);
315 if (!len)
317 LocalFree(argv);
318 return NULL;
320 if (len < deslen) break;
321 deslen *= 2;
322 size = sizeof(WCHAR *) * 2 + deslen * sizeof(WCHAR);
323 LocalFree(argv);
325 argv[0] = (WCHAR *)(argv + 2);
326 argv[1] = NULL;
327 *numargs = 1;
329 return argv;
332 /* --- First count the arguments */
333 argc = 1;
334 s = cmdline;
335 /* The first argument, the executable path, follows special rules */
336 if (*s == '"')
338 /* The executable path ends at the next quote, no matter what */
339 s++;
340 while (*s)
341 if (*s++ == '"')
342 break;
344 else
346 /* The executable path ends at the next space, no matter what */
347 while (*s && *s != ' ' && *s != '\t')
348 s++;
350 /* skip to the first argument, if any */
351 while (*s == ' ' || *s == '\t')
352 s++;
353 if (*s)
354 argc++;
356 /* Analyze the remaining arguments */
357 qcount = bcount = 0;
358 while (*s)
360 if ((*s == ' ' || *s == '\t') && qcount == 0)
362 /* skip to the next argument and count it if any */
363 while (*s == ' ' || *s == '\t')
364 s++;
365 if (*s)
366 argc++;
367 bcount = 0;
369 else if (*s == '\\')
371 /* '\', count them */
372 bcount++;
373 s++;
375 else if (*s == '"')
377 /* '"' */
378 if ((bcount & 1) == 0)
379 qcount++; /* unescaped '"' */
380 s++;
381 bcount = 0;
382 /* consecutive quotes, see comment in copying code below */
383 while (*s == '"')
385 qcount++;
386 s++;
388 qcount = qcount % 3;
389 if (qcount == 2)
390 qcount = 0;
392 else
394 /* a regular character */
395 bcount = 0;
396 s++;
400 /* Allocate in a single lump, the string array, and the strings that go
401 * with it. This way the caller can make a single LocalFree() call to free
402 * both, as per MSDN.
404 argv = LocalAlloc(LMEM_FIXED, (argc + 1) * sizeof(WCHAR *) + (lstrlenW(cmdline) + 1) * sizeof(WCHAR));
405 if (!argv)
406 return NULL;
408 /* --- Then split and copy the arguments */
409 argv[0] = d = lstrcpyW((WCHAR *)(argv + argc + 1), cmdline);
410 argc = 1;
411 /* The first argument, the executable path, follows special rules */
412 if (*d == '"')
414 /* The executable path ends at the next quote, no matter what */
415 s = d + 1;
416 while (*s)
418 if (*s == '"')
420 s++;
421 break;
423 *d++ = *s++;
426 else
428 /* The executable path ends at the next space, no matter what */
429 while (*d && *d != ' ' && *d != '\t')
430 d++;
431 s = d;
432 if (*s)
433 s++;
435 /* close the executable path */
436 *d++ = 0;
437 /* skip to the first argument and initialize it if any */
438 while (*s == ' ' || *s == '\t')
439 s++;
440 if (!*s)
442 /* There are no parameters so we are all done */
443 argv[argc] = NULL;
444 *numargs = argc;
445 return argv;
448 /* Split and copy the remaining arguments */
449 argv[argc++] = d;
450 qcount = bcount = 0;
451 while (*s)
453 if ((*s == ' ' || *s == '\t') && qcount == 0)
455 /* close the argument */
456 *d++ = 0;
457 bcount = 0;
459 /* skip to the next one and initialize it if any */
460 do {
461 s++;
462 } while (*s == ' ' || *s == '\t');
463 if (*s)
464 argv[argc++] = d;
466 else if (*s=='\\')
468 *d++ = *s++;
469 bcount++;
471 else if (*s == '"')
473 if ((bcount & 1) == 0)
475 /* Preceded by an even number of '\', this is half that
476 * number of '\', plus a quote which we erase.
478 d -= bcount / 2;
479 qcount++;
481 else
483 /* Preceded by an odd number of '\', this is half that
484 * number of '\' followed by a '"'
486 d = d - bcount / 2 - 1;
487 *d++ = '"';
489 s++;
490 bcount = 0;
491 /* Now count the number of consecutive quotes. Note that qcount
492 * already takes into account the opening quote if any, as well as
493 * the quote that lead us here.
495 while (*s == '"')
497 if (++qcount == 3)
499 *d++ = '"';
500 qcount = 0;
502 s++;
504 if (qcount == 2)
505 qcount = 0;
507 else
509 /* a regular character */
510 *d++ = *s++;
511 bcount = 0;
514 *d = '\0';
515 argv[argc] = NULL;
516 *numargs = argc;
518 return argv;
521 struct shstream
523 IStream IStream_iface;
524 LONG refcount;
526 union
528 struct
530 BYTE *buffer;
531 DWORD length;
532 DWORD position;
534 HKEY hkey;
535 WCHAR *valuename;
536 } mem;
537 struct
539 HANDLE handle;
540 DWORD mode;
541 WCHAR *path;
542 } file;
543 } u;
546 static inline struct shstream *impl_from_IStream(IStream *iface)
548 return CONTAINING_RECORD(iface, struct shstream, IStream_iface);
551 static HRESULT WINAPI shstream_QueryInterface(IStream *iface, REFIID riid, void **out)
553 struct shstream *stream = impl_from_IStream(iface);
555 TRACE("(%p)->(%s, %p)\n", stream, debugstr_guid(riid), out);
557 if (IsEqualIID(riid, &IID_IUnknown) ||
558 IsEqualIID(riid, &IID_IStream) ||
559 IsEqualIID(riid, &IID_ISequentialStream))
561 *out = iface;
562 IStream_AddRef(iface);
563 return S_OK;
566 *out = NULL;
567 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
568 return E_NOINTERFACE;
571 static ULONG WINAPI shstream_AddRef(IStream *iface)
573 struct shstream *stream = impl_from_IStream(iface);
574 ULONG refcount = InterlockedIncrement(&stream->refcount);
576 TRACE("%p, refcount %lu.\n", iface, refcount);
578 return refcount;
581 static ULONG WINAPI memstream_Release(IStream *iface)
583 struct shstream *stream = impl_from_IStream(iface);
584 ULONG refcount = InterlockedDecrement(&stream->refcount);
586 TRACE("%p, refcount %lu.\n", iface, refcount);
588 if (!refcount)
590 heap_free(stream->u.mem.buffer);
591 heap_free(stream);
594 return refcount;
597 static HRESULT WINAPI memstream_Read(IStream *iface, void *buff, ULONG buff_size, ULONG *read_len)
599 struct shstream *stream = impl_from_IStream(iface);
600 DWORD length;
602 TRACE("%p, %p, %lu, %p.\n", iface, buff, buff_size, read_len);
604 if (stream->u.mem.position >= stream->u.mem.length)
606 if (read_len)
607 *read_len = 0;
608 return S_FALSE;
611 length = stream->u.mem.length - stream->u.mem.position;
612 if (buff_size < length)
613 length = buff_size;
615 memmove(buff, stream->u.mem.buffer + stream->u.mem.position, length);
616 stream->u.mem.position += length;
618 if (read_len)
619 *read_len = length;
621 return S_OK;
624 static HRESULT WINAPI memstream_Write(IStream *iface, const void *buff, ULONG buff_size, ULONG *written)
626 struct shstream *stream = impl_from_IStream(iface);
627 DWORD length = stream->u.mem.position + buff_size;
629 TRACE("%p, %p, %lu, %p.\n", iface, buff, buff_size, written);
631 if (length < stream->u.mem.position) /* overflow */
632 return STG_E_INSUFFICIENTMEMORY;
634 if (length > stream->u.mem.length)
636 BYTE *buffer = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, stream->u.mem.buffer, length);
637 if (!buffer)
638 return STG_E_INSUFFICIENTMEMORY;
640 stream->u.mem.length = length;
641 stream->u.mem.buffer = buffer;
643 memmove(stream->u.mem.buffer + stream->u.mem.position, buff, buff_size);
644 stream->u.mem.position += buff_size; /* adjust pointer */
646 if (written)
647 *written = buff_size;
649 return S_OK;
652 static HRESULT WINAPI memstream_Seek(IStream *iface, LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER*new_pos)
654 struct shstream *stream = impl_from_IStream(iface);
655 LARGE_INTEGER tmp;
657 TRACE("%p, %s, %ld, %p.\n", iface, wine_dbgstr_longlong(move.QuadPart), origin, new_pos);
659 if (origin == STREAM_SEEK_SET)
660 tmp = move;
661 else if (origin == STREAM_SEEK_CUR)
662 tmp.QuadPart = stream->u.mem.position + move.QuadPart;
663 else if (origin == STREAM_SEEK_END)
664 tmp.QuadPart = stream->u.mem.length + move.QuadPart;
665 else
666 return STG_E_INVALIDPARAMETER;
668 if (tmp.QuadPart < 0)
669 return STG_E_INVALIDFUNCTION;
671 /* we cut off the high part here */
672 stream->u.mem.position = tmp.u.LowPart;
674 if (new_pos)
675 new_pos->QuadPart = stream->u.mem.position;
676 return S_OK;
679 static HRESULT WINAPI memstream_SetSize(IStream *iface, ULARGE_INTEGER new_size)
681 struct shstream *stream = impl_from_IStream(iface);
682 DWORD length;
683 BYTE *buffer;
685 TRACE("(%p, %s)\n", stream, wine_dbgstr_longlong(new_size.QuadPart));
687 /* we cut off the high part here */
688 length = new_size.u.LowPart;
689 buffer = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, stream->u.mem.buffer, length);
690 if (!buffer)
691 return STG_E_INSUFFICIENTMEMORY;
693 stream->u.mem.buffer = buffer;
694 stream->u.mem.length = length;
696 return S_OK;
699 static HRESULT WINAPI shstream_CopyTo(IStream *iface, IStream *dest, ULARGE_INTEGER size,
700 ULARGE_INTEGER *read_len, ULARGE_INTEGER *written)
702 struct shstream *stream = impl_from_IStream(iface);
703 ULARGE_INTEGER total_read, total_written;
704 HRESULT hr = S_OK;
705 BYTE buffer[0x400];
707 TRACE("(%p, %p, %s, %p, %p)\n", stream, dest, wine_dbgstr_longlong(size.QuadPart), read_len, written);
709 if (!dest)
710 return E_POINTER;
712 total_read.QuadPart = 0;
713 total_written.QuadPart = 0;
715 while (size.QuadPart > 0)
717 ULONG chunk_size = size.QuadPart >= sizeof(buffer) ? sizeof(buffer) : size.u.LowPart;
718 ULONG chunk_read, chunk_written;
720 hr = IStream_Read(iface, buffer, chunk_size, &chunk_read);
721 if (FAILED(hr))
722 break;
724 total_read.QuadPart += chunk_read;
726 if (chunk_read)
728 hr = IStream_Write(dest, buffer, chunk_read, &chunk_written);
729 if (FAILED(hr))
730 break;
732 total_written.QuadPart += chunk_written;
735 if (chunk_read != chunk_size)
736 size.QuadPart = 0;
737 else
738 size.QuadPart -= chunk_read;
741 if (read_len)
742 read_len->QuadPart = total_read.QuadPart;
743 if (written)
744 written->QuadPart = total_written.QuadPart;
746 return hr;
749 static HRESULT WINAPI shstream_Commit(IStream *iface, DWORD flags)
751 TRACE("%p, %#lx.\n", iface, flags);
753 /* Commit is not supported by this stream */
754 return E_NOTIMPL;
757 static HRESULT WINAPI shstream_Revert(IStream *iface)
759 struct shstream *stream = impl_from_IStream(iface);
761 TRACE("(%p)\n", stream);
763 /* revert not supported by this stream */
764 return E_NOTIMPL;
767 static HRESULT WINAPI shstream_LockRegion(IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER size, DWORD lock_type)
769 struct shstream *stream = impl_from_IStream(iface);
771 TRACE("(%p)\n", stream);
773 /* lock/unlock not supported by this stream */
774 return E_NOTIMPL;
777 static HRESULT WINAPI shstream_UnlockRegion(IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER size, DWORD lock_type)
779 struct shstream *stream = impl_from_IStream(iface);
781 TRACE("(%p)\n", stream);
783 /* lock/unlock not supported by this stream */
784 return E_NOTIMPL;
787 static HRESULT WINAPI memstream_Stat(IStream *iface, STATSTG *statstg, DWORD flags)
789 struct shstream *stream = impl_from_IStream(iface);
791 TRACE("%p, %p, %#lx.\n", iface, statstg, flags);
793 memset(statstg, 0, sizeof(*statstg));
794 statstg->type = STGTY_STREAM;
795 statstg->cbSize.QuadPart = stream->u.mem.length;
796 statstg->grfMode = STGM_READWRITE;
798 return S_OK;
801 static HRESULT WINAPI shstream_Clone(IStream *iface, IStream **dest)
803 struct shstream *stream = impl_from_IStream(iface);
805 TRACE("(%p, %p)\n", stream, dest);
807 *dest = NULL;
809 /* clone not supported by this stream */
810 return E_NOTIMPL;
813 static const IStreamVtbl memstreamvtbl =
815 shstream_QueryInterface,
816 shstream_AddRef,
817 memstream_Release,
818 memstream_Read,
819 memstream_Write,
820 memstream_Seek,
821 memstream_SetSize,
822 shstream_CopyTo,
823 shstream_Commit,
824 shstream_Revert,
825 shstream_LockRegion,
826 shstream_UnlockRegion,
827 memstream_Stat,
828 shstream_Clone,
831 static struct shstream *shstream_create(const IStreamVtbl *vtbl, const BYTE *data, UINT data_len)
833 struct shstream *stream;
835 if (!data)
836 data_len = 0;
838 stream = heap_alloc(sizeof(*stream));
839 stream->IStream_iface.lpVtbl = vtbl;
840 stream->refcount = 1;
841 stream->u.mem.buffer = heap_alloc(data_len);
842 if (!stream->u.mem.buffer)
844 heap_free(stream);
845 return NULL;
847 memcpy(stream->u.mem.buffer, data, data_len);
848 stream->u.mem.length = data_len;
849 stream->u.mem.position = 0;
851 return stream;
854 /*************************************************************************
855 * SHCreateMemStream [SHCORE.@]
857 * Create an IStream object on a block of memory.
859 * PARAMS
860 * data [I] Memory block to create the IStream object on
861 * data_len [I] Length of data block
863 * RETURNS
864 * Success: A pointer to the IStream object.
865 * Failure: NULL, if any parameters are invalid or an error occurs.
867 * NOTES
868 * A copy of the memory block is made, it's freed when the stream is released.
870 IStream * WINAPI SHCreateMemStream(const BYTE *data, UINT data_len)
872 struct shstream *stream;
874 TRACE("(%p, %u)\n", data, data_len);
876 stream = shstream_create(&memstreamvtbl, data, data_len);
877 return stream ? &stream->IStream_iface : NULL;
880 static ULONG WINAPI filestream_Release(IStream *iface)
882 struct shstream *stream = impl_from_IStream(iface);
883 ULONG refcount = InterlockedDecrement(&stream->refcount);
885 TRACE("%p, refcount %lu.\n", iface, refcount);
887 if (!refcount)
889 CloseHandle(stream->u.file.handle);
890 heap_free(stream->u.file.path);
891 heap_free(stream);
894 return refcount;
897 static HRESULT WINAPI filestream_Read(IStream *iface, void *buff, ULONG size, ULONG *read_len)
899 struct shstream *stream = impl_from_IStream(iface);
900 DWORD read = 0;
902 TRACE("%p, %p, %lu, %p.\n", iface, buff, size, read_len);
904 if (!ReadFile(stream->u.file.handle, buff, size, &read, NULL))
906 WARN("error %ld reading file\n", GetLastError());
907 return S_FALSE;
910 if (read_len)
911 *read_len = read;
913 return read == size ? S_OK : S_FALSE;
916 static HRESULT WINAPI filestream_Write(IStream *iface, const void *buff, ULONG size, ULONG *written)
918 struct shstream *stream = impl_from_IStream(iface);
919 DWORD written_len = 0;
921 TRACE("%p, %p, %lu, %p.\n", iface, buff, size, written);
923 switch (stream->u.file.mode & 0xf)
925 case STGM_WRITE:
926 case STGM_READWRITE:
927 break;
928 default:
929 return STG_E_ACCESSDENIED;
932 if (!WriteFile(stream->u.file.handle, buff, size, &written_len, NULL))
933 return HRESULT_FROM_WIN32(GetLastError());
935 if (written)
936 *written = written_len;
938 return S_OK;
941 static HRESULT WINAPI filestream_Seek(IStream *iface, LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER *new_pos)
943 struct shstream *stream = impl_from_IStream(iface);
944 DWORD position;
946 TRACE("%p, %s, %ld, %p.\n", iface, wine_dbgstr_longlong(move.QuadPart), origin, new_pos);
948 position = SetFilePointer(stream->u.file.handle, move.u.LowPart, NULL, origin);
949 if (position == INVALID_SET_FILE_POINTER)
950 return HRESULT_FROM_WIN32(GetLastError());
952 if (new_pos)
954 new_pos->u.HighPart = 0;
955 new_pos->u.LowPart = position;
958 return S_OK;
961 static HRESULT WINAPI filestream_SetSize(IStream *iface, ULARGE_INTEGER size)
963 struct shstream *stream = impl_from_IStream(iface);
964 LARGE_INTEGER origin, move;
966 TRACE("(%p, %s)\n", stream, wine_dbgstr_longlong(size.QuadPart));
968 move.QuadPart = 0;
969 if (!SetFilePointerEx(stream->u.file.handle, move, &origin, FILE_CURRENT))
970 return E_FAIL;
972 move.QuadPart = size.QuadPart;
973 if (!SetFilePointerEx(stream->u.file.handle, move, NULL, FILE_BEGIN))
974 return E_FAIL;
976 if (stream->u.file.mode != STGM_READ)
978 if (!SetEndOfFile(stream->u.file.handle))
979 return E_FAIL;
980 if (!SetFilePointerEx(stream->u.file.handle, origin, NULL, FILE_BEGIN))
981 return E_FAIL;
984 return S_OK;
987 static HRESULT WINAPI filestream_CopyTo(IStream *iface, IStream *dest, ULARGE_INTEGER size,
988 ULARGE_INTEGER *read_len, ULARGE_INTEGER *written)
990 struct shstream *stream = impl_from_IStream(iface);
991 HRESULT hr = S_OK;
992 char buff[1024];
994 TRACE("(%p, %p, %s, %p, %p)\n", stream, dest, wine_dbgstr_longlong(size.QuadPart), read_len, written);
996 if (read_len)
997 read_len->QuadPart = 0;
998 if (written)
999 written->QuadPart = 0;
1001 if (!dest)
1002 return S_OK;
1004 while (size.QuadPart)
1006 ULONG left, read_chunk, written_chunk;
1008 left = size.QuadPart > sizeof(buff) ? sizeof(buff) : size.QuadPart;
1010 /* Read */
1011 hr = IStream_Read(iface, buff, left, &read_chunk);
1012 if (FAILED(hr) || read_chunk == 0)
1013 break;
1014 if (read_len)
1015 read_len->QuadPart += read_chunk;
1017 /* Write */
1018 hr = IStream_Write(dest, buff, read_chunk, &written_chunk);
1019 if (written_chunk)
1020 written->QuadPart += written_chunk;
1021 if (FAILED(hr) || written_chunk != left)
1022 break;
1024 size.QuadPart -= left;
1027 return hr;
1030 static HRESULT WINAPI filestream_Commit(IStream *iface, DWORD flags)
1032 TRACE("%p, %#lx.\n", iface, flags);
1034 return S_OK;
1037 static HRESULT WINAPI filestream_Stat(IStream *iface, STATSTG *statstg, DWORD flags)
1039 struct shstream *stream = impl_from_IStream(iface);
1040 BY_HANDLE_FILE_INFORMATION fi;
1042 TRACE("%p, %p, %#lx.\n", iface, statstg, flags);
1044 if (!statstg)
1045 return STG_E_INVALIDPOINTER;
1047 memset(&fi, 0, sizeof(fi));
1048 GetFileInformationByHandle(stream->u.file.handle, &fi);
1050 if (flags & STATFLAG_NONAME)
1051 statstg->pwcsName = NULL;
1052 else
1054 int len = lstrlenW(stream->u.file.path);
1055 if ((statstg->pwcsName = CoTaskMemAlloc((len + 1) * sizeof(WCHAR))))
1056 memcpy(statstg->pwcsName, stream->u.file.path, (len + 1) * sizeof(WCHAR));
1058 statstg->type = 0;
1059 statstg->cbSize.u.LowPart = fi.nFileSizeLow;
1060 statstg->cbSize.u.HighPart = fi.nFileSizeHigh;
1061 statstg->mtime = fi.ftLastWriteTime;
1062 statstg->ctime = fi.ftCreationTime;
1063 statstg->atime = fi.ftLastAccessTime;
1064 statstg->grfMode = stream->u.file.mode;
1065 statstg->grfLocksSupported = 0;
1066 memcpy(&statstg->clsid, &IID_IStream, sizeof(CLSID));
1067 statstg->grfStateBits = 0;
1068 statstg->reserved = 0;
1070 return S_OK;
1073 static const IStreamVtbl filestreamvtbl =
1075 shstream_QueryInterface,
1076 shstream_AddRef,
1077 filestream_Release,
1078 filestream_Read,
1079 filestream_Write,
1080 filestream_Seek,
1081 filestream_SetSize,
1082 filestream_CopyTo,
1083 filestream_Commit,
1084 shstream_Revert,
1085 shstream_LockRegion,
1086 shstream_UnlockRegion,
1087 filestream_Stat,
1088 shstream_Clone,
1091 /*************************************************************************
1092 * SHCreateStreamOnFileEx [SHCORE.@]
1094 HRESULT WINAPI SHCreateStreamOnFileEx(const WCHAR *path, DWORD mode, DWORD attributes,
1095 BOOL create, IStream *template, IStream **ret)
1097 DWORD access, share, creation_disposition, len;
1098 struct shstream *stream;
1099 HANDLE hFile;
1101 TRACE("%s, %ld, %#lx, %d, %p, %p)\n", debugstr_w(path), mode, attributes,
1102 create, template, ret);
1104 if (!path || !ret || template)
1105 return E_INVALIDARG;
1107 *ret = NULL;
1109 /* Access */
1110 switch (mode & 0xf)
1112 case STGM_WRITE:
1113 case STGM_READWRITE:
1114 access = GENERIC_READ | GENERIC_WRITE;
1115 break;
1116 case STGM_READ:
1117 access = GENERIC_READ;
1118 break;
1119 default:
1120 return E_INVALIDARG;
1123 /* Sharing */
1124 switch (mode & 0xf0)
1126 case 0:
1127 case STGM_SHARE_DENY_NONE:
1128 share = FILE_SHARE_READ | FILE_SHARE_WRITE;
1129 break;
1130 case STGM_SHARE_DENY_READ:
1131 share = FILE_SHARE_WRITE;
1132 break;
1133 case STGM_SHARE_DENY_WRITE:
1134 share = FILE_SHARE_READ;
1135 break;
1136 case STGM_SHARE_EXCLUSIVE:
1137 share = 0;
1138 break;
1139 default:
1140 return E_INVALIDARG;
1143 switch (mode & 0xf000)
1145 case STGM_FAILIFTHERE:
1146 creation_disposition = create ? CREATE_NEW : OPEN_EXISTING;
1147 break;
1148 case STGM_CREATE:
1149 creation_disposition = CREATE_ALWAYS;
1150 break;
1151 default:
1152 return E_INVALIDARG;
1155 hFile = CreateFileW(path, access, share, NULL, creation_disposition, attributes, 0);
1156 if (hFile == INVALID_HANDLE_VALUE)
1157 return HRESULT_FROM_WIN32(GetLastError());
1159 stream = heap_alloc(sizeof(*stream));
1160 stream->IStream_iface.lpVtbl = &filestreamvtbl;
1161 stream->refcount = 1;
1162 stream->u.file.handle = hFile;
1163 stream->u.file.mode = mode;
1165 len = lstrlenW(path);
1166 stream->u.file.path = heap_alloc((len + 1) * sizeof(WCHAR));
1167 memcpy(stream->u.file.path, path, (len + 1) * sizeof(WCHAR));
1169 *ret = &stream->IStream_iface;
1171 return S_OK;
1174 /*************************************************************************
1175 * SHCreateStreamOnFileW [SHCORE.@]
1177 HRESULT WINAPI SHCreateStreamOnFileW(const WCHAR *path, DWORD mode, IStream **stream)
1179 TRACE("%s, %#lx, %p.\n", debugstr_w(path), mode, stream);
1181 if (!path || !stream)
1182 return E_INVALIDARG;
1184 if ((mode & (STGM_CONVERT | STGM_DELETEONRELEASE | STGM_TRANSACTED)) != 0)
1185 return E_INVALIDARG;
1187 return SHCreateStreamOnFileEx(path, mode, 0, FALSE, NULL, stream);
1190 /*************************************************************************
1191 * SHCreateStreamOnFileA [SHCORE.@]
1193 HRESULT WINAPI SHCreateStreamOnFileA(const char *path, DWORD mode, IStream **stream)
1195 WCHAR *pathW;
1196 HRESULT hr;
1197 DWORD len;
1199 TRACE("%s, %#lx, %p.\n", debugstr_a(path), mode, stream);
1201 if (!path)
1202 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1204 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1205 pathW = heap_alloc(len * sizeof(WCHAR));
1206 if (!pathW)
1207 return E_OUTOFMEMORY;
1209 MultiByteToWideChar(CP_ACP, 0, path, -1, pathW, len);
1210 hr = SHCreateStreamOnFileW(pathW, mode, stream);
1211 heap_free(pathW);
1213 return hr;
1216 static ULONG WINAPI regstream_Release(IStream *iface)
1218 struct shstream *stream = impl_from_IStream(iface);
1219 ULONG refcount = InterlockedDecrement(&stream->refcount);
1221 TRACE("%p, refcount %lu.\n", iface, refcount);
1223 if (!refcount)
1225 if (stream->u.mem.hkey)
1227 if (stream->u.mem.length)
1228 RegSetValueExW(stream->u.mem.hkey, stream->u.mem.valuename, 0, REG_BINARY,
1229 (const BYTE *)stream->u.mem.buffer, stream->u.mem.length);
1230 else
1231 RegDeleteValueW(stream->u.mem.hkey, stream->u.mem.valuename);
1232 RegCloseKey(stream->u.mem.hkey);
1234 CoTaskMemFree(stream->u.mem.valuename);
1235 heap_free(stream->u.mem.buffer);
1236 heap_free(stream);
1239 return refcount;
1242 static const IStreamVtbl regstreamvtbl =
1244 shstream_QueryInterface,
1245 shstream_AddRef,
1246 regstream_Release,
1247 memstream_Read,
1248 memstream_Write,
1249 memstream_Seek,
1250 memstream_SetSize,
1251 shstream_CopyTo,
1252 shstream_Commit,
1253 shstream_Revert,
1254 shstream_LockRegion,
1255 shstream_UnlockRegion,
1256 memstream_Stat,
1257 shstream_Clone,
1260 /*************************************************************************
1261 * SHOpenRegStream2W [SHCORE.@]
1263 IStream * WINAPI SHOpenRegStream2W(HKEY hKey, const WCHAR *subkey, const WCHAR *value, DWORD mode)
1265 struct shstream *stream;
1266 HKEY hStrKey = NULL;
1267 BYTE *buff = NULL;
1268 DWORD length = 0;
1269 LONG ret;
1271 TRACE("%p, %s, %s, %#lx.\n", hKey, debugstr_w(subkey), debugstr_w(value), mode);
1273 if (mode == STGM_READ)
1274 ret = RegOpenKeyExW(hKey, subkey, 0, KEY_READ, &hStrKey);
1275 else /* in write mode we make sure the subkey exits */
1276 ret = RegCreateKeyExW(hKey, subkey, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &hStrKey, NULL);
1278 if (ret == ERROR_SUCCESS)
1280 if (mode == STGM_READ || mode == STGM_READWRITE)
1282 /* read initial data */
1283 ret = RegQueryValueExW(hStrKey, value, 0, 0, 0, &length);
1284 if (ret == ERROR_SUCCESS && length)
1286 buff = heap_alloc(length);
1287 RegQueryValueExW(hStrKey, value, 0, 0, buff, &length);
1291 if (!length)
1292 buff = heap_alloc(length);
1294 stream = shstream_create(&regstreamvtbl, buff, length);
1295 heap_free(buff);
1296 if (stream)
1298 stream->u.mem.hkey = hStrKey;
1299 SHStrDupW(value, &stream->u.mem.valuename);
1300 return &stream->IStream_iface;
1304 if (hStrKey)
1305 RegCloseKey(hStrKey);
1307 return NULL;
1310 /*************************************************************************
1311 * SHOpenRegStream2A [SHCORE.@]
1313 IStream * WINAPI SHOpenRegStream2A(HKEY hKey, const char *subkey, const char *value, DWORD mode)
1315 WCHAR *subkeyW = NULL, *valueW = NULL;
1316 IStream *stream;
1318 TRACE("%p, %s, %s, %#lx.\n", hKey, debugstr_a(subkey), debugstr_a(value), mode);
1320 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1321 return NULL;
1322 if (value && FAILED(SHStrDupA(value, &valueW)))
1324 CoTaskMemFree(subkeyW);
1325 return NULL;
1328 stream = SHOpenRegStream2W(hKey, subkeyW, valueW, mode);
1329 CoTaskMemFree(subkeyW);
1330 CoTaskMemFree(valueW);
1331 return stream;
1334 /*************************************************************************
1335 * SHOpenRegStreamA [SHCORE.@]
1337 IStream * WINAPI SHOpenRegStreamA(HKEY hkey, const char *subkey, const char *value, DWORD mode)
1339 WCHAR *subkeyW = NULL, *valueW = NULL;
1340 IStream *stream;
1342 TRACE("%p, %s, %s, %#lx.\n", hkey, debugstr_a(subkey), debugstr_a(value), mode);
1344 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1345 return NULL;
1346 if (value && FAILED(SHStrDupA(value, &valueW)))
1348 CoTaskMemFree(subkeyW);
1349 return NULL;
1352 stream = SHOpenRegStreamW(hkey, subkeyW, valueW, mode);
1353 CoTaskMemFree(subkeyW);
1354 CoTaskMemFree(valueW);
1355 return stream;
1358 static ULONG WINAPI dummystream_AddRef(IStream *iface)
1360 TRACE("()\n");
1361 return 2;
1364 static ULONG WINAPI dummystream_Release(IStream *iface)
1366 TRACE("()\n");
1367 return 1;
1370 static HRESULT WINAPI dummystream_Read(IStream *iface, void *buff, ULONG buff_size, ULONG *read_len)
1372 if (read_len)
1373 *read_len = 0;
1375 return E_NOTIMPL;
1378 static const IStreamVtbl dummystreamvtbl =
1380 shstream_QueryInterface,
1381 dummystream_AddRef,
1382 dummystream_Release,
1383 dummystream_Read,
1384 memstream_Write,
1385 memstream_Seek,
1386 memstream_SetSize,
1387 shstream_CopyTo,
1388 shstream_Commit,
1389 shstream_Revert,
1390 shstream_LockRegion,
1391 shstream_UnlockRegion,
1392 memstream_Stat,
1393 shstream_Clone,
1396 static struct shstream dummyregstream = { { &dummystreamvtbl } };
1398 /*************************************************************************
1399 * SHOpenRegStreamW [SHCORE.@]
1401 IStream * WINAPI SHOpenRegStreamW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, DWORD mode)
1403 IStream *stream;
1405 TRACE("%p, %s, %s, %#lx.\n", hkey, debugstr_w(subkey), debugstr_w(value), mode);
1406 stream = SHOpenRegStream2W(hkey, subkey, value, mode);
1407 return stream ? stream : &dummyregstream.IStream_iface;
1410 struct threadref
1412 IUnknown IUnknown_iface;
1413 LONG *refcount;
1416 static inline struct threadref *threadref_impl_from_IUnknown(IUnknown *iface)
1418 return CONTAINING_RECORD(iface, struct threadref, IUnknown_iface);
1421 static HRESULT WINAPI threadref_QueryInterface(IUnknown *iface, REFIID riid, void **out)
1423 struct threadref *threadref = threadref_impl_from_IUnknown(iface);
1425 TRACE("(%p, %s, %p)\n", threadref, debugstr_guid(riid), out);
1427 if (out == NULL)
1428 return E_POINTER;
1430 if (IsEqualGUID(&IID_IUnknown, riid))
1432 *out = iface;
1433 IUnknown_AddRef(iface);
1434 return S_OK;
1437 *out = NULL;
1438 WARN("Interface %s not supported.\n", debugstr_guid(riid));
1439 return E_NOINTERFACE;
1442 static ULONG WINAPI threadref_AddRef(IUnknown *iface)
1444 struct threadref *threadref = threadref_impl_from_IUnknown(iface);
1445 LONG refcount = InterlockedIncrement(threadref->refcount);
1447 TRACE("%p, refcount %ld.\n", threadref, refcount);
1449 return refcount;
1452 static ULONG WINAPI threadref_Release(IUnknown *iface)
1454 struct threadref *threadref = threadref_impl_from_IUnknown(iface);
1455 LONG refcount = InterlockedDecrement(threadref->refcount);
1457 TRACE("%p, refcount %ld.\n", threadref, refcount);
1459 if (!refcount)
1460 heap_free(threadref);
1462 return refcount;
1465 static const IUnknownVtbl threadrefvtbl =
1467 threadref_QueryInterface,
1468 threadref_AddRef,
1469 threadref_Release,
1472 /*************************************************************************
1473 * SHCreateThreadRef [SHCORE.@]
1475 HRESULT WINAPI SHCreateThreadRef(LONG *refcount, IUnknown **out)
1477 struct threadref *threadref;
1479 TRACE("(%p, %p)\n", refcount, out);
1481 if (!refcount || !out)
1482 return E_INVALIDARG;
1484 *out = NULL;
1486 threadref = heap_alloc(sizeof(*threadref));
1487 if (!threadref)
1488 return E_OUTOFMEMORY;
1489 threadref->IUnknown_iface.lpVtbl = &threadrefvtbl;
1490 threadref->refcount = refcount;
1492 *refcount = 1;
1493 *out = &threadref->IUnknown_iface;
1495 TRACE("Created %p.\n", threadref);
1496 return S_OK;
1499 /*************************************************************************
1500 * SHGetThreadRef [SHCORE.@]
1502 HRESULT WINAPI SHGetThreadRef(IUnknown **out)
1504 TRACE("(%p)\n", out);
1506 if (shcore_tls == TLS_OUT_OF_INDEXES)
1507 return E_NOINTERFACE;
1509 *out = TlsGetValue(shcore_tls);
1510 if (!*out)
1511 return E_NOINTERFACE;
1513 IUnknown_AddRef(*out);
1514 return S_OK;
1517 /*************************************************************************
1518 * SHSetThreadRef [SHCORE.@]
1520 HRESULT WINAPI SHSetThreadRef(IUnknown *obj)
1522 TRACE("(%p)\n", obj);
1524 if (shcore_tls == TLS_OUT_OF_INDEXES)
1525 return E_NOINTERFACE;
1527 TlsSetValue(shcore_tls, obj);
1528 return S_OK;
1531 /*************************************************************************
1532 * SHReleaseThreadRef [SHCORE.@]
1534 HRESULT WINAPI SHReleaseThreadRef(void)
1536 FIXME("() - stub!\n");
1537 return S_OK;
1540 /*************************************************************************
1541 * GetProcessReference [SHCORE.@]
1543 HRESULT WINAPI GetProcessReference(IUnknown **obj)
1545 TRACE("(%p)\n", obj);
1547 *obj = process_ref;
1549 if (!process_ref)
1550 return E_FAIL;
1552 if (*obj)
1553 IUnknown_AddRef(*obj);
1555 return S_OK;
1558 /*************************************************************************
1559 * SetProcessReference [SHCORE.@]
1561 void WINAPI SetProcessReference(IUnknown *obj)
1563 TRACE("(%p)\n", obj);
1565 process_ref = obj;
1568 struct thread_data
1570 LPTHREAD_START_ROUTINE thread_proc;
1571 LPTHREAD_START_ROUTINE callback;
1572 void *data;
1573 DWORD flags;
1574 HANDLE hEvent;
1575 IUnknown *thread_ref;
1576 IUnknown *process_ref;
1579 static DWORD WINAPI shcore_thread_wrapper(void *data)
1581 struct thread_data thread_data;
1582 HRESULT hr = E_FAIL;
1583 DWORD retval;
1585 TRACE("(%p)\n", data);
1587 /* We are now executing in the context of the newly created thread.
1588 * So we copy the data passed to us (it is on the stack of the function
1589 * that called us, which is waiting for us to signal an event before
1590 * returning). */
1591 thread_data = *(struct thread_data *)data;
1593 if (thread_data.flags & CTF_COINIT)
1595 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
1596 if (FAILED(hr))
1597 hr = CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE);
1600 if (thread_data.callback)
1601 thread_data.callback(thread_data.data);
1603 /* Signal the thread that created us; it can return now. */
1604 SetEvent(thread_data.hEvent);
1606 /* Execute the callers start code. */
1607 retval = thread_data.thread_proc(thread_data.data);
1609 /* Release thread and process references. */
1610 if (thread_data.thread_ref)
1611 IUnknown_Release(thread_data.thread_ref);
1613 if (thread_data.process_ref)
1614 IUnknown_Release(thread_data.process_ref);
1616 if (SUCCEEDED(hr))
1617 CoUninitialize();
1619 return retval;
1622 /*************************************************************************
1623 * SHCreateThread [SHCORE.@]
1625 BOOL WINAPI SHCreateThread(LPTHREAD_START_ROUTINE thread_proc, void *data, DWORD flags, LPTHREAD_START_ROUTINE callback)
1627 struct thread_data thread_data;
1628 BOOL called = FALSE;
1630 TRACE("%p, %p, %#lx, %p.\n", thread_proc, data, flags, callback);
1632 thread_data.thread_proc = thread_proc;
1633 thread_data.callback = callback;
1634 thread_data.data = data;
1635 thread_data.flags = flags;
1636 thread_data.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
1638 if (flags & CTF_THREAD_REF)
1639 SHGetThreadRef(&thread_data.thread_ref);
1640 else
1641 thread_data.thread_ref = NULL;
1643 if (flags & CTF_PROCESS_REF)
1644 GetProcessReference(&thread_data.process_ref);
1645 else
1646 thread_data.process_ref = NULL;
1648 /* Create the thread */
1649 if (thread_data.hEvent)
1651 HANDLE hThread;
1652 DWORD retval;
1654 hThread = CreateThread(NULL, 0, shcore_thread_wrapper, &thread_data, 0, &retval);
1655 if (hThread)
1657 /* Wait for the thread to signal us to continue */
1658 WaitForSingleObject(thread_data.hEvent, INFINITE);
1659 CloseHandle(hThread);
1660 called = TRUE;
1662 CloseHandle(thread_data.hEvent);
1665 if (!called)
1667 if (!thread_data.callback && flags & CTF_INSIST)
1669 /* Couldn't call, call synchronously */
1670 thread_data.thread_proc(data);
1671 called = TRUE;
1673 else
1675 if (thread_data.thread_ref)
1676 IUnknown_Release(thread_data.thread_ref);
1678 if (thread_data.process_ref)
1679 IUnknown_Release(thread_data.process_ref);
1683 return called;
1686 /*************************************************************************
1687 * SHStrDupW [SHCORE.@]
1689 HRESULT WINAPI SHStrDupW(const WCHAR *src, WCHAR **dest)
1691 size_t len;
1693 TRACE("(%s, %p)\n", debugstr_w(src), dest);
1695 *dest = NULL;
1697 if (!src)
1698 return E_INVALIDARG;
1700 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
1701 *dest = CoTaskMemAlloc(len);
1702 if (!*dest)
1703 return E_OUTOFMEMORY;
1705 memcpy(*dest, src, len);
1707 return S_OK;
1710 /*************************************************************************
1711 * SHStrDupA [SHCORE.@]
1713 HRESULT WINAPI SHStrDupA(const char *src, WCHAR **dest)
1715 DWORD len;
1717 *dest = NULL;
1719 if (!src)
1720 return E_INVALIDARG;
1722 len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
1723 *dest = CoTaskMemAlloc(len * sizeof(WCHAR));
1724 if (!*dest)
1725 return E_OUTOFMEMORY;
1727 MultiByteToWideChar(CP_ACP, 0, src, -1, *dest, len);
1729 return S_OK;
1732 /*************************************************************************
1733 * SHAnsiToAnsi [SHCORE.@]
1735 DWORD WINAPI SHAnsiToAnsi(const char *src, char *dest, int dest_len)
1737 DWORD ret;
1739 TRACE("(%s, %p, %d)\n", debugstr_a(src), dest, dest_len);
1741 if (!src || !dest || dest_len <= 0)
1742 return 0;
1744 lstrcpynA(dest, src, dest_len);
1745 ret = strlen(dest);
1747 return src[ret] ? 0 : ret + 1;
1750 /*************************************************************************
1751 * SHUnicodeToAnsi [SHCORE.@]
1753 DWORD WINAPI SHUnicodeToAnsi(const WCHAR *src, char *dest, int dest_len)
1755 int ret = 1;
1757 TRACE("(%s, %p, %d)\n", debugstr_w(src), dest, dest_len);
1759 if (!dest || !dest_len)
1760 return 0;
1762 if (src)
1764 ret = WideCharToMultiByte(CP_ACP, 0, src, -1, dest, dest_len, NULL, NULL);
1765 if (!ret)
1767 dest[dest_len - 1] = 0;
1768 ret = dest_len;
1771 else
1772 dest[0] = 0;
1774 return ret;
1777 /*************************************************************************
1778 * SHUnicodeToUnicode [SHCORE.@]
1780 DWORD WINAPI SHUnicodeToUnicode(const WCHAR *src, WCHAR *dest, int dest_len)
1782 DWORD ret;
1784 TRACE("(%s, %p, %d)\n", debugstr_w(src), dest, dest_len);
1786 if (!src || !dest || dest_len <= 0)
1787 return 0;
1789 lstrcpynW(dest, src, dest_len);
1790 ret = lstrlenW(dest);
1792 return src[ret] ? 0 : ret + 1;
1795 /*************************************************************************
1796 * SHAnsiToUnicode [SHCORE.@]
1798 DWORD WINAPI SHAnsiToUnicode(const char *src, WCHAR *dest, int dest_len)
1800 int ret = 1;
1802 TRACE("(%s, %p, %d)\n", debugstr_a(src), dest, dest_len);
1804 if (!dest || !dest_len)
1805 return 0;
1807 if (src)
1809 ret = MultiByteToWideChar(CP_ACP, 0, src, -1, dest, dest_len);
1810 if (!ret)
1812 dest[dest_len - 1] = 0;
1813 ret = dest_len;
1816 else
1817 dest[0] = 0;
1819 return ret;
1822 /*************************************************************************
1823 * SHRegDuplicateHKey [SHCORE.@]
1825 HKEY WINAPI SHRegDuplicateHKey(HKEY hKey)
1827 HKEY newKey = 0;
1829 RegOpenKeyExW(hKey, 0, 0, MAXIMUM_ALLOWED, &newKey);
1830 TRACE("new key is %p\n", newKey);
1831 return newKey;
1834 /*************************************************************************
1835 * SHDeleteEmptyKeyW [SHCORE.@]
1837 DWORD WINAPI SHDeleteEmptyKeyW(HKEY hkey, const WCHAR *subkey)
1839 DWORD ret, count = 0;
1840 HKEY hsubkey = 0;
1842 TRACE("(%p, %s)\n", hkey, debugstr_w(subkey));
1844 ret = RegOpenKeyExW(hkey, subkey, 0, KEY_READ, &hsubkey);
1845 if (!ret)
1847 ret = RegQueryInfoKeyW(hsubkey, NULL, NULL, NULL, &count,
1848 NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1849 RegCloseKey(hsubkey);
1850 if (!ret)
1852 if (count)
1853 ret = ERROR_KEY_HAS_CHILDREN;
1854 else
1855 ret = RegDeleteKeyW(hkey, subkey);
1859 return ret;
1862 /*************************************************************************
1863 * SHDeleteEmptyKeyA [SHCORE.@]
1865 DWORD WINAPI SHDeleteEmptyKeyA(HKEY hkey, const char *subkey)
1867 WCHAR *subkeyW = NULL;
1868 DWORD ret;
1870 TRACE("(%p, %s)\n", hkey, debugstr_a(subkey));
1872 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1873 return ERROR_OUTOFMEMORY;
1875 ret = SHDeleteEmptyKeyW(hkey, subkeyW);
1876 CoTaskMemFree(subkeyW);
1877 return ret;
1880 /*************************************************************************
1881 * SHDeleteKeyW [SHCORE.@]
1883 DWORD WINAPI SHDeleteKeyW(HKEY hkey, const WCHAR *subkey)
1885 TRACE("(%p, %s)\n", hkey, debugstr_w(subkey));
1887 return RegDeleteTreeW(hkey, subkey);
1890 /*************************************************************************
1891 * SHDeleteKeyA [SHCORE.@]
1893 DWORD WINAPI SHDeleteKeyA(HKEY hkey, const char *subkey)
1895 TRACE("(%p, %s)\n", hkey, debugstr_a(subkey));
1897 return RegDeleteTreeA(hkey, subkey);
1900 /*************************************************************************
1901 * SHDeleteValueW [SHCORE.@]
1903 DWORD WINAPI SHDeleteValueW(HKEY hkey, const WCHAR *subkey, const WCHAR *value)
1905 HKEY hsubkey;
1906 DWORD ret;
1908 TRACE("(%p, %s, %s)\n", hkey, debugstr_w(subkey), debugstr_w(value));
1910 ret = RegOpenKeyExW(hkey, subkey, 0, KEY_SET_VALUE, &hsubkey);
1911 if (!ret)
1913 ret = RegDeleteValueW(hsubkey, value);
1914 RegCloseKey(hsubkey);
1917 return ret;
1920 /*************************************************************************
1921 * SHDeleteValueA [SHCORE.@]
1923 DWORD WINAPI SHDeleteValueA(HKEY hkey, const char *subkey, const char *value)
1925 WCHAR *subkeyW = NULL, *valueW = NULL;
1926 DWORD ret;
1928 TRACE("(%p, %s, %s)\n", hkey, debugstr_a(subkey), debugstr_a(value));
1930 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1931 return ERROR_OUTOFMEMORY;
1932 if (value && FAILED(SHStrDupA(value, &valueW)))
1934 CoTaskMemFree(subkeyW);
1935 return ERROR_OUTOFMEMORY;
1938 ret = SHDeleteValueW(hkey, subkeyW, valueW);
1939 CoTaskMemFree(subkeyW);
1940 CoTaskMemFree(valueW);
1941 return ret;
1944 /*************************************************************************
1945 * SHCopyKeyA [SHCORE.@]
1947 DWORD WINAPI SHCopyKeyA(HKEY hkey_src, const char *subkey, HKEY hkey_dst, DWORD reserved)
1949 WCHAR *subkeyW = NULL;
1950 DWORD ret;
1952 TRACE("%p, %s, %p, %ld.\n", hkey_src, debugstr_a(subkey), hkey_dst, reserved);
1954 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1955 return 0;
1957 ret = SHCopyKeyW(hkey_src, subkeyW, hkey_dst, reserved);
1958 CoTaskMemFree(subkeyW);
1959 return ret;
1962 /*************************************************************************
1963 * SHCopyKeyW [SHCORE.@]
1965 DWORD WINAPI SHCopyKeyW(HKEY hkey_src, const WCHAR *subkey, HKEY hkey_dst, DWORD reserved)
1967 DWORD key_count = 0, value_count = 0, max_key_len = 0;
1968 WCHAR name[MAX_PATH], *ptr_name = name;
1969 BYTE buff[1024], *ptr = buff;
1970 DWORD max_data_len = 0, i;
1971 DWORD ret = 0;
1973 TRACE("%p, %s, %p, %ld.\n", hkey_src, debugstr_w(subkey), hkey_dst, reserved);
1975 if (!hkey_dst || !hkey_src)
1976 return ERROR_INVALID_PARAMETER;
1978 if (subkey)
1979 ret = RegOpenKeyExW(hkey_src, subkey, 0, KEY_ALL_ACCESS, &hkey_src);
1981 if (ret)
1982 hkey_src = NULL; /* Don't close this key since we didn't open it */
1983 else
1985 DWORD max_value_len;
1987 ret = RegQueryInfoKeyW(hkey_src, NULL, NULL, NULL, &key_count, &max_key_len,
1988 NULL, &value_count, &max_value_len, &max_data_len, NULL, NULL);
1989 if (!ret)
1991 /* Get max size for key/value names */
1992 max_key_len = max(max_key_len, max_value_len);
1994 if (max_key_len++ > MAX_PATH - 1)
1995 ptr_name = heap_alloc(max_key_len * sizeof(WCHAR));
1997 if (max_data_len > sizeof(buff))
1998 ptr = heap_alloc(max_data_len);
2000 if (!ptr_name || !ptr)
2001 ret = ERROR_NOT_ENOUGH_MEMORY;
2005 for (i = 0; i < key_count && !ret; i++)
2007 HKEY hsubkey_src, hsubkey_dst;
2008 DWORD length = max_key_len;
2010 ret = RegEnumKeyExW(hkey_src, i, ptr_name, &length, NULL, NULL, NULL, NULL);
2011 if (!ret)
2013 ret = RegOpenKeyExW(hkey_src, ptr_name, 0, KEY_READ, &hsubkey_src);
2014 if (!ret)
2016 /* Create destination sub key */
2017 ret = RegCreateKeyW(hkey_dst, ptr_name, &hsubkey_dst);
2018 if (!ret)
2020 /* Recursively copy keys and values from the sub key */
2021 ret = SHCopyKeyW(hsubkey_src, NULL, hsubkey_dst, 0);
2022 RegCloseKey(hsubkey_dst);
2025 RegCloseKey(hsubkey_src);
2029 /* Copy all the values in this key */
2030 for (i = 0; i < value_count && !ret; i++)
2032 DWORD length = max_key_len, type, data_len = max_data_len;
2034 ret = RegEnumValueW(hkey_src, i, ptr_name, &length, NULL, &type, ptr, &data_len);
2035 if (!ret) {
2036 ret = SHSetValueW(hkey_dst, NULL, ptr_name, type, ptr, data_len);
2040 /* Free buffers if allocated */
2041 if (ptr_name != name)
2042 heap_free(ptr_name);
2043 if (ptr != buff)
2044 heap_free(ptr);
2046 if (subkey && hkey_src)
2047 RegCloseKey(hkey_src);
2049 return ret;
2053 /*************************************************************************
2054 * SHEnumKeyExA [SHCORE.@]
2056 LONG WINAPI SHEnumKeyExA(HKEY hkey, DWORD index, char *subkey, DWORD *length)
2058 TRACE("%p, %ld, %s, %p.\n", hkey, index, debugstr_a(subkey), length);
2060 return RegEnumKeyExA(hkey, index, subkey, length, NULL, NULL, NULL, NULL);
2063 /*************************************************************************
2064 * SHEnumKeyExW [SHCORE.@]
2066 LONG WINAPI SHEnumKeyExW(HKEY hkey, DWORD index, WCHAR *subkey, DWORD *length)
2068 TRACE("%p, %ld, %s, %p.\n", hkey, index, debugstr_w(subkey), length);
2070 return RegEnumKeyExW(hkey, index, subkey, length, NULL, NULL, NULL, NULL);
2073 /*************************************************************************
2074 * SHEnumValueA [SHCORE.@]
2076 LONG WINAPI SHEnumValueA(HKEY hkey, DWORD index, char *value, DWORD *length, DWORD *type,
2077 void *data, DWORD *data_len)
2079 TRACE("%p, %ld, %s, %p, %p, %p, %p.\n", hkey, index, debugstr_a(value), length, type, data, data_len);
2081 return RegEnumValueA(hkey, index, value, length, NULL, type, data, data_len);
2084 /*************************************************************************
2085 * SHEnumValueW [SHCORE.@]
2087 LONG WINAPI SHEnumValueW(HKEY hkey, DWORD index, WCHAR *value, DWORD *length, DWORD *type,
2088 void *data, DWORD *data_len)
2090 TRACE("%p, %ld, %s, %p, %p, %p, %p.\n", hkey, index, debugstr_w(value), length, type, data, data_len);
2092 return RegEnumValueW(hkey, index, value, length, NULL, type, data, data_len);
2095 /*************************************************************************
2096 * SHQueryValueExW [SHCORE.@]
2098 DWORD WINAPI SHQueryValueExW(HKEY hkey, const WCHAR *name, DWORD *reserved, DWORD *type,
2099 void *buff, DWORD *buff_len)
2101 DWORD ret, value_type, data_len = 0;
2103 TRACE("(%p, %s, %p, %p, %p, %p)\n", hkey, debugstr_w(name), reserved, type, buff, buff_len);
2105 if (buff_len)
2106 data_len = *buff_len;
2108 ret = RegQueryValueExW(hkey, name, reserved, &value_type, buff, &data_len);
2109 if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)
2110 return ret;
2112 if (buff_len && value_type == REG_EXPAND_SZ)
2114 DWORD length;
2115 WCHAR *value;
2117 if (!buff || ret == ERROR_MORE_DATA)
2119 length = data_len;
2120 value = heap_alloc(length);
2121 RegQueryValueExW(hkey, name, reserved, NULL, (BYTE *)value, &length);
2122 length = ExpandEnvironmentStringsW(value, NULL, 0);
2124 else
2126 length = (lstrlenW(buff) + 1) * sizeof(WCHAR);
2127 value = heap_alloc(length);
2128 memcpy(value, buff, length);
2129 length = ExpandEnvironmentStringsW(value, buff, *buff_len / sizeof(WCHAR));
2130 if (length > *buff_len) ret = ERROR_MORE_DATA;
2132 data_len = max(data_len, length);
2133 heap_free(value);
2136 if (type)
2137 *type = value_type == REG_EXPAND_SZ ? REG_SZ : value_type;
2138 if (buff_len)
2139 *buff_len = data_len;
2140 return ret;
2143 /*************************************************************************
2144 * SHQueryValueExA [SHCORE.@]
2146 DWORD WINAPI SHQueryValueExA(HKEY hkey, const char *name, DWORD *reserved, DWORD *type,
2147 void *buff, DWORD *buff_len)
2149 DWORD ret, value_type, data_len = 0;
2151 TRACE("(%p, %s, %p, %p, %p, %p)\n", hkey, debugstr_a(name), reserved, type, buff, buff_len);
2153 if (buff_len)
2154 data_len = *buff_len;
2156 ret = RegQueryValueExA(hkey, name, reserved, &value_type, buff, &data_len);
2157 if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)
2158 return ret;
2160 if (buff_len && value_type == REG_EXPAND_SZ)
2162 DWORD length;
2163 char *value;
2165 if (!buff || ret == ERROR_MORE_DATA)
2167 length = data_len;
2168 value = heap_alloc(length);
2169 RegQueryValueExA(hkey, name, reserved, NULL, (BYTE *)value, &length);
2170 length = ExpandEnvironmentStringsA(value, NULL, 0);
2172 else
2174 length = strlen(buff) + 1;
2175 value = heap_alloc(length);
2176 memcpy(value, buff, length);
2177 length = ExpandEnvironmentStringsA(value, buff, *buff_len);
2178 if (length > *buff_len) ret = ERROR_MORE_DATA;
2180 data_len = max(data_len, length);
2181 heap_free(value);
2184 if (type)
2185 *type = value_type == REG_EXPAND_SZ ? REG_SZ : value_type;
2186 if (buff_len)
2187 *buff_len = data_len;
2188 return ret;
2191 /*************************************************************************
2192 * SHGetValueA [SHCORE.@]
2194 DWORD WINAPI SHGetValueA(HKEY hkey, const char *subkey, const char *value,
2195 DWORD *type, void *data, DWORD *data_len)
2197 HKEY hsubkey = 0;
2198 DWORD ret = 0;
2200 TRACE("(%p, %s, %s, %p, %p, %p)\n", hkey, debugstr_a(subkey), debugstr_a(value),
2201 type, data, data_len);
2203 if (subkey)
2204 ret = RegOpenKeyExA(hkey, subkey, 0, KEY_QUERY_VALUE, &hsubkey);
2206 if (!ret)
2208 ret = SHQueryValueExA(hsubkey ? hsubkey : hkey, value, 0, type, data, data_len);
2209 if (subkey)
2210 RegCloseKey(hsubkey);
2213 return ret;
2216 /*************************************************************************
2217 * SHGetValueW [SHCORE.@]
2219 DWORD WINAPI SHGetValueW(HKEY hkey, const WCHAR *subkey, const WCHAR *value,
2220 DWORD *type, void *data, DWORD *data_len)
2222 HKEY hsubkey = 0;
2223 DWORD ret = 0;
2225 TRACE("(%p, %s, %s, %p, %p, %p)\n", hkey, debugstr_w(subkey), debugstr_w(value),
2226 type, data, data_len);
2228 if (subkey)
2229 ret = RegOpenKeyExW(hkey, subkey, 0, KEY_QUERY_VALUE, &hsubkey);
2231 if (!ret)
2233 ret = SHQueryValueExW(hsubkey ? hsubkey : hkey, value, 0, type, data, data_len);
2234 if (subkey)
2235 RegCloseKey(hsubkey);
2238 return ret;
2241 /*************************************************************************
2242 * SHRegGetIntW [SHCORE.280]
2244 int WINAPI SHRegGetIntW(HKEY hkey, const WCHAR *value, int default_value)
2246 WCHAR buff[32];
2247 DWORD buff_len;
2249 TRACE("(%p, %s, %d)\n", hkey, debugstr_w(value), default_value);
2251 buff[0] = 0;
2252 buff_len = sizeof(buff);
2253 if (SHQueryValueExW(hkey, value, 0, 0, buff, &buff_len))
2254 return default_value;
2256 if (*buff >= '0' && *buff <= '9')
2257 return wcstol(buff, NULL, 10);
2259 return default_value;
2262 /*************************************************************************
2263 * SHRegGetPathA [SHCORE.@]
2265 DWORD WINAPI SHRegGetPathA(HKEY hkey, const char *subkey, const char *value, char *path, DWORD flags)
2267 DWORD length = MAX_PATH;
2269 TRACE("%p, %s, %s, %p, %#lx.\n", hkey, debugstr_a(subkey), debugstr_a(value), path, flags);
2271 return SHGetValueA(hkey, subkey, value, 0, path, &length);
2274 /*************************************************************************
2275 * SHRegGetPathW [SHCORE.@]
2277 DWORD WINAPI SHRegGetPathW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, WCHAR *path, DWORD flags)
2279 DWORD length = MAX_PATH;
2281 TRACE("%p, %s, %s, %p, %#lx.\n", hkey, debugstr_w(subkey), debugstr_w(value), path, flags);
2283 return SHGetValueW(hkey, subkey, value, 0, path, &length);
2286 /*************************************************************************
2287 * SHSetValueW [SHCORE.@]
2289 DWORD WINAPI SHSetValueW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, DWORD type,
2290 const void *data, DWORD data_len)
2292 DWORD ret = ERROR_SUCCESS, dummy;
2293 HKEY hsubkey;
2295 TRACE("%p, %s, %s, %ld, %p, %ld.\n", hkey, debugstr_w(subkey), debugstr_w(value),
2296 type, data, data_len);
2298 if (subkey && *subkey)
2299 ret = RegCreateKeyExW(hkey, subkey, 0, NULL, 0, KEY_SET_VALUE, NULL, &hsubkey, &dummy);
2300 else
2301 hsubkey = hkey;
2303 if (!ret)
2305 ret = RegSetValueExW(hsubkey, value, 0, type, data, data_len);
2306 if (hsubkey != hkey)
2307 RegCloseKey(hsubkey);
2310 return ret;
2313 /*************************************************************************
2314 * SHSetValueA [SHCORE.@]
2316 DWORD WINAPI SHSetValueA(HKEY hkey, const char *subkey, const char *value,
2317 DWORD type, const void *data, DWORD data_len)
2319 DWORD ret = ERROR_SUCCESS, dummy;
2320 HKEY hsubkey;
2322 TRACE("%p, %s, %s, %ld, %p, %ld.\n", hkey, debugstr_a(subkey), debugstr_a(value),
2323 type, data, data_len);
2325 if (subkey && *subkey)
2326 ret = RegCreateKeyExA(hkey, subkey, 0, NULL, 0, KEY_SET_VALUE, NULL, &hsubkey, &dummy);
2327 else
2328 hsubkey = hkey;
2330 if (!ret)
2332 ret = RegSetValueExA(hsubkey, value, 0, type, data, data_len);
2333 if (hsubkey != hkey)
2334 RegCloseKey(hsubkey);
2337 return ret;
2340 /*************************************************************************
2341 * SHRegSetPathA [SHCORE.@]
2343 DWORD WINAPI SHRegSetPathA(HKEY hkey, const char *subkey, const char *value, const char *path, DWORD flags)
2345 FIXME("%p, %s, %s, %s, %#lx - semi-stub\n", hkey, debugstr_a(subkey),
2346 debugstr_a(value), debugstr_a(path), flags);
2348 /* FIXME: PathUnExpandEnvStringsA() */
2350 return SHSetValueA(hkey, subkey, value, REG_SZ, path, lstrlenA(path));
2353 /*************************************************************************
2354 * SHRegSetPathW [SHCORE.@]
2356 DWORD WINAPI SHRegSetPathW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, const WCHAR *path, DWORD flags)
2358 FIXME("%p, %s, %s, %s, %#lx semi-stub\n", hkey, debugstr_w(subkey),
2359 debugstr_w(value), debugstr_w(path), flags);
2361 /* FIXME: PathUnExpandEnvStringsW(); */
2363 return SHSetValueW(hkey, subkey, value, REG_SZ, path, lstrlenW(path));
2366 /*************************************************************************
2367 * SHQueryInfoKeyA [SHCORE.@]
2369 LONG WINAPI SHQueryInfoKeyA(HKEY hkey, DWORD *subkeys, DWORD *subkey_max, DWORD *values, DWORD *value_max)
2371 TRACE("(%p, %p, %p, %p, %p)\n", hkey, subkeys, subkey_max, values, value_max);
2373 return RegQueryInfoKeyA(hkey, NULL, NULL, NULL, subkeys, subkey_max, NULL, values, value_max, NULL, NULL, NULL);
2376 /*************************************************************************
2377 * SHQueryInfoKeyW [SHCORE.@]
2379 LONG WINAPI SHQueryInfoKeyW(HKEY hkey, DWORD *subkeys, DWORD *subkey_max, DWORD *values, DWORD *value_max)
2381 TRACE("(%p, %p, %p, %p, %p)\n", hkey, subkeys, subkey_max, values, value_max);
2383 return RegQueryInfoKeyW(hkey, NULL, NULL, NULL, subkeys, subkey_max, NULL, values, value_max, NULL, NULL, NULL);
2386 /*************************************************************************
2387 * IsOS [SHCORE.@]
2389 BOOL WINAPI IsOS(DWORD feature)
2391 DWORD platform, majorv, minorv;
2392 OSVERSIONINFOA osvi;
2394 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
2395 if (!GetVersionExA(&osvi))
2396 return FALSE;
2398 majorv = osvi.dwMajorVersion;
2399 minorv = osvi.dwMinorVersion;
2400 platform = osvi.dwPlatformId;
2402 #define ISOS_RETURN(x) \
2403 TRACE("(%#lx) ret %d\n",feature,(x)); \
2404 return (x)
2406 switch(feature) {
2407 case OS_WIN32SORGREATER:
2408 ISOS_RETURN(platform == VER_PLATFORM_WIN32s
2409 || platform == VER_PLATFORM_WIN32_WINDOWS);
2410 case OS_NT:
2411 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2412 case OS_WIN95ORGREATER:
2413 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS);
2414 case OS_NT4ORGREATER:
2415 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 4);
2416 case OS_WIN2000ORGREATER_ALT:
2417 case OS_WIN2000ORGREATER:
2418 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5);
2419 case OS_WIN98ORGREATER:
2420 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 10);
2421 case OS_WIN98_GOLD:
2422 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 10);
2423 case OS_WIN2000PRO:
2424 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5);
2425 case OS_WIN2000SERVER:
2426 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2427 case OS_WIN2000ADVSERVER:
2428 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2429 case OS_WIN2000DATACENTER:
2430 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2431 case OS_WIN2000TERMINAL:
2432 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2433 case OS_EMBEDDED:
2434 FIXME("(OS_EMBEDDED) What should we return here?\n");
2435 return FALSE;
2436 case OS_TERMINALCLIENT:
2437 FIXME("(OS_TERMINALCLIENT) What should we return here?\n");
2438 return FALSE;
2439 case OS_TERMINALREMOTEADMIN:
2440 FIXME("(OS_TERMINALREMOTEADMIN) What should we return here?\n");
2441 return FALSE;
2442 case OS_WIN95_GOLD:
2443 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 0);
2444 case OS_MEORGREATER:
2445 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 90);
2446 case OS_XPORGREATER:
2447 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1);
2448 case OS_HOME:
2449 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1);
2450 case OS_PROFESSIONAL:
2451 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2452 case OS_DATACENTER:
2453 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2454 case OS_ADVSERVER:
2455 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5);
2456 case OS_SERVER:
2457 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2458 case OS_TERMINALSERVER:
2459 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2460 case OS_PERSONALTERMINALSERVER:
2461 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && minorv >= 1 && majorv >= 5);
2462 case OS_FASTUSERSWITCHING:
2463 FIXME("(OS_FASTUSERSWITCHING) What should we return here?\n");
2464 return TRUE;
2465 case OS_WELCOMELOGONUI:
2466 FIXME("(OS_WELCOMELOGONUI) What should we return here?\n");
2467 return FALSE;
2468 case OS_DOMAINMEMBER:
2469 FIXME("(OS_DOMAINMEMBER) What should we return here?\n");
2470 return TRUE;
2471 case OS_ANYSERVER:
2472 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2473 case OS_WOW6432:
2475 BOOL is_wow64;
2476 IsWow64Process(GetCurrentProcess(), &is_wow64);
2477 return is_wow64;
2479 case OS_WEBSERVER:
2480 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2481 case OS_SMALLBUSINESSSERVER:
2482 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2483 case OS_TABLETPC:
2484 FIXME("(OS_TABLETPC) What should we return here?\n");
2485 return FALSE;
2486 case OS_SERVERADMINUI:
2487 FIXME("(OS_SERVERADMINUI) What should we return here?\n");
2488 return FALSE;
2489 case OS_MEDIACENTER:
2490 FIXME("(OS_MEDIACENTER) What should we return here?\n");
2491 return FALSE;
2492 case OS_APPLIANCE:
2493 FIXME("(OS_APPLIANCE) What should we return here?\n");
2494 return FALSE;
2495 case 0x25: /*OS_VISTAORGREATER*/
2496 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 6);
2499 #undef ISOS_RETURN
2501 WARN("(%#lx) unknown parameter\n", feature);
2503 return FALSE;
2506 /*************************************************************************
2507 * SubscribeFeatureStateChangeNotification [SHCORE.@]
2509 void WINAPI SubscribeFeatureStateChangeNotification(FEATURE_STATE_CHANGE_SUBSCRIPTION *subscription,
2510 FEATURE_STATE_CHANGE_CALLBACK *callback, void *context)
2512 FIXME("(%p, %p, %p) stub\n", subscription, callback, context);
2515 /*************************************************************************
2516 * GetFeatureEnabledState [SHCORE.@]
2518 FEATURE_ENABLED_STATE WINAPI GetFeatureEnabledState(UINT32 feature, FEATURE_CHANGE_TIME change_time)
2520 FIXME("(%u, %u) stub\n", feature, change_time);
2521 return FEATURE_ENABLED_STATE_DEFAULT;