1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/install_verification/win/loaded_modules_snapshot.h"
6
7#include <Psapi.h>
8
9#include "base/logging.h"
10
11bool GetLoadedModulesSnapshot(std::vector<HMODULE>* snapshot) {
12  DCHECK(snapshot);
13  DCHECK_EQ(0u, snapshot->size());
14  snapshot->resize(1);
15
16  HANDLE process = ::GetCurrentProcess();
17
18  // We will retry at least once after first determining |bytes_required|. If
19  // the list of modules changes after we receive |bytes_required| we may retry
20  // more than once.
21  int retries_remaining = 5;
22  do {
23    DWORD bytes_required = 0;
24    // EnumProcessModules returns 'success' even if the buffer size is too
25    // small.
26    if (!::EnumProcessModules(process,
27                              &(*snapshot)[0],
28                              snapshot->size() * sizeof(HMODULE),
29                              &bytes_required)) {
30      DPLOG(ERROR) << "::EnumProcessModules failed.";
31      return false;
32    }
33    DCHECK_EQ(0u, bytes_required % sizeof(HMODULE));
34    size_t num_modules = bytes_required / sizeof(HMODULE);
35    if (num_modules <= snapshot->size()) {
36      // Buffer size was too big, presumably because a module was unloaded.
37      snapshot->erase(snapshot->begin() + num_modules, snapshot->end());
38      return true;
39    } else if (num_modules == 0) {
40      DLOG(ERROR) << "Can't determine the module list size.";
41      return false;
42    } else {
43      // Buffer size was too small. Try again with a larger buffer.
44      snapshot->resize(num_modules, NULL);
45    }
46  } while (--retries_remaining);
47
48  DLOG(ERROR) << "Failed to enumerate modules.";
49  return false;
50}
51