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"
35 #include "wine/debug.h"
36 #include "wine/heap.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(shcore
);
40 static DWORD shcore_tls
;
41 static IUnknown
*process_ref
;
43 BOOL WINAPI
DllMain(HINSTANCE instance
, DWORD reason
, void *reserved
)
45 TRACE("%p, %lu, %p.\n", instance
, reason
, reserved
);
49 case DLL_PROCESS_ATTACH
:
50 DisableThreadLibraryCalls(instance
);
51 shcore_tls
= TlsAlloc();
53 case DLL_PROCESS_DETACH
:
55 if (shcore_tls
!= TLS_OUT_OF_INDEXES
)
63 HRESULT WINAPI
GetProcessDpiAwareness(HANDLE process
, PROCESS_DPI_AWARENESS
*value
)
65 if (GetProcessDpiAwarenessInternal( process
, (DPI_AWARENESS
*)value
)) return S_OK
;
66 return HRESULT_FROM_WIN32( GetLastError() );
69 HRESULT WINAPI
SetProcessDpiAwareness(PROCESS_DPI_AWARENESS value
)
71 if (SetProcessDpiAwarenessInternal( value
)) return S_OK
;
72 return HRESULT_FROM_WIN32( GetLastError() );
75 HRESULT WINAPI
GetDpiForMonitor(HMONITOR monitor
, MONITOR_DPI_TYPE type
, UINT
*x
, UINT
*y
)
77 if (GetDpiForMonitorInternal( monitor
, type
, x
, y
)) return S_OK
;
78 return HRESULT_FROM_WIN32( GetLastError() );
81 HRESULT WINAPI
GetScaleFactorForMonitor(HMONITOR monitor
, DEVICE_SCALE_FACTOR
*scale
)
83 FIXME("(%p %p): stub\n", monitor
, scale
);
85 *scale
= SCALE_100_PERCENT
;
89 DEVICE_SCALE_FACTOR WINAPI
GetScaleFactorForDevice(DISPLAY_DEVICE_TYPE device_type
)
91 FIXME("%d\n", device_type
);
93 return SCALE_100_PERCENT
;
96 HRESULT WINAPI
_IStream_Read(IStream
*stream
, void *dest
, ULONG size
)
101 TRACE("%p, %p, %lu.\n", stream
, dest
, size
);
103 hr
= IStream_Read(stream
, dest
, size
, &read
);
104 if (SUCCEEDED(hr
) && read
!= size
)
109 HRESULT WINAPI
IStream_Reset(IStream
*stream
)
111 static const LARGE_INTEGER zero
;
113 TRACE("(%p)\n", stream
);
115 return IStream_Seek(stream
, zero
, 0, NULL
);
118 HRESULT WINAPI
IStream_Size(IStream
*stream
, ULARGE_INTEGER
*size
)
123 TRACE("(%p, %p)\n", stream
, size
);
125 memset(&statstg
, 0, sizeof(statstg
));
127 hr
= IStream_Stat(stream
, &statstg
, STATFLAG_NONAME
);
129 if (SUCCEEDED(hr
) && size
)
130 *size
= statstg
.cbSize
;
134 HRESULT WINAPI
_IStream_Write(IStream
*stream
, const void *src
, ULONG size
)
139 TRACE("%p, %p, %lu.\n", stream
, src
, size
);
141 hr
= IStream_Write(stream
, src
, size
, &written
);
142 if (SUCCEEDED(hr
) && written
!= size
)
148 void WINAPI
IUnknown_AtomicRelease(IUnknown
**obj
)
150 TRACE("(%p)\n", obj
);
155 IUnknown_Release(*obj
);
159 HRESULT WINAPI
IUnknown_GetSite(IUnknown
*unk
, REFIID iid
, void **site
)
161 IObjectWithSite
*obj
= NULL
;
162 HRESULT hr
= E_INVALIDARG
;
164 TRACE("(%p, %s, %p)\n", unk
, debugstr_guid(iid
), site
);
166 if (unk
&& iid
&& site
)
168 hr
= IUnknown_QueryInterface(unk
, &IID_IObjectWithSite
, (void **)&obj
);
169 if (SUCCEEDED(hr
) && obj
)
171 hr
= IObjectWithSite_GetSite(obj
, iid
, site
);
172 IObjectWithSite_Release(obj
);
179 HRESULT WINAPI
IUnknown_QueryService(IUnknown
*obj
, REFGUID sid
, REFIID iid
, void **out
)
181 IServiceProvider
*provider
= NULL
;
192 hr
= IUnknown_QueryInterface(obj
, &IID_IServiceProvider
, (void **)&provider
);
193 if (hr
== S_OK
&& provider
)
195 TRACE("Using provider %p.\n", provider
);
197 hr
= IServiceProvider_QueryService(provider
, sid
, iid
, out
);
199 TRACE("Provider %p returned %p.\n", provider
, *out
);
201 IServiceProvider_Release(provider
);
207 void WINAPI
IUnknown_Set(IUnknown
**dest
, IUnknown
*src
)
209 TRACE("(%p, %p)\n", dest
, src
);
211 IUnknown_AtomicRelease(dest
);
215 IUnknown_AddRef(src
);
220 HRESULT WINAPI
IUnknown_SetSite(IUnknown
*obj
, IUnknown
*site
)
222 IInternetSecurityManager
*sec_manager
;
223 IObjectWithSite
*objwithsite
;
229 hr
= IUnknown_QueryInterface(obj
, &IID_IObjectWithSite
, (void **)&objwithsite
);
230 TRACE("ObjectWithSite %p, hr %#lx.\n", objwithsite
, hr
);
233 hr
= IObjectWithSite_SetSite(objwithsite
, site
);
234 TRACE("SetSite() hr %#lx.\n", hr
);
235 IObjectWithSite_Release(objwithsite
);
239 hr
= IUnknown_QueryInterface(obj
, &IID_IInternetSecurityManager
, (void **)&sec_manager
);
240 TRACE("InternetSecurityManager %p, hr %#lx.\n", sec_manager
, hr
);
244 hr
= IInternetSecurityManager_SetSecuritySite(sec_manager
, (IInternetSecurityMgrSite
*)site
);
245 TRACE("SetSecuritySite() hr %#lx.\n", hr
);
246 IInternetSecurityManager_Release(sec_manager
);
252 HRESULT WINAPI
SetCurrentProcessExplicitAppUserModelID(const WCHAR
*appid
)
254 FIXME("%s: stub\n", debugstr_w(appid
));
258 HRESULT WINAPI
GetCurrentProcessExplicitAppUserModelID(const WCHAR
**appid
)
260 FIXME("%p: stub\n", appid
);
265 /*************************************************************************
266 * CommandLineToArgvW [SHCORE.@]
268 * We must interpret the quotes in the command line to rebuild the argv
270 * - arguments are separated by spaces or tabs
271 * - quotes serve as optional argument delimiters
273 * - escaped quotes must be converted back to '"'
275 * - consecutive backslashes preceding a quote see their number halved with
276 * the remainder escaping the quote:
277 * 2n backslashes + quote -> n backslashes + quote as an argument delimiter
278 * 2n+1 backslashes + quote -> n backslashes + literal quote
279 * - backslashes that are not followed by a quote are copied literally:
282 * - in quoted strings, consecutive quotes see their number divided by three
283 * with the remainder modulo 3 deciding whether to close the string or not.
284 * Note that the opening quote must be counted in the consecutive quotes,
285 * that's the (1+) below:
286 * (1+) 3n quotes -> n quotes
287 * (1+) 3n+1 quotes -> n quotes plus closes the quoted string
288 * (1+) 3n+2 quotes -> n+1 quotes plus closes the quoted string
289 * - in unquoted strings, the first quote opens the quoted string and the
290 * remaining consecutive quotes follow the above rule.
292 WCHAR
** WINAPI
CommandLineToArgvW(const WCHAR
*cmdline
, int *numargs
)
302 SetLastError(ERROR_INVALID_PARAMETER
);
308 /* Return the path to the executable */
309 DWORD len
, deslen
= MAX_PATH
, size
;
311 size
= sizeof(WCHAR
*) * 2 + deslen
* sizeof(WCHAR
);
314 if (!(argv
= LocalAlloc(LMEM_FIXED
, size
))) return NULL
;
315 len
= GetModuleFileNameW(0, (WCHAR
*)(argv
+ 2), deslen
);
321 if (len
< deslen
) break;
323 size
= sizeof(WCHAR
*) * 2 + deslen
* sizeof(WCHAR
);
326 argv
[0] = (WCHAR
*)(argv
+ 2);
333 /* --- First count the arguments */
336 /* The first argument, the executable path, follows special rules */
339 /* The executable path ends at the next quote, no matter what */
347 /* The executable path ends at the next space, no matter what */
348 while (*s
&& *s
!= ' ' && *s
!= '\t')
351 /* skip to the first argument, if any */
352 while (*s
== ' ' || *s
== '\t')
357 /* Analyze the remaining arguments */
361 if ((*s
== ' ' || *s
== '\t') && qcount
== 0)
363 /* skip to the next argument and count it if any */
364 while (*s
== ' ' || *s
== '\t')
372 /* '\', count them */
379 if ((bcount
& 1) == 0)
380 qcount
++; /* unescaped '"' */
383 /* consecutive quotes, see comment in copying code below */
395 /* a regular character */
401 /* Allocate in a single lump, the string array, and the strings that go
402 * with it. This way the caller can make a single LocalFree() call to free
405 argv
= LocalAlloc(LMEM_FIXED
, (argc
+ 1) * sizeof(WCHAR
*) + (lstrlenW(cmdline
) + 1) * sizeof(WCHAR
));
409 /* --- Then split and copy the arguments */
410 argv
[0] = d
= lstrcpyW((WCHAR
*)(argv
+ argc
+ 1), cmdline
);
412 /* The first argument, the executable path, follows special rules */
415 /* The executable path ends at the next quote, no matter what */
429 /* The executable path ends at the next space, no matter what */
430 while (*d
&& *d
!= ' ' && *d
!= '\t')
436 /* close the executable path */
438 /* skip to the first argument and initialize it if any */
439 while (*s
== ' ' || *s
== '\t')
443 /* There are no parameters so we are all done */
449 /* Split and copy the remaining arguments */
454 if ((*s
== ' ' || *s
== '\t') && qcount
== 0)
456 /* close the argument */
460 /* skip to the next one and initialize it if any */
463 } while (*s
== ' ' || *s
== '\t');
474 if ((bcount
& 1) == 0)
476 /* Preceded by an even number of '\', this is half that
477 * number of '\', plus a quote which we erase.
484 /* Preceded by an odd number of '\', this is half that
485 * number of '\' followed by a '"'
487 d
= d
- bcount
/ 2 - 1;
492 /* Now count the number of consecutive quotes. Note that qcount
493 * already takes into account the opening quote if any, as well as
494 * the quote that lead us here.
510 /* a regular character */
524 IStream IStream_iface
;
547 static inline struct shstream
*impl_from_IStream(IStream
*iface
)
549 return CONTAINING_RECORD(iface
, struct shstream
, IStream_iface
);
552 static HRESULT WINAPI
shstream_QueryInterface(IStream
*iface
, REFIID riid
, void **out
)
554 struct shstream
*stream
= impl_from_IStream(iface
);
556 TRACE("(%p)->(%s, %p)\n", stream
, debugstr_guid(riid
), out
);
558 if (IsEqualIID(riid
, &IID_IUnknown
) ||
559 IsEqualIID(riid
, &IID_IStream
) ||
560 IsEqualIID(riid
, &IID_ISequentialStream
))
563 IStream_AddRef(iface
);
568 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
569 return E_NOINTERFACE
;
572 static ULONG WINAPI
shstream_AddRef(IStream
*iface
)
574 struct shstream
*stream
= impl_from_IStream(iface
);
575 ULONG refcount
= InterlockedIncrement(&stream
->refcount
);
577 TRACE("%p, refcount %lu.\n", iface
, refcount
);
582 static ULONG WINAPI
memstream_Release(IStream
*iface
)
584 struct shstream
*stream
= impl_from_IStream(iface
);
585 ULONG refcount
= InterlockedDecrement(&stream
->refcount
);
587 TRACE("%p, refcount %lu.\n", iface
, refcount
);
591 heap_free(stream
->u
.mem
.buffer
);
598 static HRESULT WINAPI
memstream_Read(IStream
*iface
, void *buff
, ULONG buff_size
, ULONG
*read_len
)
600 struct shstream
*stream
= impl_from_IStream(iface
);
603 TRACE("%p, %p, %lu, %p.\n", iface
, buff
, buff_size
, read_len
);
605 if (stream
->u
.mem
.position
>= stream
->u
.mem
.length
)
612 length
= stream
->u
.mem
.length
- stream
->u
.mem
.position
;
613 if (buff_size
< length
)
616 memmove(buff
, stream
->u
.mem
.buffer
+ stream
->u
.mem
.position
, length
);
617 stream
->u
.mem
.position
+= length
;
625 static HRESULT WINAPI
memstream_Write(IStream
*iface
, const void *buff
, ULONG buff_size
, ULONG
*written
)
627 struct shstream
*stream
= impl_from_IStream(iface
);
628 DWORD length
= stream
->u
.mem
.position
+ buff_size
;
630 TRACE("%p, %p, %lu, %p.\n", iface
, buff
, buff_size
, written
);
632 if (length
< stream
->u
.mem
.position
) /* overflow */
633 return STG_E_INSUFFICIENTMEMORY
;
635 if (length
> stream
->u
.mem
.length
)
637 BYTE
*buffer
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, stream
->u
.mem
.buffer
, length
);
639 return STG_E_INSUFFICIENTMEMORY
;
641 stream
->u
.mem
.length
= length
;
642 stream
->u
.mem
.buffer
= buffer
;
644 memmove(stream
->u
.mem
.buffer
+ stream
->u
.mem
.position
, buff
, buff_size
);
645 stream
->u
.mem
.position
+= buff_size
; /* adjust pointer */
648 *written
= buff_size
;
653 static HRESULT WINAPI
memstream_Seek(IStream
*iface
, LARGE_INTEGER move
, DWORD origin
, ULARGE_INTEGER
*new_pos
)
655 struct shstream
*stream
= impl_from_IStream(iface
);
658 TRACE("%p, %s, %ld, %p.\n", iface
, wine_dbgstr_longlong(move
.QuadPart
), origin
, new_pos
);
660 if (origin
== STREAM_SEEK_SET
)
662 else if (origin
== STREAM_SEEK_CUR
)
663 tmp
.QuadPart
= stream
->u
.mem
.position
+ move
.QuadPart
;
664 else if (origin
== STREAM_SEEK_END
)
665 tmp
.QuadPart
= stream
->u
.mem
.length
+ move
.QuadPart
;
667 return STG_E_INVALIDPARAMETER
;
669 if (tmp
.QuadPart
< 0)
670 return STG_E_INVALIDFUNCTION
;
672 /* we cut off the high part here */
673 stream
->u
.mem
.position
= tmp
.u
.LowPart
;
676 new_pos
->QuadPart
= stream
->u
.mem
.position
;
680 static HRESULT WINAPI
memstream_SetSize(IStream
*iface
, ULARGE_INTEGER new_size
)
682 struct shstream
*stream
= impl_from_IStream(iface
);
686 TRACE("(%p, %s)\n", stream
, wine_dbgstr_longlong(new_size
.QuadPart
));
688 /* we cut off the high part here */
689 length
= new_size
.u
.LowPart
;
690 buffer
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, stream
->u
.mem
.buffer
, length
);
692 return STG_E_INSUFFICIENTMEMORY
;
694 stream
->u
.mem
.buffer
= buffer
;
695 stream
->u
.mem
.length
= length
;
700 static HRESULT WINAPI
shstream_CopyTo(IStream
*iface
, IStream
*dest
, ULARGE_INTEGER size
,
701 ULARGE_INTEGER
*read_len
, ULARGE_INTEGER
*written
)
703 struct shstream
*stream
= impl_from_IStream(iface
);
704 ULARGE_INTEGER total_read
, total_written
;
708 TRACE("(%p, %p, %s, %p, %p)\n", stream
, dest
, wine_dbgstr_longlong(size
.QuadPart
), read_len
, written
);
713 total_read
.QuadPart
= 0;
714 total_written
.QuadPart
= 0;
716 while (size
.QuadPart
> 0)
718 ULONG chunk_size
= size
.QuadPart
>= sizeof(buffer
) ? sizeof(buffer
) : size
.u
.LowPart
;
719 ULONG chunk_read
, chunk_written
;
721 hr
= IStream_Read(iface
, buffer
, chunk_size
, &chunk_read
);
725 total_read
.QuadPart
+= chunk_read
;
729 hr
= IStream_Write(dest
, buffer
, chunk_read
, &chunk_written
);
733 total_written
.QuadPart
+= chunk_written
;
736 if (chunk_read
!= chunk_size
)
739 size
.QuadPart
-= chunk_read
;
743 read_len
->QuadPart
= total_read
.QuadPart
;
745 written
->QuadPart
= total_written
.QuadPart
;
750 static HRESULT WINAPI
shstream_Commit(IStream
*iface
, DWORD flags
)
752 TRACE("%p, %#lx.\n", iface
, flags
);
754 /* Commit is not supported by this stream */
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 */
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 */
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 */
788 static HRESULT WINAPI
memstream_Stat(IStream
*iface
, STATSTG
*statstg
, DWORD flags
)
790 struct shstream
*stream
= impl_from_IStream(iface
);
792 TRACE("%p, %p, %#lx.\n", iface
, statstg
, flags
);
794 memset(statstg
, 0, sizeof(*statstg
));
795 statstg
->type
= STGTY_STREAM
;
796 statstg
->cbSize
.QuadPart
= stream
->u
.mem
.length
;
797 statstg
->grfMode
= STGM_READWRITE
;
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
);
810 /* clone not supported by this stream */
814 static const IStreamVtbl memstreamvtbl
=
816 shstream_QueryInterface
,
827 shstream_UnlockRegion
,
832 static struct shstream
*shstream_create(const IStreamVtbl
*vtbl
, const BYTE
*data
, UINT data_len
)
834 struct shstream
*stream
;
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
)
848 memcpy(stream
->u
.mem
.buffer
, data
, data_len
);
849 stream
->u
.mem
.length
= data_len
;
850 stream
->u
.mem
.position
= 0;
855 /*************************************************************************
856 * SHCreateMemStream [SHCORE.@]
858 * Create an IStream object on a block of memory.
861 * data [I] Memory block to create the IStream object on
862 * data_len [I] Length of data block
865 * Success: A pointer to the IStream object.
866 * Failure: NULL, if any parameters are invalid or an error occurs.
869 * A copy of the memory block is made, it's freed when the stream is released.
871 IStream
* WINAPI
SHCreateMemStream(const BYTE
*data
, UINT data_len
)
873 struct shstream
*stream
;
875 TRACE("(%p, %u)\n", data
, data_len
);
877 stream
= shstream_create(&memstreamvtbl
, data
, data_len
);
878 return stream
? &stream
->IStream_iface
: NULL
;
881 static ULONG WINAPI
filestream_Release(IStream
*iface
)
883 struct shstream
*stream
= impl_from_IStream(iface
);
884 ULONG refcount
= InterlockedDecrement(&stream
->refcount
);
886 TRACE("%p, refcount %lu.\n", iface
, refcount
);
890 CloseHandle(stream
->u
.file
.handle
);
891 heap_free(stream
->u
.file
.path
);
898 static HRESULT WINAPI
filestream_Read(IStream
*iface
, void *buff
, ULONG size
, ULONG
*read_len
)
900 struct shstream
*stream
= impl_from_IStream(iface
);
903 TRACE("%p, %p, %lu, %p.\n", iface
, buff
, size
, read_len
);
905 if (!ReadFile(stream
->u
.file
.handle
, buff
, size
, &read
, NULL
))
907 WARN("error %ld reading file\n", GetLastError());
914 return read
== size
? S_OK
: S_FALSE
;
917 static HRESULT WINAPI
filestream_Write(IStream
*iface
, const void *buff
, ULONG size
, ULONG
*written
)
919 struct shstream
*stream
= impl_from_IStream(iface
);
920 DWORD written_len
= 0;
922 TRACE("%p, %p, %lu, %p.\n", iface
, buff
, size
, written
);
924 switch (stream
->u
.file
.mode
& 0xf)
930 return STG_E_ACCESSDENIED
;
933 if (!WriteFile(stream
->u
.file
.handle
, buff
, size
, &written_len
, NULL
))
934 return HRESULT_FROM_WIN32(GetLastError());
937 *written
= written_len
;
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
);
947 TRACE("%p, %s, %ld, %p.\n", iface
, wine_dbgstr_longlong(move
.QuadPart
), origin
, new_pos
);
949 position
= SetFilePointer(stream
->u
.file
.handle
, move
.u
.LowPart
, NULL
, origin
);
950 if (position
== INVALID_SET_FILE_POINTER
)
951 return HRESULT_FROM_WIN32(GetLastError());
955 new_pos
->u
.HighPart
= 0;
956 new_pos
->u
.LowPart
= position
;
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
));
970 if (!SetFilePointerEx(stream
->u
.file
.handle
, move
, &origin
, FILE_CURRENT
))
973 move
.QuadPart
= size
.QuadPart
;
974 if (!SetFilePointerEx(stream
->u
.file
.handle
, move
, NULL
, FILE_BEGIN
))
977 if (stream
->u
.file
.mode
!= STGM_READ
)
979 if (!SetEndOfFile(stream
->u
.file
.handle
))
981 if (!SetFilePointerEx(stream
->u
.file
.handle
, origin
, NULL
, FILE_BEGIN
))
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
);
995 TRACE("(%p, %p, %s, %p, %p)\n", stream
, dest
, wine_dbgstr_longlong(size
.QuadPart
), read_len
, written
);
998 read_len
->QuadPart
= 0;
1000 written
->QuadPart
= 0;
1005 while (size
.QuadPart
)
1007 ULONG left
, read_chunk
, written_chunk
;
1009 left
= size
.QuadPart
> sizeof(buff
) ? sizeof(buff
) : size
.QuadPart
;
1012 hr
= IStream_Read(iface
, buff
, left
, &read_chunk
);
1013 if (FAILED(hr
) || read_chunk
== 0)
1016 read_len
->QuadPart
+= read_chunk
;
1019 hr
= IStream_Write(dest
, buff
, read_chunk
, &written_chunk
);
1021 written
->QuadPart
+= written_chunk
;
1022 if (FAILED(hr
) || written_chunk
!= left
)
1025 size
.QuadPart
-= left
;
1031 static HRESULT WINAPI
filestream_Commit(IStream
*iface
, DWORD flags
)
1033 TRACE("%p, %#lx.\n", iface
, flags
);
1038 static HRESULT WINAPI
filestream_Stat(IStream
*iface
, STATSTG
*statstg
, DWORD flags
)
1040 struct shstream
*stream
= impl_from_IStream(iface
);
1041 BY_HANDLE_FILE_INFORMATION fi
;
1043 TRACE("%p, %p, %#lx.\n", iface
, statstg
, flags
);
1046 return STG_E_INVALIDPOINTER
;
1048 memset(&fi
, 0, sizeof(fi
));
1049 GetFileInformationByHandle(stream
->u
.file
.handle
, &fi
);
1051 if (flags
& STATFLAG_NONAME
)
1052 statstg
->pwcsName
= NULL
;
1055 int len
= lstrlenW(stream
->u
.file
.path
);
1056 if ((statstg
->pwcsName
= CoTaskMemAlloc((len
+ 1) * sizeof(WCHAR
))))
1057 memcpy(statstg
->pwcsName
, stream
->u
.file
.path
, (len
+ 1) * sizeof(WCHAR
));
1060 statstg
->cbSize
.u
.LowPart
= fi
.nFileSizeLow
;
1061 statstg
->cbSize
.u
.HighPart
= fi
.nFileSizeHigh
;
1062 statstg
->mtime
= fi
.ftLastWriteTime
;
1063 statstg
->ctime
= fi
.ftCreationTime
;
1064 statstg
->atime
= fi
.ftLastAccessTime
;
1065 statstg
->grfMode
= stream
->u
.file
.mode
;
1066 statstg
->grfLocksSupported
= 0;
1067 memcpy(&statstg
->clsid
, &IID_IStream
, sizeof(CLSID
));
1068 statstg
->grfStateBits
= 0;
1069 statstg
->reserved
= 0;
1074 static const IStreamVtbl filestreamvtbl
=
1076 shstream_QueryInterface
,
1086 shstream_LockRegion
,
1087 shstream_UnlockRegion
,
1092 /*************************************************************************
1093 * SHCreateStreamOnFileEx [SHCORE.@]
1095 HRESULT WINAPI
SHCreateStreamOnFileEx(const WCHAR
*path
, DWORD mode
, DWORD attributes
,
1096 BOOL create
, IStream
*template, IStream
**ret
)
1098 DWORD access
, share
, creation_disposition
, len
;
1099 struct shstream
*stream
;
1102 TRACE("%s, %ld, %#lx, %d, %p, %p)\n", debugstr_w(path
), mode
, attributes
,
1103 create
, template, ret
);
1105 if (!path
|| !ret
|| template)
1106 return E_INVALIDARG
;
1114 case STGM_READWRITE
:
1115 access
= GENERIC_READ
| GENERIC_WRITE
;
1118 access
= GENERIC_READ
;
1121 return E_INVALIDARG
;
1125 switch (mode
& 0xf0)
1128 case STGM_SHARE_DENY_NONE
:
1129 share
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
1131 case STGM_SHARE_DENY_READ
:
1132 share
= FILE_SHARE_WRITE
;
1134 case STGM_SHARE_DENY_WRITE
:
1135 share
= FILE_SHARE_READ
;
1137 case STGM_SHARE_EXCLUSIVE
:
1141 return E_INVALIDARG
;
1144 switch (mode
& 0xf000)
1146 case STGM_FAILIFTHERE
:
1147 creation_disposition
= create
? CREATE_NEW
: OPEN_EXISTING
;
1150 creation_disposition
= CREATE_ALWAYS
;
1153 return E_INVALIDARG
;
1156 hFile
= CreateFileW(path
, access
, share
, NULL
, creation_disposition
, attributes
, 0);
1157 if (hFile
== INVALID_HANDLE_VALUE
)
1158 return HRESULT_FROM_WIN32(GetLastError());
1160 stream
= heap_alloc(sizeof(*stream
));
1161 stream
->IStream_iface
.lpVtbl
= &filestreamvtbl
;
1162 stream
->refcount
= 1;
1163 stream
->u
.file
.handle
= hFile
;
1164 stream
->u
.file
.mode
= mode
;
1166 len
= lstrlenW(path
);
1167 stream
->u
.file
.path
= heap_alloc((len
+ 1) * sizeof(WCHAR
));
1168 memcpy(stream
->u
.file
.path
, path
, (len
+ 1) * sizeof(WCHAR
));
1170 *ret
= &stream
->IStream_iface
;
1175 /*************************************************************************
1176 * SHCreateStreamOnFileW [SHCORE.@]
1178 HRESULT WINAPI
SHCreateStreamOnFileW(const WCHAR
*path
, DWORD mode
, IStream
**stream
)
1180 TRACE("%s, %#lx, %p.\n", debugstr_w(path
), mode
, stream
);
1182 if (!path
|| !stream
)
1183 return E_INVALIDARG
;
1185 if ((mode
& (STGM_CONVERT
| STGM_DELETEONRELEASE
| STGM_TRANSACTED
)) != 0)
1186 return E_INVALIDARG
;
1188 return SHCreateStreamOnFileEx(path
, mode
, 0, FALSE
, NULL
, stream
);
1191 /*************************************************************************
1192 * SHCreateStreamOnFileA [SHCORE.@]
1194 HRESULT WINAPI
SHCreateStreamOnFileA(const char *path
, DWORD mode
, IStream
**stream
)
1200 TRACE("%s, %#lx, %p.\n", debugstr_a(path
), mode
, stream
);
1203 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND
);
1205 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
1206 pathW
= heap_alloc(len
* sizeof(WCHAR
));
1208 return E_OUTOFMEMORY
;
1210 MultiByteToWideChar(CP_ACP
, 0, path
, -1, pathW
, len
);
1211 hr
= SHCreateStreamOnFileW(pathW
, mode
, stream
);
1217 static ULONG WINAPI
regstream_Release(IStream
*iface
)
1219 struct shstream
*stream
= impl_from_IStream(iface
);
1220 ULONG refcount
= InterlockedDecrement(&stream
->refcount
);
1222 TRACE("%p, refcount %lu.\n", iface
, refcount
);
1226 if (stream
->u
.mem
.hkey
)
1228 if (stream
->u
.mem
.length
)
1229 RegSetValueExW(stream
->u
.mem
.hkey
, stream
->u
.mem
.valuename
, 0, REG_BINARY
,
1230 (const BYTE
*)stream
->u
.mem
.buffer
, stream
->u
.mem
.length
);
1232 RegDeleteValueW(stream
->u
.mem
.hkey
, stream
->u
.mem
.valuename
);
1233 RegCloseKey(stream
->u
.mem
.hkey
);
1235 CoTaskMemFree(stream
->u
.mem
.valuename
);
1236 heap_free(stream
->u
.mem
.buffer
);
1243 static const IStreamVtbl regstreamvtbl
=
1245 shstream_QueryInterface
,
1255 shstream_LockRegion
,
1256 shstream_UnlockRegion
,
1261 /*************************************************************************
1262 * SHOpenRegStream2W [SHCORE.@]
1264 IStream
* WINAPI
SHOpenRegStream2W(HKEY hKey
, const WCHAR
*subkey
, const WCHAR
*value
, DWORD mode
)
1266 struct shstream
*stream
;
1267 HKEY hStrKey
= NULL
;
1272 TRACE("%p, %s, %s, %#lx.\n", hKey
, debugstr_w(subkey
), debugstr_w(value
), mode
);
1274 if (mode
== STGM_READ
)
1275 ret
= RegOpenKeyExW(hKey
, subkey
, 0, KEY_READ
, &hStrKey
);
1276 else /* in write mode we make sure the subkey exits */
1277 ret
= RegCreateKeyExW(hKey
, subkey
, 0, NULL
, 0, KEY_READ
| KEY_WRITE
, NULL
, &hStrKey
, NULL
);
1279 if (ret
== ERROR_SUCCESS
)
1281 if (mode
== STGM_READ
|| mode
== STGM_READWRITE
)
1283 /* read initial data */
1284 ret
= RegQueryValueExW(hStrKey
, value
, 0, 0, 0, &length
);
1285 if (ret
== ERROR_SUCCESS
&& length
)
1287 buff
= heap_alloc(length
);
1288 RegQueryValueExW(hStrKey
, value
, 0, 0, buff
, &length
);
1293 buff
= heap_alloc(length
);
1295 stream
= shstream_create(®streamvtbl
, buff
, length
);
1299 stream
->u
.mem
.hkey
= hStrKey
;
1300 SHStrDupW(value
, &stream
->u
.mem
.valuename
);
1301 return &stream
->IStream_iface
;
1306 RegCloseKey(hStrKey
);
1311 /*************************************************************************
1312 * SHOpenRegStream2A [SHCORE.@]
1314 IStream
* WINAPI
SHOpenRegStream2A(HKEY hKey
, const char *subkey
, const char *value
, DWORD mode
)
1316 WCHAR
*subkeyW
= NULL
, *valueW
= NULL
;
1319 TRACE("%p, %s, %s, %#lx.\n", hKey
, debugstr_a(subkey
), debugstr_a(value
), mode
);
1321 if (subkey
&& FAILED(SHStrDupA(subkey
, &subkeyW
)))
1323 if (value
&& FAILED(SHStrDupA(value
, &valueW
)))
1325 CoTaskMemFree(subkeyW
);
1329 stream
= SHOpenRegStream2W(hKey
, subkeyW
, valueW
, mode
);
1330 CoTaskMemFree(subkeyW
);
1331 CoTaskMemFree(valueW
);
1335 /*************************************************************************
1336 * SHOpenRegStreamA [SHCORE.@]
1338 IStream
* WINAPI
SHOpenRegStreamA(HKEY hkey
, const char *subkey
, const char *value
, DWORD mode
)
1340 WCHAR
*subkeyW
= NULL
, *valueW
= NULL
;
1343 TRACE("%p, %s, %s, %#lx.\n", hkey
, debugstr_a(subkey
), debugstr_a(value
), mode
);
1345 if (subkey
&& FAILED(SHStrDupA(subkey
, &subkeyW
)))
1347 if (value
&& FAILED(SHStrDupA(value
, &valueW
)))
1349 CoTaskMemFree(subkeyW
);
1353 stream
= SHOpenRegStreamW(hkey
, subkeyW
, valueW
, mode
);
1354 CoTaskMemFree(subkeyW
);
1355 CoTaskMemFree(valueW
);
1359 static ULONG WINAPI
dummystream_AddRef(IStream
*iface
)
1365 static ULONG WINAPI
dummystream_Release(IStream
*iface
)
1371 static HRESULT WINAPI
dummystream_Read(IStream
*iface
, void *buff
, ULONG buff_size
, ULONG
*read_len
)
1379 static const IStreamVtbl dummystreamvtbl
=
1381 shstream_QueryInterface
,
1383 dummystream_Release
,
1391 shstream_LockRegion
,
1392 shstream_UnlockRegion
,
1397 static struct shstream dummyregstream
= { { &dummystreamvtbl
} };
1399 /*************************************************************************
1400 * SHOpenRegStreamW [SHCORE.@]
1402 IStream
* WINAPI
SHOpenRegStreamW(HKEY hkey
, const WCHAR
*subkey
, const WCHAR
*value
, DWORD mode
)
1406 TRACE("%p, %s, %s, %#lx.\n", hkey
, debugstr_w(subkey
), debugstr_w(value
), mode
);
1407 stream
= SHOpenRegStream2W(hkey
, subkey
, value
, mode
);
1408 return stream
? stream
: &dummyregstream
.IStream_iface
;
1413 IUnknown IUnknown_iface
;
1417 static inline struct threadref
*threadref_impl_from_IUnknown(IUnknown
*iface
)
1419 return CONTAINING_RECORD(iface
, struct threadref
, IUnknown_iface
);
1422 static HRESULT WINAPI
threadref_QueryInterface(IUnknown
*iface
, REFIID riid
, void **out
)
1424 struct threadref
*threadref
= threadref_impl_from_IUnknown(iface
);
1426 TRACE("(%p, %s, %p)\n", threadref
, debugstr_guid(riid
), out
);
1431 if (IsEqualGUID(&IID_IUnknown
, riid
))
1434 IUnknown_AddRef(iface
);
1439 WARN("Interface %s not supported.\n", debugstr_guid(riid
));
1440 return E_NOINTERFACE
;
1443 static ULONG WINAPI
threadref_AddRef(IUnknown
*iface
)
1445 struct threadref
*threadref
= threadref_impl_from_IUnknown(iface
);
1446 LONG refcount
= InterlockedIncrement(threadref
->refcount
);
1448 TRACE("%p, refcount %ld.\n", threadref
, refcount
);
1453 static ULONG WINAPI
threadref_Release(IUnknown
*iface
)
1455 struct threadref
*threadref
= threadref_impl_from_IUnknown(iface
);
1456 LONG refcount
= InterlockedDecrement(threadref
->refcount
);
1458 TRACE("%p, refcount %ld.\n", threadref
, refcount
);
1461 heap_free(threadref
);
1466 static const IUnknownVtbl threadrefvtbl
=
1468 threadref_QueryInterface
,
1473 /*************************************************************************
1474 * SHCreateThreadRef [SHCORE.@]
1476 HRESULT WINAPI
SHCreateThreadRef(LONG
*refcount
, IUnknown
**out
)
1478 struct threadref
*threadref
;
1480 TRACE("(%p, %p)\n", refcount
, out
);
1482 if (!refcount
|| !out
)
1483 return E_INVALIDARG
;
1487 threadref
= heap_alloc(sizeof(*threadref
));
1489 return E_OUTOFMEMORY
;
1490 threadref
->IUnknown_iface
.lpVtbl
= &threadrefvtbl
;
1491 threadref
->refcount
= refcount
;
1494 *out
= &threadref
->IUnknown_iface
;
1496 TRACE("Created %p.\n", threadref
);
1500 /*************************************************************************
1501 * SHGetThreadRef [SHCORE.@]
1503 HRESULT WINAPI
SHGetThreadRef(IUnknown
**out
)
1505 TRACE("(%p)\n", out
);
1507 if (shcore_tls
== TLS_OUT_OF_INDEXES
)
1508 return E_NOINTERFACE
;
1510 *out
= TlsGetValue(shcore_tls
);
1512 return E_NOINTERFACE
;
1514 IUnknown_AddRef(*out
);
1518 /*************************************************************************
1519 * SHSetThreadRef [SHCORE.@]
1521 HRESULT WINAPI
SHSetThreadRef(IUnknown
*obj
)
1523 TRACE("(%p)\n", obj
);
1525 if (shcore_tls
== TLS_OUT_OF_INDEXES
)
1526 return E_NOINTERFACE
;
1528 TlsSetValue(shcore_tls
, obj
);
1532 /*************************************************************************
1533 * SHReleaseThreadRef [SHCORE.@]
1535 HRESULT WINAPI
SHReleaseThreadRef(void)
1537 FIXME("() - stub!\n");
1541 /*************************************************************************
1542 * GetProcessReference [SHCORE.@]
1544 HRESULT WINAPI
GetProcessReference(IUnknown
**obj
)
1546 TRACE("(%p)\n", obj
);
1554 IUnknown_AddRef(*obj
);
1559 /*************************************************************************
1560 * SetProcessReference [SHCORE.@]
1562 void WINAPI
SetProcessReference(IUnknown
*obj
)
1564 TRACE("(%p)\n", obj
);
1571 LPTHREAD_START_ROUTINE thread_proc
;
1572 LPTHREAD_START_ROUTINE callback
;
1576 IUnknown
*thread_ref
;
1577 IUnknown
*process_ref
;
1580 static DWORD WINAPI
shcore_thread_wrapper(void *data
)
1582 struct thread_data thread_data
;
1583 HRESULT hr
= E_FAIL
;
1586 TRACE("(%p)\n", data
);
1588 /* We are now executing in the context of the newly created thread.
1589 * So we copy the data passed to us (it is on the stack of the function
1590 * that called us, which is waiting for us to signal an event before
1592 thread_data
= *(struct thread_data
*)data
;
1594 if (thread_data
.flags
& CTF_COINIT
)
1596 hr
= CoInitializeEx(NULL
, COINIT_APARTMENTTHREADED
| COINIT_DISABLE_OLE1DDE
);
1598 hr
= CoInitializeEx(NULL
, COINIT_DISABLE_OLE1DDE
);
1601 if (thread_data
.callback
)
1602 thread_data
.callback(thread_data
.data
);
1604 /* Signal the thread that created us; it can return now. */
1605 SetEvent(thread_data
.hEvent
);
1607 /* Execute the callers start code. */
1608 retval
= thread_data
.thread_proc(thread_data
.data
);
1610 /* Release thread and process references. */
1611 if (thread_data
.thread_ref
)
1612 IUnknown_Release(thread_data
.thread_ref
);
1614 if (thread_data
.process_ref
)
1615 IUnknown_Release(thread_data
.process_ref
);
1623 /*************************************************************************
1624 * SHCreateThread [SHCORE.@]
1626 BOOL WINAPI
SHCreateThread(LPTHREAD_START_ROUTINE thread_proc
, void *data
, DWORD flags
, LPTHREAD_START_ROUTINE callback
)
1628 struct thread_data thread_data
;
1629 BOOL called
= FALSE
;
1631 TRACE("%p, %p, %#lx, %p.\n", thread_proc
, data
, flags
, callback
);
1633 thread_data
.thread_proc
= thread_proc
;
1634 thread_data
.callback
= callback
;
1635 thread_data
.data
= data
;
1636 thread_data
.flags
= flags
;
1637 thread_data
.hEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1639 if (flags
& CTF_THREAD_REF
)
1640 SHGetThreadRef(&thread_data
.thread_ref
);
1642 thread_data
.thread_ref
= NULL
;
1644 if (flags
& CTF_PROCESS_REF
)
1645 GetProcessReference(&thread_data
.process_ref
);
1647 thread_data
.process_ref
= NULL
;
1649 /* Create the thread */
1650 if (thread_data
.hEvent
)
1655 hThread
= CreateThread(NULL
, 0, shcore_thread_wrapper
, &thread_data
, 0, &retval
);
1658 /* Wait for the thread to signal us to continue */
1659 WaitForSingleObject(thread_data
.hEvent
, INFINITE
);
1660 CloseHandle(hThread
);
1663 CloseHandle(thread_data
.hEvent
);
1668 if (!thread_data
.callback
&& flags
& CTF_INSIST
)
1670 /* Couldn't call, call synchronously */
1671 thread_data
.thread_proc(data
);
1676 if (thread_data
.thread_ref
)
1677 IUnknown_Release(thread_data
.thread_ref
);
1679 if (thread_data
.process_ref
)
1680 IUnknown_Release(thread_data
.process_ref
);
1687 /*************************************************************************
1688 * SHStrDupW [SHCORE.@]
1690 HRESULT WINAPI
SHStrDupW(const WCHAR
*src
, WCHAR
**dest
)
1694 TRACE("(%s, %p)\n", debugstr_w(src
), dest
);
1699 return E_INVALIDARG
;
1701 len
= (lstrlenW(src
) + 1) * sizeof(WCHAR
);
1702 *dest
= CoTaskMemAlloc(len
);
1704 return E_OUTOFMEMORY
;
1706 memcpy(*dest
, src
, len
);
1711 /*************************************************************************
1712 * SHStrDupA [SHCORE.@]
1714 HRESULT WINAPI
SHStrDupA(const char *src
, WCHAR
**dest
)
1721 return E_INVALIDARG
;
1723 len
= MultiByteToWideChar(CP_ACP
, 0, src
, -1, NULL
, 0);
1724 *dest
= CoTaskMemAlloc(len
* sizeof(WCHAR
));
1726 return E_OUTOFMEMORY
;
1728 MultiByteToWideChar(CP_ACP
, 0, src
, -1, *dest
, len
);
1733 /*************************************************************************
1734 * SHAnsiToAnsi [SHCORE.@]
1736 DWORD WINAPI
SHAnsiToAnsi(const char *src
, char *dest
, int dest_len
)
1740 TRACE("(%s, %p, %d)\n", debugstr_a(src
), dest
, dest_len
);
1742 if (!src
|| !dest
|| dest_len
<= 0)
1745 lstrcpynA(dest
, src
, dest_len
);
1748 return src
[ret
] ? 0 : ret
+ 1;
1751 /*************************************************************************
1752 * SHUnicodeToAnsi [SHCORE.@]
1754 DWORD WINAPI
SHUnicodeToAnsi(const WCHAR
*src
, char *dest
, int dest_len
)
1758 TRACE("(%s, %p, %d)\n", debugstr_w(src
), dest
, dest_len
);
1760 if (!dest
|| !dest_len
)
1765 ret
= WideCharToMultiByte(CP_ACP
, 0, src
, -1, dest
, dest_len
, NULL
, NULL
);
1768 dest
[dest_len
- 1] = 0;
1778 /*************************************************************************
1779 * SHUnicodeToUnicode [SHCORE.@]
1781 DWORD WINAPI
SHUnicodeToUnicode(const WCHAR
*src
, WCHAR
*dest
, int dest_len
)
1785 TRACE("(%s, %p, %d)\n", debugstr_w(src
), dest
, dest_len
);
1787 if (!src
|| !dest
|| dest_len
<= 0)
1790 lstrcpynW(dest
, src
, dest_len
);
1791 ret
= lstrlenW(dest
);
1793 return src
[ret
] ? 0 : ret
+ 1;
1796 /*************************************************************************
1797 * SHAnsiToUnicode [SHCORE.@]
1799 DWORD WINAPI
SHAnsiToUnicode(const char *src
, WCHAR
*dest
, int dest_len
)
1803 TRACE("(%s, %p, %d)\n", debugstr_a(src
), dest
, dest_len
);
1805 if (!dest
|| !dest_len
)
1810 ret
= MultiByteToWideChar(CP_ACP
, 0, src
, -1, dest
, dest_len
);
1813 dest
[dest_len
- 1] = 0;
1823 /*************************************************************************
1824 * SHRegDuplicateHKey [SHCORE.@]
1826 HKEY WINAPI
SHRegDuplicateHKey(HKEY hKey
)
1830 RegOpenKeyExW(hKey
, 0, 0, MAXIMUM_ALLOWED
, &newKey
);
1831 TRACE("new key is %p\n", newKey
);
1835 /*************************************************************************
1836 * SHDeleteEmptyKeyW [SHCORE.@]
1838 DWORD WINAPI
SHDeleteEmptyKeyW(HKEY hkey
, const WCHAR
*subkey
)
1840 DWORD ret
, count
= 0;
1843 TRACE("(%p, %s)\n", hkey
, debugstr_w(subkey
));
1845 ret
= RegOpenKeyExW(hkey
, subkey
, 0, KEY_READ
, &hsubkey
);
1848 ret
= RegQueryInfoKeyW(hsubkey
, NULL
, NULL
, NULL
, &count
,
1849 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1850 RegCloseKey(hsubkey
);
1854 ret
= ERROR_KEY_HAS_CHILDREN
;
1856 ret
= RegDeleteKeyW(hkey
, subkey
);
1863 /*************************************************************************
1864 * SHDeleteEmptyKeyA [SHCORE.@]
1866 DWORD WINAPI
SHDeleteEmptyKeyA(HKEY hkey
, const char *subkey
)
1868 WCHAR
*subkeyW
= NULL
;
1871 TRACE("(%p, %s)\n", hkey
, debugstr_a(subkey
));
1873 if (subkey
&& FAILED(SHStrDupA(subkey
, &subkeyW
)))
1874 return ERROR_OUTOFMEMORY
;
1876 ret
= SHDeleteEmptyKeyW(hkey
, subkeyW
);
1877 CoTaskMemFree(subkeyW
);
1881 /*************************************************************************
1882 * SHDeleteKeyW [SHCORE.@]
1884 DWORD WINAPI
SHDeleteKeyW(HKEY hkey
, const WCHAR
*subkey
)
1886 TRACE("(%p, %s)\n", hkey
, debugstr_w(subkey
));
1888 return RegDeleteTreeW(hkey
, subkey
);
1891 /*************************************************************************
1892 * SHDeleteKeyA [SHCORE.@]
1894 DWORD WINAPI
SHDeleteKeyA(HKEY hkey
, const char *subkey
)
1896 TRACE("(%p, %s)\n", hkey
, debugstr_a(subkey
));
1898 return RegDeleteTreeA(hkey
, subkey
);
1901 /*************************************************************************
1902 * SHDeleteValueW [SHCORE.@]
1904 DWORD WINAPI
SHDeleteValueW(HKEY hkey
, const WCHAR
*subkey
, const WCHAR
*value
)
1909 TRACE("(%p, %s, %s)\n", hkey
, debugstr_w(subkey
), debugstr_w(value
));
1911 ret
= RegOpenKeyExW(hkey
, subkey
, 0, KEY_SET_VALUE
, &hsubkey
);
1914 ret
= RegDeleteValueW(hsubkey
, value
);
1915 RegCloseKey(hsubkey
);
1921 /*************************************************************************
1922 * SHDeleteValueA [SHCORE.@]
1924 DWORD WINAPI
SHDeleteValueA(HKEY hkey
, const char *subkey
, const char *value
)
1926 WCHAR
*subkeyW
= NULL
, *valueW
= NULL
;
1929 TRACE("(%p, %s, %s)\n", hkey
, debugstr_a(subkey
), debugstr_a(value
));
1931 if (subkey
&& FAILED(SHStrDupA(subkey
, &subkeyW
)))
1932 return ERROR_OUTOFMEMORY
;
1933 if (value
&& FAILED(SHStrDupA(value
, &valueW
)))
1935 CoTaskMemFree(subkeyW
);
1936 return ERROR_OUTOFMEMORY
;
1939 ret
= SHDeleteValueW(hkey
, subkeyW
, valueW
);
1940 CoTaskMemFree(subkeyW
);
1941 CoTaskMemFree(valueW
);
1945 /*************************************************************************
1946 * SHCopyKeyA [SHCORE.@]
1948 DWORD WINAPI
SHCopyKeyA(HKEY hkey_src
, const char *subkey
, HKEY hkey_dst
, DWORD reserved
)
1950 WCHAR
*subkeyW
= NULL
;
1953 TRACE("%p, %s, %p, %ld.\n", hkey_src
, debugstr_a(subkey
), hkey_dst
, reserved
);
1955 if (subkey
&& FAILED(SHStrDupA(subkey
, &subkeyW
)))
1958 ret
= SHCopyKeyW(hkey_src
, subkeyW
, hkey_dst
, reserved
);
1959 CoTaskMemFree(subkeyW
);
1963 /*************************************************************************
1964 * SHCopyKeyW [SHCORE.@]
1966 DWORD WINAPI
SHCopyKeyW(HKEY hkey_src
, const WCHAR
*subkey
, HKEY hkey_dst
, DWORD reserved
)
1968 DWORD key_count
= 0, value_count
= 0, max_key_len
= 0;
1969 WCHAR name
[MAX_PATH
], *ptr_name
= name
;
1970 BYTE buff
[1024], *ptr
= buff
;
1971 DWORD max_data_len
= 0, i
;
1974 TRACE("%p, %s, %p, %ld.\n", hkey_src
, debugstr_w(subkey
), hkey_dst
, reserved
);
1976 if (!hkey_dst
|| !hkey_src
)
1977 return ERROR_INVALID_PARAMETER
;
1980 ret
= RegOpenKeyExW(hkey_src
, subkey
, 0, KEY_ALL_ACCESS
, &hkey_src
);
1983 hkey_src
= NULL
; /* Don't close this key since we didn't open it */
1986 DWORD max_value_len
;
1988 ret
= RegQueryInfoKeyW(hkey_src
, NULL
, NULL
, NULL
, &key_count
, &max_key_len
,
1989 NULL
, &value_count
, &max_value_len
, &max_data_len
, NULL
, NULL
);
1992 /* Get max size for key/value names */
1993 max_key_len
= max(max_key_len
, max_value_len
);
1995 if (max_key_len
++ > MAX_PATH
- 1)
1996 ptr_name
= heap_alloc(max_key_len
* sizeof(WCHAR
));
1998 if (max_data_len
> sizeof(buff
))
1999 ptr
= heap_alloc(max_data_len
);
2001 if (!ptr_name
|| !ptr
)
2002 ret
= ERROR_NOT_ENOUGH_MEMORY
;
2006 for (i
= 0; i
< key_count
&& !ret
; i
++)
2008 HKEY hsubkey_src
, hsubkey_dst
;
2009 DWORD length
= max_key_len
;
2011 ret
= RegEnumKeyExW(hkey_src
, i
, ptr_name
, &length
, NULL
, NULL
, NULL
, NULL
);
2014 ret
= RegOpenKeyExW(hkey_src
, ptr_name
, 0, KEY_READ
, &hsubkey_src
);
2017 /* Create destination sub key */
2018 ret
= RegCreateKeyW(hkey_dst
, ptr_name
, &hsubkey_dst
);
2021 /* Recursively copy keys and values from the sub key */
2022 ret
= SHCopyKeyW(hsubkey_src
, NULL
, hsubkey_dst
, 0);
2023 RegCloseKey(hsubkey_dst
);
2026 RegCloseKey(hsubkey_src
);
2030 /* Copy all the values in this key */
2031 for (i
= 0; i
< value_count
&& !ret
; i
++)
2033 DWORD length
= max_key_len
, type
, data_len
= max_data_len
;
2035 ret
= RegEnumValueW(hkey_src
, i
, ptr_name
, &length
, NULL
, &type
, ptr
, &data_len
);
2037 ret
= SHSetValueW(hkey_dst
, NULL
, ptr_name
, type
, ptr
, data_len
);
2041 /* Free buffers if allocated */
2042 if (ptr_name
!= name
)
2043 heap_free(ptr_name
);
2047 if (subkey
&& hkey_src
)
2048 RegCloseKey(hkey_src
);
2054 /*************************************************************************
2055 * SHEnumKeyExA [SHCORE.@]
2057 LONG WINAPI
SHEnumKeyExA(HKEY hkey
, DWORD index
, char *subkey
, DWORD
*length
)
2059 TRACE("%p, %ld, %s, %p.\n", hkey
, index
, debugstr_a(subkey
), length
);
2061 return RegEnumKeyExA(hkey
, index
, subkey
, length
, NULL
, NULL
, NULL
, NULL
);
2064 /*************************************************************************
2065 * SHEnumKeyExW [SHCORE.@]
2067 LONG WINAPI
SHEnumKeyExW(HKEY hkey
, DWORD index
, WCHAR
*subkey
, DWORD
*length
)
2069 TRACE("%p, %ld, %s, %p.\n", hkey
, index
, debugstr_w(subkey
), length
);
2071 return RegEnumKeyExW(hkey
, index
, subkey
, length
, NULL
, NULL
, NULL
, NULL
);
2074 /*************************************************************************
2075 * SHEnumValueA [SHCORE.@]
2077 LONG WINAPI
SHEnumValueA(HKEY hkey
, DWORD index
, char *value
, DWORD
*length
, DWORD
*type
,
2078 void *data
, DWORD
*data_len
)
2080 TRACE("%p, %ld, %s, %p, %p, %p, %p.\n", hkey
, index
, debugstr_a(value
), length
, type
, data
, data_len
);
2082 return RegEnumValueA(hkey
, index
, value
, length
, NULL
, type
, data
, data_len
);
2085 /*************************************************************************
2086 * SHEnumValueW [SHCORE.@]
2088 LONG WINAPI
SHEnumValueW(HKEY hkey
, DWORD index
, WCHAR
*value
, DWORD
*length
, DWORD
*type
,
2089 void *data
, DWORD
*data_len
)
2091 TRACE("%p, %ld, %s, %p, %p, %p, %p.\n", hkey
, index
, debugstr_w(value
), length
, type
, data
, data_len
);
2093 return RegEnumValueW(hkey
, index
, value
, length
, NULL
, type
, data
, data_len
);
2096 /*************************************************************************
2097 * SHQueryValueExW [SHCORE.@]
2099 DWORD WINAPI
SHQueryValueExW(HKEY hkey
, const WCHAR
*name
, DWORD
*reserved
, DWORD
*type
,
2100 void *buff
, DWORD
*buff_len
)
2102 DWORD ret
, value_type
, data_len
= 0;
2104 TRACE("(%p, %s, %p, %p, %p, %p)\n", hkey
, debugstr_w(name
), reserved
, type
, buff
, buff_len
);
2107 data_len
= *buff_len
;
2109 ret
= RegQueryValueExW(hkey
, name
, reserved
, &value_type
, buff
, &data_len
);
2110 if (ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)
2113 if (buff_len
&& value_type
== REG_EXPAND_SZ
)
2118 if (!buff
|| ret
== ERROR_MORE_DATA
)
2121 value
= heap_alloc(length
);
2122 RegQueryValueExW(hkey
, name
, reserved
, NULL
, (BYTE
*)value
, &length
);
2123 length
= ExpandEnvironmentStringsW(value
, NULL
, 0);
2127 length
= (lstrlenW(buff
) + 1) * sizeof(WCHAR
);
2128 value
= heap_alloc(length
);
2129 memcpy(value
, buff
, length
);
2130 length
= ExpandEnvironmentStringsW(value
, buff
, *buff_len
/ sizeof(WCHAR
));
2131 if (length
> *buff_len
) ret
= ERROR_MORE_DATA
;
2133 data_len
= max(data_len
, length
);
2138 *type
= value_type
== REG_EXPAND_SZ
? REG_SZ
: value_type
;
2140 *buff_len
= data_len
;
2144 /*************************************************************************
2145 * SHQueryValueExA [SHCORE.@]
2147 DWORD WINAPI
SHQueryValueExA(HKEY hkey
, const char *name
, DWORD
*reserved
, DWORD
*type
,
2148 void *buff
, DWORD
*buff_len
)
2150 DWORD ret
, value_type
, data_len
= 0;
2152 TRACE("(%p, %s, %p, %p, %p, %p)\n", hkey
, debugstr_a(name
), reserved
, type
, buff
, buff_len
);
2155 data_len
= *buff_len
;
2157 ret
= RegQueryValueExA(hkey
, name
, reserved
, &value_type
, buff
, &data_len
);
2158 if (ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)
2161 if (buff_len
&& value_type
== REG_EXPAND_SZ
)
2166 if (!buff
|| ret
== ERROR_MORE_DATA
)
2169 value
= heap_alloc(length
);
2170 RegQueryValueExA(hkey
, name
, reserved
, NULL
, (BYTE
*)value
, &length
);
2171 length
= ExpandEnvironmentStringsA(value
, NULL
, 0);
2175 length
= strlen(buff
) + 1;
2176 value
= heap_alloc(length
);
2177 memcpy(value
, buff
, length
);
2178 length
= ExpandEnvironmentStringsA(value
, buff
, *buff_len
);
2179 if (length
> *buff_len
) ret
= ERROR_MORE_DATA
;
2181 data_len
= max(data_len
, length
);
2186 *type
= value_type
== REG_EXPAND_SZ
? REG_SZ
: value_type
;
2188 *buff_len
= data_len
;
2192 /*************************************************************************
2193 * SHGetValueA [SHCORE.@]
2195 DWORD WINAPI
SHGetValueA(HKEY hkey
, const char *subkey
, const char *value
,
2196 DWORD
*type
, void *data
, DWORD
*data_len
)
2201 TRACE("(%p, %s, %s, %p, %p, %p)\n", hkey
, debugstr_a(subkey
), debugstr_a(value
),
2202 type
, data
, data_len
);
2205 ret
= RegOpenKeyExA(hkey
, subkey
, 0, KEY_QUERY_VALUE
, &hsubkey
);
2209 ret
= SHQueryValueExA(hsubkey
? hsubkey
: hkey
, value
, 0, type
, data
, data_len
);
2211 RegCloseKey(hsubkey
);
2217 /*************************************************************************
2218 * SHGetValueW [SHCORE.@]
2220 DWORD WINAPI
SHGetValueW(HKEY hkey
, const WCHAR
*subkey
, const WCHAR
*value
,
2221 DWORD
*type
, void *data
, DWORD
*data_len
)
2226 TRACE("(%p, %s, %s, %p, %p, %p)\n", hkey
, debugstr_w(subkey
), debugstr_w(value
),
2227 type
, data
, data_len
);
2230 ret
= RegOpenKeyExW(hkey
, subkey
, 0, KEY_QUERY_VALUE
, &hsubkey
);
2234 ret
= SHQueryValueExW(hsubkey
? hsubkey
: hkey
, value
, 0, type
, data
, data_len
);
2236 RegCloseKey(hsubkey
);
2242 /*************************************************************************
2243 * SHRegGetIntW [SHCORE.280]
2245 int WINAPI
SHRegGetIntW(HKEY hkey
, const WCHAR
*value
, int default_value
)
2250 TRACE("(%p, %s, %d)\n", hkey
, debugstr_w(value
), default_value
);
2253 buff_len
= sizeof(buff
);
2254 if (SHQueryValueExW(hkey
, value
, 0, 0, buff
, &buff_len
))
2255 return default_value
;
2257 if (*buff
>= '0' && *buff
<= '9')
2258 return wcstol(buff
, NULL
, 10);
2260 return default_value
;
2263 /*************************************************************************
2264 * SHRegGetPathA [SHCORE.@]
2266 DWORD WINAPI
SHRegGetPathA(HKEY hkey
, const char *subkey
, const char *value
, char *path
, DWORD flags
)
2268 DWORD length
= MAX_PATH
;
2270 TRACE("%p, %s, %s, %p, %#lx.\n", hkey
, debugstr_a(subkey
), debugstr_a(value
), path
, flags
);
2272 return SHGetValueA(hkey
, subkey
, value
, 0, path
, &length
);
2275 /*************************************************************************
2276 * SHRegGetPathW [SHCORE.@]
2278 DWORD WINAPI
SHRegGetPathW(HKEY hkey
, const WCHAR
*subkey
, const WCHAR
*value
, WCHAR
*path
, DWORD flags
)
2280 DWORD length
= MAX_PATH
;
2282 TRACE("%p, %s, %s, %p, %#lx.\n", hkey
, debugstr_w(subkey
), debugstr_w(value
), path
, flags
);
2284 return SHGetValueW(hkey
, subkey
, value
, 0, path
, &length
);
2287 /*************************************************************************
2288 * SHSetValueW [SHCORE.@]
2290 DWORD WINAPI
SHSetValueW(HKEY hkey
, const WCHAR
*subkey
, const WCHAR
*value
, DWORD type
,
2291 const void *data
, DWORD data_len
)
2293 DWORD ret
= ERROR_SUCCESS
, dummy
;
2296 TRACE("%p, %s, %s, %ld, %p, %ld.\n", hkey
, debugstr_w(subkey
), debugstr_w(value
),
2297 type
, data
, data_len
);
2299 if (subkey
&& *subkey
)
2300 ret
= RegCreateKeyExW(hkey
, subkey
, 0, NULL
, 0, KEY_SET_VALUE
, NULL
, &hsubkey
, &dummy
);
2306 ret
= RegSetValueExW(hsubkey
, value
, 0, type
, data
, data_len
);
2307 if (hsubkey
!= hkey
)
2308 RegCloseKey(hsubkey
);
2314 /*************************************************************************
2315 * SHSetValueA [SHCORE.@]
2317 DWORD WINAPI
SHSetValueA(HKEY hkey
, const char *subkey
, const char *value
,
2318 DWORD type
, const void *data
, DWORD data_len
)
2320 DWORD ret
= ERROR_SUCCESS
, dummy
;
2323 TRACE("%p, %s, %s, %ld, %p, %ld.\n", hkey
, debugstr_a(subkey
), debugstr_a(value
),
2324 type
, data
, data_len
);
2326 if (subkey
&& *subkey
)
2327 ret
= RegCreateKeyExA(hkey
, subkey
, 0, NULL
, 0, KEY_SET_VALUE
, NULL
, &hsubkey
, &dummy
);
2333 ret
= RegSetValueExA(hsubkey
, value
, 0, type
, data
, data_len
);
2334 if (hsubkey
!= hkey
)
2335 RegCloseKey(hsubkey
);
2341 /*************************************************************************
2342 * SHRegSetPathA [SHCORE.@]
2344 DWORD WINAPI
SHRegSetPathA(HKEY hkey
, const char *subkey
, const char *value
, const char *path
, DWORD flags
)
2346 FIXME("%p, %s, %s, %s, %#lx - semi-stub\n", hkey
, debugstr_a(subkey
),
2347 debugstr_a(value
), debugstr_a(path
), flags
);
2349 /* FIXME: PathUnExpandEnvStringsA() */
2351 return SHSetValueA(hkey
, subkey
, value
, REG_SZ
, path
, lstrlenA(path
));
2354 /*************************************************************************
2355 * SHRegSetPathW [SHCORE.@]
2357 DWORD WINAPI
SHRegSetPathW(HKEY hkey
, const WCHAR
*subkey
, const WCHAR
*value
, const WCHAR
*path
, DWORD flags
)
2359 FIXME("%p, %s, %s, %s, %#lx semi-stub\n", hkey
, debugstr_w(subkey
),
2360 debugstr_w(value
), debugstr_w(path
), flags
);
2362 /* FIXME: PathUnExpandEnvStringsW(); */
2364 return SHSetValueW(hkey
, subkey
, value
, REG_SZ
, path
, lstrlenW(path
));
2367 /*************************************************************************
2368 * SHQueryInfoKeyA [SHCORE.@]
2370 LONG WINAPI
SHQueryInfoKeyA(HKEY hkey
, DWORD
*subkeys
, DWORD
*subkey_max
, DWORD
*values
, DWORD
*value_max
)
2372 TRACE("(%p, %p, %p, %p, %p)\n", hkey
, subkeys
, subkey_max
, values
, value_max
);
2374 return RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, subkeys
, subkey_max
, NULL
, values
, value_max
, NULL
, NULL
, NULL
);
2377 /*************************************************************************
2378 * SHQueryInfoKeyW [SHCORE.@]
2380 LONG WINAPI
SHQueryInfoKeyW(HKEY hkey
, DWORD
*subkeys
, DWORD
*subkey_max
, DWORD
*values
, DWORD
*value_max
)
2382 TRACE("(%p, %p, %p, %p, %p)\n", hkey
, subkeys
, subkey_max
, values
, value_max
);
2384 return RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, subkeys
, subkey_max
, NULL
, values
, value_max
, NULL
, NULL
, NULL
);
2387 /*************************************************************************
2390 BOOL WINAPI
IsOS(DWORD feature
)
2392 DWORD platform
, majorv
, minorv
;
2393 OSVERSIONINFOA osvi
;
2395 osvi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOA
);
2396 if (!GetVersionExA(&osvi
))
2399 majorv
= osvi
.dwMajorVersion
;
2400 minorv
= osvi
.dwMinorVersion
;
2401 platform
= osvi
.dwPlatformId
;
2403 #define ISOS_RETURN(x) \
2404 TRACE("(%#lx) ret %d\n",feature,(x)); \
2408 case OS_WIN32SORGREATER
:
2409 ISOS_RETURN(platform
== VER_PLATFORM_WIN32s
2410 || platform
== VER_PLATFORM_WIN32_WINDOWS
);
2412 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
);
2413 case OS_WIN95ORGREATER
:
2414 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_WINDOWS
);
2415 case OS_NT4ORGREATER
:
2416 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& majorv
>= 4);
2417 case OS_WIN2000ORGREATER_ALT
:
2418 case OS_WIN2000ORGREATER
:
2419 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& majorv
>= 5);
2420 case OS_WIN98ORGREATER
:
2421 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_WINDOWS
&& minorv
>= 10);
2423 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_WINDOWS
&& minorv
== 10);
2425 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& majorv
>= 5);
2426 case OS_WIN2000SERVER
:
2427 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& (minorv
== 0 || minorv
== 1));
2428 case OS_WIN2000ADVSERVER
:
2429 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& (minorv
== 0 || minorv
== 1));
2430 case OS_WIN2000DATACENTER
:
2431 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& (minorv
== 0 || minorv
== 1));
2432 case OS_WIN2000TERMINAL
:
2433 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& (minorv
== 0 || minorv
== 1));
2435 FIXME("(OS_EMBEDDED) What should we return here?\n");
2437 case OS_TERMINALCLIENT
:
2438 FIXME("(OS_TERMINALCLIENT) What should we return here?\n");
2440 case OS_TERMINALREMOTEADMIN
:
2441 FIXME("(OS_TERMINALREMOTEADMIN) What should we return here?\n");
2444 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_WINDOWS
&& minorv
== 0);
2445 case OS_MEORGREATER
:
2446 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_WINDOWS
&& minorv
>= 90);
2447 case OS_XPORGREATER
:
2448 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& majorv
>= 5 && minorv
>= 1);
2450 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& majorv
>= 5 && minorv
>= 1);
2451 case OS_PROFESSIONAL
:
2452 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
);
2454 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
);
2456 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& majorv
>= 5);
2458 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
);
2459 case OS_TERMINALSERVER
:
2460 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
);
2461 case OS_PERSONALTERMINALSERVER
:
2462 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& minorv
>= 1 && majorv
>= 5);
2463 case OS_FASTUSERSWITCHING
:
2464 FIXME("(OS_FASTUSERSWITCHING) What should we return here?\n");
2466 case OS_WELCOMELOGONUI
:
2467 FIXME("(OS_WELCOMELOGONUI) What should we return here?\n");
2469 case OS_DOMAINMEMBER
:
2470 FIXME("(OS_DOMAINMEMBER) What should we return here?\n");
2473 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
);
2477 IsWow64Process(GetCurrentProcess(), &is_wow64
);
2481 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
);
2482 case OS_SMALLBUSINESSSERVER
:
2483 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
);
2485 FIXME("(OS_TABLETPC) What should we return here?\n");
2487 case OS_SERVERADMINUI
:
2488 FIXME("(OS_SERVERADMINUI) What should we return here?\n");
2490 case OS_MEDIACENTER
:
2491 FIXME("(OS_MEDIACENTER) What should we return here?\n");
2494 FIXME("(OS_APPLIANCE) What should we return here?\n");
2496 case 0x25: /*OS_VISTAORGREATER*/
2497 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& majorv
>= 6);
2502 WARN("(%#lx) unknown parameter\n", feature
);
2507 /*************************************************************************
2508 * SubscribeFeatureStateChangeNotification [SHCORE.@]
2510 void WINAPI
SubscribeFeatureStateChangeNotification(FEATURE_STATE_CHANGE_SUBSCRIPTION
*subscription
,
2511 FEATURE_STATE_CHANGE_CALLBACK
*callback
, void *context
)
2513 FIXME("(%p, %p, %p) stub\n", subscription
, callback
, context
);
2516 /*************************************************************************
2517 * GetFeatureEnabledState [SHCORE.@]
2519 FEATURE_ENABLED_STATE WINAPI
GetFeatureEnabledState(UINT32 feature
, FEATURE_CHANGE_TIME change_time
)
2521 FIXME("(%u, %u) stub\n", feature
, change_time
);
2522 return FEATURE_ENABLED_STATE_DEFAULT
;