910e62b5创建于 1月15日历史提交
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BASE_WIN_DELAYLOAD_HELPERS_H_
#define BASE_WIN_DELAYLOAD_HELPERS_H_

#include <windows.h>

#include <delayimp.h>

#include "base/strings/cstring_view.h"
#include "base/types/expected.h"

namespace base::win {

// Resolves all delayload imports for `module` rather than doing so when the
// functions are first called. Returns `bool:true` if the attempt succeeded,
// `bool:false` if the module is not a delayloaded dep of the current module
// (this often happens in tests or the component build), or an `HRESULT` error
// otherwise. This helper is `inline` so that the module calling this helper
// is the one that attempts the import (rather than base.dll in the component
// build), and brings in `<windows.h>`.
//
// See docs for __HrLoadAllImportsForDll() at
// https://learn.microsoft.com/en-us/cpp/build/reference/linker-support-for-delay-loaded-dlls
//
// Note that `dll_name` is case-sensitive including the dll extension and must
// match the name listed in the current module's delayloaded imports section.
inline base::expected<bool, HRESULT> LoadAllImportsForDll(
    base::cstring_view dll_name) {
  HRESULT hr = E_FAIL;
  __try {
    hr = ::__HrLoadAllImportsForDll(dll_name.c_str());

    if (hr == HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND)) {
      // __HrLoadAllImportsForDll returns this exact value (FACILITY_WIN32)
      // if the module is not found in the calling module's list of delay
      // imports. This may be the case in the component build or in tests,
      // where the module may be delayloaded by some module other than
      // chrome.dll or the test binary.
      return base::ok(false);
    }
  } __except (HRESULT_FACILITY(::GetExceptionCode()) == FACILITY_VISUALCPP
                  ? EXCEPTION_EXECUTE_HANDLER
                  : EXCEPTION_CONTINUE_SEARCH) {
    // Resolution of all imports failed; possibly because the module failed to
    // load or because one or more imports was not found. Note that the filter
    // expression above matches exceptions where the code is an HRESULT with the
    // facility bits set to FACILITY_VISUALCPP, so the following cast is safe.
    hr = static_cast<HRESULT>(::GetExceptionCode());
  }
  if (FAILED(hr)) {
    return base::unexpected(hr);
  }
  return base::ok(true);
}

}  // namespace base::win

#endif  // BASE_WIN_DELAYLOAD_HELPERS_H_