SetWindowText snippet fixing?

ZirconStorms

Veteran
Veteran
Joined
Dec 22, 2014
Messages
359
Reaction score
111
First Language
English
Primarily Uses
RMVXA
Original code is in one of the replies: https://forums.rpgmakerweb.com/index.php?threads/fps-counter.42661/

I want to try and fix Tsukihime's script snippet, which would allow the game's title to be changed.
As-is, the original game title and the new one ("test change") flickers back and forth between each other.

Fixed code (original reply's formatting is broken):
Code:
module Window_Text
  SetWindowText = Win32API.new('user32', 'SetWindowText', 'pp', 'i')
  CreateWindowEx = Win32API.new('user32', 'CreateWindowEx', 'ippiiiiiiiii', 'i')
  FindWindow = Win32API.new('user32', 'FindWindow' , 'pp', 'i')
  HWND = FindWindow.call('RGSS Player', 0)
  def self.run
    SetWindowText.call(HWND, "test change")
  end
end

module Graphics
  class << self
    alias :th_old_update :update
    def update
      th_old_update
      Window_Text.run
    end
    end
  end
It's the def update section which breaks everything, is there some way to turn this into an in-game script call? Same user has managed to disable window borders using a win32api call (that can be performed in a script or in-game) link: so I think it can be done.
 
Last edited:

Heirukichi

Veteran
Veteran
Joined
Sep 24, 2015
Messages
1,421
Reaction score
596
First Language
Italian
Primarily Uses
RMVXA
In a fresh project it does not flicker. The new name completely replaces the old one unless you restart the game again. At least that is what happens in my engine.

EDIT: Ok, I see what you mean. After minimizing the window and restoring it to its original size the window name started to flicker.

Given the fact that you can show frames count in the window title it is clear how Graphics.update has to rename the window each frame. I am afraid the window name is stored somewhere when starting the game and it is used to rename the window each frame for the sole purpose of showing FPS.

That stored window name might not even be part of the window itself but rather part of the Graphic module (which is one of the hidden modules of VX Ace). After all after calling SetWindowText the text attribute for the window itself should be changed and it should not keep track of the last name. The only way for it to change again is to be overwritten from the Graphic module.
 
Last edited:

ZirconStorms

Veteran
Veteran
Joined
Dec 22, 2014
Messages
359
Reaction score
111
First Language
English
Primarily Uses
RMVXA
In a fresh project it does not flicker. The new name completely replaces the old one unless you restart the game again. At least that is what happens in my engine.

EDIT: Ok, I see what you mean. After minimizing the window and restoring it to its original size the window name started to flicker.

Given the fact that you can show frames count in the window title it is clear how Graphics.update has to rename the window each frame. I am afraid the window name is stored somewhere when starting the game and it is used to rename the window each frame for the sole purpose of showing FPS.

That stored window name might not even be part of the window itself but rather part of the Graphic module (which is one of the hidden modules of VX Ace). After all after calling SetWindowText the text attribute for the window itself should be changed and it should not keep track of the last name. The only way for it to change again is to be overwritten from the Graphic module.
Ah yeah, it's even buggier in a new game project.
https://steamcommunity.com/app/220700/discussions/2/598198356170566826/
This is a completely different method but it is possible to rewrite the game ini title data, which requires a restart to apply. I don't think resetting/hiding a piece of ini data like that would be possible without breaking one of Enterbrain's rules, but yeah it's the stored title in the ini file that's (at least) partially causing the flicker.
 

Heirukichi

Veteran
Veteran
Joined
Sep 24, 2015
Messages
1,421
Reaction score
596
First Language
Italian
Primarily Uses
RMVXA
Yes, I have been trying a way to rename the Game.ini data. However, that does indeed require a restart AND it does not work if you are testing your game. When using F12 to test the game your title will be the one saved in the database and not the one in the Game.ini file.

What causes the flickering is not the name stored in the ini file. The said name is loaded into memory when launching the game, that is why you can solve it by changing the name in the ini file and restarting the game. If you change the name in the ini file but do not restart the game the stored name is the old game name. That is what causes the flickering.

Unfortunately, other than restarting the game, I see no way of changing it as I do not know how to access that value that the Graphics module uses to constantly update your window name.
 

KK20

Just some XP Scripter
Veteran
Joined
Oct 11, 2018
Messages
281
Reaction score
106
First Language
English
Primarily Uses
RMXP
If you don't mind losing out on the F2 FPS counter, you could create a DLL that overwrites the WindowProc callback on Game.exe to intercept WM_SETTEXT messages and straight-up ignore them. Then export a method (e.g. int DLL_EXPORT ChangeTitle(LPCSTR newTitle) ) that will temporarily disable the WM_SETTEXT interception.

Heck, you could probably just replace the game title in WM_SETTEXT's lParam to the new title which is stored in a variable in the DLL or something.
 

Heirukichi

Veteran
Veteran
Joined
Sep 24, 2015
Messages
1,421
Reaction score
596
First Language
Italian
Primarily Uses
RMVXA
you could create a DLL that overwrites the WindowProc callback on Game.exe to intercept WM_SETTEXT messages and straight-up ignore them
How do you exactly do that? As far as I know you cannot overwrite methods/functions in C/C++ so you have to refer to them using either a pointer or a different name. Is there any other way to do that?
Because having to call them with a different name does not prevent the Graphics module from calling the original one.
 

KK20

Just some XP Scripter
Veteran
Joined
Oct 11, 2018
Messages
281
Reaction score
106
First Language
English
Primarily Uses
RMXP
I'll test out my theory and reply back with the results.

EDIT:
Okay, maybe my choice of words wasn't great. Not "overwrite" but rather use another window process first and THEN use the default window process if needed.

DLL code
Code:
// flag to call original windowproc
bool original_settext = false;
// Keep original window procedure if we need to use default behaviors
WNDPROC originalWndProc;
// handle to our game window
HWND window_handle;
// initialize only once
bool initialized = false;

// Define our new window procedure
LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
    switch(msg)
    {
    case WM_SETTEXT:
        if (original_settext)
        {
            original_settext = false;
            return CallWindowProc(originalWndProc, hwnd, msg, wp, lp);
        }
        return true;
    default:
        return CallWindowProc(originalWndProc, hwnd, msg, wp, lp);
    }
    return 0;
}

int DLL_EXPORT Initialize(LPCSTR iniFile)
{
    if (!initialized) // Call only once
    {
        // Get Window handle
        char buffer[256];
        GetPrivateProfileStringA("Game", "Title", "", buffer, 256, iniFile);
        window_handle = FindWindowA("RGSS Player", buffer);

        // Get address to the window's procedure
        originalWndProc = (WNDPROC)GetWindowLong(window_handle, GWL_WNDPROC);
        // Set new address for window procedure
        if (SetWindowLong(window_handle, GWL_WNDPROC, (LONG_PTR)&WindowProc) == 0)
            return -1; // Something went wrong, abort
        initialized = true;
        return 1; // All is good
    }
    return 0; // Already initialized
}

int DLL_EXPORT ChangeTitle(LPCSTR newTitle)
{
    original_settext = true;
    SetWindowText(window_handle, newTitle);
    return 0;
}
Ruby code
Code:
module ChangeTitle
  @@_changetitle = Win32API.new('MessageIntercept', 'ChangeTitle', 'p', 'i')
  Win32API.new('MessageIntercept', 'Initialize', 'p', 'i').call(".\\Game.ini")
  def self.run(title)
    @@_changetitle.call(title)
  end
end
Make an event do a script call "ChangeTitle.run('title')".
And the DLL to download is attached.

Intercepting messages is pretty neat. It's how I can keep the Game window running when it's not in focus.
 

Attachments

Last edited:

Users Who Are Viewing This Thread (Users: 0, Guests: 1)

Latest Threads

Latest Posts

Latest Profile Posts

Couple hours of work. Might use in my game as a secret find or something. Not sure. Fancy though no? :D
Holy stink, where have I been? Well, I started my temporary job this week. So less time to spend on game design... :(
Cartoonier cloud cover that better fits the art style, as well as (slightly) improved blending/fading... fading clouds when there are larger patterns is still somewhat abrupt for some reason.
Do you Find Tilesetting or Looking for Tilesets/Plugins more fun? Personally I like making my tileset for my Game (Cretaceous Park TM) xD
How many parameters is 'too many'??

Forum statistics

Threads
105,863
Messages
1,017,053
Members
137,571
Latest member
grr
Top