Skip to content

Commit c82de19

Browse files
committed
winmidi: rework initialization
1 parent f089df0 commit c82de19

3 files changed

Lines changed: 138 additions & 15 deletions

File tree

include/libremidi/backends/coremidi/midi_out.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ class midi_out_core final
111111
const MIDITimeStamp timestamp = LIBREMIDI_AUDIO_GET_CURRENT_HOST_TIME();
112112

113113
const ByteCount bufsize = nBytes > 65535 ? 65535 : nBytes;
114-
Byte buffer[bufsize + 16]; // pad for other struct members
115-
ByteCount listSize = sizeof(buffer);
114+
Byte* buffer = (Byte*)alloca(bufsize + 16); // pad for other struct members
115+
ByteCount listSize = bufsize + 16;
116116
MIDIPacketList* packetList = (MIDIPacketList*)buffer;
117117

118118
ByteCount remainingBytes = nBytes;

include/libremidi/backends/winmidi.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ struct backend
1919
static const constexpr std::string_view name = "winmidi";
2020
static const constexpr std::string_view display_name = "Windows MIDI Services";
2121

22-
static constexpr inline bool available() noexcept { return true; }
22+
static inline bool available() noexcept {
23+
return libremidi::instance<winmidi_shared_data_instance>()->ready;
24+
}
2325
};
2426
} // NAMESPACE_LIBREMIDI

include/libremidi/backends/winmidi/helpers.hpp

Lines changed: 133 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,14 @@
2424
LIBREMIDI_STATIC constexpr const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
2525

2626
NAMESPACE_LIBREMIDI {
27-
LIBREMIDI_DEFINE_GUID_CONSTEXPR(IID, IID_IMidiEndpointConnectionMessagesReceivedCallback, 0x8087b303,0x0519,0x31d1,0x31,0xd1,0x00,0x00,0x00,0x00,0x00,0x10);
28-
LIBREMIDI_DEFINE_GUID_CONSTEXPR(IID, IID_IMidiEndpointConnectionRaw, 0x8087b303,0x0519,0x31d1,0x31,0xd1,0x00,0x00,0x00,0x00,0x00,0x20);
29-
LIBREMIDI_DEFINE_GUID_CONSTEXPR(IID, IID_IMidiClientInitializer, 0x8087b303, 0xd551, 0xbce2, 0x1e, 0xad, 0xa2, 0x50, 0x0d, 0x50, 0xc5, 0x80);
30-
LIBREMIDI_DEFINE_GUID_CONSTEXPR(IID, IID_MidiClientInitializerUuid, 0xc3263827, 0xc3b0, 0xbdbd, 0x25, 0x00, 0xce, 0x63, 0xa3, 0xf3, 0xf2, 0xc3);
27+
LIBREMIDI_DEFINE_GUID_CONSTEXPR(IID, IID_IMidiEndpointConnectionMessagesReceivedCallback, 0x8087b303, 0x0519, 0x31d1, 0x31, 0xd1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10);
28+
LIBREMIDI_DEFINE_GUID_CONSTEXPR(IID, IID_IMidiEndpointConnectionRaw, 0x8087b303, 0x0519, 0x31d1, 0x31, 0xd1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20);
29+
LIBREMIDI_DEFINE_GUID_CONSTEXPR(IID, IID_IMidiClientInitializer, 0x8087b303, 0xd551, 0xbce2, 0x1e, 0xad, 0xa2, 0x50, 0x0d, 0x50, 0xc5, 0x80);
30+
LIBREMIDI_DEFINE_GUID_CONSTEXPR(IID, IID_MidiClientInitializerUuid, 0xc3263827, 0xc3b0, 0xbdbd, 0x25, 0x00, 0xce, 0x63, 0xa3, 0xf3, 0xf2, 0xc3);
31+
LIBREMIDI_DEFINE_GUID_CONSTEXPR(IID, IID_MidiSrvTransportUuid, 0x2ba15e4e, 0x5417, 0x4a66, 0x85, 0xb8, 0x2b, 0x22, 0x60, 0xef, 0xbc, 0x84);
3132
}
3233
#endif
3334

34-
#include <init/Microsoft.Windows.Devices.Midi2.Initialization.hpp>
3535
// clang-format on
3636

3737
namespace midi2 = winrt::Microsoft::Windows::Devices::Midi2;
@@ -44,7 +44,6 @@ using namespace winrt::Windows::Foundation;
4444
using namespace winrt::Windows::Devices::Enumeration;
4545
using namespace winrt::Windows::Storage::Streams;
4646
using namespace winrt::Microsoft::Windows::Devices::Midi2;
47-
using namespace ::Microsoft::Windows::Devices::Midi2::Initialization;
4847

4948
inline bool ichar_equals(char a, char b)
5049
{
@@ -82,16 +81,138 @@ get_port(const std::string& device_name, int group_terminal_block)
8281
}
8382
return {nullptr, nullptr};
8483
}
84+
85+
// From Microsoft.Windows.Devices.Midi2.Initialization.hpp
86+
typedef enum
87+
{
88+
Platform_x64 = 1,
89+
// Platform_Arm64 = 2,
90+
// Platform_Arm64EC = 3,
91+
Platform_Arm64X = 4,
92+
} MidiAppSDKPlatform;
93+
94+
struct IMidiClientInitializer : ::IUnknown
95+
{
96+
// returns the SDK version info. Supply nullptr for arguments you don't care about
97+
STDMETHOD(GetInstalledWindowsMidiServicesSdkVersion)(
98+
MidiAppSDKPlatform* buildPlatform,
99+
USHORT* versionMajor,
100+
USHORT* versionMinor,
101+
USHORT* versionPatch,
102+
103+
LPWSTR* buildSource,
104+
LPWSTR* versionName,
105+
LPWSTR* versionFullString
106+
) = 0;
107+
108+
// demand-starts the service if present
109+
STDMETHOD(EnsureServiceAvailable)() = 0;
110+
};
111+
struct winmidi_shared_data_instance
112+
{
113+
IMidiClientInitializer* initializer{nullptr};
114+
bool ready{false};
115+
winmidi_shared_data_instance()
116+
{
117+
// 1. Check if MIDI Services are available
118+
{
119+
::IUnknown* servicePointer{ nullptr };
120+
auto hr = CoCreateInstance(
121+
libremidi::IID_MidiSrvTransportUuid,
122+
NULL,
123+
CLSCTX_INPROC_SERVER,
124+
IID_PPV_ARGS(&servicePointer)
125+
);
126+
127+
if (SUCCEEDED(hr))
128+
{
129+
if (servicePointer == nullptr)
130+
{
131+
ready = false;
132+
return;
133+
}
134+
135+
// Here is the good case:
136+
servicePointer->Release();
137+
servicePointer = nullptr;
138+
ready = true;
139+
}
140+
else if (hr == REGDB_E_CLASSNOTREG)
141+
{
142+
servicePointer = nullptr;
143+
ready = false;
144+
return;
145+
}
146+
else
147+
{
148+
servicePointer = nullptr;
149+
ready = false;
150+
return;
151+
}
152+
}
153+
154+
// 2. Check if MIDI services can be created
155+
{
156+
if (SUCCEEDED(CoCreateInstance(
157+
libremidi::IID_MidiClientInitializerUuid,
158+
NULL,
159+
CLSCTX::CLSCTX_INPROC_SERVER | CLSCTX::CLSCTX_FROM_DEFAULT_CONTEXT,
160+
libremidi::IID_IMidiClientInitializer,
161+
reinterpret_cast<void**>(&initializer)
162+
)))
163+
{
164+
if (initializer != nullptr)
165+
{
166+
ready = true;
167+
}
168+
else
169+
{
170+
ready = false;
171+
return;
172+
}
173+
}
174+
else
175+
{
176+
ready = false;
177+
return;
178+
}
179+
}
180+
181+
// 3. Check if MIDI services can be used
182+
if (SUCCEEDED(initializer->EnsureServiceAvailable()))
183+
{
184+
ready = true;
185+
}
186+
else
187+
{
188+
ready = false;
189+
initializer->Release();
190+
initializer = nullptr;
191+
return;
192+
}
193+
}
194+
195+
~winmidi_shared_data_instance()
196+
{
197+
if (initializer != nullptr)
198+
{
199+
initializer->Release();
200+
initializer = nullptr;
201+
}
202+
}
203+
};
204+
85205
struct winmidi_shared_data
86206
{
87-
std::shared_ptr<MidiDesktopAppSdkInitializer> initializer;
88-
bool m_ready{false};
207+
std::shared_ptr<winmidi_shared_data_instance> self = libremidi::instance<winmidi_shared_data_instance>();
208+
89209
winmidi_shared_data()
90-
: initializer{libremidi::instance<MidiDesktopAppSdkInitializer>()}
91-
, m_ready{
92-
initializer && initializer->InitializeSdkRuntime()
93-
&& initializer->EnsureServiceAvailable()}
210+
{
211+
}
212+
213+
~winmidi_shared_data()
94214
{
95215
}
96216
};
217+
97218
}

0 commit comments

Comments
 (0)