Hi guys so I'm back to messing with rpg maker XP Ace and rmx-os, I'm wondering if a script can be made to stop people closing the client or rpg maker using the X? Maybe something that of its pressed send a message to use end game instead? Thanks
You mean the X button in the top right corner? I rhibk this might be possible.
There are Ruby methods to do such things. I know in RMXP (Ruby 1.8.1) you can alias exit and that method will be called when the player closes the game normally or presses X. This doesn't work anymore in 1.9.2 (RMVXA/XPA) for some reason.
I could've sworn I did find a solution to that before on accident and I believe it had to do something with Exceptions, specifically SystemExit. Though I've tried a bunch of things and didn't get anywhere. Google didn't help either :|
It should be possible to catch the WM_CLOSE event using a hook and do a clean exit with disconnect. It doesn't prevent exiting, but at least a clean disconnect will ensure that stuff is properly saved, etc. WM_CLOSE is also triggered on ALT+F4. I'm not sure you can abort WM_CLOSE with RMs so a clean exit might be the only option.
Any chance you guys could put something together for me? Thanks!
Wow. How do you hook window messages in RGSS?
It turns out that once WM_CLOSE has been fired, it can't be stopped. :/ But you can still disable the X button when the game is activated. Just put this on top of your script list.
module DisableX
def self.get_window
game_name = "\0" * 256
read_ini = Win32API.new('kernel32', 'GetPrivateProfileStringA', 'pppplp', 'l')
read_ini.call('Game', 'Title', '', game_name, 255, './Game.ini')
game_name += "\0"
find_window = Win32API.new('user32', 'FindWindowA', 'pp', 'L')
return find_window.call('RGSS Player', game_name)
end
window = self.get_window
if window != 0
menu = Win32API.new('user32', 'GetSystemMenu', 'll', 'l').call(window, 0)
if menu != 0
Win32API.new('user32', 'EnableMenuItem', 'lll', 'l').call(menu, 0xF060, 0x1) # SC_CLOSE, MF_BYCOMMAND | MF_GRAYED
end
end
end
@Mason: This is a simple piece of C code that can hook messages. If you compile this as a DLL with Visual Studio and link to user32.lib, this will work.
#define NOMINMAX
#include <windows.h>
#define DLL_EXPORT __declspec(dllexport)
LRESULT CALLBACK CallWndProc(int code, WPARAM wParam, LPARAM lParam)
{
if (code >= 0)
{
PCWPSTRUCT msg = (PCWPSTRUCT)lParam;
if (msg->message == WM_CLOSE) // this would be processing some stuff regarding WM_CLOSE
{
// extra code would go here, maybe something like MessageBoxA(0, "TEST", "HELLO THERE", 0);
}
}
return CallNextHookEx(NULL, code, wParam, lParam);
}
int initialized = 0;
void DLL_EXPORT Initialize(HWND hwnd) // assuming you get HWND from RUBY using FindWindowA() with the above Ruby code (self.get_window)
{
if (!initialized)
{
HINSTANCE hinstance = (HINSTANCE)GetWindowLongW(hwnd, GWL_HINSTANCE);
DWORD threadId = GetCurrentThreadId(); // some hooks can't be thread specific, but this one can
if (hinstance != 0 && threadId != 0 && SetWindowsHookExW(WH_CALLWNDPROC, CallWndProc, hinstance, threadId) != 0)
{
initialized = 1;
}
}
}
You could call the DLL like this from Ruby:
module MySpecialCode
def self.get_window
game_name = "\0" * 256
read_ini = Win32API.new('kernel32', 'GetPrivateProfileStringA', ['p', 'p', 'p', 'p', 'l', 'p'], 'l')
read_ini.call('Game', 'Title', '', game_name, 255, './Game.ini')
game_name += "\0"
find_window = Win32API.new('user32', 'FindWindowA', ['p', 'p'], 'L')
return find_window.call('RGSS Player', game_name)
end
window = self.get_window
if window != 0
Win32API.new('MyDll', 'Initialize', 'l', 'v').call(window)
end
end
thanks Blizz epic! 1 more things can u keep game running when u minimize or change windows? rpg maker xp stops :(
I don't think this one is possible. Altough, maybe if you add a hook and intercept the WM_ACTIVATE event. Not sure how RMXP handles the stopping, but it could be that it handles the WM_ACTIVATE or WM_ACTIVATEAPP event and responds accordingly. So disabling these events through a hook might be able to stop that from happening and keep the game running in background. But somebody else has to try that, I'm not sure I'll have any time over the course of the next week to look into that. xD The C code on top should almost work with some minor edits.
thanks Blizz I'm testing the DDL that was posted that keeps it running in background, I'm thinking now I need to remove minimize to keep rmx-os running to stop issues
You can intercept these messages as well. Or you can actually hide the top-right by changing the "style of window" as well. Just google around, you just need 1 or 2 Win32API calls for that.
being as noob as I am could u post something for me man :) ?
This will disable the system menu, but somebody else has to do that WM_ACTIVATE disabling in C.
module DisableSystemMenu
def self.get_window
game_name = "\0" * 256
read_ini = Win32API.new('kernel32', 'GetPrivateProfileStringA', 'pppplp', 'l')
read_ini.call('Game', 'Title', '', game_name, 255, './Game.ini')
game_name += "\0"
find_window = Win32API.new('user32', 'FindWindowA', 'pp', 'L')
return find_window.call('RGSS Player', game_name)
end
window = self.get_window
if window != 0
style = Win32API.new('user32', 'GetWindowLong', 'll', 'l').call(window, -16) # GWL_STYLE
style &= ~0x00080000 # removing WS_SYSMENU
Win32API.new('user32', 'SetWindowLong', 'lll', 'l').call(window, -16, style)
end
end