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