Load, unload or reload a driver at runtime
If you develop drivers for Windows CE or Embedded Compact you know it is a major PITA to have to reload the entire kernel every time you change something in the driver code. You need to do this even in a debug kernel because the driver binaries are in use (and thus you can't re-compile & link) when the driver is loaded.
To workaround this I created a tool that allows you to unload or (re)load a driver at runtime. The way I use it is as follows:
- I build a small debug kernel including the driver under development
- I add the driver dll to the list of modules that will be loaded from the Release Directory (in VS2K5 with PB go to menu "Target"->"Release Directory Modules..." and add the driver)
- I add my tool (see below) as a subproject to the OS Design
Now when I download the kernel the driver will load (if the correct Drivers\BuiltIn registry values are there of course). I can set breakpoints in and step through my driver code, etc. Now when I find a bug I just press F5 to continue execution, open a "Target Control" window (menu Target->Target Control) and use my tool to unload the driver, then fix the bug, recompile & link and then (re)load the driver without the need for rebuilding or even reloading the kernel:
reloaddrv [-u] drv1: [[-u] drv2: {etc}]
In Target Control you use the 's' command to start an executable: s reloaddrv -u drv1:
The drv1: is the name of your driver (a 3 letter prefix followed by an index and a colon). Make sure to specify the -u (unload) parameter before the driver name!
To just reload the driver (so a quick unload followed immediately by a load; great for debugging initialization and clean-up) you use the tool as follows: s reloaddrv drv1:
If the driver was not loaded when you executed the above command the tool will try to find the BuiltIn registry key for the driver and load it from there.
You can specify multiple drivers on the commandline as well (-u always applies to the driver directly following it): s reloaddrv -u drv1: -u drv2: drv3: -u drv4: drv5: drv6:
I'm sure this tool is useful to a lot of you developing drivers for Windows CE/Embedded Compact, so here it is:
HINSTANCE hPrevInstance,
LPWSTR lpCmdLine,
int nCmdShow)
{
BOOL bLoad = TRUE;
LPWSTR pszToken = wcstok(lpCmdLine, L" ");
while (pszToken)
{ // Process parameters
if (wcsicmp(pszToken, L"-u")==0)
{ // Reset load flag if only unload requested
bLoad = FALSE;
pszToken = wcstok(NULL, L" ");
continue;
}
// See if the driver is loaded
DEVMGR_DEVICE_INFORMATION devInfo = {0};
LPWSTR pszDeviceKey = NULL;
devInfo.dwSize = sizeof(devInfo);
HANDLE hFind = FindFirstDevice(DeviceSearchByLegacyName, pszToken, &devInfo);
if (INVALID_HANDLE_VALUE != hFind)
{ // Clean up find handle
FindClose(hFind);
// Store driver registry key
pszDeviceKey = wcsdup(devInfo.szDeviceKey);
// Unload driver
RETAILMSG(1, (L"Found driver \"%s\", unloading...", devInfo.szLegacyName));
DeactivateDevice(devInfo.hDevice);
}
else
RETAILMSG(1, (L"Driver \"%s\" not loaded.", pszToken));
if (bLoad)
{ // Load driver if requested
if (NULL == pszDeviceKey)
{ // Try to find driver key in registry
WCHAR szPrefix[4] = {0};
DWORD dwIndex = 0;
wcsncpy(szPrefix, pszToken, 3);
dwIndex = _wtol(&pszToken[3]);
HKEY hKey;
BOOL bFound = FALSE;
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Drivers\\BuiltIn", 0, NULL, &hKey))
{ // Opened BuiltIn drivers key
DWORD i = 0;
WCHAR szDriverKey[MAX_PATH];
DWORD dwCount = _countof(szDriverKey);
while (ERROR_NO_MORE_ITEMS != RegEnumKeyEx(hKey, i++, szDriverKey, &dwCount, NULL, NULL, NULL, NULL))
{ // Enumerate all driver keys
HKEY hDriverKey;
if (ERROR_SUCCESS == RegOpenKeyEx(hKey, szDriverKey, 0, NULL, &hDriverKey))
{ // Check if the prefix matches the specified one
WCHAR szDriverPrefix[MAX_PATH] = {0};
dwCount = sizeof(szDriverPrefix);
RegQueryValueEx(hDriverKey, L"Prefix", NULL, NULL, (LPBYTE)szDriverPrefix, &dwCount);
if (0 == wcsicmp(szPrefix, szDriverPrefix))
{ // And check if the index matches the specified one
DWORD dwDriverIndex = 0;
dwCount = sizeof(dwDriverIndex);
RegQueryValueEx(hDriverKey, L"Index", NULL, NULL, (LPBYTE)&dwDriverIndex, &dwCount);
if (dwDriverIndex == dwIndex)
{ // We found our driver key!
bFound = TRUE;
RegCloseKey(hDriverKey);
break;
}
}
RegCloseKey(hDriverKey);
}
dwCount = _countof(szDriverKey);
}
if (bFound)
{ // Copy driver key name into pszDeviceKey
pszDeviceKey = (LPWSTR)malloc(MAX_PATH * sizeof(WCHAR));
if (pszDeviceKey)
wsprintf(pszDeviceKey, L"Drivers\\BuiltIn\\%s", szDriverKey);
}
else
RETAILMSG(1, (L"Can't find driver key for \"%s\"...", pszToken));
RegCloseKey(hKey);
}
}
if (pszDeviceKey)
{ // Reload driver
RETAILMSG(1, (L"Reloading from \"%s\"...", pszDeviceKey));
ActivateDeviceEx(pszDeviceKey, NULL, 0, NULL);
}
}
// Clean up and get ready for next parameter
if (pszDeviceKey)
free(pszDeviceKey);
bLoad = TRUE;
pszToken = wcstok(NULL, L" ");
}
return 0;
}
And for your convenience here's the tool 7-zipped up as an OS Design subproject: reloaddrv.7z
Attachment | Size |
---|---|
reloaddrv.7z | 2.53 KB |
Comments
Windows CE LoadDriver
A similar tool with a few more options can be found here: http://bogong.codeplex.com.
Re: Windows CE LoadDriver
Cool, thanks! Only benefit my source code has is that you don't have to know the registry key name or long hex handle value, just the legacy prefix+index is enough. It's a bit easier to use I guess, but bogong definitely has its benefits too.