3457 lines
79 KiB
C
3457 lines
79 KiB
C
/*++
|
||
|
||
Copyright (c) 1990 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
comm.c
|
||
|
||
Abstract:
|
||
|
||
This module implements Win32 comm APIs
|
||
|
||
Author:
|
||
|
||
Anthony V. Ercolano (tonye) 25-April-1991
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "basedll.h"
|
||
#pragma hdrstop
|
||
|
||
#include "ntddser.h"
|
||
#include "cfgmgr32.h"
|
||
|
||
WCHAR CfgmgrDllString[] = L"cfgmgr32.dll";
|
||
|
||
typedef struct _LOCALMATCHSTR {
|
||
DWORD FoundIt;
|
||
LPCWSTR FriendlyName;
|
||
} LOCALMATCHSTR,*PLOCALMATCHSTR;
|
||
|
||
|
||
static
|
||
NTSTATUS
|
||
GetConfigDialogName(
|
||
IN PWSTR ValueName,
|
||
IN ULONG ValueType,
|
||
IN PVOID ValueData,
|
||
IN ULONG ValueLength,
|
||
IN PVOID Context,
|
||
IN PVOID EntryContext
|
||
)
|
||
|
||
{
|
||
|
||
PUNICODE_STRING dllToLoad = Context;
|
||
if (ValueType != REG_SZ) {
|
||
|
||
return STATUS_INVALID_PARAMETER;
|
||
|
||
}
|
||
|
||
//
|
||
// Allocate heap to hold the unicode string. We know
|
||
// that the string is zero terminated. Allocate that
|
||
// much. Set the maximum size and size to
|
||
// sizeof(WCHAR) - ValueLength.
|
||
//
|
||
|
||
RtlInitUnicodeString(
|
||
dllToLoad,
|
||
NULL
|
||
);
|
||
|
||
dllToLoad->Buffer = RtlAllocateHeap(
|
||
RtlProcessHeap(),
|
||
MAKE_TAG( TMP_TAG ),
|
||
ValueLength
|
||
);
|
||
|
||
if (!dllToLoad->Buffer) {
|
||
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
}
|
||
|
||
RtlMoveMemory(
|
||
dllToLoad->Buffer,
|
||
ValueData,
|
||
ValueLength
|
||
);
|
||
|
||
dllToLoad->Length = (USHORT)(ValueLength - (sizeof(WCHAR)));
|
||
dllToLoad->MaximumLength = (USHORT)ValueLength;
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
static
|
||
NTSTATUS
|
||
GetFriendlyMatchComm(
|
||
IN PWSTR ValueName,
|
||
IN ULONG ValueType,
|
||
IN PVOID ValueData,
|
||
IN ULONG ValueLength,
|
||
IN PVOID Context,
|
||
IN PVOID EntryContext
|
||
)
|
||
|
||
{
|
||
|
||
UNICODE_STRING s1;
|
||
UNICODE_STRING s2;
|
||
PLOCALMATCHSTR localMatch = Context;
|
||
|
||
RtlInitUnicodeString(
|
||
&s1,
|
||
localMatch->FriendlyName
|
||
);
|
||
RtlInitUnicodeString(
|
||
&s2,
|
||
ValueData
|
||
);
|
||
|
||
if (RtlEqualUnicodeString(
|
||
&s1,
|
||
&s2,
|
||
TRUE
|
||
)) {
|
||
|
||
localMatch->FoundIt = TRUE;
|
||
|
||
}
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
VOID
|
||
GetFriendlyUi(
|
||
LPCWSTR FriendlyName,
|
||
PUNICODE_STRING DllToInvoke
|
||
)
|
||
|
||
{
|
||
|
||
RTL_QUERY_REGISTRY_TABLE paramTable[2] = {0};
|
||
LOCALMATCHSTR localMatch = {0,FriendlyName};
|
||
HINSTANCE libHandle;
|
||
|
||
|
||
paramTable[0].QueryRoutine = GetFriendlyMatchComm;
|
||
paramTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
|
||
//
|
||
// First things first. Load the cfg manager library.
|
||
//
|
||
|
||
libHandle = LoadLibraryW(CfgmgrDllString);
|
||
|
||
if (libHandle) {
|
||
|
||
FARPROC getSize;
|
||
FARPROC getList;
|
||
FARPROC locateDevNode;
|
||
FARPROC openDevKey;
|
||
|
||
try {
|
||
getSize = GetProcAddress(
|
||
libHandle,
|
||
"CM_Get_Device_ID_List_SizeW"
|
||
);
|
||
|
||
getList = GetProcAddress(
|
||
libHandle,
|
||
"CM_Get_Device_ID_ListW"
|
||
);
|
||
|
||
locateDevNode = GetProcAddress(
|
||
libHandle,
|
||
"CM_Locate_DevNodeW"
|
||
);
|
||
|
||
openDevKey = GetProcAddress(
|
||
libHandle,
|
||
"CM_Open_DevNode_Key"
|
||
);
|
||
|
||
if (getSize && getList && locateDevNode && openDevKey) {
|
||
|
||
PWCHAR bufferForList = NULL;
|
||
DWORD sizeOfBuffer;
|
||
|
||
//
|
||
// Find how much memory for the buffer.
|
||
//
|
||
|
||
if (getSize(
|
||
&sizeOfBuffer,
|
||
L"MODEM",
|
||
CM_GETIDLIST_FILTER_SERVICE
|
||
) == CR_SUCCESS) {
|
||
|
||
//
|
||
// Allocate 2 extra wchar.
|
||
//
|
||
|
||
bufferForList = RtlAllocateHeap(
|
||
RtlProcessHeap(),
|
||
MAKE_TAG( TMP_TAG ),
|
||
(sizeOfBuffer*sizeof(WCHAR))
|
||
+(sizeof(WCHAR)*2)
|
||
);
|
||
|
||
if (bufferForList) {
|
||
|
||
PWCHAR currentId;
|
||
|
||
try {
|
||
|
||
if (getList(
|
||
L"modem",
|
||
bufferForList,
|
||
sizeOfBuffer,
|
||
CM_GETIDLIST_FILTER_SERVICE
|
||
) == CR_SUCCESS) {
|
||
|
||
for (
|
||
currentId = bufferForList;
|
||
*currentId;
|
||
currentId += wcslen(currentId)+1
|
||
) {
|
||
|
||
DWORD devInst = 0;
|
||
|
||
if (locateDevNode(
|
||
&devInst,
|
||
currentId,
|
||
CM_LOCATE_DEVINST_NORMAL
|
||
) == CR_SUCCESS) {
|
||
|
||
HANDLE handleToDev;
|
||
|
||
if (openDevKey(
|
||
devInst,
|
||
KEY_ALL_ACCESS,
|
||
0,
|
||
RegDisposition_OpenAlways,
|
||
&handleToDev,
|
||
CM_REGISTRY_SOFTWARE
|
||
) == CR_SUCCESS) {
|
||
|
||
NTSTATUS statusOfQuery;
|
||
|
||
localMatch.FoundIt = 0;
|
||
paramTable[0].Name =
|
||
L"FriendlyName";
|
||
|
||
//
|
||
// We now have an open
|
||
// handle to a dev node.
|
||
//
|
||
// Check to see if it's
|
||
// friendly name matches ours.
|
||
//
|
||
|
||
if (!NT_SUCCESS(
|
||
RtlQueryRegistryValues(
|
||
RTL_REGISTRY_HANDLE,
|
||
handleToDev,
|
||
¶mTable[0],
|
||
&localMatch,
|
||
NULL
|
||
)
|
||
)) {
|
||
|
||
CloseHandle(handleToDev);
|
||
continue;
|
||
|
||
}
|
||
|
||
if (!localMatch.FoundIt) {
|
||
|
||
CloseHandle(handleToDev);
|
||
continue;
|
||
|
||
}
|
||
|
||
//
|
||
// The names match. Now look
|
||
// for the config dll name.
|
||
//
|
||
|
||
paramTable[0].QueryRoutine =
|
||
GetConfigDialogName;
|
||
paramTable[0].Name =
|
||
L"ConfigDialog";
|
||
statusOfQuery =
|
||
RtlQueryRegistryValues(
|
||
RTL_REGISTRY_HANDLE,
|
||
handleToDev,
|
||
¶mTable[0],
|
||
DllToInvoke,
|
||
NULL
|
||
);
|
||
|
||
paramTable[0].QueryRoutine =
|
||
GetFriendlyMatchComm;
|
||
|
||
if (!NT_SUCCESS(statusOfQuery)) {
|
||
|
||
//
|
||
// We had a bad status
|
||
// back from getting the dll
|
||
// name we should have gotten.
|
||
//
|
||
// There is no point in
|
||
// looking for anymore
|
||
//
|
||
|
||
BaseSetLastNTError(
|
||
statusOfQuery
|
||
);
|
||
CloseHandle(handleToDev);
|
||
return;
|
||
|
||
}
|
||
|
||
//
|
||
// We know that we are dealing
|
||
// with a local registry here.
|
||
// we just call closehandle.
|
||
//
|
||
|
||
CloseHandle(handleToDev);
|
||
|
||
if (DllToInvoke->Buffer) {
|
||
|
||
//
|
||
// We have found a dll for
|
||
// the friendly name. Just
|
||
// leave. The finally
|
||
// handlers will clean up
|
||
// our allocations.
|
||
//
|
||
|
||
return;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
} finally {
|
||
|
||
//
|
||
// Free the idlist memory.
|
||
//
|
||
|
||
RtlFreeHeap(
|
||
RtlProcessHeap(),
|
||
0,
|
||
bufferForList
|
||
);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
} finally {
|
||
|
||
FreeLibrary(libHandle);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
if (!DllToInvoke->Buffer) {
|
||
|
||
//
|
||
// Couldn't find the friendly name in the enum tree.
|
||
// See if the value is a valid comm port name. If
|
||
// it is, default return serialui.dll
|
||
//
|
||
|
||
paramTable[0].Name = NULL;
|
||
RtlQueryRegistryValues(
|
||
RTL_REGISTRY_DEVICEMAP,
|
||
L"SERIALCOMM",
|
||
paramTable,
|
||
&localMatch,
|
||
NULL
|
||
);
|
||
|
||
if (localMatch.FoundIt) {
|
||
|
||
ANSI_STRING ansiString;
|
||
|
||
RtlInitAnsiString(
|
||
&ansiString,
|
||
"serialui.dll"
|
||
);
|
||
|
||
DllToInvoke->Buffer = RtlAllocateHeap(
|
||
RtlProcessHeap(),
|
||
MAKE_TAG( TMP_TAG ),
|
||
(ansiString.Length+2)*sizeof(WCHAR)
|
||
);
|
||
|
||
if (!DllToInvoke->Buffer) {
|
||
|
||
BaseSetLastNTError(STATUS_INSUFFICIENT_RESOURCES);
|
||
return;
|
||
|
||
}
|
||
|
||
DllToInvoke->Length = 0;
|
||
DllToInvoke->MaximumLength = (ansiString.Length+1)*sizeof(WCHAR);
|
||
|
||
RtlAnsiStringToUnicodeString(
|
||
DllToInvoke,
|
||
&ansiString,
|
||
FALSE
|
||
);
|
||
*(DllToInvoke->Buffer+ansiString.Length) = 0;
|
||
|
||
} else {
|
||
|
||
SetLastError(ERROR_INVALID_PARAMETER);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
BOOL
|
||
CommConfigDialogW(
|
||
LPCWSTR lpszName,
|
||
HWND hWnd,
|
||
LPCOMMCONFIG lpCC
|
||
)
|
||
|
||
{
|
||
|
||
|
||
UNICODE_STRING dllName = {0};
|
||
BOOL boolToReturn = TRUE;
|
||
HINSTANCE libInstance = 0;
|
||
DWORD statOfCall = 0;
|
||
|
||
|
||
//
|
||
// Given the "friendly name" get the name of the dll to load.
|
||
//
|
||
|
||
GetFriendlyUi(
|
||
lpszName,
|
||
&dllName
|
||
);
|
||
|
||
try {
|
||
|
||
if (dllName.Buffer) {
|
||
|
||
//
|
||
// Got the new library name. Try to load it.
|
||
//
|
||
|
||
libInstance = LoadLibraryW(dllName.Buffer);
|
||
|
||
if (libInstance) {
|
||
|
||
FARPROC procToCall;
|
||
|
||
//
|
||
// Got the lib. Get the proc address we need.
|
||
//
|
||
|
||
procToCall = GetProcAddress(
|
||
libInstance,
|
||
"drvCommConfigDialogW"
|
||
);
|
||
|
||
statOfCall = (DWORD)procToCall(
|
||
lpszName,
|
||
hWnd,
|
||
lpCC
|
||
);
|
||
|
||
} else {
|
||
|
||
boolToReturn = FALSE;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// Assume that an appropriate error has been set.
|
||
//
|
||
|
||
boolToReturn = FALSE;
|
||
|
||
}
|
||
|
||
|
||
} finally {
|
||
|
||
if (dllName.Buffer) {
|
||
|
||
RtlFreeHeap(
|
||
RtlProcessHeap(),
|
||
0,
|
||
dllName.Buffer
|
||
);
|
||
|
||
}
|
||
|
||
if (libInstance) {
|
||
|
||
FreeLibrary(libInstance);
|
||
|
||
}
|
||
|
||
if (statOfCall) {
|
||
|
||
SetLastError(statOfCall);
|
||
boolToReturn = FALSE;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
return boolToReturn;
|
||
|
||
|
||
}
|
||
|
||
BOOL
|
||
CommConfigDialogA(
|
||
LPCSTR lpszName,
|
||
HWND hWnd,
|
||
LPCOMMCONFIG lpCC
|
||
)
|
||
|
||
{
|
||
|
||
PWCHAR unicodeName;
|
||
UNICODE_STRING tmpString;
|
||
ANSI_STRING ansiString;
|
||
BOOL uniBool;
|
||
|
||
RtlInitAnsiString(
|
||
&ansiString,
|
||
lpszName
|
||
);
|
||
|
||
unicodeName = RtlAllocateHeap(
|
||
RtlProcessHeap(),
|
||
MAKE_TAG( TMP_TAG ),
|
||
(ansiString.Length+2)*sizeof(WCHAR)
|
||
);
|
||
|
||
if (!unicodeName) {
|
||
|
||
BaseSetLastNTError(STATUS_INSUFFICIENT_RESOURCES);
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
tmpString.Length = 0;
|
||
tmpString.MaximumLength = (ansiString.Length+1)*sizeof(WCHAR);
|
||
tmpString.Buffer = unicodeName;
|
||
|
||
RtlAnsiStringToUnicodeString(
|
||
&tmpString,
|
||
&ansiString,
|
||
FALSE
|
||
);
|
||
*(unicodeName+ansiString.Length) = 0;
|
||
|
||
try {
|
||
|
||
uniBool = CommConfigDialogW(
|
||
unicodeName,
|
||
hWnd,
|
||
lpCC
|
||
);
|
||
|
||
|
||
} finally {
|
||
|
||
RtlFreeHeap(
|
||
RtlProcessHeap(),
|
||
0,
|
||
unicodeName
|
||
);
|
||
|
||
}
|
||
|
||
return uniBool;
|
||
|
||
}
|
||
|
||
BOOL
|
||
GetDefaultCommConfigW(
|
||
LPCWSTR lpszName,
|
||
LPCOMMCONFIG lpCC,
|
||
LPDWORD lpdwSize
|
||
)
|
||
{
|
||
|
||
UNICODE_STRING dllName = {0};
|
||
BOOL boolToReturn = TRUE;
|
||
HINSTANCE libInstance = 0;
|
||
DWORD statOfCall = 0;
|
||
|
||
|
||
//
|
||
// Given the "friendly name" get the name of the dll to load.
|
||
//
|
||
|
||
GetFriendlyUi(
|
||
lpszName,
|
||
&dllName
|
||
);
|
||
|
||
try {
|
||
|
||
if (dllName.Buffer) {
|
||
|
||
//
|
||
// Got the new library name. Try to load it.
|
||
//
|
||
|
||
libInstance = LoadLibraryW(dllName.Buffer);
|
||
|
||
if (libInstance) {
|
||
|
||
FARPROC procToCall;
|
||
|
||
//
|
||
// Got the lib. Get the proc address we need.
|
||
//
|
||
|
||
procToCall = GetProcAddress(
|
||
libInstance,
|
||
"drvGetDefaultCommConfigW"
|
||
);
|
||
|
||
statOfCall = (DWORD)procToCall(
|
||
lpszName,
|
||
lpCC,
|
||
lpdwSize
|
||
);
|
||
|
||
} else {
|
||
|
||
boolToReturn = FALSE;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// Assume that an appropriate error has been set.
|
||
//
|
||
|
||
boolToReturn = FALSE;
|
||
|
||
}
|
||
|
||
|
||
} finally {
|
||
|
||
if (dllName.Buffer) {
|
||
|
||
RtlFreeHeap(
|
||
RtlProcessHeap(),
|
||
0,
|
||
dllName.Buffer
|
||
);
|
||
|
||
}
|
||
|
||
if (libInstance) {
|
||
|
||
FreeLibrary(libInstance);
|
||
|
||
}
|
||
|
||
if (statOfCall) {
|
||
|
||
SetLastError(statOfCall);
|
||
boolToReturn = FALSE;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
return boolToReturn;
|
||
|
||
}
|
||
|
||
BOOL
|
||
GetDefaultCommConfigA(
|
||
LPCSTR lpszName,
|
||
LPCOMMCONFIG lpCC,
|
||
LPDWORD lpdwSize
|
||
)
|
||
{
|
||
|
||
PWCHAR unicodeName;
|
||
UNICODE_STRING tmpString;
|
||
ANSI_STRING ansiString;
|
||
BOOL uniBool;
|
||
|
||
RtlInitAnsiString(
|
||
&ansiString,
|
||
lpszName
|
||
);
|
||
|
||
unicodeName = RtlAllocateHeap(
|
||
RtlProcessHeap(),
|
||
MAKE_TAG( TMP_TAG ),
|
||
(ansiString.Length+2)*sizeof(WCHAR)
|
||
);
|
||
|
||
if (!unicodeName) {
|
||
|
||
BaseSetLastNTError(STATUS_INSUFFICIENT_RESOURCES);
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
tmpString.Length = 0;
|
||
tmpString.MaximumLength = (ansiString.Length+1)*sizeof(WCHAR);
|
||
tmpString.Buffer = unicodeName;
|
||
|
||
RtlAnsiStringToUnicodeString(
|
||
&tmpString,
|
||
&ansiString,
|
||
FALSE
|
||
);
|
||
*(unicodeName+ansiString.Length) = 0;
|
||
|
||
try {
|
||
|
||
uniBool = GetDefaultCommConfigW(
|
||
unicodeName,
|
||
lpCC,
|
||
lpdwSize
|
||
);
|
||
|
||
} finally {
|
||
|
||
RtlFreeHeap(
|
||
RtlProcessHeap(),
|
||
0,
|
||
unicodeName
|
||
);
|
||
|
||
}
|
||
|
||
return uniBool;
|
||
|
||
}
|
||
|
||
BOOL
|
||
SetDefaultCommConfigW(
|
||
LPCWSTR lpszName,
|
||
LPCOMMCONFIG lpCC,
|
||
DWORD dwSize
|
||
)
|
||
{
|
||
|
||
UNICODE_STRING dllName = {0};
|
||
BOOL boolToReturn = TRUE;
|
||
HINSTANCE libInstance = 0;
|
||
DWORD statOfCall = 0;
|
||
|
||
|
||
//
|
||
// Given the "friendly name" get the name of the dll to load.
|
||
//
|
||
|
||
GetFriendlyUi(
|
||
lpszName,
|
||
&dllName
|
||
);
|
||
|
||
try {
|
||
|
||
if (dllName.Buffer) {
|
||
|
||
//
|
||
// Got the new library name. Try to load it.
|
||
//
|
||
|
||
libInstance = LoadLibraryW(dllName.Buffer);
|
||
|
||
if (libInstance) {
|
||
|
||
FARPROC procToCall;
|
||
|
||
//
|
||
// Got the lib. Get the proc address we need.
|
||
//
|
||
|
||
procToCall = GetProcAddress(
|
||
libInstance,
|
||
"drvSetDefaultCommConfigW"
|
||
);
|
||
|
||
statOfCall = (DWORD)procToCall(
|
||
lpszName,
|
||
lpCC,
|
||
dwSize
|
||
);
|
||
|
||
} else {
|
||
|
||
boolToReturn = FALSE;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// Assume that an appropriate error has been set.
|
||
//
|
||
|
||
boolToReturn = FALSE;
|
||
|
||
}
|
||
|
||
|
||
} finally {
|
||
|
||
if (dllName.Buffer) {
|
||
|
||
RtlFreeHeap(
|
||
RtlProcessHeap(),
|
||
0,
|
||
dllName.Buffer
|
||
);
|
||
|
||
}
|
||
|
||
if (libInstance) {
|
||
|
||
FreeLibrary(libInstance);
|
||
|
||
}
|
||
|
||
if (statOfCall) {
|
||
|
||
SetLastError(statOfCall);
|
||
boolToReturn = FALSE;
|
||
|
||
}
|
||
|
||
}
|
||
return boolToReturn;
|
||
}
|
||
|
||
BOOL
|
||
SetDefaultCommConfigA(
|
||
LPCSTR lpszName,
|
||
LPCOMMCONFIG lpCC,
|
||
DWORD dwSize
|
||
)
|
||
{
|
||
|
||
PWCHAR unicodeName;
|
||
UNICODE_STRING tmpString;
|
||
ANSI_STRING ansiString;
|
||
BOOL uniBool = TRUE;
|
||
|
||
RtlInitAnsiString(
|
||
&ansiString,
|
||
lpszName
|
||
);
|
||
|
||
unicodeName = RtlAllocateHeap(
|
||
RtlProcessHeap(),
|
||
MAKE_TAG( TMP_TAG ),
|
||
(ansiString.Length+2)*sizeof(WCHAR)
|
||
);
|
||
|
||
if (!unicodeName) {
|
||
|
||
BaseSetLastNTError(STATUS_INSUFFICIENT_RESOURCES);
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
tmpString.Length = 0;
|
||
tmpString.MaximumLength = (ansiString.Length+1)*sizeof(WCHAR);
|
||
tmpString.Buffer = unicodeName;
|
||
|
||
RtlAnsiStringToUnicodeString(
|
||
&tmpString,
|
||
&ansiString,
|
||
FALSE
|
||
);
|
||
*(unicodeName+ansiString.Length) = 0;
|
||
|
||
try {
|
||
|
||
uniBool = SetDefaultCommConfigW(
|
||
unicodeName,
|
||
lpCC,
|
||
dwSize
|
||
);
|
||
|
||
} finally {
|
||
|
||
RtlFreeHeap(
|
||
RtlProcessHeap(),
|
||
0,
|
||
unicodeName
|
||
);
|
||
|
||
}
|
||
|
||
return uniBool;
|
||
|
||
}
|
||
|
||
BOOL
|
||
ClearCommBreak(
|
||
HANDLE hFile
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The function restores character transmission and places the transmission
|
||
line in a nonbreak state.
|
||
|
||
Arguments:
|
||
|
||
hFile - Specifies the communication device to be adjusted.
|
||
|
||
Return Value:
|
||
|
||
The return value is TRUE if the function is successful or FALSE
|
||
if an error occurs.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
return EscapeCommFunction(hFile,CLRBREAK);
|
||
|
||
}
|
||
|
||
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
|
||
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
|
||
GetCommConfig(
|
||
HANDLE hCommDev,
|
||
LPCOMMCONFIG lpCC,
|
||
LPDWORD lpdwSize
|
||
)
|
||
{
|
||
|
||
NTSTATUS Status;
|
||
IO_STATUS_BLOCK Iosb;
|
||
ULONG configLength;
|
||
HANDLE Event;
|
||
DWORD olddwSize = *lpdwSize;
|
||
|
||
|
||
//
|
||
// Ask the device how big the device config structure is.
|
||
//
|
||
|
||
if (!(Event = CreateEvent(
|
||
NULL,
|
||
TRUE,
|
||
FALSE,
|
||
NULL
|
||
))) {
|
||
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
Status = NtDeviceIoControlFile(
|
||
hCommDev,
|
||
Event,
|
||
NULL,
|
||
NULL,
|
||
&Iosb,
|
||
IOCTL_SERIAL_CONFIG_SIZE,
|
||
NULL,
|
||
0,
|
||
&configLength,
|
||
sizeof(configLength)
|
||
);
|
||
|
||
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)) {
|
||
|
||
configLength = 0;
|
||
|
||
}
|
||
|
||
if (!configLength) {
|
||
|
||
//
|
||
// The size needed is simply the size of the comm config structure.
|
||
//
|
||
|
||
CloseHandle(Event);
|
||
if (!ARGUMENT_PRESENT(lpdwSize)) {
|
||
|
||
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
|
||
return FALSE;
|
||
|
||
} else {
|
||
|
||
*lpdwSize = sizeof(COMMCONFIG);
|
||
|
||
if (ARGUMENT_PRESENT(lpCC)) {
|
||
|
||
//
|
||
// Fill in the random fields.
|
||
//
|
||
|
||
lpCC->dwSize = sizeof(COMMCONFIG);
|
||
lpCC->wVersion = 1;
|
||
lpCC->wReserved = 0;
|
||
lpCC->dwProviderSubType = PST_RS232;
|
||
lpCC->dwProviderOffset = 0;
|
||
lpCC->dwProviderSize = 0;
|
||
lpCC->wcProviderData[0] = 0;
|
||
|
||
return GetCommState(
|
||
hCommDev,
|
||
&lpCC->dcb
|
||
);
|
||
|
||
} else {
|
||
|
||
return TRUE;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
if (!ARGUMENT_PRESENT(lpdwSize)) {
|
||
|
||
CloseHandle(Event);
|
||
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
|
||
return FALSE;
|
||
|
||
} else {
|
||
|
||
if (*lpdwSize < sizeof(COMMCONFIG)) {
|
||
|
||
CloseHandle(Event);
|
||
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
|
||
*lpdwSize = configLength;
|
||
return FALSE;
|
||
|
||
} else {
|
||
|
||
if (ARGUMENT_PRESENT(lpCC)) {
|
||
|
||
lpCC->wVersion = 1;
|
||
lpCC->dwProviderSubType = PST_MODEM;
|
||
|
||
if (*lpdwSize < configLength) {
|
||
|
||
lpCC->dwProviderOffset = 0;
|
||
lpCC->dwProviderSize = 0;
|
||
lpCC->wcProviderData[0] = 0;
|
||
*lpdwSize = sizeof(COMMCONFIG);
|
||
CloseHandle(Event);
|
||
|
||
return GetCommState(
|
||
hCommDev,
|
||
&lpCC->dcb
|
||
);
|
||
|
||
} else {
|
||
|
||
*lpdwSize = configLength;
|
||
|
||
//
|
||
// Call down to the lower level serial provider
|
||
// if there is a passed comm config. Assume
|
||
// that the buffer is as large as it needs to be.
|
||
// Parameter validation will insure that we
|
||
// can write to at least that much.
|
||
//
|
||
|
||
Status = NtDeviceIoControlFile(
|
||
hCommDev,
|
||
Event,
|
||
NULL,
|
||
NULL,
|
||
&Iosb,
|
||
IOCTL_SERIAL_GET_COMMCONFIG,
|
||
NULL,
|
||
0,
|
||
lpCC,
|
||
configLength
|
||
);
|
||
|
||
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;
|
||
|
||
}
|
||
|
||
//
|
||
// Got the config stuff, get the comm state too.
|
||
//
|
||
|
||
CloseHandle(Event);
|
||
return GetCommState(
|
||
hCommDev,
|
||
&lpCC->dcb
|
||
);
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
|
||
*lpdwSize = configLength;
|
||
CloseHandle(Event);
|
||
return TRUE;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
BOOL
|
||
GetCommMask(
|
||
HANDLE hFile,
|
||
LPDWORD lpEvtMask
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
This function retrieves the value of the event mask for the handle
|
||
hFile. The mask is not cleared
|
||
|
||
Arguments:
|
||
|
||
hFile - Specifies the communication device to be examined.
|
||
The CreateFile function returns this value.
|
||
|
||
lpEvtMask - Points to a DWORD which is to receive the mask of events
|
||
which are currently enabled.
|
||
|
||
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;
|
||
|
||
//
|
||
// First we do an assert to make sure that the
|
||
// values in the win header files are the same
|
||
// as the nt serial interface, and that the
|
||
// size of the win32 wait mask is the same size
|
||
// as the nt wait mask.
|
||
//
|
||
|
||
ASSERT((SERIAL_EV_RXCHAR == EV_RXCHAR ) &&
|
||
(SERIAL_EV_RXFLAG == EV_RXFLAG ) &&
|
||
(SERIAL_EV_TXEMPTY == EV_TXEMPTY ) &&
|
||
(SERIAL_EV_CTS == EV_CTS ) &&
|
||
(SERIAL_EV_DSR == EV_DSR ) &&
|
||
(SERIAL_EV_RLSD == EV_RLSD ) &&
|
||
(SERIAL_EV_BREAK == EV_BREAK ) &&
|
||
(SERIAL_EV_ERR == EV_ERR ) &&
|
||
(SERIAL_EV_RING == EV_RING ) &&
|
||
(SERIAL_EV_PERR == EV_PERR ) &&
|
||
(SERIAL_EV_RX80FULL == EV_RX80FULL) &&
|
||
(SERIAL_EV_EVENT1 == EV_EVENT1 ) &&
|
||
(SERIAL_EV_EVENT2 == EV_EVENT2 ) &&
|
||
(sizeof(ULONG) == sizeof(DWORD)));
|
||
|
||
//
|
||
// All is well, get the mask from the driver.
|
||
//
|
||
|
||
if (!(SyncEvent = CreateEvent(
|
||
NULL,
|
||
TRUE,
|
||
FALSE,
|
||
NULL
|
||
))) {
|
||
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
Status = NtDeviceIoControlFile(
|
||
hFile,
|
||
SyncEvent,
|
||
NULL,
|
||
NULL,
|
||
&Iosb,
|
||
IOCTL_SERIAL_GET_WAIT_MASK,
|
||
NULL,
|
||
0,
|
||
lpEvtMask,
|
||
sizeof(ULONG)
|
||
);
|
||
|
||
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
|
||
GetCommModemStatus(
|
||
HANDLE hFile,
|
||
LPDWORD lpModemStat
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns the most current value of the modem
|
||
status registers non-delta values.
|
||
|
||
|
||
Arguments:
|
||
|
||
hFile - Specifies the communication device to be examined.
|
||
The CreateFile function returns this value.
|
||
|
||
lpEvtMask - Points to a DWORD which is to receive the mask of
|
||
non-delta values in the modem status register.
|
||
|
||
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;
|
||
|
||
if (!(SyncEvent = CreateEvent(
|
||
NULL,
|
||
TRUE,
|
||
FALSE,
|
||
NULL
|
||
))) {
|
||
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
Status = NtDeviceIoControlFile(
|
||
hFile,
|
||
SyncEvent,
|
||
NULL,
|
||
NULL,
|
||
&Iosb,
|
||
IOCTL_SERIAL_GET_MODEMSTATUS,
|
||
NULL,
|
||
0,
|
||
lpModemStat,
|
||
sizeof(DWORD)
|
||
);
|
||
|
||
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
|
||
GetCommProperties(
|
||
HANDLE hFile,
|
||
LPCOMMPROP lpCommProp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function fills the ubffer pointed to by lpCommProp with the
|
||
communications properties associated with the communications device
|
||
specified by the hFile.
|
||
|
||
Arguments:
|
||
|
||
hFile - Specifies the communication device to be examined.
|
||
The CreateFile function returns this value.
|
||
|
||
lpCommProp - Points to the COMMPROP data structure that is to
|
||
receive the communications properties structure. This
|
||
structure defines certain properties of 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;
|
||
DWORD bufferLength;
|
||
|
||
//
|
||
// Make sure that the windows defines and the nt defines are
|
||
// still in sync.
|
||
//
|
||
|
||
ASSERT((SERIAL_PCF_DTRDSR == PCF_DTRDSR) &&
|
||
(SERIAL_PCF_RTSCTS == PCF_RTSCTS) &&
|
||
(SERIAL_PCF_CD == PCF_RLSD) &&
|
||
(SERIAL_PCF_PARITY_CHECK == PCF_PARITY_CHECK) &&
|
||
(SERIAL_PCF_XONXOFF == PCF_XONXOFF) &&
|
||
(SERIAL_PCF_SETXCHAR == PCF_SETXCHAR) &&
|
||
(SERIAL_PCF_TOTALTIMEOUTS == PCF_TOTALTIMEOUTS) &&
|
||
(SERIAL_PCF_INTTIMEOUTS == PCF_INTTIMEOUTS) &&
|
||
(SERIAL_PCF_SPECIALCHARS == PCF_SPECIALCHARS) &&
|
||
(SERIAL_PCF_16BITMODE == PCF_16BITMODE) &&
|
||
(SERIAL_SP_PARITY == SP_PARITY) &&
|
||
(SERIAL_SP_BAUD == SP_BAUD) &&
|
||
(SERIAL_SP_DATABITS == SP_DATABITS) &&
|
||
(SERIAL_SP_STOPBITS == SP_STOPBITS) &&
|
||
(SERIAL_SP_HANDSHAKING == SP_HANDSHAKING) &&
|
||
(SERIAL_SP_PARITY_CHECK == SP_PARITY_CHECK) &&
|
||
(SERIAL_SP_CARRIER_DETECT == SP_RLSD) &&
|
||
(SERIAL_BAUD_075 == BAUD_075) &&
|
||
(SERIAL_BAUD_110 == BAUD_110) &&
|
||
(SERIAL_BAUD_134_5 == BAUD_134_5) &&
|
||
(SERIAL_BAUD_150 == BAUD_150) &&
|
||
(SERIAL_BAUD_300 == BAUD_300) &&
|
||
(SERIAL_BAUD_600 == BAUD_600) &&
|
||
(SERIAL_BAUD_1200 == BAUD_1200) &&
|
||
(SERIAL_BAUD_1800 == BAUD_1800) &&
|
||
(SERIAL_BAUD_2400 == BAUD_2400) &&
|
||
(SERIAL_BAUD_4800 == BAUD_4800) &&
|
||
(SERIAL_BAUD_7200 == BAUD_7200) &&
|
||
(SERIAL_BAUD_9600 == BAUD_9600) &&
|
||
(SERIAL_BAUD_14400 == BAUD_14400) &&
|
||
(SERIAL_BAUD_19200 == BAUD_19200) &&
|
||
(SERIAL_BAUD_38400 == BAUD_38400) &&
|
||
(SERIAL_BAUD_56K == BAUD_56K) &&
|
||
(SERIAL_BAUD_57600 == BAUD_57600) &&
|
||
(SERIAL_BAUD_115200 == BAUD_115200) &&
|
||
(SERIAL_BAUD_USER == BAUD_USER) &&
|
||
(SERIAL_DATABITS_5 == DATABITS_5) &&
|
||
(SERIAL_DATABITS_6 == DATABITS_6) &&
|
||
(SERIAL_DATABITS_7 == DATABITS_7) &&
|
||
(SERIAL_DATABITS_8 == DATABITS_8) &&
|
||
(SERIAL_DATABITS_16 == DATABITS_16) &&
|
||
(SERIAL_DATABITS_16X == DATABITS_16X) &&
|
||
(SERIAL_STOPBITS_10 == STOPBITS_10) &&
|
||
(SERIAL_STOPBITS_15 == STOPBITS_15) &&
|
||
(SERIAL_STOPBITS_20 == STOPBITS_20) &&
|
||
(SERIAL_PARITY_NONE == PARITY_NONE) &&
|
||
(SERIAL_PARITY_ODD == PARITY_ODD) &&
|
||
(SERIAL_PARITY_EVEN == PARITY_EVEN) &&
|
||
(SERIAL_PARITY_MARK == PARITY_MARK) &&
|
||
(SERIAL_PARITY_SPACE == PARITY_SPACE));
|
||
ASSERT((SERIAL_SP_UNSPECIFIED == PST_UNSPECIFIED) &&
|
||
(SERIAL_SP_RS232 == PST_RS232) &&
|
||
(SERIAL_SP_PARALLEL == PST_PARALLELPORT) &&
|
||
(SERIAL_SP_RS422 == PST_RS422) &&
|
||
(SERIAL_SP_RS423 == PST_RS423) &&
|
||
(SERIAL_SP_RS449 == PST_RS449) &&
|
||
(SERIAL_SP_FAX == PST_FAX) &&
|
||
(SERIAL_SP_SCANNER == PST_SCANNER) &&
|
||
(SERIAL_SP_BRIDGE == PST_NETWORK_BRIDGE) &&
|
||
(SERIAL_SP_LAT == PST_LAT) &&
|
||
(SERIAL_SP_TELNET == PST_TCPIP_TELNET) &&
|
||
(SERIAL_SP_X25 == PST_X25));
|
||
|
||
ASSERT(sizeof(SERIAL_COMMPROP) == sizeof(COMMPROP));
|
||
//
|
||
// Get the total length of what to pass down. If the
|
||
// application indicates that there is provider specific data
|
||
// (by setting dwProvSpec1 to COMMPROP_INITIAILIZED) then
|
||
// use what's at the start of the commprop.
|
||
//
|
||
|
||
bufferLength = sizeof(COMMPROP);
|
||
|
||
if (lpCommProp->dwProvSpec1 == COMMPROP_INITIALIZED) {
|
||
|
||
bufferLength = lpCommProp->wPacketLength;
|
||
|
||
}
|
||
|
||
//
|
||
// Zero out the commprop. 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(lpCommProp, bufferLength);
|
||
|
||
if (!(SyncEvent = CreateEvent(
|
||
NULL,
|
||
TRUE,
|
||
FALSE,
|
||
NULL
|
||
))) {
|
||
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
Status = NtDeviceIoControlFile(
|
||
hFile,
|
||
SyncEvent,
|
||
NULL,
|
||
NULL,
|
||
&Iosb,
|
||
IOCTL_SERIAL_GET_PROPERTIES,
|
||
NULL,
|
||
0,
|
||
lpCommProp,
|
||
bufferLength
|
||
);
|
||
|
||
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
|
||
GetCommTimeouts(
|
||
HANDLE hFile,
|
||
LPCOMMTIMEOUTS lpCommTimeouts
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function returns the timeout characteristics for all read and
|
||
write operations on the handle specified by hFile.
|
||
|
||
Arguments:
|
||
|
||
hFile - Specifies the communication device to be examined.
|
||
The CreateFile function returns this value.
|
||
|
||
lpCommTimeouts - Points to a structure which is to receive the
|
||
current communications timeouts.
|
||
|
||
|
||
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;
|
||
|
||
if (!(Event = CreateEvent(
|
||
NULL,
|
||
TRUE,
|
||
FALSE,
|
||
NULL
|
||
))) {
|
||
|
||
return FALSE;
|
||
|
||
} else {
|
||
|
||
|
||
Status = NtDeviceIoControlFile(
|
||
hFile,
|
||
Event,
|
||
NULL,
|
||
NULL,
|
||
&Iosb,
|
||
IOCTL_SERIAL_GET_TIMEOUTS,
|
||
NULL,
|
||
0,
|
||
&To,
|
||
sizeof(To)
|
||
);
|
||
|
||
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)) {
|
||
|
||
BaseSetLastNTError(Status);
|
||
CloseHandle(Event);
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
CloseHandle(Event);
|
||
|
||
//
|
||
// Everything went ok. Move the value from the Nt records
|
||
// to the windows record.
|
||
//
|
||
|
||
lpCommTimeouts->ReadIntervalTimeout = To.ReadIntervalTimeout;
|
||
lpCommTimeouts->ReadTotalTimeoutMultiplier = To.ReadTotalTimeoutMultiplier;
|
||
lpCommTimeouts->ReadTotalTimeoutConstant = To.ReadTotalTimeoutConstant;
|
||
lpCommTimeouts->WriteTotalTimeoutMultiplier = To.WriteTotalTimeoutMultiplier;
|
||
lpCommTimeouts->WriteTotalTimeoutConstant = To.WriteTotalTimeoutConstant;
|
||
|
||
return TRUE;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
BOOL
|
||
PurgeComm(
|
||
HANDLE hFile,
|
||
DWORD dwFlags
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is used to purge all characters from the transmit
|
||
or receive queues of the communication device specified by the
|
||
hFile parameter. The dwFlags parameter specifies what function
|
||
is to be performed.
|
||
|
||
Arguments:
|
||
|
||
hFile - Specifies the communication device to be purged.
|
||
The CreateFile function returns this value.
|
||
|
||
dwFlags - Bit mask defining actions to be taken.
|
||
|
||
Return Value:
|
||
|
||
The return value is TRUE if the function is successful or FALSE
|
||
if an error occurs.
|
||
|
||
--*/
|
||
|
||
{
|
||
HANDLE Event;
|
||
NTSTATUS Status;
|
||
IO_STATUS_BLOCK Iosb;
|
||
|
||
if (!(Event = CreateEvent(
|
||
NULL,
|
||
TRUE,
|
||
FALSE,
|
||
NULL
|
||
))) {
|
||
|
||
return FALSE;
|
||
|
||
} else {
|
||
|
||
Status = NtDeviceIoControlFile(
|
||
hFile,
|
||
Event,
|
||
NULL,
|
||
NULL,
|
||
&Iosb,
|
||
IOCTL_SERIAL_PURGE,
|
||
&dwFlags,
|
||
sizeof(ULONG),
|
||
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
|
||
SetCommBreak(
|
||
HANDLE hFile
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The function suspends character transmission and places the transmission
|
||
line in a break state until the break condition is cleared..
|
||
|
||
Arguments:
|
||
|
||
hFile - Specifies the communication device to be suspended.
|
||
The CreateFile function returns this value.
|
||
|
||
Return Value:
|
||
|
||
The return value is TRUE if the function is successful or FALSE
|
||
if an error occurs.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
return EscapeCommFunction(hFile,SETBREAK);
|
||
|
||
}
|
||
|
||
BOOL
|
||
SetCommConfig(
|
||
HANDLE hCommDev,
|
||
LPCOMMCONFIG lpCC,
|
||
DWORD dwSize
|
||
)
|
||
|
||
{
|
||
|
||
|
||
NTSTATUS Status;
|
||
IO_STATUS_BLOCK Iosb;
|
||
HANDLE Event;
|
||
LPCOMMCONFIG comConf = lpCC;
|
||
|
||
if (lpCC->dwProviderOffset) {
|
||
|
||
if (!(Event = CreateEvent(
|
||
NULL,
|
||
TRUE,
|
||
FALSE,
|
||
NULL
|
||
))) {
|
||
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
//
|
||
//
|
||
// Call the driver to set the config structure.
|
||
//
|
||
|
||
Status = NtDeviceIoControlFile(
|
||
hCommDev,
|
||
Event,
|
||
NULL,
|
||
NULL,
|
||
&Iosb,
|
||
IOCTL_SERIAL_SET_COMMCONFIG,
|
||
lpCC,
|
||
dwSize,
|
||
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 SetCommState(
|
||
hCommDev,
|
||
&comConf->dcb
|
||
);
|
||
}
|
||
|
||
BOOL
|
||
SetCommMask(
|
||
HANDLE hFile,
|
||
DWORD dwEvtMask
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The function enables the event mask of the communication device
|
||
specified by the hFile parameter. The bits of the nEvtMask parameter
|
||
define which events are to be enabled.
|
||
|
||
Arguments:
|
||
|
||
hFile - Specifies the communication device to receive the settings.
|
||
The CreateFile function returns this value.
|
||
|
||
dwEvtMask - Specifies which events are to enabled.
|
||
|
||
Return Value:
|
||
|
||
The return value is TRUE if the function is successful or FALSE
|
||
if an error occurs.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
NTSTATUS Status;
|
||
IO_STATUS_BLOCK Iosb;
|
||
HANDLE Event;
|
||
|
||
//
|
||
// First we do an assert to make sure that the
|
||
// values in the win header files are the same
|
||
// as the nt serial interface and the the size
|
||
// mask that serial expects is the same as the
|
||
// size that win32 expects.
|
||
//
|
||
|
||
ASSERT((SERIAL_EV_RXCHAR == EV_RXCHAR ) &&
|
||
(SERIAL_EV_RXFLAG == EV_RXFLAG ) &&
|
||
(SERIAL_EV_TXEMPTY == EV_TXEMPTY ) &&
|
||
(SERIAL_EV_CTS == EV_CTS ) &&
|
||
(SERIAL_EV_DSR == EV_DSR ) &&
|
||
(SERIAL_EV_RLSD == EV_RLSD ) &&
|
||
(SERIAL_EV_BREAK == EV_BREAK ) &&
|
||
(SERIAL_EV_ERR == EV_ERR ) &&
|
||
(SERIAL_EV_RING == EV_RING ) &&
|
||
(SERIAL_EV_PERR == EV_PERR ) &&
|
||
(SERIAL_EV_RX80FULL == EV_RX80FULL) &&
|
||
(SERIAL_EV_EVENT1 == EV_EVENT1 ) &&
|
||
(SERIAL_EV_EVENT2 == EV_EVENT2 ) &&
|
||
(sizeof(DWORD) == sizeof(ULONG)));
|
||
|
||
|
||
//
|
||
// Make sure that the users mask doesn't contain any values
|
||
// we don't support.
|
||
//
|
||
|
||
if (dwEvtMask & (~(EV_RXCHAR |
|
||
EV_RXFLAG |
|
||
EV_TXEMPTY |
|
||
EV_CTS |
|
||
EV_DSR |
|
||
EV_RLSD |
|
||
EV_BREAK |
|
||
EV_ERR |
|
||
EV_RING |
|
||
EV_PERR |
|
||
EV_RX80FULL |
|
||
EV_EVENT1 |
|
||
EV_EVENT2))) {
|
||
|
||
SetLastError(ERROR_INVALID_DATA);
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
|
||
if (!(Event = CreateEvent(
|
||
NULL,
|
||
TRUE,
|
||
FALSE,
|
||
NULL
|
||
))) {
|
||
|
||
return FALSE;
|
||
|
||
} else {
|
||
|
||
|
||
//
|
||
// All is well, send the mask to the driver.
|
||
//
|
||
|
||
ULONG LocalMask = dwEvtMask;
|
||
|
||
Status = NtDeviceIoControlFile(
|
||
hFile,
|
||
Event,
|
||
NULL,
|
||
NULL,
|
||
&Iosb,
|
||
IOCTL_SERIAL_SET_WAIT_MASK,
|
||
&LocalMask,
|
||
sizeof(ULONG),
|
||
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
|
||
TransmitCommChar(
|
||
HANDLE hFile,
|
||
char cChar
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The function marks the character specified by the cChar parameter
|
||
for immediate transmission, by placing it at the head of the transmit
|
||
queue.
|
||
|
||
Arguments:
|
||
|
||
hFile - Specifies the communication device to send the character.
|
||
The CreateFile function returns this value.
|
||
|
||
cChar - Specifies the character to be placed in the recieve queue.
|
||
|
||
Return Value:
|
||
|
||
The return value is TRUE if the function is successful or FALSE
|
||
if an error occurs.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
NTSTATUS Status;
|
||
IO_STATUS_BLOCK Iosb;
|
||
HANDLE Event;
|
||
|
||
if (!(Event = CreateEvent(
|
||
NULL,
|
||
TRUE,
|
||
FALSE,
|
||
NULL
|
||
))) {
|
||
|
||
return FALSE;
|
||
|
||
} else {
|
||
|
||
Status = NtDeviceIoControlFile(
|
||
hFile,
|
||
Event,
|
||
NULL,
|
||
NULL,
|
||
&Iosb,
|
||
IOCTL_SERIAL_IMMEDIATE_CHAR,
|
||
&cChar,
|
||
sizeof(UCHAR),
|
||
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
|
||
WaitCommEvent(
|
||
HANDLE hFile,
|
||
LPDWORD lpEvtMask,
|
||
LPOVERLAPPED lpOverlapped
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function will wait until any of the events occur that were
|
||
provided as the nEvtMask parameter to SetcommMask. If while waiting
|
||
the event mask is changed (via another call to SetCommMask), the
|
||
function will return immediately. The function will fill the EvtMask
|
||
pointed to by the lpEvtMask parameter with the reasons that the
|
||
wait was satisfied.
|
||
|
||
Arguments:
|
||
|
||
hFile - Specifies the communication device to be waited on.
|
||
The CreateFile function returns this value.
|
||
|
||
lpEvtMask - Points to a mask that will receive the reason that
|
||
the wait was satisfied.
|
||
|
||
lpOverLapped - An optional overlapped handle.
|
||
|
||
Return Value:
|
||
|
||
The return value is TRUE if the function is successful or FALSE
|
||
if an error occurs.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
NTSTATUS Status;
|
||
|
||
if (ARGUMENT_PRESENT(lpOverlapped)) {
|
||
lpOverlapped->Internal = (DWORD)STATUS_PENDING;
|
||
|
||
Status = NtDeviceIoControlFile(
|
||
hFile,
|
||
lpOverlapped->hEvent,
|
||
NULL,
|
||
(ULONG_PTR)lpOverlapped->hEvent & 1 ? NULL : lpOverlapped,
|
||
(PIO_STATUS_BLOCK)&lpOverlapped->Internal,
|
||
IOCTL_SERIAL_WAIT_ON_MASK,
|
||
NULL,
|
||
0,
|
||
lpEvtMask,
|
||
sizeof(ULONG)
|
||
);
|
||
|
||
if (!NT_ERROR(Status) && (Status != STATUS_PENDING)) {
|
||
|
||
return TRUE;
|
||
|
||
} else {
|
||
|
||
BaseSetLastNTError(Status);
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
IO_STATUS_BLOCK Iosb;
|
||
HANDLE Event;
|
||
|
||
if (!(Event = CreateEvent(
|
||
NULL,
|
||
TRUE,
|
||
FALSE,
|
||
NULL
|
||
))) {
|
||
|
||
return FALSE;
|
||
|
||
} else {
|
||
|
||
Status = NtDeviceIoControlFile(
|
||
hFile,
|
||
Event,
|
||
NULL,
|
||
NULL,
|
||
&Iosb,
|
||
IOCTL_SERIAL_WAIT_ON_MASK,
|
||
NULL,
|
||
0,
|
||
lpEvtMask,
|
||
sizeof(ULONG)
|
||
);
|
||
|
||
if ( Status == STATUS_PENDING) {
|
||
|
||
//
|
||
// Operation must complete before return &
|
||
// IoStatusBlock destroyed
|
||
|
||
Status = NtWaitForSingleObject( Event, FALSE, NULL );
|
||
if ( NT_SUCCESS(Status)) {
|
||
|
||
Status = Iosb.Status;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
CloseHandle(Event);
|
||
|
||
if (NT_ERROR(Status)) {
|
||
|
||
BaseSetLastNTError(Status);
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
return TRUE;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|