Created
June 24, 2025 14:31
-
-
Save deepak1556/f11695e81ae7972c7f0bdadb3565deb3 to your computer and use it in GitHub Desktop.
Patch to make Electron load resources from a versioned folder that is extracted from exe file info
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
``` | |
diff --git a/base/base_paths.cc b/base/base_paths.cc | |
index 59ffbd2b67501..2eb39666e8778 100644 | |
--- a/base/base_paths.cc | |
+++ b/base/base_paths.cc | |
@@ -71,8 +71,10 @@ bool PathProvider(int key, FilePath* result) { | |
} | |
*result = result->DirName(); | |
return true; | |
+#if !BUILDFLAG(IS_WIN) | |
case DIR_ASSETS: | |
return PathService::Get(DIR_MODULE, result); | |
+#endif // !BUILDFLAG(IS_WIN) | |
#endif // !BUILDFLAG(IS_FUCHSIA) && !BUILDFLAG(IS_IOS) | |
case DIR_TEMP: | |
return GetTempDir(result); | |
diff --git a/base/base_paths_win.cc b/base/base_paths_win.cc | |
index aa9d066a2a994..f4ea3c1ef3801 100644 | |
--- a/base/base_paths_win.cc | |
+++ b/base/base_paths_win.cc | |
@@ -12,8 +12,10 @@ | |
#include "base/environment.h" | |
#include "base/files/file_path.h" | |
#include "base/files/file_util.h" | |
+#include "base/file_version_info.h" | |
#include "base/path_service.h" | |
#include "base/strings/string_util.h" | |
+#include "base/strings/string_util_win.h" | |
#include "base/strings/utf_string_conversions.h" | |
#include "base/win/current_module.h" | |
#include "base/win/scoped_co_mem.h" | |
@@ -49,6 +51,18 @@ bool PathProviderWin(int key, FilePath* result) { | |
cur = FilePath(system_buffer); | |
break; | |
} | |
+ case base::DIR_ASSETS: { | |
+ auto file_version_info = FileVersionInfo::CreateFileVersionInfoForModule( | |
+ CURRENT_MODULE()); | |
+ if (!PathService::Get(DIR_MODULE, &cur)) { | |
+ return false; | |
+ } | |
+ if (!file_version_info) { | |
+ break; | |
+ } | |
+ cur = cur.Append(base::AsWString(file_version_info->product_version())); | |
+ break; | |
+ } | |
case base::DIR_WINDOWS: | |
GetWindowsDirectory(system_buffer, MAX_PATH); | |
cur = FilePath(system_buffer); | |
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.cc b/content/browser/gpu/gpu_data_manager_impl_private.cc | |
index 003659857de3c..f64a4acdea81c 100644 | |
--- a/content/browser/gpu/gpu_data_manager_impl_private.cc | |
+++ b/content/browser/gpu/gpu_data_manager_impl_private.cc | |
@@ -152,7 +152,7 @@ bool GetIntelCacheFileNames(std::vector<base::FilePath::StringType>* names) { | |
DCHECK(names); | |
DCHECK(names->empty()); | |
base::FilePath module_path; | |
- if (!base::PathService::Get(base::FILE_EXE, &module_path)) | |
+ if (!base::PathService::Get(base::DIR_ASSETS, &module_path)) | |
return false; | |
module_path = module_path.BaseName().RemoveExtension(); | |
base::FilePath::StringType module_name = module_path.value(); | |
diff --git a/sandbox/policy/win/sandbox_win.cc b/sandbox/policy/win/sandbox_win.cc | |
index 53b72124ffaa7..bcc2f90c6920d 100644 | |
--- a/sandbox/policy/win/sandbox_win.cc | |
+++ b/sandbox/policy/win/sandbox_win.cc | |
@@ -151,10 +151,10 @@ ResultCode AddGenericConfig(sandbox::TargetConfig* config) { | |
// Add the policy for read-only PDB file access for stack traces. | |
#if !defined(OFFICIAL_BUILD) | |
- base::FilePath exe; | |
- if (!base::PathService::Get(base::FILE_EXE, &exe)) | |
+ base::FilePath assets_path; | |
+ if (!base::PathService::Get(base::DIR_ASSETS, &assets_path)) | |
return SBOX_ERROR_GENERIC; | |
- base::FilePath pdb_path = exe.DirName().Append(L"*.pdb"); | |
+ base::FilePath pdb_path = assets_path.Append(L"*.pdb"); | |
{ | |
ResultCode result = config->AllowFileAccess(FileSemantics::kAllowReadonly, | |
pdb_path.value().c_str()); | |
diff --git a/sandbox/win/src/process_mitigations.cc b/sandbox/win/src/process_mitigations.cc | |
index 39282ab6be12d..2f15ef4d448c5 100644 | |
--- a/sandbox/win/src/process_mitigations.cc | |
+++ b/sandbox/win/src/process_mitigations.cc | |
@@ -21,6 +21,7 @@ | |
#include "base/check_op.h" | |
#include "base/files/file_path.h" | |
#include "base/notreached.h" | |
+#include "base/path_service.h" | |
#include "base/rand_util.h" | |
#include "base/scoped_native_library.h" | |
#include "base/win/access_token.h" | |
@@ -119,6 +120,13 @@ bool ApplyProcessMitigationsToCurrentProcess(MitigationFlags starting_flags, | |
return false; | |
} | |
+++ b/sandbox/policy/win/sandbox_win.cc | |
@@ -151,10 +151,10 @@ ResultCode AddGenericConfig(sandbox::TargetConfig* config) { | |
// Add the policy for read-only PDB file access for stack traces. | |
#if !defined(OFFICIAL_BUILD) | |
- base::FilePath exe; | |
- if (!base::PathService::Get(base::FILE_EXE, &exe)) | |
+ base::FilePath assets_path; | |
+ if (!base::PathService::Get(base::DIR_ASSETS, &assets_path)) | |
return SBOX_ERROR_GENERIC; | |
- base::FilePath pdb_path = exe.DirName().Append(L"*.pdb"); | |
+ base::FilePath pdb_path = assets_path.Append(L"*.pdb"); | |
{ | |
ResultCode result = config->AllowFileAccess(FileSemantics::kAllowReadonly, | |
pdb_path.value().c_str()); | |
diff --git a/sandbox/win/src/process_mitigations.cc b/sandbox/win/src/process_mitigations.cc | |
index 39282ab6be12d..2f15ef4d448c5 100644 | |
--- a/sandbox/win/src/process_mitigations.cc | |
+++ b/sandbox/win/src/process_mitigations.cc | |
@@ -21,6 +21,7 @@ | |
#include "base/check_op.h" | |
#include "base/files/file_path.h" | |
#include "base/notreached.h" | |
+#include "base/path_service.h" | |
#include "base/rand_util.h" | |
#include "base/scoped_native_library.h" | |
#include "base/win/access_token.h" | |
@@ -119,6 +120,13 @@ bool ApplyProcessMitigationsToCurrentProcess(MitigationFlags starting_flags, | |
return false; | |
} | |
+ base::FilePath assets_path; | |
+ if (base::PathService::Get(base::DIR_ASSETS, &assets_path)) { | |
+ LOG(WARNING) << "Adding assets path to DLL search order: " | |
+ << assets_path.value(); | |
+ AddDllDirectory(assets_path.value().c_str()); | |
+ } | |
+ | |
applied_flags |= MITIGATION_DLL_SEARCH_ORDER; | |
} | |
``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
``` | |
diff --git a/shell/app/electron_main_delegate.cc b/shell/app/electron_main_delegate.cc | |
index a66e140a1e..36ddcb15e0 100644 | |
--- a/shell/app/electron_main_delegate.cc | |
+++ b/shell/app/electron_main_delegate.cc | |
@@ -218,7 +218,7 @@ std::string LoadResourceBundle(const std::string& locale) { | |
pak_dir = | |
base::apple::FrameworkBundlePath().Append(FILE_PATH_LITERAL("Resources")); | |
#else | |
- base::PathService::Get(base::DIR_MODULE, &pak_dir); | |
+ base::PathService::Get(base::DIR_ASSETS, &pak_dir); | |
#endif | |
std::string loaded_locale = ui::ResourceBundle::InitSharedInstanceWithLocale( | |
diff --git a/shell/app/electron_main_win.cc b/shell/app/electron_main_win.cc | |
index da0143a9e6..30e9b00cf7 100644 | |
--- a/shell/app/electron_main_win.cc | |
+++ b/shell/app/electron_main_win.cc | |
@@ -13,17 +13,26 @@ | |
#include <cstdlib> | |
#include <memory> | |
#include <string> | |
+#include <string_view> | |
#include <utility> | |
+#include "base/base_paths.h" | |
#include "base/at_exit.h" | |
#include "base/debug/alias.h" | |
+#include "base/files/file.h" | |
+#include "base/files/file_path.h" | |
+#include "base/files/file_util.h" | |
#include "base/i18n/icu_util.h" | |
+#include "base/logging.h" | |
#include "base/memory/raw_ptr_exclusion.h" | |
+#include "base/path_service.h" | |
#include "base/process/launch.h" | |
#include "base/strings/cstring_view.h" | |
+#include "base/strings/string_util.h" | |
#include "base/strings/utf_string_conversions.h" | |
#include "base/win/dark_mode_support.h" | |
#include "chrome/app/exit_code_watcher_win.h" | |
+#include "chrome/common/win/delay_load_notify_hook.h" | |
#include "components/crash/core/app/crash_switches.h" | |
#include "components/crash/core/app/run_as_crashpad_handler_win.h" | |
#include "content/public/app/content_main.h" | |
@@ -44,6 +53,7 @@ namespace { | |
// from //electron:electron_app | |
const char kUserDataDir[] = "user-data-dir"; | |
const char kProcessType[] = "type"; | |
+const wchar_t kFFmpegDll[] = L"ffmpeg.dll"; | |
[[nodiscard]] bool IsEnvSet(const base::cstring_view name) { | |
size_t required_size = 0; | |
@@ -51,6 +61,58 @@ const char kProcessType[] = "type"; | |
return required_size != 0; | |
} | |
+// Indicates whether a file can be opened using the same flags that | |
+// ::LoadLibrary() uses to open modules. | |
+bool ModuleCanBeRead(const base::FilePath& file_path) { | |
+ return base::File(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ) | |
+ .IsValid(); | |
+} | |
+ | |
+// Returns the full path to |module_name|. | |
+base::FilePath GetModulePath(std::wstring_view module_name) { | |
+ base::FilePath assets_dir; | |
+ const bool has_path = base::PathService::Get(base::DIR_ASSETS, &assets_dir); | |
+ DCHECK(has_path); | |
+ | |
+ // Look for the module in a versioned sub-directory of the current | |
+ // executable's directory and return the path if it can be read. This is the | |
+ // expected location of modules for proper installs. | |
+ const base::FilePath module_path = | |
+ assets_dir.Append(module_name); | |
+ if (ModuleCanBeRead(module_path)) | |
+ return module_path; | |
+ | |
+ // Othwerwise, return the path to the module in the current executable's | |
+ // directory. This is the expected location of modules for dev builds. | |
+ base::FilePath exe_dir; | |
+ DCHECK(base::PathService::Get(base::DIR_EXE, &exe_dir)); | |
+ return exe_dir.Append(module_name); | |
+} | |
+ | |
+FARPROC DelayLoadCallback(unsigned delay_load_event, | |
+ DelayLoadInfo* delay_load_info) { | |
+ if (delay_load_event == dliNotePreLoadLibrary && | |
+ base::EqualsCaseInsensitiveASCII( | |
+ delay_load_info->szDll, "ffmpeg.dll")) { | |
+ PLOG(WARNING) << "Delay load event: " << delay_load_event | |
+ << ", Dll: " << delay_load_info->szDll; | |
+ base::FilePath file = GetModulePath(kFFmpegDll); | |
+ if (file.empty()) { | |
+ PLOG(ERROR) << "Cannot find module " << kFFmpegDll; | |
+ return nullptr; | |
+ } | |
+ ::SetCurrentDirectoryW(file.DirName().value().c_str()); | |
+ HMODULE handle = ::LoadLibraryExW(file.value().c_str(), nullptr, | |
+ LOAD_WITH_ALTERED_SEARCH_PATH); | |
+ if (!handle) { | |
+ PLOG(ERROR) << "Failed to load FFmpeg DLL from " << file.value(); | |
+ return nullptr; | |
+ } | |
+ return reinterpret_cast<FARPROC>(handle); | |
+ } | |
+ return nullptr; | |
+} | |
+ | |
} // namespace | |
namespace crash_reporter { | |
@@ -220,6 +282,8 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) { | |
if (!electron::CheckCommandLineArguments(command_line->argv())) | |
return -1; | |
+ chrome::SetDelayLoadHookCallback(&DelayLoadCallback); | |
+ | |
sandbox::SandboxInterfaceInfo sandbox_info = {nullptr}; | |
content::InitializeSandboxInfo(&sandbox_info); | |
electron::ElectronMainDelegate delegate; | |
diff --git a/shell/browser/api/electron_api_app.cc b/shell/browser/api/electron_api_app.cc | |
index 3c19d19172..cc7a2f4e37 100644 | |
--- a/shell/browser/api/electron_api_app.cc | |
+++ b/shell/browser/api/electron_api_app.cc | |
@@ -399,6 +399,7 @@ int GetPathConstant(std::string_view name) { | |
{"pictures", chrome::DIR_USER_PICTURES}, | |
#if BUILDFLAG(IS_WIN) | |
{"recent", electron::DIR_RECENT}, | |
+ {"assets", base::DIR_ASSETS}, | |
#endif | |
{"sessionData", DIR_SESSION_DATA}, | |
{"temp", base::DIR_TEMP}, | |
diff --git a/shell/common/asar/archive_win.cc b/shell/common/asar/archive_win.cc | |
index d1deb6e346..effcde3ba3 100644 | |
--- a/shell/common/asar/archive_win.cc | |
+++ b/shell/common/asar/archive_win.cc | |
@@ -24,13 +24,13 @@ const wchar_t kIntegrityCheckResourceType[] = L"Integrity"; | |
const wchar_t kIntegrityCheckResourceItem[] = L"ElectronAsar"; | |
std::optional<base::FilePath> Archive::RelativePath() const { | |
- base::FilePath exe_path; | |
- if (!base::PathService::Get(base::FILE_EXE, &exe_path)) { | |
- LOG(FATAL) << "Couldn't get exe file path"; | |
+ base::FilePath assets_path; | |
+ if (!base::PathService::Get(base::DIR_ASSETS, &assets_path)) { | |
+ LOG(FATAL) << "Couldn't get assets file path"; | |
} | |
base::FilePath relative_path; | |
- if (!exe_path.DirName().AppendRelativePath(path_, &relative_path)) { | |
+ if (!assets_path.AppendRelativePath(path_, &relative_path)) { | |
return std::nullopt; | |
} | |
diff --git a/shell/common/node_bindings.cc b/shell/common/node_bindings.cc | |
index 9ad2274e6a..1a92ad0ae5 100644 | |
--- a/shell/common/node_bindings.cc | |
+++ b/shell/common/node_bindings.cc | |
@@ -442,11 +442,10 @@ base::FilePath GetResourcesPath() { | |
#if BUILDFLAG(IS_MAC) | |
return MainApplicationBundlePath().Append("Contents").Append("Resources"); | |
#else | |
- auto* command_line = base::CommandLine::ForCurrentProcess(); | |
- base::FilePath exec_path(command_line->GetProgram()); | |
- base::PathService::Get(base::FILE_EXE, &exec_path); | |
+ base::FilePath assets_path; | |
+ base::PathService::Get(base::DIR_ASSETS, &assets_path); | |
- return exec_path.DirName().Append(FILE_PATH_LITERAL("resources")); | |
+ return assets_path.Append(FILE_PATH_LITERAL("resources")); | |
#endif | |
} | |
} // namespace | |
``` |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
StringFileInfo block in the resources only has limited size for the version string and it cannot capture the values we want. Moving it to the StringTable helps overcome the size limit. Following changes need to be adopted to read from the table instead,