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