dynamic_load_windows.h 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. // Copyright The OpenTelemetry Authors
  2. // SPDX-License-Identifier: Apache-2.0
  3. #pragma once
  4. #include <memory>
  5. #include "opentelemetry/plugin/detail/dynamic_library_handle.h"
  6. #include "opentelemetry/plugin/detail/loader_info.h"
  7. #include "opentelemetry/plugin/detail/utility.h"
  8. #include "opentelemetry/plugin/factory.h"
  9. #include "opentelemetry/plugin/hook.h"
  10. #include "opentelemetry/version.h"
  11. #include <Windows.h>
  12. #include <WinBase.h>
  13. #include <errhandlingapi.h>
  14. OPENTELEMETRY_BEGIN_NAMESPACE
  15. namespace plugin
  16. {
  17. namespace detail
  18. {
  19. inline void GetLastErrorMessage(std::string &error_message) noexcept
  20. {
  21. auto error_code = ::GetLastError();
  22. // See https://stackoverflow.com/a/455533/4447365
  23. LPTSTR error_text = nullptr;
  24. auto size = ::FormatMessage(
  25. FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
  26. nullptr, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  27. reinterpret_cast<LPTSTR>(&error_text), 0, nullptr);
  28. if (size == 0)
  29. {
  30. return;
  31. }
  32. CopyErrorMessage(error_text, error_message);
  33. ::LocalFree(error_text);
  34. }
  35. } // namespace detail
  36. class DynamicLibraryHandleWindows final : public DynamicLibraryHandle
  37. {
  38. public:
  39. explicit DynamicLibraryHandleWindows(HINSTANCE handle) : handle_{handle} {}
  40. ~DynamicLibraryHandleWindows() override { ::FreeLibrary(handle_); }
  41. private:
  42. HINSTANCE handle_;
  43. };
  44. inline std::unique_ptr<Factory> LoadFactory(const char *plugin, std::string &error_message) noexcept
  45. {
  46. auto handle = ::LoadLibrary(plugin);
  47. if (handle == nullptr)
  48. {
  49. detail::GetLastErrorMessage(error_message);
  50. return nullptr;
  51. }
  52. std::shared_ptr<DynamicLibraryHandle> library_handle{new (std::nothrow)
  53. DynamicLibraryHandleWindows{handle}};
  54. if (library_handle == nullptr)
  55. {
  56. detail::CopyErrorMessage("Allocation failure", error_message);
  57. return nullptr;
  58. }
  59. auto make_factory_impl = reinterpret_cast<OpenTelemetryHook *>(
  60. ::GetProcAddress(handle, "OpenTelemetryMakeFactoryImpl"));
  61. if (make_factory_impl == nullptr)
  62. {
  63. detail::GetLastErrorMessage(error_message);
  64. return nullptr;
  65. }
  66. if (*make_factory_impl == nullptr)
  67. {
  68. detail::CopyErrorMessage("Invalid plugin hook", error_message);
  69. return nullptr;
  70. }
  71. LoaderInfo loader_info;
  72. nostd::unique_ptr<char[]> plugin_error_message;
  73. auto factory_impl = (**make_factory_impl)(loader_info, plugin_error_message);
  74. if (factory_impl == nullptr)
  75. {
  76. detail::CopyErrorMessage(plugin_error_message.get(), error_message);
  77. return nullptr;
  78. }
  79. return std::unique_ptr<Factory>{new (std::nothrow)
  80. Factory{std::move(library_handle), std::move(factory_impl)}};
  81. }
  82. } // namespace plugin
  83. OPENTELEMETRY_END_NAMESPACE