Windows-Server-2003/sdktools/debuggers/dbg-common/ntnative.cpp

4817 lines
122 KiB
C++

//----------------------------------------------------------------------------
//
// Support routines for NT-native binaries.
//
// Copyright (C) Microsoft Corporation, 2000-2002.
//
//----------------------------------------------------------------------------
#include "pch.hpp"
#ifdef NT_NATIVE
#define _CRTIMP
#include <time.h>
#include <ntddser.h>
#include "ntnative.h"
#include "cmnutil.hpp"
void* __cdecl operator new(size_t Bytes)
{
return RtlAllocateHeap(RtlProcessHeap(), 0, Bytes);
}
void __cdecl operator delete(void* Ptr)
{
RtlFreeHeap(RtlProcessHeap(), 0, Ptr);
}
int __cdecl _purecall(void)
{
return 0;
}
int __cdecl atexit(void (__cdecl* func)(void))
{
return 1;
}
#define BASE_YEAR_ADJUSTMENT 11644473600
time_t __cdecl time(time_t* timer)
{
LARGE_INTEGER SystemTime;
//
// Read system time from shared region.
//
do
{
SystemTime.HighPart = USER_SHARED_DATA->SystemTime.High1Time;
SystemTime.LowPart = USER_SHARED_DATA->SystemTime.LowPart;
} while (SystemTime.HighPart != USER_SHARED_DATA->SystemTime.High2Time);
// Convert to seconds.
ULONG64 TimeDate = SystemTime.QuadPart / 10000000;
// Convert from base year 1601 to base year 1970.
return (ULONG)(TimeDate - BASE_YEAR_ADJUSTMENT);
}
#ifdef _X86_
LONG WINAPI
InterlockedIncrement(
IN OUT LONG volatile *lpAddend
)
{
__asm
{
mov ecx,lpAddend ; get pointer to addend variable
mov eax,1 ; set increment value
lock xadd [ecx],eax ; interlocked increment
inc eax ; adjust return value
}
}
LONG WINAPI
InterlockedDecrement(
IN OUT LONG volatile *lpAddend
)
{
__asm
{
mov ecx,lpAddend ; get pointer to addend variable
mov eax,-1 ; set decrement value
lock xadd [ecx],eax ; interlocked decrement
dec eax ; adjust return value
}
}
LONG WINAPI
InterlockedExchange(
IN OUT LONG volatile *Target,
IN LONG Value
)
{
__asm
{
mov ecx, [Target] ; (ecx) = Target
mov edx, [Value] ; (edx) = Value
mov eax, [ecx] ; get comperand value
Ixchg:
lock cmpxchg [ecx], edx ; compare and swap
jnz Ixchg ; if nz, exchange failed
}
}
#endif // #ifdef _X86_
DWORD WINAPI
GetLastError(
VOID
)
{
return (DWORD)NtCurrentTeb()->LastErrorValue;
}
VOID WINAPI
SetLastError(
DWORD dwErrCode
)
{
NtCurrentTeb()->LastErrorValue = (LONG)dwErrCode;
}
void
BaseSetLastNTError(NTSTATUS NtStatus)
{
SetLastError(RtlNtStatusToDosError(NtStatus));
}
void WINAPI
Sleep(DWORD Milliseconds)
{
LARGE_INTEGER Timeout;
Win32ToNtTimeout(Milliseconds, &Timeout);
NtDelayExecution(FALSE, &Timeout);
}
HANDLE WINAPI
OpenProcess(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
DWORD dwProcessId
)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES Obja;
HANDLE Handle=NULL;
CLIENT_ID ClientId;
ClientId.UniqueThread = NULL;
ClientId.UniqueProcess = LongToHandle(dwProcessId);
InitializeObjectAttributes(
&Obja,
NULL,
(bInheritHandle ? OBJ_INHERIT : 0),
NULL,
NULL
);
Status = NtOpenProcess(
&Handle,
(ACCESS_MASK)dwDesiredAccess,
&Obja,
&ClientId
);
if ( NT_SUCCESS(Status) )
{
BaseSetLastNTError(Status);
return Handle;
}
else
{
return NULL;
}
}
BOOL
CloseHandle(
HANDLE hObject
)
{
return NT_SUCCESS(NtClose(hObject));
}
int
WINAPI
MultiByteToWideChar(
IN UINT CodePage,
IN DWORD dwFlags,
IN LPCSTR lpMultiByteStr,
IN int cbMultiByte,
OUT LPWSTR lpWideCharStr,
IN int cchWideChar)
{
if (CodePage != CP_ACP || dwFlags != 0)
{
return 0;
}
UNICODE_STRING Wide;
ANSI_STRING Ansi;
RtlInitAnsiString(&Ansi, lpMultiByteStr);
Wide.Buffer = lpWideCharStr;
Wide.MaximumLength = (USHORT)cchWideChar;
if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&Wide, &Ansi, FALSE)))
{
return 0;
}
else
{
return Wide.Length / sizeof(WCHAR) + 1;
}
}
int
WINAPI
WideCharToMultiByte(
IN UINT CodePage,
IN DWORD dwFlags,
IN LPCWSTR lpWideCharStr,
IN int cchWideChar,
OUT LPSTR lpMultiByteStr,
IN int cbMultiByte,
IN LPCSTR lpDefaultChar,
OUT LPBOOL lpUsedDefaultChar)
{
if (CodePage != CP_ACP || dwFlags != 0 || lpDefaultChar != NULL ||
lpUsedDefaultChar != NULL)
{
return 0;
}
UNICODE_STRING Wide;
ANSI_STRING Ansi;
RtlInitUnicodeString(&Wide, lpWideCharStr);
Ansi.Buffer = lpMultiByteStr;
Ansi.MaximumLength = (USHORT)cbMultiByte;
if (!NT_SUCCESS(RtlUnicodeStringToAnsiString(&Ansi, &Wide, FALSE)))
{
return 0;
}
else
{
return Ansi.Length + 1;
}
}
DWORD
WINAPI
SuspendThread(
IN HANDLE hThread
)
{
DWORD PrevCount=0;
NTSTATUS NtStatus;
NtStatus = NtSuspendThread(hThread, &PrevCount);
if (NT_SUCCESS(NtStatus))
{
return PrevCount;
}
else
{
BaseSetLastNTError(NtStatus);
return -1;
}
}
DWORD
WINAPI
ResumeThread(
IN HANDLE hThread
)
{
DWORD PrevCount=0;
NTSTATUS NtStatus;
NtStatus = NtResumeThread(hThread, &PrevCount);
if (NT_SUCCESS(NtStatus))
{
return PrevCount;
}
else
{
BaseSetLastNTError(NtStatus);
return -1;
}
}
DWORD
WINAPI
GetCurrentThreadId(void)
{
return HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread);
}
DWORD
WINAPI
GetCurrentProcessId(void)
{
return HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess);
}
HANDLE
WINAPI
GetCurrentProcess(void)
{
return NtCurrentProcess();
}
BOOL
WINAPI
ReadProcessMemory(
HANDLE hProcess,
LPCVOID lpBaseAddress,
LPVOID lpBuffer,
SIZE_T nSize,
SIZE_T *lpNumberOfBytesRead
)
{
NTSTATUS Status;
SIZE_T NtNumberOfBytesRead=0;
Status = NtReadVirtualMemory(hProcess,
(PVOID)lpBaseAddress,
lpBuffer,
nSize,
&NtNumberOfBytesRead
);
if ( lpNumberOfBytesRead != NULL )
{
*lpNumberOfBytesRead = NtNumberOfBytesRead;
}
if ( !NT_SUCCESS(Status) )
{
BaseSetLastNTError(Status);
return FALSE;
}
else
{
return TRUE;
}
}
BOOL
WINAPI
WriteProcessMemory(
HANDLE hProcess,
LPVOID lpBaseAddress,
LPCVOID lpBuffer,
SIZE_T nSize,
SIZE_T *lpNumberOfBytesWritten
)
{
NTSTATUS Status, xStatus;
ULONG OldProtect;
SIZE_T RegionSize;
PVOID Base;
SIZE_T NtNumberOfBytesWritten;
//
// Set the protection to allow writes
//
RegionSize = nSize;
Base = lpBaseAddress;
Status = NtProtectVirtualMemory(hProcess,
&Base,
&RegionSize,
PAGE_EXECUTE_READWRITE,
&OldProtect
);
if ( NT_SUCCESS(Status) )
{
//
// See if previous protection was writable. If so,
// then reset protection and do the write.
// Otherwise, see if previous protection was read-only or
// no access. In this case, don't do the write, just fail
//
if ( (OldProtect & PAGE_READWRITE) == PAGE_READWRITE ||
(OldProtect & PAGE_WRITECOPY) == PAGE_WRITECOPY ||
(OldProtect & PAGE_EXECUTE_READWRITE) == PAGE_EXECUTE_READWRITE ||
(OldProtect & PAGE_EXECUTE_WRITECOPY) == PAGE_EXECUTE_WRITECOPY )
{
Status = NtProtectVirtualMemory(hProcess,
&Base,
&RegionSize,
OldProtect,
&OldProtect
);
Status = NtWriteVirtualMemory(hProcess,
lpBaseAddress,
lpBuffer,
nSize,
&NtNumberOfBytesWritten
);
if ( lpNumberOfBytesWritten != NULL )
{
*lpNumberOfBytesWritten = NtNumberOfBytesWritten;
}
if ( !NT_SUCCESS(Status) )
{
BaseSetLastNTError(Status);
return FALSE;
}
NtFlushInstructionCache(hProcess,lpBaseAddress,nSize);
return TRUE;
}
else
{
//
// See if the previous protection was read only or no access. If
// this is the case, restore the previous protection and return
// an access violation error.
//
if ( (OldProtect & PAGE_NOACCESS) == PAGE_NOACCESS ||
(OldProtect & PAGE_READONLY) == PAGE_READONLY )
{
Status = NtProtectVirtualMemory(hProcess,
&Base,
&RegionSize,
OldProtect,
&OldProtect
);
BaseSetLastNTError(STATUS_ACCESS_VIOLATION);
return FALSE;
}
else
{
//
// The previous protection must have been code and the caller
// is trying to set a breakpoint or edit the code. Do the write
// and then restore the previous protection.
//
Status = NtWriteVirtualMemory(hProcess,
lpBaseAddress,
lpBuffer,
nSize,
&NtNumberOfBytesWritten
);
if ( lpNumberOfBytesWritten != NULL )
{
*lpNumberOfBytesWritten = NtNumberOfBytesWritten;
}
xStatus = NtProtectVirtualMemory(hProcess,
&Base,
&RegionSize,
OldProtect,
&OldProtect
);
if ( !NT_SUCCESS(Status) )
{
BaseSetLastNTError(STATUS_ACCESS_VIOLATION);
return STATUS_ACCESS_VIOLATION;
}
NtFlushInstructionCache(hProcess,lpBaseAddress,nSize);
return TRUE;
}
}
}
else
{
BaseSetLastNTError(Status);
return FALSE;
}
}
BOOL
DuplicateHandle(
HANDLE hSourceProcessHandle,
HANDLE hSourceHandle,
HANDLE hTargetProcessHandle,
LPHANDLE lpTargetHandle,
DWORD dwDesiredAccess,
BOOL bInheritHandle,
DWORD dwOptions
)
{
NTSTATUS Status;
Status = NtDuplicateObject(hSourceProcessHandle,
hSourceHandle,
hTargetProcessHandle,
lpTargetHandle,
(ACCESS_MASK)dwDesiredAccess,
bInheritHandle ? OBJ_INHERIT : 0,
dwOptions
);
if ( NT_SUCCESS(Status) )
{
return TRUE;
}
else
{
BaseSetLastNTError(Status);
return FALSE;
}
return FALSE;
}
BOOL
APIENTRY
GetThreadContext(
HANDLE hThread,
LPCONTEXT lpContext
)
{
NTSTATUS Status;
Status = NtGetContextThread(hThread,lpContext);
if ( !NT_SUCCESS(Status) )
{
BaseSetLastNTError(Status);
return FALSE;
}
else
{
return TRUE;
}
}
BOOL
APIENTRY
SetThreadContext(
HANDLE hThread,
CONST CONTEXT *lpContext
)
{
NTSTATUS Status;
Status = NtSetContextThread(hThread,(PCONTEXT)lpContext);
if ( !NT_SUCCESS(Status) )
{
BaseSetLastNTError(Status);
return FALSE;
}
else
{
return TRUE;
}
}
BOOL
APIENTRY
GetThreadSelectorEntry(
HANDLE hThread,
DWORD dwSelector,
LPLDT_ENTRY lpSelectorEntry
)
{
#if defined(i386)
DESCRIPTOR_TABLE_ENTRY DescriptorEntry;
NTSTATUS Status;
DescriptorEntry.Selector = dwSelector;
Status = NtQueryInformationThread(hThread,
ThreadDescriptorTableEntry,
&DescriptorEntry,
sizeof(DescriptorEntry),
NULL
);
if ( !NT_SUCCESS(Status) )
{
BaseSetLastNTError(Status);
return FALSE;
}
*lpSelectorEntry = DescriptorEntry.Descriptor;
return TRUE;
#else
BaseSetLastNTError(STATUS_NOT_SUPPORTED);
return FALSE;
#endif // i386
}
BOOL
WINAPI
SetEnvironmentVariableA(
LPCSTR lpName,
LPCSTR lpValue
)
{
NTSTATUS Status;
STRING Name;
STRING Value;
UNICODE_STRING UnicodeName;
UNICODE_STRING UnicodeValue;
RtlInitString( &Name, lpName );
Status = RtlAnsiStringToUnicodeString(&UnicodeName, &Name, TRUE);
if ( !NT_SUCCESS(Status) )
{
BaseSetLastNTError( Status );
return FALSE;
}
if (ARGUMENT_PRESENT( lpValue ))
{
RtlInitString( &Value, lpValue );
Status = RtlAnsiStringToUnicodeString(&UnicodeValue, &Value, TRUE);
if ( !NT_SUCCESS(Status) )
{
BaseSetLastNTError( Status );
RtlFreeUnicodeString(&UnicodeName);
return FALSE;
}
Status = RtlSetEnvironmentVariable( NULL, &UnicodeName, &UnicodeValue);
RtlFreeUnicodeString(&UnicodeValue);
}
else
{
Status = RtlSetEnvironmentVariable( NULL, &UnicodeName, NULL);
}
RtlFreeUnicodeString(&UnicodeName);
if (NT_SUCCESS( Status ))
{
return( TRUE );
}
else
{
BaseSetLastNTError( Status );
return( FALSE );
}
}
BOOL
WINAPI
TerminateProcess(
HANDLE hProcess,
UINT uExitCode
)
{
NTSTATUS Status;
if ( hProcess == NULL )
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
Status = NtTerminateProcess(hProcess,(NTSTATUS)uExitCode);
if ( NT_SUCCESS(Status) )
{
return TRUE;
}
else
{
BaseSetLastNTError(Status);
return FALSE;
}
}
BOOL
WINAPI
GetExitCodeProcess(
HANDLE hProcess,
LPDWORD lpExitCode
)
{
NTSTATUS Status;
PROCESS_BASIC_INFORMATION BasicInformation;
Status = NtQueryInformationProcess(hProcess,
ProcessBasicInformation,
&BasicInformation,
sizeof(BasicInformation),
NULL
);
if ( NT_SUCCESS(Status) )
{
*lpExitCode = BasicInformation.ExitStatus;
return TRUE;
}
else
{
BaseSetLastNTError(Status);
return FALSE;
}
}
HANDLE
WINAPI
NtNativeCreateFileW(
LPCWSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile,
BOOL TranslatePath
)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES Obja;
HANDLE Handle;
UNICODE_STRING FileName;
IO_STATUS_BLOCK IoStatusBlock;
BOOLEAN TranslationStatus;
PVOID FreeBuffer;
ULONG CreateDisposition;
ULONG CreateFlags = 0;
FILE_ALLOCATION_INFORMATION AllocationInfo;
PUNICODE_STRING lpConsoleName;
BOOL bInheritHandle;
BOOL EndsInSlash;
DWORD SQOSFlags;
BOOLEAN ContextTrackingMode = FALSE;
BOOLEAN EffectiveOnly = FALSE;
SECURITY_IMPERSONATION_LEVEL ImpersonationLevel = SecurityAnonymous;
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
if (ARGUMENT_PRESENT(hTemplateFile))
{
return INVALID_HANDLE_VALUE;
}
switch ( dwCreationDisposition )
{
case CREATE_NEW :
CreateDisposition = FILE_CREATE;
break;
case CREATE_ALWAYS :
CreateDisposition = FILE_OVERWRITE_IF;
break;
case OPEN_EXISTING :
CreateDisposition = FILE_OPEN;
break;
case OPEN_ALWAYS :
CreateDisposition = FILE_OPEN_IF;
break;
case TRUNCATE_EXISTING :
CreateDisposition = FILE_OPEN;
if ( !(dwDesiredAccess & GENERIC_WRITE) )
{
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
break;
default :
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
RtlInitUnicodeString(&FileName,lpFileName);
if (TranslatePath)
{
TranslationStatus = RtlDosPathNameToNtPathName_U(lpFileName,
&FileName,
NULL,
NULL
);
if ( !TranslationStatus )
{
SetLastError(ERROR_PATH_NOT_FOUND);
return INVALID_HANDLE_VALUE;
}
FreeBuffer = FileName.Buffer;
}
else
{
FreeBuffer = NULL;
}
InitializeObjectAttributes(&Obja,
&FileName,
(dwFlagsAndAttributes & FILE_FLAG_POSIX_SEMANTICS) ? 0 : OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
SQOSFlags = dwFlagsAndAttributes & SECURITY_VALID_SQOS_FLAGS;
if ( SQOSFlags & SECURITY_SQOS_PRESENT )
{
SQOSFlags &= ~SECURITY_SQOS_PRESENT;
if (SQOSFlags & SECURITY_CONTEXT_TRACKING)
{
SecurityQualityOfService.ContextTrackingMode = (SECURITY_CONTEXT_TRACKING_MODE) TRUE;
SQOSFlags &= ~SECURITY_CONTEXT_TRACKING;
}
else
{
SecurityQualityOfService.ContextTrackingMode = (SECURITY_CONTEXT_TRACKING_MODE) FALSE;
}
if (SQOSFlags & SECURITY_EFFECTIVE_ONLY)
{
SecurityQualityOfService.EffectiveOnly = TRUE;
SQOSFlags &= ~SECURITY_EFFECTIVE_ONLY;
}
else
{
SecurityQualityOfService.EffectiveOnly = FALSE;
}
SecurityQualityOfService.ImpersonationLevel = (SECURITY_IMPERSONATION_LEVEL)(SQOSFlags >> 16);
}
else
{
SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
SecurityQualityOfService.EffectiveOnly = TRUE;
}
SecurityQualityOfService.Length = sizeof( SECURITY_QUALITY_OF_SERVICE );
Obja.SecurityQualityOfService = &SecurityQualityOfService;
if ( ARGUMENT_PRESENT(lpSecurityAttributes) )
{
Obja.SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
if ( lpSecurityAttributes->bInheritHandle )
{
Obja.Attributes |= OBJ_INHERIT;
}
}
CreateFlags |= (dwFlagsAndAttributes & FILE_FLAG_NO_BUFFERING ? FILE_NO_INTERMEDIATE_BUFFERING : 0 );
CreateFlags |= (dwFlagsAndAttributes & FILE_FLAG_WRITE_THROUGH ? FILE_WRITE_THROUGH : 0 );
CreateFlags |= (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED ? 0 : FILE_SYNCHRONOUS_IO_NONALERT );
CreateFlags |= (dwFlagsAndAttributes & FILE_FLAG_SEQUENTIAL_SCAN ? FILE_SEQUENTIAL_ONLY : 0 );
CreateFlags |= (dwFlagsAndAttributes & FILE_FLAG_RANDOM_ACCESS ? FILE_RANDOM_ACCESS : 0 );
CreateFlags |= (dwFlagsAndAttributes & FILE_FLAG_BACKUP_SEMANTICS ? FILE_OPEN_FOR_BACKUP_INTENT : 0 );
if ( dwFlagsAndAttributes & FILE_FLAG_DELETE_ON_CLOSE )
{
CreateFlags |= FILE_DELETE_ON_CLOSE;
dwDesiredAccess |= DELETE;
}
if ( dwFlagsAndAttributes & FILE_FLAG_OPEN_REPARSE_POINT )
{
CreateFlags |= FILE_OPEN_REPARSE_POINT;
}
if ( dwFlagsAndAttributes & FILE_FLAG_OPEN_NO_RECALL )
{
CreateFlags |= FILE_OPEN_NO_RECALL;
}
//
// Backup semantics allow directories to be opened
//
if ( !(dwFlagsAndAttributes & FILE_FLAG_BACKUP_SEMANTICS) )
{
CreateFlags |= FILE_NON_DIRECTORY_FILE;
}
else
{
//
// Backup intent was specified... Now look to see if we are to allow
// directory creation
//
if ( (dwFlagsAndAttributes & FILE_ATTRIBUTE_DIRECTORY ) &&
(dwFlagsAndAttributes & FILE_FLAG_POSIX_SEMANTICS ) &&
(CreateDisposition == FILE_CREATE) )
{
CreateFlags |= FILE_DIRECTORY_FILE;
}
}
Status = NtCreateFile(&Handle,
(ACCESS_MASK)dwDesiredAccess | SYNCHRONIZE | FILE_READ_ATTRIBUTES,
&Obja,
&IoStatusBlock,
NULL,
dwFlagsAndAttributes & (FILE_ATTRIBUTE_VALID_FLAGS & ~FILE_ATTRIBUTE_DIRECTORY),
dwShareMode,
CreateDisposition,
CreateFlags,
NULL,
0
);
if (FreeBuffer != NULL)
{
RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
}
if ( !NT_SUCCESS(Status) )
{
BaseSetLastNTError(Status);
if ( Status == STATUS_OBJECT_NAME_COLLISION )
{
SetLastError(ERROR_FILE_EXISTS);
}
else if ( Status == STATUS_FILE_IS_A_DIRECTORY )
{
SetLastError(ERROR_ACCESS_DENIED);
}
return INVALID_HANDLE_VALUE;
}
//
// if NT returns supersede/overwritten, it means that a create_always, openalways
// found an existing copy of the file. In this case ERROR_ALREADY_EXISTS is returned
//
if ( (dwCreationDisposition == CREATE_ALWAYS && IoStatusBlock.Information ==
FILE_OVERWRITTEN) ||
(dwCreationDisposition == OPEN_ALWAYS && IoStatusBlock.Information == FILE_OPENED) )
{
SetLastError(ERROR_ALREADY_EXISTS);
}
else
{
SetLastError(0);
}
//
// Truncate the file if required
//
if ( dwCreationDisposition == TRUNCATE_EXISTING)
{
AllocationInfo.AllocationSize.QuadPart = 0;
Status = NtSetInformationFile(Handle,
&IoStatusBlock,
&AllocationInfo,
sizeof(AllocationInfo),
FileAllocationInformation
);
if ( !NT_SUCCESS(Status) )
{
BaseSetLastNTError(Status);
NtClose(Handle);
Handle = INVALID_HANDLE_VALUE;
}
}
return Handle;
}
HANDLE
WINAPI
NtNativeCreateFileA(
LPCSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile,
BOOL TranslatePath
)
{
NTSTATUS Status;
ANSI_STRING AnsiFile;
UNICODE_STRING WideFile;
RtlInitAnsiString(&AnsiFile, lpFileName);
Status = RtlAnsiStringToUnicodeString(&WideFile, &AnsiFile, TRUE);
if (!NT_SUCCESS(Status))
{
BaseSetLastNTError(Status);
return FALSE;
}
HANDLE File;
File = NtNativeCreateFileW(WideFile.Buffer, dwDesiredAccess, dwShareMode,
lpSecurityAttributes, dwCreationDisposition,
dwFlagsAndAttributes, hTemplateFile,
TranslatePath);
RtlFreeUnicodeString(&WideFile);
return File;
}
HANDLE
WINAPI
CreateFileA(
LPCSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile
)
{
return NtNativeCreateFileA(lpFileName, dwDesiredAccess, dwShareMode,
lpSecurityAttributes, dwCreationDisposition,
dwFlagsAndAttributes, hTemplateFile,
TRUE);
}
BOOL
WINAPI
DeviceIoControl(
HANDLE hDevice,
DWORD dwIoControlCode,
LPVOID lpInBuffer,
DWORD nInBufferSize,
LPVOID lpOutBuffer,
DWORD nOutBufferSize,
LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped
)
{
if ((dwIoControlCode >> 16) == FILE_DEVICE_FILE_SYSTEM ||
lpOverlapped != NULL)
{
return FALSE;
}
IO_STATUS_BLOCK Iosb;
NTSTATUS Status;
Status = NtDeviceIoControlFile(hDevice,
NULL,
NULL, // APC routine
NULL, // APC Context
&Iosb,
dwIoControlCode, // IoControlCode
lpInBuffer, // Buffer for data to the FS
nInBufferSize,
lpOutBuffer, // OutputBuffer for data from the FS
nOutBufferSize // OutputBuffer Length
);
if ( Status == STATUS_PENDING)
{
// Operation must complete before return & Iosb destroyed
Status = NtWaitForSingleObject( hDevice, FALSE, NULL );
if ( NT_SUCCESS(Status))
{
Status = Iosb.Status;
}
}
if ( NT_SUCCESS(Status) )
{
*lpBytesReturned = (DWORD)Iosb.Information;
return TRUE;
}
else
{
// handle warning value STATUS_BUFFER_OVERFLOW somewhat correctly
if ( !NT_ERROR(Status) )
{
*lpBytesReturned = (DWORD)Iosb.Information;
}
BaseSetLastNTError(Status);
return FALSE;
}
}
BOOL
WINAPI
ReadFile(
HANDLE hFile,
LPVOID lpBuffer,
DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped
)
{
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
if ( ARGUMENT_PRESENT(lpNumberOfBytesRead) )
{
*lpNumberOfBytesRead = 0;
}
if ( ARGUMENT_PRESENT( lpOverlapped ) )
{
LARGE_INTEGER Li;
lpOverlapped->Internal = (DWORD)STATUS_PENDING;
Li.LowPart = lpOverlapped->Offset;
Li.HighPart = lpOverlapped->OffsetHigh;
Status = NtReadFile(
hFile,
lpOverlapped->hEvent,
NULL,
(ULONG_PTR)lpOverlapped->hEvent & 1 ? NULL : lpOverlapped,
(PIO_STATUS_BLOCK)&lpOverlapped->Internal,
lpBuffer,
nNumberOfBytesToRead,
&Li,
NULL
);
if ( NT_SUCCESS(Status) && Status != STATUS_PENDING)
{
if ( ARGUMENT_PRESENT(lpNumberOfBytesRead) )
{
__try
{
*lpNumberOfBytesRead = (DWORD)lpOverlapped->InternalHigh;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
*lpNumberOfBytesRead = 0;
}
}
return TRUE;
}
else if (Status == STATUS_END_OF_FILE)
{
if ( ARGUMENT_PRESENT(lpNumberOfBytesRead) )
{
*lpNumberOfBytesRead = 0;
}
BaseSetLastNTError(Status);
return FALSE;
}
else
{
BaseSetLastNTError(Status);
return FALSE;
}
}
else
{
Status = NtReadFile(hFile,
NULL,
NULL,
NULL,
&IoStatusBlock,
lpBuffer,
nNumberOfBytesToRead,
NULL,
NULL
);
if ( Status == STATUS_PENDING)
{
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( hFile, FALSE, NULL );
if ( NT_SUCCESS(Status))
{
Status = IoStatusBlock.Status;
}
}
if ( NT_SUCCESS(Status) )
{
*lpNumberOfBytesRead = (DWORD)IoStatusBlock.Information;
return TRUE;
}
else
{
if (Status == STATUS_END_OF_FILE)
{
*lpNumberOfBytesRead = 0;
return TRUE;
}
else
{
if ( NT_WARNING(Status) )
{
*lpNumberOfBytesRead = (DWORD)IoStatusBlock.Information;
}
BaseSetLastNTError(Status);
return FALSE;
}
}
}
}
BOOL
WINAPI
WriteFile(
HANDLE hFile,
LPCVOID lpBuffer,
DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped
)
{
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
if ( ARGUMENT_PRESENT(lpNumberOfBytesWritten) )
{
*lpNumberOfBytesWritten = 0;
}
if ( ARGUMENT_PRESENT( lpOverlapped ) )
{
LARGE_INTEGER Li;
lpOverlapped->Internal = (DWORD)STATUS_PENDING;
Li.LowPart = lpOverlapped->Offset;
Li.HighPart = lpOverlapped->OffsetHigh;
Status = NtWriteFile(
hFile,
lpOverlapped->hEvent,
NULL,
(ULONG_PTR)lpOverlapped->hEvent & 1 ? NULL : lpOverlapped,
(PIO_STATUS_BLOCK)&lpOverlapped->Internal,
(PVOID)lpBuffer,
nNumberOfBytesToWrite,
&Li,
NULL
);
if ( !NT_ERROR(Status) && Status != STATUS_PENDING)
{
if ( ARGUMENT_PRESENT(lpNumberOfBytesWritten) )
{
__try
{
*lpNumberOfBytesWritten = (DWORD)lpOverlapped->InternalHigh;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
*lpNumberOfBytesWritten = 0;
}
}
return TRUE;
}
else
{
BaseSetLastNTError(Status);
return FALSE;
}
}
else
{
Status = NtWriteFile(hFile,
NULL,
NULL,
NULL,
&IoStatusBlock,
(PVOID)lpBuffer,
nNumberOfBytesToWrite,
NULL,
NULL
);
if ( Status == STATUS_PENDING)
{
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( hFile, FALSE, NULL );
if ( NT_SUCCESS(Status))
{
Status = IoStatusBlock.Status;
}
}
if ( NT_SUCCESS(Status))
{
*lpNumberOfBytesWritten = (DWORD)IoStatusBlock.Information;
return TRUE;
}
else
{
if ( NT_WARNING(Status) )
{
*lpNumberOfBytesWritten = (DWORD)IoStatusBlock.Information;
}
BaseSetLastNTError(Status);
return FALSE;
}
}
}
SIZE_T
WINAPI
VirtualQueryEx(
HANDLE hProcess,
LPCVOID lpAddress,
PMEMORY_BASIC_INFORMATION lpBuffer,
SIZE_T dwLength
)
{
NTSTATUS Status;
SIZE_T ReturnLength = 0;
Status = NtQueryVirtualMemory( hProcess,
(LPVOID)lpAddress,
MemoryBasicInformation,
(PMEMORY_BASIC_INFORMATION)lpBuffer,
dwLength,
&ReturnLength
);
if (NT_SUCCESS( Status ))
{
return( ReturnLength );
}
else
{
BaseSetLastNTError( Status );
return( 0 );
}
}
BOOL
WINAPI
VirtualProtectEx(
HANDLE hProcess,
PVOID lpAddress,
SIZE_T dwSize,
DWORD flNewProtect,
PDWORD lpflOldProtect
)
{
NTSTATUS Status;
Status = NtProtectVirtualMemory( hProcess,
&lpAddress,
&dwSize,
flNewProtect,
lpflOldProtect
);
if (NT_SUCCESS( Status )) {
return( TRUE );
}
else {
if (Status == STATUS_INVALID_PAGE_PROTECTION) {
if (hProcess == NtCurrentProcess()) {
//
// Unlock any pages that were locked with MmSecureVirtualMemory.
// This is useful for SANs.
//
if (RtlFlushSecureMemoryCache(lpAddress, dwSize)) {
Status = NtProtectVirtualMemory( hProcess,
&lpAddress,
&dwSize,
flNewProtect,
lpflOldProtect
);
if (NT_SUCCESS( Status )) {
return( TRUE );
}
}
}
}
BaseSetLastNTError( Status );
return( FALSE );
}
}
PVOID
WINAPI
VirtualAllocEx(
HANDLE hProcess,
PVOID lpAddress,
SIZE_T dwSize,
DWORD flAllocationType,
DWORD flProtect
)
{
NTSTATUS Status;
__try {
Status = NtAllocateVirtualMemory( hProcess,
&lpAddress,
0,
&dwSize,
flAllocationType,
flProtect
);
}
__except( EXCEPTION_EXECUTE_HANDLER ) {
Status = GetExceptionCode();
}
if (NT_SUCCESS( Status )) {
return( lpAddress );
}
else {
BaseSetLastNTError( Status );
return( NULL );
}
}
BOOL
WINAPI
VirtualFreeEx(
HANDLE hProcess,
LPVOID lpAddress,
SIZE_T dwSize,
DWORD dwFreeType
)
{
NTSTATUS Status;
if ( (dwFreeType & MEM_RELEASE ) && dwSize != 0 ) {
BaseSetLastNTError( STATUS_INVALID_PARAMETER );
return FALSE;
}
Status = NtFreeVirtualMemory( hProcess,
&lpAddress,
&dwSize,
dwFreeType
);
if (NT_SUCCESS( Status )) {
return( TRUE );
}
else {
if (Status == STATUS_INVALID_PAGE_PROTECTION) {
if (hProcess == NtCurrentProcess()) {
//
// Unlock any pages that were locked with MmSecureVirtualMemory.
// This is useful for SANs.
//
if (RtlFlushSecureMemoryCache(lpAddress, dwSize)) {
Status = NtFreeVirtualMemory( hProcess,
&lpAddress,
&dwSize,
dwFreeType
);
if (NT_SUCCESS( Status )) {
return( TRUE );
}
}
}
}
BaseSetLastNTError( Status );
return( FALSE );
}
}
HANDLE
APIENTRY
CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId
)
{
return CreateRemoteThread( NtCurrentProcess(),
lpThreadAttributes,
dwStackSize,
lpStartAddress,
lpParameter,
dwCreationFlags,
lpThreadId
);
}
HANDLE
APIENTRY
CreateRemoteThread(
HANDLE hProcess,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId
)
{
NTSTATUS Status;
HANDLE Handle;
CLIENT_ID ClientId;
Handle = NULL;
//
// Allocate a stack for this thread in the address space of the target
// process.
//
if ((dwCreationFlags & STACK_SIZE_PARAM_IS_A_RESERVATION) ||
dwStackSize != 0 || lpThreadAttributes != NULL)
{
return NULL;
}
Status = RtlCreateUserThread (hProcess,
NULL,
(dwCreationFlags & CREATE_SUSPENDED) ?
TRUE : FALSE,
0,
0,
0,
(PUSER_THREAD_START_ROUTINE)lpStartAddress,
lpParameter,
&Handle,
&ClientId);
if ( ARGUMENT_PRESENT(lpThreadId) )
{
*lpThreadId = HandleToUlong(ClientId.UniqueThread);
}
return Handle;
}
#define DOS_LOCAL_PIPE_PREFIX L"\\\\.\\pipe\\"
#define DOS_LOCAL_PIPE L"\\DosDevices\\pipe\\"
#define DOS_REMOTE_PIPE L"\\DosDevices\\UNC\\"
#define INVALID_PIPE_MODE_BITS ~(PIPE_READMODE_BYTE \
| PIPE_READMODE_MESSAGE \
| PIPE_WAIT \
| PIPE_NOWAIT)
HANDLE
APIENTRY
NtNativeCreateNamedPipeW(
LPCWSTR lpName,
DWORD dwOpenMode,
DWORD dwPipeMode,
DWORD nMaxInstances,
DWORD nOutBufferSize,
DWORD nInBufferSize,
DWORD nDefaultTimeOut,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
BOOL TranslatePath
)
/*++
Parameters:
lpName --Supplies the pipe name Documented in "Pipe Names" section
earlier. This must be a local name.
dwOpenMode --Supplies the set of flags that define the mode which the
pipe is to be opened with. The open mode consists of access
flags (one of three values) logically ORed with a writethrough
flag (one of two values) and an overlapped flag (one of two
values), as described below.
dwOpenMode Flags:
PIPE_ACCESS_DUPLEX --Pipe is bidirectional. (This is
semantically equivalent to calling CreateFile with access
flags of GENERIC_READ | GENERIC_WRITE.)
PIPE_ACCESS_INBOUND --Data goes from client to server only.
(This is semantically equivalent to calling CreateFile with
access flags of GENERIC_READ.)
PIPE_ACCESS_OUTBOUND --Data goes from server to client only.
(This is semantically equivalent to calling CreateFile with
access flags of GENERIC_WRITE.)
PIPE_WRITETHROUGH --The redirector is not permitted to delay the
transmission of data to the named pipe buffer on the remote
server. This disables a performance enhancement for
applications that need synchronization with every write
operation.
FILE_FLAG_OVERLAPPED --Indicates that the system should
initialize the file so that ReadFile, WriteFile and other
operations that may take a significant time to process will
return ERROR_IO_PENDING. An event will be set to the
signalled state when the operation completes.
FILE_FLAG_WRITETHROUGH -- No intermediate buffering.
WRITE_DAC -- Standard security desired access
WRITE_OWNER -- ditto
ACCESS_SYSTEM_SECURITY -- ditto
dwPipeMode --Supplies the pipe-specific modes (as flags) of the pipe.
This parameter is a combination of a read-mode flag, a type flag,
and a wait flag.
dwPipeMode Flags:
PIPE_WAIT --Blocking mode is to be used for this handle.
PIPE_NOWAIT --Nonblocking mode is to be used for this handle.
PIPE_READMODE_BYTE --Read pipe as a byte stream.
PIPE_READMODE_MESSAGE --Read pipe as a message stream. Note that
this is not allowed with PIPE_TYPE_BYTE.
PIPE_TYPE_BYTE --Pipe is a byte-stream pipe. Note that this is
not allowed with PIPE_READMODE_MESSAGE.
PIPE_TYPE_MESSAGE --Pipe is a message-stream pipe.
nMaxInstances --Gives the maximum number of instances for this pipe.
Acceptable values are 1 to PIPE_UNLIMITED_INSTANCES-1 and
PIPE_UNLIMITED_INSTANCES.
nMaxInstances Special Values:
PIPE_UNLIMITED_INSTANCES --Unlimited instances of this pipe can
be created.
nOutBufferSize --Specifies an advisory on the number of bytes to
reserve for the outgoing buffer.
nInBufferSize --Specifies an advisory on the number of bytes to
reserve for the incoming buffer.
nDefaultTimeOut -- Specifies an optional pointer to a timeout value
that is to be used if a timeout value is not specified when
waiting for an instance of a named pipe. This parameter is only
meaningful when the first instance of a named pipe is created. If
neither CreateNamedPipe or WaitNamedPipe specify a timeout 50
milliseconds will be used.
lpSecurityAttributes --An optional parameter that, if present and
supported on the target system, supplies a security descriptor
for the named pipe. This parameter includes an inheritance flag
for the handle. If this parameter is not present, the handle is
not inherited by child processes.
Return Value:
Returns one of the following:
INVALID_HANDLE_VALUE --An error occurred. Call GetLastError for more
information.
Anything else --Returns a handle for use in the server side of
subsequent named pipe operations.
--*/
{
NTSTATUS Status;
OBJECT_ATTRIBUTES Obja;
HANDLE Handle;
UNICODE_STRING FileName;
IO_STATUS_BLOCK IoStatusBlock;
BOOLEAN TranslationStatus;
LARGE_INTEGER Timeout;
PVOID FreeBuffer;
ULONG CreateFlags;
ULONG DesiredAccess;
ULONG ShareAccess;
ULONG MaxInstances;
SECURITY_DESCRIPTOR SecurityDescriptor;
PACL DefaultAcl = NULL;
if ((nMaxInstances == 0) ||
(nMaxInstances > PIPE_UNLIMITED_INSTANCES)) {
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
// Convert Win32 maximum Instances to Nt maximum instances.
MaxInstances = (nMaxInstances == PIPE_UNLIMITED_INSTANCES)?
0xffffffff : nMaxInstances;
if (TranslatePath)
{
TranslationStatus = RtlDosPathNameToNtPathName_U(
lpName,
&FileName,
NULL,
NULL
);
if ( !TranslationStatus ) {
SetLastError(ERROR_PATH_NOT_FOUND);
return INVALID_HANDLE_VALUE;
}
FreeBuffer = FileName.Buffer;
}
else
{
RtlInitUnicodeString(&FileName, lpName);
FreeBuffer = NULL;
}
InitializeObjectAttributes(
&Obja,
&FileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
if ( ARGUMENT_PRESENT(lpSecurityAttributes) ) {
Obja.SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
if ( lpSecurityAttributes->bInheritHandle ) {
Obja.Attributes |= OBJ_INHERIT;
}
}
if (Obja.SecurityDescriptor == NULL) {
//
// Apply default security if none specified (bug 131090)
//
Status = RtlDefaultNpAcl( &DefaultAcl );
if (NT_SUCCESS( Status )) {
RtlCreateSecurityDescriptor( &SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION );
RtlSetDaclSecurityDescriptor( &SecurityDescriptor, TRUE, DefaultAcl, FALSE );
Obja.SecurityDescriptor = &SecurityDescriptor;
} else {
if (FreeBuffer != NULL)
{
RtlFreeHeap(RtlProcessHeap(),0,FreeBuffer);
}
BaseSetLastNTError(Status);
return INVALID_HANDLE_VALUE;
}
}
// End of code common with fileopcr.c CreateFile()
CreateFlags = (dwOpenMode & FILE_FLAG_WRITE_THROUGH ? FILE_WRITE_THROUGH : 0 );
CreateFlags |= (dwOpenMode & FILE_FLAG_OVERLAPPED ? 0 : FILE_SYNCHRONOUS_IO_NONALERT);
//
// Determine the timeout. Convert from milliseconds to an Nt delta time
//
if ( nDefaultTimeOut ) {
Timeout.QuadPart = - (LONGLONG)UInt32x32To64( 10 * 1000, nDefaultTimeOut );
}
else {
// Default timeout is 50 Milliseconds
Timeout.QuadPart = -10 * 1000 * 50;
}
// Check no reserved bits are set by mistake.
if (( dwOpenMode & ~(PIPE_ACCESS_DUPLEX |
FILE_FLAG_OVERLAPPED | FILE_FLAG_WRITE_THROUGH |
FILE_FLAG_FIRST_PIPE_INSTANCE | WRITE_DAC |
WRITE_OWNER | ACCESS_SYSTEM_SECURITY ))||
( dwPipeMode & ~(PIPE_NOWAIT | PIPE_READMODE_MESSAGE |
PIPE_TYPE_MESSAGE ))) {
if (FreeBuffer != NULL)
{
RtlFreeHeap(RtlProcessHeap(),0,FreeBuffer);
}
if (DefaultAcl != NULL) {
RtlFreeHeap(RtlProcessHeap(),0,DefaultAcl);
}
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
//
// Translate the open mode into a sharemode to restrict the clients access
// and derive the appropriate local desired access.
//
switch ( dwOpenMode & PIPE_ACCESS_DUPLEX ) {
case PIPE_ACCESS_INBOUND:
ShareAccess = FILE_SHARE_WRITE;
DesiredAccess = GENERIC_READ;
break;
case PIPE_ACCESS_OUTBOUND:
ShareAccess = FILE_SHARE_READ;
DesiredAccess = GENERIC_WRITE;
break;
case PIPE_ACCESS_DUPLEX:
ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE;
DesiredAccess = GENERIC_READ | GENERIC_WRITE;
break;
default:
if (FreeBuffer != NULL)
{
RtlFreeHeap(RtlProcessHeap(),0,FreeBuffer);
}
if (DefaultAcl != NULL) {
RtlFreeHeap(RtlProcessHeap(),0,DefaultAcl);
}
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
DesiredAccess |= SYNCHRONIZE |
( dwOpenMode & (WRITE_DAC | WRITE_OWNER | ACCESS_SYSTEM_SECURITY ));
Status = NtCreateNamedPipeFile (
&Handle,
DesiredAccess,
&Obja,
&IoStatusBlock,
ShareAccess,
(dwOpenMode & FILE_FLAG_FIRST_PIPE_INSTANCE) ?
FILE_CREATE : FILE_OPEN_IF, // Create first instance or subsequent
CreateFlags, // Create Options
dwPipeMode & PIPE_TYPE_MESSAGE ?
FILE_PIPE_MESSAGE_TYPE : FILE_PIPE_BYTE_STREAM_TYPE,
dwPipeMode & PIPE_READMODE_MESSAGE ?
FILE_PIPE_MESSAGE_MODE : FILE_PIPE_BYTE_STREAM_MODE,
dwPipeMode & PIPE_NOWAIT ?
FILE_PIPE_COMPLETE_OPERATION : FILE_PIPE_QUEUE_OPERATION,
MaxInstances, // Max instances
nInBufferSize, // Inbound quota
nOutBufferSize, // Outbound quota
(PLARGE_INTEGER)&Timeout
);
if ( Status == STATUS_NOT_SUPPORTED ||
Status == STATUS_INVALID_DEVICE_REQUEST ) {
//
// The request must have been processed by some other device driver
// (other than NPFS). Map the error to something reasonable.
//
Status = STATUS_OBJECT_NAME_INVALID;
}
if (FreeBuffer != NULL)
{
RtlFreeHeap(RtlProcessHeap(),0,FreeBuffer);
}
if (DefaultAcl != NULL) {
RtlFreeHeap(RtlProcessHeap(),0,DefaultAcl);
}
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return INVALID_HANDLE_VALUE;
}
return Handle;
}
HANDLE
APIENTRY
NtNativeCreateNamedPipeA(
LPCSTR lpName,
DWORD dwOpenMode,
DWORD dwPipeMode,
DWORD nMaxInstances,
DWORD nOutBufferSize,
DWORD nInBufferSize,
DWORD nDefaultTimeOut,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
BOOL TranslatePath
)
/*++
Ansi thunk to CreateNamedPipeW.
--*/
{
NTSTATUS Status;
PUNICODE_STRING Unicode;
ANSI_STRING AnsiString;
Unicode = &NtCurrentTeb()->StaticUnicodeString;
RtlInitAnsiString(&AnsiString,lpName);
Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
if ( !NT_SUCCESS(Status) ) {
if ( Status == STATUS_BUFFER_OVERFLOW ) {
SetLastError(ERROR_FILENAME_EXCED_RANGE);
}
else {
BaseSetLastNTError(Status);
}
return INVALID_HANDLE_VALUE;
}
return NtNativeCreateNamedPipeW(
(LPCWSTR)Unicode->Buffer,
dwOpenMode,
dwPipeMode,
nMaxInstances,
nOutBufferSize,
nInBufferSize,
nDefaultTimeOut,
lpSecurityAttributes,
TranslatePath);
}
BOOL
APIENTRY
ConnectNamedPipe(
HANDLE hNamedPipe,
LPOVERLAPPED lpOverlapped
)
/*++
Routine Description:
The ConnectNamedPipe function is used by the server side of a named pipe
to wait for a client to connect to the named pipe with a CreateFile
request. The handle provided with the call to ConnectNamedPipe must have
been previously returned by a successful call to CreateNamedPipe. The pipe
must be in the disconnected, listening or connected states for
ConnectNamedPipe to succeed.
The behavior of this call depends on the blocking/nonblocking mode selected
with the PIPE_WAIT/PIPE_NOWAIT flags when the server end of the pipe was
created with CreateNamedPipe.
If blocking mode is specified, ConnectNamedPipe will change the state from
disconnected to listening and block. When a client connects with a
CreateFile, the state will be changed from listening to connected and the
ConnectNamedPipe returns TRUE. When the file handle is created with
FILE_FLAG_OVERLAPPED on a blocking mode pipe, the lpOverlapped parameter
can be specified. This allows the caller to continue processing while the
ConnectNamedPipe API awaits a connection. When the pipe enters the
signalled state the event is set to the signalled state.
When nonblocking is specified ConnectNamedPipe will not block. On the
first call the state will change from disconnected to listening. When a
client connects with an Open the state will be changed from listening to
connected. The ConnectNamedPipe will return FALSE (with GetLastError
returning ERROR_PIPE_LISTENING) until the state is changed to the listening
state.
Arguments:
hNamedPipe - Supplies a Handle to the server side of a named pipe.
lpOverlapped - Supplies an overlap structure to be used with the request.
If NULL then the API will not return until the operation completes. When
FILE_FLAG_OVERLAPPED is specified when the handle was created,
ConnectNamedPipe may return ERROR_IO_PENDING to allow the caller to
continue processing while the operation completes. The event (or File
handle if hEvent=NULL) will be set to the not signalled state before
ERROR_IO_PENDING is returned. The event will be set to the signalled
state upon completion of the request. GetOverlappedResult is used to
determine the error status.
Return Value:
TRUE -- The operation was successful, the pipe is in the
connected state.
FALSE -- The operation failed. Extended error status is available using
GetLastError.
--*/
{
NTSTATUS Status;
IO_STATUS_BLOCK Iosb;
if ( lpOverlapped ) {
lpOverlapped->Internal = (DWORD)STATUS_PENDING;
}
Status = NtFsControlFile(
hNamedPipe,
(lpOverlapped==NULL)? NULL : lpOverlapped->hEvent,
NULL, // ApcRoutine
lpOverlapped ? ((ULONG_PTR)lpOverlapped->hEvent & 1 ? NULL : lpOverlapped) : NULL,
(lpOverlapped==NULL) ? &Iosb : (PIO_STATUS_BLOCK)&lpOverlapped->Internal,
FSCTL_PIPE_LISTEN,
NULL, // InputBuffer
0, // InputBufferLength,
NULL, // OutputBuffer
0 // OutputBufferLength
);
if ( lpOverlapped == NULL && Status == STATUS_PENDING) {
// Operation must complete before return & Iosb destroyed
Status = NtWaitForSingleObject( hNamedPipe, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
if (NT_SUCCESS( Status ) && Status != STATUS_PENDING ) {
return TRUE;
}
else
{
BaseSetLastNTError(Status);
return FALSE;
}
}
BOOL
APIENTRY
WaitNamedPipeA(
LPCSTR lpNamedPipeName,
DWORD nTimeOut
)
/*++
Ansi thunk to WaitNamedPipeW
--*/
{
ANSI_STRING Ansi;
UNICODE_STRING UnicodeString;
BOOL b;
RtlInitAnsiString(&Ansi, lpNamedPipeName);
if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicodeString, &Ansi, TRUE))) {
return FALSE;
}
b = WaitNamedPipeW( UnicodeString.Buffer, nTimeOut );
RtlFreeUnicodeString(&UnicodeString);
return b;
}
BOOL
APIENTRY
WaitNamedPipeW(
LPCWSTR lpNamedPipeName,
DWORD nTimeOut
)
/*++
Routine Description:
The WaitNamedPipe function waits for a named pipe to become available.
Arguments:
lpNamedPipeName - Supplies the name of the named pipe.
nTimeOut - Gives a value (in milliseconds) that is the amount of time
this function should wait for the pipe to become available. (Note
that the function may take longer than that to execute, due to
various factors.)
nTimeOut Special Values:
NMPWAIT_WAIT_FOREVER
No timeout.
NMPWAIT_USE_DEFAULT_WAIT
Use default timeout set in call to CreateNamedPipe.
Return Value:
TRUE -- The operation was successful.
FALSE -- The operation failed. Extended error status is available using
GetLastError.
--*/
{
IO_STATUS_BLOCK Iosb;
OBJECT_ATTRIBUTES Obja;
NTSTATUS Status;
RTL_PATH_TYPE PathType;
ULONG WaitPipeLength;
PFILE_PIPE_WAIT_FOR_BUFFER WaitPipe;
PWSTR FreeBuffer;
UNICODE_STRING FileSystem;
UNICODE_STRING PipeName;
UNICODE_STRING OriginalPipeName;
UNICODE_STRING ValidUnicodePrefix;
HANDLE Handle;
IO_STATUS_BLOCK IoStatusBlock;
LPWSTR Pwc;
ULONG Index;
//
// Open a handle either to the redirector or the NPFS depending on
// the start of the pipe name. Split lpNamedPipeName into two
// halves as follows:
// \\.\pipe\pipename \\.\pipe\ and pipename
// \\server\pipe\pipename \\ and server\pipe\pipename
//
if (!RtlCreateUnicodeString( &OriginalPipeName, lpNamedPipeName)) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
//
// Change all the forward slashes into backward slashes.
//
for ( Index =0; Index < (OriginalPipeName.Length/sizeof(WCHAR)); Index++ ) {
if (OriginalPipeName.Buffer[Index] == L'/') {
OriginalPipeName.Buffer[Index] = L'\\';
}
}
PipeName = OriginalPipeName;
PathType = RtlDetermineDosPathNameType_U(lpNamedPipeName);
FreeBuffer = NULL;
switch ( PathType ) {
case RtlPathTypeLocalDevice:
// Name should be of the form \\.\pipe\pipename (IgnoreCase)
RtlInitUnicodeString( &ValidUnicodePrefix, DOS_LOCAL_PIPE_PREFIX);
if (RtlPrefixString((PSTRING)&ValidUnicodePrefix,
(PSTRING)&PipeName,
TRUE) == FALSE) {
RtlFreeUnicodeString(&OriginalPipeName);
BaseSetLastNTError(STATUS_OBJECT_PATH_SYNTAX_BAD);
return FALSE;
}
// Skip first 9 characters "\\.\pipe\"
PipeName.Buffer+=9;
PipeName.Length-=9*sizeof(WCHAR);
RtlInitUnicodeString( &FileSystem, DOS_LOCAL_PIPE);
break;
case RtlPathTypeUncAbsolute:
// Name is of the form \\server\pipe\pipename
// Find the pipe name.
for ( Pwc = &PipeName.Buffer[2]; *Pwc != 0; Pwc++) {
if ( *Pwc == L'\\') {
// Found backslash after servername
break;
}
}
if ( (*Pwc != 0) &&
( _wcsnicmp( Pwc + 1, L"pipe\\", 5 ) == 0 ) ) {
// Temporarily, break this up into 2 strings
// string1 = \\server\pipe
// string2 = the-rest
Pwc += (sizeof (L"pipe\\") / sizeof( WCHAR ) ) - 1;
} else {
// This is not a valid remote path name.
RtlFreeUnicodeString(&OriginalPipeName);
BaseSetLastNTError(STATUS_OBJECT_PATH_SYNTAX_BAD);
return FALSE;
}
// Pwc now points to the first path seperator after \\server\pipe.
// Attempt to open \DosDevices\Unc\Servername\Pipe.
PipeName.Buffer = &PipeName.Buffer[2];
PipeName.Length = (USHORT)((PCHAR)Pwc - (PCHAR)PipeName.Buffer);
PipeName.MaximumLength = PipeName.Length;
FileSystem.MaximumLength =
(USHORT)sizeof( DOS_REMOTE_PIPE ) +
PipeName.MaximumLength;
FileSystem.Buffer = (PWSTR)RtlAllocateHeap(
RtlProcessHeap(), 0,
FileSystem.MaximumLength
);
if ( !FileSystem.Buffer ) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
RtlFreeUnicodeString(&OriginalPipeName);
return FALSE;
}
FreeBuffer = FileSystem.Buffer;
RtlCopyMemory(
FileSystem.Buffer,
DOS_REMOTE_PIPE,
sizeof( DOS_REMOTE_PIPE ) - sizeof(WCHAR)
);
FileSystem.Length = sizeof( DOS_REMOTE_PIPE ) - sizeof(WCHAR);
RtlAppendUnicodeStringToString( &FileSystem, &PipeName );
// Set up pipe name, skip leading backslashes.
RtlInitUnicodeString( &PipeName, (PWCH)Pwc + 1 );
break;
default:
BaseSetLastNTError(STATUS_OBJECT_PATH_SYNTAX_BAD);
RtlFreeUnicodeString(&OriginalPipeName);
return FALSE;
}
InitializeObjectAttributes(
&Obja,
&FileSystem,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = NtOpenFile(
&Handle,
(ACCESS_MASK)FILE_READ_ATTRIBUTES | SYNCHRONIZE,
&Obja,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT
);
if (FreeBuffer != NULL) {
RtlFreeHeap(RtlProcessHeap(),0,FreeBuffer);
}
if ( !NT_SUCCESS(Status) ) {
RtlFreeUnicodeString(&OriginalPipeName);
BaseSetLastNTError(Status);
return FALSE;
}
WaitPipeLength =
FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER, Name[0]) + PipeName.Length;
WaitPipe = (PFILE_PIPE_WAIT_FOR_BUFFER)
RtlAllocateHeap(RtlProcessHeap(), 0, WaitPipeLength);
if ( !WaitPipe ) {
RtlFreeUnicodeString(&OriginalPipeName);
NtClose(Handle);
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
if ( nTimeOut == NMPWAIT_USE_DEFAULT_WAIT ) {
WaitPipe->TimeoutSpecified = FALSE;
}
else {
if ( nTimeOut == NMPWAIT_WAIT_FOREVER ) {
WaitPipe->Timeout.LowPart = 0;
WaitPipe->Timeout.HighPart =0x80000000;
}
else {
//
// Convert from milliseconds to an Nt delta time.
//
WaitPipe->Timeout.QuadPart =
- (LONGLONG)UInt32x32To64( 10 * 1000, nTimeOut );
}
WaitPipe->TimeoutSpecified = TRUE;
}
WaitPipe->NameLength = PipeName.Length;
RtlCopyMemory(
WaitPipe->Name,
PipeName.Buffer,
PipeName.Length
);
RtlFreeUnicodeString(&OriginalPipeName);
Status = NtFsControlFile(Handle,
NULL,
NULL, // APC routine
NULL, // APC Context
&Iosb,
FSCTL_PIPE_WAIT,// IoControlCode
WaitPipe, // Buffer for data to the FS
WaitPipeLength,
NULL, // OutputBuffer for data from the FS
0 // OutputBuffer Length
);
RtlFreeHeap(RtlProcessHeap(),0,WaitPipe);
NtClose(Handle);
if (NT_SUCCESS( Status ) ) {
return TRUE;
}
else
{
BaseSetLastNTError(Status);
return FALSE;
}
}
BOOL
APIENTRY
PeekNamedPipe(
HANDLE hNamedPipe,
LPVOID lpBuffer,
DWORD nBufferSize,
LPDWORD lpBytesRead,
LPDWORD lpTotalBytesAvail,
LPDWORD lpBytesLeftThisMessage
)
/*++
Routine Description:
The PeekNamedPipe function copies a named pipe's data into a buffer for
preview without removing it. The results of a PeekNamedPipe are similar to
a ReadFile on the pipe except more information is returned, the function
never blocks and if the pipe handle is reading in message mode, a partial
message can be returned.
A partial message peek'd on a message mode pipe will return TRUE.
It is not an error if all of the pointers passed to this function are
null. However, there is no reason for calling it this way.
The NT peek call has the received data immediately after the state
information so this routine needs to allocate an intermediate buffer
large enough for the state information plus data.
Arguments:
hNamedPipe - Supplies a handle to a named pipe.
lpBuffer - If non-null, pointer to buffer to read data into.
nBufferSize - Size of input buffer, in bytes. (Ignored if lpBuffer
is null.)
lpBytesRead - If non-null, this points to a DWORD which will be set
with the number of bytes actually read.
lpTotalBytesAvail - If non-null, this points to a DWORD which receives
a value giving the number of bytes that were available to be read.
lpBytesLeftThisMessage - If non-null, this points to a DWORD which
will be set to the number of bytes left in this message. (This will
be zero for a byte-stream pipe.)
Return Value:
TRUE -- The operation was successful.
FALSE -- The operation failed. Extended error status is available using
GetLastError.
--*/
{
IO_STATUS_BLOCK Iosb;
NTSTATUS Status;
PFILE_PIPE_PEEK_BUFFER PeekBuffer;
DWORD IOLength;
// Allocate enough for the users data and FILE_PIPE_PEEK_BUFFER
IOLength = nBufferSize + FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]);
PeekBuffer = (PFILE_PIPE_PEEK_BUFFER)
RtlAllocateHeap(RtlProcessHeap(), 0, IOLength);
if (PeekBuffer == NULL) {
BaseSetLastNTError (STATUS_INSUFFICIENT_RESOURCES);
return FALSE;
}
__try {
Status = NtFsControlFile(hNamedPipe,
NULL,
NULL, // APC routine
NULL, // APC Context
&Iosb, // I/O Status block
FSCTL_PIPE_PEEK,// IoControlCode
NULL, // Buffer for data to the FS
0, // Length.
PeekBuffer, // OutputBuffer for data from the FS
IOLength // OutputBuffer Length
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( hNamedPipe, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
//
// Buffer overflow simply means that lpBytesLeftThisMessage != 0
//
if ( Status == STATUS_BUFFER_OVERFLOW ) {
Status = STATUS_SUCCESS;
}
//
// Peek is complete, package up data for caller ensuring that
// the PeekBuffer is deleted even if an invalid pointer was given.
//
if ( NT_SUCCESS(Status)) {
__try {
if ( ARGUMENT_PRESENT( lpTotalBytesAvail ) ) {
*lpTotalBytesAvail = PeekBuffer->ReadDataAvailable;
}
if ( ARGUMENT_PRESENT( lpBytesRead ) ) {
*lpBytesRead = (ULONG)(Iosb.Information - FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]));
}
if ( ARGUMENT_PRESENT( lpBytesLeftThisMessage ) ) {
*lpBytesLeftThisMessage =
PeekBuffer->MessageLength -
(ULONG)(Iosb.Information - FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]));
}
if ( ARGUMENT_PRESENT( lpBuffer ) ) {
RtlCopyMemory(
lpBuffer,
PeekBuffer->Data,
Iosb.Information - FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]));
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
Status = STATUS_ACCESS_VIOLATION;
}
}
}
__finally {
if ( PeekBuffer != NULL ) {
RtlFreeHeap(RtlProcessHeap(),0,PeekBuffer);
}
}
if ( NT_SUCCESS(Status) ) {
return TRUE;
}
else {
BaseSetLastNTError(Status);
return FALSE;
}
}
DWORD
WaitForSingleObject(
HANDLE hHandle,
DWORD dwMilliseconds
)
/*++
Routine Description:
A wait operation on a waitable object is accomplished with the
WaitForSingleObject function.
Waiting on an object checks the current state of the object. If the
current state of the object allows continued execution, any
adjustments to the object state are made (for example, decrementing
the semaphore count for a semaphore object) and the thread continues
execution. If the current state of the object does not allow
continued execution, the thread is placed into the wait state
pending the change of the object's state or time-out.
Arguments:
hHandle - An open handle to a waitable object. The handle must have
SYNCHRONIZE access to the object.
dwMilliseconds - A time-out value that specifies the relative time,
in milliseconds, over which the wait is to be completed. A
timeout value of 0 specified that the wait is to timeout
immediately. This allows an application to test an object to
determine if it is in the signaled state. A timeout value of -1
specifies an infinite timeout period.
Return Value:
WAIT_TIME_OUT - Indicates that the wait was terminated due to the
TimeOut conditions.
0 - indicates the specified object attained a Signaled
state thus completing the wait.
WAIT_ABANDONED - indicates the specified object attained a Signaled
state but was abandoned.
--*/
{
return WaitForSingleObjectEx(hHandle,dwMilliseconds,FALSE);
}
DWORD
APIENTRY
WaitForSingleObjectEx(
HANDLE hHandle,
DWORD dwMilliseconds,
BOOL bAlertable
)
/*++
Routine Description:
A wait operation on a waitable object is accomplished with the
WaitForSingleObjectEx function.
Waiting on an object checks the current state of the object. If the
current state of the object allows continued execution, any
adjustments to the object state are made (for example, decrementing
the semaphore count for a semaphore object) and the thread continues
execution. If the current state of the object does not allow
continued execution, the thread is placed into the wait state
pending the change of the object's state or time-out.
If the bAlertable parameter is FALSE, the only way the wait
terminates is because the specified timeout period expires, or
because the specified object entered the signaled state. If the
bAlertable parameter is TRUE, then the wait can return due to any
one of the above wait termination conditions, or because an I/O
completion callback terminated the wait early (return value of
WAIT_IO_COMPLETION).
Arguments:
hHandle - An open handle to a waitable object. The handle must have
SYNCHRONIZE access to the object.
dwMilliseconds - A time-out value that specifies the relative time,
in milliseconds, over which the wait is to be completed. A
timeout value of 0 specified that the wait is to timeout
immediately. This allows an application to test an object to
determine if it is in the signaled state. A timeout value of
0xffffffff specifies an infinite timeout period.
bAlertable - Supplies a flag that controls whether or not the
wait may terminate early due to an I/O completion callback.
A value of TRUE allows this API to complete early due to an I/O
completion callback. A value of FALSE will not allow I/O
completion callbacks to terminate this call early.
Return Value:
WAIT_TIME_OUT - Indicates that the wait was terminated due to the
TimeOut conditions.
0 - indicates the specified object attained a Signaled
state thus completing the wait.
0xffffffff - The wait terminated due to an error. GetLastError may be
used to get additional error information.
WAIT_ABANDONED - indicates the specified object attained a Signaled
state but was abandoned.
WAIT_IO_COMPLETION - The wait terminated due to one or more I/O
completion callbacks.
--*/
{
NTSTATUS Status;
LARGE_INTEGER TimeOut;
PLARGE_INTEGER pTimeOut;
PPEB Peb;
RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME Frame = { sizeof(Frame), RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER };
RtlActivateActivationContextUnsafeFast(&Frame, NULL); // make the process default activation context active so that APCs are delivered under it
__try {
if (dwMilliseconds == INFINITE)
{
pTimeOut = NULL;
}
else
{
Win32ToNtTimeout(dwMilliseconds, &TimeOut);
pTimeOut = &TimeOut;
}
rewait:
Status = NtWaitForSingleObject(hHandle,(BOOLEAN)bAlertable,pTimeOut);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
Status = (NTSTATUS)0xffffffff;
}
else {
if ( bAlertable && Status == STATUS_ALERTED ) {
goto rewait;
}
}
} __finally {
RtlDeactivateActivationContextUnsafeFast(&Frame);
}
return (DWORD)Status;
}
DWORD
WaitForMultipleObjects(
DWORD nCount,
CONST HANDLE *lpHandles,
BOOL bWaitAll,
DWORD dwMilliseconds
)
/*++
Routine Description:
A wait operation on multiple waitable objects (up to
MAXIMUM_WAIT_OBJECTS) is accomplished with the WaitForMultipleObjects
function.
Arguments:
nCount - A count of the number of objects that are to be waited on.
lpHandles - An array of object handles. Each handle must have
SYNCHRONIZE access to the associated object.
bWaitAll - A flag that supplies the wait type. A value of TRUE
indicates a "wait all". A value of false indicates a "wait
any".
dwMilliseconds - A time-out value that specifies the relative time,
in milliseconds, over which the wait is to be completed. A
timeout value of 0 specified that the wait is to timeout
immediately. This allows an application to test an object to
determine if it is in the signaled state. A timeout value of -1
specifies an infinite timeout period.
Return Value:
WAIT_TIME_OUT - indicates that the wait was terminated due to the
TimeOut conditions.
0 to MAXIMUM_WAIT_OBJECTS-1, indicates, in the case of wait for any
object, the object number which satisfied the wait. In the case
of wait for all objects, the value only indicates that the wait
was completed successfully.
WAIT_ABANDONED_0 to (WAIT_ABANDONED_0)+(MAXIMUM_WAIT_OBJECTS - 1),
indicates, in the case of wait for any object, the object number
which satisfied the event, and that the object which satisfied
the event was abandoned. In the case of wait for all objects,
the value indicates that the wait was completed successfully and
at least one of the objects was abandoned.
--*/
{
return WaitForMultipleObjectsEx(nCount,lpHandles,bWaitAll,dwMilliseconds,FALSE);
}
DWORD
APIENTRY
WaitForMultipleObjectsEx(
DWORD nCount,
CONST HANDLE *lpHandles,
BOOL bWaitAll,
DWORD dwMilliseconds,
BOOL bAlertable
)
/*++
Routine Description:
A wait operation on multiple waitable objects (up to
MAXIMUM_WAIT_OBJECTS) is accomplished with the
WaitForMultipleObjects function.
This API can be used to wait on any of the specified objects to
enter the signaled state, or all of the objects to enter the
signaled state.
If the bAlertable parameter is FALSE, the only way the wait
terminates is because the specified timeout period expires, or
because the specified objects entered the signaled state. If the
bAlertable parameter is TRUE, then the wait can return due to any one of
the above wait termination conditions, or because an I/O completion
callback terminated the wait early (return value of
WAIT_IO_COMPLETION).
Arguments:
nCount - A count of the number of objects that are to be waited on.
lpHandles - An array of object handles. Each handle must have
SYNCHRONIZE access to the associated object.
bWaitAll - A flag that supplies the wait type. A value of TRUE
indicates a "wait all". A value of false indicates a "wait
any".
dwMilliseconds - A time-out value that specifies the relative time,
in milliseconds, over which the wait is to be completed. A
timeout value of 0 specified that the wait is to timeout
immediately. This allows an application to test an object to
determine if it is in the signaled state. A timeout value of
0xffffffff specifies an infinite timeout period.
bAlertable - Supplies a flag that controls whether or not the
wait may terminate early due to an I/O completion callback.
A value of TRUE allows this API to complete early due to an I/O
completion callback. A value of FALSE will not allow I/O
completion callbacks to terminate this call early.
Return Value:
WAIT_TIME_OUT - indicates that the wait was terminated due to the
TimeOut conditions.
0 to MAXIMUM_WAIT_OBJECTS-1, indicates, in the case of wait for any
object, the object number which satisfied the wait. In the case
of wait for all objects, the value only indicates that the wait
was completed successfully.
0xffffffff - The wait terminated due to an error. GetLastError may be
used to get additional error information.
WAIT_ABANDONED_0 to (WAIT_ABANDONED_0)+(MAXIMUM_WAIT_OBJECTS - 1),
indicates, in the case of wait for any object, the object number
which satisfied the event, and that the object which satisfied
the event was abandoned. In the case of wait for all objects,
the value indicates that the wait was completed successfully and
at least one of the objects was abandoned.
WAIT_IO_COMPLETION - The wait terminated due to one or more I/O
completion callbacks.
--*/
{
NTSTATUS Status;
LARGE_INTEGER TimeOut;
PLARGE_INTEGER pTimeOut;
DWORD i;
LPHANDLE HandleArray;
HANDLE Handles[ 8 ];
PPEB Peb;
RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME Frame = { sizeof(Frame), RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER };
if (nCount > 8) {
BaseSetLastNTError(STATUS_NO_MEMORY);
return 0xffffffff;
}
RtlActivateActivationContextUnsafeFast(&Frame, NULL); // make the process default activation context active so that APCs are delivered under it
__try {
HandleArray = Handles;
RtlCopyMemory(HandleArray,(LPVOID)lpHandles,nCount*sizeof(HANDLE));
Peb = NtCurrentPeb();
if (dwMilliseconds == INFINITE)
{
pTimeOut = NULL;
}
else
{
Win32ToNtTimeout(dwMilliseconds, &TimeOut);
pTimeOut = &TimeOut;
}
rewait:
Status = NtWaitForMultipleObjects(
(CHAR)nCount,
HandleArray,
bWaitAll ? WaitAll : WaitAny,
(BOOLEAN)bAlertable,
pTimeOut
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
Status = (NTSTATUS)0xffffffff;
}
else {
if ( bAlertable && Status == STATUS_ALERTED ) {
goto rewait;
}
}
if (HandleArray != Handles) {
RtlFreeHeap(RtlProcessHeap(), 0, HandleArray);
}
} __finally {
RtlDeactivateActivationContextUnsafeFast(&Frame);
}
return (DWORD)Status;
}
HANDLE
APIENTRY
CreateEventA(
LPSECURITY_ATTRIBUTES lpEventAttributes,
BOOL bManualReset,
BOOL bInitialState,
LPCSTR lpName
)
/*++
Routine Description:
ANSI thunk to CreateEventW
--*/
{
PUNICODE_STRING Unicode;
ANSI_STRING AnsiString;
NTSTATUS Status;
LPCWSTR NameBuffer;
NameBuffer = NULL;
if ( ARGUMENT_PRESENT(lpName) ) {
Unicode = &NtCurrentTeb()->StaticUnicodeString;
RtlInitAnsiString(&AnsiString,lpName);
Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
if ( !NT_SUCCESS(Status) ) {
if ( Status == STATUS_BUFFER_OVERFLOW ) {
SetLastError(ERROR_FILENAME_EXCED_RANGE);
}
else {
BaseSetLastNTError(Status);
}
return NULL;
}
NameBuffer = (LPCWSTR)Unicode->Buffer;
}
return CreateEventW(
lpEventAttributes,
bManualReset,
bInitialState,
NameBuffer
);
}
HANDLE
APIENTRY
CreateEventW(
LPSECURITY_ATTRIBUTES lpEventAttributes,
BOOL bManualReset,
BOOL bInitialState,
LPCWSTR lpName
)
/*++
Routine Description:
An event object is created and a handle opened for access to the
object with the CreateEvent function.
The CreateEvent function creates an event object with the specified
initial state. If an event is in the Signaled state (TRUE), a wait
operation on the event does not block. If the event is in the Not-
Signaled state (FALSE), a wait operation on the event blocks until
the specified event attains a state of Signaled, or the timeout
value is exceeded.
In addition to the STANDARD_RIGHTS_REQUIRED access flags, the following
object type specific access flags are valid for event objects:
- EVENT_MODIFY_STATE - Modify state access (set and reset) to
the event is desired.
- SYNCHRONIZE - Synchronization access (wait) to the event is
desired.
- EVENT_ALL_ACCESS - This set of access flags specifies all of
the possible access flags for an event object.
Arguments:
lpEventAttributes - An optional parameter that may be used to
specify the attributes of the new event. If the parameter is
not specified, then the event is created without a security
descriptor, and the resulting handle is not inherited on process
creation.
bManualReset - Supplies a flag which if TRUE specifies that the
event must be manually reset. If the value is FALSE, then after
releasing a single waiter, the system automaticaly resets the
event.
bInitialState - The initial state of the event object, one of TRUE
or FALSE. If the InitialState is specified as TRUE, the event's
current state value is set to one, otherwise it is set to zero.
lpName - Optional unicode name of event
Return Value:
NON-NULL - Returns a handle to the new event. The handle has full
access to the new event and may be used in any API that requires
a handle to an event object.
FALSE/NULL - The operation failed. Extended error status is available
using GetLastError.
--*/
{
NTSTATUS Status;
OBJECT_ATTRIBUTES Obja;
POBJECT_ATTRIBUTES pObja;
HANDLE Handle;
UNICODE_STRING ObjectName;
PWCHAR pstrNewObjName = NULL;
if (lpName != NULL || lpEventAttributes != NULL)
{
return FALSE;
}
pObja = NULL;
Status = NtCreateEvent(
&Handle,
EVENT_ALL_ACCESS,
pObja,
bManualReset ? NotificationEvent : SynchronizationEvent,
(BOOLEAN)bInitialState
);
if (pstrNewObjName) {
RtlFreeHeap(RtlProcessHeap(), 0, pstrNewObjName);
}
if ( NT_SUCCESS(Status) ) {
if ( Status == STATUS_OBJECT_NAME_EXISTS ) {
SetLastError(ERROR_ALREADY_EXISTS);
}
else {
SetLastError(0);
}
return Handle;
}
else {
BaseSetLastNTError(Status);
return NULL;
}
}
BOOL
SetEvent(
HANDLE hEvent
)
/*++
Routine Description:
An event can be set to the signaled state (TRUE) with the SetEvent
function.
Setting the event causes the event to attain a state of Signaled,
which releases all currently waiting threads (for manual reset
events), or a single waiting thread (for automatic reset events).
Arguments:
hEvent - Supplies an open handle to an event object. The
handle must have EVENT_MODIFY_STATE access to the event.
Return Value:
TRUE - The operation was successful
FALSE/NULL - The operation failed. Extended error status is available
using GetLastError.
--*/
{
NTSTATUS Status;
Status = NtSetEvent(hEvent,NULL);
if ( NT_SUCCESS(Status) ) {
return TRUE;
}
else {
BaseSetLastNTError(Status);
return FALSE;
}
}
BOOL
ResetEvent(
HANDLE hEvent
)
/*++
Routine Description:
The state of an event is set to the Not-Signaled state (FALSE) using
the ClearEvent function.
Once the event attains a state of Not-Signaled, any threads which
wait on the event block, awaiting the event to become Signaled. The
reset event service sets the event count to zero for the state of
the event.
Arguments:
hEvent - Supplies an open handle to an event object. The
handle must have EVENT_MODIFY_STATE access to the event.
Return Value:
TRUE - The operation was successful
FALSE/NULL - The operation failed. Extended error status is available
using GetLastError.
--*/
{
NTSTATUS Status;
Status = NtClearEvent(hEvent);
if ( NT_SUCCESS(Status) ) {
return TRUE;
}
else {
BaseSetLastNTError(Status);
return FALSE;
}
}
BOOL
WINAPI
GetOverlappedResult(
HANDLE hFile,
LPOVERLAPPED lpOverlapped,
LPDWORD lpNumberOfBytesTransferred,
BOOL bWait
)
/*++
Routine Description:
The GetOverlappedResult function returns the result of the last
operation that used lpOverlapped and returned ERROR_IO_PENDING.
Arguments:
hFile - Supplies the open handle to the file that the overlapped
structure lpOverlapped was supplied to ReadFile, WriteFile,
ConnectNamedPipe, WaitNamedPipe or TransactNamedPipe.
lpOverlapped - Points to an OVERLAPPED structure previously supplied to
ReadFile, WriteFile, ConnectNamedPipe, WaitNamedPipe or
TransactNamedPipe.
lpNumberOfBytesTransferred - Returns the number of bytes transferred
by the operation.
bWait - A boolean value that affects the behavior when the operation
is still in progress. If TRUE and the operation is still in progress,
GetOverlappedResult will wait for the operation to complete before
returning. If FALSE and the operation is incomplete,
GetOverlappedResult will return FALSE. In this case the extended
error information available from the GetLastError function will be
set to ERROR_IO_INCOMPLETE.
Return Value:
TRUE -- The operation was successful, the pipe is in the
connected state.
FALSE -- The operation failed. Extended error status is available using
GetLastError.
--*/
{
DWORD WaitReturn;
//
// Did caller specify an event to the original operation or was the
// default (file handle) used?
//
if (lpOverlapped->Internal == (DWORD)STATUS_PENDING ) {
if ( bWait ) {
WaitReturn = WaitForSingleObject(
( lpOverlapped->hEvent != NULL ) ?
lpOverlapped->hEvent : hFile,
INFINITE
);
}
else {
WaitReturn = WAIT_TIMEOUT;
}
if ( WaitReturn == WAIT_TIMEOUT ) {
// !bWait and event in not signalled state
SetLastError( ERROR_IO_INCOMPLETE );
return FALSE;
}
if ( WaitReturn != 0 ) {
return FALSE; // WaitForSingleObject calls BaseSetLastError
}
}
*lpNumberOfBytesTransferred = (DWORD)lpOverlapped->InternalHigh;
if ( NT_SUCCESS((NTSTATUS)lpOverlapped->Internal) ){
return TRUE;
}
else {
BaseSetLastNTError( (NTSTATUS)lpOverlapped->Internal );
return FALSE;
}
}
BOOL
WINAPI
CancelIo(
HANDLE hFile
)
/*++
Routine Description:
This routine cancels all of the outstanding I/O for the specified handle
for the specified file.
Arguments:
hFile - Supplies the handle to the file whose pending I/O is to be
canceled.
Return Value:
TRUE -- The operation was successful.
FALSE -- The operation failed. Extended error status is available using
GetLastError.
--*/
{
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
//
// Simply cancel the I/O for the specified file.
//
Status = NtCancelIoFile(hFile, &IoStatusBlock);
if ( NT_SUCCESS(Status) ) {
return TRUE;
}
else {
BaseSetLastNTError(Status);
return FALSE;
}
}
BOOL
ClearCommError(
HANDLE hFile,
LPDWORD lpErrors,
LPCOMSTAT lpStat
)
/*++
Routine Description:
In case of a communications error, such as a buffer overrun or
framing error, the communications software will abort all
read and write operations on the communication port. No further
read or write operations will be accepted until this function
is called.
Arguments:
hFile - Specifies the communication device to be adjusted.
lpErrors - Points to the DWORD that is to receive the mask of the
error that occured.
lpStat - Points to the COMMSTAT structure that is to receive
the device status. The structure contains information
about the communications device.
Return Value:
The return value is TRUE if the function is successful or FALSE
if an error occurs.
--*/
{
NTSTATUS Status;
HANDLE SyncEvent;
IO_STATUS_BLOCK Iosb;
SERIAL_STATUS LocalStat;
RtlZeroMemory(&LocalStat, sizeof(SERIAL_STATUS));
if (!(SyncEvent = CreateEvent(
NULL,
TRUE,
FALSE,
NULL
))) {
return FALSE;
}
Status = NtDeviceIoControlFile(
hFile,
SyncEvent,
NULL,
NULL,
&Iosb,
IOCTL_SERIAL_GET_COMMSTATUS,
NULL,
0,
&LocalStat,
sizeof(LocalStat)
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
CloseHandle(SyncEvent);
BaseSetLastNTError(Status);
return FALSE;
}
if (lpStat) {
//
// All is well up to this point. Translate the NT values
// into win32 values.
//
if (LocalStat.HoldReasons & SERIAL_TX_WAITING_FOR_CTS) {
lpStat->fCtsHold = TRUE;
} else {
lpStat->fCtsHold = FALSE;
}
if (LocalStat.HoldReasons & SERIAL_TX_WAITING_FOR_DSR) {
lpStat->fDsrHold = TRUE;
} else {
lpStat->fDsrHold = FALSE;
}
if (LocalStat.HoldReasons & SERIAL_TX_WAITING_FOR_DCD) {
lpStat->fRlsdHold = TRUE;
} else {
lpStat->fRlsdHold = FALSE;
}
if (LocalStat.HoldReasons & SERIAL_TX_WAITING_FOR_XON) {
lpStat->fXoffHold = TRUE;
} else {
lpStat->fXoffHold = FALSE;
}
if (LocalStat.HoldReasons & SERIAL_TX_WAITING_XOFF_SENT) {
lpStat->fXoffSent = TRUE;
} else {
lpStat->fXoffSent = FALSE;
}
lpStat->fEof = LocalStat.EofReceived;
lpStat->fTxim = LocalStat.WaitForImmediate;
lpStat->cbInQue = LocalStat.AmountInInQueue;
lpStat->cbOutQue = LocalStat.AmountInOutQueue;
}
if (lpErrors) {
*lpErrors = 0;
if (LocalStat.Errors & SERIAL_ERROR_BREAK) {
*lpErrors = *lpErrors | CE_BREAK;
}
if (LocalStat.Errors & SERIAL_ERROR_FRAMING) {
*lpErrors = *lpErrors | CE_FRAME;
}
if (LocalStat.Errors & SERIAL_ERROR_OVERRUN) {
*lpErrors = *lpErrors | CE_OVERRUN;
}
if (LocalStat.Errors & SERIAL_ERROR_QUEUEOVERRUN) {
*lpErrors = *lpErrors | CE_RXOVER;
}
if (LocalStat.Errors & SERIAL_ERROR_PARITY) {
*lpErrors = *lpErrors | CE_RXPARITY;
}
}
CloseHandle(SyncEvent);
return TRUE;
}
BOOL
SetupComm(
HANDLE hFile,
DWORD dwInQueue,
DWORD dwOutQueue
)
/*++
Routine Description:
The communication device is not initialized until SetupComm is
called. This function allocates space for receive and transmit
queues. These queues are used by the interrupt-driven transmit/
receive software and are internal to the provider.
Arguments:
hFile - Specifies the communication device to receive the settings.
The CreateFile function returns this value.
dwInQueue - Specifies the recommended size of the provider's
internal receive queue in bytes. This value must be
even. A value of -1 indicates that the default should
be used.
dwOutQueue - Specifies the recommended size of the provider's
internal transmit queue in bytes. This value must be
even. A value of -1 indicates that the default should
be used.
Return Value:
The return value is TRUE if the function is successful or FALSE
if an error occurs.
--*/
{
NTSTATUS Status;
HANDLE SyncEvent;
IO_STATUS_BLOCK Iosb;
SERIAL_QUEUE_SIZE NewSizes = {0};
//
// Make sure that the sizes are even.
//
if (dwOutQueue != ((DWORD)-1)) {
if (((dwOutQueue/2)*2) != dwOutQueue) {
SetLastError(ERROR_INVALID_DATA);
return FALSE;
}
}
if (dwInQueue != ((DWORD)-1)) {
if (((dwInQueue/2)*2) != dwInQueue) {
SetLastError(ERROR_INVALID_DATA);
return FALSE;
}
}
NewSizes.InSize = dwInQueue;
NewSizes.OutSize = dwOutQueue;
if (!(SyncEvent = CreateEvent(
NULL,
TRUE,
FALSE,
NULL
))) {
return FALSE;
}
Status = NtDeviceIoControlFile(
hFile,
SyncEvent,
NULL,
NULL,
&Iosb,
IOCTL_SERIAL_SET_QUEUE_SIZE,
&NewSizes,
sizeof(SERIAL_QUEUE_SIZE),
NULL,
0
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
CloseHandle(SyncEvent);
BaseSetLastNTError(Status);
return FALSE;
}
CloseHandle(SyncEvent);
return TRUE;
}
BOOL
GetCommState(
HANDLE hFile,
LPDCB lpDCB
)
/*++
Routine Description:
This function fills the buffer pointed to by the lpDCB parameter with
the device control block of the communication device specified by hFile
parameter.
Arguments:
hFile - Specifies the communication device to be examined.
The CreateFile function returns this value.
lpDCB - Points to the DCB data structure that is to receive the current
device control block. The structure defines the control settings
for the device.
Return Value:
The return value is TRUE if the function is successful or FALSE
if an error occurs.
--*/
{
SERIAL_BAUD_RATE LocalBaud;
SERIAL_LINE_CONTROL LineControl;
SERIAL_CHARS Chars;
SERIAL_HANDFLOW HandFlow;
IO_STATUS_BLOCK Iosb;
NTSTATUS Status;
//
// Given the possiblity that the app may be doing asynchronous
// io we need an event to wait on.
//
// We need to make sure that any exit to this routine closes this
// event handle.
//
HANDLE SyncEvent;
//
// Make sure the windows mapping is the same as the NT mapping.
//
ASSERT((ONESTOPBIT == STOP_BIT_1) &&
(ONE5STOPBITS == STOP_BITS_1_5) &&
(TWOSTOPBITS == STOP_BITS_2));
ASSERT((NOPARITY == NO_PARITY) &&
(ODDPARITY == ODD_PARITY) &&
(EVENPARITY == EVEN_PARITY) &&
(MARKPARITY == MARK_PARITY) &&
(SPACEPARITY == SPACE_PARITY));
//
// Zero out the dcb. This might create an access violation
// if it isn't big enough. Which is ok, since we would rather
// get it before we create the sync event.
//
RtlZeroMemory(lpDCB, sizeof(DCB));
lpDCB->DCBlength = sizeof(DCB);
lpDCB->fBinary = TRUE;
if (!(SyncEvent = CreateEvent(
NULL,
TRUE,
FALSE,
NULL
))) {
return FALSE;
}
Status = NtDeviceIoControlFile(
hFile,
SyncEvent,
NULL,
NULL,
&Iosb,
IOCTL_SERIAL_GET_BAUD_RATE,
NULL,
0,
&LocalBaud,
sizeof(LocalBaud)
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
CloseHandle(SyncEvent);
BaseSetLastNTError(Status);
return FALSE;
}
lpDCB->BaudRate = LocalBaud.BaudRate;
Status = NtDeviceIoControlFile(
hFile,
SyncEvent,
NULL,
NULL,
&Iosb,
IOCTL_SERIAL_GET_LINE_CONTROL,
NULL,
0,
&LineControl,
sizeof(LineControl)
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
CloseHandle(SyncEvent);
BaseSetLastNTError(Status);
return FALSE;
}
lpDCB->Parity = LineControl.Parity;
lpDCB->ByteSize = LineControl.WordLength;
lpDCB->StopBits = LineControl.StopBits;
Status = NtDeviceIoControlFile(
hFile,
SyncEvent,
NULL,
NULL,
&Iosb,
IOCTL_SERIAL_GET_CHARS,
NULL,
0,
&Chars,
sizeof(Chars)
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
CloseHandle(SyncEvent);
BaseSetLastNTError(Status);
return FALSE;
}
lpDCB->XonChar = Chars.XonChar;
lpDCB->XoffChar = Chars.XoffChar;
lpDCB->ErrorChar = Chars.ErrorChar;
lpDCB->EofChar = Chars.EofChar;
lpDCB->EvtChar = Chars.EventChar;
Status = NtDeviceIoControlFile(
hFile,
SyncEvent,
NULL,
NULL,
&Iosb,
IOCTL_SERIAL_GET_HANDFLOW,
NULL,
0,
&HandFlow,
sizeof(HandFlow)
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
CloseHandle(SyncEvent);
BaseSetLastNTError(Status);
return FALSE;
}
if (HandFlow.ControlHandShake & SERIAL_CTS_HANDSHAKE) {
lpDCB->fOutxCtsFlow = TRUE;
}
if (HandFlow.ControlHandShake & SERIAL_DSR_HANDSHAKE) {
lpDCB->fOutxDsrFlow = TRUE;
}
if (HandFlow.FlowReplace & SERIAL_AUTO_TRANSMIT) {
lpDCB->fOutX = TRUE;
}
if (HandFlow.FlowReplace & SERIAL_AUTO_RECEIVE) {
lpDCB->fInX = TRUE;
}
if (HandFlow.FlowReplace & SERIAL_NULL_STRIPPING) {
lpDCB->fNull = TRUE;
}
if (HandFlow.FlowReplace & SERIAL_ERROR_CHAR) {
lpDCB->fErrorChar = TRUE;
}
if (HandFlow.FlowReplace & SERIAL_XOFF_CONTINUE) {
lpDCB->fTXContinueOnXoff = TRUE;
}
if (HandFlow.ControlHandShake & SERIAL_ERROR_ABORT) {
lpDCB->fAbortOnError = TRUE;
}
switch (HandFlow.FlowReplace & SERIAL_RTS_MASK) {
case 0:
lpDCB->fRtsControl = RTS_CONTROL_DISABLE;
break;
case SERIAL_RTS_CONTROL:
lpDCB->fRtsControl = RTS_CONTROL_ENABLE;
break;
case SERIAL_RTS_HANDSHAKE:
lpDCB->fRtsControl = RTS_CONTROL_HANDSHAKE;
break;
case SERIAL_TRANSMIT_TOGGLE:
lpDCB->fRtsControl = RTS_CONTROL_TOGGLE;
break;
}
switch (HandFlow.ControlHandShake & SERIAL_DTR_MASK) {
case 0:
lpDCB->fDtrControl = DTR_CONTROL_DISABLE;
break;
case SERIAL_DTR_CONTROL:
lpDCB->fDtrControl = DTR_CONTROL_ENABLE;
break;
case SERIAL_DTR_HANDSHAKE:
lpDCB->fDtrControl = DTR_CONTROL_HANDSHAKE;
break;
}
lpDCB->fDsrSensitivity =
(HandFlow.ControlHandShake & SERIAL_DSR_SENSITIVITY)?(TRUE):(FALSE);
lpDCB->XonLim = (WORD)HandFlow.XonLimit;
lpDCB->XoffLim = (WORD)HandFlow.XoffLimit;
CloseHandle(SyncEvent);
return TRUE;
}
BOOL
EscapeCommFunction(
HANDLE hFile,
DWORD dwFunc
)
/*++
Routine Description:
This function directs the communication-device specified by the
hFile parameter to carry out the extended function specified by
the dwFunc parameter.
Arguments:
hFile - Specifies the communication device to receive the settings.
The CreateFile function returns this value.
dwFunc - Specifies the function code of the extended function.
Return Value:
The return value is TRUE if the function is successful or FALSE
if an error occurs.
--*/
{
NTSTATUS Status;
IO_STATUS_BLOCK Iosb;
ULONG ControlCode;
HANDLE Event;
switch (dwFunc) {
case SETXOFF: {
ControlCode = IOCTL_SERIAL_SET_XOFF;
break;
}
case SETXON: {
ControlCode = IOCTL_SERIAL_SET_XON;
break;
}
case SETRTS: {
ControlCode = IOCTL_SERIAL_SET_RTS;
break;
}
case CLRRTS: {
ControlCode = IOCTL_SERIAL_CLR_RTS;
break;
}
case SETDTR: {
ControlCode = IOCTL_SERIAL_SET_DTR;
break;
}
case CLRDTR: {
ControlCode = IOCTL_SERIAL_CLR_DTR;
break;
}
case RESETDEV: {
ControlCode = IOCTL_SERIAL_RESET_DEVICE;
break;
}
case SETBREAK: {
ControlCode = IOCTL_SERIAL_SET_BREAK_ON;
break;
}
case CLRBREAK: {
ControlCode = IOCTL_SERIAL_SET_BREAK_OFF;
break;
}
default: {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
}
if (!(Event = CreateEvent(
NULL,
TRUE,
FALSE,
NULL
))) {
return FALSE;
}
Status = NtDeviceIoControlFile(
hFile,
Event,
NULL,
NULL,
&Iosb,
ControlCode,
NULL,
0,
NULL,
0
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( Event, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
CloseHandle(Event);
BaseSetLastNTError(Status);
return FALSE;
}
CloseHandle(Event);
return TRUE;
}
BOOL
SetCommState(
HANDLE hFile,
LPDCB lpDCB
)
/*++
Routine Description:
The SetCommState function sets a communication device to the state
specified in the lpDCB parameter. The device is identified by the
hFile parameter. This function reinitializes all hardwae and controls
as specified byt the lpDCB, but does not empty the transmit or
receive queues.
Arguments:
hFile - Specifies the communication device to receive the settings.
The CreateFile function returns this value.
lpDCB - Points to a DCB structure that contains the desired
communications setting for the device.
Return Value:
The return value is TRUE if the function is successful or FALSE
if an error occurs.
--*/
{
SERIAL_BAUD_RATE LocalBaud;
SERIAL_LINE_CONTROL LineControl;
SERIAL_CHARS Chars;
SERIAL_HANDFLOW HandFlow = {0};
IO_STATUS_BLOCK Iosb;
NTSTATUS Status;
//
// Keep a copy of what the DCB was like before we started
// changing things. If some error occurs we can use
// it to restore the old setup.
//
DCB OldDcb;
//
// Given the possiblity that the app may be doing asynchronous
// io we need an event to wait on. While it would be very
// strange to be setting the comm state while IO is active
// we need to make sure we don't compound the problem by
// returning before this API's IO is actually finished. This
// can happen because the file handle is set on the completion
// of any IO.
//
// We need to make sure that any exit to this routine closes this
// event handle.
//
HANDLE SyncEvent;
if (GetCommState(
hFile,
&OldDcb
)) {
//
// Try to set the baud rate. If we fail here, we just return
// because we never actually got to set anything.
//
if (!(SyncEvent = CreateEvent(
NULL,
TRUE,
FALSE,
NULL
))) {
return FALSE;
}
LocalBaud.BaudRate = lpDCB->BaudRate;
Status = NtDeviceIoControlFile(
hFile,
SyncEvent,
NULL,
NULL,
&Iosb,
IOCTL_SERIAL_SET_BAUD_RATE,
&LocalBaud,
sizeof(LocalBaud),
NULL,
0
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
CloseHandle(SyncEvent);
BaseSetLastNTError(Status);
return FALSE;
}
LineControl.StopBits = lpDCB->StopBits;
LineControl.Parity = lpDCB->Parity;
LineControl.WordLength = lpDCB->ByteSize;
LocalBaud.BaudRate = lpDCB->BaudRate;
Chars.XonChar = lpDCB->XonChar;
Chars.XoffChar = lpDCB->XoffChar;
Chars.ErrorChar = lpDCB->ErrorChar;
Chars.BreakChar = lpDCB->ErrorChar;
Chars.EofChar = lpDCB->EofChar;
Chars.EventChar = lpDCB->EvtChar;
HandFlow.FlowReplace &= ~SERIAL_RTS_MASK;
switch (lpDCB->fRtsControl) {
case RTS_CONTROL_DISABLE:
break;
case RTS_CONTROL_ENABLE:
HandFlow.FlowReplace |= SERIAL_RTS_CONTROL;
break;
case RTS_CONTROL_HANDSHAKE:
HandFlow.FlowReplace |= SERIAL_RTS_HANDSHAKE;
break;
case RTS_CONTROL_TOGGLE:
HandFlow.FlowReplace |= SERIAL_TRANSMIT_TOGGLE;
break;
default:
SetCommState(
hFile,
&OldDcb
);
CloseHandle(SyncEvent);
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
return FALSE;
}
HandFlow.ControlHandShake &= ~SERIAL_DTR_MASK;
switch (lpDCB->fDtrControl) {
case DTR_CONTROL_DISABLE:
break;
case DTR_CONTROL_ENABLE:
HandFlow.ControlHandShake |= SERIAL_DTR_CONTROL;
break;
case DTR_CONTROL_HANDSHAKE:
HandFlow.ControlHandShake |= SERIAL_DTR_HANDSHAKE;
break;
default:
SetCommState(
hFile,
&OldDcb
);
CloseHandle(SyncEvent);
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
return FALSE;
}
if (lpDCB->fDsrSensitivity) {
HandFlow.ControlHandShake |= SERIAL_DSR_SENSITIVITY;
}
if (lpDCB->fOutxCtsFlow) {
HandFlow.ControlHandShake |= SERIAL_CTS_HANDSHAKE;
}
if (lpDCB->fOutxDsrFlow) {
HandFlow.ControlHandShake |= SERIAL_DSR_HANDSHAKE;
}
if (lpDCB->fOutX) {
HandFlow.FlowReplace |= SERIAL_AUTO_TRANSMIT;
}
if (lpDCB->fInX) {
HandFlow.FlowReplace |= SERIAL_AUTO_RECEIVE;
}
if (lpDCB->fNull) {
HandFlow.FlowReplace |= SERIAL_NULL_STRIPPING;
}
if (lpDCB->fErrorChar) {
HandFlow.FlowReplace |= SERIAL_ERROR_CHAR;
}
if (lpDCB->fTXContinueOnXoff) {
HandFlow.FlowReplace |= SERIAL_XOFF_CONTINUE;
}
if (lpDCB->fAbortOnError) {
HandFlow.ControlHandShake |= SERIAL_ERROR_ABORT;
}
//
// For win95 compatiblity, if we are setting with
// xxx_control_XXXXXXX then set the modem status line
// to that state.
//
if (lpDCB->fRtsControl == RTS_CONTROL_ENABLE) {
EscapeCommFunction(
hFile,
SETRTS
);
} else if (lpDCB->fRtsControl == RTS_CONTROL_DISABLE) {
EscapeCommFunction(
hFile,
CLRRTS
);
}
if (lpDCB->fDtrControl == DTR_CONTROL_ENABLE) {
EscapeCommFunction(
hFile,
SETDTR
);
} else if (lpDCB->fDtrControl == DTR_CONTROL_DISABLE) {
EscapeCommFunction(
hFile,
CLRDTR
);
}
HandFlow.XonLimit = lpDCB->XonLim;
HandFlow.XoffLimit = lpDCB->XoffLim;
Status = NtDeviceIoControlFile(
hFile,
SyncEvent,
NULL,
NULL,
&Iosb,
IOCTL_SERIAL_SET_LINE_CONTROL,
&LineControl,
sizeof(LineControl),
NULL,
0
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
CloseHandle(SyncEvent);
SetCommState(
hFile,
&OldDcb
);
BaseSetLastNTError(Status);
return FALSE;
}
Status = NtDeviceIoControlFile(
hFile,
SyncEvent,
NULL,
NULL,
&Iosb,
IOCTL_SERIAL_SET_CHARS,
&Chars,
sizeof(Chars),
NULL,
0
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
CloseHandle(SyncEvent);
SetCommState(
hFile,
&OldDcb
);
BaseSetLastNTError(Status);
return FALSE;
}
Status = NtDeviceIoControlFile(
hFile,
SyncEvent,
NULL,
NULL,
&Iosb,
IOCTL_SERIAL_SET_HANDFLOW,
&HandFlow,
sizeof(HandFlow),
NULL,
0
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
CloseHandle(SyncEvent);
SetCommState(
hFile,
&OldDcb
);
BaseSetLastNTError(Status);
return FALSE;
}
CloseHandle(SyncEvent);
return TRUE;
}
return FALSE;
}
BOOL
SetCommTimeouts(
HANDLE hFile,
LPCOMMTIMEOUTS lpCommTimeouts
)
/*++
Routine Description:
This function establishes the timeout characteristics for all
read and write operations on the handle specified by hFile.
Arguments:
hFile - Specifies the communication device to receive the settings.
The CreateFile function returns this value.
lpCommTimeouts - Points to a structure containing timeout parameters.
Return Value:
The return value is TRUE if the function is successful or FALSE
if an error occurs.
--*/
{
SERIAL_TIMEOUTS To;
NTSTATUS Status;
IO_STATUS_BLOCK Iosb;
HANDLE Event;
To.ReadIntervalTimeout = lpCommTimeouts->ReadIntervalTimeout;
To.ReadTotalTimeoutMultiplier = lpCommTimeouts->ReadTotalTimeoutMultiplier;
To.ReadTotalTimeoutConstant = lpCommTimeouts->ReadTotalTimeoutConstant;
To.WriteTotalTimeoutMultiplier = lpCommTimeouts->WriteTotalTimeoutMultiplier;
To.WriteTotalTimeoutConstant = lpCommTimeouts->WriteTotalTimeoutConstant;
if (!(Event = CreateEvent(
NULL,
TRUE,
FALSE,
NULL
))) {
return FALSE;
} else {
Status = NtDeviceIoControlFile(
hFile,
Event,
NULL,
NULL,
&Iosb,
IOCTL_SERIAL_SET_TIMEOUTS,
&To,
sizeof(To),
NULL,
0
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( Event, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
CloseHandle(Event);
BaseSetLastNTError(Status);
return FALSE;
}
CloseHandle(Event);
return TRUE;
}
}
BOOL
APIENTRY
InitializeSecurityDescriptor (
PSECURITY_DESCRIPTOR pSecurityDescriptor,
DWORD dwRevision
)
{
NTSTATUS Status;
Status = RtlCreateSecurityDescriptor (
pSecurityDescriptor,
dwRevision
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
SetSecurityDescriptorDacl (
PSECURITY_DESCRIPTOR pSecurityDescriptor,
BOOL bDaclPresent,
PACL pDacl OPTIONAL,
BOOL bDaclDefaulted OPTIONAL
)
{
NTSTATUS Status;
Status = RtlSetDaclSecurityDescriptor (
pSecurityDescriptor,
(BOOLEAN)bDaclPresent,
pDacl,
(BOOLEAN)bDaclDefaulted
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
InitializeAcl (
PACL pAcl,
DWORD nAclLength,
DWORD dwAclRevision
)
/*++
Routine Description:
InitializeAcl creates a new ACL in the caller supplied memory
buffer. The ACL contains zero ACEs; therefore, it is an empty ACL
as opposed to a nonexistent ACL. That is, if the ACL is now set
to an object it will implicitly deny access to everyone.
Arguments:
pAcl - Supplies the buffer containing the ACL being initialized
nAclLength - Supplies the length of the ace buffer in bytes
dwAclRevision - Supplies the revision for this Acl
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlCreateAcl (
pAcl,
nAclLength,
dwAclRevision
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
AddAccessAllowedAce (
PACL pAcl,
DWORD dwAceRevision,
DWORD AccessMask,
PSID pSid
)
/*++
Routine Description:
This routine adds an ACCESS_ALLOWED ACE to an ACL. This is
expected to be a common form of ACL modification.
A very bland ACE header is placed in the ACE. It provides no
inheritance and no ACE flags.
Arguments:
PAcl - Supplies the Acl being modified
dwAceRevision - Supplies the Acl/Ace revision of the ACE being added
AccessMask - The mask of accesses to be granted to the specified SID.
pSid - Pointer to the SID being granted access.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlAddAccessAllowedAce (
pAcl,
dwAceRevision,
AccessMask,
pSid
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
AddAccessDeniedAce (
PACL pAcl,
DWORD dwAceRevision,
DWORD AccessMask,
PSID pSid
)
/*++
Routine Description:
This routine adds an ACCESS_DENIED ACE to an ACL. This is
expected to be a common form of ACL modification.
A very bland ACE header is placed in the ACE. It provides no
inheritance and no ACE flags.
Arguments:
pAcl - Supplies the Acl being modified
dwAceRevision - Supplies the Acl/Ace revision of the ACE being added
AccessMask - The mask of accesses to be denied to the specified SID.
pSid - Pointer to the SID being denied access.
Return Value:
Returns TRUE for success, FALSE for failure. Extended error status
is available using GetLastError.
--*/
{
NTSTATUS Status;
Status = RtlAddAccessDeniedAce (
pAcl,
dwAceRevision,
AccessMask,
pSid
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
PVOID
APIENTRY
FreeSid(
PSID pSid
)
/*++
Routine Description:
This function is used to free a SID previously allocated using
AllocateAndInitializeSid().
Arguments:
Sid - Pointer to the SID to free.
Return Value:
None.
--*/
{
return(RtlFreeSid( pSid ));
}
DWORD
APIENTRY
GetLengthSid (
PSID pSid
)
/*++
Routine Description:
This routine returns the length, in bytes, of a structurally valid SID.
Arguments:
pSid - Points to the SID whose length is to be returned. The
SID's structure is assumed to be valid.
Return Value:
DWORD - The length, in bytes, of the SID.
--*/
{
SetLastError(0);
return RtlLengthSid (
pSid
);
}
BOOL
APIENTRY
AllocateAndInitializeSid (
PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,
BYTE nSubAuthorityCount,
DWORD nSubAuthority0,
DWORD nSubAuthority1,
DWORD nSubAuthority2,
DWORD nSubAuthority3,
DWORD nSubAuthority4,
DWORD nSubAuthority5,
DWORD nSubAuthority6,
DWORD nSubAuthority7,
PSID *pSid
)
/*++
Routine Description:
This function allocates and initializes a sid with the specified
number of sub-authorities (up to 8). A sid allocated with this
routine must be freed using FreeSid().
Arguments:
pIdentifierAuthority - Pointer to the Identifier Authority value to
set in the SID.
nSubAuthorityCount - The number of sub-authorities to place in the SID.
This also identifies how many of the SubAuthorityN parameters
have meaningful values. This must contain a value from 0 through
8.
nSubAuthority0-7 - Provides the corresponding sub-authority value to
place in the SID. For example, a SubAuthorityCount value of 3
indicates that SubAuthority0, SubAuthority1, and SubAuthority0
have meaningful values and the rest are to be ignored.
Sid - Receives a pointer to the allocated and initialized SID data
structure.
Return Value:
ERROR_NO_MEMORY - The attempt to allocate memory for the SID
failed.
ERROR_INVALID_SID - The number of sub-authorities specified did
not fall in the valid range for this api (0 through 8).
--*/
{
NTSTATUS Status;
Status = RtlAllocateAndInitializeSid (
pIdentifierAuthority,
(UCHAR)nSubAuthorityCount,
(ULONG)nSubAuthority0,
(ULONG)nSubAuthority1,
(ULONG)nSubAuthority2,
(ULONG)nSubAuthority3,
(ULONG)nSubAuthority4,
(ULONG)nSubAuthority5,
(ULONG)nSubAuthority6,
(ULONG)nSubAuthority7,
pSid
);
if ( !NT_SUCCESS( Status )) {
BaseSetLastNTError( Status );
return( FALSE );
}
return( TRUE );
}
ULONG
APIENTRY
GetTickCount(void)
{
return NtGetTickCount();
}
LPSTR
WINAPI
GetCommandLineA(
VOID
)
{
// Purely to allow linkage, not expected to be used.
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return NULL;
}
LPWSTR
WINAPI
GetCommandLineW(
VOID
)
{
return NtCurrentPeb()->ProcessParameters->CommandLine.Buffer;
}
#endif // #ifdef NT_NATIVE