1 #include "discord_rpc.h"
2
3 #define WIN32_LEAN_AND_MEAN
4 #define NOMCX
5 #define NOSERVICE
6 #define NOIME
7 #include <windows.h>
8 #include <psapi.h>
9 #include <wchar.h>
10 #include <stdio.h>
11
get_process_id(void)12 int get_process_id(void)
13 {
14 return (int)GetCurrentProcessId();
15 }
16
17 /**
18 * Updated fixes for MinGW and WinXP
19 * This block is written the way it does not involve changing the rest of the code
20 * Checked to be compiling
21 * 1) strsafe.h belongs to Windows SDK and cannot be added to MinGW
22 * #include guarded, functions redirected to <string.h> substitutes
23 * 2) RegSetKeyValueW and LSTATUS are not declared in <winreg.h>
24 * The entire function is rewritten
25 */
26 #ifdef __MINGW32__
27 /* strsafe.h fixes */
StringCbPrintfW(LPWSTR pszDest,size_t cbDest,LPCWSTR pszFormat,...)28 static HRESULT StringCbPrintfW(LPWSTR pszDest,
29 size_t cbDest, LPCWSTR pszFormat, ...)
30 {
31 HRESULT ret;
32 va_list va;
33 va_start(va, pszFormat);
34 cbDest /= 2; /* Size is divided by 2 to convert from bytes to wide characters - causes segfault */
35 /* othervise */
36 ret = vsnwprintf(pszDest, cbDest, pszFormat, va);
37 pszDest[cbDest - 1] = 0; /* Terminate the string in case a buffer overflow; -1 will be returned */
38 va_end(va);
39 return ret;
40 }
41 #else
42 #include <strsafe.h>
43 #endif /* __MINGW32__ */
44
45 /* winreg.h fixes */
46 #ifndef LSTATUS
47 #define LSTATUS LONG
48 #endif
49 #ifdef RegSetKeyValueW
50 #undefine RegSetKeyValueW
51 #endif
52 #define RegSetKeyValueW regset
regset(HKEY hkey,LPCWSTR subkey,LPCWSTR name,DWORD type,const void * data,DWORD len)53 static LSTATUS regset(HKEY hkey,
54 LPCWSTR subkey,
55 LPCWSTR name,
56 DWORD type,
57 const void* data,
58 DWORD len)
59 {
60 LSTATUS ret;
61 HKEY htkey = hkey, hsubkey = NULL;
62 if (subkey && subkey[0])
63 {
64 if ((ret = RegCreateKeyExW(hkey, subkey, 0, 0, 0, KEY_ALL_ACCESS, 0, &hsubkey, 0)) !=
65 ERROR_SUCCESS)
66 return ret;
67 htkey = hsubkey;
68 }
69 ret = RegSetValueExW(htkey, name, 0, type, (const BYTE*)data, len);
70 if (hsubkey && hsubkey != hkey)
71 RegCloseKey(hsubkey);
72 return ret;
73 }
74
Discord_RegisterW(const wchar_t * applicationId,const wchar_t * command)75 static void Discord_RegisterW(
76 const wchar_t* applicationId, const wchar_t* command)
77 {
78 /* https://msdn.microsoft.com/en-us/library/aa767914(v=vs.85).aspx
79 * we want to register games so we can run them as discord-<appid>://
80 * Update the HKEY_CURRENT_USER, because it doesn't seem to require special permissions. */
81
82 DWORD len;
83 LSTATUS result;
84 wchar_t urlProtocol = 0;
85 wchar_t keyName[256];
86 wchar_t protocolName[64];
87 wchar_t protocolDescription[128];
88 wchar_t exeFilePath[MAX_PATH];
89 DWORD exeLen = GetModuleFileNameW(NULL, exeFilePath, MAX_PATH);
90 wchar_t openCommand[1024];
91
92 if (command && command[0])
93 StringCbPrintfW(openCommand, sizeof(openCommand), L"%S", command);
94 else
95 StringCbPrintfW(openCommand, sizeof(openCommand), L"%S", exeFilePath);
96
97 StringCbPrintfW(protocolName, sizeof(protocolName),
98 L"discord-%S", applicationId);
99 StringCbPrintfW(
100 protocolDescription, sizeof(protocolDescription),
101 L"URL:Run game %S protocol", applicationId);
102 StringCbPrintfW(keyName, sizeof(keyName), L"Software\\Classes\\%S", protocolName);
103 HKEY key;
104 LSTATUS status =
105 RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, NULL, 0, KEY_WRITE, NULL, &key, NULL);
106 if (status != ERROR_SUCCESS)
107 {
108 fprintf(stderr, "Error creating key\n");
109 return;
110 }
111 len = (DWORD)lstrlenW(protocolDescription) + 1;
112 result =
113 RegSetKeyValueW(key, NULL, NULL, REG_SZ, protocolDescription, len * sizeof(wchar_t));
114 if (FAILED(result))
115 fprintf(stderr, "Error writing description\n");
116
117 len = (DWORD)lstrlenW(protocolDescription) + 1;
118 result = RegSetKeyValueW(key, NULL, L"URL Protocol", REG_SZ, &urlProtocol, sizeof(wchar_t));
119 if (FAILED(result))
120 fprintf(stderr, "Error writing description\n");
121
122 result = RegSetKeyValueW(
123 key, L"DefaultIcon", NULL, REG_SZ, exeFilePath, (exeLen + 1) * sizeof(wchar_t));
124 if (FAILED(result))
125 fprintf(stderr, "Error writing icon\n");
126
127 len = (DWORD)lstrlenW(openCommand) + 1;
128 result = RegSetKeyValueW(
129 key, L"shell\\open\\command", NULL, REG_SZ, openCommand, len * sizeof(wchar_t));
130 if (FAILED(result))
131 fprintf(stderr, "Error writing command\n");
132 RegCloseKey(key);
133 }
134
Discord_Register(const char * applicationId,const char * command)135 void Discord_Register(const char* applicationId, const char* command)
136 {
137 wchar_t appId[32];
138 wchar_t openCommand[1024];
139 const wchar_t* wcommand = NULL;
140
141 MultiByteToWideChar(CP_UTF8, 0, applicationId, -1, appId, 32);
142
143 if (command && command[0])
144 {
145 const int commandBufferLen =
146 sizeof(openCommand) / sizeof(*openCommand);
147 MultiByteToWideChar(CP_UTF8, 0, command, -1,
148 openCommand, commandBufferLen);
149 wcommand = openCommand;
150 }
151
152 Discord_RegisterW(appId, wcommand);
153 }
154
Discord_RegisterSteamGame(const char * applicationId,const char * steamId)155 void Discord_RegisterSteamGame(
156 const char* applicationId,
157 const char* steamId)
158 {
159 DWORD pathChars, pathBytes, i;
160 HKEY key;
161 wchar_t steamPath[MAX_PATH];
162 wchar_t command[1024];
163 wchar_t appId[32];
164 wchar_t wSteamId[32];
165 MultiByteToWideChar(CP_UTF8, 0, applicationId, -1, appId, 32);
166 MultiByteToWideChar(CP_UTF8, 0, steamId, -1, wSteamId, 32);
167 LSTATUS status = RegOpenKeyExW(HKEY_CURRENT_USER,
168 L"Software\\Valve\\Steam", 0, KEY_READ, &key);
169 if (status != ERROR_SUCCESS)
170 {
171 fprintf(stderr, "Error opening Steam key\n");
172 return;
173 }
174
175 pathBytes = sizeof(steamPath);
176 status = RegQueryValueExW(key,
177 L"SteamExe", NULL, NULL, (BYTE*)steamPath, &pathBytes);
178 RegCloseKey(key);
179 if (status != ERROR_SUCCESS || pathBytes < 1)
180 {
181 fprintf(stderr, "Error reading SteamExe key\n");
182 return;
183 }
184
185 pathChars = pathBytes / sizeof(wchar_t);
186 for (i = 0; i < pathChars; ++i)
187 {
188 if (steamPath[i] == L'/')
189 steamPath[i] = L'\\';
190 }
191
192 StringCbPrintfW(command, sizeof(command),
193 L"\"%s\" steam://rungameid/%s", steamPath, wSteamId);
194
195 Discord_RegisterW(appId, command);
196 }
197