1 // license:BSD-3-Clause
2 // copyright-holders:Olivier Galibert, R. Belmont
3 //============================================================
4 //
5 //  sdlos_*.c - OS specific low level code
6 //
7 //  SDLMAME by Olivier Galibert and R. Belmont
8 //
9 //============================================================
10 
11 #include <windows.h>
12 #include <mmsystem.h>
13 
14 #include <cstdlib>
15 #ifndef _MSC_VER
16 #include <unistd.h>
17 #endif
18 
19 #include <cstdio>
20 #include <memory>
21 
22 // MAME headers
23 #include "osdlib.h"
24 #include "osdcomm.h"
25 #include "osdcore.h"
26 #include "strconv.h"
27 
28 #ifdef OSD_WINDOWS
29 #include "winutf8.h"
30 #endif
31 
32 //============================================================
33 //  GLOBAL VARIABLES
34 //============================================================
35 
36 #ifdef OSD_WINDOWS
37 void (*s_debugger_stack_crawler)() = nullptr;
38 #endif
39 
40 
41 //============================================================
42 //  osd_getenv
43 //============================================================
44 
osd_getenv(const char * name)45 const char *osd_getenv(const char *name)
46 {
47 	return getenv(name);
48 }
49 
50 
51 //============================================================
52 //  osd_setenv
53 //============================================================
54 
osd_setenv(const char * name,const char * value,int overwrite)55 int osd_setenv(const char *name, const char *value, int overwrite)
56 {
57 	char *buf;
58 	int result;
59 
60 	if (!overwrite)
61 	{
62 		if (osd_getenv(name) != nullptr)
63 			return 0;
64 	}
65 	buf = (char *) malloc(strlen(name)+strlen(value)+2);
66 	sprintf(buf, "%s=%s", name, value);
67 	result = putenv(buf);
68 
69 	/* will be referenced by environment
70 	 * Therefore it is not freed here
71 	 */
72 
73 	return result;
74 }
75 
76 //============================================================
77 //  osd_process_kill
78 //============================================================
79 
osd_process_kill()80 void osd_process_kill()
81 {
82 	TerminateProcess(GetCurrentProcess(), -1);
83 }
84 
85 //============================================================
86 //  osd_alloc_executable
87 //
88 //  allocates "size" bytes of executable memory.  this must take
89 //  things like NX support into account.
90 //============================================================
91 
osd_alloc_executable(size_t size)92 void *osd_alloc_executable(size_t size)
93 {
94 	return VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
95 }
96 
97 
98 //============================================================
99 //  osd_free_executable
100 //
101 //  frees memory allocated with osd_alloc_executable
102 //============================================================
103 
osd_free_executable(void * ptr,size_t size)104 void osd_free_executable(void *ptr, size_t size)
105 {
106 	VirtualFree(ptr, 0, MEM_RELEASE);
107 }
108 
109 
110 //============================================================
111 //  osd_break_into_debugger
112 //============================================================
113 
osd_break_into_debugger(const char * message)114 void osd_break_into_debugger(const char *message)
115 {
116 #ifdef OSD_WINDOWS
117 	if (IsDebuggerPresent())
118 	{
119 		win_output_debug_string_utf8(message);
120 		DebugBreak();
121 	}
122 	else if (s_debugger_stack_crawler != nullptr)
123 		(*s_debugger_stack_crawler)();
124 #else
125 	if (IsDebuggerPresent())
126 	{
127 		OutputDebugStringA(message);
128 		DebugBreak();
129 	}
130 #endif
131 }
132 
133 //============================================================
134 //  get_clipboard_text_by_format
135 //============================================================
136 
get_clipboard_text_by_format(std::string & result_text,UINT format,std::string (* convert)(LPCVOID data))137 static bool get_clipboard_text_by_format(std::string &result_text, UINT format, std::string (*convert)(LPCVOID data))
138 {
139 	bool result = false;
140 	HANDLE data_handle;
141 	LPVOID data;
142 
143 	// check to see if this format is available
144 	if (IsClipboardFormatAvailable(format))
145 	{
146 		// open the clipboard
147 		if (OpenClipboard(nullptr))
148 		{
149 			// try to access clipboard data
150 			data_handle = GetClipboardData(format);
151 			if (data_handle != nullptr)
152 			{
153 				// lock the data
154 				data = GlobalLock(data_handle);
155 				if (data != nullptr)
156 				{
157 					// invoke the convert
158 					result_text = (*convert)(data);
159 					result = true;
160 
161 					// unlock the data
162 					GlobalUnlock(data_handle);
163 				}
164 			}
165 
166 			// close out the clipboard
167 			CloseClipboard();
168 		}
169 	}
170 	return result;
171 }
172 
173 //============================================================
174 //  convert_wide
175 //============================================================
176 
convert_wide(LPCVOID data)177 static std::string convert_wide(LPCVOID data)
178 {
179 	return osd::text::from_wstring((LPCWSTR) data);
180 }
181 
182 //============================================================
183 //  convert_ansi
184 //============================================================
185 
convert_ansi(LPCVOID data)186 static std::string convert_ansi(LPCVOID data)
187 {
188 	return osd::text::from_astring((LPCSTR) data);
189 }
190 
191 //============================================================
192 //  osd_get_clipboard_text
193 //============================================================
194 
osd_get_clipboard_text()195 std::string osd_get_clipboard_text()
196 {
197 	std::string result;
198 
199 	// try to access unicode text
200 	if (!get_clipboard_text_by_format(result, CF_UNICODETEXT, convert_wide))
201 	{
202 		// try to access ANSI text
203 		get_clipboard_text_by_format(result, CF_TEXT, convert_ansi);
204 	}
205 
206 	return result;
207 }
208 
209 //============================================================
210 //  osd_getpid
211 //============================================================
212 
osd_getpid()213 int osd_getpid()
214 {
215 	return GetCurrentProcessId();
216 }
217 
218 //============================================================
219 //  osd_dynamic_bind
220 //============================================================
221 
222 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
223 // for classic desktop applications
224 #define load_library(filename) LoadLibrary(filename)
225 #else
226 // for Windows Store universal applications
227 #define load_library(filename) LoadPackagedLibrary(filename, 0)
228 #endif
229 
230 namespace osd {
231 class dynamic_module_win32_impl : public dynamic_module
232 {
233 public:
dynamic_module_win32_impl(std::vector<std::string> & libraries)234 	dynamic_module_win32_impl(std::vector<std::string> &libraries)
235 		: m_module(nullptr)
236 	{
237 		m_libraries = libraries;
238 	}
239 
~dynamic_module_win32_impl()240 	virtual ~dynamic_module_win32_impl() override
241 	{
242 		if (m_module != nullptr)
243 			FreeLibrary(m_module);
244 	};
245 
246 protected:
get_symbol_address(char const * symbol)247 	virtual generic_fptr_t get_symbol_address(char const *symbol) override
248 	{
249 		/*
250 		 * given a list of libraries, if a first symbol is successfully loaded from
251 		 * one of them, all additional symbols will be loaded from the same library
252 		 */
253 		if (m_module)
254 		{
255 			return reinterpret_cast<generic_fptr_t>(GetProcAddress(m_module, symbol));
256 		}
257 
258 		for (auto const &library : m_libraries)
259 		{
260 			osd::text::tstring tempstr = osd::text::to_tstring(library);
261 			HMODULE module = load_library(tempstr.c_str());
262 
263 			if (module != nullptr)
264 			{
265 				auto function = reinterpret_cast<generic_fptr_t>(GetProcAddress(module, symbol));
266 
267 				if (function != nullptr)
268 				{
269 					m_module = module;
270 					return function;
271 				}
272 				else
273 				{
274 					FreeLibrary(module);
275 				}
276 			}
277 		}
278 
279 		return nullptr;
280 	}
281 
282 private:
283 	std::vector<std::string> m_libraries;
284 	HMODULE                  m_module;
285 };
286 
open(std::vector<std::string> && names)287 dynamic_module::ptr dynamic_module::open(std::vector<std::string> &&names)
288 {
289 	return std::make_unique<dynamic_module_win32_impl>(names);
290 }
291 
292 } // namespace osd
293