mirror of https://github.com/tongzx/nt5src
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.
3456 lines
79 KiB
3456 lines
79 KiB
/*++
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|