int win_message_box_utf8(HWND window, const char *text, const char *caption, UINT type) { int result = IDNO; TCHAR *t_text = NULL; TCHAR *t_caption = NULL; if (text) { t_text = tstring_from_utf8(text); if (!t_text) goto done; } if (caption) { t_caption = tstring_from_utf8(caption); if (!t_caption) goto done; } result = MessageBox(window, t_text, t_caption, type); done: if (t_text) free(t_text); if (t_caption) free(t_caption); return result; }
HWND win_create_window_ex_utf8(DWORD exstyle, const char* classname, const char* windowname, DWORD style, int x, int y, int width, int height, HWND parent, HMENU menu, HINSTANCE instance, void* param) { TCHAR* t_classname; TCHAR* t_windowname; HWND result = 0; t_classname = tstring_from_utf8(classname); if( !t_classname ) return result; t_windowname = tstring_from_utf8(windowname); if( !t_windowname ) { free(t_classname); return result; } result = CreateWindowEx(exstyle, t_classname, t_windowname, style, x, y, width, height, parent, menu, instance, param); free(t_windowname); free(t_classname); return result; }
HWND debugview_info::create_source_combobox(HWND parent, LONG_PTR userdata) { // create a combo box HWND const result = CreateWindowEx(COMBO_BOX_STYLE_EX, TEXT("COMBOBOX"), nullptr, COMBO_BOX_STYLE, 0, 0, 100, 1000, parent, nullptr, GetModuleHandleUni(), nullptr); SetWindowLongPtr(result, GWLP_USERDATA, userdata); SendMessage(result, WM_SETFONT, (WPARAM)metrics().debug_font(), (LPARAM)FALSE); // populate the combobox debug_view_source const *const cursource = m_view->source(); int maxlength = 0; for (debug_view_source const *source = m_view->first_source(); source != nullptr; source = source->next()) { int const length = strlen(source->name()); if (length > maxlength) maxlength = length; auto t_name = tstring_from_utf8(source->name()); SendMessage(result, CB_ADDSTRING, 0, (LPARAM)t_name.c_str()); } if (cursource != nullptr) { SendMessage(result, CB_SETCURSEL, m_view->source_list().indexof(*cursource), 0); SendMessage(result, CB_SETDROPPEDWIDTH, ((maxlength + 2) * metrics().debug_font_width()) + metrics().vscroll_width(), 0); m_view->set_source(*cursource); } return result; }
void TabView_Reset(HWND hWndTabView) { struct TabViewInfo *pTabViewInfo = GetTabViewInfo(hWndTabView); TCITEM tci; (void)TabCtrl_DeleteAllItems(hWndTabView); memset(&tci, 0, sizeof(TCITEM)); tci.mask = TCIF_TEXT | TCIF_IMAGE; tci.cchTextMax = 20; for (int i = 0; i < pTabViewInfo->nTabCount; i++) { if (!pTabViewInfo->pCallbacks->pfnGetShowTab || pTabViewInfo->pCallbacks->pfnGetShowTab(i)) { TCHAR *t_text = tstring_from_utf8(pTabViewInfo->pCallbacks->pfnGetTabLongName(i)); if(!t_text) return; tci.pszText = t_text; tci.iImage = i; (void)TabCtrl_InsertItem(hWndTabView, i, &tci); free(t_text); } } TabView_UpdateSelection(hWndTabView); }
void TabView_Reset(HWND hwndTabView) { struct TabViewInfo *pTabViewInfo; TC_ITEM tci; int i; TCHAR* t_text; HRESULT res; BOOL b_res; pTabViewInfo = GetTabViewInfo(hwndTabView); b_res = TabCtrl_DeleteAllItems(hwndTabView); memset(&tci, 0, sizeof(tci)); tci.mask = TCIF_TEXT; tci.cchTextMax = 20; for (i = 0; i < pTabViewInfo->nTabCount; i++) { if (!pTabViewInfo->pCallbacks->pfnGetShowTab || pTabViewInfo->pCallbacks->pfnGetShowTab(i)) { t_text = tstring_from_utf8(pTabViewInfo->pCallbacks->pfnGetTabLongName(i)); if( !t_text ) return; tci.pszText = t_text; res = TabCtrl_InsertItem(hwndTabView, i, &tci); osd_free(t_text); } } TabView_UpdateSelection(hwndTabView); }
osd_directory_entry *osd_stat(const char *path) { osd_directory_entry *result = NULL; TCHAR *t_path; HANDLE find = INVALID_HANDLE_VALUE; WIN32_FIND_DATA find_data; // convert the path to TCHARs t_path = tstring_from_utf8(path); if (t_path == NULL) goto done; // attempt to find the first file find = FindFirstFile(t_path, &find_data); if (find == INVALID_HANDLE_VALUE) goto done; // create an osd_directory_entry; be sure to make sure that the caller can // free all resources by just freeing the resulting osd_directory_entry result = (osd_directory_entry *) malloc(sizeof(*result) + strlen(path) + 1); if (!result) goto done; strcpy(((char *) result) + sizeof(*result), path); result->name = ((char *) result) + sizeof(*result); result->type = win_attributes_to_entry_type(find_data.dwFileAttributes); result->size = find_data.nFileSizeLow | ((UINT64) find_data.nFileSizeHigh << 32); done: if (t_path) osd_free(t_path); return result; }
static BOOL DirListPopulateControl(datamap *map, HWND dialog, HWND control, windows_options *opts, const char *option_name) { int driver_index, pos, new_pos, current_item; const char *dir_list; TCHAR *t_dir_list; TCHAR *s; LV_COLUMN lvc; RECT r; HRESULT res; BOOL b_res; // access the directory list, and convert to TCHARs driver_index = PropertiesCurrentGame(dialog); dir_list = GetExtraSoftwarePaths(driver_index); t_dir_list = tstring_from_utf8(dir_list); if (!t_dir_list) return FALSE; // delete all items in the list control b_res = ListView_DeleteAllItems(control); // add the column GetClientRect(control, &r); memset(&lvc, 0, sizeof(LVCOLUMN)); lvc.mask = LVCF_WIDTH; lvc.cx = r.right - r.left - GetSystemMetrics(SM_CXHSCROLL); res = ListView_InsertColumn(control, 0, &lvc); // add each of the directories pos = 0; current_item = 0; while(t_dir_list[pos] != '\0') { // parse off this item s = _tcschr(&t_dir_list[pos], ';'); if (s != NULL) { *s = '\0'; new_pos = s - t_dir_list + 1; } else { new_pos = pos + _tcslen(&t_dir_list[pos]); } // append this item AppendList(control, &t_dir_list[pos], current_item); // advance to next item pos = new_pos; current_item++; } // finish up AppendList(control, TEXT(DIRLIST_NEWENTRYTEXT), current_item); ListView_SetItemState(control, 0, LVIS_SELECTED, LVIS_SELECTED); osd_free(t_dir_list); return TRUE; }
//============================================================ // osd_subst_env //============================================================ void osd_subst_env(std::string &dst, const std::string &src) { TCHAR buffer[MAX_PATH]; auto t_src = tstring_from_utf8(src.c_str()); ExpandEnvironmentStrings(t_src.c_str(), buffer, ARRAY_LENGTH(buffer)); utf8_from_tstring(dst, buffer); }
//============================================================ // osd_subst_env //============================================================ void osd_subst_env(char **dst, const char *src) { TCHAR buffer[MAX_PATH]; TCHAR *t_src = tstring_from_utf8(src); ExpandEnvironmentStrings(t_src, buffer, ARRAY_LENGTH(buffer)); *dst = utf8_from_tstring(buffer); }
bool osd_font_windows::open(const char *font_path, const char *_name, int &height) { // accept qualifiers from the name astring name(_name); if (name == "default") name = "Tahoma"; bool bold = (name.replace(0, "[B]", "") + name.replace(0, "[b]", "") > 0); bool italic = (name.replace(0, "[I]", "") + name.replace(0, "[i]", "") > 0); // build a basic LOGFONT description of what we want LOGFONT logfont; logfont.lfHeight = DEFAULT_FONT_HEIGHT; logfont.lfWidth = 0; logfont.lfEscapement = 0; logfont.lfOrientation = 0; logfont.lfWeight = bold ? FW_BOLD : FW_MEDIUM; logfont.lfItalic = italic; logfont.lfUnderline = FALSE; logfont.lfStrikeOut = FALSE; logfont.lfCharSet = ANSI_CHARSET; logfont.lfOutPrecision = OUT_DEFAULT_PRECIS; logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS; logfont.lfQuality = NONANTIALIASED_QUALITY; logfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; // copy in the face name TCHAR *face = tstring_from_utf8(name); _tcsncpy(logfont.lfFaceName, face, sizeof(logfont.lfFaceName) / sizeof(TCHAR)); logfont.lfFaceName[sizeof(logfont.lfFaceName) / sizeof(TCHAR)-1] = 0; osd_free(face); // create the font height = logfont.lfHeight; m_font = CreateFontIndirect(&logfont); if (m_font == NULL) return false; // select it into a temp DC and get the real font name HDC dummyDC = CreateCompatibleDC(NULL); HGDIOBJ oldfont = SelectObject(dummyDC, m_font); TCHAR realname[100]; GetTextFace(dummyDC, ARRAY_LENGTH(realname), realname); SelectObject(dummyDC, oldfont); DeleteDC(dummyDC); // if it doesn't match our request, fail char *utf = utf8_from_tstring(realname); int result = core_stricmp(utf, name); osd_free(utf); // if we didn't match, nuke our font and fall back if (result != 0) { DeleteObject(m_font); m_font = NULL; return false; } return true; }
void win_output_debug_string_utf8(const char *string) { TCHAR *t_string = tstring_from_utf8(string); if (t_string != NULL) { OutputDebugString(t_string); free(t_string); } }
bool osd_is_absolute_path(std::string const &path) { bool result = false; TCHAR *t_path = tstring_from_utf8(path.c_str()); if (t_path != nullptr) { result = !PathIsRelative(t_path); osd_free(t_path); } return result; }
static void DirWatcher_Signal(PDIRWATCHER pWatcher, struct DirWatcherEntry *pEntry) { LPSTR pszFileName; LPSTR pszFullFileName; BOOL bPause; HANDLE hFile; int nTries; TCHAR* t_filename; { int nLength; nLength = WideCharToMultiByte(CP_ACP, 0, pEntry->u.notify.FileName, -1, NULL, 0, NULL, NULL); pszFileName = (LPSTR) alloca(nLength * sizeof(*pszFileName)); WideCharToMultiByte(CP_ACP, 0, pEntry->u.notify.FileName, -1, pszFileName, nLength, NULL, NULL); } // get the full path to this new file pszFullFileName = (LPSTR) alloca(strlen(pEntry->szDirPath) + strlen(pszFileName) + 2); strcpy(pszFullFileName, pEntry->szDirPath); strcat(pszFullFileName, "\\"); strcat(pszFullFileName, pszFileName); // attempt to busy wait until any result other than ERROR_SHARING_VIOLATION // is generated nTries = 100; do { hFile = win_create_file_utf8(pszFullFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile); bPause = (nTries--) && (hFile == INVALID_HANDLE_VALUE) && (GetLastError() == ERROR_SHARING_VIOLATION); if (bPause) Sleep(10); } while(bPause); // send the message (assuming that we have a target) if (pWatcher->hwndTarget) { t_filename = tstring_from_utf8(pszFileName); if( !t_filename ) return; SendMessage(pWatcher->hwndTarget, pWatcher->nMessage, (pEntry->nIndex << 16) | (pEntry->nSubIndex << 0), (LPARAM)(LPCTSTR) win_tstring_strdup(t_filename)); osd_free(t_filename); } DirWatcher_SetupWatch(pWatcher, pEntry); }
int osd_is_absolute_path(const char *path) { int result = FALSE; TCHAR *t_path = tstring_from_utf8(path); if (t_path != NULL) { result = !PathIsRelative(t_path); free(t_path); } return result; }
void consolewin_info::update_menu() { disasmbasewin_info::update_menu(); if (m_devices_menu != NULL) { // create the image menu image_interface_iterator iter(machine().root_device()); device_image_interface *img; UINT32 cnt; for (img = iter.first(), cnt = 0; img != NULL; img = iter.next(), cnt++) { HMENU const devicesubmenu = CreatePopupMenu(); UINT_PTR const new_item = ID_DEVICE_OPTIONS + (cnt * DEVOPTION_MAX); UINT flags_for_exists = MF_ENABLED | MF_STRING; if (!img->exists()) flags_for_exists |= MF_GRAYED; UINT flags_for_writing = flags_for_exists; if (img->is_readonly()) flags_for_writing |= MF_GRAYED; AppendMenu(devicesubmenu, MF_STRING, new_item + DEVOPTION_OPEN, TEXT("Mount...")); //if (img->is_creatable()) //AppendMenu(devicesubmenu, MF_STRING, new_item + DEVOPTION_CREATE, TEXT("Create...")); AppendMenu(devicesubmenu, flags_for_exists, new_item + DEVOPTION_CLOSE, TEXT("Unmount")); if (img->device().type() == CASSETTE) { cassette_state const state = (cassette_state)(img->exists() ? (downcast<cassette_image_device *>(&img->device())->get_state() & CASSETTE_MASK_UISTATE) : CASSETTE_STOPPED); AppendMenu(devicesubmenu, MF_SEPARATOR, 0, NULL); AppendMenu(devicesubmenu, flags_for_exists | ((state == CASSETTE_STOPPED) ? MF_CHECKED : 0), new_item + DEVOPTION_CASSETTE_STOPPAUSE, TEXT("Pause/Stop")); AppendMenu(devicesubmenu, flags_for_exists | ((state == CASSETTE_PLAY) ? MF_CHECKED : 0), new_item + DEVOPTION_CASSETTE_PLAY, TEXT("Play")); AppendMenu(devicesubmenu, flags_for_writing | ((state == CASSETTE_RECORD) ? MF_CHECKED : 0), new_item + DEVOPTION_CASSETTE_RECORD, TEXT("Record")); AppendMenu(devicesubmenu, flags_for_exists, new_item + DEVOPTION_CASSETTE_REWIND, TEXT("Rewind")); AppendMenu(devicesubmenu, flags_for_exists, new_item + DEVOPTION_CASSETTE_FASTFORWARD, TEXT("Fast Forward")); } astring temp; temp.format("%s :%s", img->device().name(), img->exists() ? img->filename() : "[empty slot]"); TCHAR *tc_buf = tstring_from_utf8(temp.c_str()); if (tc_buf != NULL) { ModifyMenu(m_devices_menu, cnt, MF_BYPOSITION | MF_POPUP, (UINT_PTR)devicesubmenu, tc_buf); osd_free(tc_buf); } } } }
HICON win_extract_icon_utf8(HINSTANCE inst, const char* exefilename, UINT iconindex) { HICON icon = 0; TCHAR* t_exefilename = tstring_from_utf8(exefilename); if( !t_exefilename ) return icon; icon = ExtractIcon(inst, t_exefilename, iconindex); osd_free(t_exefilename); return icon; }
HANDLE win_find_first_file_utf8(const char* filename, LPWIN32_FIND_DATA findfiledata) { HANDLE result = 0; TCHAR* t_filename = tstring_from_utf8(filename); if( !t_filename ) return result; result = FindFirstFile(t_filename, findfiledata); osd_free(t_filename); return result; }
osd_file::error osd_file::remove(std::string const &filename) { TCHAR *tempstr = tstring_from_utf8(filename.c_str()); if (!tempstr) return error::OUT_OF_MEMORY; error filerr = error::NONE; if (!DeleteFile(tempstr)) filerr = win_error_to_file_error(GetLastError()); osd_free(tempstr); return filerr; }
BOOL win_set_file_attributes_utf8(const char* filename, DWORD fileattributes) { BOOL result = FALSE; TCHAR* t_filename = tstring_from_utf8(filename); if( !t_filename ) return result; result = SetFileAttributes(t_filename, fileattributes); free(t_filename); return result; }
void DisplayTextFile(HWND hWnd, const char *cName) { HINSTANCE hErr; LPCTSTR msg = 0; LPTSTR tName; tName = tstring_from_utf8(cName); if( !tName ) return; hErr = ShellExecute(hWnd, NULL, tName, NULL, NULL, SW_SHOWNORMAL); if ((FPTR)hErr > 32) { osd_free(tName); return; } switch((FPTR)hErr) { case 0: msg = TEXT("The operating system is out of memory or resources."); break; case ERROR_FILE_NOT_FOUND: msg = TEXT("The specified file was not found."); break; case SE_ERR_NOASSOC : msg = TEXT("There is no application associated with the given filename extension."); break; case SE_ERR_OOM : msg = TEXT("There was not enough memory to complete the operation."); break; case SE_ERR_PNF : msg = TEXT("The specified path was not found."); break; case SE_ERR_SHARE : msg = TEXT("A sharing violation occurred."); break; default: msg = TEXT("Unknown error."); } MessageBox(NULL, msg, tName, MB_OK); osd_free(tName); }
BOOL win_move_file_utf8(const char* existingfilename, const char* newfilename) { TCHAR* t_existingfilename; TCHAR* t_newfilename; BOOL result = FALSE; t_existingfilename = tstring_from_utf8(existingfilename); if( !t_existingfilename ) return result; t_newfilename = tstring_from_utf8(newfilename); if( !t_newfilename ) { free(t_existingfilename); return result; } result = MoveFile(t_existingfilename, t_newfilename); free(t_newfilename); free(t_existingfilename); return result; }
BOOL win_copy_file_utf8(const char* existingfilename, const char* newfilename, BOOL failifexists) { TCHAR* t_existingfilename; TCHAR* t_newfilename; BOOL result = FALSE; t_existingfilename = tstring_from_utf8(existingfilename); if( !t_existingfilename ) return result; t_newfilename = tstring_from_utf8(newfilename); if( !t_newfilename ) { free(t_existingfilename); return result; } result = CopyFile(t_existingfilename, t_newfilename, failifexists); free(t_newfilename); free(t_existingfilename); return result; }
HANDLE win_create_file_utf8(const char* filename, DWORD desiredmode, DWORD sharemode, LPSECURITY_ATTRIBUTES securityattributes, DWORD creationdisposition, DWORD flagsandattributes, HANDLE templatehandle) { HANDLE result = 0; TCHAR* t_filename = tstring_from_utf8(filename); if( !t_filename ) return result; result = CreateFile(t_filename, desiredmode, sharemode, securityattributes, creationdisposition, flagsandattributes, templatehandle); osd_free(t_filename); return result; }
osd_directory *osd_opendir(const char *dirname) { osd_directory *dir = NULL; TCHAR *t_dirname = NULL; TCHAR *dirfilter = NULL; size_t dirfilter_size; // allocate memory to hold the osd_tool_directory structure dir = malloc(sizeof(*dir)); if (dir == NULL) goto error; memset(dir, 0, sizeof(*dir)); // initialize the structure dir->find = INVALID_HANDLE_VALUE; dir->is_first = TRUE; // convert the path to TCHARs t_dirname = tstring_from_utf8(dirname); if (t_dirname == NULL) goto error; // append \*.* to the directory name dirfilter_size = _tcslen(t_dirname) + 5; dirfilter = (TCHAR *)malloc(dirfilter_size * sizeof(*dirfilter)); if (dirfilter == NULL) goto error; _sntprintf(dirfilter, dirfilter_size, TEXT("%s\\*.*"), t_dirname); // attempt to find the first file dir->find = FindFirstFile(dirfilter, &dir->data); error: // cleanup if (t_dirname != NULL) free(t_dirname); if (dirfilter != NULL) free(dirfilter); if (dir != NULL && dir->find == INVALID_HANDLE_VALUE) { free(dir); dir = NULL; } return dir; }
file_error win_open_ptty(const char *path, UINT32 openflags, osd_file **file, UINT64 *filesize) { TCHAR *t_name; HANDLE pipe; if((t_name = tstring_from_utf8(path)) == NULL) return FILERR_OUT_OF_MEMORY; pipe = CreateNamedPipe(t_name, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_NOWAIT, 1, 32, 32, 0, NULL); if(pipe == INVALID_HANDLE_VALUE) return FILERR_ACCESS_DENIED; (*file)->handle = pipe; *filesize = 0; osd_free(t_name); return FILERR_NONE; }
std::unique_ptr<osd::directory::entry> osd_stat(const std::string &path) { // convert the path to TCHARs std::unique_ptr<TCHAR, void (*)(void *)> const t_path(tstring_from_utf8(path.c_str()), &osd_free); if (!t_path) return nullptr; // is this path a root directory (e.g. - C:)? WIN32_FIND_DATA find_data; std::memset(&find_data, 0, sizeof(find_data)); if (isalpha(path[0]) && (path[1] == ':') && (path[2] == '\0')) { // need to do special logic for root directories if (!GetFileAttributesEx(t_path.get(), GetFileExInfoStandard, &find_data.dwFileAttributes)) find_data.dwFileAttributes = INVALID_FILE_ATTRIBUTES; } else { // attempt to find the first file HANDLE find = FindFirstFileEx(t_path.get(), FindExInfoStandard, &find_data, FindExSearchNameMatch, nullptr, 0); if (find == INVALID_HANDLE_VALUE) return nullptr; FindClose(find); } // create an osd::directory::entry; be sure to make sure that the caller can // free all resources by just freeing the resulting osd::directory::entry osd::directory::entry *result; try { result = reinterpret_cast<osd::directory::entry *>(::operator new(sizeof(*result) + path.length() + 1)); } catch (...) { return nullptr; } new (result) osd::directory::entry; strcpy(((char *) result) + sizeof(*result), path.c_str()); result->name = ((char *) result) + sizeof(*result); result->type = win_attributes_to_entry_type(find_data.dwFileAttributes); result->size = find_data.nFileSizeLow | ((UINT64) find_data.nFileSizeHigh << 32); result->last_modified = win_time_point_from_filetime(&find_data.ftLastWriteTime); return std::unique_ptr<osd::directory::entry>(result); }
BOOL win_set_window_text_utf8(HWND window, const char *text) { BOOL result = FALSE; TCHAR *t_text = NULL; if (text) { t_text = tstring_from_utf8(text); if (!t_text) goto done; } result = SetWindowText(window, t_text); done: if (t_text) free(t_text); return result; }
int osd_get_physical_drive_geometry(const char *filename, UINT32 *cylinders, UINT32 *heads, UINT32 *sectors, UINT32 *bps) { DISK_GEOMETRY dg; DWORD bytesRead; TCHAR *t_filename; HANDLE file; int result; // if it doesn't smell like a physical drive, just return FALSE if (!is_path_to_physical_drive(filename)) return FALSE; // do a create file on the drive t_filename = tstring_from_utf8(filename); if (t_filename == nullptr) return FALSE; file = CreateFile(t_filename, GENERIC_READ, FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, nullptr); osd_free(t_filename); if (file == INVALID_HANDLE_VALUE) return FALSE; // device I/O control should return the geometry result = DeviceIoControl(file, IOCTL_DISK_GET_DRIVE_GEOMETRY, nullptr, 0, &dg, sizeof(dg), &bytesRead, nullptr); CloseHandle(file); // if that failed, return false if (!result) return FALSE; // store the results *cylinders = (UINT32)dg.Cylinders.QuadPart; *heads = dg.TracksPerCylinder; *sectors = dg.SectorsPerTrack; *bps = dg.BytesPerSector; // normalize while (*heads > 16 && !(*heads & 1)) { *heads /= 2; *cylinders *= 2; } return TRUE; }
osd_file::error win_open_ptty(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) { auto t_name = tstring_from_utf8(path.c_str()); HANDLE pipe = CreateNamedPipe(t_name.c_str(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_NOWAIT, 1, 32, 32, 0, nullptr); if (INVALID_HANDLE_VALUE == pipe) return osd_file::error::ACCESS_DENIED; try { file = std::make_unique<win_osd_ptty>(pipe); filesize = 0; return osd_file::error::NONE; } catch (...) { CloseHandle(pipe); return osd_file::error::OUT_OF_MEMORY; } }
osd_file::error osd_get_full_path(std::string &dst, std::string const &path) { // convert the path to TCHARs TCHAR *t_path = tstring_from_utf8(path.c_str()); osd_disposer<TCHAR> t_path_disposer(t_path); if (!t_path) return osd_file::error::OUT_OF_MEMORY; // cannonicalize the path TCHAR buffer[MAX_PATH]; if (!GetFullPathName(t_path, ARRAY_LENGTH(buffer), buffer, nullptr)) return win_error_to_file_error(GetLastError()); // convert the result back to UTF-8 char *result = utf8_from_tstring(buffer); osd_disposer<char> result_disposer(result); if (!result) return osd_file::error::OUT_OF_MEMORY; dst = result; return osd_file::error::NONE; }