SameBoy | Accurate GB/GBC emulator |
| download: https://git.y1.nz/archives/sameboy.tar.gz | |
| README | Files | Log | Refs | LICENSE |
commit fc76063ec0e36faedc2858ed5c73abdaa7b6c57a parent 6568cca6bbe02b18e49bd2e637fab18f4acf55de Author: Lior Halphon <LIJI32@gmail.com> Date: Fri, 15 Nov 2024 16:17:42 +0200 File associations & icons on Windows, use a manifest for themed dialogs Diffstat:
| M | Makefile | 3 | ++- |
| M | SDL/configuration.h | 4 | +++- |
| M | SDL/gui.c | 29 | ++++++++++++++++++++++++++++- |
| M | SDL/main.c | 31 | +++++++++++++++++++++++++++++++ |
| A | Windows/Cartridge.ico | 0 | |
| A | Windows/ColorCartridge.ico | 0 | |
| A | Windows/associations.c | 90 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | Windows/associations.h | 2 | ++ |
| A | Windows/manifest.xml | 22 | ++++++++++++++++++++++ |
| M | Windows/resources.rc | 0 |
10 files changed, 178 insertions(+), 3 deletions(-)
diff --git a/Makefile b/Makefile @@ -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),) diff --git a/SDL/configuration.h b/SDL/configuration.h @@ -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; diff --git a/SDL/gui.c b/SDL/gui.c @@ -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; diff --git a/SDL/main.c b/SDL/main.c @@ -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); diff --git a/Windows/Cartridge.ico b/Windows/Cartridge.ico Binary files differ. diff --git a/Windows/ColorCartridge.ico b/Windows/ColorCartridge.ico Binary files differ. diff --git a/Windows/associations.c b/Windows/associations.c @@ -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; +} diff --git a/Windows/associations.h b/Windows/associations.h @@ -0,0 +1,2 @@ +#include <stdbool.h> +bool GB_do_windows_association(void); diff --git a/Windows/manifest.xml b/Windows/manifest.xml @@ -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> diff --git a/Windows/resources.rc b/Windows/resources.rc Binary files differ.
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.