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.

844 lines
24 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. Grabmi.cpp
  5. Abstract:
  6. Contains the entry point & core code for the application.
  7. Notes:
  8. ANSI & Unicode via TCHAR - runs on Win9x/NT/2K/XP etc.
  9. History:
  10. 07/18/00 jdoherty Created
  11. 12/16/00 jdoherty Modified to use SDBAPI routines
  12. 12/29/00 prashkud Modified to take space in the filepath
  13. 01/23/02 rparsons Re-wrote existing code
  14. 02/19/02 rparsons Implemented strsafe functions
  15. --*/
  16. #include "grabmi.h"
  17. //
  18. // This structure contains all the data we'll need to access
  19. // throughout the application.
  20. //
  21. APPINFO g_ai;
  22. /*++
  23. Routine Description:
  24. Prints a formatted string to the debugger.
  25. Arguments:
  26. dwDetail - Specifies the level of the information provided.
  27. pszFmt - The string to be displayed.
  28. ... - A va_list of insertion strings.
  29. Return Value:
  30. None.
  31. --*/
  32. void
  33. __cdecl
  34. DebugPrintfEx(
  35. IN DEBUGLEVEL dwDetail,
  36. IN LPSTR pszFmt,
  37. ...
  38. )
  39. {
  40. char szT[1024];
  41. va_list arglist;
  42. int len;
  43. va_start(arglist, pszFmt);
  44. //
  45. // Reserve one character for the potential '\n' that we may be adding.
  46. //
  47. StringCchVPrintfA(szT, sizeof(szT) - 1, pszFmt, arglist);
  48. va_end(arglist);
  49. //
  50. // Make sure we have a '\n' at the end of the string
  51. //
  52. len = strlen(szT);
  53. if (len > 0 && szT[len - 1] != '\n') {
  54. szT[len] = '\n';
  55. szT[len + 1] = 0;
  56. }
  57. switch (dwDetail) {
  58. case dlPrint:
  59. OutputDebugString("[MSG ] ");
  60. break;
  61. case dlError:
  62. OutputDebugString("[FAIL] ");
  63. break;
  64. case dlWarning:
  65. OutputDebugString("[WARN] ");
  66. break;
  67. case dlInfo:
  68. OutputDebugString("[INFO] ");
  69. break;
  70. default:
  71. OutputDebugString("[XXXX] ");
  72. break;
  73. }
  74. OutputDebugString(szT);
  75. }
  76. /*++
  77. Routine Description:
  78. Displays command-line syntax to the user.
  79. Arguments:
  80. None.
  81. Return Value:
  82. None.
  83. --*/
  84. void
  85. DisplayUsage(
  86. void
  87. )
  88. {
  89. _tprintf(_T("Microsoft(R) Windows(TM) Grab Matching Information\n"));
  90. _tprintf(_T("Copyright (C) Microsoft Corporation. All rights reserved.\n"));
  91. _tprintf(_T("\nGrabMI can be used in one of the following ways:\n")
  92. _T(" *** The following flags can be used with other flags:\n")
  93. _T(" -f, -a, -n, and -h \n")
  94. _T(" otherwise the last flag specified will be used.\n")
  95. _T(" *** If no arguments are provided, matching information will be\n")
  96. _T(" extracted from the current directory.\n\n")
  97. _T(" grabmi [path to start generating info ie. c:\\progs]\n")
  98. _T(" Grabs matching information from the path specified. Limits the\n")
  99. _T(" information gathered to 10 miscellaneous files per directory,\n")
  100. _T(" and includes all files with extensions .icd, .exe, .dll,\n")
  101. _T(" .msi, ._mp. If a path is not specified, the directory that GrabMI\n")
  102. _T(" was executed from is used.\n\n")
  103. _T(" grabmi [-d]\n")
  104. _T(" Grabs matching information from %%windir%%\\system32\\drivers.\n")
  105. _T(" The format of the information is slightly different in this case\n")
  106. _T(" and only information for *.sys files will be grabbed.\n\n")
  107. _T(" grabmi [-f drive:\\filename.txt]\n")
  108. _T(" The matching information is stored in a file specified by the user.\n")
  109. _T(" If a full path is not specified and the -d flag is used, the file\n")
  110. _T(" is stored in the %%windir%%\\system(32) directory. Otherwise, the file\n")
  111. _T(" is stored in the directory that GrabMI was executed from.\n\n")
  112. _T(" grabmi [-h or -?]\n")
  113. _T(" Displays this help.\n\n")
  114. _T(" grabmi [-o]\n")
  115. _T(" Grabs information for the file specified. If a file was not specified,\n")
  116. _T(" the call will fail. If the destination file exists, then the information\n")
  117. _T(" will be concatenated to the end of the existing file.\n\n")
  118. _T(" grabmi [-p]\n")
  119. _T(" Grabs information for files with .icd, .exe, .dll, .msi, ._mp extensions\n")
  120. _T(" only.\n\n")
  121. _T(" grabmi [-q]\n")
  122. _T(" Grabs matching information and does not display the file when completed.\n\n")
  123. _T(" grabmi [-s]\n")
  124. _T(" Grabs information for the following system files:\n")
  125. _T(" advapi32.dll, gdi32.dll, ntdll.dll, kernel32.dll, winsock.dll\n")
  126. _T(" ole32.dll, oleaut32.dll, shell32.dll, user32.dll, and wininet.dll\n\n")
  127. _T(" grabmi [-v]\n")
  128. _T(" Grabs matching information for all files. \n\n")
  129. _T(" grabmi [-a]\n")
  130. _T(" Appends new matching information to the existing matching\n")
  131. _T(" information file. \n\n")
  132. _T(" grabmi [-n]\n")
  133. _T(" Allows to more information to be appended the file later (see -a). \n"));
  134. }
  135. /*++
  136. Routine Description:
  137. Initializes the application. Saves away common paths
  138. and other useful items for later.
  139. Arguments:
  140. None.
  141. Return Value:
  142. TRUE on success, FALSE otherwise.
  143. --*/
  144. BOOL
  145. InitializeApplication(
  146. void
  147. )
  148. {
  149. DWORD cchReturned;
  150. UINT cchSize;
  151. TCHAR* pszTemp = NULL;
  152. OSVERSIONINFO osvi;
  153. //
  154. // Initialize our defaults, determine where we're running
  155. // from, and get the version of the OS we're on.
  156. //
  157. *g_ai.szOutputFile = 0;
  158. *g_ai.szGrabPath = 0;
  159. g_ai.dwFilter = GRABMI_FILTER_NORMAL;
  160. g_ai.fDisplayFile = TRUE;
  161. g_ai.szCurrentDir[ARRAYSIZE(g_ai.szCurrentDir) - 1] = 0;
  162. cchReturned = GetModuleFileName(NULL,
  163. g_ai.szCurrentDir,
  164. ARRAYSIZE(g_ai.szCurrentDir));
  165. if (g_ai.szCurrentDir[ARRAYSIZE(g_ai.szCurrentDir) - 1] != 0 ||
  166. cchReturned == 0) {
  167. DPF(dlError,
  168. "[InitializeApplication] 0x%08X Failed to get module filename",
  169. GetLastError());
  170. return FALSE;
  171. }
  172. pszTemp = _tcsrchr(g_ai.szCurrentDir, '\\');
  173. if (pszTemp) {
  174. *pszTemp = 0;
  175. }
  176. cchSize = GetSystemDirectory(g_ai.szSystemDir, ARRAYSIZE(g_ai.szSystemDir));
  177. if (cchSize > ARRAYSIZE(g_ai.szSystemDir) || cchSize == 0) {
  178. DPF(dlError,
  179. "[InitializeApplication] 0x%08X Failed to get system directory",
  180. GetLastError());
  181. return FALSE;
  182. }
  183. ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
  184. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  185. if (!GetVersionEx(&osvi)) {
  186. DPF(dlError,
  187. "[InitializeApplication] 0x%08X Failed to get version info",
  188. GetLastError());
  189. return FALSE;
  190. }
  191. //
  192. // Determine if we should use apphelp.dll, sdbapiu.dll, or sdbapi.dll.
  193. //
  194. if (osvi.dwMajorVersion >= 5 && osvi.dwMinorVersion >= 1) {
  195. //
  196. // Apphelp.dll is available on XP.
  197. //
  198. g_ai.dwLibraryFlags = GRABMI_FLAG_APPHELP;
  199. } else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) {
  200. //
  201. // Apphelp.dll is not available on Windows 2000, use sdbapiu.dll.
  202. //
  203. g_ai.dwLibraryFlags = GRABMI_FLAG_NT;
  204. } else {
  205. //
  206. // Downlevel platforms should use sdbapi.dll.
  207. //
  208. g_ai.dwLibraryFlags = 0;
  209. }
  210. return TRUE;
  211. }
  212. /*++
  213. Routine Description:
  214. Parses the command-line to determine our mode of operation.
  215. Arguments:
  216. argc - Number command-line of arguments provided by the user.
  217. argv[] - An array of command-line arguments.
  218. Return Value:
  219. TRUE if valid arguments were provided, FALSE otherwise.
  220. --*/
  221. BOOL
  222. ParseCommandLine(
  223. IN int argc,
  224. IN TCHAR* argv[]
  225. )
  226. {
  227. int nCount = 1;
  228. HRESULT hr;
  229. if (argc == 1) {
  230. return TRUE;
  231. }
  232. //
  233. // The first argument should be our starting directory.
  234. //
  235. if ((argv[nCount][0] != '-') && (argv[nCount][0] != '/')) {
  236. hr = StringCchCopy(g_ai.szGrabPath,
  237. ARRAYSIZE(g_ai.szGrabPath),
  238. argv[nCount]);
  239. if (FAILED(hr)) {
  240. DPF(dlError, "[ParseCommandLine] Buffer too small (1)");
  241. return FALSE;
  242. }
  243. }
  244. for (nCount = 1; nCount < argc; nCount++) {
  245. if ((argv[nCount][0] == '-') || (argv[nCount][0] == '/')) {
  246. switch (argv[nCount][1]) {
  247. case '?':
  248. case 'H':
  249. case 'h':
  250. return FALSE;
  251. case 'F':
  252. case 'f':
  253. //
  254. // Do a little work to figure out if a file was specified.
  255. //
  256. if (nCount < argc - 1) {
  257. if ((argv[nCount + 1][0] == '-') || (argv[nCount + 1][0] == '/')) {
  258. return FALSE;
  259. } else {
  260. //
  261. // Grab the specified path.
  262. //
  263. hr = StringCchCopy(g_ai.szOutputFile,
  264. ARRAYSIZE(g_ai.szOutputFile),
  265. argv[nCount + 1]);
  266. if (FAILED(hr)) {
  267. DPF(dlError, "[ParseCommandLine] Buffer too small (2)");
  268. return FALSE;
  269. }
  270. }
  271. }
  272. break;
  273. case 'D':
  274. case 'd':
  275. g_ai.dwFilter = GRABMI_FILTER_DRIVERS;
  276. break;
  277. case 'O':
  278. case 'o':
  279. g_ai.dwFilter = GRABMI_FILTER_THISFILEONLY;
  280. break;
  281. case 'V':
  282. case 'v':
  283. g_ai.dwFilter = GRABMI_FILTER_VERBOSE;
  284. break;
  285. case 'Q':
  286. case 'q':
  287. g_ai.fDisplayFile = FALSE;
  288. break;
  289. case 'P':
  290. case 'p':
  291. g_ai.dwFilter = GRABMI_FILTER_PRIVACY;
  292. break;
  293. case 'S':
  294. case 's':
  295. g_ai.dwFilter = GRABMI_FILTER_SYSTEM;
  296. break;
  297. case 'A':
  298. case 'a':
  299. g_ai.dwFilterFlags |= GRABMI_FILTER_APPEND;
  300. break;
  301. case 'N':
  302. case 'n':
  303. g_ai.dwFilterFlags |= GRABMI_FILTER_NOCLOSE;
  304. break;
  305. default:
  306. return FALSE;
  307. }
  308. }
  309. }
  310. return TRUE;
  311. }
  312. /*++
  313. Routine Description:
  314. Displays a home-grown "progress bar" to inform the user that
  315. the application is working.
  316. Arguments:
  317. See below.
  318. Return Value:
  319. TRUE on success, FALSE otherwise.
  320. --*/
  321. BOOL
  322. CALLBACK
  323. _GrabmiCallback(
  324. IN LPVOID lpvCallbackParam, // application-defined parameter
  325. IN LPCTSTR lpszRoot, // root directory path
  326. IN LPCTSTR lpszRelative, // relative path
  327. IN PATTRINFO pAttrInfo, // attributes
  328. IN LPCWSTR pwszXML // resulting xml
  329. )
  330. {
  331. static int State = 0;
  332. static TCHAR szIcon[] = _T("||//--\\\\");
  333. State = ++State % (ARRAYSIZE(szIcon) - 1);
  334. _tcprintf(_T("%c\r"), szIcon[State]);
  335. return TRUE;
  336. }
  337. /*++
  338. Routine Description:
  339. Obtains function pointers to the SDB APIs and makes the call
  340. that obtains the matching information.
  341. Arguments:
  342. pszOutputFile - Contains the path to the file we will save
  343. the results to.
  344. Return Value:
  345. TRUE on success, FALSE otherwise.
  346. --*/
  347. BOOL
  348. CallSdbAPIFunctions(
  349. IN LPCTSTR pszOutputFile
  350. )
  351. {
  352. HMODULE hModule;
  353. BOOL bResult = FALSE;
  354. TCHAR* pszLibrary = NULL;
  355. TCHAR szLibraryPath[MAX_PATH];
  356. WCHAR wszGrabPath[MAX_PATH];
  357. WCHAR wszOutputFile[MAX_PATH];
  358. HRESULT hr;
  359. PFNSdbGrabMatchingInfoExA pfnSdbGrabMatchingInfoExA = NULL;
  360. PFNSdbGrabMatchingInfoExW pfnSdbGrabMatchingInfoExW = NULL;
  361. if (!pszOutputFile) {
  362. DPF(dlError, "[CallSdbAPIFunctions] Invalid argument");
  363. return FALSE;
  364. }
  365. //
  366. // Attempt to load files from the current directory first.
  367. // If this fails, attempt to load from %windir%\system.
  368. // We don't call LoadLibrary without a full path because
  369. // it's a security risk.
  370. //
  371. switch (g_ai.dwLibraryFlags) {
  372. case GRABMI_FLAG_APPHELP:
  373. pszLibrary = APPHELP_LIBRARY;
  374. break;
  375. case GRABMI_FLAG_NT:
  376. pszLibrary = SDBAPIU_LIBRARY;
  377. break;
  378. default:
  379. pszLibrary = SDBAPI_LIBRARY;
  380. break;
  381. }
  382. hr = StringCchPrintf(szLibraryPath,
  383. ARRAYSIZE(szLibraryPath),
  384. "%s\\%s",
  385. g_ai.szCurrentDir,
  386. pszLibrary);
  387. if (FAILED(hr)) {
  388. DPF(dlError, "[CallSdbAPIFunctions] Buffer too small (1)");
  389. return FALSE;
  390. }
  391. hModule = LoadLibrary(szLibraryPath);
  392. if (!hModule) {
  393. DPF(dlWarning,
  394. "[CallSdbAPIFunctions] Attempt to load %s failed",
  395. szLibraryPath);
  396. //
  397. // Attempt to load from the system directory.
  398. //
  399. hr = StringCchPrintf(szLibraryPath,
  400. ARRAYSIZE(szLibraryPath),
  401. "%s\\%s",
  402. g_ai.szSystemDir,
  403. pszLibrary);
  404. if (FAILED(hr)) {
  405. DPF(dlError, "[CallSdbAPIFunctions] Buffer too small (2)");
  406. return FALSE;
  407. }
  408. hModule = LoadLibrary(szLibraryPath);
  409. if (!hModule) {
  410. DPF(dlError,
  411. "[CallSdbAPIFunctions] 0x%08X Attempt to load %s failed",
  412. GetLastError(),
  413. szLibraryPath);
  414. return FALSE;
  415. }
  416. }
  417. //
  418. // Get pointers to the functions that we'll be calling.
  419. //
  420. if (0 == g_ai.dwLibraryFlags) {
  421. pfnSdbGrabMatchingInfoExA =
  422. (PFNSdbGrabMatchingInfoExA)GetProcAddress(hModule, PFN_GMI);
  423. if (!pfnSdbGrabMatchingInfoExA) {
  424. DPF(dlError,
  425. "[CallSdbAPIFunctions] 0x%08X Failed to get Ansi function pointer",
  426. GetLastError());
  427. goto cleanup;
  428. }
  429. } else {
  430. pfnSdbGrabMatchingInfoExW =
  431. (PFNSdbGrabMatchingInfoExW)GetProcAddress(hModule, PFN_GMI);
  432. if (!pfnSdbGrabMatchingInfoExW) {
  433. DPF(dlError,
  434. "[CallSdbAPIFunctions] 0x%08X Failed to get Unicode function pointer",
  435. GetLastError());
  436. goto cleanup;
  437. }
  438. }
  439. //
  440. // If we're running on NT/W2K/XP, convert strings to Unicode before making
  441. // the function call.
  442. //
  443. if ((g_ai.dwLibraryFlags & GRABMI_FLAG_NT) ||
  444. (g_ai.dwLibraryFlags & GRABMI_FLAG_APPHELP)) {
  445. if (!MultiByteToWideChar(CP_ACP,
  446. 0,
  447. g_ai.szGrabPath,
  448. -1,
  449. wszGrabPath,
  450. ARRAYSIZE(wszGrabPath))) {
  451. DPF(dlError,
  452. "[CallSdbAPIFunctions] 0x%08X Failed to convert %s",
  453. GetLastError(),
  454. g_ai.szGrabPath);
  455. goto cleanup;
  456. }
  457. if (!MultiByteToWideChar(CP_ACP,
  458. 0,
  459. pszOutputFile,
  460. -1,
  461. wszOutputFile,
  462. ARRAYSIZE(wszGrabPath))) {
  463. DPF(dlError,
  464. "[CallSdbAPIFunctions] 0x%08X Failed to convert %s",
  465. GetLastError(),
  466. pszOutputFile);
  467. goto cleanup;
  468. }
  469. }
  470. if (0 == g_ai.dwLibraryFlags) {
  471. if (pfnSdbGrabMatchingInfoExA(g_ai.szGrabPath,
  472. g_ai.dwFilter | g_ai.dwFilterFlags,
  473. pszOutputFile,
  474. _GrabmiCallback,
  475. NULL) != GMI_SUCCESS) {
  476. DPF(dlError,
  477. "[CallSdbAPIFunctions] Failed to get matching information (Ansi)");
  478. goto cleanup;
  479. }
  480. } else {
  481. if (pfnSdbGrabMatchingInfoExW(wszGrabPath,
  482. g_ai.dwFilter | g_ai.dwFilterFlags,
  483. wszOutputFile,
  484. _GrabmiCallback,
  485. NULL) != GMI_SUCCESS) {
  486. DPF(dlError,
  487. "[CallSdbAPIFunctions] Failed to get matching information (Unicode)");
  488. goto cleanup;
  489. }
  490. }
  491. bResult = TRUE;
  492. cleanup:
  493. FreeLibrary(hModule);
  494. return bResult;
  495. }
  496. /*++
  497. Routine Description:
  498. Displays the contents of the output file to the user.
  499. Arguments:
  500. pszOutputFile - Contains the path to the file we will show
  501. to the user.
  502. Return Value:
  503. TRUE on success, FALSE otherwise.
  504. --*/
  505. BOOL
  506. DisplayOutputFile(
  507. IN LPTSTR pszOutputFile
  508. )
  509. {
  510. const TCHAR szWrite[] = "write";
  511. const TCHAR szNotepad[] = "notepad";
  512. int cchSize;
  513. TCHAR* pszCmdLine = NULL;
  514. BOOL bReturn;
  515. STARTUPINFO si;
  516. PROCESS_INFORMATION pi;
  517. if (!pszOutputFile) {
  518. DPF(dlError, "[DisplayOuputFile] Invalid argument");
  519. return FALSE;
  520. }
  521. cchSize = _tcslen(pszOutputFile);
  522. cchSize += _tcslen(szNotepad);
  523. cchSize += 4; // space, two " marks, and a NULL
  524. pszCmdLine = (TCHAR*)HeapAlloc(GetProcessHeap(),
  525. HEAP_ZERO_MEMORY,
  526. cchSize * sizeof(TCHAR));
  527. if (!pszCmdLine) {
  528. DPF(dlError, "[DisplayOutputFile] Failed to allocate memory");
  529. return FALSE;
  530. }
  531. StringCchPrintf(pszCmdLine,
  532. cchSize,
  533. "%s \"%s\"",
  534. g_ai.dwLibraryFlags ? szNotepad : szWrite,
  535. pszOutputFile);
  536. ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
  537. ZeroMemory(&si, sizeof(STARTUPINFO));
  538. si.cb = sizeof(STARTUPINFO);
  539. //
  540. // BUGBUG: Need to pass lpApplicationName also.
  541. //
  542. bReturn = CreateProcess(NULL,
  543. pszCmdLine,
  544. NULL,
  545. NULL,
  546. FALSE,
  547. 0,
  548. NULL,
  549. NULL,
  550. &si,
  551. &pi);
  552. if (pi.hThread) {
  553. CloseHandle(pi.hThread);
  554. }
  555. if (pi.hProcess) {
  556. CloseHandle(pi.hProcess);
  557. }
  558. HeapFree(GetProcessHeap(), 0, pszCmdLine);
  559. return bReturn;
  560. }
  561. /*++
  562. Routine Description:
  563. Application entry point.
  564. Arguments:
  565. argc - Number command-line of arguments provided by the user.
  566. argv[] - An array of command-line arguments.
  567. Return Value:
  568. 0 on failure, 1 on success.
  569. --*/
  570. int
  571. __cdecl
  572. main(
  573. IN int argc,
  574. IN TCHAR* argv[]
  575. )
  576. {
  577. TCHAR szOutputFile[MAX_PATH];
  578. HRESULT hr;
  579. //
  580. // Perform some initialization.
  581. //
  582. if (!InitializeApplication()) {
  583. DPF(dlError, "[main] Failed to initialize the application");
  584. _tprintf("An error occured while initializing the application\n");
  585. return 0;
  586. }
  587. //
  588. // Parse the command-line and determine our mode of operation.
  589. //
  590. if (!ParseCommandLine(argc, argv)) {
  591. DPF(dlError, "[main] Invalid command-line arguments provided");
  592. DisplayUsage();
  593. return 0;
  594. }
  595. //
  596. // Sanity check here...can't specify a directory name and use the
  597. // -d flag (drivers) at the same time.
  598. //
  599. if (*g_ai.szGrabPath && g_ai.dwFilter == GRABMI_FILTER_DRIVERS) {
  600. _tprintf("Invalid syntax - can't use directory and -d flag together\n\n");
  601. DisplayUsage();
  602. return 0;
  603. }
  604. //
  605. // If the user did not specify a destination file, default to
  606. // %windir%\system32\matchinginfo.txt.
  607. //
  608. if (!*g_ai.szOutputFile) {
  609. hr = StringCchPrintf(szOutputFile,
  610. ARRAYSIZE(szOutputFile),
  611. "%s\\"MATCHINGINFO_FILENAME,
  612. g_ai.szSystemDir);
  613. if (FAILED(hr)) {
  614. DPF(dlError, "[main] Buffer too small for output file");
  615. _tprintf("An error occured while formatting the output file location");
  616. return 0;
  617. }
  618. } else {
  619. hr = StringCchCopy(szOutputFile,
  620. ARRAYSIZE(szOutputFile),
  621. g_ai.szOutputFile);
  622. if (FAILED(hr)) {
  623. DPF(dlError, "[main] Buffer too small for specified output file");
  624. _tprintf("An error occured while formatting the output file location");
  625. return 0;
  626. }
  627. }
  628. //
  629. // If no starting path was specified, check the filter specified
  630. // and go to the system or current directory.
  631. //
  632. if (!*g_ai.szGrabPath) {
  633. if (GRABMI_FILTER_DRIVERS == g_ai.dwFilter) {
  634. hr = StringCchPrintf(g_ai.szGrabPath,
  635. ARRAYSIZE(g_ai.szGrabPath),
  636. "%s\\drivers",
  637. g_ai.szSystemDir);
  638. if (FAILED(hr)) {
  639. DPF(dlError, "[main] Buffer too small for grab path");
  640. _tprintf("An error occured while formatting the starting directory location");
  641. return 0;
  642. }
  643. } else {
  644. hr = StringCchCopy(g_ai.szGrabPath,
  645. ARRAYSIZE(g_ai.szGrabPath),
  646. g_ai.szCurrentDir);
  647. if (FAILED(hr)) {
  648. DPF(dlError, "[main] Buffer too small for specified grab path");
  649. _tprintf("An error occured while formatting the starting directory location");
  650. return 0;
  651. }
  652. }
  653. }
  654. //
  655. // Obtain pointers to functions within our libraries and perform
  656. // the grunt of the work.
  657. //
  658. if (!CallSdbAPIFunctions(szOutputFile)) {
  659. DPF(dlError, "[main] Failed to call the Sdb API functions");
  660. _tprintf("An error occured while attempting to get matching information");
  661. return 0;
  662. }
  663. //
  664. // Success - inform the user and display the file if requested.
  665. //
  666. _tprintf("Matching information retrieved successfully\n");
  667. if (g_ai.fDisplayFile) {
  668. if (!DisplayOutputFile(szOutputFile)) {
  669. DPF(dlError,
  670. "[main] Failed to display output file %s",
  671. szOutputFile);
  672. return 0;
  673. }
  674. }
  675. return 1;
  676. }