Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1333 lines
34 KiB

/*++
Copyright (C) Microsoft Corporation
Module Name:
tsmain.cpp
Abstract:
This module implements Device Manager troubleshooting supporting classes
Author:
William Hsieh (williamh) created
Revision History:
--*/
//
#include "devmgr.h"
#include "proppage.h"
#include "devdrvpg.h"
#include "tsmisc.h"
#include "tswizard.h"
#include "cdriver.h"
const CMPROBLEM_INFO ProblemInfo[DEVMGR_NUM_CM_PROB] =
{
// no problem
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_WORKING_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_NOT_CONFIGURED
{
TRUE,
FIX_COMMAND_REINSTALL,
IDS_INST_REINSTALL,
1,
IDS_FIXIT_REINSTALL
},
// CM_PROB_DEVLOADER_FAILED
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_OUT_OF_MEMORY
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_IS_WRONG_TYPE
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_LACKED_ARBITRATOR
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_BOOT_CONFIG_CONFLICT
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_FAILED_FILTER (Never used)
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_DEVLOADER_NOT_FOUND (Never used)
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_INVALID_DATA
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_FAILED_START
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_LIAR (Never used)
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_NORMAL_CONFLICT
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_NOT_VERIFIED (Never used)
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_NEED_RESTART
{
TRUE,
FIX_COMMAND_RESTARTCOMPUTER,
IDS_INST_RESTARTCOMPUTER,
1,
IDS_FIXIT_RESTARTCOMPUTER
},
// CM_PROB_REENUMERATION
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_PARTIAL_LOG_CONF
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_UNKNOWN_RESOURCE
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_REINSTALL
{
TRUE,
FIX_COMMAND_REINSTALL,
IDS_INST_REINSTALL,
1,
IDS_FIXIT_REINSTALL
},
// CM_PROB_REGISTRY (Never used)
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_VXDLDR (Never used)
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_WILL_BE_REMOVED (Never used)
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_DISABLED
{
TRUE,
FIX_COMMAND_ENABLEDEVICE,
IDS_INST_ENABLEDEVICE,
1,
IDS_FIXIT_ENABLEDEVICE
},
// CM_PROB_DEVLOADER_NOT_READY (Never used)
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_DEVICE_NOT_THERE
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_MOVED
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_TOO_EARLY
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_NO_VALID_LOG_CONF
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_FAILED_INSTALL
{
TRUE,
FIX_COMMAND_REINSTALL,
IDS_INST_REINSTALL,
1,
IDS_FIXIT_REINSTALL
},
// CM_PROB_HARDWARE_DISABLED
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_CANT_SHARE_IRQ
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_FAILED_ADD
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_DISABLED_SERVICE
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_TRANSLATION_FAILED
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_NO_SOFTCONFIG
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_BIOS_TABLE
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_IRQ_TRANSLATION_FAILED
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_FAILED_DRIVER_ENTRY
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_DRIVER_FAILED_PRIOR_UNLOAD
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_DRIVER_FAILED_LOAD
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_DRIVER_SERVICE_KEY_INVALID
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_LEGACY_SERVICE_NO_DEVICES
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_DUPLICATE_DEVICE
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_FAILED_POST_START
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_HALTED
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_PHANTOM
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_SYSTEM_SHUTDOWN
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_HELD_FOR_EJECT
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_DRIVER_BLOCKED
{
TRUE,
FIX_COMMAND_DRIVERBLOCKED,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_REGISTRY_TOO_LARGE
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// CM_PROB_SETPROPERTIES_FAILED
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
// UNKNOWN PROBLEM
{
TRUE,
FIX_COMMAND_TROUBLESHOOTER,
IDS_INST_TROUBLESHOOTER,
1,
IDS_FIXIT_TROUBLESHOOTER
},
};
//
// CProblemAgent implementation
//
CProblemAgent::CProblemAgent(
CDevice* pDevice,
ULONG Problem,
BOOL SeparateProcess
)
{
m_pDevice = pDevice;
m_Problem = Problem;
ASSERT(pDevice);
m_idInstFirst = ProblemInfo[min(Problem, DEVMGR_NUM_CM_PROB-1)].idInstFirst;
m_idInstCount = ProblemInfo[min(Problem, DEVMGR_NUM_CM_PROB-1)].idInstCount;
m_idFixit = ProblemInfo[min(Problem, DEVMGR_NUM_CM_PROB-1)].idFixit;
m_FixCommand = ProblemInfo[min(Problem, DEVMGR_NUM_CM_PROB-1)].FixCommand;
m_SeparateProcess = SeparateProcess;
}
DWORD
CProblemAgent::InstructionText(
LPTSTR Buffer,
DWORD BufferSize
)
{
String strLocalBuffer;
SetLastError(ERROR_SUCCESS);
if (m_idInstFirst) {
strLocalBuffer.LoadString(g_hInstance, m_idInstFirst);
String strTemp;
for (int i = 1; i < m_idInstCount; i++) {
strTemp.LoadString(g_hInstance, m_idInstFirst + i);
strLocalBuffer += strTemp;
}
if (BufferSize > (DWORD)strLocalBuffer.GetLength()) {
StringCchCopy(Buffer, BufferSize, (LPCTSTR)strLocalBuffer);
}
else if (strLocalBuffer.GetLength()) {
SetLastError(ERROR_INSUFFICIENT_BUFFER);
}
return strLocalBuffer.GetLength();
}
return 0;
}
DWORD
CProblemAgent::FixitText(
LPTSTR Buffer,
DWORD BufferSize
)
{
if (!Buffer && BufferSize)
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
SetLastError(ERROR_SUCCESS);
if (m_idFixit)
{
return LoadResourceString(m_idFixit, Buffer, BufferSize);
}
return 0;
}
BOOL
CProblemAgent::FixIt(
HWND hwndOwner
)
/*++
Lanuches a troubleshooter based on the m_FixCommand.
Arguments:
hwndOwner - Parent window handle
Return Value:
TRUE if launching the troubleshooter changed the device in some way
so that the UI on the general tab needs to be refreshed.
FALSE if launching the troubleshooter did not change the device in
any way.
--*/
{
BOOL Result = FALSE;
SP_TROUBLESHOOTER_PARAMS tsp;
DWORD RequiredSize;
tsp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
tsp.ClassInstallHeader.InstallFunction = DIF_TROUBLESHOOTER;
tsp.ChmFile[0] = TEXT('\0');
tsp.HtmlTroubleShooter[0] = TEXT('\0');
m_pDevice->m_pMachine->DiSetClassInstallParams(*m_pDevice,
&tsp.ClassInstallHeader,
sizeof(tsp)
);
//
// If the class installer retuns NO_ERROR (SetupDiCallClassInstaller returns TRUE)
// then don't launch the default troubleshooters because the class installer has
// launched it's own troubleshooter
//
if (m_pDevice->m_pMachine->DiCallClassInstaller(DIF_TROUBLESHOOTER, *m_pDevice)) {
return TRUE;
} else if (ERROR_DI_DO_DEFAULT == GetLastError()) {
m_pDevice->m_pMachine->DiGetClassInstallParams(*m_pDevice,
&tsp.ClassInstallHeader,
sizeof(tsp),
&RequiredSize
);
}
switch (m_FixCommand)
{
case FIX_COMMAND_UPGRADEDRIVERS:
Result = UpgradeDriver(hwndOwner, m_pDevice);
break;
case FIX_COMMAND_REINSTALL:
Result = Reinstall(hwndOwner, m_pDevice);
break;
case FIX_COMMAND_ENABLEDEVICE:
Result = EnableDevice(hwndOwner, m_pDevice);
break;
case FIX_COMMAND_STARTDEVICE:
Result = EnableDevice(hwndOwner, m_pDevice);
break;
case FIX_COMMAND_RESTARTCOMPUTER:
Result = RestartComputer(hwndOwner, m_pDevice);
break;
case FIX_COMMAND_DRIVERBLOCKED:
Result = FixDriverBlocked(hwndOwner, m_pDevice, tsp.ChmFile, ARRAYLEN(tsp.ChmFile), tsp.HtmlTroubleShooter, ARRAYLEN(tsp.HtmlTroubleShooter));
break;
case FIX_COMMAND_TROUBLESHOOTER:
Result = StartTroubleShooter(hwndOwner, m_pDevice, tsp.ChmFile, tsp.HtmlTroubleShooter);
break;
case FIX_COMMAND_DONOTHING:
Result = TRUE;
break;
default:
Result = FALSE;
}
return Result;
}
BOOL
CProblemAgent::UpgradeDriver(
HWND hwndOwner,
CDevice* pDevice
)
{
DWORD Status = 0, Problem = 0;
if (!pDevice || !pDevice->m_pMachine->IsLocal() || !g_IsAdmin) {
//
// Must be an admin and on the local machine to update a device.
//
ASSERT(FALSE);
return FALSE;
}
//
// If the device has the DN_WILL_BE_REMOVED flag set and the user is
// attempting to update the driver then we will prompt them for a
// reboot and include text in the prompt that explains this device
// is in the process of being removed.
//
if (pDevice->GetStatus(&Status, &Problem) &&
(Status & DN_WILL_BE_REMOVED)) {
//
// First try and send a MMCPropertyChangeNotify message to our
// CComponent so that it can prompt for a reboot inside the
// device manager thread instead of our thread. If this is not
// done then the property sheet will hang around after device
// manager has gone away...which will cause a "hung app" dialog
// to appear.
//
CNotifyRebootRequest* pNRR = new CNotifyRebootRequest(hwndOwner, DI_NEEDRESTART, IDS_WILL_BE_REMOVED_NO_UPDATE_DRIVER);
if (pNRR) {
if (!pDevice->m_psd.PropertyChangeNotify(reinterpret_cast<LONG_PTR>(pNRR))) {
//
// There isn't a CComponent around, so this is just a property
// sheet running outside of MMC.
//
pNRR->Release();
PromptForRestart(hwndOwner, DI_NEEDRESTART, IDS_WILL_BE_REMOVED_NO_UPDATE_DRIVER);
}
} else {
//
// We couldn't allocate memory to create our CNotifyRebootRequest
// instance, so just prompt for a reboot in this thread.
//
PromptForRestart(hwndOwner, DI_NEEDRESTART, IDS_WILL_BE_REMOVED_NO_UPDATE_DRIVER);
}
return FALSE;
}
pDevice->m_pMachine->InstallDevInst(hwndOwner, pDevice->GetDeviceID(), TRUE, NULL);
return TRUE;
}
BOOL
CProblemAgent::Reinstall(
HWND hwndOwner,
CDevice* pDevice
)
{
return UpgradeDriver(hwndOwner, pDevice);
}
BOOL
CProblemAgent::EnableDevice(
HWND hwndOwner,
CDevice* pDevice
)
{
CWizard98 theSheet(hwndOwner);
CTSEnableDeviceIntroPage* pEnableDeviceIntroPage = new CTSEnableDeviceIntroPage;
if (!pEnableDeviceIntroPage) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
HPROPSHEETPAGE hIntroPage = pEnableDeviceIntroPage->Create(pDevice);
theSheet.InsertPage(hIntroPage);
CTSEnableDeviceFinishPage* pEnableDeviceFinishPage = new CTSEnableDeviceFinishPage;
if (!pEnableDeviceFinishPage) {
if (pEnableDeviceIntroPage) {
delete pEnableDeviceIntroPage;
}
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
HPROPSHEETPAGE hFinishPage = pEnableDeviceFinishPage->Create(pDevice);
theSheet.InsertPage(hFinishPage);
return (BOOL)theSheet.DoSheet();
}
BOOL
CProblemAgent::RestartComputer(
HWND hwndOwner,
CDevice* pDevice
)
{
HWND hwndFocus;
if (!pDevice || !pDevice->m_pMachine)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
hwndFocus = GetFocus();
CWizard98 theSheet(hwndOwner);
CTSRestartComputerFinishPage* pRestartComputerFinishPage = new CTSRestartComputerFinishPage;
if (!pRestartComputerFinishPage) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
HPROPSHEETPAGE hPage = pRestartComputerFinishPage->Create(pDevice);
theSheet.InsertPage(hPage);
theSheet.DoSheet();
// restore focus
if (hwndFocus) {
SetFocus(hwndFocus);
}
return TRUE;
}
BOOL
CProblemAgent::FixDriverBlocked(
HWND hwndOwner,
CDevice* pDevice,
LPTSTR ChmFile,
ULONG ChmFileSize,
LPTSTR HtmlTroubleShooter,
ULONG HtmlTroubleShooterSize
)
{
CDriver *pDriver = NULL;
CDriverFile* pDrvFile = NULL;
PVOID Context;
LPCTSTR pBlockDriverHtmlHelpID = NULL;
*ChmFile = TEXT('\0');
pDriver = pDevice->CreateDriver();
if (pDriver) {
//
// Build up a list of function and filter drivers for this device.
//
pDriver->BuildDriverList(TRUE);
//
// Enumerate through the list of drivers for this device until we find
// one that has a blocked driver html help ID.
//
pDriver->GetFirstDriverFile(&pDrvFile, Context);
if (pDrvFile) {
do {
if (pDrvFile &&
((pBlockDriverHtmlHelpID = pDrvFile->GetBlockedDriverHtmlHelpID()) != NULL) &&
(*pBlockDriverHtmlHelpID != TEXT('\0')) &&
(lstrlen(pBlockDriverHtmlHelpID) < (int)ChmFileSize)) {
//
// Found a Blocked Driver html help ID, assuming we can
// copy it into our local ChmFile buffer, then break
// out of the loop. If we can't then just continue, since
// we can't launch a truncated help center page!
//
if (SUCCEEDED(StringCchCopy(ChmFile,
ChmFileSize,
pBlockDriverHtmlHelpID))) {
break;
}
}
} while (pDriver->GetNextDriverFile(&pDrvFile, Context));
}
}
//
// If we have a ChmFile then launch that troubleshooter, otherwise
// Get the troubleshooter and launch it.
//
if (*ChmFile ||
GetTroubleShooter(pDevice, ChmFile, ChmFileSize, HtmlTroubleShooter, HtmlTroubleShooterSize)) {
LaunchHtlmTroubleShooter(hwndOwner, ChmFile, HtmlTroubleShooter);
}
if (pDriver) {
delete pDriver;
}
return TRUE;
}
BOOL
ParseTroubleShooter(
LPCTSTR TSString,
LPTSTR ChmFile,
ULONG ChmFileSize,
LPTSTR HtmlTroubleShooter,
ULONG HtmlTroubleShooterSize
)
{
//
// Berify parameters
//
if (!TSString || TEXT('\0') == TSString[0] || !ChmFile || !HtmlTroubleShooter)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
//
// Make a copy of the string because we have to party on it
//
ULONG Len = lstrlen(TSString) + 1;
TCHAR* psz = new TCHAR[Len];
if (!psz) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
StringCchCopy(psz, Len, TSString);
LPTSTR ChmName = NULL;
LPTSTR ChmNameEnd = NULL;
LPTSTR HtmName = NULL;
LPTSTR HtmNameEnd = NULL;
LPTSTR p;
p = psz;
SetLastError(ERROR_SUCCESS);
//
// the format of the string is "chmfile, htmlfile"
//
p = SkipBlankChars(p);
if (TEXT('\0') != *p) {
//
// looking for CHM file which could be enclosed
// inside double quote chars.
// NOTE: not double quote chars inside double quoted string is allowed.
//
if (TEXT('\"') == *p) {
ChmName = ++p;
while (TEXT('\"') != *p && TEXT('\0') != *p) {
p++;
}
ChmNameEnd = p;
if (TEXT('\"') == *p) {
p++;
}
} else {
ChmName = p;
while ((TEXT('\0') != *p) &&
!IsBlankChar(*p) &&
(TEXT(',') != *p)
) {
p++;
}
ChmNameEnd = p;
}
//
// looking for ','
//
if (TEXT('\0') != *p) {
p = SkipBlankChars(p);
if (TEXT('\0') != *p && TEXT(',') == *p) {
p = SkipBlankChars(p + 1);
if (TEXT('\0') != *p) {
HtmName = p++;
while (!IsBlankChar(*p) && TEXT('\0') != *p) {
p++;
}
HtmNameEnd = p;
}
}
}
}
if (HtmName && HtmNameEnd) {
*HtmNameEnd = TEXT('\0');
if (FAILED(StringCchCopy(HtmlTroubleShooter, HtmlTroubleShooterSize, HtmName))) {
//
// We could not copy all of the troubleshooter name into the buffer
// so set HtmName and ChmName to NULL, so that we will FAIL the call.
//
HtmName = NULL;
ChmName = NULL;
}
}
if (ChmName && ChmNameEnd){
*ChmNameEnd = TEXT('\0');
if (FAILED(StringCchCopy(ChmFile, ChmFileSize, ChmName))) {
//
// We could not copy all of the Chm file name into the buffer
// so set the HtmName and ChmName to NULL, so that we will FAIL this
// call.
//
HtmName = NULL;
ChmName = NULL;
}
}
if (HtmName || ChmName) {
return TRUE;
}
return FALSE;
}
//
// This function looks for CHM and HTM troubleshooter files for this device.
//
// The troubleshoooter string value has the following form:
// "TroubleShooter-xx" = "foo.chm, bar.htm"
// where xx is the problem code for the device
//
// It first looks under the devices driver key.
// If nothing is found there it looks under the class key.
// If nothing is there it looks in the default troubleshooter location
// If nothing is there it just displays the hard-coded generic troubleshooter.
//
BOOL
CProblemAgent::GetTroubleShooter(
CDevice* pDevice,
LPTSTR ChmFile,
ULONG ChmFileSize,
LPTSTR HtmlTroubleShooter,
ULONG HtmlTroubleShooterSize
)
{
BOOL Result = FALSE;
DWORD Status, Problem = 0;
String strTroubleShooterKey;
String strTroubleShooterValue;
HKEY hKey;
strTroubleShooterKey.Empty();
strTroubleShooterValue.Empty();
try {
if (pDevice->GetStatus(&Status, &Problem)) {
//
// If the device is a phantom device, use the CM_PROB_DEVICE_NOT_THERE
//
if (pDevice->IsPhantom()) {
Problem = CM_PROB_PHANTOM;
}
//
// If the device is not started and no problem is assigned to it
// fake the problem number to be failed start.
//
if (!(Status & DN_STARTED) && !Problem && pDevice->IsRAW()) {
Problem = CM_PROB_FAILED_START;
}
}
strTroubleShooterKey.Format(TEXT("TroubleShooter-%d"), Problem);
//
// First check the devices driver key
//
hKey = pDevice->m_pMachine->DiOpenDevRegKey(*pDevice, DICS_FLAG_GLOBAL,
0, DIREG_DRV, KEY_READ);
if (INVALID_HANDLE_VALUE != hKey)
{
CSafeRegistry regDrv(hKey);
//
// Get the TroubleShooter value from the driver key
//
if (regDrv.GetValue((LPTSTR)strTroubleShooterKey, strTroubleShooterValue))
{
if (ParseTroubleShooter((LPTSTR)strTroubleShooterValue, ChmFile, ChmFileSize, HtmlTroubleShooter, HtmlTroubleShooterSize)) {
Result = TRUE;
}
}
}
//
// If we don't have a TroubleShooter yet then try the class key
//
if (!Result) {
CClass* pClass = pDevice->GetClass();
ASSERT(pClass);
LPGUID pClassGuid = *pClass;
hKey = pDevice->m_pMachine->DiOpenClassRegKey(pClassGuid, KEY_READ, DIOCR_INSTALLER);
if (INVALID_HANDLE_VALUE != hKey)
{
CSafeRegistry regClass(hKey);
// get the TroubleShooter value from the class key
if (regClass.GetValue((LPTSTR)strTroubleShooterKey, strTroubleShooterValue))
{
if (ParseTroubleShooter((LPTSTR)strTroubleShooterValue, ChmFile, ChmFileSize, HtmlTroubleShooter, HtmlTroubleShooterSize)) {
Result = TRUE;
}
}
}
}
//
// If we still don't have a TroubleShooter then try the default TroubleShooters
// key.
//
if (!Result) {
CSafeRegistry regDevMgr;
CSafeRegistry regTroubleShooters;
if (regDevMgr.Open(HKEY_LOCAL_MACHINE, REG_PATH_DEVICE_MANAGER) &&
regTroubleShooters.Open(regDevMgr, REG_STR_TROUBLESHOOTERS)) {
//
// Get the TroubleShooter value from the default TroubleShooters key
//
if (regTroubleShooters.GetValue((LPTSTR)strTroubleShooterKey, strTroubleShooterValue))
{
if (ParseTroubleShooter((LPTSTR)strTroubleShooterValue, ChmFile, ChmFileSize, HtmlTroubleShooter, HtmlTroubleShooterSize)) {
Result = TRUE;
}
}
}
}
//
// And finally, if still not TroubleShooter we will just use the default one
//
if (!Result) {
if (SUCCEEDED(StringCchCopy(ChmFile, ChmFileSize, TEXT("hcp://help/tshoot/hdw_generic.htm")))) {
HtmlTroubleShooter[0] = TEXT('\0');
Result = TRUE;
}
}
}
catch (CMemoryException* e)
{
e->Delete();
Result = FALSE;
}
return Result;
}
void
CProblemAgent::LaunchHtlmTroubleShooter(
HWND hwndOwner,
LPTSTR ChmFile,
LPTSTR HtmlTroubleShooter
)
{
String strFormat, strCommand;
if ((!ChmFile || !*ChmFile) &&
(!HtmlTroubleShooter || !*HtmlTroubleShooter)) {
//
// If both ChmFile and HtmlTroubleShooter are NULL then
// bail out.
//
return;
}
//
// There are two different types of troubleshooters that can be launched.
// HelpCenter troubleshooters and HtmlHelp troubleshooters. This API tells
// the difference by checking if a HtmlTroubleShooter was specified or not.
// If only a ChmFile was specified and it starts with hcp:// then this API
// will send the entire string to help center. Otherwise we send the string
// to HtmlHelp (or hh.exe if it is launched as a separate process).
//
if ((!HtmlTroubleShooter || (HtmlTroubleShooter[0] == TEXT('\0'))) &&
(StrCmpNI(ChmFile, TEXT("hcp://"), lstrlen(TEXT("hcp://"))) == 0)) {
//
// This is a new HelpCenter troubleshooter
//
strCommand.Format(TEXT(" -url %s"), ChmFile);
ShellExecute(hwndOwner,
TEXT("open"),
TEXT("HELPCTR.EXE"),
(LPTSTR)strCommand,
NULL,
SW_SHOWNORMAL
);
} else {
//
// This is an old HtlmHelp troubleshooter
//
if (m_SeparateProcess) {
STARTUPINFO si;
PROCESS_INFORMATION pi;
if (strFormat.GetSystemWindowsDirectory()) {
//
// Tack on an extra back slash if one is needed
//
if (_T('\\') != strFormat[strFormat.GetLength() - 1]) {
strFormat += (LPCTSTR)TEXT("\\");
}
strFormat += (LPCTSTR)TEXT("hh.exe ms-its:%s::/%s");
strCommand.Format((LPCTSTR)strFormat, ChmFile, HtmlTroubleShooter);
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_NORMAL;
if (CreateProcess(NULL, (LPTSTR)strCommand, NULL, NULL, FALSE, 0, 0, NULL, &si, &pi)) {
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
}
} else {
HtmlHelp(hwndOwner, ChmFile, HH_DISPLAY_TOPIC, (LPARAM)HtmlTroubleShooter);
}
}
}
BOOL
CProblemAgent::StartTroubleShooter(
HWND hwndOwner,
CDevice* pDevice,
LPTSTR ChmFile,
LPTSTR HtmlTroubleShooter
)
{
//
// If the class installers or one of the co-installers returned
// ERROR_DI_DO_DEFAULT then verify that they filled in either the ChmFile
// or the HtmlTroubleShooter, or both.
//
if ((ERROR_DI_DO_DEFAULT == GetLastError()) &&
(((ChmFile[0] != TEXT('\0')) ||
(HtmlTroubleShooter[0] != TEXT('\0'))))) {
LaunchHtlmTroubleShooter(hwndOwner, ChmFile, HtmlTroubleShooter);
} else {
SP_TROUBLESHOOTER_PARAMS tsp;
tsp.ChmFile[0] = TEXT('\0');
tsp.HtmlTroubleShooter[0] = TEXT('\0');
//
// Get CHM file and TroubleShooter file from the registry
//
if (GetTroubleShooter(pDevice, tsp.ChmFile, ARRAYLEN(tsp.ChmFile), tsp.HtmlTroubleShooter, ARRAYLEN(tsp.HtmlTroubleShooter))) {
LaunchHtlmTroubleShooter(hwndOwner, tsp.ChmFile, tsp.HtmlTroubleShooter);
}
}
//
// Return FALSE since launching the troubleshooter does not change the device
// in any way.
//
return FALSE;
}
CWizard98::CWizard98(
HWND hwndParent,
UINT MaxPages
)
{
m_MaxPages = 0;
if (MaxPages && MaxPages <= 32) {
m_MaxPages = MaxPages;
memset(&m_psh, 0, sizeof(m_psh));
m_psh.hInstance = g_hInstance;
m_psh.hwndParent = hwndParent;
m_psh.phpage = new HPROPSHEETPAGE[MaxPages];
m_psh.dwSize = sizeof(m_psh);
m_psh.dwFlags = PSH_WIZARD | PSH_USEICONID | PSH_USECALLBACK | PSH_WIZARD97 | PSH_WATERMARK | PSH_STRETCHWATERMARK | PSH_HEADER;
m_psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK);
m_psh.pszbmHeader = MAKEINTRESOURCE(IDB_BANNER);
m_psh.pszIcon = MAKEINTRESOURCE(IDI_DEVMGR);
m_psh.pszCaption = MAKEINTRESOURCE(IDS_TROUBLESHOOTING_NAME);
m_psh.pfnCallback = CWizard98::WizardCallback;
}
}
INT
CWizard98::WizardCallback(
IN HWND hwndDlg,
IN UINT uMsg,
IN LPARAM lParam
)
/*++
Routine Description:
Call back used to remove the "?" from the wizard page.
Arguments:
hwndDlg - Handle to the property sheet dialog box.
uMsg - Identifies the message being received. This parameter
is one of the following values:
PSCB_INITIALIZED - Indicates that the property sheet is
being initialized. The lParam value is zero for this message.
PSCB_PRECREATE Indicates that the property sheet is about
to be created. The hwndDlg parameter is NULL and the lParam
parameter is a pointer to a dialog template in memory. This
template is in the form of a DLGTEMPLATE structure followed
by one or more DLGITEMTEMPLATE structures.
lParam - Specifies additional information about the message. The
meaning of this value depends on the uMsg parameter.
Return Value:
The function returns zero.
--*/
{
UNREFERENCED_PARAMETER(hwndDlg);
switch( uMsg ) {
case PSCB_INITIALIZED:
break;
case PSCB_PRECREATE:
if( lParam ){
DLGTEMPLATE *pDlgTemplate = (DLGTEMPLATE *)lParam;
pDlgTemplate->style &= ~(DS_CONTEXTHELP | WS_SYSMENU);
}
break;
}
return FALSE;
}