conhost: Use more standard hide cursor sequence.
[wine.git] / dlls / shcore / main.c
blob32649cccd9c8114e8c8015310b22d781b52b9aa1
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) || IsEqualIID(riid, &IID_IStream))
560 *out = iface;
561 IStream_AddRef(iface);
562 return S_OK;
565 *out = NULL;
566 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
567 return E_NOINTERFACE;
570 static ULONG WINAPI shstream_AddRef(IStream *iface)
572 struct shstream *stream = impl_from_IStream(iface);
573 ULONG refcount = InterlockedIncrement(&stream->refcount);
575 TRACE("(%p)->(%u)\n", stream, refcount);
577 return refcount;
580 static ULONG WINAPI memstream_Release(IStream *iface)
582 struct shstream *stream = impl_from_IStream(iface);
583 ULONG refcount = InterlockedDecrement(&stream->refcount);
585 TRACE("(%p)->(%u)\n", stream, refcount);
587 if (!refcount)
589 heap_free(stream->u.mem.buffer);
590 heap_free(stream);
593 return refcount;
596 static HRESULT WINAPI memstream_Read(IStream *iface, void *buff, ULONG buff_size, ULONG *read_len)
598 struct shstream *stream = impl_from_IStream(iface);
599 DWORD length;
601 TRACE("(%p)->(%p, %u, %p)\n", stream, buff, buff_size, read_len);
603 if (stream->u.mem.position >= stream->u.mem.length)
604 length = 0;
605 else
606 length = stream->u.mem.length - stream->u.mem.position;
608 length = buff_size > length ? length : buff_size;
609 if (length != 0) /* not at end of buffer and we want to read something */
611 memmove(buff, stream->u.mem.buffer + stream->u.mem.position, length);
612 stream->u.mem.position += length; /* adjust pointer */
615 if (read_len)
616 *read_len = length;
618 return S_OK;
621 static HRESULT WINAPI memstream_Write(IStream *iface, const void *buff, ULONG buff_size, ULONG *written)
623 struct shstream *stream = impl_from_IStream(iface);
624 DWORD length = stream->u.mem.position + buff_size;
626 TRACE("(%p)->(%p, %u, %p)\n", stream, buff, buff_size, written);
628 if (length < stream->u.mem.position) /* overflow */
629 return STG_E_INSUFFICIENTMEMORY;
631 if (length > stream->u.mem.length)
633 BYTE *buffer = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, stream->u.mem.buffer, length);
634 if (!buffer)
635 return STG_E_INSUFFICIENTMEMORY;
637 stream->u.mem.length = length;
638 stream->u.mem.buffer = buffer;
640 memmove(stream->u.mem.buffer + stream->u.mem.position, buff, buff_size);
641 stream->u.mem.position += buff_size; /* adjust pointer */
643 if (written)
644 *written = buff_size;
646 return S_OK;
649 static HRESULT WINAPI memstream_Seek(IStream *iface, LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER*new_pos)
651 struct shstream *stream = impl_from_IStream(iface);
652 LARGE_INTEGER tmp;
654 TRACE("(%p)->(%s, %d, %p)\n", stream, wine_dbgstr_longlong(move.QuadPart), origin, new_pos);
656 if (origin == STREAM_SEEK_SET)
657 tmp = move;
658 else if (origin == STREAM_SEEK_CUR)
659 tmp.QuadPart = stream->u.mem.position + move.QuadPart;
660 else if (origin == STREAM_SEEK_END)
661 tmp.QuadPart = stream->u.mem.length + move.QuadPart;
662 else
663 return STG_E_INVALIDPARAMETER;
665 if (tmp.QuadPart < 0)
666 return STG_E_INVALIDFUNCTION;
668 /* we cut off the high part here */
669 stream->u.mem.position = tmp.u.LowPart;
671 if (new_pos)
672 new_pos->QuadPart = stream->u.mem.position;
673 return S_OK;
676 static HRESULT WINAPI memstream_SetSize(IStream *iface, ULARGE_INTEGER new_size)
678 struct shstream *stream = impl_from_IStream(iface);
679 DWORD length;
680 BYTE *buffer;
682 TRACE("(%p, %s)\n", stream, wine_dbgstr_longlong(new_size.QuadPart));
684 /* we cut off the high part here */
685 length = new_size.u.LowPart;
686 buffer = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, stream->u.mem.buffer, length);
687 if (!buffer)
688 return STG_E_INSUFFICIENTMEMORY;
690 stream->u.mem.buffer = buffer;
691 stream->u.mem.length = length;
693 return S_OK;
696 static HRESULT WINAPI shstream_CopyTo(IStream *iface, IStream *pstm, ULARGE_INTEGER size, ULARGE_INTEGER *read_len, ULARGE_INTEGER *written)
698 struct shstream *stream = impl_from_IStream(iface);
700 TRACE("(%p)\n", stream);
702 if (read_len)
703 read_len->QuadPart = 0;
705 if (written)
706 written->QuadPart = 0;
708 /* TODO implement */
709 return E_NOTIMPL;
712 static HRESULT WINAPI shstream_Commit(IStream *iface, DWORD flags)
714 struct shstream *stream = impl_from_IStream(iface);
716 TRACE("(%p, %#x)\n", stream, flags);
718 /* Commit is not supported by this stream */
719 return E_NOTIMPL;
722 static HRESULT WINAPI shstream_Revert(IStream *iface)
724 struct shstream *stream = impl_from_IStream(iface);
726 TRACE("(%p)\n", stream);
728 /* revert not supported by this stream */
729 return E_NOTIMPL;
732 static HRESULT WINAPI shstream_LockRegion(IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER size, DWORD lock_type)
734 struct shstream *stream = impl_from_IStream(iface);
736 TRACE("(%p)\n", stream);
738 /* lock/unlock not supported by this stream */
739 return E_NOTIMPL;
742 static HRESULT WINAPI shstream_UnlockRegion(IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER size, DWORD lock_type)
744 struct shstream *stream = impl_from_IStream(iface);
746 TRACE("(%p)\n", stream);
748 /* lock/unlock not supported by this stream */
749 return E_NOTIMPL;
752 static HRESULT WINAPI memstream_Stat(IStream *iface, STATSTG *statstg, DWORD flags)
754 struct shstream *stream = impl_from_IStream(iface);
756 TRACE("(%p, %p, %#x)\n", stream, statstg, flags);
758 memset(statstg, 0, sizeof(*statstg));
759 statstg->type = STGTY_STREAM;
760 statstg->cbSize.QuadPart = stream->u.mem.length;
761 statstg->grfMode = STGM_READWRITE;
763 return S_OK;
766 static HRESULT WINAPI shstream_Clone(IStream *iface, IStream **dest)
768 struct shstream *stream = impl_from_IStream(iface);
770 TRACE("(%p, %p)\n", stream, dest);
772 *dest = NULL;
774 /* clone not supported by this stream */
775 return E_NOTIMPL;
778 static const IStreamVtbl memstreamvtbl =
780 shstream_QueryInterface,
781 shstream_AddRef,
782 memstream_Release,
783 memstream_Read,
784 memstream_Write,
785 memstream_Seek,
786 memstream_SetSize,
787 shstream_CopyTo,
788 shstream_Commit,
789 shstream_Revert,
790 shstream_LockRegion,
791 shstream_UnlockRegion,
792 memstream_Stat,
793 shstream_Clone,
796 static struct shstream *shstream_create(const IStreamVtbl *vtbl, const BYTE *data, UINT data_len)
798 struct shstream *stream;
800 if (!data)
801 data_len = 0;
803 stream = heap_alloc(sizeof(*stream));
804 stream->IStream_iface.lpVtbl = vtbl;
805 stream->refcount = 1;
806 stream->u.mem.buffer = heap_alloc(data_len);
807 if (!stream->u.mem.buffer)
809 heap_free(stream);
810 return NULL;
812 memcpy(stream->u.mem.buffer, data, data_len);
813 stream->u.mem.length = data_len;
814 stream->u.mem.position = 0;
816 return stream;
819 /*************************************************************************
820 * SHCreateMemStream [SHCORE.@]
822 * Create an IStream object on a block of memory.
824 * PARAMS
825 * data [I] Memory block to create the IStream object on
826 * data_len [I] Length of data block
828 * RETURNS
829 * Success: A pointer to the IStream object.
830 * Failure: NULL, if any parameters are invalid or an error occurs.
832 * NOTES
833 * A copy of the memory block is made, it's freed when the stream is released.
835 IStream * WINAPI SHCreateMemStream(const BYTE *data, UINT data_len)
837 struct shstream *stream;
839 TRACE("(%p, %u)\n", data, data_len);
841 stream = shstream_create(&memstreamvtbl, data, data_len);
842 return stream ? &stream->IStream_iface : NULL;
845 static ULONG WINAPI filestream_Release(IStream *iface)
847 struct shstream *stream = impl_from_IStream(iface);
848 ULONG refcount = InterlockedDecrement(&stream->refcount);
850 TRACE("(%p)->(%u)\n", stream, refcount);
852 if (!refcount)
854 CloseHandle(stream->u.file.handle);
855 heap_free(stream->u.file.path);
856 heap_free(stream);
859 return refcount;
862 static HRESULT WINAPI filestream_Read(IStream *iface, void *buff, ULONG size, ULONG *read_len)
864 struct shstream *stream = impl_from_IStream(iface);
865 DWORD read = 0;
867 TRACE("(%p, %p, %u, %p)\n", stream, buff, size, read_len);
869 if (!ReadFile(stream->u.file.handle, buff, size, &read, NULL))
871 WARN("error %d reading file\n", GetLastError());
872 return S_FALSE;
875 if (read_len)
876 *read_len = read;
878 return read == size ? S_OK : S_FALSE;
881 static HRESULT WINAPI filestream_Write(IStream *iface, const void *buff, ULONG size, ULONG *written)
883 struct shstream *stream = impl_from_IStream(iface);
884 DWORD written_len = 0;
886 TRACE("(%p, %p, %u, %p)\n", stream, buff, size, written);
888 switch (stream->u.file.mode & 0xf)
890 case STGM_WRITE:
891 case STGM_READWRITE:
892 break;
893 default:
894 return STG_E_ACCESSDENIED;
897 if (!WriteFile(stream->u.file.handle, buff, size, &written_len, NULL))
898 return HRESULT_FROM_WIN32(GetLastError());
900 if (written)
901 *written = written_len;
903 return S_OK;
906 static HRESULT WINAPI filestream_Seek(IStream *iface, LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER *new_pos)
908 struct shstream *stream = impl_from_IStream(iface);
909 DWORD position;
911 TRACE("(%p, %s, %d, %p)\n", stream, wine_dbgstr_longlong(move.QuadPart), origin, new_pos);
913 position = SetFilePointer(stream->u.file.handle, move.u.LowPart, NULL, origin);
914 if (position == INVALID_SET_FILE_POINTER)
915 return HRESULT_FROM_WIN32(GetLastError());
917 if (new_pos)
919 new_pos->u.HighPart = 0;
920 new_pos->u.LowPart = position;
923 return S_OK;
926 static HRESULT WINAPI filestream_SetSize(IStream *iface, ULARGE_INTEGER size)
928 struct shstream *stream = impl_from_IStream(iface);
929 LARGE_INTEGER origin, move;
931 TRACE("(%p, %s)\n", stream, wine_dbgstr_longlong(size.QuadPart));
933 move.QuadPart = 0;
934 if (!SetFilePointerEx(stream->u.file.handle, move, &origin, FILE_CURRENT))
935 return E_FAIL;
937 move.QuadPart = size.QuadPart;
938 if (!SetFilePointerEx(stream->u.file.handle, move, NULL, FILE_BEGIN))
939 return E_FAIL;
941 if (stream->u.file.mode != STGM_READ)
943 if (!SetEndOfFile(stream->u.file.handle))
944 return E_FAIL;
945 if (!SetFilePointerEx(stream->u.file.handle, origin, NULL, FILE_BEGIN))
946 return E_FAIL;
949 return S_OK;
952 static HRESULT WINAPI filestream_CopyTo(IStream *iface, IStream *dest, ULARGE_INTEGER size,
953 ULARGE_INTEGER *read_len, ULARGE_INTEGER *written)
955 struct shstream *stream = impl_from_IStream(iface);
956 HRESULT hr = S_OK;
957 char buff[1024];
959 TRACE("(%p, %p, %s, %p, %p)\n", stream, dest, wine_dbgstr_longlong(size.QuadPart), read_len, written);
961 if (read_len)
962 read_len->QuadPart = 0;
963 if (written)
964 written->QuadPart = 0;
966 if (!dest)
967 return S_OK;
969 while (size.QuadPart)
971 ULONG left, read_chunk, written_chunk;
973 left = size.QuadPart > sizeof(buff) ? sizeof(buff) : size.QuadPart;
975 /* Read */
976 hr = IStream_Read(iface, buff, left, &read_chunk);
977 if (FAILED(hr) || read_chunk == 0)
978 break;
979 if (read_len)
980 read_len->QuadPart += read_chunk;
982 /* Write */
983 hr = IStream_Write(dest, buff, read_chunk, &written_chunk);
984 if (written_chunk)
985 written->QuadPart += written_chunk;
986 if (FAILED(hr) || written_chunk != left)
987 break;
989 size.QuadPart -= left;
992 return hr;
995 static HRESULT WINAPI filestream_Commit(IStream *iface, DWORD flags)
997 struct shstream *stream = impl_from_IStream(iface);
999 TRACE("(%p, %#x)\n", stream, flags);
1001 return S_OK;
1004 static HRESULT WINAPI filestream_Stat(IStream *iface, STATSTG *statstg, DWORD flags)
1006 struct shstream *stream = impl_from_IStream(iface);
1007 BY_HANDLE_FILE_INFORMATION fi;
1009 TRACE("(%p, %p, %#x)\n", stream, statstg, flags);
1011 if (!statstg)
1012 return STG_E_INVALIDPOINTER;
1014 memset(&fi, 0, sizeof(fi));
1015 GetFileInformationByHandle(stream->u.file.handle, &fi);
1017 if (flags & STATFLAG_NONAME)
1018 statstg->pwcsName = NULL;
1019 else
1021 int len = lstrlenW(stream->u.file.path);
1022 if ((statstg->pwcsName = CoTaskMemAlloc((len + 1) * sizeof(WCHAR))))
1023 memcpy(statstg->pwcsName, stream->u.file.path, (len + 1) * sizeof(WCHAR));
1025 statstg->type = 0;
1026 statstg->cbSize.u.LowPart = fi.nFileSizeLow;
1027 statstg->cbSize.u.HighPart = fi.nFileSizeHigh;
1028 statstg->mtime = fi.ftLastWriteTime;
1029 statstg->ctime = fi.ftCreationTime;
1030 statstg->atime = fi.ftLastAccessTime;
1031 statstg->grfMode = stream->u.file.mode;
1032 statstg->grfLocksSupported = 0;
1033 memcpy(&statstg->clsid, &IID_IStream, sizeof(CLSID));
1034 statstg->grfStateBits = 0;
1035 statstg->reserved = 0;
1037 return S_OK;
1040 static const IStreamVtbl filestreamvtbl =
1042 shstream_QueryInterface,
1043 shstream_AddRef,
1044 filestream_Release,
1045 filestream_Read,
1046 filestream_Write,
1047 filestream_Seek,
1048 filestream_SetSize,
1049 filestream_CopyTo,
1050 filestream_Commit,
1051 shstream_Revert,
1052 shstream_LockRegion,
1053 shstream_UnlockRegion,
1054 filestream_Stat,
1055 shstream_Clone,
1058 /*************************************************************************
1059 * SHCreateStreamOnFileEx [SHCORE.@]
1061 HRESULT WINAPI SHCreateStreamOnFileEx(const WCHAR *path, DWORD mode, DWORD attributes,
1062 BOOL create, IStream *template, IStream **ret)
1064 DWORD access, share, creation_disposition, len;
1065 struct shstream *stream;
1066 HANDLE hFile;
1068 TRACE("(%s, %d, 0x%08X, %d, %p, %p)\n", debugstr_w(path), mode, attributes,
1069 create, template, ret);
1071 if (!path || !ret || template)
1072 return E_INVALIDARG;
1074 *ret = NULL;
1076 /* Access */
1077 switch (mode & 0xf)
1079 case STGM_WRITE:
1080 case STGM_READWRITE:
1081 access = GENERIC_READ | GENERIC_WRITE;
1082 break;
1083 case STGM_READ:
1084 access = GENERIC_READ;
1085 break;
1086 default:
1087 return E_INVALIDARG;
1090 /* Sharing */
1091 switch (mode & 0xf0)
1093 case 0:
1094 case STGM_SHARE_DENY_NONE:
1095 share = FILE_SHARE_READ | FILE_SHARE_WRITE;
1096 break;
1097 case STGM_SHARE_DENY_READ:
1098 share = FILE_SHARE_WRITE;
1099 break;
1100 case STGM_SHARE_DENY_WRITE:
1101 share = FILE_SHARE_READ;
1102 break;
1103 case STGM_SHARE_EXCLUSIVE:
1104 share = 0;
1105 break;
1106 default:
1107 return E_INVALIDARG;
1110 switch (mode & 0xf000)
1112 case STGM_FAILIFTHERE:
1113 creation_disposition = create ? CREATE_NEW : OPEN_EXISTING;
1114 break;
1115 case STGM_CREATE:
1116 creation_disposition = CREATE_ALWAYS;
1117 break;
1118 default:
1119 return E_INVALIDARG;
1122 hFile = CreateFileW(path, access, share, NULL, creation_disposition, attributes, 0);
1123 if (hFile == INVALID_HANDLE_VALUE)
1124 return HRESULT_FROM_WIN32(GetLastError());
1126 stream = heap_alloc(sizeof(*stream));
1127 stream->IStream_iface.lpVtbl = &filestreamvtbl;
1128 stream->refcount = 1;
1129 stream->u.file.handle = hFile;
1130 stream->u.file.mode = mode;
1132 len = lstrlenW(path);
1133 stream->u.file.path = heap_alloc((len + 1) * sizeof(WCHAR));
1134 memcpy(stream->u.file.path, path, (len + 1) * sizeof(WCHAR));
1136 *ret = &stream->IStream_iface;
1138 return S_OK;
1141 /*************************************************************************
1142 * SHCreateStreamOnFileW [SHCORE.@]
1144 HRESULT WINAPI SHCreateStreamOnFileW(const WCHAR *path, DWORD mode, IStream **stream)
1146 TRACE("(%s, %#x, %p)\n", debugstr_w(path), mode, stream);
1148 if (!path || !stream)
1149 return E_INVALIDARG;
1151 if ((mode & (STGM_CONVERT | STGM_DELETEONRELEASE | STGM_TRANSACTED)) != 0)
1152 return E_INVALIDARG;
1154 return SHCreateStreamOnFileEx(path, mode, 0, FALSE, NULL, stream);
1157 /*************************************************************************
1158 * SHCreateStreamOnFileA [SHCORE.@]
1160 HRESULT WINAPI SHCreateStreamOnFileA(const char *path, DWORD mode, IStream **stream)
1162 WCHAR *pathW;
1163 HRESULT hr;
1164 DWORD len;
1166 TRACE("(%s, %#x, %p)\n", debugstr_a(path), mode, stream);
1168 if (!path)
1169 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1171 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1172 pathW = heap_alloc(len * sizeof(WCHAR));
1173 if (!pathW)
1174 return E_OUTOFMEMORY;
1176 MultiByteToWideChar(CP_ACP, 0, path, -1, pathW, len);
1177 hr = SHCreateStreamOnFileW(pathW, mode, stream);
1178 heap_free(pathW);
1180 return hr;
1183 static ULONG WINAPI regstream_Release(IStream *iface)
1185 struct shstream *stream = impl_from_IStream(iface);
1186 ULONG refcount = InterlockedDecrement(&stream->refcount);
1188 TRACE("(%p)->(%u)\n", stream, refcount);
1190 if (!refcount)
1192 if (stream->u.mem.hkey)
1194 if (stream->u.mem.length)
1195 RegSetValueExW(stream->u.mem.hkey, stream->u.mem.valuename, 0, REG_BINARY,
1196 (const BYTE *)stream->u.mem.buffer, stream->u.mem.length);
1197 else
1198 RegDeleteValueW(stream->u.mem.hkey, stream->u.mem.valuename);
1199 RegCloseKey(stream->u.mem.hkey);
1201 CoTaskMemFree(stream->u.mem.valuename);
1202 heap_free(stream->u.mem.buffer);
1203 heap_free(stream);
1206 return refcount;
1209 static const IStreamVtbl regstreamvtbl =
1211 shstream_QueryInterface,
1212 shstream_AddRef,
1213 regstream_Release,
1214 memstream_Read,
1215 memstream_Write,
1216 memstream_Seek,
1217 memstream_SetSize,
1218 shstream_CopyTo,
1219 shstream_Commit,
1220 shstream_Revert,
1221 shstream_LockRegion,
1222 shstream_UnlockRegion,
1223 memstream_Stat,
1224 shstream_Clone,
1227 /*************************************************************************
1228 * SHOpenRegStream2W [SHCORE.@]
1230 IStream * WINAPI SHOpenRegStream2W(HKEY hKey, const WCHAR *subkey, const WCHAR *value, DWORD mode)
1232 struct shstream *stream;
1233 HKEY hStrKey = NULL;
1234 BYTE *buff = NULL;
1235 DWORD length = 0;
1236 LONG ret;
1238 TRACE("(%p, %s, %s, %#x)\n", hKey, debugstr_w(subkey), debugstr_w(value), mode);
1240 if (mode == STGM_READ)
1241 ret = RegOpenKeyExW(hKey, subkey, 0, KEY_READ, &hStrKey);
1242 else /* in write mode we make sure the subkey exits */
1243 ret = RegCreateKeyExW(hKey, subkey, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &hStrKey, NULL);
1245 if (ret == ERROR_SUCCESS)
1247 if (mode == STGM_READ || mode == STGM_READWRITE)
1249 /* read initial data */
1250 ret = RegQueryValueExW(hStrKey, value, 0, 0, 0, &length);
1251 if (ret == ERROR_SUCCESS && length)
1253 buff = heap_alloc(length);
1254 RegQueryValueExW(hStrKey, value, 0, 0, buff, &length);
1258 if (!length)
1259 buff = heap_alloc(length);
1261 stream = shstream_create(&regstreamvtbl, buff, length);
1262 heap_free(buff);
1263 if (stream)
1265 stream->u.mem.hkey = hStrKey;
1266 SHStrDupW(value, &stream->u.mem.valuename);
1267 return &stream->IStream_iface;
1271 if (hStrKey)
1272 RegCloseKey(hStrKey);
1274 return NULL;
1277 /*************************************************************************
1278 * SHOpenRegStream2A [SHCORE.@]
1280 IStream * WINAPI SHOpenRegStream2A(HKEY hKey, const char *subkey, const char *value, DWORD mode)
1282 WCHAR *subkeyW = NULL, *valueW = NULL;
1283 IStream *stream;
1285 TRACE("(%p, %s, %s, %#x)\n", hKey, debugstr_a(subkey), debugstr_a(value), mode);
1287 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1288 return NULL;
1289 if (value && FAILED(SHStrDupA(value, &valueW)))
1291 CoTaskMemFree(subkeyW);
1292 return NULL;
1295 stream = SHOpenRegStream2W(hKey, subkeyW, valueW, mode);
1296 CoTaskMemFree(subkeyW);
1297 CoTaskMemFree(valueW);
1298 return stream;
1301 /*************************************************************************
1302 * SHOpenRegStreamA [SHCORE.@]
1304 IStream * WINAPI SHOpenRegStreamA(HKEY hkey, const char *subkey, const char *value, DWORD mode)
1306 WCHAR *subkeyW = NULL, *valueW = NULL;
1307 IStream *stream;
1309 TRACE("(%p, %s, %s, %#x)\n", hkey, debugstr_a(subkey), debugstr_a(value), mode);
1311 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1312 return NULL;
1313 if (value && FAILED(SHStrDupA(value, &valueW)))
1315 CoTaskMemFree(subkeyW);
1316 return NULL;
1319 stream = SHOpenRegStreamW(hkey, subkeyW, valueW, mode);
1320 CoTaskMemFree(subkeyW);
1321 CoTaskMemFree(valueW);
1322 return stream;
1325 static ULONG WINAPI dummystream_AddRef(IStream *iface)
1327 TRACE("()\n");
1328 return 2;
1331 static ULONG WINAPI dummystream_Release(IStream *iface)
1333 TRACE("()\n");
1334 return 1;
1337 static HRESULT WINAPI dummystream_Read(IStream *iface, void *buff, ULONG buff_size, ULONG *read_len)
1339 if (read_len)
1340 *read_len = 0;
1342 return E_NOTIMPL;
1345 static const IStreamVtbl dummystreamvtbl =
1347 shstream_QueryInterface,
1348 dummystream_AddRef,
1349 dummystream_Release,
1350 dummystream_Read,
1351 memstream_Write,
1352 memstream_Seek,
1353 memstream_SetSize,
1354 shstream_CopyTo,
1355 shstream_Commit,
1356 shstream_Revert,
1357 shstream_LockRegion,
1358 shstream_UnlockRegion,
1359 memstream_Stat,
1360 shstream_Clone,
1363 static struct shstream dummyregstream = { { &dummystreamvtbl } };
1365 /*************************************************************************
1366 * SHOpenRegStreamW [SHCORE.@]
1368 IStream * WINAPI SHOpenRegStreamW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, DWORD mode)
1370 IStream *stream;
1372 TRACE("(%p, %s, %s, %#x)\n", hkey, debugstr_w(subkey), debugstr_w(value), mode);
1373 stream = SHOpenRegStream2W(hkey, subkey, value, mode);
1374 return stream ? stream : &dummyregstream.IStream_iface;
1377 struct threadref
1379 IUnknown IUnknown_iface;
1380 LONG *refcount;
1383 static inline struct threadref *threadref_impl_from_IUnknown(IUnknown *iface)
1385 return CONTAINING_RECORD(iface, struct threadref, IUnknown_iface);
1388 static HRESULT WINAPI threadref_QueryInterface(IUnknown *iface, REFIID riid, void **out)
1390 struct threadref *threadref = threadref_impl_from_IUnknown(iface);
1392 TRACE("(%p, %s, %p)\n", threadref, debugstr_guid(riid), out);
1394 if (out == NULL)
1395 return E_POINTER;
1397 if (IsEqualGUID(&IID_IUnknown, riid))
1399 *out = iface;
1400 IUnknown_AddRef(iface);
1401 return S_OK;
1404 *out = NULL;
1405 WARN("Interface %s not supported.\n", debugstr_guid(riid));
1406 return E_NOINTERFACE;
1409 static ULONG WINAPI threadref_AddRef(IUnknown *iface)
1411 struct threadref *threadref = threadref_impl_from_IUnknown(iface);
1412 LONG refcount = InterlockedIncrement(threadref->refcount);
1414 TRACE("(%p, %d)\n", threadref, refcount);
1416 return refcount;
1419 static ULONG WINAPI threadref_Release(IUnknown *iface)
1421 struct threadref *threadref = threadref_impl_from_IUnknown(iface);
1422 LONG refcount = InterlockedDecrement(threadref->refcount);
1424 TRACE("(%p, %d)\n", threadref, refcount);
1426 if (!refcount)
1427 heap_free(threadref);
1429 return refcount;
1432 static const IUnknownVtbl threadrefvtbl =
1434 threadref_QueryInterface,
1435 threadref_AddRef,
1436 threadref_Release,
1439 /*************************************************************************
1440 * SHCreateThreadRef [SHCORE.@]
1442 HRESULT WINAPI SHCreateThreadRef(LONG *refcount, IUnknown **out)
1444 struct threadref *threadref;
1446 TRACE("(%p, %p)\n", refcount, out);
1448 if (!refcount || !out)
1449 return E_INVALIDARG;
1451 *out = NULL;
1453 threadref = heap_alloc(sizeof(*threadref));
1454 if (!threadref)
1455 return E_OUTOFMEMORY;
1456 threadref->IUnknown_iface.lpVtbl = &threadrefvtbl;
1457 threadref->refcount = refcount;
1459 *refcount = 1;
1460 *out = &threadref->IUnknown_iface;
1462 TRACE("Created %p.\n", threadref);
1463 return S_OK;
1466 /*************************************************************************
1467 * SHGetThreadRef [SHCORE.@]
1469 HRESULT WINAPI SHGetThreadRef(IUnknown **out)
1471 TRACE("(%p)\n", out);
1473 if (shcore_tls == TLS_OUT_OF_INDEXES)
1474 return E_NOINTERFACE;
1476 *out = TlsGetValue(shcore_tls);
1477 if (!*out)
1478 return E_NOINTERFACE;
1480 IUnknown_AddRef(*out);
1481 return S_OK;
1484 /*************************************************************************
1485 * SHSetThreadRef [SHCORE.@]
1487 HRESULT WINAPI SHSetThreadRef(IUnknown *obj)
1489 TRACE("(%p)\n", obj);
1491 if (shcore_tls == TLS_OUT_OF_INDEXES)
1492 return E_NOINTERFACE;
1494 TlsSetValue(shcore_tls, obj);
1495 return S_OK;
1498 /*************************************************************************
1499 * SHReleaseThreadRef [SHCORE.@]
1501 HRESULT WINAPI SHReleaseThreadRef(void)
1503 FIXME("() - stub!\n");
1504 return S_OK;
1507 /*************************************************************************
1508 * GetProcessReference [SHCORE.@]
1510 HRESULT WINAPI GetProcessReference(IUnknown **obj)
1512 TRACE("(%p)\n", obj);
1514 *obj = process_ref;
1516 if (!process_ref)
1517 return E_FAIL;
1519 if (*obj)
1520 IUnknown_AddRef(*obj);
1522 return S_OK;
1525 /*************************************************************************
1526 * SetProcessReference [SHCORE.@]
1528 void WINAPI SetProcessReference(IUnknown *obj)
1530 TRACE("(%p)\n", obj);
1532 process_ref = obj;
1535 struct thread_data
1537 LPTHREAD_START_ROUTINE thread_proc;
1538 LPTHREAD_START_ROUTINE callback;
1539 void *data;
1540 DWORD flags;
1541 HANDLE hEvent;
1542 IUnknown *thread_ref;
1543 IUnknown *process_ref;
1546 static DWORD WINAPI shcore_thread_wrapper(void *data)
1548 struct thread_data thread_data;
1549 HRESULT hr = E_FAIL;
1550 DWORD retval;
1552 TRACE("(%p)\n", data);
1554 /* We are now executing in the context of the newly created thread.
1555 * So we copy the data passed to us (it is on the stack of the function
1556 * that called us, which is waiting for us to signal an event before
1557 * returning). */
1558 thread_data = *(struct thread_data *)data;
1560 if (thread_data.flags & CTF_COINIT)
1562 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
1563 if (FAILED(hr))
1564 hr = CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE);
1567 if (thread_data.callback)
1568 thread_data.callback(thread_data.data);
1570 /* Signal the thread that created us; it can return now. */
1571 SetEvent(thread_data.hEvent);
1573 /* Execute the callers start code. */
1574 retval = thread_data.thread_proc(thread_data.data);
1576 /* Release thread and process references. */
1577 if (thread_data.thread_ref)
1578 IUnknown_Release(thread_data.thread_ref);
1580 if (thread_data.process_ref)
1581 IUnknown_Release(thread_data.process_ref);
1583 if (SUCCEEDED(hr))
1584 CoUninitialize();
1586 return retval;
1589 /*************************************************************************
1590 * SHCreateThread [SHCORE.@]
1592 BOOL WINAPI SHCreateThread(LPTHREAD_START_ROUTINE thread_proc, void *data, DWORD flags, LPTHREAD_START_ROUTINE callback)
1594 struct thread_data thread_data;
1595 BOOL called = FALSE;
1597 TRACE("(%p, %p, %#x, %p)\n", thread_proc, data, flags, callback);
1599 thread_data.thread_proc = thread_proc;
1600 thread_data.callback = callback;
1601 thread_data.data = data;
1602 thread_data.flags = flags;
1603 thread_data.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
1605 if (flags & CTF_THREAD_REF)
1606 SHGetThreadRef(&thread_data.thread_ref);
1607 else
1608 thread_data.thread_ref = NULL;
1610 if (flags & CTF_PROCESS_REF)
1611 GetProcessReference(&thread_data.process_ref);
1612 else
1613 thread_data.process_ref = NULL;
1615 /* Create the thread */
1616 if (thread_data.hEvent)
1618 HANDLE hThread;
1619 DWORD retval;
1621 hThread = CreateThread(NULL, 0, shcore_thread_wrapper, &thread_data, 0, &retval);
1622 if (hThread)
1624 /* Wait for the thread to signal us to continue */
1625 WaitForSingleObject(thread_data.hEvent, INFINITE);
1626 CloseHandle(hThread);
1627 called = TRUE;
1629 CloseHandle(thread_data.hEvent);
1632 if (!called)
1634 if (!thread_data.callback && flags & CTF_INSIST)
1636 /* Couldn't call, call synchronously */
1637 thread_data.thread_proc(data);
1638 called = TRUE;
1640 else
1642 if (thread_data.thread_ref)
1643 IUnknown_Release(thread_data.thread_ref);
1645 if (thread_data.process_ref)
1646 IUnknown_Release(thread_data.process_ref);
1650 return called;
1653 /*************************************************************************
1654 * SHStrDupW [SHCORE.@]
1656 HRESULT WINAPI SHStrDupW(const WCHAR *src, WCHAR **dest)
1658 size_t len;
1660 TRACE("(%s, %p)\n", debugstr_w(src), dest);
1662 *dest = NULL;
1664 if (!src)
1665 return E_INVALIDARG;
1667 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
1668 *dest = CoTaskMemAlloc(len);
1669 if (!*dest)
1670 return E_OUTOFMEMORY;
1672 memcpy(*dest, src, len);
1674 return S_OK;
1677 /*************************************************************************
1678 * SHStrDupA [SHCORE.@]
1680 HRESULT WINAPI SHStrDupA(const char *src, WCHAR **dest)
1682 DWORD len;
1684 *dest = NULL;
1686 if (!src)
1687 return E_INVALIDARG;
1689 len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
1690 *dest = CoTaskMemAlloc(len * sizeof(WCHAR));
1691 if (!*dest)
1692 return E_OUTOFMEMORY;
1694 MultiByteToWideChar(CP_ACP, 0, src, -1, *dest, len);
1696 return S_OK;
1699 /*************************************************************************
1700 * SHAnsiToAnsi [SHCORE.@]
1702 DWORD WINAPI SHAnsiToAnsi(const char *src, char *dest, int dest_len)
1704 DWORD ret;
1706 TRACE("(%s, %p, %d)\n", debugstr_a(src), dest, dest_len);
1708 if (!src || !dest || dest_len <= 0)
1709 return 0;
1711 lstrcpynA(dest, src, dest_len);
1712 ret = strlen(dest);
1714 return src[ret] ? 0 : ret + 1;
1717 /*************************************************************************
1718 * SHUnicodeToAnsi [SHCORE.@]
1720 DWORD WINAPI SHUnicodeToAnsi(const WCHAR *src, char *dest, int dest_len)
1722 int ret = 1;
1724 TRACE("(%s, %p, %d)\n", debugstr_w(src), dest, dest_len);
1726 if (!dest || !dest_len)
1727 return 0;
1729 if (src)
1731 ret = WideCharToMultiByte(CP_ACP, 0, src, -1, dest, dest_len, NULL, NULL);
1732 if (!ret)
1734 dest[dest_len - 1] = 0;
1735 ret = dest_len;
1738 else
1739 dest[0] = 0;
1741 return ret;
1744 /*************************************************************************
1745 * SHUnicodeToUnicode [SHCORE.@]
1747 DWORD WINAPI SHUnicodeToUnicode(const WCHAR *src, WCHAR *dest, int dest_len)
1749 DWORD ret;
1751 TRACE("(%s, %p, %d)\n", debugstr_w(src), dest, dest_len);
1753 if (!src || !dest || dest_len <= 0)
1754 return 0;
1756 lstrcpynW(dest, src, dest_len);
1757 ret = lstrlenW(dest);
1759 return src[ret] ? 0 : ret + 1;
1762 /*************************************************************************
1763 * SHAnsiToUnicode [SHCORE.@]
1765 DWORD WINAPI SHAnsiToUnicode(const char *src, WCHAR *dest, int dest_len)
1767 int ret = 1;
1769 TRACE("(%s, %p, %d)\n", debugstr_a(src), dest, dest_len);
1771 if (!dest || !dest_len)
1772 return 0;
1774 if (src)
1776 ret = MultiByteToWideChar(CP_ACP, 0, src, -1, dest, dest_len);
1777 if (!ret)
1779 dest[dest_len - 1] = 0;
1780 ret = dest_len;
1783 else
1784 dest[0] = 0;
1786 return ret;
1789 /*************************************************************************
1790 * SHRegDuplicateHKey [SHCORE.@]
1792 HKEY WINAPI SHRegDuplicateHKey(HKEY hKey)
1794 HKEY newKey = 0;
1796 RegOpenKeyExW(hKey, 0, 0, MAXIMUM_ALLOWED, &newKey);
1797 TRACE("new key is %p\n", newKey);
1798 return newKey;
1801 /*************************************************************************
1802 * SHDeleteEmptyKeyW [SHCORE.@]
1804 DWORD WINAPI SHDeleteEmptyKeyW(HKEY hkey, const WCHAR *subkey)
1806 DWORD ret, count = 0;
1807 HKEY hsubkey = 0;
1809 TRACE("(%p, %s)\n", hkey, debugstr_w(subkey));
1811 ret = RegOpenKeyExW(hkey, subkey, 0, KEY_READ, &hsubkey);
1812 if (!ret)
1814 ret = RegQueryInfoKeyW(hsubkey, NULL, NULL, NULL, &count,
1815 NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1816 RegCloseKey(hsubkey);
1817 if (!ret)
1819 if (count)
1820 ret = ERROR_KEY_HAS_CHILDREN;
1821 else
1822 ret = RegDeleteKeyW(hkey, subkey);
1826 return ret;
1829 /*************************************************************************
1830 * SHDeleteEmptyKeyA [SHCORE.@]
1832 DWORD WINAPI SHDeleteEmptyKeyA(HKEY hkey, const char *subkey)
1834 WCHAR *subkeyW = NULL;
1835 DWORD ret;
1837 TRACE("(%p, %s)\n", hkey, debugstr_a(subkey));
1839 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1840 return ERROR_OUTOFMEMORY;
1842 ret = SHDeleteEmptyKeyW(hkey, subkeyW);
1843 CoTaskMemFree(subkeyW);
1844 return ret;
1847 /*************************************************************************
1848 * SHDeleteKeyW [SHCORE.@]
1850 DWORD WINAPI SHDeleteKeyW(HKEY hkey, const WCHAR *subkey)
1852 TRACE("(%p, %s)\n", hkey, debugstr_w(subkey));
1854 return RegDeleteTreeW(hkey, subkey);
1857 /*************************************************************************
1858 * SHDeleteKeyA [SHCORE.@]
1860 DWORD WINAPI SHDeleteKeyA(HKEY hkey, const char *subkey)
1862 TRACE("(%p, %s)\n", hkey, debugstr_a(subkey));
1864 return RegDeleteTreeA(hkey, subkey);
1867 /*************************************************************************
1868 * SHDeleteValueW [SHCORE.@]
1870 DWORD WINAPI SHDeleteValueW(HKEY hkey, const WCHAR *subkey, const WCHAR *value)
1872 HKEY hsubkey;
1873 DWORD ret;
1875 TRACE("(%p, %s, %s)\n", hkey, debugstr_w(subkey), debugstr_w(value));
1877 ret = RegOpenKeyExW(hkey, subkey, 0, KEY_SET_VALUE, &hsubkey);
1878 if (!ret)
1880 ret = RegDeleteValueW(hsubkey, value);
1881 RegCloseKey(hsubkey);
1884 return ret;
1887 /*************************************************************************
1888 * SHDeleteValueA [SHCORE.@]
1890 DWORD WINAPI SHDeleteValueA(HKEY hkey, const char *subkey, const char *value)
1892 WCHAR *subkeyW = NULL, *valueW = NULL;
1893 DWORD ret;
1895 TRACE("(%p, %s, %s)\n", hkey, debugstr_a(subkey), debugstr_a(value));
1897 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1898 return ERROR_OUTOFMEMORY;
1899 if (value && FAILED(SHStrDupA(value, &valueW)))
1901 CoTaskMemFree(subkeyW);
1902 return ERROR_OUTOFMEMORY;
1905 ret = SHDeleteValueW(hkey, subkeyW, valueW);
1906 CoTaskMemFree(subkeyW);
1907 CoTaskMemFree(valueW);
1908 return ret;
1911 /*************************************************************************
1912 * SHCopyKeyA [SHCORE.@]
1914 DWORD WINAPI SHCopyKeyA(HKEY hkey_src, const char *subkey, HKEY hkey_dst, DWORD reserved)
1916 WCHAR *subkeyW = NULL;
1917 DWORD ret;
1919 TRACE("(%p, %s, %p, %d)\n", hkey_src, debugstr_a(subkey), hkey_dst, reserved);
1921 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1922 return 0;
1924 ret = SHCopyKeyW(hkey_src, subkeyW, hkey_dst, reserved);
1925 CoTaskMemFree(subkeyW);
1926 return ret;
1929 /*************************************************************************
1930 * SHCopyKeyW [SHCORE.@]
1932 DWORD WINAPI SHCopyKeyW(HKEY hkey_src, const WCHAR *subkey, HKEY hkey_dst, DWORD reserved)
1934 DWORD key_count = 0, value_count = 0, max_key_len = 0;
1935 WCHAR name[MAX_PATH], *ptr_name = name;
1936 BYTE buff[1024], *ptr = buff;
1937 DWORD max_data_len = 0, i;
1938 DWORD ret = 0;
1940 TRACE("(%p, %s, %p, %d)\n", hkey_src, debugstr_w(subkey), hkey_dst, reserved);
1942 if (!hkey_dst || !hkey_src)
1943 return ERROR_INVALID_PARAMETER;
1945 if (subkey)
1946 ret = RegOpenKeyExW(hkey_src, subkey, 0, KEY_ALL_ACCESS, &hkey_src);
1948 if (ret)
1949 hkey_src = NULL; /* Don't close this key since we didn't open it */
1950 else
1952 DWORD max_value_len;
1954 ret = RegQueryInfoKeyW(hkey_src, NULL, NULL, NULL, &key_count, &max_key_len,
1955 NULL, &value_count, &max_value_len, &max_data_len, NULL, NULL);
1956 if (!ret)
1958 /* Get max size for key/value names */
1959 max_key_len = max(max_key_len, max_value_len);
1961 if (max_key_len++ > MAX_PATH - 1)
1962 ptr_name = heap_alloc(max_key_len * sizeof(WCHAR));
1964 if (max_data_len > sizeof(buff))
1965 ptr = heap_alloc(max_data_len);
1967 if (!ptr_name || !ptr)
1968 ret = ERROR_NOT_ENOUGH_MEMORY;
1972 for (i = 0; i < key_count && !ret; i++)
1974 HKEY hsubkey_src, hsubkey_dst;
1975 DWORD length = max_key_len;
1977 ret = RegEnumKeyExW(hkey_src, i, ptr_name, &length, NULL, NULL, NULL, NULL);
1978 if (!ret)
1980 ret = RegOpenKeyExW(hkey_src, ptr_name, 0, KEY_READ, &hsubkey_src);
1981 if (!ret)
1983 /* Create destination sub key */
1984 ret = RegCreateKeyW(hkey_dst, ptr_name, &hsubkey_dst);
1985 if (!ret)
1987 /* Recursively copy keys and values from the sub key */
1988 ret = SHCopyKeyW(hsubkey_src, NULL, hsubkey_dst, 0);
1989 RegCloseKey(hsubkey_dst);
1992 RegCloseKey(hsubkey_src);
1996 /* Copy all the values in this key */
1997 for (i = 0; i < value_count && !ret; i++)
1999 DWORD length = max_key_len, type, data_len = max_data_len;
2001 ret = RegEnumValueW(hkey_src, i, ptr_name, &length, NULL, &type, ptr, &data_len);
2002 if (!ret) {
2003 ret = SHSetValueW(hkey_dst, NULL, ptr_name, type, ptr, data_len);
2007 /* Free buffers if allocated */
2008 if (ptr_name != name)
2009 heap_free(ptr_name);
2010 if (ptr != buff)
2011 heap_free(ptr);
2013 if (subkey && hkey_src)
2014 RegCloseKey(hkey_src);
2016 return ret;
2020 /*************************************************************************
2021 * SHEnumKeyExA [SHCORE.@]
2023 LONG WINAPI SHEnumKeyExA(HKEY hkey, DWORD index, char *subkey, DWORD *length)
2025 TRACE("(%p, %d, %s, %p)\n", hkey, index, debugstr_a(subkey), length);
2027 return RegEnumKeyExA(hkey, index, subkey, length, NULL, NULL, NULL, NULL);
2030 /*************************************************************************
2031 * SHEnumKeyExW [SHCORE.@]
2033 LONG WINAPI SHEnumKeyExW(HKEY hkey, DWORD index, WCHAR *subkey, DWORD *length)
2035 TRACE("(%p, %d, %s, %p)\n", hkey, index, debugstr_w(subkey), length);
2037 return RegEnumKeyExW(hkey, index, subkey, length, NULL, NULL, NULL, NULL);
2040 /*************************************************************************
2041 * SHEnumValueA [SHCORE.@]
2043 LONG WINAPI SHEnumValueA(HKEY hkey, DWORD index, char *value, DWORD *length, DWORD *type,
2044 void *data, DWORD *data_len)
2046 TRACE("(%p, %d, %s, %p, %p, %p, %p)\n", hkey, index, debugstr_a(value), length, type, data, data_len);
2048 return RegEnumValueA(hkey, index, value, length, NULL, type, data, data_len);
2051 /*************************************************************************
2052 * SHEnumValueW [SHCORE.@]
2054 LONG WINAPI SHEnumValueW(HKEY hkey, DWORD index, WCHAR *value, DWORD *length, DWORD *type,
2055 void *data, DWORD *data_len)
2057 TRACE("(%p, %d, %s, %p, %p, %p, %p)\n", hkey, index, debugstr_w(value), length, type, data, data_len);
2059 return RegEnumValueW(hkey, index, value, length, NULL, type, data, data_len);
2062 /*************************************************************************
2063 * SHQueryValueExW [SHCORE.@]
2065 DWORD WINAPI SHQueryValueExW(HKEY hkey, const WCHAR *name, DWORD *reserved, DWORD *type,
2066 void *buff, DWORD *buff_len)
2068 DWORD ret, value_type, data_len = 0;
2070 TRACE("(%p, %s, %p, %p, %p, %p)\n", hkey, debugstr_w(name), reserved, type, buff, buff_len);
2072 if (buff_len)
2073 data_len = *buff_len;
2075 ret = RegQueryValueExW(hkey, name, reserved, &value_type, buff, &data_len);
2076 if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)
2077 return ret;
2079 if (buff_len && value_type == REG_EXPAND_SZ)
2081 DWORD length;
2082 WCHAR *value;
2084 if (!buff || ret == ERROR_MORE_DATA)
2086 length = data_len;
2087 value = heap_alloc(length);
2088 RegQueryValueExW(hkey, name, reserved, NULL, (BYTE *)value, &length);
2089 length = ExpandEnvironmentStringsW(value, NULL, 0);
2091 else
2093 length = (lstrlenW(buff) + 1) * sizeof(WCHAR);
2094 value = heap_alloc(length);
2095 memcpy(value, buff, length);
2096 length = ExpandEnvironmentStringsW(value, buff, *buff_len / sizeof(WCHAR));
2097 if (length > *buff_len) ret = ERROR_MORE_DATA;
2099 data_len = max(data_len, length);
2100 heap_free(value);
2103 if (type)
2104 *type = value_type == REG_EXPAND_SZ ? REG_SZ : value_type;
2105 if (buff_len)
2106 *buff_len = data_len;
2107 return ret;
2110 /*************************************************************************
2111 * SHQueryValueExA [SHCORE.@]
2113 DWORD WINAPI SHQueryValueExA(HKEY hkey, const char *name, DWORD *reserved, DWORD *type,
2114 void *buff, DWORD *buff_len)
2116 DWORD ret, value_type, data_len = 0;
2118 TRACE("(%p, %s, %p, %p, %p, %p)\n", hkey, debugstr_a(name), reserved, type, buff, buff_len);
2120 if (buff_len)
2121 data_len = *buff_len;
2123 ret = RegQueryValueExA(hkey, name, reserved, &value_type, buff, &data_len);
2124 if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)
2125 return ret;
2127 if (buff_len && value_type == REG_EXPAND_SZ)
2129 DWORD length;
2130 char *value;
2132 if (!buff || ret == ERROR_MORE_DATA)
2134 length = data_len;
2135 value = heap_alloc(length);
2136 RegQueryValueExA(hkey, name, reserved, NULL, (BYTE *)value, &length);
2137 length = ExpandEnvironmentStringsA(value, NULL, 0);
2139 else
2141 length = strlen(buff) + 1;
2142 value = heap_alloc(length);
2143 memcpy(value, buff, length);
2144 length = ExpandEnvironmentStringsA(value, buff, *buff_len);
2145 if (length > *buff_len) ret = ERROR_MORE_DATA;
2147 data_len = max(data_len, length);
2148 heap_free(value);
2151 if (type)
2152 *type = value_type == REG_EXPAND_SZ ? REG_SZ : value_type;
2153 if (buff_len)
2154 *buff_len = data_len;
2155 return ret;
2158 /*************************************************************************
2159 * SHGetValueA [SHCORE.@]
2161 DWORD WINAPI SHGetValueA(HKEY hkey, const char *subkey, const char *value,
2162 DWORD *type, void *data, DWORD *data_len)
2164 HKEY hsubkey = 0;
2165 DWORD ret = 0;
2167 TRACE("(%p, %s, %s, %p, %p, %p)\n", hkey, debugstr_a(subkey), debugstr_a(value),
2168 type, data, data_len);
2170 if (subkey)
2171 ret = RegOpenKeyExA(hkey, subkey, 0, KEY_QUERY_VALUE, &hsubkey);
2173 if (!ret)
2175 ret = SHQueryValueExA(hsubkey ? hsubkey : hkey, value, 0, type, data, data_len);
2176 if (subkey)
2177 RegCloseKey(hsubkey);
2180 return ret;
2183 /*************************************************************************
2184 * SHGetValueW [SHCORE.@]
2186 DWORD WINAPI SHGetValueW(HKEY hkey, const WCHAR *subkey, const WCHAR *value,
2187 DWORD *type, void *data, DWORD *data_len)
2189 HKEY hsubkey = 0;
2190 DWORD ret = 0;
2192 TRACE("(%p, %s, %s, %p, %p, %p)\n", hkey, debugstr_w(subkey), debugstr_w(value),
2193 type, data, data_len);
2195 if (subkey)
2196 ret = RegOpenKeyExW(hkey, subkey, 0, KEY_QUERY_VALUE, &hsubkey);
2198 if (!ret)
2200 ret = SHQueryValueExW(hsubkey ? hsubkey : hkey, value, 0, type, data, data_len);
2201 if (subkey)
2202 RegCloseKey(hsubkey);
2205 return ret;
2208 /*************************************************************************
2209 * SHRegGetIntW [SHCORE.280]
2211 int WINAPI SHRegGetIntW(HKEY hkey, const WCHAR *value, int default_value)
2213 WCHAR buff[32];
2214 DWORD buff_len;
2216 TRACE("(%p, %s, %d)\n", hkey, debugstr_w(value), default_value);
2218 buff[0] = 0;
2219 buff_len = sizeof(buff);
2220 if (SHQueryValueExW(hkey, value, 0, 0, buff, &buff_len))
2221 return default_value;
2223 if (*buff >= '0' && *buff <= '9')
2224 return wcstol(buff, NULL, 10);
2226 return default_value;
2229 /*************************************************************************
2230 * SHRegGetPathA [SHCORE.@]
2232 DWORD WINAPI SHRegGetPathA(HKEY hkey, const char *subkey, const char *value, char *path, DWORD flags)
2234 DWORD length = MAX_PATH;
2236 TRACE("(%p, %s, %s, %p, %#x)\n", hkey, debugstr_a(subkey), debugstr_a(value), path, flags);
2238 return SHGetValueA(hkey, subkey, value, 0, path, &length);
2241 /*************************************************************************
2242 * SHRegGetPathW [SHCORE.@]
2244 DWORD WINAPI SHRegGetPathW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, WCHAR *path, DWORD flags)
2246 DWORD length = MAX_PATH;
2248 TRACE("(%p, %s, %s, %p, %d)\n", hkey, debugstr_w(subkey), debugstr_w(value), path, flags);
2250 return SHGetValueW(hkey, subkey, value, 0, path, &length);
2253 /*************************************************************************
2254 * SHSetValueW [SHCORE.@]
2256 DWORD WINAPI SHSetValueW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, DWORD type,
2257 const void *data, DWORD data_len)
2259 DWORD ret = ERROR_SUCCESS, dummy;
2260 HKEY hsubkey;
2262 TRACE("(%p, %s, %s, %d, %p, %d)\n", hkey, debugstr_w(subkey), debugstr_w(value),
2263 type, data, data_len);
2265 if (subkey && *subkey)
2266 ret = RegCreateKeyExW(hkey, subkey, 0, NULL, 0, KEY_SET_VALUE, NULL, &hsubkey, &dummy);
2267 else
2268 hsubkey = hkey;
2270 if (!ret)
2272 ret = RegSetValueExW(hsubkey, value, 0, type, data, data_len);
2273 if (hsubkey != hkey)
2274 RegCloseKey(hsubkey);
2277 return ret;
2280 /*************************************************************************
2281 * SHSetValueA [SHCORE.@]
2283 DWORD WINAPI SHSetValueA(HKEY hkey, const char *subkey, const char *value,
2284 DWORD type, const void *data, DWORD data_len)
2286 DWORD ret = ERROR_SUCCESS, dummy;
2287 HKEY hsubkey;
2289 TRACE("(%p, %s, %s, %d, %p, %d)\n", hkey, debugstr_a(subkey), debugstr_a(value),
2290 type, data, data_len);
2292 if (subkey && *subkey)
2293 ret = RegCreateKeyExA(hkey, subkey, 0, NULL, 0, KEY_SET_VALUE, NULL, &hsubkey, &dummy);
2294 else
2295 hsubkey = hkey;
2297 if (!ret)
2299 ret = RegSetValueExA(hsubkey, value, 0, type, data, data_len);
2300 if (hsubkey != hkey)
2301 RegCloseKey(hsubkey);
2304 return ret;
2307 /*************************************************************************
2308 * SHRegSetPathA [SHCORE.@]
2310 DWORD WINAPI SHRegSetPathA(HKEY hkey, const char *subkey, const char *value, const char *path, DWORD flags)
2312 FIXME("(%p, %s, %s, %s, %#x) - semi-stub\n", hkey, debugstr_a(subkey),
2313 debugstr_a(value), debugstr_a(path), flags);
2315 /* FIXME: PathUnExpandEnvStringsA() */
2317 return SHSetValueA(hkey, subkey, value, REG_SZ, path, lstrlenA(path));
2320 /*************************************************************************
2321 * SHRegSetPathW [SHCORE.@]
2323 DWORD WINAPI SHRegSetPathW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, const WCHAR *path, DWORD flags)
2325 FIXME("(%p, %s, %s, %s, %#x) - semi-stub\n", hkey, debugstr_w(subkey),
2326 debugstr_w(value), debugstr_w(path), flags);
2328 /* FIXME: PathUnExpandEnvStringsW(); */
2330 return SHSetValueW(hkey, subkey, value, REG_SZ, path, lstrlenW(path));
2333 /*************************************************************************
2334 * SHQueryInfoKeyA [SHCORE.@]
2336 LONG WINAPI SHQueryInfoKeyA(HKEY hkey, DWORD *subkeys, DWORD *subkey_max, DWORD *values, DWORD *value_max)
2338 TRACE("(%p, %p, %p, %p, %p)\n", hkey, subkeys, subkey_max, values, value_max);
2340 return RegQueryInfoKeyA(hkey, NULL, NULL, NULL, subkeys, subkey_max, NULL, values, value_max, NULL, NULL, NULL);
2343 /*************************************************************************
2344 * SHQueryInfoKeyW [SHCORE.@]
2346 LONG WINAPI SHQueryInfoKeyW(HKEY hkey, DWORD *subkeys, DWORD *subkey_max, DWORD *values, DWORD *value_max)
2348 TRACE("(%p, %p, %p, %p, %p)\n", hkey, subkeys, subkey_max, values, value_max);
2350 return RegQueryInfoKeyW(hkey, NULL, NULL, NULL, subkeys, subkey_max, NULL, values, value_max, NULL, NULL, NULL);
2353 /*************************************************************************
2354 * IsOS [SHCORE.@]
2356 BOOL WINAPI IsOS(DWORD feature)
2358 DWORD platform, majorv, minorv;
2359 OSVERSIONINFOA osvi;
2361 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
2362 if (!GetVersionExA(&osvi))
2363 return FALSE;
2365 majorv = osvi.dwMajorVersion;
2366 minorv = osvi.dwMinorVersion;
2367 platform = osvi.dwPlatformId;
2369 #define ISOS_RETURN(x) \
2370 TRACE("(0x%x) ret=%d\n",feature,(x)); \
2371 return (x)
2373 switch(feature) {
2374 case OS_WIN32SORGREATER:
2375 ISOS_RETURN(platform == VER_PLATFORM_WIN32s
2376 || platform == VER_PLATFORM_WIN32_WINDOWS);
2377 case OS_NT:
2378 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2379 case OS_WIN95ORGREATER:
2380 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS);
2381 case OS_NT4ORGREATER:
2382 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 4);
2383 case OS_WIN2000ORGREATER_ALT:
2384 case OS_WIN2000ORGREATER:
2385 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5);
2386 case OS_WIN98ORGREATER:
2387 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 10);
2388 case OS_WIN98_GOLD:
2389 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 10);
2390 case OS_WIN2000PRO:
2391 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5);
2392 case OS_WIN2000SERVER:
2393 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2394 case OS_WIN2000ADVSERVER:
2395 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2396 case OS_WIN2000DATACENTER:
2397 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2398 case OS_WIN2000TERMINAL:
2399 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2400 case OS_EMBEDDED:
2401 FIXME("(OS_EMBEDDED) What should we return here?\n");
2402 return FALSE;
2403 case OS_TERMINALCLIENT:
2404 FIXME("(OS_TERMINALCLIENT) What should we return here?\n");
2405 return FALSE;
2406 case OS_TERMINALREMOTEADMIN:
2407 FIXME("(OS_TERMINALREMOTEADMIN) What should we return here?\n");
2408 return FALSE;
2409 case OS_WIN95_GOLD:
2410 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 0);
2411 case OS_MEORGREATER:
2412 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 90);
2413 case OS_XPORGREATER:
2414 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1);
2415 case OS_HOME:
2416 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1);
2417 case OS_PROFESSIONAL:
2418 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2419 case OS_DATACENTER:
2420 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2421 case OS_ADVSERVER:
2422 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5);
2423 case OS_SERVER:
2424 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2425 case OS_TERMINALSERVER:
2426 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2427 case OS_PERSONALTERMINALSERVER:
2428 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && minorv >= 1 && majorv >= 5);
2429 case OS_FASTUSERSWITCHING:
2430 FIXME("(OS_FASTUSERSWITCHING) What should we return here?\n");
2431 return TRUE;
2432 case OS_WELCOMELOGONUI:
2433 FIXME("(OS_WELCOMELOGONUI) What should we return here?\n");
2434 return FALSE;
2435 case OS_DOMAINMEMBER:
2436 FIXME("(OS_DOMAINMEMBER) What should we return here?\n");
2437 return TRUE;
2438 case OS_ANYSERVER:
2439 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2440 case OS_WOW6432:
2442 BOOL is_wow64;
2443 IsWow64Process(GetCurrentProcess(), &is_wow64);
2444 return is_wow64;
2446 case OS_WEBSERVER:
2447 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2448 case OS_SMALLBUSINESSSERVER:
2449 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2450 case OS_TABLETPC:
2451 FIXME("(OS_TABLETPC) What should we return here?\n");
2452 return FALSE;
2453 case OS_SERVERADMINUI:
2454 FIXME("(OS_SERVERADMINUI) What should we return here?\n");
2455 return FALSE;
2456 case OS_MEDIACENTER:
2457 FIXME("(OS_MEDIACENTER) What should we return here?\n");
2458 return FALSE;
2459 case OS_APPLIANCE:
2460 FIXME("(OS_APPLIANCE) What should we return here?\n");
2461 return FALSE;
2462 case 0x25: /*OS_VISTAORGREATER*/
2463 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 6);
2466 #undef ISOS_RETURN
2468 WARN("(0x%x) unknown parameter\n", feature);
2470 return FALSE;