|
1
|
1 #include "pfc-lite.h"
|
|
|
2
|
|
|
3 #ifdef _WIN32
|
|
|
4 #include "win-objects.h"
|
|
|
5 #include "array.h"
|
|
|
6 #include "pp-winapi.h"
|
|
|
7 #include "string_conv.h"
|
|
|
8 #include "string_base.h"
|
|
|
9 #include "debug.h"
|
|
|
10 #include "string-conv-lite.h"
|
|
|
11
|
|
|
12 #include "pfc-fb2k-hooks.h"
|
|
|
13
|
|
|
14 #include "sortstring.h"
|
|
|
15
|
|
|
16 // StrCmpLogicalW()
|
|
|
17 #include <Shlwapi.h>
|
|
|
18 #pragma comment(lib, "Shlwapi.lib")
|
|
|
19
|
|
|
20 namespace pfc {
|
|
|
21
|
|
|
22 BOOL winFormatSystemErrorMessageImpl(pfc::string_base & p_out,DWORD p_code) {
|
|
|
23 switch(p_code) {
|
|
|
24 case ERROR_CHILD_NOT_COMPLETE:
|
|
|
25 p_out = "Application cannot be run in Win32 mode.";
|
|
|
26 return TRUE;
|
|
|
27 case ERROR_INVALID_ORDINAL:
|
|
|
28 p_out = "Invalid ordinal.";
|
|
|
29 return TRUE;
|
|
|
30 case ERROR_INVALID_STARTING_CODESEG:
|
|
|
31 p_out = "Invalid code segment.";
|
|
|
32 return TRUE;
|
|
|
33 case ERROR_INVALID_STACKSEG:
|
|
|
34 p_out = "Invalid stack segment.";
|
|
|
35 return TRUE;
|
|
|
36 case ERROR_INVALID_MODULETYPE:
|
|
|
37 p_out = "Invalid module type.";
|
|
|
38 return TRUE;
|
|
|
39 case ERROR_INVALID_EXE_SIGNATURE:
|
|
|
40 p_out = "Invalid executable signature.";
|
|
|
41 return TRUE;
|
|
|
42 case ERROR_BAD_EXE_FORMAT:
|
|
|
43 p_out = "Not a valid Win32 application.";
|
|
|
44 return TRUE;
|
|
|
45 case ERROR_EXE_MACHINE_TYPE_MISMATCH:
|
|
|
46 p_out = "Machine type mismatch.";
|
|
|
47 return TRUE;
|
|
|
48 case ERROR_EXE_CANNOT_MODIFY_SIGNED_BINARY:
|
|
|
49 case ERROR_EXE_CANNOT_MODIFY_STRONG_SIGNED_BINARY:
|
|
|
50 p_out = "Unable to modify a signed binary.";
|
|
|
51 return TRUE;
|
|
|
52 default:
|
|
|
53 {
|
|
|
54 #ifdef PFC_WINDOWS_DESKTOP_APP
|
|
|
55 TCHAR temp[512];
|
|
|
56 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0,p_code,0,temp,_countof(temp),0) == 0) return FALSE;
|
|
|
57 for(t_size n=0;n<_countof(temp);n++) {
|
|
|
58 switch(temp[n]) {
|
|
|
59 case '\n':
|
|
|
60 case '\r':
|
|
|
61 temp[n] = ' ';
|
|
|
62 break;
|
|
|
63 }
|
|
|
64 }
|
|
|
65 p_out = stringcvt::string_utf8_from_os(temp,_countof(temp));
|
|
|
66 return TRUE;
|
|
|
67 #else
|
|
|
68 return FALSE;
|
|
|
69 #endif
|
|
|
70 }
|
|
|
71 }
|
|
|
72 }
|
|
|
73 void winPrefixPath(pfc::string_base & out, const char * p_path) {
|
|
|
74 if (pfc::string_has_prefix(p_path, "..\\") || strstr(p_path, "\\..\\") ) {
|
|
|
75 // do not touch relative paths if we somehow got them here
|
|
|
76 out = p_path;
|
|
|
77 return;
|
|
|
78 }
|
|
|
79 const char * prepend_header = "\\\\?\\";
|
|
|
80 const char * prepend_header_net = "\\\\?\\UNC\\";
|
|
|
81 if (pfc::strcmp_partial( p_path, prepend_header ) == 0) { out = p_path; return; }
|
|
|
82 out.reset();
|
|
|
83 if (pfc::strcmp_partial(p_path,"\\\\") != 0) {
|
|
|
84 out << prepend_header << p_path;
|
|
|
85 } else {
|
|
|
86 out << prepend_header_net << (p_path+2);
|
|
|
87 }
|
|
|
88 };
|
|
|
89
|
|
|
90 BOOL winFormatSystemErrorMessage(pfc::string_base & p_out, DWORD p_code) {
|
|
|
91 return winFormatSystemErrorMessageHook( p_out, p_code );
|
|
|
92 }
|
|
|
93 void winUnPrefixPath(pfc::string_base & out, const char * p_path) {
|
|
|
94 const char * prepend_header = "\\\\?\\";
|
|
|
95 const char * prepend_header_net = "\\\\?\\UNC\\";
|
|
|
96 if (pfc::strcmp_partial(p_path, prepend_header_net) == 0) {
|
|
|
97 out = PFC_string_formatter() << "\\\\" << (p_path + strlen(prepend_header_net) );
|
|
|
98 return;
|
|
|
99 }
|
|
|
100 if (pfc::strcmp_partial(p_path, prepend_header) == 0) {
|
|
|
101 out = (p_path + strlen(prepend_header));
|
|
|
102 return;
|
|
|
103 }
|
|
|
104 out = p_path;
|
|
|
105 }
|
|
|
106
|
|
|
107 string8 winPrefixPath(const char * in) {
|
|
|
108 string8 temp; winPrefixPath(temp, in); return temp;
|
|
|
109 }
|
|
|
110 string8 winUnPrefixPath(const char * in) {
|
|
|
111 string8 temp; winUnPrefixPath(temp, in); return temp;
|
|
|
112 }
|
|
|
113
|
|
|
114 } // namespace pfc
|
|
|
115
|
|
|
116 pfc::string8 format_win32_error(DWORD p_code) {
|
|
|
117 pfc::LastErrorRevertScope revert;
|
|
|
118 pfc::string8 buffer;
|
|
|
119 if (p_code == 0) buffer = "Undefined error";
|
|
|
120 else if (!pfc::winFormatSystemErrorMessage(buffer,p_code)) buffer << "Unknown error code (" << (unsigned)p_code << ")";
|
|
|
121 return buffer;
|
|
|
122 }
|
|
|
123
|
|
|
124 static void format_hresult_stamp_hex(pfc::string8 & buffer, HRESULT p_code) {
|
|
|
125 buffer << " (0x" << pfc::format_hex((t_uint32)p_code, 8) << ")";
|
|
|
126 }
|
|
|
127
|
|
|
128 pfc::string8 format_hresult(HRESULT p_code) {
|
|
|
129 pfc::string8 buffer;
|
|
|
130 if (!pfc::winFormatSystemErrorMessage(buffer,(DWORD)p_code)) buffer = "Unknown error code";
|
|
|
131 format_hresult_stamp_hex(buffer, p_code);
|
|
|
132 return buffer;
|
|
|
133 }
|
|
|
134 pfc::string8 format_hresult(HRESULT p_code, const char * msgOverride) {
|
|
|
135 pfc::string8 buffer = msgOverride;
|
|
|
136 format_hresult_stamp_hex(buffer, p_code);
|
|
|
137 return buffer;
|
|
|
138 }
|
|
|
139
|
|
|
140
|
|
|
141 #ifdef PFC_WINDOWS_DESKTOP_APP
|
|
|
142
|
|
|
143 namespace pfc {
|
|
|
144 HWND findOwningPopup(HWND p_wnd)
|
|
|
145 {
|
|
|
146 HWND walk = p_wnd;
|
|
|
147 while (walk != 0 && (GetWindowLong(walk, GWL_STYLE) & WS_CHILD) != 0)
|
|
|
148 walk = GetParent(walk);
|
|
|
149 return walk ? walk : p_wnd;
|
|
|
150 }
|
|
|
151 string8 getWindowClassName(HWND wnd) {
|
|
|
152 TCHAR temp[1024] = {};
|
|
|
153 if (GetClassName(wnd, temp, PFC_TABSIZE(temp)) == 0) {
|
|
|
154 PFC_ASSERT(!"Should not get here");
|
|
|
155 return "";
|
|
|
156 }
|
|
|
157 return pfc::stringcvt::string_utf8_from_os(temp).get_ptr();
|
|
|
158 }
|
|
|
159 void setWindowText(HWND wnd, const char * txt) {
|
|
|
160 SetWindowText(wnd, stringcvt::string_os_from_utf8(txt));
|
|
|
161 }
|
|
|
162 string8 getWindowText(HWND wnd) {
|
|
|
163 PFC_ASSERT(wnd != NULL);
|
|
|
164 int len = GetWindowTextLength(wnd);
|
|
|
165 if (len >= 0)
|
|
|
166 {
|
|
|
167 len++;
|
|
|
168 pfc::array_t<TCHAR> temp;
|
|
|
169 temp.set_size(len);
|
|
|
170 temp[0] = 0;
|
|
|
171 if (GetWindowText(wnd, temp.get_ptr(), len) > 0)
|
|
|
172 {
|
|
|
173 return stringcvt::string_utf8_from_os(temp.get_ptr(), len).get_ptr();
|
|
|
174 }
|
|
|
175 }
|
|
|
176 return "";
|
|
|
177 }
|
|
|
178 }
|
|
|
179
|
|
|
180 void uAddWindowStyle(HWND p_wnd,LONG p_style) {
|
|
|
181 SetWindowLong(p_wnd,GWL_STYLE, GetWindowLong(p_wnd,GWL_STYLE) | p_style);
|
|
|
182 }
|
|
|
183
|
|
|
184 void uRemoveWindowStyle(HWND p_wnd,LONG p_style) {
|
|
|
185 SetWindowLong(p_wnd,GWL_STYLE, GetWindowLong(p_wnd,GWL_STYLE) & ~p_style);
|
|
|
186 }
|
|
|
187
|
|
|
188 void uAddWindowExStyle(HWND p_wnd,LONG p_style) {
|
|
|
189 SetWindowLong(p_wnd,GWL_EXSTYLE, GetWindowLong(p_wnd,GWL_EXSTYLE) | p_style);
|
|
|
190 }
|
|
|
191
|
|
|
192 void uRemoveWindowExStyle(HWND p_wnd,LONG p_style) {
|
|
|
193 SetWindowLong(p_wnd,GWL_EXSTYLE, GetWindowLong(p_wnd,GWL_EXSTYLE) & ~p_style);
|
|
|
194 }
|
|
|
195
|
|
|
196 unsigned MapDialogWidth(HWND p_dialog,unsigned p_value) {
|
|
|
197 RECT temp;
|
|
|
198 temp.left = 0; temp.right = p_value; temp.top = temp.bottom = 0;
|
|
|
199 if (!MapDialogRect(p_dialog,&temp)) return 0;
|
|
|
200 return temp.right;
|
|
|
201 }
|
|
|
202
|
|
|
203 bool IsKeyPressed(unsigned vk) {
|
|
|
204 return (GetKeyState(vk) & 0x8000) ? true : false;
|
|
|
205 }
|
|
|
206
|
|
|
207 //! Returns current modifier keys pressed, using win32 MOD_* flags.
|
|
|
208 unsigned GetHotkeyModifierFlags() {
|
|
|
209 unsigned ret = 0;
|
|
|
210 if (IsKeyPressed(VK_CONTROL)) ret |= MOD_CONTROL;
|
|
|
211 if (IsKeyPressed(VK_SHIFT)) ret |= MOD_SHIFT;
|
|
|
212 if (IsKeyPressed(VK_MENU)) ret |= MOD_ALT;
|
|
|
213 if (IsKeyPressed(VK_LWIN) || IsKeyPressed(VK_RWIN)) ret |= MOD_WIN;
|
|
|
214 return ret;
|
|
|
215 }
|
|
|
216
|
|
|
217
|
|
|
218
|
|
|
219 bool CClipboardOpenScope::Open(HWND p_owner) {
|
|
|
220 Close();
|
|
|
221 if (OpenClipboard(p_owner)) {
|
|
|
222 m_open = true;
|
|
|
223 return true;
|
|
|
224 } else {
|
|
|
225 return false;
|
|
|
226 }
|
|
|
227 }
|
|
|
228 void CClipboardOpenScope::Close() {
|
|
|
229 if (m_open) {
|
|
|
230 m_open = false;
|
|
|
231 CloseClipboard();
|
|
|
232 }
|
|
|
233 }
|
|
|
234
|
|
|
235
|
|
|
236 CGlobalLockScope::CGlobalLockScope(HGLOBAL p_handle) : m_ptr(GlobalLock(p_handle)), m_handle(p_handle) {
|
|
|
237 if (m_ptr == NULL) throw std::bad_alloc();
|
|
|
238 }
|
|
|
239 CGlobalLockScope::~CGlobalLockScope() {
|
|
|
240 if (m_ptr != NULL) GlobalUnlock(m_handle);
|
|
|
241 }
|
|
|
242
|
|
|
243 bool IsPointInsideControl(const POINT& pt, HWND wnd) {
|
|
|
244 HWND walk = WindowFromPoint(pt);
|
|
|
245 for(;;) {
|
|
|
246 if (walk == NULL) return false;
|
|
|
247 if (walk == wnd) return true;
|
|
|
248 if (GetWindowLong(walk,GWL_STYLE) & WS_POPUP) return false;
|
|
|
249 walk = GetParent(walk);
|
|
|
250 }
|
|
|
251 }
|
|
|
252 bool IsPopupWindowChildOf(HWND child, HWND parent) {
|
|
|
253 HWND walk = child;
|
|
|
254 while (walk != parent && walk != NULL) {
|
|
|
255 walk = GetParent(walk);
|
|
|
256 }
|
|
|
257 return walk == parent;
|
|
|
258 }
|
|
|
259 bool IsWindowChildOf(HWND child, HWND parent) {
|
|
|
260 HWND walk = child;
|
|
|
261 while(walk != parent && walk != NULL && (GetWindowLong(walk,GWL_STYLE) & WS_CHILD) != 0) {
|
|
|
262 walk = GetParent(walk);
|
|
|
263 }
|
|
|
264 return walk == parent;
|
|
|
265 }
|
|
|
266 void ResignActiveWindow(HWND wnd) {
|
|
|
267 if (IsPopupWindowChildOf(GetActiveWindow(), wnd)) {
|
|
|
268 HWND parent = GetParent(wnd);
|
|
|
269 if ( parent != NULL ) SetActiveWindow(parent);
|
|
|
270 }
|
|
|
271 }
|
|
|
272 void win32_menu::release() {
|
|
|
273 if (m_menu != NULL) {
|
|
|
274 DestroyMenu(m_menu);
|
|
|
275 m_menu = NULL;
|
|
|
276 }
|
|
|
277 }
|
|
|
278
|
|
|
279 void win32_menu::create_popup() {
|
|
|
280 release();
|
|
|
281 SetLastError(NO_ERROR);
|
|
|
282 m_menu = CreatePopupMenu();
|
|
|
283 if (m_menu == NULL) throw exception_win32(GetLastError());
|
|
|
284 }
|
|
|
285
|
|
|
286 #endif // #ifdef PFC_WINDOWS_DESKTOP_APP
|
|
|
287
|
|
|
288 void win32_event::create(bool p_manualreset,bool p_initialstate) {
|
|
|
289 release();
|
|
|
290 SetLastError(NO_ERROR);
|
|
|
291 m_handle = CreateEvent(NULL,p_manualreset ? TRUE : FALSE, p_initialstate ? TRUE : FALSE,NULL);
|
|
|
292 if (m_handle == NULL) throw exception_win32(GetLastError());
|
|
|
293 }
|
|
|
294
|
|
|
295 void win32_event::release() {
|
|
|
296 HANDLE temp = detach();
|
|
|
297 if (temp != NULL) CloseHandle(temp);
|
|
|
298 }
|
|
|
299
|
|
|
300
|
|
|
301 DWORD win32_event::g_calculate_wait_time(double p_seconds) {
|
|
|
302 DWORD time = 0;
|
|
|
303 if (p_seconds> 0) {
|
|
|
304 time = pfc::rint32(p_seconds * 1000.0);
|
|
|
305 if (time == 0) time = 1;
|
|
|
306 } else if (p_seconds < 0) {
|
|
|
307 time = INFINITE;
|
|
|
308 }
|
|
|
309 return time;
|
|
|
310 }
|
|
|
311
|
|
|
312 //! Returns true when signaled, false on timeout
|
|
|
313 bool win32_event::g_wait_for(HANDLE p_event,double p_timeout_seconds) {
|
|
|
314 SetLastError(NO_ERROR);
|
|
|
315 DWORD status = WaitForSingleObject(p_event,g_calculate_wait_time(p_timeout_seconds));
|
|
|
316 switch(status) {
|
|
|
317 case WAIT_FAILED:
|
|
|
318 throw exception_win32(GetLastError());
|
|
|
319 case WAIT_OBJECT_0:
|
|
|
320 return true;
|
|
|
321 case WAIT_TIMEOUT:
|
|
|
322 return false;
|
|
|
323 default:
|
|
|
324 pfc::crash();
|
|
|
325 }
|
|
|
326 }
|
|
|
327
|
|
|
328 void win32_event::set_state(bool p_state) {
|
|
|
329 PFC_ASSERT(m_handle != NULL);
|
|
|
330 if (p_state) SetEvent(m_handle);
|
|
|
331 else ResetEvent(m_handle);
|
|
|
332 }
|
|
|
333
|
|
|
334 size_t win32_event::g_multiWait(const HANDLE* events, size_t count, double timeout) {
|
|
|
335 auto status = WaitForMultipleObjects((DWORD)count, events, FALSE, g_calculate_wait_time(timeout));
|
|
|
336 size_t idx = (size_t)(status - WAIT_OBJECT_0);
|
|
|
337 if (idx < count) {
|
|
|
338 return idx;
|
|
|
339 }
|
|
|
340 if (status == WAIT_TIMEOUT) return SIZE_MAX;
|
|
|
341 pfc::crash();
|
|
|
342 }
|
|
|
343 size_t win32_event::g_multiWait( std::initializer_list<HANDLE> const & arg, double timeout ) {
|
|
|
344 return g_multiWait(arg.begin(), arg.size(), timeout);
|
|
|
345 }
|
|
|
346
|
|
|
347 int win32_event::g_twoEventWait( HANDLE ev1, HANDLE ev2, double timeout ) {
|
|
|
348 HANDLE h[2] = {ev1, ev2};
|
|
|
349 switch(WaitForMultipleObjects(2, h, FALSE, g_calculate_wait_time( timeout ) )) {
|
|
|
350 default:
|
|
|
351 pfc::crash();
|
|
|
352 case WAIT_TIMEOUT:
|
|
|
353 return 0;
|
|
|
354 case WAIT_OBJECT_0:
|
|
|
355 return 1;
|
|
|
356 case WAIT_OBJECT_0 + 1:
|
|
|
357 return 2;
|
|
|
358 }
|
|
|
359 }
|
|
|
360
|
|
|
361 int win32_event::g_twoEventWait( win32_event & ev1, win32_event & ev2, double timeout ) {
|
|
|
362 return g_twoEventWait( ev1.get_handle(), ev2.get_handle(), timeout );
|
|
|
363 }
|
|
|
364
|
|
|
365 #ifdef PFC_WINDOWS_DESKTOP_APP
|
|
|
366
|
|
|
367 void win32_icon::release() {
|
|
|
368 HICON temp = detach();
|
|
|
369 if (temp != NULL) DestroyIcon(temp);
|
|
|
370 }
|
|
|
371
|
|
|
372
|
|
|
373 void win32_accelerator::load(HINSTANCE p_inst,const TCHAR * p_id) {
|
|
|
374 release();
|
|
|
375 SetLastError(NO_ERROR);
|
|
|
376 m_accel = LoadAccelerators(p_inst,p_id);
|
|
|
377 if (m_accel == NULL) {
|
|
|
378 throw exception_win32(GetLastError());
|
|
|
379 }
|
|
|
380 }
|
|
|
381
|
|
|
382 void win32_accelerator::release() {
|
|
|
383 if (m_accel != NULL) {
|
|
|
384 DestroyAcceleratorTable(m_accel);
|
|
|
385 m_accel = NULL;
|
|
|
386 }
|
|
|
387 }
|
|
|
388
|
|
|
389 #endif // #ifdef PFC_WINDOWS_DESKTOP_APP
|
|
|
390
|
|
|
391 void uSleepSeconds(double p_time,bool p_alertable) {
|
|
|
392 SleepEx(win32_event::g_calculate_wait_time(p_time),p_alertable ? TRUE : FALSE);
|
|
|
393 }
|
|
|
394
|
|
|
395
|
|
|
396 #ifdef PFC_WINDOWS_DESKTOP_APP
|
|
|
397
|
|
|
398 WORD GetWindowsVersionCode() throw() {
|
|
|
399 const DWORD ver = GetVersion();
|
|
|
400 return (WORD)HIBYTE(LOWORD(ver)) | ((WORD)LOBYTE(LOWORD(ver)) << 8);
|
|
|
401 }
|
|
|
402
|
|
|
403
|
|
|
404 namespace pfc {
|
|
|
405 bool isShiftKeyPressed() {
|
|
|
406 return IsKeyPressed(VK_SHIFT);
|
|
|
407 }
|
|
|
408 bool isCtrlKeyPressed() {
|
|
|
409 return IsKeyPressed(VK_CONTROL);
|
|
|
410 }
|
|
|
411 bool isAltKeyPressed() {
|
|
|
412 return IsKeyPressed(VK_MENU);
|
|
|
413 }
|
|
|
414
|
|
|
415 void winSetThreadDescription(HANDLE hThread, const wchar_t * desc) {
|
|
|
416 #if _WIN32_WINNT >= 0xA00
|
|
|
417 SetThreadDescription(hThread, desc);
|
|
|
418 #else
|
|
|
419 auto proc = GetProcAddress(GetModuleHandle(L"KernelBase.dll"), "SetThreadDescription");
|
|
|
420 if (proc == nullptr) {
|
|
|
421 proc = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "SetThreadDescription");
|
|
|
422 }
|
|
|
423 if (proc != nullptr) {
|
|
|
424 typedef HRESULT(__stdcall * pSetThreadDescription_t)(HANDLE hThread, PCWSTR lpThreadDescription);
|
|
|
425 auto proc2 = reinterpret_cast<pSetThreadDescription_t>(proc);
|
|
|
426 proc2(hThread, desc);
|
|
|
427 }
|
|
|
428 #endif
|
|
|
429 }
|
|
|
430 pfc::string8 format_window(HWND wnd) {
|
|
|
431 pfc::string_formatter ret;
|
|
|
432 ret << "0x" << format_hex( (size_t)wnd );
|
|
|
433 auto title = getWindowText(wnd);
|
|
|
434 if (title.length() > 0) {
|
|
|
435 ret << " [" << title << "]";
|
|
|
436 }
|
|
|
437 return ret;
|
|
|
438 }
|
|
|
439
|
|
|
440 #define _(X) {X, #X}
|
|
|
441 struct winStyle_t {
|
|
|
442 DWORD v; const char * n;
|
|
|
443 };
|
|
|
444 static const winStyle_t winStyles[] = {
|
|
|
445 _(WS_POPUP), _(WS_CHILD), _(WS_MINIMIZE), _(WS_VISIBLE),
|
|
|
446 _(WS_DISABLED), _(WS_CLIPSIBLINGS), _(WS_CLIPCHILDREN), _(WS_MAXIMIZE),
|
|
|
447 _(WS_BORDER), _(WS_DLGFRAME), _(WS_VSCROLL), _(WS_HSCROLL),
|
|
|
448 _(WS_SYSMENU), _(WS_THICKFRAME), _(WS_GROUP), _(WS_TABSTOP),
|
|
|
449 _(WS_MINIMIZEBOX), _(WS_MAXIMIZEBOX)
|
|
|
450 };
|
|
|
451
|
|
|
452 pfc::string8 format_windowStyle(DWORD style) {
|
|
|
453 pfc::string_formatter ret;
|
|
|
454 ret << "0x" << format_hex( style, 8 );
|
|
|
455 if (style != 0) {
|
|
|
456 pfc::string_formatter label;
|
|
|
457 for (auto& s : winStyles) if (style & s.v) {
|
|
|
458 if ( label.length() > 0 ) label << "|";
|
|
|
459 label << s.n;
|
|
|
460 }
|
|
|
461 if (label.length() > 0) {
|
|
|
462 ret << " [" << label << "]";
|
|
|
463 }
|
|
|
464 }
|
|
|
465 return ret;
|
|
|
466 }
|
|
|
467 }
|
|
|
468
|
|
|
469 #else
|
|
|
470 // If unknown / not available on this architecture, return false always
|
|
|
471 namespace pfc {
|
|
|
472 bool isShiftKeyPressed() {
|
|
|
473 return false;
|
|
|
474 }
|
|
|
475 bool isCtrlKeyPressed() {
|
|
|
476 return false;
|
|
|
477 }
|
|
|
478 bool isAltKeyPressed() {
|
|
|
479 return false;
|
|
|
480 }
|
|
|
481 }
|
|
|
482
|
|
|
483 #endif // #ifdef PFC_WINDOWS_DESKTOP_APP
|
|
|
484
|
|
|
485 namespace pfc {
|
|
|
486 void winSleep( double seconds ) {
|
|
|
487 DWORD ms = INFINITE;
|
|
|
488 if (seconds > 0) {
|
|
|
489 ms = rint32(seconds * 1000);
|
|
|
490 if (ms < 1) ms = 1;
|
|
|
491 } else if (seconds == 0) {
|
|
|
492 ms = 0;
|
|
|
493 }
|
|
|
494 Sleep(ms);
|
|
|
495 }
|
|
|
496 void sleepSeconds(double seconds) {
|
|
|
497 winSleep(seconds);
|
|
|
498 }
|
|
|
499 void yield() {
|
|
|
500 Sleep(1);
|
|
|
501 }
|
|
|
502
|
|
|
503 static pfc::string8 winUnicodeNormalize(const char* str, NORM_FORM form) {
|
|
|
504 pfc::string8 ret;
|
|
|
505 if (str != nullptr && *str != 0) {
|
|
|
506 auto w = wideFromUTF8(str);
|
|
|
507 int needed = NormalizeString(form, w, -1, nullptr, 0);
|
|
|
508 if (needed > 0) {
|
|
|
509 pfc::array_t<wchar_t> buf; buf.resize(needed);
|
|
|
510 int status = NormalizeString(form, w, -1, buf.get_ptr(), needed);
|
|
|
511 if (status > 0) {
|
|
|
512 ret = utf8FromWide(buf.get_ptr());
|
|
|
513 }
|
|
|
514 }
|
|
|
515 }
|
|
|
516 return ret;
|
|
|
517 }
|
|
|
518 pfc::string8 unicodeNormalizeD(const char* str) {
|
|
|
519 return winUnicodeNormalize(str, NormalizationD);
|
|
|
520 }
|
|
|
521 pfc::string8 unicodeNormalizeC(const char* str) {
|
|
|
522 return winUnicodeNormalize(str, NormalizationC);
|
|
|
523 }
|
|
|
524 int winNaturalSortCompare(const char* s1, const char* s2) {
|
|
|
525 int ret = winNaturalSortCompareI(s1, s2);
|
|
|
526 if (ret == 0) ret = strcmp(s1, s2);
|
|
|
527 return ret;
|
|
|
528 }
|
|
|
529 int winNaturalSortCompare(const wchar_t* s1, const wchar_t* s2) {
|
|
|
530 int ret = winNaturalSortCompareI(s1, s2);
|
|
|
531 if (ret == 0) ret = wcscmp(s1, s2);
|
|
|
532 return ret;
|
|
|
533 }
|
|
|
534 int winNaturalSortCompareI(const char* s1, const char* s2) {
|
|
|
535 return winNaturalSortCompareI(wideFromUTF8(s1), wideFromUTF8(s2));
|
|
|
536 }
|
|
|
537 int winNaturalSortCompareI(const wchar_t* s1, const wchar_t* s2) {
|
|
|
538 return StrCmpLogicalW(s1, s2);
|
|
|
539 }
|
|
|
540
|
|
|
541 #ifndef PFC_SORTSTRING_GENERIC
|
|
|
542 sortString_t makeSortString(const char* in) {
|
|
|
543 auto out = std::make_unique<wchar_t[]>(pfc::stringcvt::estimate_utf8_to_wide(in));
|
|
|
544 pfc::stringcvt::convert_utf8_to_wide_unchecked(out.get(), in);
|
|
|
545 return out;
|
|
|
546 }
|
|
|
547 sortString_t makeSortString(const wchar_t* in) {
|
|
|
548 size_t l = wcslen(in) + 1;
|
|
|
549 auto out = std::make_unique<wchar_t[]>(l+1);
|
|
|
550 memcpy(out.get(), in, sizeof(wchar_t) * l);
|
|
|
551 return out;
|
|
|
552 }
|
|
|
553 int sortStringCompare(sortString_t const& s1, sortString_t const& s2) {
|
|
|
554 return winNaturalSortCompare(s1.get(), s2.get());
|
|
|
555 }
|
|
|
556 int sortStringCompareI(sortString_t const& s1, sortString_t const& s2) {
|
|
|
557 return winNaturalSortCompareI(s1.get(), s2.get());
|
|
|
558 }
|
|
|
559 #endif
|
|
|
560 }
|
|
|
561
|
|
|
562
|
|
|
563 #endif // _WIN32
|