Closed k1-801 closed 6 years ago
Made a pull request with these patches in hope it helps.
What compile options make this work? Here is my attempt:
MINGW32 /r/discord-rpc/build
$ cmake ..
-- The C compiler identification is GNU 7.2.0
-- The CXX compiler identification is GNU 7.2.0
-- Check for working C compiler: /mingw32/bin/cc.exe
-- Check for working C compiler: /mingw32/bin/cc.exe -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /mingw32/bin/c++.exe
-- Check for working CXX compiler: /mingw32/bin/c++.exe -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
no rapidjson, download
-- Configuring done
-- Generating done
-- Build files have been written to: /r/discord-rpc/build
MINGW32 /r/discord-rpc/build
$ cmake --build . --target install
Scanning dependencies of target discord-rpc
[ 12%] Building CXX object src/CMakeFiles/discord-rpc.dir/discord-rpc.cpp.o
[ 25%] Building CXX object src/CMakeFiles/discord-rpc.dir/rpc_connection.cpp.o
[ 37%] Building CXX object src/CMakeFiles/discord-rpc.dir/serialization.cpp.o
[ 50%] Building CXX object src/CMakeFiles/discord-rpc.dir/connection_unix.cpp.o
R:/discord-rpc/src/connection_unix.cpp:7:10: fatal error: sys/socket.h: No such file or directory
#include <sys/socket.h>
^~~~~~~~~~~~~~
compilation terminated.
make[2]: *** [src/CMakeFiles/discord-rpc.dir/build.make:135: src/CMakeFiles/discord-rpc.dir/connection_unix.cpp.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:86: src/CMakeFiles/discord-rpc.dir/all] Error 2
make: *** [Makefile:130: all] Error 2
It seems it thinks my target is Unix and not Windows. Looks like I will have to hack up the CMakeLists to give me GCC compile flags for a Windows target.
I used codeblocks to compile this, so I'm not sure about cmake. When this problem appeared, I simply removed unix and linux files from compilation lists and it worked. Also, mingw segfaults on empty {} in initialization list sometimes, probably a weird mingw/gcc bug.
I made this quick change:
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index c3dab48..9fa12f6 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -59,15 +59,18 @@ if(WIN32)
endif(WIN32)
if(UNIX)
- set(BASE_RPC_SRC ${BASE_RPC_SRC} connection_unix.cpp)
-
- if (APPLE)
- add_definitions(-DDISCORD_OSX)
- set(BASE_RPC_SRC ${BASE_RPC_SRC} discord_register_osx.m)
- else (APPLE)
- add_definitions(-DDISCORD_LINUX)
- set(BASE_RPC_SRC ${BASE_RPC_SRC} discord_register_linux.cpp)
- endif(APPLE)
+ if(MINGW)
+ set(BASE_RPC_SRC ${BASE_RPC_SRC} connection_win.cpp discord_register_win.cpp)
+ else(MINGW)
+ set(BASE_RPC_SRC ${BASE_RPC_SRC} connection_unix.cpp)
+ if (APPLE)
+ add_definitions(-DDISCORD_OSX)
+ set(BASE_RPC_SRC ${BASE_RPC_SRC} discord_register_osx.m)
+ else (APPLE)
+ add_definitions(-DDISCORD_LINUX)
+ set(BASE_RPC_SRC ${BASE_RPC_SRC} discord_register_linux.cpp)
+ endif(APPLE)
+ endif(MINGW)
add_library(discord-rpc ${BASE_RPC_SRC})
target_link_libraries(discord-rpc PUBLIC pthread)
Now it seems to compile successfully.
It may be a good idea to make a pull request for this if it works.
I will consider it. Thanks.
Well, turns out it didn't work. On Discord_Initialize
the stack frame seems to jump to 0x00000000 and a segfault occurs. Tried it on someone else's project and the same thing happens.
$ gcc -v
Using built-in specs.
COLLECT_GCC=D:\Programs\msys64\mingw32\bin\gcc.exe
COLLECT_LTO_WRAPPER=D:/Programs/msys64/mingw32/bin/../lib/gcc/i686-w64-mingw32/7.2.0/lto-wrapper.exe
Target: i686-w64-mingw32
Configured with: ../gcc-7.2.0/configure --prefix=/mingw32 --with-local-prefix=/mingw32/local --build=i686-w64-mingw32 --host=i686-w64-mingw32 --target=i686-w64-mingw32 --with-native-system-header-dir=/mingw32/i686-w64-mingw32/include --libexecdir=/mingw32/lib --enable-bootstrap --with-arch=i686 --with-tune=generic --enable-languages=c,lto,c++,objc,obj-c++,fortran,ada --enable-shared --enable-static --enable-libatomic --enable-threads=posix --enable-graphite --enable-fully-dynamic-string --enable-libstdcxx-time=yes --disable-libstdcxx-pch --disable-libstdcxx-debug --disable-isl-version-check --enable-lto --enable-libgomp --disable-multilib --enable-checking=release --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --with-libiconv --with-system-zlib --with-gmp=/mingw32 --with-mpfr=/mingw32 --with-mpc=/mingw32 --with-isl=/mingw32 --with-pkgversion='Rev1, Built by MSYS2 project' --with-bugurl=https://sourceforge.net/projects/msys2 --with-gnu-as --with-gnu-ld --disable-sjlj-exceptions --with-dwarf2
Thread model: posix
gcc version 7.2.0 (Rev1, Built by MSYS2 project)
Disassembly right at the call:
26 [1] Discord_Initialize(APPLICATION_ID, &handlers, 1, nullptr);
0x429125 <+0x00af> 8b 45 b4 mov -0x4c(%ebp),%eax
0x429128 <+0x00b2> 8b 00 mov (%eax),%eax
0x42912a <+0x00b4> c7 44 24 0c 00 00 00 00 movl $0x0,0xc(%esp)
0x429132 <+0x00bc> c7 44 24 08 01 00 00 00 movl $0x1,0x8(%esp)
0x42913a <+0x00c4> 8d 55 c4 lea -0x3c(%ebp),%edx
0x42913d <+0x00c7> 89 54 24 04 mov %edx,0x4(%esp)
0x429141 <+0x00cb> 89 04 24 mov %eax,(%esp)
0x429144 <+0x00ce> e8 17 3a 00 00 call 0x42cb60 <Discord_Initialize(char const*, DiscordEventHandlers*, int, char const*)>
Here is the body of that function:
Discord::Discord()
{
DiscordEventHandlers handlers;
std::memset(&handlers, 0, sizeof(handlers));
handlers = {};
handlers.ready = [] {
qInfo() << "Discord RPC ready";
};
/*
handlers.disconnected = [](int errorCode, const char* message) {
qInfo() << "Discord RPC disconnected! " << message;
};
handlers.errored = [](int errorCode, const char* message) {
qWarning() << "Discord RPC errored out! " << message;
};
*/
qInfo() << "Are things working out all right?";
Discord_Initialize(APPLICATION_ID, &handlers, 1, nullptr);
}
The string Are things working out all right?
gets printed and the breakpoint at that point gets hit, so the problem obviously lies in Discord_Initialize. I was able to step through discord_register_win.cpp and found that the segfault was reached right at RegCloseKey(key)
in Discord_RegisterW
. So the problem is either in closing the registry key (unlikely) (I modified it to step over a few lines after the closing the key) or a compiler problem in returning from the function (somewhat likely but still bizarre) (confirmed; segfault occurs at leave
instruction before ret
in Discord_RegisterW
, so the stack was corrupted somehow).
I'm completely dumbfounded at what the issue could be.
For now, I'm going to stick to the pre-built DLLs.
I still have nothing to test the library with. But, checking some documentation for WinAPI shows that RegCreateKey[W] function is obsolete and may even be unsupported in newer versions in favor of RegCreateKeyEx[W]. However, this is almost the same code as used in ReactOS, so it should have worked. If this is the reason for stack corruption, replacing it as manual suggests should work. Does changing the line that uses it to
if ((ret = RegCreateKeyExW(hkey, subkey, 0, 0, 0, KEY_ALL_ACCESS, 0, &hsubkey, 0)) != ERROR_SUCCESS) return ret;
fix the issue? Also, what is the Windows version you are using for tests?
Hi, thanks for getting back. I am using Windows 7 64-bit with the latest updates.
The code you provided unfortunately seems to have no effect. The stack corruption still occurs.
Found another detail about RegCreateKey[Ex][W]:
If hKey is one of the predefined keys, lpSubKey may be NULL. In that case, phkResult receives the same hKey handle passed in to the function.
That being said, if the second argument is null, hsubkey in regset may be equal to hkey, so it gets closed when regset returns, but hkey may be still in use. I'm surprised I didn't see it or even think about it when I was readin it first time, although this behaviour seems logical. The first thing that comes to my mind is to check them to be equal before closing, so regset would look like that:
LSTATUS regset(HKEY hkey, LPCWSTR subkey, LPCWSTR name, DWORD type, const void *data, DWORD len)
{
HKEY htkey = hkey, hsubkey = nullptr;
LSTATUS ret;
if (subkey && subkey[0])
{
if((ret = RegCreateKeyExW(hkey, subkey, 0, 0, 0, KEY_ALL_ACCESS, 0, &hsubkey, 0)) != ERROR_SUCCESS) return ret;
htkey = hsubkey;
}
ret = RegSetValueExW(htkey, name, 0, type, (const BYTE*)data, len);
if (hsubkey && hsubkey != hkey) RegCloseKey(hsubkey);
return ret;
}
Which is more complicated than the original one, but this is the most obvious solution that comes to my mind. Although, I don't know why this code works in ReactOS without consequences, unless it doesn't really close key handlers, which should be fixed as well. I'm pretty sure this one should fix the issue. Also, I'm not sure about KEY_ALL_ACCESS. It is said to be the default one, but I have no idea how this thing works, so a more specific constant may be needed. P.S. This is the reference function used: https://doxygen.reactos.org/d2/da2/RegSetKeyValue_8c_source.html
Tried it again, yet the stack corruption persists. What's going on?
It took a while to do some debugging. Turns out the problem wasn't even in the registry interactions - the stack gets destroyed after StringCbCopyW call, which in my case was replaced with my own function, and by all means it is my fault. In this case, MSVS builds were not spoiled by my changes. The reason for this code behavior is simple: strsafe.h functions take the size in bytes (and it is retrieved by sizeof()), while string.h ones take it in wide characters, and some conversion must be done first. I've already finished adapting my replacement code to the standards, currently testing it. So, things that had to be done: 1) This dumb substitute function
HRESULT StringCbPrintfW(LPWSTR pszDest, size_t cbDest, LPCWSTR pszFormat, ...)
{
HRESULT ret;
va_list va;
va_start(va, pszFormat);
cbDest /= 2; // Size is divided by 2 to convert from bytes to wide characters - causes segfault othervise
ret = vsnwprintf(pszDest, cbDest, pszFormat, va);
pszDest[cbDest - 1] = 0; // Terminate the string in case a buffer overflow; -1 will be returned
va_end(va);
return ret;
}
instead of a simple #define. This allows size conversion and a guaranteed 0-terminator. 2) The only call of StringCbCopyW was replaced with StringCbPrintfW with a L"%s" format string. It was a commonly used style in the rest of this file anyway.
//StringCbCopyW(openCommand, oc_len, exeFilePath);
StringCbPrintfW(openCommand, sizeof(openCommand), L"%s", exeFilePath);
The function itself was removed.
UPD: Tested 4 times, seems to be working by now. Please confirm this solution to be working or inform me if it's not. Made a PR #105 with fixes.
@k1-801 can we close this with the merge of #105 ?
There were several questions about MinGW and WinXP support in discord-rpc (#88, #83, #34), all being closed as "not supported".
Inserting this piece of code into discord_register_win.cpp (instead of old preprocessor blocks) makes it compilable with MinGW as well.
UPD: Wrong solution, causes segfaults on MinGW builds, see comments below and PR #105
It may be not the best solution, but it definetely makes the code compilable with MinGW (not tested to be working though, just finished rewriting it - will test as soon as I write some code to test it with).
The idea is:
Also, serialization.h contains #pragma declarations meant to supress warnings in MSVS, but they cause warnings in MinGW, so I wrapped them in #ifndefs, like this:
What should I do next with these patches?