Instead of using CM_Open_DevNode_Key, call SetupDiOpenDevRegKey in both
spots, it does the same thing.
d
-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of William Michael
Jones
Sent: Thursday, February 09, 2006 6:51 AM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] Changing Serial Port Number?
Hi,
I hope the following helps.
Sincerely,
William Michael Jones “Mike”
/***
Hi,
i’m feeling quite stupid to ask the list again, but i’m really stuck and
under pressure… i wrote a driver which does nothing else than creating
a
virtual serial
port and forwarding all IRPs (except from some special ioctls) to
another
serial
port driver.
now i want to change the serial port number of my virtual serial port to
any unused serial port the user desires (from user mode).
currently i’m trying to achieve this through the following steps:
-telling the driver that its port changed (special ioctl)
-updating the HKLM\Hardware\Devicemap\SerialComm registry key
-retrieving a HDEVINFO handle to the PORTS class
-using a previously obtained SP_DEVINFO_DATA struct +
CM_Open_DevNode_Key function (cfgMr32.lib) to open the devices registry
key
-setting the devices “PortName” registry property to the desired new
port name
-updating the devices “FriendlyName” through
SetupDiSetDeviceRegistryProperty
-updating the devices symbolic link through QueryDosDevice /
DefineDosDevice
-and finally freeing the old and claiming the new port through
ComDBReleasePort/ComDBClaimPort
now i’m able to access the port through its new name (with
hyperterminal) , but first SetupDiEnumDeviceInfo
doesn’t enumerate my device anymore and second the device manager still
displays the old name
and can’t even remove my driver anymore but instead tells my, that my
device is “perhaps” required
to start the computer.
what should i do to change my drivers port name? am i completly wrong
and there’s
a single API?
the code is attached below.
regards,
daniel.
***/
int CSerialMap::relinkPort(CString portName, const int newPortNo,
PPORT_INFO
portInfo)
{
int status;
DWORD oldPortNumber;
TCHAR targetPath[MAX_NAME_PORTS],
newPortName[MAX_NAME_PORTS], newFriendlyName[MAX_NAME_PORTS];
_GUID* guidTmp;
HDEVINFO deviceInfoSet;
BOOL guidTest = FALSE;
DWORD requiredSize = 0;
SP_DEVINFO_DATA devInfoData;
HKEY keyDevice;
static CM_Open_DevNode_Key openDevNodeKey = NULL;
static HINSTANCE cfgMan;
if (NULL == openDevNodeKey)
{
cfgMan = LoadLibrary(“cfgmgr32”);
if (!cfgMan)
{
lastError = ERR_DYNAMIC_LIB;
return lastError;
}
openDevNodeKey = (CM_Open_DevNode_Key)GetProcAddress(cfgMan,
“CM_Open_DevNode_Key”);
if (!openDevNodeKey)
{
lastError = ERR_DYNAMIC_LIB;
FreeLibrary(cfgMan);
goto rlpErr1;
}
}
devInfoData = portInfo->DeviceInfoData;
_stprintf(newPortName, “COM%d”, newPortNo + 1);
// update the devices portname and friendly name registry keys:
guidTest = SetupDiClassGuidsFromNameA(“Ports”, 0, 0, &requiredSize);
if (requiredSize < 1)
{
lastError = ERR_DEVICE_MANAGER;
goto rlpErr1;
}
guidTmp = (_GUID*) malloc(requiredSize * sizeof(GUID));
// get GUID of the ports class:
guidTest = SetupDiClassGuidsFromNameA(“Ports”, guidTmp, requiredSize
*
sizeof(GUID), &requiredSize);
if (!guidTest)
{
lastError = ERR_DEVICE_MANAGER;
free(guidTmp);
goto rlpErr1;
}
// get devices within ports class:
deviceInfoSet = SetupDiGetClassDevs(guidTmp, NULL, NULL,
DIGCF_PRESENT);
free(guidTmp);
if (INVALID_HANDLE_VALUE == deviceInfoSet)
{
lastError = ERR_DEVICE_MANAGER;
goto rlpErr1;
}
/////////
{
TCHAR szFriendlyName[MAX_PATH];
SP_DEVINFO_DATA deidThis;
HKEY hkeyDev;
TCHAR szPortNameVal[MAX_PATH];
DWORD dwLen = MAX_PATH;
LONG lRet;
// I used the SetupXXX calls
// Walk the list of port devices to make sure it is yours
deidThis.cbSize = sizeof( SP_DEVINFO_DATA );
while( SetupDiEnumDeviceInfo( hdiPortsForCard, nDevIdx++, &deidThis
) )
{
// Open the Device Parameters Key of the device
hkeyDev = SetupDiOpenDevRegKey( hdiPortsForCard, &deidThis,
DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_ALL_ACCESS );
// Now you can query and set all you want here and check with
regedit
RegQueryValueEx( hkeyDev, _T(“PortName”), NULL, NULL,
(LPBYTE)szPortNameVal, &dwLen ) != ERROR_SUCCESS )
// Query and set other things too
…
lRet = RegSetValueEx( hkeyDev, _T(“PortName”), 0,REG_SZ,
(LPBYTE)szPortNameVal, (DWORD) (_tcslen( szPortNameVal ) + 1 ) * sizeof(
TCHAR) );
if( lRet != ERROR_SUCCESS )
{
continue;
}
RegCloseKey( hkeyDev );
// Write the new Friendly Name which includes the COM port
memset( szFriendlyName, 0x00, MAX_PATH );
wsprintf( szFriendlyName, _T(“Avocent ESP Port (COM%u)”),
dwNewComNum );
if( !SetupDiSetDeviceRegistryProperty( hdiPortsForCard,
&deidThis,SPDRP_FRIENDLYNAME,(PBYTE)szFriendlyName,
(DWORD) (_tcslen( szFriendlyName
) +
1 ) * sizeof( TCHAR) ) )
{
continue;
}
} // while( SetupDiEnumDeviceInfo( hdiPortsForCard, nDevIdx++,
&deidThis ) )
// I would not use the openDevNodeKey() stuff. Check that the
registry
is changed here tool.
// Now do your QueryDosNames DDD_REMOVE_DEFINITION etc. Note I had
to do
DDD_REMOVE_DEFINITION in a loop to get it
// too completely delete. You can check this with WinObj.exe from
sysinternals.com
// query and store the target device of the specified port (i.e.
“\Device\Serial0”):
status = QueryDosDevice(portName, (PTCHAR)&targetPath,
MAX_NAME_PORTS);
if (status < 1)
{
lastError = ::GetLastError();
return lastError;
}
// Do a loop here till all are gone…!!! for DDD_REMOVE_DEFINITION
check with WinObj
// delete the current symbolic link:
if (TRUE != DefineDosDevice(DDD_REMOVE_DEFINITION, portName, NULL))
{
lastError = ::GetLastError();
return lastError;
}
// create the new link:
if (TRUE != DefineDosDevice(DDD_RAW_TARGET_PATH, newPortName,
targetPath))
{
lastError = ::GetLastError();
// try to restore the old link:
DefineDosDevice(DDD_RAW_TARGET_PATH, portName, targetPath);
return lastError;
}
// update COM port database:
HCOMDB comDB;
status = ComDBOpen(&comDB);
if (ERROR_SUCCESS != status)
{
lastError = status;
return status;
}
oldPortNumber = atoi(portName.Mid(3));
status = ComDBReleasePort(comDB, oldPortNumber);
if (ERROR_SUCCESS != status)
lastError = status;
status = ComDBClaimPort(comDB, (DWORD)newPortNo + 1, TRUE, NULL);
if (ERROR_SUCCESS != status)
{
lastError = status;
ComDBClose(comDB);
return status;
}
ComDBClose(comDB);
}
////////// The following you change Device Manager to renumerate the
FriendlyName
SetupDiDestroyDeviceInfoList( hdiPortsForCard );
deip.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
SetupDiGetDeviceInstallParams( hdi, pdeid, &deip );
ESPPRINT((DBG_OnApply, _T(“OnApply: Old Flags for Port=0x%08x\n”),
deip.FlagsEx ));
deip.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
deip.FlagsEx |= DI_FLAGSEX_PROPCHANGE_PENDING;
ESPPRINT((DBG_OnApply, _T(“OnApply():New Flags for Port=0x%08x (Set
DI_FLAGSEX_PROPCHANGE_PENDING)\n”), deip.FlagsEx ));
SetupDiSetDeviceInstallParams( hdi, pdeid, &deip );
// Do this before…
SetupDiDestroyDeviceInfoList(deviceInfoSet);
FreeLibrary(cfgMan);
////////////
// open device registry key:
status = openDevNodeKey(devInfoData.DevInst, KEY_QUERY_VALUE |
KEY_SET_VALUE, 0,
RegDisposition_OpenExisting, &keyDevice,
CM_REGISTRY_HARDWARE);
if (ERROR_SUCCESS != status)
{
lastError = ERR_REGISTRY;
goto rlpErr2;
}
// set the new portname registry key:
status = RegSetValueEx(keyDevice, “PortName”, 0, REG_SZ,
(PBYTE)newPortName, (_tclen(newPortName) + 1)
*
sizeof(TCHAR));
RegCloseKey(keyDevice);
if (ERROR_SUCCESS != status)
{
lastError = ERR_REGISTRY;
goto rlpErr2;
}
// create the new FriendlyName property:
status = SetupDiGetDeviceRegistryProperty(deviceInfoSet,
&devInfoData,
SPDRP_FRIENDLYNAME,
NULL,
(PBYTE)newFriendlyName,
MAX_NAME_PORTS, NULL);
if (ERROR_SUCCESS == status)
{
createNewFriendlyName(newFriendlyName, newPortName);
SetupDiSetDeviceRegistryProperty(deviceInfoSet, &devInfoData,
SPDRP_FRIENDLYNAME,
(PBYTE)newFriendlyName,
(_tclen(newFriendlyName) + 1) * sizeof(TCHAR));
}
///////////
SetupDiDestroyDeviceInfoList(deviceInfoSet);
FreeLibrary(cfgMan);
// query and store the target device of the specified port (i.e.
“\Device\Serial0”):
status = QueryDosDevice(portName, (PTCHAR)&targetPath,
MAX_NAME_PORTS);
if (status < 1)
{
lastError = ::GetLastError();
return lastError;
}
// delete the current symbolic link:
if (TRUE != DefineDosDevice(DDD_REMOVE_DEFINITION, portName, NULL))
{
lastError = ::GetLastError();
return lastError;
}
// create the new link:
if (TRUE != DefineDosDevice(DDD_RAW_TARGET_PATH, newPortName,
targetPath))
{
lastError = ::GetLastError();
// try to restore the old link:
DefineDosDevice(DDD_RAW_TARGET_PATH, portName, targetPath);
return lastError;
}
// update COM port database:
HCOMDB comDB;
status = ComDBOpen(&comDB);
if (ERROR_SUCCESS != status)
{
lastError = status;
return status;
}
oldPortNumber = atoi(portName.Mid(3));
status = ComDBReleasePort(comDB, oldPortNumber);
if (ERROR_SUCCESS != status)
lastError = status;
status = ComDBClaimPort(comDB, (DWORD)newPortNo + 1, TRUE, NULL);
if (ERROR_SUCCESS != status)
{
lastError = status;
ComDBClose(comDB);
return status;
}
ComDBClose(comDB);
return SUCCESS;
rlpErr2:
SetupDiDestroyDeviceInfoList(deviceInfoSet);
rlpErr1:
FreeLibrary(cfgMan);
return lastError;
}
“L3sT4Rd” wrote in message news:xxxxx@ntdev…
> Hi,
>
> i’m feeling quite stupid to ask the list again, but i’m really stuck
and
> under pressure…
> i wrote a driver which does nothing else than creating a virtual
serial
> port and
> forwarding all IRPs (except from some special ioctls) to another
serial
> port driver.
>
> now i want to change the serial port number of my virtual serial port
to
> any unused serial
> port the user desires (from user mode).
>
> currently i’m trying to achieve this through the following steps:
> -telling the driver that its port changed (special ioctl)
> -updating the HKLM\Hardware\Devicemap\SerialComm registry key
> -retrieving a HDEVINFO handle to the PORTS class
> -using a previously obtained SP_DEVINFO_DATA struct +
> CM_Open_DevNode_Key function (cfgMr32.lib) to open the devices
registry
> key
> -setting the devices “PortName” registry property to the desired new
> port name
> -updating the devices “FriendlyName” through
> SetupDiSetDeviceRegistryProperty
> -updating the devices symbolic link through QueryDosDevice /
> DefineDosDevice
> -and finally freeing the old and claiming the new port through
> ComDBReleasePort/ComDBClaimPort
>
> now i’m able to access the port through its new name (with
> hyperterminal) , but first SetupDiEnumDeviceInfo
> doesn’t enumerate my device anymore and second the device manager
still
> displays the old name
> and can’t even remove my driver anymore but instead tells my, that my
> device is “perhaps” required
> to start the computer.
>
> what should i do to change my drivers port name? am i completly wrong
> and there’s
> a single API?
> the code is attached below.
> regards,
> daniel.
>
> int CSerialMap::relinkPort(CString portName, const int newPortNo,
> PPORT_INFO portInfo)
> {
> int status;
> DWORD oldPortNumber;
> TCHAR targetPath[MAX_NAME_PORTS],
> newPortName[MAX_NAME_PORTS],
> newFriendlyName[MAX_NAME_PORTS];
> _GUID* guidTmp;
> HDEVINFO deviceInfoSet;
> BOOL guidTest = FALSE;
> DWORD requiredSize = 0;
> SP_DEVINFO_DATA devInfoData;
> HKEY keyDevice;
> static CM_Open_DevNode_Key openDevNodeKey = NULL;
> static HINSTANCE cfgMan;
>
> if (NULL == openDevNodeKey)
> {
> cfgMan = LoadLibrary(“cfgmgr32”);
> if (!cfgMan)
> {
> lastError = ERR_DYNAMIC_LIB;
> return lastError;
> }
> openDevNodeKey = (CM_Open_DevNode_Key)GetProcAddress(cfgMan,
> “CM_Open_DevNode_Key”);
> if (!openDevNodeKey)
> {
> lastError = ERR_DYNAMIC_LIB;
> FreeLibrary(cfgMan);
> goto rlpErr1;
> }
> }
>
> devInfoData = portInfo->DeviceInfoData;
>
> _stprintf(newPortName, “COM%d”, newPortNo + 1);
>
> //update the devices portname and friendly name registry keys:
> guidTest = SetupDiClassGuidsFromNameA(“Ports”, 0, 0, &requiredSize);
> if (requiredSize < 1)
> {
> lastError = ERR_DEVICE_MANAGER;
> goto rlpErr1;
> }
>
> guidTmp = (_GUID*) malloc(requiredSize * sizeof(GUID));
>
> //get GUID of the ports class:
> guidTest = SetupDiClassGuidsFromNameA(“Ports”, guidTmp, requiredSize *
> sizeof(GUID), &requiredSize);
> if (!guidTest)
> {
> lastError = ERR_DEVICE_MANAGER;
> free(guidTmp);
> goto rlpErr1;
> }
>
> //get devices within ports class:
> deviceInfoSet = SetupDiGetClassDevs(guidTmp, NULL, NULL,
DIGCF_PRESENT);
> free(guidTmp);
> if (INVALID_HANDLE_VALUE == deviceInfoSet)
> {
> lastError = ERR_DEVICE_MANAGER;
> goto rlpErr1;
> }
>
> //open device registry key:
> status = openDevNodeKey(devInfoData.DevInst, KEY_QUERY_VALUE |
> KEY_SET_VALUE, 0,
> RegDisposition_OpenExisting, &keyDevice, CM_REGISTRY_HARDWARE);
> if (ERROR_SUCCESS != status)
> {
> lastError = ERR_REGISTRY;
> goto rlpErr2;
> }
>
> //set the new portname registry key:
> status = RegSetValueEx(keyDevice, “PortName”, 0, REG_SZ,
> (PBYTE)newPortName, (_tclen(newPortName) + 1) * sizeof(TCHAR));
> RegCloseKey(keyDevice);
> if (ERROR_SUCCESS != status)
> {
> lastError = ERR_REGISTRY;
> goto rlpErr2;
> }
>
> //create the new FriendlyName property:
> status = SetupDiGetDeviceRegistryProperty(deviceInfoSet, &devInfoData,
> SPDRP_FRIENDLYNAME,
> NULL, (PBYTE)newFriendlyName, MAX_NAME_PORTS, NULL);
> if (ERROR_SUCCESS == status)
> {
> createNewFriendlyName(newFriendlyName, newPortName);
>
> SetupDiSetDeviceRegistryProperty(deviceInfoSet, &devInfoData,
> SPDRP_FRIENDLYNAME,
> (PBYTE)newFriendlyName, (_tclen(newFriendlyName) + 1) *
sizeof(TCHAR));
> }
>
> SetupDiDestroyDeviceInfoList(deviceInfoSet);
> FreeLibrary(cfgMan);
>
>
>
> //query and store the target device of the specified port (i.e.
> “\Device\Serial0”):
> status = QueryDosDevice(portName, (PTCHAR)&targetPath,
MAX_NAME_PORTS);
> if (status < 1)
> {
> lastError = ::GetLastError();
> return lastError;
> }
>
> //delete the current symbolic link:
> if (TRUE != DefineDosDevice(DDD_REMOVE_DEFINITION, portName, NULL))
> {
> lastError = ::GetLastError();
> return lastError;
> }
>
> //create the new link:
> if (TRUE != DefineDosDevice(DDD_RAW_TARGET_PATH, newPortName,
targetPath))
> {
> lastError = ::GetLastError();
> //try to restore the old link:
> DefineDosDevice(DDD_RAW_TARGET_PATH, portName, targetPath);
> return lastError;
> }
>
>
>
> //update COM port database:
> HCOMDB comDB;
> status = ComDBOpen(&comDB);
> if (ERROR_SUCCESS != status)
> {
> lastError = status;
> return status;
> }
>
> oldPortNumber = atoi(portName.Mid(3));
> status = ComDBReleasePort(comDB, oldPortNumber);
> if (ERROR_SUCCESS != status)
> lastError = status;
>
> status = ComDBClaimPort(comDB, (DWORD)newPortNo + 1, TRUE, NULL);
> if (ERROR_SUCCESS != status)
> {
> lastError = status;
> ComDBClose(comDB);
> return status;
> }
> ComDBClose(comDB);
>
> return SUCCESS;
>
> rlpErr2:
> SetupDiDestroyDeviceInfoList(deviceInfoSet);
> rlpErr1:
> FreeLibrary(cfgMan);
> return lastError;
> }
>
>
>
>
—
Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256
You are currently subscribed to ntdev as: xxxxx@microsoft.com
To unsubscribe send a blank email to xxxxx@lists.osr.com