Source code of Windows XP (NT5)
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.

2030 lines
49 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1996 - 1999
  6. //
  7. // File: miscutil.c
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "newdevp.h"
  11. TCHAR szUnknownDevice[64];
  12. USHORT LenUnknownDevice;
  13. TCHAR szUnknown[64];
  14. USHORT LenUnknown;
  15. HMODULE hSrClientDll;
  16. typedef
  17. BOOL
  18. (*SRSETRESTOREPOINT)(
  19. PRESTOREPOINTINFO pRestorePtSpec,
  20. PSTATEMGRSTATUS pSMgrStatus
  21. );
  22. BOOL
  23. FormatMessageString(
  24. UINT idTemplate,
  25. LPTSTR pszStrOut,
  26. DWORD cchSize,
  27. ...
  28. )
  29. {
  30. BOOL fResult = FALSE;
  31. va_list vaParamList;
  32. TCHAR szFormat[1024];
  33. if (LoadString(hNewDev, idTemplate, szFormat, ARRAYSIZE(szFormat)))
  34. {
  35. va_start(vaParamList, cchSize);
  36. fResult = FormatMessage(FORMAT_MESSAGE_FROM_STRING, szFormat, 0, 0, pszStrOut, cchSize, &vaParamList);
  37. va_end(vaParamList);
  38. }
  39. return fResult;
  40. }
  41. void
  42. OffsetWindow(
  43. HWND hwnd,
  44. int dx,
  45. int dy
  46. )
  47. {
  48. RECT rc;
  49. GetWindowRect(hwnd, &rc);
  50. MapWindowPoints(NULL, GetParent(hwnd), (LPPOINT)&rc, 2);
  51. OffsetRect(&rc, dx, dy);
  52. SetWindowPos(hwnd, NULL, rc.left, rc.top, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
  53. }
  54. PTCHAR
  55. BuildFriendlyName(
  56. DEVINST DevInst,
  57. BOOL UseNewDeviceDesc,
  58. HMACHINE hMachine
  59. )
  60. {
  61. PTCHAR Location;
  62. PTCHAR FriendlyName;
  63. CONFIGRET ConfigRet = CR_SUCCESS;
  64. ULONG ulSize;
  65. TCHAR szBuffer[MAX_PATH];
  66. *szBuffer = TEXT('\0');
  67. //
  68. // Try the registry for NewDeviceDesc
  69. //
  70. if (UseNewDeviceDesc) {
  71. HKEY hKey;
  72. DWORD dwType = REG_SZ;
  73. ConfigRet = CM_Open_DevNode_Key(DevInst,
  74. KEY_READ,
  75. 0,
  76. RegDisposition_OpenExisting,
  77. &hKey,
  78. CM_REGISTRY_HARDWARE
  79. );
  80. if (ConfigRet == CR_SUCCESS) {
  81. ulSize = sizeof(szBuffer);
  82. RegQueryValueEx(hKey,
  83. REGSTR_VAL_NEW_DEVICE_DESC,
  84. NULL,
  85. &dwType,
  86. (LPBYTE)szBuffer,
  87. &ulSize
  88. );
  89. RegCloseKey(hKey);
  90. }
  91. }
  92. if (ConfigRet != CR_SUCCESS || !*szBuffer) {
  93. //
  94. // Try the registry for FRIENDLYNAME
  95. //
  96. ulSize = sizeof(szBuffer);
  97. ConfigRet = CM_Get_DevNode_Registry_Property_Ex(DevInst,
  98. CM_DRP_FRIENDLYNAME,
  99. NULL,
  100. szBuffer,
  101. &ulSize,
  102. 0,
  103. hMachine
  104. );
  105. if (ConfigRet != CR_SUCCESS || !*szBuffer) {
  106. //
  107. // Try the registry for DEVICEDESC
  108. //
  109. ulSize = sizeof(szBuffer);
  110. ConfigRet = CM_Get_DevNode_Registry_Property_Ex(DevInst,
  111. CM_DRP_DEVICEDESC,
  112. NULL,
  113. szBuffer,
  114. &ulSize,
  115. 0,
  116. hMachine
  117. );
  118. if (ConfigRet != CR_SUCCESS || !*szBuffer) {
  119. GUID ClassGuid;
  120. //
  121. // Initialize ClassGuid to GUID_NULL
  122. //
  123. CopyMemory(&ClassGuid,
  124. &GUID_NULL,
  125. sizeof(GUID)
  126. );
  127. //
  128. // Try the registry for CLASSNAME
  129. //
  130. ulSize = sizeof(szBuffer);
  131. ConfigRet = CM_Get_DevNode_Registry_Property_Ex(DevInst,
  132. CM_DRP_CLASSGUID,
  133. NULL,
  134. szBuffer,
  135. &ulSize,
  136. 0,
  137. hMachine
  138. );
  139. if (ConfigRet == CR_SUCCESS) {
  140. pSetupGuidFromString(szBuffer, &ClassGuid);
  141. }
  142. if (!IsEqualGUID(&ClassGuid, &GUID_NULL) &&
  143. !IsEqualGUID(&ClassGuid, &GUID_DEVCLASS_UNKNOWN))
  144. {
  145. ulSize = sizeof(szBuffer);
  146. ConfigRet = CM_Get_DevNode_Registry_Property_Ex(DevInst,
  147. CM_DRP_CLASS,
  148. NULL,
  149. szBuffer,
  150. &ulSize,
  151. 0,
  152. hMachine
  153. );
  154. }
  155. else {
  156. ConfigRet = ~CR_SUCCESS;
  157. }
  158. }
  159. }
  160. }
  161. if (ConfigRet == CR_SUCCESS && *szBuffer) {
  162. FriendlyName = LocalAlloc(LPTR, ulSize);
  163. if (FriendlyName) {
  164. memcpy(FriendlyName, szBuffer, ulSize);
  165. }
  166. }
  167. else {
  168. FriendlyName = NULL;
  169. }
  170. return FriendlyName;
  171. }
  172. /* ----------------------------------------------------------------------
  173. * SetDlgText - Set Dialog Text Field
  174. *
  175. * Concatenates a number of string resources and does a SetWindowText()
  176. * for a dialog text control.
  177. *
  178. * Parameters:
  179. *
  180. * hDlg - Dialog handle
  181. * iControl - Dialog control ID to receive text
  182. * nStartString - ID of first string resource to concatenate
  183. * nEndString - ID of last string resource to concatenate
  184. *
  185. * Note: the string IDs must be consecutive.
  186. */
  187. void
  188. SetDlgText(HWND hDlg, int iControl, int nStartString, int nEndString)
  189. {
  190. int iX;
  191. TCHAR szText[SDT_MAX_TEXT];
  192. szText[0] = '\0';
  193. for (iX = nStartString; iX<= nEndString; iX++) {
  194. LoadString(hNewDev,
  195. iX,
  196. szText + lstrlen(szText),
  197. sizeof(szText)/sizeof(TCHAR) - lstrlen(szText)
  198. );
  199. }
  200. if (iControl) {
  201. SetDlgItemText(hDlg, iControl, szText);
  202. } else {
  203. SetWindowText(hDlg, szText);
  204. }
  205. }
  206. void
  207. LoadText(PTCHAR szText, int SizeText, int nStartString, int nEndString)
  208. {
  209. int iX;
  210. for (iX = nStartString; iX<= nEndString; iX++) {
  211. LoadString(hNewDev,
  212. iX,
  213. szText + lstrlen(szText),
  214. SizeText/sizeof(TCHAR) - lstrlen(szText)
  215. );
  216. }
  217. return;
  218. }
  219. VOID
  220. _OnSysColorChange(
  221. HWND hWnd,
  222. WPARAM wParam,
  223. LPARAM lParam
  224. )
  225. {
  226. HWND hChildWnd;
  227. hChildWnd = GetWindow(hWnd, GW_CHILD);
  228. while (hChildWnd != NULL) {
  229. SendMessage(hChildWnd, WM_SYSCOLORCHANGE, wParam, lParam);
  230. hChildWnd = GetWindow(hChildWnd, GW_HWNDNEXT);
  231. }
  232. }
  233. BOOL
  234. NoPrivilegeWarning(
  235. HWND hWnd
  236. )
  237. /*++
  238. This function checks to see if the user has Administrator privileges.
  239. If the user does NOT have this administrator privilege then a warning is displayed telling
  240. them that they have insufficient privileges to install hardware on this machine.
  241. Arguments
  242. hWnd - Parent window handle
  243. Return Value:
  244. TRUE if the user does NOT have Administrator privileges and
  245. FALSE if the user does have this privilege
  246. --*/
  247. {
  248. TCHAR szMsg[MAX_PATH];
  249. TCHAR szCaption[MAX_PATH];
  250. if (!pSetupIsUserAdmin()) {
  251. if (LoadString(hNewDev,
  252. IDS_NDW_NOTADMIN,
  253. szMsg,
  254. MAX_PATH)
  255. &&
  256. LoadString(hNewDev,
  257. IDS_NEWDEVICENAME,
  258. szCaption,
  259. MAX_PATH))
  260. {
  261. MessageBox(hWnd, szMsg, szCaption, MB_OK | MB_ICONEXCLAMATION);
  262. }
  263. return TRUE;
  264. }
  265. return FALSE;
  266. }
  267. LONG
  268. NdwBuildClassInfoList(
  269. PNEWDEVWIZ NewDevWiz,
  270. DWORD ClassListFlags
  271. )
  272. {
  273. LONG Error;
  274. //
  275. // Build the class info list
  276. //
  277. while (!SetupDiBuildClassInfoList(ClassListFlags,
  278. NewDevWiz->ClassGuidList,
  279. NewDevWiz->ClassGuidSize,
  280. &NewDevWiz->ClassGuidNum
  281. ))
  282. {
  283. Error = GetLastError();
  284. if (NewDevWiz->ClassGuidList) {
  285. LocalFree(NewDevWiz->ClassGuidList);
  286. NewDevWiz->ClassGuidList = NULL;
  287. }
  288. if (Error == ERROR_INSUFFICIENT_BUFFER &&
  289. NewDevWiz->ClassGuidNum > NewDevWiz->ClassGuidSize)
  290. {
  291. NewDevWiz->ClassGuidList = LocalAlloc(LPTR, NewDevWiz->ClassGuidNum*sizeof(GUID));
  292. if (!NewDevWiz->ClassGuidList) {
  293. NewDevWiz->ClassGuidSize = 0;
  294. NewDevWiz->ClassGuidNum = 0;
  295. return ERROR_NOT_ENOUGH_MEMORY;
  296. }
  297. NewDevWiz->ClassGuidSize = NewDevWiz->ClassGuidNum;
  298. } else {
  299. if (NewDevWiz->ClassGuidList) {
  300. LocalFree(NewDevWiz->ClassGuidList);
  301. }
  302. NewDevWiz->ClassGuidSize = 0;
  303. NewDevWiz->ClassGuidNum = 0;
  304. return Error;
  305. }
  306. }
  307. return ERROR_SUCCESS;
  308. }
  309. void
  310. HideWindowByMove(
  311. HWND hDlg
  312. )
  313. {
  314. RECT rect;
  315. //
  316. // Move the window offscreen, using the virtual coords for Upper Left Corner
  317. //
  318. GetWindowRect(hDlg, &rect);
  319. MoveWindow(hDlg,
  320. GetSystemMetrics(SM_XVIRTUALSCREEN),
  321. GetSystemMetrics(SM_YVIRTUALSCREEN) - (rect.bottom - rect.top),
  322. rect.right - rect.left,
  323. rect.bottom - rect.top,
  324. TRUE
  325. );
  326. }
  327. LONG
  328. NdwUnhandledExceptionFilter(
  329. struct _EXCEPTION_POINTERS *ExceptionPointers
  330. )
  331. {
  332. LONG lRet;
  333. BOOL BeingDebugged;
  334. lRet = UnhandledExceptionFilter(ExceptionPointers);
  335. BeingDebugged = IsDebuggerPresent();
  336. //
  337. // Normal code path is to handle the exception.
  338. // However, if a debugger is present, and the system's unhandled
  339. // exception filter returns continue search, we let it go
  340. // thru to allow the debugger a chance at it.
  341. //
  342. if (lRet == EXCEPTION_CONTINUE_SEARCH && !BeingDebugged) {
  343. lRet = EXCEPTION_EXECUTE_HANDLER;
  344. }
  345. return lRet;
  346. }
  347. BOOL
  348. SetClassGuid(
  349. HDEVINFO hDeviceInfo,
  350. PSP_DEVINFO_DATA DeviceInfoData,
  351. LPGUID ClassGuid
  352. )
  353. {
  354. TCHAR ClassGuidString[MAX_GUID_STRING_LEN];
  355. pSetupStringFromGuid(ClassGuid,
  356. ClassGuidString,
  357. sizeof(ClassGuidString)/sizeof(TCHAR)
  358. );
  359. return SetupDiSetDeviceRegistryProperty(hDeviceInfo,
  360. DeviceInfoData,
  361. SPDRP_CLASSGUID,
  362. (LPBYTE)ClassGuidString,
  363. MAX_GUID_STRING_LEN * sizeof(TCHAR)
  364. );
  365. }
  366. HPROPSHEETPAGE
  367. CreateWizExtPage(
  368. int PageResourceId,
  369. DLGPROC pfnDlgProc,
  370. PNEWDEVWIZ NewDevWiz
  371. )
  372. {
  373. PROPSHEETPAGE psp;
  374. memset(&psp, 0, sizeof(PROPSHEETPAGE));
  375. psp.dwSize = sizeof(PROPSHEETPAGE);
  376. psp.dwFlags = PSP_DEFAULT;
  377. psp.hInstance = hNewDev;
  378. psp.lParam = (LPARAM)NewDevWiz;
  379. psp.pszTemplate = MAKEINTRESOURCE(PageResourceId);
  380. psp.pfnDlgProc = pfnDlgProc;
  381. return CreatePropertySheetPage(&psp);
  382. }
  383. BOOL
  384. AddClassWizExtPages(
  385. HWND hwndParentDlg,
  386. PNEWDEVWIZ NewDevWiz,
  387. PSP_NEWDEVICEWIZARD_DATA DeviceWizardData,
  388. DI_FUNCTION InstallFunction,
  389. HPROPSHEETPAGE hIntroPage
  390. )
  391. {
  392. DWORD NumPages;
  393. BOOL bRet = FALSE;
  394. //
  395. // If this is not a manual install, then only the DIF_NEWDEVICEWIZARD_FINISHINSTALL
  396. // wizard is valid.
  397. //
  398. if (!(NewDevWiz->Flags & IDI_FLAG_MANUALINSTALL) &&
  399. (DIF_NEWDEVICEWIZARD_FINISHINSTALL != InstallFunction)) {
  400. return FALSE;
  401. }
  402. memset(DeviceWizardData, 0, sizeof(SP_NEWDEVICEWIZARD_DATA));
  403. DeviceWizardData->ClassInstallHeader.InstallFunction = InstallFunction;
  404. DeviceWizardData->ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
  405. DeviceWizardData->hwndWizardDlg = hwndParentDlg;
  406. if (SetupDiSetClassInstallParams(NewDevWiz->hDeviceInfo,
  407. &NewDevWiz->DeviceInfoData,
  408. &DeviceWizardData->ClassInstallHeader,
  409. sizeof(SP_NEWDEVICEWIZARD_DATA)
  410. )
  411. &&
  412. (SetupDiCallClassInstaller(InstallFunction,
  413. NewDevWiz->hDeviceInfo,
  414. &NewDevWiz->DeviceInfoData
  415. )
  416. ||
  417. (ERROR_DI_DO_DEFAULT == GetLastError()))
  418. &&
  419. SetupDiGetClassInstallParams(NewDevWiz->hDeviceInfo,
  420. &NewDevWiz->DeviceInfoData,
  421. &DeviceWizardData->ClassInstallHeader,
  422. sizeof(SP_NEWDEVICEWIZARD_DATA),
  423. NULL
  424. )
  425. &&
  426. DeviceWizardData->NumDynamicPages)
  427. {
  428. //
  429. // If this is not a IDI_FLAG_NONINTERACTIVE install and we were given a intro
  430. // page then add it first.
  431. //
  432. PropSheet_AddPage(hwndParentDlg, hIntroPage);
  433. for (NumPages = 0; NumPages < DeviceWizardData->NumDynamicPages; NumPages++) {
  434. //
  435. // If this is a IDI_FLAG_NONINTERACTIVE install then we will destory the property
  436. // sheet pages since we can't display them, otherwise we will add them
  437. // to the wizard.
  438. //
  439. if (NewDevWiz->Flags & IDI_FLAG_NONINTERACTIVE) {
  440. DestroyPropertySheetPage(DeviceWizardData->DynamicPages[NumPages]);
  441. } else {
  442. PropSheet_AddPage(hwndParentDlg, DeviceWizardData->DynamicPages[NumPages]);
  443. }
  444. }
  445. //
  446. // If class/co-installers said they had pages to display then we always return TRUE,
  447. // regardless of if we actually added those pages to the wizard or not.
  448. //
  449. bRet = TRUE;
  450. }
  451. //
  452. // Clear the class install parameters.
  453. //
  454. SetupDiSetClassInstallParams(NewDevWiz->hDeviceInfo,
  455. &NewDevWiz->DeviceInfoData,
  456. NULL,
  457. 0
  458. );
  459. return bRet;
  460. }
  461. void
  462. RemoveClassWizExtPages(
  463. HWND hwndParentDlg,
  464. PSP_NEWDEVICEWIZARD_DATA DeviceWizardData
  465. )
  466. {
  467. DWORD NumPages;
  468. NumPages = DeviceWizardData->NumDynamicPages;
  469. while (NumPages--) {
  470. PropSheet_RemovePage(hwndParentDlg,
  471. (WPARAM)-1,
  472. DeviceWizardData->DynamicPages[NumPages]
  473. );
  474. }
  475. memset(DeviceWizardData, 0, sizeof(SP_NEWDEVICEWIZARD_DATA));
  476. return;
  477. }
  478. BOOL
  479. FileExists(
  480. IN PCTSTR FileName,
  481. OUT PWIN32_FIND_DATA FindData OPTIONAL
  482. )
  483. /*++
  484. Routine Description:
  485. Determine if a file exists and is accessible.
  486. Errormode is set (and then restored) so the user will not see
  487. any pop-ups.
  488. Arguments:
  489. FileName - supplies full path of file to check for existance.
  490. FindData - if specified, receives find data for the file.
  491. Return Value:
  492. TRUE if the file exists and is accessible.
  493. FALSE if not. GetLastError() returns extended error info.
  494. --*/
  495. {
  496. WIN32_FIND_DATA findData;
  497. HANDLE FindHandle;
  498. UINT OldMode;
  499. DWORD Error;
  500. OldMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  501. FindHandle = FindFirstFile(FileName, &findData);
  502. if(FindHandle == INVALID_HANDLE_VALUE) {
  503. Error = GetLastError();
  504. } else {
  505. FindClose(FindHandle);
  506. if(FindData) {
  507. *FindData = findData;
  508. }
  509. Error = NO_ERROR;
  510. }
  511. SetErrorMode(OldMode);
  512. SetLastError(Error);
  513. return (Error == NO_ERROR);
  514. }
  515. BOOL
  516. pVerifyUpdateDriverInfoPath(
  517. PNEWDEVWIZ NewDevWiz
  518. )
  519. /*++
  520. This API will verify that the selected driver node lives in the path
  521. specified in UpdateDriverInfo->InfPathName.
  522. Return Value:
  523. This API will return TRUE in all cases except where we have a valid
  524. UpdateDriverInfo structure and a valid InfPathName field and that
  525. path does not match the path where the selected driver lives.
  526. --*/
  527. {
  528. SP_DRVINFO_DATA DriverInfoData;
  529. SP_DRVINFO_DETAIL_DATA DriverInfoDetailData;
  530. //
  531. // If we don't have a UpdateDriverInfo structure or a valid InfPathName field
  532. // in that structure then just return TRUE now.
  533. //
  534. if (!NewDevWiz->UpdateDriverInfo || !NewDevWiz->UpdateDriverInfo->InfPathName) {
  535. return TRUE;
  536. }
  537. //
  538. // Get the selected driver's path
  539. //
  540. ZeroMemory(&DriverInfoData, sizeof(DriverInfoData));
  541. DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
  542. if (!SetupDiGetSelectedDriver(NewDevWiz->hDeviceInfo,
  543. &NewDevWiz->DeviceInfoData,
  544. &DriverInfoData
  545. )) {
  546. //
  547. // There is no selected driver so just return TRUE
  548. //
  549. return TRUE;
  550. }
  551. DriverInfoDetailData.cbSize = sizeof(DriverInfoDetailData);
  552. if (!SetupDiGetDriverInfoDetail(NewDevWiz->hDeviceInfo,
  553. &NewDevWiz->DeviceInfoData,
  554. &DriverInfoData,
  555. &DriverInfoDetailData,
  556. sizeof(DriverInfoDetailData),
  557. NULL
  558. )
  559. &&
  560. GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
  561. //
  562. // We should never hit this case, but if we have a selected driver and
  563. // we can't get the SP_DRVINFO_DETAIL_DATA that contains the InfFileName
  564. // the return FALSE.
  565. //
  566. return FALSE;
  567. }
  568. if (lstrlen(NewDevWiz->UpdateDriverInfo->InfPathName) ==
  569. lstrlen(DriverInfoDetailData.InfFileName)) {
  570. //
  571. // If the two paths are the same size then we will just compare them
  572. //
  573. return (!lstrcmpi(NewDevWiz->UpdateDriverInfo->InfPathName,
  574. DriverInfoDetailData.InfFileName));
  575. } else {
  576. //
  577. // The two paths are different lengths so we'll tack a trailing backslash
  578. // onto the UpdateDriverInfo->InfPathName and then do a _tcsnicmp
  579. // NOTE that we only tack on a trailing backslash if the length of the
  580. // path is greater than two since it isn't needed on the driver letter
  581. // followed by a colon case (A:).
  582. //
  583. // The reason we do this is we don't want the following case to match
  584. // c:\winnt\in
  585. // c:\winnt\inf\foo.inf
  586. //
  587. TCHAR TempPath[MAX_PATH];
  588. lstrcpy(TempPath, NewDevWiz->UpdateDriverInfo->InfPathName);
  589. if (lstrlen(NewDevWiz->UpdateDriverInfo->InfPathName) > 2) {
  590. lstrcat(TempPath, TEXT("\\"));
  591. }
  592. return (!_tcsnicmp(TempPath,
  593. DriverInfoDetailData.InfFileName,
  594. lstrlen(TempPath)));
  595. }
  596. }
  597. BOOL
  598. ConcatenatePaths(
  599. IN OUT PTSTR Target,
  600. IN PCTSTR Path,
  601. IN UINT TargetBufferSize,
  602. OUT PUINT RequiredSize OPTIONAL
  603. )
  604. /*++
  605. Routine Description:
  606. Concatenate 2 paths, ensuring that one, and only one,
  607. path separator character is introduced at the junction point.
  608. Arguments:
  609. Target - supplies first part of path. Path is appended to this.
  610. Path - supplies path to be concatenated to Target.
  611. TargetBufferSize - supplies the size of the Target buffer,
  612. in characters.
  613. RequiredSize - if specified, receives the number of characters
  614. required to hold the fully concatenated path, including
  615. the terminating nul.
  616. Return Value:
  617. TRUE if the full path fit in Target buffer. Otherwise the path
  618. will have been truncated.
  619. --*/
  620. {
  621. UINT TargetLength,PathLength;
  622. BOOL TrailingBackslash,LeadingBackslash;
  623. UINT EndingLength;
  624. TargetLength = lstrlen(Target);
  625. PathLength = lstrlen(Path);
  626. //
  627. // See whether the target has a trailing backslash.
  628. //
  629. if(TargetLength && (*CharPrev(Target,Target+TargetLength) == TEXT('\\'))) {
  630. TrailingBackslash = TRUE;
  631. TargetLength--;
  632. } else {
  633. TrailingBackslash = FALSE;
  634. }
  635. //
  636. // See whether the path has a leading backshash.
  637. //
  638. if(Path[0] == TEXT('\\')) {
  639. LeadingBackslash = TRUE;
  640. PathLength--;
  641. } else {
  642. LeadingBackslash = FALSE;
  643. }
  644. //
  645. // Calculate the ending length, which is equal to the sum of
  646. // the length of the two strings modulo leading/trailing
  647. // backslashes, plus one path separator, plus a nul.
  648. //
  649. EndingLength = TargetLength + PathLength + 2;
  650. if(RequiredSize) {
  651. *RequiredSize = EndingLength;
  652. }
  653. if(!LeadingBackslash && (TargetLength < TargetBufferSize)) {
  654. Target[TargetLength++] = TEXT('\\');
  655. }
  656. if(TargetBufferSize > TargetLength) {
  657. lstrcpyn(Target+TargetLength,Path,TargetBufferSize-TargetLength);
  658. }
  659. //
  660. // Make sure the buffer is nul terminated in all cases.
  661. //
  662. if (TargetBufferSize) {
  663. Target[TargetBufferSize-1] = 0;
  664. }
  665. return(EndingLength <= TargetBufferSize);
  666. }
  667. BOOL
  668. RemoveDir(
  669. PTSTR Path
  670. )
  671. /*++
  672. Routine Description:
  673. This routine recursively deletes the specified directory and all the
  674. files in it.
  675. Arguments:
  676. Path - Path to remove.
  677. Return Value:
  678. TRUE - if the directory was sucessfully deleted.
  679. FALSE - if the directory was not successfully deleted.
  680. --*/
  681. {
  682. WIN32_FIND_DATA FindFileData;
  683. HANDLE hFind;
  684. BOOL bFind = TRUE;
  685. BOOL Ret = TRUE;
  686. TCHAR szTemp[MAX_PATH];
  687. TCHAR FindPath[MAX_PATH];
  688. DWORD dwAttributes;
  689. //
  690. //If this is a directory then tack on *.* to the end of the path
  691. //
  692. lstrcpyn(FindPath, Path, MAX_PATH);
  693. dwAttributes = GetFileAttributes(Path);
  694. if (dwAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  695. ConcatenatePaths(FindPath,TEXT("*.*"),MAX_PATH,NULL);
  696. }
  697. hFind = FindFirstFile(FindPath, &FindFileData);
  698. while (hFind != INVALID_HANDLE_VALUE && bFind == TRUE) {
  699. lstrcpyn(szTemp, Path, MAX_PATH);
  700. ConcatenatePaths(szTemp,FindFileData.cFileName,MAX_PATH,NULL);
  701. //
  702. //This is a directory
  703. //
  704. if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
  705. (FindFileData.cFileName[0] != TEXT('.'))) {
  706. if (!RemoveDir(szTemp)) {
  707. Ret = FALSE;
  708. }
  709. RemoveDirectory(szTemp);
  710. }
  711. //
  712. //This is a file
  713. //
  714. else if (!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  715. DeleteFile(szTemp);
  716. }
  717. bFind = FindNextFile(hFind, &FindFileData);
  718. }
  719. FindClose(hFind);
  720. //
  721. //Remove the root directory
  722. //
  723. dwAttributes = GetFileAttributes(Path);
  724. if (dwAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  725. if (!RemoveDirectory(Path)) {
  726. Ret = FALSE;
  727. }
  728. }
  729. return Ret;
  730. }
  731. BOOL
  732. pAToI(
  733. IN PCTSTR Field,
  734. OUT PINT IntegerValue
  735. )
  736. /*++
  737. Routine Description:
  738. Arguments:
  739. Return Value:
  740. Remarks:
  741. Hexadecimal numbers are also supported. They must be prefixed by '0x' or '0X', with no
  742. space allowed between the prefix and the number.
  743. --*/
  744. {
  745. INT Value;
  746. UINT c;
  747. BOOL Neg;
  748. UINT Base;
  749. UINT NextDigitValue;
  750. INT OverflowCheck;
  751. BOOL b;
  752. if(!Field) {
  753. SetLastError(ERROR_INVALID_PARAMETER);
  754. return(FALSE);
  755. }
  756. if(*Field == TEXT('-')) {
  757. Neg = TRUE;
  758. Field++;
  759. } else {
  760. Neg = FALSE;
  761. if(*Field == TEXT('+')) {
  762. Field++;
  763. }
  764. }
  765. if((*Field == TEXT('0')) &&
  766. ((*(Field+1) == TEXT('x')) || (*(Field+1) == TEXT('X')))) {
  767. //
  768. // The number is in hexadecimal.
  769. //
  770. Base = 16;
  771. Field += 2;
  772. } else {
  773. //
  774. // The number is in decimal.
  775. //
  776. Base = 10;
  777. }
  778. for(OverflowCheck = Value = 0; *Field; Field++) {
  779. c = (UINT)*Field;
  780. if((c >= (UINT)'0') && (c <= (UINT)'9')) {
  781. NextDigitValue = c - (UINT)'0';
  782. } else if(Base == 16) {
  783. if((c >= (UINT)'a') && (c <= (UINT)'f')) {
  784. NextDigitValue = (c - (UINT)'a') + 10;
  785. } else if ((c >= (UINT)'A') && (c <= (UINT)'F')) {
  786. NextDigitValue = (c - (UINT)'A') + 10;
  787. } else {
  788. break;
  789. }
  790. } else {
  791. break;
  792. }
  793. Value *= Base;
  794. Value += NextDigitValue;
  795. //
  796. // Check for overflow. For decimal numbers, we check to see whether the
  797. // new value has overflowed into the sign bit (i.e., is less than the
  798. // previous value. For hexadecimal numbers, we check to make sure we
  799. // haven't gotten more digits than will fit in a DWORD.
  800. //
  801. if(Base == 16) {
  802. if(++OverflowCheck > (sizeof(INT) * 2)) {
  803. break;
  804. }
  805. } else {
  806. if(Value < OverflowCheck) {
  807. break;
  808. } else {
  809. OverflowCheck = Value;
  810. }
  811. }
  812. }
  813. if(*Field) {
  814. SetLastError(ERROR_INVALID_DATA);
  815. return(FALSE);
  816. }
  817. if(Neg) {
  818. Value = 0-Value;
  819. }
  820. b = TRUE;
  821. try {
  822. *IntegerValue = Value;
  823. } except(EXCEPTION_EXECUTE_HANDLER) {
  824. b = FALSE;
  825. }
  826. if(!b) {
  827. SetLastError(ERROR_INVALID_PARAMETER);
  828. }
  829. return(b);
  830. }
  831. RemoveCdmDirectory(
  832. PTSTR CdmDirectory
  833. )
  834. {
  835. TCHAR ReinstallBackupDirectory[MAX_PATH];
  836. //
  837. // First verify that this directory is a subdirectory of %windir%\system32\ReinstallBackups
  838. //
  839. if (GetSystemDirectory(ReinstallBackupDirectory, SIZECHARS(ReinstallBackupDirectory))) {
  840. ConcatenatePaths(ReinstallBackupDirectory, TEXT("ReinstallBackups"), MAX_PATH, NULL);
  841. do {
  842. PTSTR p = _tcsrchr(CdmDirectory, TEXT('\\'));
  843. if (!p) {
  844. break;
  845. }
  846. *p = 0;
  847. if (_tcsnicmp(CdmDirectory,
  848. ReinstallBackupDirectory,
  849. lstrlen(ReinstallBackupDirectory))) {
  850. //
  851. // This is not a subdirectory of the ReinstallBackups directory, so don't
  852. // delete it!
  853. //
  854. break;
  855. }
  856. if (!lstrcmpi(CdmDirectory,
  857. ReinstallBackupDirectory)) {
  858. //
  859. // We have reached the actuall ReinstallBackups directory so stop deleting!
  860. //
  861. break;
  862. }
  863. } while (RemoveDir(CdmDirectory));
  864. }
  865. }
  866. BOOL
  867. pSetupGetDriverDate(
  868. IN PCTSTR DriverVer,
  869. IN OUT PFILETIME pFileTime
  870. )
  871. /*++
  872. Routine Description:
  873. Retreive the date from a DriverVer string.
  874. The Date specified in DriverVer string has the following format:
  875. DriverVer=xx/yy/zzzz
  876. or
  877. DriverVer=xx-yy-zzzz
  878. where xx is the month, yy is the day, and zzzz is the for digit year.
  879. Note that the year MUST be 4 digits. A year of 98 will be considered
  880. 0098 and not 1998!
  881. This date should be the date of the Drivers and not for the INF itself.
  882. So a single INF can have multiple driver install Sections and each can
  883. have different dates depending on when the driver was last updated.
  884. Arguments:
  885. DriverVer - String that holds the DriverVer entry from an INF file.
  886. pFileTime - points to a FILETIME structure that will receive the Date,
  887. if it exists.
  888. Return Value:
  889. BOOL. TRUE if a valid date existed in the specified string and FALSE otherwise.
  890. --*/
  891. {
  892. SYSTEMTIME SystemTime;
  893. TCHAR DriverDate[LINE_LEN];
  894. PTSTR Convert, Temp;
  895. DWORD Value;
  896. if (!DriverVer) {
  897. SetLastError(ERROR_INVALID_PARAMETER);
  898. return FALSE;
  899. }
  900. try {
  901. *DriverDate = 0;
  902. ZeroMemory(&SystemTime, sizeof(SYSTEMTIME));
  903. pFileTime->dwLowDateTime = 0;
  904. pFileTime->dwHighDateTime = 0;
  905. //
  906. // First copy just the DriverDate portion of the DriverVer into the DriverDate
  907. // variable. The DriverDate should be everything before the first comma.
  908. //
  909. lstrcpy(DriverDate, DriverVer);
  910. Temp = DriverDate;
  911. while (*Temp && (*Temp != TEXT(','))) {
  912. Temp++;
  913. }
  914. if (*Temp) {
  915. *Temp = TEXT('\0');
  916. }
  917. Convert = DriverDate;
  918. if (*Convert) {
  919. Temp = DriverDate;
  920. while (*Temp && (*Temp != TEXT('-')) && (*Temp != TEXT('/')))
  921. Temp++;
  922. *Temp = 0;
  923. //
  924. //Convert the month
  925. //
  926. pAToI(Convert, (PINT)&Value);
  927. SystemTime.wMonth = LOWORD(Value);
  928. Convert = Temp+1;
  929. if (*Convert) {
  930. Temp = Convert;
  931. while (*Temp && (*Temp != TEXT('-')) && (*Temp != TEXT('/')))
  932. Temp++;
  933. *Temp = 0;
  934. //
  935. //Convert the day
  936. //
  937. pAToI(Convert, (PINT)&Value);
  938. SystemTime.wDay = LOWORD(Value);
  939. Convert = Temp+1;
  940. if (*Convert) {
  941. //
  942. //Convert the year
  943. //
  944. pAToI(Convert, (PINT)&Value);
  945. SystemTime.wYear = LOWORD(Value);
  946. //
  947. //Convert SYSTEMTIME into FILETIME
  948. //
  949. SystemTimeToFileTime(&SystemTime, pFileTime);
  950. }
  951. }
  952. }
  953. } except(EXCEPTION_EXECUTE_HANDLER) {
  954. SetLastError(ERROR_INVALID_PARAMETER);
  955. return FALSE;
  956. }
  957. SetLastError(NO_ERROR);
  958. return((pFileTime->dwLowDateTime != 0) || (pFileTime->dwHighDateTime != 0));
  959. }
  960. BOOL
  961. IsInternetAvailable(
  962. HMODULE *hCdmInstance
  963. )
  964. {
  965. OSVERSIONINFOEX info;
  966. CDM_INTERNET_AVAILABLE_PROC pfnCDMInternetAvailable;
  967. if (!hCdmInstance) {
  968. return FALSE;
  969. }
  970. //
  971. // We can't call CDM during GUI setup.
  972. //
  973. if (GuiSetupInProgress) {
  974. return FALSE;
  975. }
  976. //
  977. // Never call CDM if this is DataCenter
  978. //
  979. info.dwOSVersionInfoSize = sizeof(info);
  980. if (GetVersionEx((POSVERSIONINFOW)&info) &&
  981. (info.wSuiteMask & VER_SUITE_DATACENTER)) {
  982. return FALSE;
  983. }
  984. //
  985. // Load CDM.DLL if it is not already loaded
  986. //
  987. if (!(*hCdmInstance)) {
  988. *hCdmInstance = LoadLibrary(TEXT("CDM.DLL"));
  989. }
  990. pfnCDMInternetAvailable = (CDM_INTERNET_AVAILABLE_PROC)GetProcAddress(*hCdmInstance,
  991. "DownloadIsInternetAvailable"
  992. );
  993. if (!pfnCDMInternetAvailable) {
  994. return FALSE;
  995. }
  996. return pfnCDMInternetAvailable();
  997. }
  998. BOOL
  999. GetLogPnPIdPolicy(
  1000. )
  1001. /*++
  1002. Routine Description:
  1003. This function checks the policy portion of the registry to see if the user wants
  1004. us to log the Hardware Id for devices that we cannot find drivers for.
  1005. Arguments:
  1006. none
  1007. Return Value:
  1008. BOOL - TRUE if we can log the Hardware Id and FALSE if the policy tells us not
  1009. to log the hardware Id.
  1010. --*/
  1011. {
  1012. HKEY hKey;
  1013. DWORD LogPnPIdPolicy;
  1014. ULONG cbData;
  1015. BOOL bLogHardwareIds = TRUE;
  1016. OSVERSIONINFOEX info;
  1017. //
  1018. // If we are in gui-setup then we can't log hardware Ids, so always return
  1019. // FALSE.
  1020. //
  1021. if (GuiSetupInProgress) {
  1022. return FALSE;
  1023. }
  1024. //
  1025. // Never call log Ids on DataCenter
  1026. //
  1027. info.dwOSVersionInfoSize = sizeof(info);
  1028. if (GetVersionEx((POSVERSIONINFOW)&info) &&
  1029. (info.wSuiteMask & VER_SUITE_DATACENTER)) {
  1030. return FALSE;
  1031. }
  1032. if (RegOpenKeyEx(HKEY_CURRENT_USER,
  1033. TEXT("Software\\Policies\\Microsoft\\Windows\\DriverSearching"),
  1034. 0,
  1035. KEY_READ,
  1036. &hKey
  1037. ) == ERROR_SUCCESS) {
  1038. LogPnPIdPolicy = 0;
  1039. cbData = sizeof(LogPnPIdPolicy);
  1040. if ((RegQueryValueEx(hKey,
  1041. TEXT("DontLogHardwareIds"),
  1042. NULL,
  1043. NULL,
  1044. (LPBYTE)&LogPnPIdPolicy,
  1045. &cbData
  1046. ) == ERROR_SUCCESS) &&
  1047. (LogPnPIdPolicy)) {
  1048. bLogHardwareIds = FALSE;
  1049. }
  1050. RegCloseKey(hKey);
  1051. }
  1052. return (bLogHardwareIds);
  1053. }
  1054. void
  1055. CdmLogDriverNotFound(
  1056. HMODULE hCdmInstance,
  1057. HANDLE hContext,
  1058. LPCTSTR DeviceInstanceId,
  1059. DWORD Flags
  1060. )
  1061. {
  1062. LOG_DRIVER_NOT_FOUND_PROC pfnLogDriverNotFound;
  1063. if (!hCdmInstance) {
  1064. return;
  1065. }
  1066. pfnLogDriverNotFound = (LOG_DRIVER_NOT_FOUND_PROC)GetProcAddress(hCdmInstance,
  1067. "LogDriverNotFound"
  1068. );
  1069. if (!pfnLogDriverNotFound) {
  1070. return;
  1071. }
  1072. pfnLogDriverNotFound(hContext, DeviceInstanceId, Flags);
  1073. }
  1074. BOOL
  1075. GetInstalledInf(
  1076. IN DEVNODE DevNode, OPTIONAL
  1077. IN PTSTR DeviceInstanceId, OPTIONAL
  1078. IN OUT PTSTR InfFile,
  1079. IN OUT DWORD *Size
  1080. )
  1081. {
  1082. DEVNODE dn;
  1083. HKEY hKey = INVALID_HANDLE_VALUE;
  1084. DWORD dwType;
  1085. BOOL bSuccess = FALSE;
  1086. if (DevNode != 0) {
  1087. dn = DevNode;
  1088. } else if (CM_Locate_DevNode(&dn, DeviceInstanceId, 0) != CR_SUCCESS) {
  1089. goto clean0;
  1090. }
  1091. //
  1092. // Open the device's driver (software) registry key so we can get the InfPath
  1093. //
  1094. if (CM_Open_DevNode_Key(dn,
  1095. KEY_READ,
  1096. 0,
  1097. RegDisposition_OpenExisting,
  1098. &hKey,
  1099. CM_REGISTRY_SOFTWARE
  1100. ) != CR_SUCCESS) {
  1101. goto clean0;
  1102. }
  1103. if (hKey != INVALID_HANDLE_VALUE) {
  1104. dwType = REG_SZ;
  1105. if (RegQueryValueEx(hKey,
  1106. REGSTR_VAL_INFPATH,
  1107. NULL,
  1108. &dwType,
  1109. (LPBYTE)InfFile,
  1110. Size
  1111. ) == ERROR_SUCCESS) {
  1112. bSuccess = TRUE;
  1113. }
  1114. }
  1115. clean0:
  1116. if (hKey != INVALID_HANDLE_VALUE) {
  1117. RegCloseKey(hKey);
  1118. }
  1119. return bSuccess;
  1120. }
  1121. BOOL
  1122. IsInfFromOem(
  1123. IN PCTSTR InfFile
  1124. )
  1125. /*++
  1126. Routine Description:
  1127. Determine if an Inf is an OEM Inf.
  1128. Arguments:
  1129. InfFile - supplies name of Inf file.
  1130. Return Value:
  1131. BOOL. TRUE if the InfFile is an OEM Inf file, and FALSE otherwise.
  1132. --*/
  1133. {
  1134. PTSTR p;
  1135. //
  1136. // Make sure we are passed a valid Inf file and it's length is at least 8
  1137. // chararacters or more for oemX.inf
  1138. if (!InfFile ||
  1139. (InfFile[0] == TEXT('\0')) ||
  1140. (lstrlen(InfFile) < 8)) {
  1141. return FALSE;
  1142. }
  1143. //
  1144. // First check that the first 3 characters are OEM
  1145. //
  1146. if (_tcsnicmp(InfFile, TEXT("oem"), 3)) {
  1147. return FALSE;
  1148. }
  1149. //
  1150. // Next verify that any characters after "oem" and before ".inf"
  1151. // are digits.
  1152. //
  1153. p = (PTSTR)InfFile;
  1154. p = CharNext(p);
  1155. p = CharNext(p);
  1156. p = CharNext(p);
  1157. while ((*p != TEXT('\0')) && (*p != TEXT('.'))) {
  1158. if ((*p < TEXT('0')) || (*p > TEXT('9'))) {
  1159. return FALSE;
  1160. }
  1161. p = CharNext(p);
  1162. }
  1163. //
  1164. // Finally, verify that the last 4 characters are ".inf"
  1165. //
  1166. if (lstrcmpi(p, TEXT(".inf"))) {
  1167. return FALSE;
  1168. }
  1169. //
  1170. // This is an OEM Inf file
  1171. //
  1172. return TRUE;
  1173. }
  1174. BOOL
  1175. IsConnectedToInternet()
  1176. {
  1177. DWORD dwFlags = INTERNET_CONNECTION_LAN |
  1178. INTERNET_CONNECTION_MODEM |
  1179. INTERNET_CONNECTION_PROXY;
  1180. //
  1181. // If we are in gui-setup then return FALSE since we can't connect to the
  1182. // Internet at this time, and since the network is not fully installed yet
  1183. // bad things can happen when we call Inet APIs.
  1184. //
  1185. if (GuiSetupInProgress) {
  1186. return FALSE;
  1187. }
  1188. return InternetGetConnectedState(&dwFlags, 0);
  1189. }
  1190. DWORD
  1191. GetSearchOptions(
  1192. void
  1193. )
  1194. {
  1195. DWORD SearchOptions = SEARCH_FLOPPY;
  1196. DWORD cbData;
  1197. HKEY hKeyDeviceInstaller;
  1198. if (RegOpenKeyEx(HKEY_CURRENT_USER,
  1199. REGSTR_PATH_DEVICEINSTALLER,
  1200. 0,
  1201. KEY_READ,
  1202. &hKeyDeviceInstaller
  1203. ) == ERROR_SUCCESS) {
  1204. cbData = sizeof(SearchOptions);
  1205. RegQueryValueEx(hKeyDeviceInstaller,
  1206. REGSTR_VAL_SEARCHOPTIONS,
  1207. NULL,
  1208. NULL,
  1209. (LPBYTE)&SearchOptions,
  1210. &cbData
  1211. );
  1212. RegCloseKey(hKeyDeviceInstaller);
  1213. }
  1214. return SearchOptions;
  1215. }
  1216. VOID
  1217. SetSearchOptions(
  1218. DWORD SearchOptions
  1219. )
  1220. {
  1221. HKEY hKeyDeviceInstaller;
  1222. if (RegCreateKeyEx(HKEY_CURRENT_USER,
  1223. REGSTR_PATH_DEVICEINSTALLER,
  1224. 0,
  1225. NULL,
  1226. REG_OPTION_NON_VOLATILE,
  1227. KEY_WRITE,
  1228. NULL,
  1229. &hKeyDeviceInstaller,
  1230. NULL) == ERROR_SUCCESS) {
  1231. RegSetValueEx(hKeyDeviceInstaller,
  1232. REGSTR_VAL_SEARCHOPTIONS,
  1233. 0,
  1234. REG_DWORD,
  1235. (LPBYTE)&SearchOptions,
  1236. sizeof(SearchOptions)
  1237. );
  1238. RegCloseKey(hKeyDeviceInstaller);
  1239. }
  1240. }
  1241. BOOL
  1242. IsInstallComplete(
  1243. HDEVINFO hDevInfo,
  1244. PSP_DEVINFO_DATA DeviceInfoData
  1245. )
  1246. /*++
  1247. Routine Description:
  1248. This routine determines whether the install is complete on the specified
  1249. device or not. If a device has configflags and CONFIGFLAG_REINSTALL and
  1250. CONFIGFLAG_FINISH_INSTALL are not set then the install is considered
  1251. complete.
  1252. This API is needed since we could bring up the Found New Hardware wizard
  1253. for one user and another user can switch away to their session. Umpnpmgr.dll
  1254. will prompt the new user to install drivers as well. If the new user does
  1255. complete the device install then we want the first user's Found New
  1256. Hardware wizard to go away as well.
  1257. Arguments:
  1258. hDevInfo -
  1259. DeviceInfoData -
  1260. Return Value:
  1261. BOOL. TRUE if the installation is complete and FALSE otherwise.
  1262. --*/
  1263. {
  1264. BOOL bDriverInstalled = FALSE;
  1265. DWORD ConfigFlags = 0;
  1266. if (SetupDiGetDeviceRegistryProperty(hDevInfo,
  1267. DeviceInfoData,
  1268. SPDRP_CONFIGFLAGS,
  1269. NULL,
  1270. (PBYTE)&ConfigFlags,
  1271. sizeof(ConfigFlags),
  1272. NULL) &&
  1273. !(ConfigFlags & CONFIGFLAG_REINSTALL) &&
  1274. !(ConfigFlags & CONFIGFLAG_FINISH_INSTALL)) {
  1275. bDriverInstalled = TRUE;
  1276. }
  1277. return bDriverInstalled;
  1278. }
  1279. BOOL
  1280. GetIsWow64 (
  1281. VOID
  1282. )
  1283. /*++
  1284. Routine Description:
  1285. Determine if we're running on WOW64 or not. This will tell us if somebody
  1286. is calling the 32-bit version of newdev.dll on a 64-bit machine.
  1287. We call the GetSystemWow64Directory API, and if it fails and GetLastError()
  1288. returns ERROR_CALL_NOT_IMPLENETED then this means we are on a 32-bit OS.
  1289. Arguments:
  1290. none
  1291. Return value:
  1292. TRUE if running under WOw64 (and special Wow64 features available)
  1293. --*/
  1294. {
  1295. #ifdef _WIN64
  1296. //
  1297. // If this is the 64-bit version of newdev.dll then always return FALSE.
  1298. //
  1299. return FALSE;
  1300. #else
  1301. TCHAR Wow64Directory[MAX_PATH];
  1302. if ((GetSystemWow64Directory(Wow64Directory, SIZECHARS(Wow64Directory)) == 0) &&
  1303. (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)) {
  1304. return FALSE;
  1305. }
  1306. //
  1307. // GetSystemWow64Directory succeeded so we are on a 64-bit OS.
  1308. //
  1309. return TRUE;
  1310. #endif
  1311. }
  1312. BOOL
  1313. OpenCdmContextIfNeeded(
  1314. HMODULE *hCdmInstance,
  1315. HANDLE *hCdmContext
  1316. )
  1317. {
  1318. OPEN_CDM_CONTEXT_EX_PROC pfnOpenCDMContextEx;
  1319. OSVERSIONINFOEX info;
  1320. //
  1321. // We can't load CDM if we are in the gui-setup.
  1322. //
  1323. if (GuiSetupInProgress) {
  1324. return FALSE;
  1325. }
  1326. //
  1327. // Never call CDM if this is DataCenter
  1328. //
  1329. info.dwOSVersionInfoSize = sizeof(info);
  1330. if (GetVersionEx((POSVERSIONINFOW)&info) &&
  1331. (info.wSuiteMask & VER_SUITE_DATACENTER)) {
  1332. return FALSE;
  1333. }
  1334. //
  1335. // First check to see if they are already loaded
  1336. //
  1337. if (*hCdmInstance && *hCdmContext) {
  1338. return TRUE;
  1339. }
  1340. //
  1341. // Load CDM.DLL if it is not already loaded
  1342. //
  1343. if (!(*hCdmInstance)) {
  1344. *hCdmInstance = LoadLibrary(TEXT("CDM.DLL"));
  1345. }
  1346. if (*hCdmInstance) {
  1347. //
  1348. // Get a context handle to Cdm.dll by calling OpenCDMContextEx(FALSE).
  1349. // By passing FALSE we are telling CDM.DLL to not connect to the Internet
  1350. // if there isn't currently a connection.
  1351. //
  1352. if (!(*hCdmContext)) {
  1353. pfnOpenCDMContextEx = (OPEN_CDM_CONTEXT_EX_PROC)GetProcAddress(*hCdmInstance,
  1354. "OpenCDMContextEx"
  1355. );
  1356. if (pfnOpenCDMContextEx) {
  1357. *hCdmContext = pfnOpenCDMContextEx(FALSE);
  1358. }
  1359. }
  1360. }
  1361. if (*hCdmInstance && *hCdmContext) {
  1362. return TRUE;
  1363. } else {
  1364. return FALSE;
  1365. }
  1366. }
  1367. BOOL
  1368. pSetSystemRestorePoint(
  1369. BOOL Begin,
  1370. BOOL CancelOperation,
  1371. int RestorePointResourceId
  1372. )
  1373. {
  1374. RESTOREPOINTINFO RestorePointInfo;
  1375. STATEMGRSTATUS SMgrStatus;
  1376. SRSETRESTOREPOINT pfnSrSetRestorePoint;
  1377. BOOL b = FALSE;
  1378. if (!hSrClientDll) {
  1379. hSrClientDll = LoadLibrary(TEXT("srclient.dll"));
  1380. if (!hSrClientDll) {
  1381. return FALSE;
  1382. }
  1383. }
  1384. pfnSrSetRestorePoint = (SRSETRESTOREPOINT)GetProcAddress(hSrClientDll,
  1385. "SRSetRestorePointW"
  1386. );
  1387. //
  1388. // If we can't get the proc address for SRSetRestorePoint then just
  1389. // free the library.
  1390. //
  1391. if (!pfnSrSetRestorePoint) {
  1392. FreeLibrary(hSrClientDll);
  1393. hSrClientDll = FALSE;
  1394. return FALSE;
  1395. }
  1396. //
  1397. // Set the system restore point.
  1398. //
  1399. RestorePointInfo.dwEventType = Begin
  1400. ? BEGIN_NESTED_SYSTEM_CHANGE
  1401. : END_NESTED_SYSTEM_CHANGE;
  1402. RestorePointInfo.dwRestorePtType = CancelOperation
  1403. ? CANCELLED_OPERATION
  1404. : DEVICE_DRIVER_INSTALL;
  1405. RestorePointInfo.llSequenceNumber = 0;
  1406. if (RestorePointResourceId) {
  1407. if (!LoadString(hNewDev,
  1408. RestorePointResourceId,
  1409. RestorePointInfo.szDescription,
  1410. SIZECHARS(RestorePointInfo.szDescription)
  1411. )) {
  1412. RestorePointInfo.szDescription[0] = TEXT('\0');
  1413. }
  1414. } else {
  1415. RestorePointInfo.szDescription[0] = TEXT('\0');
  1416. }
  1417. b = pfnSrSetRestorePoint(&RestorePointInfo, &SMgrStatus);
  1418. //
  1419. // If we are calling END_NESTED_SYSTEM_CHANGE then unload the srclient.dll
  1420. // since we won't be needing it again.
  1421. //
  1422. if (!Begin) {
  1423. FreeLibrary(hSrClientDll);
  1424. hSrClientDll = FALSE;
  1425. }
  1426. return b;
  1427. }
  1428. BOOL
  1429. GetProcessorExtension(
  1430. LPTSTR ProcessorExtension,
  1431. DWORD ProcessorExtensionSize
  1432. )
  1433. {
  1434. SYSTEM_INFO SystemInfo;
  1435. BOOL bReturn = TRUE;
  1436. ZeroMemory(&SystemInfo, sizeof(SystemInfo));
  1437. GetSystemInfo(&SystemInfo);
  1438. switch(SystemInfo.wProcessorArchitecture) {
  1439. case PROCESSOR_ARCHITECTURE_INTEL:
  1440. lstrcpyn(ProcessorExtension, TEXT("i386"), ProcessorExtensionSize);
  1441. break;
  1442. case PROCESSOR_ARCHITECTURE_IA64:
  1443. lstrcpyn(ProcessorExtension, TEXT("IA64"), ProcessorExtensionSize);
  1444. break;
  1445. case PROCESSOR_ARCHITECTURE_MSIL:
  1446. lstrcpyn(ProcessorExtension, TEXT("MSIL"), ProcessorExtensionSize);
  1447. break;
  1448. case PROCESSOR_ARCHITECTURE_AMD64:
  1449. lstrcpyn(ProcessorExtension, TEXT("AMD64"), ProcessorExtensionSize);
  1450. break;
  1451. default:
  1452. ASSERT(0);
  1453. bReturn = FALSE;
  1454. break;
  1455. }
  1456. return bReturn;
  1457. }
  1458. BOOL
  1459. GetGuiSetupInProgress(
  1460. VOID
  1461. )
  1462. /*++
  1463. Routine Description:
  1464. This routine determines if we're doing a gui-mode setup.
  1465. This value is retrieved from the following registry location:
  1466. \HKLM\System\Setup\
  1467. SystemSetupInProgress : REG_DWORD : 0x00 (where nonzero means we're doing a gui-setup)
  1468. Arguments:
  1469. None.
  1470. Return Value:
  1471. TRUE if we are in gui-mode setup, FALSE otherwise.
  1472. --*/
  1473. {
  1474. HKEY hKey;
  1475. TCHAR CharBuffer[SIZECHARS(REGSTR_PATH_SETUP) - 1 + SIZECHARS(REGSTR_KEY_SETUP)];
  1476. DWORD Err, DataType, DataSize = sizeof(DWORD);
  1477. DWORD Value;
  1478. if((Err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1479. TEXT("System\\Setup"),
  1480. 0,
  1481. KEY_READ,
  1482. &hKey)) == ERROR_SUCCESS) {
  1483. //
  1484. // Attempt to read the the "DriverCachePath" value.
  1485. //
  1486. Err = RegQueryValueEx(
  1487. hKey,
  1488. TEXT("SystemSetupInProgress"),
  1489. NULL,
  1490. &DataType,
  1491. (LPBYTE)&Value,
  1492. &DataSize);
  1493. RegCloseKey(hKey);
  1494. }
  1495. if(Err == NO_ERROR) {
  1496. if(Value) {
  1497. return(TRUE);
  1498. }
  1499. }
  1500. return(FALSE);
  1501. }
  1502. DWORD
  1503. GetBusInformation(
  1504. DEVNODE DevNode
  1505. )
  1506. /*++
  1507. Routine Description:
  1508. This routine retrieves the bus information flags.
  1509. Arguments:
  1510. DeviceInfoSet -
  1511. DeviceInfoData -
  1512. Return Value:
  1513. DWORD that contains the bus information flags.
  1514. --*/
  1515. {
  1516. GUID BusTypeGuid;
  1517. TCHAR BusTypeGuidString[MAX_GUID_STRING_LEN];
  1518. HKEY hBusInformationKey;
  1519. DWORD BusInformation = 0;
  1520. DWORD dwType, cbData;
  1521. //
  1522. // Get the bus type GUID for this device.
  1523. //
  1524. cbData = sizeof(BusTypeGuid);
  1525. if (CM_Get_DevNode_Registry_Property(DevNode,
  1526. CM_DRP_BUSTYPEGUID,
  1527. &dwType,
  1528. (PVOID)&BusTypeGuid,
  1529. &cbData,
  1530. 0) != CR_SUCCESS) {
  1531. goto clean0;
  1532. }
  1533. //
  1534. // Convert the bus type GUID into a string.
  1535. //
  1536. if (pSetupStringFromGuid(&BusTypeGuid,
  1537. BusTypeGuidString,
  1538. sizeof(BusTypeGuidString)/sizeof(TCHAR)
  1539. ) != NO_ERROR) {
  1540. goto clean0;
  1541. }
  1542. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1543. REGSTR_PATH_BUSINFORMATION,
  1544. 0,
  1545. KEY_READ,
  1546. &hBusInformationKey
  1547. ) != ERROR_SUCCESS) {
  1548. goto clean0;
  1549. }
  1550. cbData = sizeof(BusInformation);
  1551. RegQueryValueEx(hBusInformationKey,
  1552. BusTypeGuidString,
  1553. NULL,
  1554. &dwType,
  1555. (LPBYTE)&BusInformation,
  1556. &cbData);
  1557. RegCloseKey(hBusInformationKey);
  1558. clean0:
  1559. return BusInformation;
  1560. }
  1561. void
  1562. CdmCancelCDMOperation(
  1563. HMODULE hCdmInstance
  1564. )
  1565. {
  1566. CANCEL_CDM_OPERATION_PROC pfnCancelCDMOperation;
  1567. if (!hCdmInstance) {
  1568. return;
  1569. }
  1570. pfnCancelCDMOperation = (CANCEL_CDM_OPERATION_PROC)GetProcAddress(hCdmInstance,
  1571. "CancelCDMOperation"
  1572. );
  1573. if (!pfnCancelCDMOperation) {
  1574. return;
  1575. }
  1576. pfnCancelCDMOperation();
  1577. }