SDL  2.0
SDL_windows.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
4 
5  This software is provided 'as-is', without any express or implied
6  warranty. In no event will the authors be held liable for any damages
7  arising from the use of this software.
8 
9  Permission is granted to anyone to use this software for any purpose,
10  including commercial applications, and to alter it and redistribute it
11  freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19  3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../../SDL_internal.h"
22 
23 #if defined(__WIN32__) || defined(__WINRT__)
24 
25 #include "SDL_windows.h"
26 #include "SDL_error.h"
27 #include "SDL_assert.h"
28 
29 #include <objbase.h> /* for CoInitialize/CoUninitialize (Win32 only) */
30 
31 #ifndef _WIN32_WINNT_VISTA
32 #define _WIN32_WINNT_VISTA 0x0600
33 #endif
34 
35 
36 /* Sets an error message based on an HRESULT */
37 int
38 WIN_SetErrorFromHRESULT(const char *prefix, HRESULT hr)
39 {
40  TCHAR buffer[1024];
41  char *message;
42  FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, 0,
43  buffer, SDL_arraysize(buffer), NULL);
44  message = WIN_StringToUTF8(buffer);
45  SDL_SetError("%s%s%s", prefix ? prefix : "", prefix ? ": " : "", message);
46  SDL_free(message);
47  return -1;
48 }
49 
50 /* Sets an error message based on GetLastError() */
51 int
52 WIN_SetError(const char *prefix)
53 {
54  return WIN_SetErrorFromHRESULT(prefix, GetLastError());
55 }
56 
57 HRESULT
58 WIN_CoInitialize(void)
59 {
60  /* SDL handles any threading model, so initialize with the default, which
61  is compatible with OLE and if that doesn't work, try multi-threaded mode.
62 
63  If you need multi-threaded mode, call CoInitializeEx() before SDL_Init()
64  */
65 #ifdef __WINRT__
66  /* DLudwig: On WinRT, it is assumed that COM was initialized in main().
67  CoInitializeEx is available (not CoInitialize though), however
68  on WinRT, main() is typically declared with the [MTAThread]
69  attribute, which, AFAIK, should initialize COM.
70  */
71  return S_OK;
72 #else
73  HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
74  if (hr == RPC_E_CHANGED_MODE) {
75  hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
76  }
77 
78  /* S_FALSE means success, but someone else already initialized. */
79  /* You still need to call CoUninitialize in this case! */
80  if (hr == S_FALSE) {
81  return S_OK;
82  }
83 
84  return hr;
85 #endif
86 }
87 
88 void
90 {
91 #ifndef __WINRT__
92  CoUninitialize();
93 #endif
94 }
95 
96 #ifndef __WINRT__
97 static BOOL
98 IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor)
99 {
100  OSVERSIONINFOEXW osvi;
101  DWORDLONG const dwlConditionMask = VerSetConditionMask(
102  VerSetConditionMask(
103  VerSetConditionMask(
104  0, VER_MAJORVERSION, VER_GREATER_EQUAL ),
105  VER_MINORVERSION, VER_GREATER_EQUAL ),
106  VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL );
107 
108  SDL_zero(osvi);
109  osvi.dwOSVersionInfoSize = sizeof(osvi);
110  osvi.dwMajorVersion = wMajorVersion;
111  osvi.dwMinorVersion = wMinorVersion;
112  osvi.wServicePackMajor = wServicePackMajor;
113 
114  return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE;
115 }
116 #endif
117 
119 {
120 #ifdef __WINRT__
121  return TRUE;
122 #else
123  return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 0);
124 #endif
125 }
126 
127 BOOL WIN_IsWindows7OrGreater(void)
128 {
129 #ifdef __WINRT__
130  return TRUE;
131 #else
132  return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 0);
133 #endif
134 }
135 
136 /*
137 WAVExxxCAPS gives you 31 bytes for the device name, and just truncates if it's
138 longer. However, since WinXP, you can use the WAVExxxCAPS2 structure, which
139 will give you a name GUID. The full name is in the Windows Registry under
140 that GUID, located here: HKLM\System\CurrentControlSet\Control\MediaCategories
141 
142 Note that drivers can report GUID_NULL for the name GUID, in which case,
143 Windows makes a best effort to fill in those 31 bytes in the usual place.
144 This info summarized from MSDN:
145 
146 http://web.archive.org/web/20131027093034/http://msdn.microsoft.com/en-us/library/windows/hardware/ff536382(v=vs.85).aspx
147 
148 Always look this up in the registry if possible, because the strings are
149 different! At least on Win10, I see "Yeti Stereo Microphone" in the
150 Registry, and a unhelpful "Microphone(Yeti Stereo Microph" in winmm. Sigh.
151 
152 (Also, DirectSound shouldn't be limited to 32 chars, but its device enum
153 has the same problem.)
154 
155 WASAPI doesn't need this. This is just for DirectSound/WinMM.
156 */
157 char *
158 WIN_LookupAudioDeviceName(const WCHAR *name, const GUID *guid)
159 {
160 #if __WINRT__
161  return WIN_StringToUTF8(name); /* No registry access on WinRT/UWP, go with what we've got. */
162 #else
163  static const GUID nullguid = { 0 };
164  const unsigned char *ptr;
165  char keystr[128];
166  WCHAR *strw = NULL;
167  SDL_bool rc;
168  HKEY hkey;
169  DWORD len = 0;
170  char *retval = NULL;
171 
172  if (WIN_IsEqualGUID(guid, &nullguid)) {
173  return WIN_StringToUTF8(name); /* No GUID, go with what we've got. */
174  }
175 
176  ptr = (const unsigned char *) guid;
177  SDL_snprintf(keystr, sizeof (keystr),
178  "System\\CurrentControlSet\\Control\\MediaCategories\\{%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
179  ptr[3], ptr[2], ptr[1], ptr[0], ptr[5], ptr[4], ptr[7], ptr[6],
180  ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15]);
181 
182  strw = WIN_UTF8ToString(keystr);
183  rc = (RegOpenKeyExW(HKEY_LOCAL_MACHINE, strw, 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS);
184  SDL_free(strw);
185  if (!rc) {
186  return WIN_StringToUTF8(name); /* oh well. */
187  }
188 
189  rc = (RegQueryValueExW(hkey, L"Name", NULL, NULL, NULL, &len) == ERROR_SUCCESS);
190  if (!rc) {
191  RegCloseKey(hkey);
192  return WIN_StringToUTF8(name); /* oh well. */
193  }
194 
195  strw = (WCHAR *) SDL_malloc(len + sizeof (WCHAR));
196  if (!strw) {
197  RegCloseKey(hkey);
198  return WIN_StringToUTF8(name); /* oh well. */
199  }
200 
201  rc = (RegQueryValueExW(hkey, L"Name", NULL, NULL, (LPBYTE) strw, &len) == ERROR_SUCCESS);
202  RegCloseKey(hkey);
203  if (!rc) {
204  SDL_free(strw);
205  return WIN_StringToUTF8(name); /* oh well. */
206  }
207 
208  strw[len / 2] = 0; /* make sure it's null-terminated. */
209 
210  retval = WIN_StringToUTF8(strw);
211  SDL_free(strw);
212  return retval ? retval : WIN_StringToUTF8(name);
213 #endif /* if __WINRT__ / else */
214 }
215 
216 BOOL
217 WIN_IsEqualGUID(const GUID * a, const GUID * b)
218 {
219  return (SDL_memcmp(a, b, sizeof (*a)) == 0);
220 }
221 
222 BOOL
223 WIN_IsEqualIID(REFIID a, REFIID b)
224 {
225  return (SDL_memcmp(a, b, sizeof (*a)) == 0);
226 }
227 
228 #endif /* __WIN32__ || __WINRT__ */
229 
230 /* vi: set ts=4 sw=4 expandtab: */
#define WIN_UTF8ToString(S)
Definition: SDL_windows.h:47
BOOL WIN_IsWindowsVistaOrGreater(void)
GLuint GLsizei const GLchar * message
int WIN_SetErrorFromHRESULT(const char *prefix, HRESULT hr)
BOOL WIN_IsEqualGUID(const GUID *a, const GUID *b)
GLenum GLsizei len
GLuint const GLchar * name
SDL_bool retval
char * WIN_LookupAudioDeviceName(const WCHAR *name, const GUID *guid)
HRESULT WIN_CoInitialize(void)
#define SDL_free
BOOL WIN_IsWindows7OrGreater(void)
#define TRUE
Definition: edid-parse.c:33
#define SDL_memcmp
#define WIN_StringToUTF8(S)
Definition: SDL_windows.h:46
#define SDL_zero(x)
Definition: SDL_stdinc.h:416
#define S_OK
Definition: SDL_directx.h:47
#define NULL
Definition: begin_code.h:164
SDL_bool
Definition: SDL_stdinc.h:139
GLuint buffer
void WIN_CoUninitialize(void)
int WIN_SetError(const char *prefix)
#define SDL_SetError
BOOL WIN_IsEqualIID(REFIID a, REFIID b)
#define SDL_snprintf
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:93
#define SDL_malloc
#define FALSE
Definition: edid-parse.c:34
GLboolean GLboolean GLboolean GLboolean a
GLboolean GLboolean GLboolean b