makefiles: Install PE files in an architecture-specific directory.
[wine.git] / dlls / shcore / main.c
blob82b236bb47d42540eb54de3d3636375dfc4ab216
1 /*
2 * Copyright 2002 Jon Griffiths
3 * Copyright 2016 Sebastian Lackner
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <stdarg.h>
22 #define COBJMACROS
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "initguid.h"
29 #include "ocidl.h"
30 #include "shellscalingapi.h"
31 #include "shlwapi.h"
33 #include "wine/debug.h"
34 #include "wine/heap.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(shcore);
38 static DWORD shcore_tls;
39 static IUnknown *process_ref;
41 BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved)
43 TRACE("(%p, %u, %p)\n", instance, reason, reserved);
45 switch (reason)
47 case DLL_PROCESS_ATTACH:
48 DisableThreadLibraryCalls(instance);
49 shcore_tls = TlsAlloc();
50 break;
51 case DLL_PROCESS_DETACH:
52 if (reserved) break;
53 if (shcore_tls != TLS_OUT_OF_INDEXES)
54 TlsFree(shcore_tls);
55 break;
58 return TRUE;
61 HRESULT WINAPI GetProcessDpiAwareness(HANDLE process, PROCESS_DPI_AWARENESS *value)
63 if (GetProcessDpiAwarenessInternal( process, (DPI_AWARENESS *)value )) return S_OK;
64 return HRESULT_FROM_WIN32( GetLastError() );
67 HRESULT WINAPI SetProcessDpiAwareness(PROCESS_DPI_AWARENESS value)
69 if (SetProcessDpiAwarenessInternal( value )) return S_OK;
70 return HRESULT_FROM_WIN32( GetLastError() );
73 HRESULT WINAPI GetDpiForMonitor(HMONITOR monitor, MONITOR_DPI_TYPE type, UINT *x, UINT *y)
75 if (GetDpiForMonitorInternal( monitor, type, x, y )) return S_OK;
76 return HRESULT_FROM_WIN32( GetLastError() );
79 HRESULT WINAPI GetScaleFactorForMonitor(HMONITOR monitor, DEVICE_SCALE_FACTOR *scale)
81 FIXME("(%p %p): stub\n", monitor, scale);
83 *scale = SCALE_100_PERCENT;
84 return S_OK;
87 DEVICE_SCALE_FACTOR WINAPI GetScaleFactorForDevice(DISPLAY_DEVICE_TYPE device_type)
89 FIXME("%d\n", device_type);
91 return SCALE_100_PERCENT;
94 HRESULT WINAPI _IStream_Read(IStream *stream, void *dest, ULONG size)
96 ULONG read;
97 HRESULT hr;
99 TRACE("(%p, %p, %u)\n", stream, dest, size);
101 hr = IStream_Read(stream, dest, size, &read);
102 if (SUCCEEDED(hr) && read != size)
103 hr = E_FAIL;
104 return hr;
107 HRESULT WINAPI IStream_Reset(IStream *stream)
109 static const LARGE_INTEGER zero;
111 TRACE("(%p)\n", stream);
113 return IStream_Seek(stream, zero, 0, NULL);
116 HRESULT WINAPI IStream_Size(IStream *stream, ULARGE_INTEGER *size)
118 STATSTG statstg;
119 HRESULT hr;
121 TRACE("(%p, %p)\n", stream, size);
123 memset(&statstg, 0, sizeof(statstg));
125 hr = IStream_Stat(stream, &statstg, STATFLAG_NONAME);
127 if (SUCCEEDED(hr) && size)
128 *size = statstg.cbSize;
129 return hr;
132 HRESULT WINAPI _IStream_Write(IStream *stream, const void *src, ULONG size)
134 ULONG written;
135 HRESULT hr;
137 TRACE("(%p, %p, %u)\n", stream, src, size);
139 hr = IStream_Write(stream, src, size, &written);
140 if (SUCCEEDED(hr) && written != size)
141 hr = E_FAIL;
143 return hr;
146 void WINAPI IUnknown_AtomicRelease(IUnknown **obj)
148 TRACE("(%p)\n", obj);
150 if (!obj || !*obj)
151 return;
153 IUnknown_Release(*obj);
154 *obj = NULL;
157 HRESULT WINAPI IUnknown_GetSite(IUnknown *unk, REFIID iid, void **site)
159 IObjectWithSite *obj = NULL;
160 HRESULT hr = E_INVALIDARG;
162 TRACE("(%p, %s, %p)\n", unk, debugstr_guid(iid), site);
164 if (unk && iid && site)
166 hr = IUnknown_QueryInterface(unk, &IID_IObjectWithSite, (void **)&obj);
167 if (SUCCEEDED(hr) && obj)
169 hr = IObjectWithSite_GetSite(obj, iid, site);
170 IObjectWithSite_Release(obj);
174 return hr;
177 HRESULT WINAPI IUnknown_QueryService(IUnknown *obj, REFGUID sid, REFIID iid, void **out)
179 IServiceProvider *provider = NULL;
180 HRESULT hr;
182 if (!out)
183 return E_FAIL;
185 *out = NULL;
187 if (!obj)
188 return E_FAIL;
190 hr = IUnknown_QueryInterface(obj, &IID_IServiceProvider, (void **)&provider);
191 if (hr == S_OK && provider)
193 TRACE("Using provider %p.\n", provider);
195 hr = IServiceProvider_QueryService(provider, sid, iid, out);
197 TRACE("Provider %p returned %p.\n", provider, *out);
199 IServiceProvider_Release(provider);
202 return hr;
205 void WINAPI IUnknown_Set(IUnknown **dest, IUnknown *src)
207 TRACE("(%p, %p)\n", dest, src);
209 IUnknown_AtomicRelease(dest);
211 if (src)
213 IUnknown_AddRef(src);
214 *dest = src;
218 HRESULT WINAPI IUnknown_SetSite(IUnknown *obj, IUnknown *site)
220 IInternetSecurityManager *sec_manager;
221 IObjectWithSite *objwithsite;
222 HRESULT hr;
224 if (!obj)
225 return E_FAIL;
227 hr = IUnknown_QueryInterface(obj, &IID_IObjectWithSite, (void **)&objwithsite);
228 TRACE("ObjectWithSite %p, hr %#x.\n", objwithsite, hr);
229 if (SUCCEEDED(hr))
231 hr = IObjectWithSite_SetSite(objwithsite, site);
232 TRACE("SetSite() hr %#x.\n", hr);
233 IObjectWithSite_Release(objwithsite);
235 else
237 hr = IUnknown_QueryInterface(obj, &IID_IInternetSecurityManager, (void **)&sec_manager);
238 TRACE("InternetSecurityManager %p, hr %#x.\n", sec_manager, hr);
239 if (FAILED(hr))
240 return hr;
242 hr = IInternetSecurityManager_SetSecuritySite(sec_manager, (IInternetSecurityMgrSite *)site);
243 TRACE("SetSecuritySite() hr %#x.\n", hr);
244 IInternetSecurityManager_Release(sec_manager);
247 return hr;
250 HRESULT WINAPI SetCurrentProcessExplicitAppUserModelID(const WCHAR *appid)
252 FIXME("%s: stub\n", debugstr_w(appid));
253 return S_OK;
256 HRESULT WINAPI GetCurrentProcessExplicitAppUserModelID(const WCHAR **appid)
258 FIXME("%p: stub\n", appid);
259 *appid = NULL;
260 return E_NOTIMPL;
263 /*************************************************************************
264 * CommandLineToArgvW [SHCORE.@]
266 * We must interpret the quotes in the command line to rebuild the argv
267 * array correctly:
268 * - arguments are separated by spaces or tabs
269 * - quotes serve as optional argument delimiters
270 * '"a b"' -> 'a b'
271 * - escaped quotes must be converted back to '"'
272 * '\"' -> '"'
273 * - consecutive backslashes preceding a quote see their number halved with
274 * the remainder escaping the quote:
275 * 2n backslashes + quote -> n backslashes + quote as an argument delimiter
276 * 2n+1 backslashes + quote -> n backslashes + literal quote
277 * - backslashes that are not followed by a quote are copied literally:
278 * 'a\b' -> 'a\b'
279 * 'a\\b' -> 'a\\b'
280 * - in quoted strings, consecutive quotes see their number divided by three
281 * with the remainder modulo 3 deciding whether to close the string or not.
282 * Note that the opening quote must be counted in the consecutive quotes,
283 * that's the (1+) below:
284 * (1+) 3n quotes -> n quotes
285 * (1+) 3n+1 quotes -> n quotes plus closes the quoted string
286 * (1+) 3n+2 quotes -> n+1 quotes plus closes the quoted string
287 * - in unquoted strings, the first quote opens the quoted string and the
288 * remaining consecutive quotes follow the above rule.
290 WCHAR** WINAPI CommandLineToArgvW(const WCHAR *cmdline, int *numargs)
292 int qcount, bcount;
293 const WCHAR *s;
294 WCHAR **argv;
295 DWORD argc;
296 WCHAR *d;
298 if (!numargs)
300 SetLastError(ERROR_INVALID_PARAMETER);
301 return NULL;
304 if (*cmdline == 0)
306 /* Return the path to the executable */
307 DWORD len, deslen = MAX_PATH, size;
309 size = sizeof(WCHAR *) * 2 + deslen * sizeof(WCHAR);
310 for (;;)
312 if (!(argv = LocalAlloc(LMEM_FIXED, size))) return NULL;
313 len = GetModuleFileNameW(0, (WCHAR *)(argv + 2), deslen);
314 if (!len)
316 LocalFree(argv);
317 return NULL;
319 if (len < deslen) break;
320 deslen *= 2;
321 size = sizeof(WCHAR *) * 2 + deslen * sizeof(WCHAR);
322 LocalFree(argv);
324 argv[0] = (WCHAR *)(argv + 2);
325 argv[1] = NULL;
326 *numargs = 1;
328 return argv;
331 /* --- First count the arguments */
332 argc = 1;
333 s = cmdline;
334 /* The first argument, the executable path, follows special rules */
335 if (*s == '"')
337 /* The executable path ends at the next quote, no matter what */
338 s++;
339 while (*s)
340 if (*s++ == '"')
341 break;
343 else
345 /* The executable path ends at the next space, no matter what */
346 while (*s && *s != ' ' && *s != '\t')
347 s++;
349 /* skip to the first argument, if any */
350 while (*s == ' ' || *s == '\t')
351 s++;
352 if (*s)
353 argc++;
355 /* Analyze the remaining arguments */
356 qcount = bcount = 0;
357 while (*s)
359 if ((*s == ' ' || *s == '\t') && qcount == 0)
361 /* skip to the next argument and count it if any */
362 while (*s == ' ' || *s == '\t')
363 s++;
364 if (*s)
365 argc++;
366 bcount = 0;
368 else if (*s == '\\')
370 /* '\', count them */
371 bcount++;
372 s++;
374 else if (*s == '"')
376 /* '"' */
377 if ((bcount & 1) == 0)
378 qcount++; /* unescaped '"' */
379 s++;
380 bcount = 0;
381 /* consecutive quotes, see comment in copying code below */
382 while (*s == '"')
384 qcount++;
385 s++;
387 qcount = qcount % 3;
388 if (qcount == 2)
389 qcount = 0;
391 else
393 /* a regular character */
394 bcount = 0;
395 s++;
399 /* Allocate in a single lump, the string array, and the strings that go
400 * with it. This way the caller can make a single LocalFree() call to free
401 * both, as per MSDN.
403 argv = LocalAlloc(LMEM_FIXED, (argc + 1) * sizeof(WCHAR *) + (lstrlenW(cmdline) + 1) * sizeof(WCHAR));
404 if (!argv)
405 return NULL;
407 /* --- Then split and copy the arguments */
408 argv[0] = d = lstrcpyW((WCHAR *)(argv + argc + 1), cmdline);
409 argc = 1;
410 /* The first argument, the executable path, follows special rules */
411 if (*d == '"')
413 /* The executable path ends at the next quote, no matter what */
414 s = d + 1;
415 while (*s)
417 if (*s == '"')
419 s++;
420 break;
422 *d++ = *s++;
425 else
427 /* The executable path ends at the next space, no matter what */
428 while (*d && *d != ' ' && *d != '\t')
429 d++;
430 s = d;
431 if (*s)
432 s++;
434 /* close the executable path */
435 *d++ = 0;
436 /* skip to the first argument and initialize it if any */
437 while (*s == ' ' || *s == '\t')
438 s++;
439 if (!*s)
441 /* There are no parameters so we are all done */
442 argv[argc] = NULL;
443 *numargs = argc;
444 return argv;
447 /* Split and copy the remaining arguments */
448 argv[argc++] = d;
449 qcount = bcount = 0;
450 while (*s)
452 if ((*s == ' ' || *s == '\t') && qcount == 0)
454 /* close the argument */
455 *d++ = 0;
456 bcount = 0;
458 /* skip to the next one and initialize it if any */
459 do {
460 s++;
461 } while (*s == ' ' || *s == '\t');
462 if (*s)
463 argv[argc++] = d;
465 else if (*s=='\\')
467 *d++ = *s++;
468 bcount++;
470 else if (*s == '"')
472 if ((bcount & 1) == 0)
474 /* Preceded by an even number of '\', this is half that
475 * number of '\', plus a quote which we erase.
477 d -= bcount / 2;
478 qcount++;
480 else
482 /* Preceded by an odd number of '\', this is half that
483 * number of '\' followed by a '"'
485 d = d - bcount / 2 - 1;
486 *d++ = '"';
488 s++;
489 bcount = 0;
490 /* Now count the number of consecutive quotes. Note that qcount
491 * already takes into account the opening quote if any, as well as
492 * the quote that lead us here.
494 while (*s == '"')
496 if (++qcount == 3)
498 *d++ = '"';
499 qcount = 0;
501 s++;
503 if (qcount == 2)
504 qcount = 0;
506 else
508 /* a regular character */
509 *d++ = *s++;
510 bcount = 0;
513 *d = '\0';
514 argv[argc] = NULL;
515 *numargs = argc;
517 return argv;
520 struct shstream
522 IStream IStream_iface;
523 LONG refcount;
525 union
527 struct
529 BYTE *buffer;
530 DWORD length;
531 DWORD position;
533 HKEY hkey;
534 WCHAR *valuename;
535 } mem;
536 struct
538 HANDLE handle;
539 DWORD mode;
540 WCHAR *path;
541 } file;
542 } u;
545 static inline struct shstream *impl_from_IStream(IStream *iface)
547 return CONTAINING_RECORD(iface, struct shstream, IStream_iface);
550 static HRESULT WINAPI shstream_QueryInterface(IStream *iface, REFIID riid, void **out)
552 struct shstream *stream = impl_from_IStream(iface);
554 TRACE("(%p)->(%s, %p)\n", stream, debugstr_guid(riid), out);
556 if (IsEqualIID(riid, &IID_IUnknown) ||
557 IsEqualIID(riid, &IID_IStream) ||
558 IsEqualIID(riid, &IID_ISequentialStream))
560 *out = iface;
561 IStream_AddRef(iface);
562 return S_OK;
565 *out = NULL;
566 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
567 return E_NOINTERFACE;
570 static ULONG WINAPI shstream_AddRef(IStream *iface)
572 struct shstream *stream = impl_from_IStream(iface);
573 ULONG refcount = InterlockedIncrement(&stream->refcount);
575 TRACE("(%p)->(%u)\n", stream, refcount);
577 return refcount;
580 static ULONG WINAPI memstream_Release(IStream *iface)
582 struct shstream *stream = impl_from_IStream(iface);
583 ULONG refcount = InterlockedDecrement(&stream->refcount);
585 TRACE("(%p)->(%u)\n", stream, refcount);
587 if (!refcount)
589 heap_free(stream->u.mem.buffer);
590 heap_free(stream);
593 return refcount;
596 static HRESULT WINAPI memstream_Read(IStream *iface, void *buff, ULONG buff_size, ULONG *read_len)
598 struct shstream *stream = impl_from_IStream(iface);
599 DWORD length;
601 TRACE("(%p)->(%p, %u, %p)\n", stream, buff, buff_size, read_len);
603 if (stream->u.mem.position >= stream->u.mem.length)
605 if (read_len)
606 *read_len = 0;
607 return S_FALSE;
610 length = stream->u.mem.length - stream->u.mem.position;
611 if (buff_size < length)
612 length = buff_size;
614 memmove(buff, stream->u.mem.buffer + stream->u.mem.position, length);
615 stream->u.mem.position += length;
617 if (read_len)
618 *read_len = length;
620 return S_OK;
623 static HRESULT WINAPI memstream_Write(IStream *iface, const void *buff, ULONG buff_size, ULONG *written)
625 struct shstream *stream = impl_from_IStream(iface);
626 DWORD length = stream->u.mem.position + buff_size;
628 TRACE("(%p)->(%p, %u, %p)\n", stream, buff, buff_size, written);
630 if (length < stream->u.mem.position) /* overflow */
631 return STG_E_INSUFFICIENTMEMORY;
633 if (length > stream->u.mem.length)
635 BYTE *buffer = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, stream->u.mem.buffer, length);
636 if (!buffer)
637 return STG_E_INSUFFICIENTMEMORY;
639 stream->u.mem.length = length;
640 stream->u.mem.buffer = buffer;
642 memmove(stream->u.mem.buffer + stream->u.mem.position, buff, buff_size);
643 stream->u.mem.position += buff_size; /* adjust pointer */
645 if (written)
646 *written = buff_size;
648 return S_OK;
651 static HRESULT WINAPI memstream_Seek(IStream *iface, LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER*new_pos)
653 struct shstream *stream = impl_from_IStream(iface);
654 LARGE_INTEGER tmp;
656 TRACE("(%p)->(%s, %d, %p)\n", stream, wine_dbgstr_longlong(move.QuadPart), origin, new_pos);
658 if (origin == STREAM_SEEK_SET)
659 tmp = move;
660 else if (origin == STREAM_SEEK_CUR)
661 tmp.QuadPart = stream->u.mem.position + move.QuadPart;
662 else if (origin == STREAM_SEEK_END)
663 tmp.QuadPart = stream->u.mem.length + move.QuadPart;
664 else
665 return STG_E_INVALIDPARAMETER;
667 if (tmp.QuadPart < 0)
668 return STG_E_INVALIDFUNCTION;
670 /* we cut off the high part here */
671 stream->u.mem.position = tmp.u.LowPart;
673 if (new_pos)
674 new_pos->QuadPart = stream->u.mem.position;
675 return S_OK;
678 static HRESULT WINAPI memstream_SetSize(IStream *iface, ULARGE_INTEGER new_size)
680 struct shstream *stream = impl_from_IStream(iface);
681 DWORD length;
682 BYTE *buffer;
684 TRACE("(%p, %s)\n", stream, wine_dbgstr_longlong(new_size.QuadPart));
686 /* we cut off the high part here */
687 length = new_size.u.LowPart;
688 buffer = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, stream->u.mem.buffer, length);
689 if (!buffer)
690 return STG_E_INSUFFICIENTMEMORY;
692 stream->u.mem.buffer = buffer;
693 stream->u.mem.length = length;
695 return S_OK;
698 static HRESULT WINAPI shstream_CopyTo(IStream *iface, IStream *dest, ULARGE_INTEGER size,
699 ULARGE_INTEGER *read_len, ULARGE_INTEGER *written)
701 struct shstream *stream = impl_from_IStream(iface);
702 ULARGE_INTEGER total_read, total_written;
703 HRESULT hr = S_OK;
704 BYTE buffer[0x400];
706 TRACE("(%p, %p, %s, %p, %p)\n", stream, dest, wine_dbgstr_longlong(size.QuadPart), read_len, written);
708 if (!dest)
709 return E_POINTER;
711 total_read.QuadPart = 0;
712 total_written.QuadPart = 0;
714 while (size.QuadPart > 0)
716 ULONG chunk_size = size.QuadPart >= sizeof(buffer) ? sizeof(buffer) : size.u.LowPart;
717 ULONG chunk_read, chunk_written;
719 hr = IStream_Read(iface, buffer, chunk_size, &chunk_read);
720 if (FAILED(hr))
721 break;
723 total_read.QuadPart += chunk_read;
725 if (chunk_read)
727 hr = IStream_Write(dest, buffer, chunk_read, &chunk_written);
728 if (FAILED(hr))
729 break;
731 total_written.QuadPart += chunk_written;
734 if (chunk_read != chunk_size)
735 size.QuadPart = 0;
736 else
737 size.QuadPart -= chunk_read;
740 if (read_len)
741 read_len->QuadPart = total_read.QuadPart;
742 if (written)
743 written->QuadPart = total_written.QuadPart;
745 return hr;
748 static HRESULT WINAPI shstream_Commit(IStream *iface, DWORD flags)
750 struct shstream *stream = impl_from_IStream(iface);
752 TRACE("(%p, %#x)\n", stream, 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, %#x)\n", stream, 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)->(%u)\n", stream, 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, %u, %p)\n", stream, buff, size, read_len);
905 if (!ReadFile(stream->u.file.handle, buff, size, &read, NULL))
907 WARN("error %d 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, %u, %p)\n", stream, 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, %d, %p)\n", stream, 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 struct shstream *stream = impl_from_IStream(iface);
1035 TRACE("(%p, %#x)\n", stream, flags);
1037 return S_OK;
1040 static HRESULT WINAPI filestream_Stat(IStream *iface, STATSTG *statstg, DWORD flags)
1042 struct shstream *stream = impl_from_IStream(iface);
1043 BY_HANDLE_FILE_INFORMATION fi;
1045 TRACE("(%p, %p, %#x)\n", stream, statstg, flags);
1047 if (!statstg)
1048 return STG_E_INVALIDPOINTER;
1050 memset(&fi, 0, sizeof(fi));
1051 GetFileInformationByHandle(stream->u.file.handle, &fi);
1053 if (flags & STATFLAG_NONAME)
1054 statstg->pwcsName = NULL;
1055 else
1057 int len = lstrlenW(stream->u.file.path);
1058 if ((statstg->pwcsName = CoTaskMemAlloc((len + 1) * sizeof(WCHAR))))
1059 memcpy(statstg->pwcsName, stream->u.file.path, (len + 1) * sizeof(WCHAR));
1061 statstg->type = 0;
1062 statstg->cbSize.u.LowPart = fi.nFileSizeLow;
1063 statstg->cbSize.u.HighPart = fi.nFileSizeHigh;
1064 statstg->mtime = fi.ftLastWriteTime;
1065 statstg->ctime = fi.ftCreationTime;
1066 statstg->atime = fi.ftLastAccessTime;
1067 statstg->grfMode = stream->u.file.mode;
1068 statstg->grfLocksSupported = 0;
1069 memcpy(&statstg->clsid, &IID_IStream, sizeof(CLSID));
1070 statstg->grfStateBits = 0;
1071 statstg->reserved = 0;
1073 return S_OK;
1076 static const IStreamVtbl filestreamvtbl =
1078 shstream_QueryInterface,
1079 shstream_AddRef,
1080 filestream_Release,
1081 filestream_Read,
1082 filestream_Write,
1083 filestream_Seek,
1084 filestream_SetSize,
1085 filestream_CopyTo,
1086 filestream_Commit,
1087 shstream_Revert,
1088 shstream_LockRegion,
1089 shstream_UnlockRegion,
1090 filestream_Stat,
1091 shstream_Clone,
1094 /*************************************************************************
1095 * SHCreateStreamOnFileEx [SHCORE.@]
1097 HRESULT WINAPI SHCreateStreamOnFileEx(const WCHAR *path, DWORD mode, DWORD attributes,
1098 BOOL create, IStream *template, IStream **ret)
1100 DWORD access, share, creation_disposition, len;
1101 struct shstream *stream;
1102 HANDLE hFile;
1104 TRACE("(%s, %d, 0x%08X, %d, %p, %p)\n", debugstr_w(path), mode, attributes,
1105 create, template, ret);
1107 if (!path || !ret || template)
1108 return E_INVALIDARG;
1110 *ret = NULL;
1112 /* Access */
1113 switch (mode & 0xf)
1115 case STGM_WRITE:
1116 case STGM_READWRITE:
1117 access = GENERIC_READ | GENERIC_WRITE;
1118 break;
1119 case STGM_READ:
1120 access = GENERIC_READ;
1121 break;
1122 default:
1123 return E_INVALIDARG;
1126 /* Sharing */
1127 switch (mode & 0xf0)
1129 case 0:
1130 case STGM_SHARE_DENY_NONE:
1131 share = FILE_SHARE_READ | FILE_SHARE_WRITE;
1132 break;
1133 case STGM_SHARE_DENY_READ:
1134 share = FILE_SHARE_WRITE;
1135 break;
1136 case STGM_SHARE_DENY_WRITE:
1137 share = FILE_SHARE_READ;
1138 break;
1139 case STGM_SHARE_EXCLUSIVE:
1140 share = 0;
1141 break;
1142 default:
1143 return E_INVALIDARG;
1146 switch (mode & 0xf000)
1148 case STGM_FAILIFTHERE:
1149 creation_disposition = create ? CREATE_NEW : OPEN_EXISTING;
1150 break;
1151 case STGM_CREATE:
1152 creation_disposition = CREATE_ALWAYS;
1153 break;
1154 default:
1155 return E_INVALIDARG;
1158 hFile = CreateFileW(path, access, share, NULL, creation_disposition, attributes, 0);
1159 if (hFile == INVALID_HANDLE_VALUE)
1160 return HRESULT_FROM_WIN32(GetLastError());
1162 stream = heap_alloc(sizeof(*stream));
1163 stream->IStream_iface.lpVtbl = &filestreamvtbl;
1164 stream->refcount = 1;
1165 stream->u.file.handle = hFile;
1166 stream->u.file.mode = mode;
1168 len = lstrlenW(path);
1169 stream->u.file.path = heap_alloc((len + 1) * sizeof(WCHAR));
1170 memcpy(stream->u.file.path, path, (len + 1) * sizeof(WCHAR));
1172 *ret = &stream->IStream_iface;
1174 return S_OK;
1177 /*************************************************************************
1178 * SHCreateStreamOnFileW [SHCORE.@]
1180 HRESULT WINAPI SHCreateStreamOnFileW(const WCHAR *path, DWORD mode, IStream **stream)
1182 TRACE("(%s, %#x, %p)\n", debugstr_w(path), mode, stream);
1184 if (!path || !stream)
1185 return E_INVALIDARG;
1187 if ((mode & (STGM_CONVERT | STGM_DELETEONRELEASE | STGM_TRANSACTED)) != 0)
1188 return E_INVALIDARG;
1190 return SHCreateStreamOnFileEx(path, mode, 0, FALSE, NULL, stream);
1193 /*************************************************************************
1194 * SHCreateStreamOnFileA [SHCORE.@]
1196 HRESULT WINAPI SHCreateStreamOnFileA(const char *path, DWORD mode, IStream **stream)
1198 WCHAR *pathW;
1199 HRESULT hr;
1200 DWORD len;
1202 TRACE("(%s, %#x, %p)\n", debugstr_a(path), mode, stream);
1204 if (!path)
1205 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1207 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1208 pathW = heap_alloc(len * sizeof(WCHAR));
1209 if (!pathW)
1210 return E_OUTOFMEMORY;
1212 MultiByteToWideChar(CP_ACP, 0, path, -1, pathW, len);
1213 hr = SHCreateStreamOnFileW(pathW, mode, stream);
1214 heap_free(pathW);
1216 return hr;
1219 static ULONG WINAPI regstream_Release(IStream *iface)
1221 struct shstream *stream = impl_from_IStream(iface);
1222 ULONG refcount = InterlockedDecrement(&stream->refcount);
1224 TRACE("(%p)->(%u)\n", stream, refcount);
1226 if (!refcount)
1228 if (stream->u.mem.hkey)
1230 if (stream->u.mem.length)
1231 RegSetValueExW(stream->u.mem.hkey, stream->u.mem.valuename, 0, REG_BINARY,
1232 (const BYTE *)stream->u.mem.buffer, stream->u.mem.length);
1233 else
1234 RegDeleteValueW(stream->u.mem.hkey, stream->u.mem.valuename);
1235 RegCloseKey(stream->u.mem.hkey);
1237 CoTaskMemFree(stream->u.mem.valuename);
1238 heap_free(stream->u.mem.buffer);
1239 heap_free(stream);
1242 return refcount;
1245 static const IStreamVtbl regstreamvtbl =
1247 shstream_QueryInterface,
1248 shstream_AddRef,
1249 regstream_Release,
1250 memstream_Read,
1251 memstream_Write,
1252 memstream_Seek,
1253 memstream_SetSize,
1254 shstream_CopyTo,
1255 shstream_Commit,
1256 shstream_Revert,
1257 shstream_LockRegion,
1258 shstream_UnlockRegion,
1259 memstream_Stat,
1260 shstream_Clone,
1263 /*************************************************************************
1264 * SHOpenRegStream2W [SHCORE.@]
1266 IStream * WINAPI SHOpenRegStream2W(HKEY hKey, const WCHAR *subkey, const WCHAR *value, DWORD mode)
1268 struct shstream *stream;
1269 HKEY hStrKey = NULL;
1270 BYTE *buff = NULL;
1271 DWORD length = 0;
1272 LONG ret;
1274 TRACE("(%p, %s, %s, %#x)\n", hKey, debugstr_w(subkey), debugstr_w(value), mode);
1276 if (mode == STGM_READ)
1277 ret = RegOpenKeyExW(hKey, subkey, 0, KEY_READ, &hStrKey);
1278 else /* in write mode we make sure the subkey exits */
1279 ret = RegCreateKeyExW(hKey, subkey, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &hStrKey, NULL);
1281 if (ret == ERROR_SUCCESS)
1283 if (mode == STGM_READ || mode == STGM_READWRITE)
1285 /* read initial data */
1286 ret = RegQueryValueExW(hStrKey, value, 0, 0, 0, &length);
1287 if (ret == ERROR_SUCCESS && length)
1289 buff = heap_alloc(length);
1290 RegQueryValueExW(hStrKey, value, 0, 0, buff, &length);
1294 if (!length)
1295 buff = heap_alloc(length);
1297 stream = shstream_create(&regstreamvtbl, buff, length);
1298 heap_free(buff);
1299 if (stream)
1301 stream->u.mem.hkey = hStrKey;
1302 SHStrDupW(value, &stream->u.mem.valuename);
1303 return &stream->IStream_iface;
1307 if (hStrKey)
1308 RegCloseKey(hStrKey);
1310 return NULL;
1313 /*************************************************************************
1314 * SHOpenRegStream2A [SHCORE.@]
1316 IStream * WINAPI SHOpenRegStream2A(HKEY hKey, const char *subkey, const char *value, DWORD mode)
1318 WCHAR *subkeyW = NULL, *valueW = NULL;
1319 IStream *stream;
1321 TRACE("(%p, %s, %s, %#x)\n", hKey, debugstr_a(subkey), debugstr_a(value), mode);
1323 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1324 return NULL;
1325 if (value && FAILED(SHStrDupA(value, &valueW)))
1327 CoTaskMemFree(subkeyW);
1328 return NULL;
1331 stream = SHOpenRegStream2W(hKey, subkeyW, valueW, mode);
1332 CoTaskMemFree(subkeyW);
1333 CoTaskMemFree(valueW);
1334 return stream;
1337 /*************************************************************************
1338 * SHOpenRegStreamA [SHCORE.@]
1340 IStream * WINAPI SHOpenRegStreamA(HKEY hkey, const char *subkey, const char *value, DWORD mode)
1342 WCHAR *subkeyW = NULL, *valueW = NULL;
1343 IStream *stream;
1345 TRACE("(%p, %s, %s, %#x)\n", hkey, debugstr_a(subkey), debugstr_a(value), mode);
1347 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1348 return NULL;
1349 if (value && FAILED(SHStrDupA(value, &valueW)))
1351 CoTaskMemFree(subkeyW);
1352 return NULL;
1355 stream = SHOpenRegStreamW(hkey, subkeyW, valueW, mode);
1356 CoTaskMemFree(subkeyW);
1357 CoTaskMemFree(valueW);
1358 return stream;
1361 static ULONG WINAPI dummystream_AddRef(IStream *iface)
1363 TRACE("()\n");
1364 return 2;
1367 static ULONG WINAPI dummystream_Release(IStream *iface)
1369 TRACE("()\n");
1370 return 1;
1373 static HRESULT WINAPI dummystream_Read(IStream *iface, void *buff, ULONG buff_size, ULONG *read_len)
1375 if (read_len)
1376 *read_len = 0;
1378 return E_NOTIMPL;
1381 static const IStreamVtbl dummystreamvtbl =
1383 shstream_QueryInterface,
1384 dummystream_AddRef,
1385 dummystream_Release,
1386 dummystream_Read,
1387 memstream_Write,
1388 memstream_Seek,
1389 memstream_SetSize,
1390 shstream_CopyTo,
1391 shstream_Commit,
1392 shstream_Revert,
1393 shstream_LockRegion,
1394 shstream_UnlockRegion,
1395 memstream_Stat,
1396 shstream_Clone,
1399 static struct shstream dummyregstream = { { &dummystreamvtbl } };
1401 /*************************************************************************
1402 * SHOpenRegStreamW [SHCORE.@]
1404 IStream * WINAPI SHOpenRegStreamW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, DWORD mode)
1406 IStream *stream;
1408 TRACE("(%p, %s, %s, %#x)\n", hkey, debugstr_w(subkey), debugstr_w(value), mode);
1409 stream = SHOpenRegStream2W(hkey, subkey, value, mode);
1410 return stream ? stream : &dummyregstream.IStream_iface;
1413 struct threadref
1415 IUnknown IUnknown_iface;
1416 LONG *refcount;
1419 static inline struct threadref *threadref_impl_from_IUnknown(IUnknown *iface)
1421 return CONTAINING_RECORD(iface, struct threadref, IUnknown_iface);
1424 static HRESULT WINAPI threadref_QueryInterface(IUnknown *iface, REFIID riid, void **out)
1426 struct threadref *threadref = threadref_impl_from_IUnknown(iface);
1428 TRACE("(%p, %s, %p)\n", threadref, debugstr_guid(riid), out);
1430 if (out == NULL)
1431 return E_POINTER;
1433 if (IsEqualGUID(&IID_IUnknown, riid))
1435 *out = iface;
1436 IUnknown_AddRef(iface);
1437 return S_OK;
1440 *out = NULL;
1441 WARN("Interface %s not supported.\n", debugstr_guid(riid));
1442 return E_NOINTERFACE;
1445 static ULONG WINAPI threadref_AddRef(IUnknown *iface)
1447 struct threadref *threadref = threadref_impl_from_IUnknown(iface);
1448 LONG refcount = InterlockedIncrement(threadref->refcount);
1450 TRACE("(%p, %d)\n", threadref, refcount);
1452 return refcount;
1455 static ULONG WINAPI threadref_Release(IUnknown *iface)
1457 struct threadref *threadref = threadref_impl_from_IUnknown(iface);
1458 LONG refcount = InterlockedDecrement(threadref->refcount);
1460 TRACE("(%p, %d)\n", threadref, refcount);
1462 if (!refcount)
1463 heap_free(threadref);
1465 return refcount;
1468 static const IUnknownVtbl threadrefvtbl =
1470 threadref_QueryInterface,
1471 threadref_AddRef,
1472 threadref_Release,
1475 /*************************************************************************
1476 * SHCreateThreadRef [SHCORE.@]
1478 HRESULT WINAPI SHCreateThreadRef(LONG *refcount, IUnknown **out)
1480 struct threadref *threadref;
1482 TRACE("(%p, %p)\n", refcount, out);
1484 if (!refcount || !out)
1485 return E_INVALIDARG;
1487 *out = NULL;
1489 threadref = heap_alloc(sizeof(*threadref));
1490 if (!threadref)
1491 return E_OUTOFMEMORY;
1492 threadref->IUnknown_iface.lpVtbl = &threadrefvtbl;
1493 threadref->refcount = refcount;
1495 *refcount = 1;
1496 *out = &threadref->IUnknown_iface;
1498 TRACE("Created %p.\n", threadref);
1499 return S_OK;
1502 /*************************************************************************
1503 * SHGetThreadRef [SHCORE.@]
1505 HRESULT WINAPI SHGetThreadRef(IUnknown **out)
1507 TRACE("(%p)\n", out);
1509 if (shcore_tls == TLS_OUT_OF_INDEXES)
1510 return E_NOINTERFACE;
1512 *out = TlsGetValue(shcore_tls);
1513 if (!*out)
1514 return E_NOINTERFACE;
1516 IUnknown_AddRef(*out);
1517 return S_OK;
1520 /*************************************************************************
1521 * SHSetThreadRef [SHCORE.@]
1523 HRESULT WINAPI SHSetThreadRef(IUnknown *obj)
1525 TRACE("(%p)\n", obj);
1527 if (shcore_tls == TLS_OUT_OF_INDEXES)
1528 return E_NOINTERFACE;
1530 TlsSetValue(shcore_tls, obj);
1531 return S_OK;
1534 /*************************************************************************
1535 * SHReleaseThreadRef [SHCORE.@]
1537 HRESULT WINAPI SHReleaseThreadRef(void)
1539 FIXME("() - stub!\n");
1540 return S_OK;
1543 /*************************************************************************
1544 * GetProcessReference [SHCORE.@]
1546 HRESULT WINAPI GetProcessReference(IUnknown **obj)
1548 TRACE("(%p)\n", obj);
1550 *obj = process_ref;
1552 if (!process_ref)
1553 return E_FAIL;
1555 if (*obj)
1556 IUnknown_AddRef(*obj);
1558 return S_OK;
1561 /*************************************************************************
1562 * SetProcessReference [SHCORE.@]
1564 void WINAPI SetProcessReference(IUnknown *obj)
1566 TRACE("(%p)\n", obj);
1568 process_ref = obj;
1571 struct thread_data
1573 LPTHREAD_START_ROUTINE thread_proc;
1574 LPTHREAD_START_ROUTINE callback;
1575 void *data;
1576 DWORD flags;
1577 HANDLE hEvent;
1578 IUnknown *thread_ref;
1579 IUnknown *process_ref;
1582 static DWORD WINAPI shcore_thread_wrapper(void *data)
1584 struct thread_data thread_data;
1585 HRESULT hr = E_FAIL;
1586 DWORD retval;
1588 TRACE("(%p)\n", data);
1590 /* We are now executing in the context of the newly created thread.
1591 * So we copy the data passed to us (it is on the stack of the function
1592 * that called us, which is waiting for us to signal an event before
1593 * returning). */
1594 thread_data = *(struct thread_data *)data;
1596 if (thread_data.flags & CTF_COINIT)
1598 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
1599 if (FAILED(hr))
1600 hr = CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE);
1603 if (thread_data.callback)
1604 thread_data.callback(thread_data.data);
1606 /* Signal the thread that created us; it can return now. */
1607 SetEvent(thread_data.hEvent);
1609 /* Execute the callers start code. */
1610 retval = thread_data.thread_proc(thread_data.data);
1612 /* Release thread and process references. */
1613 if (thread_data.thread_ref)
1614 IUnknown_Release(thread_data.thread_ref);
1616 if (thread_data.process_ref)
1617 IUnknown_Release(thread_data.process_ref);
1619 if (SUCCEEDED(hr))
1620 CoUninitialize();
1622 return retval;
1625 /*************************************************************************
1626 * SHCreateThread [SHCORE.@]
1628 BOOL WINAPI SHCreateThread(LPTHREAD_START_ROUTINE thread_proc, void *data, DWORD flags, LPTHREAD_START_ROUTINE callback)
1630 struct thread_data thread_data;
1631 BOOL called = FALSE;
1633 TRACE("(%p, %p, %#x, %p)\n", thread_proc, data, flags, callback);
1635 thread_data.thread_proc = thread_proc;
1636 thread_data.callback = callback;
1637 thread_data.data = data;
1638 thread_data.flags = flags;
1639 thread_data.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
1641 if (flags & CTF_THREAD_REF)
1642 SHGetThreadRef(&thread_data.thread_ref);
1643 else
1644 thread_data.thread_ref = NULL;
1646 if (flags & CTF_PROCESS_REF)
1647 GetProcessReference(&thread_data.process_ref);
1648 else
1649 thread_data.process_ref = NULL;
1651 /* Create the thread */
1652 if (thread_data.hEvent)
1654 HANDLE hThread;
1655 DWORD retval;
1657 hThread = CreateThread(NULL, 0, shcore_thread_wrapper, &thread_data, 0, &retval);
1658 if (hThread)
1660 /* Wait for the thread to signal us to continue */
1661 WaitForSingleObject(thread_data.hEvent, INFINITE);
1662 CloseHandle(hThread);
1663 called = TRUE;
1665 CloseHandle(thread_data.hEvent);
1668 if (!called)
1670 if (!thread_data.callback && flags & CTF_INSIST)
1672 /* Couldn't call, call synchronously */
1673 thread_data.thread_proc(data);
1674 called = TRUE;
1676 else
1678 if (thread_data.thread_ref)
1679 IUnknown_Release(thread_data.thread_ref);
1681 if (thread_data.process_ref)
1682 IUnknown_Release(thread_data.process_ref);
1686 return called;
1689 /*************************************************************************
1690 * SHStrDupW [SHCORE.@]
1692 HRESULT WINAPI SHStrDupW(const WCHAR *src, WCHAR **dest)
1694 size_t len;
1696 TRACE("(%s, %p)\n", debugstr_w(src), dest);
1698 *dest = NULL;
1700 if (!src)
1701 return E_INVALIDARG;
1703 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
1704 *dest = CoTaskMemAlloc(len);
1705 if (!*dest)
1706 return E_OUTOFMEMORY;
1708 memcpy(*dest, src, len);
1710 return S_OK;
1713 /*************************************************************************
1714 * SHStrDupA [SHCORE.@]
1716 HRESULT WINAPI SHStrDupA(const char *src, WCHAR **dest)
1718 DWORD len;
1720 *dest = NULL;
1722 if (!src)
1723 return E_INVALIDARG;
1725 len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
1726 *dest = CoTaskMemAlloc(len * sizeof(WCHAR));
1727 if (!*dest)
1728 return E_OUTOFMEMORY;
1730 MultiByteToWideChar(CP_ACP, 0, src, -1, *dest, len);
1732 return S_OK;
1735 /*************************************************************************
1736 * SHAnsiToAnsi [SHCORE.@]
1738 DWORD WINAPI SHAnsiToAnsi(const char *src, char *dest, int dest_len)
1740 DWORD ret;
1742 TRACE("(%s, %p, %d)\n", debugstr_a(src), dest, dest_len);
1744 if (!src || !dest || dest_len <= 0)
1745 return 0;
1747 lstrcpynA(dest, src, dest_len);
1748 ret = strlen(dest);
1750 return src[ret] ? 0 : ret + 1;
1753 /*************************************************************************
1754 * SHUnicodeToAnsi [SHCORE.@]
1756 DWORD WINAPI SHUnicodeToAnsi(const WCHAR *src, char *dest, int dest_len)
1758 int ret = 1;
1760 TRACE("(%s, %p, %d)\n", debugstr_w(src), dest, dest_len);
1762 if (!dest || !dest_len)
1763 return 0;
1765 if (src)
1767 ret = WideCharToMultiByte(CP_ACP, 0, src, -1, dest, dest_len, NULL, NULL);
1768 if (!ret)
1770 dest[dest_len - 1] = 0;
1771 ret = dest_len;
1774 else
1775 dest[0] = 0;
1777 return ret;
1780 /*************************************************************************
1781 * SHUnicodeToUnicode [SHCORE.@]
1783 DWORD WINAPI SHUnicodeToUnicode(const WCHAR *src, WCHAR *dest, int dest_len)
1785 DWORD ret;
1787 TRACE("(%s, %p, %d)\n", debugstr_w(src), dest, dest_len);
1789 if (!src || !dest || dest_len <= 0)
1790 return 0;
1792 lstrcpynW(dest, src, dest_len);
1793 ret = lstrlenW(dest);
1795 return src[ret] ? 0 : ret + 1;
1798 /*************************************************************************
1799 * SHAnsiToUnicode [SHCORE.@]
1801 DWORD WINAPI SHAnsiToUnicode(const char *src, WCHAR *dest, int dest_len)
1803 int ret = 1;
1805 TRACE("(%s, %p, %d)\n", debugstr_a(src), dest, dest_len);
1807 if (!dest || !dest_len)
1808 return 0;
1810 if (src)
1812 ret = MultiByteToWideChar(CP_ACP, 0, src, -1, dest, dest_len);
1813 if (!ret)
1815 dest[dest_len - 1] = 0;
1816 ret = dest_len;
1819 else
1820 dest[0] = 0;
1822 return ret;
1825 /*************************************************************************
1826 * SHRegDuplicateHKey [SHCORE.@]
1828 HKEY WINAPI SHRegDuplicateHKey(HKEY hKey)
1830 HKEY newKey = 0;
1832 RegOpenKeyExW(hKey, 0, 0, MAXIMUM_ALLOWED, &newKey);
1833 TRACE("new key is %p\n", newKey);
1834 return newKey;
1837 /*************************************************************************
1838 * SHDeleteEmptyKeyW [SHCORE.@]
1840 DWORD WINAPI SHDeleteEmptyKeyW(HKEY hkey, const WCHAR *subkey)
1842 DWORD ret, count = 0;
1843 HKEY hsubkey = 0;
1845 TRACE("(%p, %s)\n", hkey, debugstr_w(subkey));
1847 ret = RegOpenKeyExW(hkey, subkey, 0, KEY_READ, &hsubkey);
1848 if (!ret)
1850 ret = RegQueryInfoKeyW(hsubkey, NULL, NULL, NULL, &count,
1851 NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1852 RegCloseKey(hsubkey);
1853 if (!ret)
1855 if (count)
1856 ret = ERROR_KEY_HAS_CHILDREN;
1857 else
1858 ret = RegDeleteKeyW(hkey, subkey);
1862 return ret;
1865 /*************************************************************************
1866 * SHDeleteEmptyKeyA [SHCORE.@]
1868 DWORD WINAPI SHDeleteEmptyKeyA(HKEY hkey, const char *subkey)
1870 WCHAR *subkeyW = NULL;
1871 DWORD ret;
1873 TRACE("(%p, %s)\n", hkey, debugstr_a(subkey));
1875 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1876 return ERROR_OUTOFMEMORY;
1878 ret = SHDeleteEmptyKeyW(hkey, subkeyW);
1879 CoTaskMemFree(subkeyW);
1880 return ret;
1883 /*************************************************************************
1884 * SHDeleteKeyW [SHCORE.@]
1886 DWORD WINAPI SHDeleteKeyW(HKEY hkey, const WCHAR *subkey)
1888 TRACE("(%p, %s)\n", hkey, debugstr_w(subkey));
1890 return RegDeleteTreeW(hkey, subkey);
1893 /*************************************************************************
1894 * SHDeleteKeyA [SHCORE.@]
1896 DWORD WINAPI SHDeleteKeyA(HKEY hkey, const char *subkey)
1898 TRACE("(%p, %s)\n", hkey, debugstr_a(subkey));
1900 return RegDeleteTreeA(hkey, subkey);
1903 /*************************************************************************
1904 * SHDeleteValueW [SHCORE.@]
1906 DWORD WINAPI SHDeleteValueW(HKEY hkey, const WCHAR *subkey, const WCHAR *value)
1908 HKEY hsubkey;
1909 DWORD ret;
1911 TRACE("(%p, %s, %s)\n", hkey, debugstr_w(subkey), debugstr_w(value));
1913 ret = RegOpenKeyExW(hkey, subkey, 0, KEY_SET_VALUE, &hsubkey);
1914 if (!ret)
1916 ret = RegDeleteValueW(hsubkey, value);
1917 RegCloseKey(hsubkey);
1920 return ret;
1923 /*************************************************************************
1924 * SHDeleteValueA [SHCORE.@]
1926 DWORD WINAPI SHDeleteValueA(HKEY hkey, const char *subkey, const char *value)
1928 WCHAR *subkeyW = NULL, *valueW = NULL;
1929 DWORD ret;
1931 TRACE("(%p, %s, %s)\n", hkey, debugstr_a(subkey), debugstr_a(value));
1933 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1934 return ERROR_OUTOFMEMORY;
1935 if (value && FAILED(SHStrDupA(value, &valueW)))
1937 CoTaskMemFree(subkeyW);
1938 return ERROR_OUTOFMEMORY;
1941 ret = SHDeleteValueW(hkey, subkeyW, valueW);
1942 CoTaskMemFree(subkeyW);
1943 CoTaskMemFree(valueW);
1944 return ret;
1947 /*************************************************************************
1948 * SHCopyKeyA [SHCORE.@]
1950 DWORD WINAPI SHCopyKeyA(HKEY hkey_src, const char *subkey, HKEY hkey_dst, DWORD reserved)
1952 WCHAR *subkeyW = NULL;
1953 DWORD ret;
1955 TRACE("(%p, %s, %p, %d)\n", hkey_src, debugstr_a(subkey), hkey_dst, reserved);
1957 if (subkey && FAILED(SHStrDupA(subkey, &subkeyW)))
1958 return 0;
1960 ret = SHCopyKeyW(hkey_src, subkeyW, hkey_dst, reserved);
1961 CoTaskMemFree(subkeyW);
1962 return ret;
1965 /*************************************************************************
1966 * SHCopyKeyW [SHCORE.@]
1968 DWORD WINAPI SHCopyKeyW(HKEY hkey_src, const WCHAR *subkey, HKEY hkey_dst, DWORD reserved)
1970 DWORD key_count = 0, value_count = 0, max_key_len = 0;
1971 WCHAR name[MAX_PATH], *ptr_name = name;
1972 BYTE buff[1024], *ptr = buff;
1973 DWORD max_data_len = 0, i;
1974 DWORD ret = 0;
1976 TRACE("(%p, %s, %p, %d)\n", hkey_src, debugstr_w(subkey), hkey_dst, reserved);
1978 if (!hkey_dst || !hkey_src)
1979 return ERROR_INVALID_PARAMETER;
1981 if (subkey)
1982 ret = RegOpenKeyExW(hkey_src, subkey, 0, KEY_ALL_ACCESS, &hkey_src);
1984 if (ret)
1985 hkey_src = NULL; /* Don't close this key since we didn't open it */
1986 else
1988 DWORD max_value_len;
1990 ret = RegQueryInfoKeyW(hkey_src, NULL, NULL, NULL, &key_count, &max_key_len,
1991 NULL, &value_count, &max_value_len, &max_data_len, NULL, NULL);
1992 if (!ret)
1994 /* Get max size for key/value names */
1995 max_key_len = max(max_key_len, max_value_len);
1997 if (max_key_len++ > MAX_PATH - 1)
1998 ptr_name = heap_alloc(max_key_len * sizeof(WCHAR));
2000 if (max_data_len > sizeof(buff))
2001 ptr = heap_alloc(max_data_len);
2003 if (!ptr_name || !ptr)
2004 ret = ERROR_NOT_ENOUGH_MEMORY;
2008 for (i = 0; i < key_count && !ret; i++)
2010 HKEY hsubkey_src, hsubkey_dst;
2011 DWORD length = max_key_len;
2013 ret = RegEnumKeyExW(hkey_src, i, ptr_name, &length, NULL, NULL, NULL, NULL);
2014 if (!ret)
2016 ret = RegOpenKeyExW(hkey_src, ptr_name, 0, KEY_READ, &hsubkey_src);
2017 if (!ret)
2019 /* Create destination sub key */
2020 ret = RegCreateKeyW(hkey_dst, ptr_name, &hsubkey_dst);
2021 if (!ret)
2023 /* Recursively copy keys and values from the sub key */
2024 ret = SHCopyKeyW(hsubkey_src, NULL, hsubkey_dst, 0);
2025 RegCloseKey(hsubkey_dst);
2028 RegCloseKey(hsubkey_src);
2032 /* Copy all the values in this key */
2033 for (i = 0; i < value_count && !ret; i++)
2035 DWORD length = max_key_len, type, data_len = max_data_len;
2037 ret = RegEnumValueW(hkey_src, i, ptr_name, &length, NULL, &type, ptr, &data_len);
2038 if (!ret) {
2039 ret = SHSetValueW(hkey_dst, NULL, ptr_name, type, ptr, data_len);
2043 /* Free buffers if allocated */
2044 if (ptr_name != name)
2045 heap_free(ptr_name);
2046 if (ptr != buff)
2047 heap_free(ptr);
2049 if (subkey && hkey_src)
2050 RegCloseKey(hkey_src);
2052 return ret;
2056 /*************************************************************************
2057 * SHEnumKeyExA [SHCORE.@]
2059 LONG WINAPI SHEnumKeyExA(HKEY hkey, DWORD index, char *subkey, DWORD *length)
2061 TRACE("(%p, %d, %s, %p)\n", hkey, index, debugstr_a(subkey), length);
2063 return RegEnumKeyExA(hkey, index, subkey, length, NULL, NULL, NULL, NULL);
2066 /*************************************************************************
2067 * SHEnumKeyExW [SHCORE.@]
2069 LONG WINAPI SHEnumKeyExW(HKEY hkey, DWORD index, WCHAR *subkey, DWORD *length)
2071 TRACE("(%p, %d, %s, %p)\n", hkey, index, debugstr_w(subkey), length);
2073 return RegEnumKeyExW(hkey, index, subkey, length, NULL, NULL, NULL, NULL);
2076 /*************************************************************************
2077 * SHEnumValueA [SHCORE.@]
2079 LONG WINAPI SHEnumValueA(HKEY hkey, DWORD index, char *value, DWORD *length, DWORD *type,
2080 void *data, DWORD *data_len)
2082 TRACE("(%p, %d, %s, %p, %p, %p, %p)\n", hkey, index, debugstr_a(value), length, type, data, data_len);
2084 return RegEnumValueA(hkey, index, value, length, NULL, type, data, data_len);
2087 /*************************************************************************
2088 * SHEnumValueW [SHCORE.@]
2090 LONG WINAPI SHEnumValueW(HKEY hkey, DWORD index, WCHAR *value, DWORD *length, DWORD *type,
2091 void *data, DWORD *data_len)
2093 TRACE("(%p, %d, %s, %p, %p, %p, %p)\n", hkey, index, debugstr_w(value), length, type, data, data_len);
2095 return RegEnumValueW(hkey, index, value, length, NULL, type, data, data_len);
2098 /*************************************************************************
2099 * SHQueryValueExW [SHCORE.@]
2101 DWORD WINAPI SHQueryValueExW(HKEY hkey, const WCHAR *name, DWORD *reserved, DWORD *type,
2102 void *buff, DWORD *buff_len)
2104 DWORD ret, value_type, data_len = 0;
2106 TRACE("(%p, %s, %p, %p, %p, %p)\n", hkey, debugstr_w(name), reserved, type, buff, buff_len);
2108 if (buff_len)
2109 data_len = *buff_len;
2111 ret = RegQueryValueExW(hkey, name, reserved, &value_type, buff, &data_len);
2112 if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)
2113 return ret;
2115 if (buff_len && value_type == REG_EXPAND_SZ)
2117 DWORD length;
2118 WCHAR *value;
2120 if (!buff || ret == ERROR_MORE_DATA)
2122 length = data_len;
2123 value = heap_alloc(length);
2124 RegQueryValueExW(hkey, name, reserved, NULL, (BYTE *)value, &length);
2125 length = ExpandEnvironmentStringsW(value, NULL, 0);
2127 else
2129 length = (lstrlenW(buff) + 1) * sizeof(WCHAR);
2130 value = heap_alloc(length);
2131 memcpy(value, buff, length);
2132 length = ExpandEnvironmentStringsW(value, buff, *buff_len / sizeof(WCHAR));
2133 if (length > *buff_len) ret = ERROR_MORE_DATA;
2135 data_len = max(data_len, length);
2136 heap_free(value);
2139 if (type)
2140 *type = value_type == REG_EXPAND_SZ ? REG_SZ : value_type;
2141 if (buff_len)
2142 *buff_len = data_len;
2143 return ret;
2146 /*************************************************************************
2147 * SHQueryValueExA [SHCORE.@]
2149 DWORD WINAPI SHQueryValueExA(HKEY hkey, const char *name, DWORD *reserved, DWORD *type,
2150 void *buff, DWORD *buff_len)
2152 DWORD ret, value_type, data_len = 0;
2154 TRACE("(%p, %s, %p, %p, %p, %p)\n", hkey, debugstr_a(name), reserved, type, buff, buff_len);
2156 if (buff_len)
2157 data_len = *buff_len;
2159 ret = RegQueryValueExA(hkey, name, reserved, &value_type, buff, &data_len);
2160 if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)
2161 return ret;
2163 if (buff_len && value_type == REG_EXPAND_SZ)
2165 DWORD length;
2166 char *value;
2168 if (!buff || ret == ERROR_MORE_DATA)
2170 length = data_len;
2171 value = heap_alloc(length);
2172 RegQueryValueExA(hkey, name, reserved, NULL, (BYTE *)value, &length);
2173 length = ExpandEnvironmentStringsA(value, NULL, 0);
2175 else
2177 length = strlen(buff) + 1;
2178 value = heap_alloc(length);
2179 memcpy(value, buff, length);
2180 length = ExpandEnvironmentStringsA(value, buff, *buff_len);
2181 if (length > *buff_len) ret = ERROR_MORE_DATA;
2183 data_len = max(data_len, length);
2184 heap_free(value);
2187 if (type)
2188 *type = value_type == REG_EXPAND_SZ ? REG_SZ : value_type;
2189 if (buff_len)
2190 *buff_len = data_len;
2191 return ret;
2194 /*************************************************************************
2195 * SHGetValueA [SHCORE.@]
2197 DWORD WINAPI SHGetValueA(HKEY hkey, const char *subkey, const char *value,
2198 DWORD *type, void *data, DWORD *data_len)
2200 HKEY hsubkey = 0;
2201 DWORD ret = 0;
2203 TRACE("(%p, %s, %s, %p, %p, %p)\n", hkey, debugstr_a(subkey), debugstr_a(value),
2204 type, data, data_len);
2206 if (subkey)
2207 ret = RegOpenKeyExA(hkey, subkey, 0, KEY_QUERY_VALUE, &hsubkey);
2209 if (!ret)
2211 ret = SHQueryValueExA(hsubkey ? hsubkey : hkey, value, 0, type, data, data_len);
2212 if (subkey)
2213 RegCloseKey(hsubkey);
2216 return ret;
2219 /*************************************************************************
2220 * SHGetValueW [SHCORE.@]
2222 DWORD WINAPI SHGetValueW(HKEY hkey, const WCHAR *subkey, const WCHAR *value,
2223 DWORD *type, void *data, DWORD *data_len)
2225 HKEY hsubkey = 0;
2226 DWORD ret = 0;
2228 TRACE("(%p, %s, %s, %p, %p, %p)\n", hkey, debugstr_w(subkey), debugstr_w(value),
2229 type, data, data_len);
2231 if (subkey)
2232 ret = RegOpenKeyExW(hkey, subkey, 0, KEY_QUERY_VALUE, &hsubkey);
2234 if (!ret)
2236 ret = SHQueryValueExW(hsubkey ? hsubkey : hkey, value, 0, type, data, data_len);
2237 if (subkey)
2238 RegCloseKey(hsubkey);
2241 return ret;
2244 /*************************************************************************
2245 * SHRegGetIntW [SHCORE.280]
2247 int WINAPI SHRegGetIntW(HKEY hkey, const WCHAR *value, int default_value)
2249 WCHAR buff[32];
2250 DWORD buff_len;
2252 TRACE("(%p, %s, %d)\n", hkey, debugstr_w(value), default_value);
2254 buff[0] = 0;
2255 buff_len = sizeof(buff);
2256 if (SHQueryValueExW(hkey, value, 0, 0, buff, &buff_len))
2257 return default_value;
2259 if (*buff >= '0' && *buff <= '9')
2260 return wcstol(buff, NULL, 10);
2262 return default_value;
2265 /*************************************************************************
2266 * SHRegGetPathA [SHCORE.@]
2268 DWORD WINAPI SHRegGetPathA(HKEY hkey, const char *subkey, const char *value, char *path, DWORD flags)
2270 DWORD length = MAX_PATH;
2272 TRACE("(%p, %s, %s, %p, %#x)\n", hkey, debugstr_a(subkey), debugstr_a(value), path, flags);
2274 return SHGetValueA(hkey, subkey, value, 0, path, &length);
2277 /*************************************************************************
2278 * SHRegGetPathW [SHCORE.@]
2280 DWORD WINAPI SHRegGetPathW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, WCHAR *path, DWORD flags)
2282 DWORD length = MAX_PATH;
2284 TRACE("(%p, %s, %s, %p, %d)\n", hkey, debugstr_w(subkey), debugstr_w(value), path, flags);
2286 return SHGetValueW(hkey, subkey, value, 0, path, &length);
2289 /*************************************************************************
2290 * SHSetValueW [SHCORE.@]
2292 DWORD WINAPI SHSetValueW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, DWORD type,
2293 const void *data, DWORD data_len)
2295 DWORD ret = ERROR_SUCCESS, dummy;
2296 HKEY hsubkey;
2298 TRACE("(%p, %s, %s, %d, %p, %d)\n", hkey, debugstr_w(subkey), debugstr_w(value),
2299 type, data, data_len);
2301 if (subkey && *subkey)
2302 ret = RegCreateKeyExW(hkey, subkey, 0, NULL, 0, KEY_SET_VALUE, NULL, &hsubkey, &dummy);
2303 else
2304 hsubkey = hkey;
2306 if (!ret)
2308 ret = RegSetValueExW(hsubkey, value, 0, type, data, data_len);
2309 if (hsubkey != hkey)
2310 RegCloseKey(hsubkey);
2313 return ret;
2316 /*************************************************************************
2317 * SHSetValueA [SHCORE.@]
2319 DWORD WINAPI SHSetValueA(HKEY hkey, const char *subkey, const char *value,
2320 DWORD type, const void *data, DWORD data_len)
2322 DWORD ret = ERROR_SUCCESS, dummy;
2323 HKEY hsubkey;
2325 TRACE("(%p, %s, %s, %d, %p, %d)\n", hkey, debugstr_a(subkey), debugstr_a(value),
2326 type, data, data_len);
2328 if (subkey && *subkey)
2329 ret = RegCreateKeyExA(hkey, subkey, 0, NULL, 0, KEY_SET_VALUE, NULL, &hsubkey, &dummy);
2330 else
2331 hsubkey = hkey;
2333 if (!ret)
2335 ret = RegSetValueExA(hsubkey, value, 0, type, data, data_len);
2336 if (hsubkey != hkey)
2337 RegCloseKey(hsubkey);
2340 return ret;
2343 /*************************************************************************
2344 * SHRegSetPathA [SHCORE.@]
2346 DWORD WINAPI SHRegSetPathA(HKEY hkey, const char *subkey, const char *value, const char *path, DWORD flags)
2348 FIXME("(%p, %s, %s, %s, %#x) - semi-stub\n", hkey, debugstr_a(subkey),
2349 debugstr_a(value), debugstr_a(path), flags);
2351 /* FIXME: PathUnExpandEnvStringsA() */
2353 return SHSetValueA(hkey, subkey, value, REG_SZ, path, lstrlenA(path));
2356 /*************************************************************************
2357 * SHRegSetPathW [SHCORE.@]
2359 DWORD WINAPI SHRegSetPathW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, const WCHAR *path, DWORD flags)
2361 FIXME("(%p, %s, %s, %s, %#x) - semi-stub\n", hkey, debugstr_w(subkey),
2362 debugstr_w(value), debugstr_w(path), flags);
2364 /* FIXME: PathUnExpandEnvStringsW(); */
2366 return SHSetValueW(hkey, subkey, value, REG_SZ, path, lstrlenW(path));
2369 /*************************************************************************
2370 * SHQueryInfoKeyA [SHCORE.@]
2372 LONG WINAPI SHQueryInfoKeyA(HKEY hkey, DWORD *subkeys, DWORD *subkey_max, DWORD *values, DWORD *value_max)
2374 TRACE("(%p, %p, %p, %p, %p)\n", hkey, subkeys, subkey_max, values, value_max);
2376 return RegQueryInfoKeyA(hkey, NULL, NULL, NULL, subkeys, subkey_max, NULL, values, value_max, NULL, NULL, NULL);
2379 /*************************************************************************
2380 * SHQueryInfoKeyW [SHCORE.@]
2382 LONG WINAPI SHQueryInfoKeyW(HKEY hkey, DWORD *subkeys, DWORD *subkey_max, DWORD *values, DWORD *value_max)
2384 TRACE("(%p, %p, %p, %p, %p)\n", hkey, subkeys, subkey_max, values, value_max);
2386 return RegQueryInfoKeyW(hkey, NULL, NULL, NULL, subkeys, subkey_max, NULL, values, value_max, NULL, NULL, NULL);
2389 /*************************************************************************
2390 * IsOS [SHCORE.@]
2392 BOOL WINAPI IsOS(DWORD feature)
2394 DWORD platform, majorv, minorv;
2395 OSVERSIONINFOA osvi;
2397 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
2398 if (!GetVersionExA(&osvi))
2399 return FALSE;
2401 majorv = osvi.dwMajorVersion;
2402 minorv = osvi.dwMinorVersion;
2403 platform = osvi.dwPlatformId;
2405 #define ISOS_RETURN(x) \
2406 TRACE("(0x%x) ret=%d\n",feature,(x)); \
2407 return (x)
2409 switch(feature) {
2410 case OS_WIN32SORGREATER:
2411 ISOS_RETURN(platform == VER_PLATFORM_WIN32s
2412 || platform == VER_PLATFORM_WIN32_WINDOWS);
2413 case OS_NT:
2414 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2415 case OS_WIN95ORGREATER:
2416 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS);
2417 case OS_NT4ORGREATER:
2418 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 4);
2419 case OS_WIN2000ORGREATER_ALT:
2420 case OS_WIN2000ORGREATER:
2421 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5);
2422 case OS_WIN98ORGREATER:
2423 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 10);
2424 case OS_WIN98_GOLD:
2425 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 10);
2426 case OS_WIN2000PRO:
2427 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5);
2428 case OS_WIN2000SERVER:
2429 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2430 case OS_WIN2000ADVSERVER:
2431 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2432 case OS_WIN2000DATACENTER:
2433 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2434 case OS_WIN2000TERMINAL:
2435 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1));
2436 case OS_EMBEDDED:
2437 FIXME("(OS_EMBEDDED) What should we return here?\n");
2438 return FALSE;
2439 case OS_TERMINALCLIENT:
2440 FIXME("(OS_TERMINALCLIENT) What should we return here?\n");
2441 return FALSE;
2442 case OS_TERMINALREMOTEADMIN:
2443 FIXME("(OS_TERMINALREMOTEADMIN) What should we return here?\n");
2444 return FALSE;
2445 case OS_WIN95_GOLD:
2446 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 0);
2447 case OS_MEORGREATER:
2448 ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 90);
2449 case OS_XPORGREATER:
2450 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1);
2451 case OS_HOME:
2452 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1);
2453 case OS_PROFESSIONAL:
2454 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2455 case OS_DATACENTER:
2456 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2457 case OS_ADVSERVER:
2458 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5);
2459 case OS_SERVER:
2460 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2461 case OS_TERMINALSERVER:
2462 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2463 case OS_PERSONALTERMINALSERVER:
2464 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && minorv >= 1 && majorv >= 5);
2465 case OS_FASTUSERSWITCHING:
2466 FIXME("(OS_FASTUSERSWITCHING) What should we return here?\n");
2467 return TRUE;
2468 case OS_WELCOMELOGONUI:
2469 FIXME("(OS_WELCOMELOGONUI) What should we return here?\n");
2470 return FALSE;
2471 case OS_DOMAINMEMBER:
2472 FIXME("(OS_DOMAINMEMBER) What should we return here?\n");
2473 return TRUE;
2474 case OS_ANYSERVER:
2475 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2476 case OS_WOW6432:
2478 BOOL is_wow64;
2479 IsWow64Process(GetCurrentProcess(), &is_wow64);
2480 return is_wow64;
2482 case OS_WEBSERVER:
2483 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2484 case OS_SMALLBUSINESSSERVER:
2485 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT);
2486 case OS_TABLETPC:
2487 FIXME("(OS_TABLETPC) What should we return here?\n");
2488 return FALSE;
2489 case OS_SERVERADMINUI:
2490 FIXME("(OS_SERVERADMINUI) What should we return here?\n");
2491 return FALSE;
2492 case OS_MEDIACENTER:
2493 FIXME("(OS_MEDIACENTER) What should we return here?\n");
2494 return FALSE;
2495 case OS_APPLIANCE:
2496 FIXME("(OS_APPLIANCE) What should we return here?\n");
2497 return FALSE;
2498 case 0x25: /*OS_VISTAORGREATER*/
2499 ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 6);
2502 #undef ISOS_RETURN
2504 WARN("(0x%x) unknown parameter\n", feature);
2506 return FALSE;