mirror of
https://github.com/chromium/crashpad.git
synced 2024-12-27 15:32:10 +08:00
win: Add and use GET_FUNCTION() and GET_FUNCTION_REQUIRED()
These wrap the GetProcAddress(LoadLibrary(), …) idiom into macros that are much less wordy. TEST=crashpad_util_test GetFunction.GetFunction and all others R=scottmg@chromium.org Review URL: https://codereview.chromium.org/1405323003 .
This commit is contained in:
parent
2adcd13fd6
commit
d075a9eb2e
@ -25,6 +25,7 @@
|
||||
#include "client/crashpad_client.h"
|
||||
#include "tools/tool_support.h"
|
||||
#include "util/win/critical_section_with_debug_info.h"
|
||||
#include "util/win/get_function.h"
|
||||
|
||||
namespace crashpad {
|
||||
namespace {
|
||||
@ -32,10 +33,8 @@ namespace {
|
||||
CRITICAL_SECTION g_test_critical_section;
|
||||
|
||||
ULONG RtlNtStatusToDosError(NTSTATUS status) {
|
||||
static decltype(::RtlNtStatusToDosError)* rtl_nt_status_to_dos_error =
|
||||
reinterpret_cast<decltype(::RtlNtStatusToDosError)*>(
|
||||
GetProcAddress(LoadLibrary(L"ntdll.dll"), "RtlNtStatusToDosError"));
|
||||
DCHECK(rtl_nt_status_to_dos_error);
|
||||
static const auto rtl_nt_status_to_dos_error =
|
||||
GET_FUNCTION_REQUIRED(L"ntdll.dll", ::RtlNtStatusToDosError);
|
||||
return rtl_nt_status_to_dos_error(status);
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "snapshot/win/process_reader_win.h"
|
||||
#include "util/win/get_function.h"
|
||||
|
||||
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||
|
||||
@ -30,10 +31,8 @@ BOOL CrashpadGetModuleInformation(HANDLE process,
|
||||
HMODULE module,
|
||||
MODULEINFO* module_info,
|
||||
DWORD cb) {
|
||||
static decltype(GetModuleInformation)* get_module_information =
|
||||
reinterpret_cast<decltype(GetModuleInformation)*>(
|
||||
GetProcAddress(LoadLibrary(L"psapi.dll"), "GetModuleInformation"));
|
||||
DCHECK(get_module_information);
|
||||
static const auto get_module_information =
|
||||
GET_FUNCTION_REQUIRED(L"psapi.dll", ::GetModuleInformation);
|
||||
return get_module_information(process, module, module_info, cb);
|
||||
}
|
||||
|
||||
|
@ -156,6 +156,8 @@
|
||||
'win/critical_section_with_debug_info.h',
|
||||
'win/exception_handler_server.cc',
|
||||
'win/exception_handler_server.h',
|
||||
'win/get_function.cc',
|
||||
'win/get_function.h',
|
||||
'win/module_version.cc',
|
||||
'win/module_version.h',
|
||||
'win/nt_internals.cc',
|
||||
|
@ -82,6 +82,7 @@
|
||||
'win/capture_context_test.cc',
|
||||
'win/critical_section_with_debug_info_test.cc',
|
||||
'win/exception_handler_server_test.cc',
|
||||
'win/get_function_test.cc',
|
||||
'win/process_info_test.cc',
|
||||
'win/scoped_process_suspend_test.cc',
|
||||
'win/time_test.cc',
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "util/win/critical_section_with_debug_info.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "util/win/get_function.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
@ -24,13 +25,8 @@ BOOL CrashpadInitializeCriticalSectionEx(
|
||||
CRITICAL_SECTION* critical_section,
|
||||
DWORD spin_count,
|
||||
DWORD flags) {
|
||||
static decltype(InitializeCriticalSectionEx)* initialize_critical_section_ex =
|
||||
reinterpret_cast<decltype(InitializeCriticalSectionEx)*>(GetProcAddress(
|
||||
LoadLibrary(L"kernel32.dll"), "InitializeCriticalSectionEx"));
|
||||
if (!initialize_critical_section_ex) {
|
||||
PLOG(ERROR) << "GetProcAddress";
|
||||
return false;
|
||||
}
|
||||
static const auto initialize_critical_section_ex =
|
||||
GET_FUNCTION_REQUIRED(L"kernel32.dll", ::InitializeCriticalSectionEx);
|
||||
bool ret =
|
||||
initialize_critical_section_ex(critical_section, spin_count, flags);
|
||||
if (!ret) {
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "util/file/file_writer.h"
|
||||
#include "util/misc/tri_state.h"
|
||||
#include "util/misc/uuid.h"
|
||||
#include "util/win/get_function.h"
|
||||
#include "util/win/registration_protocol_win.h"
|
||||
#include "util/win/xp_compat.h"
|
||||
|
||||
@ -35,10 +36,9 @@ namespace crashpad {
|
||||
namespace {
|
||||
|
||||
decltype(GetNamedPipeClientProcessId)* GetNamedPipeClientProcessIdFunction() {
|
||||
static decltype(GetNamedPipeClientProcessId)* func =
|
||||
reinterpret_cast<decltype(GetNamedPipeClientProcessId)*>(GetProcAddress(
|
||||
GetModuleHandle(L"kernel32.dll"), "GetNamedPipeClientProcessId"));
|
||||
return func;
|
||||
static const auto get_named_pipe_client_process_id =
|
||||
GET_FUNCTION(L"kernel32.dll", ::GetNamedPipeClientProcessId);
|
||||
return get_named_pipe_client_process_id;
|
||||
}
|
||||
|
||||
HANDLE DuplicateEvent(HANDLE process, HANDLE event) {
|
||||
|
44
util/win/get_function.cc
Normal file
44
util/win/get_function.cc
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright 2015 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "util/win/get_function.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
|
||||
namespace crashpad {
|
||||
namespace internal {
|
||||
|
||||
FARPROC GetFunctionInternal(
|
||||
const wchar_t* library, const char* function, bool required) {
|
||||
HMODULE module = LoadLibrary(library);
|
||||
DPCHECK(!required || module) << "LoadLibrary " << base::UTF16ToUTF8(library);
|
||||
if (!module) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Strip off any leading :: that may have come from stringifying the
|
||||
// function’s name.
|
||||
if (function[0] == ':' && function[1] == ':' &&
|
||||
function[2] && function[2] != ':') {
|
||||
function += 2;
|
||||
}
|
||||
|
||||
FARPROC proc = GetProcAddress(module, function);
|
||||
DPCHECK(!required || proc) << "GetProcAddress " << function;
|
||||
return proc;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace crashpad
|
121
util/win/get_function.h
Normal file
121
util/win/get_function.h
Normal file
@ -0,0 +1,121 @@
|
||||
// Copyright 2015 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef CRASHPAD_UTIL_WIN_GET_FUNCTION_H_
|
||||
#define CRASHPAD_UTIL_WIN_GET_FUNCTION_H_
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
//! \file
|
||||
|
||||
namespace crashpad {
|
||||
namespace internal {
|
||||
|
||||
//! \brief Returns a function pointer to a named function in a library.
|
||||
//!
|
||||
//! Do not call this directly, use the GET_FUNCTION() or GET_FUNCTION_REQUIRED()
|
||||
//! macros instead.
|
||||
//!
|
||||
//! This accesses \a library by calling `LoadLibrary()` and is subject to the
|
||||
//! same restrictions as that function. Notably, it can’t be used from a
|
||||
//! `DllMain()` entry point.
|
||||
//!
|
||||
//! \param[in] library The library to search in.
|
||||
//! \param[in] function The function to search for. If a leading `::` is
|
||||
//! present, it will be stripped.
|
||||
//! \param[in] required If `true`, require the function to resolve by `DCHECK`.
|
||||
//!
|
||||
//! \return A pointer to the requested function on success. If \a required is
|
||||
//! `true`, triggers a `DCHECK` assertion on failure, otherwise, `nullptr`
|
||||
//! on failure.
|
||||
FARPROC GetFunctionInternal(
|
||||
const wchar_t* library, const char* function, bool required);
|
||||
|
||||
//! \copydoc GetFunctionInternal
|
||||
template <typename FunctionType>
|
||||
FunctionType* GetFunction(
|
||||
const wchar_t* library, const char* function, bool required) {
|
||||
return reinterpret_cast<FunctionType*>(
|
||||
internal::GetFunctionInternal(library, function, required));
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace crashpad
|
||||
|
||||
//! \brief Returns a function pointer to a named function in a library without
|
||||
//! requiring that it be found.
|
||||
//!
|
||||
//! If the library or function cannot be found, this will return `nullptr`. This
|
||||
//! macro is intended to be used to access functions that may not be available
|
||||
//! at runtime.
|
||||
//!
|
||||
//! This macro returns a properly-typed function pointer. It is expected to be
|
||||
//! used in this way:
|
||||
//! \code
|
||||
//! static const auto get_named_pipe_client_process_id =
|
||||
//! GET_FUNCTION(L"kernel32.dll", ::GetNamedPipeClientProcessId);
|
||||
//! if (get_named_pipe_client_process_id) {
|
||||
//! BOOL rv = get_named_pipe_client_process_id(pipe, &client_process_id);
|
||||
//! }
|
||||
//! \endcode
|
||||
//!
|
||||
//! This accesses \a library by calling `LoadLibrary()` and is subject to the
|
||||
//! same restrictions as that function. Notably, it can’t be used from a
|
||||
//! `DllMain()` entry point.
|
||||
//!
|
||||
//! \param[in] library The library to search in.
|
||||
//! \param[in] function The function to search for. A leading `::` is
|
||||
//! recommended when a wrapper function of the same name is present.
|
||||
//!
|
||||
//! \return A pointer to the requested function on success, or `nullptr` on
|
||||
//! failure.
|
||||
//!
|
||||
//! \sa GET_FUNCTION_REQUIRED
|
||||
#define GET_FUNCTION(library, function) \
|
||||
crashpad::internal::GetFunction<decltype(function)>( \
|
||||
library, #function, false)
|
||||
|
||||
//! \brief Returns a function pointer to a named function in a library,
|
||||
//! requiring that it be found.
|
||||
//!
|
||||
//! If the library or function cannot be found, this will trigger a `DCHECK`
|
||||
//! assertion. This macro is intended to be used to access functions that are
|
||||
//! always expected to be available at runtime but which are not present in any
|
||||
//! import library.
|
||||
//!
|
||||
//! This macro returns a properly-typed function pointer. It is expected to be
|
||||
//! used in this way:
|
||||
//! \code
|
||||
//! static const auto nt_query_object =
|
||||
//! GET_FUNCTION_REQUIRED(L"ntdll.dll", ::NtQueryObject);
|
||||
//! NTSTATUS status =
|
||||
//! nt_query_object(handle, type, &info, info_length, &return_length);
|
||||
//! \endcode
|
||||
//!
|
||||
//! This accesses \a library by calling `LoadLibrary()` and is subject to the
|
||||
//! same restrictions as that function. Notably, it can’t be used from a
|
||||
//! `DllMain()` entry point.
|
||||
//!
|
||||
//! \param[in] library The library to search in.
|
||||
//! \param[in] function The function to search for. A leading `::` is
|
||||
//! recommended when a wrapper function of the same name is present.
|
||||
//!
|
||||
//! \return A pointer to the requested function.
|
||||
//!
|
||||
//! \sa GET_FUNCTION
|
||||
#define GET_FUNCTION_REQUIRED(library, function) \
|
||||
crashpad::internal::GetFunction<decltype(function)>( \
|
||||
library, #function, true)
|
||||
|
||||
#endif // CRASHPAD_UTIL_WIN_GET_FUNCTION_H_
|
78
util/win/get_function_test.cc
Normal file
78
util/win/get_function_test.cc
Normal file
@ -0,0 +1,78 @@
|
||||
// Copyright 2015 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "util/win/get_function.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <winternl.h>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace crashpad {
|
||||
namespace test {
|
||||
namespace {
|
||||
|
||||
TEST(GetFunction, GetFunction) {
|
||||
// Check equivalence of GET_FUNCTION_REQUIRED() with functions that are
|
||||
// available in the SDK normally.
|
||||
EXPECT_EQ(&GetProcAddress,
|
||||
GET_FUNCTION_REQUIRED(L"kernel32.dll", GetProcAddress));
|
||||
EXPECT_EQ(&LoadLibraryW,
|
||||
GET_FUNCTION_REQUIRED(L"kernel32.dll", LoadLibraryW));
|
||||
|
||||
// Make sure that a function pointer retrieved by GET_FUNCTION_REQUIRED() can
|
||||
// be called and that it works correctly.
|
||||
const auto get_current_process_id =
|
||||
GET_FUNCTION_REQUIRED(L"kernel32.dll", GetCurrentProcessId);
|
||||
EXPECT_EQ(&GetCurrentProcessId, get_current_process_id);
|
||||
ASSERT_TRUE(get_current_process_id);
|
||||
EXPECT_EQ(GetCurrentProcessId(), get_current_process_id());
|
||||
|
||||
// GET_FUNCTION_REQUIRED() and GET_FUNCTION() should behave identically when
|
||||
// the function is present.
|
||||
EXPECT_EQ(get_current_process_id,
|
||||
GET_FUNCTION(L"kernel32.dll", GetCurrentProcessId));
|
||||
|
||||
// Using a leading :: should also work.
|
||||
EXPECT_EQ(get_current_process_id,
|
||||
GET_FUNCTION(L"kernel32.dll", ::GetCurrentProcessId));
|
||||
EXPECT_EQ(get_current_process_id,
|
||||
GET_FUNCTION_REQUIRED(L"kernel32.dll", ::GetCurrentProcessId));
|
||||
|
||||
// Try a function that’s declared in the SDK’s headers but that has no import
|
||||
// library.
|
||||
EXPECT_TRUE(GET_FUNCTION_REQUIRED(L"ntdll.dll", RtlNtStatusToDosError));
|
||||
|
||||
// GetNamedPipeClientProcessId() is only available on Vista and later.
|
||||
const auto get_named_pipe_client_process_id =
|
||||
GET_FUNCTION(L"kernel32.dll", GetNamedPipeClientProcessId);
|
||||
const DWORD version = GetVersion();
|
||||
const DWORD major_version = LOBYTE(LOWORD(version));
|
||||
EXPECT_EQ(major_version >= 6, get_named_pipe_client_process_id != nullptr);
|
||||
|
||||
// Test that GET_FUNCTION() can fail by trying a nonexistent library and a
|
||||
// symbol that doesn’t exist in the specified library.
|
||||
EXPECT_FALSE(GET_FUNCTION(L"not_a_real_library.dll", TerminateProcess));
|
||||
EXPECT_FALSE(GET_FUNCTION(L"ntdll.dll", TerminateProcess));
|
||||
EXPECT_FALSE(GET_FUNCTION(L"not_a_real_library.dll", ::TerminateProcess));
|
||||
EXPECT_FALSE(GET_FUNCTION(L"ntdll.dll", ::TerminateProcess));
|
||||
|
||||
// Here it is!
|
||||
EXPECT_TRUE(GET_FUNCTION(L"kernel32.dll", TerminateProcess));
|
||||
EXPECT_TRUE(GET_FUNCTION(L"kernel32.dll", ::TerminateProcess));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
@ -15,6 +15,16 @@
|
||||
#include "util/win/nt_internals.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "util/win/get_function.h"
|
||||
|
||||
// Declarations that the system headers should provide but don’t.
|
||||
|
||||
struct CLIENT_ID;
|
||||
|
||||
NTSTATUS NTAPI NtOpenThread(HANDLE* ThreadHandle,
|
||||
ACCESS_MASK DesiredAccess,
|
||||
OBJECT_ATTRIBUTES* ObjectAttributes,
|
||||
CLIENT_ID* ClientId);
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
@ -23,10 +33,8 @@ NTSTATUS NtQuerySystemInformation(
|
||||
PVOID system_information,
|
||||
ULONG system_information_length,
|
||||
PULONG return_length) {
|
||||
static decltype(::NtQuerySystemInformation)* nt_query_system_information =
|
||||
reinterpret_cast<decltype(::NtQuerySystemInformation)*>(GetProcAddress(
|
||||
LoadLibrary(L"ntdll.dll"), "NtQuerySystemInformation"));
|
||||
DCHECK(nt_query_system_information);
|
||||
static const auto nt_query_system_information =
|
||||
GET_FUNCTION_REQUIRED(L"ntdll.dll", ::NtQuerySystemInformation);
|
||||
return nt_query_system_information(system_information_class,
|
||||
system_information,
|
||||
system_information_length,
|
||||
@ -38,10 +46,8 @@ NTSTATUS NtQueryInformationThread(HANDLE thread_handle,
|
||||
PVOID thread_information,
|
||||
ULONG thread_information_length,
|
||||
PULONG return_length) {
|
||||
static decltype(::NtQueryInformationThread)* nt_query_information_thread =
|
||||
reinterpret_cast<decltype(::NtQueryInformationThread)*>(GetProcAddress(
|
||||
LoadLibrary(L"ntdll.dll"), "NtQueryInformationThread"));
|
||||
DCHECK(nt_query_information_thread);
|
||||
static const auto nt_query_information_thread =
|
||||
GET_FUNCTION_REQUIRED(L"ntdll.dll", ::NtQueryInformationThread);
|
||||
return nt_query_information_thread(thread_handle,
|
||||
thread_information_class,
|
||||
thread_information,
|
||||
@ -49,27 +55,18 @@ NTSTATUS NtQueryInformationThread(HANDLE thread_handle,
|
||||
return_length);
|
||||
}
|
||||
|
||||
// The 4th argument is CLIENT_ID*, but as we can't typedef that, we simply cast
|
||||
// to void* here.
|
||||
typedef NTSTATUS(WINAPI* NtOpenThreadFunction)(
|
||||
PHANDLE ThreadHandle,
|
||||
ACCESS_MASK DesiredAccess,
|
||||
POBJECT_ATTRIBUTES ObjectAttributes,
|
||||
const void* ClientId);
|
||||
|
||||
template <class Traits>
|
||||
NTSTATUS NtOpenThread(PHANDLE thread_handle,
|
||||
ACCESS_MASK desired_access,
|
||||
POBJECT_ATTRIBUTES object_attributes,
|
||||
const process_types::CLIENT_ID<Traits>* client_id) {
|
||||
static NtOpenThreadFunction nt_open_thread =
|
||||
reinterpret_cast<NtOpenThreadFunction>(
|
||||
GetProcAddress(LoadLibrary(L"ntdll.dll"), "NtOpenThread"));
|
||||
DCHECK(nt_open_thread);
|
||||
return nt_open_thread(thread_handle,
|
||||
desired_access,
|
||||
object_attributes,
|
||||
static_cast<const void*>(client_id));
|
||||
static const auto nt_open_thread =
|
||||
GET_FUNCTION_REQUIRED(L"ntdll.dll", ::NtOpenThread);
|
||||
return nt_open_thread(
|
||||
thread_handle,
|
||||
desired_access,
|
||||
object_attributes,
|
||||
const_cast<CLIENT_ID*>(reinterpret_cast<const CLIENT_ID*>(client_id)));
|
||||
}
|
||||
|
||||
NTSTATUS NtQueryObject(HANDLE handle,
|
||||
@ -77,10 +74,8 @@ NTSTATUS NtQueryObject(HANDLE handle,
|
||||
void* object_information,
|
||||
ULONG object_information_length,
|
||||
ULONG* return_length) {
|
||||
static decltype(::NtQueryObject)* nt_query_object =
|
||||
reinterpret_cast<decltype(::NtQueryObject)*>(
|
||||
GetProcAddress(LoadLibrary(L"ntdll.dll"), "NtQueryObject"));
|
||||
DCHECK(nt_query_object);
|
||||
static const auto nt_query_object =
|
||||
GET_FUNCTION_REQUIRED(L"ntdll.dll", ::NtQueryObject);
|
||||
return nt_query_object(handle,
|
||||
object_information_class,
|
||||
object_information,
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "base/template_util.h"
|
||||
#include "build/build_config.h"
|
||||
#include "util/numeric/safe_assignment.h"
|
||||
#include "util/win/get_function.h"
|
||||
#include "util/win/nt_internals.h"
|
||||
#include "util/win/ntstatus_logging.h"
|
||||
#include "util/win/process_structs.h"
|
||||
@ -39,10 +40,8 @@ NTSTATUS NtQueryInformationProcess(HANDLE process_handle,
|
||||
PVOID process_information,
|
||||
ULONG process_information_length,
|
||||
PULONG return_length) {
|
||||
static decltype(::NtQueryInformationProcess)* nt_query_information_process =
|
||||
reinterpret_cast<decltype(::NtQueryInformationProcess)*>(GetProcAddress(
|
||||
LoadLibrary(L"ntdll.dll"), "NtQueryInformationProcess"));
|
||||
DCHECK(nt_query_information_process);
|
||||
static const auto nt_query_information_process =
|
||||
GET_FUNCTION_REQUIRED(L"ntdll.dll", ::NtQueryInformationProcess);
|
||||
return nt_query_information_process(process_handle,
|
||||
process_information_class,
|
||||
process_information,
|
||||
@ -51,9 +50,8 @@ NTSTATUS NtQueryInformationProcess(HANDLE process_handle,
|
||||
}
|
||||
|
||||
bool IsProcessWow64(HANDLE process_handle) {
|
||||
static decltype(IsWow64Process)* is_wow64_process =
|
||||
reinterpret_cast<decltype(IsWow64Process)*>(
|
||||
GetProcAddress(LoadLibrary(L"kernel32.dll"), "IsWow64Process"));
|
||||
static const auto is_wow64_process =
|
||||
GET_FUNCTION(L"kernel32.dll", ::IsWow64Process);
|
||||
if (!is_wow64_process)
|
||||
return false;
|
||||
BOOL is_wow64;
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "test/win/child_launcher.h"
|
||||
#include "util/file/file_io.h"
|
||||
#include "util/misc/uuid.h"
|
||||
#include "util/win/get_function.h"
|
||||
#include "util/win/scoped_handle.h"
|
||||
|
||||
namespace crashpad {
|
||||
@ -40,9 +41,8 @@ namespace {
|
||||
const wchar_t kNtdllName[] = L"\\ntdll.dll";
|
||||
|
||||
bool IsProcessWow64(HANDLE process_handle) {
|
||||
static decltype(IsWow64Process)* is_wow64_process =
|
||||
reinterpret_cast<decltype(IsWow64Process)*>(
|
||||
GetProcAddress(LoadLibrary(L"kernel32.dll"), "IsWow64Process"));
|
||||
static const auto is_wow64_process =
|
||||
GET_FUNCTION(L"kernel32.dll", ::IsWow64Process);
|
||||
if (!is_wow64_process)
|
||||
return false;
|
||||
BOOL is_wow64;
|
||||
|
Loading…
x
Reference in New Issue
Block a user