Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(53)

Side by Side Diff: base/native_library_win.cc

Issue 2744043003: Use LoadLibraryExW if applicable in LoadNativeLibrary on Windows (Closed)
Patch Set: Add a wrapper method for UMA. Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/native_library.h" 5 #include "base/native_library.h"
6 6
7 #include <windows.h> 7 #include <windows.h>
8 8
9 #include "base/files/file_util.h" 9 #include "base/files/file_util.h"
10 #include "base/metrics/histogram_macros.h"
10 #include "base/strings/string_util.h" 11 #include "base/strings/string_util.h"
11 #include "base/strings/stringprintf.h" 12 #include "base/strings/stringprintf.h"
12 #include "base/strings/utf_string_conversions.h" 13 #include "base/strings/utf_string_conversions.h"
13 #include "base/threading/thread_restrictions.h" 14 #include "base/threading/thread_restrictions.h"
14 15
15 namespace base { 16 namespace base {
16 17
17 typedef HMODULE (WINAPI* LoadLibraryFunction)(const wchar_t* file_name); 18 typedef HMODULE(WINAPI* AddDllDirectory)(PCWSTR NewDirectory);
18 19
19 namespace { 20 namespace {
21 enum LoadLibraryResult {
Ilya Sherman 2017/03/14 18:42:28 nit: Please document that this is used to back an
chengx 2017/03/14 23:08:30 Done.
22 // LoadLibraryExW API/flags are available and the call succeeds.
23 SUCCEED = 0,
24 // LoadLibraryExW API/flags are availabe to use but the call fails, then
25 // LoadLibraryW is used and succeeds.
26 FAIL_AND_SUCCEED,
27 // LoadLibraryExW API/flags are availabe to use but the call fails, then
28 // LoadLibraryW is used but fails as well.
29 FAIL_AND_FAIL,
30 // LoadLibraryExW API/flags are unavailabe to use, then LoadLibraryW is used
31 // and succeeds.
32 UNAVAILABLE_AND_SUCCEED,
33 // LoadLibraryExW API/flags are unavailabe to use, then LoadLibraryW is used
34 // but fails.
35 UNAVAILABLE_AND_FAIL,
36 // Add new items before this one, always keep this one at the end.
37 END
38 };
39
40 // A helper method to log library loading result to UMA.
41 void LogLibrarayLoadResultToUMA(LoadLibraryResult& result) {
xhwang 2017/03/14 21:48:25 We pretty much never pass non-const ref in Chromiu
chengx 2017/03/14 23:08:30 Yep, should pass by const ref or pass by value (ac
42 UMA_HISTOGRAM_ENUMERATION("LibraryLoader.NativeLibraryDynamicallyLoad",
43 result, LoadLibraryResult::END);
44 }
45
46 // A helper method to check if AddDllDirectory method is available, thus
47 // LOAD_LIBRARY_SEARCH_* flags are available on systems.
48 bool IsLoadLibSearchFlagsAvailable() {
xhwang 2017/03/14 21:48:25 nit: s/Is/Are. Also since this is related to LOAD_
chengx 2017/03/14 23:08:30 Renamed to AreSearchFlagsAvailable().
49 // The LOAD_LIBRARY_SEARCH_* flags are available on systems that have
50 // KB2533623 installed. To determine whether the flags are available, use
51 // GetProcAddress to get the address of the AddDllDirectory,
52 // RemoveDllDirectory, or SetDefaultDllDirectories function. If GetProcAddress
53 // succeeds, the LOAD_LIBRARY_SEARCH_* flags can be used with LoadLibraryEx.
54 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms684179(v=vs.85). aspx
55 // The LOAD_LIBRARY_SEARCH_* flags are used in LoadNativeLibraryHelperEx
56 // method above.
xhwang 2017/03/14 21:48:25 "above" is not accurate now
chengx 2017/03/14 23:08:30 Done.
57 auto add_dll_dir_func = reinterpret_cast<AddDllDirectory>(
58 GetProcAddress(GetModuleHandle(L"kernel32.dll"), "AddDllDirectory"));
59 return !!add_dll_dir_func;
60 }
20 61
21 NativeLibrary LoadNativeLibraryHelper(const FilePath& library_path, 62 NativeLibrary LoadNativeLibraryHelper(const FilePath& library_path,
22 LoadLibraryFunction load_library_api,
23 NativeLibraryLoadError* error) { 63 NativeLibraryLoadError* error) {
24 // LoadLibrary() opens the file off disk. 64 // LoadLibrary() opens the file off disk.
25 ThreadRestrictions::AssertIOAllowed(); 65 ThreadRestrictions::AssertIOAllowed();
26 66
67 HMODULE load_library_module = nullptr;
xhwang 2017/03/14 21:48:25 nit: ISTM the old name |module| is concise and cle
chengx 2017/03/14 23:08:30 Done.
68
69 // This variable records the library loading result.
70 LoadLibraryResult load_library_status = LoadLibraryResult::SUCCEED;
71
72 bool is_load_lib_flags_available = IsLoadLibSearchFlagsAvailable();
73 if (is_load_lib_flags_available) {
74 // LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR flag is needed to search the library
75 // directory as the library may have dependencies on DLLs in this
76 // directory.
77 load_library_module = ::LoadLibraryExW(
78 library_path.value().c_str(), nullptr,
79 LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
80 // If LoadLibraryExW succeeds, log this metric and return.
81 if (load_library_module) {
82 LogLibrarayLoadResultToUMA(load_library_status);
83 return load_library_module;
84 }
85 // GetLastError() needs to be called immediately after
86 // LoadLibraryExW call.
87 if (error)
88 error->code = GetLastError();
89 }
90
91 // If LoadLibraryExW API/flags are unavailable or API call fails, try
92 // LoadLibraryW API.
xhwang 2017/03/14 21:48:25 nit: add an empty line here since these two lines
chengx 2017/03/14 23:08:30 Done.
27 // Switch the current directory to the library directory as the library 93 // Switch the current directory to the library directory as the library
28 // may have dependencies on DLLs in this directory. 94 // may have dependencies on DLLs in this directory.
29 bool restore_directory = false; 95 bool restore_directory = false;
30 FilePath current_directory; 96 FilePath current_directory;
31 if (GetCurrentDirectory(&current_directory)) { 97 if (GetCurrentDirectory(&current_directory)) {
32 FilePath plugin_path = library_path.DirName(); 98 FilePath plugin_path = library_path.DirName();
33 if (!plugin_path.empty()) { 99 if (!plugin_path.empty()) {
34 SetCurrentDirectory(plugin_path); 100 SetCurrentDirectory(plugin_path);
35 restore_directory = true; 101 restore_directory = true;
36 } 102 }
37 } 103 }
38 104
39 HMODULE module = (*load_library_api)(library_path.value().c_str()); 105 load_library_module = ::LoadLibraryW(library_path.value().c_str());
40 if (!module && error) { 106
41 // GetLastError() needs to be called immediately after |load_library_api|. 107 // GetLastError() needs to be called immediately after LoadLibraryW call.
108 if (!load_library_module && error)
42 error->code = GetLastError(); 109 error->code = GetLastError();
43 }
44 110
45 if (restore_directory) 111 if (restore_directory)
46 SetCurrentDirectory(current_directory); 112 SetCurrentDirectory(current_directory);
47 113
48 return module; 114 // Record the library loading result.
115 if (is_load_lib_flags_available) {
116 if (load_library_module)
117 load_library_status = LoadLibraryResult::FAIL_AND_SUCCEED;
118 else
119 load_library_status = LoadLibraryResult::FAIL_AND_FAIL;
120 } else if (load_library_module)
xhwang 2017/03/14 21:48:25 nit: use curly here and below as well: https://go
chengx 2017/03/14 23:08:30 Done.
121 load_library_status = LoadLibraryResult::UNAVAILABLE_AND_SUCCEED;
122 else
123 load_library_status = LoadLibraryResult::UNAVAILABLE_AND_FAIL;
xhwang 2017/03/14 21:48:25 nit: Probably move these into a helper function as
chengx 2017/03/14 23:08:30 Done.
124
125 LogLibrarayLoadResultToUMA(load_library_status);
126
127 return load_library_module;
49 } 128 }
50
51 } // namespace 129 } // namespace
52 130
53 std::string NativeLibraryLoadError::ToString() const { 131 std::string NativeLibraryLoadError::ToString() const {
54 return StringPrintf("%u", code); 132 return StringPrintf("%u", code);
55 } 133 }
56 134
57 // static 135 // static
58 NativeLibrary LoadNativeLibraryWithOptions(const FilePath& library_path, 136 NativeLibrary LoadNativeLibraryWithOptions(const FilePath& library_path,
59 const NativeLibraryOptions& options, 137 const NativeLibraryOptions& options,
60 NativeLibraryLoadError* error) { 138 NativeLibraryLoadError* error) {
61 return LoadNativeLibraryHelper(library_path, LoadLibraryW, error); 139 return LoadNativeLibraryHelper(library_path, error);
62 }
63
64 NativeLibrary LoadNativeLibraryDynamically(const FilePath& library_path) {
65 typedef HMODULE (WINAPI* LoadLibraryFunction)(const wchar_t* file_name);
66
67 LoadLibraryFunction load_library = reinterpret_cast<LoadLibraryFunction>(
68 GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW"));
69
70 return LoadNativeLibraryHelper(library_path, load_library, NULL);
71 } 140 }
72 141
73 // static 142 // static
74 void UnloadNativeLibrary(NativeLibrary library) { 143 void UnloadNativeLibrary(NativeLibrary library) {
75 FreeLibrary(library); 144 FreeLibrary(library);
76 } 145 }
77 146
78 // static 147 // static
79 void* GetFunctionPointerFromNativeLibrary(NativeLibrary library, 148 void* GetFunctionPointerFromNativeLibrary(NativeLibrary library,
80 StringPiece name) { 149 StringPiece name) {
81 return GetProcAddress(library, name.data()); 150 return GetProcAddress(library, name.data());
82 } 151 }
83 152
84 // static 153 // static
85 std::string GetNativeLibraryName(StringPiece name) { 154 std::string GetNativeLibraryName(StringPiece name) {
86 DCHECK(IsStringASCII(name)); 155 DCHECK(IsStringASCII(name));
87 return name.as_string() + ".dll"; 156 return name.as_string() + ".dll";
88 } 157 }
89 158
90 } // namespace base 159 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698