include: Add X3DAUDIO_CALCULATE_* defines.
[wine.git] / dlls / shcore / main.c
blob3f95c1ffd872b5541ffc6061253f2f8395c76c1f
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 HRESULT WINAPI _IStream_Read(IStream *stream, void *dest, ULONG size)
91 ULONG read;
92 HRESULT hr;
94 TRACE("(%p, %p, %u)\n", stream, dest, size);
96 hr = IStream_Read(stream, dest, size, &read);
97 if (SUCCEEDED(hr) && read != size)
98 hr = E_FAIL;
99 return hr;
102 HRESULT WINAPI IStream_Reset(IStream *stream)
104 static const LARGE_INTEGER zero;
106 TRACE("(%p)\n", stream);
108 return IStream_Seek(stream, zero, 0, NULL);
111 HRESULT WINAPI IStream_Size(IStream *stream, ULARGE_INTEGER *size)
113 STATSTG statstg;
114 HRESULT hr;
116 TRACE("(%p, %p)\n", stream, size);
118 memset(&statstg, 0, sizeof(statstg));
120 hr = IStream_Stat(stream, &statstg, STATFLAG_NONAME);
122 if (SUCCEEDED(hr) && size)
123 *size = statstg.cbSize;
124 return hr;
127 HRESULT WINAPI _IStream_Write(IStream *stream, const void *src, ULONG size)
129 ULONG written;
130 HRESULT hr;
132 TRACE("(%p, %p, %u)\n", stream, src, size);
134 hr = IStream_Write(stream, src, size, &written);
135 if (SUCCEEDED(hr) && written != size)
136 hr = E_FAIL;
138 return hr;
141 void WINAPI IUnknown_AtomicRelease(IUnknown **obj)
143 TRACE("(%p)\n", obj);
145 if (!obj || !*obj)
146 return;
148 IUnknown_Release(*obj);
149 *obj = NULL;
152 HRESULT WINAPI IUnknown_GetSite(IUnknown *unk, REFIID iid, void **site)
154 IObjectWithSite *obj = NULL;
155 HRESULT hr = E_INVALIDARG;
157 TRACE("(%p, %s, %p)\n", unk, debugstr_guid(iid), site);
159 if (unk && iid && site)
161 hr = IUnknown_QueryInterface(unk, &IID_IObjectWithSite, (void **)&obj);
162 if (SUCCEEDED(hr) && obj)
164 hr = IObjectWithSite_GetSite(obj, iid, site);
165 IObjectWithSite_Release(obj);
169 return hr;
172 HRESULT WINAPI IUnknown_QueryService(IUnknown *obj, REFGUID sid, REFIID iid, void **out)
174 IServiceProvider *provider = NULL;
175 HRESULT hr;
177 if (!out)
178 return E_FAIL;
180 *out = NULL;
182 if (!obj)
183 return E_FAIL;
185 hr = IUnknown_QueryInterface(obj, &IID_IServiceProvider, (void **)&provider);
186 if (hr == S_OK && provider)
188 TRACE("Using provider %p.\n", provider);
190 hr = IServiceProvider_QueryService(provider, sid, iid, out);
192 TRACE("Provider %p returned %p.\n", provider, *out);
194 IServiceProvider_Release(provider);
197 return hr;
200 void WINAPI IUnknown_Set(IUnknown **dest, IUnknown *src)
202 TRACE("(%p, %p)\n", dest, src);
204 IUnknown_AtomicRelease(dest);
206 if (src)
208 IUnknown_AddRef(src);
209 *dest = src;
213 HRESULT WINAPI IUnknown_SetSite(IUnknown *obj, IUnknown *site)
215 IInternetSecurityManager *sec_manager;
216 IObjectWithSite *objwithsite;
217 HRESULT hr;
219 if (!obj)
220 return E_FAIL;
222 hr = IUnknown_QueryInterface(obj, &IID_IObjectWithSite, (void **)&objwithsite);
223 TRACE("ObjectWithSite %p, hr %#x.\n", objwithsite, hr);
224 if (SUCCEEDED(hr))
226 hr = IObjectWithSite_SetSite(objwithsite, site);
227 TRACE("SetSite() hr %#x.\n", hr);
228 IObjectWithSite_Release(objwithsite);
230 else
232 hr = IUnknown_QueryInterface(obj, &IID_IInternetSecurityManager, (void **)&sec_manager);
233 TRACE("InternetSecurityManager %p, hr %#x.\n", sec_manager, hr);
234 if (FAILED(hr))
235 return hr;
237 hr = IInternetSecurityManager_SetSecuritySite(sec_manager, (IInternetSecurityMgrSite *)site);
238 TRACE("SetSecuritySite() hr %#x.\n", hr);
239 IInternetSecurityManager_Release(sec_manager);
242 return hr;
245 HRESULT WINAPI SetCurrentProcessExplicitAppUserModelID(const WCHAR *appid)
247 FIXME("%s: stub\n", debugstr_w(appid));
248 return E_NOTIMPL;
251 HRESULT WINAPI GetCurrentProcessExplicitAppUserModelID(const WCHAR **appid)
253 FIXME("%p: stub\n", appid);
254 *appid = NULL;
255 return E_NOTIMPL;
258 /*************************************************************************
259 * CommandLineToArgvW [SHCORE.@]
261 * We must interpret the quotes in the command line to rebuild the argv
262 * array correctly:
263 * - arguments are separated by spaces or tabs
264 * - quotes serve as optional argument delimiters
265 * '"a b"' -> 'a b'
266 * - escaped quotes must be converted back to '"'
267 * '\"' -> '"'
268 * - consecutive backslashes preceding a quote see their number halved with
269 * the remainder escaping the quote:
270 * 2n backslashes + quote -> n backslashes + quote as an argument delimiter
271 * 2n+1 backslashes + quote -> n backslashes + literal quote
272 * - backslashes that are not followed by a quote are copied literally:
273 * 'a\b' -> 'a\b'
274 * 'a\\b' -> 'a\\b'
275 * - in quoted strings, consecutive quotes see their number divided by three
276 * with the remainder modulo 3 deciding whether to close the string or not.
277 * Note that the opening quote must be counted in the consecutive quotes,
278 * that's the (1+) below:
279 * (1+) 3n quotes -> n quotes
280 * (1+) 3n+1 quotes -> n quotes plus closes the quoted string
281 * (1+) 3n+2 quotes -> n+1 quotes plus closes the quoted string
282 * - in unquoted strings, the first quote opens the quoted string and the
283 * remaining consecutive quotes follow the above rule.
285 WCHAR** WINAPI CommandLineToArgvW(const WCHAR *cmdline, int *numargs)
287 int qcount, bcount;
288 const WCHAR *s;
289 WCHAR **argv;
290 DWORD argc;
291 WCHAR *d;
293 if (!numargs)
295 SetLastError(ERROR_INVALID_PARAMETER);
296 return NULL;
299 if (*cmdline == 0)
301 /* Return the path to the executable */
302 DWORD len, deslen = MAX_PATH, size;
304 size = sizeof(WCHAR *) * 2 + deslen * sizeof(WCHAR);
305 for (;;)
307 if (!(argv = LocalAlloc(LMEM_FIXED, size))) return NULL;
308 len = GetModuleFileNameW(0, (WCHAR *)(argv + 2), deslen);
309 if (!len)
311 LocalFree(argv);
312 return NULL;
314 if (len < deslen) break;
315 deslen *= 2;
316 size = sizeof(WCHAR *) * 2 + deslen * sizeof(WCHAR);
317 LocalFree(argv);
319 argv[0] = (WCHAR *)(argv + 2);
320 argv[1] = NULL;
321 *numargs = 1;
323 return argv;
326 /* --- First count the arguments */
327 argc = 1;
328 s = cmdline;
329 /* The first argument, the executable path, follows special rules */
330 if (*s == '"')
332 /* The executable path ends at the next quote, no matter what */
333 s++;
334 while (*s)
335 if (*s++ == '"')
336 break;
338 else
340 /* The executable path ends at the next space, no matter what */
341 while (*s && *s != ' ' && *s != '\t')
342 s++;
344 /* skip to the first argument, if any */
345 while (*s == ' ' || *s == '\t')
346 s++;
347 if (*s)
348 argc++;
350 /* Analyze the remaining arguments */
351 qcount = bcount = 0;
352 while (*s)
354 if ((*s == ' ' || *s == '\t') && qcount == 0)
356 /* skip to the next argument and count it if any */
357 while (*s == ' ' || *s == '\t')
358 s++;
359 if (*s)
360 argc++;
361 bcount = 0;
363 else if (*s == '\\')
365 /* '\', count them */
366 bcount++;
367 s++;
369 else if (*s == '"')
371 /* '"' */
372 if ((bcount & 1) == 0)
373 qcount++; /* unescaped '"' */
374 s++;
375 bcount = 0;
376 /* consecutive quotes, see comment in copying code below */
377 while (*s == '"')
379 qcount++;
380 s++;
382 qcount = qcount % 3;
383 if (qcount == 2)
384 qcount = 0;
386 else
388 /* a regular character */
389 bcount = 0;
390 s++;
394 /* Allocate in a single lump, the string array, and the strings that go
395 * with it. This way the caller can make a single LocalFree() call to free
396 * both, as per MSDN.
398 argv = LocalAlloc(LMEM_FIXED, (argc + 1) * sizeof(WCHAR *) + (lstrlenW(cmdline) + 1) * sizeof(WCHAR));
399 if (!argv)
400 return NULL;
402 /* --- Then split and copy the arguments */
403 argv[0] = d = lstrcpyW((WCHAR *)(argv + argc + 1), cmdline);
404 argc = 1;
405 /* The first argument, the executable path, follows special rules */
406 if (*d == '"')
408 /* The executable path ends at the next quote, no matter what */
409 s = d + 1;
410 while (*s)
412 if (*s == '"')
414 s++;
415 break;
417 *d++ = *s++;
420 else
422 /* The executable path ends at the next space, no matter what */
423 while (*d && *d != ' ' && *d != '\t')
424 d++;
425 s = d;
426 if (*s)
427 s++;
429 /* close the executable path */
430 *d++ = 0;
431 /* skip to the first argument and initialize it if any */
432 while (*s == ' ' || *s == '\t')
433 s++;
434 if (!*s)
436 /* There are no parameters so we are all done */
437 argv[argc] = NULL;
438 *numargs = argc;
439 return argv;
442 /* Split and copy the remaining arguments */
443 argv[argc++] = d;
444 qcount = bcount = 0;
445 while (*s)
447 if ((*s == ' ' || *s == '\t') && qcount == 0)
449 /* close the argument */
450 *d++ = 0;
451 bcount = 0;
453 /* skip to the next one and initialize it if any */
454 do {
455 s++;
456 } while (*s == ' ' || *s == '\t');
457 if (*s)
458 argv[argc++] = d;
460 else if (*s=='\\')
462 *d++ = *s++;
463 bcount++;
465 else if (*s == '"')
467 if ((bcount & 1) == 0)
469 /* Preceded by an even number of '\', this is half that
470 * number of '\', plus a quote which we erase.
472 d -= bcount / 2;
473 qcount++;
475 else
477 /* Preceded by an odd number of '\', this is half that
478 * number of '\' followed by a '"'
480 d = d - bcount / 2 - 1;
481 *d++ = '"';
483 s++;
484 bcount = 0;
485 /* Now count the number of consecutive quotes. Note that qcount
486 * already takes into account the opening quote if any, as well as
487 * the quote that lead us here.
489 while (*s == '"')
491 if (++qcount == 3)
493 *d++ = '"';
494 qcount = 0;
496 s++;
498 if (qcount == 2)
499 qcount = 0;
501 else
503 /* a regular character */
504 *d++ = *s++;
505 bcount = 0;
508 *d = '\0';
509 argv[argc] = NULL;
510 *numargs = argc;
512 return argv;
515 struct shstream
517 IStream IStream_iface;
518 LONG refcount;
520 union
522 struct
524 BYTE *buffer;
525 DWORD length;
526 DWORD position;
528 HKEY hkey;
529 WCHAR *valuename;
530 } mem;
531 struct
533 HANDLE handle;
534 DWORD mode;
535 WCHAR *path;
536 } file;
537 } u;
540 static inline struct shstream *impl_from_IStream(IStream *iface)
542 return CONTAINING_RECORD(iface, struct shstream, IStream_iface);
545 static HRESULT WINAPI shstream_QueryInterface(IStream *iface, REFIID riid, void **out)
547 struct shstream *stream = impl_from_IStream(iface);
549 TRACE("(%p)->(%s, %p)\n", stream, debugstr_guid(riid), out);
551 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IStream))
553 *out = iface;
554 IStream_AddRef(iface);
555 return S_OK;
558 *out = NULL;
559 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
560 return E_NOINTERFACE;
563 static ULONG WINAPI shstream_AddRef(IStream *iface)
565 struct shstream *stream = impl_from_IStream(iface);
566 ULONG refcount = InterlockedIncrement(&stream->refcount);
568 TRACE("(%p)->(%u)\n", stream, refcount);
570 return refcount;
573 static ULONG WINAPI memstream_Release(IStream *iface)
575 struct shstream *stream = impl_from_IStream(iface);
576 ULONG refcount = InterlockedDecrement(&stream->refcount);
578 TRACE("(%p)->(%u)\n", stream, refcount);
580 if (!refcount)
582 heap_free(stream->u.mem.buffer);
583 heap_free(stream);
586 return refcount;
589 static HRESULT WINAPI memstream_Read(IStream *iface, void *buff, ULONG buff_size, ULONG *read_len)
591 struct shstream *stream = impl_from_IStream(iface);
592 DWORD length;
594 TRACE("(%p)->(%p, %u, %p)\n", stream, buff, buff_size, read_len);
596 if (stream->u.mem.position >= stream->u.mem.length)
597 length = 0;
598 else
599 length = stream->u.mem.length - stream->u.mem.position;
601 length = buff_size > length ? length : buff_size;
602 if (length != 0) /* not at end of buffer and we want to read something */
604 memmove(buff, stream->u.mem.buffer + stream->u.mem.position, length);
605 stream->u.mem.position += length; /* adjust pointer */
608 if (read_len)
609 *read_len = length;
611 return S_OK;
614 static HRESULT WINAPI memstream_Write(IStream *iface, const void *buff, ULONG buff_size, ULONG *written)
616 struct shstream *stream = impl_from_IStream(iface);
617 DWORD length = stream->u.mem.position + buff_size;
619 TRACE("(%p)->(%p, %u, %p)\n", stream, buff, buff_size, written);
621 if (length < stream->u.mem.position) /* overflow */
622 return STG_E_INSUFFICIENTMEMORY;
624 if (length > stream->u.mem.length)
626 BYTE *buffer = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, stream->u.mem.buffer, length);
627 if (!buffer)
628 return STG_E_INSUFFICIENTMEMORY;
630 stream->u.mem.length = length;
631 stream->u.mem.buffer = buffer;
633 memmove(stream->u.mem.buffer + stream->u.mem.position, buff, buff_size);
634 stream->u.mem.position += buff_size; /* adjust pointer */
636 if (written)
637 *written = buff_size;
639 return S_OK;
642 static HRESULT WINAPI memstream_Seek(IStream *iface, LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER*new_pos)
644 struct shstream *stream = impl_from_IStream(iface);
645 LARGE_INTEGER tmp;
647 TRACE("(%p)->(%s, %d, %p)\n", stream, wine_dbgstr_longlong(move.QuadPart), origin, new_pos);
649 if (origin == STREAM_SEEK_SET)
650 tmp = move;
651 else if (origin == STREAM_SEEK_CUR)
652 tmp.QuadPart = stream->u.mem.position + move.QuadPart;
653 else if (origin == STREAM_SEEK_END)
654 tmp.QuadPart = stream->u.mem.length + move.QuadPart;
655 else
656 return STG_E_INVALIDPARAMETER;
658 if (tmp.QuadPart < 0)
659 return STG_E_INVALIDFUNCTION;
661 /* we cut off the high part here */
662 stream->u.mem.position = tmp.u.LowPart;
664 if (new_pos)
665 new_pos->QuadPart = stream->u.mem.position;
666 return S_OK;
669 static HRESULT WINAPI memstream_SetSize(IStream *iface, ULARGE_INTEGER new_size)
671 struct shstream *stream = impl_from_IStream(iface);
672 DWORD length;
673 BYTE *buffer;
675 TRACE("(%p, %s)\n", stream, wine_dbgstr_longlong(new_size.QuadPart));
677 /* we cut off the high part here */
678 length = new_size.u.LowPart;
679 buffer = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, stream->u.mem.buffer, length);
680 if (!buffer)
681 return STG_E_INSUFFICIENTMEMORY;
683 stream->u.mem.buffer = buffer;
684 stream->u.mem.length = length;
686 return S_OK;
689 static HRESULT WINAPI shstream_CopyTo(IStream *iface, IStream *pstm, ULARGE_INTEGER size, ULARGE_INTEGER *read_len, ULARGE_INTEGER *written)
691 struct shstream *stream = impl_from_IStream(iface);
693 TRACE("(%p)\n", stream);
695 if (read_len)
696 read_len->QuadPart = 0;
698 if (written)
699 written->QuadPart = 0;
701 /* TODO implement */
702 return E_NOTIMPL;
705 static HRESULT WINAPI shstream_Commit(IStream *iface, DWORD flags)
707 struct shstream *stream = impl_from_IStream(iface);
709 TRACE("(%p, %#x)\n", stream, flags);
711 /* Commit is not supported by this stream */
712 return E_NOTIMPL;
715 static HRESULT WINAPI shstream_Revert(IStream *iface)
717 struct shstream *stream = impl_from_IStream(iface);
719 TRACE("(%p)\n", stream);
721 /* revert not supported by this stream */
722 return E_NOTIMPL;
725 static HRESULT WINAPI shstream_LockRegion(IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER size, DWORD lock_type)
727 struct shstream *stream = impl_from_IStream(iface);
729 TRACE("(%p)\n", stream);
731 /* lock/unlock not supported by this stream */
732 return E_NOTIMPL;
735 static HRESULT WINAPI shstream_UnlockRegion(IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER size, DWORD lock_type)
737 struct shstream *stream = impl_from_IStream(iface);
739 TRACE("(%p)\n", stream);
741 /* lock/unlock not supported by this stream */
742 return E_NOTIMPL;
745 static HRESULT WINAPI memstream_Stat(IStream *iface, STATSTG *statstg, DWORD flags)
747 struct shstream *stream = impl_from_IStream(iface);
749 TRACE("(%p, %p, %#x)\n", stream, statstg, flags);
751 memset(statstg, 0, sizeof(*statstg));
752 statstg->type = STGTY_STREAM;
753 statstg->cbSize.QuadPart = stream->u.mem.length;
754 statstg->grfMode = STGM_READWRITE;
756 return S_OK;
759 static HRESULT WINAPI shstream_Clone(IStream *iface, IStream **dest)
761 struct shstream *stream = impl_from_IStream(iface);
763 TRACE("(%p, %p)\n", stream, dest);
765 *dest = NULL;
767 /* clone not supported by this stream */
768 return E_NOTIMPL;
771 static const IStreamVtbl memstreamvtbl =
773 shstream_QueryInterface,
774 shstream_AddRef,
775 memstream_Release,
776 memstream_Read,
777 memstream_Write,
778 memstream_Seek,
779 memstream_SetSize,
780 shstream_CopyTo,
781 shstream_Commit,
782 shstream_Revert,
783 shstream_LockRegion,
784 shstream_UnlockRegion,
785 memstream_Stat,
786 shstream_Clone,
789 static struct shstream *shstream_create(const IStreamVtbl *vtbl, const BYTE *data, UINT data_len)
791 struct shstream *stream;
793 if (!data)
794 data_len = 0;
796 stream = heap_alloc(sizeof(*stream));
797 stream->IStream_iface.lpVtbl = vtbl;
798 stream->refcount = 1;
799 stream->u.mem.buffer = heap_alloc(data_len);
800 if (!stream->u.mem.buffer)
802 heap_free(stream);
803 return NULL;
805 memcpy(stream->u.mem.buffer, data, data_len);
806 stream->u.mem.length = data_len;
807 stream->u.mem.position = 0;
809 return stream;
812 /*************************************************************************
813 * SHCreateMemStream [SHCORE.@]
815 * Create an IStream object on a block of memory.
817 * PARAMS
818 * data [I] Memory block to create the IStream object on
819 * data_len [I] Length of data block
821 * RETURNS
822 * Success: A pointer to the IStream object.
823 * Failure: NULL, if any parameters are invalid or an error occurs.
825 * NOTES
826 * A copy of the memory block is made, it's freed when the stream is released.
828 IStream * WINAPI SHCreateMemStream(const BYTE *data, UINT data_len)
830 struct shstream *stream;
832 TRACE("(%p, %u)\n", data, data_len);
834 stream = shstream_create(&memstreamvtbl, data, data_len);
835 return stream ? &stream->IStream_iface : NULL;
838 static ULONG WINAPI filestream_Release(IStream *iface)
840 struct shstream *stream = impl_from_IStream(iface);
841 ULONG refcount = InterlockedDecrement(&stream->refcount);
843 TRACE("(%p)->(%u)\n", stream, refcount);
845 if (!refcount)
847 CloseHandle(stream->u.file.handle);
848 heap_free(stream->u.file.path);
849 heap_free(stream);
852 return refcount;
855 static HRESULT WINAPI filestream_Read(IStream *iface, void *buff, ULONG size, ULONG *read_len)
857 struct shstream *stream = impl_from_IStream(iface);
858 DWORD read = 0;
860 TRACE("(%p, %p, %u, %p)\n", stream, buff, size, read_len);
862 if (!ReadFile(stream->u.file.handle, buff, size, &read, NULL))
864 WARN("error %d reading file\n", GetLastError());
865 return S_FALSE;
868 if (read_len)
869 *read_len = read;
871 return read == size ? S_OK : S_FALSE;
874 static HRESULT WINAPI filestream_Write(IStream *iface, const void *buff, ULONG size, ULONG *written)
876 struct shstream *stream = impl_from_IStream(iface);
877 DWORD written_len = 0;
879 TRACE("(%p, %p, %u, %p)\n", stream, buff, size, written);
881 switch (stream->u.file.mode & 0xf)
883 case STGM_WRITE:
884 case STGM_READWRITE:
885 break;
886 default:
887 return STG_E_ACCESSDENIED;
890 if (!WriteFile(stream->u.file.handle, buff, size, &written_len, NULL))
891 return HRESULT_FROM_WIN32(GetLastError());
893 if (written)
894 *written = written_len;
896 return S_OK;
899 static HRESULT WINAPI filestream_Seek(IStream *iface, LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER *new_pos)
901 struct shstream *stream = impl_from_IStream(iface);
902 DWORD position;
904 TRACE("(%p, %s, %d, %p)\n", stream, wine_dbgstr_longlong(move.QuadPart), origin, new_pos);
906 position = SetFilePointer(stream->u.file.handle, move.u.LowPart, NULL, origin);
907 if (position == INVALID_SET_FILE_POINTER)
908 return HRESULT_FROM_WIN32(GetLastError());
910 if (new_pos)
912 new_pos->u.HighPart = 0;
913 new_pos->u.LowPart = position;
916 return S_OK;
919 static HRESULT WINAPI filestream_SetSize(IStream *iface, ULARGE_INTEGER size)
921 struct shstream *stream = impl_from_IStream(iface);
922 LARGE_INTEGER origin, move;
924 TRACE("(%p, %s)\n", stream, wine_dbgstr_longlong(size.QuadPart));
926 move.QuadPart = 0;
927 if (!SetFilePointerEx(stream->u.file.handle, move, &origin, FILE_CURRENT))
928 return E_FAIL;
930 move.QuadPart = size.QuadPart;
931 if (!SetFilePointerEx(stream->u.file.handle, move, NULL, FILE_BEGIN))
932 return E_FAIL;
934 if (stream->u.file.mode != STGM_READ)
936 if (!SetEndOfFile(stream->u.file.handle))
937 return E_FAIL;
938 if (!SetFilePointerEx(stream->u.file.handle, origin, NULL, FILE_BEGIN))
939 return E_FAIL;
942 return S_OK;
945 static HRESULT WINAPI filestream_CopyTo(IStream *iface, IStream *dest, ULARGE_INTEGER size,
946 ULARGE_INTEGER *read_len, ULARGE_INTEGER *written)
948 struct shstream *stream = impl_from_IStream(iface);
949 HRESULT hr = S_OK;
950 char buff[1024];
952 TRACE("(%p, %p, %s, %p, %p)\n", stream, dest, wine_dbgstr_longlong(size.QuadPart), read_len, written);
954 if (read_len)
955 read_len->QuadPart = 0;
956 if (written)
957 written->QuadPart = 0;
959 if (!dest)
960 return S_OK;
962 while (size.QuadPart)
964 ULONG left, read_chunk, written_chunk;
966 left = size.QuadPart > sizeof(buff) ? sizeof(buff) : size.QuadPart;
968 /* Read */
969 hr = IStream_Read(iface, buff, left, &read_chunk);
970 if (FAILED(hr) || read_chunk == 0)
971 break;
972 if (read_len)
973 read_len->QuadPart += read_chunk;
975 /* Write */
976 hr = IStream_Write(dest, buff, read_chunk, &written_chunk);
977 if (written_chunk)
978 written->QuadPart += written_chunk;
979 if (FAILED(hr) || written_chunk != left)
980 break;
982 size.QuadPart -= left;
985 return hr;
988 static HRESULT WINAPI filestream_Commit(IStream *iface, DWORD flags)
990 struct shstream *stream = impl_from_IStream(iface);
992 TRACE("(%p, %#x)\n", stream, flags);
994 return S_OK;
997 static HRESULT WINAPI filestream_Stat(IStream *iface, STATSTG *statstg, DWORD flags)
999 struct shstream *stream = impl_from_IStream(iface);
1000 BY_HANDLE_FILE_INFORMATION fi;
1002 TRACE("(%p, %p, %#x)\n", stream, statstg, flags);
1004 if (!statstg)
1005 return STG_E_INVALIDPOINTER;
1007 memset(&fi, 0, sizeof(fi));
1008 GetFileInformationByHandle(stream->u.file.handle, &fi);
1010 if (flags & STATFLAG_NONAME)
1011 statstg->pwcsName = NULL;
1012 else
1014 int len = lstrlenW(stream->u.file.path);
1015 if ((statstg->pwcsName = CoTaskMemAlloc((len + 1) * sizeof(WCHAR))))
1016 memcpy(statstg->pwcsName, stream->u.file.path, (len + 1) * sizeof(WCHAR));
1018 statstg->type = 0;
1019 statstg->cbSize.u.LowPart = fi.nFileSizeLow;
1020 statstg->cbSize.u.HighPart = fi.nFileSizeHigh;
1021 statstg->mtime = fi.ftLastWriteTime;
1022 statstg->ctime = fi.ftCreationTime;
1023 statstg->atime = fi.ftLastAccessTime;
1024 statstg->grfMode = stream->u.file.mode;
1025 statstg->grfLocksSupported = 0;
1026 memcpy(&statstg->clsid, &IID_IStream, sizeof(CLSID));
1027 statstg->grfStateBits = 0;
1028 statstg->reserved = 0;
1030 return S_OK;
1033 static const IStreamVtbl filestreamvtbl =
1035 shstream_QueryInterface,
1036 shstream_AddRef,
1037 filestream_Release,
1038 filestream_Read,
1039 filestream_Write,
1040 filestream_Seek,
1041 filestream_SetSize,
1042 filestream_CopyTo,
1043 filestream_Commit,
1044 shstream_Revert,
1045 shstream_LockRegion,
1046 shstream_UnlockRegion,
1047 filestream_Stat,
1048 shstream_Clone,
1051 /*************************************************************************
1052 * SHCreateStreamOnFileEx [SHCORE.@]
1054 HRESULT WINAPI SHCreateStreamOnFileEx(const WCHAR *path, DWORD mode, DWORD attributes,
1055 BOOL create, IStream *template, IStream **ret)
1057 DWORD access, share, creation_disposition, len;
1058 struct shstream *stream;
1059 HANDLE hFile;
1061 TRACE("(%s, %d, 0x%08X, %d, %p, %p)\n", debugstr_w(path), mode, attributes,
1062 create, template, ret);
1064 if (!path || !ret || template)
1065 return E_INVALIDARG;
1067 *ret = NULL;
1069 /* Access */
1070 switch (mode & 0xf)
1072 case STGM_WRITE:
1073 case STGM_READWRITE:
1074 access = GENERIC_READ | GENERIC_WRITE;
1075 break;
1076 case STGM_READ:
1077 access = GENERIC_READ;
1078 break;
1079 default:
1080 return E_INVALIDARG;
1083 /* Sharing */
1084 switch (mode & 0xf0)
1086 case 0:
1087 case STGM_SHARE_DENY_NONE:
1088 share = FILE_SHARE_READ | FILE_SHARE_WRITE;
1089 break;
1090 case STGM_SHARE_DENY_READ:
1091 share = FILE_SHARE_WRITE;
1092 break;
1093 case STGM_SHARE_DENY_WRITE:
1094 share = FILE_SHARE_READ;
1095 break;
1096 case STGM_SHARE_EXCLUSIVE:
1097 share = 0;
1098 break;
1099 default:
1100 return E_INVALIDARG;
1103 switch (mode & 0xf000)
1105 case STGM_FAILIFTHERE:
1106 creation_disposition = create ? CREATE_NEW : OPEN_EXISTING;
1107 break;
1108 case STGM_CREATE:
1109 creation_disposition = CREATE_ALWAYS;
1110 break;
1111 default:
1112 return E_INVALIDARG;
1115 hFile = CreateFileW(path, access, share, NULL, creation_disposition, attributes, 0);
1116 if (hFile == INVALID_HANDLE_VALUE)
1117 return HRESULT_FROM_WIN32(GetLastError());
1119 stream = heap_alloc(sizeof(*stream));
1120 stream->IStream_iface.lpVtbl = &filestreamvtbl;
1121 stream->refcount = 1;
1122 stream->u.file.handle = hFile;
1123 stream->u.file.mode = mode;
1125 len = lstrlenW(path);
1126 stream->u.file.path = heap_alloc((len + 1) * sizeof(WCHAR));
1127 memcpy(stream->u.file.path, path, (len + 1) * sizeof(WCHAR));
1129 *ret = &stream->IStream_iface;
1131 return S_OK;
1134 /*************************************************************************
1135 * SHCreateStreamOnFileW [SHCORE.@]
1137 HRESULT WINAPI SHCreateStreamOnFileW(const WCHAR *path, DWORD mode, IStream **stream)
1139 TRACE("(%s, %#x, %p)\n", debugstr_w(path), mode, stream);
1141 if (!path || !stream)
1142 return E_INVALIDARG;
1144 if ((mode & (STGM_CONVERT | STGM_DELETEONRELEASE | STGM_TRANSACTED)) != 0)
1145 return E_INVALIDARG;
1147 return SHCreateStreamOnFileEx(path, mode, 0, FALSE, NULL, stream);
1150 /*************************************************************************
1151 * SHCreateStreamOnFileA [SHCORE.@]
1153 HRESULT WINAPI SHCreateStreamOnFileA(const char *path, DWORD mode, IStream **stream)
1155 WCHAR *pathW;
1156 HRESULT hr;
1157 DWORD len;
1159 TRACE("(%s, %#x, %p)\n", debugstr_a(path), mode, stream);
1161 if (!path)
1162 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1164 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1165 pathW = heap_alloc(len * sizeof(WCHAR));
1166 if (!pathW)
1167 return E_OUTOFMEMORY;
1169 MultiByteToWideChar(CP_ACP, 0, path, -1, pathW, len);
1170 hr = SHCreateStreamOnFileW(pathW, mode, stream);
1171 heap_free(pathW);
1173 return hr;
1176 static ULONG WINAPI regstream_Release(IStream *iface)
1178 struct shstream *stream = impl_from_IStream(iface);
1179 ULONG refcount = InterlockedDecrement(&stream->refcount);
1181 TRACE("(%p)->(%u)\n", stream, refcount);
1183 if (!refcount)
1185 if (stream->u.mem.hkey)
1187 if (stream->u.mem.length)
1188 RegSetValueExW(stream->u.mem.hkey, stream->u.mem.valuename, 0, REG_BINARY,
1189 (const BYTE *)stream->u.mem.buffer, stream->u.mem.length);
1190 else
1191 RegDeleteValueW(stream->u.mem.hkey, stream->u.mem.valuename);
1192 RegCloseKey(stream->u.mem.hkey);
1194 CoTaskMemFree(stream->u.mem.valuename);
1195 heap_free(stream->u.mem.buffer);
1196 heap_free(stream);
1199 return refcount;
1202 static const IStreamVtbl regstreamvtbl =
1204 shstream_QueryInterface,
1205 shstream_AddRef,
1206 regstream_Release,
1207 memstream_Read,
1208 memstream_Write,
1209 memstream_Seek,
1210 memstream_SetSize,
1211 shstream_CopyTo,
1212 shstream_Commit,
1213 shstream_Revert,
1214 shstream_LockRegion,
1215 shstream_UnlockRegion,
1216 memstream_Stat,
1217 shstream_Clone,
1220 /*************************************************************************
1221 * SHOpenRegStream2W [SHCORE.@]
1223 IStream * WINAPI SHOpenRegStream2W(HKEY hKey, const WCHAR *subkey, const WCHAR *value, DWORD mode)
1225 struct shstream *stream;
1226 HKEY hStrKey = NULL;
1227 BYTE *buff = NULL;
1228 DWORD length = 0;
1229 LONG ret;
1231 TRACE("(%p, %s, %s, %#x)\n", hKey, debugstr_w(subkey), debugstr_w(value), mode);
1233 if (mode == STGM_READ)
1234 ret = RegOpenKeyExW(hKey, subkey, 0, KEY_READ, &hStrKey);
1235 else /* in write mode we make sure the subkey exits */
1236 ret = RegCreateKeyExW(hKey, subkey, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &hStrKey, NULL);
1238 if (ret == ERROR_SUCCESS)
1240 if (mode == STGM_READ || mode == STGM_READWRITE)
1242 /* read initial data */
1243 ret = RegQueryValueExW(hStrKey, value, 0, 0, 0, &length);
1244 if (ret == ERROR_SUCCESS && length)
1246 buff = heap_alloc(length);
1247 RegQueryValueExW(hStrKey, value, 0, 0, buff, &length);
1251 if (!length)
1252 buff = heap_alloc(length);
1254 stream = shstream_create(&regstreamvtbl, buff, length);
1255 heap_free(buff);
1256 if (stream)
1258 stream->u.mem.hkey = hStrKey;
1259 SHStrDupW(value, &stream->u.mem.valuename);
1260 return &stream->IStream_iface;
1264 if (hStrKey)
1265 RegCloseKey(hStrKey);
1267 return NULL;
1270 /*************************************************************************
1271 * SHOpenRegStream2A [SHCORE.@]
1273 IStream * WINAPI SHOpenRegStream2A(HKEY hKey, const char *subkey, const char *value, DWORD mode)
1275 WCHAR *subkeyW = NULL, *valueW = NULL;
1276 IStream *stream;
1278 TRACE("(%p, %s, %s, %#x)\n", hKey, debugstr_a(subkey), debugstr_a(value), mode);
1280 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1281 return NULL;
1282 if (value && FAILED(SHStrDupA(value, &valueW)))
1284 CoTaskMemFree(subkeyW);
1285 return NULL;
1288 stream = SHOpenRegStream2W(hKey, subkeyW, valueW, mode);
1289 CoTaskMemFree(subkeyW);
1290 CoTaskMemFree(valueW);
1291 return stream;
1294 /*************************************************************************
1295 * SHOpenRegStreamA [SHCORE.@]
1297 IStream * WINAPI SHOpenRegStreamA(HKEY hkey, const char *subkey, const char *value, DWORD mode)
1299 WCHAR *subkeyW = NULL, *valueW = NULL;
1300 IStream *stream;
1302 TRACE("(%p, %s, %s, %#x)\n", hkey, debugstr_a(subkey), debugstr_a(value), mode);
1304 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1305 return NULL;
1306 if (value && FAILED(SHStrDupA(value, &valueW)))
1308 CoTaskMemFree(subkeyW);
1309 return NULL;
1312 stream = SHOpenRegStreamW(hkey, subkeyW, valueW, mode);
1313 CoTaskMemFree(subkeyW);
1314 CoTaskMemFree(valueW);
1315 return stream;
1318 static ULONG WINAPI dummystream_AddRef(IStream *iface)
1320 TRACE("()\n");
1321 return 2;
1324 static ULONG WINAPI dummystream_Release(IStream *iface)
1326 TRACE("()\n");
1327 return 1;
1330 static HRESULT WINAPI dummystream_Read(IStream *iface, void *buff, ULONG buff_size, ULONG *read_len)
1332 if (read_len)
1333 *read_len = 0;
1335 return E_NOTIMPL;
1338 static const IStreamVtbl dummystreamvtbl =
1340 shstream_QueryInterface,
1341 dummystream_AddRef,
1342 dummystream_Release,
1343 dummystream_Read,
1344 memstream_Write,
1345 memstream_Seek,
1346 memstream_SetSize,
1347 shstream_CopyTo,
1348 shstream_Commit,
1349 shstream_Revert,
1350 shstream_LockRegion,
1351 shstream_UnlockRegion,
1352 memstream_Stat,
1353 shstream_Clone,
1356 static struct shstream dummyregstream = { { &dummystreamvtbl } };
1358 /*************************************************************************
1359 * SHOpenRegStreamW [SHCORE.@]
1361 IStream * WINAPI SHOpenRegStreamW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, DWORD mode)
1363 IStream *stream;
1365 TRACE("(%p, %s, %s, %#x)\n", hkey, debugstr_w(subkey), debugstr_w(value), mode);
1366 stream = SHOpenRegStream2W(hkey, subkey, value, mode);
1367 return stream ? stream : &dummyregstream.IStream_iface;
1370 struct threadref
1372 IUnknown IUnknown_iface;
1373 LONG *refcount;
1376 static inline struct threadref *threadref_impl_from_IUnknown(IUnknown *iface)
1378 return CONTAINING_RECORD(iface, struct threadref, IUnknown_iface);
1381 static HRESULT WINAPI threadref_QueryInterface(IUnknown *iface, REFIID riid, void **out)
1383 struct threadref *threadref = threadref_impl_from_IUnknown(iface);
1385 TRACE("(%p, %s, %p)\n", threadref, debugstr_guid(riid), out);
1387 if (out == NULL)
1388 return E_POINTER;
1390 if (IsEqualGUID(&IID_IUnknown, riid))
1392 *out = iface;
1393 IUnknown_AddRef(iface);
1394 return S_OK;
1397 *out = NULL;
1398 WARN("Interface %s not supported.\n", debugstr_guid(riid));
1399 return E_NOINTERFACE;
1402 static ULONG WINAPI threadref_AddRef(IUnknown *iface)
1404 struct threadref *threadref = threadref_impl_from_IUnknown(iface);
1405 LONG refcount = InterlockedIncrement(threadref->refcount);
1407 TRACE("(%p, %d)\n", threadref, refcount);
1409 return refcount;
1412 static ULONG WINAPI threadref_Release(IUnknown *iface)
1414 struct threadref *threadref = threadref_impl_from_IUnknown(iface);
1415 LONG refcount = InterlockedDecrement(threadref->refcount);
1417 TRACE("(%p, %d)\n", threadref, refcount);
1419 if (!refcount)
1420 heap_free(threadref);
1422 return refcount;
1425 static const IUnknownVtbl threadrefvtbl =
1427 threadref_QueryInterface,
1428 threadref_AddRef,
1429 threadref_Release,
1432 /*************************************************************************
1433 * SHCreateThreadRef [SHCORE.@]
1435 HRESULT WINAPI SHCreateThreadRef(LONG *refcount, IUnknown **out)
1437 struct threadref *threadref;
1439 TRACE("(%p, %p)\n", refcount, out);
1441 if (!refcount || !out)
1442 return E_INVALIDARG;
1444 *out = NULL;
1446 threadref = heap_alloc(sizeof(*threadref));
1447 if (!threadref)
1448 return E_OUTOFMEMORY;
1449 threadref->IUnknown_iface.lpVtbl = &threadrefvtbl;
1450 threadref->refcount = refcount;
1452 *refcount = 1;
1453 *out = &threadref->IUnknown_iface;
1455 TRACE("Created %p.\n", threadref);
1456 return S_OK;
1459 /*************************************************************************
1460 * SHGetThreadRef [SHCORE.@]
1462 HRESULT WINAPI SHGetThreadRef(IUnknown **out)
1464 TRACE("(%p)\n", out);
1466 if (shcore_tls == TLS_OUT_OF_INDEXES)
1467 return E_NOINTERFACE;
1469 *out = TlsGetValue(shcore_tls);
1470 if (!*out)
1471 return E_NOINTERFACE;
1473 IUnknown_AddRef(*out);
1474 return S_OK;
1477 /*************************************************************************
1478 * SHSetThreadRef [SHCORE.@]
1480 HRESULT WINAPI SHSetThreadRef(IUnknown *obj)
1482 TRACE("(%p)\n", obj);
1484 if (shcore_tls == TLS_OUT_OF_INDEXES)
1485 return E_NOINTERFACE;
1487 TlsSetValue(shcore_tls, obj);
1488 return S_OK;
1491 /*************************************************************************
1492 * SHReleaseThreadRef [SHCORE.@]
1494 HRESULT WINAPI SHReleaseThreadRef(void)
1496 FIXME("() - stub!\n");
1497 return S_OK;
1500 /*************************************************************************
1501 * GetProcessReference [SHCORE.@]
1503 HRESULT WINAPI GetProcessReference(IUnknown **obj)
1505 TRACE("(%p)\n", obj);
1507 *obj = process_ref;
1509 if (!process_ref)
1510 return E_FAIL;
1512 if (*obj)
1513 IUnknown_AddRef(*obj);
1515 return S_OK;
1518 /*************************************************************************
1519 * SetProcessReference [SHCORE.@]
1521 void WINAPI SetProcessReference(IUnknown *obj)
1523 TRACE("(%p)\n", obj);
1525 process_ref = obj;
1528 struct thread_data
1530 LPTHREAD_START_ROUTINE thread_proc;
1531 LPTHREAD_START_ROUTINE callback;
1532 void *data;
1533 DWORD flags;
1534 HANDLE hEvent;
1535 IUnknown *thread_ref;
1536 IUnknown *process_ref;
1539 static DWORD WINAPI shcore_thread_wrapper(void *data)
1541 struct thread_data thread_data;
1542 HRESULT hr = E_FAIL;
1543 DWORD retval;
1545 TRACE("(%p)\n", data);
1547 /* We are now executing in the context of the newly created thread.
1548 * So we copy the data passed to us (it is on the stack of the function
1549 * that called us, which is waiting for us to signal an event before
1550 * returning). */
1551 thread_data = *(struct thread_data *)data;
1553 if (thread_data.flags & CTF_COINIT)
1555 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
1556 if (FAILED(hr))
1557 hr = CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE);
1560 if (thread_data.callback)
1561 thread_data.callback(thread_data.data);
1563 /* Signal the thread that created us; it can return now. */
1564 SetEvent(thread_data.hEvent);
1566 /* Execute the callers start code. */
1567 retval = thread_data.thread_proc(thread_data.data);
1569 /* Release thread and process references. */
1570 if (thread_data.thread_ref)
1571 IUnknown_Release(thread_data.thread_ref);
1573 if (thread_data.process_ref)
1574 IUnknown_Release(thread_data.process_ref);
1576 if (SUCCEEDED(hr))
1577 CoUninitialize();
1579 return retval;
1582 /*************************************************************************
1583 * SHCreateThread [SHCORE.@]
1585 BOOL WINAPI SHCreateThread(LPTHREAD_START_ROUTINE thread_proc, void *data, DWORD flags, LPTHREAD_START_ROUTINE callback)
1587 struct thread_data thread_data;
1588 BOOL called = FALSE;
1590 TRACE("(%p, %p, %#x, %p)\n", thread_proc, data, flags, callback);
1592 thread_data.thread_proc = thread_proc;
1593 thread_data.callback = callback;
1594 thread_data.data = data;
1595 thread_data.flags = flags;
1596 thread_data.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
1598 if (flags & CTF_THREAD_REF)
1599 SHGetThreadRef(&thread_data.thread_ref);
1600 else
1601 thread_data.thread_ref = NULL;
1603 if (flags & CTF_PROCESS_REF)
1604 GetProcessReference(&thread_data.process_ref);
1605 else
1606 thread_data.process_ref = NULL;
1608 /* Create the thread */
1609 if (thread_data.hEvent)
1611 HANDLE hThread;
1612 DWORD retval;
1614 hThread = CreateThread(NULL, 0, shcore_thread_wrapper, &thread_data, 0, &retval);
1615 if (hThread)
1617 /* Wait for the thread to signal us to continue */
1618 WaitForSingleObject(thread_data.hEvent, INFINITE);
1619 CloseHandle(hThread);
1620 called = TRUE;
1622 CloseHandle(thread_data.hEvent);
1625 if (!called)
1627 if (!thread_data.callback && flags & CTF_INSIST)
1629 /* Couldn't call, call synchronously */
1630 thread_data.thread_proc(data);
1631 called = TRUE;
1633 else
1635 if (thread_data.thread_ref)
1636 IUnknown_Release(thread_data.thread_ref);
1638 if (thread_data.process_ref)
1639 IUnknown_Release(thread_data.process_ref);
1643 return called;
1646 /*************************************************************************
1647 * SHStrDupW [SHCORE.@]
1649 HRESULT WINAPI SHStrDupW(const WCHAR *src, WCHAR **dest)
1651 size_t len;
1653 TRACE("(%s, %p)\n", debugstr_w(src), dest);
1655 *dest = NULL;
1657 if (!src)
1658 return E_INVALIDARG;
1660 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
1661 *dest = CoTaskMemAlloc(len);
1662 if (!*dest)
1663 return E_OUTOFMEMORY;
1665 memcpy(*dest, src, len);
1667 return S_OK;
1670 /*************************************************************************
1671 * SHStrDupA [SHCORE.@]
1673 HRESULT WINAPI SHStrDupA(const char *src, WCHAR **dest)
1675 DWORD len;
1677 *dest = NULL;
1679 if (!src)
1680 return E_INVALIDARG;
1682 len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
1683 *dest = CoTaskMemAlloc(len * sizeof(WCHAR));
1684 if (!*dest)
1685 return E_OUTOFMEMORY;
1687 MultiByteToWideChar(CP_ACP, 0, src, -1, *dest, len);
1689 return S_OK;
1692 /*************************************************************************
1693 * SHAnsiToAnsi [SHCORE.@]
1695 DWORD WINAPI SHAnsiToAnsi(const char *src, char *dest, int dest_len)
1697 DWORD ret;
1699 TRACE("(%s, %p, %d)\n", debugstr_a(src), dest, dest_len);
1701 if (!src || !dest || dest_len <= 0)
1702 return 0;
1704 lstrcpynA(dest, src, dest_len);
1705 ret = strlen(dest);
1707 return src[ret] ? 0 : ret + 1;
1710 /*************************************************************************
1711 * SHUnicodeToAnsi [SHCORE.@]
1713 DWORD WINAPI SHUnicodeToAnsi(const WCHAR *src, char *dest, int dest_len)
1715 int ret = 1;
1717 TRACE("(%s, %p, %d)\n", debugstr_w(src), dest, dest_len);
1719 if (!dest || !dest_len)
1720 return 0;
1722 if (src)
1724 ret = WideCharToMultiByte(CP_ACP, 0, src, -1, dest, dest_len, NULL, NULL);
1725 if (!ret)
1727 dest[dest_len - 1] = 0;
1728 ret = dest_len;
1731 else
1732 dest[0] = 0;
1734 return ret;
1737 /*************************************************************************
1738 * SHUnicodeToUnicode [SHCORE.@]
1740 DWORD WINAPI SHUnicodeToUnicode(const WCHAR *src, WCHAR *dest, int dest_len)
1742 DWORD ret;
1744 TRACE("(%s, %p, %d)\n", debugstr_w(src), dest, dest_len);
1746 if (!src || !dest || dest_len <= 0)
1747 return 0;
1749 lstrcpynW(dest, src, dest_len);
1750 ret = lstrlenW(dest);
1752 return src[ret] ? 0 : ret + 1;
1755 /*************************************************************************
1756 * SHAnsiToUnicode [SHCORE.@]
1758 DWORD WINAPI SHAnsiToUnicode(const char *src, WCHAR *dest, int dest_len)
1760 int ret = 1;
1762 TRACE("(%s, %p, %d)\n", debugstr_a(src), dest, dest_len);
1764 if (!dest || !dest_len)
1765 return 0;
1767 if (src)
1769 ret = MultiByteToWideChar(CP_ACP, 0, src, -1, dest, dest_len);
1770 if (!ret)
1772 dest[dest_len - 1] = 0;
1773 ret = dest_len;
1776 else
1777 dest[0] = 0;
1779 return ret;
1782 /*************************************************************************
1783 * SHRegDuplicateHKey [SHCORE.@]
1785 HKEY WINAPI SHRegDuplicateHKey(HKEY hKey)
1787 HKEY newKey = 0;
1789 RegOpenKeyExW(hKey, 0, 0, MAXIMUM_ALLOWED, &newKey);
1790 TRACE("new key is %p\n", newKey);
1791 return newKey;
1794 /*************************************************************************
1795 * SHDeleteEmptyKeyW [SHCORE.@]
1797 DWORD WINAPI SHDeleteEmptyKeyW(HKEY hkey, const WCHAR *subkey)
1799 DWORD ret, count = 0;
1800 HKEY hsubkey = 0;
1802 TRACE("(%p, %s)\n", hkey, debugstr_w(subkey));
1804 ret = RegOpenKeyExW(hkey, subkey, 0, KEY_READ, &hsubkey);
1805 if (!ret)
1807 ret = RegQueryInfoKeyW(hsubkey, NULL, NULL, NULL, &count,
1808 NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1809 RegCloseKey(hsubkey);
1810 if (!ret)
1812 if (count)
1813 ret = ERROR_KEY_HAS_CHILDREN;
1814 else
1815 ret = RegDeleteKeyW(hkey, subkey);
1819 return ret;
1822 /*************************************************************************
1823 * SHDeleteEmptyKeyA [SHCORE.@]
1825 DWORD WINAPI SHDeleteEmptyKeyA(HKEY hkey, const char *subkey)
1827 WCHAR *subkeyW = NULL;
1828 DWORD ret;
1830 TRACE("(%p, %s)\n", hkey, debugstr_a(subkey));
1832 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1833 return ERROR_OUTOFMEMORY;
1835 ret = SHDeleteEmptyKeyW(hkey, subkeyW);
1836 CoTaskMemFree(subkeyW);
1837 return ret;
1840 /*************************************************************************
1841 * SHDeleteKeyW [SHCORE.@]
1843 DWORD WINAPI SHDeleteKeyW(HKEY hkey, const WCHAR *subkey)
1845 TRACE("(%p, %s)\n", hkey, debugstr_w(subkey));
1847 return RegDeleteTreeW(hkey, subkey);
1850 /*************************************************************************
1851 * SHDeleteKeyA [SHCORE.@]
1853 DWORD WINAPI SHDeleteKeyA(HKEY hkey, const char *subkey)
1855 TRACE("(%p, %s)\n", hkey, debugstr_a(subkey));
1857 return RegDeleteTreeA(hkey, subkey);
1860 /*************************************************************************
1861 * SHDeleteValueW [SHCORE.@]
1863 DWORD WINAPI SHDeleteValueW(HKEY hkey, const WCHAR *subkey, const WCHAR *value)
1865 HKEY hsubkey;
1866 DWORD ret;
1868 TRACE("(%p, %s, %s)\n", hkey, debugstr_w(subkey), debugstr_w(value));
1870 ret = RegOpenKeyExW(hkey, subkey, 0, KEY_SET_VALUE, &hsubkey);
1871 if (!ret)
1873 ret = RegDeleteValueW(hsubkey, value);
1874 RegCloseKey(hsubkey);
1877 return ret;
1880 /*************************************************************************
1881 * SHDeleteValueA [SHCORE.@]
1883 DWORD WINAPI SHDeleteValueA(HKEY hkey, const char *subkey, const char *value)
1885 WCHAR *subkeyW = NULL, *valueW = NULL;
1886 DWORD ret;
1888 TRACE("(%p, %s, %s)\n", hkey, debugstr_a(subkey), debugstr_a(value));
1890 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1891 return ERROR_OUTOFMEMORY;
1892 if (value && FAILED(SHStrDupA(value, &valueW)))
1894 CoTaskMemFree(subkeyW);
1895 return ERROR_OUTOFMEMORY;
1898 ret = SHDeleteValueW(hkey, subkeyW, valueW);
1899 CoTaskMemFree(subkeyW);
1900 CoTaskMemFree(valueW);
1901 return ret;
1904 /*************************************************************************
1905 * SHCopyKeyA [SHCORE.@]
1907 DWORD WINAPI SHCopyKeyA(HKEY hkey_src, const char *subkey, HKEY hkey_dst, DWORD reserved)
1909 WCHAR *subkeyW = NULL;
1910 DWORD ret;
1912 TRACE("(%p, %s, %p, %d)\n", hkey_src, debugstr_a(subkey), hkey_dst, reserved);
1914 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1915 return 0;
1917 ret = SHCopyKeyW(hkey_src, subkeyW, hkey_dst, reserved);
1918 CoTaskMemFree(subkeyW);
1919 return ret;
1922 /*************************************************************************
1923 * SHCopyKeyW [SHCORE.@]
1925 DWORD WINAPI SHCopyKeyW(HKEY hkey_src, const WCHAR *subkey, HKEY hkey_dst, DWORD reserved)
1927 DWORD key_count = 0, value_count = 0, max_key_len = 0;
1928 WCHAR name[MAX_PATH], *ptr_name = name;
1929 BYTE buff[1024], *ptr = buff;
1930 DWORD max_data_len = 0, i;
1931 DWORD ret = 0;
1933 TRACE("(%p, %s, %p, %d)\n", hkey_src, debugstr_w(subkey), hkey_dst, reserved);
1935 if (!hkey_dst || !hkey_src)
1936 return ERROR_INVALID_PARAMETER;
1938 if (subkey)
1939 ret = RegOpenKeyExW(hkey_src, subkey, 0, KEY_ALL_ACCESS, &hkey_src);
1941 if (ret)
1942 hkey_src = NULL; /* Don't close this key since we didn't open it */
1943 else
1945 DWORD max_value_len;
1947 ret = RegQueryInfoKeyW(hkey_src, NULL, NULL, NULL, &key_count, &max_key_len,
1948 NULL, &value_count, &max_value_len, &max_data_len, NULL, NULL);
1949 if (!ret)
1951 /* Get max size for key/value names */
1952 max_key_len = max(max_key_len, max_value_len);
1954 if (max_key_len++ > MAX_PATH - 1)
1955 ptr_name = heap_alloc(max_key_len * sizeof(WCHAR));
1957 if (max_data_len > sizeof(buff))
1958 ptr = heap_alloc(max_data_len);
1960 if (!ptr_name || !ptr)
1961 ret = ERROR_NOT_ENOUGH_MEMORY;
1965 for (i = 0; i < key_count && !ret; i++)
1967 HKEY hsubkey_src, hsubkey_dst;
1968 DWORD length = max_key_len;
1970 ret = RegEnumKeyExW(hkey_src, i, ptr_name, &length, NULL, NULL, NULL, NULL);
1971 if (!ret)
1973 ret = RegOpenKeyExW(hkey_src, ptr_name, 0, KEY_READ, &hsubkey_src);
1974 if (!ret)
1976 /* Create destination sub key */
1977 ret = RegCreateKeyW(hkey_dst, ptr_name, &hsubkey_dst);
1978 if (!ret)
1980 /* Recursively copy keys and values from the sub key */
1981 ret = SHCopyKeyW(hsubkey_src, NULL, hsubkey_dst, 0);
1982 RegCloseKey(hsubkey_dst);
1985 RegCloseKey(hsubkey_src);
1989 /* Copy all the values in this key */
1990 for (i = 0; i < value_count && !ret; i++)
1992 DWORD length = max_key_len, type, data_len = max_data_len;
1994 ret = RegEnumValueW(hkey_src, i, ptr_name, &length, NULL, &type, ptr, &data_len);
1995 if (!ret) {
1996 ret = SHSetValueW(hkey_dst, NULL, ptr_name, type, ptr, data_len);
2000 /* Free buffers if allocated */
2001 if (ptr_name != name)
2002 heap_free(ptr_name);
2003 if (ptr != buff)
2004 heap_free(ptr);
2006 if (subkey && hkey_src)
2007 RegCloseKey(hkey_src);
2009 return ret;
2013 /*************************************************************************
2014 * SHEnumKeyExA [SHCORE.@]
2016 LONG WINAPI SHEnumKeyExA(HKEY hkey, DWORD index, char *subkey, DWORD *length)
2018 TRACE("(%p, %d, %s, %p)\n", hkey, index, debugstr_a(subkey), length);
2020 return RegEnumKeyExA(hkey, index, subkey, length, NULL, NULL, NULL, NULL);
2023 /*************************************************************************
2024 * SHEnumKeyExW [SHCORE.@]
2026 LONG WINAPI SHEnumKeyExW(HKEY hkey, DWORD index, WCHAR *subkey, DWORD *length)
2028 TRACE("(%p, %d, %s, %p)\n", hkey, index, debugstr_w(subkey), length);
2030 return RegEnumKeyExW(hkey, index, subkey, length, NULL, NULL, NULL, NULL);
2033 /*************************************************************************
2034 * SHEnumValueA [SHCORE.@]
2036 LONG WINAPI SHEnumValueA(HKEY hkey, DWORD index, char *value, DWORD *length, DWORD *type,
2037 void *data, DWORD *data_len)
2039 TRACE("(%p, %d, %s, %p, %p, %p, %p)\n", hkey, index, debugstr_a(value), length, type, data, data_len);
2041 return RegEnumValueA(hkey, index, value, length, NULL, type, data, data_len);
2044 /*************************************************************************
2045 * SHEnumValueW [SHCORE.@]
2047 LONG WINAPI SHEnumValueW(HKEY hkey, DWORD index, WCHAR *value, DWORD *length, DWORD *type,
2048 void *data, DWORD *data_len)
2050 TRACE("(%p, %d, %s, %p, %p, %p, %p)\n", hkey, index, debugstr_w(value), length, type, data, data_len);
2052 return RegEnumValueW(hkey, index, value, length, NULL, type, data, data_len);
2055 /*************************************************************************
2056 * SHQueryValueExW [SHCORE.@]
2058 DWORD WINAPI SHQueryValueExW(HKEY hkey, const WCHAR *name, DWORD *reserved, DWORD *type,
2059 void *buff, DWORD *buff_len)
2061 DWORD ret, value_type, data_len = 0;
2063 TRACE("(%p, %s, %p, %p, %p, %p)\n", hkey, debugstr_w(name), reserved, type, buff, buff_len);
2065 if (buff_len)
2066 data_len = *buff_len;
2068 ret = RegQueryValueExW(hkey, name, reserved, &value_type, buff, &data_len);
2069 if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)
2070 return ret;
2072 if (buff_len && value_type == REG_EXPAND_SZ)
2074 DWORD length;
2075 WCHAR *value;
2077 if (!buff || ret == ERROR_MORE_DATA)
2079 length = data_len;
2080 value = heap_alloc(length);
2081 RegQueryValueExW(hkey, name, reserved, NULL, (BYTE *)value, &length);
2082 length = ExpandEnvironmentStringsW(value, NULL, 0);
2084 else
2086 length = (lstrlenW(buff) + 1) * sizeof(WCHAR);
2087 value = heap_alloc(length);
2088 memcpy(value, buff, length);
2089 length = ExpandEnvironmentStringsW(value, buff, *buff_len / sizeof(WCHAR));
2090 if (length > *buff_len) ret = ERROR_MORE_DATA;
2092 data_len = max(data_len, length);
2093 heap_free(value);
2096 if (type)
2097 *type = value_type == REG_EXPAND_SZ ? REG_SZ : value_type;
2098 if (buff_len)
2099 *buff_len = data_len;
2100 return ret;
2103 /*************************************************************************
2104 * SHQueryValueExA [SHCORE.@]
2106 DWORD WINAPI SHQueryValueExA(HKEY hkey, const char *name, DWORD *reserved, DWORD *type,
2107 void *buff, DWORD *buff_len)
2109 DWORD ret, value_type, data_len = 0;
2111 TRACE("(%p, %s, %p, %p, %p, %p)\n", hkey, debugstr_a(name), reserved, type, buff, buff_len);
2113 if (buff_len)
2114 data_len = *buff_len;
2116 ret = RegQueryValueExA(hkey, name, reserved, &value_type, buff, &data_len);
2117 if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)
2118 return ret;
2120 if (buff_len && value_type == REG_EXPAND_SZ)
2122 DWORD length;
2123 char *value;
2125 if (!buff || ret == ERROR_MORE_DATA)
2127 length = data_len;
2128 value = heap_alloc(length);
2129 RegQueryValueExA(hkey, name, reserved, NULL, (BYTE *)value, &length);
2130 length = ExpandEnvironmentStringsA(value, NULL, 0);
2132 else
2134 length = strlen(buff) + 1;
2135 value = heap_alloc(length);
2136 memcpy(value, buff, length);
2137 length = ExpandEnvironmentStringsA(value, buff, *buff_len);
2138 if (length > *buff_len) ret = ERROR_MORE_DATA;
2140 data_len = max(data_len, length);
2141 heap_free(value);
2144 if (type)
2145 *type = value_type == REG_EXPAND_SZ ? REG_SZ : value_type;
2146 if (buff_len)
2147 *buff_len = data_len;
2148 return ret;
2151 /*************************************************************************
2152 * SHGetValueA [SHCORE.@]
2154 DWORD WINAPI SHGetValueA(HKEY hkey, const char *subkey, const char *value,
2155 DWORD *type, void *data, DWORD *data_len)
2157 HKEY hsubkey = 0;
2158 DWORD ret = 0;
2160 TRACE("(%p, %s, %s, %p, %p, %p)\n", hkey, debugstr_a(subkey), debugstr_a(value),
2161 type, data, data_len);
2163 if (subkey)
2164 ret = RegOpenKeyExA(hkey, subkey, 0, KEY_QUERY_VALUE, &hsubkey);
2166 if (!ret)
2168 ret = SHQueryValueExA(hsubkey ? hsubkey : hkey, value, 0, type, data, data_len);
2169 if (subkey)
2170 RegCloseKey(hsubkey);
2173 return ret;
2176 /*************************************************************************
2177 * SHGetValueW [SHCORE.@]
2179 DWORD WINAPI SHGetValueW(HKEY hkey, const WCHAR *subkey, const WCHAR *value,
2180 DWORD *type, void *data, DWORD *data_len)
2182 HKEY hsubkey = 0;
2183 DWORD ret = 0;
2185 TRACE("(%p, %s, %s, %p, %p, %p)\n", hkey, debugstr_w(subkey), debugstr_w(value),
2186 type, data, data_len);
2188 if (subkey)
2189 ret = RegOpenKeyExW(hkey, subkey, 0, KEY_QUERY_VALUE, &hsubkey);
2191 if (!ret)
2193 ret = SHQueryValueExW(hsubkey ? hsubkey : hkey, value, 0, type, data, data_len);
2194 if (subkey)
2195 RegCloseKey(hsubkey);
2198 return ret;
2201 /*************************************************************************
2202 * SHRegGetIntW [SHCORE.280]
2204 int WINAPI SHRegGetIntW(HKEY hkey, const WCHAR *value, int default_value)
2206 WCHAR buff[32];
2207 DWORD buff_len;
2209 TRACE("(%p, %s, %d)\n", hkey, debugstr_w(value), default_value);
2211 buff[0] = 0;
2212 buff_len = sizeof(buff);
2213 if (SHQueryValueExW(hkey, value, 0, 0, buff, &buff_len))
2214 return default_value;
2216 if (*buff >= '0' && *buff <= '9')
2217 return wcstol(buff, NULL, 10);
2219 return default_value;
2222 /*************************************************************************
2223 * SHRegGetPathA [SHCORE.@]
2225 DWORD WINAPI SHRegGetPathA(HKEY hkey, const char *subkey, const char *value, char *path, DWORD flags)
2227 DWORD length = MAX_PATH;
2229 TRACE("(%p, %s, %s, %p, %#x)\n", hkey, debugstr_a(subkey), debugstr_a(value), path, flags);
2231 return SHGetValueA(hkey, subkey, value, 0, path, &length);
2234 /*************************************************************************
2235 * SHRegGetPathW [SHCORE.@]
2237 DWORD WINAPI SHRegGetPathW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, WCHAR *path, DWORD flags)
2239 DWORD length = MAX_PATH;
2241 TRACE("(%p, %s, %s, %p, %d)\n", hkey, debugstr_w(subkey), debugstr_w(value), path, flags);
2243 return SHGetValueW(hkey, subkey, value, 0, path, &length);
2246 /*************************************************************************
2247 * SHSetValueW [SHCORE.@]
2249 DWORD WINAPI SHSetValueW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, DWORD type,
2250 const void *data, DWORD data_len)
2252 DWORD ret = ERROR_SUCCESS, dummy;
2253 HKEY hsubkey;
2255 TRACE("(%p, %s, %s, %d, %p, %d)\n", hkey, debugstr_w(subkey), debugstr_w(value),
2256 type, data, data_len);
2258 if (subkey && *subkey)
2259 ret = RegCreateKeyExW(hkey, subkey, 0, NULL, 0, KEY_SET_VALUE, NULL, &hsubkey, &dummy);
2260 else
2261 hsubkey = hkey;
2263 if (!ret)
2265 ret = RegSetValueExW(hsubkey, value, 0, type, data, data_len);
2266 if (hsubkey != hkey)
2267 RegCloseKey(hsubkey);
2270 return ret;
2273 /*************************************************************************
2274 * SHSetValueA [SHCORE.@]
2276 DWORD WINAPI SHSetValueA(HKEY hkey, const char *subkey, const char *value,
2277 DWORD type, const void *data, DWORD data_len)
2279 DWORD ret = ERROR_SUCCESS, dummy;
2280 HKEY hsubkey;
2282 TRACE("(%p, %s, %s, %d, %p, %d)\n", hkey, debugstr_a(subkey), debugstr_a(value),
2283 type, data, data_len);
2285 if (subkey && *subkey)
2286 ret = RegCreateKeyExA(hkey, subkey, 0, NULL, 0, KEY_SET_VALUE, NULL, &hsubkey, &dummy);
2287 else
2288 hsubkey = hkey;
2290 if (!ret)
2292 ret = RegSetValueExA(hsubkey, value, 0, type, data, data_len);
2293 if (hsubkey != hkey)
2294 RegCloseKey(hsubkey);
2297 return ret;
2300 /*************************************************************************
2301 * SHRegSetPathA [SHCORE.@]
2303 DWORD WINAPI SHRegSetPathA(HKEY hkey, const char *subkey, const char *value, const char *path, DWORD flags)
2305 FIXME("(%p, %s, %s, %s, %#x) - semi-stub\n", hkey, debugstr_a(subkey),
2306 debugstr_a(value), debugstr_a(path), flags);
2308 /* FIXME: PathUnExpandEnvStringsA() */
2310 return SHSetValueA(hkey, subkey, value, REG_SZ, path, lstrlenA(path));
2313 /*************************************************************************
2314 * SHRegSetPathW [SHCORE.@]
2316 DWORD WINAPI SHRegSetPathW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, const WCHAR *path, DWORD flags)
2318 FIXME("(%p, %s, %s, %s, %#x) - semi-stub\n", hkey, debugstr_w(subkey),
2319 debugstr_w(value), debugstr_w(path), flags);
2321 /* FIXME: PathUnExpandEnvStringsW(); */
2323 return SHSetValueW(hkey, subkey, value, REG_SZ, path, lstrlenW(path));
2326 /*************************************************************************
2327 * SHQueryInfoKeyA [SHCORE.@]
2329 LONG WINAPI SHQueryInfoKeyA(HKEY hkey, DWORD *subkeys, DWORD *subkey_max, DWORD *values, DWORD *value_max)
2331 TRACE("(%p, %p, %p, %p, %p)\n", hkey, subkeys, subkey_max, values, value_max);
2333 return RegQueryInfoKeyA(hkey, NULL, NULL, NULL, subkeys, subkey_max, NULL, values, value_max, NULL, NULL, NULL);
2336 /*************************************************************************
2337 * SHQueryInfoKeyW [SHCORE.@]
2339 LONG WINAPI SHQueryInfoKeyW(HKEY hkey, DWORD *subkeys, DWORD *subkey_max, DWORD *values, DWORD *value_max)
2341 TRACE("(%p, %p, %p, %p, %p)\n", hkey, subkeys, subkey_max, values, value_max);
2343 return RegQueryInfoKeyW(hkey, NULL, NULL, NULL, subkeys, subkey_max, NULL, values, value_max, NULL, NULL, NULL);
2346 /*************************************************************************
2347 * IsOS [SHCORE.@]
2349 BOOL WINAPI IsOS(DWORD feature)
2351 DWORD platform, majorv, minorv;
2352 OSVERSIONINFOA osvi;
2354 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
2355 if (!GetVersionExA(&osvi))
2356 return FALSE;
2358 majorv = osvi.dwMajorVersion;
2359 minorv = osvi.dwMinorVersion;
2360 platform = osvi.dwPlatformId;
2362 #define ISOS_RETURN(x) \
2363 TRACE("(0x%x) ret=%d\n",feature,(x)); \
2364 return (x)
2366 switch(feature) {
2367 case OS_WIN32SORGREATER:
2368 ISOS_RETURN(platform == VER_PLATFORM_WIN32s
2369 || platform == VER_PLATFORM_WIN32_WINDOWS);
2370 case OS_NT:
2371 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2372 case OS_WIN95ORGREATER:
2373 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS);
2374 case OS_NT4ORGREATER:
2375 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 4);
2376 case OS_WIN2000ORGREATER_ALT:
2377 case OS_WIN2000ORGREATER:
2378 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5);
2379 case OS_WIN98ORGREATER:
2380 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 10);
2381 case OS_WIN98_GOLD:
2382 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 10);
2383 case OS_WIN2000PRO:
2384 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5);
2385 case OS_WIN2000SERVER:
2386 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2387 case OS_WIN2000ADVSERVER:
2388 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2389 case OS_WIN2000DATACENTER:
2390 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2391 case OS_WIN2000TERMINAL:
2392 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2393 case OS_EMBEDDED:
2394 FIXME("(OS_EMBEDDED) What should we return here?\n");
2395 return FALSE;
2396 case OS_TERMINALCLIENT:
2397 FIXME("(OS_TERMINALCLIENT) What should we return here?\n");
2398 return FALSE;
2399 case OS_TERMINALREMOTEADMIN:
2400 FIXME("(OS_TERMINALREMOTEADMIN) What should we return here?\n");
2401 return FALSE;
2402 case OS_WIN95_GOLD:
2403 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 0);
2404 case OS_MEORGREATER:
2405 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 90);
2406 case OS_XPORGREATER:
2407 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1);
2408 case OS_HOME:
2409 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1);
2410 case OS_PROFESSIONAL:
2411 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2412 case OS_DATACENTER:
2413 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2414 case OS_ADVSERVER:
2415 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5);
2416 case OS_SERVER:
2417 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2418 case OS_TERMINALSERVER:
2419 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2420 case OS_PERSONALTERMINALSERVER:
2421 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && minorv >= 1 && majorv >= 5);
2422 case OS_FASTUSERSWITCHING:
2423 FIXME("(OS_FASTUSERSWITCHING) What should we return here?\n");
2424 return TRUE;
2425 case OS_WELCOMELOGONUI:
2426 FIXME("(OS_WELCOMELOGONUI) What should we return here?\n");
2427 return FALSE;
2428 case OS_DOMAINMEMBER:
2429 FIXME("(OS_DOMAINMEMBER) What should we return here?\n");
2430 return TRUE;
2431 case OS_ANYSERVER:
2432 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2433 case OS_WOW6432:
2435 BOOL is_wow64;
2436 IsWow64Process(GetCurrentProcess(), &is_wow64);
2437 return is_wow64;
2439 case OS_WEBSERVER:
2440 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2441 case OS_SMALLBUSINESSSERVER:
2442 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2443 case OS_TABLETPC:
2444 FIXME("(OS_TABLETPC) What should we return here?\n");
2445 return FALSE;
2446 case OS_SERVERADMINUI:
2447 FIXME("(OS_SERVERADMINUI) What should we return here?\n");
2448 return FALSE;
2449 case OS_MEDIACENTER:
2450 FIXME("(OS_MEDIACENTER) What should we return here?\n");
2451 return FALSE;
2452 case OS_APPLIANCE:
2453 FIXME("(OS_APPLIANCE) What should we return here?\n");
2454 return FALSE;
2455 case 0x25: /*OS_VISTAORGREATER*/
2456 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 6);
2459 #undef ISOS_RETURN
2461 WARN("(0x%x) unknown parameter\n", feature);
2463 return FALSE;