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
31 #include "shellscalingapi.h"
34 #include "wine/debug.h"
35 #include "wine/heap.h"
36 #include "wine/unicode.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(shcore
);
40 static DWORD shcore_tls
;
41 static IUnknown
*process_ref
;
43 BOOL WINAPI
DllMain(HINSTANCE instance
, DWORD reason
, void *reserved
)
45 TRACE("(%p, %u, %p)\n", instance
, reason
, reserved
);
49 case DLL_WINE_PREATTACH
:
50 return FALSE
; /* prefer native version */
51 case DLL_PROCESS_ATTACH
:
52 DisableThreadLibraryCalls(instance
);
53 shcore_tls
= TlsAlloc();
55 case DLL_PROCESS_DETACH
:
57 if (shcore_tls
!= TLS_OUT_OF_INDEXES
)
65 HRESULT WINAPI
GetProcessDpiAwareness(HANDLE process
, PROCESS_DPI_AWARENESS
*value
)
67 if (GetProcessDpiAwarenessInternal( process
, (DPI_AWARENESS
*)value
)) return S_OK
;
68 return HRESULT_FROM_WIN32( GetLastError() );
71 HRESULT WINAPI
SetProcessDpiAwareness(PROCESS_DPI_AWARENESS value
)
73 if (SetProcessDpiAwarenessInternal( value
)) return S_OK
;
74 return HRESULT_FROM_WIN32( GetLastError() );
77 HRESULT WINAPI
GetDpiForMonitor(HMONITOR monitor
, MONITOR_DPI_TYPE type
, UINT
*x
, UINT
*y
)
79 if (GetDpiForMonitorInternal( monitor
, type
, x
, y
)) return S_OK
;
80 return HRESULT_FROM_WIN32( GetLastError() );
83 HRESULT WINAPI
_IStream_Read(IStream
*stream
, void *dest
, ULONG size
)
88 TRACE("(%p, %p, %u)\n", stream
, dest
, size
);
90 hr
= IStream_Read(stream
, dest
, size
, &read
);
91 if (SUCCEEDED(hr
) && read
!= size
)
96 HRESULT WINAPI
IStream_Reset(IStream
*stream
)
98 static const LARGE_INTEGER zero
;
100 TRACE("(%p)\n", stream
);
102 return IStream_Seek(stream
, zero
, 0, NULL
);
105 HRESULT WINAPI
IStream_Size(IStream
*stream
, ULARGE_INTEGER
*size
)
110 TRACE("(%p, %p)\n", stream
, size
);
112 memset(&statstg
, 0, sizeof(statstg
));
114 hr
= IStream_Stat(stream
, &statstg
, STATFLAG_NONAME
);
116 if (SUCCEEDED(hr
) && size
)
117 *size
= statstg
.cbSize
;
121 HRESULT WINAPI
_IStream_Write(IStream
*stream
, const void *src
, ULONG size
)
126 TRACE("(%p, %p, %u)\n", stream
, src
, size
);
128 hr
= IStream_Write(stream
, src
, size
, &written
);
129 if (SUCCEEDED(hr
) && written
!= size
)
135 void WINAPI
IUnknown_AtomicRelease(IUnknown
**obj
)
137 TRACE("(%p)\n", obj
);
142 IUnknown_Release(*obj
);
146 HRESULT WINAPI
IUnknown_GetSite(IUnknown
*unk
, REFIID iid
, void **site
)
148 IObjectWithSite
*obj
= NULL
;
149 HRESULT hr
= E_INVALIDARG
;
151 TRACE("(%p, %s, %p)\n", unk
, debugstr_guid(iid
), site
);
153 if (unk
&& iid
&& site
)
155 hr
= IUnknown_QueryInterface(unk
, &IID_IObjectWithSite
, (void **)&obj
);
156 if (SUCCEEDED(hr
) && obj
)
158 hr
= IObjectWithSite_GetSite(obj
, iid
, site
);
159 IObjectWithSite_Release(obj
);
166 HRESULT WINAPI
IUnknown_QueryService(IUnknown
*obj
, REFGUID sid
, REFIID iid
, void **out
)
168 IServiceProvider
*provider
= NULL
;
179 hr
= IUnknown_QueryInterface(obj
, &IID_IServiceProvider
, (void **)&provider
);
180 if (hr
== S_OK
&& provider
)
182 TRACE("Using provider %p.\n", provider
);
184 hr
= IServiceProvider_QueryService(provider
, sid
, iid
, out
);
186 TRACE("Provider %p returned %p.\n", provider
, *out
);
188 IServiceProvider_Release(provider
);
194 void WINAPI
IUnknown_Set(IUnknown
**dest
, IUnknown
*src
)
196 TRACE("(%p, %p)\n", dest
, src
);
198 IUnknown_AtomicRelease(dest
);
202 IUnknown_AddRef(src
);
207 HRESULT WINAPI
IUnknown_SetSite(IUnknown
*obj
, IUnknown
*site
)
209 IInternetSecurityManager
*sec_manager
;
210 IObjectWithSite
*objwithsite
;
216 hr
= IUnknown_QueryInterface(obj
, &IID_IObjectWithSite
, (void **)&objwithsite
);
217 TRACE("ObjectWithSite %p, hr %#x.\n", objwithsite
, hr
);
220 hr
= IObjectWithSite_SetSite(objwithsite
, site
);
221 TRACE("SetSite() hr %#x.\n", hr
);
222 IObjectWithSite_Release(objwithsite
);
226 hr
= IUnknown_QueryInterface(obj
, &IID_IInternetSecurityManager
, (void **)&sec_manager
);
227 TRACE("InternetSecurityManager %p, hr %#x.\n", sec_manager
, hr
);
231 hr
= IInternetSecurityManager_SetSecuritySite(sec_manager
, (IInternetSecurityMgrSite
*)site
);
232 TRACE("SetSecuritySite() hr %#x.\n", hr
);
233 IInternetSecurityManager_Release(sec_manager
);
239 HRESULT WINAPI
SetCurrentProcessExplicitAppUserModelID(const WCHAR
*appid
)
241 FIXME("%s: stub\n", debugstr_w(appid
));
245 HRESULT WINAPI
GetCurrentProcessExplicitAppUserModelID(const WCHAR
**appid
)
247 FIXME("%p: stub\n", appid
);
252 /*************************************************************************
253 * CommandLineToArgvW [SHCORE.@]
255 * We must interpret the quotes in the command line to rebuild the argv
257 * - arguments are separated by spaces or tabs
258 * - quotes serve as optional argument delimiters
260 * - escaped quotes must be converted back to '"'
262 * - consecutive backslashes preceding a quote see their number halved with
263 * the remainder escaping the quote:
264 * 2n backslashes + quote -> n backslashes + quote as an argument delimiter
265 * 2n+1 backslashes + quote -> n backslashes + literal quote
266 * - backslashes that are not followed by a quote are copied literally:
269 * - in quoted strings, consecutive quotes see their number divided by three
270 * with the remainder modulo 3 deciding whether to close the string or not.
271 * Note that the opening quote must be counted in the consecutive quotes,
272 * that's the (1+) below:
273 * (1+) 3n quotes -> n quotes
274 * (1+) 3n+1 quotes -> n quotes plus closes the quoted string
275 * (1+) 3n+2 quotes -> n+1 quotes plus closes the quoted string
276 * - in unquoted strings, the first quote opens the quoted string and the
277 * remaining consecutive quotes follow the above rule.
279 WCHAR
** WINAPI
CommandLineToArgvW(const WCHAR
*cmdline
, int *numargs
)
289 SetLastError(ERROR_INVALID_PARAMETER
);
295 /* Return the path to the executable */
296 DWORD len
, deslen
= MAX_PATH
, size
;
298 size
= sizeof(WCHAR
*) * 2 + deslen
* sizeof(WCHAR
);
301 if (!(argv
= LocalAlloc(LMEM_FIXED
, size
))) return NULL
;
302 len
= GetModuleFileNameW(0, (WCHAR
*)(argv
+ 2), deslen
);
308 if (len
< deslen
) break;
310 size
= sizeof(WCHAR
*) * 2 + deslen
* sizeof(WCHAR
);
313 argv
[0] = (WCHAR
*)(argv
+ 2);
320 /* --- First count the arguments */
323 /* The first argument, the executable path, follows special rules */
326 /* The executable path ends at the next quote, no matter what */
334 /* The executable path ends at the next space, no matter what */
335 while (*s
&& *s
!= ' ' && *s
!= '\t')
338 /* skip to the first argument, if any */
339 while (*s
== ' ' || *s
== '\t')
344 /* Analyze the remaining arguments */
348 if ((*s
== ' ' || *s
== '\t') && qcount
== 0)
350 /* skip to the next argument and count it if any */
351 while (*s
== ' ' || *s
== '\t')
359 /* '\', count them */
366 if ((bcount
& 1) == 0)
367 qcount
++; /* unescaped '"' */
370 /* consecutive quotes, see comment in copying code below */
382 /* a regular character */
388 /* Allocate in a single lump, the string array, and the strings that go
389 * with it. This way the caller can make a single LocalFree() call to free
392 argv
= LocalAlloc(LMEM_FIXED
, (argc
+ 1) * sizeof(WCHAR
*) + (strlenW(cmdline
) + 1) * sizeof(WCHAR
));
396 /* --- Then split and copy the arguments */
397 argv
[0] = d
= strcpyW((WCHAR
*)(argv
+ argc
+ 1), cmdline
);
399 /* The first argument, the executable path, follows special rules */
402 /* The executable path ends at the next quote, no matter what */
416 /* The executable path ends at the next space, no matter what */
417 while (*d
&& *d
!= ' ' && *d
!= '\t')
423 /* close the executable path */
425 /* skip to the first argument and initialize it if any */
426 while (*s
== ' ' || *s
== '\t')
430 /* There are no parameters so we are all done */
436 /* Split and copy the remaining arguments */
441 if ((*s
== ' ' || *s
== '\t') && qcount
== 0)
443 /* close the argument */
447 /* skip to the next one and initialize it if any */
450 } while (*s
== ' ' || *s
== '\t');
461 if ((bcount
& 1) == 0)
463 /* Preceded by an even number of '\', this is half that
464 * number of '\', plus a quote which we erase.
471 /* Preceded by an odd number of '\', this is half that
472 * number of '\' followed by a '"'
474 d
= d
- bcount
/ 2 - 1;
479 /* Now count the number of consecutive quotes. Note that qcount
480 * already takes into account the opening quote if any, as well as
481 * the quote that lead us here.
497 /* a regular character */
511 IStream IStream_iface
;
534 static inline struct shstream
*impl_from_IStream(IStream
*iface
)
536 return CONTAINING_RECORD(iface
, struct shstream
, IStream_iface
);
539 static HRESULT WINAPI
shstream_QueryInterface(IStream
*iface
, REFIID riid
, void **out
)
541 struct shstream
*stream
= impl_from_IStream(iface
);
543 TRACE("(%p)->(%s, %p)\n", stream
, debugstr_guid(riid
), out
);
545 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IStream
))
548 IStream_AddRef(iface
);
553 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
554 return E_NOINTERFACE
;
557 static ULONG WINAPI
shstream_AddRef(IStream
*iface
)
559 struct shstream
*stream
= impl_from_IStream(iface
);
560 ULONG refcount
= InterlockedIncrement(&stream
->refcount
);
562 TRACE("(%p)->(%u)\n", stream
, refcount
);
567 static ULONG WINAPI
memstream_Release(IStream
*iface
)
569 struct shstream
*stream
= impl_from_IStream(iface
);
570 ULONG refcount
= InterlockedDecrement(&stream
->refcount
);
572 TRACE("(%p)->(%u)\n", stream
, refcount
);
576 heap_free(stream
->u
.mem
.buffer
);
583 static HRESULT WINAPI
memstream_Read(IStream
*iface
, void *buff
, ULONG buff_size
, ULONG
*read_len
)
585 struct shstream
*stream
= impl_from_IStream(iface
);
588 TRACE("(%p)->(%p, %u, %p)\n", stream
, buff
, buff_size
, read_len
);
590 if (stream
->u
.mem
.position
>= stream
->u
.mem
.length
)
593 length
= stream
->u
.mem
.length
- stream
->u
.mem
.position
;
595 length
= buff_size
> length
? length
: buff_size
;
596 if (length
!= 0) /* not at end of buffer and we want to read something */
598 memmove(buff
, stream
->u
.mem
.buffer
+ stream
->u
.mem
.position
, length
);
599 stream
->u
.mem
.position
+= length
; /* adjust pointer */
608 static HRESULT WINAPI
memstream_Write(IStream
*iface
, const void *buff
, ULONG buff_size
, ULONG
*written
)
610 struct shstream
*stream
= impl_from_IStream(iface
);
611 DWORD length
= stream
->u
.mem
.position
+ buff_size
;
613 TRACE("(%p)->(%p, %u, %p)\n", stream
, buff
, buff_size
, written
);
615 if (length
< stream
->u
.mem
.position
) /* overflow */
616 return STG_E_INSUFFICIENTMEMORY
;
618 if (length
> stream
->u
.mem
.length
)
620 BYTE
*buffer
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, stream
->u
.mem
.buffer
, length
);
622 return STG_E_INSUFFICIENTMEMORY
;
624 stream
->u
.mem
.length
= length
;
625 stream
->u
.mem
.buffer
= buffer
;
627 memmove(stream
->u
.mem
.buffer
+ stream
->u
.mem
.position
, buff
, buff_size
);
628 stream
->u
.mem
.position
+= buff_size
; /* adjust pointer */
631 *written
= buff_size
;
636 static HRESULT WINAPI
memstream_Seek(IStream
*iface
, LARGE_INTEGER move
, DWORD origin
, ULARGE_INTEGER
*new_pos
)
638 struct shstream
*stream
= impl_from_IStream(iface
);
641 TRACE("(%p)->(%s, %d, %p)\n", stream
, wine_dbgstr_longlong(move
.QuadPart
), origin
, new_pos
);
643 if (origin
== STREAM_SEEK_SET
)
645 else if (origin
== STREAM_SEEK_CUR
)
646 tmp
.QuadPart
= stream
->u
.mem
.position
+ move
.QuadPart
;
647 else if (origin
== STREAM_SEEK_END
)
648 tmp
.QuadPart
= stream
->u
.mem
.length
+ move
.QuadPart
;
650 return STG_E_INVALIDPARAMETER
;
652 if (tmp
.QuadPart
< 0)
653 return STG_E_INVALIDFUNCTION
;
655 /* we cut off the high part here */
656 stream
->u
.mem
.position
= tmp
.u
.LowPart
;
659 new_pos
->QuadPart
= stream
->u
.mem
.position
;
663 static HRESULT WINAPI
memstream_SetSize(IStream
*iface
, ULARGE_INTEGER new_size
)
665 struct shstream
*stream
= impl_from_IStream(iface
);
669 TRACE("(%p, %s)\n", stream
, wine_dbgstr_longlong(new_size
.QuadPart
));
671 /* we cut off the high part here */
672 length
= new_size
.u
.LowPart
;
673 buffer
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, stream
->u
.mem
.buffer
, length
);
675 return STG_E_INSUFFICIENTMEMORY
;
677 stream
->u
.mem
.buffer
= buffer
;
678 stream
->u
.mem
.length
= length
;
683 static HRESULT WINAPI
shstream_CopyTo(IStream
*iface
, IStream
*pstm
, ULARGE_INTEGER size
, ULARGE_INTEGER
*read_len
, ULARGE_INTEGER
*written
)
685 struct shstream
*stream
= impl_from_IStream(iface
);
687 TRACE("(%p)\n", stream
);
690 read_len
->QuadPart
= 0;
693 written
->QuadPart
= 0;
699 static HRESULT WINAPI
shstream_Commit(IStream
*iface
, DWORD flags
)
701 struct shstream
*stream
= impl_from_IStream(iface
);
703 TRACE("(%p, %#x)\n", stream
, flags
);
705 /* Commit is not supported by this stream */
709 static HRESULT WINAPI
shstream_Revert(IStream
*iface
)
711 struct shstream
*stream
= impl_from_IStream(iface
);
713 TRACE("(%p)\n", stream
);
715 /* revert not supported by this stream */
719 static HRESULT WINAPI
shstream_LockRegion(IStream
*iface
, ULARGE_INTEGER offset
, ULARGE_INTEGER size
, DWORD lock_type
)
721 struct shstream
*stream
= impl_from_IStream(iface
);
723 TRACE("(%p)\n", stream
);
725 /* lock/unlock not supported by this stream */
729 static HRESULT WINAPI
shstream_UnlockRegion(IStream
*iface
, ULARGE_INTEGER offset
, ULARGE_INTEGER size
, DWORD lock_type
)
731 struct shstream
*stream
= impl_from_IStream(iface
);
733 TRACE("(%p)\n", stream
);
735 /* lock/unlock not supported by this stream */
739 static HRESULT WINAPI
memstream_Stat(IStream
*iface
, STATSTG
*statstg
, DWORD flags
)
741 struct shstream
*stream
= impl_from_IStream(iface
);
743 TRACE("(%p, %p, %#x)\n", stream
, statstg
, flags
);
745 memset(statstg
, 0, sizeof(*statstg
));
746 statstg
->type
= STGTY_STREAM
;
747 statstg
->cbSize
.QuadPart
= stream
->u
.mem
.length
;
748 statstg
->grfMode
= STGM_READWRITE
;
753 static HRESULT WINAPI
shstream_Clone(IStream
*iface
, IStream
**dest
)
755 struct shstream
*stream
= impl_from_IStream(iface
);
757 TRACE("(%p, %p)\n", stream
, dest
);
761 /* clone not supported by this stream */
765 static const IStreamVtbl memstreamvtbl
=
767 shstream_QueryInterface
,
778 shstream_UnlockRegion
,
783 static struct shstream
*shstream_create(const IStreamVtbl
*vtbl
, const BYTE
*data
, UINT data_len
)
785 struct shstream
*stream
;
790 stream
= heap_alloc(sizeof(*stream
));
791 stream
->IStream_iface
.lpVtbl
= vtbl
;
792 stream
->refcount
= 1;
793 stream
->u
.mem
.buffer
= heap_alloc(data_len
);
794 if (!stream
->u
.mem
.buffer
)
799 memcpy(stream
->u
.mem
.buffer
, data
, data_len
);
800 stream
->u
.mem
.length
= data_len
;
801 stream
->u
.mem
.position
= 0;
806 /*************************************************************************
807 * SHCreateMemStream [SHCORE.@]
809 * Create an IStream object on a block of memory.
812 * data [I] Memory block to create the IStream object on
813 * data_len [I] Length of data block
816 * Success: A pointer to the IStream object.
817 * Failure: NULL, if any parameters are invalid or an error occurs.
820 * A copy of the memory block is made, it's freed when the stream is released.
822 IStream
* WINAPI
SHCreateMemStream(const BYTE
*data
, UINT data_len
)
824 struct shstream
*stream
;
826 TRACE("(%p, %u)\n", data
, data_len
);
828 stream
= shstream_create(&memstreamvtbl
, data
, data_len
);
829 return stream
? &stream
->IStream_iface
: NULL
;
832 static ULONG WINAPI
filestream_Release(IStream
*iface
)
834 struct shstream
*stream
= impl_from_IStream(iface
);
835 ULONG refcount
= InterlockedDecrement(&stream
->refcount
);
837 TRACE("(%p)->(%u)\n", stream
, refcount
);
841 CloseHandle(stream
->u
.file
.handle
);
842 heap_free(stream
->u
.file
.path
);
849 static HRESULT WINAPI
filestream_Read(IStream
*iface
, void *buff
, ULONG size
, ULONG
*read_len
)
851 struct shstream
*stream
= impl_from_IStream(iface
);
854 TRACE("(%p, %p, %u, %p)\n", stream
, buff
, size
, read_len
);
856 if (!ReadFile(stream
->u
.file
.handle
, buff
, size
, &read
, NULL
))
858 WARN("error %d reading file\n", GetLastError());
865 return read
== size
? S_OK
: S_FALSE
;
868 static HRESULT WINAPI
filestream_Write(IStream
*iface
, const void *buff
, ULONG size
, ULONG
*written
)
870 struct shstream
*stream
= impl_from_IStream(iface
);
871 DWORD written_len
= 0;
873 TRACE("(%p, %p, %u, %p)\n", stream
, buff
, size
, written
);
875 switch (stream
->u
.file
.mode
& 0xf)
881 return STG_E_ACCESSDENIED
;
884 if (!WriteFile(stream
->u
.file
.handle
, buff
, size
, &written_len
, NULL
))
885 return HRESULT_FROM_WIN32(GetLastError());
888 *written
= written_len
;
893 static HRESULT WINAPI
filestream_Seek(IStream
*iface
, LARGE_INTEGER move
, DWORD origin
, ULARGE_INTEGER
*new_pos
)
895 struct shstream
*stream
= impl_from_IStream(iface
);
898 TRACE("(%p, %s, %d, %p)\n", stream
, wine_dbgstr_longlong(move
.QuadPart
), origin
, new_pos
);
900 position
= SetFilePointer(stream
->u
.file
.handle
, move
.u
.LowPart
, NULL
, origin
);
901 if (position
== INVALID_SET_FILE_POINTER
)
902 return HRESULT_FROM_WIN32(GetLastError());
906 new_pos
->u
.HighPart
= 0;
907 new_pos
->u
.LowPart
= position
;
913 static HRESULT WINAPI
filestream_SetSize(IStream
*iface
, ULARGE_INTEGER size
)
915 struct shstream
*stream
= impl_from_IStream(iface
);
916 LARGE_INTEGER origin
, move
;
918 TRACE("(%p, %s)\n", stream
, wine_dbgstr_longlong(size
.QuadPart
));
921 if (!SetFilePointerEx(stream
->u
.file
.handle
, move
, &origin
, FILE_CURRENT
))
924 move
.QuadPart
= size
.QuadPart
;
925 if (!SetFilePointerEx(stream
->u
.file
.handle
, move
, NULL
, FILE_BEGIN
))
928 if (stream
->u
.file
.mode
!= STGM_READ
)
930 if (!SetEndOfFile(stream
->u
.file
.handle
))
932 if (!SetFilePointerEx(stream
->u
.file
.handle
, origin
, NULL
, FILE_BEGIN
))
939 static HRESULT WINAPI
filestream_CopyTo(IStream
*iface
, IStream
*dest
, ULARGE_INTEGER size
,
940 ULARGE_INTEGER
*read_len
, ULARGE_INTEGER
*written
)
942 struct shstream
*stream
= impl_from_IStream(iface
);
946 TRACE("(%p, %p, %s, %p, %p)\n", stream
, dest
, wine_dbgstr_longlong(size
.QuadPart
), read_len
, written
);
949 read_len
->QuadPart
= 0;
951 written
->QuadPart
= 0;
956 while (size
.QuadPart
)
958 ULONG left
, read_chunk
, written_chunk
;
960 left
= size
.QuadPart
> sizeof(buff
) ? sizeof(buff
) : size
.QuadPart
;
963 hr
= IStream_Read(iface
, buff
, left
, &read_chunk
);
964 if (FAILED(hr
) || read_chunk
== 0)
967 read_len
->QuadPart
+= read_chunk
;
970 hr
= IStream_Write(dest
, buff
, read_chunk
, &written_chunk
);
972 written
->QuadPart
+= written_chunk
;
973 if (FAILED(hr
) || written_chunk
!= left
)
976 size
.QuadPart
-= left
;
982 static HRESULT WINAPI
filestream_Commit(IStream
*iface
, DWORD flags
)
984 struct shstream
*stream
= impl_from_IStream(iface
);
986 TRACE("(%p, %#x)\n", stream
, flags
);
991 static HRESULT WINAPI
filestream_Stat(IStream
*iface
, STATSTG
*statstg
, DWORD flags
)
993 struct shstream
*stream
= impl_from_IStream(iface
);
994 BY_HANDLE_FILE_INFORMATION fi
;
996 TRACE("(%p, %p, %#x)\n", stream
, statstg
, flags
);
999 return STG_E_INVALIDPOINTER
;
1001 memset(&fi
, 0, sizeof(fi
));
1002 GetFileInformationByHandle(stream
->u
.file
.handle
, &fi
);
1004 if (flags
& STATFLAG_NONAME
)
1005 statstg
->pwcsName
= NULL
;
1008 int len
= strlenW(stream
->u
.file
.path
);
1009 if ((statstg
->pwcsName
= CoTaskMemAlloc((len
+ 1) * sizeof(WCHAR
))))
1010 memcpy(statstg
->pwcsName
, stream
->u
.file
.path
, (len
+ 1) * sizeof(WCHAR
));
1013 statstg
->cbSize
.u
.LowPart
= fi
.nFileSizeLow
;
1014 statstg
->cbSize
.u
.HighPart
= fi
.nFileSizeHigh
;
1015 statstg
->mtime
= fi
.ftLastWriteTime
;
1016 statstg
->ctime
= fi
.ftCreationTime
;
1017 statstg
->atime
= fi
.ftLastAccessTime
;
1018 statstg
->grfMode
= stream
->u
.file
.mode
;
1019 statstg
->grfLocksSupported
= 0;
1020 memcpy(&statstg
->clsid
, &IID_IStream
, sizeof(CLSID
));
1021 statstg
->grfStateBits
= 0;
1022 statstg
->reserved
= 0;
1027 static const IStreamVtbl filestreamvtbl
=
1029 shstream_QueryInterface
,
1039 shstream_LockRegion
,
1040 shstream_UnlockRegion
,
1045 /*************************************************************************
1046 * SHCreateStreamOnFileEx [SHCORE.@]
1048 HRESULT WINAPI
SHCreateStreamOnFileEx(const WCHAR
*path
, DWORD mode
, DWORD attributes
,
1049 BOOL create
, IStream
*template, IStream
**ret
)
1051 DWORD access
, share
, creation_disposition
, len
;
1052 struct shstream
*stream
;
1055 TRACE("(%s, %d, 0x%08X, %d, %p, %p)\n", debugstr_w(path
), mode
, attributes
,
1056 create
, template, ret
);
1058 if (!path
|| !ret
|| template)
1059 return E_INVALIDARG
;
1067 case STGM_READWRITE
:
1068 access
= GENERIC_READ
| GENERIC_WRITE
;
1071 access
= GENERIC_READ
;
1074 return E_INVALIDARG
;
1078 switch (mode
& 0xf0)
1081 case STGM_SHARE_DENY_NONE
:
1082 share
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
1084 case STGM_SHARE_DENY_READ
:
1085 share
= FILE_SHARE_WRITE
;
1087 case STGM_SHARE_DENY_WRITE
:
1088 share
= FILE_SHARE_READ
;
1090 case STGM_SHARE_EXCLUSIVE
:
1094 return E_INVALIDARG
;
1097 switch (mode
& 0xf000)
1099 case STGM_FAILIFTHERE
:
1100 creation_disposition
= create
? CREATE_NEW
: OPEN_EXISTING
;
1103 creation_disposition
= CREATE_ALWAYS
;
1106 return E_INVALIDARG
;
1109 hFile
= CreateFileW(path
, access
, share
, NULL
, creation_disposition
, attributes
, 0);
1110 if (hFile
== INVALID_HANDLE_VALUE
)
1111 return HRESULT_FROM_WIN32(GetLastError());
1113 stream
= heap_alloc(sizeof(*stream
));
1114 stream
->IStream_iface
.lpVtbl
= &filestreamvtbl
;
1115 stream
->refcount
= 1;
1116 stream
->u
.file
.handle
= hFile
;
1117 stream
->u
.file
.mode
= mode
;
1119 len
= strlenW(path
);
1120 stream
->u
.file
.path
= heap_alloc((len
+ 1) * sizeof(WCHAR
));
1121 memcpy(stream
->u
.file
.path
, path
, (len
+ 1) * sizeof(WCHAR
));
1123 *ret
= &stream
->IStream_iface
;
1128 /*************************************************************************
1129 * SHCreateStreamOnFileW [SHCORE.@]
1131 HRESULT WINAPI
SHCreateStreamOnFileW(const WCHAR
*path
, DWORD mode
, IStream
**stream
)
1133 TRACE("(%s, %#x, %p)\n", debugstr_w(path
), mode
, stream
);
1135 if (!path
|| !stream
)
1136 return E_INVALIDARG
;
1138 if ((mode
& (STGM_CONVERT
| STGM_DELETEONRELEASE
| STGM_TRANSACTED
)) != 0)
1139 return E_INVALIDARG
;
1141 return SHCreateStreamOnFileEx(path
, mode
, 0, FALSE
, NULL
, stream
);
1144 /*************************************************************************
1145 * SHCreateStreamOnFileA [SHCORE.@]
1147 HRESULT WINAPI
SHCreateStreamOnFileA(const char *path
, DWORD mode
, IStream
**stream
)
1153 TRACE("(%s, %#x, %p)\n", debugstr_a(path
), mode
, stream
);
1156 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND
);
1158 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
1159 pathW
= heap_alloc(len
* sizeof(WCHAR
));
1161 return E_OUTOFMEMORY
;
1163 MultiByteToWideChar(CP_ACP
, 0, path
, -1, pathW
, len
);
1164 hr
= SHCreateStreamOnFileW(pathW
, mode
, stream
);
1170 static ULONG WINAPI
regstream_Release(IStream
*iface
)
1172 struct shstream
*stream
= impl_from_IStream(iface
);
1173 ULONG refcount
= InterlockedDecrement(&stream
->refcount
);
1175 TRACE("(%p)->(%u)\n", stream
, refcount
);
1179 if (stream
->u
.mem
.hkey
)
1181 if (stream
->u
.mem
.length
)
1182 RegSetValueExW(stream
->u
.mem
.hkey
, stream
->u
.mem
.valuename
, 0, REG_BINARY
,
1183 (const BYTE
*)stream
->u
.mem
.buffer
, stream
->u
.mem
.length
);
1185 RegDeleteValueW(stream
->u
.mem
.hkey
, stream
->u
.mem
.valuename
);
1186 RegCloseKey(stream
->u
.mem
.hkey
);
1188 CoTaskMemFree(stream
->u
.mem
.valuename
);
1189 heap_free(stream
->u
.mem
.buffer
);
1196 static const IStreamVtbl regstreamvtbl
=
1198 shstream_QueryInterface
,
1208 shstream_LockRegion
,
1209 shstream_UnlockRegion
,
1214 /*************************************************************************
1215 * SHOpenRegStream2W [SHCORE.@]
1217 IStream
* WINAPI
SHOpenRegStream2W(HKEY hKey
, const WCHAR
*subkey
, const WCHAR
*value
, DWORD mode
)
1219 struct shstream
*stream
;
1220 HKEY hStrKey
= NULL
;
1225 TRACE("(%p, %s, %s, %#x)\n", hKey
, debugstr_w(subkey
), debugstr_w(value
), mode
);
1227 if (mode
== STGM_READ
)
1228 ret
= RegOpenKeyExW(hKey
, subkey
, 0, KEY_READ
, &hStrKey
);
1229 else /* in write mode we make sure the subkey exits */
1230 ret
= RegCreateKeyExW(hKey
, subkey
, 0, NULL
, 0, KEY_READ
| KEY_WRITE
, NULL
, &hStrKey
, NULL
);
1232 if (ret
== ERROR_SUCCESS
)
1234 if (mode
== STGM_READ
|| mode
== STGM_READWRITE
)
1236 /* read initial data */
1237 ret
= RegQueryValueExW(hStrKey
, value
, 0, 0, 0, &length
);
1238 if (ret
== ERROR_SUCCESS
&& length
)
1240 buff
= heap_alloc(length
);
1241 RegQueryValueExW(hStrKey
, value
, 0, 0, buff
, &length
);
1246 buff
= heap_alloc(length
);
1248 stream
= shstream_create(®streamvtbl
, buff
, length
);
1252 stream
->u
.mem
.hkey
= hStrKey
;
1253 SHStrDupW(value
, &stream
->u
.mem
.valuename
);
1254 return &stream
->IStream_iface
;
1259 RegCloseKey(hStrKey
);
1264 /*************************************************************************
1265 * SHOpenRegStream2A [SHCORE.@]
1267 IStream
* WINAPI
SHOpenRegStream2A(HKEY hKey
, const char *subkey
, const char *value
, DWORD mode
)
1269 WCHAR
*subkeyW
= NULL
, *valueW
= NULL
;
1272 TRACE("(%p, %s, %s, %#x)\n", hKey
, debugstr_a(subkey
), debugstr_a(value
), mode
);
1274 if (subkey
&& FAILED(SHStrDupA(subkey
, &subkeyW
)))
1276 if (value
&& FAILED(SHStrDupA(value
, &valueW
)))
1278 CoTaskMemFree(subkeyW
);
1282 stream
= SHOpenRegStream2W(hKey
, subkeyW
, valueW
, mode
);
1283 CoTaskMemFree(subkeyW
);
1284 CoTaskMemFree(valueW
);
1288 /*************************************************************************
1289 * SHOpenRegStreamA [SHCORE.@]
1291 IStream
* WINAPI
SHOpenRegStreamA(HKEY hkey
, const char *subkey
, const char *value
, DWORD mode
)
1293 WCHAR
*subkeyW
= NULL
, *valueW
= NULL
;
1296 TRACE("(%p, %s, %s, %#x)\n", hkey
, debugstr_a(subkey
), debugstr_a(value
), mode
);
1298 if (subkey
&& FAILED(SHStrDupA(subkey
, &subkeyW
)))
1300 if (value
&& FAILED(SHStrDupA(value
, &valueW
)))
1302 CoTaskMemFree(subkeyW
);
1306 stream
= SHOpenRegStreamW(hkey
, subkeyW
, valueW
, mode
);
1307 CoTaskMemFree(subkeyW
);
1308 CoTaskMemFree(valueW
);
1312 static ULONG WINAPI
dummystream_AddRef(IStream
*iface
)
1318 static ULONG WINAPI
dummystream_Release(IStream
*iface
)
1324 static HRESULT WINAPI
dummystream_Read(IStream
*iface
, void *buff
, ULONG buff_size
, ULONG
*read_len
)
1332 static const IStreamVtbl dummystreamvtbl
=
1334 shstream_QueryInterface
,
1336 dummystream_Release
,
1344 shstream_LockRegion
,
1345 shstream_UnlockRegion
,
1350 static struct shstream dummyregstream
= { { &dummystreamvtbl
} };
1352 /*************************************************************************
1353 * SHOpenRegStreamW [SHCORE.@]
1355 IStream
* WINAPI
SHOpenRegStreamW(HKEY hkey
, const WCHAR
*subkey
, const WCHAR
*value
, DWORD mode
)
1359 TRACE("(%p, %s, %s, %#x)\n", hkey
, debugstr_w(subkey
), debugstr_w(value
), mode
);
1360 stream
= SHOpenRegStream2W(hkey
, subkey
, value
, mode
);
1361 return stream
? stream
: &dummyregstream
.IStream_iface
;
1366 IUnknown IUnknown_iface
;
1370 static inline struct threadref
*threadref_impl_from_IUnknown(IUnknown
*iface
)
1372 return CONTAINING_RECORD(iface
, struct threadref
, IUnknown_iface
);
1375 static HRESULT WINAPI
threadref_QueryInterface(IUnknown
*iface
, REFIID riid
, void **out
)
1377 struct threadref
*threadref
= threadref_impl_from_IUnknown(iface
);
1379 TRACE("(%p, %s, %p)\n", threadref
, debugstr_guid(riid
), out
);
1384 if (IsEqualGUID(&IID_IUnknown
, riid
))
1387 IUnknown_AddRef(iface
);
1392 WARN("Interface %s not supported.\n", debugstr_guid(riid
));
1393 return E_NOINTERFACE
;
1396 static ULONG WINAPI
threadref_AddRef(IUnknown
*iface
)
1398 struct threadref
*threadref
= threadref_impl_from_IUnknown(iface
);
1399 LONG refcount
= InterlockedIncrement(threadref
->refcount
);
1401 TRACE("(%p, %d)\n", threadref
, refcount
);
1406 static ULONG WINAPI
threadref_Release(IUnknown
*iface
)
1408 struct threadref
*threadref
= threadref_impl_from_IUnknown(iface
);
1409 LONG refcount
= InterlockedDecrement(threadref
->refcount
);
1411 TRACE("(%p, %d)\n", threadref
, refcount
);
1414 heap_free(threadref
);
1419 static const IUnknownVtbl threadrefvtbl
=
1421 threadref_QueryInterface
,
1426 /*************************************************************************
1427 * SHCreateThreadRef [SHCORE.@]
1429 HRESULT WINAPI
SHCreateThreadRef(LONG
*refcount
, IUnknown
**out
)
1431 struct threadref
*threadref
;
1433 TRACE("(%p, %p)\n", refcount
, out
);
1435 if (!refcount
|| !out
)
1436 return E_INVALIDARG
;
1440 threadref
= heap_alloc(sizeof(*threadref
));
1442 return E_OUTOFMEMORY
;
1443 threadref
->IUnknown_iface
.lpVtbl
= &threadrefvtbl
;
1444 threadref
->refcount
= refcount
;
1447 *out
= &threadref
->IUnknown_iface
;
1449 TRACE("Created %p.\n", threadref
);
1453 /*************************************************************************
1454 * SHGetThreadRef [SHCORE.@]
1456 HRESULT WINAPI
SHGetThreadRef(IUnknown
**out
)
1458 TRACE("(%p)\n", out
);
1460 if (shcore_tls
== TLS_OUT_OF_INDEXES
)
1461 return E_NOINTERFACE
;
1463 *out
= TlsGetValue(shcore_tls
);
1465 return E_NOINTERFACE
;
1467 IUnknown_AddRef(*out
);
1471 /*************************************************************************
1472 * SHSetThreadRef [SHCORE.@]
1474 HRESULT WINAPI
SHSetThreadRef(IUnknown
*obj
)
1476 TRACE("(%p)\n", obj
);
1478 if (shcore_tls
== TLS_OUT_OF_INDEXES
)
1479 return E_NOINTERFACE
;
1481 TlsSetValue(shcore_tls
, obj
);
1485 /*************************************************************************
1486 * SHReleaseThreadRef [SHCORE.@]
1488 HRESULT WINAPI
SHReleaseThreadRef(void)
1490 FIXME("() - stub!\n");
1494 /*************************************************************************
1495 * GetProcessReference [SHCORE.@]
1497 HRESULT WINAPI
GetProcessReference(IUnknown
**obj
)
1499 TRACE("(%p)\n", obj
);
1507 IUnknown_AddRef(*obj
);
1512 /*************************************************************************
1513 * SetProcessReference [SHCORE.@]
1515 void WINAPI
SetProcessReference(IUnknown
*obj
)
1517 TRACE("(%p)\n", obj
);
1524 LPTHREAD_START_ROUTINE thread_proc
;
1525 LPTHREAD_START_ROUTINE callback
;
1529 IUnknown
*thread_ref
;
1530 IUnknown
*process_ref
;
1533 static DWORD WINAPI
shcore_thread_wrapper(void *data
)
1535 struct thread_data thread_data
;
1536 HRESULT hr
= E_FAIL
;
1539 TRACE("(%p)\n", data
);
1541 /* We are now executing in the context of the newly created thread.
1542 * So we copy the data passed to us (it is on the stack of the function
1543 * that called us, which is waiting for us to signal an event before
1545 thread_data
= *(struct thread_data
*)data
;
1547 if (thread_data
.flags
& CTF_COINIT
)
1549 hr
= CoInitializeEx(NULL
, COINIT_APARTMENTTHREADED
| COINIT_DISABLE_OLE1DDE
);
1551 hr
= CoInitializeEx(NULL
, COINIT_DISABLE_OLE1DDE
);
1554 if (thread_data
.callback
)
1555 thread_data
.callback(thread_data
.data
);
1557 /* Signal the thread that created us; it can return now. */
1558 SetEvent(thread_data
.hEvent
);
1560 /* Execute the callers start code. */
1561 retval
= thread_data
.thread_proc(thread_data
.data
);
1563 /* Release thread and process references. */
1564 if (thread_data
.thread_ref
)
1565 IUnknown_Release(thread_data
.thread_ref
);
1567 if (thread_data
.process_ref
)
1568 IUnknown_Release(thread_data
.process_ref
);
1576 /*************************************************************************
1577 * SHCreateThread [SHCORE.@]
1579 BOOL WINAPI
SHCreateThread(LPTHREAD_START_ROUTINE thread_proc
, void *data
, DWORD flags
, LPTHREAD_START_ROUTINE callback
)
1581 struct thread_data thread_data
;
1582 BOOL called
= FALSE
;
1584 TRACE("(%p, %p, %#x, %p)\n", thread_proc
, data
, flags
, callback
);
1586 thread_data
.thread_proc
= thread_proc
;
1587 thread_data
.callback
= callback
;
1588 thread_data
.data
= data
;
1589 thread_data
.flags
= flags
;
1590 thread_data
.hEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1592 if (flags
& CTF_THREAD_REF
)
1593 SHGetThreadRef(&thread_data
.thread_ref
);
1595 thread_data
.thread_ref
= NULL
;
1597 if (flags
& CTF_PROCESS_REF
)
1598 GetProcessReference(&thread_data
.process_ref
);
1600 thread_data
.process_ref
= NULL
;
1602 /* Create the thread */
1603 if (thread_data
.hEvent
)
1608 hThread
= CreateThread(NULL
, 0, shcore_thread_wrapper
, &thread_data
, 0, &retval
);
1611 /* Wait for the thread to signal us to continue */
1612 WaitForSingleObject(thread_data
.hEvent
, INFINITE
);
1613 CloseHandle(hThread
);
1616 CloseHandle(thread_data
.hEvent
);
1621 if (!thread_data
.callback
&& flags
& CTF_INSIST
)
1623 /* Couldn't call, call synchronously */
1624 thread_data
.thread_proc(data
);
1629 if (thread_data
.thread_ref
)
1630 IUnknown_Release(thread_data
.thread_ref
);
1632 if (thread_data
.process_ref
)
1633 IUnknown_Release(thread_data
.process_ref
);
1640 /*************************************************************************
1641 * SHStrDupW [SHCORE.@]
1643 HRESULT WINAPI
SHStrDupW(const WCHAR
*src
, WCHAR
**dest
)
1647 TRACE("(%s, %p)\n", debugstr_w(src
), dest
);
1652 return E_INVALIDARG
;
1654 len
= (strlenW(src
) + 1) * sizeof(WCHAR
);
1655 *dest
= CoTaskMemAlloc(len
);
1657 return E_OUTOFMEMORY
;
1659 memcpy(*dest
, src
, len
);
1664 /*************************************************************************
1665 * SHStrDupA [SHCORE.@]
1667 HRESULT WINAPI
SHStrDupA(const char *src
, WCHAR
**dest
)
1674 return E_INVALIDARG
;
1676 len
= MultiByteToWideChar(CP_ACP
, 0, src
, -1, NULL
, 0);
1677 *dest
= CoTaskMemAlloc(len
* sizeof(WCHAR
));
1679 return E_OUTOFMEMORY
;
1681 MultiByteToWideChar(CP_ACP
, 0, src
, -1, *dest
, len
);
1686 /*************************************************************************
1687 * SHAnsiToAnsi [SHCORE.@]
1689 DWORD WINAPI
SHAnsiToAnsi(const char *src
, char *dest
, int dest_len
)
1693 TRACE("(%s, %p, %d)\n", debugstr_a(src
), dest
, dest_len
);
1695 if (!src
|| !dest
|| dest_len
<= 0)
1698 lstrcpynA(dest
, src
, dest_len
);
1701 return src
[ret
] ? 0 : ret
+ 1;
1704 /*************************************************************************
1705 * SHUnicodeToAnsi [SHCORE.@]
1707 DWORD WINAPI
SHUnicodeToAnsi(const WCHAR
*src
, char *dest
, int dest_len
)
1711 TRACE("(%s, %p, %d)\n", debugstr_w(src
), dest
, dest_len
);
1713 if (!dest
|| !dest_len
)
1718 ret
= WideCharToMultiByte(CP_ACP
, 0, src
, -1, dest
, dest_len
, NULL
, NULL
);
1721 dest
[dest_len
- 1] = 0;
1731 /*************************************************************************
1732 * SHUnicodeToUnicode [SHCORE.@]
1734 DWORD WINAPI
SHUnicodeToUnicode(const WCHAR
*src
, WCHAR
*dest
, int dest_len
)
1738 TRACE("(%s, %p, %d)\n", debugstr_w(src
), dest
, dest_len
);
1740 if (!src
|| !dest
|| dest_len
<= 0)
1743 lstrcpynW(dest
, src
, dest_len
);
1744 ret
= strlenW(dest
);
1746 return src
[ret
] ? 0 : ret
+ 1;
1749 /*************************************************************************
1750 * SHAnsiToUnicode [SHCORE.@]
1752 DWORD WINAPI
SHAnsiToUnicode(const char *src
, WCHAR
*dest
, int dest_len
)
1756 TRACE("(%s, %p, %d)\n", debugstr_a(src
), dest
, dest_len
);
1758 if (!dest
|| !dest_len
)
1763 ret
= MultiByteToWideChar(CP_ACP
, 0, src
, -1, dest
, dest_len
);
1766 dest
[dest_len
- 1] = 0;
1776 /*************************************************************************
1777 * SHRegDuplicateHKey [SHCORE.@]
1779 HKEY WINAPI
SHRegDuplicateHKey(HKEY hKey
)
1783 RegOpenKeyExW(hKey
, 0, 0, MAXIMUM_ALLOWED
, &newKey
);
1784 TRACE("new key is %p\n", newKey
);
1788 /*************************************************************************
1789 * SHDeleteEmptyKeyW [SHCORE.@]
1791 DWORD WINAPI
SHDeleteEmptyKeyW(HKEY hkey
, const WCHAR
*subkey
)
1793 DWORD ret
, count
= 0;
1796 TRACE("(%p, %s)\n", hkey
, debugstr_w(subkey
));
1798 ret
= RegOpenKeyExW(hkey
, subkey
, 0, KEY_READ
, &hsubkey
);
1801 ret
= RegQueryInfoKeyW(hsubkey
, NULL
, NULL
, NULL
, &count
,
1802 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1803 RegCloseKey(hsubkey
);
1807 ret
= ERROR_KEY_HAS_CHILDREN
;
1809 ret
= RegDeleteKeyW(hkey
, subkey
);
1816 /*************************************************************************
1817 * SHDeleteEmptyKeyA [SHCORE.@]
1819 DWORD WINAPI
SHDeleteEmptyKeyA(HKEY hkey
, const char *subkey
)
1821 WCHAR
*subkeyW
= NULL
;
1824 TRACE("(%p, %s)\n", hkey
, debugstr_a(subkey
));
1826 if (subkey
&& FAILED(SHStrDupA(subkey
, &subkeyW
)))
1827 return ERROR_OUTOFMEMORY
;
1829 ret
= SHDeleteEmptyKeyW(hkey
, subkeyW
);
1830 CoTaskMemFree(subkeyW
);
1834 /*************************************************************************
1835 * SHDeleteKeyW [SHCORE.@]
1837 DWORD WINAPI
SHDeleteKeyW(HKEY hkey
, const WCHAR
*subkey
)
1839 TRACE("(%p, %s)\n", hkey
, debugstr_w(subkey
));
1841 return RegDeleteTreeW(hkey
, subkey
);
1844 /*************************************************************************
1845 * SHDeleteKeyA [SHCORE.@]
1847 DWORD WINAPI
SHDeleteKeyA(HKEY hkey
, const char *subkey
)
1849 TRACE("(%p, %s)\n", hkey
, debugstr_a(subkey
));
1851 return RegDeleteTreeA(hkey
, subkey
);
1854 /*************************************************************************
1855 * SHDeleteValueW [SHCORE.@]
1857 DWORD WINAPI
SHDeleteValueW(HKEY hkey
, const WCHAR
*subkey
, const WCHAR
*value
)
1862 TRACE("(%p, %s, %s)\n", hkey
, debugstr_w(subkey
), debugstr_w(value
));
1864 ret
= RegOpenKeyExW(hkey
, subkey
, 0, KEY_SET_VALUE
, &hsubkey
);
1867 ret
= RegDeleteValueW(hsubkey
, value
);
1868 RegCloseKey(hsubkey
);
1874 /*************************************************************************
1875 * SHDeleteValueA [SHCORE.@]
1877 DWORD WINAPI
SHDeleteValueA(HKEY hkey
, const char *subkey
, const char *value
)
1879 WCHAR
*subkeyW
= NULL
, *valueW
= NULL
;
1882 TRACE("(%p, %s, %s)\n", hkey
, debugstr_a(subkey
), debugstr_a(value
));
1884 if (subkey
&& FAILED(SHStrDupA(subkey
, &subkeyW
)))
1885 return ERROR_OUTOFMEMORY
;
1886 if (value
&& FAILED(SHStrDupA(value
, &valueW
)))
1888 CoTaskMemFree(subkeyW
);
1889 return ERROR_OUTOFMEMORY
;
1892 ret
= SHDeleteValueW(hkey
, subkeyW
, valueW
);
1893 CoTaskMemFree(subkeyW
);
1894 CoTaskMemFree(valueW
);
1898 /*************************************************************************
1899 * SHCopyKeyA [SHCORE.@]
1901 DWORD WINAPI
SHCopyKeyA(HKEY hkey_src
, const char *subkey
, HKEY hkey_dst
, DWORD reserved
)
1903 WCHAR
*subkeyW
= NULL
;
1906 TRACE("(%p, %s, %p, %d)\n", hkey_src
, debugstr_a(subkey
), hkey_dst
, reserved
);
1908 if (subkey
&& FAILED(SHStrDupA(subkey
, &subkeyW
)))
1911 ret
= SHCopyKeyW(hkey_src
, subkeyW
, hkey_dst
, reserved
);
1912 CoTaskMemFree(subkeyW
);
1916 /*************************************************************************
1917 * SHCopyKeyW [SHCORE.@]
1919 DWORD WINAPI
SHCopyKeyW(HKEY hkey_src
, const WCHAR
*subkey
, HKEY hkey_dst
, DWORD reserved
)
1921 DWORD key_count
= 0, value_count
= 0, max_key_len
= 0;
1922 WCHAR name
[MAX_PATH
], *ptr_name
= name
;
1923 BYTE buff
[1024], *ptr
= buff
;
1924 DWORD max_data_len
= 0, i
;
1927 TRACE("(%p, %s, %p, %d)\n", hkey_src
, debugstr_w(subkey
), hkey_dst
, reserved
);
1929 if (!hkey_dst
|| !hkey_src
)
1930 return ERROR_INVALID_PARAMETER
;
1933 ret
= RegOpenKeyExW(hkey_src
, subkey
, 0, KEY_ALL_ACCESS
, &hkey_src
);
1936 hkey_src
= NULL
; /* Don't close this key since we didn't open it */
1939 DWORD max_value_len
;
1941 ret
= RegQueryInfoKeyW(hkey_src
, NULL
, NULL
, NULL
, &key_count
, &max_key_len
,
1942 NULL
, &value_count
, &max_value_len
, &max_data_len
, NULL
, NULL
);
1945 /* Get max size for key/value names */
1946 max_key_len
= max(max_key_len
, max_value_len
);
1948 if (max_key_len
++ > MAX_PATH
- 1)
1949 ptr_name
= heap_alloc(max_key_len
* sizeof(WCHAR
));
1951 if (max_data_len
> sizeof(buff
))
1952 ptr
= heap_alloc(max_data_len
);
1954 if (!ptr_name
|| !ptr
)
1955 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1959 for (i
= 0; i
< key_count
&& !ret
; i
++)
1961 HKEY hsubkey_src
, hsubkey_dst
;
1962 DWORD length
= max_key_len
;
1964 ret
= RegEnumKeyExW(hkey_src
, i
, ptr_name
, &length
, NULL
, NULL
, NULL
, NULL
);
1967 ret
= RegOpenKeyExW(hkey_src
, ptr_name
, 0, KEY_READ
, &hsubkey_src
);
1970 /* Create destination sub key */
1971 ret
= RegCreateKeyW(hkey_dst
, ptr_name
, &hsubkey_dst
);
1974 /* Recursively copy keys and values from the sub key */
1975 ret
= SHCopyKeyW(hsubkey_src
, NULL
, hsubkey_dst
, 0);
1976 RegCloseKey(hsubkey_dst
);
1979 RegCloseKey(hsubkey_src
);
1983 /* Copy all the values in this key */
1984 for (i
= 0; i
< value_count
&& !ret
; i
++)
1986 DWORD length
= max_key_len
, type
, data_len
= max_data_len
;
1988 ret
= RegEnumValueW(hkey_src
, i
, ptr_name
, &length
, NULL
, &type
, ptr
, &data_len
);
1990 ret
= SHSetValueW(hkey_dst
, NULL
, ptr_name
, type
, ptr
, data_len
);
1994 /* Free buffers if allocated */
1995 if (ptr_name
!= name
)
1996 heap_free(ptr_name
);
2000 if (subkey
&& hkey_src
)
2001 RegCloseKey(hkey_src
);
2007 /*************************************************************************
2008 * SHEnumKeyExA [SHCORE.@]
2010 LONG WINAPI
SHEnumKeyExA(HKEY hkey
, DWORD index
, char *subkey
, DWORD
*length
)
2012 TRACE("(%p, %d, %s, %p)\n", hkey
, index
, debugstr_a(subkey
), length
);
2014 return RegEnumKeyExA(hkey
, index
, subkey
, length
, NULL
, NULL
, NULL
, NULL
);
2017 /*************************************************************************
2018 * SHEnumKeyExW [SHCORE.@]
2020 LONG WINAPI
SHEnumKeyExW(HKEY hkey
, DWORD index
, WCHAR
*subkey
, DWORD
*length
)
2022 TRACE("(%p, %d, %s, %p)\n", hkey
, index
, debugstr_w(subkey
), length
);
2024 return RegEnumKeyExW(hkey
, index
, subkey
, length
, NULL
, NULL
, NULL
, NULL
);
2027 /*************************************************************************
2028 * SHEnumValueA [SHCORE.@]
2030 LONG WINAPI
SHEnumValueA(HKEY hkey
, DWORD index
, char *value
, DWORD
*length
, DWORD
*type
,
2031 void *data
, DWORD
*data_len
)
2033 TRACE("(%p, %d, %s, %p, %p, %p, %p)\n", hkey
, index
, debugstr_a(value
), length
, type
, data
, data_len
);
2035 return RegEnumValueA(hkey
, index
, value
, length
, NULL
, type
, data
, data_len
);
2038 /*************************************************************************
2039 * SHEnumValueW [SHCORE.@]
2041 LONG WINAPI
SHEnumValueW(HKEY hkey
, DWORD index
, WCHAR
*value
, DWORD
*length
, DWORD
*type
,
2042 void *data
, DWORD
*data_len
)
2044 TRACE("(%p, %d, %s, %p, %p, %p, %p)\n", hkey
, index
, debugstr_w(value
), length
, type
, data
, data_len
);
2046 return RegEnumValueW(hkey
, index
, value
, length
, NULL
, type
, data
, data_len
);
2049 /*************************************************************************
2050 * SHQueryValueExW [SHCORE.@]
2052 DWORD WINAPI
SHQueryValueExW(HKEY hkey
, const WCHAR
*name
, DWORD
*reserved
, DWORD
*type
,
2053 void *buff
, DWORD
*buff_len
)
2055 DWORD ret
, value_type
, data_len
= 0;
2057 TRACE("(%p, %s, %p, %p, %p, %p)\n", hkey
, debugstr_w(name
), reserved
, type
, buff
, buff_len
);
2060 data_len
= *buff_len
;
2062 ret
= RegQueryValueExW(hkey
, name
, reserved
, &value_type
, buff
, &data_len
);
2063 if (ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)
2066 if (buff_len
&& value_type
== REG_EXPAND_SZ
)
2071 if (!buff
|| ret
== ERROR_MORE_DATA
)
2074 value
= heap_alloc(length
);
2075 RegQueryValueExW(hkey
, name
, reserved
, NULL
, (BYTE
*)value
, &length
);
2076 length
= ExpandEnvironmentStringsW(value
, NULL
, 0);
2080 length
= (strlenW(buff
) + 1) * sizeof(WCHAR
);
2081 value
= heap_alloc(length
);
2082 memcpy(value
, buff
, length
);
2083 length
= ExpandEnvironmentStringsW(value
, buff
, *buff_len
/ sizeof(WCHAR
));
2084 if (length
> *buff_len
) ret
= ERROR_MORE_DATA
;
2086 data_len
= max(data_len
, length
);
2091 *type
= value_type
== REG_EXPAND_SZ
? REG_SZ
: value_type
;
2093 *buff_len
= data_len
;
2097 /*************************************************************************
2098 * SHQueryValueExA [SHCORE.@]
2100 DWORD WINAPI
SHQueryValueExA(HKEY hkey
, const char *name
, DWORD
*reserved
, DWORD
*type
,
2101 void *buff
, DWORD
*buff_len
)
2103 DWORD ret
, value_type
, data_len
= 0;
2105 TRACE("(%p, %s, %p, %p, %p, %p)\n", hkey
, debugstr_a(name
), reserved
, type
, buff
, buff_len
);
2108 data_len
= *buff_len
;
2110 ret
= RegQueryValueExA(hkey
, name
, reserved
, &value_type
, buff
, &data_len
);
2111 if (ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)
2114 if (buff_len
&& value_type
== REG_EXPAND_SZ
)
2119 if (!buff
|| ret
== ERROR_MORE_DATA
)
2122 value
= heap_alloc(length
);
2123 RegQueryValueExA(hkey
, name
, reserved
, NULL
, (BYTE
*)value
, &length
);
2124 length
= ExpandEnvironmentStringsA(value
, NULL
, 0);
2128 length
= strlen(buff
) + 1;
2129 value
= heap_alloc(length
);
2130 memcpy(value
, buff
, length
);
2131 length
= ExpandEnvironmentStringsA(value
, buff
, *buff_len
);
2132 if (length
> *buff_len
) ret
= ERROR_MORE_DATA
;
2134 data_len
= max(data_len
, length
);
2139 *type
= value_type
== REG_EXPAND_SZ
? REG_SZ
: value_type
;
2141 *buff_len
= data_len
;
2145 /*************************************************************************
2146 * SHGetValueA [SHCORE.@]
2148 DWORD WINAPI
SHGetValueA(HKEY hkey
, const char *subkey
, const char *value
,
2149 DWORD
*type
, void *data
, DWORD
*data_len
)
2154 TRACE("(%p, %s, %s, %p, %p, %p)\n", hkey
, debugstr_a(subkey
), debugstr_a(value
),
2155 type
, data
, data_len
);
2158 ret
= RegOpenKeyExA(hkey
, subkey
, 0, KEY_QUERY_VALUE
, &hsubkey
);
2162 ret
= SHQueryValueExA(hsubkey
? hsubkey
: hkey
, value
, 0, type
, data
, data_len
);
2164 RegCloseKey(hsubkey
);
2170 /*************************************************************************
2171 * SHGetValueW [SHCORE.@]
2173 DWORD WINAPI
SHGetValueW(HKEY hkey
, const WCHAR
*subkey
, const WCHAR
*value
,
2174 DWORD
*type
, void *data
, DWORD
*data_len
)
2179 TRACE("(%p, %s, %s, %p, %p, %p)\n", hkey
, debugstr_w(subkey
), debugstr_w(value
),
2180 type
, data
, data_len
);
2183 ret
= RegOpenKeyExW(hkey
, subkey
, 0, KEY_QUERY_VALUE
, &hsubkey
);
2187 ret
= SHQueryValueExW(hsubkey
? hsubkey
: hkey
, value
, 0, type
, data
, data_len
);
2189 RegCloseKey(hsubkey
);
2195 /*************************************************************************
2196 * SHRegGetIntW [SHCORE.280]
2198 int WINAPI
SHRegGetIntW(HKEY hkey
, const WCHAR
*value
, int default_value
)
2203 TRACE("(%p, %s, %d)\n", hkey
, debugstr_w(value
), default_value
);
2206 buff_len
= sizeof(buff
);
2207 if (SHQueryValueExW(hkey
, value
, 0, 0, buff
, &buff_len
))
2208 return default_value
;
2210 if (*buff
>= '0' && *buff
<= '9')
2213 return default_value
;
2216 /*************************************************************************
2217 * SHRegGetPathA [SHCORE.@]
2219 DWORD WINAPI
SHRegGetPathA(HKEY hkey
, const char *subkey
, const char *value
, char *path
, DWORD flags
)
2221 DWORD length
= MAX_PATH
;
2223 TRACE("(%p, %s, %s, %p, %#x)\n", hkey
, debugstr_a(subkey
), debugstr_a(value
), path
, flags
);
2225 return SHGetValueA(hkey
, subkey
, value
, 0, path
, &length
);
2228 /*************************************************************************
2229 * SHRegGetPathW [SHCORE.@]
2231 DWORD WINAPI
SHRegGetPathW(HKEY hkey
, const WCHAR
*subkey
, const WCHAR
*value
, WCHAR
*path
, DWORD flags
)
2233 DWORD length
= MAX_PATH
;
2235 TRACE("(%p, %s, %s, %p, %d)\n", hkey
, debugstr_w(subkey
), debugstr_w(value
), path
, flags
);
2237 return SHGetValueW(hkey
, subkey
, value
, 0, path
, &length
);
2240 /*************************************************************************
2241 * SHSetValueW [SHCORE.@]
2243 DWORD WINAPI
SHSetValueW(HKEY hkey
, const WCHAR
*subkey
, const WCHAR
*value
, DWORD type
,
2244 const void *data
, DWORD data_len
)
2246 DWORD ret
= ERROR_SUCCESS
, dummy
;
2249 TRACE("(%p, %s, %s, %d, %p, %d)\n", hkey
, debugstr_w(subkey
), debugstr_w(value
),
2250 type
, data
, data_len
);
2252 if (subkey
&& *subkey
)
2253 ret
= RegCreateKeyExW(hkey
, subkey
, 0, NULL
, 0, KEY_SET_VALUE
, NULL
, &hsubkey
, &dummy
);
2259 ret
= RegSetValueExW(hsubkey
, value
, 0, type
, data
, data_len
);
2260 if (hsubkey
!= hkey
)
2261 RegCloseKey(hsubkey
);
2267 /*************************************************************************
2268 * SHSetValueA [SHCORE.@]
2270 DWORD WINAPI
SHSetValueA(HKEY hkey
, const char *subkey
, const char *value
,
2271 DWORD type
, const void *data
, DWORD data_len
)
2273 DWORD ret
= ERROR_SUCCESS
, dummy
;
2276 TRACE("(%p, %s, %s, %d, %p, %d)\n", hkey
, debugstr_a(subkey
), debugstr_a(value
),
2277 type
, data
, data_len
);
2279 if (subkey
&& *subkey
)
2280 ret
= RegCreateKeyExA(hkey
, subkey
, 0, NULL
, 0, KEY_SET_VALUE
, NULL
, &hsubkey
, &dummy
);
2286 ret
= RegSetValueExA(hsubkey
, value
, 0, type
, data
, data_len
);
2287 if (hsubkey
!= hkey
)
2288 RegCloseKey(hsubkey
);
2294 /*************************************************************************
2295 * SHRegSetPathA [SHCORE.@]
2297 DWORD WINAPI
SHRegSetPathA(HKEY hkey
, const char *subkey
, const char *value
, const char *path
, DWORD flags
)
2299 FIXME("(%p, %s, %s, %s, %#x) - semi-stub\n", hkey
, debugstr_a(subkey
),
2300 debugstr_a(value
), debugstr_a(path
), flags
);
2302 /* FIXME: PathUnExpandEnvStringsA() */
2304 return SHSetValueA(hkey
, subkey
, value
, REG_SZ
, path
, lstrlenA(path
));
2307 /*************************************************************************
2308 * SHRegSetPathW [SHCORE.@]
2310 DWORD WINAPI
SHRegSetPathW(HKEY hkey
, const WCHAR
*subkey
, const WCHAR
*value
, const WCHAR
*path
, DWORD flags
)
2312 FIXME("(%p, %s, %s, %s, %#x) - semi-stub\n", hkey
, debugstr_w(subkey
),
2313 debugstr_w(value
), debugstr_w(path
), flags
);
2315 /* FIXME: PathUnExpandEnvStringsW(); */
2317 return SHSetValueW(hkey
, subkey
, value
, REG_SZ
, path
, lstrlenW(path
));
2320 /*************************************************************************
2321 * SHQueryInfoKeyA [SHCORE.@]
2323 LONG WINAPI
SHQueryInfoKeyA(HKEY hkey
, DWORD
*subkeys
, DWORD
*subkey_max
, DWORD
*values
, DWORD
*value_max
)
2325 TRACE("(%p, %p, %p, %p, %p)\n", hkey
, subkeys
, subkey_max
, values
, value_max
);
2327 return RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, subkeys
, subkey_max
, NULL
, values
, value_max
, NULL
, NULL
, NULL
);
2330 /*************************************************************************
2331 * SHQueryInfoKeyW [SHCORE.@]
2333 LONG WINAPI
SHQueryInfoKeyW(HKEY hkey
, DWORD
*subkeys
, DWORD
*subkey_max
, DWORD
*values
, DWORD
*value_max
)
2335 TRACE("(%p, %p, %p, %p, %p)\n", hkey
, subkeys
, subkey_max
, values
, value_max
);
2337 return RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, subkeys
, subkey_max
, NULL
, values
, value_max
, NULL
, NULL
, NULL
);
2340 /*************************************************************************
2343 BOOL WINAPI
IsOS(DWORD feature
)
2345 DWORD platform
, majorv
, minorv
;
2346 OSVERSIONINFOA osvi
;
2348 osvi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOA
);
2349 if (!GetVersionExA(&osvi
))
2352 majorv
= osvi
.dwMajorVersion
;
2353 minorv
= osvi
.dwMinorVersion
;
2354 platform
= osvi
.dwPlatformId
;
2356 #define ISOS_RETURN(x) \
2357 TRACE("(0x%x) ret=%d\n",feature,(x)); \
2361 case OS_WIN32SORGREATER
:
2362 ISOS_RETURN(platform
== VER_PLATFORM_WIN32s
2363 || platform
== VER_PLATFORM_WIN32_WINDOWS
);
2365 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
);
2366 case OS_WIN95ORGREATER
:
2367 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_WINDOWS
);
2368 case OS_NT4ORGREATER
:
2369 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& majorv
>= 4);
2370 case OS_WIN2000ORGREATER_ALT
:
2371 case OS_WIN2000ORGREATER
:
2372 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& majorv
>= 5);
2373 case OS_WIN98ORGREATER
:
2374 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_WINDOWS
&& minorv
>= 10);
2376 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_WINDOWS
&& minorv
== 10);
2378 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& majorv
>= 5);
2379 case OS_WIN2000SERVER
:
2380 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& (minorv
== 0 || minorv
== 1));
2381 case OS_WIN2000ADVSERVER
:
2382 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& (minorv
== 0 || minorv
== 1));
2383 case OS_WIN2000DATACENTER
:
2384 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& (minorv
== 0 || minorv
== 1));
2385 case OS_WIN2000TERMINAL
:
2386 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& (minorv
== 0 || minorv
== 1));
2388 FIXME("(OS_EMBEDDED) What should we return here?\n");
2390 case OS_TERMINALCLIENT
:
2391 FIXME("(OS_TERMINALCLIENT) What should we return here?\n");
2393 case OS_TERMINALREMOTEADMIN
:
2394 FIXME("(OS_TERMINALREMOTEADMIN) What should we return here?\n");
2397 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_WINDOWS
&& minorv
== 0);
2398 case OS_MEORGREATER
:
2399 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_WINDOWS
&& minorv
>= 90);
2400 case OS_XPORGREATER
:
2401 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& majorv
>= 5 && minorv
>= 1);
2403 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& majorv
>= 5 && minorv
>= 1);
2404 case OS_PROFESSIONAL
:
2405 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
);
2407 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
);
2409 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& majorv
>= 5);
2411 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
);
2412 case OS_TERMINALSERVER
:
2413 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
);
2414 case OS_PERSONALTERMINALSERVER
:
2415 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& minorv
>= 1 && majorv
>= 5);
2416 case OS_FASTUSERSWITCHING
:
2417 FIXME("(OS_FASTUSERSWITCHING) What should we return here?\n");
2419 case OS_WELCOMELOGONUI
:
2420 FIXME("(OS_WELCOMELOGONUI) What should we return here?\n");
2422 case OS_DOMAINMEMBER
:
2423 FIXME("(OS_DOMAINMEMBER) What should we return here?\n");
2426 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
);
2430 IsWow64Process(GetCurrentProcess(), &is_wow64
);
2434 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
);
2435 case OS_SMALLBUSINESSSERVER
:
2436 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
);
2438 FIXME("(OS_TABLETPC) What should we return here?\n");
2440 case OS_SERVERADMINUI
:
2441 FIXME("(OS_SERVERADMINUI) What should we return here?\n");
2443 case OS_MEDIACENTER
:
2444 FIXME("(OS_MEDIACENTER) What should we return here?\n");
2447 FIXME("(OS_APPLIANCE) What should we return here?\n");
2449 case 0x25: /*OS_VISTAORGREATER*/
2450 ISOS_RETURN(platform
== VER_PLATFORM_WIN32_NT
&& majorv
>= 6);
2455 WARN("(0x%x) unknown parameter\n", feature
);