comctl32/listbox: Use a helper to set the selected item state.
[wine.git] / dlls / shcore / main.c
blobfdf878ed2a43e7fb19f19520ff490e04b4272610
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);
916 LARGE_INTEGER origin, move;
918 TRACE("(%p, %s)\n", stream, wine_dbgstr_longlong(size.QuadPart));
920 move.QuadPart = 0;
921 if (!SetFilePointerEx(stream->u.file.handle, move, &origin, FILE_CURRENT))
922 return E_FAIL;
924 move.QuadPart = size.QuadPart;
925 if (!SetFilePointerEx(stream->u.file.handle, move, NULL, FILE_BEGIN))
926 return E_FAIL;
928 if (stream->u.file.mode != STGM_READ)
930 if (!SetEndOfFile(stream->u.file.handle))
931 return E_FAIL;
932 if (!SetFilePointerEx(stream->u.file.handle, origin, NULL, FILE_BEGIN))
933 return E_FAIL;
936 return S_OK;
939 static HRESULT WINAPI filestream_CopyTo(IStream *iface, IStream *dest, ULARGE_INTEGER size,
940 ULARGE_INTEGER *read_len, ULARGE_INTEGER *written)
942 struct shstream *stream = impl_from_IStream(iface);
943 HRESULT hr = S_OK;
944 char buff[1024];
946 TRACE("(%p, %p, %s, %p, %p)\n", stream, dest, wine_dbgstr_longlong(size.QuadPart), read_len, written);
948 if (read_len)
949 read_len->QuadPart = 0;
950 if (written)
951 written->QuadPart = 0;
953 if (!dest)
954 return S_OK;
956 while (size.QuadPart)
958 ULONG left, read_chunk, written_chunk;
960 left = size.QuadPart > sizeof(buff) ? sizeof(buff) : size.QuadPart;
962 /* Read */
963 hr = IStream_Read(iface, buff, left, &read_chunk);
964 if (FAILED(hr) || read_chunk == 0)
965 break;
966 if (read_len)
967 read_len->QuadPart += read_chunk;
969 /* Write */
970 hr = IStream_Write(dest, buff, read_chunk, &written_chunk);
971 if (written_chunk)
972 written->QuadPart += written_chunk;
973 if (FAILED(hr) || written_chunk != left)
974 break;
976 size.QuadPart -= left;
979 return hr;
982 static HRESULT WINAPI filestream_Commit(IStream *iface, DWORD flags)
984 struct shstream *stream = impl_from_IStream(iface);
986 TRACE("(%p, %#x)\n", stream, flags);
988 return S_OK;
991 static HRESULT WINAPI filestream_Stat(IStream *iface, STATSTG *statstg, DWORD flags)
993 struct shstream *stream = impl_from_IStream(iface);
994 BY_HANDLE_FILE_INFORMATION fi;
996 TRACE("(%p, %p, %#x)\n", stream, statstg, flags);
998 if (!statstg)
999 return STG_E_INVALIDPOINTER;
1001 memset(&fi, 0, sizeof(fi));
1002 GetFileInformationByHandle(stream->u.file.handle, &fi);
1004 if (flags & STATFLAG_NONAME)
1005 statstg->pwcsName = NULL;
1006 else
1008 int len = strlenW(stream->u.file.path);
1009 if ((statstg->pwcsName = CoTaskMemAlloc((len + 1) * sizeof(WCHAR))))
1010 memcpy(statstg->pwcsName, stream->u.file.path, (len + 1) * sizeof(WCHAR));
1012 statstg->type = 0;
1013 statstg->cbSize.u.LowPart = fi.nFileSizeLow;
1014 statstg->cbSize.u.HighPart = fi.nFileSizeHigh;
1015 statstg->mtime = fi.ftLastWriteTime;
1016 statstg->ctime = fi.ftCreationTime;
1017 statstg->atime = fi.ftLastAccessTime;
1018 statstg->grfMode = stream->u.file.mode;
1019 statstg->grfLocksSupported = 0;
1020 memcpy(&statstg->clsid, &IID_IStream, sizeof(CLSID));
1021 statstg->grfStateBits = 0;
1022 statstg->reserved = 0;
1024 return S_OK;
1027 static const IStreamVtbl filestreamvtbl =
1029 shstream_QueryInterface,
1030 shstream_AddRef,
1031 filestream_Release,
1032 filestream_Read,
1033 filestream_Write,
1034 filestream_Seek,
1035 filestream_SetSize,
1036 filestream_CopyTo,
1037 filestream_Commit,
1038 shstream_Revert,
1039 shstream_LockRegion,
1040 shstream_UnlockRegion,
1041 filestream_Stat,
1042 shstream_Clone,
1045 /*************************************************************************
1046 * SHCreateStreamOnFileEx [SHCORE.@]
1048 HRESULT WINAPI SHCreateStreamOnFileEx(const WCHAR *path, DWORD mode, DWORD attributes,
1049 BOOL create, IStream *template, IStream **ret)
1051 DWORD access, share, creation_disposition, len;
1052 struct shstream *stream;
1053 HANDLE hFile;
1055 TRACE("(%s, %d, 0x%08X, %d, %p, %p)\n", debugstr_w(path), mode, attributes,
1056 create, template, ret);
1058 if (!path || !ret || template)
1059 return E_INVALIDARG;
1061 *ret = NULL;
1063 /* Access */
1064 switch (mode & 0xf)
1066 case STGM_WRITE:
1067 case STGM_READWRITE:
1068 access = GENERIC_READ | GENERIC_WRITE;
1069 break;
1070 case STGM_READ:
1071 access = GENERIC_READ;
1072 break;
1073 default:
1074 return E_INVALIDARG;
1077 /* Sharing */
1078 switch (mode & 0xf0)
1080 case 0:
1081 case STGM_SHARE_DENY_NONE:
1082 share = FILE_SHARE_READ | FILE_SHARE_WRITE;
1083 break;
1084 case STGM_SHARE_DENY_READ:
1085 share = FILE_SHARE_WRITE;
1086 break;
1087 case STGM_SHARE_DENY_WRITE:
1088 share = FILE_SHARE_READ;
1089 break;
1090 case STGM_SHARE_EXCLUSIVE:
1091 share = 0;
1092 break;
1093 default:
1094 return E_INVALIDARG;
1097 switch (mode & 0xf000)
1099 case STGM_FAILIFTHERE:
1100 creation_disposition = create ? CREATE_NEW : OPEN_EXISTING;
1101 break;
1102 case STGM_CREATE:
1103 creation_disposition = CREATE_ALWAYS;
1104 break;
1105 default:
1106 return E_INVALIDARG;
1109 hFile = CreateFileW(path, access, share, NULL, creation_disposition, attributes, 0);
1110 if (hFile == INVALID_HANDLE_VALUE)
1111 return HRESULT_FROM_WIN32(GetLastError());
1113 stream = heap_alloc(sizeof(*stream));
1114 stream->IStream_iface.lpVtbl = &filestreamvtbl;
1115 stream->refcount = 1;
1116 stream->u.file.handle = hFile;
1117 stream->u.file.mode = mode;
1119 len = strlenW(path);
1120 stream->u.file.path = heap_alloc((len + 1) * sizeof(WCHAR));
1121 memcpy(stream->u.file.path, path, (len + 1) * sizeof(WCHAR));
1123 *ret = &stream->IStream_iface;
1125 return S_OK;
1128 /*************************************************************************
1129 * SHCreateStreamOnFileW [SHCORE.@]
1131 HRESULT WINAPI SHCreateStreamOnFileW(const WCHAR *path, DWORD mode, IStream **stream)
1133 TRACE("(%s, %#x, %p)\n", debugstr_w(path), mode, stream);
1135 if (!path || !stream)
1136 return E_INVALIDARG;
1138 if ((mode & (STGM_CONVERT | STGM_DELETEONRELEASE | STGM_TRANSACTED)) != 0)
1139 return E_INVALIDARG;
1141 return SHCreateStreamOnFileEx(path, mode, 0, FALSE, NULL, stream);
1144 /*************************************************************************
1145 * SHCreateStreamOnFileA [SHCORE.@]
1147 HRESULT WINAPI SHCreateStreamOnFileA(const char *path, DWORD mode, IStream **stream)
1149 WCHAR *pathW;
1150 HRESULT hr;
1151 DWORD len;
1153 TRACE("(%s, %#x, %p)\n", debugstr_a(path), mode, stream);
1155 if (!path)
1156 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1158 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1159 pathW = heap_alloc(len * sizeof(WCHAR));
1160 if (!pathW)
1161 return E_OUTOFMEMORY;
1163 MultiByteToWideChar(CP_ACP, 0, path, -1, pathW, len);
1164 hr = SHCreateStreamOnFileW(pathW, mode, stream);
1165 heap_free(pathW);
1167 return hr;
1170 static ULONG WINAPI regstream_Release(IStream *iface)
1172 struct shstream *stream = impl_from_IStream(iface);
1173 ULONG refcount = InterlockedDecrement(&stream->refcount);
1175 TRACE("(%p)->(%u)\n", stream, refcount);
1177 if (!refcount)
1179 if (stream->u.mem.hkey)
1181 if (stream->u.mem.length)
1182 RegSetValueExW(stream->u.mem.hkey, stream->u.mem.valuename, 0, REG_BINARY,
1183 (const BYTE *)stream->u.mem.buffer, stream->u.mem.length);
1184 else
1185 RegDeleteValueW(stream->u.mem.hkey, stream->u.mem.valuename);
1186 RegCloseKey(stream->u.mem.hkey);
1188 CoTaskMemFree(stream->u.mem.valuename);
1189 heap_free(stream->u.mem.buffer);
1190 heap_free(stream);
1193 return refcount;
1196 static const IStreamVtbl regstreamvtbl =
1198 shstream_QueryInterface,
1199 shstream_AddRef,
1200 regstream_Release,
1201 memstream_Read,
1202 memstream_Write,
1203 memstream_Seek,
1204 memstream_SetSize,
1205 shstream_CopyTo,
1206 shstream_Commit,
1207 shstream_Revert,
1208 shstream_LockRegion,
1209 shstream_UnlockRegion,
1210 memstream_Stat,
1211 shstream_Clone,
1214 /*************************************************************************
1215 * SHOpenRegStream2W [SHCORE.@]
1217 IStream * WINAPI SHOpenRegStream2W(HKEY hKey, const WCHAR *subkey, const WCHAR *value, DWORD mode)
1219 struct shstream *stream;
1220 HKEY hStrKey = NULL;
1221 BYTE *buff = NULL;
1222 DWORD length = 0;
1223 LONG ret;
1225 TRACE("(%p, %s, %s, %#x)\n", hKey, debugstr_w(subkey), debugstr_w(value), mode);
1227 if (mode == STGM_READ)
1228 ret = RegOpenKeyExW(hKey, subkey, 0, KEY_READ, &hStrKey);
1229 else /* in write mode we make sure the subkey exits */
1230 ret = RegCreateKeyExW(hKey, subkey, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &hStrKey, NULL);
1232 if (ret == ERROR_SUCCESS)
1234 if (mode == STGM_READ || mode == STGM_READWRITE)
1236 /* read initial data */
1237 ret = RegQueryValueExW(hStrKey, value, 0, 0, 0, &length);
1238 if (ret == ERROR_SUCCESS && length)
1240 buff = heap_alloc(length);
1241 RegQueryValueExW(hStrKey, value, 0, 0, buff, &length);
1245 if (!length)
1246 buff = heap_alloc(length);
1248 stream = shstream_create(&regstreamvtbl, buff, length);
1249 heap_free(buff);
1250 if (stream)
1252 stream->u.mem.hkey = hStrKey;
1253 SHStrDupW(value, &stream->u.mem.valuename);
1254 return &stream->IStream_iface;
1258 if (hStrKey)
1259 RegCloseKey(hStrKey);
1261 return NULL;
1264 /*************************************************************************
1265 * SHOpenRegStream2A [SHCORE.@]
1267 IStream * WINAPI SHOpenRegStream2A(HKEY hKey, const char *subkey, const char *value, DWORD mode)
1269 WCHAR *subkeyW = NULL, *valueW = NULL;
1270 IStream *stream;
1272 TRACE("(%p, %s, %s, %#x)\n", hKey, debugstr_a(subkey), debugstr_a(value), mode);
1274 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1275 return NULL;
1276 if (value && FAILED(SHStrDupA(value, &valueW)))
1278 CoTaskMemFree(subkeyW);
1279 return NULL;
1282 stream = SHOpenRegStream2W(hKey, subkeyW, valueW, mode);
1283 CoTaskMemFree(subkeyW);
1284 CoTaskMemFree(valueW);
1285 return stream;
1288 /*************************************************************************
1289 * SHOpenRegStreamA [SHCORE.@]
1291 IStream * WINAPI SHOpenRegStreamA(HKEY hkey, const char *subkey, const char *value, DWORD mode)
1293 WCHAR *subkeyW = NULL, *valueW = NULL;
1294 IStream *stream;
1296 TRACE("(%p, %s, %s, %#x)\n", hkey, debugstr_a(subkey), debugstr_a(value), mode);
1298 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1299 return NULL;
1300 if (value && FAILED(SHStrDupA(value, &valueW)))
1302 CoTaskMemFree(subkeyW);
1303 return NULL;
1306 stream = SHOpenRegStreamW(hkey, subkeyW, valueW, mode);
1307 CoTaskMemFree(subkeyW);
1308 CoTaskMemFree(valueW);
1309 return stream;
1312 static ULONG WINAPI dummystream_AddRef(IStream *iface)
1314 TRACE("()\n");
1315 return 2;
1318 static ULONG WINAPI dummystream_Release(IStream *iface)
1320 TRACE("()\n");
1321 return 1;
1324 static HRESULT WINAPI dummystream_Read(IStream *iface, void *buff, ULONG buff_size, ULONG *read_len)
1326 if (read_len)
1327 *read_len = 0;
1329 return E_NOTIMPL;
1332 static const IStreamVtbl dummystreamvtbl =
1334 shstream_QueryInterface,
1335 dummystream_AddRef,
1336 dummystream_Release,
1337 dummystream_Read,
1338 memstream_Write,
1339 memstream_Seek,
1340 memstream_SetSize,
1341 shstream_CopyTo,
1342 shstream_Commit,
1343 shstream_Revert,
1344 shstream_LockRegion,
1345 shstream_UnlockRegion,
1346 memstream_Stat,
1347 shstream_Clone,
1350 static struct shstream dummyregstream = { { &dummystreamvtbl } };
1352 /*************************************************************************
1353 * SHOpenRegStreamW [SHCORE.@]
1355 IStream * WINAPI SHOpenRegStreamW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, DWORD mode)
1357 IStream *stream;
1359 TRACE("(%p, %s, %s, %#x)\n", hkey, debugstr_w(subkey), debugstr_w(value), mode);
1360 stream = SHOpenRegStream2W(hkey, subkey, value, mode);
1361 return stream ? stream : &dummyregstream.IStream_iface;
1364 struct threadref
1366 IUnknown IUnknown_iface;
1367 LONG *refcount;
1370 static inline struct threadref *threadref_impl_from_IUnknown(IUnknown *iface)
1372 return CONTAINING_RECORD(iface, struct threadref, IUnknown_iface);
1375 static HRESULT WINAPI threadref_QueryInterface(IUnknown *iface, REFIID riid, void **out)
1377 struct threadref *threadref = threadref_impl_from_IUnknown(iface);
1379 TRACE("(%p, %s, %p)\n", threadref, debugstr_guid(riid), out);
1381 if (out == NULL)
1382 return E_POINTER;
1384 if (IsEqualGUID(&IID_IUnknown, riid))
1386 *out = iface;
1387 IUnknown_AddRef(iface);
1388 return S_OK;
1391 *out = NULL;
1392 WARN("Interface %s not supported.\n", debugstr_guid(riid));
1393 return E_NOINTERFACE;
1396 static ULONG WINAPI threadref_AddRef(IUnknown *iface)
1398 struct threadref *threadref = threadref_impl_from_IUnknown(iface);
1399 LONG refcount = InterlockedIncrement(threadref->refcount);
1401 TRACE("(%p, %d)\n", threadref, refcount);
1403 return refcount;
1406 static ULONG WINAPI threadref_Release(IUnknown *iface)
1408 struct threadref *threadref = threadref_impl_from_IUnknown(iface);
1409 LONG refcount = InterlockedDecrement(threadref->refcount);
1411 TRACE("(%p, %d)\n", threadref, refcount);
1413 if (!refcount)
1414 heap_free(threadref);
1416 return refcount;
1419 static const IUnknownVtbl threadrefvtbl =
1421 threadref_QueryInterface,
1422 threadref_AddRef,
1423 threadref_Release,
1426 /*************************************************************************
1427 * SHCreateThreadRef [SHCORE.@]
1429 HRESULT WINAPI SHCreateThreadRef(LONG *refcount, IUnknown **out)
1431 struct threadref *threadref;
1433 TRACE("(%p, %p)\n", refcount, out);
1435 if (!refcount || !out)
1436 return E_INVALIDARG;
1438 *out = NULL;
1440 threadref = heap_alloc(sizeof(*threadref));
1441 if (!threadref)
1442 return E_OUTOFMEMORY;
1443 threadref->IUnknown_iface.lpVtbl = &threadrefvtbl;
1444 threadref->refcount = refcount;
1446 *refcount = 1;
1447 *out = &threadref->IUnknown_iface;
1449 TRACE("Created %p.\n", threadref);
1450 return S_OK;
1453 /*************************************************************************
1454 * SHGetThreadRef [SHCORE.@]
1456 HRESULT WINAPI SHGetThreadRef(IUnknown **out)
1458 TRACE("(%p)\n", out);
1460 if (shcore_tls == TLS_OUT_OF_INDEXES)
1461 return E_NOINTERFACE;
1463 *out = TlsGetValue(shcore_tls);
1464 if (!*out)
1465 return E_NOINTERFACE;
1467 IUnknown_AddRef(*out);
1468 return S_OK;
1471 /*************************************************************************
1472 * SHSetThreadRef [SHCORE.@]
1474 HRESULT WINAPI SHSetThreadRef(IUnknown *obj)
1476 TRACE("(%p)\n", obj);
1478 if (shcore_tls == TLS_OUT_OF_INDEXES)
1479 return E_NOINTERFACE;
1481 TlsSetValue(shcore_tls, obj);
1482 return S_OK;
1485 /*************************************************************************
1486 * SHReleaseThreadRef [SHCORE.@]
1488 HRESULT WINAPI SHReleaseThreadRef(void)
1490 FIXME("() - stub!\n");
1491 return S_OK;
1494 /*************************************************************************
1495 * GetProcessReference [SHCORE.@]
1497 HRESULT WINAPI GetProcessReference(IUnknown **obj)
1499 TRACE("(%p)\n", obj);
1501 *obj = process_ref;
1503 if (!process_ref)
1504 return E_FAIL;
1506 if (*obj)
1507 IUnknown_AddRef(*obj);
1509 return S_OK;
1512 /*************************************************************************
1513 * SetProcessReference [SHCORE.@]
1515 void WINAPI SetProcessReference(IUnknown *obj)
1517 TRACE("(%p)\n", obj);
1519 process_ref = obj;
1522 struct thread_data
1524 LPTHREAD_START_ROUTINE thread_proc;
1525 LPTHREAD_START_ROUTINE callback;
1526 void *data;
1527 DWORD flags;
1528 HANDLE hEvent;
1529 IUnknown *thread_ref;
1530 IUnknown *process_ref;
1533 static DWORD WINAPI shcore_thread_wrapper(void *data)
1535 struct thread_data thread_data;
1536 HRESULT hr = E_FAIL;
1537 DWORD retval;
1539 TRACE("(%p)\n", data);
1541 /* We are now executing in the context of the newly created thread.
1542 * So we copy the data passed to us (it is on the stack of the function
1543 * that called us, which is waiting for us to signal an event before
1544 * returning). */
1545 thread_data = *(struct thread_data *)data;
1547 if (thread_data.flags & CTF_COINIT)
1549 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
1550 if (FAILED(hr))
1551 hr = CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE);
1554 if (thread_data.callback)
1555 thread_data.callback(thread_data.data);
1557 /* Signal the thread that created us; it can return now. */
1558 SetEvent(thread_data.hEvent);
1560 /* Execute the callers start code. */
1561 retval = thread_data.thread_proc(thread_data.data);
1563 /* Release thread and process references. */
1564 if (thread_data.thread_ref)
1565 IUnknown_Release(thread_data.thread_ref);
1567 if (thread_data.process_ref)
1568 IUnknown_Release(thread_data.process_ref);
1570 if (SUCCEEDED(hr))
1571 CoUninitialize();
1573 return retval;
1576 /*************************************************************************
1577 * SHCreateThread [SHCORE.@]
1579 BOOL WINAPI SHCreateThread(LPTHREAD_START_ROUTINE thread_proc, void *data, DWORD flags, LPTHREAD_START_ROUTINE callback)
1581 struct thread_data thread_data;
1582 BOOL called = FALSE;
1584 TRACE("(%p, %p, %#x, %p)\n", thread_proc, data, flags, callback);
1586 thread_data.thread_proc = thread_proc;
1587 thread_data.callback = callback;
1588 thread_data.data = data;
1589 thread_data.flags = flags;
1590 thread_data.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
1592 if (flags & CTF_THREAD_REF)
1593 SHGetThreadRef(&thread_data.thread_ref);
1594 else
1595 thread_data.thread_ref = NULL;
1597 if (flags & CTF_PROCESS_REF)
1598 GetProcessReference(&thread_data.process_ref);
1599 else
1600 thread_data.process_ref = NULL;
1602 /* Create the thread */
1603 if (thread_data.hEvent)
1605 HANDLE hThread;
1606 DWORD retval;
1608 hThread = CreateThread(NULL, 0, shcore_thread_wrapper, &thread_data, 0, &retval);
1609 if (hThread)
1611 /* Wait for the thread to signal us to continue */
1612 WaitForSingleObject(thread_data.hEvent, INFINITE);
1613 CloseHandle(hThread);
1614 called = TRUE;
1616 CloseHandle(thread_data.hEvent);
1619 if (!called)
1621 if (!thread_data.callback && flags & CTF_INSIST)
1623 /* Couldn't call, call synchronously */
1624 thread_data.thread_proc(data);
1625 called = TRUE;
1627 else
1629 if (thread_data.thread_ref)
1630 IUnknown_Release(thread_data.thread_ref);
1632 if (thread_data.process_ref)
1633 IUnknown_Release(thread_data.process_ref);
1637 return called;
1640 /*************************************************************************
1641 * SHStrDupW [SHCORE.@]
1643 HRESULT WINAPI SHStrDupW(const WCHAR *src, WCHAR **dest)
1645 size_t len;
1647 TRACE("(%s, %p)\n", debugstr_w(src), dest);
1649 *dest = NULL;
1651 if (!src)
1652 return E_INVALIDARG;
1654 len = (strlenW(src) + 1) * sizeof(WCHAR);
1655 *dest = CoTaskMemAlloc(len);
1656 if (!*dest)
1657 return E_OUTOFMEMORY;
1659 memcpy(*dest, src, len);
1661 return S_OK;
1664 /*************************************************************************
1665 * SHStrDupA [SHCORE.@]
1667 HRESULT WINAPI SHStrDupA(const char *src, WCHAR **dest)
1669 DWORD len;
1671 *dest = NULL;
1673 if (!src)
1674 return E_INVALIDARG;
1676 len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
1677 *dest = CoTaskMemAlloc(len * sizeof(WCHAR));
1678 if (!*dest)
1679 return E_OUTOFMEMORY;
1681 MultiByteToWideChar(CP_ACP, 0, src, -1, *dest, len);
1683 return S_OK;
1686 /*************************************************************************
1687 * SHAnsiToAnsi [SHCORE.@]
1689 DWORD WINAPI SHAnsiToAnsi(const char *src, char *dest, int dest_len)
1691 DWORD ret;
1693 TRACE("(%s, %p, %d)\n", debugstr_a(src), dest, dest_len);
1695 if (!src || !dest || dest_len <= 0)
1696 return 0;
1698 lstrcpynA(dest, src, dest_len);
1699 ret = strlen(dest);
1701 return src[ret] ? 0 : ret + 1;
1704 /*************************************************************************
1705 * SHUnicodeToAnsi [SHCORE.@]
1707 DWORD WINAPI SHUnicodeToAnsi(const WCHAR *src, char *dest, int dest_len)
1709 int ret = 1;
1711 TRACE("(%s, %p, %d)\n", debugstr_w(src), dest, dest_len);
1713 if (!dest || !dest_len)
1714 return 0;
1716 if (src)
1718 ret = WideCharToMultiByte(CP_ACP, 0, src, -1, dest, dest_len, NULL, NULL);
1719 if (!ret)
1721 dest[dest_len - 1] = 0;
1722 ret = dest_len;
1725 else
1726 dest[0] = 0;
1728 return ret;
1731 /*************************************************************************
1732 * SHUnicodeToUnicode [SHCORE.@]
1734 DWORD WINAPI SHUnicodeToUnicode(const WCHAR *src, WCHAR *dest, int dest_len)
1736 DWORD ret;
1738 TRACE("(%s, %p, %d)\n", debugstr_w(src), dest, dest_len);
1740 if (!src || !dest || dest_len <= 0)
1741 return 0;
1743 lstrcpynW(dest, src, dest_len);
1744 ret = strlenW(dest);
1746 return src[ret] ? 0 : ret + 1;
1749 /*************************************************************************
1750 * SHAnsiToUnicode [SHCORE.@]
1752 DWORD WINAPI SHAnsiToUnicode(const char *src, WCHAR *dest, int dest_len)
1754 int ret = 1;
1756 TRACE("(%s, %p, %d)\n", debugstr_a(src), dest, dest_len);
1758 if (!dest || !dest_len)
1759 return 0;
1761 if (src)
1763 ret = MultiByteToWideChar(CP_ACP, 0, src, -1, dest, dest_len);
1764 if (!ret)
1766 dest[dest_len - 1] = 0;
1767 ret = dest_len;
1770 else
1771 dest[0] = 0;
1773 return ret;
1776 /*************************************************************************
1777 * SHRegDuplicateHKey [SHCORE.@]
1779 HKEY WINAPI SHRegDuplicateHKey(HKEY hKey)
1781 HKEY newKey = 0;
1783 RegOpenKeyExW(hKey, 0, 0, MAXIMUM_ALLOWED, &newKey);
1784 TRACE("new key is %p\n", newKey);
1785 return newKey;
1788 /*************************************************************************
1789 * SHDeleteEmptyKeyW [SHCORE.@]
1791 DWORD WINAPI SHDeleteEmptyKeyW(HKEY hkey, const WCHAR *subkey)
1793 DWORD ret, count = 0;
1794 HKEY hsubkey = 0;
1796 TRACE("(%p, %s)\n", hkey, debugstr_w(subkey));
1798 ret = RegOpenKeyExW(hkey, subkey, 0, KEY_READ, &hsubkey);
1799 if (!ret)
1801 ret = RegQueryInfoKeyW(hsubkey, NULL, NULL, NULL, &count,
1802 NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1803 RegCloseKey(hsubkey);
1804 if (!ret)
1806 if (count)
1807 ret = ERROR_KEY_HAS_CHILDREN;
1808 else
1809 ret = RegDeleteKeyW(hkey, subkey);
1813 return ret;
1816 /*************************************************************************
1817 * SHDeleteEmptyKeyA [SHCORE.@]
1819 DWORD WINAPI SHDeleteEmptyKeyA(HKEY hkey, const char *subkey)
1821 WCHAR *subkeyW = NULL;
1822 DWORD ret;
1824 TRACE("(%p, %s)\n", hkey, debugstr_a(subkey));
1826 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1827 return ERROR_OUTOFMEMORY;
1829 ret = SHDeleteEmptyKeyW(hkey, subkeyW);
1830 CoTaskMemFree(subkeyW);
1831 return ret;
1834 /*************************************************************************
1835 * SHDeleteKeyW [SHCORE.@]
1837 DWORD WINAPI SHDeleteKeyW(HKEY hkey, const WCHAR *subkey)
1839 TRACE("(%p, %s)\n", hkey, debugstr_w(subkey));
1841 return RegDeleteTreeW(hkey, subkey);
1844 /*************************************************************************
1845 * SHDeleteKeyA [SHCORE.@]
1847 DWORD WINAPI SHDeleteKeyA(HKEY hkey, const char *subkey)
1849 TRACE("(%p, %s)\n", hkey, debugstr_a(subkey));
1851 return RegDeleteTreeA(hkey, subkey);
1854 /*************************************************************************
1855 * SHDeleteValueW [SHCORE.@]
1857 DWORD WINAPI SHDeleteValueW(HKEY hkey, const WCHAR *subkey, const WCHAR *value)
1859 HKEY hsubkey;
1860 DWORD ret;
1862 TRACE("(%p, %s, %s)\n", hkey, debugstr_w(subkey), debugstr_w(value));
1864 ret = RegOpenKeyExW(hkey, subkey, 0, KEY_SET_VALUE, &hsubkey);
1865 if (!ret)
1867 ret = RegDeleteValueW(hsubkey, value);
1868 RegCloseKey(hsubkey);
1871 return ret;
1874 /*************************************************************************
1875 * SHDeleteValueA [SHCORE.@]
1877 DWORD WINAPI SHDeleteValueA(HKEY hkey, const char *subkey, const char *value)
1879 WCHAR *subkeyW = NULL, *valueW = NULL;
1880 DWORD ret;
1882 TRACE("(%p, %s, %s)\n", hkey, debugstr_a(subkey), debugstr_a(value));
1884 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1885 return ERROR_OUTOFMEMORY;
1886 if (value && FAILED(SHStrDupA(value, &valueW)))
1888 CoTaskMemFree(subkeyW);
1889 return ERROR_OUTOFMEMORY;
1892 ret = SHDeleteValueW(hkey, subkeyW, valueW);
1893 CoTaskMemFree(subkeyW);
1894 CoTaskMemFree(valueW);
1895 return ret;
1898 /*************************************************************************
1899 * SHCopyKeyA [SHCORE.@]
1901 DWORD WINAPI SHCopyKeyA(HKEY hkey_src, const char *subkey, HKEY hkey_dst, DWORD reserved)
1903 WCHAR *subkeyW = NULL;
1904 DWORD ret;
1906 TRACE("(%p, %s, %p, %d)\n", hkey_src, debugstr_a(subkey), hkey_dst, reserved);
1908 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1909 return 0;
1911 ret = SHCopyKeyW(hkey_src, subkeyW, hkey_dst, reserved);
1912 CoTaskMemFree(subkeyW);
1913 return ret;
1916 /*************************************************************************
1917 * SHCopyKeyW [SHCORE.@]
1919 DWORD WINAPI SHCopyKeyW(HKEY hkey_src, const WCHAR *subkey, HKEY hkey_dst, DWORD reserved)
1921 DWORD key_count = 0, value_count = 0, max_key_len = 0;
1922 WCHAR name[MAX_PATH], *ptr_name = name;
1923 BYTE buff[1024], *ptr = buff;
1924 DWORD max_data_len = 0, i;
1925 DWORD ret = 0;
1927 TRACE("(%p, %s, %p, %d)\n", hkey_src, debugstr_w(subkey), hkey_dst, reserved);
1929 if (!hkey_dst || !hkey_src)
1930 return ERROR_INVALID_PARAMETER;
1932 if (subkey)
1933 ret = RegOpenKeyExW(hkey_src, subkey, 0, KEY_ALL_ACCESS, &hkey_src);
1935 if (ret)
1936 hkey_src = NULL; /* Don't close this key since we didn't open it */
1937 else
1939 DWORD max_value_len;
1941 ret = RegQueryInfoKeyW(hkey_src, NULL, NULL, NULL, &key_count, &max_key_len,
1942 NULL, &value_count, &max_value_len, &max_data_len, NULL, NULL);
1943 if (!ret)
1945 /* Get max size for key/value names */
1946 max_key_len = max(max_key_len, max_value_len);
1948 if (max_key_len++ > MAX_PATH - 1)
1949 ptr_name = heap_alloc(max_key_len * sizeof(WCHAR));
1951 if (max_data_len > sizeof(buff))
1952 ptr = heap_alloc(max_data_len);
1954 if (!ptr_name || !ptr)
1955 ret = ERROR_NOT_ENOUGH_MEMORY;
1959 for (i = 0; i < key_count && !ret; i++)
1961 HKEY hsubkey_src, hsubkey_dst;
1962 DWORD length = max_key_len;
1964 ret = RegEnumKeyExW(hkey_src, i, ptr_name, &length, NULL, NULL, NULL, NULL);
1965 if (!ret)
1967 ret = RegOpenKeyExW(hkey_src, ptr_name, 0, KEY_READ, &hsubkey_src);
1968 if (!ret)
1970 /* Create destination sub key */
1971 ret = RegCreateKeyW(hkey_dst, ptr_name, &hsubkey_dst);
1972 if (!ret)
1974 /* Recursively copy keys and values from the sub key */
1975 ret = SHCopyKeyW(hsubkey_src, NULL, hsubkey_dst, 0);
1976 RegCloseKey(hsubkey_dst);
1979 RegCloseKey(hsubkey_src);
1983 /* Copy all the values in this key */
1984 for (i = 0; i < value_count && !ret; i++)
1986 DWORD length = max_key_len, type, data_len = max_data_len;
1988 ret = RegEnumValueW(hkey_src, i, ptr_name, &length, NULL, &type, ptr, &data_len);
1989 if (!ret) {
1990 ret = SHSetValueW(hkey_dst, NULL, ptr_name, type, ptr, data_len);
1994 /* Free buffers if allocated */
1995 if (ptr_name != name)
1996 heap_free(ptr_name);
1997 if (ptr != buff)
1998 heap_free(ptr);
2000 if (subkey && hkey_src)
2001 RegCloseKey(hkey_src);
2003 return ret;
2007 /*************************************************************************
2008 * SHEnumKeyExA [SHCORE.@]
2010 LONG WINAPI SHEnumKeyExA(HKEY hkey, DWORD index, char *subkey, DWORD *length)
2012 TRACE("(%p, %d, %s, %p)\n", hkey, index, debugstr_a(subkey), length);
2014 return RegEnumKeyExA(hkey, index, subkey, length, NULL, NULL, NULL, NULL);
2017 /*************************************************************************
2018 * SHEnumKeyExW [SHCORE.@]
2020 LONG WINAPI SHEnumKeyExW(HKEY hkey, DWORD index, WCHAR *subkey, DWORD *length)
2022 TRACE("(%p, %d, %s, %p)\n", hkey, index, debugstr_w(subkey), length);
2024 return RegEnumKeyExW(hkey, index, subkey, length, NULL, NULL, NULL, NULL);
2027 /*************************************************************************
2028 * SHEnumValueA [SHCORE.@]
2030 LONG WINAPI SHEnumValueA(HKEY hkey, DWORD index, char *value, DWORD *length, DWORD *type,
2031 void *data, DWORD *data_len)
2033 TRACE("(%p, %d, %s, %p, %p, %p, %p)\n", hkey, index, debugstr_a(value), length, type, data, data_len);
2035 return RegEnumValueA(hkey, index, value, length, NULL, type, data, data_len);
2038 /*************************************************************************
2039 * SHEnumValueW [SHCORE.@]
2041 LONG WINAPI SHEnumValueW(HKEY hkey, DWORD index, WCHAR *value, DWORD *length, DWORD *type,
2042 void *data, DWORD *data_len)
2044 TRACE("(%p, %d, %s, %p, %p, %p, %p)\n", hkey, index, debugstr_w(value), length, type, data, data_len);
2046 return RegEnumValueW(hkey, index, value, length, NULL, type, data, data_len);
2049 /*************************************************************************
2050 * SHQueryValueExW [SHCORE.@]
2052 DWORD WINAPI SHQueryValueExW(HKEY hkey, const WCHAR *name, DWORD *reserved, DWORD *type,
2053 void *buff, DWORD *buff_len)
2055 DWORD ret, value_type, data_len = 0;
2057 TRACE("(%p, %s, %p, %p, %p, %p)\n", hkey, debugstr_w(name), reserved, type, buff, buff_len);
2059 if (buff_len)
2060 data_len = *buff_len;
2062 ret = RegQueryValueExW(hkey, name, reserved, &value_type, buff, &data_len);
2063 if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)
2064 return ret;
2066 if (buff_len && value_type == REG_EXPAND_SZ)
2068 DWORD length;
2069 WCHAR *value;
2071 if (!buff || ret == ERROR_MORE_DATA)
2073 length = data_len;
2074 value = heap_alloc(length);
2075 RegQueryValueExW(hkey, name, reserved, NULL, (BYTE *)value, &length);
2076 length = ExpandEnvironmentStringsW(value, NULL, 0);
2078 else
2080 length = (strlenW(buff) + 1) * sizeof(WCHAR);
2081 value = heap_alloc(length);
2082 memcpy(value, buff, length);
2083 length = ExpandEnvironmentStringsW(value, buff, *buff_len / sizeof(WCHAR));
2084 if (length > *buff_len) ret = ERROR_MORE_DATA;
2086 data_len = max(data_len, length);
2087 heap_free(value);
2090 if (type)
2091 *type = value_type == REG_EXPAND_SZ ? REG_SZ : value_type;
2092 if (buff_len)
2093 *buff_len = data_len;
2094 return ret;
2097 /*************************************************************************
2098 * SHQueryValueExA [SHCORE.@]
2100 DWORD WINAPI SHQueryValueExA(HKEY hkey, const char *name, DWORD *reserved, DWORD *type,
2101 void *buff, DWORD *buff_len)
2103 DWORD ret, value_type, data_len = 0;
2105 TRACE("(%p, %s, %p, %p, %p, %p)\n", hkey, debugstr_a(name), reserved, type, buff, buff_len);
2107 if (buff_len)
2108 data_len = *buff_len;
2110 ret = RegQueryValueExA(hkey, name, reserved, &value_type, buff, &data_len);
2111 if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)
2112 return ret;
2114 if (buff_len && value_type == REG_EXPAND_SZ)
2116 DWORD length;
2117 char *value;
2119 if (!buff || ret == ERROR_MORE_DATA)
2121 length = data_len;
2122 value = heap_alloc(length);
2123 RegQueryValueExA(hkey, name, reserved, NULL, (BYTE *)value, &length);
2124 length = ExpandEnvironmentStringsA(value, NULL, 0);
2126 else
2128 length = strlen(buff) + 1;
2129 value = heap_alloc(length);
2130 memcpy(value, buff, length);
2131 length = ExpandEnvironmentStringsA(value, buff, *buff_len);
2132 if (length > *buff_len) ret = ERROR_MORE_DATA;
2134 data_len = max(data_len, length);
2135 heap_free(value);
2138 if (type)
2139 *type = value_type == REG_EXPAND_SZ ? REG_SZ : value_type;
2140 if (buff_len)
2141 *buff_len = data_len;
2142 return ret;
2145 /*************************************************************************
2146 * SHGetValueA [SHCORE.@]
2148 DWORD WINAPI SHGetValueA(HKEY hkey, const char *subkey, const char *value,
2149 DWORD *type, void *data, DWORD *data_len)
2151 HKEY hsubkey = 0;
2152 DWORD ret = 0;
2154 TRACE("(%p, %s, %s, %p, %p, %p)\n", hkey, debugstr_a(subkey), debugstr_a(value),
2155 type, data, data_len);
2157 if (subkey)
2158 ret = RegOpenKeyExA(hkey, subkey, 0, KEY_QUERY_VALUE, &hsubkey);
2160 if (!ret)
2162 ret = SHQueryValueExA(hsubkey ? hsubkey : hkey, value, 0, type, data, data_len);
2163 if (subkey)
2164 RegCloseKey(hsubkey);
2167 return ret;
2170 /*************************************************************************
2171 * SHGetValueW [SHCORE.@]
2173 DWORD WINAPI SHGetValueW(HKEY hkey, const WCHAR *subkey, const WCHAR *value,
2174 DWORD *type, void *data, DWORD *data_len)
2176 HKEY hsubkey = 0;
2177 DWORD ret = 0;
2179 TRACE("(%p, %s, %s, %p, %p, %p)\n", hkey, debugstr_w(subkey), debugstr_w(value),
2180 type, data, data_len);
2182 if (subkey)
2183 ret = RegOpenKeyExW(hkey, subkey, 0, KEY_QUERY_VALUE, &hsubkey);
2185 if (!ret)
2187 ret = SHQueryValueExW(hsubkey ? hsubkey : hkey, value, 0, type, data, data_len);
2188 if (subkey)
2189 RegCloseKey(hsubkey);
2192 return ret;
2195 /*************************************************************************
2196 * SHRegGetIntW [SHCORE.280]
2198 int WINAPI SHRegGetIntW(HKEY hkey, const WCHAR *value, int default_value)
2200 WCHAR buff[32];
2201 DWORD buff_len;
2203 TRACE("(%p, %s, %d)\n", hkey, debugstr_w(value), default_value);
2205 buff[0] = 0;
2206 buff_len = sizeof(buff);
2207 if (SHQueryValueExW(hkey, value, 0, 0, buff, &buff_len))
2208 return default_value;
2210 if (*buff >= '0' && *buff <= '9')
2211 return atoiW(buff);
2213 return default_value;
2216 /*************************************************************************
2217 * SHRegGetPathA [SHCORE.@]
2219 DWORD WINAPI SHRegGetPathA(HKEY hkey, const char *subkey, const char *value, char *path, DWORD flags)
2221 DWORD length = MAX_PATH;
2223 TRACE("(%p, %s, %s, %p, %#x)\n", hkey, debugstr_a(subkey), debugstr_a(value), path, flags);
2225 return SHGetValueA(hkey, subkey, value, 0, path, &length);
2228 /*************************************************************************
2229 * SHRegGetPathW [SHCORE.@]
2231 DWORD WINAPI SHRegGetPathW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, WCHAR *path, DWORD flags)
2233 DWORD length = MAX_PATH;
2235 TRACE("(%p, %s, %s, %p, %d)\n", hkey, debugstr_w(subkey), debugstr_w(value), path, flags);
2237 return SHGetValueW(hkey, subkey, value, 0, path, &length);
2240 /*************************************************************************
2241 * SHSetValueW [SHCORE.@]
2243 DWORD WINAPI SHSetValueW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, DWORD type,
2244 const void *data, DWORD data_len)
2246 DWORD ret = ERROR_SUCCESS, dummy;
2247 HKEY hsubkey;
2249 TRACE("(%p, %s, %s, %d, %p, %d)\n", hkey, debugstr_w(subkey), debugstr_w(value),
2250 type, data, data_len);
2252 if (subkey && *subkey)
2253 ret = RegCreateKeyExW(hkey, subkey, 0, NULL, 0, KEY_SET_VALUE, NULL, &hsubkey, &dummy);
2254 else
2255 hsubkey = hkey;
2257 if (!ret)
2259 ret = RegSetValueExW(hsubkey, value, 0, type, data, data_len);
2260 if (hsubkey != hkey)
2261 RegCloseKey(hsubkey);
2264 return ret;
2267 /*************************************************************************
2268 * SHSetValueA [SHCORE.@]
2270 DWORD WINAPI SHSetValueA(HKEY hkey, const char *subkey, const char *value,
2271 DWORD type, const void *data, DWORD data_len)
2273 DWORD ret = ERROR_SUCCESS, dummy;
2274 HKEY hsubkey;
2276 TRACE("(%p, %s, %s, %d, %p, %d)\n", hkey, debugstr_a(subkey), debugstr_a(value),
2277 type, data, data_len);
2279 if (subkey && *subkey)
2280 ret = RegCreateKeyExA(hkey, subkey, 0, NULL, 0, KEY_SET_VALUE, NULL, &hsubkey, &dummy);
2281 else
2282 hsubkey = hkey;
2284 if (!ret)
2286 ret = RegSetValueExA(hsubkey, value, 0, type, data, data_len);
2287 if (hsubkey != hkey)
2288 RegCloseKey(hsubkey);
2291 return ret;
2294 /*************************************************************************
2295 * SHRegSetPathA [SHCORE.@]
2297 DWORD WINAPI SHRegSetPathA(HKEY hkey, const char *subkey, const char *value, const char *path, DWORD flags)
2299 FIXME("(%p, %s, %s, %s, %#x) - semi-stub\n", hkey, debugstr_a(subkey),
2300 debugstr_a(value), debugstr_a(path), flags);
2302 /* FIXME: PathUnExpandEnvStringsA() */
2304 return SHSetValueA(hkey, subkey, value, REG_SZ, path, lstrlenA(path));
2307 /*************************************************************************
2308 * SHRegSetPathW [SHCORE.@]
2310 DWORD WINAPI SHRegSetPathW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, const WCHAR *path, DWORD flags)
2312 FIXME("(%p, %s, %s, %s, %#x) - semi-stub\n", hkey, debugstr_w(subkey),
2313 debugstr_w(value), debugstr_w(path), flags);
2315 /* FIXME: PathUnExpandEnvStringsW(); */
2317 return SHSetValueW(hkey, subkey, value, REG_SZ, path, lstrlenW(path));
2320 /*************************************************************************
2321 * SHQueryInfoKeyA [SHCORE.@]
2323 LONG WINAPI SHQueryInfoKeyA(HKEY hkey, DWORD *subkeys, DWORD *subkey_max, DWORD *values, DWORD *value_max)
2325 TRACE("(%p, %p, %p, %p, %p)\n", hkey, subkeys, subkey_max, values, value_max);
2327 return RegQueryInfoKeyA(hkey, NULL, NULL, NULL, subkeys, subkey_max, NULL, values, value_max, NULL, NULL, NULL);
2330 /*************************************************************************
2331 * SHQueryInfoKeyW [SHCORE.@]
2333 LONG WINAPI SHQueryInfoKeyW(HKEY hkey, DWORD *subkeys, DWORD *subkey_max, DWORD *values, DWORD *value_max)
2335 TRACE("(%p, %p, %p, %p, %p)\n", hkey, subkeys, subkey_max, values, value_max);
2337 return RegQueryInfoKeyW(hkey, NULL, NULL, NULL, subkeys, subkey_max, NULL, values, value_max, NULL, NULL, NULL);
2340 /*************************************************************************
2341 * IsOS [SHCORE.@]
2343 BOOL WINAPI IsOS(DWORD feature)
2345 DWORD platform, majorv, minorv;
2346 OSVERSIONINFOA osvi;
2348 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
2349 if (!GetVersionExA(&osvi))
2350 return FALSE;
2352 majorv = osvi.dwMajorVersion;
2353 minorv = osvi.dwMinorVersion;
2354 platform = osvi.dwPlatformId;
2356 #define ISOS_RETURN(x) \
2357 TRACE("(0x%x) ret=%d\n",feature,(x)); \
2358 return (x)
2360 switch(feature) {
2361 case OS_WIN32SORGREATER:
2362 ISOS_RETURN(platform == VER_PLATFORM_WIN32s
2363 || platform == VER_PLATFORM_WIN32_WINDOWS);
2364 case OS_NT:
2365 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2366 case OS_WIN95ORGREATER:
2367 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS);
2368 case OS_NT4ORGREATER:
2369 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 4);
2370 case OS_WIN2000ORGREATER_ALT:
2371 case OS_WIN2000ORGREATER:
2372 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5);
2373 case OS_WIN98ORGREATER:
2374 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 10);
2375 case OS_WIN98_GOLD:
2376 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 10);
2377 case OS_WIN2000PRO:
2378 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5);
2379 case OS_WIN2000SERVER:
2380 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2381 case OS_WIN2000ADVSERVER:
2382 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2383 case OS_WIN2000DATACENTER:
2384 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2385 case OS_WIN2000TERMINAL:
2386 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2387 case OS_EMBEDDED:
2388 FIXME("(OS_EMBEDDED) What should we return here?\n");
2389 return FALSE;
2390 case OS_TERMINALCLIENT:
2391 FIXME("(OS_TERMINALCLIENT) What should we return here?\n");
2392 return FALSE;
2393 case OS_TERMINALREMOTEADMIN:
2394 FIXME("(OS_TERMINALREMOTEADMIN) What should we return here?\n");
2395 return FALSE;
2396 case OS_WIN95_GOLD:
2397 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 0);
2398 case OS_MEORGREATER:
2399 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 90);
2400 case OS_XPORGREATER:
2401 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1);
2402 case OS_HOME:
2403 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1);
2404 case OS_PROFESSIONAL:
2405 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2406 case OS_DATACENTER:
2407 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2408 case OS_ADVSERVER:
2409 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5);
2410 case OS_SERVER:
2411 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2412 case OS_TERMINALSERVER:
2413 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2414 case OS_PERSONALTERMINALSERVER:
2415 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && minorv >= 1 && majorv >= 5);
2416 case OS_FASTUSERSWITCHING:
2417 FIXME("(OS_FASTUSERSWITCHING) What should we return here?\n");
2418 return TRUE;
2419 case OS_WELCOMELOGONUI:
2420 FIXME("(OS_WELCOMELOGONUI) What should we return here?\n");
2421 return FALSE;
2422 case OS_DOMAINMEMBER:
2423 FIXME("(OS_DOMAINMEMBER) What should we return here?\n");
2424 return TRUE;
2425 case OS_ANYSERVER:
2426 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2427 case OS_WOW6432:
2429 BOOL is_wow64;
2430 IsWow64Process(GetCurrentProcess(), &is_wow64);
2431 return is_wow64;
2433 case OS_WEBSERVER:
2434 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2435 case OS_SMALLBUSINESSSERVER:
2436 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2437 case OS_TABLETPC:
2438 FIXME("(OS_TABLETPC) What should we return here?\n");
2439 return FALSE;
2440 case OS_SERVERADMINUI:
2441 FIXME("(OS_SERVERADMINUI) What should we return here?\n");
2442 return FALSE;
2443 case OS_MEDIACENTER:
2444 FIXME("(OS_MEDIACENTER) What should we return here?\n");
2445 return FALSE;
2446 case OS_APPLIANCE:
2447 FIXME("(OS_APPLIANCE) What should we return here?\n");
2448 return FALSE;
2449 case 0x25: /*OS_VISTAORGREATER*/
2450 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 6);
2453 #undef ISOS_RETURN
2455 WARN("(0x%x) unknown parameter\n", feature);
2457 return FALSE;