2 * Copyright 2016 Michael Müller
3 * Copyright 2017 Andrey Gusev
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
23 #define WIN32_NO_STATUS
30 #include "wine/debug.h"
31 #include "kernelbase.h"
32 #include "wine/heap.h"
33 #include "wine/list.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(kernelbase
);
38 BOOL is_wow64
= FALSE
;
40 /***********************************************************************
43 BOOL WINAPI
DllMain( HINSTANCE hinst
, DWORD reason
, LPVOID reserved
)
45 if (reason
== DLL_PROCESS_ATTACH
)
47 DisableThreadLibraryCalls( hinst
);
48 IsWow64Process( GetCurrentProcess(), &is_wow64
);
51 init_startup_info( NtCurrentTeb()->Peb
->ProcessParameters
);
58 /*************************************************************
61 BOOL WINAPI
DllMainCRTStartup( HANDLE inst
, DWORD reason
, LPVOID reserved
)
63 return DllMain( inst
, reason
, reserved
);
67 /***********************************************************************
68 * MulDiv (kernelbase.@)
70 INT WINAPI
MulDiv( INT a
, INT b
, INT c
)
76 /* We want to deal with a positive divisor to simplify the logic. */
83 /* If the result is positive, we "add" to round. else, we subtract to round. */
84 if ((a
< 0 && b
< 0) || (a
>= 0 && b
>= 0))
85 ret
= (((LONGLONG
)a
* b
) + (c
/ 2)) / c
;
87 ret
= (((LONGLONG
)a
* b
) - (c
/ 2)) / c
;
89 if (ret
> 2147483647 || ret
< -2147483647) return -1;
93 /***********************************************************************
94 * AppPolicyGetMediaFoundationCodecLoading (KERNELBASE.@)
97 LONG WINAPI
AppPolicyGetMediaFoundationCodecLoading(HANDLE token
, AppPolicyMediaFoundationCodecLoading
*policy
)
99 FIXME("%p, %p\n", token
, policy
);
102 *policy
= AppPolicyMediaFoundationCodecLoading_All
;
104 return ERROR_SUCCESS
;
107 /***********************************************************************
108 * AppPolicyGetProcessTerminationMethod (KERNELBASE.@)
110 LONG WINAPI
AppPolicyGetProcessTerminationMethod(HANDLE token
, AppPolicyProcessTerminationMethod
*policy
)
112 FIXME("%p, %p\n", token
, policy
);
115 *policy
= AppPolicyProcessTerminationMethod_ExitProcess
;
117 return ERROR_SUCCESS
;
120 /***********************************************************************
121 * AppPolicyGetThreadInitializationType (KERNELBASE.@)
123 LONG WINAPI
AppPolicyGetThreadInitializationType(HANDLE token
, AppPolicyThreadInitializationType
*policy
)
125 FIXME("%p, %p\n", token
, policy
);
128 *policy
= AppPolicyThreadInitializationType_None
;
130 return ERROR_SUCCESS
;
133 /***********************************************************************
134 * AppPolicyGetShowDeveloperDiagnostic (KERNELBASE.@)
136 LONG WINAPI
AppPolicyGetShowDeveloperDiagnostic(HANDLE token
, AppPolicyShowDeveloperDiagnostic
*policy
)
138 FIXME("%p, %p\n", token
, policy
);
141 *policy
= AppPolicyShowDeveloperDiagnostic_ShowUI
;
143 return ERROR_SUCCESS
;
146 /***********************************************************************
147 * AppPolicyGetWindowingModel (KERNELBASE.@)
149 LONG WINAPI
AppPolicyGetWindowingModel(HANDLE token
, AppPolicyWindowingModel
*policy
)
151 FIXME("%p, %p\n", token
, policy
);
154 *policy
= AppPolicyWindowingModel_ClassicDesktop
;
156 return ERROR_SUCCESS
;
159 struct counterset_template
161 PERF_COUNTERSET_INFO counterset
;
162 PERF_COUNTER_INFO counter
[1];
165 struct counterset_instance
168 struct counterset_template
*template;
169 PERF_COUNTERSET_INSTANCE instance
;
175 PERFLIBREQUEST callback
;
176 struct counterset_template
**countersets
;
177 unsigned int counterset_count
;
179 struct list instance_list
;
182 static struct perf_provider
*perf_provider_from_handle(HANDLE prov
)
184 return (struct perf_provider
*)prov
;
187 /***********************************************************************
188 * PerfCreateInstance (KERNELBASE.@)
190 PERF_COUNTERSET_INSTANCE WINAPI
*PerfCreateInstance( HANDLE handle
, const GUID
*guid
,
191 const WCHAR
*name
, ULONG id
)
193 struct perf_provider
*prov
= perf_provider_from_handle( handle
);
194 struct counterset_template
*template;
195 struct counterset_instance
*inst
;
199 FIXME( "handle %p, guid %s, name %s, id %lu semi-stub.\n", handle
, debugstr_guid(guid
), debugstr_w(name
), id
);
201 if (!prov
|| !guid
|| !name
)
203 SetLastError( ERROR_INVALID_PARAMETER
);
207 for (i
= 0; i
< prov
->counterset_count
; ++i
)
208 if (IsEqualGUID(guid
, &prov
->countersets
[i
]->counterset
.CounterSetGuid
)) break;
210 if (i
== prov
->counterset_count
)
212 SetLastError( ERROR_NOT_FOUND
);
216 template = prov
->countersets
[i
];
218 LIST_FOR_EACH_ENTRY(inst
, &prov
->instance_list
, struct counterset_instance
, entry
)
220 if (inst
->template == template && inst
->instance
.InstanceId
== id
)
222 SetLastError( ERROR_ALREADY_EXISTS
);
227 size
= (sizeof(PERF_COUNTERSET_INSTANCE
) + template->counterset
.NumCounters
* sizeof(UINT64
)
228 + (lstrlenW( name
) + 1) * sizeof(WCHAR
) + 7) & ~7;
229 inst
= heap_alloc_zero( offsetof(struct counterset_instance
, instance
) + size
);
232 SetLastError( ERROR_OUTOFMEMORY
);
236 inst
->template = template;
237 inst
->instance
.CounterSetGuid
= *guid
;
238 inst
->instance
.dwSize
= size
;
239 inst
->instance
.InstanceId
= id
;
240 inst
->instance
.InstanceNameOffset
= sizeof(PERF_COUNTERSET_INSTANCE
)
241 + template->counterset
.NumCounters
* sizeof(UINT64
);
242 inst
->instance
.InstanceNameSize
= (lstrlenW( name
) + 1) * sizeof(WCHAR
);
243 memcpy( (BYTE
*)&inst
->instance
+ inst
->instance
.InstanceNameOffset
, name
, inst
->instance
.InstanceNameSize
);
244 list_add_tail( &prov
->instance_list
, &inst
->entry
);
246 return &inst
->instance
;
249 /***********************************************************************
250 * PerfDeleteInstance (KERNELBASE.@)
252 ULONG WINAPI
PerfDeleteInstance(HANDLE provider
, PERF_COUNTERSET_INSTANCE
*block
)
254 struct perf_provider
*prov
= perf_provider_from_handle( provider
);
255 struct counterset_instance
*inst
;
257 TRACE( "provider %p, block %p.\n", provider
, block
);
259 if (!prov
|| !block
) return ERROR_INVALID_PARAMETER
;
261 inst
= CONTAINING_RECORD(block
, struct counterset_instance
, instance
);
262 list_remove( &inst
->entry
);
265 return ERROR_SUCCESS
;
268 /***********************************************************************
269 * PerfSetCounterSetInfo (KERNELBASE.@)
271 ULONG WINAPI
PerfSetCounterSetInfo( HANDLE handle
, PERF_COUNTERSET_INFO
*template, ULONG size
)
273 struct perf_provider
*prov
= perf_provider_from_handle( handle
);
274 struct counterset_template
**new_array
;
275 struct counterset_template
*new;
278 FIXME( "handle %p, template %p, size %lu semi-stub.\n", handle
, template, size
);
280 if (!prov
|| !template) return ERROR_INVALID_PARAMETER
;
281 if (!template->NumCounters
) return ERROR_INVALID_PARAMETER
;
282 if (size
< sizeof(*template) || (size
- (sizeof(*template))) / sizeof(PERF_COUNTER_INFO
) < template->NumCounters
)
283 return ERROR_INVALID_PARAMETER
;
285 for (i
= 0; i
< prov
->counterset_count
; ++i
)
287 if (IsEqualGUID( &template->CounterSetGuid
, &prov
->countersets
[i
]->counterset
.CounterSetGuid
))
288 return ERROR_ALREADY_EXISTS
;
291 size
= offsetof( struct counterset_template
, counter
[template->NumCounters
] );
292 if (!(new = heap_alloc( size
))) return ERROR_OUTOFMEMORY
;
294 if (prov
->counterset_count
)
295 new_array
= heap_realloc( prov
->countersets
, sizeof(*prov
->countersets
) * (prov
->counterset_count
+ 1) );
297 new_array
= heap_alloc( sizeof(*prov
->countersets
) );
302 return ERROR_OUTOFMEMORY
;
304 memcpy( new, template, size
);
305 for (i
= 0; i
< template->NumCounters
; ++i
)
306 new->counter
[i
].Offset
= i
* sizeof(UINT64
);
307 new_array
[prov
->counterset_count
++] = new;
308 prov
->countersets
= new_array
;
310 return STATUS_SUCCESS
;
313 /***********************************************************************
314 * PerfSetCounterRefValue (KERNELBASE.@)
316 ULONG WINAPI
PerfSetCounterRefValue(HANDLE provider
, PERF_COUNTERSET_INSTANCE
*instance
,
317 ULONG counterid
, void *address
)
319 struct perf_provider
*prov
= perf_provider_from_handle( provider
);
320 struct counterset_template
*template;
321 struct counterset_instance
*inst
;
324 FIXME( "provider %p, instance %p, counterid %lu, address %p semi-stub.\n",
325 provider
, instance
, counterid
, address
);
327 if (!prov
|| !instance
|| !address
) return ERROR_INVALID_PARAMETER
;
329 inst
= CONTAINING_RECORD(instance
, struct counterset_instance
, instance
);
330 template = inst
->template;
332 for (i
= 0; i
< template->counterset
.NumCounters
; ++i
)
333 if (template->counter
[i
].CounterId
== counterid
) break;
335 if (i
== template->counterset
.NumCounters
) return ERROR_NOT_FOUND
;
336 *(void **)((BYTE
*)&inst
->instance
+ sizeof(PERF_COUNTERSET_INSTANCE
) + template->counter
[i
].Offset
) = address
;
338 return STATUS_SUCCESS
;
341 /***********************************************************************
342 * PerfStartProvider (KERNELBASE.@)
344 ULONG WINAPI
PerfStartProvider( GUID
*guid
, PERFLIBREQUEST callback
, HANDLE
*provider
)
346 PERF_PROVIDER_CONTEXT ctx
;
348 FIXME( "guid %s, callback %p, provider %p semi-stub.\n", debugstr_guid(guid
), callback
, provider
);
350 memset( &ctx
, 0, sizeof(ctx
) );
351 ctx
.ContextSize
= sizeof(ctx
);
352 ctx
.ControlCallback
= callback
;
354 return PerfStartProviderEx( guid
, &ctx
, provider
);
357 /***********************************************************************
358 * PerfStartProviderEx (KERNELBASE.@)
360 ULONG WINAPI
PerfStartProviderEx( GUID
*guid
, PERF_PROVIDER_CONTEXT
*context
, HANDLE
*provider
)
362 struct perf_provider
*prov
;
364 FIXME( "guid %s, context %p, provider %p semi-stub.\n", debugstr_guid(guid
), context
, provider
);
366 if (!guid
|| !context
|| !provider
) return ERROR_INVALID_PARAMETER
;
367 if (context
->ContextSize
< sizeof(*context
)) return ERROR_INVALID_PARAMETER
;
369 if (context
->MemAllocRoutine
|| context
->MemFreeRoutine
)
370 FIXME("Memory allocation routine is not supported.\n");
372 if (!(prov
= heap_alloc_zero( sizeof(*prov
) ))) return ERROR_OUTOFMEMORY
;
373 list_init( &prov
->instance_list
);
374 memcpy( &prov
->guid
, guid
, sizeof(prov
->guid
) );
375 prov
->callback
= context
->ControlCallback
;
378 return STATUS_SUCCESS
;
381 /***********************************************************************
382 * PerfStopProvider (KERNELBASE.@)
384 ULONG WINAPI
PerfStopProvider(HANDLE handle
)
386 struct perf_provider
*prov
= perf_provider_from_handle( handle
);
387 struct counterset_instance
*inst
, *next
;
390 TRACE( "handle %p.\n", handle
);
392 if (!list_empty( &prov
->instance_list
))
393 WARN( "Stopping provider with active counter instances.\n" );
395 LIST_FOR_EACH_ENTRY_SAFE(inst
, next
, &prov
->instance_list
, struct counterset_instance
, entry
)
397 list_remove( &inst
->entry
);
401 for (i
= 0; i
< prov
->counterset_count
; ++i
)
402 heap_free( prov
->countersets
[i
] );
403 heap_free( prov
->countersets
);
405 return STATUS_SUCCESS
;
408 /***********************************************************************
409 * QuirkIsEnabled (KERNELBASE.@)
411 BOOL WINAPI
QuirkIsEnabled(void *arg
)
413 FIXME("(%p): stub\n", arg
);
417 /***********************************************************************
418 * QuirkIsEnabled3 (KERNELBASE.@)
420 BOOL WINAPI
QuirkIsEnabled3(void *unk1
, void *unk2
)
425 FIXME("(%p, %p) stub!\n", unk1
, unk2
);
430 HRESULT WINAPI
QISearch(void *base
, const QITAB
*table
, REFIID riid
, void **obj
)
435 TRACE("%p, %p, %s, %p\n", base
, table
, debugstr_guid(riid
), obj
);
440 for (ptr
= table
; ptr
->piid
; ++ptr
)
442 TRACE("trying (offset %ld) %s\n", ptr
->dwOffset
, debugstr_guid(ptr
->piid
));
443 if (IsEqualIID(riid
, ptr
->piid
))
445 unk
= (IUnknown
*)((BYTE
*)base
+ ptr
->dwOffset
);
446 TRACE("matched, returning (%p)\n", unk
);
448 IUnknown_AddRef(unk
);
453 if (IsEqualIID(riid
, &IID_IUnknown
))
455 unk
= (IUnknown
*)((BYTE
*)base
+ table
->dwOffset
);
456 TRACE("returning first for IUnknown (%p)\n", unk
);
458 IUnknown_AddRef(unk
);
462 WARN("Not found %s.\n", debugstr_guid(riid
));
464 return E_NOINTERFACE
;
467 HRESULT WINAPI
GetAcceptLanguagesA(LPSTR langbuf
, DWORD
*buflen
)
469 DWORD buflenW
, convlen
;
473 TRACE("%p, %p, *%p: %ld\n", langbuf
, buflen
, buflen
, buflen
? *buflen
: -1);
475 if (!langbuf
|| !buflen
|| !*buflen
)
479 langbufW
= heap_alloc(sizeof(WCHAR
) * buflenW
);
480 hr
= GetAcceptLanguagesW(langbufW
, &buflenW
);
484 convlen
= WideCharToMultiByte(CP_ACP
, 0, langbufW
, -1, langbuf
, *buflen
, NULL
, NULL
);
485 convlen
--; /* do not count the terminating 0 */
487 else /* copy partial string anyway */
489 convlen
= WideCharToMultiByte(CP_ACP
, 0, langbufW
, *buflen
, langbuf
, *buflen
, NULL
, NULL
);
490 if (convlen
< *buflen
)
492 langbuf
[convlen
] = 0;
493 convlen
--; /* do not count the terminating 0 */
500 *buflen
= buflenW
? convlen
: 0;
506 static HRESULT
lcid_to_rfc1766(LCID lcid
, WCHAR
*rfc1766
, INT len
)
508 WCHAR buffer
[6 /* MAX_RFC1766_NAME */];
509 INT n
= GetLocaleInfoW(lcid
, LOCALE_SISO639LANGNAME
, buffer
, ARRAY_SIZE(buffer
));
514 i
= PRIMARYLANGID(lcid
);
515 if ((((i
== LANG_ENGLISH
) || (i
== LANG_CHINESE
) || (i
== LANG_ARABIC
)) &&
516 (SUBLANGID(lcid
) == SUBLANG_DEFAULT
)) ||
517 (SUBLANGID(lcid
) > SUBLANG_DEFAULT
)) {
520 i
= GetLocaleInfoW(lcid
, LOCALE_SISO3166CTRYNAME
, buffer
+ n
, ARRAY_SIZE(buffer
) - n
);
522 buffer
[n
- 1] = '\0';
527 LCMapStringW(LOCALE_USER_DEFAULT
, LCMAP_LOWERCASE
, buffer
, n
+ i
, rfc1766
, len
);
528 return ((n
+ i
) > len
) ? E_INVALIDARG
: S_OK
;
533 HRESULT WINAPI
GetAcceptLanguagesW(WCHAR
*langbuf
, DWORD
*buflen
)
535 DWORD mystrlen
, mytype
;
542 TRACE("%p, %p, *%p: %ld\n", langbuf
, buflen
, buflen
, buflen
? *buflen
: -1);
544 if (!langbuf
|| !buflen
|| !*buflen
)
547 mystrlen
= (*buflen
> 20) ? *buflen
: 20 ;
548 len
= mystrlen
* sizeof(WCHAR
);
549 mystr
= heap_alloc(len
);
551 RegOpenKeyExW(HKEY_CURRENT_USER
, L
"Software\\Microsoft\\Internet Explorer\\International",
552 0, KEY_QUERY_VALUE
, &mykey
);
553 lres
= RegQueryValueExW(mykey
, L
"AcceptLanguage", 0, &mytype
, (PBYTE
)mystr
, &len
);
555 len
= lstrlenW(mystr
);
557 if (!lres
&& (*buflen
> len
))
559 lstrcpyW(langbuf
, mystr
);
565 /* Did not find a value in the registry or the user buffer is too small */
566 mylcid
= GetUserDefaultLCID();
567 lcid_to_rfc1766(mylcid
, mystr
, mystrlen
);
568 len
= lstrlenW(mystr
);
570 memcpy(langbuf
, mystr
, min(*buflen
, len
+ 1)*sizeof(WCHAR
));
580 return E_NOT_SUFFICIENT_BUFFER
;