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.

juce_win32_HiddenMessageWindow.h 4.4KB

9 years ago
9 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2015 - ROLI 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) (pointer_sized_uint) atom; }
  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. virtual void systemDeviceChanged() = 0;
  81. void triggerAsyncDeviceChangeCallback()
  82. {
  83. // We'll pause before sending a message, because on device removal, the OS hasn't always updated
  84. // its device lists correctly at this point. This also helps avoid repeated callbacks.
  85. startTimer (500);
  86. }
  87. private:
  88. HiddenMessageWindow messageWindow;
  89. static LRESULT CALLBACK deviceChangeEventCallback (HWND h, const UINT message,
  90. const WPARAM wParam, const LPARAM lParam)
  91. {
  92. if (message == WM_DEVICECHANGE
  93. && (wParam == 0x8000 /*DBT_DEVICEARRIVAL*/
  94. || wParam == 0x8004 /*DBT_DEVICEREMOVECOMPLETE*/
  95. || wParam == 0x0007 /*DBT_DEVNODES_CHANGED*/))
  96. {
  97. ((DeviceChangeDetector*) GetWindowLongPtr (h, GWLP_USERDATA))
  98. ->triggerAsyncDeviceChangeCallback();
  99. }
  100. return DefWindowProc (h, message, wParam, lParam);
  101. }
  102. void timerCallback() override
  103. {
  104. stopTimer();
  105. systemDeviceChanged();
  106. }
  107. };
  108. #endif // JUCE_WIN32_HIDDENMESSAGEWINDOW_H_INCLUDED