#include #include #include #include #define PAL_PATH_NAME "SDLPAL" static std::string g_savepath, g_basepath; template static bool WaitOnTask(T task, int64 wait_timeout) { auto start = GetTickCount64(); while (!task.is_done() && (int64)(GetTickCount64() - start) <= wait_timeout) Sleep(1); return task.is_done(); } static void ConvertString(Platform::String^ src, std::string& dst) { int len = WideCharToMultiByte(CP_ACP, 0, src->Begin(), -1, nullptr, 0, nullptr, nullptr); dst.resize(len - 1); WideCharToMultiByte(CP_ACP, 0, src->Begin(), -1, (char*)dst.data(), len, nullptr, nullptr); } static bool CheckGamePath(Windows::Storage::StorageFolder^ root) { Platform::String^ required_files[] = { L"ABC.MKF", L"BALL.MKF", L"DATA.MKF", L"F.MKF", L"FBP.MKF", L"FIRE.MKF", L"GOP.MKF", L"MAP.MKF", L"MGO.MKF", L"PAT.MKF", L"RGM.MKF", L"RNG.MKF", L"SSS.MKF" }; Platform::String^ optional_required_files[] = { L"VOC.MKF", L"SOUNDS.MKF" }; /* The words.dat & m.msg may be configurable in the future, so not check here */ /* Try to get the path */ auto foldertask = concurrency::create_task(root->GetFolderAsync(PAL_PATH_NAME)); if (!WaitOnTask(foldertask, 500)) return false; // Wait for 500ms max try { /* Check the access right of necessary files */ auto folder = foldertask.get(); for (int i = 0; i < 13; i++) { auto filetask = concurrency::create_task(foldertask.get()->GetFileAsync(required_files[i])); if (!WaitOnTask(filetask, 500) || _waccess_s(filetask.get()->Path->Begin(), 2)) return false; } for (int i = 0; i < 2; i++) { auto filetask = concurrency::create_task(foldertask.get()->GetFileAsync(optional_required_files[i])); if (WaitOnTask(filetask, 500) && _waccess_s(filetask.get()->Path->Begin(), 2) == 0) return true; } } catch(Platform::Exception^) { /* Accessing SD card failed, or required file is missing, or access is denied */ } return false; } extern "C" LPCSTR UTIL_BasePath(VOID) { if (g_basepath.empty()) { auto enumtask = concurrency::create_task(Windows::Storage::KnownFolders::RemovableDevices->GetFoldersAsync()); if (WaitOnTask(enumtask, 1000)) // Wait for 1000ms max { auto folderiter = enumtask.get()->First(); while (folderiter->HasCurrent) { if (CheckGamePath(folderiter->Current)) { /* Folder examination succeeded */ auto folder = folderiter->Current->Path; if (folder->End()[-1] != L'\\') folder += "\\"; folder += PAL_PATH_NAME "\\"; ConvertString(folder, g_basepath); /* Check whether the folder is writable */ FILE* fp; if (_wfopen_s(&fp, (folder + "sdlpal.rpg")->Begin(), L"w") == 0) { g_savepath = g_basepath; fclose(fp); } break; } folderiter->MoveNext(); } } if (g_basepath.empty()) { g_basepath.assign("Assets\\Data\\"); } } return g_basepath.c_str(); } extern "C" LPCSTR UTIL_SavePath(VOID) { if (g_savepath.empty()) { auto localfolder = Windows::Storage::ApplicationData::Current->LocalFolder->Path; if (localfolder->End()[-1] != L'\\') localfolder += "\\"; ConvertString(localfolder, g_savepath); } return g_savepath.c_str(); } extern "C" BOOL UTIL_GetScreenSize(DWORD *pdwScreenWidth, DWORD *pdwScreenHeight) { DXGI_OUTPUT_DESC desc; IDXGIFactory1* pFactory = nullptr; IDXGIAdapter1* pAdapter = nullptr; IDXGIOutput* pOutput = nullptr; DWORD retval = FALSE; if (!pdwScreenWidth || !pdwScreenHeight) return FALSE; if (FAILED(CreateDXGIFactory1(IID_IDXGIFactory1, (void**)&pFactory))) goto UTIL_WP_GetScreenSize_exit; if (FAILED(pFactory->EnumAdapters1(0, &pAdapter))) goto UTIL_WP_GetScreenSize_exit; if (FAILED(pAdapter->EnumOutputs(0, &pOutput))) goto UTIL_WP_GetScreenSize_exit; if (SUCCEEDED(pOutput->GetDesc(&desc))) { *pdwScreenWidth = (desc.DesktopCoordinates.bottom - desc.DesktopCoordinates.top); *pdwScreenHeight = (desc.DesktopCoordinates.right - desc.DesktopCoordinates.left); retval = TRUE; } UTIL_WP_GetScreenSize_exit: if (pOutput) pOutput->Release(); if (pAdapter) pAdapter->Release(); if (pFactory) pFactory->Release(); return retval; }