File associations & icons on Windows, use a manifest for themed dialogs

This commit is contained in:
Lior Halphon 2024-11-15 16:17:42 +02:00
parent 6568cca6bb
commit fc76063ec0
10 changed files with 178 additions and 3 deletions

View File

@ -263,7 +263,8 @@ endif
ifeq ($(PLATFORM),windows32)
CFLAGS += -IWindows -Drandom=rand --target=x86_64-pc-windows
LDFLAGS += -lmsvcrt -lcomdlg32 -luser32 -lshell32 -lole32 -lSDL2main -Wl,/MANIFESTFILE:NUL --target=x86_64-pc-windows
LDFLAGS += -lmsvcrt -lcomdlg32 -luser32 -lshell32 -lole32 -ladvapi32 -lSDL2main -Wl,/MANIFESTFILE:NUL --target=x86_64-pc-windows
SDL_LDFLAGS := -lSDL2
GL_LDFLAGS := -lopengl32
ifneq ($(REDIST_XAUDIO),)

View File

@ -143,7 +143,6 @@ typedef struct {
bool osd;
struct __attribute__((packed, aligned(4))) {
/* v0.15 */
bool allow_mouse_controls;
uint8_t cgb_revision;
@ -155,6 +154,9 @@ typedef struct {
char dmg_palette_name[25];
hotkey_action_t hotkey_actions[2];
uint16_t agb_revision;
/* v1.0 */
bool windows_associations_prompted; // Windows only
};
} configuration_t;

View File

@ -11,6 +11,10 @@
#include "font.h"
#include "audio/audio.h"
#ifdef _WIN32
#include <associations.h>
#endif
static const SDL_Color gui_palette[4] = {{8, 24, 16,}, {57, 97, 57,}, {132, 165, 99}, {198, 222, 140}};
static uint32_t gui_palette_native[4];
@ -399,15 +403,38 @@ static void return_to_root_menu(unsigned index)
recalculate_menu_height();
}
static const struct menu_item options_menu[] = {
#ifdef _WIN32
static void associate_rom_files(unsigned index);
#endif
static
#ifndef _WIN32
const
#endif
struct menu_item options_menu[] = {
{"Emulation Options", enter_emulation_menu},
{"Graphic Options", enter_graphics_menu},
{"Audio Options", enter_audio_menu},
{"Control Options", enter_controls_menu},
#ifdef _WIN32
{"Associate ROM Files", associate_rom_files},
#endif
{"Back", return_to_root_menu},
{NULL,}
};
#ifdef _WIN32
static void associate_rom_files(unsigned index)
{
if (GB_do_windows_association()) {
options_menu[index].string = "ROM Files Associated";
}
else {
options_menu[index].string = "Files Association Failed";
}
}
#endif
static void enter_options_menu(unsigned index)
{
current_menu = options_menu;

View File

@ -18,6 +18,7 @@
#include <fcntl.h>
#else
#include <Windows.h>
#include <associations.h>
#endif
static bool stop_on_start = false;
@ -1253,6 +1254,36 @@ int main(int argc, char **argv)
}
update_viewport();
#ifdef _WIN32
if (!configuration.windows_associations_prompted) {
configuration.windows_associations_prompted = true;
save_configuration();
SDL_MessageBoxButtonData buttons[2] = {
{
.flags = SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT,
.buttonid = 0,
.text = "No",
},
{
.flags = SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT,
.buttonid = 1,
.text = "Yes",
},
};
SDL_MessageBoxData box = {
.title = "Associate SameBoy with Game Boy ROMs",
.message = "Would you like to associate SameBoy with Game Boy ROMs?\nThis can be also done later in the Options menu.",
.numbuttons = 2,
.buttons = buttons,
};
int button;
SDL_ShowMessageBox(&box, &button);
if (button) {
GB_do_windows_association();
}
}
#endif
if (filename == NULL) {
stop_on_start = false;
run_gui(false);

BIN
Windows/Cartridge.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 KiB

BIN
Windows/ColorCartridge.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

90
Windows/associations.c Executable file
View File

@ -0,0 +1,90 @@
#include <windows.h>
#include <shlobj.h>
#include <stdbool.h>
#include "associations.h"
static bool set_registry_string(HKEY hive, const char *folder, const char *name, const char *value)
{
HKEY hkey;
LONG status = RegCreateKeyExA(hive, folder, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
if (status != ERROR_SUCCESS || hkey == NULL) {
return false;
}
status = RegSetValueExA(hkey, name, 0, REG_SZ, (void *)value, strlen(value) + 1);
RegCloseKey(hkey);
return status == ERROR_SUCCESS;
}
static bool delete_registry_key(HKEY hive, const char *folder, const char *name)
{
HKEY hkey;
LONG status = RegCreateKeyExA(hive, folder, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
if (status != ERROR_SUCCESS || hkey == NULL) {
return false;
}
status = RegDeleteTreeA(hkey, name);
RegCloseKey(hkey);
return status == ERROR_SUCCESS;
}
static bool set_registry_string_unicode(HKEY hive, const char *folder, const char *name, const wchar_t *value)
{
HKEY hkey;
LONG status = RegCreateKeyExA(hive, folder, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
if (status != ERROR_SUCCESS || hkey == NULL) {
return false;
}
wchar_t wide_name[strlen(name) + 1];
MultiByteToWideChar(CP_UTF8, 0, name, -1, wide_name, sizeof(wide_name) / sizeof(wide_name[0]));
status = RegSetValueExW(hkey, wide_name, 0, REG_SZ, (void *)value, (wcslen(value) + 1) * 2);
RegCloseKey(hkey);
return status == ERROR_SUCCESS;
}
static bool associate(const char *extension, const char *class, const char *description, signed icon)
{
char path[128] = "Software\\Classes\\";
strcat(path, extension);
if (!set_registry_string(HKEY_CURRENT_USER, path, "", class)) return false;
strcpy(path, "Software\\Classes\\");
strcat(path, class);
if (!set_registry_string(HKEY_CURRENT_USER, path, "", description)) return false;
strcat(path, "\\shell\\open\\command");
wchar_t exe[MAX_PATH];
GetModuleFileNameW(NULL, exe, MAX_PATH);
wchar_t temp[sizeof(exe) + 32];
wsprintfW(temp, L"\"\%s\" \"%%1\"", exe);
if (!set_registry_string_unicode(HKEY_CURRENT_USER, path, "", temp)) return false;
strcpy(path, "Software\\Classes\\");
strcat(path, class);
strcat(path, "\\DefaultIcon");
wsprintfW(temp, L"\%s,%d", exe, icon);
if (!set_registry_string_unicode(HKEY_CURRENT_USER, path, "", temp)) return false;
strcpy(path, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\");
strcat(path, extension);
delete_registry_key(HKEY_CURRENT_USER, path, "UserChoice"); // Might not exist, do not check return value
return true;
}
bool GB_do_windows_association(void)
{
bool ret = true;
ret &= associate(".gb", "SameBoy.gb", "Game Boy Game", 1);
ret &= associate(".gbc", "SameBoy.gbc", "Game Boy Color Game", 2);
ret &= associate(".isx", "SameBoy.isx", "Game Boy ISX File", 2);
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
return ret;
}

2
Windows/associations.h Executable file
View File

@ -0,0 +1,2 @@
#include <stdbool.h>
bool GB_do_windows_association(void);

22
Windows/manifest.xml Normal file
View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
version="1.0.0.0"
processorArchitecture="*"
name="com.github.liji32.sameboy.windows"
type="win32"
/>
<description>SameBoy</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
</assembly>

Binary file not shown.