makefiles: Add support for Automake-style silent make rules.
[wine.git] / dlls / shcore / main.c
blobd5fce76eadedcc2a533a63c9d6e2e8bbeda48c93
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 "shellscalingapi.h"
31 #include "shlwapi.h"
33 #include "wine/debug.h"
34 #include "wine/heap.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(shcore);
38 static DWORD shcore_tls;
39 static IUnknown *process_ref;
41 BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved)
43 TRACE("(%p, %u, %p)\n", instance, reason, reserved);
45 switch (reason)
47 case DLL_WINE_PREATTACH:
48 return FALSE; /* prefer native version */
49 case DLL_PROCESS_ATTACH:
50 DisableThreadLibraryCalls(instance);
51 shcore_tls = TlsAlloc();
52 break;
53 case DLL_PROCESS_DETACH:
54 if (reserved) break;
55 if (shcore_tls != TLS_OUT_OF_INDEXES)
56 TlsFree(shcore_tls);
57 break;
60 return TRUE;
63 HRESULT WINAPI GetProcessDpiAwareness(HANDLE process, PROCESS_DPI_AWARENESS *value)
65 if (GetProcessDpiAwarenessInternal( process, (DPI_AWARENESS *)value )) return S_OK;
66 return HRESULT_FROM_WIN32( GetLastError() );
69 HRESULT WINAPI SetProcessDpiAwareness(PROCESS_DPI_AWARENESS value)
71 if (SetProcessDpiAwarenessInternal( value )) return S_OK;
72 return HRESULT_FROM_WIN32( GetLastError() );
75 HRESULT WINAPI GetDpiForMonitor(HMONITOR monitor, MONITOR_DPI_TYPE type, UINT *x, UINT *y)
77 if (GetDpiForMonitorInternal( monitor, type, x, y )) return S_OK;
78 return HRESULT_FROM_WIN32( GetLastError() );
81 HRESULT WINAPI GetScaleFactorForMonitor(HMONITOR monitor, DEVICE_SCALE_FACTOR *scale)
83 FIXME("(%p %p): stub\n", monitor, scale);
85 *scale = SCALE_100_PERCENT;
86 return S_OK;
89 DEVICE_SCALE_FACTOR WINAPI GetScaleFactorForDevice(DISPLAY_DEVICE_TYPE device_type)
91 FIXME("%d\n", device_type);
93 return SCALE_100_PERCENT;
96 HRESULT WINAPI _IStream_Read(IStream *stream, void *dest, ULONG size)
98 ULONG read;
99 HRESULT hr;
101 TRACE("(%p, %p, %u)\n", stream, dest, size);
103 hr = IStream_Read(stream, dest, size, &read);
104 if (SUCCEEDED(hr) && read != size)
105 hr = E_FAIL;
106 return hr;
109 HRESULT WINAPI IStream_Reset(IStream *stream)
111 static const LARGE_INTEGER zero;
113 TRACE("(%p)\n", stream);
115 return IStream_Seek(stream, zero, 0, NULL);
118 HRESULT WINAPI IStream_Size(IStream *stream, ULARGE_INTEGER *size)
120 STATSTG statstg;
121 HRESULT hr;
123 TRACE("(%p, %p)\n", stream, size);
125 memset(&statstg, 0, sizeof(statstg));
127 hr = IStream_Stat(stream, &statstg, STATFLAG_NONAME);
129 if (SUCCEEDED(hr) && size)
130 *size = statstg.cbSize;
131 return hr;
134 HRESULT WINAPI _IStream_Write(IStream *stream, const void *src, ULONG size)
136 ULONG written;
137 HRESULT hr;
139 TRACE("(%p, %p, %u)\n", stream, src, size);
141 hr = IStream_Write(stream, src, size, &written);
142 if (SUCCEEDED(hr) && written != size)
143 hr = E_FAIL;
145 return hr;
148 void WINAPI IUnknown_AtomicRelease(IUnknown **obj)
150 TRACE("(%p)\n", obj);
152 if (!obj || !*obj)
153 return;
155 IUnknown_Release(*obj);
156 *obj = NULL;
159 HRESULT WINAPI IUnknown_GetSite(IUnknown *unk, REFIID iid, void **site)
161 IObjectWithSite *obj = NULL;
162 HRESULT hr = E_INVALIDARG;
164 TRACE("(%p, %s, %p)\n", unk, debugstr_guid(iid), site);
166 if (unk && iid && site)
168 hr = IUnknown_QueryInterface(unk, &IID_IObjectWithSite, (void **)&obj);
169 if (SUCCEEDED(hr) && obj)
171 hr = IObjectWithSite_GetSite(obj, iid, site);
172 IObjectWithSite_Release(obj);
176 return hr;
179 HRESULT WINAPI IUnknown_QueryService(IUnknown *obj, REFGUID sid, REFIID iid, void **out)
181 IServiceProvider *provider = NULL;
182 HRESULT hr;
184 if (!out)
185 return E_FAIL;
187 *out = NULL;
189 if (!obj)
190 return E_FAIL;
192 hr = IUnknown_QueryInterface(obj, &IID_IServiceProvider, (void **)&provider);
193 if (hr == S_OK && provider)
195 TRACE("Using provider %p.\n", provider);
197 hr = IServiceProvider_QueryService(provider, sid, iid, out);
199 TRACE("Provider %p returned %p.\n", provider, *out);
201 IServiceProvider_Release(provider);
204 return hr;
207 void WINAPI IUnknown_Set(IUnknown **dest, IUnknown *src)
209 TRACE("(%p, %p)\n", dest, src);
211 IUnknown_AtomicRelease(dest);
213 if (src)
215 IUnknown_AddRef(src);
216 *dest = src;
220 HRESULT WINAPI IUnknown_SetSite(IUnknown *obj, IUnknown *site)
222 IInternetSecurityManager *sec_manager;
223 IObjectWithSite *objwithsite;
224 HRESULT hr;
226 if (!obj)
227 return E_FAIL;
229 hr = IUnknown_QueryInterface(obj, &IID_IObjectWithSite, (void **)&objwithsite);
230 TRACE("ObjectWithSite %p, hr %#x.\n", objwithsite, hr);
231 if (SUCCEEDED(hr))
233 hr = IObjectWithSite_SetSite(objwithsite, site);
234 TRACE("SetSite() hr %#x.\n", hr);
235 IObjectWithSite_Release(objwithsite);
237 else
239 hr = IUnknown_QueryInterface(obj, &IID_IInternetSecurityManager, (void **)&sec_manager);
240 TRACE("InternetSecurityManager %p, hr %#x.\n", sec_manager, hr);
241 if (FAILED(hr))
242 return hr;
244 hr = IInternetSecurityManager_SetSecuritySite(sec_manager, (IInternetSecurityMgrSite *)site);
245 TRACE("SetSecuritySite() hr %#x.\n", hr);
246 IInternetSecurityManager_Release(sec_manager);
249 return hr;
252 HRESULT WINAPI SetCurrentProcessExplicitAppUserModelID(const WCHAR *appid)
254 FIXME("%s: stub\n", debugstr_w(appid));
255 return S_OK;
258 HRESULT WINAPI GetCurrentProcessExplicitAppUserModelID(const WCHAR **appid)
260 FIXME("%p: stub\n", appid);
261 *appid = NULL;
262 return E_NOTIMPL;
265 /*************************************************************************
266 * CommandLineToArgvW [SHCORE.@]
268 * We must interpret the quotes in the command line to rebuild the argv
269 * array correctly:
270 * - arguments are separated by spaces or tabs
271 * - quotes serve as optional argument delimiters
272 * '"a b"' -> 'a b'
273 * - escaped quotes must be converted back to '"'
274 * '\"' -> '"'
275 * - consecutive backslashes preceding a quote see their number halved with
276 * the remainder escaping the quote:
277 * 2n backslashes + quote -> n backslashes + quote as an argument delimiter
278 * 2n+1 backslashes + quote -> n backslashes + literal quote
279 * - backslashes that are not followed by a quote are copied literally:
280 * 'a\b' -> 'a\b'
281 * 'a\\b' -> 'a\\b'
282 * - in quoted strings, consecutive quotes see their number divided by three
283 * with the remainder modulo 3 deciding whether to close the string or not.
284 * Note that the opening quote must be counted in the consecutive quotes,
285 * that's the (1+) below:
286 * (1+) 3n quotes -> n quotes
287 * (1+) 3n+1 quotes -> n quotes plus closes the quoted string
288 * (1+) 3n+2 quotes -> n+1 quotes plus closes the quoted string
289 * - in unquoted strings, the first quote opens the quoted string and the
290 * remaining consecutive quotes follow the above rule.
292 WCHAR** WINAPI CommandLineToArgvW(const WCHAR *cmdline, int *numargs)
294 int qcount, bcount;
295 const WCHAR *s;
296 WCHAR **argv;
297 DWORD argc;
298 WCHAR *d;
300 if (!numargs)
302 SetLastError(ERROR_INVALID_PARAMETER);
303 return NULL;
306 if (*cmdline == 0)
308 /* Return the path to the executable */
309 DWORD len, deslen = MAX_PATH, size;
311 size = sizeof(WCHAR *) * 2 + deslen * sizeof(WCHAR);
312 for (;;)
314 if (!(argv = LocalAlloc(LMEM_FIXED, size))) return NULL;
315 len = GetModuleFileNameW(0, (WCHAR *)(argv + 2), deslen);
316 if (!len)
318 LocalFree(argv);
319 return NULL;
321 if (len < deslen) break;
322 deslen *= 2;
323 size = sizeof(WCHAR *) * 2 + deslen * sizeof(WCHAR);
324 LocalFree(argv);
326 argv[0] = (WCHAR *)(argv + 2);
327 argv[1] = NULL;
328 *numargs = 1;
330 return argv;
333 /* --- First count the arguments */
334 argc = 1;
335 s = cmdline;
336 /* The first argument, the executable path, follows special rules */
337 if (*s == '"')
339 /* The executable path ends at the next quote, no matter what */
340 s++;
341 while (*s)
342 if (*s++ == '"')
343 break;
345 else
347 /* The executable path ends at the next space, no matter what */
348 while (*s && *s != ' ' && *s != '\t')
349 s++;
351 /* skip to the first argument, if any */
352 while (*s == ' ' || *s == '\t')
353 s++;
354 if (*s)
355 argc++;
357 /* Analyze the remaining arguments */
358 qcount = bcount = 0;
359 while (*s)
361 if ((*s == ' ' || *s == '\t') && qcount == 0)
363 /* skip to the next argument and count it if any */
364 while (*s == ' ' || *s == '\t')
365 s++;
366 if (*s)
367 argc++;
368 bcount = 0;
370 else if (*s == '\\')
372 /* '\', count them */
373 bcount++;
374 s++;
376 else if (*s == '"')
378 /* '"' */
379 if ((bcount & 1) == 0)
380 qcount++; /* unescaped '"' */
381 s++;
382 bcount = 0;
383 /* consecutive quotes, see comment in copying code below */
384 while (*s == '"')
386 qcount++;
387 s++;
389 qcount = qcount % 3;
390 if (qcount == 2)
391 qcount = 0;
393 else
395 /* a regular character */
396 bcount = 0;
397 s++;
401 /* Allocate in a single lump, the string array, and the strings that go
402 * with it. This way the caller can make a single LocalFree() call to free
403 * both, as per MSDN.
405 argv = LocalAlloc(LMEM_FIXED, (argc + 1) * sizeof(WCHAR *) + (lstrlenW(cmdline) + 1) * sizeof(WCHAR));
406 if (!argv)
407 return NULL;
409 /* --- Then split and copy the arguments */
410 argv[0] = d = lstrcpyW((WCHAR *)(argv + argc + 1), cmdline);
411 argc = 1;
412 /* The first argument, the executable path, follows special rules */
413 if (*d == '"')
415 /* The executable path ends at the next quote, no matter what */
416 s = d + 1;
417 while (*s)
419 if (*s == '"')
421 s++;
422 break;
424 *d++ = *s++;
427 else
429 /* The executable path ends at the next space, no matter what */
430 while (*d && *d != ' ' && *d != '\t')
431 d++;
432 s = d;
433 if (*s)
434 s++;
436 /* close the executable path */
437 *d++ = 0;
438 /* skip to the first argument and initialize it if any */
439 while (*s == ' ' || *s == '\t')
440 s++;
441 if (!*s)
443 /* There are no parameters so we are all done */
444 argv[argc] = NULL;
445 *numargs = argc;
446 return argv;
449 /* Split and copy the remaining arguments */
450 argv[argc++] = d;
451 qcount = bcount = 0;
452 while (*s)
454 if ((*s == ' ' || *s == '\t') && qcount == 0)
456 /* close the argument */
457 *d++ = 0;
458 bcount = 0;
460 /* skip to the next one and initialize it if any */
461 do {
462 s++;
463 } while (*s == ' ' || *s == '\t');
464 if (*s)
465 argv[argc++] = d;
467 else if (*s=='\\')
469 *d++ = *s++;
470 bcount++;
472 else if (*s == '"')
474 if ((bcount & 1) == 0)
476 /* Preceded by an even number of '\', this is half that
477 * number of '\', plus a quote which we erase.
479 d -= bcount / 2;
480 qcount++;
482 else
484 /* Preceded by an odd number of '\', this is half that
485 * number of '\' followed by a '"'
487 d = d - bcount / 2 - 1;
488 *d++ = '"';
490 s++;
491 bcount = 0;
492 /* Now count the number of consecutive quotes. Note that qcount
493 * already takes into account the opening quote if any, as well as
494 * the quote that lead us here.
496 while (*s == '"')
498 if (++qcount == 3)
500 *d++ = '"';
501 qcount = 0;
503 s++;
505 if (qcount == 2)
506 qcount = 0;
508 else
510 /* a regular character */
511 *d++ = *s++;
512 bcount = 0;
515 *d = '\0';
516 argv[argc] = NULL;
517 *numargs = argc;
519 return argv;
522 struct shstream
524 IStream IStream_iface;
525 LONG refcount;
527 union
529 struct
531 BYTE *buffer;
532 DWORD length;
533 DWORD position;
535 HKEY hkey;
536 WCHAR *valuename;
537 } mem;
538 struct
540 HANDLE handle;
541 DWORD mode;
542 WCHAR *path;
543 } file;
544 } u;
547 static inline struct shstream *impl_from_IStream(IStream *iface)
549 return CONTAINING_RECORD(iface, struct shstream, IStream_iface);
552 static HRESULT WINAPI shstream_QueryInterface(IStream *iface, REFIID riid, void **out)
554 struct shstream *stream = impl_from_IStream(iface);
556 TRACE("(%p)->(%s, %p)\n", stream, debugstr_guid(riid), out);
558 if (IsEqualIID(riid, &IID_IUnknown) ||
559 IsEqualIID(riid, &IID_IStream) ||
560 IsEqualIID(riid, &IID_ISequentialStream))
562 *out = iface;
563 IStream_AddRef(iface);
564 return S_OK;
567 *out = NULL;
568 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
569 return E_NOINTERFACE;
572 static ULONG WINAPI shstream_AddRef(IStream *iface)
574 struct shstream *stream = impl_from_IStream(iface);
575 ULONG refcount = InterlockedIncrement(&stream->refcount);
577 TRACE("(%p)->(%u)\n", stream, refcount);
579 return refcount;
582 static ULONG WINAPI memstream_Release(IStream *iface)
584 struct shstream *stream = impl_from_IStream(iface);
585 ULONG refcount = InterlockedDecrement(&stream->refcount);
587 TRACE("(%p)->(%u)\n", stream, refcount);
589 if (!refcount)
591 heap_free(stream->u.mem.buffer);
592 heap_free(stream);
595 return refcount;
598 static HRESULT WINAPI memstream_Read(IStream *iface, void *buff, ULONG buff_size, ULONG *read_len)
600 struct shstream *stream = impl_from_IStream(iface);
601 DWORD length;
603 TRACE("(%p)->(%p, %u, %p)\n", stream, buff, buff_size, read_len);
605 if (stream->u.mem.position >= stream->u.mem.length)
607 if (read_len)
608 *read_len = 0;
609 return S_FALSE;
612 length = stream->u.mem.length - stream->u.mem.position;
613 if (buff_size < length)
614 length = buff_size;
616 memmove(buff, stream->u.mem.buffer + stream->u.mem.position, length);
617 stream->u.mem.position += length;
619 if (read_len)
620 *read_len = length;
622 return S_OK;
625 static HRESULT WINAPI memstream_Write(IStream *iface, const void *buff, ULONG buff_size, ULONG *written)
627 struct shstream *stream = impl_from_IStream(iface);
628 DWORD length = stream->u.mem.position + buff_size;
630 TRACE("(%p)->(%p, %u, %p)\n", stream, buff, buff_size, written);
632 if (length < stream->u.mem.position) /* overflow */
633 return STG_E_INSUFFICIENTMEMORY;
635 if (length > stream->u.mem.length)
637 BYTE *buffer = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, stream->u.mem.buffer, length);
638 if (!buffer)
639 return STG_E_INSUFFICIENTMEMORY;
641 stream->u.mem.length = length;
642 stream->u.mem.buffer = buffer;
644 memmove(stream->u.mem.buffer + stream->u.mem.position, buff, buff_size);
645 stream->u.mem.position += buff_size; /* adjust pointer */
647 if (written)
648 *written = buff_size;
650 return S_OK;
653 static HRESULT WINAPI memstream_Seek(IStream *iface, LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER*new_pos)
655 struct shstream *stream = impl_from_IStream(iface);
656 LARGE_INTEGER tmp;
658 TRACE("(%p)->(%s, %d, %p)\n", stream, wine_dbgstr_longlong(move.QuadPart), origin, new_pos);
660 if (origin == STREAM_SEEK_SET)
661 tmp = move;
662 else if (origin == STREAM_SEEK_CUR)
663 tmp.QuadPart = stream->u.mem.position + move.QuadPart;
664 else if (origin == STREAM_SEEK_END)
665 tmp.QuadPart = stream->u.mem.length + move.QuadPart;
666 else
667 return STG_E_INVALIDPARAMETER;
669 if (tmp.QuadPart < 0)
670 return STG_E_INVALIDFUNCTION;
672 /* we cut off the high part here */
673 stream->u.mem.position = tmp.u.LowPart;
675 if (new_pos)
676 new_pos->QuadPart = stream->u.mem.position;
677 return S_OK;
680 static HRESULT WINAPI memstream_SetSize(IStream *iface, ULARGE_INTEGER new_size)
682 struct shstream *stream = impl_from_IStream(iface);
683 DWORD length;
684 BYTE *buffer;
686 TRACE("(%p, %s)\n", stream, wine_dbgstr_longlong(new_size.QuadPart));
688 /* we cut off the high part here */
689 length = new_size.u.LowPart;
690 buffer = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, stream->u.mem.buffer, length);
691 if (!buffer)
692 return STG_E_INSUFFICIENTMEMORY;
694 stream->u.mem.buffer = buffer;
695 stream->u.mem.length = length;
697 return S_OK;
700 static HRESULT WINAPI shstream_CopyTo(IStream *iface, IStream *pstm, ULARGE_INTEGER size, ULARGE_INTEGER *read_len, ULARGE_INTEGER *written)
702 struct shstream *stream = impl_from_IStream(iface);
704 TRACE("(%p)\n", stream);
706 if (read_len)
707 read_len->QuadPart = 0;
709 if (written)
710 written->QuadPart = 0;
712 /* TODO implement */
713 return E_NOTIMPL;
716 static HRESULT WINAPI shstream_Commit(IStream *iface, DWORD flags)
718 struct shstream *stream = impl_from_IStream(iface);
720 TRACE("(%p, %#x)\n", stream, flags);
722 /* Commit is not supported by this stream */
723 return E_NOTIMPL;
726 static HRESULT WINAPI shstream_Revert(IStream *iface)
728 struct shstream *stream = impl_from_IStream(iface);
730 TRACE("(%p)\n", stream);
732 /* revert not supported by this stream */
733 return E_NOTIMPL;
736 static HRESULT WINAPI shstream_LockRegion(IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER size, DWORD lock_type)
738 struct shstream *stream = impl_from_IStream(iface);
740 TRACE("(%p)\n", stream);
742 /* lock/unlock not supported by this stream */
743 return E_NOTIMPL;
746 static HRESULT WINAPI shstream_UnlockRegion(IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER size, DWORD lock_type)
748 struct shstream *stream = impl_from_IStream(iface);
750 TRACE("(%p)\n", stream);
752 /* lock/unlock not supported by this stream */
753 return E_NOTIMPL;
756 static HRESULT WINAPI memstream_Stat(IStream *iface, STATSTG *statstg, DWORD flags)
758 struct shstream *stream = impl_from_IStream(iface);
760 TRACE("(%p, %p, %#x)\n", stream, statstg, flags);
762 memset(statstg, 0, sizeof(*statstg));
763 statstg->type = STGTY_STREAM;
764 statstg->cbSize.QuadPart = stream->u.mem.length;
765 statstg->grfMode = STGM_READWRITE;
767 return S_OK;
770 static HRESULT WINAPI shstream_Clone(IStream *iface, IStream **dest)
772 struct shstream *stream = impl_from_IStream(iface);
774 TRACE("(%p, %p)\n", stream, dest);
776 *dest = NULL;
778 /* clone not supported by this stream */
779 return E_NOTIMPL;
782 static const IStreamVtbl memstreamvtbl =
784 shstream_QueryInterface,
785 shstream_AddRef,
786 memstream_Release,
787 memstream_Read,
788 memstream_Write,
789 memstream_Seek,
790 memstream_SetSize,
791 shstream_CopyTo,
792 shstream_Commit,
793 shstream_Revert,
794 shstream_LockRegion,
795 shstream_UnlockRegion,
796 memstream_Stat,
797 shstream_Clone,
800 static struct shstream *shstream_create(const IStreamVtbl *vtbl, const BYTE *data, UINT data_len)
802 struct shstream *stream;
804 if (!data)
805 data_len = 0;
807 stream = heap_alloc(sizeof(*stream));
808 stream->IStream_iface.lpVtbl = vtbl;
809 stream->refcount = 1;
810 stream->u.mem.buffer = heap_alloc(data_len);
811 if (!stream->u.mem.buffer)
813 heap_free(stream);
814 return NULL;
816 memcpy(stream->u.mem.buffer, data, data_len);
817 stream->u.mem.length = data_len;
818 stream->u.mem.position = 0;
820 return stream;
823 /*************************************************************************
824 * SHCreateMemStream [SHCORE.@]
826 * Create an IStream object on a block of memory.
828 * PARAMS
829 * data [I] Memory block to create the IStream object on
830 * data_len [I] Length of data block
832 * RETURNS
833 * Success: A pointer to the IStream object.
834 * Failure: NULL, if any parameters are invalid or an error occurs.
836 * NOTES
837 * A copy of the memory block is made, it's freed when the stream is released.
839 IStream * WINAPI SHCreateMemStream(const BYTE *data, UINT data_len)
841 struct shstream *stream;
843 TRACE("(%p, %u)\n", data, data_len);
845 stream = shstream_create(&memstreamvtbl, data, data_len);
846 return stream ? &stream->IStream_iface : NULL;
849 static ULONG WINAPI filestream_Release(IStream *iface)
851 struct shstream *stream = impl_from_IStream(iface);
852 ULONG refcount = InterlockedDecrement(&stream->refcount);
854 TRACE("(%p)->(%u)\n", stream, refcount);
856 if (!refcount)
858 CloseHandle(stream->u.file.handle);
859 heap_free(stream->u.file.path);
860 heap_free(stream);
863 return refcount;
866 static HRESULT WINAPI filestream_Read(IStream *iface, void *buff, ULONG size, ULONG *read_len)
868 struct shstream *stream = impl_from_IStream(iface);
869 DWORD read = 0;
871 TRACE("(%p, %p, %u, %p)\n", stream, buff, size, read_len);
873 if (!ReadFile(stream->u.file.handle, buff, size, &read, NULL))
875 WARN("error %d reading file\n", GetLastError());
876 return S_FALSE;
879 if (read_len)
880 *read_len = read;
882 return read == size ? S_OK : S_FALSE;
885 static HRESULT WINAPI filestream_Write(IStream *iface, const void *buff, ULONG size, ULONG *written)
887 struct shstream *stream = impl_from_IStream(iface);
888 DWORD written_len = 0;
890 TRACE("(%p, %p, %u, %p)\n", stream, buff, size, written);
892 switch (stream->u.file.mode & 0xf)
894 case STGM_WRITE:
895 case STGM_READWRITE:
896 break;
897 default:
898 return STG_E_ACCESSDENIED;
901 if (!WriteFile(stream->u.file.handle, buff, size, &written_len, NULL))
902 return HRESULT_FROM_WIN32(GetLastError());
904 if (written)
905 *written = written_len;
907 return S_OK;
910 static HRESULT WINAPI filestream_Seek(IStream *iface, LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER *new_pos)
912 struct shstream *stream = impl_from_IStream(iface);
913 DWORD position;
915 TRACE("(%p, %s, %d, %p)\n", stream, wine_dbgstr_longlong(move.QuadPart), origin, new_pos);
917 position = SetFilePointer(stream->u.file.handle, move.u.LowPart, NULL, origin);
918 if (position == INVALID_SET_FILE_POINTER)
919 return HRESULT_FROM_WIN32(GetLastError());
921 if (new_pos)
923 new_pos->u.HighPart = 0;
924 new_pos->u.LowPart = position;
927 return S_OK;
930 static HRESULT WINAPI filestream_SetSize(IStream *iface, ULARGE_INTEGER size)
932 struct shstream *stream = impl_from_IStream(iface);
933 LARGE_INTEGER origin, move;
935 TRACE("(%p, %s)\n", stream, wine_dbgstr_longlong(size.QuadPart));
937 move.QuadPart = 0;
938 if (!SetFilePointerEx(stream->u.file.handle, move, &origin, FILE_CURRENT))
939 return E_FAIL;
941 move.QuadPart = size.QuadPart;
942 if (!SetFilePointerEx(stream->u.file.handle, move, NULL, FILE_BEGIN))
943 return E_FAIL;
945 if (stream->u.file.mode != STGM_READ)
947 if (!SetEndOfFile(stream->u.file.handle))
948 return E_FAIL;
949 if (!SetFilePointerEx(stream->u.file.handle, origin, NULL, FILE_BEGIN))
950 return E_FAIL;
953 return S_OK;
956 static HRESULT WINAPI filestream_CopyTo(IStream *iface, IStream *dest, ULARGE_INTEGER size,
957 ULARGE_INTEGER *read_len, ULARGE_INTEGER *written)
959 struct shstream *stream = impl_from_IStream(iface);
960 HRESULT hr = S_OK;
961 char buff[1024];
963 TRACE("(%p, %p, %s, %p, %p)\n", stream, dest, wine_dbgstr_longlong(size.QuadPart), read_len, written);
965 if (read_len)
966 read_len->QuadPart = 0;
967 if (written)
968 written->QuadPart = 0;
970 if (!dest)
971 return S_OK;
973 while (size.QuadPart)
975 ULONG left, read_chunk, written_chunk;
977 left = size.QuadPart > sizeof(buff) ? sizeof(buff) : size.QuadPart;
979 /* Read */
980 hr = IStream_Read(iface, buff, left, &read_chunk);
981 if (FAILED(hr) || read_chunk == 0)
982 break;
983 if (read_len)
984 read_len->QuadPart += read_chunk;
986 /* Write */
987 hr = IStream_Write(dest, buff, read_chunk, &written_chunk);
988 if (written_chunk)
989 written->QuadPart += written_chunk;
990 if (FAILED(hr) || written_chunk != left)
991 break;
993 size.QuadPart -= left;
996 return hr;
999 static HRESULT WINAPI filestream_Commit(IStream *iface, DWORD flags)
1001 struct shstream *stream = impl_from_IStream(iface);
1003 TRACE("(%p, %#x)\n", stream, flags);
1005 return S_OK;
1008 static HRESULT WINAPI filestream_Stat(IStream *iface, STATSTG *statstg, DWORD flags)
1010 struct shstream *stream = impl_from_IStream(iface);
1011 BY_HANDLE_FILE_INFORMATION fi;
1013 TRACE("(%p, %p, %#x)\n", stream, statstg, flags);
1015 if (!statstg)
1016 return STG_E_INVALIDPOINTER;
1018 memset(&fi, 0, sizeof(fi));
1019 GetFileInformationByHandle(stream->u.file.handle, &fi);
1021 if (flags & STATFLAG_NONAME)
1022 statstg->pwcsName = NULL;
1023 else
1025 int len = lstrlenW(stream->u.file.path);
1026 if ((statstg->pwcsName = CoTaskMemAlloc((len + 1) * sizeof(WCHAR))))
1027 memcpy(statstg->pwcsName, stream->u.file.path, (len + 1) * sizeof(WCHAR));
1029 statstg->type = 0;
1030 statstg->cbSize.u.LowPart = fi.nFileSizeLow;
1031 statstg->cbSize.u.HighPart = fi.nFileSizeHigh;
1032 statstg->mtime = fi.ftLastWriteTime;
1033 statstg->ctime = fi.ftCreationTime;
1034 statstg->atime = fi.ftLastAccessTime;
1035 statstg->grfMode = stream->u.file.mode;
1036 statstg->grfLocksSupported = 0;
1037 memcpy(&statstg->clsid, &IID_IStream, sizeof(CLSID));
1038 statstg->grfStateBits = 0;
1039 statstg->reserved = 0;
1041 return S_OK;
1044 static const IStreamVtbl filestreamvtbl =
1046 shstream_QueryInterface,
1047 shstream_AddRef,
1048 filestream_Release,
1049 filestream_Read,
1050 filestream_Write,
1051 filestream_Seek,
1052 filestream_SetSize,
1053 filestream_CopyTo,
1054 filestream_Commit,
1055 shstream_Revert,
1056 shstream_LockRegion,
1057 shstream_UnlockRegion,
1058 filestream_Stat,
1059 shstream_Clone,
1062 /*************************************************************************
1063 * SHCreateStreamOnFileEx [SHCORE.@]
1065 HRESULT WINAPI SHCreateStreamOnFileEx(const WCHAR *path, DWORD mode, DWORD attributes,
1066 BOOL create, IStream *template, IStream **ret)
1068 DWORD access, share, creation_disposition, len;
1069 struct shstream *stream;
1070 HANDLE hFile;
1072 TRACE("(%s, %d, 0x%08X, %d, %p, %p)\n", debugstr_w(path), mode, attributes,
1073 create, template, ret);
1075 if (!path || !ret || template)
1076 return E_INVALIDARG;
1078 *ret = NULL;
1080 /* Access */
1081 switch (mode & 0xf)
1083 case STGM_WRITE:
1084 case STGM_READWRITE:
1085 access = GENERIC_READ | GENERIC_WRITE;
1086 break;
1087 case STGM_READ:
1088 access = GENERIC_READ;
1089 break;
1090 default:
1091 return E_INVALIDARG;
1094 /* Sharing */
1095 switch (mode & 0xf0)
1097 case 0:
1098 case STGM_SHARE_DENY_NONE:
1099 share = FILE_SHARE_READ | FILE_SHARE_WRITE;
1100 break;
1101 case STGM_SHARE_DENY_READ:
1102 share = FILE_SHARE_WRITE;
1103 break;
1104 case STGM_SHARE_DENY_WRITE:
1105 share = FILE_SHARE_READ;
1106 break;
1107 case STGM_SHARE_EXCLUSIVE:
1108 share = 0;
1109 break;
1110 default:
1111 return E_INVALIDARG;
1114 switch (mode & 0xf000)
1116 case STGM_FAILIFTHERE:
1117 creation_disposition = create ? CREATE_NEW : OPEN_EXISTING;
1118 break;
1119 case STGM_CREATE:
1120 creation_disposition = CREATE_ALWAYS;
1121 break;
1122 default:
1123 return E_INVALIDARG;
1126 hFile = CreateFileW(path, access, share, NULL, creation_disposition, attributes, 0);
1127 if (hFile == INVALID_HANDLE_VALUE)
1128 return HRESULT_FROM_WIN32(GetLastError());
1130 stream = heap_alloc(sizeof(*stream));
1131 stream->IStream_iface.lpVtbl = &filestreamvtbl;
1132 stream->refcount = 1;
1133 stream->u.file.handle = hFile;
1134 stream->u.file.mode = mode;
1136 len = lstrlenW(path);
1137 stream->u.file.path = heap_alloc((len + 1) * sizeof(WCHAR));
1138 memcpy(stream->u.file.path, path, (len + 1) * sizeof(WCHAR));
1140 *ret = &stream->IStream_iface;
1142 return S_OK;
1145 /*************************************************************************
1146 * SHCreateStreamOnFileW [SHCORE.@]
1148 HRESULT WINAPI SHCreateStreamOnFileW(const WCHAR *path, DWORD mode, IStream **stream)
1150 TRACE("(%s, %#x, %p)\n", debugstr_w(path), mode, stream);
1152 if (!path || !stream)
1153 return E_INVALIDARG;
1155 if ((mode & (STGM_CONVERT | STGM_DELETEONRELEASE | STGM_TRANSACTED)) != 0)
1156 return E_INVALIDARG;
1158 return SHCreateStreamOnFileEx(path, mode, 0, FALSE, NULL, stream);
1161 /*************************************************************************
1162 * SHCreateStreamOnFileA [SHCORE.@]
1164 HRESULT WINAPI SHCreateStreamOnFileA(const char *path, DWORD mode, IStream **stream)
1166 WCHAR *pathW;
1167 HRESULT hr;
1168 DWORD len;
1170 TRACE("(%s, %#x, %p)\n", debugstr_a(path), mode, stream);
1172 if (!path)
1173 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1175 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1176 pathW = heap_alloc(len * sizeof(WCHAR));
1177 if (!pathW)
1178 return E_OUTOFMEMORY;
1180 MultiByteToWideChar(CP_ACP, 0, path, -1, pathW, len);
1181 hr = SHCreateStreamOnFileW(pathW, mode, stream);
1182 heap_free(pathW);
1184 return hr;
1187 static ULONG WINAPI regstream_Release(IStream *iface)
1189 struct shstream *stream = impl_from_IStream(iface);
1190 ULONG refcount = InterlockedDecrement(&stream->refcount);
1192 TRACE("(%p)->(%u)\n", stream, refcount);
1194 if (!refcount)
1196 if (stream->u.mem.hkey)
1198 if (stream->u.mem.length)
1199 RegSetValueExW(stream->u.mem.hkey, stream->u.mem.valuename, 0, REG_BINARY,
1200 (const BYTE *)stream->u.mem.buffer, stream->u.mem.length);
1201 else
1202 RegDeleteValueW(stream->u.mem.hkey, stream->u.mem.valuename);
1203 RegCloseKey(stream->u.mem.hkey);
1205 CoTaskMemFree(stream->u.mem.valuename);
1206 heap_free(stream->u.mem.buffer);
1207 heap_free(stream);
1210 return refcount;
1213 static const IStreamVtbl regstreamvtbl =
1215 shstream_QueryInterface,
1216 shstream_AddRef,
1217 regstream_Release,
1218 memstream_Read,
1219 memstream_Write,
1220 memstream_Seek,
1221 memstream_SetSize,
1222 shstream_CopyTo,
1223 shstream_Commit,
1224 shstream_Revert,
1225 shstream_LockRegion,
1226 shstream_UnlockRegion,
1227 memstream_Stat,
1228 shstream_Clone,
1231 /*************************************************************************
1232 * SHOpenRegStream2W [SHCORE.@]
1234 IStream * WINAPI SHOpenRegStream2W(HKEY hKey, const WCHAR *subkey, const WCHAR *value, DWORD mode)
1236 struct shstream *stream;
1237 HKEY hStrKey = NULL;
1238 BYTE *buff = NULL;
1239 DWORD length = 0;
1240 LONG ret;
1242 TRACE("(%p, %s, %s, %#x)\n", hKey, debugstr_w(subkey), debugstr_w(value), mode);
1244 if (mode == STGM_READ)
1245 ret = RegOpenKeyExW(hKey, subkey, 0, KEY_READ, &hStrKey);
1246 else /* in write mode we make sure the subkey exits */
1247 ret = RegCreateKeyExW(hKey, subkey, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &hStrKey, NULL);
1249 if (ret == ERROR_SUCCESS)
1251 if (mode == STGM_READ || mode == STGM_READWRITE)
1253 /* read initial data */
1254 ret = RegQueryValueExW(hStrKey, value, 0, 0, 0, &length);
1255 if (ret == ERROR_SUCCESS && length)
1257 buff = heap_alloc(length);
1258 RegQueryValueExW(hStrKey, value, 0, 0, buff, &length);
1262 if (!length)
1263 buff = heap_alloc(length);
1265 stream = shstream_create(&regstreamvtbl, buff, length);
1266 heap_free(buff);
1267 if (stream)
1269 stream->u.mem.hkey = hStrKey;
1270 SHStrDupW(value, &stream->u.mem.valuename);
1271 return &stream->IStream_iface;
1275 if (hStrKey)
1276 RegCloseKey(hStrKey);
1278 return NULL;
1281 /*************************************************************************
1282 * SHOpenRegStream2A [SHCORE.@]
1284 IStream * WINAPI SHOpenRegStream2A(HKEY hKey, const char *subkey, const char *value, DWORD mode)
1286 WCHAR *subkeyW = NULL, *valueW = NULL;
1287 IStream *stream;
1289 TRACE("(%p, %s, %s, %#x)\n", hKey, debugstr_a(subkey), debugstr_a(value), mode);
1291 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1292 return NULL;
1293 if (value && FAILED(SHStrDupA(value, &valueW)))
1295 CoTaskMemFree(subkeyW);
1296 return NULL;
1299 stream = SHOpenRegStream2W(hKey, subkeyW, valueW, mode);
1300 CoTaskMemFree(subkeyW);
1301 CoTaskMemFree(valueW);
1302 return stream;
1305 /*************************************************************************
1306 * SHOpenRegStreamA [SHCORE.@]
1308 IStream * WINAPI SHOpenRegStreamA(HKEY hkey, const char *subkey, const char *value, DWORD mode)
1310 WCHAR *subkeyW = NULL, *valueW = NULL;
1311 IStream *stream;
1313 TRACE("(%p, %s, %s, %#x)\n", hkey, debugstr_a(subkey), debugstr_a(value), mode);
1315 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1316 return NULL;
1317 if (value && FAILED(SHStrDupA(value, &valueW)))
1319 CoTaskMemFree(subkeyW);
1320 return NULL;
1323 stream = SHOpenRegStreamW(hkey, subkeyW, valueW, mode);
1324 CoTaskMemFree(subkeyW);
1325 CoTaskMemFree(valueW);
1326 return stream;
1329 static ULONG WINAPI dummystream_AddRef(IStream *iface)
1331 TRACE("()\n");
1332 return 2;
1335 static ULONG WINAPI dummystream_Release(IStream *iface)
1337 TRACE("()\n");
1338 return 1;
1341 static HRESULT WINAPI dummystream_Read(IStream *iface, void *buff, ULONG buff_size, ULONG *read_len)
1343 if (read_len)
1344 *read_len = 0;
1346 return E_NOTIMPL;
1349 static const IStreamVtbl dummystreamvtbl =
1351 shstream_QueryInterface,
1352 dummystream_AddRef,
1353 dummystream_Release,
1354 dummystream_Read,
1355 memstream_Write,
1356 memstream_Seek,
1357 memstream_SetSize,
1358 shstream_CopyTo,
1359 shstream_Commit,
1360 shstream_Revert,
1361 shstream_LockRegion,
1362 shstream_UnlockRegion,
1363 memstream_Stat,
1364 shstream_Clone,
1367 static struct shstream dummyregstream = { { &dummystreamvtbl } };
1369 /*************************************************************************
1370 * SHOpenRegStreamW [SHCORE.@]
1372 IStream * WINAPI SHOpenRegStreamW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, DWORD mode)
1374 IStream *stream;
1376 TRACE("(%p, %s, %s, %#x)\n", hkey, debugstr_w(subkey), debugstr_w(value), mode);
1377 stream = SHOpenRegStream2W(hkey, subkey, value, mode);
1378 return stream ? stream : &dummyregstream.IStream_iface;
1381 struct threadref
1383 IUnknown IUnknown_iface;
1384 LONG *refcount;
1387 static inline struct threadref *threadref_impl_from_IUnknown(IUnknown *iface)
1389 return CONTAINING_RECORD(iface, struct threadref, IUnknown_iface);
1392 static HRESULT WINAPI threadref_QueryInterface(IUnknown *iface, REFIID riid, void **out)
1394 struct threadref *threadref = threadref_impl_from_IUnknown(iface);
1396 TRACE("(%p, %s, %p)\n", threadref, debugstr_guid(riid), out);
1398 if (out == NULL)
1399 return E_POINTER;
1401 if (IsEqualGUID(&IID_IUnknown, riid))
1403 *out = iface;
1404 IUnknown_AddRef(iface);
1405 return S_OK;
1408 *out = NULL;
1409 WARN("Interface %s not supported.\n", debugstr_guid(riid));
1410 return E_NOINTERFACE;
1413 static ULONG WINAPI threadref_AddRef(IUnknown *iface)
1415 struct threadref *threadref = threadref_impl_from_IUnknown(iface);
1416 LONG refcount = InterlockedIncrement(threadref->refcount);
1418 TRACE("(%p, %d)\n", threadref, refcount);
1420 return refcount;
1423 static ULONG WINAPI threadref_Release(IUnknown *iface)
1425 struct threadref *threadref = threadref_impl_from_IUnknown(iface);
1426 LONG refcount = InterlockedDecrement(threadref->refcount);
1428 TRACE("(%p, %d)\n", threadref, refcount);
1430 if (!refcount)
1431 heap_free(threadref);
1433 return refcount;
1436 static const IUnknownVtbl threadrefvtbl =
1438 threadref_QueryInterface,
1439 threadref_AddRef,
1440 threadref_Release,
1443 /*************************************************************************
1444 * SHCreateThreadRef [SHCORE.@]
1446 HRESULT WINAPI SHCreateThreadRef(LONG *refcount, IUnknown **out)
1448 struct threadref *threadref;
1450 TRACE("(%p, %p)\n", refcount, out);
1452 if (!refcount || !out)
1453 return E_INVALIDARG;
1455 *out = NULL;
1457 threadref = heap_alloc(sizeof(*threadref));
1458 if (!threadref)
1459 return E_OUTOFMEMORY;
1460 threadref->IUnknown_iface.lpVtbl = &threadrefvtbl;
1461 threadref->refcount = refcount;
1463 *refcount = 1;
1464 *out = &threadref->IUnknown_iface;
1466 TRACE("Created %p.\n", threadref);
1467 return S_OK;
1470 /*************************************************************************
1471 * SHGetThreadRef [SHCORE.@]
1473 HRESULT WINAPI SHGetThreadRef(IUnknown **out)
1475 TRACE("(%p)\n", out);
1477 if (shcore_tls == TLS_OUT_OF_INDEXES)
1478 return E_NOINTERFACE;
1480 *out = TlsGetValue(shcore_tls);
1481 if (!*out)
1482 return E_NOINTERFACE;
1484 IUnknown_AddRef(*out);
1485 return S_OK;
1488 /*************************************************************************
1489 * SHSetThreadRef [SHCORE.@]
1491 HRESULT WINAPI SHSetThreadRef(IUnknown *obj)
1493 TRACE("(%p)\n", obj);
1495 if (shcore_tls == TLS_OUT_OF_INDEXES)
1496 return E_NOINTERFACE;
1498 TlsSetValue(shcore_tls, obj);
1499 return S_OK;
1502 /*************************************************************************
1503 * SHReleaseThreadRef [SHCORE.@]
1505 HRESULT WINAPI SHReleaseThreadRef(void)
1507 FIXME("() - stub!\n");
1508 return S_OK;
1511 /*************************************************************************
1512 * GetProcessReference [SHCORE.@]
1514 HRESULT WINAPI GetProcessReference(IUnknown **obj)
1516 TRACE("(%p)\n", obj);
1518 *obj = process_ref;
1520 if (!process_ref)
1521 return E_FAIL;
1523 if (*obj)
1524 IUnknown_AddRef(*obj);
1526 return S_OK;
1529 /*************************************************************************
1530 * SetProcessReference [SHCORE.@]
1532 void WINAPI SetProcessReference(IUnknown *obj)
1534 TRACE("(%p)\n", obj);
1536 process_ref = obj;
1539 struct thread_data
1541 LPTHREAD_START_ROUTINE thread_proc;
1542 LPTHREAD_START_ROUTINE callback;
1543 void *data;
1544 DWORD flags;
1545 HANDLE hEvent;
1546 IUnknown *thread_ref;
1547 IUnknown *process_ref;
1550 static DWORD WINAPI shcore_thread_wrapper(void *data)
1552 struct thread_data thread_data;
1553 HRESULT hr = E_FAIL;
1554 DWORD retval;
1556 TRACE("(%p)\n", data);
1558 /* We are now executing in the context of the newly created thread.
1559 * So we copy the data passed to us (it is on the stack of the function
1560 * that called us, which is waiting for us to signal an event before
1561 * returning). */
1562 thread_data = *(struct thread_data *)data;
1564 if (thread_data.flags & CTF_COINIT)
1566 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
1567 if (FAILED(hr))
1568 hr = CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE);
1571 if (thread_data.callback)
1572 thread_data.callback(thread_data.data);
1574 /* Signal the thread that created us; it can return now. */
1575 SetEvent(thread_data.hEvent);
1577 /* Execute the callers start code. */
1578 retval = thread_data.thread_proc(thread_data.data);
1580 /* Release thread and process references. */
1581 if (thread_data.thread_ref)
1582 IUnknown_Release(thread_data.thread_ref);
1584 if (thread_data.process_ref)
1585 IUnknown_Release(thread_data.process_ref);
1587 if (SUCCEEDED(hr))
1588 CoUninitialize();
1590 return retval;
1593 /*************************************************************************
1594 * SHCreateThread [SHCORE.@]
1596 BOOL WINAPI SHCreateThread(LPTHREAD_START_ROUTINE thread_proc, void *data, DWORD flags, LPTHREAD_START_ROUTINE callback)
1598 struct thread_data thread_data;
1599 BOOL called = FALSE;
1601 TRACE("(%p, %p, %#x, %p)\n", thread_proc, data, flags, callback);
1603 thread_data.thread_proc = thread_proc;
1604 thread_data.callback = callback;
1605 thread_data.data = data;
1606 thread_data.flags = flags;
1607 thread_data.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
1609 if (flags & CTF_THREAD_REF)
1610 SHGetThreadRef(&thread_data.thread_ref);
1611 else
1612 thread_data.thread_ref = NULL;
1614 if (flags & CTF_PROCESS_REF)
1615 GetProcessReference(&thread_data.process_ref);
1616 else
1617 thread_data.process_ref = NULL;
1619 /* Create the thread */
1620 if (thread_data.hEvent)
1622 HANDLE hThread;
1623 DWORD retval;
1625 hThread = CreateThread(NULL, 0, shcore_thread_wrapper, &thread_data, 0, &retval);
1626 if (hThread)
1628 /* Wait for the thread to signal us to continue */
1629 WaitForSingleObject(thread_data.hEvent, INFINITE);
1630 CloseHandle(hThread);
1631 called = TRUE;
1633 CloseHandle(thread_data.hEvent);
1636 if (!called)
1638 if (!thread_data.callback && flags & CTF_INSIST)
1640 /* Couldn't call, call synchronously */
1641 thread_data.thread_proc(data);
1642 called = TRUE;
1644 else
1646 if (thread_data.thread_ref)
1647 IUnknown_Release(thread_data.thread_ref);
1649 if (thread_data.process_ref)
1650 IUnknown_Release(thread_data.process_ref);
1654 return called;
1657 /*************************************************************************
1658 * SHStrDupW [SHCORE.@]
1660 HRESULT WINAPI SHStrDupW(const WCHAR *src, WCHAR **dest)
1662 size_t len;
1664 TRACE("(%s, %p)\n", debugstr_w(src), dest);
1666 *dest = NULL;
1668 if (!src)
1669 return E_INVALIDARG;
1671 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
1672 *dest = CoTaskMemAlloc(len);
1673 if (!*dest)
1674 return E_OUTOFMEMORY;
1676 memcpy(*dest, src, len);
1678 return S_OK;
1681 /*************************************************************************
1682 * SHStrDupA [SHCORE.@]
1684 HRESULT WINAPI SHStrDupA(const char *src, WCHAR **dest)
1686 DWORD len;
1688 *dest = NULL;
1690 if (!src)
1691 return E_INVALIDARG;
1693 len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
1694 *dest = CoTaskMemAlloc(len * sizeof(WCHAR));
1695 if (!*dest)
1696 return E_OUTOFMEMORY;
1698 MultiByteToWideChar(CP_ACP, 0, src, -1, *dest, len);
1700 return S_OK;
1703 /*************************************************************************
1704 * SHAnsiToAnsi [SHCORE.@]
1706 DWORD WINAPI SHAnsiToAnsi(const char *src, char *dest, int dest_len)
1708 DWORD ret;
1710 TRACE("(%s, %p, %d)\n", debugstr_a(src), dest, dest_len);
1712 if (!src || !dest || dest_len <= 0)
1713 return 0;
1715 lstrcpynA(dest, src, dest_len);
1716 ret = strlen(dest);
1718 return src[ret] ? 0 : ret + 1;
1721 /*************************************************************************
1722 * SHUnicodeToAnsi [SHCORE.@]
1724 DWORD WINAPI SHUnicodeToAnsi(const WCHAR *src, char *dest, int dest_len)
1726 int ret = 1;
1728 TRACE("(%s, %p, %d)\n", debugstr_w(src), dest, dest_len);
1730 if (!dest || !dest_len)
1731 return 0;
1733 if (src)
1735 ret = WideCharToMultiByte(CP_ACP, 0, src, -1, dest, dest_len, NULL, NULL);
1736 if (!ret)
1738 dest[dest_len - 1] = 0;
1739 ret = dest_len;
1742 else
1743 dest[0] = 0;
1745 return ret;
1748 /*************************************************************************
1749 * SHUnicodeToUnicode [SHCORE.@]
1751 DWORD WINAPI SHUnicodeToUnicode(const WCHAR *src, WCHAR *dest, int dest_len)
1753 DWORD ret;
1755 TRACE("(%s, %p, %d)\n", debugstr_w(src), dest, dest_len);
1757 if (!src || !dest || dest_len <= 0)
1758 return 0;
1760 lstrcpynW(dest, src, dest_len);
1761 ret = lstrlenW(dest);
1763 return src[ret] ? 0 : ret + 1;
1766 /*************************************************************************
1767 * SHAnsiToUnicode [SHCORE.@]
1769 DWORD WINAPI SHAnsiToUnicode(const char *src, WCHAR *dest, int dest_len)
1771 int ret = 1;
1773 TRACE("(%s, %p, %d)\n", debugstr_a(src), dest, dest_len);
1775 if (!dest || !dest_len)
1776 return 0;
1778 if (src)
1780 ret = MultiByteToWideChar(CP_ACP, 0, src, -1, dest, dest_len);
1781 if (!ret)
1783 dest[dest_len - 1] = 0;
1784 ret = dest_len;
1787 else
1788 dest[0] = 0;
1790 return ret;
1793 /*************************************************************************
1794 * SHRegDuplicateHKey [SHCORE.@]
1796 HKEY WINAPI SHRegDuplicateHKey(HKEY hKey)
1798 HKEY newKey = 0;
1800 RegOpenKeyExW(hKey, 0, 0, MAXIMUM_ALLOWED, &newKey);
1801 TRACE("new key is %p\n", newKey);
1802 return newKey;
1805 /*************************************************************************
1806 * SHDeleteEmptyKeyW [SHCORE.@]
1808 DWORD WINAPI SHDeleteEmptyKeyW(HKEY hkey, const WCHAR *subkey)
1810 DWORD ret, count = 0;
1811 HKEY hsubkey = 0;
1813 TRACE("(%p, %s)\n", hkey, debugstr_w(subkey));
1815 ret = RegOpenKeyExW(hkey, subkey, 0, KEY_READ, &hsubkey);
1816 if (!ret)
1818 ret = RegQueryInfoKeyW(hsubkey, NULL, NULL, NULL, &count,
1819 NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1820 RegCloseKey(hsubkey);
1821 if (!ret)
1823 if (count)
1824 ret = ERROR_KEY_HAS_CHILDREN;
1825 else
1826 ret = RegDeleteKeyW(hkey, subkey);
1830 return ret;
1833 /*************************************************************************
1834 * SHDeleteEmptyKeyA [SHCORE.@]
1836 DWORD WINAPI SHDeleteEmptyKeyA(HKEY hkey, const char *subkey)
1838 WCHAR *subkeyW = NULL;
1839 DWORD ret;
1841 TRACE("(%p, %s)\n", hkey, debugstr_a(subkey));
1843 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1844 return ERROR_OUTOFMEMORY;
1846 ret = SHDeleteEmptyKeyW(hkey, subkeyW);
1847 CoTaskMemFree(subkeyW);
1848 return ret;
1851 /*************************************************************************
1852 * SHDeleteKeyW [SHCORE.@]
1854 DWORD WINAPI SHDeleteKeyW(HKEY hkey, const WCHAR *subkey)
1856 TRACE("(%p, %s)\n", hkey, debugstr_w(subkey));
1858 return RegDeleteTreeW(hkey, subkey);
1861 /*************************************************************************
1862 * SHDeleteKeyA [SHCORE.@]
1864 DWORD WINAPI SHDeleteKeyA(HKEY hkey, const char *subkey)
1866 TRACE("(%p, %s)\n", hkey, debugstr_a(subkey));
1868 return RegDeleteTreeA(hkey, subkey);
1871 /*************************************************************************
1872 * SHDeleteValueW [SHCORE.@]
1874 DWORD WINAPI SHDeleteValueW(HKEY hkey, const WCHAR *subkey, const WCHAR *value)
1876 HKEY hsubkey;
1877 DWORD ret;
1879 TRACE("(%p, %s, %s)\n", hkey, debugstr_w(subkey), debugstr_w(value));
1881 ret = RegOpenKeyExW(hkey, subkey, 0, KEY_SET_VALUE, &hsubkey);
1882 if (!ret)
1884 ret = RegDeleteValueW(hsubkey, value);
1885 RegCloseKey(hsubkey);
1888 return ret;
1891 /*************************************************************************
1892 * SHDeleteValueA [SHCORE.@]
1894 DWORD WINAPI SHDeleteValueA(HKEY hkey, const char *subkey, const char *value)
1896 WCHAR *subkeyW = NULL, *valueW = NULL;
1897 DWORD ret;
1899 TRACE("(%p, %s, %s)\n", hkey, debugstr_a(subkey), debugstr_a(value));
1901 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1902 return ERROR_OUTOFMEMORY;
1903 if (value && FAILED(SHStrDupA(value, &valueW)))
1905 CoTaskMemFree(subkeyW);
1906 return ERROR_OUTOFMEMORY;
1909 ret = SHDeleteValueW(hkey, subkeyW, valueW);
1910 CoTaskMemFree(subkeyW);
1911 CoTaskMemFree(valueW);
1912 return ret;
1915 /*************************************************************************
1916 * SHCopyKeyA [SHCORE.@]
1918 DWORD WINAPI SHCopyKeyA(HKEY hkey_src, const char *subkey, HKEY hkey_dst, DWORD reserved)
1920 WCHAR *subkeyW = NULL;
1921 DWORD ret;
1923 TRACE("(%p, %s, %p, %d)\n", hkey_src, debugstr_a(subkey), hkey_dst, reserved);
1925 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1926 return 0;
1928 ret = SHCopyKeyW(hkey_src, subkeyW, hkey_dst, reserved);
1929 CoTaskMemFree(subkeyW);
1930 return ret;
1933 /*************************************************************************
1934 * SHCopyKeyW [SHCORE.@]
1936 DWORD WINAPI SHCopyKeyW(HKEY hkey_src, const WCHAR *subkey, HKEY hkey_dst, DWORD reserved)
1938 DWORD key_count = 0, value_count = 0, max_key_len = 0;
1939 WCHAR name[MAX_PATH], *ptr_name = name;
1940 BYTE buff[1024], *ptr = buff;
1941 DWORD max_data_len = 0, i;
1942 DWORD ret = 0;
1944 TRACE("(%p, %s, %p, %d)\n", hkey_src, debugstr_w(subkey), hkey_dst, reserved);
1946 if (!hkey_dst || !hkey_src)
1947 return ERROR_INVALID_PARAMETER;
1949 if (subkey)
1950 ret = RegOpenKeyExW(hkey_src, subkey, 0, KEY_ALL_ACCESS, &hkey_src);
1952 if (ret)
1953 hkey_src = NULL; /* Don't close this key since we didn't open it */
1954 else
1956 DWORD max_value_len;
1958 ret = RegQueryInfoKeyW(hkey_src, NULL, NULL, NULL, &key_count, &max_key_len,
1959 NULL, &value_count, &max_value_len, &max_data_len, NULL, NULL);
1960 if (!ret)
1962 /* Get max size for key/value names */
1963 max_key_len = max(max_key_len, max_value_len);
1965 if (max_key_len++ > MAX_PATH - 1)
1966 ptr_name = heap_alloc(max_key_len * sizeof(WCHAR));
1968 if (max_data_len > sizeof(buff))
1969 ptr = heap_alloc(max_data_len);
1971 if (!ptr_name || !ptr)
1972 ret = ERROR_NOT_ENOUGH_MEMORY;
1976 for (i = 0; i < key_count && !ret; i++)
1978 HKEY hsubkey_src, hsubkey_dst;
1979 DWORD length = max_key_len;
1981 ret = RegEnumKeyExW(hkey_src, i, ptr_name, &length, NULL, NULL, NULL, NULL);
1982 if (!ret)
1984 ret = RegOpenKeyExW(hkey_src, ptr_name, 0, KEY_READ, &hsubkey_src);
1985 if (!ret)
1987 /* Create destination sub key */
1988 ret = RegCreateKeyW(hkey_dst, ptr_name, &hsubkey_dst);
1989 if (!ret)
1991 /* Recursively copy keys and values from the sub key */
1992 ret = SHCopyKeyW(hsubkey_src, NULL, hsubkey_dst, 0);
1993 RegCloseKey(hsubkey_dst);
1996 RegCloseKey(hsubkey_src);
2000 /* Copy all the values in this key */
2001 for (i = 0; i < value_count && !ret; i++)
2003 DWORD length = max_key_len, type, data_len = max_data_len;
2005 ret = RegEnumValueW(hkey_src, i, ptr_name, &length, NULL, &type, ptr, &data_len);
2006 if (!ret) {
2007 ret = SHSetValueW(hkey_dst, NULL, ptr_name, type, ptr, data_len);
2011 /* Free buffers if allocated */
2012 if (ptr_name != name)
2013 heap_free(ptr_name);
2014 if (ptr != buff)
2015 heap_free(ptr);
2017 if (subkey && hkey_src)
2018 RegCloseKey(hkey_src);
2020 return ret;
2024 /*************************************************************************
2025 * SHEnumKeyExA [SHCORE.@]
2027 LONG WINAPI SHEnumKeyExA(HKEY hkey, DWORD index, char *subkey, DWORD *length)
2029 TRACE("(%p, %d, %s, %p)\n", hkey, index, debugstr_a(subkey), length);
2031 return RegEnumKeyExA(hkey, index, subkey, length, NULL, NULL, NULL, NULL);
2034 /*************************************************************************
2035 * SHEnumKeyExW [SHCORE.@]
2037 LONG WINAPI SHEnumKeyExW(HKEY hkey, DWORD index, WCHAR *subkey, DWORD *length)
2039 TRACE("(%p, %d, %s, %p)\n", hkey, index, debugstr_w(subkey), length);
2041 return RegEnumKeyExW(hkey, index, subkey, length, NULL, NULL, NULL, NULL);
2044 /*************************************************************************
2045 * SHEnumValueA [SHCORE.@]
2047 LONG WINAPI SHEnumValueA(HKEY hkey, DWORD index, char *value, DWORD *length, DWORD *type,
2048 void *data, DWORD *data_len)
2050 TRACE("(%p, %d, %s, %p, %p, %p, %p)\n", hkey, index, debugstr_a(value), length, type, data, data_len);
2052 return RegEnumValueA(hkey, index, value, length, NULL, type, data, data_len);
2055 /*************************************************************************
2056 * SHEnumValueW [SHCORE.@]
2058 LONG WINAPI SHEnumValueW(HKEY hkey, DWORD index, WCHAR *value, DWORD *length, DWORD *type,
2059 void *data, DWORD *data_len)
2061 TRACE("(%p, %d, %s, %p, %p, %p, %p)\n", hkey, index, debugstr_w(value), length, type, data, data_len);
2063 return RegEnumValueW(hkey, index, value, length, NULL, type, data, data_len);
2066 /*************************************************************************
2067 * SHQueryValueExW [SHCORE.@]
2069 DWORD WINAPI SHQueryValueExW(HKEY hkey, const WCHAR *name, DWORD *reserved, DWORD *type,
2070 void *buff, DWORD *buff_len)
2072 DWORD ret, value_type, data_len = 0;
2074 TRACE("(%p, %s, %p, %p, %p, %p)\n", hkey, debugstr_w(name), reserved, type, buff, buff_len);
2076 if (buff_len)
2077 data_len = *buff_len;
2079 ret = RegQueryValueExW(hkey, name, reserved, &value_type, buff, &data_len);
2080 if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)
2081 return ret;
2083 if (buff_len && value_type == REG_EXPAND_SZ)
2085 DWORD length;
2086 WCHAR *value;
2088 if (!buff || ret == ERROR_MORE_DATA)
2090 length = data_len;
2091 value = heap_alloc(length);
2092 RegQueryValueExW(hkey, name, reserved, NULL, (BYTE *)value, &length);
2093 length = ExpandEnvironmentStringsW(value, NULL, 0);
2095 else
2097 length = (lstrlenW(buff) + 1) * sizeof(WCHAR);
2098 value = heap_alloc(length);
2099 memcpy(value, buff, length);
2100 length = ExpandEnvironmentStringsW(value, buff, *buff_len / sizeof(WCHAR));
2101 if (length > *buff_len) ret = ERROR_MORE_DATA;
2103 data_len = max(data_len, length);
2104 heap_free(value);
2107 if (type)
2108 *type = value_type == REG_EXPAND_SZ ? REG_SZ : value_type;
2109 if (buff_len)
2110 *buff_len = data_len;
2111 return ret;
2114 /*************************************************************************
2115 * SHQueryValueExA [SHCORE.@]
2117 DWORD WINAPI SHQueryValueExA(HKEY hkey, const char *name, DWORD *reserved, DWORD *type,
2118 void *buff, DWORD *buff_len)
2120 DWORD ret, value_type, data_len = 0;
2122 TRACE("(%p, %s, %p, %p, %p, %p)\n", hkey, debugstr_a(name), reserved, type, buff, buff_len);
2124 if (buff_len)
2125 data_len = *buff_len;
2127 ret = RegQueryValueExA(hkey, name, reserved, &value_type, buff, &data_len);
2128 if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)
2129 return ret;
2131 if (buff_len && value_type == REG_EXPAND_SZ)
2133 DWORD length;
2134 char *value;
2136 if (!buff || ret == ERROR_MORE_DATA)
2138 length = data_len;
2139 value = heap_alloc(length);
2140 RegQueryValueExA(hkey, name, reserved, NULL, (BYTE *)value, &length);
2141 length = ExpandEnvironmentStringsA(value, NULL, 0);
2143 else
2145 length = strlen(buff) + 1;
2146 value = heap_alloc(length);
2147 memcpy(value, buff, length);
2148 length = ExpandEnvironmentStringsA(value, buff, *buff_len);
2149 if (length > *buff_len) ret = ERROR_MORE_DATA;
2151 data_len = max(data_len, length);
2152 heap_free(value);
2155 if (type)
2156 *type = value_type == REG_EXPAND_SZ ? REG_SZ : value_type;
2157 if (buff_len)
2158 *buff_len = data_len;
2159 return ret;
2162 /*************************************************************************
2163 * SHGetValueA [SHCORE.@]
2165 DWORD WINAPI SHGetValueA(HKEY hkey, const char *subkey, const char *value,
2166 DWORD *type, void *data, DWORD *data_len)
2168 HKEY hsubkey = 0;
2169 DWORD ret = 0;
2171 TRACE("(%p, %s, %s, %p, %p, %p)\n", hkey, debugstr_a(subkey), debugstr_a(value),
2172 type, data, data_len);
2174 if (subkey)
2175 ret = RegOpenKeyExA(hkey, subkey, 0, KEY_QUERY_VALUE, &hsubkey);
2177 if (!ret)
2179 ret = SHQueryValueExA(hsubkey ? hsubkey : hkey, value, 0, type, data, data_len);
2180 if (subkey)
2181 RegCloseKey(hsubkey);
2184 return ret;
2187 /*************************************************************************
2188 * SHGetValueW [SHCORE.@]
2190 DWORD WINAPI SHGetValueW(HKEY hkey, const WCHAR *subkey, const WCHAR *value,
2191 DWORD *type, void *data, DWORD *data_len)
2193 HKEY hsubkey = 0;
2194 DWORD ret = 0;
2196 TRACE("(%p, %s, %s, %p, %p, %p)\n", hkey, debugstr_w(subkey), debugstr_w(value),
2197 type, data, data_len);
2199 if (subkey)
2200 ret = RegOpenKeyExW(hkey, subkey, 0, KEY_QUERY_VALUE, &hsubkey);
2202 if (!ret)
2204 ret = SHQueryValueExW(hsubkey ? hsubkey : hkey, value, 0, type, data, data_len);
2205 if (subkey)
2206 RegCloseKey(hsubkey);
2209 return ret;
2212 /*************************************************************************
2213 * SHRegGetIntW [SHCORE.280]
2215 int WINAPI SHRegGetIntW(HKEY hkey, const WCHAR *value, int default_value)
2217 WCHAR buff[32];
2218 DWORD buff_len;
2220 TRACE("(%p, %s, %d)\n", hkey, debugstr_w(value), default_value);
2222 buff[0] = 0;
2223 buff_len = sizeof(buff);
2224 if (SHQueryValueExW(hkey, value, 0, 0, buff, &buff_len))
2225 return default_value;
2227 if (*buff >= '0' && *buff <= '9')
2228 return wcstol(buff, NULL, 10);
2230 return default_value;
2233 /*************************************************************************
2234 * SHRegGetPathA [SHCORE.@]
2236 DWORD WINAPI SHRegGetPathA(HKEY hkey, const char *subkey, const char *value, char *path, DWORD flags)
2238 DWORD length = MAX_PATH;
2240 TRACE("(%p, %s, %s, %p, %#x)\n", hkey, debugstr_a(subkey), debugstr_a(value), path, flags);
2242 return SHGetValueA(hkey, subkey, value, 0, path, &length);
2245 /*************************************************************************
2246 * SHRegGetPathW [SHCORE.@]
2248 DWORD WINAPI SHRegGetPathW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, WCHAR *path, DWORD flags)
2250 DWORD length = MAX_PATH;
2252 TRACE("(%p, %s, %s, %p, %d)\n", hkey, debugstr_w(subkey), debugstr_w(value), path, flags);
2254 return SHGetValueW(hkey, subkey, value, 0, path, &length);
2257 /*************************************************************************
2258 * SHSetValueW [SHCORE.@]
2260 DWORD WINAPI SHSetValueW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, DWORD type,
2261 const void *data, DWORD data_len)
2263 DWORD ret = ERROR_SUCCESS, dummy;
2264 HKEY hsubkey;
2266 TRACE("(%p, %s, %s, %d, %p, %d)\n", hkey, debugstr_w(subkey), debugstr_w(value),
2267 type, data, data_len);
2269 if (subkey && *subkey)
2270 ret = RegCreateKeyExW(hkey, subkey, 0, NULL, 0, KEY_SET_VALUE, NULL, &hsubkey, &dummy);
2271 else
2272 hsubkey = hkey;
2274 if (!ret)
2276 ret = RegSetValueExW(hsubkey, value, 0, type, data, data_len);
2277 if (hsubkey != hkey)
2278 RegCloseKey(hsubkey);
2281 return ret;
2284 /*************************************************************************
2285 * SHSetValueA [SHCORE.@]
2287 DWORD WINAPI SHSetValueA(HKEY hkey, const char *subkey, const char *value,
2288 DWORD type, const void *data, DWORD data_len)
2290 DWORD ret = ERROR_SUCCESS, dummy;
2291 HKEY hsubkey;
2293 TRACE("(%p, %s, %s, %d, %p, %d)\n", hkey, debugstr_a(subkey), debugstr_a(value),
2294 type, data, data_len);
2296 if (subkey && *subkey)
2297 ret = RegCreateKeyExA(hkey, subkey, 0, NULL, 0, KEY_SET_VALUE, NULL, &hsubkey, &dummy);
2298 else
2299 hsubkey = hkey;
2301 if (!ret)
2303 ret = RegSetValueExA(hsubkey, value, 0, type, data, data_len);
2304 if (hsubkey != hkey)
2305 RegCloseKey(hsubkey);
2308 return ret;
2311 /*************************************************************************
2312 * SHRegSetPathA [SHCORE.@]
2314 DWORD WINAPI SHRegSetPathA(HKEY hkey, const char *subkey, const char *value, const char *path, DWORD flags)
2316 FIXME("(%p, %s, %s, %s, %#x) - semi-stub\n", hkey, debugstr_a(subkey),
2317 debugstr_a(value), debugstr_a(path), flags);
2319 /* FIXME: PathUnExpandEnvStringsA() */
2321 return SHSetValueA(hkey, subkey, value, REG_SZ, path, lstrlenA(path));
2324 /*************************************************************************
2325 * SHRegSetPathW [SHCORE.@]
2327 DWORD WINAPI SHRegSetPathW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, const WCHAR *path, DWORD flags)
2329 FIXME("(%p, %s, %s, %s, %#x) - semi-stub\n", hkey, debugstr_w(subkey),
2330 debugstr_w(value), debugstr_w(path), flags);
2332 /* FIXME: PathUnExpandEnvStringsW(); */
2334 return SHSetValueW(hkey, subkey, value, REG_SZ, path, lstrlenW(path));
2337 /*************************************************************************
2338 * SHQueryInfoKeyA [SHCORE.@]
2340 LONG WINAPI SHQueryInfoKeyA(HKEY hkey, DWORD *subkeys, DWORD *subkey_max, DWORD *values, DWORD *value_max)
2342 TRACE("(%p, %p, %p, %p, %p)\n", hkey, subkeys, subkey_max, values, value_max);
2344 return RegQueryInfoKeyA(hkey, NULL, NULL, NULL, subkeys, subkey_max, NULL, values, value_max, NULL, NULL, NULL);
2347 /*************************************************************************
2348 * SHQueryInfoKeyW [SHCORE.@]
2350 LONG WINAPI SHQueryInfoKeyW(HKEY hkey, DWORD *subkeys, DWORD *subkey_max, DWORD *values, DWORD *value_max)
2352 TRACE("(%p, %p, %p, %p, %p)\n", hkey, subkeys, subkey_max, values, value_max);
2354 return RegQueryInfoKeyW(hkey, NULL, NULL, NULL, subkeys, subkey_max, NULL, values, value_max, NULL, NULL, NULL);
2357 /*************************************************************************
2358 * IsOS [SHCORE.@]
2360 BOOL WINAPI IsOS(DWORD feature)
2362 DWORD platform, majorv, minorv;
2363 OSVERSIONINFOA osvi;
2365 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
2366 if (!GetVersionExA(&osvi))
2367 return FALSE;
2369 majorv = osvi.dwMajorVersion;
2370 minorv = osvi.dwMinorVersion;
2371 platform = osvi.dwPlatformId;
2373 #define ISOS_RETURN(x) \
2374 TRACE("(0x%x) ret=%d\n",feature,(x)); \
2375 return (x)
2377 switch(feature) {
2378 case OS_WIN32SORGREATER:
2379 ISOS_RETURN(platform == VER_PLATFORM_WIN32s
2380 || platform == VER_PLATFORM_WIN32_WINDOWS);
2381 case OS_NT:
2382 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2383 case OS_WIN95ORGREATER:
2384 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS);
2385 case OS_NT4ORGREATER:
2386 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 4);
2387 case OS_WIN2000ORGREATER_ALT:
2388 case OS_WIN2000ORGREATER:
2389 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5);
2390 case OS_WIN98ORGREATER:
2391 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 10);
2392 case OS_WIN98_GOLD:
2393 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 10);
2394 case OS_WIN2000PRO:
2395 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5);
2396 case OS_WIN2000SERVER:
2397 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2398 case OS_WIN2000ADVSERVER:
2399 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2400 case OS_WIN2000DATACENTER:
2401 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2402 case OS_WIN2000TERMINAL:
2403 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2404 case OS_EMBEDDED:
2405 FIXME("(OS_EMBEDDED) What should we return here?\n");
2406 return FALSE;
2407 case OS_TERMINALCLIENT:
2408 FIXME("(OS_TERMINALCLIENT) What should we return here?\n");
2409 return FALSE;
2410 case OS_TERMINALREMOTEADMIN:
2411 FIXME("(OS_TERMINALREMOTEADMIN) What should we return here?\n");
2412 return FALSE;
2413 case OS_WIN95_GOLD:
2414 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 0);
2415 case OS_MEORGREATER:
2416 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 90);
2417 case OS_XPORGREATER:
2418 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1);
2419 case OS_HOME:
2420 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1);
2421 case OS_PROFESSIONAL:
2422 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2423 case OS_DATACENTER:
2424 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2425 case OS_ADVSERVER:
2426 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5);
2427 case OS_SERVER:
2428 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2429 case OS_TERMINALSERVER:
2430 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2431 case OS_PERSONALTERMINALSERVER:
2432 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && minorv >= 1 && majorv >= 5);
2433 case OS_FASTUSERSWITCHING:
2434 FIXME("(OS_FASTUSERSWITCHING) What should we return here?\n");
2435 return TRUE;
2436 case OS_WELCOMELOGONUI:
2437 FIXME("(OS_WELCOMELOGONUI) What should we return here?\n");
2438 return FALSE;
2439 case OS_DOMAINMEMBER:
2440 FIXME("(OS_DOMAINMEMBER) What should we return here?\n");
2441 return TRUE;
2442 case OS_ANYSERVER:
2443 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2444 case OS_WOW6432:
2446 BOOL is_wow64;
2447 IsWow64Process(GetCurrentProcess(), &is_wow64);
2448 return is_wow64;
2450 case OS_WEBSERVER:
2451 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2452 case OS_SMALLBUSINESSSERVER:
2453 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2454 case OS_TABLETPC:
2455 FIXME("(OS_TABLETPC) What should we return here?\n");
2456 return FALSE;
2457 case OS_SERVERADMINUI:
2458 FIXME("(OS_SERVERADMINUI) What should we return here?\n");
2459 return FALSE;
2460 case OS_MEDIACENTER:
2461 FIXME("(OS_MEDIACENTER) What should we return here?\n");
2462 return FALSE;
2463 case OS_APPLIANCE:
2464 FIXME("(OS_APPLIANCE) What should we return here?\n");
2465 return FALSE;
2466 case 0x25: /*OS_VISTAORGREATER*/
2467 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 6);
2470 #undef ISOS_RETURN
2472 WARN("(0x%x) unknown parameter\n", feature);
2474 return FALSE;