newlib-cygwin/winsup/cygwin/kernel32.cc

440 lines
12 KiB
C++
Raw Normal View History

* Makefile.in (DLL_OFILES): Add kernel32.o. * autoload.cc (WSACloseEvent): Remove. (WSACreateEvent): Remove. * cygheap.cc (cygheap_init): Drop initializing shared_prefix. * cygheap.h (struct init_cygheap): Drop shared_prefix and shared_prefix_buf members. * fhandler_socket.cc (sock_shared_name): New static function. (search_wsa_event_slot): Convert name buffers to WCHAR. Call NtCreateMutant/NtOpenMutant to create mutexes in session local namespace. (fhandler_socket::init_events): Ditto. Fix debug output. (fhandler_socket::release_events): Close mutexes using NtClose. (fhandler_socket::dup): Ditto. * kernel32.cc: New file, implementing Win32 calls in a Cygwin-specific way. * mmap.cc (MapView): Make static. * ntdll.h: Fix status code sorting. (STATUS_OBJECT_NAME_EXISTS): Define. (SEMAPHORE_QUERY_STATE): Define. (CYG_SHARED_DIR_ACCESS): Define. (CYG_MUTANT_ACCESS): Define. (CYG_EVENT_ACCESS): Define. (CYG_SEMAPHORE_ACCESS): Define. (enum _PROCESSINFOCLASS): Define ProcessSessionInformation. (struct _PROCESS_SESSION_INFORMATION): Define. (NtCreateSemaphore): Declare. (NtOpenSemaphore): Declare. * flock.cc: Use CYG_xxx_ACCESS access masks where appropriate. * posix_ipc.cc (ipc_mutex_init): Use native functions to create mutex. Create in cygwin-shared subdir. (ipc_cond_init): Ditto for event. (ipc_mutex_close): Use NtClose. (ipc_cond_close): Ditto. (mq_open): Drop "cyg" prefix from mqh_uname. * shared.cc (CYG_SHARED_DIR_ACCESS): Drop definition here. (_cygwin_testing): Declare extern on file level. (get_shared_parent_dir): Change name of shared directory. Add name to api_fatal output. (get_session_parent_dir): New function. (shared_name): Simplify. (shared_info::initialize): Call get_session_parent_dir. * shared_info.h (get_session_parent_dir): Declare. * smallprint.cc (__small_vswprintf): Fix bug in multibyte string conversion. * thread.cc (semaphore::semaphore): Align semaphore name to object names in posix IPC functions. * include/cygwin/version.h (CYGWIN_VERSION_SHARED_DATA): Bump.
2008-04-21 20:46:58 +08:00
/* kernel32.cc: Win32 replacement functions.
Copyright 2008 Red Hat, Inc.
This file is part of Cygwin.
This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#include "winsup.h"
#include "shared_info.h"
#include "ntdll.h"
#include <wchar.h>
* Makefile.in (DLL_OFILES): Add kernel32.o. * autoload.cc (WSACloseEvent): Remove. (WSACreateEvent): Remove. * cygheap.cc (cygheap_init): Drop initializing shared_prefix. * cygheap.h (struct init_cygheap): Drop shared_prefix and shared_prefix_buf members. * fhandler_socket.cc (sock_shared_name): New static function. (search_wsa_event_slot): Convert name buffers to WCHAR. Call NtCreateMutant/NtOpenMutant to create mutexes in session local namespace. (fhandler_socket::init_events): Ditto. Fix debug output. (fhandler_socket::release_events): Close mutexes using NtClose. (fhandler_socket::dup): Ditto. * kernel32.cc: New file, implementing Win32 calls in a Cygwin-specific way. * mmap.cc (MapView): Make static. * ntdll.h: Fix status code sorting. (STATUS_OBJECT_NAME_EXISTS): Define. (SEMAPHORE_QUERY_STATE): Define. (CYG_SHARED_DIR_ACCESS): Define. (CYG_MUTANT_ACCESS): Define. (CYG_EVENT_ACCESS): Define. (CYG_SEMAPHORE_ACCESS): Define. (enum _PROCESSINFOCLASS): Define ProcessSessionInformation. (struct _PROCESS_SESSION_INFORMATION): Define. (NtCreateSemaphore): Declare. (NtOpenSemaphore): Declare. * flock.cc: Use CYG_xxx_ACCESS access masks where appropriate. * posix_ipc.cc (ipc_mutex_init): Use native functions to create mutex. Create in cygwin-shared subdir. (ipc_cond_init): Ditto for event. (ipc_mutex_close): Use NtClose. (ipc_cond_close): Ditto. (mq_open): Drop "cyg" prefix from mqh_uname. * shared.cc (CYG_SHARED_DIR_ACCESS): Drop definition here. (_cygwin_testing): Declare extern on file level. (get_shared_parent_dir): Change name of shared directory. Add name to api_fatal output. (get_session_parent_dir): New function. (shared_name): Simplify. (shared_info::initialize): Call get_session_parent_dir. * shared_info.h (get_session_parent_dir): Declare. * smallprint.cc (__small_vswprintf): Fix bug in multibyte string conversion. * thread.cc (semaphore::semaphore): Align semaphore name to object names in posix IPC functions. * include/cygwin/version.h (CYGWIN_VERSION_SHARED_DATA): Bump.
2008-04-21 20:46:58 +08:00
/* Implement CreateEvent/OpenEvent so that named objects are always created in
Cygwin shared object namespace. */
HANDLE WINAPI
CreateEventW (LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset,
BOOL bInitialState, LPCWSTR lpName)
{
HANDLE evt;
UNICODE_STRING uname;
OBJECT_ATTRIBUTES attr;
NTSTATUS status;
ULONG flags = 0;
if (lpEventAttributes && lpEventAttributes->bInheritHandle)
flags |= OBJ_INHERIT;
if (lpName)
{
RtlInitUnicodeString (&uname, lpName);
flags |= OBJ_OPENIF | OBJ_CASE_INSENSITIVE;
}
InitializeObjectAttributes (&attr, lpName ? &uname : NULL, flags,
lpName ? get_shared_parent_dir () : NULL,
lpEventAttributes
? lpEventAttributes->lpSecurityDescriptor : NULL);
status = NtCreateEvent (&evt, CYG_EVENT_ACCESS, &attr,
bManualReset ? NotificationEvent
: SynchronizationEvent,
bInitialState);
if (!NT_SUCCESS (status))
{
SetLastError (RtlNtStatusToDosError (status));
return NULL;
}
SetLastError (status == STATUS_OBJECT_NAME_EXISTS
? ERROR_ALREADY_EXISTS : ERROR_SUCCESS);
return evt;
}
HANDLE WINAPI
CreateEventA (LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset,
BOOL bInitialState, LPCSTR lpName)
{
WCHAR name[MAX_PATH];
if (lpName && !sys_mbstowcs (name, MAX_PATH, lpName))
{
SetLastError (ERROR_FILENAME_EXCED_RANGE);
return NULL;
}
return CreateEventW (lpEventAttributes, bManualReset, bInitialState,
lpName ? name : NULL);
}
HANDLE WINAPI
OpenEventW (DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName)
{
HANDLE evt;
UNICODE_STRING uname;
OBJECT_ATTRIBUTES attr;
NTSTATUS status;
ULONG flags = 0;
* Makefile.in (DLL_OFILES): Add kernel32.o. * autoload.cc (WSACloseEvent): Remove. (WSACreateEvent): Remove. * cygheap.cc (cygheap_init): Drop initializing shared_prefix. * cygheap.h (struct init_cygheap): Drop shared_prefix and shared_prefix_buf members. * fhandler_socket.cc (sock_shared_name): New static function. (search_wsa_event_slot): Convert name buffers to WCHAR. Call NtCreateMutant/NtOpenMutant to create mutexes in session local namespace. (fhandler_socket::init_events): Ditto. Fix debug output. (fhandler_socket::release_events): Close mutexes using NtClose. (fhandler_socket::dup): Ditto. * kernel32.cc: New file, implementing Win32 calls in a Cygwin-specific way. * mmap.cc (MapView): Make static. * ntdll.h: Fix status code sorting. (STATUS_OBJECT_NAME_EXISTS): Define. (SEMAPHORE_QUERY_STATE): Define. (CYG_SHARED_DIR_ACCESS): Define. (CYG_MUTANT_ACCESS): Define. (CYG_EVENT_ACCESS): Define. (CYG_SEMAPHORE_ACCESS): Define. (enum _PROCESSINFOCLASS): Define ProcessSessionInformation. (struct _PROCESS_SESSION_INFORMATION): Define. (NtCreateSemaphore): Declare. (NtOpenSemaphore): Declare. * flock.cc: Use CYG_xxx_ACCESS access masks where appropriate. * posix_ipc.cc (ipc_mutex_init): Use native functions to create mutex. Create in cygwin-shared subdir. (ipc_cond_init): Ditto for event. (ipc_mutex_close): Use NtClose. (ipc_cond_close): Ditto. (mq_open): Drop "cyg" prefix from mqh_uname. * shared.cc (CYG_SHARED_DIR_ACCESS): Drop definition here. (_cygwin_testing): Declare extern on file level. (get_shared_parent_dir): Change name of shared directory. Add name to api_fatal output. (get_session_parent_dir): New function. (shared_name): Simplify. (shared_info::initialize): Call get_session_parent_dir. * shared_info.h (get_session_parent_dir): Declare. * smallprint.cc (__small_vswprintf): Fix bug in multibyte string conversion. * thread.cc (semaphore::semaphore): Align semaphore name to object names in posix IPC functions. * include/cygwin/version.h (CYGWIN_VERSION_SHARED_DATA): Bump.
2008-04-21 20:46:58 +08:00
if (bInheritHandle)
flags |= OBJ_INHERIT;
if (lpName)
{
RtlInitUnicodeString (&uname, lpName);
flags |= OBJ_CASE_INSENSITIVE;
}
InitializeObjectAttributes (&attr, lpName ? &uname : NULL, flags,
lpName ? get_shared_parent_dir () : NULL,
NULL);
status = NtOpenEvent (&evt, dwDesiredAccess, &attr);
if (!NT_SUCCESS (status))
{
SetLastError (RtlNtStatusToDosError (status));
return NULL;
}
return evt;
}
HANDLE WINAPI
OpenEventA (DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName)
{
WCHAR name[MAX_PATH];
if (lpName && !sys_mbstowcs (name, MAX_PATH, lpName))
{
SetLastError (ERROR_FILENAME_EXCED_RANGE);
return NULL;
}
return OpenEventW (dwDesiredAccess, bInheritHandle, lpName ? name : NULL);
}
/* Implement CreateMutex/OpenMutex so that named objects are always created in
Cygwin shared object namespace. */
HANDLE WINAPI
CreateMutexW (LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner,
LPCWSTR lpName)
{
HANDLE mtx;
UNICODE_STRING uname;
OBJECT_ATTRIBUTES attr;
NTSTATUS status;
ULONG flags = 0;
if (lpMutexAttributes && lpMutexAttributes->bInheritHandle)
flags |= OBJ_INHERIT;
if (lpName)
{
RtlInitUnicodeString (&uname, lpName);
flags |= OBJ_OPENIF | OBJ_CASE_INSENSITIVE;
}
InitializeObjectAttributes (&attr, lpName ? &uname : NULL, flags,
lpName ? get_shared_parent_dir () : NULL,
lpMutexAttributes
? lpMutexAttributes->lpSecurityDescriptor : NULL);
status = NtCreateMutant (&mtx, CYG_EVENT_ACCESS, &attr, bInitialOwner);
if (!NT_SUCCESS (status))
{
SetLastError (RtlNtStatusToDosError (status));
return NULL;
}
SetLastError (status == STATUS_OBJECT_NAME_EXISTS
? ERROR_ALREADY_EXISTS : ERROR_SUCCESS);
return mtx;
}
HANDLE WINAPI
CreateMutexA (LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner,
LPCSTR lpName)
{
WCHAR name[MAX_PATH];
if (lpName && !sys_mbstowcs (name, MAX_PATH, lpName))
{
SetLastError (ERROR_FILENAME_EXCED_RANGE);
return NULL;
}
return CreateMutexW (lpMutexAttributes, bInitialOwner, lpName ? name : NULL);
}
HANDLE WINAPI
OpenMutexW (DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName)
{
HANDLE mtx;
UNICODE_STRING uname;
OBJECT_ATTRIBUTES attr;
NTSTATUS status;
ULONG flags = 0;
if (bInheritHandle)
flags |= OBJ_INHERIT;
if (lpName)
{
RtlInitUnicodeString (&uname, lpName);
flags |= OBJ_CASE_INSENSITIVE;
}
InitializeObjectAttributes (&attr, lpName ? &uname : NULL, flags,
lpName ? get_shared_parent_dir () : NULL,
NULL);
status = NtOpenMutant (&mtx, dwDesiredAccess, &attr);
if (!NT_SUCCESS (status))
{
SetLastError (RtlNtStatusToDosError (status));
return NULL;
}
return mtx;
}
HANDLE WINAPI
OpenMutexA (DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName)
{
WCHAR name[MAX_PATH];
if (lpName && !sys_mbstowcs (name, MAX_PATH, lpName))
{
SetLastError (ERROR_FILENAME_EXCED_RANGE);
return NULL;
}
return OpenMutexW (dwDesiredAccess, bInheritHandle, lpName ? name : NULL);
}
/* Implement CreateSemaphore/OpenSemaphore so that named objects are always
created in Cygwin shared object namespace. */
HANDLE WINAPI
CreateSemaphoreW (LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
LONG lInitialCount, LONG lMaximumCount, LPCWSTR lpName)
{
HANDLE sem;
UNICODE_STRING uname;
OBJECT_ATTRIBUTES attr;
NTSTATUS status;
ULONG flags = 0;
if (lpSemaphoreAttributes && lpSemaphoreAttributes->bInheritHandle)
flags |= OBJ_INHERIT;
if (lpName)
{
RtlInitUnicodeString (&uname, lpName);
flags |= OBJ_OPENIF | OBJ_CASE_INSENSITIVE;
}
InitializeObjectAttributes (&attr, lpName ? &uname : NULL, flags,
lpName ? get_shared_parent_dir () : NULL,
lpSemaphoreAttributes
? lpSemaphoreAttributes->lpSecurityDescriptor
: NULL);
status = NtCreateSemaphore (&sem, CYG_EVENT_ACCESS, &attr,
lInitialCount, lMaximumCount);
if (!NT_SUCCESS (status))
{
SetLastError (RtlNtStatusToDosError (status));
return NULL;
}
SetLastError (status == STATUS_OBJECT_NAME_EXISTS
? ERROR_ALREADY_EXISTS : ERROR_SUCCESS);
return sem;
}
HANDLE WINAPI
CreateSemaphoreA (LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
LONG lInitialCount, LONG lMaximumCount, LPCSTR lpName)
{
WCHAR name[MAX_PATH];
if (lpName && !sys_mbstowcs (name, MAX_PATH, lpName))
{
SetLastError (ERROR_FILENAME_EXCED_RANGE);
return NULL;
}
return CreateSemaphoreW (lpSemaphoreAttributes, lInitialCount, lMaximumCount,
lpName ? name : NULL);
}
HANDLE WINAPI
OpenSemaphoreW (DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName)
{
HANDLE sem;
UNICODE_STRING uname;
OBJECT_ATTRIBUTES attr;
NTSTATUS status;
ULONG flags = 0;
if (bInheritHandle)
flags |= OBJ_INHERIT;
if (lpName)
{
RtlInitUnicodeString (&uname, lpName);
flags |= OBJ_CASE_INSENSITIVE;
}
InitializeObjectAttributes (&attr, lpName ? &uname : NULL, flags,
lpName ? get_shared_parent_dir () : NULL,
NULL);
status = NtOpenSemaphore (&sem, dwDesiredAccess, &attr);
if (!NT_SUCCESS (status))
{
SetLastError (RtlNtStatusToDosError (status));
return NULL;
}
return sem;
}
HANDLE WINAPI
OpenSemaphoreA (DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName)
{
WCHAR name[MAX_PATH];
if (lpName && !sys_mbstowcs (name, MAX_PATH, lpName))
{
SetLastError (ERROR_FILENAME_EXCED_RANGE);
return NULL;
}
return OpenSemaphoreW (dwDesiredAccess, bInheritHandle, lpName ? name : NULL);
}
/* Implement CreateFileMapping/OpenFileMapping so that named objects are always
created in Cygwin shared object namespace. */
HANDLE WINAPI
CreateFileMappingW (HANDLE hFile, LPSECURITY_ATTRIBUTES lpAttributes,
DWORD flProtect, DWORD dwMaximumSizeHigh,
DWORD dwMaximumSizeLow, LPCWSTR lpName)
{
HANDLE sect;
UNICODE_STRING uname;
OBJECT_ATTRIBUTES attr;
NTSTATUS status;
ULONG flags = 0;
ACCESS_MASK access = READ_CONTROL | SECTION_QUERY | SECTION_MAP_READ;
ULONG prot = flProtect & (PAGE_NOACCESS | PAGE_READONLY | PAGE_READWRITE
| PAGE_WRITECOPY | PAGE_EXECUTE
| PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE
| PAGE_EXECUTE_WRITECOPY);
ULONG attribs = flProtect & (SEC_BASED | SEC_NO_CHANGE | SEC_IMAGE | SEC_VLM
| SEC_RESERVE | SEC_COMMIT | SEC_NOCACHE);
LARGE_INTEGER size = {{ LowPart : dwMaximumSizeLow,
HighPart : dwMaximumSizeHigh }};
PLARGE_INTEGER psize = size.QuadPart ? &size : NULL;
if (prot & (PAGE_READWRITE | PAGE_WRITECOPY
| PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY))
access |= SECTION_MAP_WRITE;
if (prot & (PAGE_EXECUTE | PAGE_EXECUTE_READ
| PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY))
access |= SECTION_MAP_EXECUTE;
if (lpAttributes && lpAttributes->bInheritHandle)
flags |= OBJ_INHERIT;
if (lpName)
{
RtlInitUnicodeString (&uname, lpName);
flags |= OBJ_OPENIF | OBJ_CASE_INSENSITIVE;
}
InitializeObjectAttributes (&attr, lpName ? &uname : NULL, flags,
lpName ? get_shared_parent_dir () : NULL,
lpAttributes
? lpAttributes->lpSecurityDescriptor
: NULL);
if (!(attribs & (SEC_RESERVE | SEC_COMMIT)))
attribs |= SEC_COMMIT;
* Makefile.in (DLL_OFILES): Add kernel32.o. * autoload.cc (WSACloseEvent): Remove. (WSACreateEvent): Remove. * cygheap.cc (cygheap_init): Drop initializing shared_prefix. * cygheap.h (struct init_cygheap): Drop shared_prefix and shared_prefix_buf members. * fhandler_socket.cc (sock_shared_name): New static function. (search_wsa_event_slot): Convert name buffers to WCHAR. Call NtCreateMutant/NtOpenMutant to create mutexes in session local namespace. (fhandler_socket::init_events): Ditto. Fix debug output. (fhandler_socket::release_events): Close mutexes using NtClose. (fhandler_socket::dup): Ditto. * kernel32.cc: New file, implementing Win32 calls in a Cygwin-specific way. * mmap.cc (MapView): Make static. * ntdll.h: Fix status code sorting. (STATUS_OBJECT_NAME_EXISTS): Define. (SEMAPHORE_QUERY_STATE): Define. (CYG_SHARED_DIR_ACCESS): Define. (CYG_MUTANT_ACCESS): Define. (CYG_EVENT_ACCESS): Define. (CYG_SEMAPHORE_ACCESS): Define. (enum _PROCESSINFOCLASS): Define ProcessSessionInformation. (struct _PROCESS_SESSION_INFORMATION): Define. (NtCreateSemaphore): Declare. (NtOpenSemaphore): Declare. * flock.cc: Use CYG_xxx_ACCESS access masks where appropriate. * posix_ipc.cc (ipc_mutex_init): Use native functions to create mutex. Create in cygwin-shared subdir. (ipc_cond_init): Ditto for event. (ipc_mutex_close): Use NtClose. (ipc_cond_close): Ditto. (mq_open): Drop "cyg" prefix from mqh_uname. * shared.cc (CYG_SHARED_DIR_ACCESS): Drop definition here. (_cygwin_testing): Declare extern on file level. (get_shared_parent_dir): Change name of shared directory. Add name to api_fatal output. (get_session_parent_dir): New function. (shared_name): Simplify. (shared_info::initialize): Call get_session_parent_dir. * shared_info.h (get_session_parent_dir): Declare. * smallprint.cc (__small_vswprintf): Fix bug in multibyte string conversion. * thread.cc (semaphore::semaphore): Align semaphore name to object names in posix IPC functions. * include/cygwin/version.h (CYGWIN_VERSION_SHARED_DATA): Bump.
2008-04-21 20:46:58 +08:00
if (hFile == INVALID_HANDLE_VALUE)
hFile = NULL;
status = NtCreateSection (&sect, access, &attr, psize, prot, attribs, hFile);
if (!NT_SUCCESS (status))
{
SetLastError (RtlNtStatusToDosError (status));
return NULL;
}
SetLastError (status == STATUS_OBJECT_NAME_EXISTS
? ERROR_ALREADY_EXISTS : ERROR_SUCCESS);
return sect;
}
HANDLE WINAPI
CreateFileMappingA (HANDLE hFile, LPSECURITY_ATTRIBUTES lpAttributes,
DWORD flProtect, DWORD dwMaximumSizeHigh,
DWORD dwMaximumSizeLow, LPCSTR lpName)
{
WCHAR name[MAX_PATH];
if (lpName && !sys_mbstowcs (name, MAX_PATH, lpName))
{
SetLastError (ERROR_FILENAME_EXCED_RANGE);
return NULL;
}
return CreateFileMappingW (hFile, lpAttributes, flProtect, dwMaximumSizeHigh,
dwMaximumSizeLow, lpName ? name : NULL);
}
HANDLE WINAPI
OpenFileMappingW (DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName)
{
HANDLE sect;
UNICODE_STRING uname;
OBJECT_ATTRIBUTES attr;
NTSTATUS status;
ULONG flags = 0;
if (bInheritHandle)
flags |= OBJ_INHERIT;
if (lpName)
{
RtlInitUnicodeString (&uname, lpName);
flags |= OBJ_CASE_INSENSITIVE;
}
InitializeObjectAttributes (&attr, lpName ? &uname : NULL, flags,
lpName ? get_shared_parent_dir () : NULL,
NULL);
status = NtOpenSection (&sect, dwDesiredAccess, &attr);
if (!NT_SUCCESS (status))
{
SetLastError (RtlNtStatusToDosError (status));
return NULL;
}
return sect;
}
HANDLE WINAPI
OpenFileMappingA (DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName)
{
WCHAR name[MAX_PATH];
if (lpName && !sys_mbstowcs (name, MAX_PATH, lpName))
{
SetLastError (ERROR_FILENAME_EXCED_RANGE);
return NULL;
}
return OpenFileMappingW (dwDesiredAccess, bInheritHandle, lpName ? name : NULL);
}
/* When Terminal Services are installed, the GetWindowsDirectory function
does not return the system installation dir, but a user specific directory
instead. That's not what we have in mind when calling GetWindowsDirectory
from within Cygwin. So we're calling GetSystemWindowsDirectory from here,
except on NT4 where we use the method as described in KB186498. */
#define SYSTEM32 (sizeof ("\\System32") - 1)
UINT WINAPI
GetWindowsDirectoryW (LPWSTR buf, UINT size)
{
if (wincap.has_terminal_services ())
return GetSystemWindowsDirectoryW (buf, size);
/* NT4 */
WCHAR name [size + SYSTEM32];
UINT ret = GetSystemDirectoryW (name, size + SYSTEM32);
if (ret < size + SYSTEM32)
{
name[ret - SYSTEM32] = L'\0';
wcscpy (buf, name);
}
return ret - SYSTEM32;
}
UINT WINAPI
GetWindowsDirectoryA (LPSTR buf, UINT size)
{
WCHAR name[MAX_PATH];
UINT ret = GetWindowsDirectoryW (name, min (size, MAX_PATH));
if (ret < size)
sys_wcstombs (buf, size, name);
return ret;
}