Skip to content

Commit

Permalink
File associations & icons on Windows, use a manifest for themed dialogs
Browse files Browse the repository at this point in the history
  • Loading branch information
LIJI32 committed Nov 15, 2024
1 parent 6568cca commit fc76063
Show file tree
Hide file tree
Showing 10 changed files with 178 additions and 3 deletions.
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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),)
Expand Down
4 changes: 3 additions & 1 deletion SDL/configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,6 @@ typedef struct {
bool osd;

struct __attribute__((packed, aligned(4))) {

/* v0.15 */
bool allow_mouse_controls;
uint8_t cgb_revision;
Expand All @@ -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;

Expand Down
29 changes: 28 additions & 1 deletion SDL/gui.c
Original file line number Diff line number Diff line change
Expand Up @@ -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];

Expand Down Expand Up @@ -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;
Expand Down
31 changes: 31 additions & 0 deletions SDL/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <fcntl.h>
#else
#include <Windows.h>
#include <associations.h>
#endif

static bool stop_on_start = false;
Expand Down Expand Up @@ -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);
Expand Down
Binary file added Windows/Cartridge.ico
Binary file not shown.
Binary file added Windows/ColorCartridge.ico
Binary file not shown.
90 changes: 90 additions & 0 deletions Windows/associations.c
Original file line number Diff line number Diff line change
@@ -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 changes: 2 additions & 0 deletions Windows/associations.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#include <stdbool.h>
bool GB_do_windows_association(void);
22 changes: 22 additions & 0 deletions Windows/manifest.xml
Original file line number Diff line number Diff line change
@@ -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 modified Windows/resources.rc
Binary file not shown.

0 comments on commit fc76063

Please sign in to comment.