Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

139 lines
4.5KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. #ifndef JUCE_WIN32_HIDDENMESSAGEWINDOW_H_INCLUDED
  18. #define JUCE_WIN32_HIDDENMESSAGEWINDOW_H_INCLUDED
  19. //==============================================================================
  20. class HiddenMessageWindow
  21. {
  22. public:
  23. HiddenMessageWindow (const TCHAR* const messageWindowName, WNDPROC wndProc)
  24. {
  25. String className ("JUCE_");
  26. className << String::toHexString (Time::getHighResolutionTicks());
  27. HMODULE moduleHandle = (HMODULE) Process::getCurrentModuleInstanceHandle();
  28. WNDCLASSEX wc = { 0 };
  29. wc.cbSize = sizeof (wc);
  30. wc.lpfnWndProc = wndProc;
  31. wc.cbWndExtra = 4;
  32. wc.hInstance = moduleHandle;
  33. wc.lpszClassName = className.toWideCharPointer();
  34. atom = RegisterClassEx (&wc);
  35. jassert (atom != 0);
  36. hwnd = CreateWindow (getClassNameFromAtom(), messageWindowName,
  37. 0, 0, 0, 0, 0, 0, 0, moduleHandle, 0);
  38. jassert (hwnd != 0);
  39. }
  40. ~HiddenMessageWindow()
  41. {
  42. DestroyWindow (hwnd);
  43. UnregisterClass (getClassNameFromAtom(), 0);
  44. }
  45. inline HWND getHWND() const noexcept { return hwnd; }
  46. private:
  47. ATOM atom;
  48. HWND hwnd;
  49. LPCTSTR getClassNameFromAtom() noexcept { return (LPCTSTR) MAKELONG (atom, 0); }
  50. };
  51. //==============================================================================
  52. class JuceWindowIdentifier
  53. {
  54. public:
  55. static bool isJUCEWindow (HWND hwnd) noexcept
  56. {
  57. return GetWindowLongPtr (hwnd, GWLP_USERDATA) == getImprobableWindowNumber();
  58. }
  59. static void setAsJUCEWindow (HWND hwnd, bool isJuceWindow) noexcept
  60. {
  61. SetWindowLongPtr (hwnd, GWLP_USERDATA, isJuceWindow ? getImprobableWindowNumber() : 0);
  62. }
  63. private:
  64. static LONG_PTR getImprobableWindowNumber() noexcept
  65. {
  66. static LONG_PTR number = (LONG_PTR) Random::getSystemRandom().nextInt64();
  67. return number;
  68. }
  69. };
  70. //==============================================================================
  71. class DeviceChangeDetector : private Timer
  72. {
  73. public:
  74. DeviceChangeDetector (const wchar_t* const name)
  75. : messageWindow (name, (WNDPROC) deviceChangeEventCallback)
  76. {
  77. SetWindowLongPtr (messageWindow.getHWND(), GWLP_USERDATA, (LONG_PTR) this);
  78. }
  79. virtual ~DeviceChangeDetector() {}
  80. protected:
  81. virtual void systemDeviceChanged() = 0;
  82. void triggerAsyncDeviceChangeCallback()
  83. {
  84. // We'll pause before sending a message, because on device removal, the OS hasn't always updated
  85. // its device lists correctly at this point. This also helps avoid repeated callbacks.
  86. startTimer (500);
  87. }
  88. private:
  89. HiddenMessageWindow messageWindow;
  90. static LRESULT CALLBACK deviceChangeEventCallback (HWND h, const UINT message,
  91. const WPARAM wParam, const LPARAM lParam)
  92. {
  93. if (message == WM_DEVICECHANGE
  94. && (wParam == 0x8000 /*DBT_DEVICEARRIVAL*/
  95. || wParam == 0x8004 /*DBT_DEVICEREMOVECOMPLETE*/
  96. || wParam == 0x0007 /*DBT_DEVNODES_CHANGED*/))
  97. {
  98. ((DeviceChangeDetector*) GetWindowLongPtr (h, GWLP_USERDATA))
  99. ->triggerAsyncDeviceChangeCallback();
  100. }
  101. return DefWindowProc (h, message, wParam, lParam);
  102. }
  103. void timerCallback() override
  104. {
  105. stopTimer();
  106. systemDeviceChanged();
  107. }
  108. };
  109. #endif // JUCE_WIN32_HIDDENMESSAGEWINDOW_H_INCLUDED