mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-28 13:28:01 +03:00
Use Microsoft::WRL::ComPtr (#16744)
Some checks are pending
Build RPCS3 / Linux_Build (/rpcs3/.ci/build-linux-aarch64.sh, clang, rpcs3/rpcs3-ci-jammy-aarch64:1.0, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / Linux_Build (/rpcs3/.ci/build-linux.sh, clang, rpcs3/rpcs3-ci-jammy:1.0, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / Linux_Build (/rpcs3/.ci/build-linux.sh, gcc, rpcs3/rpcs3-ci-jammy:1.0, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / Windows_Build (push) Waiting to run
Some checks are pending
Build RPCS3 / Linux_Build (/rpcs3/.ci/build-linux-aarch64.sh, clang, rpcs3/rpcs3-ci-jammy-aarch64:1.0, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / Linux_Build (/rpcs3/.ci/build-linux.sh, clang, rpcs3/rpcs3-ci-jammy:1.0, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / Linux_Build (/rpcs3/.ci/build-linux.sh, gcc, rpcs3/rpcs3-ci-jammy:1.0, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / Windows_Build (push) Waiting to run
This commit is contained in:
parent
796a237128
commit
b08273b127
8 changed files with 44 additions and 58 deletions
|
@ -65,7 +65,7 @@ XAudio2Backend::XAudio2Backend()
|
||||||
m_com_init_success = true;
|
m_com_init_success = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HRESULT hr = XAudio2Create(instance.GetAddressOf(), 0, XAUDIO2_USE_DEFAULT_PROCESSOR); FAILED(hr))
|
if (HRESULT hr = XAudio2Create(&instance, 0, XAUDIO2_USE_DEFAULT_PROCESSOR); FAILED(hr))
|
||||||
{
|
{
|
||||||
XAudio.error("XAudio2Create() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
XAudio.error("XAudio2Create() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||||
return;
|
return;
|
||||||
|
@ -78,7 +78,7 @@ XAudio2Backend::XAudio2Backend()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to register a listener for device changes
|
// Try to register a listener for device changes
|
||||||
if (HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(enumerator.GetAddressOf())); FAILED(hr))
|
if (HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&enumerator)); FAILED(hr))
|
||||||
{
|
{
|
||||||
XAudio.error("CoCreateInstance() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
XAudio.error("CoCreateInstance() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||||
return;
|
return;
|
||||||
|
@ -215,7 +215,7 @@ bool XAudio2Backend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSi
|
||||||
if (use_default_device)
|
if (use_default_device)
|
||||||
{
|
{
|
||||||
Microsoft::WRL::ComPtr<IMMDevice> default_dev{};
|
Microsoft::WRL::ComPtr<IMMDevice> default_dev{};
|
||||||
if (HRESULT hr = m_device_enumerator->GetDefaultAudioEndpoint(eRender, eConsole, default_dev.GetAddressOf()); FAILED(hr))
|
if (HRESULT hr = m_device_enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &default_dev); FAILED(hr))
|
||||||
{
|
{
|
||||||
XAudio.error("GetDefaultAudioEndpoint() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
XAudio.error("GetDefaultAudioEndpoint() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||||
return false;
|
return false;
|
||||||
|
@ -319,7 +319,7 @@ f64 XAudio2Backend::GetCallbackFrameLen()
|
||||||
Microsoft::WRL::ComPtr<IXAudio2Extension> xaudio_ext{};
|
Microsoft::WRL::ComPtr<IXAudio2Extension> xaudio_ext{};
|
||||||
f64 min_latency{};
|
f64 min_latency{};
|
||||||
|
|
||||||
if (HRESULT hr = m_xaudio2_instance->QueryInterface(IID_IXAudio2Extension, std::bit_cast<void**>(xaudio_ext.GetAddressOf())); FAILED(hr))
|
if (HRESULT hr = m_xaudio2_instance.As(&xaudio_ext); FAILED(hr))
|
||||||
{
|
{
|
||||||
XAudio.error("QueryInterface() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
XAudio.error("QueryInterface() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ xaudio2_enumerator::~xaudio2_enumerator()
|
||||||
std::vector<audio_device_enumerator::audio_device> xaudio2_enumerator::get_output_devices()
|
std::vector<audio_device_enumerator::audio_device> xaudio2_enumerator::get_output_devices()
|
||||||
{
|
{
|
||||||
Microsoft::WRL::ComPtr<IMMDeviceEnumerator> devEnum{};
|
Microsoft::WRL::ComPtr<IMMDeviceEnumerator> devEnum{};
|
||||||
if (HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(devEnum.GetAddressOf())); FAILED(hr))
|
if (HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&devEnum)); FAILED(hr))
|
||||||
{
|
{
|
||||||
xaudio_dev_enum.error("CoCreateInstance() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
xaudio_dev_enum.error("CoCreateInstance() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||||
return {};
|
return {};
|
||||||
|
@ -57,7 +57,7 @@ std::vector<audio_device_enumerator::audio_device> xaudio2_enumerator::get_outpu
|
||||||
for (UINT dev_idx = 0; dev_idx < count; dev_idx++)
|
for (UINT dev_idx = 0; dev_idx < count; dev_idx++)
|
||||||
{
|
{
|
||||||
Microsoft::WRL::ComPtr<IMMDevice> endpoint{};
|
Microsoft::WRL::ComPtr<IMMDevice> endpoint{};
|
||||||
if (HRESULT hr = devices->Item(dev_idx, endpoint.GetAddressOf()); FAILED(hr))
|
if (HRESULT hr = devices->Item(dev_idx, &endpoint); FAILED(hr))
|
||||||
{
|
{
|
||||||
xaudio_dev_enum.error("devices->Item() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
xaudio_dev_enum.error("devices->Item() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||||
continue;
|
continue;
|
||||||
|
@ -83,7 +83,7 @@ std::vector<audio_device_enumerator::audio_device> xaudio2_enumerator::get_outpu
|
||||||
CoTaskMemFree(id);
|
CoTaskMemFree(id);
|
||||||
|
|
||||||
Microsoft::WRL::ComPtr<IPropertyStore> props{};
|
Microsoft::WRL::ComPtr<IPropertyStore> props{};
|
||||||
if (HRESULT hr = endpoint->OpenPropertyStore(STGM_READ, props.GetAddressOf()); FAILED(hr))
|
if (HRESULT hr = endpoint->OpenPropertyStore(STGM_READ, &props); FAILED(hr))
|
||||||
{
|
{
|
||||||
xaudio_dev_enum.error("endpoint->OpenPropertyStore() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
xaudio_dev_enum.error("endpoint->OpenPropertyStore() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -627,11 +627,6 @@ if(TARGET 3rdparty_vulkan)
|
||||||
RSX/VK/VKVertexProgram.cpp
|
RSX/VK/VKVertexProgram.cpp
|
||||||
RSX/VK/VKTextureCache.cpp
|
RSX/VK/VKTextureCache.cpp
|
||||||
)
|
)
|
||||||
if(MSVC)
|
|
||||||
set_source_files_properties(RSX/VK/vkutils/shared.cpp PROPERTIES
|
|
||||||
COMPILE_FLAGS /EHs-
|
|
||||||
SKIP_PRECOMPILE_HEADERS ON)
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_link_libraries(rpcs3_emu
|
target_link_libraries(rpcs3_emu
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "xinput_pad_handler.h"
|
#include "xinput_pad_handler.h"
|
||||||
#include "Emu/Io/pad_config.h"
|
#include "Emu/Io/pad_config.h"
|
||||||
|
#include "util/dyn_lib.hpp"
|
||||||
|
|
||||||
namespace XINPUT_INFO
|
namespace XINPUT_INFO
|
||||||
{
|
{
|
||||||
|
@ -77,8 +78,6 @@ xinput_pad_handler::~xinput_pad_handler()
|
||||||
{
|
{
|
||||||
if (library)
|
if (library)
|
||||||
{
|
{
|
||||||
FreeLibrary(library);
|
|
||||||
library = nullptr;
|
|
||||||
xinputGetExtended = nullptr;
|
xinputGetExtended = nullptr;
|
||||||
xinputGetCustomData = nullptr;
|
xinputGetCustomData = nullptr;
|
||||||
xinputGetState = nullptr;
|
xinputGetState = nullptr;
|
||||||
|
@ -374,12 +373,6 @@ pad_preview_values xinput_pad_handler::get_preview_values(const std::unordered_m
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
|
||||||
T getProc(HMODULE hModule, LPCSTR lpProcName)
|
|
||||||
{
|
|
||||||
return reinterpret_cast<T>(GetProcAddress(hModule, lpProcName));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool xinput_pad_handler::Init()
|
bool xinput_pad_handler::Init()
|
||||||
{
|
{
|
||||||
if (m_is_init)
|
if (m_is_init)
|
||||||
|
@ -387,17 +380,17 @@ bool xinput_pad_handler::Init()
|
||||||
|
|
||||||
for (auto it : XINPUT_INFO::LIBRARY_FILENAMES)
|
for (auto it : XINPUT_INFO::LIBRARY_FILENAMES)
|
||||||
{
|
{
|
||||||
library = LoadLibrary(it);
|
library.load(it);
|
||||||
if (library)
|
if (library)
|
||||||
{
|
{
|
||||||
xinputGetExtended = getProc<PFN_XINPUTGETEXTENDED>(library, "XInputGetExtended"); // Optional
|
xinputGetExtended = library.get<PFN_XINPUTGETEXTENDED>("XInputGetExtended"); // Optional
|
||||||
xinputGetCustomData = getProc<PFN_XINPUTGETCUSTOMDATA>(library, "XInputGetCustomData"); // Optional
|
xinputGetCustomData = library.get<PFN_XINPUTGETCUSTOMDATA>("XInputGetCustomData"); // Optional
|
||||||
xinputGetState = getProc<PFN_XINPUTGETSTATE>(library, reinterpret_cast<LPCSTR>(100));
|
xinputGetState = library.get<PFN_XINPUTGETSTATE>(reinterpret_cast<LPCSTR>(100));
|
||||||
if (!xinputGetState)
|
if (!xinputGetState)
|
||||||
xinputGetState = getProc<PFN_XINPUTGETSTATE>(library, "XInputGetState");
|
xinputGetState = library.get<PFN_XINPUTGETSTATE>("XInputGetState");
|
||||||
|
|
||||||
xinputSetState = getProc<PFN_XINPUTSETSTATE>(library, "XInputSetState");
|
xinputSetState = library.get<PFN_XINPUTSETSTATE>("XInputSetState");
|
||||||
xinputGetBatteryInformation = getProc<PFN_XINPUTGETBATTERYINFORMATION>(library, "XInputGetBatteryInformation");
|
xinputGetBatteryInformation = library.get<PFN_XINPUTGETBATTERYINFORMATION>("XInputGetBatteryInformation");
|
||||||
|
|
||||||
if (xinputGetState && xinputSetState && xinputGetBatteryInformation)
|
if (xinputGetState && xinputSetState && xinputGetBatteryInformation)
|
||||||
{
|
{
|
||||||
|
@ -405,8 +398,6 @@ bool xinput_pad_handler::Init()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
FreeLibrary(library);
|
|
||||||
library = nullptr;
|
|
||||||
xinputGetExtended = nullptr;
|
xinputGetExtended = nullptr;
|
||||||
xinputGetCustomData = nullptr;
|
xinputGetCustomData = nullptr;
|
||||||
xinputGetState = nullptr;
|
xinputGetState = nullptr;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Emu/Io/PadHandler.h"
|
#include "Emu/Io/PadHandler.h"
|
||||||
|
#include "util/dyn_lib.hpp"
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
|
@ -9,7 +10,6 @@
|
||||||
#endif
|
#endif
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <Xinput.h>
|
#include <Xinput.h>
|
||||||
#include <chrono>
|
|
||||||
|
|
||||||
// ScpToolkit defined structure for pressure sensitive button query
|
// ScpToolkit defined structure for pressure sensitive button query
|
||||||
struct SCP_EXTN
|
struct SCP_EXTN
|
||||||
|
@ -116,22 +116,22 @@ public:
|
||||||
void init_config(cfg_pad* cfg) override;
|
void init_config(cfg_pad* cfg) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef DWORD (WINAPI * PFN_XINPUTGETEXTENDED)(DWORD, SCP_EXTN *);
|
using PFN_XINPUTGETEXTENDED = DWORD(WINAPI*)(DWORD, SCP_EXTN*);
|
||||||
typedef DWORD (WINAPI * PFN_XINPUTGETCUSTOMDATA)(DWORD, DWORD, void *);
|
using PFN_XINPUTGETCUSTOMDATA = DWORD(WINAPI*)(DWORD, DWORD, void*);
|
||||||
typedef DWORD (WINAPI * PFN_XINPUTGETSTATE)(DWORD, XINPUT_STATE *);
|
using PFN_XINPUTGETSTATE = DWORD(WINAPI*)(DWORD, XINPUT_STATE*);
|
||||||
typedef DWORD (WINAPI * PFN_XINPUTSETSTATE)(DWORD, XINPUT_VIBRATION *);
|
using PFN_XINPUTSETSTATE = DWORD(WINAPI*)(DWORD, XINPUT_VIBRATION*);
|
||||||
typedef DWORD (WINAPI * PFN_XINPUTGETBATTERYINFORMATION)(DWORD, BYTE, XINPUT_BATTERY_INFORMATION *);
|
using PFN_XINPUTGETBATTERYINFORMATION = DWORD(WINAPI*)(DWORD, BYTE, XINPUT_BATTERY_INFORMATION*);
|
||||||
|
|
||||||
int GetDeviceNumber(const std::string& padId);
|
int GetDeviceNumber(const std::string& padId);
|
||||||
static PadButtonValues get_button_values_base(const XINPUT_STATE& state, trigger_recognition_mode trigger_mode);
|
static PadButtonValues get_button_values_base(const XINPUT_STATE& state, trigger_recognition_mode trigger_mode);
|
||||||
static PadButtonValues get_button_values_scp(const SCP_EXTN& state, trigger_recognition_mode trigger_mode);
|
static PadButtonValues get_button_values_scp(const SCP_EXTN& state, trigger_recognition_mode trigger_mode);
|
||||||
|
|
||||||
HMODULE library{ nullptr };
|
|
||||||
PFN_XINPUTGETEXTENDED xinputGetExtended{ nullptr };
|
PFN_XINPUTGETEXTENDED xinputGetExtended{ nullptr };
|
||||||
PFN_XINPUTGETCUSTOMDATA xinputGetCustomData{ nullptr };
|
PFN_XINPUTGETCUSTOMDATA xinputGetCustomData{ nullptr };
|
||||||
PFN_XINPUTGETSTATE xinputGetState{ nullptr };
|
PFN_XINPUTGETSTATE xinputGetState{ nullptr };
|
||||||
PFN_XINPUTSETSTATE xinputSetState{ nullptr };
|
PFN_XINPUTSETSTATE xinputSetState{ nullptr };
|
||||||
PFN_XINPUTGETBATTERYINFORMATION xinputGetBatteryInformation{ nullptr };
|
PFN_XINPUTGETBATTERYINFORMATION xinputGetBatteryInformation{ nullptr };
|
||||||
|
utils::dynamic_library library;
|
||||||
|
|
||||||
std::shared_ptr<PadDevice> get_device(const std::string& device) override;
|
std::shared_ptr<PadDevice> get_device(const std::string& device) override;
|
||||||
bool get_is_left_trigger(const std::shared_ptr<PadDevice>& device, u64 keyCode) override;
|
bool get_is_left_trigger(const std::shared_ptr<PadDevice>& device, u64 keyCode) override;
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <comdef.h>
|
#include <comdef.h>
|
||||||
|
|
||||||
#include "Emu/system_utils.hpp"
|
#include "Emu/system_utils.hpp"
|
||||||
|
#include <wrl/client.h>
|
||||||
#else
|
#else
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
@ -142,19 +143,17 @@ namespace gui::utils
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
IShellLink* pShellLink = nullptr;
|
Microsoft::WRL::ComPtr<IShellLink> pShellLink;
|
||||||
IPersistFile* pPersistFile = nullptr;
|
Microsoft::WRL::ComPtr<IPersistFile> pPersistFile;
|
||||||
|
|
||||||
const auto cleanup = [&](bool return_value, const std::string& fail_reason) -> bool
|
const auto cleanup = [&](bool return_value, const std::string& fail_reason) -> bool
|
||||||
{
|
{
|
||||||
if (!return_value) sys_log.error("Failed to create shortcut: %s", fail_reason);
|
if (!return_value) sys_log.error("Failed to create shortcut: %s", fail_reason);
|
||||||
if (pPersistFile) pPersistFile->Release();
|
|
||||||
if (pShellLink) pShellLink->Release();
|
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
return return_value;
|
return return_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
res = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pShellLink));
|
res = CoCreateInstance(__uuidof(ShellLink), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pShellLink));
|
||||||
if (FAILED(res))
|
if (FAILED(res))
|
||||||
return cleanup(false, "CoCreateInstance failed");
|
return cleanup(false, "CoCreateInstance failed");
|
||||||
|
|
||||||
|
@ -200,7 +199,7 @@ namespace gui::utils
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the IPersistFile object to save the shell link
|
// Use the IPersistFile object to save the shell link
|
||||||
res = pShellLink->QueryInterface(IID_PPV_ARGS(&pPersistFile));
|
res = pShellLink.As(&pPersistFile);
|
||||||
if (FAILED(res))
|
if (FAILED(res))
|
||||||
return cleanup(false, fmt::format("QueryInterface failed (%s)", str_error(res)));
|
return cleanup(false, fmt::format("QueryInterface failed (%s)", str_error(res)));
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,14 @@ namespace utils
|
||||||
return loaded();
|
return loaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
bool dynamic_library::load(const std::wstring& path)
|
||||||
|
{
|
||||||
|
m_handle = LoadLibraryW(path.c_str());
|
||||||
|
return loaded();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void dynamic_library::close()
|
void dynamic_library::close()
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
@ -39,12 +47,12 @@ namespace utils
|
||||||
m_handle = nullptr;
|
m_handle = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* dynamic_library::get_impl(const std::string& name) const
|
void* dynamic_library::get_impl(const char* name) const
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
return reinterpret_cast<void*>(GetProcAddress(reinterpret_cast<HMODULE>(m_handle), name.c_str()));
|
return reinterpret_cast<void*>(GetProcAddress(reinterpret_cast<HMODULE>(m_handle), name));
|
||||||
#else
|
#else
|
||||||
return dlsym(m_handle, name.c_str());
|
return dlsym(m_handle, name);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,26 +31,19 @@ namespace utils
|
||||||
~dynamic_library();
|
~dynamic_library();
|
||||||
|
|
||||||
bool load(const std::string& path);
|
bool load(const std::string& path);
|
||||||
|
#ifdef _WIN32
|
||||||
|
bool load(const std::wstring& path);
|
||||||
|
#endif
|
||||||
void close();
|
void close();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void* get_impl(const std::string& name) const;
|
void* get_impl(const char* name) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template <typename Type = void>
|
template <typename Type = void>
|
||||||
Type* get(const std::string& name) const
|
Type get(const char* name) const
|
||||||
{
|
{
|
||||||
Type* result;
|
return reinterpret_cast<Type>(get_impl(name));
|
||||||
*reinterpret_cast<void**>(&result) = get_impl(name);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Type>
|
|
||||||
bool get(Type*& function, const std::string& name) const
|
|
||||||
{
|
|
||||||
*reinterpret_cast<void**>(&function) = get_impl(name);
|
|
||||||
|
|
||||||
return function != nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool loaded() const;
|
bool loaded() const;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue