tdh: Add TdhLoadManifestFromBinary stub.
[wine.git] / dlls / shcore / main.c
blobfd21db423ead15508164104bf80988cb9d70043d
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_PROCESS_ATTACH:
48 DisableThreadLibraryCalls(instance);
49 shcore_tls = TlsAlloc();
50 break;
51 case DLL_PROCESS_DETACH:
52 if (reserved) break;
53 if (shcore_tls != TLS_OUT_OF_INDEXES)
54 TlsFree(shcore_tls);
55 break;
58 return TRUE;
61 HRESULT WINAPI GetProcessDpiAwareness(HANDLE process, PROCESS_DPI_AWARENESS *value)
63 if (GetProcessDpiAwarenessInternal( process, (DPI_AWARENESS *)value )) return S_OK;
64 return HRESULT_FROM_WIN32( GetLastError() );
67 HRESULT WINAPI SetProcessDpiAwareness(PROCESS_DPI_AWARENESS value)
69 if (SetProcessDpiAwarenessInternal( value )) return S_OK;
70 return HRESULT_FROM_WIN32( GetLastError() );
73 HRESULT WINAPI GetDpiForMonitor(HMONITOR monitor, MONITOR_DPI_TYPE type, UINT *x, UINT *y)
75 if (GetDpiForMonitorInternal( monitor, type, x, y )) return S_OK;
76 return HRESULT_FROM_WIN32( GetLastError() );
79 HRESULT WINAPI GetScaleFactorForMonitor(HMONITOR monitor, DEVICE_SCALE_FACTOR *scale)
81 FIXME("(%p %p): stub\n", monitor, scale);
83 *scale = SCALE_100_PERCENT;
84 return S_OK;
87 DEVICE_SCALE_FACTOR WINAPI GetScaleFactorForDevice(DISPLAY_DEVICE_TYPE device_type)
89 FIXME("%d\n", device_type);
91 return SCALE_100_PERCENT;
94 HRESULT WINAPI _IStream_Read(IStream *stream, void *dest, ULONG size)
96 ULONG read;
97 HRESULT hr;
99 TRACE("(%p, %p, %u)\n", stream, dest, size);
101 hr = IStream_Read(stream, dest, size, &read);
102 if (SUCCEEDED(hr) && read != size)
103 hr = E_FAIL;
104 return hr;
107 HRESULT WINAPI IStream_Reset(IStream *stream)
109 static const LARGE_INTEGER zero;
111 TRACE("(%p)\n", stream);
113 return IStream_Seek(stream, zero, 0, NULL);
116 HRESULT WINAPI IStream_Size(IStream *stream, ULARGE_INTEGER *size)
118 STATSTG statstg;
119 HRESULT hr;
121 TRACE("(%p, %p)\n", stream, size);
123 memset(&statstg, 0, sizeof(statstg));
125 hr = IStream_Stat(stream, &statstg, STATFLAG_NONAME);
127 if (SUCCEEDED(hr) && size)
128 *size = statstg.cbSize;
129 return hr;
132 HRESULT WINAPI _IStream_Write(IStream *stream, const void *src, ULONG size)
134 ULONG written;
135 HRESULT hr;
137 TRACE("(%p, %p, %u)\n", stream, src, size);
139 hr = IStream_Write(stream, src, size, &written);
140 if (SUCCEEDED(hr) && written != size)
141 hr = E_FAIL;
143 return hr;
146 void WINAPI IUnknown_AtomicRelease(IUnknown **obj)
148 TRACE("(%p)\n", obj);
150 if (!obj || !*obj)
151 return;
153 IUnknown_Release(*obj);
154 *obj = NULL;
157 HRESULT WINAPI IUnknown_GetSite(IUnknown *unk, REFIID iid, void **site)
159 IObjectWithSite *obj = NULL;
160 HRESULT hr = E_INVALIDARG;
162 TRACE("(%p, %s, %p)\n", unk, debugstr_guid(iid), site);
164 if (unk && iid && site)
166 hr = IUnknown_QueryInterface(unk, &IID_IObjectWithSite, (void **)&obj);
167 if (SUCCEEDED(hr) && obj)
169 hr = IObjectWithSite_GetSite(obj, iid, site);
170 IObjectWithSite_Release(obj);
174 return hr;
177 HRESULT WINAPI IUnknown_QueryService(IUnknown *obj, REFGUID sid, REFIID iid, void **out)
179 IServiceProvider *provider = NULL;
180 HRESULT hr;
182 if (!out)
183 return E_FAIL;
185 *out = NULL;
187 if (!obj)
188 return E_FAIL;
190 hr = IUnknown_QueryInterface(obj, &IID_IServiceProvider, (void **)&provider);
191 if (hr == S_OK && provider)
193 TRACE("Using provider %p.\n", provider);
195 hr = IServiceProvider_QueryService(provider, sid, iid, out);
197 TRACE("Provider %p returned %p.\n", provider, *out);
199 IServiceProvider_Release(provider);
202 return hr;
205 void WINAPI IUnknown_Set(IUnknown **dest, IUnknown *src)
207 TRACE("(%p, %p)\n", dest, src);
209 IUnknown_AtomicRelease(dest);
211 if (src)
213 IUnknown_AddRef(src);
214 *dest = src;
218 HRESULT WINAPI IUnknown_SetSite(IUnknown *obj, IUnknown *site)
220 IInternetSecurityManager *sec_manager;
221 IObjectWithSite *objwithsite;
222 HRESULT hr;
224 if (!obj)
225 return E_FAIL;
227 hr = IUnknown_QueryInterface(obj, &IID_IObjectWithSite, (void **)&objwithsite);
228 TRACE("ObjectWithSite %p, hr %#x.\n", objwithsite, hr);
229 if (SUCCEEDED(hr))
231 hr = IObjectWithSite_SetSite(objwithsite, site);
232 TRACE("SetSite() hr %#x.\n", hr);
233 IObjectWithSite_Release(objwithsite);
235 else
237 hr = IUnknown_QueryInterface(obj, &IID_IInternetSecurityManager, (void **)&sec_manager);
238 TRACE("InternetSecurityManager %p, hr %#x.\n", sec_manager, hr);
239 if (FAILED(hr))
240 return hr;
242 hr = IInternetSecurityManager_SetSecuritySite(sec_manager, (IInternetSecurityMgrSite *)site);
243 TRACE("SetSecuritySite() hr %#x.\n", hr);
244 IInternetSecurityManager_Release(sec_manager);
247 return hr;
250 HRESULT WINAPI SetCurrentProcessExplicitAppUserModelID(const WCHAR *appid)
252 FIXME("%s: stub\n", debugstr_w(appid));
253 return S_OK;
256 HRESULT WINAPI GetCurrentProcessExplicitAppUserModelID(const WCHAR **appid)
258 FIXME("%p: stub\n", appid);
259 *appid = NULL;
260 return E_NOTIMPL;
263 /*************************************************************************
264 * CommandLineToArgvW [SHCORE.@]
266 * We must interpret the quotes in the command line to rebuild the argv
267 * array correctly:
268 * - arguments are separated by spaces or tabs
269 * - quotes serve as optional argument delimiters
270 * '"a b"' -> 'a b'
271 * - escaped quotes must be converted back to '"'
272 * '\"' -> '"'
273 * - consecutive backslashes preceding a quote see their number halved with
274 * the remainder escaping the quote:
275 * 2n backslashes + quote -> n backslashes + quote as an argument delimiter
276 * 2n+1 backslashes + quote -> n backslashes + literal quote
277 * - backslashes that are not followed by a quote are copied literally:
278 * 'a\b' -> 'a\b'
279 * 'a\\b' -> 'a\\b'
280 * - in quoted strings, consecutive quotes see their number divided by three
281 * with the remainder modulo 3 deciding whether to close the string or not.
282 * Note that the opening quote must be counted in the consecutive quotes,
283 * that's the (1+) below:
284 * (1+) 3n quotes -> n quotes
285 * (1+) 3n+1 quotes -> n quotes plus closes the quoted string
286 * (1+) 3n+2 quotes -> n+1 quotes plus closes the quoted string
287 * - in unquoted strings, the first quote opens the quoted string and the
288 * remaining consecutive quotes follow the above rule.
290 WCHAR** WINAPI CommandLineToArgvW(const WCHAR *cmdline, int *numargs)
292 int qcount, bcount;
293 const WCHAR *s;
294 WCHAR **argv;
295 DWORD argc;
296 WCHAR *d;
298 if (!numargs)
300 SetLastError(ERROR_INVALID_PARAMETER);
301 return NULL;
304 if (*cmdline == 0)
306 /* Return the path to the executable */
307 DWORD len, deslen = MAX_PATH, size;
309 size = sizeof(WCHAR *) * 2 + deslen * sizeof(WCHAR);
310 for (;;)
312 if (!(argv = LocalAlloc(LMEM_FIXED, size))) return NULL;
313 len = GetModuleFileNameW(0, (WCHAR *)(argv + 2), deslen);
314 if (!len)
316 LocalFree(argv);
317 return NULL;
319 if (len < deslen) break;
320 deslen *= 2;
321 size = sizeof(WCHAR *) * 2 + deslen * sizeof(WCHAR);
322 LocalFree(argv);
324 argv[0] = (WCHAR *)(argv + 2);
325 argv[1] = NULL;
326 *numargs = 1;
328 return argv;
331 /* --- First count the arguments */
332 argc = 1;
333 s = cmdline;
334 /* The first argument, the executable path, follows special rules */
335 if (*s == '"')
337 /* The executable path ends at the next quote, no matter what */
338 s++;
339 while (*s)
340 if (*s++ == '"')
341 break;
343 else
345 /* The executable path ends at the next space, no matter what */
346 while (*s && *s != ' ' && *s != '\t')
347 s++;
349 /* skip to the first argument, if any */
350 while (*s == ' ' || *s == '\t')
351 s++;
352 if (*s)
353 argc++;
355 /* Analyze the remaining arguments */
356 qcount = bcount = 0;
357 while (*s)
359 if ((*s == ' ' || *s == '\t') && qcount == 0)
361 /* skip to the next argument and count it if any */
362 while (*s == ' ' || *s == '\t')
363 s++;
364 if (*s)
365 argc++;
366 bcount = 0;
368 else if (*s == '\\')
370 /* '\', count them */
371 bcount++;
372 s++;
374 else if (*s == '"')
376 /* '"' */
377 if ((bcount & 1) == 0)
378 qcount++; /* unescaped '"' */
379 s++;
380 bcount = 0;
381 /* consecutive quotes, see comment in copying code below */
382 while (*s == '"')
384 qcount++;
385 s++;
387 qcount = qcount % 3;
388 if (qcount == 2)
389 qcount = 0;
391 else
393 /* a regular character */
394 bcount = 0;
395 s++;
399 /* Allocate in a single lump, the string array, and the strings that go
400 * with it. This way the caller can make a single LocalFree() call to free
401 * both, as per MSDN.
403 argv = LocalAlloc(LMEM_FIXED, (argc + 1) * sizeof(WCHAR *) + (lstrlenW(cmdline) + 1) * sizeof(WCHAR));
404 if (!argv)
405 return NULL;
407 /* --- Then split and copy the arguments */
408 argv[0] = d = lstrcpyW((WCHAR *)(argv + argc + 1), cmdline);
409 argc = 1;
410 /* The first argument, the executable path, follows special rules */
411 if (*d == '"')
413 /* The executable path ends at the next quote, no matter what */
414 s = d + 1;
415 while (*s)
417 if (*s == '"')
419 s++;
420 break;
422 *d++ = *s++;
425 else
427 /* The executable path ends at the next space, no matter what */
428 while (*d && *d != ' ' && *d != '\t')
429 d++;
430 s = d;
431 if (*s)
432 s++;
434 /* close the executable path */
435 *d++ = 0;
436 /* skip to the first argument and initialize it if any */
437 while (*s == ' ' || *s == '\t')
438 s++;
439 if (!*s)
441 /* There are no parameters so we are all done */
442 argv[argc] = NULL;
443 *numargs = argc;
444 return argv;
447 /* Split and copy the remaining arguments */
448 argv[argc++] = d;
449 qcount = bcount = 0;
450 while (*s)
452 if ((*s == ' ' || *s == '\t') && qcount == 0)
454 /* close the argument */
455 *d++ = 0;
456 bcount = 0;
458 /* skip to the next one and initialize it if any */
459 do {
460 s++;
461 } while (*s == ' ' || *s == '\t');
462 if (*s)
463 argv[argc++] = d;
465 else if (*s=='\\')
467 *d++ = *s++;
468 bcount++;
470 else if (*s == '"')
472 if ((bcount & 1) == 0)
474 /* Preceded by an even number of '\', this is half that
475 * number of '\', plus a quote which we erase.
477 d -= bcount / 2;
478 qcount++;
480 else
482 /* Preceded by an odd number of '\', this is half that
483 * number of '\' followed by a '"'
485 d = d - bcount / 2 - 1;
486 *d++ = '"';
488 s++;
489 bcount = 0;
490 /* Now count the number of consecutive quotes. Note that qcount
491 * already takes into account the opening quote if any, as well as
492 * the quote that lead us here.
494 while (*s == '"')
496 if (++qcount == 3)
498 *d++ = '"';
499 qcount = 0;
501 s++;
503 if (qcount == 2)
504 qcount = 0;
506 else
508 /* a regular character */
509 *d++ = *s++;
510 bcount = 0;
513 *d = '\0';
514 argv[argc] = NULL;
515 *numargs = argc;
517 return argv;
520 struct shstream
522 IStream IStream_iface;
523 LONG refcount;
525 union
527 struct
529 BYTE *buffer;
530 DWORD length;
531 DWORD position;
533 HKEY hkey;
534 WCHAR *valuename;
535 } mem;
536 struct
538 HANDLE handle;
539 DWORD mode;
540 WCHAR *path;
541 } file;
542 } u;
545 static inline struct shstream *impl_from_IStream(IStream *iface)
547 return CONTAINING_RECORD(iface, struct shstream, IStream_iface);
550 static HRESULT WINAPI shstream_QueryInterface(IStream *iface, REFIID riid, void **out)
552 struct shstream *stream = impl_from_IStream(iface);
554 TRACE("(%p)->(%s, %p)\n", stream, debugstr_guid(riid), out);
556 if (IsEqualIID(riid, &IID_IUnknown) ||
557 IsEqualIID(riid, &IID_IStream) ||
558 IsEqualIID(riid, &IID_ISequentialStream))
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)
605 if (read_len)
606 *read_len = 0;
607 return S_FALSE;
610 length = stream->u.mem.length - stream->u.mem.position;
611 if (buff_size < length)
612 length = buff_size;
614 memmove(buff, stream->u.mem.buffer + stream->u.mem.position, length);
615 stream->u.mem.position += length;
617 if (read_len)
618 *read_len = length;
620 return S_OK;
623 static HRESULT WINAPI memstream_Write(IStream *iface, const void *buff, ULONG buff_size, ULONG *written)
625 struct shstream *stream = impl_from_IStream(iface);
626 DWORD length = stream->u.mem.position + buff_size;
628 TRACE("(%p)->(%p, %u, %p)\n", stream, buff, buff_size, written);
630 if (length < stream->u.mem.position) /* overflow */
631 return STG_E_INSUFFICIENTMEMORY;
633 if (length > stream->u.mem.length)
635 BYTE *buffer = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, stream->u.mem.buffer, length);
636 if (!buffer)
637 return STG_E_INSUFFICIENTMEMORY;
639 stream->u.mem.length = length;
640 stream->u.mem.buffer = buffer;
642 memmove(stream->u.mem.buffer + stream->u.mem.position, buff, buff_size);
643 stream->u.mem.position += buff_size; /* adjust pointer */
645 if (written)
646 *written = buff_size;
648 return S_OK;
651 static HRESULT WINAPI memstream_Seek(IStream *iface, LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER*new_pos)
653 struct shstream *stream = impl_from_IStream(iface);
654 LARGE_INTEGER tmp;
656 TRACE("(%p)->(%s, %d, %p)\n", stream, wine_dbgstr_longlong(move.QuadPart), origin, new_pos);
658 if (origin == STREAM_SEEK_SET)
659 tmp = move;
660 else if (origin == STREAM_SEEK_CUR)
661 tmp.QuadPart = stream->u.mem.position + move.QuadPart;
662 else if (origin == STREAM_SEEK_END)
663 tmp.QuadPart = stream->u.mem.length + move.QuadPart;
664 else
665 return STG_E_INVALIDPARAMETER;
667 if (tmp.QuadPart < 0)
668 return STG_E_INVALIDFUNCTION;
670 /* we cut off the high part here */
671 stream->u.mem.position = tmp.u.LowPart;
673 if (new_pos)
674 new_pos->QuadPart = stream->u.mem.position;
675 return S_OK;
678 static HRESULT WINAPI memstream_SetSize(IStream *iface, ULARGE_INTEGER new_size)
680 struct shstream *stream = impl_from_IStream(iface);
681 DWORD length;
682 BYTE *buffer;
684 TRACE("(%p, %s)\n", stream, wine_dbgstr_longlong(new_size.QuadPart));
686 /* we cut off the high part here */
687 length = new_size.u.LowPart;
688 buffer = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, stream->u.mem.buffer, length);
689 if (!buffer)
690 return STG_E_INSUFFICIENTMEMORY;
692 stream->u.mem.buffer = buffer;
693 stream->u.mem.length = length;
695 return S_OK;
698 static HRESULT WINAPI shstream_CopyTo(IStream *iface, IStream *pstm, ULARGE_INTEGER size, ULARGE_INTEGER *read_len, ULARGE_INTEGER *written)
700 struct shstream *stream = impl_from_IStream(iface);
702 TRACE("(%p)\n", stream);
704 if (read_len)
705 read_len->QuadPart = 0;
707 if (written)
708 written->QuadPart = 0;
710 /* TODO implement */
711 return E_NOTIMPL;
714 static HRESULT WINAPI shstream_Commit(IStream *iface, DWORD flags)
716 struct shstream *stream = impl_from_IStream(iface);
718 TRACE("(%p, %#x)\n", stream, flags);
720 /* Commit is not supported by this stream */
721 return E_NOTIMPL;
724 static HRESULT WINAPI shstream_Revert(IStream *iface)
726 struct shstream *stream = impl_from_IStream(iface);
728 TRACE("(%p)\n", stream);
730 /* revert not supported by this stream */
731 return E_NOTIMPL;
734 static HRESULT WINAPI shstream_LockRegion(IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER size, DWORD lock_type)
736 struct shstream *stream = impl_from_IStream(iface);
738 TRACE("(%p)\n", stream);
740 /* lock/unlock not supported by this stream */
741 return E_NOTIMPL;
744 static HRESULT WINAPI shstream_UnlockRegion(IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER size, DWORD lock_type)
746 struct shstream *stream = impl_from_IStream(iface);
748 TRACE("(%p)\n", stream);
750 /* lock/unlock not supported by this stream */
751 return E_NOTIMPL;
754 static HRESULT WINAPI memstream_Stat(IStream *iface, STATSTG *statstg, DWORD flags)
756 struct shstream *stream = impl_from_IStream(iface);
758 TRACE("(%p, %p, %#x)\n", stream, statstg, flags);
760 memset(statstg, 0, sizeof(*statstg));
761 statstg->type = STGTY_STREAM;
762 statstg->cbSize.QuadPart = stream->u.mem.length;
763 statstg->grfMode = STGM_READWRITE;
765 return S_OK;
768 static HRESULT WINAPI shstream_Clone(IStream *iface, IStream **dest)
770 struct shstream *stream = impl_from_IStream(iface);
772 TRACE("(%p, %p)\n", stream, dest);
774 *dest = NULL;
776 /* clone not supported by this stream */
777 return E_NOTIMPL;
780 static const IStreamVtbl memstreamvtbl =
782 shstream_QueryInterface,
783 shstream_AddRef,
784 memstream_Release,
785 memstream_Read,
786 memstream_Write,
787 memstream_Seek,
788 memstream_SetSize,
789 shstream_CopyTo,
790 shstream_Commit,
791 shstream_Revert,
792 shstream_LockRegion,
793 shstream_UnlockRegion,
794 memstream_Stat,
795 shstream_Clone,
798 static struct shstream *shstream_create(const IStreamVtbl *vtbl, const BYTE *data, UINT data_len)
800 struct shstream *stream;
802 if (!data)
803 data_len = 0;
805 stream = heap_alloc(sizeof(*stream));
806 stream->IStream_iface.lpVtbl = vtbl;
807 stream->refcount = 1;
808 stream->u.mem.buffer = heap_alloc(data_len);
809 if (!stream->u.mem.buffer)
811 heap_free(stream);
812 return NULL;
814 memcpy(stream->u.mem.buffer, data, data_len);
815 stream->u.mem.length = data_len;
816 stream->u.mem.position = 0;
818 return stream;
821 /*************************************************************************
822 * SHCreateMemStream [SHCORE.@]
824 * Create an IStream object on a block of memory.
826 * PARAMS
827 * data [I] Memory block to create the IStream object on
828 * data_len [I] Length of data block
830 * RETURNS
831 * Success: A pointer to the IStream object.
832 * Failure: NULL, if any parameters are invalid or an error occurs.
834 * NOTES
835 * A copy of the memory block is made, it's freed when the stream is released.
837 IStream * WINAPI SHCreateMemStream(const BYTE *data, UINT data_len)
839 struct shstream *stream;
841 TRACE("(%p, %u)\n", data, data_len);
843 stream = shstream_create(&memstreamvtbl, data, data_len);
844 return stream ? &stream->IStream_iface : NULL;
847 static ULONG WINAPI filestream_Release(IStream *iface)
849 struct shstream *stream = impl_from_IStream(iface);
850 ULONG refcount = InterlockedDecrement(&stream->refcount);
852 TRACE("(%p)->(%u)\n", stream, refcount);
854 if (!refcount)
856 CloseHandle(stream->u.file.handle);
857 heap_free(stream->u.file.path);
858 heap_free(stream);
861 return refcount;
864 static HRESULT WINAPI filestream_Read(IStream *iface, void *buff, ULONG size, ULONG *read_len)
866 struct shstream *stream = impl_from_IStream(iface);
867 DWORD read = 0;
869 TRACE("(%p, %p, %u, %p)\n", stream, buff, size, read_len);
871 if (!ReadFile(stream->u.file.handle, buff, size, &read, NULL))
873 WARN("error %d reading file\n", GetLastError());
874 return S_FALSE;
877 if (read_len)
878 *read_len = read;
880 return read == size ? S_OK : S_FALSE;
883 static HRESULT WINAPI filestream_Write(IStream *iface, const void *buff, ULONG size, ULONG *written)
885 struct shstream *stream = impl_from_IStream(iface);
886 DWORD written_len = 0;
888 TRACE("(%p, %p, %u, %p)\n", stream, buff, size, written);
890 switch (stream->u.file.mode & 0xf)
892 case STGM_WRITE:
893 case STGM_READWRITE:
894 break;
895 default:
896 return STG_E_ACCESSDENIED;
899 if (!WriteFile(stream->u.file.handle, buff, size, &written_len, NULL))
900 return HRESULT_FROM_WIN32(GetLastError());
902 if (written)
903 *written = written_len;
905 return S_OK;
908 static HRESULT WINAPI filestream_Seek(IStream *iface, LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER *new_pos)
910 struct shstream *stream = impl_from_IStream(iface);
911 DWORD position;
913 TRACE("(%p, %s, %d, %p)\n", stream, wine_dbgstr_longlong(move.QuadPart), origin, new_pos);
915 position = SetFilePointer(stream->u.file.handle, move.u.LowPart, NULL, origin);
916 if (position == INVALID_SET_FILE_POINTER)
917 return HRESULT_FROM_WIN32(GetLastError());
919 if (new_pos)
921 new_pos->u.HighPart = 0;
922 new_pos->u.LowPart = position;
925 return S_OK;
928 static HRESULT WINAPI filestream_SetSize(IStream *iface, ULARGE_INTEGER size)
930 struct shstream *stream = impl_from_IStream(iface);
931 LARGE_INTEGER origin, move;
933 TRACE("(%p, %s)\n", stream, wine_dbgstr_longlong(size.QuadPart));
935 move.QuadPart = 0;
936 if (!SetFilePointerEx(stream->u.file.handle, move, &origin, FILE_CURRENT))
937 return E_FAIL;
939 move.QuadPart = size.QuadPart;
940 if (!SetFilePointerEx(stream->u.file.handle, move, NULL, FILE_BEGIN))
941 return E_FAIL;
943 if (stream->u.file.mode != STGM_READ)
945 if (!SetEndOfFile(stream->u.file.handle))
946 return E_FAIL;
947 if (!SetFilePointerEx(stream->u.file.handle, origin, NULL, FILE_BEGIN))
948 return E_FAIL;
951 return S_OK;
954 static HRESULT WINAPI filestream_CopyTo(IStream *iface, IStream *dest, ULARGE_INTEGER size,
955 ULARGE_INTEGER *read_len, ULARGE_INTEGER *written)
957 struct shstream *stream = impl_from_IStream(iface);
958 HRESULT hr = S_OK;
959 char buff[1024];
961 TRACE("(%p, %p, %s, %p, %p)\n", stream, dest, wine_dbgstr_longlong(size.QuadPart), read_len, written);
963 if (read_len)
964 read_len->QuadPart = 0;
965 if (written)
966 written->QuadPart = 0;
968 if (!dest)
969 return S_OK;
971 while (size.QuadPart)
973 ULONG left, read_chunk, written_chunk;
975 left = size.QuadPart > sizeof(buff) ? sizeof(buff) : size.QuadPart;
977 /* Read */
978 hr = IStream_Read(iface, buff, left, &read_chunk);
979 if (FAILED(hr) || read_chunk == 0)
980 break;
981 if (read_len)
982 read_len->QuadPart += read_chunk;
984 /* Write */
985 hr = IStream_Write(dest, buff, read_chunk, &written_chunk);
986 if (written_chunk)
987 written->QuadPart += written_chunk;
988 if (FAILED(hr) || written_chunk != left)
989 break;
991 size.QuadPart -= left;
994 return hr;
997 static HRESULT WINAPI filestream_Commit(IStream *iface, DWORD flags)
999 struct shstream *stream = impl_from_IStream(iface);
1001 TRACE("(%p, %#x)\n", stream, flags);
1003 return S_OK;
1006 static HRESULT WINAPI filestream_Stat(IStream *iface, STATSTG *statstg, DWORD flags)
1008 struct shstream *stream = impl_from_IStream(iface);
1009 BY_HANDLE_FILE_INFORMATION fi;
1011 TRACE("(%p, %p, %#x)\n", stream, statstg, flags);
1013 if (!statstg)
1014 return STG_E_INVALIDPOINTER;
1016 memset(&fi, 0, sizeof(fi));
1017 GetFileInformationByHandle(stream->u.file.handle, &fi);
1019 if (flags & STATFLAG_NONAME)
1020 statstg->pwcsName = NULL;
1021 else
1023 int len = lstrlenW(stream->u.file.path);
1024 if ((statstg->pwcsName = CoTaskMemAlloc((len + 1) * sizeof(WCHAR))))
1025 memcpy(statstg->pwcsName, stream->u.file.path, (len + 1) * sizeof(WCHAR));
1027 statstg->type = 0;
1028 statstg->cbSize.u.LowPart = fi.nFileSizeLow;
1029 statstg->cbSize.u.HighPart = fi.nFileSizeHigh;
1030 statstg->mtime = fi.ftLastWriteTime;
1031 statstg->ctime = fi.ftCreationTime;
1032 statstg->atime = fi.ftLastAccessTime;
1033 statstg->grfMode = stream->u.file.mode;
1034 statstg->grfLocksSupported = 0;
1035 memcpy(&statstg->clsid, &IID_IStream, sizeof(CLSID));
1036 statstg->grfStateBits = 0;
1037 statstg->reserved = 0;
1039 return S_OK;
1042 static const IStreamVtbl filestreamvtbl =
1044 shstream_QueryInterface,
1045 shstream_AddRef,
1046 filestream_Release,
1047 filestream_Read,
1048 filestream_Write,
1049 filestream_Seek,
1050 filestream_SetSize,
1051 filestream_CopyTo,
1052 filestream_Commit,
1053 shstream_Revert,
1054 shstream_LockRegion,
1055 shstream_UnlockRegion,
1056 filestream_Stat,
1057 shstream_Clone,
1060 /*************************************************************************
1061 * SHCreateStreamOnFileEx [SHCORE.@]
1063 HRESULT WINAPI SHCreateStreamOnFileEx(const WCHAR *path, DWORD mode, DWORD attributes,
1064 BOOL create, IStream *template, IStream **ret)
1066 DWORD access, share, creation_disposition, len;
1067 struct shstream *stream;
1068 HANDLE hFile;
1070 TRACE("(%s, %d, 0x%08X, %d, %p, %p)\n", debugstr_w(path), mode, attributes,
1071 create, template, ret);
1073 if (!path || !ret || template)
1074 return E_INVALIDARG;
1076 *ret = NULL;
1078 /* Access */
1079 switch (mode & 0xf)
1081 case STGM_WRITE:
1082 case STGM_READWRITE:
1083 access = GENERIC_READ | GENERIC_WRITE;
1084 break;
1085 case STGM_READ:
1086 access = GENERIC_READ;
1087 break;
1088 default:
1089 return E_INVALIDARG;
1092 /* Sharing */
1093 switch (mode & 0xf0)
1095 case 0:
1096 case STGM_SHARE_DENY_NONE:
1097 share = FILE_SHARE_READ | FILE_SHARE_WRITE;
1098 break;
1099 case STGM_SHARE_DENY_READ:
1100 share = FILE_SHARE_WRITE;
1101 break;
1102 case STGM_SHARE_DENY_WRITE:
1103 share = FILE_SHARE_READ;
1104 break;
1105 case STGM_SHARE_EXCLUSIVE:
1106 share = 0;
1107 break;
1108 default:
1109 return E_INVALIDARG;
1112 switch (mode & 0xf000)
1114 case STGM_FAILIFTHERE:
1115 creation_disposition = create ? CREATE_NEW : OPEN_EXISTING;
1116 break;
1117 case STGM_CREATE:
1118 creation_disposition = CREATE_ALWAYS;
1119 break;
1120 default:
1121 return E_INVALIDARG;
1124 hFile = CreateFileW(path, access, share, NULL, creation_disposition, attributes, 0);
1125 if (hFile == INVALID_HANDLE_VALUE)
1126 return HRESULT_FROM_WIN32(GetLastError());
1128 stream = heap_alloc(sizeof(*stream));
1129 stream->IStream_iface.lpVtbl = &filestreamvtbl;
1130 stream->refcount = 1;
1131 stream->u.file.handle = hFile;
1132 stream->u.file.mode = mode;
1134 len = lstrlenW(path);
1135 stream->u.file.path = heap_alloc((len + 1) * sizeof(WCHAR));
1136 memcpy(stream->u.file.path, path, (len + 1) * sizeof(WCHAR));
1138 *ret = &stream->IStream_iface;
1140 return S_OK;
1143 /*************************************************************************
1144 * SHCreateStreamOnFileW [SHCORE.@]
1146 HRESULT WINAPI SHCreateStreamOnFileW(const WCHAR *path, DWORD mode, IStream **stream)
1148 TRACE("(%s, %#x, %p)\n", debugstr_w(path), mode, stream);
1150 if (!path || !stream)
1151 return E_INVALIDARG;
1153 if ((mode & (STGM_CONVERT | STGM_DELETEONRELEASE | STGM_TRANSACTED)) != 0)
1154 return E_INVALIDARG;
1156 return SHCreateStreamOnFileEx(path, mode, 0, FALSE, NULL, stream);
1159 /*************************************************************************
1160 * SHCreateStreamOnFileA [SHCORE.@]
1162 HRESULT WINAPI SHCreateStreamOnFileA(const char *path, DWORD mode, IStream **stream)
1164 WCHAR *pathW;
1165 HRESULT hr;
1166 DWORD len;
1168 TRACE("(%s, %#x, %p)\n", debugstr_a(path), mode, stream);
1170 if (!path)
1171 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1173 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1174 pathW = heap_alloc(len * sizeof(WCHAR));
1175 if (!pathW)
1176 return E_OUTOFMEMORY;
1178 MultiByteToWideChar(CP_ACP, 0, path, -1, pathW, len);
1179 hr = SHCreateStreamOnFileW(pathW, mode, stream);
1180 heap_free(pathW);
1182 return hr;
1185 static ULONG WINAPI regstream_Release(IStream *iface)
1187 struct shstream *stream = impl_from_IStream(iface);
1188 ULONG refcount = InterlockedDecrement(&stream->refcount);
1190 TRACE("(%p)->(%u)\n", stream, refcount);
1192 if (!refcount)
1194 if (stream->u.mem.hkey)
1196 if (stream->u.mem.length)
1197 RegSetValueExW(stream->u.mem.hkey, stream->u.mem.valuename, 0, REG_BINARY,
1198 (const BYTE *)stream->u.mem.buffer, stream->u.mem.length);
1199 else
1200 RegDeleteValueW(stream->u.mem.hkey, stream->u.mem.valuename);
1201 RegCloseKey(stream->u.mem.hkey);
1203 CoTaskMemFree(stream->u.mem.valuename);
1204 heap_free(stream->u.mem.buffer);
1205 heap_free(stream);
1208 return refcount;
1211 static const IStreamVtbl regstreamvtbl =
1213 shstream_QueryInterface,
1214 shstream_AddRef,
1215 regstream_Release,
1216 memstream_Read,
1217 memstream_Write,
1218 memstream_Seek,
1219 memstream_SetSize,
1220 shstream_CopyTo,
1221 shstream_Commit,
1222 shstream_Revert,
1223 shstream_LockRegion,
1224 shstream_UnlockRegion,
1225 memstream_Stat,
1226 shstream_Clone,
1229 /*************************************************************************
1230 * SHOpenRegStream2W [SHCORE.@]
1232 IStream * WINAPI SHOpenRegStream2W(HKEY hKey, const WCHAR *subkey, const WCHAR *value, DWORD mode)
1234 struct shstream *stream;
1235 HKEY hStrKey = NULL;
1236 BYTE *buff = NULL;
1237 DWORD length = 0;
1238 LONG ret;
1240 TRACE("(%p, %s, %s, %#x)\n", hKey, debugstr_w(subkey), debugstr_w(value), mode);
1242 if (mode == STGM_READ)
1243 ret = RegOpenKeyExW(hKey, subkey, 0, KEY_READ, &hStrKey);
1244 else /* in write mode we make sure the subkey exits */
1245 ret = RegCreateKeyExW(hKey, subkey, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &hStrKey, NULL);
1247 if (ret == ERROR_SUCCESS)
1249 if (mode == STGM_READ || mode == STGM_READWRITE)
1251 /* read initial data */
1252 ret = RegQueryValueExW(hStrKey, value, 0, 0, 0, &length);
1253 if (ret == ERROR_SUCCESS && length)
1255 buff = heap_alloc(length);
1256 RegQueryValueExW(hStrKey, value, 0, 0, buff, &length);
1260 if (!length)
1261 buff = heap_alloc(length);
1263 stream = shstream_create(&regstreamvtbl, buff, length);
1264 heap_free(buff);
1265 if (stream)
1267 stream->u.mem.hkey = hStrKey;
1268 SHStrDupW(value, &stream->u.mem.valuename);
1269 return &stream->IStream_iface;
1273 if (hStrKey)
1274 RegCloseKey(hStrKey);
1276 return NULL;
1279 /*************************************************************************
1280 * SHOpenRegStream2A [SHCORE.@]
1282 IStream * WINAPI SHOpenRegStream2A(HKEY hKey, const char *subkey, const char *value, DWORD mode)
1284 WCHAR *subkeyW = NULL, *valueW = NULL;
1285 IStream *stream;
1287 TRACE("(%p, %s, %s, %#x)\n", hKey, debugstr_a(subkey), debugstr_a(value), mode);
1289 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1290 return NULL;
1291 if (value && FAILED(SHStrDupA(value, &valueW)))
1293 CoTaskMemFree(subkeyW);
1294 return NULL;
1297 stream = SHOpenRegStream2W(hKey, subkeyW, valueW, mode);
1298 CoTaskMemFree(subkeyW);
1299 CoTaskMemFree(valueW);
1300 return stream;
1303 /*************************************************************************
1304 * SHOpenRegStreamA [SHCORE.@]
1306 IStream * WINAPI SHOpenRegStreamA(HKEY hkey, const char *subkey, const char *value, DWORD mode)
1308 WCHAR *subkeyW = NULL, *valueW = NULL;
1309 IStream *stream;
1311 TRACE("(%p, %s, %s, %#x)\n", hkey, debugstr_a(subkey), debugstr_a(value), mode);
1313 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1314 return NULL;
1315 if (value && FAILED(SHStrDupA(value, &valueW)))
1317 CoTaskMemFree(subkeyW);
1318 return NULL;
1321 stream = SHOpenRegStreamW(hkey, subkeyW, valueW, mode);
1322 CoTaskMemFree(subkeyW);
1323 CoTaskMemFree(valueW);
1324 return stream;
1327 static ULONG WINAPI dummystream_AddRef(IStream *iface)
1329 TRACE("()\n");
1330 return 2;
1333 static ULONG WINAPI dummystream_Release(IStream *iface)
1335 TRACE("()\n");
1336 return 1;
1339 static HRESULT WINAPI dummystream_Read(IStream *iface, void *buff, ULONG buff_size, ULONG *read_len)
1341 if (read_len)
1342 *read_len = 0;
1344 return E_NOTIMPL;
1347 static const IStreamVtbl dummystreamvtbl =
1349 shstream_QueryInterface,
1350 dummystream_AddRef,
1351 dummystream_Release,
1352 dummystream_Read,
1353 memstream_Write,
1354 memstream_Seek,
1355 memstream_SetSize,
1356 shstream_CopyTo,
1357 shstream_Commit,
1358 shstream_Revert,
1359 shstream_LockRegion,
1360 shstream_UnlockRegion,
1361 memstream_Stat,
1362 shstream_Clone,
1365 static struct shstream dummyregstream = { { &dummystreamvtbl } };
1367 /*************************************************************************
1368 * SHOpenRegStreamW [SHCORE.@]
1370 IStream * WINAPI SHOpenRegStreamW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, DWORD mode)
1372 IStream *stream;
1374 TRACE("(%p, %s, %s, %#x)\n", hkey, debugstr_w(subkey), debugstr_w(value), mode);
1375 stream = SHOpenRegStream2W(hkey, subkey, value, mode);
1376 return stream ? stream : &dummyregstream.IStream_iface;
1379 struct threadref
1381 IUnknown IUnknown_iface;
1382 LONG *refcount;
1385 static inline struct threadref *threadref_impl_from_IUnknown(IUnknown *iface)
1387 return CONTAINING_RECORD(iface, struct threadref, IUnknown_iface);
1390 static HRESULT WINAPI threadref_QueryInterface(IUnknown *iface, REFIID riid, void **out)
1392 struct threadref *threadref = threadref_impl_from_IUnknown(iface);
1394 TRACE("(%p, %s, %p)\n", threadref, debugstr_guid(riid), out);
1396 if (out == NULL)
1397 return E_POINTER;
1399 if (IsEqualGUID(&IID_IUnknown, riid))
1401 *out = iface;
1402 IUnknown_AddRef(iface);
1403 return S_OK;
1406 *out = NULL;
1407 WARN("Interface %s not supported.\n", debugstr_guid(riid));
1408 return E_NOINTERFACE;
1411 static ULONG WINAPI threadref_AddRef(IUnknown *iface)
1413 struct threadref *threadref = threadref_impl_from_IUnknown(iface);
1414 LONG refcount = InterlockedIncrement(threadref->refcount);
1416 TRACE("(%p, %d)\n", threadref, refcount);
1418 return refcount;
1421 static ULONG WINAPI threadref_Release(IUnknown *iface)
1423 struct threadref *threadref = threadref_impl_from_IUnknown(iface);
1424 LONG refcount = InterlockedDecrement(threadref->refcount);
1426 TRACE("(%p, %d)\n", threadref, refcount);
1428 if (!refcount)
1429 heap_free(threadref);
1431 return refcount;
1434 static const IUnknownVtbl threadrefvtbl =
1436 threadref_QueryInterface,
1437 threadref_AddRef,
1438 threadref_Release,
1441 /*************************************************************************
1442 * SHCreateThreadRef [SHCORE.@]
1444 HRESULT WINAPI SHCreateThreadRef(LONG *refcount, IUnknown **out)
1446 struct threadref *threadref;
1448 TRACE("(%p, %p)\n", refcount, out);
1450 if (!refcount || !out)
1451 return E_INVALIDARG;
1453 *out = NULL;
1455 threadref = heap_alloc(sizeof(*threadref));
1456 if (!threadref)
1457 return E_OUTOFMEMORY;
1458 threadref->IUnknown_iface.lpVtbl = &threadrefvtbl;
1459 threadref->refcount = refcount;
1461 *refcount = 1;
1462 *out = &threadref->IUnknown_iface;
1464 TRACE("Created %p.\n", threadref);
1465 return S_OK;
1468 /*************************************************************************
1469 * SHGetThreadRef [SHCORE.@]
1471 HRESULT WINAPI SHGetThreadRef(IUnknown **out)
1473 TRACE("(%p)\n", out);
1475 if (shcore_tls == TLS_OUT_OF_INDEXES)
1476 return E_NOINTERFACE;
1478 *out = TlsGetValue(shcore_tls);
1479 if (!*out)
1480 return E_NOINTERFACE;
1482 IUnknown_AddRef(*out);
1483 return S_OK;
1486 /*************************************************************************
1487 * SHSetThreadRef [SHCORE.@]
1489 HRESULT WINAPI SHSetThreadRef(IUnknown *obj)
1491 TRACE("(%p)\n", obj);
1493 if (shcore_tls == TLS_OUT_OF_INDEXES)
1494 return E_NOINTERFACE;
1496 TlsSetValue(shcore_tls, obj);
1497 return S_OK;
1500 /*************************************************************************
1501 * SHReleaseThreadRef [SHCORE.@]
1503 HRESULT WINAPI SHReleaseThreadRef(void)
1505 FIXME("() - stub!\n");
1506 return S_OK;
1509 /*************************************************************************
1510 * GetProcessReference [SHCORE.@]
1512 HRESULT WINAPI GetProcessReference(IUnknown **obj)
1514 TRACE("(%p)\n", obj);
1516 *obj = process_ref;
1518 if (!process_ref)
1519 return E_FAIL;
1521 if (*obj)
1522 IUnknown_AddRef(*obj);
1524 return S_OK;
1527 /*************************************************************************
1528 * SetProcessReference [SHCORE.@]
1530 void WINAPI SetProcessReference(IUnknown *obj)
1532 TRACE("(%p)\n", obj);
1534 process_ref = obj;
1537 struct thread_data
1539 LPTHREAD_START_ROUTINE thread_proc;
1540 LPTHREAD_START_ROUTINE callback;
1541 void *data;
1542 DWORD flags;
1543 HANDLE hEvent;
1544 IUnknown *thread_ref;
1545 IUnknown *process_ref;
1548 static DWORD WINAPI shcore_thread_wrapper(void *data)
1550 struct thread_data thread_data;
1551 HRESULT hr = E_FAIL;
1552 DWORD retval;
1554 TRACE("(%p)\n", data);
1556 /* We are now executing in the context of the newly created thread.
1557 * So we copy the data passed to us (it is on the stack of the function
1558 * that called us, which is waiting for us to signal an event before
1559 * returning). */
1560 thread_data = *(struct thread_data *)data;
1562 if (thread_data.flags & CTF_COINIT)
1564 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
1565 if (FAILED(hr))
1566 hr = CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE);
1569 if (thread_data.callback)
1570 thread_data.callback(thread_data.data);
1572 /* Signal the thread that created us; it can return now. */
1573 SetEvent(thread_data.hEvent);
1575 /* Execute the callers start code. */
1576 retval = thread_data.thread_proc(thread_data.data);
1578 /* Release thread and process references. */
1579 if (thread_data.thread_ref)
1580 IUnknown_Release(thread_data.thread_ref);
1582 if (thread_data.process_ref)
1583 IUnknown_Release(thread_data.process_ref);
1585 if (SUCCEEDED(hr))
1586 CoUninitialize();
1588 return retval;
1591 /*************************************************************************
1592 * SHCreateThread [SHCORE.@]
1594 BOOL WINAPI SHCreateThread(LPTHREAD_START_ROUTINE thread_proc, void *data, DWORD flags, LPTHREAD_START_ROUTINE callback)
1596 struct thread_data thread_data;
1597 BOOL called = FALSE;
1599 TRACE("(%p, %p, %#x, %p)\n", thread_proc, data, flags, callback);
1601 thread_data.thread_proc = thread_proc;
1602 thread_data.callback = callback;
1603 thread_data.data = data;
1604 thread_data.flags = flags;
1605 thread_data.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
1607 if (flags & CTF_THREAD_REF)
1608 SHGetThreadRef(&thread_data.thread_ref);
1609 else
1610 thread_data.thread_ref = NULL;
1612 if (flags & CTF_PROCESS_REF)
1613 GetProcessReference(&thread_data.process_ref);
1614 else
1615 thread_data.process_ref = NULL;
1617 /* Create the thread */
1618 if (thread_data.hEvent)
1620 HANDLE hThread;
1621 DWORD retval;
1623 hThread = CreateThread(NULL, 0, shcore_thread_wrapper, &thread_data, 0, &retval);
1624 if (hThread)
1626 /* Wait for the thread to signal us to continue */
1627 WaitForSingleObject(thread_data.hEvent, INFINITE);
1628 CloseHandle(hThread);
1629 called = TRUE;
1631 CloseHandle(thread_data.hEvent);
1634 if (!called)
1636 if (!thread_data.callback && flags & CTF_INSIST)
1638 /* Couldn't call, call synchronously */
1639 thread_data.thread_proc(data);
1640 called = TRUE;
1642 else
1644 if (thread_data.thread_ref)
1645 IUnknown_Release(thread_data.thread_ref);
1647 if (thread_data.process_ref)
1648 IUnknown_Release(thread_data.process_ref);
1652 return called;
1655 /*************************************************************************
1656 * SHStrDupW [SHCORE.@]
1658 HRESULT WINAPI SHStrDupW(const WCHAR *src, WCHAR **dest)
1660 size_t len;
1662 TRACE("(%s, %p)\n", debugstr_w(src), dest);
1664 *dest = NULL;
1666 if (!src)
1667 return E_INVALIDARG;
1669 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
1670 *dest = CoTaskMemAlloc(len);
1671 if (!*dest)
1672 return E_OUTOFMEMORY;
1674 memcpy(*dest, src, len);
1676 return S_OK;
1679 /*************************************************************************
1680 * SHStrDupA [SHCORE.@]
1682 HRESULT WINAPI SHStrDupA(const char *src, WCHAR **dest)
1684 DWORD len;
1686 *dest = NULL;
1688 if (!src)
1689 return E_INVALIDARG;
1691 len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
1692 *dest = CoTaskMemAlloc(len * sizeof(WCHAR));
1693 if (!*dest)
1694 return E_OUTOFMEMORY;
1696 MultiByteToWideChar(CP_ACP, 0, src, -1, *dest, len);
1698 return S_OK;
1701 /*************************************************************************
1702 * SHAnsiToAnsi [SHCORE.@]
1704 DWORD WINAPI SHAnsiToAnsi(const char *src, char *dest, int dest_len)
1706 DWORD ret;
1708 TRACE("(%s, %p, %d)\n", debugstr_a(src), dest, dest_len);
1710 if (!src || !dest || dest_len <= 0)
1711 return 0;
1713 lstrcpynA(dest, src, dest_len);
1714 ret = strlen(dest);
1716 return src[ret] ? 0 : ret + 1;
1719 /*************************************************************************
1720 * SHUnicodeToAnsi [SHCORE.@]
1722 DWORD WINAPI SHUnicodeToAnsi(const WCHAR *src, char *dest, int dest_len)
1724 int ret = 1;
1726 TRACE("(%s, %p, %d)\n", debugstr_w(src), dest, dest_len);
1728 if (!dest || !dest_len)
1729 return 0;
1731 if (src)
1733 ret = WideCharToMultiByte(CP_ACP, 0, src, -1, dest, dest_len, NULL, NULL);
1734 if (!ret)
1736 dest[dest_len - 1] = 0;
1737 ret = dest_len;
1740 else
1741 dest[0] = 0;
1743 return ret;
1746 /*************************************************************************
1747 * SHUnicodeToUnicode [SHCORE.@]
1749 DWORD WINAPI SHUnicodeToUnicode(const WCHAR *src, WCHAR *dest, int dest_len)
1751 DWORD ret;
1753 TRACE("(%s, %p, %d)\n", debugstr_w(src), dest, dest_len);
1755 if (!src || !dest || dest_len <= 0)
1756 return 0;
1758 lstrcpynW(dest, src, dest_len);
1759 ret = lstrlenW(dest);
1761 return src[ret] ? 0 : ret + 1;
1764 /*************************************************************************
1765 * SHAnsiToUnicode [SHCORE.@]
1767 DWORD WINAPI SHAnsiToUnicode(const char *src, WCHAR *dest, int dest_len)
1769 int ret = 1;
1771 TRACE("(%s, %p, %d)\n", debugstr_a(src), dest, dest_len);
1773 if (!dest || !dest_len)
1774 return 0;
1776 if (src)
1778 ret = MultiByteToWideChar(CP_ACP, 0, src, -1, dest, dest_len);
1779 if (!ret)
1781 dest[dest_len - 1] = 0;
1782 ret = dest_len;
1785 else
1786 dest[0] = 0;
1788 return ret;
1791 /*************************************************************************
1792 * SHRegDuplicateHKey [SHCORE.@]
1794 HKEY WINAPI SHRegDuplicateHKey(HKEY hKey)
1796 HKEY newKey = 0;
1798 RegOpenKeyExW(hKey, 0, 0, MAXIMUM_ALLOWED, &newKey);
1799 TRACE("new key is %p\n", newKey);
1800 return newKey;
1803 /*************************************************************************
1804 * SHDeleteEmptyKeyW [SHCORE.@]
1806 DWORD WINAPI SHDeleteEmptyKeyW(HKEY hkey, const WCHAR *subkey)
1808 DWORD ret, count = 0;
1809 HKEY hsubkey = 0;
1811 TRACE("(%p, %s)\n", hkey, debugstr_w(subkey));
1813 ret = RegOpenKeyExW(hkey, subkey, 0, KEY_READ, &hsubkey);
1814 if (!ret)
1816 ret = RegQueryInfoKeyW(hsubkey, NULL, NULL, NULL, &count,
1817 NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1818 RegCloseKey(hsubkey);
1819 if (!ret)
1821 if (count)
1822 ret = ERROR_KEY_HAS_CHILDREN;
1823 else
1824 ret = RegDeleteKeyW(hkey, subkey);
1828 return ret;
1831 /*************************************************************************
1832 * SHDeleteEmptyKeyA [SHCORE.@]
1834 DWORD WINAPI SHDeleteEmptyKeyA(HKEY hkey, const char *subkey)
1836 WCHAR *subkeyW = NULL;
1837 DWORD ret;
1839 TRACE("(%p, %s)\n", hkey, debugstr_a(subkey));
1841 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1842 return ERROR_OUTOFMEMORY;
1844 ret = SHDeleteEmptyKeyW(hkey, subkeyW);
1845 CoTaskMemFree(subkeyW);
1846 return ret;
1849 /*************************************************************************
1850 * SHDeleteKeyW [SHCORE.@]
1852 DWORD WINAPI SHDeleteKeyW(HKEY hkey, const WCHAR *subkey)
1854 TRACE("(%p, %s)\n", hkey, debugstr_w(subkey));
1856 return RegDeleteTreeW(hkey, subkey);
1859 /*************************************************************************
1860 * SHDeleteKeyA [SHCORE.@]
1862 DWORD WINAPI SHDeleteKeyA(HKEY hkey, const char *subkey)
1864 TRACE("(%p, %s)\n", hkey, debugstr_a(subkey));
1866 return RegDeleteTreeA(hkey, subkey);
1869 /*************************************************************************
1870 * SHDeleteValueW [SHCORE.@]
1872 DWORD WINAPI SHDeleteValueW(HKEY hkey, const WCHAR *subkey, const WCHAR *value)
1874 HKEY hsubkey;
1875 DWORD ret;
1877 TRACE("(%p, %s, %s)\n", hkey, debugstr_w(subkey), debugstr_w(value));
1879 ret = RegOpenKeyExW(hkey, subkey, 0, KEY_SET_VALUE, &hsubkey);
1880 if (!ret)
1882 ret = RegDeleteValueW(hsubkey, value);
1883 RegCloseKey(hsubkey);
1886 return ret;
1889 /*************************************************************************
1890 * SHDeleteValueA [SHCORE.@]
1892 DWORD WINAPI SHDeleteValueA(HKEY hkey, const char *subkey, const char *value)
1894 WCHAR *subkeyW = NULL, *valueW = NULL;
1895 DWORD ret;
1897 TRACE("(%p, %s, %s)\n", hkey, debugstr_a(subkey), debugstr_a(value));
1899 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1900 return ERROR_OUTOFMEMORY;
1901 if (value && FAILED(SHStrDupA(value, &valueW)))
1903 CoTaskMemFree(subkeyW);
1904 return ERROR_OUTOFMEMORY;
1907 ret = SHDeleteValueW(hkey, subkeyW, valueW);
1908 CoTaskMemFree(subkeyW);
1909 CoTaskMemFree(valueW);
1910 return ret;
1913 /*************************************************************************
1914 * SHCopyKeyA [SHCORE.@]
1916 DWORD WINAPI SHCopyKeyA(HKEY hkey_src, const char *subkey, HKEY hkey_dst, DWORD reserved)
1918 WCHAR *subkeyW = NULL;
1919 DWORD ret;
1921 TRACE("(%p, %s, %p, %d)\n", hkey_src, debugstr_a(subkey), hkey_dst, reserved);
1923 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1924 return 0;
1926 ret = SHCopyKeyW(hkey_src, subkeyW, hkey_dst, reserved);
1927 CoTaskMemFree(subkeyW);
1928 return ret;
1931 /*************************************************************************
1932 * SHCopyKeyW [SHCORE.@]
1934 DWORD WINAPI SHCopyKeyW(HKEY hkey_src, const WCHAR *subkey, HKEY hkey_dst, DWORD reserved)
1936 DWORD key_count = 0, value_count = 0, max_key_len = 0;
1937 WCHAR name[MAX_PATH], *ptr_name = name;
1938 BYTE buff[1024], *ptr = buff;
1939 DWORD max_data_len = 0, i;
1940 DWORD ret = 0;
1942 TRACE("(%p, %s, %p, %d)\n", hkey_src, debugstr_w(subkey), hkey_dst, reserved);
1944 if (!hkey_dst || !hkey_src)
1945 return ERROR_INVALID_PARAMETER;
1947 if (subkey)
1948 ret = RegOpenKeyExW(hkey_src, subkey, 0, KEY_ALL_ACCESS, &hkey_src);
1950 if (ret)
1951 hkey_src = NULL; /* Don't close this key since we didn't open it */
1952 else
1954 DWORD max_value_len;
1956 ret = RegQueryInfoKeyW(hkey_src, NULL, NULL, NULL, &key_count, &max_key_len,
1957 NULL, &value_count, &max_value_len, &max_data_len, NULL, NULL);
1958 if (!ret)
1960 /* Get max size for key/value names */
1961 max_key_len = max(max_key_len, max_value_len);
1963 if (max_key_len++ > MAX_PATH - 1)
1964 ptr_name = heap_alloc(max_key_len * sizeof(WCHAR));
1966 if (max_data_len > sizeof(buff))
1967 ptr = heap_alloc(max_data_len);
1969 if (!ptr_name || !ptr)
1970 ret = ERROR_NOT_ENOUGH_MEMORY;
1974 for (i = 0; i < key_count && !ret; i++)
1976 HKEY hsubkey_src, hsubkey_dst;
1977 DWORD length = max_key_len;
1979 ret = RegEnumKeyExW(hkey_src, i, ptr_name, &length, NULL, NULL, NULL, NULL);
1980 if (!ret)
1982 ret = RegOpenKeyExW(hkey_src, ptr_name, 0, KEY_READ, &hsubkey_src);
1983 if (!ret)
1985 /* Create destination sub key */
1986 ret = RegCreateKeyW(hkey_dst, ptr_name, &hsubkey_dst);
1987 if (!ret)
1989 /* Recursively copy keys and values from the sub key */
1990 ret = SHCopyKeyW(hsubkey_src, NULL, hsubkey_dst, 0);
1991 RegCloseKey(hsubkey_dst);
1994 RegCloseKey(hsubkey_src);
1998 /* Copy all the values in this key */
1999 for (i = 0; i < value_count && !ret; i++)
2001 DWORD length = max_key_len, type, data_len = max_data_len;
2003 ret = RegEnumValueW(hkey_src, i, ptr_name, &length, NULL, &type, ptr, &data_len);
2004 if (!ret) {
2005 ret = SHSetValueW(hkey_dst, NULL, ptr_name, type, ptr, data_len);
2009 /* Free buffers if allocated */
2010 if (ptr_name != name)
2011 heap_free(ptr_name);
2012 if (ptr != buff)
2013 heap_free(ptr);
2015 if (subkey && hkey_src)
2016 RegCloseKey(hkey_src);
2018 return ret;
2022 /*************************************************************************
2023 * SHEnumKeyExA [SHCORE.@]
2025 LONG WINAPI SHEnumKeyExA(HKEY hkey, DWORD index, char *subkey, DWORD *length)
2027 TRACE("(%p, %d, %s, %p)\n", hkey, index, debugstr_a(subkey), length);
2029 return RegEnumKeyExA(hkey, index, subkey, length, NULL, NULL, NULL, NULL);
2032 /*************************************************************************
2033 * SHEnumKeyExW [SHCORE.@]
2035 LONG WINAPI SHEnumKeyExW(HKEY hkey, DWORD index, WCHAR *subkey, DWORD *length)
2037 TRACE("(%p, %d, %s, %p)\n", hkey, index, debugstr_w(subkey), length);
2039 return RegEnumKeyExW(hkey, index, subkey, length, NULL, NULL, NULL, NULL);
2042 /*************************************************************************
2043 * SHEnumValueA [SHCORE.@]
2045 LONG WINAPI SHEnumValueA(HKEY hkey, DWORD index, char *value, DWORD *length, DWORD *type,
2046 void *data, DWORD *data_len)
2048 TRACE("(%p, %d, %s, %p, %p, %p, %p)\n", hkey, index, debugstr_a(value), length, type, data, data_len);
2050 return RegEnumValueA(hkey, index, value, length, NULL, type, data, data_len);
2053 /*************************************************************************
2054 * SHEnumValueW [SHCORE.@]
2056 LONG WINAPI SHEnumValueW(HKEY hkey, DWORD index, WCHAR *value, DWORD *length, DWORD *type,
2057 void *data, DWORD *data_len)
2059 TRACE("(%p, %d, %s, %p, %p, %p, %p)\n", hkey, index, debugstr_w(value), length, type, data, data_len);
2061 return RegEnumValueW(hkey, index, value, length, NULL, type, data, data_len);
2064 /*************************************************************************
2065 * SHQueryValueExW [SHCORE.@]
2067 DWORD WINAPI SHQueryValueExW(HKEY hkey, const WCHAR *name, DWORD *reserved, DWORD *type,
2068 void *buff, DWORD *buff_len)
2070 DWORD ret, value_type, data_len = 0;
2072 TRACE("(%p, %s, %p, %p, %p, %p)\n", hkey, debugstr_w(name), reserved, type, buff, buff_len);
2074 if (buff_len)
2075 data_len = *buff_len;
2077 ret = RegQueryValueExW(hkey, name, reserved, &value_type, buff, &data_len);
2078 if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)
2079 return ret;
2081 if (buff_len && value_type == REG_EXPAND_SZ)
2083 DWORD length;
2084 WCHAR *value;
2086 if (!buff || ret == ERROR_MORE_DATA)
2088 length = data_len;
2089 value = heap_alloc(length);
2090 RegQueryValueExW(hkey, name, reserved, NULL, (BYTE *)value, &length);
2091 length = ExpandEnvironmentStringsW(value, NULL, 0);
2093 else
2095 length = (lstrlenW(buff) + 1) * sizeof(WCHAR);
2096 value = heap_alloc(length);
2097 memcpy(value, buff, length);
2098 length = ExpandEnvironmentStringsW(value, buff, *buff_len / sizeof(WCHAR));
2099 if (length > *buff_len) ret = ERROR_MORE_DATA;
2101 data_len = max(data_len, length);
2102 heap_free(value);
2105 if (type)
2106 *type = value_type == REG_EXPAND_SZ ? REG_SZ : value_type;
2107 if (buff_len)
2108 *buff_len = data_len;
2109 return ret;
2112 /*************************************************************************
2113 * SHQueryValueExA [SHCORE.@]
2115 DWORD WINAPI SHQueryValueExA(HKEY hkey, const char *name, DWORD *reserved, DWORD *type,
2116 void *buff, DWORD *buff_len)
2118 DWORD ret, value_type, data_len = 0;
2120 TRACE("(%p, %s, %p, %p, %p, %p)\n", hkey, debugstr_a(name), reserved, type, buff, buff_len);
2122 if (buff_len)
2123 data_len = *buff_len;
2125 ret = RegQueryValueExA(hkey, name, reserved, &value_type, buff, &data_len);
2126 if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)
2127 return ret;
2129 if (buff_len && value_type == REG_EXPAND_SZ)
2131 DWORD length;
2132 char *value;
2134 if (!buff || ret == ERROR_MORE_DATA)
2136 length = data_len;
2137 value = heap_alloc(length);
2138 RegQueryValueExA(hkey, name, reserved, NULL, (BYTE *)value, &length);
2139 length = ExpandEnvironmentStringsA(value, NULL, 0);
2141 else
2143 length = strlen(buff) + 1;
2144 value = heap_alloc(length);
2145 memcpy(value, buff, length);
2146 length = ExpandEnvironmentStringsA(value, buff, *buff_len);
2147 if (length > *buff_len) ret = ERROR_MORE_DATA;
2149 data_len = max(data_len, length);
2150 heap_free(value);
2153 if (type)
2154 *type = value_type == REG_EXPAND_SZ ? REG_SZ : value_type;
2155 if (buff_len)
2156 *buff_len = data_len;
2157 return ret;
2160 /*************************************************************************
2161 * SHGetValueA [SHCORE.@]
2163 DWORD WINAPI SHGetValueA(HKEY hkey, const char *subkey, const char *value,
2164 DWORD *type, void *data, DWORD *data_len)
2166 HKEY hsubkey = 0;
2167 DWORD ret = 0;
2169 TRACE("(%p, %s, %s, %p, %p, %p)\n", hkey, debugstr_a(subkey), debugstr_a(value),
2170 type, data, data_len);
2172 if (subkey)
2173 ret = RegOpenKeyExA(hkey, subkey, 0, KEY_QUERY_VALUE, &hsubkey);
2175 if (!ret)
2177 ret = SHQueryValueExA(hsubkey ? hsubkey : hkey, value, 0, type, data, data_len);
2178 if (subkey)
2179 RegCloseKey(hsubkey);
2182 return ret;
2185 /*************************************************************************
2186 * SHGetValueW [SHCORE.@]
2188 DWORD WINAPI SHGetValueW(HKEY hkey, const WCHAR *subkey, const WCHAR *value,
2189 DWORD *type, void *data, DWORD *data_len)
2191 HKEY hsubkey = 0;
2192 DWORD ret = 0;
2194 TRACE("(%p, %s, %s, %p, %p, %p)\n", hkey, debugstr_w(subkey), debugstr_w(value),
2195 type, data, data_len);
2197 if (subkey)
2198 ret = RegOpenKeyExW(hkey, subkey, 0, KEY_QUERY_VALUE, &hsubkey);
2200 if (!ret)
2202 ret = SHQueryValueExW(hsubkey ? hsubkey : hkey, value, 0, type, data, data_len);
2203 if (subkey)
2204 RegCloseKey(hsubkey);
2207 return ret;
2210 /*************************************************************************
2211 * SHRegGetIntW [SHCORE.280]
2213 int WINAPI SHRegGetIntW(HKEY hkey, const WCHAR *value, int default_value)
2215 WCHAR buff[32];
2216 DWORD buff_len;
2218 TRACE("(%p, %s, %d)\n", hkey, debugstr_w(value), default_value);
2220 buff[0] = 0;
2221 buff_len = sizeof(buff);
2222 if (SHQueryValueExW(hkey, value, 0, 0, buff, &buff_len))
2223 return default_value;
2225 if (*buff >= '0' && *buff <= '9')
2226 return wcstol(buff, NULL, 10);
2228 return default_value;
2231 /*************************************************************************
2232 * SHRegGetPathA [SHCORE.@]
2234 DWORD WINAPI SHRegGetPathA(HKEY hkey, const char *subkey, const char *value, char *path, DWORD flags)
2236 DWORD length = MAX_PATH;
2238 TRACE("(%p, %s, %s, %p, %#x)\n", hkey, debugstr_a(subkey), debugstr_a(value), path, flags);
2240 return SHGetValueA(hkey, subkey, value, 0, path, &length);
2243 /*************************************************************************
2244 * SHRegGetPathW [SHCORE.@]
2246 DWORD WINAPI SHRegGetPathW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, WCHAR *path, DWORD flags)
2248 DWORD length = MAX_PATH;
2250 TRACE("(%p, %s, %s, %p, %d)\n", hkey, debugstr_w(subkey), debugstr_w(value), path, flags);
2252 return SHGetValueW(hkey, subkey, value, 0, path, &length);
2255 /*************************************************************************
2256 * SHSetValueW [SHCORE.@]
2258 DWORD WINAPI SHSetValueW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, DWORD type,
2259 const void *data, DWORD data_len)
2261 DWORD ret = ERROR_SUCCESS, dummy;
2262 HKEY hsubkey;
2264 TRACE("(%p, %s, %s, %d, %p, %d)\n", hkey, debugstr_w(subkey), debugstr_w(value),
2265 type, data, data_len);
2267 if (subkey && *subkey)
2268 ret = RegCreateKeyExW(hkey, subkey, 0, NULL, 0, KEY_SET_VALUE, NULL, &hsubkey, &dummy);
2269 else
2270 hsubkey = hkey;
2272 if (!ret)
2274 ret = RegSetValueExW(hsubkey, value, 0, type, data, data_len);
2275 if (hsubkey != hkey)
2276 RegCloseKey(hsubkey);
2279 return ret;
2282 /*************************************************************************
2283 * SHSetValueA [SHCORE.@]
2285 DWORD WINAPI SHSetValueA(HKEY hkey, const char *subkey, const char *value,
2286 DWORD type, const void *data, DWORD data_len)
2288 DWORD ret = ERROR_SUCCESS, dummy;
2289 HKEY hsubkey;
2291 TRACE("(%p, %s, %s, %d, %p, %d)\n", hkey, debugstr_a(subkey), debugstr_a(value),
2292 type, data, data_len);
2294 if (subkey && *subkey)
2295 ret = RegCreateKeyExA(hkey, subkey, 0, NULL, 0, KEY_SET_VALUE, NULL, &hsubkey, &dummy);
2296 else
2297 hsubkey = hkey;
2299 if (!ret)
2301 ret = RegSetValueExA(hsubkey, value, 0, type, data, data_len);
2302 if (hsubkey != hkey)
2303 RegCloseKey(hsubkey);
2306 return ret;
2309 /*************************************************************************
2310 * SHRegSetPathA [SHCORE.@]
2312 DWORD WINAPI SHRegSetPathA(HKEY hkey, const char *subkey, const char *value, const char *path, DWORD flags)
2314 FIXME("(%p, %s, %s, %s, %#x) - semi-stub\n", hkey, debugstr_a(subkey),
2315 debugstr_a(value), debugstr_a(path), flags);
2317 /* FIXME: PathUnExpandEnvStringsA() */
2319 return SHSetValueA(hkey, subkey, value, REG_SZ, path, lstrlenA(path));
2322 /*************************************************************************
2323 * SHRegSetPathW [SHCORE.@]
2325 DWORD WINAPI SHRegSetPathW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, const WCHAR *path, DWORD flags)
2327 FIXME("(%p, %s, %s, %s, %#x) - semi-stub\n", hkey, debugstr_w(subkey),
2328 debugstr_w(value), debugstr_w(path), flags);
2330 /* FIXME: PathUnExpandEnvStringsW(); */
2332 return SHSetValueW(hkey, subkey, value, REG_SZ, path, lstrlenW(path));
2335 /*************************************************************************
2336 * SHQueryInfoKeyA [SHCORE.@]
2338 LONG WINAPI SHQueryInfoKeyA(HKEY hkey, DWORD *subkeys, DWORD *subkey_max, DWORD *values, DWORD *value_max)
2340 TRACE("(%p, %p, %p, %p, %p)\n", hkey, subkeys, subkey_max, values, value_max);
2342 return RegQueryInfoKeyA(hkey, NULL, NULL, NULL, subkeys, subkey_max, NULL, values, value_max, NULL, NULL, NULL);
2345 /*************************************************************************
2346 * SHQueryInfoKeyW [SHCORE.@]
2348 LONG WINAPI SHQueryInfoKeyW(HKEY hkey, DWORD *subkeys, DWORD *subkey_max, DWORD *values, DWORD *value_max)
2350 TRACE("(%p, %p, %p, %p, %p)\n", hkey, subkeys, subkey_max, values, value_max);
2352 return RegQueryInfoKeyW(hkey, NULL, NULL, NULL, subkeys, subkey_max, NULL, values, value_max, NULL, NULL, NULL);
2355 /*************************************************************************
2356 * IsOS [SHCORE.@]
2358 BOOL WINAPI IsOS(DWORD feature)
2360 DWORD platform, majorv, minorv;
2361 OSVERSIONINFOA osvi;
2363 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
2364 if (!GetVersionExA(&osvi))
2365 return FALSE;
2367 majorv = osvi.dwMajorVersion;
2368 minorv = osvi.dwMinorVersion;
2369 platform = osvi.dwPlatformId;
2371 #define ISOS_RETURN(x) \
2372 TRACE("(0x%x) ret=%d\n",feature,(x)); \
2373 return (x)
2375 switch(feature) {
2376 case OS_WIN32SORGREATER:
2377 ISOS_RETURN(platform == VER_PLATFORM_WIN32s
2378 || platform == VER_PLATFORM_WIN32_WINDOWS);
2379 case OS_NT:
2380 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2381 case OS_WIN95ORGREATER:
2382 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS);
2383 case OS_NT4ORGREATER:
2384 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 4);
2385 case OS_WIN2000ORGREATER_ALT:
2386 case OS_WIN2000ORGREATER:
2387 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5);
2388 case OS_WIN98ORGREATER:
2389 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 10);
2390 case OS_WIN98_GOLD:
2391 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 10);
2392 case OS_WIN2000PRO:
2393 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5);
2394 case OS_WIN2000SERVER:
2395 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2396 case OS_WIN2000ADVSERVER:
2397 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2398 case OS_WIN2000DATACENTER:
2399 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2400 case OS_WIN2000TERMINAL:
2401 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2402 case OS_EMBEDDED:
2403 FIXME("(OS_EMBEDDED) What should we return here?\n");
2404 return FALSE;
2405 case OS_TERMINALCLIENT:
2406 FIXME("(OS_TERMINALCLIENT) What should we return here?\n");
2407 return FALSE;
2408 case OS_TERMINALREMOTEADMIN:
2409 FIXME("(OS_TERMINALREMOTEADMIN) What should we return here?\n");
2410 return FALSE;
2411 case OS_WIN95_GOLD:
2412 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 0);
2413 case OS_MEORGREATER:
2414 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 90);
2415 case OS_XPORGREATER:
2416 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1);
2417 case OS_HOME:
2418 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1);
2419 case OS_PROFESSIONAL:
2420 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2421 case OS_DATACENTER:
2422 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2423 case OS_ADVSERVER:
2424 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5);
2425 case OS_SERVER:
2426 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2427 case OS_TERMINALSERVER:
2428 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2429 case OS_PERSONALTERMINALSERVER:
2430 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && minorv >= 1 && majorv >= 5);
2431 case OS_FASTUSERSWITCHING:
2432 FIXME("(OS_FASTUSERSWITCHING) What should we return here?\n");
2433 return TRUE;
2434 case OS_WELCOMELOGONUI:
2435 FIXME("(OS_WELCOMELOGONUI) What should we return here?\n");
2436 return FALSE;
2437 case OS_DOMAINMEMBER:
2438 FIXME("(OS_DOMAINMEMBER) What should we return here?\n");
2439 return TRUE;
2440 case OS_ANYSERVER:
2441 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2442 case OS_WOW6432:
2444 BOOL is_wow64;
2445 IsWow64Process(GetCurrentProcess(), &is_wow64);
2446 return is_wow64;
2448 case OS_WEBSERVER:
2449 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2450 case OS_SMALLBUSINESSSERVER:
2451 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2452 case OS_TABLETPC:
2453 FIXME("(OS_TABLETPC) What should we return here?\n");
2454 return FALSE;
2455 case OS_SERVERADMINUI:
2456 FIXME("(OS_SERVERADMINUI) What should we return here?\n");
2457 return FALSE;
2458 case OS_MEDIACENTER:
2459 FIXME("(OS_MEDIACENTER) What should we return here?\n");
2460 return FALSE;
2461 case OS_APPLIANCE:
2462 FIXME("(OS_APPLIANCE) What should we return here?\n");
2463 return FALSE;
2464 case 0x25: /*OS_VISTAORGREATER*/
2465 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 6);
2468 #undef ISOS_RETURN
2470 WARN("(0x%x) unknown parameter\n", feature);
2472 return FALSE;