winhttp: Don't refill buffer after receiving server response.
[wine.git] / dlls / shcore / main.c
blob278eeb82fd5c1f3eb82a38d995e2e62d1eb08877
1 /*
2 * Copyright 2002 Jon Griffiths
3 * Copyright 2016 Sebastian Lackner
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <stdarg.h>
22 #define COBJMACROS
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "initguid.h"
29 #include "ocidl.h"
30 #include "featurestagingapi.h"
31 #include "shellscalingapi.h"
32 #define WINSHLWAPI
33 #include "shlwapi.h"
35 #include "wine/debug.h"
36 #include "wine/heap.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, %lu, %p.\n", instance, reason, reserved);
47 switch (reason)
49 case DLL_PROCESS_ATTACH:
50 DisableThreadLibraryCalls(instance);
51 shcore_tls = TlsAlloc();
52 break;
53 case DLL_PROCESS_DETACH:
54 if (reserved) break;
55 if (shcore_tls != TLS_OUT_OF_INDEXES)
56 TlsFree(shcore_tls);
57 break;
60 return TRUE;
63 HRESULT WINAPI GetProcessDpiAwareness(HANDLE process, PROCESS_DPI_AWARENESS *value)
65 if (GetProcessDpiAwarenessInternal( process, (DPI_AWARENESS *)value )) return S_OK;
66 return HRESULT_FROM_WIN32( GetLastError() );
69 HRESULT WINAPI SetProcessDpiAwareness(PROCESS_DPI_AWARENESS value)
71 if (SetProcessDpiAwarenessInternal( value )) return S_OK;
72 return HRESULT_FROM_WIN32( GetLastError() );
75 HRESULT WINAPI GetDpiForMonitor(HMONITOR monitor, MONITOR_DPI_TYPE type, UINT *x, UINT *y)
77 if (GetDpiForMonitorInternal( monitor, type, x, y )) return S_OK;
78 return HRESULT_FROM_WIN32( GetLastError() );
81 HRESULT WINAPI GetScaleFactorForMonitor(HMONITOR monitor, DEVICE_SCALE_FACTOR *scale)
83 FIXME("(%p %p): stub\n", monitor, scale);
85 *scale = SCALE_100_PERCENT;
86 return S_OK;
89 DEVICE_SCALE_FACTOR WINAPI GetScaleFactorForDevice(DISPLAY_DEVICE_TYPE device_type)
91 FIXME("%d\n", device_type);
93 return SCALE_100_PERCENT;
96 HRESULT WINAPI _IStream_Read(IStream *stream, void *dest, ULONG size)
98 ULONG read;
99 HRESULT hr;
101 TRACE("%p, %p, %lu.\n", stream, dest, size);
103 hr = IStream_Read(stream, dest, size, &read);
104 if (SUCCEEDED(hr) && read != size)
105 hr = E_FAIL;
106 return hr;
109 HRESULT WINAPI IStream_Reset(IStream *stream)
111 static const LARGE_INTEGER zero;
113 TRACE("(%p)\n", stream);
115 return IStream_Seek(stream, zero, 0, NULL);
118 HRESULT WINAPI IStream_Size(IStream *stream, ULARGE_INTEGER *size)
120 STATSTG statstg;
121 HRESULT hr;
123 TRACE("(%p, %p)\n", stream, size);
125 memset(&statstg, 0, sizeof(statstg));
127 hr = IStream_Stat(stream, &statstg, STATFLAG_NONAME);
129 if (SUCCEEDED(hr) && size)
130 *size = statstg.cbSize;
131 return hr;
134 HRESULT WINAPI _IStream_Write(IStream *stream, const void *src, ULONG size)
136 ULONG written;
137 HRESULT hr;
139 TRACE("%p, %p, %lu.\n", stream, src, size);
141 hr = IStream_Write(stream, src, size, &written);
142 if (SUCCEEDED(hr) && written != size)
143 hr = E_FAIL;
145 return hr;
148 void WINAPI IUnknown_AtomicRelease(IUnknown **obj)
150 TRACE("(%p)\n", obj);
152 if (!obj || !*obj)
153 return;
155 IUnknown_Release(*obj);
156 *obj = NULL;
159 HRESULT WINAPI IUnknown_GetSite(IUnknown *unk, REFIID iid, void **site)
161 IObjectWithSite *obj = NULL;
162 HRESULT hr = E_INVALIDARG;
164 TRACE("(%p, %s, %p)\n", unk, debugstr_guid(iid), site);
166 if (unk && iid && site)
168 hr = IUnknown_QueryInterface(unk, &IID_IObjectWithSite, (void **)&obj);
169 if (SUCCEEDED(hr) && obj)
171 hr = IObjectWithSite_GetSite(obj, iid, site);
172 IObjectWithSite_Release(obj);
176 return hr;
179 HRESULT WINAPI IUnknown_QueryService(IUnknown *obj, REFGUID sid, REFIID iid, void **out)
181 IServiceProvider *provider = NULL;
182 HRESULT hr;
184 if (!out)
185 return E_FAIL;
187 *out = NULL;
189 if (!obj)
190 return E_FAIL;
192 hr = IUnknown_QueryInterface(obj, &IID_IServiceProvider, (void **)&provider);
193 if (hr == S_OK && provider)
195 TRACE("Using provider %p.\n", provider);
197 hr = IServiceProvider_QueryService(provider, sid, iid, out);
199 TRACE("Provider %p returned %p.\n", provider, *out);
201 IServiceProvider_Release(provider);
204 return hr;
207 void WINAPI IUnknown_Set(IUnknown **dest, IUnknown *src)
209 TRACE("(%p, %p)\n", dest, src);
211 IUnknown_AtomicRelease(dest);
213 if (src)
215 IUnknown_AddRef(src);
216 *dest = src;
220 HRESULT WINAPI IUnknown_SetSite(IUnknown *obj, IUnknown *site)
222 IInternetSecurityManager *sec_manager;
223 IObjectWithSite *objwithsite;
224 HRESULT hr;
226 if (!obj)
227 return E_FAIL;
229 hr = IUnknown_QueryInterface(obj, &IID_IObjectWithSite, (void **)&objwithsite);
230 TRACE("ObjectWithSite %p, hr %#lx.\n", objwithsite, hr);
231 if (SUCCEEDED(hr))
233 hr = IObjectWithSite_SetSite(objwithsite, site);
234 TRACE("SetSite() hr %#lx.\n", hr);
235 IObjectWithSite_Release(objwithsite);
237 else
239 hr = IUnknown_QueryInterface(obj, &IID_IInternetSecurityManager, (void **)&sec_manager);
240 TRACE("InternetSecurityManager %p, hr %#lx.\n", sec_manager, hr);
241 if (FAILED(hr))
242 return hr;
244 hr = IInternetSecurityManager_SetSecuritySite(sec_manager, (IInternetSecurityMgrSite *)site);
245 TRACE("SetSecuritySite() hr %#lx.\n", hr);
246 IInternetSecurityManager_Release(sec_manager);
249 return hr;
252 HRESULT WINAPI SetCurrentProcessExplicitAppUserModelID(const WCHAR *appid)
254 FIXME("%s: stub\n", debugstr_w(appid));
255 return S_OK;
258 HRESULT WINAPI GetCurrentProcessExplicitAppUserModelID(const WCHAR **appid)
260 FIXME("%p: stub\n", appid);
261 *appid = NULL;
262 return E_NOTIMPL;
265 /*************************************************************************
266 * CommandLineToArgvW [SHCORE.@]
268 * We must interpret the quotes in the command line to rebuild the argv
269 * array correctly:
270 * - arguments are separated by spaces or tabs
271 * - quotes serve as optional argument delimiters
272 * '"a b"' -> 'a b'
273 * - escaped quotes must be converted back to '"'
274 * '\"' -> '"'
275 * - consecutive backslashes preceding a quote see their number halved with
276 * the remainder escaping the quote:
277 * 2n backslashes + quote -> n backslashes + quote as an argument delimiter
278 * 2n+1 backslashes + quote -> n backslashes + literal quote
279 * - backslashes that are not followed by a quote are copied literally:
280 * 'a\b' -> 'a\b'
281 * 'a\\b' -> 'a\\b'
282 * - in quoted strings, consecutive quotes see their number divided by three
283 * with the remainder modulo 3 deciding whether to close the string or not.
284 * Note that the opening quote must be counted in the consecutive quotes,
285 * that's the (1+) below:
286 * (1+) 3n quotes -> n quotes
287 * (1+) 3n+1 quotes -> n quotes plus closes the quoted string
288 * (1+) 3n+2 quotes -> n+1 quotes plus closes the quoted string
289 * - in unquoted strings, the first quote opens the quoted string and the
290 * remaining consecutive quotes follow the above rule.
292 WCHAR** WINAPI CommandLineToArgvW(const WCHAR *cmdline, int *numargs)
294 int qcount, bcount;
295 const WCHAR *s;
296 WCHAR **argv;
297 DWORD argc;
298 WCHAR *d;
300 if (!numargs)
302 SetLastError(ERROR_INVALID_PARAMETER);
303 return NULL;
306 if (*cmdline == 0)
308 /* Return the path to the executable */
309 DWORD len, deslen = MAX_PATH, size;
311 size = sizeof(WCHAR *) * 2 + deslen * sizeof(WCHAR);
312 for (;;)
314 if (!(argv = LocalAlloc(LMEM_FIXED, size))) return NULL;
315 len = GetModuleFileNameW(0, (WCHAR *)(argv + 2), deslen);
316 if (!len)
318 LocalFree(argv);
319 return NULL;
321 if (len < deslen) break;
322 deslen *= 2;
323 size = sizeof(WCHAR *) * 2 + deslen * sizeof(WCHAR);
324 LocalFree(argv);
326 argv[0] = (WCHAR *)(argv + 2);
327 argv[1] = NULL;
328 *numargs = 1;
330 return argv;
333 /* --- First count the arguments */
334 argc = 1;
335 s = cmdline;
336 /* The first argument, the executable path, follows special rules */
337 if (*s == '"')
339 /* The executable path ends at the next quote, no matter what */
340 s++;
341 while (*s)
342 if (*s++ == '"')
343 break;
345 else
347 /* The executable path ends at the next space, no matter what */
348 while (*s && *s != ' ' && *s != '\t')
349 s++;
351 /* skip to the first argument, if any */
352 while (*s == ' ' || *s == '\t')
353 s++;
354 if (*s)
355 argc++;
357 /* Analyze the remaining arguments */
358 qcount = bcount = 0;
359 while (*s)
361 if ((*s == ' ' || *s == '\t') && qcount == 0)
363 /* skip to the next argument and count it if any */
364 while (*s == ' ' || *s == '\t')
365 s++;
366 if (*s)
367 argc++;
368 bcount = 0;
370 else if (*s == '\\')
372 /* '\', count them */
373 bcount++;
374 s++;
376 else if (*s == '"')
378 /* '"' */
379 if ((bcount & 1) == 0)
380 qcount++; /* unescaped '"' */
381 s++;
382 bcount = 0;
383 /* consecutive quotes, see comment in copying code below */
384 while (*s == '"')
386 qcount++;
387 s++;
389 qcount = qcount % 3;
390 if (qcount == 2)
391 qcount = 0;
393 else
395 /* a regular character */
396 bcount = 0;
397 s++;
401 /* Allocate in a single lump, the string array, and the strings that go
402 * with it. This way the caller can make a single LocalFree() call to free
403 * both, as per MSDN.
405 argv = LocalAlloc(LMEM_FIXED, (argc + 1) * sizeof(WCHAR *) + (lstrlenW(cmdline) + 1) * sizeof(WCHAR));
406 if (!argv)
407 return NULL;
409 /* --- Then split and copy the arguments */
410 argv[0] = d = lstrcpyW((WCHAR *)(argv + argc + 1), cmdline);
411 argc = 1;
412 /* The first argument, the executable path, follows special rules */
413 if (*d == '"')
415 /* The executable path ends at the next quote, no matter what */
416 s = d + 1;
417 while (*s)
419 if (*s == '"')
421 s++;
422 break;
424 *d++ = *s++;
427 else
429 /* The executable path ends at the next space, no matter what */
430 while (*d && *d != ' ' && *d != '\t')
431 d++;
432 s = d;
433 if (*s)
434 s++;
436 /* close the executable path */
437 *d++ = 0;
438 /* skip to the first argument and initialize it if any */
439 while (*s == ' ' || *s == '\t')
440 s++;
441 if (!*s)
443 /* There are no parameters so we are all done */
444 argv[argc] = NULL;
445 *numargs = argc;
446 return argv;
449 /* Split and copy the remaining arguments */
450 argv[argc++] = d;
451 qcount = bcount = 0;
452 while (*s)
454 if ((*s == ' ' || *s == '\t') && qcount == 0)
456 /* close the argument */
457 *d++ = 0;
458 bcount = 0;
460 /* skip to the next one and initialize it if any */
461 do {
462 s++;
463 } while (*s == ' ' || *s == '\t');
464 if (*s)
465 argv[argc++] = d;
467 else if (*s=='\\')
469 *d++ = *s++;
470 bcount++;
472 else if (*s == '"')
474 if ((bcount & 1) == 0)
476 /* Preceded by an even number of '\', this is half that
477 * number of '\', plus a quote which we erase.
479 d -= bcount / 2;
480 qcount++;
482 else
484 /* Preceded by an odd number of '\', this is half that
485 * number of '\' followed by a '"'
487 d = d - bcount / 2 - 1;
488 *d++ = '"';
490 s++;
491 bcount = 0;
492 /* Now count the number of consecutive quotes. Note that qcount
493 * already takes into account the opening quote if any, as well as
494 * the quote that lead us here.
496 while (*s == '"')
498 if (++qcount == 3)
500 *d++ = '"';
501 qcount = 0;
503 s++;
505 if (qcount == 2)
506 qcount = 0;
508 else
510 /* a regular character */
511 *d++ = *s++;
512 bcount = 0;
515 *d = '\0';
516 argv[argc] = NULL;
517 *numargs = argc;
519 return argv;
522 struct shstream
524 IStream IStream_iface;
525 LONG refcount;
527 union
529 struct
531 BYTE *buffer;
532 DWORD length;
533 DWORD position;
535 HKEY hkey;
536 WCHAR *valuename;
537 } mem;
538 struct
540 HANDLE handle;
541 DWORD mode;
542 WCHAR *path;
543 } file;
544 } u;
547 static inline struct shstream *impl_from_IStream(IStream *iface)
549 return CONTAINING_RECORD(iface, struct shstream, IStream_iface);
552 static HRESULT WINAPI shstream_QueryInterface(IStream *iface, REFIID riid, void **out)
554 struct shstream *stream = impl_from_IStream(iface);
556 TRACE("(%p)->(%s, %p)\n", stream, debugstr_guid(riid), out);
558 if (IsEqualIID(riid, &IID_IUnknown) ||
559 IsEqualIID(riid, &IID_IStream) ||
560 IsEqualIID(riid, &IID_ISequentialStream))
562 *out = iface;
563 IStream_AddRef(iface);
564 return S_OK;
567 *out = NULL;
568 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
569 return E_NOINTERFACE;
572 static ULONG WINAPI shstream_AddRef(IStream *iface)
574 struct shstream *stream = impl_from_IStream(iface);
575 ULONG refcount = InterlockedIncrement(&stream->refcount);
577 TRACE("%p, refcount %lu.\n", iface, refcount);
579 return refcount;
582 static ULONG WINAPI memstream_Release(IStream *iface)
584 struct shstream *stream = impl_from_IStream(iface);
585 ULONG refcount = InterlockedDecrement(&stream->refcount);
587 TRACE("%p, refcount %lu.\n", iface, refcount);
589 if (!refcount)
591 heap_free(stream->u.mem.buffer);
592 heap_free(stream);
595 return refcount;
598 static HRESULT WINAPI memstream_Read(IStream *iface, void *buff, ULONG buff_size, ULONG *read_len)
600 struct shstream *stream = impl_from_IStream(iface);
601 DWORD length;
603 TRACE("%p, %p, %lu, %p.\n", iface, buff, buff_size, read_len);
605 if (stream->u.mem.position >= stream->u.mem.length)
607 if (read_len)
608 *read_len = 0;
609 return S_FALSE;
612 length = stream->u.mem.length - stream->u.mem.position;
613 if (buff_size < length)
614 length = buff_size;
616 memmove(buff, stream->u.mem.buffer + stream->u.mem.position, length);
617 stream->u.mem.position += length;
619 if (read_len)
620 *read_len = length;
622 return S_OK;
625 static HRESULT WINAPI memstream_Write(IStream *iface, const void *buff, ULONG buff_size, ULONG *written)
627 struct shstream *stream = impl_from_IStream(iface);
628 DWORD length = stream->u.mem.position + buff_size;
630 TRACE("%p, %p, %lu, %p.\n", iface, buff, buff_size, written);
632 if (length < stream->u.mem.position) /* overflow */
633 return STG_E_INSUFFICIENTMEMORY;
635 if (length > stream->u.mem.length)
637 BYTE *buffer = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, stream->u.mem.buffer, length);
638 if (!buffer)
639 return STG_E_INSUFFICIENTMEMORY;
641 stream->u.mem.length = length;
642 stream->u.mem.buffer = buffer;
644 memmove(stream->u.mem.buffer + stream->u.mem.position, buff, buff_size);
645 stream->u.mem.position += buff_size; /* adjust pointer */
647 if (written)
648 *written = buff_size;
650 return S_OK;
653 static HRESULT WINAPI memstream_Seek(IStream *iface, LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER*new_pos)
655 struct shstream *stream = impl_from_IStream(iface);
656 LARGE_INTEGER tmp;
658 TRACE("%p, %s, %ld, %p.\n", iface, wine_dbgstr_longlong(move.QuadPart), origin, new_pos);
660 if (origin == STREAM_SEEK_SET)
661 tmp = move;
662 else if (origin == STREAM_SEEK_CUR)
663 tmp.QuadPart = stream->u.mem.position + move.QuadPart;
664 else if (origin == STREAM_SEEK_END)
665 tmp.QuadPart = stream->u.mem.length + move.QuadPart;
666 else
667 return STG_E_INVALIDPARAMETER;
669 if (tmp.QuadPart < 0)
670 return STG_E_INVALIDFUNCTION;
672 /* we cut off the high part here */
673 stream->u.mem.position = tmp.u.LowPart;
675 if (new_pos)
676 new_pos->QuadPart = stream->u.mem.position;
677 return S_OK;
680 static HRESULT WINAPI memstream_SetSize(IStream *iface, ULARGE_INTEGER new_size)
682 struct shstream *stream = impl_from_IStream(iface);
683 DWORD length;
684 BYTE *buffer;
686 TRACE("(%p, %s)\n", stream, wine_dbgstr_longlong(new_size.QuadPart));
688 /* we cut off the high part here */
689 length = new_size.u.LowPart;
690 buffer = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, stream->u.mem.buffer, length);
691 if (!buffer)
692 return STG_E_INSUFFICIENTMEMORY;
694 stream->u.mem.buffer = buffer;
695 stream->u.mem.length = length;
697 return S_OK;
700 static HRESULT WINAPI shstream_CopyTo(IStream *iface, IStream *dest, ULARGE_INTEGER size,
701 ULARGE_INTEGER *read_len, ULARGE_INTEGER *written)
703 struct shstream *stream = impl_from_IStream(iface);
704 ULARGE_INTEGER total_read, total_written;
705 HRESULT hr = S_OK;
706 BYTE buffer[0x400];
708 TRACE("(%p, %p, %s, %p, %p)\n", stream, dest, wine_dbgstr_longlong(size.QuadPart), read_len, written);
710 if (!dest)
711 return E_POINTER;
713 total_read.QuadPart = 0;
714 total_written.QuadPart = 0;
716 while (size.QuadPart > 0)
718 ULONG chunk_size = size.QuadPart >= sizeof(buffer) ? sizeof(buffer) : size.u.LowPart;
719 ULONG chunk_read, chunk_written;
721 hr = IStream_Read(iface, buffer, chunk_size, &chunk_read);
722 if (FAILED(hr))
723 break;
725 total_read.QuadPart += chunk_read;
727 if (chunk_read)
729 hr = IStream_Write(dest, buffer, chunk_read, &chunk_written);
730 if (FAILED(hr))
731 break;
733 total_written.QuadPart += chunk_written;
736 if (chunk_read != chunk_size)
737 size.QuadPart = 0;
738 else
739 size.QuadPart -= chunk_read;
742 if (read_len)
743 read_len->QuadPart = total_read.QuadPart;
744 if (written)
745 written->QuadPart = total_written.QuadPart;
747 return hr;
750 static HRESULT WINAPI shstream_Commit(IStream *iface, DWORD flags)
752 TRACE("%p, %#lx.\n", iface, flags);
754 /* Commit is not supported by this stream */
755 return E_NOTIMPL;
758 static HRESULT WINAPI shstream_Revert(IStream *iface)
760 struct shstream *stream = impl_from_IStream(iface);
762 TRACE("(%p)\n", stream);
764 /* revert not supported by this stream */
765 return E_NOTIMPL;
768 static HRESULT WINAPI shstream_LockRegion(IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER size, DWORD lock_type)
770 struct shstream *stream = impl_from_IStream(iface);
772 TRACE("(%p)\n", stream);
774 /* lock/unlock not supported by this stream */
775 return E_NOTIMPL;
778 static HRESULT WINAPI shstream_UnlockRegion(IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER size, DWORD lock_type)
780 struct shstream *stream = impl_from_IStream(iface);
782 TRACE("(%p)\n", stream);
784 /* lock/unlock not supported by this stream */
785 return E_NOTIMPL;
788 static HRESULT WINAPI memstream_Stat(IStream *iface, STATSTG *statstg, DWORD flags)
790 struct shstream *stream = impl_from_IStream(iface);
792 TRACE("%p, %p, %#lx.\n", iface, statstg, flags);
794 memset(statstg, 0, sizeof(*statstg));
795 statstg->type = STGTY_STREAM;
796 statstg->cbSize.QuadPart = stream->u.mem.length;
797 statstg->grfMode = STGM_READWRITE;
799 return S_OK;
802 static HRESULT WINAPI shstream_Clone(IStream *iface, IStream **dest)
804 struct shstream *stream = impl_from_IStream(iface);
806 TRACE("(%p, %p)\n", stream, dest);
808 *dest = NULL;
810 /* clone not supported by this stream */
811 return E_NOTIMPL;
814 static const IStreamVtbl memstreamvtbl =
816 shstream_QueryInterface,
817 shstream_AddRef,
818 memstream_Release,
819 memstream_Read,
820 memstream_Write,
821 memstream_Seek,
822 memstream_SetSize,
823 shstream_CopyTo,
824 shstream_Commit,
825 shstream_Revert,
826 shstream_LockRegion,
827 shstream_UnlockRegion,
828 memstream_Stat,
829 shstream_Clone,
832 static struct shstream *shstream_create(const IStreamVtbl *vtbl, const BYTE *data, UINT data_len)
834 struct shstream *stream;
836 if (!data)
837 data_len = 0;
839 stream = heap_alloc(sizeof(*stream));
840 stream->IStream_iface.lpVtbl = vtbl;
841 stream->refcount = 1;
842 stream->u.mem.buffer = heap_alloc(data_len);
843 if (!stream->u.mem.buffer)
845 heap_free(stream);
846 return NULL;
848 memcpy(stream->u.mem.buffer, data, data_len);
849 stream->u.mem.length = data_len;
850 stream->u.mem.position = 0;
852 return stream;
855 /*************************************************************************
856 * SHCreateMemStream [SHCORE.@]
858 * Create an IStream object on a block of memory.
860 * PARAMS
861 * data [I] Memory block to create the IStream object on
862 * data_len [I] Length of data block
864 * RETURNS
865 * Success: A pointer to the IStream object.
866 * Failure: NULL, if any parameters are invalid or an error occurs.
868 * NOTES
869 * A copy of the memory block is made, it's freed when the stream is released.
871 IStream * WINAPI SHCreateMemStream(const BYTE *data, UINT data_len)
873 struct shstream *stream;
875 TRACE("(%p, %u)\n", data, data_len);
877 stream = shstream_create(&memstreamvtbl, data, data_len);
878 return stream ? &stream->IStream_iface : NULL;
881 static ULONG WINAPI filestream_Release(IStream *iface)
883 struct shstream *stream = impl_from_IStream(iface);
884 ULONG refcount = InterlockedDecrement(&stream->refcount);
886 TRACE("%p, refcount %lu.\n", iface, refcount);
888 if (!refcount)
890 CloseHandle(stream->u.file.handle);
891 heap_free(stream->u.file.path);
892 heap_free(stream);
895 return refcount;
898 static HRESULT WINAPI filestream_Read(IStream *iface, void *buff, ULONG size, ULONG *read_len)
900 struct shstream *stream = impl_from_IStream(iface);
901 DWORD read = 0;
903 TRACE("%p, %p, %lu, %p.\n", iface, buff, size, read_len);
905 if (!ReadFile(stream->u.file.handle, buff, size, &read, NULL))
907 WARN("error %ld reading file\n", GetLastError());
908 return S_FALSE;
911 if (read_len)
912 *read_len = read;
914 return read == size ? S_OK : S_FALSE;
917 static HRESULT WINAPI filestream_Write(IStream *iface, const void *buff, ULONG size, ULONG *written)
919 struct shstream *stream = impl_from_IStream(iface);
920 DWORD written_len = 0;
922 TRACE("%p, %p, %lu, %p.\n", iface, buff, size, written);
924 switch (stream->u.file.mode & 0xf)
926 case STGM_WRITE:
927 case STGM_READWRITE:
928 break;
929 default:
930 return STG_E_ACCESSDENIED;
933 if (!WriteFile(stream->u.file.handle, buff, size, &written_len, NULL))
934 return HRESULT_FROM_WIN32(GetLastError());
936 if (written)
937 *written = written_len;
939 return S_OK;
942 static HRESULT WINAPI filestream_Seek(IStream *iface, LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER *new_pos)
944 struct shstream *stream = impl_from_IStream(iface);
945 DWORD position;
947 TRACE("%p, %s, %ld, %p.\n", iface, wine_dbgstr_longlong(move.QuadPart), origin, new_pos);
949 position = SetFilePointer(stream->u.file.handle, move.u.LowPart, NULL, origin);
950 if (position == INVALID_SET_FILE_POINTER)
951 return HRESULT_FROM_WIN32(GetLastError());
953 if (new_pos)
955 new_pos->u.HighPart = 0;
956 new_pos->u.LowPart = position;
959 return S_OK;
962 static HRESULT WINAPI filestream_SetSize(IStream *iface, ULARGE_INTEGER size)
964 struct shstream *stream = impl_from_IStream(iface);
965 LARGE_INTEGER origin, move;
967 TRACE("(%p, %s)\n", stream, wine_dbgstr_longlong(size.QuadPart));
969 move.QuadPart = 0;
970 if (!SetFilePointerEx(stream->u.file.handle, move, &origin, FILE_CURRENT))
971 return E_FAIL;
973 move.QuadPart = size.QuadPart;
974 if (!SetFilePointerEx(stream->u.file.handle, move, NULL, FILE_BEGIN))
975 return E_FAIL;
977 if (stream->u.file.mode != STGM_READ)
979 if (!SetEndOfFile(stream->u.file.handle))
980 return E_FAIL;
981 if (!SetFilePointerEx(stream->u.file.handle, origin, NULL, FILE_BEGIN))
982 return E_FAIL;
985 return S_OK;
988 static HRESULT WINAPI filestream_CopyTo(IStream *iface, IStream *dest, ULARGE_INTEGER size,
989 ULARGE_INTEGER *read_len, ULARGE_INTEGER *written)
991 struct shstream *stream = impl_from_IStream(iface);
992 HRESULT hr = S_OK;
993 char buff[1024];
995 TRACE("(%p, %p, %s, %p, %p)\n", stream, dest, wine_dbgstr_longlong(size.QuadPart), read_len, written);
997 if (read_len)
998 read_len->QuadPart = 0;
999 if (written)
1000 written->QuadPart = 0;
1002 if (!dest)
1003 return S_OK;
1005 while (size.QuadPart)
1007 ULONG left, read_chunk, written_chunk;
1009 left = size.QuadPart > sizeof(buff) ? sizeof(buff) : size.QuadPart;
1011 /* Read */
1012 hr = IStream_Read(iface, buff, left, &read_chunk);
1013 if (FAILED(hr) || read_chunk == 0)
1014 break;
1015 if (read_len)
1016 read_len->QuadPart += read_chunk;
1018 /* Write */
1019 hr = IStream_Write(dest, buff, read_chunk, &written_chunk);
1020 if (written_chunk)
1021 written->QuadPart += written_chunk;
1022 if (FAILED(hr) || written_chunk != left)
1023 break;
1025 size.QuadPart -= left;
1028 return hr;
1031 static HRESULT WINAPI filestream_Commit(IStream *iface, DWORD flags)
1033 TRACE("%p, %#lx.\n", iface, flags);
1035 return S_OK;
1038 static HRESULT WINAPI filestream_Stat(IStream *iface, STATSTG *statstg, DWORD flags)
1040 struct shstream *stream = impl_from_IStream(iface);
1041 BY_HANDLE_FILE_INFORMATION fi;
1043 TRACE("%p, %p, %#lx.\n", iface, statstg, flags);
1045 if (!statstg)
1046 return STG_E_INVALIDPOINTER;
1048 memset(&fi, 0, sizeof(fi));
1049 GetFileInformationByHandle(stream->u.file.handle, &fi);
1051 if (flags & STATFLAG_NONAME)
1052 statstg->pwcsName = NULL;
1053 else
1055 int len = lstrlenW(stream->u.file.path);
1056 if ((statstg->pwcsName = CoTaskMemAlloc((len + 1) * sizeof(WCHAR))))
1057 memcpy(statstg->pwcsName, stream->u.file.path, (len + 1) * sizeof(WCHAR));
1059 statstg->type = 0;
1060 statstg->cbSize.u.LowPart = fi.nFileSizeLow;
1061 statstg->cbSize.u.HighPart = fi.nFileSizeHigh;
1062 statstg->mtime = fi.ftLastWriteTime;
1063 statstg->ctime = fi.ftCreationTime;
1064 statstg->atime = fi.ftLastAccessTime;
1065 statstg->grfMode = stream->u.file.mode;
1066 statstg->grfLocksSupported = 0;
1067 memcpy(&statstg->clsid, &IID_IStream, sizeof(CLSID));
1068 statstg->grfStateBits = 0;
1069 statstg->reserved = 0;
1071 return S_OK;
1074 static const IStreamVtbl filestreamvtbl =
1076 shstream_QueryInterface,
1077 shstream_AddRef,
1078 filestream_Release,
1079 filestream_Read,
1080 filestream_Write,
1081 filestream_Seek,
1082 filestream_SetSize,
1083 filestream_CopyTo,
1084 filestream_Commit,
1085 shstream_Revert,
1086 shstream_LockRegion,
1087 shstream_UnlockRegion,
1088 filestream_Stat,
1089 shstream_Clone,
1092 /*************************************************************************
1093 * SHCreateStreamOnFileEx [SHCORE.@]
1095 HRESULT WINAPI SHCreateStreamOnFileEx(const WCHAR *path, DWORD mode, DWORD attributes,
1096 BOOL create, IStream *template, IStream **ret)
1098 DWORD access, share, creation_disposition, len;
1099 struct shstream *stream;
1100 HANDLE hFile;
1102 TRACE("%s, %ld, %#lx, %d, %p, %p)\n", debugstr_w(path), mode, attributes,
1103 create, template, ret);
1105 if (!path || !ret || template)
1106 return E_INVALIDARG;
1108 *ret = NULL;
1110 /* Access */
1111 switch (mode & 0xf)
1113 case STGM_WRITE:
1114 case STGM_READWRITE:
1115 access = GENERIC_READ | GENERIC_WRITE;
1116 break;
1117 case STGM_READ:
1118 access = GENERIC_READ;
1119 break;
1120 default:
1121 return E_INVALIDARG;
1124 /* Sharing */
1125 switch (mode & 0xf0)
1127 case 0:
1128 case STGM_SHARE_DENY_NONE:
1129 share = FILE_SHARE_READ | FILE_SHARE_WRITE;
1130 break;
1131 case STGM_SHARE_DENY_READ:
1132 share = FILE_SHARE_WRITE;
1133 break;
1134 case STGM_SHARE_DENY_WRITE:
1135 share = FILE_SHARE_READ;
1136 break;
1137 case STGM_SHARE_EXCLUSIVE:
1138 share = 0;
1139 break;
1140 default:
1141 return E_INVALIDARG;
1144 switch (mode & 0xf000)
1146 case STGM_FAILIFTHERE:
1147 creation_disposition = create ? CREATE_NEW : OPEN_EXISTING;
1148 break;
1149 case STGM_CREATE:
1150 creation_disposition = CREATE_ALWAYS;
1151 break;
1152 default:
1153 return E_INVALIDARG;
1156 hFile = CreateFileW(path, access, share, NULL, creation_disposition, attributes, 0);
1157 if (hFile == INVALID_HANDLE_VALUE)
1158 return HRESULT_FROM_WIN32(GetLastError());
1160 stream = heap_alloc(sizeof(*stream));
1161 stream->IStream_iface.lpVtbl = &filestreamvtbl;
1162 stream->refcount = 1;
1163 stream->u.file.handle = hFile;
1164 stream->u.file.mode = mode;
1166 len = lstrlenW(path);
1167 stream->u.file.path = heap_alloc((len + 1) * sizeof(WCHAR));
1168 memcpy(stream->u.file.path, path, (len + 1) * sizeof(WCHAR));
1170 *ret = &stream->IStream_iface;
1172 return S_OK;
1175 /*************************************************************************
1176 * SHCreateStreamOnFileW [SHCORE.@]
1178 HRESULT WINAPI SHCreateStreamOnFileW(const WCHAR *path, DWORD mode, IStream **stream)
1180 TRACE("%s, %#lx, %p.\n", debugstr_w(path), mode, stream);
1182 if (!path || !stream)
1183 return E_INVALIDARG;
1185 if ((mode & (STGM_CONVERT | STGM_DELETEONRELEASE | STGM_TRANSACTED)) != 0)
1186 return E_INVALIDARG;
1188 return SHCreateStreamOnFileEx(path, mode, 0, FALSE, NULL, stream);
1191 /*************************************************************************
1192 * SHCreateStreamOnFileA [SHCORE.@]
1194 HRESULT WINAPI SHCreateStreamOnFileA(const char *path, DWORD mode, IStream **stream)
1196 WCHAR *pathW;
1197 HRESULT hr;
1198 DWORD len;
1200 TRACE("%s, %#lx, %p.\n", debugstr_a(path), mode, stream);
1202 if (!path)
1203 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1205 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1206 pathW = heap_alloc(len * sizeof(WCHAR));
1207 if (!pathW)
1208 return E_OUTOFMEMORY;
1210 MultiByteToWideChar(CP_ACP, 0, path, -1, pathW, len);
1211 hr = SHCreateStreamOnFileW(pathW, mode, stream);
1212 heap_free(pathW);
1214 return hr;
1217 static ULONG WINAPI regstream_Release(IStream *iface)
1219 struct shstream *stream = impl_from_IStream(iface);
1220 ULONG refcount = InterlockedDecrement(&stream->refcount);
1222 TRACE("%p, refcount %lu.\n", iface, refcount);
1224 if (!refcount)
1226 if (stream->u.mem.hkey)
1228 if (stream->u.mem.length)
1229 RegSetValueExW(stream->u.mem.hkey, stream->u.mem.valuename, 0, REG_BINARY,
1230 (const BYTE *)stream->u.mem.buffer, stream->u.mem.length);
1231 else
1232 RegDeleteValueW(stream->u.mem.hkey, stream->u.mem.valuename);
1233 RegCloseKey(stream->u.mem.hkey);
1235 CoTaskMemFree(stream->u.mem.valuename);
1236 heap_free(stream->u.mem.buffer);
1237 heap_free(stream);
1240 return refcount;
1243 static const IStreamVtbl regstreamvtbl =
1245 shstream_QueryInterface,
1246 shstream_AddRef,
1247 regstream_Release,
1248 memstream_Read,
1249 memstream_Write,
1250 memstream_Seek,
1251 memstream_SetSize,
1252 shstream_CopyTo,
1253 shstream_Commit,
1254 shstream_Revert,
1255 shstream_LockRegion,
1256 shstream_UnlockRegion,
1257 memstream_Stat,
1258 shstream_Clone,
1261 /*************************************************************************
1262 * SHOpenRegStream2W [SHCORE.@]
1264 IStream * WINAPI SHOpenRegStream2W(HKEY hKey, const WCHAR *subkey, const WCHAR *value, DWORD mode)
1266 struct shstream *stream;
1267 HKEY hStrKey = NULL;
1268 BYTE *buff = NULL;
1269 DWORD length = 0;
1270 LONG ret;
1272 TRACE("%p, %s, %s, %#lx.\n", hKey, debugstr_w(subkey), debugstr_w(value), mode);
1274 if (mode == STGM_READ)
1275 ret = RegOpenKeyExW(hKey, subkey, 0, KEY_READ, &hStrKey);
1276 else /* in write mode we make sure the subkey exits */
1277 ret = RegCreateKeyExW(hKey, subkey, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &hStrKey, NULL);
1279 if (ret == ERROR_SUCCESS)
1281 if (mode == STGM_READ || mode == STGM_READWRITE)
1283 /* read initial data */
1284 ret = RegQueryValueExW(hStrKey, value, 0, 0, 0, &length);
1285 if (ret == ERROR_SUCCESS && length)
1287 buff = heap_alloc(length);
1288 RegQueryValueExW(hStrKey, value, 0, 0, buff, &length);
1292 if (!length)
1293 buff = heap_alloc(length);
1295 stream = shstream_create(&regstreamvtbl, buff, length);
1296 heap_free(buff);
1297 if (stream)
1299 stream->u.mem.hkey = hStrKey;
1300 SHStrDupW(value, &stream->u.mem.valuename);
1301 return &stream->IStream_iface;
1305 if (hStrKey)
1306 RegCloseKey(hStrKey);
1308 return NULL;
1311 /*************************************************************************
1312 * SHOpenRegStream2A [SHCORE.@]
1314 IStream * WINAPI SHOpenRegStream2A(HKEY hKey, const char *subkey, const char *value, DWORD mode)
1316 WCHAR *subkeyW = NULL, *valueW = NULL;
1317 IStream *stream;
1319 TRACE("%p, %s, %s, %#lx.\n", hKey, debugstr_a(subkey), debugstr_a(value), mode);
1321 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1322 return NULL;
1323 if (value && FAILED(SHStrDupA(value, &valueW)))
1325 CoTaskMemFree(subkeyW);
1326 return NULL;
1329 stream = SHOpenRegStream2W(hKey, subkeyW, valueW, mode);
1330 CoTaskMemFree(subkeyW);
1331 CoTaskMemFree(valueW);
1332 return stream;
1335 /*************************************************************************
1336 * SHOpenRegStreamA [SHCORE.@]
1338 IStream * WINAPI SHOpenRegStreamA(HKEY hkey, const char *subkey, const char *value, DWORD mode)
1340 WCHAR *subkeyW = NULL, *valueW = NULL;
1341 IStream *stream;
1343 TRACE("%p, %s, %s, %#lx.\n", hkey, debugstr_a(subkey), debugstr_a(value), mode);
1345 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1346 return NULL;
1347 if (value && FAILED(SHStrDupA(value, &valueW)))
1349 CoTaskMemFree(subkeyW);
1350 return NULL;
1353 stream = SHOpenRegStreamW(hkey, subkeyW, valueW, mode);
1354 CoTaskMemFree(subkeyW);
1355 CoTaskMemFree(valueW);
1356 return stream;
1359 static ULONG WINAPI dummystream_AddRef(IStream *iface)
1361 TRACE("()\n");
1362 return 2;
1365 static ULONG WINAPI dummystream_Release(IStream *iface)
1367 TRACE("()\n");
1368 return 1;
1371 static HRESULT WINAPI dummystream_Read(IStream *iface, void *buff, ULONG buff_size, ULONG *read_len)
1373 if (read_len)
1374 *read_len = 0;
1376 return E_NOTIMPL;
1379 static const IStreamVtbl dummystreamvtbl =
1381 shstream_QueryInterface,
1382 dummystream_AddRef,
1383 dummystream_Release,
1384 dummystream_Read,
1385 memstream_Write,
1386 memstream_Seek,
1387 memstream_SetSize,
1388 shstream_CopyTo,
1389 shstream_Commit,
1390 shstream_Revert,
1391 shstream_LockRegion,
1392 shstream_UnlockRegion,
1393 memstream_Stat,
1394 shstream_Clone,
1397 static struct shstream dummyregstream = { { &dummystreamvtbl } };
1399 /*************************************************************************
1400 * SHOpenRegStreamW [SHCORE.@]
1402 IStream * WINAPI SHOpenRegStreamW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, DWORD mode)
1404 IStream *stream;
1406 TRACE("%p, %s, %s, %#lx.\n", hkey, debugstr_w(subkey), debugstr_w(value), mode);
1407 stream = SHOpenRegStream2W(hkey, subkey, value, mode);
1408 return stream ? stream : &dummyregstream.IStream_iface;
1411 struct threadref
1413 IUnknown IUnknown_iface;
1414 LONG *refcount;
1417 static inline struct threadref *threadref_impl_from_IUnknown(IUnknown *iface)
1419 return CONTAINING_RECORD(iface, struct threadref, IUnknown_iface);
1422 static HRESULT WINAPI threadref_QueryInterface(IUnknown *iface, REFIID riid, void **out)
1424 struct threadref *threadref = threadref_impl_from_IUnknown(iface);
1426 TRACE("(%p, %s, %p)\n", threadref, debugstr_guid(riid), out);
1428 if (out == NULL)
1429 return E_POINTER;
1431 if (IsEqualGUID(&IID_IUnknown, riid))
1433 *out = iface;
1434 IUnknown_AddRef(iface);
1435 return S_OK;
1438 *out = NULL;
1439 WARN("Interface %s not supported.\n", debugstr_guid(riid));
1440 return E_NOINTERFACE;
1443 static ULONG WINAPI threadref_AddRef(IUnknown *iface)
1445 struct threadref *threadref = threadref_impl_from_IUnknown(iface);
1446 LONG refcount = InterlockedIncrement(threadref->refcount);
1448 TRACE("%p, refcount %ld.\n", threadref, refcount);
1450 return refcount;
1453 static ULONG WINAPI threadref_Release(IUnknown *iface)
1455 struct threadref *threadref = threadref_impl_from_IUnknown(iface);
1456 LONG refcount = InterlockedDecrement(threadref->refcount);
1458 TRACE("%p, refcount %ld.\n", threadref, refcount);
1460 if (!refcount)
1461 heap_free(threadref);
1463 return refcount;
1466 static const IUnknownVtbl threadrefvtbl =
1468 threadref_QueryInterface,
1469 threadref_AddRef,
1470 threadref_Release,
1473 /*************************************************************************
1474 * SHCreateThreadRef [SHCORE.@]
1476 HRESULT WINAPI SHCreateThreadRef(LONG *refcount, IUnknown **out)
1478 struct threadref *threadref;
1480 TRACE("(%p, %p)\n", refcount, out);
1482 if (!refcount || !out)
1483 return E_INVALIDARG;
1485 *out = NULL;
1487 threadref = heap_alloc(sizeof(*threadref));
1488 if (!threadref)
1489 return E_OUTOFMEMORY;
1490 threadref->IUnknown_iface.lpVtbl = &threadrefvtbl;
1491 threadref->refcount = refcount;
1493 *refcount = 1;
1494 *out = &threadref->IUnknown_iface;
1496 TRACE("Created %p.\n", threadref);
1497 return S_OK;
1500 /*************************************************************************
1501 * SHGetThreadRef [SHCORE.@]
1503 HRESULT WINAPI SHGetThreadRef(IUnknown **out)
1505 TRACE("(%p)\n", out);
1507 if (shcore_tls == TLS_OUT_OF_INDEXES)
1508 return E_NOINTERFACE;
1510 *out = TlsGetValue(shcore_tls);
1511 if (!*out)
1512 return E_NOINTERFACE;
1514 IUnknown_AddRef(*out);
1515 return S_OK;
1518 /*************************************************************************
1519 * SHSetThreadRef [SHCORE.@]
1521 HRESULT WINAPI SHSetThreadRef(IUnknown *obj)
1523 TRACE("(%p)\n", obj);
1525 if (shcore_tls == TLS_OUT_OF_INDEXES)
1526 return E_NOINTERFACE;
1528 TlsSetValue(shcore_tls, obj);
1529 return S_OK;
1532 /*************************************************************************
1533 * SHReleaseThreadRef [SHCORE.@]
1535 HRESULT WINAPI SHReleaseThreadRef(void)
1537 FIXME("() - stub!\n");
1538 return S_OK;
1541 /*************************************************************************
1542 * GetProcessReference [SHCORE.@]
1544 HRESULT WINAPI GetProcessReference(IUnknown **obj)
1546 TRACE("(%p)\n", obj);
1548 *obj = process_ref;
1550 if (!process_ref)
1551 return E_FAIL;
1553 if (*obj)
1554 IUnknown_AddRef(*obj);
1556 return S_OK;
1559 /*************************************************************************
1560 * SetProcessReference [SHCORE.@]
1562 void WINAPI SetProcessReference(IUnknown *obj)
1564 TRACE("(%p)\n", obj);
1566 process_ref = obj;
1569 struct thread_data
1571 LPTHREAD_START_ROUTINE thread_proc;
1572 LPTHREAD_START_ROUTINE callback;
1573 void *data;
1574 DWORD flags;
1575 HANDLE hEvent;
1576 IUnknown *thread_ref;
1577 IUnknown *process_ref;
1580 static DWORD WINAPI shcore_thread_wrapper(void *data)
1582 struct thread_data thread_data;
1583 HRESULT hr = E_FAIL;
1584 DWORD retval;
1586 TRACE("(%p)\n", data);
1588 /* We are now executing in the context of the newly created thread.
1589 * So we copy the data passed to us (it is on the stack of the function
1590 * that called us, which is waiting for us to signal an event before
1591 * returning). */
1592 thread_data = *(struct thread_data *)data;
1594 if (thread_data.flags & CTF_COINIT)
1596 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
1597 if (FAILED(hr))
1598 hr = CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE);
1601 if (thread_data.callback)
1602 thread_data.callback(thread_data.data);
1604 /* Signal the thread that created us; it can return now. */
1605 SetEvent(thread_data.hEvent);
1607 /* Execute the callers start code. */
1608 retval = thread_data.thread_proc(thread_data.data);
1610 /* Release thread and process references. */
1611 if (thread_data.thread_ref)
1612 IUnknown_Release(thread_data.thread_ref);
1614 if (thread_data.process_ref)
1615 IUnknown_Release(thread_data.process_ref);
1617 if (SUCCEEDED(hr))
1618 CoUninitialize();
1620 return retval;
1623 /*************************************************************************
1624 * SHCreateThread [SHCORE.@]
1626 BOOL WINAPI SHCreateThread(LPTHREAD_START_ROUTINE thread_proc, void *data, DWORD flags, LPTHREAD_START_ROUTINE callback)
1628 struct thread_data thread_data;
1629 BOOL called = FALSE;
1631 TRACE("%p, %p, %#lx, %p.\n", thread_proc, data, flags, callback);
1633 thread_data.thread_proc = thread_proc;
1634 thread_data.callback = callback;
1635 thread_data.data = data;
1636 thread_data.flags = flags;
1637 thread_data.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
1639 if (flags & CTF_THREAD_REF)
1640 SHGetThreadRef(&thread_data.thread_ref);
1641 else
1642 thread_data.thread_ref = NULL;
1644 if (flags & CTF_PROCESS_REF)
1645 GetProcessReference(&thread_data.process_ref);
1646 else
1647 thread_data.process_ref = NULL;
1649 /* Create the thread */
1650 if (thread_data.hEvent)
1652 HANDLE hThread;
1653 DWORD retval;
1655 hThread = CreateThread(NULL, 0, shcore_thread_wrapper, &thread_data, 0, &retval);
1656 if (hThread)
1658 /* Wait for the thread to signal us to continue */
1659 WaitForSingleObject(thread_data.hEvent, INFINITE);
1660 CloseHandle(hThread);
1661 called = TRUE;
1663 CloseHandle(thread_data.hEvent);
1666 if (!called)
1668 if (!thread_data.callback && flags & CTF_INSIST)
1670 /* Couldn't call, call synchronously */
1671 thread_data.thread_proc(data);
1672 called = TRUE;
1674 else
1676 if (thread_data.thread_ref)
1677 IUnknown_Release(thread_data.thread_ref);
1679 if (thread_data.process_ref)
1680 IUnknown_Release(thread_data.process_ref);
1684 return called;
1687 /*************************************************************************
1688 * SHStrDupW [SHCORE.@]
1690 HRESULT WINAPI SHStrDupW(const WCHAR *src, WCHAR **dest)
1692 size_t len;
1694 TRACE("(%s, %p)\n", debugstr_w(src), dest);
1696 *dest = NULL;
1698 if (!src)
1699 return E_INVALIDARG;
1701 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
1702 *dest = CoTaskMemAlloc(len);
1703 if (!*dest)
1704 return E_OUTOFMEMORY;
1706 memcpy(*dest, src, len);
1708 return S_OK;
1711 /*************************************************************************
1712 * SHStrDupA [SHCORE.@]
1714 HRESULT WINAPI SHStrDupA(const char *src, WCHAR **dest)
1716 DWORD len;
1718 *dest = NULL;
1720 if (!src)
1721 return E_INVALIDARG;
1723 len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
1724 *dest = CoTaskMemAlloc(len * sizeof(WCHAR));
1725 if (!*dest)
1726 return E_OUTOFMEMORY;
1728 MultiByteToWideChar(CP_ACP, 0, src, -1, *dest, len);
1730 return S_OK;
1733 /*************************************************************************
1734 * SHAnsiToAnsi [SHCORE.@]
1736 DWORD WINAPI SHAnsiToAnsi(const char *src, char *dest, int dest_len)
1738 DWORD ret;
1740 TRACE("(%s, %p, %d)\n", debugstr_a(src), dest, dest_len);
1742 if (!src || !dest || dest_len <= 0)
1743 return 0;
1745 lstrcpynA(dest, src, dest_len);
1746 ret = strlen(dest);
1748 return src[ret] ? 0 : ret + 1;
1751 /*************************************************************************
1752 * SHUnicodeToAnsi [SHCORE.@]
1754 DWORD WINAPI SHUnicodeToAnsi(const WCHAR *src, char *dest, int dest_len)
1756 int ret = 1;
1758 TRACE("(%s, %p, %d)\n", debugstr_w(src), dest, dest_len);
1760 if (!dest || !dest_len)
1761 return 0;
1763 if (src)
1765 ret = WideCharToMultiByte(CP_ACP, 0, src, -1, dest, dest_len, NULL, NULL);
1766 if (!ret)
1768 dest[dest_len - 1] = 0;
1769 ret = dest_len;
1772 else
1773 dest[0] = 0;
1775 return ret;
1778 /*************************************************************************
1779 * SHUnicodeToUnicode [SHCORE.@]
1781 DWORD WINAPI SHUnicodeToUnicode(const WCHAR *src, WCHAR *dest, int dest_len)
1783 DWORD ret;
1785 TRACE("(%s, %p, %d)\n", debugstr_w(src), dest, dest_len);
1787 if (!src || !dest || dest_len <= 0)
1788 return 0;
1790 lstrcpynW(dest, src, dest_len);
1791 ret = lstrlenW(dest);
1793 return src[ret] ? 0 : ret + 1;
1796 /*************************************************************************
1797 * SHAnsiToUnicode [SHCORE.@]
1799 DWORD WINAPI SHAnsiToUnicode(const char *src, WCHAR *dest, int dest_len)
1801 int ret = 1;
1803 TRACE("(%s, %p, %d)\n", debugstr_a(src), dest, dest_len);
1805 if (!dest || !dest_len)
1806 return 0;
1808 if (src)
1810 ret = MultiByteToWideChar(CP_ACP, 0, src, -1, dest, dest_len);
1811 if (!ret)
1813 dest[dest_len - 1] = 0;
1814 ret = dest_len;
1817 else
1818 dest[0] = 0;
1820 return ret;
1823 /*************************************************************************
1824 * SHRegDuplicateHKey [SHCORE.@]
1826 HKEY WINAPI SHRegDuplicateHKey(HKEY hKey)
1828 HKEY newKey = 0;
1830 RegOpenKeyExW(hKey, 0, 0, MAXIMUM_ALLOWED, &newKey);
1831 TRACE("new key is %p\n", newKey);
1832 return newKey;
1835 /*************************************************************************
1836 * SHDeleteEmptyKeyW [SHCORE.@]
1838 DWORD WINAPI SHDeleteEmptyKeyW(HKEY hkey, const WCHAR *subkey)
1840 DWORD ret, count = 0;
1841 HKEY hsubkey = 0;
1843 TRACE("(%p, %s)\n", hkey, debugstr_w(subkey));
1845 ret = RegOpenKeyExW(hkey, subkey, 0, KEY_READ, &hsubkey);
1846 if (!ret)
1848 ret = RegQueryInfoKeyW(hsubkey, NULL, NULL, NULL, &count,
1849 NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1850 RegCloseKey(hsubkey);
1851 if (!ret)
1853 if (count)
1854 ret = ERROR_KEY_HAS_CHILDREN;
1855 else
1856 ret = RegDeleteKeyW(hkey, subkey);
1860 return ret;
1863 /*************************************************************************
1864 * SHDeleteEmptyKeyA [SHCORE.@]
1866 DWORD WINAPI SHDeleteEmptyKeyA(HKEY hkey, const char *subkey)
1868 WCHAR *subkeyW = NULL;
1869 DWORD ret;
1871 TRACE("(%p, %s)\n", hkey, debugstr_a(subkey));
1873 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1874 return ERROR_OUTOFMEMORY;
1876 ret = SHDeleteEmptyKeyW(hkey, subkeyW);
1877 CoTaskMemFree(subkeyW);
1878 return ret;
1881 /*************************************************************************
1882 * SHDeleteKeyW [SHCORE.@]
1884 DWORD WINAPI SHDeleteKeyW(HKEY hkey, const WCHAR *subkey)
1886 TRACE("(%p, %s)\n", hkey, debugstr_w(subkey));
1888 return RegDeleteTreeW(hkey, subkey);
1891 /*************************************************************************
1892 * SHDeleteKeyA [SHCORE.@]
1894 DWORD WINAPI SHDeleteKeyA(HKEY hkey, const char *subkey)
1896 TRACE("(%p, %s)\n", hkey, debugstr_a(subkey));
1898 return RegDeleteTreeA(hkey, subkey);
1901 /*************************************************************************
1902 * SHDeleteValueW [SHCORE.@]
1904 DWORD WINAPI SHDeleteValueW(HKEY hkey, const WCHAR *subkey, const WCHAR *value)
1906 HKEY hsubkey;
1907 DWORD ret;
1909 TRACE("(%p, %s, %s)\n", hkey, debugstr_w(subkey), debugstr_w(value));
1911 ret = RegOpenKeyExW(hkey, subkey, 0, KEY_SET_VALUE, &hsubkey);
1912 if (!ret)
1914 ret = RegDeleteValueW(hsubkey, value);
1915 RegCloseKey(hsubkey);
1918 return ret;
1921 /*************************************************************************
1922 * SHDeleteValueA [SHCORE.@]
1924 DWORD WINAPI SHDeleteValueA(HKEY hkey, const char *subkey, const char *value)
1926 WCHAR *subkeyW = NULL, *valueW = NULL;
1927 DWORD ret;
1929 TRACE("(%p, %s, %s)\n", hkey, debugstr_a(subkey), debugstr_a(value));
1931 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1932 return ERROR_OUTOFMEMORY;
1933 if (value && FAILED(SHStrDupA(value, &valueW)))
1935 CoTaskMemFree(subkeyW);
1936 return ERROR_OUTOFMEMORY;
1939 ret = SHDeleteValueW(hkey, subkeyW, valueW);
1940 CoTaskMemFree(subkeyW);
1941 CoTaskMemFree(valueW);
1942 return ret;
1945 /*************************************************************************
1946 * SHCopyKeyA [SHCORE.@]
1948 DWORD WINAPI SHCopyKeyA(HKEY hkey_src, const char *subkey, HKEY hkey_dst, DWORD reserved)
1950 WCHAR *subkeyW = NULL;
1951 DWORD ret;
1953 TRACE("%p, %s, %p, %ld.\n", hkey_src, debugstr_a(subkey), hkey_dst, reserved);
1955 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1956 return 0;
1958 ret = SHCopyKeyW(hkey_src, subkeyW, hkey_dst, reserved);
1959 CoTaskMemFree(subkeyW);
1960 return ret;
1963 /*************************************************************************
1964 * SHCopyKeyW [SHCORE.@]
1966 DWORD WINAPI SHCopyKeyW(HKEY hkey_src, const WCHAR *subkey, HKEY hkey_dst, DWORD reserved)
1968 DWORD key_count = 0, value_count = 0, max_key_len = 0;
1969 WCHAR name[MAX_PATH], *ptr_name = name;
1970 BYTE buff[1024], *ptr = buff;
1971 DWORD max_data_len = 0, i;
1972 DWORD ret = 0;
1974 TRACE("%p, %s, %p, %ld.\n", hkey_src, debugstr_w(subkey), hkey_dst, reserved);
1976 if (!hkey_dst || !hkey_src)
1977 return ERROR_INVALID_PARAMETER;
1979 if (subkey)
1980 ret = RegOpenKeyExW(hkey_src, subkey, 0, KEY_ALL_ACCESS, &hkey_src);
1982 if (ret)
1983 hkey_src = NULL; /* Don't close this key since we didn't open it */
1984 else
1986 DWORD max_value_len;
1988 ret = RegQueryInfoKeyW(hkey_src, NULL, NULL, NULL, &key_count, &max_key_len,
1989 NULL, &value_count, &max_value_len, &max_data_len, NULL, NULL);
1990 if (!ret)
1992 /* Get max size for key/value names */
1993 max_key_len = max(max_key_len, max_value_len);
1995 if (max_key_len++ > MAX_PATH - 1)
1996 ptr_name = heap_alloc(max_key_len * sizeof(WCHAR));
1998 if (max_data_len > sizeof(buff))
1999 ptr = heap_alloc(max_data_len);
2001 if (!ptr_name || !ptr)
2002 ret = ERROR_NOT_ENOUGH_MEMORY;
2006 for (i = 0; i < key_count && !ret; i++)
2008 HKEY hsubkey_src, hsubkey_dst;
2009 DWORD length = max_key_len;
2011 ret = RegEnumKeyExW(hkey_src, i, ptr_name, &length, NULL, NULL, NULL, NULL);
2012 if (!ret)
2014 ret = RegOpenKeyExW(hkey_src, ptr_name, 0, KEY_READ, &hsubkey_src);
2015 if (!ret)
2017 /* Create destination sub key */
2018 ret = RegCreateKeyW(hkey_dst, ptr_name, &hsubkey_dst);
2019 if (!ret)
2021 /* Recursively copy keys and values from the sub key */
2022 ret = SHCopyKeyW(hsubkey_src, NULL, hsubkey_dst, 0);
2023 RegCloseKey(hsubkey_dst);
2026 RegCloseKey(hsubkey_src);
2030 /* Copy all the values in this key */
2031 for (i = 0; i < value_count && !ret; i++)
2033 DWORD length = max_key_len, type, data_len = max_data_len;
2035 ret = RegEnumValueW(hkey_src, i, ptr_name, &length, NULL, &type, ptr, &data_len);
2036 if (!ret) {
2037 ret = SHSetValueW(hkey_dst, NULL, ptr_name, type, ptr, data_len);
2041 /* Free buffers if allocated */
2042 if (ptr_name != name)
2043 heap_free(ptr_name);
2044 if (ptr != buff)
2045 heap_free(ptr);
2047 if (subkey && hkey_src)
2048 RegCloseKey(hkey_src);
2050 return ret;
2054 /*************************************************************************
2055 * SHEnumKeyExA [SHCORE.@]
2057 LONG WINAPI SHEnumKeyExA(HKEY hkey, DWORD index, char *subkey, DWORD *length)
2059 TRACE("%p, %ld, %s, %p.\n", hkey, index, debugstr_a(subkey), length);
2061 return RegEnumKeyExA(hkey, index, subkey, length, NULL, NULL, NULL, NULL);
2064 /*************************************************************************
2065 * SHEnumKeyExW [SHCORE.@]
2067 LONG WINAPI SHEnumKeyExW(HKEY hkey, DWORD index, WCHAR *subkey, DWORD *length)
2069 TRACE("%p, %ld, %s, %p.\n", hkey, index, debugstr_w(subkey), length);
2071 return RegEnumKeyExW(hkey, index, subkey, length, NULL, NULL, NULL, NULL);
2074 /*************************************************************************
2075 * SHEnumValueA [SHCORE.@]
2077 LONG WINAPI SHEnumValueA(HKEY hkey, DWORD index, char *value, DWORD *length, DWORD *type,
2078 void *data, DWORD *data_len)
2080 TRACE("%p, %ld, %s, %p, %p, %p, %p.\n", hkey, index, debugstr_a(value), length, type, data, data_len);
2082 return RegEnumValueA(hkey, index, value, length, NULL, type, data, data_len);
2085 /*************************************************************************
2086 * SHEnumValueW [SHCORE.@]
2088 LONG WINAPI SHEnumValueW(HKEY hkey, DWORD index, WCHAR *value, DWORD *length, DWORD *type,
2089 void *data, DWORD *data_len)
2091 TRACE("%p, %ld, %s, %p, %p, %p, %p.\n", hkey, index, debugstr_w(value), length, type, data, data_len);
2093 return RegEnumValueW(hkey, index, value, length, NULL, type, data, data_len);
2096 /*************************************************************************
2097 * SHQueryValueExW [SHCORE.@]
2099 DWORD WINAPI SHQueryValueExW(HKEY hkey, const WCHAR *name, DWORD *reserved, DWORD *type,
2100 void *buff, DWORD *buff_len)
2102 DWORD ret, value_type, data_len = 0;
2104 TRACE("(%p, %s, %p, %p, %p, %p)\n", hkey, debugstr_w(name), reserved, type, buff, buff_len);
2106 if (buff_len)
2107 data_len = *buff_len;
2109 ret = RegQueryValueExW(hkey, name, reserved, &value_type, buff, &data_len);
2110 if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)
2111 return ret;
2113 if (buff_len && value_type == REG_EXPAND_SZ)
2115 DWORD length;
2116 WCHAR *value;
2118 if (!buff || ret == ERROR_MORE_DATA)
2120 length = data_len;
2121 value = heap_alloc(length);
2122 RegQueryValueExW(hkey, name, reserved, NULL, (BYTE *)value, &length);
2123 length = ExpandEnvironmentStringsW(value, NULL, 0);
2125 else
2127 length = (lstrlenW(buff) + 1) * sizeof(WCHAR);
2128 value = heap_alloc(length);
2129 memcpy(value, buff, length);
2130 length = ExpandEnvironmentStringsW(value, buff, *buff_len / sizeof(WCHAR));
2131 if (length > *buff_len) ret = ERROR_MORE_DATA;
2133 data_len = max(data_len, length);
2134 heap_free(value);
2137 if (type)
2138 *type = value_type == REG_EXPAND_SZ ? REG_SZ : value_type;
2139 if (buff_len)
2140 *buff_len = data_len;
2141 return ret;
2144 /*************************************************************************
2145 * SHQueryValueExA [SHCORE.@]
2147 DWORD WINAPI SHQueryValueExA(HKEY hkey, const char *name, DWORD *reserved, DWORD *type,
2148 void *buff, DWORD *buff_len)
2150 DWORD ret, value_type, data_len = 0;
2152 TRACE("(%p, %s, %p, %p, %p, %p)\n", hkey, debugstr_a(name), reserved, type, buff, buff_len);
2154 if (buff_len)
2155 data_len = *buff_len;
2157 ret = RegQueryValueExA(hkey, name, reserved, &value_type, buff, &data_len);
2158 if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)
2159 return ret;
2161 if (buff_len && value_type == REG_EXPAND_SZ)
2163 DWORD length;
2164 char *value;
2166 if (!buff || ret == ERROR_MORE_DATA)
2168 length = data_len;
2169 value = heap_alloc(length);
2170 RegQueryValueExA(hkey, name, reserved, NULL, (BYTE *)value, &length);
2171 length = ExpandEnvironmentStringsA(value, NULL, 0);
2173 else
2175 length = strlen(buff) + 1;
2176 value = heap_alloc(length);
2177 memcpy(value, buff, length);
2178 length = ExpandEnvironmentStringsA(value, buff, *buff_len);
2179 if (length > *buff_len) ret = ERROR_MORE_DATA;
2181 data_len = max(data_len, length);
2182 heap_free(value);
2185 if (type)
2186 *type = value_type == REG_EXPAND_SZ ? REG_SZ : value_type;
2187 if (buff_len)
2188 *buff_len = data_len;
2189 return ret;
2192 /*************************************************************************
2193 * SHGetValueA [SHCORE.@]
2195 DWORD WINAPI SHGetValueA(HKEY hkey, const char *subkey, const char *value,
2196 DWORD *type, void *data, DWORD *data_len)
2198 HKEY hsubkey = 0;
2199 DWORD ret = 0;
2201 TRACE("(%p, %s, %s, %p, %p, %p)\n", hkey, debugstr_a(subkey), debugstr_a(value),
2202 type, data, data_len);
2204 if (subkey)
2205 ret = RegOpenKeyExA(hkey, subkey, 0, KEY_QUERY_VALUE, &hsubkey);
2207 if (!ret)
2209 ret = SHQueryValueExA(hsubkey ? hsubkey : hkey, value, 0, type, data, data_len);
2210 if (subkey)
2211 RegCloseKey(hsubkey);
2214 return ret;
2217 /*************************************************************************
2218 * SHGetValueW [SHCORE.@]
2220 DWORD WINAPI SHGetValueW(HKEY hkey, const WCHAR *subkey, const WCHAR *value,
2221 DWORD *type, void *data, DWORD *data_len)
2223 HKEY hsubkey = 0;
2224 DWORD ret = 0;
2226 TRACE("(%p, %s, %s, %p, %p, %p)\n", hkey, debugstr_w(subkey), debugstr_w(value),
2227 type, data, data_len);
2229 if (subkey)
2230 ret = RegOpenKeyExW(hkey, subkey, 0, KEY_QUERY_VALUE, &hsubkey);
2232 if (!ret)
2234 ret = SHQueryValueExW(hsubkey ? hsubkey : hkey, value, 0, type, data, data_len);
2235 if (subkey)
2236 RegCloseKey(hsubkey);
2239 return ret;
2242 /*************************************************************************
2243 * SHRegGetIntW [SHCORE.280]
2245 int WINAPI SHRegGetIntW(HKEY hkey, const WCHAR *value, int default_value)
2247 WCHAR buff[32];
2248 DWORD buff_len;
2250 TRACE("(%p, %s, %d)\n", hkey, debugstr_w(value), default_value);
2252 buff[0] = 0;
2253 buff_len = sizeof(buff);
2254 if (SHQueryValueExW(hkey, value, 0, 0, buff, &buff_len))
2255 return default_value;
2257 if (*buff >= '0' && *buff <= '9')
2258 return wcstol(buff, NULL, 10);
2260 return default_value;
2263 /*************************************************************************
2264 * SHRegGetPathA [SHCORE.@]
2266 DWORD WINAPI SHRegGetPathA(HKEY hkey, const char *subkey, const char *value, char *path, DWORD flags)
2268 DWORD length = MAX_PATH;
2270 TRACE("%p, %s, %s, %p, %#lx.\n", hkey, debugstr_a(subkey), debugstr_a(value), path, flags);
2272 return SHGetValueA(hkey, subkey, value, 0, path, &length);
2275 /*************************************************************************
2276 * SHRegGetPathW [SHCORE.@]
2278 DWORD WINAPI SHRegGetPathW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, WCHAR *path, DWORD flags)
2280 DWORD length = MAX_PATH;
2282 TRACE("%p, %s, %s, %p, %#lx.\n", hkey, debugstr_w(subkey), debugstr_w(value), path, flags);
2284 return SHGetValueW(hkey, subkey, value, 0, path, &length);
2287 /*************************************************************************
2288 * SHSetValueW [SHCORE.@]
2290 DWORD WINAPI SHSetValueW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, DWORD type,
2291 const void *data, DWORD data_len)
2293 DWORD ret = ERROR_SUCCESS, dummy;
2294 HKEY hsubkey;
2296 TRACE("%p, %s, %s, %ld, %p, %ld.\n", hkey, debugstr_w(subkey), debugstr_w(value),
2297 type, data, data_len);
2299 if (subkey && *subkey)
2300 ret = RegCreateKeyExW(hkey, subkey, 0, NULL, 0, KEY_SET_VALUE, NULL, &hsubkey, &dummy);
2301 else
2302 hsubkey = hkey;
2304 if (!ret)
2306 ret = RegSetValueExW(hsubkey, value, 0, type, data, data_len);
2307 if (hsubkey != hkey)
2308 RegCloseKey(hsubkey);
2311 return ret;
2314 /*************************************************************************
2315 * SHSetValueA [SHCORE.@]
2317 DWORD WINAPI SHSetValueA(HKEY hkey, const char *subkey, const char *value,
2318 DWORD type, const void *data, DWORD data_len)
2320 DWORD ret = ERROR_SUCCESS, dummy;
2321 HKEY hsubkey;
2323 TRACE("%p, %s, %s, %ld, %p, %ld.\n", hkey, debugstr_a(subkey), debugstr_a(value),
2324 type, data, data_len);
2326 if (subkey && *subkey)
2327 ret = RegCreateKeyExA(hkey, subkey, 0, NULL, 0, KEY_SET_VALUE, NULL, &hsubkey, &dummy);
2328 else
2329 hsubkey = hkey;
2331 if (!ret)
2333 ret = RegSetValueExA(hsubkey, value, 0, type, data, data_len);
2334 if (hsubkey != hkey)
2335 RegCloseKey(hsubkey);
2338 return ret;
2341 /*************************************************************************
2342 * SHRegSetPathA [SHCORE.@]
2344 DWORD WINAPI SHRegSetPathA(HKEY hkey, const char *subkey, const char *value, const char *path, DWORD flags)
2346 FIXME("%p, %s, %s, %s, %#lx - semi-stub\n", hkey, debugstr_a(subkey),
2347 debugstr_a(value), debugstr_a(path), flags);
2349 /* FIXME: PathUnExpandEnvStringsA() */
2351 return SHSetValueA(hkey, subkey, value, REG_SZ, path, lstrlenA(path));
2354 /*************************************************************************
2355 * SHRegSetPathW [SHCORE.@]
2357 DWORD WINAPI SHRegSetPathW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, const WCHAR *path, DWORD flags)
2359 FIXME("%p, %s, %s, %s, %#lx semi-stub\n", hkey, debugstr_w(subkey),
2360 debugstr_w(value), debugstr_w(path), flags);
2362 /* FIXME: PathUnExpandEnvStringsW(); */
2364 return SHSetValueW(hkey, subkey, value, REG_SZ, path, lstrlenW(path));
2367 /*************************************************************************
2368 * SHQueryInfoKeyA [SHCORE.@]
2370 LONG WINAPI SHQueryInfoKeyA(HKEY hkey, DWORD *subkeys, DWORD *subkey_max, DWORD *values, DWORD *value_max)
2372 TRACE("(%p, %p, %p, %p, %p)\n", hkey, subkeys, subkey_max, values, value_max);
2374 return RegQueryInfoKeyA(hkey, NULL, NULL, NULL, subkeys, subkey_max, NULL, values, value_max, NULL, NULL, NULL);
2377 /*************************************************************************
2378 * SHQueryInfoKeyW [SHCORE.@]
2380 LONG WINAPI SHQueryInfoKeyW(HKEY hkey, DWORD *subkeys, DWORD *subkey_max, DWORD *values, DWORD *value_max)
2382 TRACE("(%p, %p, %p, %p, %p)\n", hkey, subkeys, subkey_max, values, value_max);
2384 return RegQueryInfoKeyW(hkey, NULL, NULL, NULL, subkeys, subkey_max, NULL, values, value_max, NULL, NULL, NULL);
2387 /*************************************************************************
2388 * IsOS [SHCORE.@]
2390 BOOL WINAPI IsOS(DWORD feature)
2392 DWORD platform, majorv, minorv;
2393 OSVERSIONINFOA osvi;
2395 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
2396 if (!GetVersionExA(&osvi))
2397 return FALSE;
2399 majorv = osvi.dwMajorVersion;
2400 minorv = osvi.dwMinorVersion;
2401 platform = osvi.dwPlatformId;
2403 #define ISOS_RETURN(x) \
2404 TRACE("(%#lx) ret %d\n",feature,(x)); \
2405 return (x)
2407 switch(feature) {
2408 case OS_WIN32SORGREATER:
2409 ISOS_RETURN(platform == VER_PLATFORM_WIN32s
2410 || platform == VER_PLATFORM_WIN32_WINDOWS);
2411 case OS_NT:
2412 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2413 case OS_WIN95ORGREATER:
2414 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS);
2415 case OS_NT4ORGREATER:
2416 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 4);
2417 case OS_WIN2000ORGREATER_ALT:
2418 case OS_WIN2000ORGREATER:
2419 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5);
2420 case OS_WIN98ORGREATER:
2421 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 10);
2422 case OS_WIN98_GOLD:
2423 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 10);
2424 case OS_WIN2000PRO:
2425 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5);
2426 case OS_WIN2000SERVER:
2427 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2428 case OS_WIN2000ADVSERVER:
2429 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2430 case OS_WIN2000DATACENTER:
2431 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2432 case OS_WIN2000TERMINAL:
2433 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2434 case OS_EMBEDDED:
2435 FIXME("(OS_EMBEDDED) What should we return here?\n");
2436 return FALSE;
2437 case OS_TERMINALCLIENT:
2438 FIXME("(OS_TERMINALCLIENT) What should we return here?\n");
2439 return FALSE;
2440 case OS_TERMINALREMOTEADMIN:
2441 FIXME("(OS_TERMINALREMOTEADMIN) What should we return here?\n");
2442 return FALSE;
2443 case OS_WIN95_GOLD:
2444 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 0);
2445 case OS_MEORGREATER:
2446 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 90);
2447 case OS_XPORGREATER:
2448 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1);
2449 case OS_HOME:
2450 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1);
2451 case OS_PROFESSIONAL:
2452 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2453 case OS_DATACENTER:
2454 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2455 case OS_ADVSERVER:
2456 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5);
2457 case OS_SERVER:
2458 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2459 case OS_TERMINALSERVER:
2460 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2461 case OS_PERSONALTERMINALSERVER:
2462 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && minorv >= 1 && majorv >= 5);
2463 case OS_FASTUSERSWITCHING:
2464 FIXME("(OS_FASTUSERSWITCHING) What should we return here?\n");
2465 return TRUE;
2466 case OS_WELCOMELOGONUI:
2467 FIXME("(OS_WELCOMELOGONUI) What should we return here?\n");
2468 return FALSE;
2469 case OS_DOMAINMEMBER:
2470 FIXME("(OS_DOMAINMEMBER) What should we return here?\n");
2471 return TRUE;
2472 case OS_ANYSERVER:
2473 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2474 case OS_WOW6432:
2476 BOOL is_wow64;
2477 IsWow64Process(GetCurrentProcess(), &is_wow64);
2478 return is_wow64;
2480 case OS_WEBSERVER:
2481 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2482 case OS_SMALLBUSINESSSERVER:
2483 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2484 case OS_TABLETPC:
2485 FIXME("(OS_TABLETPC) What should we return here?\n");
2486 return FALSE;
2487 case OS_SERVERADMINUI:
2488 FIXME("(OS_SERVERADMINUI) What should we return here?\n");
2489 return FALSE;
2490 case OS_MEDIACENTER:
2491 FIXME("(OS_MEDIACENTER) What should we return here?\n");
2492 return FALSE;
2493 case OS_APPLIANCE:
2494 FIXME("(OS_APPLIANCE) What should we return here?\n");
2495 return FALSE;
2496 case 0x25: /*OS_VISTAORGREATER*/
2497 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 6);
2500 #undef ISOS_RETURN
2502 WARN("(%#lx) unknown parameter\n", feature);
2504 return FALSE;
2507 /*************************************************************************
2508 * SubscribeFeatureStateChangeNotification [SHCORE.@]
2510 void WINAPI SubscribeFeatureStateChangeNotification(FEATURE_STATE_CHANGE_SUBSCRIPTION *subscription,
2511 FEATURE_STATE_CHANGE_CALLBACK *callback, void *context)
2513 FIXME("(%p, %p, %p) stub\n", subscription, callback, context);
2516 /*************************************************************************
2517 * GetFeatureEnabledState [SHCORE.@]
2519 FEATURE_ENABLED_STATE WINAPI GetFeatureEnabledState(UINT32 feature, FEATURE_CHANGE_TIME change_time)
2521 FIXME("(%u, %u) stub\n", feature, change_time);
2522 return FEATURE_ENABLED_STATE_DEFAULT;