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
30 #include "featurestagingapi.h"
31 #include "shellscalingapi.h"
34 #include "wine/debug.h"
35 #include "wine/heap.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(shcore
);
39 static DWORD shcore_tls
;
40 static IUnknown
*process_ref
;
42 BOOL WINAPI
DllMain(HINSTANCE instance
, DWORD reason
, void *reserved
)
44 TRACE("%p, %lu, %p.\n", instance
, reason
, reserved
);
48 case DLL_PROCESS_ATTACH
:
49 DisableThreadLibraryCalls(instance
);
50 shcore_tls
= TlsAlloc();
52 case DLL_PROCESS_DETACH
:
54 if (shcore_tls
!= TLS_OUT_OF_INDEXES
)
62 HRESULT WINAPI
GetProcessDpiAwareness(HANDLE process
, PROCESS_DPI_AWARENESS
*value
)
64 if (GetProcessDpiAwarenessInternal( process
, (DPI_AWARENESS
*)value
)) return S_OK
;
65 return HRESULT_FROM_WIN32( GetLastError() );
68 HRESULT WINAPI
SetProcessDpiAwareness(PROCESS_DPI_AWARENESS value
)
70 if (SetProcessDpiAwarenessInternal( value
)) return S_OK
;
71 return HRESULT_FROM_WIN32( GetLastError() );
74 HRESULT WINAPI
GetDpiForMonitor(HMONITOR monitor
, MONITOR_DPI_TYPE type
, UINT
*x
, UINT
*y
)
76 if (GetDpiForMonitorInternal( monitor
, type
, x
, y
)) return S_OK
;
77 return HRESULT_FROM_WIN32( GetLastError() );
80 HRESULT WINAPI
GetScaleFactorForMonitor(HMONITOR monitor
, DEVICE_SCALE_FACTOR
*scale
)
82 FIXME("(%p %p): stub\n", monitor
, scale
);
84 *scale
= SCALE_100_PERCENT
;
88 DEVICE_SCALE_FACTOR WINAPI
GetScaleFactorForDevice(DISPLAY_DEVICE_TYPE device_type
)
90 FIXME("%d\n", device_type
);
92 return SCALE_100_PERCENT
;
95 HRESULT WINAPI
_IStream_Read(IStream
*stream
, void *dest
, ULONG size
)
100 TRACE("%p, %p, %lu.\n", stream
, dest
, size
);
102 hr
= IStream_Read(stream
, dest
, size
, &read
);
103 if (SUCCEEDED(hr
) && read
!= size
)
108 HRESULT WINAPI
IStream_Reset(IStream
*stream
)
110 static const LARGE_INTEGER zero
;
112 TRACE("(%p)\n", stream
);
114 return IStream_Seek(stream
, zero
, 0, NULL
);
117 HRESULT WINAPI
IStream_Size(IStream
*stream
, ULARGE_INTEGER
*size
)
122 TRACE("(%p, %p)\n", stream
, size
);
124 memset(&statstg
, 0, sizeof(statstg
));
126 hr
= IStream_Stat(stream
, &statstg
, STATFLAG_NONAME
);
128 if (SUCCEEDED(hr
) && size
)
129 *size
= statstg
.cbSize
;
133 HRESULT WINAPI
_IStream_Write(IStream
*stream
, const void *src
, ULONG size
)
138 TRACE("%p, %p, %lu.\n", stream
, src
, size
);
140 hr
= IStream_Write(stream
, src
, size
, &written
);
141 if (SUCCEEDED(hr
) && written
!= size
)
147 void WINAPI
IUnknown_AtomicRelease(IUnknown
**obj
)
149 TRACE("(%p)\n", obj
);
154 IUnknown_Release(*obj
);
158 HRESULT WINAPI
IUnknown_GetSite(IUnknown
*unk
, REFIID iid
, void **site
)
160 IObjectWithSite
*obj
= NULL
;
161 HRESULT hr
= E_INVALIDARG
;
163 TRACE("(%p, %s, %p)\n", unk
, debugstr_guid(iid
), site
);
165 if (unk
&& iid
&& site
)
167 hr
= IUnknown_QueryInterface(unk
, &IID_IObjectWithSite
, (void **)&obj
);
168 if (SUCCEEDED(hr
) && obj
)
170 hr
= IObjectWithSite_GetSite(obj
, iid
, site
);
171 IObjectWithSite_Release(obj
);
178 HRESULT WINAPI
IUnknown_QueryService(IUnknown
*obj
, REFGUID sid
, REFIID iid
, void **out
)
180 IServiceProvider
*provider
= NULL
;
191 hr
= IUnknown_QueryInterface(obj
, &IID_IServiceProvider
, (void **)&provider
);
192 if (hr
== S_OK
&& provider
)
194 TRACE("Using provider %p.\n", provider
);
196 hr
= IServiceProvider_QueryService(provider
, sid
, iid
, out
);
198 TRACE("Provider %p returned %p.\n", provider
, *out
);
200 IServiceProvider_Release(provider
);
206 void WINAPI
IUnknown_Set(IUnknown
**dest
, IUnknown
*src
)
208 TRACE("(%p, %p)\n", dest
, src
);
210 IUnknown_AtomicRelease(dest
);
214 IUnknown_AddRef(src
);
219 HRESULT WINAPI
IUnknown_SetSite(IUnknown
*obj
, IUnknown
*site
)
221 IInternetSecurityManager
*sec_manager
;
222 IObjectWithSite
*objwithsite
;
228 hr
= IUnknown_QueryInterface(obj
, &IID_IObjectWithSite
, (void **)&objwithsite
);
229 TRACE("ObjectWithSite %p, hr %#lx.\n", objwithsite
, hr
);
232 hr
= IObjectWithSite_SetSite(objwithsite
, site
);
233 TRACE("SetSite() hr %#lx.\n", hr
);
234 IObjectWithSite_Release(objwithsite
);
238 hr
= IUnknown_QueryInterface(obj
, &IID_IInternetSecurityManager
, (void **)&sec_manager
);
239 TRACE("InternetSecurityManager %p, hr %#lx.\n", sec_manager
, hr
);
243 hr
= IInternetSecurityManager_SetSecuritySite(sec_manager
, (IInternetSecurityMgrSite
*)site
);
244 TRACE("SetSecuritySite() hr %#lx.\n", hr
);
245 IInternetSecurityManager_Release(sec_manager
);
251 HRESULT WINAPI
SetCurrentProcessExplicitAppUserModelID(const WCHAR
*appid
)
253 FIXME("%s: stub\n", debugstr_w(appid
));
257 HRESULT WINAPI
GetCurrentProcessExplicitAppUserModelID(const WCHAR
**appid
)
259 FIXME("%p: stub\n", appid
);
264 /*************************************************************************
265 * CommandLineToArgvW [SHCORE.@]
267 * We must interpret the quotes in the command line to rebuild the argv
269 * - arguments are separated by spaces or tabs
270 * - quotes serve as optional argument delimiters
272 * - escaped quotes must be converted back to '"'
274 * - consecutive backslashes preceding a quote see their number halved with
275 * the remainder escaping the quote:
276 * 2n backslashes + quote -> n backslashes + quote as an argument delimiter
277 * 2n+1 backslashes + quote -> n backslashes + literal quote
278 * - backslashes that are not followed by a quote are copied literally:
281 * - in quoted strings, consecutive quotes see their number divided by three
282 * with the remainder modulo 3 deciding whether to close the string or not.
283 * Note that the opening quote must be counted in the consecutive quotes,
284 * that's the (1+) below:
285 * (1+) 3n quotes -> n quotes
286 * (1+) 3n+1 quotes -> n quotes plus closes the quoted string
287 * (1+) 3n+2 quotes -> n+1 quotes plus closes the quoted string
288 * - in unquoted strings, the first quote opens the quoted string and the
289 * remaining consecutive quotes follow the above rule.
291 WCHAR
** WINAPI
CommandLineToArgvW(const WCHAR
*cmdline
, int *numargs
)
301 SetLastError(ERROR_INVALID_PARAMETER
);
307 /* Return the path to the executable */
308 DWORD len
, deslen
= MAX_PATH
, size
;
310 size
= sizeof(WCHAR
*) * 2 + deslen
* sizeof(WCHAR
);
313 if (!(argv
= LocalAlloc(LMEM_FIXED
, size
))) return NULL
;
314 len
= GetModuleFileNameW(0, (WCHAR
*)(argv
+ 2), deslen
);
320 if (len
< deslen
) break;
322 size
= sizeof(WCHAR
*) * 2 + deslen
* sizeof(WCHAR
);
325 argv
[0] = (WCHAR
*)(argv
+ 2);
332 /* --- First count the arguments */
335 /* The first argument, the executable path, follows special rules */
338 /* The executable path ends at the next quote, no matter what */
346 /* The executable path ends at the next space, no matter what */
347 while (*s
&& *s
!= ' ' && *s
!= '\t')
350 /* skip to the first argument, if any */
351 while (*s
== ' ' || *s
== '\t')
356 /* Analyze the remaining arguments */
360 if ((*s
== ' ' || *s
== '\t') && qcount
== 0)
362 /* skip to the next argument and count it if any */
363 while (*s
== ' ' || *s
== '\t')
371 /* '\', count them */
378 if ((bcount
& 1) == 0)
379 qcount
++; /* unescaped '"' */
382 /* consecutive quotes, see comment in copying code below */
394 /* a regular character */
400 /* Allocate in a single lump, the string array, and the strings that go
401 * with it. This way the caller can make a single LocalFree() call to free
404 argv
= LocalAlloc(LMEM_FIXED
, (argc
+ 1) * sizeof(WCHAR
*) + (lstrlenW(cmdline
) + 1) * sizeof(WCHAR
));
408 /* --- Then split and copy the arguments */
409 argv
[0] = d
= lstrcpyW((WCHAR
*)(argv
+ argc
+ 1), cmdline
);
411 /* The first argument, the executable path, follows special rules */
414 /* The executable path ends at the next quote, no matter what */
428 /* The executable path ends at the next space, no matter what */
429 while (*d
&& *d
!= ' ' && *d
!= '\t')
435 /* close the executable path */
437 /* skip to the first argument and initialize it if any */
438 while (*s
== ' ' || *s
== '\t')
442 /* There are no parameters so we are all done */
448 /* Split and copy the remaining arguments */
453 if ((*s
== ' ' || *s
== '\t') && qcount
== 0)
455 /* close the argument */
459 /* skip to the next one and initialize it if any */
462 } while (*s
== ' ' || *s
== '\t');
473 if ((bcount
& 1) == 0)
475 /* Preceded by an even number of '\', this is half that
476 * number of '\', plus a quote which we erase.
483 /* Preceded by an odd number of '\', this is half that
484 * number of '\' followed by a '"'
486 d
= d
- bcount
/ 2 - 1;
491 /* Now count the number of consecutive quotes. Note that qcount
492 * already takes into account the opening quote if any, as well as
493 * the quote that lead us here.
509 /* a regular character */
523 IStream IStream_iface
;
546 static inline struct shstream
*impl_from_IStream(IStream
*iface
)
548 return CONTAINING_RECORD(iface
, struct shstream
, IStream_iface
);
551 static HRESULT WINAPI
shstream_QueryInterface(IStream
*iface
, REFIID riid
, void **out
)
553 struct shstream
*stream
= impl_from_IStream(iface
);
555 TRACE("(%p)->(%s, %p)\n", stream
, debugstr_guid(riid
), out
);
557 if (IsEqualIID(riid
, &IID_IUnknown
) ||
558 IsEqualIID(riid
, &IID_IStream
) ||
559 IsEqualIID(riid
, &IID_ISequentialStream
))
562 IStream_AddRef(iface
);
567 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
568 return E_NOINTERFACE
;
571 static ULONG WINAPI
shstream_AddRef(IStream
*iface
)
573 struct shstream
*stream
= impl_from_IStream(iface
);
574 ULONG refcount
= InterlockedIncrement(&stream
->refcount
);
576 TRACE("%p, refcount %lu.\n", iface
, refcount
);
581 static ULONG WINAPI
memstream_Release(IStream
*iface
)
583 struct shstream
*stream
= impl_from_IStream(iface
);
584 ULONG refcount
= InterlockedDecrement(&stream
->refcount
);
586 TRACE("%p, refcount %lu.\n", iface
, refcount
);
590 heap_free(stream
->u
.mem
.buffer
);
597 static HRESULT WINAPI
memstream_Read(IStream
*iface
, void *buff
, ULONG buff_size
, ULONG
*read_len
)
599 struct shstream
*stream
= impl_from_IStream(iface
);
602 TRACE("%p, %p, %lu, %p.\n", iface
, buff
, buff_size
, read_len
);
604 if (stream
->u
.mem
.position
>= stream
->u
.mem
.length
)
611 length
= stream
->u
.mem
.length
- stream
->u
.mem
.position
;
612 if (buff_size
< length
)
615 memmove(buff
, stream
->u
.mem
.buffer
+ stream
->u
.mem
.position
, length
);
616 stream
->u
.mem
.position
+= length
;
624 static HRESULT WINAPI
memstream_Write(IStream
*iface
, const void *buff
, ULONG buff_size
, ULONG
*written
)
626 struct shstream
*stream
= impl_from_IStream(iface
);
627 DWORD length
= stream
->u
.mem
.position
+ buff_size
;
629 TRACE("%p, %p, %lu, %p.\n", iface
, buff
, buff_size
, written
);
631 if (length
< stream
->u
.mem
.position
) /* overflow */
632 return STG_E_INSUFFICIENTMEMORY
;
634 if (length
> stream
->u
.mem
.length
)
636 BYTE
*buffer
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, stream
->u
.mem
.buffer
, length
);
638 return STG_E_INSUFFICIENTMEMORY
;
640 stream
->u
.mem
.length
= length
;
641 stream
->u
.mem
.buffer
= buffer
;
643 memmove(stream
->u
.mem
.buffer
+ stream
->u
.mem
.position
, buff
, buff_size
);
644 stream
->u
.mem
.position
+= buff_size
; /* adjust pointer */
647 *written
= buff_size
;
652 static HRESULT WINAPI
memstream_Seek(IStream
*iface
, LARGE_INTEGER move
, DWORD origin
, ULARGE_INTEGER
*new_pos
)
654 struct shstream
*stream
= impl_from_IStream(iface
);
657 TRACE("%p, %s, %ld, %p.\n", iface
, wine_dbgstr_longlong(move
.QuadPart
), origin
, new_pos
);
659 if (origin
== STREAM_SEEK_SET
)
661 else if (origin
== STREAM_SEEK_CUR
)
662 tmp
.QuadPart
= stream
->u
.mem
.position
+ move
.QuadPart
;
663 else if (origin
== STREAM_SEEK_END
)
664 tmp
.QuadPart
= stream
->u
.mem
.length
+ move
.QuadPart
;
666 return STG_E_INVALIDPARAMETER
;
668 if (tmp
.QuadPart
< 0)
669 return STG_E_INVALIDFUNCTION
;
671 /* we cut off the high part here */
672 stream
->u
.mem
.position
= tmp
.u
.LowPart
;
675 new_pos
->QuadPart
= stream
->u
.mem
.position
;
679 static HRESULT WINAPI
memstream_SetSize(IStream
*iface
, ULARGE_INTEGER new_size
)
681 struct shstream
*stream
= impl_from_IStream(iface
);
685 TRACE("(%p, %s)\n", stream
, wine_dbgstr_longlong(new_size
.QuadPart
));
687 /* we cut off the high part here */
688 length
= new_size
.u
.LowPart
;
689 buffer
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, stream
->u
.mem
.buffer
, length
);
691 return STG_E_INSUFFICIENTMEMORY
;
693 stream
->u
.mem
.buffer
= buffer
;
694 stream
->u
.mem
.length
= length
;
699 static HRESULT WINAPI
shstream_CopyTo(IStream
*iface
, IStream
*dest
, ULARGE_INTEGER size
,
700 ULARGE_INTEGER
*read_len
, ULARGE_INTEGER
*written
)
702 struct shstream
*stream
= impl_from_IStream(iface
);
703 ULARGE_INTEGER total_read
, total_written
;
707 TRACE("(%p, %p, %s, %p, %p)\n", stream
, dest
, wine_dbgstr_longlong(size
.QuadPart
), read_len
, written
);
712 total_read
.QuadPart
= 0;
713 total_written
.QuadPart
= 0;
715 while (size
.QuadPart
> 0)
717 ULONG chunk_size
= size
.QuadPart
>= sizeof(buffer
) ? sizeof(buffer
) : size
.u
.LowPart
;
718 ULONG chunk_read
, chunk_written
;
720 hr
= IStream_Read(iface
, buffer
, chunk_size
, &chunk_read
);
724 total_read
.QuadPart
+= chunk_read
;
728 hr
= IStream_Write(dest
, buffer
, chunk_read
, &chunk_written
);
732 total_written
.QuadPart
+= chunk_written
;
735 if (chunk_read
!= chunk_size
)
738 size
.QuadPart
-= chunk_read
;
742 read_len
->QuadPart
= total_read
.QuadPart
;
744 written
->QuadPart
= total_written
.QuadPart
;
749 static HRESULT WINAPI
shstream_Commit(IStream
*iface
, DWORD flags
)
751 TRACE("%p, %#lx.\n", iface
, flags
);
753 /* Commit is not supported by this stream */
757 static HRESULT WINAPI
shstream_Revert(IStream
*iface
)
759 struct shstream
*stream
= impl_from_IStream(iface
);
761 TRACE("(%p)\n", stream
);
763 /* revert not supported by this stream */
767 static HRESULT WINAPI
shstream_LockRegion(IStream
*iface
, ULARGE_INTEGER offset
, ULARGE_INTEGER size
, DWORD lock_type
)
769 struct shstream
*stream
= impl_from_IStream(iface
);
771 TRACE("(%p)\n", stream
);
773 /* lock/unlock not supported by this stream */
777 static HRESULT WINAPI
shstream_UnlockRegion(IStream
*iface
, ULARGE_INTEGER offset
, ULARGE_INTEGER size
, DWORD lock_type
)
779 struct shstream
*stream
= impl_from_IStream(iface
);
781 TRACE("(%p)\n", stream
);
783 /* lock/unlock not supported by this stream */
787 static HRESULT WINAPI
memstream_Stat(IStream
*iface
, STATSTG
*statstg
, DWORD flags
)
789 struct shstream
*stream
= impl_from_IStream(iface
);
791 TRACE("%p, %p, %#lx.\n", iface
, statstg
, flags
);
793 memset(statstg
, 0, sizeof(*statstg
));
794 statstg
->type
= STGTY_STREAM
;
795 statstg
->cbSize
.QuadPart
= stream
->u
.mem
.length
;
796 statstg
->grfMode
= STGM_READWRITE
;
801 static HRESULT WINAPI
shstream_Clone(IStream
*iface
, IStream
**dest
)
803 struct shstream
*stream
= impl_from_IStream(iface
);
805 TRACE("(%p, %p)\n", stream
, dest
);
809 /* clone not supported by this stream */
813 static const IStreamVtbl memstreamvtbl
=
815 shstream_QueryInterface
,
826 shstream_UnlockRegion
,
831 static struct shstream
*shstream_create(const IStreamVtbl
*vtbl
, const BYTE
*data
, UINT data_len
)
833 struct shstream
*stream
;
838 stream
= heap_alloc(sizeof(*stream
));
839 stream
->IStream_iface
.lpVtbl
= vtbl
;
840 stream
->refcount
= 1;
841 stream
->u
.mem
.buffer
= heap_alloc(data_len
);
842 if (!stream
->u
.mem
.buffer
)
847 memcpy(stream
->u
.mem
.buffer
, data
, data_len
);
848 stream
->u
.mem
.length
= data_len
;
849 stream
->u
.mem
.position
= 0;
854 /*************************************************************************
855 * SHCreateMemStream [SHCORE.@]
857 * Create an IStream object on a block of memory.
860 * data [I] Memory block to create the IStream object on
861 * data_len [I] Length of data block
864 * Success: A pointer to the IStream object.
865 * Failure: NULL, if any parameters are invalid or an error occurs.
868 * A copy of the memory block is made, it's freed when the stream is released.
870 IStream
* WINAPI
SHCreateMemStream(const BYTE
*data
, UINT data_len
)
872 struct shstream
*stream
;
874 TRACE("(%p, %u)\n", data
, data_len
);
876 stream
= shstream_create(&memstreamvtbl
, data
, data_len
);
877 return stream
? &stream
->IStream_iface
: NULL
;
880 static ULONG WINAPI
filestream_Release(IStream
*iface
)
882 struct shstream
*stream
= impl_from_IStream(iface
);
883 ULONG refcount
= InterlockedDecrement(&stream
->refcount
);
885 TRACE("%p, refcount %lu.\n", iface
, refcount
);
889 CloseHandle(stream
->u
.file
.handle
);
890 heap_free(stream
->u
.file
.path
);
897 static HRESULT WINAPI
filestream_Read(IStream
*iface
, void *buff
, ULONG size
, ULONG
*read_len
)
899 struct shstream
*stream
= impl_from_IStream(iface
);
902 TRACE("%p, %p, %lu, %p.\n", iface
, buff
, size
, read_len
);
904 if (!ReadFile(stream
->u
.file
.handle
, buff
, size
, &read
, NULL
))
906 WARN("error %ld reading file\n", GetLastError());
913 return read
== size
? S_OK
: S_FALSE
;
916 static HRESULT WINAPI
filestream_Write(IStream
*iface
, const void *buff
, ULONG size
, ULONG
*written
)
918 struct shstream
*stream
= impl_from_IStream(iface
);
919 DWORD written_len
= 0;
921 TRACE("%p, %p, %lu, %p.\n", iface
, buff
, size
, written
);
923 switch (stream
->u
.file
.mode
& 0xf)
929 return STG_E_ACCESSDENIED
;
932 if (!WriteFile(stream
->u
.file
.handle
, buff
, size
, &written_len
, NULL
))
933 return HRESULT_FROM_WIN32(GetLastError());
936 *written
= written_len
;
941 static HRESULT WINAPI
filestream_Seek(IStream
*iface
, LARGE_INTEGER move
, DWORD origin
, ULARGE_INTEGER
*new_pos
)
943 struct shstream
*stream
= impl_from_IStream(iface
);
946 TRACE("%p, %s, %ld, %p.\n", iface
, wine_dbgstr_longlong(move
.QuadPart
), origin
, new_pos
);
948 position
= SetFilePointer(stream
->u
.file
.handle
, move
.u
.LowPart
, NULL
, origin
);
949 if (position
== INVALID_SET_FILE_POINTER
)
950 return HRESULT_FROM_WIN32(GetLastError());
954 new_pos
->u
.HighPart
= 0;
955 new_pos
->u
.LowPart
= position
;
961 static HRESULT WINAPI
filestream_SetSize(IStream
*iface
, ULARGE_INTEGER size
)
963 struct shstream
*stream
= impl_from_IStream(iface
);
964 LARGE_INTEGER origin
, move
;
966 TRACE("(%p, %s)\n", stream
, wine_dbgstr_longlong(size
.QuadPart
));
969 if (!SetFilePointerEx(stream
->u
.file
.handle
, move
, &origin
, FILE_CURRENT
))
972 move
.QuadPart
= size
.QuadPart
;
973 if (!SetFilePointerEx(stream
->u
.file
.handle
, move
, NULL
, FILE_BEGIN
))
976 if (stream
->u
.file
.mode
!= STGM_READ
)
978 if (!SetEndOfFile(stream
->u
.file
.handle
))
980 if (!SetFilePointerEx(stream
->u
.file
.handle
, origin
, NULL
, FILE_BEGIN
))
987 static HRESULT WINAPI
filestream_CopyTo(IStream
*iface
, IStream
*dest
, ULARGE_INTEGER size
,
988 ULARGE_INTEGER
*read_len
, ULARGE_INTEGER
*written
)
990 struct shstream
*stream
= impl_from_IStream(iface
);
994 TRACE("(%p, %p, %s, %p, %p)\n", stream
, dest
, wine_dbgstr_longlong(size
.QuadPart
), read_len
, written
);
997 read_len
->QuadPart
= 0;
999 written
->QuadPart
= 0;
1004 while (size
.QuadPart
)
1006 ULONG left
, read_chunk
, written_chunk
;
1008 left
= size
.QuadPart
> sizeof(buff
) ? sizeof(buff
) : size
.QuadPart
;
1011 hr
= IStream_Read(iface
, buff
, left
, &read_chunk
);
1012 if (FAILED(hr
) || read_chunk
== 0)
1015 read_len
->QuadPart
+= read_chunk
;
1018 hr
= IStream_Write(dest
, buff
, read_chunk
, &written_chunk
);
1020 written
->QuadPart
+= written_chunk
;
1021 if (FAILED(hr
) || written_chunk
!= left
)
1024 size
.QuadPart
-= left
;
1030 static HRESULT WINAPI
filestream_Commit(IStream
*iface
, DWORD flags
)
1032 TRACE("%p, %#lx.\n", iface
, flags
);
1037 static HRESULT WINAPI
filestream_Stat(IStream
*iface
, STATSTG
*statstg
, DWORD flags
)
1039 struct shstream
*stream
= impl_from_IStream(iface
);
1040 BY_HANDLE_FILE_INFORMATION fi
;
1042 TRACE("%p, %p, %#lx.\n", iface
, statstg
, flags
);
1045 return STG_E_INVALIDPOINTER
;
1047 memset(&fi
, 0, sizeof(fi
));
1048 GetFileInformationByHandle(stream
->u
.file
.handle
, &fi
);
1050 if (flags
& STATFLAG_NONAME
)
1051 statstg
->pwcsName
= NULL
;
1054 int len
= lstrlenW(stream
->u
.file
.path
);
1055 if ((statstg
->pwcsName
= CoTaskMemAlloc((len
+ 1) * sizeof(WCHAR
))))
1056 memcpy(statstg
->pwcsName
, stream
->u
.file
.path
, (len
+ 1) * sizeof(WCHAR
));
1059 statstg
->cbSize
.u
.LowPart
= fi
.nFileSizeLow
;
1060 statstg
->cbSize
.u
.HighPart
= fi
.nFileSizeHigh
;
1061 statstg
->mtime
= fi
.ftLastWriteTime
;
1062 statstg
->ctime
= fi
.ftCreationTime
;
1063 statstg
->atime
= fi
.ftLastAccessTime
;
1064 statstg
->grfMode
= stream
->u
.file
.mode
;
1065 statstg
->grfLocksSupported
= 0;
1066 memcpy(&statstg
->clsid
, &IID_IStream
, sizeof(CLSID
));
1067 statstg
->grfStateBits
= 0;
1068 statstg
->reserved
= 0;
1073 static const IStreamVtbl filestreamvtbl
=
1075 shstream_QueryInterface
,
1085 shstream_LockRegion
,
1086 shstream_UnlockRegion
,
1091 /*************************************************************************
1092 * SHCreateStreamOnFileEx [SHCORE.@]
1094 HRESULT WINAPI
SHCreateStreamOnFileEx(const WCHAR
*path
, DWORD mode
, DWORD attributes
,
1095 BOOL create
, IStream
*template, IStream
**ret
)
1097 DWORD access
, share
, creation_disposition
, len
;
1098 struct shstream
*stream
;
1101 TRACE("%s, %ld, %#lx, %d, %p, %p)\n", debugstr_w(path
), mode
, attributes
,
1102 create
, template, ret
);
1104 if (!path
|| !ret
|| template)
1105 return E_INVALIDARG
;
1113 case STGM_READWRITE
:
1114 access
= GENERIC_READ
| GENERIC_WRITE
;
1117 access
= GENERIC_READ
;
1120 return E_INVALIDARG
;
1124 switch (mode
& 0xf0)
1127 case STGM_SHARE_DENY_NONE
:
1128 share
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
1130 case STGM_SHARE_DENY_READ
:
1131 share
= FILE_SHARE_WRITE
;
1133 case STGM_SHARE_DENY_WRITE
:
1134 share
= FILE_SHARE_READ
;
1136 case STGM_SHARE_EXCLUSIVE
:
1140 return E_INVALIDARG
;
1143 switch (mode
& 0xf000)
1145 case STGM_FAILIFTHERE
:
1146 creation_disposition
= create
? CREATE_NEW
: OPEN_EXISTING
;
1149 creation_disposition
= CREATE_ALWAYS
;
1152 return E_INVALIDARG
;
1155 hFile
= CreateFileW(path
, access
, share
, NULL
, creation_disposition
, attributes
, 0);
1156 if (hFile
== INVALID_HANDLE_VALUE
)
1157 return HRESULT_FROM_WIN32(GetLastError());
1159 stream
= heap_alloc(sizeof(*stream
));
1160 stream
->IStream_iface
.lpVtbl
= &filestreamvtbl
;
1161 stream
->refcount
= 1;
1162 stream
->u
.file
.handle
= hFile
;
1163 stream
->u
.file
.mode
= mode
;
1165 len
= lstrlenW(path
);
1166 stream
->u
.file
.path
= heap_alloc((len
+ 1) * sizeof(WCHAR
));
1167 memcpy(stream
->u
.file
.path
, path
, (len
+ 1) * sizeof(WCHAR
));
1169 *ret
= &stream
->IStream_iface
;
1174 /*************************************************************************
1175 * SHCreateStreamOnFileW [SHCORE.@]
1177 HRESULT WINAPI
SHCreateStreamOnFileW(const WCHAR
*path
, DWORD mode
, IStream
**stream
)
1179 TRACE("%s, %#lx, %p.\n", debugstr_w(path
), mode
, stream
);
1181 if (!path
|| !stream
)
1182 return E_INVALIDARG
;
1184 if ((mode
& (STGM_CONVERT
| STGM_DELETEONRELEASE
| STGM_TRANSACTED
)) != 0)
1185 return E_INVALIDARG
;
1187 return SHCreateStreamOnFileEx(path
, mode
, 0, FALSE
, NULL
, stream
);
1190 /*************************************************************************
1191 * SHCreateStreamOnFileA [SHCORE.@]
1193 HRESULT WINAPI
SHCreateStreamOnFileA(const char *path
, DWORD mode
, IStream
**stream
)
1199 TRACE("%s, %#lx, %p.\n", debugstr_a(path
), mode
, stream
);
1202 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND
);
1204 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
1205 pathW
= heap_alloc(len
* sizeof(WCHAR
));
1207 return E_OUTOFMEMORY
;
1209 MultiByteToWideChar(CP_ACP
, 0, path
, -1, pathW
, len
);
1210 hr
= SHCreateStreamOnFileW(pathW
, mode
, stream
);
1216 static ULONG WINAPI
regstream_Release(IStream
*iface
)
1218 struct shstream
*stream
= impl_from_IStream(iface
);
1219 ULONG refcount
= InterlockedDecrement(&stream
->refcount
);
1221 TRACE("%p, refcount %lu.\n", iface
, refcount
);
1225 if (stream
->u
.mem
.hkey
)
1227 if (stream
->u
.mem
.length
)
1228 RegSetValueExW(stream
->u
.mem
.hkey
, stream
->u
.mem
.valuename
, 0, REG_BINARY
,
1229 (const BYTE
*)stream
->u
.mem
.buffer
, stream
->u
.mem
.length
);
1231 RegDeleteValueW(stream
->u
.mem
.hkey
, stream
->u
.mem
.valuename
);
1232 RegCloseKey(stream
->u
.mem
.hkey
);
1234 CoTaskMemFree(stream
->u
.mem
.valuename
);
1235 heap_free(stream
->u
.mem
.buffer
);
1242 static const IStreamVtbl regstreamvtbl
=
1244 shstream_QueryInterface
,
1254 shstream_LockRegion
,
1255 shstream_UnlockRegion
,
1260 /*************************************************************************
1261 * SHOpenRegStream2W [SHCORE.@]
1263 IStream
* WINAPI
SHOpenRegStream2W(HKEY hKey
, const WCHAR
*subkey
, const WCHAR
*value
, DWORD mode
)
1265 struct shstream
*stream
;
1266 HKEY hStrKey
= NULL
;
1271 TRACE("%p, %s, %s, %#lx.\n", hKey
, debugstr_w(subkey
), debugstr_w(value
), mode
);
1273 if (mode
== STGM_READ
)
1274 ret
= RegOpenKeyExW(hKey
, subkey
, 0, KEY_READ
, &hStrKey
);
1275 else /* in write mode we make sure the subkey exits */
1276 ret
= RegCreateKeyExW(hKey
, subkey
, 0, NULL
, 0, KEY_READ
| KEY_WRITE
, NULL
, &hStrKey
, NULL
);
1278 if (ret
== ERROR_SUCCESS
)
1280 if (mode
== STGM_READ
|| mode
== STGM_READWRITE
)
1282 /* read initial data */
1283 ret
= RegQueryValueExW(hStrKey
, value
, 0, 0, 0, &length
);
1284 if (ret
== ERROR_SUCCESS
&& length
)
1286 buff
= heap_alloc(length
);
1287 RegQueryValueExW(hStrKey
, value
, 0, 0, buff
, &length
);
1292 buff
= heap_alloc(length
);
1294 stream
= shstream_create(®streamvtbl
, buff
, length
);
1298 stream
->u
.mem
.hkey
= hStrKey
;
1299 SHStrDupW(value
, &stream
->u
.mem
.valuename
);
1300 return &stream
->IStream_iface
;
1305 RegCloseKey(hStrKey
);
1310 /*************************************************************************
1311 * SHOpenRegStream2A [SHCORE.@]
1313 IStream
* WINAPI
SHOpenRegStream2A(HKEY hKey
, const char *subkey
, const char *value
, DWORD mode
)
1315 WCHAR
*subkeyW
= NULL
, *valueW
= NULL
;
1318 TRACE("%p, %s, %s, %#lx.\n", hKey
, debugstr_a(subkey
), debugstr_a(value
), mode
);
1320 if (subkey
&& FAILED(SHStrDupA(subkey
, &subkeyW
)))
1322 if (value
&& FAILED(SHStrDupA(value
, &valueW
)))
1324 CoTaskMemFree(subkeyW
);
1328 stream
= SHOpenRegStream2W(hKey
, subkeyW
, valueW
, mode
);
1329 CoTaskMemFree(subkeyW
);
1330 CoTaskMemFree(valueW
);
1334 /*************************************************************************
1335 * SHOpenRegStreamA [SHCORE.@]
1337 IStream
* WINAPI
SHOpenRegStreamA(HKEY hkey
, const char *subkey
, const char *value
, DWORD mode
)
1339 WCHAR
*subkeyW
= NULL
, *valueW
= NULL
;
1342 TRACE("%p, %s, %s, %#lx.\n", hkey
, debugstr_a(subkey
), debugstr_a(value
), mode
);
1344 if (subkey
&& FAILED(SHStrDupA(subkey
, &subkeyW
)))
1346 if (value
&& FAILED(SHStrDupA(value
, &valueW
)))
1348 CoTaskMemFree(subkeyW
);
1352 stream
= SHOpenRegStreamW(hkey
, subkeyW
, valueW
, mode
);
1353 CoTaskMemFree(subkeyW
);
1354 CoTaskMemFree(valueW
);
1358 static ULONG WINAPI
dummystream_AddRef(IStream
*iface
)
1364 static ULONG WINAPI
dummystream_Release(IStream
*iface
)
1370 static HRESULT WINAPI
dummystream_Read(IStream
*iface
, void *buff
, ULONG buff_size
, ULONG
*read_len
)
1378 static const IStreamVtbl dummystreamvtbl
=
1380 shstream_QueryInterface
,
1382 dummystream_Release
,
1390 shstream_LockRegion
,
1391 shstream_UnlockRegion
,
1396 static struct shstream dummyregstream
= { { &dummystreamvtbl
} };
1398 /*************************************************************************
1399 * SHOpenRegStreamW [SHCORE.@]
1401 IStream
* WINAPI
SHOpenRegStreamW(HKEY hkey
, const WCHAR
*subkey
, const WCHAR
*value
, DWORD mode
)
1405 TRACE("%p, %s, %s, %#lx.\n", hkey
, debugstr_w(subkey
), debugstr_w(value
), mode
);
1406 stream
= SHOpenRegStream2W(hkey
, subkey
, value
, mode
);
1407 return stream
? stream
: &dummyregstream
.IStream_iface
;
1412 IUnknown IUnknown_iface
;
1416 static inline struct threadref
*threadref_impl_from_IUnknown(IUnknown
*iface
)
1418 return CONTAINING_RECORD(iface
, struct threadref
, IUnknown_iface
);
1421 static HRESULT WINAPI
threadref_QueryInterface(IUnknown
*iface
, REFIID riid
, void **out
)
1423 struct threadref
*threadref
= threadref_impl_from_IUnknown(iface
);
1425 TRACE("(%p, %s, %p)\n", threadref
, debugstr_guid(riid
), out
);
1430 if (IsEqualGUID(&IID_IUnknown
, riid
))
1433 IUnknown_AddRef(iface
);
1438 WARN("Interface %s not supported.\n", debugstr_guid(riid
));
1439 return E_NOINTERFACE
;
1442 static ULONG WINAPI
threadref_AddRef(IUnknown
*iface
)
1444 struct threadref
*threadref
= threadref_impl_from_IUnknown(iface
);
1445 LONG refcount
= InterlockedIncrement(threadref
->refcount
);
1447 TRACE("%p, refcount %ld.\n", threadref
, refcount
);
1452 static ULONG WINAPI
threadref_Release(IUnknown
*iface
)
1454 struct threadref
*threadref
= threadref_impl_from_IUnknown(iface
);
1455 LONG refcount
= InterlockedDecrement(threadref
->refcount
);
1457 TRACE("%p, refcount %ld.\n", threadref
, refcount
);
1460 heap_free(threadref
);
1465 static const IUnknownVtbl threadrefvtbl
=
1467 threadref_QueryInterface
,
1472 /*************************************************************************
1473 * SHCreateThreadRef [SHCORE.@]
1475 HRESULT WINAPI
SHCreateThreadRef(LONG
*refcount
, IUnknown
**out
)
1477 struct threadref
*threadref
;
1479 TRACE("(%p, %p)\n", refcount
, out
);
1481 if (!refcount
|| !out
)
1482 return E_INVALIDARG
;
1486 threadref
= heap_alloc(sizeof(*threadref
));
1488 return E_OUTOFMEMORY
;
1489 threadref
->IUnknown_iface
.lpVtbl
= &threadrefvtbl
;
1490 threadref
->refcount
= refcount
;
1493 *out
= &threadref
->IUnknown_iface
;
1495 TRACE("Created %p.\n", threadref
);
1499 /*************************************************************************
1500 * SHGetThreadRef [SHCORE.@]
1502 HRESULT WINAPI
SHGetThreadRef(IUnknown
**out
)
1504 TRACE("(%p)\n", out
);
1506 if (shcore_tls
== TLS_OUT_OF_INDEXES
)
1507 return E_NOINTERFACE
;
1509 *out
= TlsGetValue(shcore_tls
);
1511 return E_NOINTERFACE
;
1513 IUnknown_AddRef(*out
);
1517 /*************************************************************************
1518 * SHSetThreadRef [SHCORE.@]
1520 HRESULT WINAPI
SHSetThreadRef(IUnknown
*obj
)
1522 TRACE("(%p)\n", obj
);
1524 if (shcore_tls
== TLS_OUT_OF_INDEXES
)
1525 return E_NOINTERFACE
;
1527 TlsSetValue(shcore_tls
, obj
);
1531 /*************************************************************************
1532 * SHReleaseThreadRef [SHCORE.@]
1534 HRESULT WINAPI
SHReleaseThreadRef(void)
1536 FIXME("() - stub!\n");
1540 /*************************************************************************
1541 * GetProcessReference [SHCORE.@]
1543 HRESULT WINAPI
GetProcessReference(IUnknown
**obj
)
1545 TRACE("(%p)\n", obj
);
1553 IUnknown_AddRef(*obj
);
1558 /*************************************************************************
1559 * SetProcessReference [SHCORE.@]
1561 void WINAPI
SetProcessReference(IUnknown
*obj
)
1563 TRACE("(%p)\n", obj
);
1570 LPTHREAD_START_ROUTINE thread_proc
;
1571 LPTHREAD_START_ROUTINE callback
;
1575 IUnknown
*thread_ref
;
1576 IUnknown
*process_ref
;
1579 static DWORD WINAPI
shcore_thread_wrapper(void *data
)
1581 struct thread_data thread_data
;
1582 HRESULT hr
= E_FAIL
;
1585 TRACE("(%p)\n", data
);
1587 /* We are now executing in the context of the newly created thread.
1588 * So we copy the data passed to us (it is on the stack of the function
1589 * that called us, which is waiting for us to signal an event before
1591 thread_data
= *(struct thread_data
*)data
;
1593 if (thread_data
.flags
& CTF_COINIT
)
1595 hr
= CoInitializeEx(NULL
, COINIT_APARTMENTTHREADED
| COINIT_DISABLE_OLE1DDE
);
1597 hr
= CoInitializeEx(NULL
, COINIT_DISABLE_OLE1DDE
);
1600 if (thread_data
.callback
)
1601 thread_data
.callback(thread_data
.data
);
1603 /* Signal the thread that created us; it can return now. */
1604 SetEvent(thread_data
.hEvent
);
1606 /* Execute the callers start code. */
1607 retval
= thread_data
.thread_proc(thread_data
.data
);
1609 /* Release thread and process references. */
1610 if (thread_data
.thread_ref
)
1611 IUnknown_Release(thread_data
.thread_ref
);
1613 if (thread_data
.process_ref
)
1614 IUnknown_Release(thread_data
.process_ref
);
1622 /*************************************************************************
1623 * SHCreateThread [SHCORE.@]
1625 BOOL WINAPI
SHCreateThread(LPTHREAD_START_ROUTINE thread_proc
, void *data
, DWORD flags
, LPTHREAD_START_ROUTINE callback
)
1627 struct thread_data thread_data
;
1628 BOOL called
= FALSE
;
1630 TRACE("%p, %p, %#lx, %p.\n", thread_proc
, data
, flags
, callback
);
1632 thread_data
.thread_proc
= thread_proc
;
1633 thread_data
.callback
= callback
;
1634 thread_data
.data
= data
;
1635 thread_data
.flags
= flags
;
1636 thread_data
.hEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1638 if (flags
& CTF_THREAD_REF
)
1639 SHGetThreadRef(&thread_data
.thread_ref
);
1641 thread_data
.thread_ref
= NULL
;
1643 if (flags
& CTF_PROCESS_REF
)
1644 GetProcessReference(&thread_data
.process_ref
);
1646 thread_data
.process_ref
= NULL
;
1648 /* Create the thread */
1649 if (thread_data
.hEvent
)
1654 hThread
= CreateThread(NULL
, 0, shcore_thread_wrapper
, &thread_data
, 0, &retval
);
1657 /* Wait for the thread to signal us to continue */
1658 WaitForSingleObject(thread_data
.hEvent
, INFINITE
);
1659 CloseHandle(hThread
);
1662 CloseHandle(thread_data
.hEvent
);
1667 if (!thread_data
.callback
&& flags
& CTF_INSIST
)
1669 /* Couldn't call, call synchronously */
1670 thread_data
.thread_proc(data
);
1675 if (thread_data
.thread_ref
)
1676 IUnknown_Release(thread_data
.thread_ref
);
1678 if (thread_data
.process_ref
)
1679 IUnknown_Release(thread_data
.process_ref
);
1686 /*************************************************************************
1687 * SHStrDupW [SHCORE.@]
1689 HRESULT WINAPI
SHStrDupW(const WCHAR
*src
, WCHAR
**dest
)
1693 TRACE("(%s, %p)\n", debugstr_w(src
), dest
);
1698 return E_INVALIDARG
;
1700 len
= (lstrlenW(src
) + 1) * sizeof(WCHAR
);
1701 *dest
= CoTaskMemAlloc(len
);
1703 return E_OUTOFMEMORY
;
1705 memcpy(*dest
, src
, len
);
1710 /*************************************************************************
1711 * SHStrDupA [SHCORE.@]
1713 HRESULT WINAPI
SHStrDupA(const char *src
, WCHAR
**dest
)
1720 return E_INVALIDARG
;
1722 len
= MultiByteToWideChar(CP_ACP
, 0, src
, -1, NULL
, 0);
1723 *dest
= CoTaskMemAlloc(len
* sizeof(WCHAR
));
1725 return E_OUTOFMEMORY
;
1727 MultiByteToWideChar(CP_ACP
, 0, src
, -1, *dest
, len
);
1732 /*************************************************************************
1733 * SHAnsiToAnsi [SHCORE.@]
1735 DWORD WINAPI
SHAnsiToAnsi(const char *src
, char *dest
, int dest_len
)
1739 TRACE("(%s, %p, %d)\n", debugstr_a(src
), dest
, dest_len
);
1741 if (!src
|| !dest
|| dest_len
<= 0)
1744 lstrcpynA(dest
, src
, dest_len
);
1747 return src
[ret
] ? 0 : ret
+ 1;
1750 /*************************************************************************
1751 * SHUnicodeToAnsi [SHCORE.@]
1753 DWORD WINAPI
SHUnicodeToAnsi(const WCHAR
*src
, char *dest
, int dest_len
)
1757 TRACE("(%s, %p, %d)\n", debugstr_w(src
), dest
, dest_len
);
1759 if (!dest
|| !dest_len
)
1764 ret
= WideCharToMultiByte(CP_ACP
, 0, src
, -1, dest
, dest_len
, NULL
, NULL
);
1767 dest
[dest_len
- 1] = 0;
1777 /*************************************************************************
1778 * SHUnicodeToUnicode [SHCORE.@]
1780 DWORD WINAPI
SHUnicodeToUnicode(const WCHAR
*src
, WCHAR
*dest
, int dest_len
)
1784 TRACE("(%s, %p, %d)\n", debugstr_w(src
), dest
, dest_len
);
1786 if (!src
|| !dest
|| dest_len
<= 0)
1789 lstrcpynW(dest
, src
, dest_len
);
1790 ret
= lstrlenW(dest
);
1792 return src
[ret
] ? 0 : ret
+ 1;
1795 /*************************************************************************
1796 * SHAnsiToUnicode [SHCORE.@]
1798 DWORD WINAPI
SHAnsiToUnicode(const char *src
, WCHAR
*dest
, int dest_len
)
1802 TRACE("(%s, %p, %d)\n", debugstr_a(src
), dest
, dest_len
);
1804 if (!dest
|| !dest_len
)
1809 ret
= MultiByteToWideChar(CP_ACP
, 0, src
, -1, dest
, dest_len
);
1812 dest
[dest_len
- 1] = 0;
1822 /*************************************************************************
1823 * SHRegDuplicateHKey [SHCORE.@]
1825 HKEY WINAPI
SHRegDuplicateHKey(HKEY hKey
)
1829 RegOpenKeyExW(hKey
, 0, 0, MAXIMUM_ALLOWED
, &newKey
);
1830 TRACE("new key is %p\n", newKey
);
1834 /*************************************************************************
1835 * SHDeleteEmptyKeyW [SHCORE.@]
1837 DWORD WINAPI
SHDeleteEmptyKeyW(HKEY hkey
, const WCHAR
*subkey
)
1839 DWORD ret
, count
= 0;
1842 TRACE("(%p, %s)\n", hkey
, debugstr_w(subkey
));
1844 ret
= RegOpenKeyExW(hkey
, subkey
, 0, KEY_READ
, &hsubkey
);
1847 ret
= RegQueryInfoKeyW(hsubkey
, NULL
, NULL
, NULL
, &count
,
1848 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1849 RegCloseKey(hsubkey
);
1853 ret
= ERROR_KEY_HAS_CHILDREN
;
1855 ret
= RegDeleteKeyW(hkey
, subkey
);
1862 /*************************************************************************
1863 * SHDeleteEmptyKeyA [SHCORE.@]
1865 DWORD WINAPI
SHDeleteEmptyKeyA(HKEY hkey
, const char *subkey
)
1867 WCHAR
*subkeyW
= NULL
;
1870 TRACE("(%p, %s)\n", hkey
, debugstr_a(subkey
));
1872 if (subkey
&& FAILED(SHStrDupA(subkey
, &subkeyW
)))
1873 return ERROR_OUTOFMEMORY
;
1875 ret
= SHDeleteEmptyKeyW(hkey
, subkeyW
);
1876 CoTaskMemFree(subkeyW
);
1880 /*************************************************************************
1881 * SHDeleteKeyW [SHCORE.@]
1883 DWORD WINAPI
SHDeleteKeyW(HKEY hkey
, const WCHAR
*subkey
)
1885 TRACE("(%p, %s)\n", hkey
, debugstr_w(subkey
));
1887 return RegDeleteTreeW(hkey
, subkey
);
1890 /*************************************************************************
1891 * SHDeleteKeyA [SHCORE.@]
1893 DWORD WINAPI
SHDeleteKeyA(HKEY hkey
, const char *subkey
)
1895 TRACE("(%p, %s)\n", hkey
, debugstr_a(subkey
));
1897 return RegDeleteTreeA(hkey
, subkey
);
1900 /*************************************************************************
1901 * SHDeleteValueW [SHCORE.@]
1903 DWORD WINAPI
SHDeleteValueW(HKEY hkey
, const WCHAR
*subkey
, const WCHAR
*value
)
1908 TRACE("(%p, %s, %s)\n", hkey
, debugstr_w(subkey
), debugstr_w(value
));
1910 ret
= RegOpenKeyExW(hkey
, subkey
, 0, KEY_SET_VALUE
, &hsubkey
);
1913 ret
= RegDeleteValueW(hsubkey
, value
);
1914 RegCloseKey(hsubkey
);
1920 /*************************************************************************
1921 * SHDeleteValueA [SHCORE.@]
1923 DWORD WINAPI
SHDeleteValueA(HKEY hkey
, const char *subkey
, const char *value
)
1925 WCHAR
*subkeyW
= NULL
, *valueW
= NULL
;
1928 TRACE("(%p, %s, %s)\n", hkey
, debugstr_a(subkey
), debugstr_a(value
));
1930 if (subkey
&& FAILED(SHStrDupA(subkey
, &subkeyW
)))
1931 return ERROR_OUTOFMEMORY
;
1932 if (value
&& FAILED(SHStrDupA(value
, &valueW
)))
1934 CoTaskMemFree(subkeyW
);
1935 return ERROR_OUTOFMEMORY
;
1938 ret
= SHDeleteValueW(hkey
, subkeyW
, valueW
);
1939 CoTaskMemFree(subkeyW
);
1940 CoTaskMemFree(valueW
);
1944 /*************************************************************************
1945 * SHCopyKeyA [SHCORE.@]
1947 DWORD WINAPI
SHCopyKeyA(HKEY hkey_src
, const char *subkey
, HKEY hkey_dst
, DWORD reserved
)
1949 WCHAR
*subkeyW
= NULL
;
1952 TRACE("%p, %s, %p, %ld.\n", hkey_src
, debugstr_a(subkey
), hkey_dst
, reserved
);
1954 if (subkey
&& FAILED(SHStrDupA(subkey
, &subkeyW
)))
1957 ret
= SHCopyKeyW(hkey_src
, subkeyW
, hkey_dst
, reserved
);
1958 CoTaskMemFree(subkeyW
);
1962 /*************************************************************************
1963 * SHCopyKeyW [SHCORE.@]
1965 DWORD WINAPI
SHCopyKeyW(HKEY hkey_src
, const WCHAR
*subkey
, HKEY hkey_dst
, DWORD reserved
)
1967 DWORD key_count
= 0, value_count
= 0, max_key_len
= 0;
1968 WCHAR name
[MAX_PATH
], *ptr_name
= name
;
1969 BYTE buff
[1024], *ptr
= buff
;
1970 DWORD max_data_len
= 0, i
;
1973 TRACE("%p, %s, %p, %ld.\n", hkey_src
, debugstr_w(subkey
), hkey_dst
, reserved
);
1975 if (!hkey_dst
|| !hkey_src
)
1976 return ERROR_INVALID_PARAMETER
;
1979 ret
= RegOpenKeyExW(hkey_src
, subkey
, 0, KEY_ALL_ACCESS
, &hkey_src
);
1982 hkey_src
= NULL
; /* Don't close this key since we didn't open it */
1985 DWORD max_value_len
;
1987 ret
= RegQueryInfoKeyW(hkey_src
, NULL
, NULL
, NULL
, &key_count
, &max_key_len
,
1988 NULL
, &value_count
, &max_value_len
, &max_data_len
, NULL
, NULL
);
1991 /* Get max size for key/value names */
1992 max_key_len
= max(max_key_len
, max_value_len
);
1994 if (max_key_len
++ > MAX_PATH
- 1)
1995 ptr_name
= heap_alloc(max_key_len
* sizeof(WCHAR
));
1997 if (max_data_len
> sizeof(buff
))
1998 ptr
= heap_alloc(max_data_len
);
2000 if (!ptr_name
|| !ptr
)
2001 ret
= ERROR_NOT_ENOUGH_MEMORY
;
2005 for (i
= 0; i
< key_count
&& !ret
; i
++)
2007 HKEY hsubkey_src
, hsubkey_dst
;
2008 DWORD length
= max_key_len
;
2010 ret
= RegEnumKeyExW(hkey_src
, i
, ptr_name
, &length
, NULL
, NULL
, NULL
, NULL
);
2013 ret
= RegOpenKeyExW(hkey_src
, ptr_name
, 0, KEY_READ
, &hsubkey_src
);
2016 /* Create destination sub key */
2017 ret
= RegCreateKeyW(hkey_dst
, ptr_name
, &hsubkey_dst
);
2020 /* Recursively copy keys and values from the sub key */
2021 ret
= SHCopyKeyW(hsubkey_src
, NULL
, hsubkey_dst
, 0);
2022 RegCloseKey(hsubkey_dst
);
2025 RegCloseKey(hsubkey_src
);
2029 /* Copy all the values in this key */
2030 for (i
= 0; i
< value_count
&& !ret
; i
++)
2032 DWORD length
= max_key_len
, type
, data_len
= max_data_len
;
2034 ret
= RegEnumValueW(hkey_src
, i
, ptr_name
, &length
, NULL
, &type
, ptr
, &data_len
);
2036 ret
= SHSetValueW(hkey_dst
, NULL
, ptr_name
, type
, ptr
, data_len
);
2040 /* Free buffers if allocated */
2041 if (ptr_name
!= name
)
2042 heap_free(ptr_name
);
2046 if (subkey
&& hkey_src
)
2047 RegCloseKey(hkey_src
);
2053 /*************************************************************************
2054 * SHEnumKeyExA [SHCORE.@]
2056 LONG WINAPI
SHEnumKeyExA(HKEY hkey
, DWORD index
, char *subkey
, DWORD
*length
)
2058 TRACE("%p, %ld, %s, %p.\n", hkey
, index
, debugstr_a(subkey
), length
);
2060 return RegEnumKeyExA(hkey
, index
, subkey
, length
, NULL
, NULL
, NULL
, NULL
);
2063 /*************************************************************************
2064 * SHEnumKeyExW [SHCORE.@]
2066 LONG WINAPI
SHEnumKeyExW(HKEY hkey
, DWORD index
, WCHAR
*subkey
, DWORD
*length
)
2068 TRACE("%p, %ld, %s, %p.\n", hkey
, index
, debugstr_w(subkey
), length
);
2070 return RegEnumKeyExW(hkey
, index
, subkey
, length
, NULL
, NULL
, NULL
, NULL
);
2073 /*************************************************************************
2074 * SHEnumValueA [SHCORE.@]
2076 LONG WINAPI
SHEnumValueA(HKEY hkey
, DWORD index
, char *value
, DWORD
*length
, DWORD
*type
,
2077 void *data
, DWORD
*data_len
)
2079 TRACE("%p, %ld, %s, %p, %p, %p, %p.\n", hkey
, index
, debugstr_a(value
), length
, type
, data
, data_len
);
2081 return RegEnumValueA(hkey
, index
, value
, length
, NULL
, type
, data
, data_len
);
2084 /*************************************************************************
2085 * SHEnumValueW [SHCORE.@]
2087 LONG WINAPI
SHEnumValueW(HKEY hkey
, DWORD index
, WCHAR
*value
, DWORD
*length
, DWORD
*type
,
2088 void *data
, DWORD
*data_len
)
2090 TRACE("%p, %ld, %s, %p, %p, %p, %p.\n", hkey
, index
, debugstr_w(value
), length
, type
, data
, data_len
);
2092 return RegEnumValueW(hkey
, index
, value
, length
, NULL
, type
, data
, data_len
);
2095 /*************************************************************************
2096 * SHQueryValueExW [SHCORE.@]
2098 DWORD WINAPI
SHQueryValueExW(HKEY hkey
, const WCHAR
*name
, DWORD
*reserved
, DWORD
*type
,
2099 void *buff
, DWORD
*buff_len
)
2101 DWORD ret
, value_type
, data_len
= 0;
2103 TRACE("(%p, %s, %p, %p, %p, %p)\n", hkey
, debugstr_w(name
), reserved
, type
, buff
, buff_len
);
2106 data_len
= *buff_len
;
2108 ret
= RegQueryValueExW(hkey
, name
, reserved
, &value_type
, buff
, &data_len
);
2109 if (ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)
2112 if (buff_len
&& value_type
== REG_EXPAND_SZ
)
2117 if (!buff
|| ret
== ERROR_MORE_DATA
)
2120 value
= heap_alloc(length
);
2121 RegQueryValueExW(hkey
, name
, reserved
, NULL
, (BYTE
*)value
, &length
);
2122 length
= ExpandEnvironmentStringsW(value
, NULL
, 0);
2126 length
= (lstrlenW(buff
) + 1) * sizeof(WCHAR
);
2127 value
= heap_alloc(length
);
2128 memcpy(value
, buff
, length
);
2129 length
= ExpandEnvironmentStringsW(value
, buff
, *buff_len
/ sizeof(WCHAR
));
2130 if (length
> *buff_len
) ret
= ERROR_MORE_DATA
;
2132 data_len
= max(data_len
, length
);
2137 *type
= value_type
== REG_EXPAND_SZ
? REG_SZ
: value_type
;
2139 *buff_len
= data_len
;
2143 /*************************************************************************
2144 * SHQueryValueExA [SHCORE.@]
2146 DWORD WINAPI
SHQueryValueExA(HKEY hkey
, const char *name
, DWORD
*reserved
, DWORD
*type
,
2147 void *buff
, DWORD
*buff_len
)
2149 DWORD ret
, value_type
, data_len
= 0;
2151 TRACE("(%p, %s, %p, %p, %p, %p)\n", hkey
, debugstr_a(name
), reserved
, type
, buff
, buff_len
);
2154 data_len
= *buff_len
;
2156 ret
= RegQueryValueExA(hkey
, name
, reserved
, &value_type
, buff
, &data_len
);
2157 if (ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)
2160 if (buff_len
&& value_type
== REG_EXPAND_SZ
)
2165 if (!buff
|| ret
== ERROR_MORE_DATA
)
2168 value
= heap_alloc(length
);
2169 RegQueryValueExA(hkey
, name
, reserved
, NULL
, (BYTE
*)value
, &length
);
2170 length
= ExpandEnvironmentStringsA(value
, NULL
, 0);
2174 length
= strlen(buff
) + 1;
2175 value
= heap_alloc(length
);
2176 memcpy(value
, buff
, length
);
2177 length
= ExpandEnvironmentStringsA(value
, buff
, *buff_len
);
2178 if (length
> *buff_len
) ret
= ERROR_MORE_DATA
;
2180 data_len
= max(data_len
, length
);
2185 *type
= value_type
== REG_EXPAND_SZ
? REG_SZ
: value_type
;
2187 *buff_len
= data_len
;
2191 /*************************************************************************
2192 * SHGetValueA [SHCORE.@]
2194 DWORD WINAPI
SHGetValueA(HKEY hkey
, const char *subkey
, const char *value
,
2195 DWORD
*type
, void *data
, DWORD
*data_len
)
2200 TRACE("(%p, %s, %s, %p, %p, %p)\n", hkey
, debugstr_a(subkey
), debugstr_a(value
),
2201 type
, data
, data_len
);
2204 ret
= RegOpenKeyExA(hkey
, subkey
, 0, KEY_QUERY_VALUE
, &hsubkey
);
2208 ret
= SHQueryValueExA(hsubkey
? hsubkey
: hkey
, value
, 0, type
, data
, data_len
);
2210 RegCloseKey(hsubkey
);
2216 /*************************************************************************
2217 * SHGetValueW [SHCORE.@]
2219 DWORD WINAPI
SHGetValueW(HKEY hkey
, const WCHAR
*subkey
, const WCHAR
*value
,
2220 DWORD
*type
, void *data
, DWORD
*data_len
)
2225 TRACE("(%p, %s, %s, %p, %p, %p)\n", hkey
, debugstr_w(subkey
), debugstr_w(value
),
2226 type
, data
, data_len
);
2229 ret
= RegOpenKeyExW(hkey
, subkey
, 0, KEY_QUERY_VALUE
, &hsubkey
);
2233 ret
= SHQueryValueExW(hsubkey
? hsubkey
: hkey
, value
, 0, type
, data
, data_len
);
2235 RegCloseKey(hsubkey
);
2241 /*************************************************************************
2242 * SHRegGetIntW [SHCORE.280]
2244 int WINAPI
SHRegGetIntW(HKEY hkey
, const WCHAR
*value
, int default_value
)
2249 TRACE("(%p, %s, %d)\n", hkey
, debugstr_w(value
), default_value
);
2252 buff_len
= sizeof(buff
);
2253 if (SHQueryValueExW(hkey
, value
, 0, 0, buff
, &buff_len
))
2254 return default_value
;
2256 if (*buff
>= '0' && *buff
<= '9')
2257 return wcstol(buff
, NULL
, 10);
2259 return default_value
;
2262 /*************************************************************************
2263 * SHRegGetPathA [SHCORE.@]
2265 DWORD WINAPI
SHRegGetPathA(HKEY hkey
, const char *subkey
, const char *value
, char *path
, DWORD flags
)
2267 DWORD length
= MAX_PATH
;
2269 TRACE("%p, %s, %s, %p, %#lx.\n", hkey
, debugstr_a(subkey
), debugstr_a(value
), path
, flags
);
2271 return SHGetValueA(hkey
, subkey
, value
, 0, path
, &length
);
2274 /*************************************************************************
2275 * SHRegGetPathW [SHCORE.@]
2277 DWORD WINAPI
SHRegGetPathW(HKEY hkey
, const WCHAR
*subkey
, const WCHAR
*value
, WCHAR
*path
, DWORD flags
)
2279 DWORD length
= MAX_PATH
;
2281 TRACE("%p, %s, %s, %p, %#lx.\n", hkey
, debugstr_w(subkey
), debugstr_w(value
), path
, flags
);
2283 return SHGetValueW(hkey
, subkey
, value
, 0, path
, &length
);
2286 /*************************************************************************
2287 * SHSetValueW [SHCORE.@]
2289 DWORD WINAPI
SHSetValueW(HKEY hkey
, const WCHAR
*subkey
, const WCHAR
*value
, DWORD type
,
2290 const void *data
, DWORD data_len
)
2292 DWORD ret
= ERROR_SUCCESS
, dummy
;
2295 TRACE("%p, %s, %s, %ld, %p, %ld.\n", hkey
, debugstr_w(subkey
), debugstr_w(value
),
2296 type
, data
, data_len
);
2298 if (subkey
&& *subkey
)
2299 ret
= RegCreateKeyExW(hkey
, subkey
, 0, NULL
, 0, KEY_SET_VALUE
, NULL
, &hsubkey
, &dummy
);
2305 ret
= RegSetValueExW(hsubkey
, value
, 0, type
, data
, data_len
);
2306 if (hsubkey
!= hkey
)
2307 RegCloseKey(hsubkey
);
2313 /*************************************************************************
2314 * SHSetValueA [SHCORE.@]
2316 DWORD WINAPI
SHSetValueA(HKEY hkey
, const char *subkey
, const char *value
,
2317 DWORD type
, const void *data
, DWORD data_len
)
2319 DWORD ret
= ERROR_SUCCESS
, dummy
;
2322 TRACE("%p, %s, %s, %ld, %p, %ld.\n", hkey
, debugstr_a(subkey
), debugstr_a(value
),
2323 type
, data
, data_len
);
2325 if (subkey
&& *subkey
)
2326 ret
= RegCreateKeyExA(hkey
, subkey
, 0, NULL
, 0, KEY_SET_VALUE
, NULL
, &hsubkey
, &dummy
);
2332 ret
= RegSetValueExA(hsubkey
, value
, 0, type
, data
, data_len
);
2333 if (hsubkey
!= hkey
)
2334 RegCloseKey(hsubkey
);
2340 /*************************************************************************
2341 * SHRegSetPathA [SHCORE.@]
2343 DWORD WINAPI
SHRegSetPathA(HKEY hkey
, const char *subkey
, const char *value
, const char *path
, DWORD flags
)
2345 FIXME("%p, %s, %s, %s, %#lx - semi-stub\n", hkey
, debugstr_a(subkey
),
2346 debugstr_a(value
), debugstr_a(path
), flags
);
2348 /* FIXME: PathUnExpandEnvStringsA() */
2350 return SHSetValueA(hkey
, subkey
, value
, REG_SZ
, path
, lstrlenA(path
));
2353 /*************************************************************************
2354 * SHRegSetPathW [SHCORE.@]
2356 DWORD WINAPI
SHRegSetPathW(HKEY hkey
, const WCHAR
*subkey
, const WCHAR
*value
, const WCHAR
*path
, DWORD flags
)
2358 FIXME("%p, %s, %s, %s, %#lx semi-stub\n", hkey
, debugstr_w(subkey
),
2359 debugstr_w(value
), debugstr_w(path
), flags
);
2361 /* FIXME: PathUnExpandEnvStringsW(); */
2363 return SHSetValueW(hkey
, subkey
, value
, REG_SZ
, path
, lstrlenW(path
));
2366 /*************************************************************************
2367 * SHQueryInfoKeyA [SHCORE.@]
2369 LONG WINAPI
SHQueryInfoKeyA(HKEY hkey
, DWORD
*subkeys
, DWORD
*subkey_max
, DWORD
*values
, DWORD
*value_max
)
2371 TRACE("(%p, %p, %p, %p, %p)\n", hkey
, subkeys
, subkey_max
, values
, value_max
);
2373 return RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, subkeys
, subkey_max
, NULL
, values
, value_max
, NULL
, NULL
, NULL
);
2376 /*************************************************************************
2377 * SHQueryInfoKeyW [SHCORE.@]
2379 LONG WINAPI
SHQueryInfoKeyW(HKEY hkey
, DWORD
*subkeys
, DWORD
*subkey_max
, DWORD
*values
, DWORD
*value_max
)
2381 TRACE("(%p, %p, %p, %p, %p)\n", hkey
, subkeys
, subkey_max
, values
, value_max
);
2383 return RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, subkeys
, subkey_max
, NULL
, values
, value_max
, NULL
, NULL
, NULL
);
2386 /*************************************************************************
2389 BOOL WINAPI
IsOS(DWORD feature
)
2391 DWORD platform
, majorv
, minorv
;
2392 OSVERSIONINFOA osvi
;
2394 osvi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOA
);
2395 if (!GetVersionExA(&osvi
))
2398 majorv
= osvi
.dwMajorVersion
;
2399 minorv
= osvi
.dwMinorVersion
;
2400 platform
= osvi
.dwPlatformId
;
2402 #define ISOS_RETURN(x) \
2403 TRACE("(%#lx) ret %d\n",feature,(x)); \
2407 case OS_WIN32SORGREATER
:
2408 ISOS_RETURN(platform
== VER_PLATFORM_WIN32s
2409 || platform
== VER_PLATFORM_WIN32_WINDOWS
);
2411 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
);
2412 case OS_WIN95ORGREATER
:
2413 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_WINDOWS
);
2414 case OS_NT4ORGREATER
:
2415 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& majorv
>= 4);
2416 case OS_WIN2000ORGREATER_ALT
:
2417 case OS_WIN2000ORGREATER
:
2418 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& majorv
>= 5);
2419 case OS_WIN98ORGREATER
:
2420 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_WINDOWS
&& minorv
>= 10);
2422 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_WINDOWS
&& minorv
== 10);
2424 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& majorv
>= 5);
2425 case OS_WIN2000SERVER
:
2426 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& (minorv
== 0 || minorv
== 1));
2427 case OS_WIN2000ADVSERVER
:
2428 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& (minorv
== 0 || minorv
== 1));
2429 case OS_WIN2000DATACENTER
:
2430 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& (minorv
== 0 || minorv
== 1));
2431 case OS_WIN2000TERMINAL
:
2432 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& (minorv
== 0 || minorv
== 1));
2434 FIXME("(OS_EMBEDDED) What should we return here?\n");
2436 case OS_TERMINALCLIENT
:
2437 FIXME("(OS_TERMINALCLIENT) What should we return here?\n");
2439 case OS_TERMINALREMOTEADMIN
:
2440 FIXME("(OS_TERMINALREMOTEADMIN) What should we return here?\n");
2443 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_WINDOWS
&& minorv
== 0);
2444 case OS_MEORGREATER
:
2445 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_WINDOWS
&& minorv
>= 90);
2446 case OS_XPORGREATER
:
2447 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& majorv
>= 5 && minorv
>= 1);
2449 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& majorv
>= 5 && minorv
>= 1);
2450 case OS_PROFESSIONAL
:
2451 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
);
2453 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
);
2455 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& majorv
>= 5);
2457 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
);
2458 case OS_TERMINALSERVER
:
2459 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
);
2460 case OS_PERSONALTERMINALSERVER
:
2461 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& minorv
>= 1 && majorv
>= 5);
2462 case OS_FASTUSERSWITCHING
:
2463 FIXME("(OS_FASTUSERSWITCHING) What should we return here?\n");
2465 case OS_WELCOMELOGONUI
:
2466 FIXME("(OS_WELCOMELOGONUI) What should we return here?\n");
2468 case OS_DOMAINMEMBER
:
2469 FIXME("(OS_DOMAINMEMBER) What should we return here?\n");
2472 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
);
2476 IsWow64Process(GetCurrentProcess(), &is_wow64
);
2480 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
);
2481 case OS_SMALLBUSINESSSERVER
:
2482 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
);
2484 FIXME("(OS_TABLETPC) What should we return here?\n");
2486 case OS_SERVERADMINUI
:
2487 FIXME("(OS_SERVERADMINUI) What should we return here?\n");
2489 case OS_MEDIACENTER
:
2490 FIXME("(OS_MEDIACENTER) What should we return here?\n");
2493 FIXME("(OS_APPLIANCE) What should we return here?\n");
2495 case 0x25: /*OS_VISTAORGREATER*/
2496 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& majorv
>= 6);
2501 WARN("(%#lx) unknown parameter\n", feature
);
2506 /*************************************************************************
2507 * SubscribeFeatureStateChangeNotification [SHCORE.@]
2509 void WINAPI
SubscribeFeatureStateChangeNotification(FEATURE_STATE_CHANGE_SUBSCRIPTION
*subscription
,
2510 FEATURE_STATE_CHANGE_CALLBACK
*callback
, void *context
)
2512 FIXME("(%p, %p, %p) stub\n", subscription
, callback
, context
);
2515 /*************************************************************************
2516 * GetFeatureEnabledState [SHCORE.@]
2518 FEATURE_ENABLED_STATE WINAPI
GetFeatureEnabledState(UINT32 feature
, FEATURE_CHANGE_TIME change_time
)
2520 FIXME("(%u, %u) stub\n", feature
, change_time
);
2521 return FEATURE_ENABLED_STATE_DEFAULT
;