wdang
9/22/2018 - 12:44 AM

windows utility functions

windows utility functions

// Copyright 2018 William Dang (william.dang@utah.edu)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#undef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#include <stdint.h>
#include <assert.h>

#include <vector>
#include <string>

#include <CommCtrl.h>
#include <CommDlg.h>
#include <Shlobj.h>
#include <Shellapi.h>
#include <windef.h>

// HANDLE_DIALOG_MSG is a version of HANDLE_MSG(windowsx.h) for dialog boxes
#define HANDLE_DIALOG_MSG(hWnd, message, fn) case (message): \
  return (SetDlgMsgResult(hWnd, uMsg, HANDLE_ ## message((hWnd), (wParam), (lParam), (fn))))

// Returns a readable string representation of a window message
const char* MessageString(UINT message);

// Encodes the given utf-16 string to utf-8
std::string UTF8(const wchar_t* utf16, size_t count);
template<size_t N>
inline std::string UTF8(const wchar_t (&utf16)[N]) {
  return UTF8(utf16, N);
}
inline std::string UTF8(const std::wstring& utf16) {
  return UTF8(&utf16[0], utf16.size());
}

// Encodes the given utf-8 string to utf-16 
std::wstring UTF16(const char* utf8, size_t count);
template<size_t N>
inline std::wstring UTF16(const char(&utf8)[N]) {
  return UTF16(utf8, N);
}
inline std::wstring UTF16(const std::string& utf8) {
  return UTF16(&utf8[0], utf8.size());
}

#ifdef __cplusplus
extern "C" {
#endif

inline  int LogicalUnitsToPoints(HDC dc, int lu) {
  return -MulDiv(lu, 72, GetDeviceCaps(dc, LOGPIXELSY));
}

inline int PointsToLogicalUnits(HDC dc, int pt) {
  return -MulDiv(pt, GetDeviceCaps(dc, LOGPIXELSY), 72);
}


// Force the system to create a message queue for the calling thread.
// A thread needs a message queue in order to receive posted messages
// from PostThreadMessage.
  inline void ForceMessageQueueForThread() {
    MSG msg;
    PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
  }

// Retrieve the HINSTANCE of the module we've been linked into.
// The Microsoft linker also provides a pseudo variable __ImageBase:
//    extern "C" IMAGE_DOS_HEADER __ImageBase
//    (HINSTANCE)&__ImageBase
//
// see:
// http://blogs.msdn.com/b/oldnewthing/archive/2004/10/25/247180.aspx
  inline HINSTANCE GetCurrentModule() {
    HINSTANCE hinstance;
    GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
                      | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
                      (LPCTSTR)GetCurrentModule,
                      &hinstance);
    return hinstance;
  }

// Center the window on the monitor containing the given window
// http://msdn.microsoft.com/en-us/library/dd162826(VS.85).aspx
  inline void CenterWindow(HWND hwnd) {
    RECT rect;
    GetWindowRect(hwnd, &rect);
    MONITORINFO mi = {sizeof(MONITORINFO)};
    GetMonitorInfo(MonitorFromRect(&rect, MONITOR_DEFAULTTONEAREST), &mi);
    SetWindowPos(hwnd, 0, (mi.rcWork.right/2)/2, (mi.rcWork.bottom/2)/2, 0, 0,
      SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
  }

  inline CHOOSEFONTW FontFromFontDialog(HWND owner) {
    CHOOSEFONTW cf  = {sizeof(cf)};
    LOGFONT logfont = {0};
    cf.hwndOwner = owner;
    cf.lpLogFont = &logfont;
    cf.hInstance = GetCurrentModule();
    cf.Flags     = CF_EFFECTS;
    ChooseFontW(&cf);

    return cf;
  }

//  65,536 on all Windows platforms as of 06/22/2011
  inline DWORD GetAllocationGranularity() {
    SYSTEM_INFO info;
    GetSystemInfo(&info);
    return info.dwAllocationGranularity;
  }

  inline int InitAllCommonControls() {
    static const INITCOMMONCONTROLSEX icc = {
      sizeof(icc),
      ICC_LISTVIEW_CLASSES   |                                   // listview, header
      ICC_TREEVIEW_CLASSES   |                                   // treeview, tooltips
      ICC_BAR_CLASSES        |                                   // toolbar, statusbar, trackbar, tooltips
      ICC_TAB_CLASSES        |                                   // tab, tooltips
      ICC_UPDOWN_CLASS       |                                   // updown
      ICC_PROGRESS_CLASS     |                                   // progress
      ICC_HOTKEY_CLASS       |                                   // hotkey
      ICC_ANIMATE_CLASS      |                                   // animate
      ICC_WIN95_CLASSES      |                                   //
      ICC_DATE_CLASSES       |                                   // month picker, date picker, time picker, updown
      ICC_USEREX_CLASSES     |                                   // comboex
      ICC_COOL_CLASSES       |                                   // rebar (coolbar) control
      ICC_INTERNET_CLASSES   |                                   // IP address class.
      ICC_NATIVEFNTCTL_CLASS |                                   // native font control class.
      ICC_STANDARD_CLASSES   |                                   // intrinsic User32 control classes: button, edit, static, listbox, combobox, and scroll bar
      ICC_LINK_CLASS                                             // hyperlink control class.
    };
    return InitCommonControlsEx(&icc);
  }

// Returns the HWND that generated the given message.
  inline HWND HWNDFromMessage(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) {
    if(message == WM_PARENTNOTIFY) {
      switch(LOWORD(wparam)) {
        case WM_CREATE:
        case WM_DESTROY: return reinterpret_cast<HWND>(lparam);
        default: return GetDlgItem(hwnd, HIWORD(wparam));
      }
    }

    switch(message) {
      case WM_NOTIFY:
        return reinterpret_cast<NMHDR*>(lparam)->hwndFrom;
      case WM_COMMAND: return reinterpret_cast<HWND>(lparam);
      case WM_CONTEXTMENU: return reinterpret_cast<HWND>(wparam);
      case WM_CTLCOLORBTN:
      case WM_CTLCOLORDLG:
      case WM_CTLCOLOREDIT:
      case WM_CTLCOLORLISTBOX:
      case WM_CTLCOLORMSGBOX:
      case WM_CTLCOLORSCROLLBAR:
      case WM_CTLCOLORSTATIC: return reinterpret_cast<HWND>(lparam);
      case WM_DRAWITEM:
      case WM_COMPAREITEM:
      case WM_DELETEITEM: return (reinterpret_cast<DELETEITEMSTRUCT*>(lparam))->hwndItem;
      case WM_VKEYTOITEM:
      case WM_CHARTOITEM:
      case WM_HSCROLL:
      case WM_VSCROLL: return reinterpret_cast<HWND>(lparam);
      case WM_MEASUREITEM: return GetDlgItem(hwnd, reinterpret_cast<MEASUREITEMSTRUCT*>(lparam)->CtlID);
      default: return hwnd;
    }
  }

  ATOM RegisterWindowClass(const TCHAR* classname, WNDPROC);

  inline void SetWindowIcon(HWND window, int id) {
    SendMessage(window, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(
                  (HINSTANCE)GetWindowLongPtr(window, GWLP_HINSTANCE), MAKEINTRESOURCE(id)));

    SendMessage(window, WM_SETICON, ICON_SMALL, (LPARAM) LoadIcon(
                  (HINSTANCE) GetWindowLongPtr(window, GWLP_HINSTANCE), MAKEINTRESOURCE(id)));
  }

  inline BOOL IsWin7orGreater() {
    OSVERSIONINFOEX vesion_info = {sizeof(OSVERSIONINFOEX)};
    vesion_info.dwMajorVersion = 6;
    vesion_info.dwMinorVersion = 1;
    DWORDLONG conditions = 0;

    conditions = VerSetConditionMask(conditions, VER_MAJORVERSION, VER_GREATER_EQUAL);
    conditions = VerSetConditionMask(conditions, VER_MINORVERSION, VER_GREATER_EQUAL);
    return VerifyVersionInfo(&vesion_info, VER_MAJORVERSION | VER_MINORVERSION, conditions);
  }

  inline HGLRC InitializeOpenGL(HWND window) {
    static PIXELFORMATDESCRIPTOR kDefaultGLPixelFormat = {
      sizeof(PIXELFORMATDESCRIPTOR),                             // Size of this structure
      1,                                                         // Version of this structure
      PFD_DRAW_TO_WINDOW |                                       // Draw to window (not to bitmap)
      PFD_SUPPORT_OPENGL |                                       // Support OpenGL calls in window
      PFD_DOUBLEBUFFER,                                          // The buffer is double-buffered,
      PFD_TYPE_RGBA,                                             // RGBA color mode
      32,                                                        // Want 32-bit color
      0, 0, 0, 0, 0, 0,                                          // Not used to select mode RGB (Bits,Shifts)
      0, 0,                                                      // Not used to select mode ALPHA (Bits,Shifts)
      0, 0, 0, 0, 0,                                             // Not used to select mode Accumbits, RGB(bits)
      24,                                                        // Depth bits (z-axis)
      8,                                                         // Specifies the depth of the stencil buffer.
      0,                                                         //  Auxiliary buffers are not supported.
      0,                                                         // (Obsolete) and/or reserved
      0,                                                         // No overlay and underlay planes
      0,                                                         // (Obsolete) and/or reserved layer mask
      0,                                                         // No transparent color for underlay plane
      0                                                          // (Obsolete)
    };

    HGLRC context = 0;
    HDC dc        = GetDC(window);
    int format;
    if(!(format = ChoosePixelFormat(dc, &kDefaultGLPixelFormat)))
      return context;


    if(!SetPixelFormat(dc, format, &kDefaultGLPixelFormat))
      return context;

    context = wglCreateContext(dc);
    wglMakeCurrent(dc, context);
    return context;
  }

#ifdef __cplusplus
}
#endif

// Returns the selected filename from a file dialog or an empty string
inline std::string FilenameFromFileDialog(HWND owner = 0, 
const char* filter = "All\0*.*\0\0") {
  char buffer[MAX_PATH] = {0};
  OPENFILENAMEA ofn     = {sizeof(ofn)};
  ofn.hwndOwner     = owner;
  ofn.hInstance     = GetCurrentModule();
  ofn.lpstrFilter   = filter;
  ofn.lpstrFile     = buffer;
  ofn.nFilterIndex  = 1;
  ofn.nMaxFile      = MAX_PATH;
  ofn.nMaxFileTitle = MAX_PATH;
  ofn.Flags         =       OFN_EXPLORER | OFN_ENABLESIZING | OFN_FILEMUSTEXIST;
  return GetOpenFileNameA(&ofn) == FALSE ? 
    std::string("") : std::string(ofn.lpstrFile);
}

inline std::wstring FilenameFromFileDialogW(HWND owner = 0, 
const wchar_t* filter = L"All\0*.*\0\0") {
  wchar_t buffer[MAX_PATH] = {0};
  OPENFILENAMEW ofn        = {sizeof(ofn)};
  ofn.hwndOwner     = owner;
  ofn.hInstance     = GetCurrentModule();
  ofn.lpstrFilter   = filter;
  ofn.lpstrFile     = buffer;
  ofn.nFilterIndex  = 1;
  ofn.nMaxFile      = MAX_PATH;
  ofn.nMaxFileTitle = MAX_PATH;
  ofn.Flags         = OFN_EXPLORER | OFN_ENABLESIZING | OFN_FILEMUSTEXIST;
  return GetOpenFileNameW(&ofn) == FALSE ? std::wstring(L"") : std::wstring(ofn.lpstrFile);
}

inline std::wstring FolderNameFromFolderDialog(HWND parent, 
const std::wstring& title) {

  BROWSEINFO bi          = {0};
  TCHAR buffer[MAX_PATH] = {0};

  bi.hwndOwner      = parent;
  bi.pszDisplayName = buffer;
  bi.lpszTitle      = L"";       //strTitle.get();
  bi.ulFlags        = BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS | BIF_SHAREABLE;
  OleInitialize(0);
  const ITEMIDLIST* folder = SHBrowseForFolder(&bi);

  if(folder && SHGetPathFromIDList(folder, buffer)) {
    OleUninitialize();
    return std::wstring(buffer);
  }

  OleUninitialize();
  return std::wstring(L"");
}

inline std::wstring GetRoamingDirectoryW() {
  wchar_t config_path[MAX_PATH] = {'\0'};
  SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, config_path);
  return std::wstring(config_path);
}

inline std::string GetRoamingDirectory() {
  char config_path[MAX_PATH] = {'\0'};
  SHGetFolderPathA(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, config_path);
  return std::string(config_path);
}

// Size of the specified file without creating a handle.
// Returns -1 on failure.
inline int64_t GetFileSize(const std::wstring& path) {
  int64_t size = -1;
  WIN32_FILE_ATTRIBUTE_DATA attr;
  if(GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &attr)) {
    size = attr.nFileSizeHigh;
    size = (size << 32) + attr.nFileSizeLow;
  }
  return size;
}

// Returns an __argv style vector where the first element
// is always THIS current process
inline std::vector<std::wstring> GetCommandLineWStrings() {
  int argc;
  wchar_t** wargv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
  wchar_t wfile_path[MAX_PATH];
  GetModuleFileNameW(GetCurrentModule(), wfile_path, MAX_PATH);
  std::vector<std::wstring> result(wargv, wargv + argc);
  result.insert(result.begin(), wfile_path);
  LocalFree(wargv);       // we're Responsible for GetModuleFileNameW's memory
  return result;
}

// Returns an __argv style vector where the first element  is always THIS 
// current process
inline std::vector<std::string> GetCommandLineStrings() {
  int argc;
  wchar_t** wargv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
  wchar_t wfile_path[MAX_PATH];
  GetModuleFileNameW(GetCurrentModule(), wfile_path, MAX_PATH);
  std::vector<std::wstring> result(wargv, wargv + argc);

  std::vector<std::string> rv(result.size() + 1, "");
  for(std::vector<std::wstring>::iterator i = result.begin(), end = result.end(); i!= end; ++i) {
    std::string arg(i->begin(), i->end());
    rv.push_back(arg);
  }
  std::string file_path(wfile_path, wfile_path + wcslen(wfile_path));
  rv.insert(rv.begin(), file_path);
  LocalFree(wargv);       // we're Responsible for GetModuleFileNameW's memory
  return rv;
}

// Load data from the given window handle
// returns a pointer to the stored data
template<class T>
inline T GetWindowData(HWND window) {
    return reinterpret_cast<T>(GetWindowLongPtr(window, GWLP_USERDATA));
}

template<class T>
inline bool GetWindowData(HWND window,T** out) {
  const LONG_PTR result = GetWindowLongPtr(window, GWLP_USERDATA);
  if(result)
    *out = reinterpret_cast<T>(result);
  return !!result;
}
// store user data in the given window handle.
template<class T>
inline void SetWindowData(HWND window, T&& userdata) {
  SetWindowLongPtr(window, GWLP_USERDATA, reinterpret_cast<uintptr_t>(userdata));
  // Changes from SetWindowLongPtr will not take
  // effect until SetWindowPos is called
  // due to internal window data caching.
  SetWindowPos(window, 0, 0, 0, 0, 0,
               SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
}

// Load a pointer associated with the given window and identified 
// by property_name into userdata
//
// returns *userdata
template<class T>
inline bool GetWindowProperty(const TCHAR* property_name, HWND window,
const T** out) {
  HANDLE data = GetProp(window, property_name);
  if(data) {
    *out = reinterpret_cast<T*>(data);
    return true;
  }
  return false;
}

template<class T>
inline T* GetWindowProperty(HWND window, const TCHAR* property_name) {
  HANDLE data = GetProp(window, property_name);
  if(data) {
    T* userdata = reinterpret_cast<T*>(data);
    return userdata;
  }

  return static_cast<T*>(0);
}

// Associates a pointer indentified by property_name with the given window
template<class T>
inline bool SetWindowProperty(HWND window, T* userdata, const TCHAR* property_name) {
  return !!SetProp(window, property_name, static_cast<HANDLE>(userdata));
}

// calls GetLastError() and returns a readable string representation 
// of the error
inline std::string GetLastErrorString() {
  const DWORD kFlags       = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
  const DWORD kBufferSize  = 4096;  // note:  buffer cannot be larger than 64K bytes
  const DWORD kCodeSize    = 64;  // size of HEX error code buffer
  const HRESULT hr         = HRESULT_FROM_WIN32(GetLastError());
  char buffer[kBufferSize] = { '\0' };
  char code[kCodeSize]     = { '\0' };
  const int len_sans_null  = FormatMessageA(kFlags, 0, hr, 0, buffer, kBufferSize, NULL);
  sprintf_s(code, kCodeSize, " (0x%08X)", hr);
  std::string result(buffer, buffer + len_sans_null - 2); // remove CRLF
  result.append(code);
  return result;
}

inline std::wstring GetLastErrorStringW() {
  const DWORD kFlags          = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
  const DWORD kBufferSize     = 4096; // note:  buffer cannot be larger than 64K bytes
  const DWORD kCodeSize       = 64; // size of HEX error code buffer
  const HRESULT hr            = HRESULT_FROM_WIN32(GetLastError());
  wchar_t buffer[kBufferSize] = { '\0' };
  wchar_t code[kCodeSize]     = { '\0' };
  const int len_sans_null     = FormatMessageW(kFlags, 0, hr, 0, buffer, kBufferSize, NULL);

  wsprintf(code, L" (0x%08X)", hr);
  // remove CRLF
  std::wstring result(buffer, buffer + len_sans_null - 2 * sizeof(wchar_t)); 
  result.append(code);
  return result;
}

// Force the system to create a message queue for the calling thread.
// A thread needs a message queue in order to receive posted messages
// from PostThreadMessage.
inline void CreateMessageQueueForThread() {
  MSG msg;
  PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
}

// returns a list of exported names from the given dll
inline std::vector<std::string> DllExports(const TCHAR* library) {
  // Issues with using
  // DONT_RESOLVE_DLL_REFERENCES
  // http://blogs.msdn.com/b/oldnewthing/archive/2005/02/14/372266.aspx
  // Summary:
  // using DONT_RESOLVE_DLL_REFERENCES causes GetModuleHandle to successfully
  // return a function pointer that will crash if invoked.
  //
  //
  // using it here is safe since routines in the given module are not going to
  // be invoked.

  // PE file format: http://msdn.microsoft.com/en-us/magazine/cc301808.aspx
  HMODULE lib = LoadLibraryEx(library, NULL, DONT_RESOLVE_DLL_REFERENCES);
  char* plib  = reinterpret_cast<char*>(lib);


  IMAGE_DOS_HEADER* header = reinterpret_cast<IMAGE_DOS_HEADER*>(plib);

  std::vector<std::string> v;
  if(header->e_magic != IMAGE_DOS_SIGNATURE)
    return v;


  IMAGE_NT_HEADERS* headers = reinterpret_cast<IMAGE_NT_HEADERS*>(plib + header->e_lfanew);

  assert(headers->Signature == IMAGE_NT_SIGNATURE);
  assert(headers->OptionalHeader.NumberOfRvaAndSizes > 0);

  ptrdiff_t offset = headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;

  IMAGE_EXPORT_DIRECTORY* exports = reinterpret_cast<IMAGE_EXPORT_DIRECTORY*>(plib + offset);

  void* names = plib + exports->AddressOfNames;
  v.reserve(exports->NumberOfNames);

  for(size_t i = 0; i < exports->NumberOfNames; i++) {
    std::string export_name(plib + static_cast<DWORD*>(names)[i]);
    v.push_back(export_name);
  }

  FreeLibrary(lib);
  return v;
}

template<class T>
inline HRESULT CoCreateInProc(REFCLSID clsid, T** out) {
  return CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, __uuidof(T),
                          reinterpret_cast<void**>(out));
}

inline HFONT MakeFont(int point_size, const std::string& font_name) {
  HDC hdc          = GetDC(0);
  int logical_size = -MulDiv(point_size, GetDeviceCaps(hdc, LOGPIXELSY), 72);
  ReleaseDC(0, hdc);
  return CreateFontA(logical_size, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, font_name.c_str());
}


// Reads the given file located at 'filename' calling back 'func'
// on each line read. These functions also support very large files.
// The function signature for 'func' should be "similar" to:
//
// void func(uint64_t line_number, const std::string& line_contents);
//
// line counts for line_number start at 1
template<class Function>
inline void Readlines(const std::wstring& filename, Function&& func) {
  HANDLE file = CreateFileW(filename.c_str(),
                            GENERIC_READ,
                            FILE_SHARE_READ,
                            0,                                                                                                                                                                                                                                                                                                                              // security: returned handle wont be inherited
                            OPEN_EXISTING,
                            FILE_FLAG_SEQUENTIAL_SCAN,
                            NULL);                                                                                                                                                                                                                                                                                                                         // supplies file attributes, ignored with OPEN_EXISITING
  uint64_t file_size;
  GetFileSizeEx(file, (PLARGE_INTEGER)&file_size); //checking for INVALID_FILE_SIZE left out for brevity
  // Create the file-mapping object.
  HANDLE file_map = CreateFileMappingW(file,
                                       0,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   // security: returned handle wont be inherited
                                       PAGE_READONLY,                                                                                                                                                                                                                                                                                                                                                                                                                                                                               //page protection, mapped views depend on this
                                       0,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 // high order max size (system determined)
                                       0,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 // low order max size (system determined)
                                       0);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                // string to identify the file_map(interprocess)
  CloseHandle(file);
  SYSTEM_INFO sys_info;
  GetSystemInfo(&sys_info);
  DWORD block_size        = sys_info.dwAllocationGranularity;
  __int64 offset          = 0;
  __int64 line_count      =0;
  __int64 bytes_remaining = file_size;
  std::wstring buffer(4096, '\0');
  uint64_t line           = 0;
  do {
    if(bytes_remaining < block_size) {
      block_size = static_cast<DWORD>(bytes_remaining);
    }

    // map a view into our address space
    unsigned char* block = static_cast<unsigned char*>(MapViewOfFile(file_map, FILE_MAP_READ,
                           static_cast<DWORD>(offset >> 32), // Starting byte
                           static_cast<DWORD>(offset & 0xFFFFFFFF), // in file
                           block_size)); // # of bytes to map

    for(DWORD i = 0; i< block_size; ++i) {
      if(block[i]!='\n') {
        buffer.push_back(block[i]);
      } else {
        ++line;
        func(line, buffer);
        buffer.clear();
      }
    }
    // unmap the view or else we'll have mulitiple views in our address space
    UnmapViewOfFile(block);
    offset          += block_size;
    bytes_remaining -= block_size;
  } while(bytes_remaining > 0);
  CloseHandle(file_map);
}
// Readlines for strings
template<class Function>
inline void Readlines(const std::string& filename, Function&& func) {
  HANDLE file = CreateFileA(filename.c_str(),
                            GENERIC_READ,
                            FILE_SHARE_READ,
                            0,                                                                                                                                                                                                                                                                                                                              // security: returned handle wont be inherited
                            OPEN_EXISTING,
                            FILE_FLAG_SEQUENTIAL_SCAN,
                            NULL);                                                                                                                                                                                                                                                                                                                         // supplies file attributes, ignored with OPEN_EXISITING

  uint64_t file_size;
  GetFileSizeEx(file, (PLARGE_INTEGER)&file_size); //checking for INVALID_FILE_SIZE left out for brevity

  // Create the file-mapping object.
  HANDLE file_map = CreateFileMappingA(file,
                                       0,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   // security: returned handle wont be inherited
                                       PAGE_READONLY,                                                                                                                                                                                                                                                                                                                                                                                                                                                                               //page protection, mapped views depend on this
                                       0,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 // high order max size (system determined)
                                       0,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 // low order max size (system determined)
                                       0);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                // string to identify the file_map(interprocess)

  CloseHandle(file);

  SYSTEM_INFO sys_info;
  GetSystemInfo(&sys_info);

  DWORD block_size        = sys_info.dwAllocationGranularity;
  __int64 offset          = 0;
  __int64 line_count      =0;
  __int64 bytes_remaining = file_size;
  std::string buffer(file_size, '\0');
  uint64_t line           = 0;
  do {
    if(bytes_remaining < block_size) {
      block_size = static_cast<DWORD>(bytes_remaining);
    }

    // map a view into our address space
    unsigned char* block = static_cast<unsigned char*>(MapViewOfFile(file_map, FILE_MAP_READ,
                           static_cast<DWORD>(offset >> 32), // Starting byte
                           static_cast<DWORD>(offset & 0xFFFFFFFF), // in file
                           block_size)); // # of bytes to map

    for(DWORD i = 0; i< block_size; ++i) {
      if(block[i]!='\n') {
        buffer.push_back(block[i]);
      } else {
        ++line;
        func(line, buffer);
        buffer.clear();
      }
    }
    // unmap the view or else we'll have mulitiple views in our address space
    UnmapViewOfFile(block);
    offset          += block_size;
    bytes_remaining -= block_size;
  } while(bytes_remaining > 0);
  CloseHandle(file_map);
}

// simulate mouse movement to the given coordinates
inline void MouseMove(int x, int y) {
  INPUT input = {0};
  input.type = INPUT_MOUSE;
  input.mi.dwFlags = MOUSEEVENTF_MOVE|MOUSEEVENTF_ABSOLUTE;

  // normalized absolute screen coordinates
  input.mi.dx = x * (65535 / GetSystemMetrics(SM_CXSCREEN)-1);
  input.mi.dy = y * (65535 / GetSystemMetrics(SM_CYSCREEN)-1);

  SendInput(1, &input, sizeof(input));
}

// Simulate right mouse click at the given coordinates
inline void MouseRightClick(int x, int y) {
  INPUT input = {0};
  input.type       = INPUT_MOUSE;

  input.mi.dwFlags =  MOUSEEVENTF_RIGHTDOWN;
  SendInput(1, &input, sizeof(input));

  input.mi.dwFlags = MOUSEEVENTF_RIGHTUP;
  SendInput(1, &input, sizeof(input));
}

// Simulate left mouse click at the given coordinates
inline void MouseLeftClick(int x, int y) {
  INPUT input = {0};
  input.type       = INPUT_MOUSE;
  input.mi.dwFlags =  MOUSEEVENTF_LEFTDOWN;

  SendInput(1, &input, sizeof(input));

  input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
  SendInput(1, &input, sizeof(input));
}

// simulate single keyboard presses
inline static void KeyPress(char key) {
  INPUT input[2] = {0};
  input[0].type       = INPUT_KEYBOARD;
  input[0].ki.wScan   = key;
  input[0].ki.dwFlags = KEYEVENTF_UNICODE;
  input[1].type       = INPUT_KEYBOARD;
  input[1].ki.wScan   = key;
  input[1].ki.dwFlags = KEYEVENTF_UNICODE|KEYEVENTF_KEYUP;
  SendInput(2, &input[0], sizeof(input[0]));
}

// simulate a string of keyboard presses
inline static void KeyPress(const std::string& keys) {
  if(keys.empty()) return;

  const size_t len = keys.size();

  std::vector<INPUT> keypresses;
  keypresses.reserve(len*2);

  INPUT input = {0};
  input.type = INPUT_KEYBOARD;

  for(size_t i = 0; i < len; ++i) {
    input.ki.wScan   = keys[i];

    input.ki.dwFlags = KEYEVENTF_UNICODE;
    keypresses.push_back(input);

    input.ki.dwFlags = KEYEVENTF_UNICODE|KEYEVENTF_KEYUP;
    keypresses.push_back(input);
  }
  SendInput(len*2, &keypresses[0], sizeof(input));
}