⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 comport.c

📁 微软的point of sale的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
                             */
                            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 + -