You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4816 lines
127 KiB
4816 lines
127 KiB
//----------------------------------------------------------------------------
|
|
//
|
|
// 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
|