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.

927 lines
27 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. efinvram.cpp
  5. Abstract:
  6. Tool that allows you to edit/view EFI
  7. nvram entries.
  8. Author:
  9. Vijay Jayaseelan (vijayj) 02-Feb-2001
  10. Revision History:
  11. None
  12. --*/
  13. extern "C" {
  14. #include <efisbent.h>
  15. #include <setupapi.h>
  16. }
  17. #include <iostream>
  18. #include <string>
  19. #include <exception>
  20. #include <windows.h>
  21. #include <tchar.h>
  22. #include <locale>
  23. #include "msg.h"
  24. #include <libmsg.h>
  25. #define MSFT_PREFIX L"Microsoft "
  26. #define DEFAULT_NAME L"Windows"
  27. #define DEFAULT_TIMEOUT 30
  28. //
  29. // Global variables used to get formatted message for this program.
  30. //
  31. HMODULE ThisModule = NULL;
  32. WCHAR Message[4096];
  33. //
  34. // function prototypes
  35. //
  36. NTSTATUS
  37. QueryCanonicalName(
  38. IN PCWSTR Name,
  39. IN ULONG MaxDepth,
  40. OUT PWSTR CanonicalName,
  41. IN ULONG SizeOfBufferInBytes
  42. );
  43. VOID
  44. GetFriendlyName(
  45. IN const std::wstring &InfFileName,
  46. OUT std::wstring &Buffer
  47. );
  48. //
  49. // Helper dump operators
  50. //
  51. std::ostream& operator<<(std::ostream &os, const std::wstring &str) {
  52. FILE *OutStream = (&os == &std::cerr) ? stderr : stdout;
  53. fwprintf(OutStream, (PWSTR)str.c_str());
  54. return os;
  55. }
  56. //
  57. // Helper dump operators
  58. //
  59. std::ostream& operator<<(std::ostream &os, WCHAR *Str) {
  60. std::wstring WStr = Str;
  61. os << WStr;
  62. return os;
  63. }
  64. PWSTR GetOptionKey(ULONG MsgId) {
  65. Message[0] = TEXT('\0');
  66. GetFormattedMessage(ThisModule,
  67. FALSE,
  68. Message,
  69. sizeof(Message)/sizeof(Message[0]),
  70. MsgId);
  71. return Message;
  72. }
  73. //
  74. // Exceptions
  75. //
  76. struct ProgramException : public std::exception {
  77. virtual void Dump(std::ostream &os) = 0;
  78. };
  79. //
  80. // Abstracts a Win32 error
  81. //
  82. struct W32Error : public ProgramException {
  83. DWORD ErrorCode;
  84. W32Error(DWORD ErrCode = GetLastError()) : ErrorCode(ErrCode){}
  85. void Dump(std::ostream &os) {
  86. WCHAR MsgBuffer[4096];
  87. MsgBuffer[0] = UNICODE_NULL;
  88. if (GetFormattedMessage(ThisModule,
  89. TRUE,
  90. MsgBuffer,
  91. sizeof(MsgBuffer)/sizeof(MsgBuffer[0]),
  92. ErrorCode)){
  93. std::wstring Msg(MsgBuffer);
  94. os << Msg;
  95. } else {
  96. os << std::hex << ErrorCode;
  97. }
  98. }
  99. };
  100. //
  101. // Invalid arguments
  102. //
  103. struct InvalidArguments : public ProgramException {
  104. const char *what() const throw() {
  105. return "Invalid Arguments";
  106. }
  107. void Dump(std::ostream &os) {
  108. os << what() << std::endl;
  109. }
  110. };
  111. //
  112. // Invalid arguments
  113. //
  114. struct ProgramUsage : public ProgramException {
  115. std::wstring PrgUsage;
  116. ProgramUsage(const std::wstring &Usg) : PrgUsage(Usg) {}
  117. const char *what() const throw() {
  118. return "Program Usage exception";
  119. }
  120. void Dump(std::ostream &os) {
  121. os << PrgUsage << std::endl;
  122. }
  123. };
  124. //
  125. // Program Arguments abstraction
  126. //
  127. struct ProgramArguments {
  128. bool ShowUsage;
  129. bool ListEntries;
  130. bool AddNewEntry;
  131. bool DeleteBootEntry;
  132. bool QuiteMode;
  133. bool SetActive;
  134. bool SetOsLoadOptions;
  135. bool SetTimeout;
  136. std::wstring LoaderVolumeName;
  137. std::wstring LoaderPath;
  138. std::wstring BootVolumeName;
  139. std::wstring BootPath;
  140. std::wstring LoadOptions;
  141. std::wstring FriendlyName;
  142. std::wstring OsLoadOptions;
  143. std::wstring AddOptionKey;
  144. std::wstring DeleteOptionKey;
  145. std::wstring ListOptionKey;
  146. std::wstring OptionsOptionKey;
  147. std::wstring SetActiveOptionKey;
  148. std::wstring TimeoutOptionKey;
  149. ULONG Timeout;
  150. ULONG EntryId;
  151. ProgramArguments(INT Argc, WCHAR *Argv[]) {
  152. ShowUsage = false;
  153. QuiteMode = false;
  154. ListEntries = AddNewEntry = DeleteBootEntry = false;
  155. SetActive = false;
  156. EntryId = -1;
  157. Timeout = DEFAULT_TIMEOUT;
  158. SetTimeout = false;
  159. //
  160. // get all the options
  161. //
  162. ListOptionKey = GetOptionKey(MSG_LIST_OPTION);
  163. AddOptionKey = GetOptionKey(MSG_ADD_OPTION);
  164. DeleteOptionKey = GetOptionKey(MSG_DELETE_OPTION);
  165. OptionsOptionKey = GetOptionKey(MSG_OPTIONS_OPTION);
  166. SetActiveOptionKey = GetOptionKey(MSG_SETACTIVE_OPTION);
  167. TimeoutOptionKey = GetOptionKey(MSG_TIMEOUT_OPTION);
  168. //
  169. // parse the arguments
  170. //
  171. for (ULONG Index=1; !ShowUsage && (Index < Argc); Index++) {
  172. if (!_wcsicmp(Argv[Index], L"/q")) {
  173. QuiteMode = true;
  174. } else if (!_wcsicmp(Argv[Index], AddOptionKey.c_str())) {
  175. std::wstring LoaderName;
  176. std::wstring BootVolName;
  177. AddNewEntry = true;
  178. ShowUsage = true;
  179. if (Argc > 3) {
  180. Index++;
  181. LoaderName = Argv[Index++];
  182. BootVolName = Argv[Index++];
  183. ShowUsage = false;
  184. for ( ; (Index < Argc) && (false == ShowUsage); Index++) {
  185. if (!_wcsicmp(Argv[Index], SetActiveOptionKey.c_str())) {
  186. SetActive = true;
  187. } else if (!_wcsicmp(Argv[Index], OptionsOptionKey.c_str())) {
  188. SetOsLoadOptions = true;
  189. Index++;
  190. if (Index < Argc) {
  191. OsLoadOptions = Argv[Index];
  192. } else {
  193. ShowUsage = true;
  194. }
  195. } else if (!_wcsicmp(Argv[Index], TimeoutOptionKey.c_str())) {
  196. SetTimeout = true;
  197. Index++;
  198. if (Index < Argc) {
  199. PWSTR EndChar = NULL;
  200. Timeout = wcstoul(Argv[Index], &EndChar, 10);
  201. if (errno) {
  202. ShowUsage = true;
  203. }
  204. }
  205. } else {
  206. ShowUsage = true;
  207. }
  208. }
  209. //
  210. // Verify the arguments
  211. //
  212. if (!ShowUsage) {
  213. if (_waccess(LoaderName.c_str(), 0) ||
  214. _waccess(BootVolName.c_str(), 0)) {
  215. throw new W32Error(::GetLastError());
  216. }
  217. //
  218. // Get the fully qualified NT name for
  219. // the the loader volume and boot volume
  220. // name
  221. //
  222. WCHAR CanonicalName[MAX_PATH];
  223. NTSTATUS Status;
  224. std::wstring NtName;
  225. std::wstring DosDevices = L"\\DosDevices\\";
  226. std::wstring::size_type LoaderColonPos = LoaderName.find(L':');
  227. std::wstring::size_type BootColonPos = BootVolName.find(L':');
  228. if (LoaderColonPos != LoaderName.npos) {
  229. NtName = DosDevices + LoaderName.substr(0, LoaderColonPos + 1);
  230. Status = QueryCanonicalName(NtName.c_str(),
  231. -1,
  232. CanonicalName,
  233. sizeof(CanonicalName));
  234. if (NT_SUCCESS(Status)) {
  235. LoaderVolumeName = CanonicalName;
  236. LoaderPath = LoaderName.substr(LoaderColonPos + 1);
  237. } else {
  238. throw new W32Error(RtlNtStatusToDosError(Status));
  239. }
  240. } else {
  241. throw new W32Error(ERROR_PATH_NOT_FOUND);
  242. }
  243. if (BootColonPos != BootVolName.npos) {
  244. NtName = DosDevices + BootVolName.substr(0, BootColonPos + 1);
  245. Status = QueryCanonicalName(NtName.c_str(),
  246. -1,
  247. CanonicalName,
  248. sizeof(CanonicalName));
  249. if (NT_SUCCESS(Status)) {
  250. BootVolumeName = CanonicalName;
  251. BootPath = BootVolName.substr(BootColonPos + 1);
  252. } else {
  253. throw new W32Error(RtlNtStatusToDosError(Status));
  254. }
  255. } else {
  256. throw new W32Error(ERROR_PATH_NOT_FOUND);
  257. }
  258. if (BootVolName[BootVolName.length() - 1] != L'\\') {
  259. BootVolName += L"\\";
  260. }
  261. std::wstring LayoutInf = BootVolName + L"inf\\layout.inf";
  262. //
  263. // Verify the inf file path
  264. //
  265. if (_waccess(LayoutInf.c_str(), 0)) {
  266. throw new W32Error(::GetLastError());
  267. }
  268. //
  269. // Extract the product friendly name for the inf file
  270. //
  271. GetFriendlyName(LayoutInf, FriendlyName);
  272. }
  273. }
  274. break;
  275. } else if (!_wcsicmp(Argv[Index], ListOptionKey.c_str())) {
  276. ListEntries = true;
  277. break;
  278. } else if (!_wcsicmp(Argv[Index], DeleteOptionKey.c_str())) {
  279. DeleteBootEntry = true;
  280. Index++;
  281. if (Index < Argc) {
  282. PWSTR EndChar = NULL;
  283. EntryId = wcstoul(Argv[Index], &EndChar, 10);
  284. }
  285. break;
  286. } else if (!_wcsicmp(Argv[Index], L"/?") ||
  287. !_wcsicmp(Argv[Index], L"-?") ||
  288. !_wcsicmp(Argv[Index], L"?") ||
  289. !_wcsicmp(Argv[Index], L"/h") ||
  290. !_wcsicmp(Argv[Index], L"-h")) {
  291. ShowUsage = true;
  292. } else if (!_wcsicmp(Argv[Index], OptionsOptionKey.c_str())) {
  293. Index++;
  294. SetOsLoadOptions = true;
  295. if (Index < Argc) {
  296. OsLoadOptions = Argv[Index];
  297. Index++;
  298. if (Index < Argc) {
  299. PWSTR EndChar = NULL;
  300. EntryId = wcstoul(Argv[Index], &EndChar, 10);
  301. }
  302. }
  303. break;
  304. } else if (!_wcsicmp(Argv[Index], SetActiveOptionKey.c_str())) {
  305. Index++;
  306. SetActive = true;
  307. if (Index < Argc) {
  308. PWSTR EndChar = NULL;
  309. EntryId = wcstoul(Argv[Index], &EndChar, 10);
  310. if (errno) {
  311. ShowUsage = true;
  312. }
  313. } else {
  314. ShowUsage = true;
  315. }
  316. break;
  317. } else if (!_wcsicmp(Argv[Index], TimeoutOptionKey.c_str())) {
  318. Index++;
  319. SetTimeout = true;
  320. if (Index < Argc) {
  321. PWSTR EndChar = NULL;
  322. Timeout = wcstoul(Argv[Index], &EndChar, 10);
  323. if (errno) {
  324. ShowUsage = true;
  325. }
  326. } else {
  327. ShowUsage = true;
  328. }
  329. } else {
  330. ShowUsage = true;
  331. }
  332. }
  333. if (!ShowUsage) {
  334. ShowUsage = (!ListEntries && !AddNewEntry && !SetActive &&
  335. !DeleteBootEntry && !SetOsLoadOptions && !SetTimeout);
  336. }
  337. if (ShowUsage) {
  338. throw new ProgramUsage(GetFormattedMessage( ThisModule,
  339. FALSE,
  340. Message,
  341. sizeof(Message)/sizeof(Message[0]),
  342. MSG_PGM_USAGE));
  343. }
  344. }
  345. friend std::ostream& operator<<(std::ostream &os, ProgramArguments &Args) {
  346. os << "List Entries : " << Args.ListEntries << std::endl;
  347. os << "Add Entry : " << Args.AddNewEntry << std::endl;
  348. os << "Delete Entry : " << Args.DeleteBootEntry << std::endl;
  349. os << "QuiteMode : " << Args.QuiteMode << std::endl;
  350. os << "Loader Vol : " << Args.LoaderVolumeName << std::endl;
  351. os << "Loader Path : " << Args.LoaderPath << std::endl;
  352. os << "Boot Vol : " << Args.BootVolumeName << std::endl;
  353. os << "Boot Path : " << Args.BootPath << std::endl;
  354. os << "Friendly Name: " << Args.FriendlyName << std::endl;
  355. os << "Load Options : " << Args.OsLoadOptions << std::endl;
  356. os << "Timeout : " << std::dec << Args.Timeout << " Secs" << std::endl;
  357. return os;
  358. }
  359. };
  360. VOID
  361. DumpOsBootEntry(
  362. IN POS_BOOT_ENTRY Entry
  363. )
  364. {
  365. if (Entry) {
  366. wprintf(GetFormattedMessage( ThisModule,
  367. FALSE,
  368. Message,
  369. sizeof(Message)/sizeof(Message[0]),
  370. MSG_BOOT_ENTRY,
  371. OSBEGetId(Entry),
  372. OSBEGetFriendlyName(Entry),
  373. OSBEGetOsLoaderVolumeName(Entry),
  374. OSBEGetOsLoaderPath(Entry),
  375. OSBEGetBootVolumeName(Entry),
  376. OSBEGetBootPath(Entry),
  377. OSBEGetOsLoadOptions(Entry)));
  378. }
  379. }
  380. VOID
  381. DumpOsBootOptions(
  382. IN POS_BOOT_OPTIONS Options
  383. )
  384. {
  385. if (Options) {
  386. ULONG Index;
  387. wprintf(GetFormattedMessage( ThisModule,
  388. FALSE,
  389. Message,
  390. sizeof(Message)/sizeof(Message[0]),
  391. MSG_TIMEOUT_AND_BOOT_ORDER,
  392. OSBOGetTimeOut(Options)));
  393. for (Index=0;
  394. Index < OSBOGetOrderedBootEntryCount(Options);
  395. Index++) {
  396. wprintf(GetFormattedMessage( ThisModule,
  397. FALSE,
  398. Message,
  399. sizeof(Message)/sizeof(Message[0]),
  400. MSG_ORDERED_BOOT_ENTRIES,
  401. OSBOGetBootEntryIdByOrder(Options, Index)));
  402. }
  403. wprintf(GetFormattedMessage( ThisModule,
  404. FALSE,
  405. Message,
  406. sizeof(Message)/sizeof(Message[0]),
  407. MSG_BOOT_ENTRIES));
  408. POS_BOOT_ENTRY Entry = OSBOGetFirstBootEntry(Options, &Index);
  409. while (Entry) {
  410. DumpOsBootEntry(Entry);
  411. Entry = OSBOGetNextBootEntry(Options, &Index);
  412. }
  413. wprintf(GetFormattedMessage( ThisModule,
  414. FALSE,
  415. Message,
  416. sizeof(Message)/sizeof(Message[0]),
  417. MSG_ACTIVE_ENTRY));
  418. DumpOsBootEntry(OSBOGetActiveBootEntry(Options));
  419. }
  420. }
  421. DWORD
  422. ListEntries(
  423. IN POS_BOOT_OPTIONS OsOptions
  424. )
  425. {
  426. DWORD Result = ERROR_INVALID_PARAMETER;
  427. if (OsOptions) {
  428. DumpOsBootOptions(OsOptions);
  429. Result = ERROR_SUCCESS;
  430. }
  431. return Result;
  432. }
  433. DWORD
  434. AddNewEntry(
  435. IN POS_BOOT_OPTIONS OsOptions,
  436. IN ProgramArguments &Args
  437. )
  438. {
  439. DWORD Result = ERROR_INVALID_PARAMETER;
  440. if (OsOptions) {
  441. POS_BOOT_ENTRY NewEntry;
  442. BOOLEAN Status = TRUE;
  443. NewEntry = OSBOAddNewBootEntry(OsOptions,
  444. Args.FriendlyName.c_str(),
  445. Args.LoaderVolumeName.c_str(),
  446. Args.LoaderPath.c_str(),
  447. Args.BootVolumeName.c_str(),
  448. Args.BootPath.c_str(),
  449. Args.OsLoadOptions.c_str());
  450. if (NewEntry) {
  451. if (Args.SetActive) {
  452. Status = (OSBOSetActiveBootEntry(OsOptions,
  453. NewEntry) != NULL);
  454. }
  455. if (Status && Args.SetTimeout) {
  456. OSBOSetTimeOut(OsOptions, Args.Timeout);
  457. }
  458. if (Status) {
  459. Status = OSBOFlush(OsOptions);
  460. }
  461. } else {
  462. Status = FALSE;
  463. }
  464. if (Status) {
  465. Result = ERROR_SUCCESS;
  466. } else {
  467. Result = ERROR_CAN_NOT_COMPLETE;
  468. }
  469. }
  470. return Result;
  471. }
  472. DWORD
  473. SetBootEntryOptions(
  474. IN POS_BOOT_OPTIONS OsOptions,
  475. IN const ProgramArguments &Args
  476. )
  477. {
  478. DWORD ErrorCode = ERROR_INVALID_PARAMETER;
  479. if (OsOptions) {
  480. POS_BOOT_ENTRY BootEntry;
  481. BOOLEAN Status = FALSE;
  482. if (Args.EntryId != -1) {
  483. BootEntry = OSBOFindBootEntry(OsOptions,
  484. Args.EntryId);
  485. } else {
  486. BootEntry = OSBOGetActiveBootEntry(OsOptions);
  487. }
  488. if (BootEntry) {
  489. Status = (OSBESetOsLoadOptions(BootEntry,
  490. Args.OsLoadOptions.c_str()) != NULL);
  491. if (Status) {
  492. Status = OSBOFlush(OsOptions);
  493. }
  494. }
  495. if (Status) {
  496. ErrorCode = ERROR_SUCCESS;
  497. } else {
  498. ErrorCode = ERROR_CAN_NOT_COMPLETE;
  499. }
  500. }
  501. return ErrorCode;
  502. }
  503. DWORD
  504. SetBootEntryActive(
  505. IN POS_BOOT_OPTIONS OsOptions,
  506. IN ProgramArguments &Args
  507. )
  508. {
  509. DWORD ErrorCode = ERROR_INVALID_PARAMETER;
  510. if (OsOptions && (Args.EntryId != -1)) {
  511. POS_BOOT_ENTRY BootEntry;
  512. BOOLEAN Status = FALSE;
  513. BootEntry = OSBOFindBootEntry(OsOptions,
  514. Args.EntryId);
  515. if (BootEntry) {
  516. Status = (OSBOSetActiveBootEntry(OsOptions,
  517. BootEntry) != NULL);
  518. if (Status) {
  519. Status = OSBOFlush(OsOptions);
  520. }
  521. }
  522. if (Status) {
  523. ErrorCode = ERROR_SUCCESS;
  524. } else {
  525. ErrorCode = ERROR_CAN_NOT_COMPLETE;
  526. }
  527. }
  528. return ErrorCode;
  529. }
  530. DWORD
  531. DeleteBootEntry(
  532. IN POS_BOOT_OPTIONS OsOptions,
  533. IN ProgramArguments &Args
  534. )
  535. {
  536. DWORD ErrorCode = ERROR_INVALID_PARAMETER;
  537. if (OsOptions) {
  538. POS_BOOT_ENTRY BootEntry;
  539. BOOLEAN Status = FALSE;
  540. if (Args.EntryId != -1) {
  541. BootEntry = OSBOFindBootEntry(OsOptions,
  542. Args.EntryId);
  543. } else {
  544. BootEntry = OSBOGetActiveBootEntry(OsOptions);
  545. }
  546. if (BootEntry) {
  547. Status = OSBODeleteBootEntry(OsOptions, BootEntry);
  548. if (Status) {
  549. Status = OSBOFlush(OsOptions);
  550. }
  551. }
  552. if (Status) {
  553. ErrorCode = ERROR_SUCCESS;
  554. } else {
  555. ErrorCode = ERROR_CAN_NOT_COMPLETE;
  556. }
  557. }
  558. return ErrorCode;
  559. }
  560. DWORD
  561. SetTimeout(
  562. IN POS_BOOT_OPTIONS OsOptions,
  563. IN const ProgramArguments &Args
  564. )
  565. {
  566. DWORD ErrorCode = ERROR_INVALID_PARAMETER;
  567. if (OsOptions && Args.SetTimeout) {
  568. OSBOSetTimeOut(OsOptions, Args.Timeout);
  569. ErrorCode = OSBOFlush(OsOptions) ? ERROR_SUCCESS : ERROR_CAN_NOT_COMPLETE;
  570. }
  571. return ErrorCode;
  572. }
  573. //
  574. // main() entry point
  575. //
  576. int
  577. __cdecl
  578. wmain(
  579. int Argc,
  580. wchar_t *Argv[]
  581. )
  582. {
  583. int Result = 0;
  584. ThisModule = GetModuleHandle(NULL);
  585. try {
  586. DWORD ErrorCode = ERROR_INVALID_PARAMETER;
  587. ProgramArguments Args(Argc, Argv);
  588. POS_BOOT_OPTIONS BootOptions = NULL;
  589. //
  590. // Initialize the library
  591. //
  592. if (OSBOLibraryInit((SBEMemAllocateRoutine)malloc, (SBEMemFreeRoutine)free)) {
  593. BootOptions = EFIOSBOCreate();
  594. }
  595. if (!BootOptions) {
  596. std::cout << GetFormattedMessage( ThisModule,
  597. FALSE,
  598. Message,
  599. sizeof(Message)/sizeof(Message[0]),
  600. MSG_ERROR_READING_BOOT_ENTRIES) << std::endl;
  601. Result = 1;
  602. } else {
  603. if (Args.ListEntries) {
  604. ErrorCode = ListEntries(BootOptions);
  605. } else if (Args.AddNewEntry) {
  606. ErrorCode = AddNewEntry(BootOptions, Args);
  607. } else if (Args.DeleteBootEntry) {
  608. ErrorCode = DeleteBootEntry(BootOptions, Args);
  609. } else if (Args.SetOsLoadOptions) {
  610. ErrorCode = SetBootEntryOptions(BootOptions, Args);
  611. } else if (Args.SetActive) {
  612. ErrorCode = SetBootEntryActive(BootOptions, Args);
  613. } else if (Args.SetTimeout) {
  614. ErrorCode = SetTimeout(BootOptions, Args);
  615. }
  616. OSBODelete(BootOptions);
  617. }
  618. if (ErrorCode != ERROR_SUCCESS) {
  619. throw new W32Error(ErrorCode);
  620. }
  621. }
  622. catch(ProgramArguments *pArgs) {
  623. Result = 1;
  624. std::cout << GetFormattedMessage( ThisModule,
  625. FALSE,
  626. Message,
  627. sizeof(Message)/sizeof(Message[0]),
  628. MSG_PGM_USAGE) << std::endl;
  629. if (pArgs) {
  630. delete pArgs;
  631. }
  632. }
  633. catch(W32Error *W32Err) {
  634. if (W32Err) { // to make prefix happy :(
  635. W32Err->Dump(std::cout);
  636. std::cout << GetFormattedMessage( ThisModule,
  637. FALSE,
  638. Message,
  639. sizeof(Message)/sizeof(Message[0]),
  640. MSG_PGM_USAGE) << std::endl;
  641. delete W32Err;
  642. }
  643. Result = 1;
  644. }
  645. catch(ProgramException *PrgExp) {
  646. Result = 1;
  647. PrgExp->Dump(std::cout);
  648. delete PrgExp;
  649. } catch (exception *Exp) {
  650. Result = 1;
  651. std::cout << Exp->what() << std::endl;
  652. }
  653. return Result;
  654. }
  655. NTSTATUS
  656. QueryCanonicalName(
  657. IN PCWSTR Name,
  658. IN ULONG MaxDepth,
  659. OUT PWSTR CanonicalName,
  660. IN ULONG SizeOfBufferInBytes
  661. )
  662. /*++
  663. Routine Description:
  664. Resolves the symbolic name to the specified depth. To resolve
  665. a symbolic name completely specify the MaxDepth as -1
  666. Arguments:
  667. Name - Symbolic name to be resolved
  668. MaxDepth - The depth till which the resolution needs to
  669. be carried out
  670. CanonicalName - The fully resolved name
  671. SizeOfBufferInBytes - The size of the CanonicalName buffer in
  672. bytes
  673. Return Value:
  674. Appropriate NT status code
  675. --*/
  676. {
  677. UNICODE_STRING name, canonName;
  678. OBJECT_ATTRIBUTES oa;
  679. NTSTATUS status;
  680. HANDLE handle;
  681. ULONG CurrentDepth;
  682. RtlInitUnicodeString(&name, Name);
  683. canonName.MaximumLength = (USHORT) (SizeOfBufferInBytes - sizeof(WCHAR));
  684. canonName.Length = 0;
  685. canonName.Buffer = CanonicalName;
  686. if (name.Length >= canonName.MaximumLength) {
  687. return STATUS_BUFFER_TOO_SMALL;
  688. }
  689. RtlCopyMemory(canonName.Buffer, name.Buffer, name.Length);
  690. canonName.Length = name.Length;
  691. canonName.Buffer[canonName.Length/sizeof(WCHAR)] = 0;
  692. for (CurrentDepth = 0; CurrentDepth < MaxDepth; CurrentDepth++) {
  693. InitializeObjectAttributes(&oa, &canonName, OBJ_CASE_INSENSITIVE, 0, 0);
  694. status = NtOpenSymbolicLinkObject(&handle,
  695. READ_CONTROL | SYMBOLIC_LINK_QUERY,
  696. &oa);
  697. if (!NT_SUCCESS(status)) {
  698. break;
  699. }
  700. status = NtQuerySymbolicLinkObject(handle, &canonName, NULL);
  701. NtClose(handle);
  702. if (!NT_SUCCESS(status)) {
  703. return status;
  704. }
  705. canonName.Buffer[canonName.Length/sizeof(WCHAR)] = 0;
  706. }
  707. return STATUS_SUCCESS;
  708. }
  709. #define PRODUCT_NAME_KEY TEXT("productname")
  710. VOID
  711. GetFriendlyName(
  712. IN const std::wstring &InfFileName,
  713. OUT std::wstring &FriendlyName
  714. )
  715. {
  716. UINT ErrorLine = 0;
  717. BOOL Status = FALSE;
  718. HINF InfHandle = ::SetupOpenInfFile(InfFileName.c_str(),
  719. NULL,
  720. INF_STYLE_WIN4,
  721. &ErrorLine);
  722. if (InfHandle != INVALID_HANDLE_VALUE) {
  723. INFCONTEXT InfContext = {0};
  724. WCHAR Buffer[MAX_PATH] = {0};
  725. //
  726. // get the key
  727. //
  728. Status = SetupFindFirstLine(InfHandle,
  729. TEXT("Strings"),
  730. PRODUCT_NAME_KEY,
  731. &InfContext);
  732. if (Status) {
  733. //
  734. // If we found the key extract the description
  735. //
  736. Status = SetupGetStringField(&InfContext,
  737. 1,
  738. Buffer,
  739. ARRAY_SIZE(Buffer),
  740. NULL);
  741. if (Status) {
  742. FriendlyName = Buffer;
  743. }
  744. }
  745. SetupCloseInfFile(InfHandle);
  746. }
  747. //
  748. // If we didn't find the description use default description
  749. //
  750. if (!Status) {
  751. FriendlyName = DEFAULT_NAME;
  752. }
  753. FriendlyName = MSFT_PREFIX + FriendlyName;
  754. }