Move the non-working "Create desktop shortcut" stuff to the request framework

This commit is contained in:
Henrik Rydgård 2023-03-24 20:05:48 +01:00
parent e71be8af2e
commit a73ac49d59
10 changed files with 93 additions and 79 deletions

View file

@ -1,6 +1,7 @@
#include "Common/System/Request.h" #include "Common/System/Request.h"
#include "Common/System/System.h" #include "Common/System/System.h"
#include "Common/Log.h" #include "Common/Log.h"
#include "Common/File/Path.h"
RequestManager g_requestManager; RequestManager g_requestManager;
@ -80,3 +81,7 @@ void RequestManager::Clear() {
pendingResponses_.clear(); pendingResponses_.clear();
callbackMap_.clear(); callbackMap_.clear();
} }
void System_CreateGameShortcut(const Path &path, const std::string &title) {
g_requestManager.MakeSystemRequest(SystemRequestType::CREATE_GAME_SHORTCUT, nullptr, path.ToString(), title, 0);
}

View file

@ -7,6 +7,8 @@
#include "Common/System/System.h" #include "Common/System/System.h"
class Path;
typedef std::function<void(const char *responseString, int responseValue)> RequestCallback; typedef std::function<void(const char *responseString, int responseValue)> RequestCallback;
// Platforms often have to process requests asynchronously, on wildly different threads. // Platforms often have to process requests asynchronously, on wildly different threads.
@ -125,3 +127,6 @@ inline void System_NotifyUIState(const std::string &state) {
inline void System_SetWindowTitle(const std::string &param) { inline void System_SetWindowTitle(const std::string &param) {
g_requestManager.MakeSystemRequest(SystemRequestType::SET_WINDOW_TITLE, nullptr, param, "", 0); g_requestManager.MakeSystemRequest(SystemRequestType::SET_WINDOW_TITLE, nullptr, param, "", 0);
} }
// Non-inline to avoid including Path.h
void System_CreateGameShortcut(const Path &path, const std::string &title);

View file

@ -68,6 +68,7 @@ enum class SystemRequestType {
SET_WINDOW_TITLE, SET_WINDOW_TITLE,
TOGGLE_FULLSCREEN_STATE, TOGGLE_FULLSCREEN_STATE,
GRAPHICS_BACKEND_FAILED_ALERT, GRAPHICS_BACKEND_FAILED_ALERT,
CREATE_GAME_SHORTCUT,
NOTIFY_UI_STATE, // Used on Android only. Not a SystemNotification since it takes a parameter. NOTIFY_UI_STATE, // Used on Android only. Not a SystemNotification since it takes a parameter.

View file

@ -30,8 +30,6 @@ public:
virtual void UpdateSound() {} // still needed for libretro, will need a proper effort. virtual void UpdateSound() {} // still needed for libretro, will need a proper effort.
virtual void ToggleDebugConsoleVisibility() {} virtual void ToggleDebugConsoleVisibility() {}
virtual bool CreateDesktopShortcut(std::string argumentPath, std::string title) {return false;}
virtual void NotifyUserMessage(const std::string &message, float duration = 1.0f, u32 color = 0x00FFFFFF, const char *id = nullptr) {} virtual void NotifyUserMessage(const std::string &message, float duration = 1.0f, u32 color = 0x00FFFFFF, const char *id = nullptr) {}
virtual void SendUIMessage(const std::string &message, const std::string &value) {} virtual void SendUIMessage(const std::string &message, const std::string &value) {}

View file

@ -29,6 +29,7 @@
#include "Common/File/FileUtil.h" #include "Common/File/FileUtil.h"
#include "Common/StringUtils.h" #include "Common/StringUtils.h"
#include "Common/System/System.h" #include "Common/System/System.h"
#include "Common/System/Request.h"
#include "Common/System/NativeApp.h" #include "Common/System/NativeApp.h"
#include "Core/Host.h" #include "Core/Host.h"
#include "Core/Config.h" #include "Core/Config.h"
@ -417,7 +418,7 @@ void GameScreen::CallbackDeleteGame(bool yes) {
UI::EventReturn GameScreen::OnCreateShortcut(UI::EventParams &e) { UI::EventReturn GameScreen::OnCreateShortcut(UI::EventParams &e) {
std::shared_ptr<GameInfo> info = g_gameInfoCache->GetInfo(NULL, gamePath_, 0); std::shared_ptr<GameInfo> info = g_gameInfoCache->GetInfo(NULL, gamePath_, 0);
if (info) { if (info) {
host->CreateDesktopShortcut(gamePath_.ToString(), info->GetTitle()); System_CreateGameShortcut(gamePath_, info->GetTitle());
} }
return UI::EVENT_DONE; return UI::EVENT_DONE;
} }

View file

@ -216,4 +216,79 @@ namespace W32Util
PostMessage(parent_, completeMsg_, 0, 0); PostMessage(parent_, completeMsg_, 0, 0);
} }
// http://msdn.microsoft.com/en-us/library/aa969393.aspx
HRESULT CreateLink(LPCWSTR lpszPathObj, LPCWSTR lpszArguments, LPCWSTR lpszPathLink, LPCWSTR lpszDesc) {
HRESULT hres;
IShellLink *psl = nullptr;
hres = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (FAILED(hres))
return hres;
// Get a pointer to the IShellLink interface. It is assumed that CoInitialize
// has already been called.
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID *)&psl);
if (SUCCEEDED(hres) && psl) {
IPersistFile *ppf = nullptr;
// Set the path to the shortcut target and add the description.
psl->SetPath(lpszPathObj);
psl->SetArguments(lpszArguments);
psl->SetDescription(lpszDesc);
// Query IShellLink for the IPersistFile interface, used for saving the
// shortcut in persistent storage.
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID *)&ppf);
if (SUCCEEDED(hres) && ppf) {
// Save the link by calling IPersistFile::Save.
hres = ppf->Save(lpszPathLink, TRUE);
ppf->Release();
}
psl->Release();
}
CoUninitialize();
return hres;
} }
bool CreateDesktopShortcut(const std::string &argumentPath, std::string gameTitle) {
// TODO: not working correctly
return false;
// Get the desktop folder
// TODO: Not long path safe.
wchar_t *pathbuf = new wchar_t[MAX_PATH + gameTitle.size() + 100];
SHGetFolderPath(0, CSIDL_DESKTOPDIRECTORY, NULL, SHGFP_TYPE_CURRENT, pathbuf);
// Sanitize the game title for banned characters.
const char bannedChars[] = "<>:\"/\\|?*";
for (size_t i = 0; i < gameTitle.size(); i++) {
for (char c : bannedChars) {
if (gameTitle[i] == c) {
gameTitle[i] = '_';
break;
}
}
}
wcscat(pathbuf, L"\\");
wcscat(pathbuf, ConvertUTF8ToWString(gameTitle).c_str());
std::wstring moduleFilename;
size_t sz;
do {
moduleFilename.resize(moduleFilename.size() + MAX_PATH);
// On failure, this will return the same value as passed in, but success will always be one lower.
sz = GetModuleFileName(nullptr, &moduleFilename[0], (DWORD)moduleFilename.size());
} while (sz >= moduleFilename.size());
moduleFilename.resize(sz);
CreateLink(moduleFilename.c_str(), ConvertUTF8ToWString(argumentPath).c_str(), pathbuf, ConvertUTF8ToWString(gameTitle).c_str());
delete[] pathbuf;
return false;
}
} // namespace

View file

@ -51,4 +51,6 @@ namespace W32Util
bool result_; bool result_;
std::string filename_; std::string filename_;
}; };
bool CreateDesktopShortcut(const std::string &argumentPath, std::string gameTitle);
} }

View file

@ -154,80 +154,6 @@ void WindowsInputManager::PollControllers() {
HLEPlugins::PluginDataAxis[JOYSTICK_AXIS_MOUSE_REL_Y] = mouseDeltaY_; HLEPlugins::PluginDataAxis[JOYSTICK_AXIS_MOUSE_REL_Y] = mouseDeltaY_;
} }
// http://msdn.microsoft.com/en-us/library/aa969393.aspx
HRESULT CreateLink(LPCWSTR lpszPathObj, LPCWSTR lpszArguments, LPCWSTR lpszPathLink, LPCWSTR lpszDesc) {
HRESULT hres;
IShellLink *psl = nullptr;
hres = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (FAILED(hres))
return hres;
// Get a pointer to the IShellLink interface. It is assumed that CoInitialize
// has already been called.
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
if (SUCCEEDED(hres) && psl) {
IPersistFile *ppf = nullptr;
// Set the path to the shortcut target and add the description.
psl->SetPath(lpszPathObj);
psl->SetArguments(lpszArguments);
psl->SetDescription(lpszDesc);
// Query IShellLink for the IPersistFile interface, used for saving the
// shortcut in persistent storage.
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
if (SUCCEEDED(hres) && ppf) {
// Save the link by calling IPersistFile::Save.
hres = ppf->Save(lpszPathLink, TRUE);
ppf->Release();
}
psl->Release();
}
CoUninitialize();
return hres;
}
bool WindowsHost::CreateDesktopShortcut(std::string argumentPath, std::string gameTitle) {
// TODO: not working correctly
return false;
// Get the desktop folder
// TODO: Not long path safe.
wchar_t *pathbuf = new wchar_t[MAX_PATH + gameTitle.size() + 100];
SHGetFolderPath(0, CSIDL_DESKTOPDIRECTORY, NULL, SHGFP_TYPE_CURRENT, pathbuf);
// Sanitize the game title for banned characters.
const char bannedChars[] = "<>:\"/\\|?*";
for (size_t i = 0; i < gameTitle.size(); i++) {
for (char c : bannedChars) {
if (gameTitle[i] == c) {
gameTitle[i] = '_';
break;
}
}
}
wcscat(pathbuf, L"\\");
wcscat(pathbuf, ConvertUTF8ToWString(gameTitle).c_str());
std::wstring moduleFilename;
size_t sz;
do {
moduleFilename.resize(moduleFilename.size() + MAX_PATH);
// On failure, this will return the same value as passed in, but success will always be one lower.
sz = GetModuleFileName(nullptr, &moduleFilename[0], (DWORD)moduleFilename.size());
} while (sz >= moduleFilename.size());
moduleFilename.resize(sz);
CreateLink(moduleFilename.c_str(), ConvertUTF8ToWString(argumentPath).c_str(), pathbuf, ConvertUTF8ToWString(gameTitle).c_str());
delete [] pathbuf;
return false;
}
void WindowsHost::ToggleDebugConsoleVisibility() { void WindowsHost::ToggleDebugConsoleVisibility() {
MainWindow::ToggleDebugConsoleVisibility(); MainWindow::ToggleDebugConsoleVisibility();
} }

View file

@ -31,8 +31,6 @@ public:
void ToggleDebugConsoleVisibility() override; void ToggleDebugConsoleVisibility() override;
bool CreateDesktopShortcut(std::string argumentPath, std::string title) override;
void NotifyUserMessage(const std::string &message, float duration = 1.0f, u32 color = 0x00FFFFFF, const char *id = nullptr) override; void NotifyUserMessage(const std::string &message, float duration = 1.0f, u32 color = 0x00FFFFFF, const char *id = nullptr) override;
private: private:

View file

@ -587,6 +587,9 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string
MessageBox(MainWindow::GetHWND(), full_error.c_str(), title.c_str(), MB_OK); MessageBox(MainWindow::GetHWND(), full_error.c_str(), title.c_str(), MB_OK);
return true; return true;
} }
case SystemRequestType::CREATE_GAME_SHORTCUT:
// This is not actually working, but ported it to the request framework anyway.
return W32Util::CreateDesktopShortcut(param1, param2);
default: default:
return false; return false;
} }