2012-11-01 16:19:01 +01:00
|
|
|
// Copyright (c) 2012- PPSSPP Project.
|
|
|
|
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
2012-11-04 23:01:49 +01:00
|
|
|
// the Free Software Foundation, version 2.0 or later versions.
|
2012-11-01 16:19:01 +01:00
|
|
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
|
|
|
|
// Official git repository and contact information can be found at
|
|
|
|
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
|
|
|
|
2018-03-23 22:54:12 +01:00
|
|
|
#include "stdafx.h"
|
2015-12-25 19:14:05 -08:00
|
|
|
#include <algorithm>
|
2016-12-05 16:51:28 +01:00
|
|
|
#include <cmath>
|
2014-02-13 15:57:36 +01:00
|
|
|
|
2013-07-28 21:01:49 -07:00
|
|
|
#include "Common/CommonWindows.h"
|
2017-02-14 10:33:42 +01:00
|
|
|
#include "Common/OSVersion.h"
|
2019-02-16 10:14:54 -08:00
|
|
|
#include "Common/Vulkan/VulkanLoader.h"
|
2019-05-10 23:25:57 +02:00
|
|
|
#include "ppsspp_config.h"
|
2017-02-14 10:33:42 +01:00
|
|
|
|
2016-12-05 16:51:28 +01:00
|
|
|
#include <Wbemidl.h>
|
|
|
|
#include <shellapi.h>
|
2019-05-21 23:22:56 +02:00
|
|
|
#include <ShlObj.h>
|
2016-12-05 16:51:28 +01:00
|
|
|
#include <mmsystem.h>
|
2012-11-01 16:19:01 +01:00
|
|
|
|
2019-02-17 08:03:10 -08:00
|
|
|
#include "base/NativeApp.h"
|
2017-01-16 19:08:26 +07:00
|
|
|
#include "base/display.h"
|
2012-11-01 16:19:01 +01:00
|
|
|
#include "file/vfs.h"
|
|
|
|
#include "file/zip_read.h"
|
2019-02-17 08:03:10 -08:00
|
|
|
#include "i18n/i18n.h"
|
2015-05-12 19:45:14 +02:00
|
|
|
#include "profiler/profiler.h"
|
2014-06-29 12:53:03 +02:00
|
|
|
#include "thread/threadutil.h"
|
2013-08-26 19:00:16 +02:00
|
|
|
#include "util/text/utf8.h"
|
2017-02-14 13:11:46 +01:00
|
|
|
#include "net/resolve.h"
|
2012-11-01 16:19:01 +01:00
|
|
|
|
2013-07-28 21:01:49 -07:00
|
|
|
#include "Core/Config.h"
|
2018-06-16 18:42:31 -07:00
|
|
|
#include "Core/ConfigValues.h"
|
2013-07-28 21:01:49 -07:00
|
|
|
#include "Core/SaveState.h"
|
|
|
|
#include "Windows/EmuThread.h"
|
2017-06-27 11:46:10 +02:00
|
|
|
#include "Windows/WindowsAudio.h"
|
2013-01-08 17:03:17 +01:00
|
|
|
#include "ext/disarm.h"
|
2012-11-01 16:19:01 +01:00
|
|
|
|
2013-07-28 21:01:49 -07:00
|
|
|
#include "Common/LogManager.h"
|
|
|
|
#include "Common/ConsoleListener.h"
|
2012-11-01 16:19:01 +01:00
|
|
|
|
|
|
|
#include "Commctrl.h"
|
|
|
|
|
2015-10-04 12:24:59 +02:00
|
|
|
#include "UI/GameInfoCache.h"
|
2012-11-01 16:19:01 +01:00
|
|
|
#include "Windows/resource.h"
|
|
|
|
|
2015-09-19 13:14:05 +02:00
|
|
|
#include "Windows/MainWindow.h"
|
2013-09-22 10:27:09 -07:00
|
|
|
#include "Windows/Debugger/Debugger_Disasm.h"
|
2012-11-01 16:19:01 +01:00
|
|
|
#include "Windows/Debugger/Debugger_MemoryDlg.h"
|
|
|
|
#include "Windows/Debugger/Debugger_VFPUDlg.h"
|
2019-05-10 23:25:57 +02:00
|
|
|
#if PPSSPP_API(ANY_GL)
|
2013-09-22 11:03:29 -07:00
|
|
|
#include "Windows/GEDebugger/GEDebugger.h"
|
2019-05-04 06:06:50 +08:00
|
|
|
#endif
|
2012-11-01 16:19:01 +01:00
|
|
|
#include "Windows/W32Util/DialogManager.h"
|
2019-02-17 08:03:10 -08:00
|
|
|
#include "Windows/W32Util/ShellUtil.h"
|
2012-11-01 16:19:01 +01:00
|
|
|
|
|
|
|
#include "Windows/Debugger/CtrlDisAsmView.h"
|
|
|
|
#include "Windows/Debugger/CtrlMemView.h"
|
|
|
|
#include "Windows/Debugger/CtrlRegisterList.h"
|
2013-12-08 20:16:18 +10:00
|
|
|
#include "Windows/InputBox.h"
|
2012-11-01 16:19:01 +01:00
|
|
|
|
|
|
|
#include "Windows/WindowsHost.h"
|
|
|
|
#include "Windows/main.h"
|
|
|
|
|
2016-04-21 23:03:08 -04:00
|
|
|
|
2017-08-28 13:45:04 +02:00
|
|
|
// Nvidia OpenGL drivers >= v302 will check if the application exports a global
|
2014-03-03 11:26:27 -05:00
|
|
|
// variable named NvOptimusEnablement to know if it should run the app in high
|
|
|
|
// performance graphics mode or using the IGP.
|
|
|
|
extern "C" {
|
|
|
|
__declspec(dllexport) DWORD NvOptimusEnablement = 1;
|
|
|
|
}
|
|
|
|
|
2018-04-15 08:41:02 +02:00
|
|
|
// Also on AMD PowerExpress: https://community.amd.com/thread/169965
|
|
|
|
extern "C" {
|
|
|
|
__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
|
|
|
|
}
|
2019-05-10 23:25:57 +02:00
|
|
|
#if PPSSPP_API(ANY_GL)
|
2019-05-04 06:06:50 +08:00
|
|
|
CGEDebugger* geDebuggerWindow = 0;
|
|
|
|
#endif
|
2018-04-15 08:41:02 +02:00
|
|
|
|
2013-03-31 18:35:29 -07:00
|
|
|
CDisasm *disasmWindow[MAX_CPUCOUNT] = {0};
|
|
|
|
CMemoryDlg *memoryWindow[MAX_CPUCOUNT] = {0};
|
2012-11-01 16:19:01 +01:00
|
|
|
|
2013-09-04 12:07:42 +02:00
|
|
|
static std::string langRegion;
|
2013-10-09 17:17:28 -04:00
|
|
|
static std::string osName;
|
2014-07-31 01:21:37 -04:00
|
|
|
static std::string gpuDriverVersion;
|
2013-09-04 12:07:42 +02:00
|
|
|
|
2017-08-31 17:13:18 +02:00
|
|
|
HMENU g_hPopupMenus;
|
|
|
|
int g_activeWindow = 0;
|
|
|
|
|
2019-05-21 23:22:56 +02:00
|
|
|
void OpenDirectory(const char *path) {
|
|
|
|
PIDLIST_ABSOLUTE pidl = ILCreateFromPath(ConvertUTF8ToWString(ReplaceAll(path, "/", "\\")).c_str());
|
|
|
|
if (pidl) {
|
|
|
|
SHOpenFolderAndSelectItems(pidl, 0, NULL, 0);
|
|
|
|
ILFree(pidl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-26 19:00:16 +02:00
|
|
|
void LaunchBrowser(const char *url) {
|
|
|
|
ShellExecute(NULL, L"open", ConvertUTF8ToWString(url).c_str(), NULL, NULL, SW_SHOWNORMAL);
|
2013-08-18 00:41:19 +02:00
|
|
|
}
|
|
|
|
|
2013-10-10 08:00:15 -07:00
|
|
|
void Vibrate(int length_ms) {
|
|
|
|
// Ignore on PC
|
|
|
|
}
|
|
|
|
|
2014-07-31 01:21:37 -04:00
|
|
|
// Adapted mostly as-is from http://www.gamedev.net/topic/495075-how-to-retrieve-info-about-videocard/?view=findpost&p=4229170
|
|
|
|
// so credit goes to that post's author, and in turn, the author of the site mentioned in that post (which seems to be down?).
|
2014-07-31 04:00:48 -04:00
|
|
|
std::string GetVideoCardDriverVersion() {
|
2014-07-31 01:21:37 -04:00
|
|
|
std::string retvalue = "";
|
|
|
|
|
|
|
|
HRESULT hr;
|
|
|
|
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
2014-08-02 12:49:09 +02:00
|
|
|
if (FAILED(hr)) {
|
|
|
|
return retvalue;
|
|
|
|
}
|
2014-07-31 01:21:37 -04:00
|
|
|
|
|
|
|
IWbemLocator *pIWbemLocator = NULL;
|
|
|
|
hr = CoCreateInstance(__uuidof(WbemLocator), NULL, CLSCTX_INPROC_SERVER,
|
|
|
|
__uuidof(IWbemLocator), (LPVOID *)&pIWbemLocator);
|
2014-08-02 12:49:09 +02:00
|
|
|
if (FAILED(hr)) {
|
|
|
|
CoUninitialize();
|
|
|
|
return retvalue;
|
|
|
|
}
|
2014-07-31 01:21:37 -04:00
|
|
|
|
|
|
|
BSTR bstrServer = SysAllocString(L"\\\\.\\root\\cimv2");
|
|
|
|
IWbemServices *pIWbemServices;
|
|
|
|
hr = pIWbemLocator->ConnectServer(bstrServer, NULL, NULL, 0L, 0L, NULL, NULL, &pIWbemServices);
|
2014-08-02 12:49:09 +02:00
|
|
|
if (FAILED(hr)) {
|
|
|
|
pIWbemLocator->Release();
|
2015-01-17 14:00:54 -08:00
|
|
|
SysFreeString(bstrServer);
|
2014-08-02 12:49:09 +02:00
|
|
|
CoUninitialize();
|
|
|
|
return retvalue;
|
|
|
|
}
|
2014-07-31 01:21:37 -04:00
|
|
|
|
|
|
|
hr = CoSetProxyBlanket(pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
|
|
|
|
NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL,EOAC_DEFAULT);
|
2014-08-02 12:49:09 +02:00
|
|
|
|
2014-07-31 01:21:37 -04:00
|
|
|
BSTR bstrWQL = SysAllocString(L"WQL");
|
|
|
|
BSTR bstrPath = SysAllocString(L"select * from Win32_VideoController");
|
|
|
|
IEnumWbemClassObject* pEnum;
|
|
|
|
hr = pIWbemServices->ExecQuery(bstrWQL, bstrPath, WBEM_FLAG_FORWARD_ONLY, NULL, &pEnum);
|
|
|
|
|
|
|
|
ULONG uReturned;
|
|
|
|
VARIANT var;
|
2014-08-02 12:49:09 +02:00
|
|
|
IWbemClassObject* pObj = NULL;
|
|
|
|
if (!FAILED(hr)) {
|
|
|
|
hr = pEnum->Next(WBEM_INFINITE, 1, &pObj, &uReturned);
|
|
|
|
}
|
2014-07-31 01:21:37 -04:00
|
|
|
|
2015-04-08 11:35:40 -07:00
|
|
|
if (!FAILED(hr) && uReturned) {
|
2014-07-31 01:21:37 -04:00
|
|
|
hr = pObj->Get(L"DriverVersion", 0, &var, NULL, NULL);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
char str[MAX_PATH];
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, var.bstrVal, -1, str, sizeof(str), NULL, NULL);
|
|
|
|
retvalue = str;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pEnum->Release();
|
|
|
|
SysFreeString(bstrPath);
|
|
|
|
SysFreeString(bstrWQL);
|
|
|
|
pIWbemServices->Release();
|
2014-08-02 12:49:09 +02:00
|
|
|
pIWbemLocator->Release();
|
2014-07-31 01:21:37 -04:00
|
|
|
SysFreeString(bstrServer);
|
|
|
|
CoUninitialize();
|
|
|
|
return retvalue;
|
|
|
|
}
|
|
|
|
|
2013-09-04 11:29:38 +02:00
|
|
|
std::string System_GetProperty(SystemProperty prop) {
|
2014-08-02 12:49:09 +02:00
|
|
|
static bool hasCheckedGPUDriverVersion = false;
|
2013-09-04 11:29:38 +02:00
|
|
|
switch (prop) {
|
|
|
|
case SYSPROP_NAME:
|
2013-10-09 17:17:28 -04:00
|
|
|
return osName;
|
2013-09-04 11:29:38 +02:00
|
|
|
case SYSPROP_LANGREGION:
|
2013-09-04 12:07:42 +02:00
|
|
|
return langRegion;
|
2014-07-21 11:59:47 +02:00
|
|
|
case SYSPROP_CLIPBOARD_TEXT:
|
|
|
|
{
|
|
|
|
std::string retval;
|
|
|
|
if (OpenClipboard(MainWindow::GetDisplayHWND())) {
|
|
|
|
HANDLE handle = GetClipboardData(CF_UNICODETEXT);
|
|
|
|
const wchar_t *wstr = (const wchar_t*)GlobalLock(handle);
|
2014-07-21 20:54:17 +08:00
|
|
|
if (wstr)
|
|
|
|
retval = ConvertWStringToUTF8(wstr);
|
|
|
|
else
|
|
|
|
retval = "";
|
2014-07-21 11:59:47 +02:00
|
|
|
GlobalUnlock(handle);
|
|
|
|
CloseClipboard();
|
|
|
|
}
|
|
|
|
return retval;
|
|
|
|
}
|
2014-07-31 01:21:37 -04:00
|
|
|
case SYSPROP_GPUDRIVER_VERSION:
|
2014-08-02 12:49:09 +02:00
|
|
|
if (!hasCheckedGPUDriverVersion) {
|
|
|
|
hasCheckedGPUDriverVersion = true;
|
|
|
|
gpuDriverVersion = GetVideoCardDriverVersion();
|
|
|
|
}
|
2014-07-31 01:21:37 -04:00
|
|
|
return gpuDriverVersion;
|
2013-09-04 11:29:38 +02:00
|
|
|
default:
|
|
|
|
return "";
|
|
|
|
}
|
2013-08-18 00:41:19 +02:00
|
|
|
}
|
|
|
|
|
2015-01-11 21:00:56 +01:00
|
|
|
// Ugly!
|
|
|
|
extern WindowsAudioBackend *winAudioBackend;
|
|
|
|
|
2017-03-17 13:22:00 +01:00
|
|
|
#ifdef _WIN32
|
|
|
|
#if PPSSPP_PLATFORM(UWP)
|
|
|
|
static int ScreenDPI() {
|
|
|
|
return 96; // TODO UWP
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static int ScreenDPI() {
|
|
|
|
HDC screenDC = GetDC(nullptr);
|
|
|
|
int dotsPerInch = GetDeviceCaps(screenDC, LOGPIXELSY);
|
|
|
|
ReleaseDC(nullptr, screenDC);
|
2017-04-30 08:54:34 +02:00
|
|
|
return dotsPerInch ? dotsPerInch : 96;
|
2017-03-17 13:22:00 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2014-07-20 12:11:50 +02:00
|
|
|
int System_GetPropertyInt(SystemProperty prop) {
|
2015-01-11 14:18:40 +01:00
|
|
|
switch (prop) {
|
|
|
|
case SYSPROP_AUDIO_SAMPLE_RATE:
|
2015-01-11 21:00:56 +01:00
|
|
|
return winAudioBackend ? winAudioBackend->GetSampleRate() : -1;
|
2015-01-14 00:45:12 +01:00
|
|
|
case SYSPROP_DISPLAY_REFRESH_RATE:
|
|
|
|
return 60000;
|
2015-10-06 19:17:29 +02:00
|
|
|
case SYSPROP_DEVICE_TYPE:
|
|
|
|
return DEVICE_TYPE_DESKTOP;
|
2017-03-17 13:22:00 +01:00
|
|
|
case SYSPROP_DISPLAY_DPI:
|
|
|
|
return ScreenDPI();
|
2017-07-30 08:33:02 -07:00
|
|
|
case SYSPROP_DISPLAY_COUNT:
|
|
|
|
return GetSystemMetrics(SM_CMONITORS);
|
2017-04-29 17:35:12 -07:00
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool System_GetPropertyBool(SystemProperty prop) {
|
|
|
|
switch (prop) {
|
2017-02-27 11:32:40 +01:00
|
|
|
case SYSPROP_HAS_FILE_BROWSER:
|
2017-04-29 17:35:12 -07:00
|
|
|
return true;
|
2017-04-02 10:50:09 -07:00
|
|
|
case SYSPROP_HAS_IMAGE_BROWSER:
|
2017-04-29 17:35:12 -07:00
|
|
|
return true;
|
2017-03-07 10:33:53 +01:00
|
|
|
case SYSPROP_HAS_BACK_BUTTON:
|
2017-04-29 17:35:12 -07:00
|
|
|
return true;
|
2017-04-05 16:21:08 +02:00
|
|
|
case SYSPROP_APP_GOLD:
|
|
|
|
#ifdef GOLD
|
2017-04-29 17:35:12 -07:00
|
|
|
return true;
|
2017-04-05 16:21:08 +02:00
|
|
|
#else
|
2017-04-29 17:35:12 -07:00
|
|
|
return false;
|
2017-04-05 16:21:08 +02:00
|
|
|
#endif
|
2015-01-11 14:18:40 +01:00
|
|
|
default:
|
2017-04-29 17:35:12 -07:00
|
|
|
return false;
|
2015-01-11 14:18:40 +01:00
|
|
|
}
|
2014-07-20 12:11:50 +02:00
|
|
|
}
|
|
|
|
|
2014-04-26 01:00:45 -04:00
|
|
|
void System_SendMessage(const char *command, const char *parameter) {
|
|
|
|
if (!strcmp(command, "finish")) {
|
2017-04-15 16:33:30 -07:00
|
|
|
if (!NativeIsRestarting()) {
|
|
|
|
PostMessage(MainWindow::GetHWND(), WM_CLOSE, 0, 0);
|
|
|
|
}
|
|
|
|
} else if (!strcmp(command, "graphics_restart")) {
|
2017-05-21 17:24:40 +02:00
|
|
|
if (IsDebuggerPresent()) {
|
|
|
|
PostMessage(MainWindow::GetHWND(), MainWindow::WM_USER_RESTART_EMUTHREAD, 0, 0);
|
|
|
|
} else {
|
|
|
|
g_Config.bRestartRequired = true;
|
|
|
|
PostMessage(MainWindow::GetHWND(), WM_CLOSE, 0, 0);
|
|
|
|
}
|
2014-07-21 17:36:25 +02:00
|
|
|
} else if (!strcmp(command, "setclipboardtext")) {
|
|
|
|
if (OpenClipboard(MainWindow::GetDisplayHWND())) {
|
|
|
|
std::wstring data = ConvertUTF8ToWString(parameter);
|
|
|
|
HANDLE handle = GlobalAlloc(GMEM_MOVEABLE, (data.size() + 1) * sizeof(wchar_t));
|
|
|
|
wchar_t *wstr = (wchar_t *)GlobalLock(handle);
|
|
|
|
memcpy(wstr, data.c_str(), (data.size() + 1) * sizeof(wchar_t));
|
|
|
|
GlobalUnlock(wstr);
|
|
|
|
SetClipboardData(CF_UNICODETEXT, handle);
|
|
|
|
GlobalFree(handle);
|
|
|
|
CloseClipboard();
|
|
|
|
}
|
2017-04-02 10:50:09 -07:00
|
|
|
} else if (!strcmp(command, "browse_file")) {
|
|
|
|
MainWindow::BrowseAndBoot("");
|
2019-02-17 08:03:10 -08:00
|
|
|
} else if (!strcmp(command, "browse_folder")) {
|
|
|
|
I18NCategory *mm = GetI18NCategory("MainMenu");
|
|
|
|
std::string folder = W32Util::BrowseForFolder(MainWindow::GetHWND(), mm->T("Choose folder"));
|
|
|
|
if (folder.size())
|
|
|
|
NativeMessageReceived("browse_folderSelect", folder.c_str());
|
2017-04-02 10:50:09 -07:00
|
|
|
} else if (!strcmp(command, "bgImage_browse")) {
|
|
|
|
MainWindow::BrowseBackground();
|
2017-07-30 07:51:53 -07:00
|
|
|
} else if (!strcmp(command, "toggle_fullscreen")) {
|
|
|
|
bool flag = !g_Config.bFullScreen;
|
|
|
|
if (strcmp(parameter, "0") == 0) {
|
|
|
|
flag = false;
|
|
|
|
} else if (strcmp(parameter, "1") == 0) {
|
|
|
|
flag = true;
|
|
|
|
}
|
|
|
|
MainWindow::SendToggleFullscreen(flag);
|
2014-04-26 01:00:45 -04:00
|
|
|
}
|
|
|
|
}
|
2013-12-04 17:41:59 +01:00
|
|
|
|
2015-12-17 22:41:50 +01:00
|
|
|
void System_AskForPermission(SystemPermission permission) {}
|
|
|
|
PermissionStatus System_GetPermissionStatus(SystemPermission permission) { return PERMISSION_STATUS_GRANTED; }
|
|
|
|
|
2015-01-17 12:32:58 -08:00
|
|
|
void EnableCrashingOnCrashes() {
|
|
|
|
typedef BOOL (WINAPI *tGetPolicy)(LPDWORD lpFlags);
|
|
|
|
typedef BOOL (WINAPI *tSetPolicy)(DWORD dwFlags);
|
|
|
|
const DWORD EXCEPTION_SWALLOWING = 0x1;
|
|
|
|
|
|
|
|
HMODULE kernel32 = LoadLibrary(L"kernel32.dll");
|
|
|
|
tGetPolicy pGetPolicy = (tGetPolicy)GetProcAddress(kernel32,
|
|
|
|
"GetProcessUserModeExceptionPolicy");
|
|
|
|
tSetPolicy pSetPolicy = (tSetPolicy)GetProcAddress(kernel32,
|
|
|
|
"SetProcessUserModeExceptionPolicy");
|
|
|
|
if (pGetPolicy && pSetPolicy) {
|
|
|
|
DWORD dwFlags;
|
|
|
|
if (pGetPolicy(&dwFlags)) {
|
|
|
|
// Turn off the filter.
|
|
|
|
pSetPolicy(dwFlags & ~EXCEPTION_SWALLOWING);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
FreeLibrary(kernel32);
|
2013-11-13 02:50:35 +10:00
|
|
|
}
|
|
|
|
|
2014-02-15 01:47:14 -08:00
|
|
|
bool System_InputBoxGetString(const char *title, const char *defaultValue, char *outValue, size_t outLength)
|
2013-12-08 20:16:18 +10:00
|
|
|
{
|
|
|
|
std::string out;
|
|
|
|
if (InputBox_GetString(MainWindow::GetHInstance(), MainWindow::GetHWND(), ConvertUTF8ToWString(title).c_str(), defaultValue, out)) {
|
|
|
|
strcpy(outValue, out.c_str());
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool System_InputBoxGetWString(const wchar_t *title, const std::wstring &defaultvalue, std::wstring &outvalue)
|
|
|
|
{
|
|
|
|
if (InputBox_GetWString(MainWindow::GetHInstance(), MainWindow::GetHWND(), title, defaultvalue, outvalue)) {
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-25 19:14:05 -08:00
|
|
|
static std::string GetDefaultLangRegion() {
|
|
|
|
wchar_t lcLangName[256] = {};
|
|
|
|
|
|
|
|
// LOCALE_SNAME is only available in WinVista+
|
|
|
|
if (0 != GetLocaleInfo(LOCALE_NAME_USER_DEFAULT, LOCALE_SNAME, lcLangName, ARRAY_SIZE(lcLangName))) {
|
|
|
|
std::string result = ConvertWStringToUTF8(lcLangName);
|
|
|
|
std::replace(result.begin(), result.end(), '-', '_');
|
|
|
|
return result;
|
|
|
|
} else {
|
|
|
|
// This should work on XP, but we may get numbers for some countries.
|
|
|
|
if (0 != GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, lcLangName, ARRAY_SIZE(lcLangName))) {
|
|
|
|
wchar_t lcRegion[256] = {};
|
|
|
|
if (0 != GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, lcRegion, ARRAY_SIZE(lcRegion))) {
|
|
|
|
return ConvertWStringToUTF8(lcLangName) + "_" + ConvertWStringToUTF8(lcRegion);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Unfortunate default. We tried.
|
|
|
|
return "en_US";
|
|
|
|
}
|
|
|
|
}
|
2014-02-17 03:30:38 -05:00
|
|
|
|
2019-02-16 10:14:54 -08:00
|
|
|
static const int EXIT_CODE_VULKAN_WORKS = 42;
|
|
|
|
|
|
|
|
static bool DetectVulkanInExternalProcess() {
|
2020-01-04 09:02:10 -08:00
|
|
|
std::wstring workingDirectory;
|
|
|
|
std::wstring moduleFilename;
|
|
|
|
W32Util::GetSelfExecuteParams(workingDirectory, moduleFilename);
|
|
|
|
|
2019-02-16 10:14:54 -08:00
|
|
|
const wchar_t *cmdline = L"--vulkan-available-check";
|
|
|
|
|
|
|
|
SHELLEXECUTEINFO info{ sizeof(SHELLEXECUTEINFO) };
|
|
|
|
info.fMask = SEE_MASK_NOCLOSEPROCESS;
|
2020-01-04 09:02:10 -08:00
|
|
|
info.lpFile = moduleFilename.c_str();
|
2019-02-16 10:14:54 -08:00
|
|
|
info.lpParameters = cmdline;
|
2020-01-04 09:02:10 -08:00
|
|
|
info.lpDirectory = workingDirectory.c_str();
|
2019-02-16 10:14:54 -08:00
|
|
|
info.nShow = SW_HIDE;
|
|
|
|
if (ShellExecuteEx(&info) != TRUE) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (info.hProcess == nullptr) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
DWORD result = WaitForSingleObject(info.hProcess, 10000);
|
|
|
|
DWORD exitCode = 0;
|
|
|
|
if (result == WAIT_FAILED || GetExitCodeProcess(info.hProcess, &exitCode) == 0) {
|
|
|
|
CloseHandle(info.hProcess);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
CloseHandle(info.hProcess);
|
|
|
|
|
|
|
|
return exitCode == EXIT_CODE_VULKAN_WORKS;
|
|
|
|
}
|
|
|
|
|
2014-08-31 01:17:25 -04:00
|
|
|
std::vector<std::wstring> GetWideCmdLine() {
|
|
|
|
wchar_t **wargv;
|
|
|
|
int wargc = -1;
|
|
|
|
wargv = CommandLineToArgvW(GetCommandLineW(), &wargc);
|
|
|
|
|
|
|
|
std::vector<std::wstring> wideArgs(wargv, wargv + wargc);
|
2018-01-17 19:25:01 +09:00
|
|
|
LocalFree(wargv);
|
|
|
|
|
2014-08-31 01:17:25 -04:00
|
|
|
return wideArgs;
|
|
|
|
}
|
|
|
|
|
2019-02-16 10:14:54 -08:00
|
|
|
static void WinMainInit() {
|
2015-01-15 22:32:25 +01:00
|
|
|
CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
2017-03-12 17:24:46 +01:00
|
|
|
net::Init(); // This needs to happen before we load the config. So on Windows we also run it in Main. It's fine to call multiple times.
|
2017-03-06 10:51:28 +01:00
|
|
|
|
|
|
|
// Windows, API init stuff
|
|
|
|
INITCOMMONCONTROLSEX comm;
|
|
|
|
comm.dwSize = sizeof(comm);
|
|
|
|
comm.dwICC = ICC_BAR_CLASSES | ICC_LISTVIEW_CLASSES | ICC_TAB_CLASSES;
|
|
|
|
InitCommonControlsEx(&comm);
|
|
|
|
|
|
|
|
EnableCrashingOnCrashes();
|
|
|
|
|
2015-10-04 12:24:59 +02:00
|
|
|
#ifdef _DEBUG
|
2016-02-10 15:22:28 +01:00
|
|
|
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
|
2015-10-04 12:24:59 +02:00
|
|
|
#endif
|
2015-05-12 19:45:14 +02:00
|
|
|
PROFILE_INIT();
|
2014-02-17 03:30:38 -05:00
|
|
|
|
2015-12-22 23:22:16 -08:00
|
|
|
#if defined(_M_X64) && defined(_MSC_VER) && _MSC_VER < 1900
|
2014-02-13 15:57:36 +01:00
|
|
|
// FMA3 support in the 2013 CRT is broken on Vista and Windows 7 RTM (fixed in SP1). Just disable it.
|
|
|
|
_set_FMA3_enable(0);
|
2014-02-13 16:02:10 +01:00
|
|
|
#endif
|
2019-02-16 10:14:54 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void WinMainCleanup() {
|
|
|
|
if (g_Config.bRestartRequired) {
|
|
|
|
W32Util::ExitAndRestart();
|
|
|
|
}
|
|
|
|
|
|
|
|
net::Shutdown();
|
|
|
|
CoUninitialize();
|
|
|
|
}
|
|
|
|
|
|
|
|
int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow) {
|
|
|
|
setCurrentThreadName("Main");
|
|
|
|
|
|
|
|
WinMainInit();
|
2014-02-13 15:57:36 +01:00
|
|
|
|
2013-10-13 12:27:05 -07:00
|
|
|
#ifndef _DEBUG
|
2013-10-15 22:27:03 -07:00
|
|
|
bool showLog = false;
|
2013-10-13 12:27:05 -07:00
|
|
|
#else
|
2015-12-25 19:14:05 -08:00
|
|
|
bool showLog = true;
|
2013-10-13 12:27:05 -07:00
|
|
|
#endif
|
|
|
|
|
2015-10-30 21:04:45 -07:00
|
|
|
const std::string &exePath = File::GetExeDirectory();
|
|
|
|
VFSRegister("", new DirectoryAssetReader((exePath + "/assets/").c_str()));
|
|
|
|
VFSRegister("", new DirectoryAssetReader(exePath.c_str()));
|
2013-09-15 11:02:13 +02:00
|
|
|
|
2015-12-25 19:14:05 -08:00
|
|
|
langRegion = GetDefaultLangRegion();
|
2013-10-09 17:17:28 -04:00
|
|
|
osName = GetWindowsVersion() + " " + GetWindowsSystemArchitecture();
|
|
|
|
|
2018-01-18 00:36:27 +09:00
|
|
|
std::string configFilename = "";
|
2014-08-31 01:17:25 -04:00
|
|
|
const std::wstring configOption = L"--config=";
|
2013-09-15 12:50:42 -04:00
|
|
|
|
2018-01-18 00:36:27 +09:00
|
|
|
std::string controlsConfigFilename = "";
|
2014-08-31 01:17:25 -04:00
|
|
|
const std::wstring controlsOption = L"--controlconfig=";
|
2013-09-15 12:50:42 -04:00
|
|
|
|
2014-08-31 01:17:25 -04:00
|
|
|
std::vector<std::wstring> wideArgs = GetWideCmdLine();
|
|
|
|
|
2014-09-12 16:58:05 -04:00
|
|
|
for (size_t i = 1; i < wideArgs.size(); ++i) {
|
2014-08-31 01:17:25 -04:00
|
|
|
if (wideArgs[i][0] == L'\0')
|
2013-09-15 12:50:42 -04:00
|
|
|
continue;
|
2014-08-31 01:17:25 -04:00
|
|
|
if (wideArgs[i][0] == L'-') {
|
|
|
|
if (wideArgs[i].find(configOption) != std::wstring::npos && wideArgs[i].size() > configOption.size()) {
|
|
|
|
const std::wstring tempWide = wideArgs[i].substr(configOption.size());
|
2018-01-18 00:36:27 +09:00
|
|
|
configFilename = ConvertWStringToUTF8(tempWide);
|
2013-09-15 12:50:42 -04:00
|
|
|
}
|
2014-08-31 01:17:25 -04:00
|
|
|
|
|
|
|
if (wideArgs[i].find(controlsOption) != std::wstring::npos && wideArgs[i].size() > controlsOption.size()) {
|
2014-11-02 20:38:00 +01:00
|
|
|
const std::wstring tempWide = wideArgs[i].substr(controlsOption.size());
|
2018-01-18 00:36:27 +09:00
|
|
|
controlsConfigFilename = ConvertWStringToUTF8(tempWide);
|
2013-09-15 12:50:42 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-06 11:44:35 +01:00
|
|
|
LogManager::Init();
|
|
|
|
|
2013-10-15 02:03:39 -04:00
|
|
|
// On Win32 it makes more sense to initialize the system directories here
|
2013-10-15 02:28:14 -04:00
|
|
|
// because the next place it was called was in the EmuThread, and it's too late by then.
|
2020-01-04 10:57:23 -08:00
|
|
|
g_Config.internalDataDirectory = W32Util::UserDocumentsPath();
|
2013-10-15 02:03:39 -04:00
|
|
|
InitSysDirectories();
|
2013-09-15 12:50:42 -04:00
|
|
|
|
2013-09-12 16:56:18 -04:00
|
|
|
// Load config up here, because those changes below would be overwritten
|
|
|
|
// if it's not loaded here first.
|
2013-10-12 16:02:03 -07:00
|
|
|
g_Config.AddSearchPath("");
|
2013-10-15 02:03:39 -04:00
|
|
|
g_Config.AddSearchPath(GetSysDirectory(DIRECTORY_SYSTEM));
|
|
|
|
g_Config.SetDefaultPath(GetSysDirectory(DIRECTORY_SYSTEM));
|
2018-01-18 00:36:27 +09:00
|
|
|
g_Config.Load(configFilename.c_str(), controlsConfigFilename.c_str());
|
2013-09-12 16:56:18 -04:00
|
|
|
|
2014-03-31 22:44:05 -04:00
|
|
|
bool debugLogLevel = false;
|
|
|
|
|
2014-09-13 01:33:45 -04:00
|
|
|
const std::wstring gpuBackend = L"--graphics=";
|
2014-09-12 16:16:13 -04:00
|
|
|
|
2013-03-31 18:22:27 -07:00
|
|
|
// The rest is handled in NativeInit().
|
2014-09-12 16:58:05 -04:00
|
|
|
for (size_t i = 1; i < wideArgs.size(); ++i) {
|
2014-08-31 01:17:25 -04:00
|
|
|
if (wideArgs[i][0] == L'\0')
|
2012-12-22 09:21:23 -08:00
|
|
|
continue;
|
|
|
|
|
2014-08-31 01:17:25 -04:00
|
|
|
if (wideArgs[i][0] == L'-') {
|
|
|
|
switch (wideArgs[i][1]) {
|
|
|
|
case L'l':
|
2013-10-15 22:27:03 -07:00
|
|
|
showLog = true;
|
2013-10-13 14:25:59 -04:00
|
|
|
g_Config.bEnableLogging = true;
|
2012-12-22 09:21:23 -08:00
|
|
|
break;
|
2014-08-31 01:17:25 -04:00
|
|
|
case L's':
|
2013-01-04 10:26:14 +01:00
|
|
|
g_Config.bAutoRun = false;
|
|
|
|
g_Config.bSaveSettings = false;
|
2012-12-22 09:21:23 -08:00
|
|
|
break;
|
2014-08-31 01:17:25 -04:00
|
|
|
case L'd':
|
2014-03-31 22:44:05 -04:00
|
|
|
debugLogLevel = true;
|
|
|
|
break;
|
2012-12-22 09:21:23 -08:00
|
|
|
}
|
2013-09-12 16:56:18 -04:00
|
|
|
|
2014-08-31 01:17:25 -04:00
|
|
|
if (wideArgs[i] == L"--windowed")
|
2013-09-12 16:56:18 -04:00
|
|
|
g_Config.bFullScreen = false;
|
2014-09-12 16:16:13 -04:00
|
|
|
|
2014-09-12 16:58:05 -04:00
|
|
|
if (wideArgs[i].find(gpuBackend) != std::wstring::npos && wideArgs[i].size() > gpuBackend.size()) {
|
2014-09-12 16:16:13 -04:00
|
|
|
const std::wstring restOfOption = wideArgs[i].substr(gpuBackend.size());
|
|
|
|
|
2014-09-13 01:33:45 -04:00
|
|
|
// Force software rendering off, as picking directx9 or gles implies HW acceleration.
|
|
|
|
// Once software rendering supports Direct3D9/11, we can add more options for software,
|
|
|
|
// such as "software-gles", "software-d3d9", and "software-d3d11", or something similar.
|
|
|
|
// For now, software rendering force-activates OpenGL.
|
|
|
|
if (restOfOption == L"directx9") {
|
2017-12-26 15:55:24 -08:00
|
|
|
g_Config.iGPUBackend = (int)GPUBackend::DIRECT3D9;
|
2014-09-13 01:33:45 -04:00
|
|
|
g_Config.bSoftwareRendering = false;
|
2017-02-16 11:30:58 +01:00
|
|
|
} else if (restOfOption == L"directx11") {
|
2017-12-26 15:55:24 -08:00
|
|
|
g_Config.iGPUBackend = (int)GPUBackend::DIRECT3D11;
|
2017-02-16 11:30:58 +01:00
|
|
|
g_Config.bSoftwareRendering = false;
|
2016-02-13 12:22:06 -08:00
|
|
|
} else if (restOfOption == L"gles") {
|
2017-12-26 15:55:24 -08:00
|
|
|
g_Config.iGPUBackend = (int)GPUBackend::OPENGL;
|
2014-09-13 01:33:45 -04:00
|
|
|
g_Config.bSoftwareRendering = false;
|
2017-02-16 11:30:58 +01:00
|
|
|
} else if (restOfOption == L"vulkan") {
|
2017-12-26 15:55:24 -08:00
|
|
|
g_Config.iGPUBackend = (int)GPUBackend::VULKAN;
|
2017-02-16 11:30:58 +01:00
|
|
|
g_Config.bSoftwareRendering = false;
|
2016-02-13 12:22:06 -08:00
|
|
|
} else if (restOfOption == L"software") {
|
2017-12-26 15:55:24 -08:00
|
|
|
g_Config.iGPUBackend = (int)GPUBackend::OPENGL;
|
2014-09-13 01:33:45 -04:00
|
|
|
g_Config.bSoftwareRendering = true;
|
|
|
|
}
|
2014-09-12 16:16:13 -04:00
|
|
|
}
|
2019-02-16 10:14:54 -08:00
|
|
|
|
|
|
|
// This should only be called by DetectVulkanInExternalProcess().
|
|
|
|
if (wideArgs[i] == L"--vulkan-available-check") {
|
|
|
|
// Just call it, this way it will crash here if it doesn't work.
|
|
|
|
// (this is an external process.)
|
|
|
|
bool result = VulkanMayBeAvailable();
|
|
|
|
|
|
|
|
LogManager::Shutdown();
|
|
|
|
WinMainCleanup();
|
|
|
|
return result ? EXIT_CODE_VULKAN_WORKS : EXIT_FAILURE;
|
|
|
|
}
|
2012-12-22 09:21:23 -08:00
|
|
|
}
|
2012-11-01 16:19:01 +01:00
|
|
|
}
|
2013-10-13 14:25:59 -04:00
|
|
|
#ifdef _DEBUG
|
|
|
|
g_Config.bEnableLogging = true;
|
|
|
|
#endif
|
2012-11-01 16:19:01 +01:00
|
|
|
|
2019-02-16 10:14:54 -08:00
|
|
|
#ifndef _DEBUG
|
|
|
|
// See #11719 - too many Vulkan drivers crash on basic init.
|
2019-06-30 23:45:14 -07:00
|
|
|
if (g_Config.IsBackendEnabled(GPUBackend::VULKAN, false)) {
|
2019-06-22 11:48:36 -07:00
|
|
|
VulkanSetAvailable(DetectVulkanInExternalProcess());
|
|
|
|
}
|
2019-02-16 10:14:54 -08:00
|
|
|
#endif
|
|
|
|
|
2015-12-25 19:18:32 -08:00
|
|
|
if (iCmdShow == SW_MAXIMIZE) {
|
|
|
|
// Consider this to mean --fullscreen.
|
|
|
|
g_Config.bFullScreen = true;
|
|
|
|
}
|
|
|
|
|
2013-10-13 12:27:05 -07:00
|
|
|
// Consider at least the following cases before changing this code:
|
|
|
|
// - By default in Release, the console should be hidden by default even if logging is enabled.
|
|
|
|
// - By default in Debug, the console should be shown by default.
|
|
|
|
// - The -l switch is expected to show the log console, REGARDLESS of config settings.
|
|
|
|
// - It should be possible to log to a file without showing the console.
|
2013-10-15 22:27:03 -07:00
|
|
|
LogManager::GetInstance()->GetConsoleListener()->Init(showLog, 150, 120, "PPSSPP Debug Console");
|
2014-03-31 22:44:05 -04:00
|
|
|
|
|
|
|
if (debugLogLevel)
|
|
|
|
LogManager::GetInstance()->SetAllLogLevels(LogTypes::LDEBUG);
|
2013-06-08 08:32:07 +08:00
|
|
|
|
2017-03-06 10:51:28 +01:00
|
|
|
timeBeginPeriod(1); // TODO: Evaluate if this makes sense to keep.
|
|
|
|
|
2012-11-01 16:19:01 +01:00
|
|
|
MainWindow::Init(_hInstance);
|
|
|
|
|
2013-08-26 19:00:16 +02:00
|
|
|
g_hPopupMenus = LoadMenu(_hInstance, (LPCWSTR)IDR_POPUPMENUS);
|
2012-11-01 16:19:01 +01:00
|
|
|
|
2014-07-17 00:06:52 -04:00
|
|
|
MainWindow::Show(_hInstance);
|
2012-11-01 16:19:01 +01:00
|
|
|
|
|
|
|
HWND hwndMain = MainWindow::GetHWND();
|
2014-06-29 22:13:53 +02:00
|
|
|
HWND hwndDisplay = MainWindow::GetDisplayHWND();
|
2013-06-08 08:32:07 +08:00
|
|
|
|
2012-11-01 16:19:01 +01:00
|
|
|
//initialize custom controls
|
|
|
|
CtrlDisAsmView::init();
|
|
|
|
CtrlMemView::init();
|
|
|
|
CtrlRegisterList::init();
|
2019-05-10 23:25:57 +02:00
|
|
|
#if PPSSPP_API(ANY_GL)
|
2013-09-27 22:41:44 -07:00
|
|
|
CGEDebugger::Init();
|
2019-05-04 06:06:50 +08:00
|
|
|
#endif
|
2012-11-01 16:19:01 +01:00
|
|
|
DialogManager::AddDlg(vfpudlg = new CVFPUDlg(_hInstance, hwndMain, currentDebugMIPS));
|
|
|
|
|
2013-08-26 14:19:46 +02:00
|
|
|
MainWindow::CreateDebugWindows();
|
|
|
|
|
2015-12-25 19:18:32 -08:00
|
|
|
const bool minimized = iCmdShow == SW_MINIMIZE || iCmdShow == SW_SHOWMINIMIZED || iCmdShow == SW_SHOWMINNOACTIVE;
|
|
|
|
if (minimized) {
|
|
|
|
MainWindow::Minimize();
|
|
|
|
}
|
|
|
|
|
2017-12-15 12:40:38 +01:00
|
|
|
// Emu thread (and render thread, if any) is always running!
|
2018-01-16 14:16:56 +01:00
|
|
|
// Only OpenGL uses an externally managed render thread (due to GL's single-threaded context design). Vulkan
|
|
|
|
// manages its own render thread.
|
2018-02-07 15:52:19 +01:00
|
|
|
MainThread_Start(g_Config.iGPUBackend == (int)GPUBackend::OPENGL);
|
2014-03-23 22:18:54 -07:00
|
|
|
InputDevice::BeginPolling();
|
2013-03-29 18:50:08 +01:00
|
|
|
|
2013-06-08 08:32:07 +08:00
|
|
|
HACCEL hAccelTable = LoadAccelerators(_hInstance, (LPCTSTR)IDR_ACCELS);
|
2013-08-14 23:30:50 +02:00
|
|
|
HACCEL hDebugAccelTable = LoadAccelerators(_hInstance, (LPCTSTR)IDR_DEBUGACCELS);
|
2012-12-22 09:21:23 -08:00
|
|
|
|
2012-11-01 16:19:01 +01:00
|
|
|
//so.. we're at the message pump of the GUI thread
|
2013-06-08 08:32:07 +08:00
|
|
|
for (MSG msg; GetMessage(&msg, NULL, 0, 0); ) // for no quit
|
2012-11-01 16:19:01 +01:00
|
|
|
{
|
2013-05-13 16:08:10 +08:00
|
|
|
if (msg.message == WM_KEYDOWN)
|
|
|
|
{
|
|
|
|
//hack to enable/disable menu command accelerate keys
|
|
|
|
MainWindow::UpdateCommands();
|
2016-02-14 22:07:10 +01:00
|
|
|
|
2013-05-13 16:08:10 +08:00
|
|
|
//hack to make it possible to get to main window from floating windows with Esc
|
|
|
|
if (msg.hwnd != hwndMain && msg.wParam == VK_ESCAPE)
|
|
|
|
BringWindowToTop(hwndMain);
|
|
|
|
}
|
2012-11-01 16:19:01 +01:00
|
|
|
|
|
|
|
//Translate accelerators and dialog messages...
|
2013-08-14 23:46:59 +02:00
|
|
|
HWND wnd;
|
|
|
|
HACCEL accel;
|
2013-09-28 14:34:08 +02:00
|
|
|
switch (g_activeWindow)
|
|
|
|
{
|
|
|
|
case WINDOW_MAINWINDOW:
|
2013-08-14 23:46:59 +02:00
|
|
|
wnd = hwndMain;
|
|
|
|
accel = hAccelTable;
|
2013-09-28 14:34:08 +02:00
|
|
|
break;
|
|
|
|
case WINDOW_CPUDEBUGGER:
|
2014-02-14 21:17:36 -08:00
|
|
|
wnd = disasmWindow[0] ? disasmWindow[0]->GetDlgHandle() : 0;
|
2013-09-28 14:34:08 +02:00
|
|
|
accel = hDebugAccelTable;
|
|
|
|
break;
|
|
|
|
case WINDOW_GEDEBUGGER:
|
|
|
|
default:
|
|
|
|
wnd = 0;
|
|
|
|
accel = 0;
|
|
|
|
break;
|
2013-08-14 23:46:59 +02:00
|
|
|
}
|
|
|
|
|
2018-02-10 09:06:43 +01:00
|
|
|
if (!TranslateAccelerator(wnd, accel, &msg)) {
|
|
|
|
if (!DialogManager::IsDialogMessage(&msg)) {
|
2012-11-01 16:19:01 +01:00
|
|
|
//and finally translate and dispatch
|
|
|
|
TranslateMessage(&msg);
|
|
|
|
DispatchMessage(&msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-10 09:06:43 +01:00
|
|
|
MainThread_Stop();
|
|
|
|
|
2013-02-08 10:35:05 -08:00
|
|
|
VFSShutdown();
|
|
|
|
|
2014-02-14 21:17:36 -08:00
|
|
|
MainWindow::DestroyDebugWindows();
|
2012-11-01 16:19:01 +01:00
|
|
|
DialogManager::DestroyAll();
|
2012-12-03 16:44:37 +08:00
|
|
|
timeEndPeriod(1);
|
2014-09-14 06:59:27 -04:00
|
|
|
|
2013-06-26 00:31:52 -07:00
|
|
|
LogManager::Shutdown();
|
2019-02-16 10:14:54 -08:00
|
|
|
WinMainCleanup();
|
2015-10-04 12:24:59 +02:00
|
|
|
|
2012-11-01 16:19:01 +01:00
|
|
|
return 0;
|
|
|
|
}
|