blob: 78cfbc67b0fd686e668f8936d7ce830adae1444b [file] [log] [blame]
// 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_