📄 comport.c
字号:
*/
WCHAR comPortIndexString[4+1];
ULONG thisComNumber;
for (i = 0; (i < 4) && (i < keyValueInfo->DataLength/sizeof(WCHAR)); i++){
comPortIndexString[i] = valuePtr[3+i];
}
comPortIndexString[i] = UNICODE_NULL;
thisComNumber = LAtoD(comPortIndexString);
if (thisComNumber == 0){
ASSERT(thisComNumber != 0);
}
else if (thisComNumber <= sizeof(ULONG)*8){
comNameMask |= 1 << (thisComNumber-1);
}
else {
ASSERT(thisComNumber <= sizeof(ULONG)*8);
}
}
}
}
} while (NT_SUCCESS(status));
/*
* First clear bit in comNameMask represents the first available COM name.
*/
for (i = 0; i < sizeof(ULONG)*8; i++){
if (!(comNameMask & (1 << i))){
WCHAR comName[] = L"COMxxxx";
ULONG comNumLen;
/*
* Save the COM port number that we're returning.
*/
comNumber = i+1;
DBGVERBOSE(("GetFreeComPortNumber: got free COM port #%xh.", comNumber));
/*
* Write a temporary COMx=COMx holder value to the SERIALCOMM key
* so that no other PDOs get this COM port number.
* This value will get overwritten by <symbolicLinkName=COMx> when the pdo is started.
*/
comNumLen = MyLog(10, comNumber)+1;
ASSERT(comNumLen <= 4);
NumToDecString(comName+3, (USHORT)comNumber, (USHORT)comNumLen);
comName[3+comNumLen] = UNICODE_NULL;
status = RtlWriteRegistryValue( RTL_REGISTRY_DEVICEMAP,
L"SERIALCOMM",
comName,
REG_SZ,
comName,
(3 + comNumLen + 1) * sizeof(WCHAR));
ASSERT(NT_SUCCESS(status));
break;
}
}
}
else {
DBGERR(("GetFreeComPortNumber: ZwOpenKey failed with status %xh", status));
}
}
else {
/*
* Windows NT.
* Use the COM Name Arbiter bitmap.
*/
HANDLE hKey;
OBJECT_ATTRIBUTES objectAttributes;
UNICODE_STRING keyName;
NTSTATUS status;
RtlInitUnicodeString(&keyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\COM Name Arbiter");
InitializeObjectAttributes( &objectAttributes,
&keyName,
OBJ_CASE_INSENSITIVE,
NULL,
(PSECURITY_DESCRIPTOR)NULL);
status = ZwOpenKey( &hKey,
KEY_QUERY_VALUE | KEY_SET_VALUE,
&objectAttributes);
if (NT_SUCCESS(status)){
UNICODE_STRING valueName;
PVOID rawData;
ULONG dataSize;
RtlInitUnicodeString(&valueName, L"ComDB");
ASSERT(hKey);
dataSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION);
/*
* Allocate one extra byte in case we have to add a byte to ComDB
*/
rawData = ALLOCPOOL(NonPagedPool, dataSize+1);
if (rawData){
status = ZwQueryValueKey( hKey,
&valueName,
KeyValuePartialInformation,
rawData,
dataSize,
&dataSize);
if (status == STATUS_BUFFER_OVERFLOW){
FREEPOOL(rawData);
ASSERT(dataSize > FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data));
/*
* Allocate one extra byte in case we have to add a byte to ComDB
*/
rawData = ALLOCPOOL(NonPagedPool, dataSize+1);
if (rawData){
status = ZwQueryValueKey( hKey,
&valueName,
KeyValuePartialInformation,
rawData,
dataSize,
&dataSize);
}
}
if (NT_SUCCESS(status)){
PKEY_VALUE_PARTIAL_INFORMATION keyPartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION)rawData;
ULONG b, i;
BOOLEAN done = FALSE;
ASSERT(dataSize >= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data));
ASSERT(keyPartialInfo->Type == REG_BINARY);
/*
* The ComDB value is just a bit mask where bit n set indicates
* that COM port # n+1 is taken.
* Get the index of the first unset bit; starting with bit 2 (COM3).
*/
for (b = 0; (b < dataSize-FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data)) && !done; b++){
for (i = (b == 0) ? 2 : 0; (i < 8) && !done; i++){
if (keyPartialInfo->Data[b] & (1 << i)){
/*
* This COM port (#8*b+i+1) is taken, go to the next one.
*/
}
else {
/*
* Found a free COM port.
* Write the value back with the new bit set.
* Only write back the number of bytes we read earlier.
* Only use this COM port if the write succeeds.
*
* Note: careful with the size of the KEY_VALUE_PARTIAL_INFORMATION
* struct. Its real size is 0x0D bytes,
* but the compiler aligns it to 0x10 bytes.
* So use FIELD_OFFSET, not sizeof, to determine
* how many bytes to write.
*/
keyPartialInfo->Data[b] |= (1 << i);
status = ZwSetValueKey( hKey,
&valueName,
0,
REG_BINARY,
(PVOID)keyPartialInfo->Data,
dataSize-FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data));
if (NT_SUCCESS(status)){
comNumber = 8*b + i + 1;
DBGVERBOSE(("GetFreeComPortNumber: got free COM port #%xh.", comNumber));
}
else {
DBGERR(("GetFreeComPortNumber: ZwSetValueKey failed with %xh.", status));
}
done = TRUE;
}
}
}
if ((b == dataSize-FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data)) && !done){
/*
* No more available bits in ComDB, so add a byte.
*/
ASSERT(comNumber == -1);
ASSERT(b > 0);
DBGWARN(("ComDB overflow -- adding new byte"));
keyPartialInfo->Data[b] = 1;
dataSize++;
status = ZwSetValueKey( hKey,
&valueName,
0,
REG_BINARY,
(PVOID)keyPartialInfo->Data,
dataSize-FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data));
if (NT_SUCCESS(status)){
comNumber = 8*b + 1;
DBGVERBOSE(("GetFreeComPortNumber: got free COM port #%xh.", comNumber));
}
else {
DBGERR(("GetFreeComPortNumber: ZwSetValueKey #2 failed with %xh.", status));
}
}
ASSERT(comNumber != -1);
}
else {
DBGERR(("GetFreeComPortNumber: ZwQueryValueKey failed with %xh.", status));
}
/*
* Check that we didn't fail the second allocation before freeing this buffer.
*/
if (rawData){
FREEPOOL(rawData);
}
}
else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
status = ZwClose(hKey);
ASSERT(NT_SUCCESS(status));
}
else {
DBGERR(("GetFreeComPortNumber: ZwOpenKey failed with %xh.", status));
}
}
ASSERT(comNumber != -1);
return comNumber;
}
VOID ReleaseCOMPort(LONG comPortNumber)
{
if (isWin9x){
/*
* We punt on this for Win9x.
* That's ok since the SERIALCOMM keys are dynamically-generated at each boot,
* so if start fails a COM port number will just be unavailable until the next boot.
*/
DBGWARN(("ReleaseCOMPort: not implemented for Win9x")); // BUGBUG
}
else {
HANDLE hKey = NULL;
OBJECT_ATTRIBUTES objectAttributes;
UNICODE_STRING keyName;
NTSTATUS status;
ASSERT(comPortNumber > 0);
RtlInitUnicodeString(&keyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\COM Name Arbiter");
InitializeObjectAttributes( &objectAttributes,
&keyName,
OBJ_CASE_INSENSITIVE,
NULL,
(PSECURITY_DESCRIPTOR)NULL);
status = ZwOpenKey(&hKey, KEY_QUERY_VALUE | KEY_SET_VALUE, &objectAttributes);
if (NT_SUCCESS(status)){
UNICODE_STRING valueName;
PVOID rawData;
ULONG dataSize;
RtlInitUnicodeString(&valueName, L"ComDB");
ASSERT(hKey);
dataSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION);
rawData = ALLOCPOOL(NonPagedPool, dataSize);
if (rawData){
status = ZwQueryValueKey( hKey,
&valueName,
KeyValuePartialInformation,
rawData,
dataSize,
&dataSize);
if (status == STATUS_BUFFER_OVERFLOW){
FREEPOOL(rawData);
ASSERT(dataSize > FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data));
rawData = ALLOCPOOL(NonPagedPool, dataSize);
if (rawData){
status = ZwQueryValueKey( hKey,
&valueName,
KeyValuePartialInformation,
rawData,
dataSize,
&dataSize);
}
}
if (NT_SUCCESS(status)){
PKEY_VALUE_PARTIAL_INFORMATION keyPartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION)rawData;
ASSERT(dataSize > FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data));
ASSERT(keyPartialInfo->Type == REG_BINARY);
/*
* The ComDB value is just a bit mask where bit n set indicates
* that COM port # n+1 is taken.
* Get the index of the first unset bit; starting with bit 2 (COM3).
*
* Note: careful with the size of the KEY_VALUE_PARTIAL_INFORMATION
* struct. Its real size is 0x0D bytes,
* but the compiler aligns it to 0x10 bytes.
* So use FIELD_OFFSET, not sizeof, to determine
* how many bytes to write.
*/
ASSERT(comPortNumber >= 3);
if ((comPortNumber > 0) && (comPortNumber <= (LONG)(dataSize-FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data))*8)){
ASSERT(keyPartialInfo->Data[(comPortNumber-1)/8] & (1 << ((comPortNumber-1) & 7)));
keyPartialInfo->Data[(comPortNumber-1)/8] &= ~(1 << ((comPortNumber-1) & 7));
status = ZwSetValueKey( hKey,
&valueName,
0,
REG_BINARY,
(PVOID)keyPartialInfo->Data,
dataSize-FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data));
if (NT_SUCCESS(status)){
DBGVERBOSE(("ReleaseCOMPort: released COM port # %xh.", comPortNumber));
}
else {
DBGERR(("ReleaseCOMPort: ZwSetValueKey failed with %xh.", status));
}
}
else {
ASSERT((comPortNumber > 0) && (comPortNumber <= (LONG)(dataSize-FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data))*8));
}
}
else {
DBGERR(("ReleaseCOMPort: ZwQueryValueKey failed with %xh.", status));
}
/*
* Check that we didn't fail the second allocation before freeing this buffer.
*/
if (rawData){
FREEPOOL(rawData);
}
}
else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
status = ZwClose(hKey);
ASSERT(NT_SUCCESS(status));
}
else {
DBGERR(("ReleaseCOMPort: ZwOpenKey failed with %xh.", status));
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -