1 // =================================
   2 // Copyright (c) 2024 Seppo Laakko
   3 // Distributed under the MIT license
   4 // =================================
   5 
   6 using System;
   7 using System.Collections;
   8 using System.IO;
   9 
  10 namespace System.Windows.API
  11 {
  12     public const long ERROR_DUPLICATE_CODE_MAPPING = -2;
  13     public const long ERROR_CODE_NOT_FOUND = -1;
  14     public const long ERROR_OUT_OF_RESOURCES = 0;
  15     public const long ERROR_FILE_NOT_FOUND = 1;
  16     public const long ERROR_PATH_NOT_FOUND = 2;
  17     public const long ERROR_BAD_FORMAT = 3;
  18     public const long SE_ERR_ACCESSDENIED =  4;
  19     public const long SE_ERR_ASSOCINCOMPLETE = 5;
  20     public const long SE_ERR_DDEBUSY = 6;
  21     public const long SE_ERR_DDEFAIL = 7;
  22     public const long SE_ERR_DDETIMEOUT = 8;
  23     public const long SE_ERR_DLLNOTFOUND = 9;
  24     public const long SE_ERR_FNF = 10;
  25     public const long SE_ERR_NOASSOC = 11;
  26     public const long SE_ERR_OOM = 12;
  27     public const long SE_ERR_PNF = 13;
  28     public const long SE_ERR_SHARE = 14;
  29 
  30     [nodiscard]
  31     public Result<string> GetWindowsAPIErrorMessage(ulong errorCode)
  32     {
  33         wchar[4096] buffer;
  34         WinFormatMessage(errorCode&buffer[0]);
  35         auto utf8Result = ToUtf8(wstring(&buffer[0]));
  36         if (utf8Result.Error())
  37         {
  38             return Result<string>(ErrorId(utf8Result.GetErrorId()));
  39         }
  40         return Result<string>(utf8Result.Value());
  41     }
  42 
  43     [nodiscard]
  44     public Result<void*> FindFirstChangeNotification(const string& directoryPath)
  45     {
  46         void* notificationHandle = WinFindFirstChangeNotification(directoryPath.Chars());
  47         if (notificationHandle == null)
  48         {
  49             int errorId = WinAllocateWindowsError("find first change notification failed"WinGetLastError());
  50             return Result<void*>(ErrorId(errorId));
  51         }
  52         return Result<void*>(notificationHandle);
  53     }
  54 
  55     [nodiscard]
  56     public Result<bool> FindNextChangeNotification(void* notificationHandle)
  57     {
  58         bool result = WinFindNextChangeNotification(notificationHandle);
  59         if (!result)
  60         {
  61             int errorId = WinAllocateWindowsError("find next change notification failed"WinGetLastError());
  62             return Result<bool>(ErrorId(errorId));
  63         }
  64         return Result<bool>(true);
  65     }
  66 
  67     [nodiscard]
  68     public Result<bool> FindCloseChangeNotification(void* notificationHandle)
  69     {
  70         bool result = WinFindCloseChangeNotification(notificationHandle);
  71         if (!result)
  72         {
  73             int errorId = WinAllocateWindowsError("find close change notification failed"WinGetLastError());
  74             return Result<bool>(ErrorId(errorId));
  75         }
  76         return Result<bool>(true);
  77     }
  78 
  79     [nodiscard]
  80     public Result<void*> CreateEvent()
  81     {
  82         void* eventHandle = WinCreateEvent();
  83         if (eventHandle == null)
  84         {
  85             int errorId = WinAllocateWindowsError("create event failed"WinGetLastError());
  86             return Result<void*>(ErrorId(errorId));
  87         }
  88         return Result<void*>(eventHandle);
  89     }
  90 
  91     [nodiscard]
  92     public Result<bool> SetEvent(void* eventHandle)
  93     {
  94         bool result = WinSetEvent(eventHandle);
  95         if (!result)
  96         {
  97             int errorId = WinAllocateWindowsError("set event failed"WinGetLastError());
  98             return Result<bool>(ErrorId(errorId));
  99         }
 100         return Result<bool>(true);
 101     }
 102 
 103     [nodiscard]
 104     public Result<bool> ResetEvent(void* eventHandle)
 105     {
 106         bool result = WinResetEvent(eventHandle);
 107         if (!result)
 108         {
 109             int errorId = WinAllocateWindowsError("reset event failed"WinGetLastError());
 110             return Result<bool>(ErrorId(errorId));
 111         }
 112         return Result<bool>(true);
 113     }
 114 
 115     [nodiscard]
 116     public Result<bool> WaitEvent(void* eventHandle)
 117     {
 118         bool result = WinWaitEvent(eventHandle);
 119         if (!result)
 120         {
 121             int errorId = WinAllocateWindowsError("wait event failed"WinGetLastError());
 122             return Result<bool>(ErrorId(errorId));
 123         }
 124         return Result<bool>(true);
 125     }
 126 
 127     [nodiscard]
 128     public Result<bool> CloseHandle(void* handle)
 129     {
 130         bool result = WinCloseHandle(handle);
 131         if (!result)
 132         {
 133             int errorId = WinAllocateWindowsError("close handle failed"WinGetLastError());
 134             return Result<bool>(ErrorId(errorId));
 135         }
 136         return Result<bool>(true);
 137     }
 138 
 139     [nodiscard]
 140     public Result<bool> CloseEvent(void* eventHandle)
 141     {
 142         return CloseHandle(eventHandle);
 143     }
 144 
 145     [nodiscard]
 146     public Result<int> WaitForMultipleObjects(const List<void*>& handles)
 147     {
 148         int result = WinWaitForMultipleObjects(cast<uint>(handles.Count())handles.Begin().Ptr());
 149         if (result >= 0 && result <= handles.Count())
 150         {
 151             return Result<int>(result);
 152         }
 153         else
 154         {
 155             int errorId = WinAllocateWindowsError("wait for multiple objects failed"WinGetLastError());
 156             return Result<int>(ErrorId(errorId));
 157         }
 158     }
 159 
 160     [nodiscard]
 161     public Result<bool> ShellExecute(const string& filePath)
 162     {
 163         long errorCode = 0;
 164         bool succeeded = WinShellExecute(filePath.Chars()errorCode);
 165         if (!succeeded)
 166         {
 167             string errorMessage = "shell execution error for file \'" + filePath + "\': ";
 168             string error = "out of resources";
 169             switch (errorCode)
 170             {
 171                 case ERROR_DUPLICATE_CODE_MAPPING:
 172                 {
 173                     error = "duplicate code mapping detected"; break;
 174                 }
 175                 case ERROR_CODE_NOT_FOUND:
 176                 {
 177                     error = "code not found"; break;
 178                 }
 179                 case ERROR_OUT_OF_RESOURCES:
 180                 {
 181                     error = "out of resources"; break;
 182                 }
 183                 case ERROR_FILE_NOT_FOUND:
 184                 {
 185                     error = "file not found"; break;
 186                 }
 187                 case ERROR_PATH_NOT_FOUND:
 188                 {
 189                     error = "path not found"; break;
 190                 }
 191                 case ERROR_BAD_FORMAT:
 192                 {
 193                     error = "invalid executable"; break;
 194                 }
 195                 case SE_ERR_ACCESSDENIED:
 196                 {
 197                     error = "access denied"; break;
 198                 }
 199                 case SE_ERR_ASSOCINCOMPLETE:
 200                 {
 201                     error = "invalid file association"; break;
 202                 }
 203                 case SE_ERR_DDEBUSY:
 204                 {
 205                     error = "DDE busy"; break;
 206                 }
 207                 case SE_ERR_DDEFAIL:
 208                 {
 209                     error = "DDE failed"; break;
 210                 }
 211                 case SE_ERR_DDETIMEOUT:
 212                 {
 213                     error = "DDE timeout"; break;
 214                 }
 215                 case SE_ERR_DLLNOTFOUND:
 216                 {
 217                     error = "DLL not found"; break;
 218                 }
 219                 case SE_ERR_FNF:
 220                 {
 221                     error = "file not found"; break;
 222                 }
 223                 case SE_ERR_NOASSOC:
 224                 {
 225                     error = "no association for this type of file"; break;
 226                 }
 227                 case SE_ERR_OOM:
 228                 {
 229                     error = "not enough memory"; break;
 230                 }
 231                 case SE_ERR_PNF:
 232                 {
 233                     error = "path not found"; break;
 234                 }
 235                 case SE_ERR_SHARE:
 236                 {
 237                     error = "sharing violation"; break;
 238                 }
 239             }
 240             errorMessage.Append(error);
 241             int errorId = AllocateError(errorMessage);
 242             return Result<bool>(ErrorId(errorId));
 243         }
 244         return Result<bool>(true);
 245     }
 246 
 247     [nodiscard]
 248     public Result<ushort> RegisterWindowClass(const char* windowClassNameuint styleint backgroundColor)
 249     {
 250         ushort windowClass = WinRegisterWindowClass(windowClassNamestylebackgroundColor);
 251         if (windowClass == 0u)
 252         {
 253             int errorId = WinAllocateWindowsError("register window class failed"WinGetLastError());
 254             return Result<ushort>(ErrorId(errorId));
 255         }
 256         return Result<ushort>(windowClass);
 257     }
 258 
 259     [nodiscard]
 260     public Result<void*> CreateWindowByClassAtom(ushort windowClassconst char* windowNamelong stylelong exStylePoint locationSize sizeControl* parent)
 261     {
 262         void* parentHandle = null;
 263         if (parent != null)
 264         {
 265             parentHandle = parent->Handle();
 266         }
 267         void* result = WinCreateWindowByClassAtom(windowClasswindowNamestyleexStylelocation.xlocation.ysize.wsize.hparentHandle);
 268         if (result == null)
 269         {
 270             int errorId = WinAllocateWindowsError("create window by class atom failed"WinGetLastError());
 271             return Result<void*>(ErrorId(errorId));
 272         }
 273         else
 274         {
 275             return Result<void*>(result);
 276         }
 277     }
 278 
 279     [nodiscard]
 280     public Result<void*> CreateWindowByClassName(const char* windowClassconst char* windowNamelong stylelong exStylePoint locationSize sizeControl* parent)
 281     {
 282         void* parentHandle = null;
 283         if (parent != null)
 284         {
 285             parentHandle = parent->Handle();
 286         }
 287         void* result = WinCreateWindowByClassName(windowClasswindowNamestyleexStylelocation.xlocation.ysize.wsize.hparentHandle);
 288         if (result == null)
 289         {
 290             int errorId = WinAllocateWindowsError("create window by class name failed"WinGetLastError());
 291             return Result<void*>(ErrorId(errorId));
 292         }
 293         else
 294         {
 295             return Result<void*>(result);
 296         }
 297     }
 298 
 299     [nodiscard]
 300     public Result<bool> MoveWindow(void* windowHandleconst Point& locationconst Size& sizebool repaint)
 301     {
 302         bool succeeded = WinMoveWindow(windowHandlelocation.xlocation.ysize.wsize.hrepaint);
 303         if (!succeeded)
 304         {
 305             int errorId = WinAllocateWindowsError("move window failed"WinGetLastError());
 306             return Result<bool>(ErrorId(errorId));
 307         }
 308         return Result<bool>(true);
 309     }
 310 
 311     [nodiscard]
 312     public Result<WinRect> GetClientRect(void* windowHandle)
 313     {
 314         WinRect rect;
 315         bool succeeded = WinGetClientRect(windowHandle&rect);
 316         if (!succeeded)
 317         {
 318             int errorId = WinAllocateWindowsError("get client rect failed"WinGetLastError());
 319             return Result<WinRect>(ErrorId(errorId));
 320         }
 321         return Result<WinRect>(rect);
 322     }
 323 
 324     [nodiscard]
 325     public Result<WinRect> GetWindowRect(void* windowHandle)
 326     {
 327         WinRect rect;
 328         bool succeeded = WinGetWindowRect(windowHandle&rect);
 329         if (!succeeded)
 330         {
 331             int errorId = WinAllocateWindowsError("get window rect failed"WinGetLastError());
 332             return Result<WinRect>(ErrorId(errorId));
 333         }
 334         return Result<WinRect>(rect);
 335     }
 336 
 337     [nodiscard]
 338     public Result<Point> ClientToScreen(void* windowHandleconst Point& point)
 339     {
 340         Point pt(point);
 341         bool succeeded = WinClientToScreen(windowHandle&pt);
 342         if (!succeeded)
 343         {
 344             int errorId = WinAllocateWindowsError("client to screen failed"WinGetLastError());
 345             return Result<Point>(ErrorId(errorId));
 346         }
 347         return Result<Point>(pt);
 348     }
 349 
 350     [nodiscard]
 351     public Result<Point> ScreenToClient(void* windowHandleconst Point& point)
 352     {
 353         Point pt(point);
 354         bool succeeded = WinScreenToClient(windowHandle&pt);
 355         if (!succeeded)
 356         {
 357             int errorId = WinAllocateWindowsError("screen to client failed"WinGetLastError());
 358             return Result<Point>(ErrorId(errorId));
 359         }
 360         return Result<Point>(pt);
 361     }
 362 
 363     public bool PtInRect(const Point& pointconst WinRect& rect)
 364     {
 365         return WinPtInRect(&rect&point);
 366     }
 367 
 368     [nodiscard]
 369     public Result<bool> SetWindowText(void* windowHandleconst string& text)
 370     {
 371         bool succeeded = WinSetWindowText(windowHandletext.Chars());
 372         if (!succeeded)
 373         {
 374             int errorId = WinAllocateWindowsError("set window text failed"WinGetLastError());
 375             return Result<bool>(ErrorId(errorId));
 376         }
 377         return Result<bool>(true);
 378     }
 379 
 380     [nodiscard]
 381     public Result<int> GetWindowTextLength(void* windowHandle)
 382     {
 383         int result = WinGetWindowTextLength(windowHandle);
 384         if (result == 0)
 385         {
 386             ulong errorCode = WinGetLastError();
 387             if (errorCode != 0u)
 388             {
 389                 int errorId = WinAllocateWindowsError("get window text length failed"errorCode);
 390                 return Result<int>(ErrorId(errorId));
 391             }
 392         }
 393         return Result<int>(result);
 394     }
 395 
 396     [nodiscard]
 397     public Result<string> GetWindowText(void* windowHandle)
 398     {
 399         Result<int> lengthResult = GetWindowTextLength(windowHandle);
 400         if (lengthResult.Error())
 401         {
 402             return Result<string>(ErrorId(lengthResult.GetErrorId()));
 403         }
 404         int length = lengthResult.Value();
 405         UniquePtr<wchar> buffer(cast<wchar*>(MemAlloc(sizeof(wchar) * (length + 1))));
 406         int result = WinGetWindowText(windowHandlebuffer.Get()length + 1);
 407         if (result == 0)
 408         {
 409             ulong errorCode = WinGetLastError();
 410             if (errorCode != 0u)
 411             {
 412                 int errorId = WinAllocateWindowsError("get window text failed"errorCode);
 413                 return Result<string>(ErrorId(errorId));
 414             }
 415         }
 416         auto utf8Result = ToUtf8(buffer.Get());
 417         if (utf8Result.Error())
 418         {
 419             return Result<string>(ErrorId(utf8Result.GetErrorId()));
 420         }
 421         return Result<string>(utf8Result.Value());
 422     }
 423 
 424     [nodiscard]
 425     public Result<bool> SetParentWindow(void* childWindowHandlevoid* parentWindowHandle)
 426     {
 427         void* result = WinSetParent(childWindowHandleparentWindowHandle);
 428         if (result == null)
 429         {
 430             int errorId = WinAllocateWindowsError("set parent window failed"WinGetLastError());
 431             return Result<bool>(ErrorId(errorId));
 432         }
 433         return Result<bool>(true);
 434     }
 435 
 436     [nodiscard]
 437     public Result<void*> BeginPaint(void* windowHandlevoid*& paintStruct)
 438     {
 439         void* result = WinBeginPaint(windowHandlepaintStruct);
 440         if (result == null)
 441         {
 442             int errorId = WinAllocateWindowsError("begin paint failed"WinGetLastError());
 443             return Result<void*>(ErrorId(errorId));
 444         }
 445         return Result<void*>(result);
 446     }
 447 
 448     public void EndPaint(void* windowHandlevoid* paintStruct)
 449     {
 450         WinEndPaint(windowHandlepaintStruct);
 451     }
 452 
 453     [nodiscard]
 454     public Result<bool> InvalidateRect(void* windowHandleWinRect* rectbool eraseBackground)
 455     {
 456         bool succeeded = WinInvalidateRect(windowHandlerecteraseBackground);
 457         if (!succeeded)
 458         {
 459             int errorId = WinAllocateWindowsError("invalidate rect failed"WinGetLastError());
 460             return Result<bool>(ErrorId(errorId));
 461         }
 462         return Result<bool>(true);
 463     }
 464 
 465     [nodiscard]
 466     public Result<bool> MessageBeep(uint beepType)
 467     {
 468         bool succeeded = WinMessageBeep(beepType);
 469         if (!succeeded)
 470         {
 471             int errorId = WinAllocateWindowsError("message beep failed"WinGetLastError());
 472             return Result<bool>(ErrorId(errorId));
 473         }
 474         return Result<bool>(true);
 475     }
 476 
 477     public void* GetDC(void* windowHandle)
 478     {
 479         return WinGetDC(windowHandle);
 480     }
 481 
 482     [nodiscard]
 483     public Result<bool> PostMessage(void* windowHandleuint msgulong wparamlong lparam)
 484     {
 485         bool succeeded = WinPostMessage(windowHandlemsgwparamlparam);
 486         if (!succeeded)
 487         {
 488             int errorId = WinAllocateWindowsError("post message failed"WinGetLastError());
 489             return Result<bool>(ErrorId(errorId));
 490         }
 491         return Result<bool>(true);
 492     }
 493 
 494     public string CommonDialogError(uint errorCode)
 495     {
 496         string errorStr;
 497         switch (errorCode)
 498         {
 499             case 65535u:
 500             {
 501                 errorStr = "CDERR_DIALOGFAILURE";
 502                 break;
 503             }
 504             case 6u:
 505             {
 506                 errorStr = "CDERR_FINDRESFAILURE";
 507                 break;
 508             }
 509             case 2u:
 510             {
 511                 errorStr = "CDERR_INITIALIZATION";
 512                 break;
 513             }
 514             case 7u:
 515             {
 516                 errorStr = "CDERR_LOADRESFAILURE";
 517                 break;
 518             }
 519             case 5u:
 520             {
 521                 errorStr = "CDERR_LOADSTRFAILURE";
 522                 break;
 523             }
 524             case 8u:
 525             {
 526                 errorStr = "CDERR_LOCKRESFAILURE";
 527                 break;
 528             }
 529             case 9u:
 530             {
 531                 errorStr = "CDERR_MEMALLOCFAILURE";
 532                 break;
 533             }
 534             case 10u:
 535             {
 536                 errorStr = "CDERR_MEMLOCKFAILURE";
 537                 break;
 538             }
 539             case 4u:
 540             {
 541                 errorStr = "CDERR_NOHINSTANCE";
 542                 break;
 543             }
 544             case 11u:
 545             {
 546                 errorStr = "CDERR_NOHOOK";
 547                 break;
 548             }
 549             case 3u:
 550             {
 551                 errorStr = "CDERR_NOTEMPLATE";
 552                 break;
 553             }
 554             case 12u:
 555             {
 556                 errorStr = "CDERR_REGISTERMSGFAIL";
 557                 break;
 558             }
 559             case 1u:
 560             {
 561                 errorStr = "CDERR_STRUCTSIZE";
 562                 break;
 563             }
 564             case 4106u:
 565             {
 566                 errorStr = "PDERR_CREATEICFAILURE";
 567                 break;
 568             }
 569             case 4108u:
 570             {
 571                 errorStr = "PDERR_DEFAULTDIFFERENT";
 572                 break;
 573             }
 574             case 4105u:
 575             {
 576                 errorStr = "PDERR_DNDMMISMATCH";
 577                 break;
 578             }
 579             case 4101u:
 580             {
 581                 errorStr = "PDERR_GETDEVMODEFAIL";
 582                 break;
 583             }
 584             case 4102u:
 585             {
 586                 errorStr = "PDERR_INITFAILURE";
 587                 break;
 588             }
 589             case 4100u:
 590             {
 591                 errorStr = "PDERR_LOADDRVFAILURE";
 592                 break;
 593             }
 594             case 4104u:
 595             {
 596                 errorStr = "PDERR_NODEFAULTPRN";
 597                 break;
 598             }
 599             case 4103u:
 600             {
 601                 errorStr = "PDERR_NODEVICES";
 602                 break;
 603             }
 604             case 4098u:
 605             {
 606                 errorStr = "PDERR_PARSEFAILURE";
 607                 break;
 608             }
 609             case 4107u:
 610             {
 611                 errorStr = "PDERR_PRINTERNOTFOUND";
 612                 break;
 613             }
 614             case 4099u:
 615             {
 616                 errorStr = "PDERR_RETDEFFAILURE";
 617                 break;
 618             }
 619             case 4097u:
 620             {
 621                 errorStr = "PDERR_SETUPFAILURE";
 622                 break;
 623             }
 624             case 8194u:
 625             {
 626                 errorStr = "CFERR_MAXLESSTHANMIN";
 627                 break;
 628             }
 629             case 8193u:
 630             {
 631                 errorStr = "CFERR_NOFONTS";
 632                 break;
 633             }
 634             case 12291u:
 635             {
 636                 errorStr = "FNERR_BUFFERTOOSMALL";
 637                 break;
 638             }
 639             case 12290u:
 640             {
 641                 errorStr = "FNERR_INVALIDFILENAME";
 642                 break;
 643             }
 644             case 12289u:
 645             {
 646                 errorStr = "FNERR_SUBCLASSFAILURE";
 647                 break;
 648             }
 649             case 16385u:
 650             {
 651                 errorStr = "FRERR_BUFFERLENGTHZERO";
 652                 break;
 653             }
 654             default:
 655             {
 656                 errorStr = "generic error";
 657                 break;
 658             }
 659         }
 660         return errorStr;
 661     }
 662 
 663     public const uint OFN_READONLY =                1u;
 664     public const uint OFN_OVERWRITEPROMPT =         2u;
 665     public const uint OFN_HIDEREADONLY =            4u;
 666     public const uint OFN_NOCHANGEDIR =             8u;
 667     public const uint OFN_SHOWHELP =                16u;
 668     public const uint OFN_ENABLEHOOK =              32u;
 669     public const uint OFN_ENABLETEMPLATE =          64u;
 670     public const uint OFN_ENABLETEMPLATEHANDLE =    128u;
 671     public const uint OFN_NOVALIDATE =              256u;
 672     public const uint OFN_ALLOWMULTISELECT =        512u;
 673     public const uint OFN_EXTENSIONDIFFERENT =      1024u;
 674     public const uint OFN_PATHMUSTEXIST =           2048u;
 675     public const uint OFN_FILEMUSTEXIST =           4096u;
 676     public const uint OFN_CREATEPROMPT =            8192u;
 677     public const uint OFN_SHAREAWARE =              16384u;
 678     public const uint OFN_NOREADONLYRETURN =        32768u;
 679     public const uint OFN_NOTESTFILECREATE =        65536u;
 680     public const uint OFN_NONETWORKBUTTON =         131072u;
 681     public const uint OFN_NOLONGNAMES =             262144u;
 682     public const uint OFN_EXPLORER =                524288u;
 683     public const uint OFN_NODEREFERENCELINKS =      1048576u;
 684     public const uint OFN_LONGNAMES =               2097152u;
 685 
 686     [nodiscard]
 687     public Result<bool> GetOpenFileName(void* windowHandleconst List<Pair<stringstring>>& descriptionFilterPairsconst string& initialDirectory
 688         const string& defaultFilePathconst string& defaultExtensionuint flagsstring& currentDirectoryList<string>& fileNames)
 689     {
 690         long filterBufferSize = 0;
 691         for (const Pair<stringstring>& descriptionFilterPair : descriptionFilterPairs)
 692         {
 693             auto descriptionResult = ToUtf16(descriptionFilterPair.first);
 694             if (descriptionResult.Error())
 695             {
 696                 return Result<bool>(ErrorId(descriptionResult.GetErrorId()));
 697             }
 698             wstring description = Rvalue(descriptionResult.Value());
 699             auto filterResult = ToUtf16(descriptionFilterPair.second);
 700             if (filterResult.Error())
 701             {
 702                 return Result<bool>(ErrorId(filterResult.GetErrorId()));
 703             }
 704             wstring filter = Rvalue(filterResult.Value());
 705             filterBufferSize = filterBufferSize + description.Length() + 1 + filter.Length() + 1;
 706         }
 707         filterBufferSize = filterBufferSize + 1 + 1;
 708         UniquePtr<wchar> filterBuffer = cast<wchar*>(MemAlloc(sizeof(wchar) * filterBufferSize));
 709         wchar* filterBufferPtr = filterBuffer.Get();
 710         for (const Pair<stringstring>& descriptionFilterPair : descriptionFilterPairs)
 711         {
 712             auto descriptionResult = ToUtf16(descriptionFilterPair.first);
 713             if (descriptionResult.Error())
 714             {
 715                 return Result<bool>(ErrorId(descriptionResult.GetErrorId()));
 716             }
 717             wstring description = Rvalue(descriptionResult.Value());
 718             long descLen = StrCopy(filterBufferPtrdescription.Chars()description.Length());
 719             filterBufferPtr = filterBufferPtr + descLen + 1;
 720             auto filterResult = ToUtf16(descriptionFilterPair.second);
 721             if (filterResult.Error())
 722             {
 723                 return Result<bool>(ErrorId(filterResult.GetErrorId()));
 724             }
 725             wstring filter = Rvalue(filterResult.Value());
 726             long filterLen = StrCopy(filterBufferPtrfilter.Chars()filter.Length());
 727             filterBufferPtr = filterBufferPtr + filterLen + 1;
 728         }
 729         *filterBufferPtr++ = '\0';
 730         *filterBufferPtr++ = '\0';
 731         long fileNameBufferSize = 16 * 1024;
 732         UniquePtr<wchar> fileNameBuffer = cast<wchar*>(MemAlloc(sizeof(wchar) * fileNameBufferSize));
 733         auto defaultFilePathResult = ToUtf16(defaultFilePath);
 734         if (defaultFilePathResult.Error())
 735         {
 736             return Result<bool>(ErrorId(defaultFilePathResult.GetErrorId()));
 737         }
 738         wstring defFilePath = Rvalue(defaultFilePathResult.Value());
 739         if (defaultFilePath.IsEmpty())
 740         {
 741             *fileNameBuffer.Get() = '\0';
 742         }
 743         else
 744         {
 745             StrCopy(fileNameBuffer.Get()defFilePath.Chars()defFilePath.Length());
 746         }
 747         auto initialDirResult = ToUtf16(initialDirectory);
 748         if (initialDirResult.Error())
 749         {
 750             return Result<bool>(ErrorId(initialDirResult.GetErrorId()));
 751         }
 752         wstring initialDir = Rvalue(initialDirResult.Value());
 753         auto defExtResult = ToUtf16(defaultExtension);
 754         if (defExtResult.Error())
 755         {
 756             return Result<bool>(ErrorId(defExtResult.GetErrorId()));
 757         }
 758         wstring defExt = Rvalue(defExtResult.Value());
 759         bool success = WinGetOpenFileName(windowHandlefilterBuffer.Get()initialDir.Chars()fileNameBuffer.Get()cast<uint>(fileNameBufferSize)flagsdefExt.Chars());
 760         if (success)
 761         {
 762             long firstPathLength = StrLen(fileNameBuffer.Get());
 763             auto firstPathResult = ToUtf8(wstring(fileNameBuffer.Get()firstPathLength));
 764             if (firstPathResult.Error())
 765             {
 766                 return Result<bool>(ErrorId(firstPathResult.GetErrorId()));
 767             }
 768             string firstPath = Rvalue(firstPathResult.Value());
 769             if ((flags & OFN_ALLOWMULTISELECT) == 0)
 770             {
 771                 currentDirectory = Path.GetDirectoryName(firstPath);
 772                 fileNames.Add(Path.GetFileName(firstPath));
 773             }
 774             else
 775             {
 776                 currentDirectory = firstPath;
 777                 long pathStart = firstPathLength + 1;
 778                 wchar* wpath = fileNameBuffer.Get() + pathStart;
 779                 while (*wpath != '\0')
 780                 {
 781                     long pathLength = StrLen(wpath);
 782                     auto pathResult = ToUtf8(wstring(wpathpathLength));
 783                     if (pathResult.Error())
 784                     {
 785                         return Result<bool>(ErrorId(pathResult.GetErrorId()));
 786                     }
 787                     string path = Rvalue(pathResult.Value());
 788                     fileNames.Add(path);
 789                     wpath = wpath + pathLength + 1;
 790                 }
 791             }
 792             return Result<bool>(true);
 793         }
 794         else
 795         {
 796             uint errorCode = WinCommDlgExtendedError();
 797             if (errorCode == 0u)
 798             {
 799                 return Result<bool>(false);
 800             }
 801             else
 802             {
 803                 string message = CommonDialogError(errorCode);
 804                 int errorId = AllocateError("get open file name failed: " + message);
 805                 return Result<bool>(ErrorId(errorId));
 806             }
 807         }
 808         return Result<bool>(false);
 809     }
 810 
 811     [nodiscard]
 812     public Result<bool> GetSaveFileName(void* windowHandleconst List<Pair<stringstring>>& descriptionFilterPairsconst string& initialDirectory
 813         const string& defaultFilePathconst string& defaultExtensionuint flagsstring& currentDirectorystring& filePath)
 814     {
 815         long filterBufferSize = 0;
 816         for (const Pair<stringstring>& descriptionFilterPair : descriptionFilterPairs)
 817         {
 818             auto descriptionResult = ToUtf16(descriptionFilterPair.first);
 819             if (descriptionResult.Error())
 820             {
 821                 return Result<bool>(ErrorId(descriptionResult.GetErrorId()));
 822             }
 823             wstring description = Rvalue(descriptionResult.Value());
 824             auto filterResult = ToUtf16(descriptionFilterPair.second);
 825             if (filterResult.Error())
 826             {
 827                 return Result<bool>(ErrorId(filterResult.GetErrorId()));
 828             }
 829             wstring filter = Rvalue(filterResult.Value());
 830             filterBufferSize = filterBufferSize + description.Length() + 1 + filter.Length() + 1;
 831         }
 832         filterBufferSize = filterBufferSize + 1 + 1;
 833         UniquePtr<wchar> filterBuffer = cast<wchar*>(MemAlloc(sizeof(wchar) * filterBufferSize));
 834         wchar* filterBufferPtr = filterBuffer.Get();
 835         for (const Pair<stringstring>& descriptionFilterPair : descriptionFilterPairs)
 836         {
 837             auto descriptionResult = ToUtf16(descriptionFilterPair.first);
 838             if (descriptionResult.Error())
 839             {
 840                 return Result<bool>(ErrorId(descriptionResult.GetErrorId()));
 841             }
 842             wstring description = Rvalue(descriptionResult.Value());
 843             long descLen = StrCopy(filterBufferPtrdescription.Chars()description.Length());
 844             filterBufferPtr = filterBufferPtr + descLen + 1;
 845             auto filterResult = ToUtf16(descriptionFilterPair.second);
 846             if (filterResult.Error())
 847             {
 848                 return Result<bool>(ErrorId(filterResult.GetErrorId()));
 849             }
 850             wstring filter = Rvalue(filterResult.Value());
 851             long filterLen = StrCopy(filterBufferPtrfilter.Chars()filter.Length());
 852             filterBufferPtr = filterBufferPtr + filterLen + 1;
 853         }
 854         *filterBufferPtr++ = '\0';
 855         *filterBufferPtr++ = '\0';
 856         long fileNameBufferSize = 1024;
 857         UniquePtr<wchar> fileNameBuffer = cast<wchar*>(MemAlloc(sizeof(wchar) * fileNameBufferSize));
 858         auto defFilePathResult = ToUtf16(defaultFilePath);
 859         if (defFilePathResult.Error())
 860         {
 861             return Result<bool>(ErrorId(defFilePathResult.GetErrorId()));
 862         }
 863         wstring defFilePath = Rvalue(defFilePathResult.Value());
 864         if (defaultFilePath.IsEmpty())
 865         {
 866             *fileNameBuffer.Get() = '\0';
 867         }
 868         else
 869         {
 870             StrCopy(fileNameBuffer.Get()defFilePath.Chars()defFilePath.Length());
 871         }
 872         auto initialDirResult = ToUtf16(initialDirectory);
 873         if (initialDirResult.Error())
 874         {
 875             return Result<bool>(ErrorId(initialDirResult.GetErrorId()));
 876         }
 877         wstring initialDir = Rvalue(initialDirResult.Value());
 878         auto defExtResult = ToUtf16(defaultExtension);
 879         if (defExtResult.Error())
 880         {
 881             return Result<bool>(ErrorId(defExtResult.GetErrorId()));
 882         }
 883         wstring defExt = Rvalue(defExtResult.Value());
 884         bool success = WinGetSaveFileName(windowHandlefilterBuffer.Get()initialDir.Chars()fileNameBuffer.Get()cast<uint>(fileNameBufferSize)flagsdefExt.Chars());
 885         if (success)
 886         {
 887             long firstPathLength = StrLen(fileNameBuffer.Get());
 888             auto filePathResult = ToUtf8(wstring(fileNameBuffer.Get()firstPathLength));
 889             if (filePathResult.Error())
 890             {
 891                 return Result<bool>(ErrorId(filePathResult.GetErrorId()));
 892             }
 893             filePath = Rvalue(filePathResult.Value());
 894             return Result<bool>(true);
 895         }
 896         else
 897         {
 898             uint errorCode = WinCommDlgExtendedError();
 899             if (errorCode == 0u)
 900             {
 901                 return Result<bool>(false);
 902             }
 903             else
 904             {
 905                 string message = CommonDialogError(errorCode);
 906                 int errorId = AllocateError("get save file name failed: " + message);
 907                 return Result<bool>(ErrorId(errorId));
 908             }
 909         }
 910         return Result<bool>(false);
 911     }
 912 
 913     [nodiscard]
 914     public Result<void*> LoadImage(const char* nameuint typeint cxint cy)
 915     {
 916         void* result = WinLoadImage(nametypecxcy);
 917         if (result == null)
 918         {
 919             int errorId = WinAllocateWindowsError("load image failed"WinGetLastError());
 920             return Result<void*>(ErrorId(errorId));
 921         }
 922         return Result<void*>(result);
 923     }
 924 
 925     [nodiscard]
 926     public Result<void*> LoadCursor(const char* name)
 927     {
 928         void* result = WinLoadCursor(name);
 929         if (result == null)
 930         {
 931             int errorId = WinAllocateWindowsError("load cursor failed"WinGetLastError());
 932             return Result<void*>(ErrorId(errorId));
 933         }
 934         return Result<void*>(result);
 935     }
 936 
 937     [nodiscard]
 938     public Result<void*> LoadIcon(const char* name)
 939     {
 940         void* result = WinLoadIcon(name);
 941         if (result == null)
 942         {
 943             int errorId = WinAllocateWindowsError("load icon failed"WinGetLastError());
 944             return Result<void*>(ErrorId(errorId));
 945         }
 946         return Result<void*>(result);
 947     }
 948 
 949     [nodiscard]
 950     public Result<void*> LoadBitmap(const char* name)
 951     {
 952         void* result = WinLoadBitmap(name);
 953         if (result == null)
 954         {
 955             int errorId = WinAllocateWindowsError("load bitmap failed"WinGetLastError());
 956             return Result<void*>(ErrorId(errorId));
 957         }
 958         return Result<void*>(result);
 959     }
 960 
 961     [nodiscard]
 962     public Result<int> GetSystemMetrics(int index)
 963     {
 964         int result = WinGetSystemMetrics(index);
 965         if (result == 0)
 966         {
 967             int errorId = WinAllocateWindowsError("get system metrics failed"WinGetLastError());
 968             return Result<int>(ErrorId(errorId));
 969         }
 970         return Result<int>(result);
 971     }
 972 
 973     public void* GetTopWindow(void* windowHandle)
 974     {
 975         return WinGetTopWindow(windowHandle);
 976     }
 977 
 978     [nodiscard]
 979     public Result<bool> BringWindowToTop(void* windowHandle)
 980     {
 981         bool succeeded = WinBringWindowToTop(windowHandle);
 982         if (!succeeded)
 983         {
 984             int errorId = WinAllocateWindowsError("bring window to top failed"WinGetLastError());
 985             return Result<bool>(ErrorId(errorId));
 986         }
 987         return Result<bool>(true);
 988     }
 989 
 990     public enum WindowPos : int
 991     {
 992         top = 0bottom = 1topmost = -1noTopmost = -2
 993     }
 994 
 995     public void* WindowPosHandle(WindowPos pos)
 996     {
 997         return cast<void*>(cast<ulong>(cast<int>(pos)));
 998     }
 999 
1000     public enum SetWindowPosFlags : uint
1001     {
1002         SWP_ASYNCWINDOWPOS = 16384u
1003         SWP_DEFERERASE = 8192u
1004         SWP_DRAWFRAME = 32u
1005         SWP_FRAMECHANGED = 32u
1006         SWP_HIDEWINDOW = 128u
1007         SWP_NOACTIVATE = 16u
1008         SWP_NOCOPYBITS = 256u
1009         SWP_NOMOVE = 2u
1010         SWP_NOOWNERZORDER = 512u
1011         SWP_NOREDRAW = 8u
1012         SWP_NOREPOSITION = 512u
1013         SWP_NOSENDCHANGING = 1024u
1014         SWP_NOSIZE = 1u
1015         SWP_NOZORDER = 4u
1016         SWP_SHOWWINDOW = 64u
1017     }
1018 
1019     [nodiscard]
1020     public Result<bool> SetWindowPos(void* windowHandlevoid* insertAfterWindowHandleint xint yint cxint cySetWindowPosFlags flags)
1021     {
1022         bool succeeded = WinSetWindowPos(windowHandleinsertAfterWindowHandlexycxcycast<uint>(flags));
1023         if (!succeeded)
1024         {
1025             int errorId = WinAllocateWindowsError("set window pos failed"WinGetLastError());
1026             return Result<bool>(ErrorId(errorId));
1027         }
1028         return Result<bool>(true);
1029     }
1030 
1031     public enum ClassLongIndex : int
1032     {
1033         GCL_CBCLSEXTRA = -20
1034         GCL_CBWNDEXTRA = -18
1035         GCL_HBRBACKGROUND = -10
1036         GCL_HCURSOR = -12
1037         GCL_HICON = -14
1038         GCL_HICONSM = -34
1039         GCL_HMODULE = -16
1040         GCL_MENUNAME = -8
1041         GCL_STYLE = -26
1042         GCL_WNDPROC = -24
1043     }
1044 
1045     [nodiscard]
1046     public Result<long> GetClassLong(void* windowHandleClassLongIndex index)
1047     {
1048         long value = WinGetClassLong(windowHandlecast<int>(index));
1049         if (value == 0)
1050         {
1051             ulong errorCode = WinGetLastError();
1052             if (errorCode != 0u)
1053             {
1054                 int errorId = WinAllocateWindowsError("get class long failed"errorCode);
1055                 return Result<long>(ErrorId(errorId));
1056             }
1057         }
1058         return Result<long>(value);
1059     }
1060 
1061     [nodiscard]
1062     public Result<long> SetClassLong(void* windowHandleClassLongIndex indexlong newValue)
1063     {
1064         long value = WinSetClassLong(windowHandlecast<int>(index)newValue);
1065         if (value == 0)
1066         {
1067             ulong errorCode = WinGetLastError();
1068             if (errorCode != 0u)
1069             {
1070                 int errorId = WinAllocateWindowsError("set class long failed"errorCode);
1071                 return Result<long>(ErrorId(errorId));
1072             }
1073         }
1074         return Result<long>(value);
1075     }
1076 
1077     public enum WindowLongIndex : int
1078     {
1079         GWL_EXSTYLE = -20
1080         GWLP_HINSTANCE = -6
1081         GWLP_ID = -12
1082         GWL_STYLE = -16
1083         GWLP_USERDATA = -21
1084         GWLP_WNDPROC = -4
1085     }
1086 
1087     [nodiscard]
1088     public Result<long> GetWindowLong(void* windowHandleWindowLongIndex index)
1089     {
1090         long value = WinGetWindowLong(windowHandlecast<int>(index));
1091         if (value == 0)
1092         {
1093             int errorId = WinAllocateWindowsError("get window long failed"WinGetLastError());
1094             return Result<long>(ErrorId(errorId));
1095         }
1096         return Result<long>(value);
1097     }
1098 
1099     [nodiscard]
1100     public Result<bool> SetWindowLong(void* windowHandleWindowLongIndex indexlong newValue)
1101     {
1102         bool succeeded = WinSetWindowLong(windowHandlecast<int>(index)newValue);
1103         if (!succeeded)
1104         {
1105             int errorId = WinAllocateWindowsError("set window long failed"WinGetLastError());
1106             return Result<bool>(ErrorId(errorId));
1107         }
1108         return Result<bool>(true);
1109     }
1110 
1111     [nodiscard]
1112     public Result<bool> ScrollWindow(void* windowHandleint xAmountint yAmountconst Rect* clientRectconst Rect* clipRect)
1113     {
1114         int clientLocX = 0;
1115         int clientLocY = 0;
1116         int clientSizeW = 0;
1117         int clientSizeH = 0;
1118         if (clientRect != null)
1119         {
1120             clientLocX = clientRect->location.x;
1121             clientLocY = clientRect->location.y;
1122             clientSizeW = clientRect->size.w;
1123             clientSizeH = clientRect->size.h;
1124         }
1125         int clipLocX = 0;
1126         int clipLocY = 0;
1127         int clipSizeW = 0;
1128         int clipSizeH = 0;
1129         if (clipRect != null)
1130         {
1131             clipLocX = clipRect->location.x;
1132             clipLocY = clipRect->location.y;
1133             clipSizeW = clipRect->size.w;
1134             clipSizeH = clipRect->size.h;
1135         }
1136         bool succeeded = WinScrollWindow(windowHandlexAmountyAmountclientLocXclientLocYclientSizeWclientSizeHclipLocXclipLocYclipSizeWclipSizeH);
1137         if (!succeeded)
1138         {
1139             int errorId = WinAllocateWindowsError("scroll window failed"WinGetLastError());
1140             return Result<bool>(ErrorId(errorId));
1141         }
1142         return Result<bool>(true);
1143     }
1144 
1145     [nodiscard]
1146     public Result<bool> ScrollWindowEx(void* windowHandleint dxint dyconst Rect* clientRectconst Rect* clipRectconst Rect& updateRect)
1147     {
1148         int clientLocX = 0;
1149         int clientLocY = 0;
1150         int clientSizeW = 0;
1151         int clientSizeH = 0;
1152         if (clientRect != null)
1153         {
1154             clientLocX = clientRect->location.x;
1155             clientLocY = clientRect->location.y;
1156             clientSizeW = clientRect->size.w;
1157             clientSizeH = clientRect->size.h;
1158         }
1159         int clipLocX = 0;
1160         int clipLocY = 0;
1161         int clipSizeW = 0;
1162         int clipSizeH = 0;
1163         if (clipRect != null)
1164         {
1165             clipLocX = clipRect->location.x;
1166             clipLocY = clipRect->location.y;
1167             clipSizeW = clipRect->size.w;
1168             clipSizeH = clipRect->size.h;
1169         }
1170         int x1 = updateRect.location.x;
1171         int y1 = updateRect.location.y;
1172         int x2 = updateRect.location.x + updateRect.size.w;
1173         int y2 = updateRect.location.y + updateRect.size.h;
1174         bool succeeded = WinScrollWindowEx(windowHandledxdyclientLocXclientLocYclientSizeWclientSizeHclipLocXclipLocYclipSizeWclipSizeHx1y1x2y2);
1175         if (!succeeded)
1176         {
1177             int errorId = WinAllocateWindowsError("scroll window ex failed"WinGetLastError());
1178             return Result<bool>(ErrorId(errorId));
1179         }
1180         return Result<bool>(true);
1181     }
1182 
1183     public enum ScrollBar : int
1184     {
1185         SB_BOTH = 3
1186         SB_CTL = 2
1187         SB_HORZ = 0
1188         SB_VERT = 1
1189     }
1190 
1191     [nodiscard]
1192     public Result<bool> GetScrollInfo(void* windowHandleScrollBar scrollBaruint& nPageint& nPosint& nMinint& nMaxint& nTrackPos)
1193     {
1194         bool succeeded = WinGetScrollInfo(windowHandlecast<int>(scrollBar)nPagenPosnMinnMaxnTrackPos);
1195         if (!succeeded)
1196         {
1197             int errorId = WinAllocateWindowsError("get scroll info failed"WinGetLastError());
1198             return Result<bool>(ErrorId(errorId));
1199         }
1200         return Result<bool>(true);
1201     }
1202 
1203     public enum ScrollInfoMask : uint
1204     {
1205         SIF_DISABLENOSCROLL = 8u
1206         SIF_PAGE = 2u
1207         SIF_POS = 4u
1208         SIF_RANGE = 1u
1209     }
1210 
1211     public int SetScrollInfo(void* windowHandleScrollBar scrollBarScrollInfoMask maskbool redrawuint nPageint nPosint nMinint nMax)
1212     {
1213         return WinSetScrollInfo(windowHandlecast<int>(scrollBar)cast<uint>(mask)redrawnPagenPosnMinnMax);
1214     }
1215 
1216     [nodiscard]
1217     public Result<bool> ShowScrollBar(void* windowHandleScrollBar scrollBarbool show)
1218     {
1219         bool succeeded = WinShowScrollBar(windowHandlecast<int>(scrollBar)show);
1220         if (!succeeded)
1221         {
1222             int errorId = WinAllocateWindowsError("show scroll bar failed"WinGetLastError());
1223             return Result<bool>(ErrorId(errorId));
1224         }
1225         return Result<bool>(true);
1226     }
1227 
1228     [nodiscard]
1229     public Result<bool> CreateCaret(void* windowHandlevoid* bitmapHandleint widthint height)
1230     {
1231         bool succeeded = WinCreateCaret(windowHandlebitmapHandlewidthheight);
1232         if (!succeeded)
1233         {
1234             int errorId = WinAllocateWindowsError("create caret failed"WinGetLastError());
1235             return Result<bool>(ErrorId(errorId));
1236         }
1237         return Result<bool>(true);
1238     }
1239 
1240     [nodiscard]
1241     public Result<bool> DestroyCaret()
1242     {
1243         bool succeeded = WinDestroyCaret();
1244         if (!succeeded)
1245         {
1246             int errorId = WinAllocateWindowsError("destroy caret failed"WinGetLastError());
1247             return Result<bool>(ErrorId(errorId));
1248         }
1249         return Result<bool>(true);
1250     }
1251 
1252     [nodiscard]
1253     public Result<bool> ShowCaret(void* windowHandle)
1254     {
1255         bool succeeded = WinShowCaret(windowHandle);
1256         if (!succeeded)
1257         {
1258             int errorId = WinAllocateWindowsError("show caret failed"WinGetLastError());
1259             return Result<bool>(ErrorId(errorId));
1260         }
1261         return Result<bool>(true);
1262     }
1263 
1264     [nodiscard]
1265     public Result<bool> HideCaret(void* windowHandle)
1266     {
1267         bool succeeded = WinHideCaret(windowHandle);
1268         if (!succeeded)
1269         {
1270             int errorId = WinAllocateWindowsError("hide caret failed"WinGetLastError());
1271             return Result<bool>(ErrorId(errorId));
1272         }
1273         return Result<bool>(true);
1274     }
1275 
1276     [nodiscard]
1277     public Result<Point> GetCaretPos()
1278     {
1279         Point caretPos;
1280         bool succeeded = WinGetCaretPos(caretPos.xcaretPos.y);
1281         if (!succeeded)
1282         {
1283             int errorId = WinAllocateWindowsError("get caret pos failed"WinGetLastError());
1284             return Result<Point>(ErrorId(errorId));
1285         }
1286         return Result<Point>(caretPos);
1287     }
1288 
1289     [nodiscard]
1290     public Result<bool> SetCaretPos(const Point& caretPos)
1291     {
1292         bool succeeded = WinSetCaretPos(caretPos.xcaretPos.y);
1293         if (!succeeded)
1294         {
1295             int errorId = WinAllocateWindowsError("set caret pos failed"WinGetLastError());
1296             return Result<bool>(ErrorId(errorId));
1297         }
1298         return Result<bool>(true);
1299     }
1300 
1301     [nodiscard]
1302     public Result<bool> SetTimer(void* windowHandleuint timerIduint elapseMs)
1303     {
1304         bool succeeded = WinSetTimer(windowHandletimerIdelapseMs);
1305         if (!succeeded)
1306         {
1307             int errorId = WinAllocateWindowsError("set timer failed"WinGetLastError());
1308             return Result<bool>(ErrorId(errorId));
1309         }
1310         return Result<bool>(true);
1311     }
1312 
1313     [nodiscard]
1314     public Result<bool> KillTimer(void* windowHandleuint timerId)
1315     {
1316         bool succeeded = WinKillTimer(windowHandletimerId);
1317         if (!succeeded)
1318         {
1319             int errorId = WinAllocateWindowsError("kill timer failed"WinGetLastError());
1320             return Result<bool>(ErrorId(errorId));
1321         }
1322         return Result<bool>(true);
1323     }
1324 
1325     [nodiscard]
1326     public Result<uint> RegisterClipboardFormat(const char* formatName)
1327     {
1328         uint format = WinRegisterClipboardFormat(formatName);
1329         if (format == 0u)
1330         {
1331             int errorId = WinAllocateWindowsError("register clipboard format failed"WinGetLastError());
1332             return Result<uint>(ErrorId(errorId));
1333         }
1334         return Result<uint>(format);
1335     }
1336 
1337     [nodiscard]
1338     public Result<bool> OpenClipboard(void* windowHandle)
1339     {
1340         uint maxWait = 100u;
1341         for (int i = 0; i < 5; ++i;)
1342         {
1343             bool succeeded = WinOpenClipboard(windowHandle);
1344             if (succeeded)
1345             {
1346                 return Result<bool>(true);
1347             }
1348             else if (i < 4)
1349             {
1350                 Sleep(Duration.FromMilliseconds(Random() % maxWait));
1351                 maxWait = maxWait * 2u;
1352             }
1353         }
1354         int errorId = WinAllocateWindowsError("open clipboard failed"WinGetLastError());
1355         return Result<bool>(ErrorId(errorId));
1356     }
1357 
1358     [nodiscard]
1359     public Result<bool> CloseClipboard()
1360     {
1361         bool succeeded = WinCloseClipboard();
1362         if (!succeeded)
1363         {
1364             int errorId = WinAllocateWindowsError("close clipboard failed"WinGetLastError());
1365             return Result<bool>(ErrorId(errorId));
1366         }
1367         return Result<bool>(true);
1368     }
1369 
1370     [nodiscard]
1371     public Result<bool> EmptyClipboard()
1372     {
1373         bool succeeded = WinEmptyClipboard();
1374         if (!succeeded)
1375         {
1376             int errorId = WinAllocateWindowsError("empty clipboard failed"WinGetLastError());
1377             return Result<bool>(ErrorId(errorId));
1378         }
1379         return Result<bool>(true);
1380     }
1381 
1382     [nodiscard]
1383     public Result<void*> SetClipboardData(uint formatvoid* mem)
1384     {
1385         void* retval = WinSetClipboardData(formatmem);
1386         if (retval == null)
1387         {
1388             int errorId = WinAllocateWindowsError("set clipboard data failed"WinGetLastError());
1389             return Result<void*>(ErrorId(errorId));
1390         }
1391         return Result<void*>(retval);
1392     }
1393 
1394     [nodiscard]
1395     public Result<void*> GetClipboardData(uint format)
1396     {
1397         void* retval = WinGetClipboardData(format);
1398         if (retval == null)
1399         {
1400             int errorId = WinAllocateWindowsError("get clipboard data failed"WinGetLastError());
1401             return Result<void*>(ErrorId(errorId));
1402         }
1403         return Result<void*>(retval);
1404     }
1405 
1406     public bool IsClipboardFormatAvailable(uint format)
1407     {
1408         return WinIsClipboardFormatAvailable(format);
1409     }
1410 
1411     [nodiscard]
1412     public Result<bool> AddClipboardFormatListener(void* windowHandle)
1413     {
1414         bool succeeded = WinAddClipboardFormatListener(windowHandle);
1415         if (!succeeded)
1416         {
1417             int errorId = WinAllocateWindowsError("add clipboard format listener failed"WinGetLastError());
1418             return Result<bool>(ErrorId(errorId));
1419         }
1420         return Result<bool>(true);
1421     }
1422 
1423     [nodiscard]
1424     public Result<bool> RemoveClipboardFormatListener(void* windowHandle)
1425     {
1426         bool succeeded = WinRemoveClipboardFormatListener(windowHandle);
1427         if (!succeeded)
1428         {
1429             int errorId = WinAllocateWindowsError("remove clipboard format listener failed"WinGetLastError());
1430             return Result<bool>(ErrorId(errorId));
1431         }
1432         return Result<bool>(true);
1433     }
1434 
1435     public enum GlobalAllocFlags : uint
1436     {
1437         GMEM_FIXED = 0u
1438         GHND = 66u
1439         GMEM_MOVEABLE = 2u
1440         GMEM_ZEROINIT = 64u
1441         GPTR = 64u
1442     }
1443 
1444     [nodiscard]
1445     public Result<void*> GlobalAlloc(GlobalAllocFlags flagsulong size)
1446     {
1447         void* retval = WinGlobalAlloc(cast<uint>(flags)size);
1448         if (retval == null)
1449         {
1450             int errorId = WinAllocateWindowsError("global alloc failed"WinGetLastError());
1451             return Result<void*>(ErrorId(errorId));
1452         }
1453         return Result<void*>(retval);
1454     }
1455 
1456     [nodiscard]
1457     public Result<void*> GlobalLock(void* memHandle)
1458     {
1459         void* retval = WinGlobalLock(memHandle);
1460         if (retval == null)
1461         {
1462             int errorId = WinAllocateWindowsError("global lock failed"WinGetLastError());
1463             return Result<void*>(ErrorId(errorId));
1464         }
1465         return Result<void*>(retval);
1466     }
1467 
1468     [nodiscard]
1469     public Result<bool> GlobalUnlock(void* memHandle)
1470     {
1471         bool retval = WinGlobalUnlock(memHandle);
1472         if (!retval)
1473         {
1474             ulong error = WinGetLastError();
1475             if (error != 0u)
1476             {
1477                 int errorId = WinAllocateWindowsError("global unlock failed"error);
1478                 return Result<bool>(ErrorId(errorId));
1479             }
1480         }
1481         return Result<bool>(true);
1482     }
1483 
1484     [nodiscard]
1485     public Result<bool> GlobalFree(void* memHandle)
1486     {
1487         void* retval = WinGlobalFree(memHandle);
1488         if (retval != null)
1489         {
1490             int errorId = WinAllocateWindowsError("global free failed"WinGetLastError());
1491             return Result<bool>(ErrorId(errorId));
1492         }
1493         return Result<bool>(true);
1494     }
1495 
1496     [nodiscard]
1497     public Result<ulong> GlobalSize(void* memHandle)
1498     {
1499         ulong size = WinGlobalSize(memHandle);
1500         if (size == 0u)
1501         {
1502             int errorId = WinAllocateWindowsError("global size failed"WinGetLastError());
1503             return Result<ulong>(ErrorId(errorId));
1504         }
1505         return Result<ulong>(size);
1506     }
1507 
1508     [nodiscard]
1509     public Result<bool> GetCursorPos(int& xint& y)
1510     {
1511         if (!WinGetCursorPos(xy))
1512         {
1513             int errorId = WinAllocateWindowsError("get cursor pos failed"WinGetLastError());
1514             return Result<bool>(ErrorId(errorId));
1515         }
1516         return Result<bool>(true);
1517     }
1518 
1519     [nodiscard]
1520     public Result<string> GetFolder(void* windowHandleconst string& defaultDirectory)
1521     {
1522         auto defaultDirResult = ToUtf16(defaultDirectory);
1523         if (defaultDirResult.Error())
1524         {
1525             return Result<string>(ErrorId(defaultDirResult.GetErrorId()));
1526         }
1527         wstring defaultDir = Rvalue(defaultDirResult.Value());
1528         long folderNameBufferSize = 1024;
1529         UniquePtr<wchar> folderNameBuffer = cast<wchar*>(MemAlloc(sizeof(wchar) * folderNameBufferSize));
1530         bool success = WinGetFolder(windowHandledefaultDir.Chars()folderNameBuffer.Get()cast<uint>(folderNameBufferSize));
1531         if (success)
1532         {
1533             wstring folderName(folderNameBuffer.Get());
1534             auto utf8Result = ToUtf8(folderName);
1535             if (utf8Result.Error())
1536             {
1537                 return utf8Result;
1538             }
1539             else
1540             {
1541                 return Result<string>(utf8Result.Value());
1542             }
1543         }
1544         else
1545         {
1546             int errorId = AllocateError("GetFolder failed");
1547             return Result<string>(ErrorId(errorId));
1548         }
1549     }