ntoskrnl.exe/tests: Fix path buffer allocation size.
[wine.git] / dlls / shcore / main.c
blob973b7c7a037ca158309bd1b3da9c24d9f393d1ff
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 "config.h"
21 #include <stdarg.h>
23 #define COBJMACROS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "initguid.h"
30 #include "ocidl.h"
31 #include "shellscalingapi.h"
32 #include "shlwapi.h"
34 #include "wine/debug.h"
35 #include "wine/heap.h"
36 #include "wine/unicode.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(shcore);
40 static DWORD shcore_tls;
41 static IUnknown *process_ref;
43 BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved)
45 TRACE("(%p, %u, %p)\n", instance, reason, reserved);
47 switch (reason)
49 case DLL_WINE_PREATTACH:
50 return FALSE; /* prefer native version */
51 case DLL_PROCESS_ATTACH:
52 DisableThreadLibraryCalls(instance);
53 shcore_tls = TlsAlloc();
54 break;
55 case DLL_PROCESS_DETACH:
56 if (reserved) break;
57 if (shcore_tls != TLS_OUT_OF_INDEXES)
58 TlsFree(shcore_tls);
59 break;
62 return TRUE;
65 HRESULT WINAPI GetProcessDpiAwareness(HANDLE process, PROCESS_DPI_AWARENESS *value)
67 if (GetProcessDpiAwarenessInternal( process, (DPI_AWARENESS *)value )) return S_OK;
68 return HRESULT_FROM_WIN32( GetLastError() );
71 HRESULT WINAPI SetProcessDpiAwareness(PROCESS_DPI_AWARENESS value)
73 if (SetProcessDpiAwarenessInternal( value )) return S_OK;
74 return HRESULT_FROM_WIN32( GetLastError() );
77 HRESULT WINAPI GetDpiForMonitor(HMONITOR monitor, MONITOR_DPI_TYPE type, UINT *x, UINT *y)
79 if (GetDpiForMonitorInternal( monitor, type, x, y )) return S_OK;
80 return HRESULT_FROM_WIN32( GetLastError() );
83 HRESULT WINAPI _IStream_Read(IStream *stream, void *dest, ULONG size)
85 ULONG read;
86 HRESULT hr;
88 TRACE("(%p, %p, %u)\n", stream, dest, size);
90 hr = IStream_Read(stream, dest, size, &read);
91 if (SUCCEEDED(hr) && read != size)
92 hr = E_FAIL;
93 return hr;
96 HRESULT WINAPI IStream_Reset(IStream *stream)
98 static const LARGE_INTEGER zero;
100 TRACE("(%p)\n", stream);
102 return IStream_Seek(stream, zero, 0, NULL);
105 HRESULT WINAPI IStream_Size(IStream *stream, ULARGE_INTEGER *size)
107 STATSTG statstg;
108 HRESULT hr;
110 TRACE("(%p, %p)\n", stream, size);
112 memset(&statstg, 0, sizeof(statstg));
114 hr = IStream_Stat(stream, &statstg, STATFLAG_NONAME);
116 if (SUCCEEDED(hr) && size)
117 *size = statstg.cbSize;
118 return hr;
121 HRESULT WINAPI _IStream_Write(IStream *stream, const void *src, ULONG size)
123 ULONG written;
124 HRESULT hr;
126 TRACE("(%p, %p, %u)\n", stream, src, size);
128 hr = IStream_Write(stream, src, size, &written);
129 if (SUCCEEDED(hr) && written != size)
130 hr = E_FAIL;
132 return hr;
135 void WINAPI IUnknown_AtomicRelease(IUnknown **obj)
137 TRACE("(%p)\n", obj);
139 if (!obj || !*obj)
140 return;
142 IUnknown_Release(*obj);
143 *obj = NULL;
146 HRESULT WINAPI IUnknown_GetSite(IUnknown *unk, REFIID iid, void **site)
148 IObjectWithSite *obj = NULL;
149 HRESULT hr = E_INVALIDARG;
151 TRACE("(%p, %s, %p)\n", unk, debugstr_guid(iid), site);
153 if (unk && iid && site)
155 hr = IUnknown_QueryInterface(unk, &IID_IObjectWithSite, (void **)&obj);
156 if (SUCCEEDED(hr) && obj)
158 hr = IObjectWithSite_GetSite(obj, iid, site);
159 IObjectWithSite_Release(obj);
163 return hr;
166 HRESULT WINAPI IUnknown_QueryService(IUnknown *obj, REFGUID sid, REFIID iid, void **out)
168 IServiceProvider *provider = NULL;
169 HRESULT hr;
171 if (!out)
172 return E_FAIL;
174 *out = NULL;
176 if (!obj)
177 return E_FAIL;
179 hr = IUnknown_QueryInterface(obj, &IID_IServiceProvider, (void **)&provider);
180 if (hr == S_OK && provider)
182 TRACE("Using provider %p.\n", provider);
184 hr = IServiceProvider_QueryService(provider, sid, iid, out);
186 TRACE("Provider %p returned %p.\n", provider, *out);
188 IServiceProvider_Release(provider);
191 return hr;
194 void WINAPI IUnknown_Set(IUnknown **dest, IUnknown *src)
196 TRACE("(%p, %p)\n", dest, src);
198 IUnknown_AtomicRelease(dest);
200 if (src)
202 IUnknown_AddRef(src);
203 *dest = src;
207 HRESULT WINAPI IUnknown_SetSite(IUnknown *obj, IUnknown *site)
209 IInternetSecurityManager *sec_manager;
210 IObjectWithSite *objwithsite;
211 HRESULT hr;
213 if (!obj)
214 return E_FAIL;
216 hr = IUnknown_QueryInterface(obj, &IID_IObjectWithSite, (void **)&objwithsite);
217 TRACE("ObjectWithSite %p, hr %#x.\n", objwithsite, hr);
218 if (SUCCEEDED(hr))
220 hr = IObjectWithSite_SetSite(objwithsite, site);
221 TRACE("SetSite() hr %#x.\n", hr);
222 IObjectWithSite_Release(objwithsite);
224 else
226 hr = IUnknown_QueryInterface(obj, &IID_IInternetSecurityManager, (void **)&sec_manager);
227 TRACE("InternetSecurityManager %p, hr %#x.\n", sec_manager, hr);
228 if (FAILED(hr))
229 return hr;
231 hr = IInternetSecurityManager_SetSecuritySite(sec_manager, (IInternetSecurityMgrSite *)site);
232 TRACE("SetSecuritySite() hr %#x.\n", hr);
233 IInternetSecurityManager_Release(sec_manager);
236 return hr;
239 HRESULT WINAPI SetCurrentProcessExplicitAppUserModelID(const WCHAR *appid)
241 FIXME("%s: stub\n", debugstr_w(appid));
242 return E_NOTIMPL;
245 HRESULT WINAPI GetCurrentProcessExplicitAppUserModelID(const WCHAR **appid)
247 FIXME("%p: stub\n", appid);
248 *appid = NULL;
249 return E_NOTIMPL;
252 /*************************************************************************
253 * CommandLineToArgvW [SHCORE.@]
255 * We must interpret the quotes in the command line to rebuild the argv
256 * array correctly:
257 * - arguments are separated by spaces or tabs
258 * - quotes serve as optional argument delimiters
259 * '"a b"' -> 'a b'
260 * - escaped quotes must be converted back to '"'
261 * '\"' -> '"'
262 * - consecutive backslashes preceding a quote see their number halved with
263 * the remainder escaping the quote:
264 * 2n backslashes + quote -> n backslashes + quote as an argument delimiter
265 * 2n+1 backslashes + quote -> n backslashes + literal quote
266 * - backslashes that are not followed by a quote are copied literally:
267 * 'a\b' -> 'a\b'
268 * 'a\\b' -> 'a\\b'
269 * - in quoted strings, consecutive quotes see their number divided by three
270 * with the remainder modulo 3 deciding whether to close the string or not.
271 * Note that the opening quote must be counted in the consecutive quotes,
272 * that's the (1+) below:
273 * (1+) 3n quotes -> n quotes
274 * (1+) 3n+1 quotes -> n quotes plus closes the quoted string
275 * (1+) 3n+2 quotes -> n+1 quotes plus closes the quoted string
276 * - in unquoted strings, the first quote opens the quoted string and the
277 * remaining consecutive quotes follow the above rule.
279 WCHAR** WINAPI CommandLineToArgvW(const WCHAR *cmdline, int *numargs)
281 int qcount, bcount;
282 const WCHAR *s;
283 WCHAR **argv;
284 DWORD argc;
285 WCHAR *d;
287 if (!numargs)
289 SetLastError(ERROR_INVALID_PARAMETER);
290 return NULL;
293 if (*cmdline == 0)
295 /* Return the path to the executable */
296 DWORD len, deslen = MAX_PATH, size;
298 size = sizeof(WCHAR *) * 2 + deslen * sizeof(WCHAR);
299 for (;;)
301 if (!(argv = LocalAlloc(LMEM_FIXED, size))) return NULL;
302 len = GetModuleFileNameW(0, (WCHAR *)(argv + 2), deslen);
303 if (!len)
305 LocalFree(argv);
306 return NULL;
308 if (len < deslen) break;
309 deslen *= 2;
310 size = sizeof(WCHAR *) * 2 + deslen * sizeof(WCHAR);
311 LocalFree(argv);
313 argv[0] = (WCHAR *)(argv + 2);
314 argv[1] = NULL;
315 *numargs = 1;
317 return argv;
320 /* --- First count the arguments */
321 argc = 1;
322 s = cmdline;
323 /* The first argument, the executable path, follows special rules */
324 if (*s == '"')
326 /* The executable path ends at the next quote, no matter what */
327 s++;
328 while (*s)
329 if (*s++ == '"')
330 break;
332 else
334 /* The executable path ends at the next space, no matter what */
335 while (*s && *s != ' ' && *s != '\t')
336 s++;
338 /* skip to the first argument, if any */
339 while (*s == ' ' || *s == '\t')
340 s++;
341 if (*s)
342 argc++;
344 /* Analyze the remaining arguments */
345 qcount = bcount = 0;
346 while (*s)
348 if ((*s == ' ' || *s == '\t') && qcount == 0)
350 /* skip to the next argument and count it if any */
351 while (*s == ' ' || *s == '\t')
352 s++;
353 if (*s)
354 argc++;
355 bcount = 0;
357 else if (*s == '\\')
359 /* '\', count them */
360 bcount++;
361 s++;
363 else if (*s == '"')
365 /* '"' */
366 if ((bcount & 1) == 0)
367 qcount++; /* unescaped '"' */
368 s++;
369 bcount = 0;
370 /* consecutive quotes, see comment in copying code below */
371 while (*s == '"')
373 qcount++;
374 s++;
376 qcount = qcount % 3;
377 if (qcount == 2)
378 qcount = 0;
380 else
382 /* a regular character */
383 bcount = 0;
384 s++;
388 /* Allocate in a single lump, the string array, and the strings that go
389 * with it. This way the caller can make a single LocalFree() call to free
390 * both, as per MSDN.
392 argv = LocalAlloc(LMEM_FIXED, (argc + 1) * sizeof(WCHAR *) + (strlenW(cmdline) + 1) * sizeof(WCHAR));
393 if (!argv)
394 return NULL;
396 /* --- Then split and copy the arguments */
397 argv[0] = d = strcpyW((WCHAR *)(argv + argc + 1), cmdline);
398 argc = 1;
399 /* The first argument, the executable path, follows special rules */
400 if (*d == '"')
402 /* The executable path ends at the next quote, no matter what */
403 s = d + 1;
404 while (*s)
406 if (*s == '"')
408 s++;
409 break;
411 *d++ = *s++;
414 else
416 /* The executable path ends at the next space, no matter what */
417 while (*d && *d != ' ' && *d != '\t')
418 d++;
419 s = d;
420 if (*s)
421 s++;
423 /* close the executable path */
424 *d++ = 0;
425 /* skip to the first argument and initialize it if any */
426 while (*s == ' ' || *s == '\t')
427 s++;
428 if (!*s)
430 /* There are no parameters so we are all done */
431 argv[argc] = NULL;
432 *numargs = argc;
433 return argv;
436 /* Split and copy the remaining arguments */
437 argv[argc++] = d;
438 qcount = bcount = 0;
439 while (*s)
441 if ((*s == ' ' || *s == '\t') && qcount == 0)
443 /* close the argument */
444 *d++ = 0;
445 bcount = 0;
447 /* skip to the next one and initialize it if any */
448 do {
449 s++;
450 } while (*s == ' ' || *s == '\t');
451 if (*s)
452 argv[argc++] = d;
454 else if (*s=='\\')
456 *d++ = *s++;
457 bcount++;
459 else if (*s == '"')
461 if ((bcount & 1) == 0)
463 /* Preceded by an even number of '\', this is half that
464 * number of '\', plus a quote which we erase.
466 d -= bcount / 2;
467 qcount++;
469 else
471 /* Preceded by an odd number of '\', this is half that
472 * number of '\' followed by a '"'
474 d = d - bcount / 2 - 1;
475 *d++ = '"';
477 s++;
478 bcount = 0;
479 /* Now count the number of consecutive quotes. Note that qcount
480 * already takes into account the opening quote if any, as well as
481 * the quote that lead us here.
483 while (*s == '"')
485 if (++qcount == 3)
487 *d++ = '"';
488 qcount = 0;
490 s++;
492 if (qcount == 2)
493 qcount = 0;
495 else
497 /* a regular character */
498 *d++ = *s++;
499 bcount = 0;
502 *d = '\0';
503 argv[argc] = NULL;
504 *numargs = argc;
506 return argv;
509 struct shstream
511 IStream IStream_iface;
512 LONG refcount;
514 union
516 struct
518 BYTE *buffer;
519 DWORD length;
520 DWORD position;
522 HKEY hkey;
523 WCHAR *valuename;
524 } mem;
525 struct
527 HANDLE handle;
528 DWORD mode;
529 WCHAR *path;
530 } file;
531 } u;
534 static inline struct shstream *impl_from_IStream(IStream *iface)
536 return CONTAINING_RECORD(iface, struct shstream, IStream_iface);
539 static HRESULT WINAPI shstream_QueryInterface(IStream *iface, REFIID riid, void **out)
541 struct shstream *stream = impl_from_IStream(iface);
543 TRACE("(%p)->(%s, %p)\n", stream, debugstr_guid(riid), out);
545 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IStream))
547 *out = iface;
548 IStream_AddRef(iface);
549 return S_OK;
552 *out = NULL;
553 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
554 return E_NOINTERFACE;
557 static ULONG WINAPI shstream_AddRef(IStream *iface)
559 struct shstream *stream = impl_from_IStream(iface);
560 ULONG refcount = InterlockedIncrement(&stream->refcount);
562 TRACE("(%p)->(%u)\n", stream, refcount);
564 return refcount;
567 static ULONG WINAPI memstream_Release(IStream *iface)
569 struct shstream *stream = impl_from_IStream(iface);
570 ULONG refcount = InterlockedDecrement(&stream->refcount);
572 TRACE("(%p)->(%u)\n", stream, refcount);
574 if (!refcount)
576 heap_free(stream->u.mem.buffer);
577 heap_free(stream);
580 return refcount;
583 static HRESULT WINAPI memstream_Read(IStream *iface, void *buff, ULONG buff_size, ULONG *read_len)
585 struct shstream *stream = impl_from_IStream(iface);
586 DWORD length;
588 TRACE("(%p)->(%p, %u, %p)\n", stream, buff, buff_size, read_len);
590 if (stream->u.mem.position >= stream->u.mem.length)
591 length = 0;
592 else
593 length = stream->u.mem.length - stream->u.mem.position;
595 length = buff_size > length ? length : buff_size;
596 if (length != 0) /* not at end of buffer and we want to read something */
598 memmove(buff, stream->u.mem.buffer + stream->u.mem.position, length);
599 stream->u.mem.position += length; /* adjust pointer */
602 if (read_len)
603 *read_len = length;
605 return S_OK;
608 static HRESULT WINAPI memstream_Write(IStream *iface, const void *buff, ULONG buff_size, ULONG *written)
610 struct shstream *stream = impl_from_IStream(iface);
611 DWORD length = stream->u.mem.position + buff_size;
613 TRACE("(%p)->(%p, %u, %p)\n", stream, buff, buff_size, written);
615 if (length < stream->u.mem.position) /* overflow */
616 return STG_E_INSUFFICIENTMEMORY;
618 if (length > stream->u.mem.length)
620 BYTE *buffer = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, stream->u.mem.buffer, length);
621 if (!buffer)
622 return STG_E_INSUFFICIENTMEMORY;
624 stream->u.mem.length = length;
625 stream->u.mem.buffer = buffer;
627 memmove(stream->u.mem.buffer + stream->u.mem.position, buff, buff_size);
628 stream->u.mem.position += buff_size; /* adjust pointer */
630 if (written)
631 *written = buff_size;
633 return S_OK;
636 static HRESULT WINAPI memstream_Seek(IStream *iface, LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER*new_pos)
638 struct shstream *stream = impl_from_IStream(iface);
639 LARGE_INTEGER tmp;
641 TRACE("(%p)->(%s, %d, %p)\n", stream, wine_dbgstr_longlong(move.QuadPart), origin, new_pos);
643 if (origin == STREAM_SEEK_SET)
644 tmp = move;
645 else if (origin == STREAM_SEEK_CUR)
646 tmp.QuadPart = stream->u.mem.position + move.QuadPart;
647 else if (origin == STREAM_SEEK_END)
648 tmp.QuadPart = stream->u.mem.length + move.QuadPart;
649 else
650 return STG_E_INVALIDPARAMETER;
652 if (tmp.QuadPart < 0)
653 return STG_E_INVALIDFUNCTION;
655 /* we cut off the high part here */
656 stream->u.mem.position = tmp.u.LowPart;
658 if (new_pos)
659 new_pos->QuadPart = stream->u.mem.position;
660 return S_OK;
663 static HRESULT WINAPI memstream_SetSize(IStream *iface, ULARGE_INTEGER new_size)
665 struct shstream *stream = impl_from_IStream(iface);
666 DWORD length;
667 BYTE *buffer;
669 TRACE("(%p, %s)\n", stream, wine_dbgstr_longlong(new_size.QuadPart));
671 /* we cut off the high part here */
672 length = new_size.u.LowPart;
673 buffer = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, stream->u.mem.buffer, length);
674 if (!buffer)
675 return STG_E_INSUFFICIENTMEMORY;
677 stream->u.mem.buffer = buffer;
678 stream->u.mem.length = length;
680 return S_OK;
683 static HRESULT WINAPI shstream_CopyTo(IStream *iface, IStream *pstm, ULARGE_INTEGER size, ULARGE_INTEGER *read_len, ULARGE_INTEGER *written)
685 struct shstream *stream = impl_from_IStream(iface);
687 TRACE("(%p)\n", stream);
689 if (read_len)
690 read_len->QuadPart = 0;
692 if (written)
693 written->QuadPart = 0;
695 /* TODO implement */
696 return E_NOTIMPL;
699 static HRESULT WINAPI shstream_Commit(IStream *iface, DWORD flags)
701 struct shstream *stream = impl_from_IStream(iface);
703 TRACE("(%p, %#x)\n", stream, flags);
705 /* Commit is not supported by this stream */
706 return E_NOTIMPL;
709 static HRESULT WINAPI shstream_Revert(IStream *iface)
711 struct shstream *stream = impl_from_IStream(iface);
713 TRACE("(%p)\n", stream);
715 /* revert not supported by this stream */
716 return E_NOTIMPL;
719 static HRESULT WINAPI shstream_LockRegion(IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER size, DWORD lock_type)
721 struct shstream *stream = impl_from_IStream(iface);
723 TRACE("(%p)\n", stream);
725 /* lock/unlock not supported by this stream */
726 return E_NOTIMPL;
729 static HRESULT WINAPI shstream_UnlockRegion(IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER size, DWORD lock_type)
731 struct shstream *stream = impl_from_IStream(iface);
733 TRACE("(%p)\n", stream);
735 /* lock/unlock not supported by this stream */
736 return E_NOTIMPL;
739 static HRESULT WINAPI memstream_Stat(IStream *iface, STATSTG *statstg, DWORD flags)
741 struct shstream *stream = impl_from_IStream(iface);
743 TRACE("(%p, %p, %#x)\n", stream, statstg, flags);
745 memset(statstg, 0, sizeof(*statstg));
746 statstg->type = STGTY_STREAM;
747 statstg->cbSize.QuadPart = stream->u.mem.length;
748 statstg->grfMode = STGM_READWRITE;
750 return S_OK;
753 static HRESULT WINAPI shstream_Clone(IStream *iface, IStream **dest)
755 struct shstream *stream = impl_from_IStream(iface);
757 TRACE("(%p, %p)\n", stream, dest);
759 *dest = NULL;
761 /* clone not supported by this stream */
762 return E_NOTIMPL;
765 static const IStreamVtbl memstreamvtbl =
767 shstream_QueryInterface,
768 shstream_AddRef,
769 memstream_Release,
770 memstream_Read,
771 memstream_Write,
772 memstream_Seek,
773 memstream_SetSize,
774 shstream_CopyTo,
775 shstream_Commit,
776 shstream_Revert,
777 shstream_LockRegion,
778 shstream_UnlockRegion,
779 memstream_Stat,
780 shstream_Clone,
783 static struct shstream *shstream_create(const IStreamVtbl *vtbl, const BYTE *data, UINT data_len)
785 struct shstream *stream;
787 if (!data)
788 data_len = 0;
790 stream = heap_alloc(sizeof(*stream));
791 stream->IStream_iface.lpVtbl = vtbl;
792 stream->refcount = 1;
793 stream->u.mem.buffer = heap_alloc(data_len);
794 if (!stream->u.mem.buffer)
796 heap_free(stream);
797 return NULL;
799 memcpy(stream->u.mem.buffer, data, data_len);
800 stream->u.mem.length = data_len;
801 stream->u.mem.position = 0;
803 return stream;
806 /*************************************************************************
807 * SHCreateMemStream [SHCORE.@]
809 * Create an IStream object on a block of memory.
811 * PARAMS
812 * data [I] Memory block to create the IStream object on
813 * data_len [I] Length of data block
815 * RETURNS
816 * Success: A pointer to the IStream object.
817 * Failure: NULL, if any parameters are invalid or an error occurs.
819 * NOTES
820 * A copy of the memory block is made, it's freed when the stream is released.
822 IStream * WINAPI SHCreateMemStream(const BYTE *data, UINT data_len)
824 struct shstream *stream;
826 TRACE("(%p, %u)\n", data, data_len);
828 stream = shstream_create(&memstreamvtbl, data, data_len);
829 return stream ? &stream->IStream_iface : NULL;
832 static ULONG WINAPI filestream_Release(IStream *iface)
834 struct shstream *stream = impl_from_IStream(iface);
835 ULONG refcount = InterlockedDecrement(&stream->refcount);
837 TRACE("(%p)->(%u)\n", stream, refcount);
839 if (!refcount)
841 CloseHandle(stream->u.file.handle);
842 heap_free(stream->u.file.path);
843 heap_free(stream);
846 return refcount;
849 static HRESULT WINAPI filestream_Read(IStream *iface, void *buff, ULONG size, ULONG *read_len)
851 struct shstream *stream = impl_from_IStream(iface);
852 DWORD read = 0;
854 TRACE("(%p, %p, %u, %p)\n", stream, buff, size, read_len);
856 if (!ReadFile(stream->u.file.handle, buff, size, &read, NULL))
858 WARN("error %d reading file\n", GetLastError());
859 return S_FALSE;
862 if (read_len)
863 *read_len = read;
865 return read == size ? S_OK : S_FALSE;
868 static HRESULT WINAPI filestream_Write(IStream *iface, const void *buff, ULONG size, ULONG *written)
870 struct shstream *stream = impl_from_IStream(iface);
871 DWORD written_len = 0;
873 TRACE("(%p, %p, %u, %p)\n", stream, buff, size, written);
875 switch (stream->u.file.mode & 0xf)
877 case STGM_WRITE:
878 case STGM_READWRITE:
879 break;
880 default:
881 return STG_E_ACCESSDENIED;
884 if (!WriteFile(stream->u.file.handle, buff, size, &written_len, NULL))
885 return HRESULT_FROM_WIN32(GetLastError());
887 if (written)
888 *written = written_len;
890 return S_OK;
893 static HRESULT WINAPI filestream_Seek(IStream *iface, LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER *new_pos)
895 struct shstream *stream = impl_from_IStream(iface);
896 DWORD position;
898 TRACE("(%p, %s, %d, %p)\n", stream, wine_dbgstr_longlong(move.QuadPart), origin, new_pos);
900 position = SetFilePointer(stream->u.file.handle, move.u.LowPart, NULL, origin);
901 if (position == INVALID_SET_FILE_POINTER)
902 return HRESULT_FROM_WIN32(GetLastError());
904 if (new_pos)
906 new_pos->u.HighPart = 0;
907 new_pos->u.LowPart = position;
910 return S_OK;
913 static HRESULT WINAPI filestream_SetSize(IStream *iface, ULARGE_INTEGER size)
915 struct shstream *stream = impl_from_IStream(iface);
917 TRACE("(%p, %s)\n", stream, wine_dbgstr_longlong(size.QuadPart));
919 if (!SetFilePointer(stream->u.file.handle, size.QuadPart, NULL, FILE_BEGIN))
920 return E_FAIL;
922 if (!SetEndOfFile(stream->u.file.handle))
923 return E_FAIL;
925 return S_OK;
928 static HRESULT WINAPI filestream_CopyTo(IStream *iface, IStream *dest, ULARGE_INTEGER size,
929 ULARGE_INTEGER *read_len, ULARGE_INTEGER *written)
931 struct shstream *stream = impl_from_IStream(iface);
932 HRESULT hr = S_OK;
933 char buff[1024];
935 TRACE("(%p, %p, %s, %p, %p)\n", stream, dest, wine_dbgstr_longlong(size.QuadPart), read_len, written);
937 if (read_len)
938 read_len->QuadPart = 0;
939 if (written)
940 written->QuadPart = 0;
942 if (!dest)
943 return S_OK;
945 while (size.QuadPart)
947 ULONG left, read_chunk, written_chunk;
949 left = size.QuadPart > sizeof(buff) ? sizeof(buff) : size.QuadPart;
951 /* Read */
952 hr = IStream_Read(iface, buff, left, &read_chunk);
953 if (FAILED(hr) || read_chunk == 0)
954 break;
955 if (read_len)
956 read_len->QuadPart += read_chunk;
958 /* Write */
959 hr = IStream_Write(dest, buff, read_chunk, &written_chunk);
960 if (written_chunk)
961 written->QuadPart += written_chunk;
962 if (FAILED(hr) || written_chunk != left)
963 break;
965 size.QuadPart -= left;
968 return hr;
971 static HRESULT WINAPI filestream_Commit(IStream *iface, DWORD flags)
973 struct shstream *stream = impl_from_IStream(iface);
975 TRACE("(%p, %#x)\n", stream, flags);
977 return S_OK;
980 static HRESULT WINAPI filestream_Stat(IStream *iface, STATSTG *statstg, DWORD flags)
982 struct shstream *stream = impl_from_IStream(iface);
983 BY_HANDLE_FILE_INFORMATION fi;
985 TRACE("(%p, %p, %#x)\n", stream, statstg, flags);
987 if (!statstg)
988 return STG_E_INVALIDPOINTER;
990 memset(&fi, 0, sizeof(fi));
991 GetFileInformationByHandle(stream->u.file.handle, &fi);
993 if (flags & STATFLAG_NONAME)
994 statstg->pwcsName = NULL;
995 else
997 int len = strlenW(stream->u.file.path);
998 if ((statstg->pwcsName = CoTaskMemAlloc((len + 1) * sizeof(WCHAR))))
999 memcpy(statstg->pwcsName, stream->u.file.path, (len + 1) * sizeof(WCHAR));
1001 statstg->type = 0;
1002 statstg->cbSize.u.LowPart = fi.nFileSizeLow;
1003 statstg->cbSize.u.HighPart = fi.nFileSizeHigh;
1004 statstg->mtime = fi.ftLastWriteTime;
1005 statstg->ctime = fi.ftCreationTime;
1006 statstg->atime = fi.ftLastAccessTime;
1007 statstg->grfMode = stream->u.file.mode;
1008 statstg->grfLocksSupported = 0;
1009 memcpy(&statstg->clsid, &IID_IStream, sizeof(CLSID));
1010 statstg->grfStateBits = 0;
1011 statstg->reserved = 0;
1013 return S_OK;
1016 static const IStreamVtbl filestreamvtbl =
1018 shstream_QueryInterface,
1019 shstream_AddRef,
1020 filestream_Release,
1021 filestream_Read,
1022 filestream_Write,
1023 filestream_Seek,
1024 filestream_SetSize,
1025 filestream_CopyTo,
1026 filestream_Commit,
1027 shstream_Revert,
1028 shstream_LockRegion,
1029 shstream_UnlockRegion,
1030 filestream_Stat,
1031 shstream_Clone,
1034 /*************************************************************************
1035 * SHCreateStreamOnFileEx [SHCORE.@]
1037 HRESULT WINAPI SHCreateStreamOnFileEx(const WCHAR *path, DWORD mode, DWORD attributes,
1038 BOOL create, IStream *template, IStream **ret)
1040 DWORD access, share, creation_disposition, len;
1041 struct shstream *stream;
1042 HANDLE hFile;
1044 TRACE("(%s, %d, 0x%08X, %d, %p, %p)\n", debugstr_w(path), mode, attributes,
1045 create, template, ret);
1047 if (!path || !ret || template)
1048 return E_INVALIDARG;
1050 *ret = NULL;
1052 /* Access */
1053 switch (mode & 0xf)
1055 case STGM_WRITE:
1056 case STGM_READWRITE:
1057 access = GENERIC_READ | GENERIC_WRITE;
1058 break;
1059 case STGM_READ:
1060 access = GENERIC_READ;
1061 break;
1062 default:
1063 return E_INVALIDARG;
1066 /* Sharing */
1067 switch (mode & 0xf0)
1069 case 0:
1070 case STGM_SHARE_DENY_NONE:
1071 share = FILE_SHARE_READ | FILE_SHARE_WRITE;
1072 break;
1073 case STGM_SHARE_DENY_READ:
1074 share = FILE_SHARE_WRITE;
1075 break;
1076 case STGM_SHARE_DENY_WRITE:
1077 share = FILE_SHARE_READ;
1078 break;
1079 case STGM_SHARE_EXCLUSIVE:
1080 share = 0;
1081 break;
1082 default:
1083 return E_INVALIDARG;
1086 switch (mode & 0xf000)
1088 case STGM_FAILIFTHERE:
1089 creation_disposition = create ? CREATE_NEW : OPEN_EXISTING;
1090 break;
1091 case STGM_CREATE:
1092 creation_disposition = CREATE_ALWAYS;
1093 break;
1094 default:
1095 return E_INVALIDARG;
1098 hFile = CreateFileW(path, access, share, NULL, creation_disposition, attributes, 0);
1099 if (hFile == INVALID_HANDLE_VALUE)
1100 return HRESULT_FROM_WIN32(GetLastError());
1102 stream = heap_alloc(sizeof(*stream));
1103 stream->IStream_iface.lpVtbl = &filestreamvtbl;
1104 stream->refcount = 1;
1105 stream->u.file.handle = hFile;
1106 stream->u.file.mode = mode;
1108 len = strlenW(path);
1109 stream->u.file.path = heap_alloc((len + 1) * sizeof(WCHAR));
1110 memcpy(stream->u.file.path, path, (len + 1) * sizeof(WCHAR));
1112 *ret = &stream->IStream_iface;
1114 return S_OK;
1117 /*************************************************************************
1118 * SHCreateStreamOnFileW [SHCORE.@]
1120 HRESULT WINAPI SHCreateStreamOnFileW(const WCHAR *path, DWORD mode, IStream **stream)
1122 TRACE("(%s, %#x, %p)\n", debugstr_w(path), mode, stream);
1124 if (!path || !stream)
1125 return E_INVALIDARG;
1127 if ((mode & (STGM_CONVERT | STGM_DELETEONRELEASE | STGM_TRANSACTED)) != 0)
1128 return E_INVALIDARG;
1130 return SHCreateStreamOnFileEx(path, mode, 0, FALSE, NULL, stream);
1133 /*************************************************************************
1134 * SHCreateStreamOnFileA [SHCORE.@]
1136 HRESULT WINAPI SHCreateStreamOnFileA(const char *path, DWORD mode, IStream **stream)
1138 WCHAR *pathW;
1139 HRESULT hr;
1140 DWORD len;
1142 TRACE("(%s, %#x, %p)\n", debugstr_a(path), mode, stream);
1144 if (!path)
1145 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1147 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1148 pathW = heap_alloc(len * sizeof(WCHAR));
1149 if (!pathW)
1150 return E_OUTOFMEMORY;
1152 MultiByteToWideChar(CP_ACP, 0, path, -1, pathW, len);
1153 hr = SHCreateStreamOnFileW(pathW, mode, stream);
1154 heap_free(pathW);
1156 return hr;
1159 static ULONG WINAPI regstream_Release(IStream *iface)
1161 struct shstream *stream = impl_from_IStream(iface);
1162 ULONG refcount = InterlockedDecrement(&stream->refcount);
1164 TRACE("(%p)->(%u)\n", stream, refcount);
1166 if (!refcount)
1168 if (stream->u.mem.hkey)
1170 if (stream->u.mem.length)
1171 RegSetValueExW(stream->u.mem.hkey, stream->u.mem.valuename, 0, REG_BINARY,
1172 (const BYTE *)stream->u.mem.buffer, stream->u.mem.length);
1173 else
1174 RegDeleteValueW(stream->u.mem.hkey, stream->u.mem.valuename);
1175 RegCloseKey(stream->u.mem.hkey);
1177 CoTaskMemFree(stream->u.mem.valuename);
1178 heap_free(stream->u.mem.buffer);
1179 heap_free(stream);
1182 return refcount;
1185 static const IStreamVtbl regstreamvtbl =
1187 shstream_QueryInterface,
1188 shstream_AddRef,
1189 regstream_Release,
1190 memstream_Read,
1191 memstream_Write,
1192 memstream_Seek,
1193 memstream_SetSize,
1194 shstream_CopyTo,
1195 shstream_Commit,
1196 shstream_Revert,
1197 shstream_LockRegion,
1198 shstream_UnlockRegion,
1199 memstream_Stat,
1200 shstream_Clone,
1203 /*************************************************************************
1204 * SHOpenRegStream2W [SHCORE.@]
1206 IStream * WINAPI SHOpenRegStream2W(HKEY hKey, const WCHAR *subkey, const WCHAR *value, DWORD mode)
1208 struct shstream *stream;
1209 HKEY hStrKey = NULL;
1210 BYTE *buff = NULL;
1211 DWORD length = 0;
1212 LONG ret;
1214 TRACE("(%p, %s, %s, %#x)\n", hKey, debugstr_w(subkey), debugstr_w(value), mode);
1216 if (mode == STGM_READ)
1217 ret = RegOpenKeyExW(hKey, subkey, 0, KEY_READ, &hStrKey);
1218 else /* in write mode we make sure the subkey exits */
1219 ret = RegCreateKeyExW(hKey, subkey, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &hStrKey, NULL);
1221 if (ret == ERROR_SUCCESS)
1223 if (mode == STGM_READ || mode == STGM_READWRITE)
1225 /* read initial data */
1226 ret = RegQueryValueExW(hStrKey, value, 0, 0, 0, &length);
1227 if (ret == ERROR_SUCCESS && length)
1229 buff = heap_alloc(length);
1230 RegQueryValueExW(hStrKey, value, 0, 0, buff, &length);
1234 if (!length)
1235 buff = heap_alloc(length);
1237 stream = shstream_create(&regstreamvtbl, buff, length);
1238 heap_free(buff);
1239 if (stream)
1241 stream->u.mem.hkey = hStrKey;
1242 SHStrDupW(value, &stream->u.mem.valuename);
1243 return &stream->IStream_iface;
1247 if (hStrKey)
1248 RegCloseKey(hStrKey);
1250 return NULL;
1253 /*************************************************************************
1254 * SHOpenRegStream2A [SHCORE.@]
1256 IStream * WINAPI SHOpenRegStream2A(HKEY hKey, const char *subkey, const char *value, DWORD mode)
1258 WCHAR *subkeyW = NULL, *valueW = NULL;
1259 IStream *stream;
1261 TRACE("(%p, %s, %s, %#x)\n", hKey, debugstr_a(subkey), debugstr_a(value), mode);
1263 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1264 return NULL;
1265 if (value && FAILED(SHStrDupA(value, &valueW)))
1267 CoTaskMemFree(subkeyW);
1268 return NULL;
1271 stream = SHOpenRegStream2W(hKey, subkeyW, valueW, mode);
1272 CoTaskMemFree(subkeyW);
1273 CoTaskMemFree(valueW);
1274 return stream;
1277 /*************************************************************************
1278 * SHOpenRegStreamA [SHCORE.@]
1280 IStream * WINAPI SHOpenRegStreamA(HKEY hkey, const char *subkey, const char *value, DWORD mode)
1282 WCHAR *subkeyW = NULL, *valueW = NULL;
1283 IStream *stream;
1285 TRACE("(%p, %s, %s, %#x)\n", hkey, debugstr_a(subkey), debugstr_a(value), mode);
1287 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1288 return NULL;
1289 if (value && FAILED(SHStrDupA(value, &valueW)))
1291 CoTaskMemFree(subkeyW);
1292 return NULL;
1295 stream = SHOpenRegStreamW(hkey, subkeyW, valueW, mode);
1296 CoTaskMemFree(subkeyW);
1297 CoTaskMemFree(valueW);
1298 return stream;
1301 static ULONG WINAPI dummystream_AddRef(IStream *iface)
1303 TRACE("()\n");
1304 return 2;
1307 static ULONG WINAPI dummystream_Release(IStream *iface)
1309 TRACE("()\n");
1310 return 1;
1313 static HRESULT WINAPI dummystream_Read(IStream *iface, void *buff, ULONG buff_size, ULONG *read_len)
1315 if (read_len)
1316 *read_len = 0;
1318 return E_NOTIMPL;
1321 static const IStreamVtbl dummystreamvtbl =
1323 shstream_QueryInterface,
1324 dummystream_AddRef,
1325 dummystream_Release,
1326 dummystream_Read,
1327 memstream_Write,
1328 memstream_Seek,
1329 memstream_SetSize,
1330 shstream_CopyTo,
1331 shstream_Commit,
1332 shstream_Revert,
1333 shstream_LockRegion,
1334 shstream_UnlockRegion,
1335 memstream_Stat,
1336 shstream_Clone,
1339 static struct shstream dummyregstream = { { &dummystreamvtbl } };
1341 /*************************************************************************
1342 * SHOpenRegStreamW [SHCORE.@]
1344 IStream * WINAPI SHOpenRegStreamW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, DWORD mode)
1346 IStream *stream;
1348 TRACE("(%p, %s, %s, %#x)\n", hkey, debugstr_w(subkey), debugstr_w(value), mode);
1349 stream = SHOpenRegStream2W(hkey, subkey, value, mode);
1350 return stream ? stream : &dummyregstream.IStream_iface;
1353 struct threadref
1355 IUnknown IUnknown_iface;
1356 LONG *refcount;
1359 static inline struct threadref *threadref_impl_from_IUnknown(IUnknown *iface)
1361 return CONTAINING_RECORD(iface, struct threadref, IUnknown_iface);
1364 static HRESULT WINAPI threadref_QueryInterface(IUnknown *iface, REFIID riid, void **out)
1366 struct threadref *threadref = threadref_impl_from_IUnknown(iface);
1368 TRACE("(%p, %s, %p)\n", threadref, debugstr_guid(riid), out);
1370 if (out == NULL)
1371 return E_POINTER;
1373 if (IsEqualGUID(&IID_IUnknown, riid))
1375 *out = iface;
1376 IUnknown_AddRef(iface);
1377 return S_OK;
1380 *out = NULL;
1381 WARN("Interface %s not supported.\n", debugstr_guid(riid));
1382 return E_NOINTERFACE;
1385 static ULONG WINAPI threadref_AddRef(IUnknown *iface)
1387 struct threadref *threadref = threadref_impl_from_IUnknown(iface);
1388 LONG refcount = InterlockedIncrement(threadref->refcount);
1390 TRACE("(%p, %d)\n", threadref, refcount);
1392 return refcount;
1395 static ULONG WINAPI threadref_Release(IUnknown *iface)
1397 struct threadref *threadref = threadref_impl_from_IUnknown(iface);
1398 LONG refcount = InterlockedDecrement(threadref->refcount);
1400 TRACE("(%p, %d)\n", threadref, refcount);
1402 if (!refcount)
1403 heap_free(threadref);
1405 return refcount;
1408 static const IUnknownVtbl threadrefvtbl =
1410 threadref_QueryInterface,
1411 threadref_AddRef,
1412 threadref_Release,
1415 /*************************************************************************
1416 * SHCreateThreadRef [SHCORE.@]
1418 HRESULT WINAPI SHCreateThreadRef(LONG *refcount, IUnknown **out)
1420 struct threadref *threadref;
1422 TRACE("(%p, %p)\n", refcount, out);
1424 if (!refcount || !out)
1425 return E_INVALIDARG;
1427 *out = NULL;
1429 threadref = heap_alloc(sizeof(*threadref));
1430 if (!threadref)
1431 return E_OUTOFMEMORY;
1432 threadref->IUnknown_iface.lpVtbl = &threadrefvtbl;
1433 threadref->refcount = refcount;
1435 *refcount = 1;
1436 *out = &threadref->IUnknown_iface;
1438 TRACE("Created %p.\n", threadref);
1439 return S_OK;
1442 /*************************************************************************
1443 * SHGetThreadRef [SHCORE.@]
1445 HRESULT WINAPI SHGetThreadRef(IUnknown **out)
1447 TRACE("(%p)\n", out);
1449 if (shcore_tls == TLS_OUT_OF_INDEXES)
1450 return E_NOINTERFACE;
1452 *out = TlsGetValue(shcore_tls);
1453 if (!*out)
1454 return E_NOINTERFACE;
1456 IUnknown_AddRef(*out);
1457 return S_OK;
1460 /*************************************************************************
1461 * SHSetThreadRef [SHCORE.@]
1463 HRESULT WINAPI SHSetThreadRef(IUnknown *obj)
1465 TRACE("(%p)\n", obj);
1467 if (shcore_tls == TLS_OUT_OF_INDEXES)
1468 return E_NOINTERFACE;
1470 TlsSetValue(shcore_tls, obj);
1471 return S_OK;
1474 /*************************************************************************
1475 * SHReleaseThreadRef [SHCORE.@]
1477 HRESULT WINAPI SHReleaseThreadRef(void)
1479 FIXME("() - stub!\n");
1480 return S_OK;
1483 /*************************************************************************
1484 * GetProcessReference [SHCORE.@]
1486 HRESULT WINAPI GetProcessReference(IUnknown **obj)
1488 TRACE("(%p)\n", obj);
1490 *obj = process_ref;
1492 if (!process_ref)
1493 return E_FAIL;
1495 if (*obj)
1496 IUnknown_AddRef(*obj);
1498 return S_OK;
1501 /*************************************************************************
1502 * SetProcessReference [SHCORE.@]
1504 void WINAPI SetProcessReference(IUnknown *obj)
1506 TRACE("(%p)\n", obj);
1508 process_ref = obj;
1511 struct thread_data
1513 LPTHREAD_START_ROUTINE thread_proc;
1514 LPTHREAD_START_ROUTINE callback;
1515 void *data;
1516 DWORD flags;
1517 HANDLE hEvent;
1518 IUnknown *thread_ref;
1519 IUnknown *process_ref;
1522 static DWORD WINAPI shcore_thread_wrapper(void *data)
1524 struct thread_data thread_data;
1525 HRESULT hr = E_FAIL;
1526 DWORD retval;
1528 TRACE("(%p)\n", data);
1530 /* We are now executing in the context of the newly created thread.
1531 * So we copy the data passed to us (it is on the stack of the function
1532 * that called us, which is waiting for us to signal an event before
1533 * returning). */
1534 thread_data = *(struct thread_data *)data;
1536 if (thread_data.flags & CTF_COINIT)
1538 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
1539 if (FAILED(hr))
1540 hr = CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE);
1543 if (thread_data.callback)
1544 thread_data.callback(thread_data.data);
1546 /* Signal the thread that created us; it can return now. */
1547 SetEvent(thread_data.hEvent);
1549 /* Execute the callers start code. */
1550 retval = thread_data.thread_proc(thread_data.data);
1552 /* Release thread and process references. */
1553 if (thread_data.thread_ref)
1554 IUnknown_Release(thread_data.thread_ref);
1556 if (thread_data.process_ref)
1557 IUnknown_Release(thread_data.process_ref);
1559 if (SUCCEEDED(hr))
1560 CoUninitialize();
1562 return retval;
1565 /*************************************************************************
1566 * SHCreateThread [SHCORE.@]
1568 BOOL WINAPI SHCreateThread(LPTHREAD_START_ROUTINE thread_proc, void *data, DWORD flags, LPTHREAD_START_ROUTINE callback)
1570 struct thread_data thread_data;
1571 BOOL called = FALSE;
1573 TRACE("(%p, %p, %#x, %p)\n", thread_proc, data, flags, callback);
1575 thread_data.thread_proc = thread_proc;
1576 thread_data.callback = callback;
1577 thread_data.data = data;
1578 thread_data.flags = flags;
1579 thread_data.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
1581 if (flags & CTF_THREAD_REF)
1582 SHGetThreadRef(&thread_data.thread_ref);
1583 else
1584 thread_data.thread_ref = NULL;
1586 if (flags & CTF_PROCESS_REF)
1587 GetProcessReference(&thread_data.process_ref);
1588 else
1589 thread_data.process_ref = NULL;
1591 /* Create the thread */
1592 if (thread_data.hEvent)
1594 HANDLE hThread;
1595 DWORD retval;
1597 hThread = CreateThread(NULL, 0, shcore_thread_wrapper, &thread_data, 0, &retval);
1598 if (hThread)
1600 /* Wait for the thread to signal us to continue */
1601 WaitForSingleObject(thread_data.hEvent, INFINITE);
1602 CloseHandle(hThread);
1603 called = TRUE;
1605 CloseHandle(thread_data.hEvent);
1608 if (!called)
1610 if (!thread_data.callback && flags & CTF_INSIST)
1612 /* Couldn't call, call synchronously */
1613 thread_data.thread_proc(data);
1614 called = TRUE;
1616 else
1618 if (thread_data.thread_ref)
1619 IUnknown_Release(thread_data.thread_ref);
1621 if (thread_data.process_ref)
1622 IUnknown_Release(thread_data.process_ref);
1626 return called;
1629 /*************************************************************************
1630 * SHStrDupW [SHCORE.@]
1632 HRESULT WINAPI SHStrDupW(const WCHAR *src, WCHAR **dest)
1634 size_t len;
1636 TRACE("(%s, %p)\n", debugstr_w(src), dest);
1638 *dest = NULL;
1640 if (!src)
1641 return E_INVALIDARG;
1643 len = (strlenW(src) + 1) * sizeof(WCHAR);
1644 *dest = CoTaskMemAlloc(len);
1645 if (!*dest)
1646 return E_OUTOFMEMORY;
1648 memcpy(*dest, src, len);
1650 return S_OK;
1653 /*************************************************************************
1654 * SHStrDupA [SHCORE.@]
1656 HRESULT WINAPI SHStrDupA(const char *src, WCHAR **dest)
1658 DWORD len;
1660 *dest = NULL;
1662 if (!src)
1663 return E_INVALIDARG;
1665 len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
1666 *dest = CoTaskMemAlloc(len * sizeof(WCHAR));
1667 if (!*dest)
1668 return E_OUTOFMEMORY;
1670 MultiByteToWideChar(CP_ACP, 0, src, -1, *dest, len);
1672 return S_OK;
1675 /*************************************************************************
1676 * SHAnsiToAnsi [SHCORE.@]
1678 DWORD WINAPI SHAnsiToAnsi(const char *src, char *dest, int dest_len)
1680 DWORD ret;
1682 TRACE("(%s, %p, %d)\n", debugstr_a(src), dest, dest_len);
1684 if (!src || !dest || dest_len <= 0)
1685 return 0;
1687 lstrcpynA(dest, src, dest_len);
1688 ret = strlen(dest);
1690 return src[ret] ? 0 : ret + 1;
1693 /*************************************************************************
1694 * SHUnicodeToAnsi [SHCORE.@]
1696 DWORD WINAPI SHUnicodeToAnsi(const WCHAR *src, char *dest, int dest_len)
1698 int ret = 1;
1700 TRACE("(%s, %p, %d)\n", debugstr_w(src), dest, dest_len);
1702 if (!dest || !dest_len)
1703 return 0;
1705 if (src)
1707 ret = WideCharToMultiByte(CP_ACP, 0, src, -1, dest, dest_len, NULL, NULL);
1708 if (!ret)
1710 dest[dest_len - 1] = 0;
1711 ret = dest_len;
1714 else
1715 dest[0] = 0;
1717 return ret;
1720 /*************************************************************************
1721 * SHUnicodeToUnicode [SHCORE.@]
1723 DWORD WINAPI SHUnicodeToUnicode(const WCHAR *src, WCHAR *dest, int dest_len)
1725 DWORD ret;
1727 TRACE("(%s, %p, %d)\n", debugstr_w(src), dest, dest_len);
1729 if (!src || !dest || dest_len <= 0)
1730 return 0;
1732 lstrcpynW(dest, src, dest_len);
1733 ret = strlenW(dest);
1735 return src[ret] ? 0 : ret + 1;
1738 /*************************************************************************
1739 * SHAnsiToUnicode [SHCORE.@]
1741 DWORD WINAPI SHAnsiToUnicode(const char *src, WCHAR *dest, int dest_len)
1743 int ret = 1;
1745 TRACE("(%s, %p, %d)\n", debugstr_a(src), dest, dest_len);
1747 if (!dest || !dest_len)
1748 return 0;
1750 if (src)
1752 ret = MultiByteToWideChar(CP_ACP, 0, src, -1, dest, dest_len);
1753 if (!ret)
1755 dest[dest_len - 1] = 0;
1756 ret = dest_len;
1759 else
1760 dest[0] = 0;
1762 return ret;
1765 /*************************************************************************
1766 * SHRegDuplicateHKey [SHCORE.@]
1768 HKEY WINAPI SHRegDuplicateHKey(HKEY hKey)
1770 HKEY newKey = 0;
1772 RegOpenKeyExW(hKey, 0, 0, MAXIMUM_ALLOWED, &newKey);
1773 TRACE("new key is %p\n", newKey);
1774 return newKey;
1777 /*************************************************************************
1778 * SHDeleteEmptyKeyW [SHCORE.@]
1780 DWORD WINAPI SHDeleteEmptyKeyW(HKEY hkey, const WCHAR *subkey)
1782 DWORD ret, count = 0;
1783 HKEY hsubkey = 0;
1785 TRACE("(%p, %s)\n", hkey, debugstr_w(subkey));
1787 ret = RegOpenKeyExW(hkey, subkey, 0, KEY_READ, &hsubkey);
1788 if (!ret)
1790 ret = RegQueryInfoKeyW(hsubkey, NULL, NULL, NULL, &count,
1791 NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1792 RegCloseKey(hsubkey);
1793 if (!ret)
1795 if (count)
1796 ret = ERROR_KEY_HAS_CHILDREN;
1797 else
1798 ret = RegDeleteKeyW(hkey, subkey);
1802 return ret;
1805 /*************************************************************************
1806 * SHDeleteEmptyKeyA [SHCORE.@]
1808 DWORD WINAPI SHDeleteEmptyKeyA(HKEY hkey, const char *subkey)
1810 WCHAR *subkeyW = NULL;
1811 DWORD ret;
1813 TRACE("(%p, %s)\n", hkey, debugstr_a(subkey));
1815 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1816 return ERROR_OUTOFMEMORY;
1818 ret = SHDeleteEmptyKeyW(hkey, subkeyW);
1819 CoTaskMemFree(subkeyW);
1820 return ret;
1823 /*************************************************************************
1824 * SHDeleteKeyW [SHCORE.@]
1826 DWORD WINAPI SHDeleteKeyW(HKEY hkey, const WCHAR *subkey)
1828 TRACE("(%p, %s)\n", hkey, debugstr_w(subkey));
1830 return RegDeleteTreeW(hkey, subkey);
1833 /*************************************************************************
1834 * SHDeleteKeyA [SHCORE.@]
1836 DWORD WINAPI SHDeleteKeyA(HKEY hkey, const char *subkey)
1838 TRACE("(%p, %s)\n", hkey, debugstr_a(subkey));
1840 return RegDeleteTreeA(hkey, subkey);
1843 /*************************************************************************
1844 * SHDeleteValueW [SHCORE.@]
1846 DWORD WINAPI SHDeleteValueW(HKEY hkey, const WCHAR *subkey, const WCHAR *value)
1848 HKEY hsubkey;
1849 DWORD ret;
1851 TRACE("(%p, %s, %s)\n", hkey, debugstr_w(subkey), debugstr_w(value));
1853 ret = RegOpenKeyExW(hkey, subkey, 0, KEY_SET_VALUE, &hsubkey);
1854 if (!ret)
1856 ret = RegDeleteValueW(hsubkey, value);
1857 RegCloseKey(hsubkey);
1860 return ret;
1863 /*************************************************************************
1864 * SHDeleteValueA [SHCORE.@]
1866 DWORD WINAPI SHDeleteValueA(HKEY hkey, const char *subkey, const char *value)
1868 WCHAR *subkeyW = NULL, *valueW = NULL;
1869 DWORD ret;
1871 TRACE("(%p, %s, %s)\n", hkey, debugstr_a(subkey), debugstr_a(value));
1873 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1874 return ERROR_OUTOFMEMORY;
1875 if (value && FAILED(SHStrDupA(value, &valueW)))
1877 CoTaskMemFree(subkeyW);
1878 return ERROR_OUTOFMEMORY;
1881 ret = SHDeleteValueW(hkey, subkeyW, valueW);
1882 CoTaskMemFree(subkeyW);
1883 CoTaskMemFree(valueW);
1884 return ret;
1887 /*************************************************************************
1888 * SHCopyKeyA [SHCORE.@]
1890 DWORD WINAPI SHCopyKeyA(HKEY hkey_src, const char *subkey, HKEY hkey_dst, DWORD reserved)
1892 WCHAR *subkeyW = NULL;
1893 DWORD ret;
1895 TRACE("(%p, %s, %p, %d)\n", hkey_src, debugstr_a(subkey), hkey_dst, reserved);
1897 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1898 return 0;
1900 ret = SHCopyKeyW(hkey_src, subkeyW, hkey_dst, reserved);
1901 CoTaskMemFree(subkeyW);
1902 return ret;
1905 /*************************************************************************
1906 * SHCopyKeyW [SHCORE.@]
1908 DWORD WINAPI SHCopyKeyW(HKEY hkey_src, const WCHAR *subkey, HKEY hkey_dst, DWORD reserved)
1910 DWORD key_count = 0, value_count = 0, max_key_len = 0;
1911 WCHAR name[MAX_PATH], *ptr_name = name;
1912 BYTE buff[1024], *ptr = buff;
1913 DWORD max_data_len = 0, i;
1914 DWORD ret = 0;
1916 TRACE("(%p, %s, %p, %d)\n", hkey_src, debugstr_w(subkey), hkey_dst, reserved);
1918 if (!hkey_dst || !hkey_src)
1919 return ERROR_INVALID_PARAMETER;
1921 if (subkey)
1922 ret = RegOpenKeyExW(hkey_src, subkey, 0, KEY_ALL_ACCESS, &hkey_src);
1924 if (ret)
1925 hkey_src = NULL; /* Don't close this key since we didn't open it */
1926 else
1928 DWORD max_value_len;
1930 ret = RegQueryInfoKeyW(hkey_src, NULL, NULL, NULL, &key_count, &max_key_len,
1931 NULL, &value_count, &max_value_len, &max_data_len, NULL, NULL);
1932 if (!ret)
1934 /* Get max size for key/value names */
1935 max_key_len = max(max_key_len, max_value_len);
1937 if (max_key_len++ > MAX_PATH - 1)
1938 ptr_name = heap_alloc(max_key_len * sizeof(WCHAR));
1940 if (max_data_len > sizeof(buff))
1941 ptr = heap_alloc(max_data_len);
1943 if (!ptr_name || !ptr)
1944 ret = ERROR_NOT_ENOUGH_MEMORY;
1948 for (i = 0; i < key_count && !ret; i++)
1950 HKEY hsubkey_src, hsubkey_dst;
1951 DWORD length = max_key_len;
1953 ret = RegEnumKeyExW(hkey_src, i, ptr_name, &length, NULL, NULL, NULL, NULL);
1954 if (!ret)
1956 ret = RegOpenKeyExW(hkey_src, ptr_name, 0, KEY_READ, &hsubkey_src);
1957 if (!ret)
1959 /* Create destination sub key */
1960 ret = RegCreateKeyW(hkey_dst, ptr_name, &hsubkey_dst);
1961 if (!ret)
1963 /* Recursively copy keys and values from the sub key */
1964 ret = SHCopyKeyW(hsubkey_src, NULL, hsubkey_dst, 0);
1965 RegCloseKey(hsubkey_dst);
1968 RegCloseKey(hsubkey_src);
1972 /* Copy all the values in this key */
1973 for (i = 0; i < value_count && !ret; i++)
1975 DWORD length = max_key_len, type, data_len = max_data_len;
1977 ret = RegEnumValueW(hkey_src, i, ptr_name, &length, NULL, &type, ptr, &data_len);
1978 if (!ret) {
1979 ret = SHSetValueW(hkey_dst, NULL, ptr_name, type, ptr, data_len);
1983 /* Free buffers if allocated */
1984 if (ptr_name != name)
1985 heap_free(ptr_name);
1986 if (ptr != buff)
1987 heap_free(ptr);
1989 if (subkey && hkey_src)
1990 RegCloseKey(hkey_src);
1992 return ret;
1996 /*************************************************************************
1997 * SHEnumKeyExA [SHCORE.@]
1999 LONG WINAPI SHEnumKeyExA(HKEY hkey, DWORD index, char *subkey, DWORD *length)
2001 TRACE("(%p, %d, %s, %p)\n", hkey, index, debugstr_a(subkey), length);
2003 return RegEnumKeyExA(hkey, index, subkey, length, NULL, NULL, NULL, NULL);
2006 /*************************************************************************
2007 * SHEnumKeyExW [SHCORE.@]
2009 LONG WINAPI SHEnumKeyExW(HKEY hkey, DWORD index, WCHAR *subkey, DWORD *length)
2011 TRACE("(%p, %d, %s, %p)\n", hkey, index, debugstr_w(subkey), length);
2013 return RegEnumKeyExW(hkey, index, subkey, length, NULL, NULL, NULL, NULL);
2016 /*************************************************************************
2017 * SHEnumValueA [SHCORE.@]
2019 LONG WINAPI SHEnumValueA(HKEY hkey, DWORD index, char *value, DWORD *length, DWORD *type,
2020 void *data, DWORD *data_len)
2022 TRACE("(%p, %d, %s, %p, %p, %p, %p)\n", hkey, index, debugstr_a(value), length, type, data, data_len);
2024 return RegEnumValueA(hkey, index, value, length, NULL, type, data, data_len);
2027 /*************************************************************************
2028 * SHEnumValueW [SHCORE.@]
2030 LONG WINAPI SHEnumValueW(HKEY hkey, DWORD index, WCHAR *value, DWORD *length, DWORD *type,
2031 void *data, DWORD *data_len)
2033 TRACE("(%p, %d, %s, %p, %p, %p, %p)\n", hkey, index, debugstr_w(value), length, type, data, data_len);
2035 return RegEnumValueW(hkey, index, value, length, NULL, type, data, data_len);
2038 /*************************************************************************
2039 * SHQueryValueExW [SHCORE.@]
2041 DWORD WINAPI SHQueryValueExW(HKEY hkey, const WCHAR *name, DWORD *reserved, DWORD *type,
2042 void *buff, DWORD *buff_len)
2044 DWORD ret, value_type, data_len = 0;
2046 TRACE("(%p, %s, %p, %p, %p, %p)\n", hkey, debugstr_w(name), reserved, type, buff, buff_len);
2048 if (buff_len)
2049 data_len = *buff_len;
2051 ret = RegQueryValueExW(hkey, name, reserved, &value_type, buff, &data_len);
2052 if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)
2053 return ret;
2055 if (buff_len && value_type == REG_EXPAND_SZ)
2057 DWORD length;
2058 WCHAR *value;
2060 if (!buff || ret == ERROR_MORE_DATA)
2062 length = data_len;
2063 value = heap_alloc(length);
2064 RegQueryValueExW(hkey, name, reserved, NULL, (BYTE *)value, &length);
2065 length = ExpandEnvironmentStringsW(value, NULL, 0);
2067 else
2069 length = (strlenW(buff) + 1) * sizeof(WCHAR);
2070 value = heap_alloc(length);
2071 memcpy(value, buff, length);
2072 length = ExpandEnvironmentStringsW(value, buff, *buff_len / sizeof(WCHAR));
2073 if (length > *buff_len) ret = ERROR_MORE_DATA;
2075 data_len = max(data_len, length);
2076 heap_free(value);
2079 if (type)
2080 *type = value_type == REG_EXPAND_SZ ? REG_SZ : value_type;
2081 if (buff_len)
2082 *buff_len = data_len;
2083 return ret;
2086 /*************************************************************************
2087 * SHQueryValueExA [SHCORE.@]
2089 DWORD WINAPI SHQueryValueExA(HKEY hkey, const char *name, DWORD *reserved, DWORD *type,
2090 void *buff, DWORD *buff_len)
2092 DWORD ret, value_type, data_len = 0;
2094 TRACE("(%p, %s, %p, %p, %p, %p)\n", hkey, debugstr_a(name), reserved, type, buff, buff_len);
2096 if (buff_len)
2097 data_len = *buff_len;
2099 ret = RegQueryValueExA(hkey, name, reserved, &value_type, buff, &data_len);
2100 if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)
2101 return ret;
2103 if (buff_len && value_type == REG_EXPAND_SZ)
2105 DWORD length;
2106 char *value;
2108 if (!buff || ret == ERROR_MORE_DATA)
2110 length = data_len;
2111 value = heap_alloc(length);
2112 RegQueryValueExA(hkey, name, reserved, NULL, (BYTE *)value, &length);
2113 length = ExpandEnvironmentStringsA(value, NULL, 0);
2115 else
2117 length = strlen(buff) + 1;
2118 value = heap_alloc(length);
2119 memcpy(value, buff, length);
2120 length = ExpandEnvironmentStringsA(value, buff, *buff_len);
2121 if (length > *buff_len) ret = ERROR_MORE_DATA;
2123 data_len = max(data_len, length);
2124 heap_free(value);
2127 if (type)
2128 *type = value_type == REG_EXPAND_SZ ? REG_SZ : value_type;
2129 if (buff_len)
2130 *buff_len = data_len;
2131 return ret;
2134 /*************************************************************************
2135 * SHGetValueA [SHCORE.@]
2137 DWORD WINAPI SHGetValueA(HKEY hkey, const char *subkey, const char *value,
2138 DWORD *type, void *data, DWORD *data_len)
2140 HKEY hsubkey = 0;
2141 DWORD ret = 0;
2143 TRACE("(%p, %s, %s, %p, %p, %p)\n", hkey, debugstr_a(subkey), debugstr_a(value),
2144 type, data, data_len);
2146 if (subkey)
2147 ret = RegOpenKeyExA(hkey, subkey, 0, KEY_QUERY_VALUE, &hsubkey);
2149 if (!ret)
2151 ret = SHQueryValueExA(hsubkey ? hsubkey : hkey, value, 0, type, data, data_len);
2152 if (subkey)
2153 RegCloseKey(hsubkey);
2156 return ret;
2159 /*************************************************************************
2160 * SHGetValueW [SHCORE.@]
2162 DWORD WINAPI SHGetValueW(HKEY hkey, const WCHAR *subkey, const WCHAR *value,
2163 DWORD *type, void *data, DWORD *data_len)
2165 HKEY hsubkey = 0;
2166 DWORD ret = 0;
2168 TRACE("(%p, %s, %s, %p, %p, %p)\n", hkey, debugstr_w(subkey), debugstr_w(value),
2169 type, data, data_len);
2171 if (subkey)
2172 ret = RegOpenKeyExW(hkey, subkey, 0, KEY_QUERY_VALUE, &hsubkey);
2174 if (!ret)
2176 ret = SHQueryValueExW(hsubkey ? hsubkey : hkey, value, 0, type, data, data_len);
2177 if (subkey)
2178 RegCloseKey(hsubkey);
2181 return ret;
2184 /*************************************************************************
2185 * SHRegGetIntW [SHCORE.280]
2187 int WINAPI SHRegGetIntW(HKEY hkey, const WCHAR *value, int default_value)
2189 WCHAR buff[32];
2190 DWORD buff_len;
2192 TRACE("(%p, %s, %d)\n", hkey, debugstr_w(value), default_value);
2194 buff[0] = 0;
2195 buff_len = sizeof(buff);
2196 if (SHQueryValueExW(hkey, value, 0, 0, buff, &buff_len))
2197 return default_value;
2199 if (*buff >= '0' && *buff <= '9')
2200 return atoiW(buff);
2202 return default_value;
2205 /*************************************************************************
2206 * SHRegGetPathA [SHCORE.@]
2208 DWORD WINAPI SHRegGetPathA(HKEY hkey, const char *subkey, const char *value, char *path, DWORD flags)
2210 DWORD length = MAX_PATH;
2212 TRACE("(%p, %s, %s, %p, %#x)\n", hkey, debugstr_a(subkey), debugstr_a(value), path, flags);
2214 return SHGetValueA(hkey, subkey, value, 0, path, &length);
2217 /*************************************************************************
2218 * SHRegGetPathW [SHCORE.@]
2220 DWORD WINAPI SHRegGetPathW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, WCHAR *path, DWORD flags)
2222 DWORD length = MAX_PATH;
2224 TRACE("(%p, %s, %s, %p, %d)\n", hkey, debugstr_w(subkey), debugstr_w(value), path, flags);
2226 return SHGetValueW(hkey, subkey, value, 0, path, &length);
2229 /*************************************************************************
2230 * SHSetValueW [SHCORE.@]
2232 DWORD WINAPI SHSetValueW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, DWORD type,
2233 const void *data, DWORD data_len)
2235 DWORD ret = ERROR_SUCCESS, dummy;
2236 HKEY hsubkey;
2238 TRACE("(%p, %s, %s, %d, %p, %d)\n", hkey, debugstr_w(subkey), debugstr_w(value),
2239 type, data, data_len);
2241 if (subkey && *subkey)
2242 ret = RegCreateKeyExW(hkey, subkey, 0, NULL, 0, KEY_SET_VALUE, NULL, &hsubkey, &dummy);
2243 else
2244 hsubkey = hkey;
2246 if (!ret)
2248 ret = RegSetValueExW(hsubkey, value, 0, type, data, data_len);
2249 if (hsubkey != hkey)
2250 RegCloseKey(hsubkey);
2253 return ret;
2256 /*************************************************************************
2257 * SHSetValueA [SHCORE.@]
2259 DWORD WINAPI SHSetValueA(HKEY hkey, const char *subkey, const char *value,
2260 DWORD type, const void *data, DWORD data_len)
2262 DWORD ret = ERROR_SUCCESS, dummy;
2263 HKEY hsubkey;
2265 TRACE("(%p, %s, %s, %d, %p, %d)\n", hkey, debugstr_a(subkey), debugstr_a(value),
2266 type, data, data_len);
2268 if (subkey && *subkey)
2269 ret = RegCreateKeyExA(hkey, subkey, 0, NULL, 0, KEY_SET_VALUE, NULL, &hsubkey, &dummy);
2270 else
2271 hsubkey = hkey;
2273 if (!ret)
2275 ret = RegSetValueExA(hsubkey, value, 0, type, data, data_len);
2276 if (hsubkey != hkey)
2277 RegCloseKey(hsubkey);
2280 return ret;
2283 /*************************************************************************
2284 * SHRegSetPathA [SHCORE.@]
2286 DWORD WINAPI SHRegSetPathA(HKEY hkey, const char *subkey, const char *value, const char *path, DWORD flags)
2288 FIXME("(%p, %s, %s, %s, %#x) - semi-stub\n", hkey, debugstr_a(subkey),
2289 debugstr_a(value), debugstr_a(path), flags);
2291 /* FIXME: PathUnExpandEnvStringsA() */
2293 return SHSetValueA(hkey, subkey, value, REG_SZ, path, lstrlenA(path));
2296 /*************************************************************************
2297 * SHRegSetPathW [SHCORE.@]
2299 DWORD WINAPI SHRegSetPathW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, const WCHAR *path, DWORD flags)
2301 FIXME("(%p, %s, %s, %s, %#x) - semi-stub\n", hkey, debugstr_w(subkey),
2302 debugstr_w(value), debugstr_w(path), flags);
2304 /* FIXME: PathUnExpandEnvStringsW(); */
2306 return SHSetValueW(hkey, subkey, value, REG_SZ, path, lstrlenW(path));
2309 /*************************************************************************
2310 * SHQueryInfoKeyA [SHCORE.@]
2312 LONG WINAPI SHQueryInfoKeyA(HKEY hkey, DWORD *subkeys, DWORD *subkey_max, DWORD *values, DWORD *value_max)
2314 TRACE("(%p, %p, %p, %p, %p)\n", hkey, subkeys, subkey_max, values, value_max);
2316 return RegQueryInfoKeyA(hkey, NULL, NULL, NULL, subkeys, subkey_max, NULL, values, value_max, NULL, NULL, NULL);
2319 /*************************************************************************
2320 * SHQueryInfoKeyW [SHCORE.@]
2322 LONG WINAPI SHQueryInfoKeyW(HKEY hkey, DWORD *subkeys, DWORD *subkey_max, DWORD *values, DWORD *value_max)
2324 TRACE("(%p, %p, %p, %p, %p)\n", hkey, subkeys, subkey_max, values, value_max);
2326 return RegQueryInfoKeyW(hkey, NULL, NULL, NULL, subkeys, subkey_max, NULL, values, value_max, NULL, NULL, NULL);
2329 /*************************************************************************
2330 * IsOS [SHCORE.@]
2332 BOOL WINAPI IsOS(DWORD feature)
2334 DWORD platform, majorv, minorv;
2335 OSVERSIONINFOA osvi;
2337 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
2338 if (!GetVersionExA(&osvi))
2339 return FALSE;
2341 majorv = osvi.dwMajorVersion;
2342 minorv = osvi.dwMinorVersion;
2343 platform = osvi.dwPlatformId;
2345 #define ISOS_RETURN(x) \
2346 TRACE("(0x%x) ret=%d\n",feature,(x)); \
2347 return (x)
2349 switch(feature) {
2350 case OS_WIN32SORGREATER:
2351 ISOS_RETURN(platform == VER_PLATFORM_WIN32s
2352 || platform == VER_PLATFORM_WIN32_WINDOWS);
2353 case OS_NT:
2354 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2355 case OS_WIN95ORGREATER:
2356 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS);
2357 case OS_NT4ORGREATER:
2358 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 4);
2359 case OS_WIN2000ORGREATER_ALT:
2360 case OS_WIN2000ORGREATER:
2361 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5);
2362 case OS_WIN98ORGREATER:
2363 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 10);
2364 case OS_WIN98_GOLD:
2365 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 10);
2366 case OS_WIN2000PRO:
2367 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5);
2368 case OS_WIN2000SERVER:
2369 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2370 case OS_WIN2000ADVSERVER:
2371 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2372 case OS_WIN2000DATACENTER:
2373 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2374 case OS_WIN2000TERMINAL:
2375 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2376 case OS_EMBEDDED:
2377 FIXME("(OS_EMBEDDED) What should we return here?\n");
2378 return FALSE;
2379 case OS_TERMINALCLIENT:
2380 FIXME("(OS_TERMINALCLIENT) What should we return here?\n");
2381 return FALSE;
2382 case OS_TERMINALREMOTEADMIN:
2383 FIXME("(OS_TERMINALREMOTEADMIN) What should we return here?\n");
2384 return FALSE;
2385 case OS_WIN95_GOLD:
2386 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 0);
2387 case OS_MEORGREATER:
2388 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 90);
2389 case OS_XPORGREATER:
2390 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1);
2391 case OS_HOME:
2392 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1);
2393 case OS_PROFESSIONAL:
2394 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2395 case OS_DATACENTER:
2396 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2397 case OS_ADVSERVER:
2398 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5);
2399 case OS_SERVER:
2400 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2401 case OS_TERMINALSERVER:
2402 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2403 case OS_PERSONALTERMINALSERVER:
2404 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && minorv >= 1 && majorv >= 5);
2405 case OS_FASTUSERSWITCHING:
2406 FIXME("(OS_FASTUSERSWITCHING) What should we return here?\n");
2407 return TRUE;
2408 case OS_WELCOMELOGONUI:
2409 FIXME("(OS_WELCOMELOGONUI) What should we return here?\n");
2410 return FALSE;
2411 case OS_DOMAINMEMBER:
2412 FIXME("(OS_DOMAINMEMBER) What should we return here?\n");
2413 return TRUE;
2414 case OS_ANYSERVER:
2415 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2416 case OS_WOW6432:
2418 BOOL is_wow64;
2419 IsWow64Process(GetCurrentProcess(), &is_wow64);
2420 return is_wow64;
2422 case OS_WEBSERVER:
2423 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2424 case OS_SMALLBUSINESSSERVER:
2425 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2426 case OS_TABLETPC:
2427 FIXME("(OS_TABLETPC) What should we return here?\n");
2428 return FALSE;
2429 case OS_SERVERADMINUI:
2430 FIXME("(OS_SERVERADMINUI) What should we return here?\n");
2431 return FALSE;
2432 case OS_MEDIACENTER:
2433 FIXME("(OS_MEDIACENTER) What should we return here?\n");
2434 return FALSE;
2435 case OS_APPLIANCE:
2436 FIXME("(OS_APPLIANCE) What should we return here?\n");
2437 return FALSE;
2438 case 0x25: /*OS_VISTAORGREATER*/
2439 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 6);
2442 #undef ISOS_RETURN
2444 WARN("(0x%x) unknown parameter\n", feature);
2446 return FALSE;