Mercurial > foo_out_sdl
comparison foosdk/sdk/pfc/win-objects.cpp @ 1:20d02a178406 default tip
*: check in everything else
yay
| author | Paper <paper@tflc.us> |
|---|---|
| date | Mon, 05 Jan 2026 02:15:46 -0500 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 0:e9bb126753e7 | 1:20d02a178406 |
|---|---|
| 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 |
