AOMover

Alles Wissenswerte über Skripte, Browser, Makros, PhP, HTML...

Moderatoren: Moderatoren, Redakteure

Benutzeravatar
Scorcher24_
Beiträge: 15527
Registriert: 11.11.2004 14:31
Persönliche Nachricht:

AOMover

Beitrag von Scorcher24_ »

Das kleine Programm habe ich ursprünglich für die Anarchy Online Community geschrieben. Habe es allerdings nun angepasst, damit man es für jedes Game verwenden kann.
Es macht folgendes:
Wenn ein Spiel als Beispiel nur fixierte Fenster anbietet und man im Fenstermodus spielen will, aber trotzdem Vollbild haben möchte, dann ist das Programm perfekt dafür.
Es ist ein Fenster ohne Border und in der Größe des Desktops. So fühlt es sich Vollbild an, ist aber keiner. So kann man schnell und leicht raustabben.
Manche Spiele verhindern das allerdings indem sie die Windowsnachricht WM_SIZE blockieren.
Man sollte auch nicht eine 4:3 Auflösung nehmen und die dann auf 16:10 strecken oder so. Das sieht dann entsprechend scheisse aus. Die DirectX/OpenGL Matrizen kann ich damit leider nicht manipulieren.
Wie funzt es?
Starten und dann habt ihr im systray ein icon. Das rechtsklicken und wenn das Spiel nicht Anarchy Online heisst, dort den Fensternamen eingeben. Vorsicht, das ganze ist case-sensitive.
http://code.google.com/p/aomover/

Der Code ist recht simpel:

Code: Alles auswählen

/*
   Project AOMover
   Copyright 2010 Scorcher24

   This software is provided 'as-is', without any express or implied
   warranty. In no event will the authors be held liable for any
   damages arising from the use of this software.

   Permission is granted to anyone to use this software for any
   purpose, including commercial applications, and to alter it and
   redistribute it freely, subject to the following restrictions:

   1. The origin of this software must not be misrepresented; you
      must not claim that you wrote the original software. If you use
      this software in a product, an acknowledgment in the product
      documentation would be appreciated but is not required.

   2. Altered source versions must be plainly marked as such, and
      must not be misrepresented as being the original software.

   3. This notice may not be removed or altered from any source
      distribution.

    Scorcher24
    Scorcher24@gmail.com
*/
#ifndef STDAFX_HPP
#define STDAFX_HPP

//////////////////////////////////////////////////////////////////////////
// wxWidgets Includes
//////////////////////////////////////////////////////////////////////////
#include <wx/wx.h>
#include <wx/taskbar.h>
#include <wx/html/htmlwin.h>
#include <wx/xml/xml.h> 
#include <wx/textdlg.h> 

//////////////////////////////////////////////////////////////////////////
// STL Includes
//////////////////////////////////////////////////////////////////////////
#include <algorithm>
#include <list>

//////////////////////////////////////////////////////////////////////////
// OS specific includes
//////////////////////////////////////////////////////////////////////////
#include <process.h>



#endif // STDAFX_HPP

Code: Alles auswählen

/*
   Project AOMover
   Copyright 2010 Scorcher24

   This software is provided 'as-is', without any express or implied
   warranty. In no event will the authors be held liable for any
   damages arising from the use of this software.

   Permission is granted to anyone to use this software for any
   purpose, including commercial applications, and to alter it and
   redistribute it freely, subject to the following restrictions:

   1. The origin of this software must not be misrepresented; you
      must not claim that you wrote the original software. If you use
      this software in a product, an acknowledgment in the product
      documentation would be appreciated but is not required.

   2. Altered source versions must be plainly marked as such, and
      must not be misrepresented as being the original software.

   3. This notice may not be removed or altered from any source
      distribution.

    Scorcher24
    Scorcher24@gmail.com
*/
#include "stdafx.hpp"
#include "wxwin16x16.xpm"

namespace AOMover{

//////////////////////////////////////////////////////////////////////////
// Forwards
//////////////////////////////////////////////////////////////////////////	
BOOL CALLBACK EnumWindowCallback(HWND hWindow, LPARAM param);
class Tray;

//////////////////////////////////////////////////////////////////////////
// Enum with all ids for this program
//////////////////////////////////////////////////////////////////////////
enum MenuId
{
	ID_CLOSE = wxID_HIGHEST + 1,
	ID_ABOUT,
	ID_RESIZE_TIMER,
	ID_CONFIGURE,
	ID_MOVE,
    ID_ENTER_WINDOW_NAME,
};

//////////////////////////////////////////////////////////////////////////
// Custom WindowHandle which keeps track of the HWND and the Process ID.
//////////////////////////////////////////////////////////////////////////
struct TWindowHandle
{
	TWindowHandle() : 
		hWindow(NULL), pid(0)
		{}		
		
	HWND hWindow;
	DWORD pid;
};

//////////////////////////////////////////////////////////////////////////
// Metrics of the System
//////////////////////////////////////////////////////////////////////////
struct AbsoluteMetrics
{
	AbsoluteMetrics()
		:  x(0), y(0)
	{}

	int x;
	int y;
};

//////////////////////////////////////////////////////////////////////////
// Struct which is passed to the thread, containing necessary information
//////////////////////////////////////////////////////////////////////////
struct ThreadInfo
{
	ThreadInfo() :
		tray(NULL), hProcess(NULL), pid(0)
	{}

	Tray* tray;
	HANDLE hProcess;
	DWORD pid;
};


//////////////////////////////////////////////////////////////////////////
// Callback for std::for_each
//////////////////////////////////////////////////////////////////////////
void for_each_thread(HANDLE hThread)
{
	CloseHandle(hThread);
}

//////////////////////////////////////////////////////////////////////////
// HTML Window Implementation for some tweaking.
//////////////////////////////////////////////////////////////////////////
class HtmlWindow : public wxHtmlWindow
{
public:
	HtmlWindow(wxWindow* parent, int id)
		: wxHtmlWindow(parent, id)
	{}

protected:
	//////////////////////////////////////////////////////////////////////////
	// Opens the clicked link in browser..
	// This is a rather easy protection, but well if someone wants to make 
	// this program rogue :|, the code is available anyway.... 
	virtual void OnLinkClicked(const wxHtmlLinkInfo &  link)
	{
		if ( link.GetHref() == "http://wxwidgets.org" ||
			 link.GetHref() == "http://anarchy-online.com")
		{
			wxLaunchDefaultBrowser(link.GetHref(), 0);
		};		
	}

};

//////////////////////////////////////////////////////////////////////////
// Class representing the tray icon which is the only thing the user
// will see from this program except maybe a future settings dialog.
//////////////////////////////////////////////////////////////////////////
class Tray : public wxTaskBarIcon
{
	typedef std::list<TWindowHandle> TWindowList;
	typedef std::list<HANDLE> TThreadList;
public:
	Tray(wxWindow* parent)
		: wxTaskBarIcon(), m_parent(parent), m_window_name("Anarchy Online")
	{}

	virtual ~Tray()
	{
		if ( IsIconInstalled() )
		{
			RemoveIcon();
		}
	}

	//////////////////////////////////////////////////////////////////////////
	// Adds an entry, avoids doubles
	//////////////////////////////////////////////////////////////////////////
	bool AddEntry(TWindowHandle handle)
	{
		TWindowList::iterator it = m_window_list.begin();
		for( it; it != m_window_list.end(); it++ )
		{
			if ( handle.hWindow == it->hWindow && handle.pid == it->pid )
			{				
				return false;
			}
		}
		m_window_list.push_back(handle);
		return true;
	}

	//////////////////////////////////////////////////////////////////////////
	// Removes an entry from the list by its pid
	//////////////////////////////////////////////////////////////////////////
	void RemoveEntry(DWORD pid)
	{
		TWindowList::iterator it = m_window_list.begin();
		for( it; it != m_window_list.end(); it++ )
		{
			if ( it->pid == pid )
			{
				it = m_window_list.erase(it);
				if ( it == m_window_list.end() )
					return;
			}
		}
	}

	//////////////////////////////////////////////////////////////////////////
	// Adds a threadhandle to the list so we can delete it later.
	//////////////////////////////////////////////////////////////////////////
	void AddThread(HANDLE hThread)
	{
		m_threadList.push_back(hThread);
	}

	//////////////////////////////////////////////////////////////////////////
	// #define replacement to have the name of the window on a central place.
	//////////////////////////////////////////////////////////////////////////
	wxString GetAnarchyWindowName() 
    { 
        return m_window_name; 
    }

protected:
	//////////////////////////////////////////////////////////////////////////
	// Creates the popupmenu for the trayicon
	//////////////////////////////////////////////////////////////////////////
	virtual wxMenu* CreatePopupMenu()
	{
		wxMenu* menu = new wxMenu();

		FindAnarchy();
		TWindowList::iterator it = m_window_list.begin();
		int i = 0;
		for( it; it != m_window_list.end(); it++ )
		{
			wxString txt;
			txt.Printf("AO - PID # %i", it->pid);
			menu->Append(ID_MOVE+i, txt);
			i++;
		}
		
		menu->AppendSeparator();
		menu->Append(ID_ABOUT, _("About.."));
		menu->AppendSeparator();
        menu->Append(ID_ENTER_WINDOW_NAME, _("Enter window name"));
		menu->AppendSeparator();
		menu->Append(ID_CLOSE, _("Exit"));

		menu->SetEventHandler(this);
		return menu;
	}

	//////////////////////////////////////////////////////////////////////////
	// Closes the dummy parent frame which will kill the app.
	//////////////////////////////////////////////////////////////////////////
	void OnMenuClose(wxCommandEvent&)
	{
		std::for_each(m_threadList.begin(), m_threadList.end(), for_each_thread);
		m_parent->Close(true);
	}

	//////////////////////////////////////////////////////////////////////////
	// Shows the About Dialog
	//////////////////////////////////////////////////////////////////////////
	void OnAboutDlg(wxCommandEvent&)
	{
		wxDialog dlg(NULL, wxID_ANY, _("About.."), wxDefaultPosition, wxSize(450,600));
		
		HtmlWindow* html = new HtmlWindow(&dlg, wxID_ANY);
		html->LoadFile(wxFileName("data/about.html"));

		dlg.ShowModal();
	}

	//////////////////////////////////////////////////////////////////////////
	// Event for moving ao.
	//////////////////////////////////////////////////////////////////////////
	void OnMenuMove(wxCommandEvent& e)
	{
		wxMenu* m = (wxMenu*)e.GetEventObject();
		int id = e.GetId() - ID_MOVE;
		wxString label = m->GetLabelText(e.GetId());

		label = label.AfterLast('#');
		int pid = atoi(label.mb_str());

		MoveAnarchy(FindHWNDByPid(pid));
	}

	//////////////////////////////////////////////////////////////////////////
	// Configures AO for usage with our program.
	//////////////////////////////////////////////////////////////////////////
	void OnConfigure(wxCommandEvent&)
	{
		AbsoluteMetrics m = GetAbsoluteUserMetrics();
		
		wxString p = GetAnarchyDirectoryFromRegistry() + wxString("/prefs");	
		wxFileDialog dlg(NULL, 
						 _("Please select the prefs.xml file from your ao-directory."), 
						 p, "prefs.xml", "XML|*.xml");
		if ( dlg.ShowModal() == wxID_OK )
		{
			wxString prefs = dlg.GetPath();
			if ( prefs.IsEmpty() )
			{
				wxMessageBox(_("You need to select a preference file to continue"), _("Error"), wxICON_ERROR|wxOK);
				return;
			}

			ModifyAOPrefs(prefs, m);
		}
	}

private:
	//////////////////////////////////////////////////////////////////////////
	// Looks for all Anarchy Online Windows and enlists them.
	//////////////////////////////////////////////////////////////////////////
	bool FindAnarchy()
	{
		EnumWindows((WNDENUMPROC)EnumWindowCallback, (LPARAM)this);
		return true;
	}

	//////////////////////////////////////////////////////////////////////////
	// Finds the hwnd of the pid
	//////////////////////////////////////////////////////////////////////////
	HWND FindHWNDByPid(DWORD pid)
	{
		TWindowList::iterator it = m_window_list.begin();
		for ( it; it != m_window_list.end(); it++ )
		{
			if ( pid == it->pid )
				return it->hWindow;
		}
		return NULL;
	}

	//////////////////////////////////////////////////////////////////////////
	// Sizes the corresponding AO-Window
	//////////////////////////////////////////////////////////////////////////
	void MoveAnarchy(HWND hWindow)
	{
		if ( IsWindow(hWindow) )
		{
			
			RECT rct;
			ZeroMemory(&rct, sizeof(rct));
			long style = GetWindowLong(hWindow, GWL_STYLE);
			SetRect(&rct,0,0,GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN)); 

			if ( style & WS_POPUP )
			{
				style &= ~WS_POPUP;
				style &= ~WS_MAXIMIZE;
				style |= WS_CAPTION|WS_MINIMIZEBOX|WS_SYSMENU|WS_OVERLAPPED|WS_CLIPSIBLINGS;				
			}
			else
			{
				style &= ~WS_CAPTION;
				style &= ~WS_MINIMIZEBOX;
				style &= ~WS_SYSMENU;
				style &= ~WS_OVERLAPPED;
				style &= ~WS_CLIPSIBLINGS;
				style |= (WS_POPUP|WS_MAXIMIZE);				
			}
			SetWindowPos(hWindow, HWND_TOP,rct.left,rct.top,rct.right-rct.left,rct.bottom-rct.top,SWP_FRAMECHANGED|SWP_DRAWFRAME);
			SetWindowLong(hWindow, GWL_STYLE, style);				
			UpdateWindow(hWindow);
		}
	}

	//////////////////////////////////////////////////////////////////////////
	// Reads the System Metrics for the Titlebar und the border and returns
	// a struct with the values.
	//////////////////////////////////////////////////////////////////////////
	AbsoluteMetrics GetAbsoluteUserMetrics()
	{
		AbsoluteMetrics m;

		// Get Caption and Bordersize
		int caption = GetSystemMetrics(SM_CYCAPTION);
		int border  = GetSystemMetrics(SM_CXBORDER);

		// Get Screensize
		int x = GetSystemMetrics(SM_CXSCREEN);
		int y = GetSystemMetrics(SM_CYSCREEN);

		m.x = x;
		m.y = y;
		return m;
	}

	//////////////////////////////////////////////////////////////////////////
	// Modifies the prefs.xml for usage with our program
	// Tested, works for 18.4
	//////////////////////////////////////////////////////////////////////////
	bool ModifyAOPrefs(const wxString prefs, AbsoluteMetrics m)
	{
		wxXmlDocument doc;
		if ( !doc.Load(prefs) )
		{
			wxMessageBox(_("Cannot access '") + prefs + "'", wxMessageBoxCaptionStr, wxOK | wxICON_ERROR);
			return false;
		}
		if ( doc.GetRoot()->GetName() != wxString("Root"))
		{
			wxMessageBox(_("XML Root not recognized. Abort."), wxMessageBoxCaptionStr, wxOK | wxICON_ERROR);
			return false;
		}
		wxXmlNode* child = doc.GetRoot()->GetChildren();

		while ( child )
		{
			if ( child->GetName() == wxString("Value") )
			{
				wxXmlAttribute* attribs = child->GetAttributes();
				if ( attribs->GetValue() == "DisplayHeight")
				{
					wxXmlAttribute* value = attribs->GetNext();
					wxString v;
					v.Printf("%i", m.y );
					value->SetValue(v);
				}
				if ( attribs->GetValue() == "DisplayWidth")
				{
					wxXmlAttribute* value = attribs->GetNext();
					wxString v;
					v.Printf("%i", m.x );
					value->SetValue(v);
				}
			}
			child = child->GetNext();
		}
		doc.Save(prefs);
		return true;
	}

	// This works pretty straigth: Tries to read the install dir set by anarchies client on win32. 
	// If not found, it returns an empty string. On all other platforms it returns an empty string only,
	// so we simply check for the string empty or not in the constructor.
	wxString GetAnarchyDirectoryFromRegistry()
	{
		wxString result = wxEmptyString;
#ifdef WIN32	
		wxRegKey* regKey = new wxRegKey("HKEY_CURRENT_USER\\Software\\Anarchy Online");
		if ( regKey->Exists() )
		{
			wxString temp;
			if ( regKey->QueryValue("Install Directory", temp) )
			{
				result = temp;
			}
		}
		delete regKey;	
#endif /* WIN32 */

		return result;
	}

    void OnEnterWindowName(wxCommandEvent&)
    {
        wxString name = wxGetTextFromUser(_("Enter exact window name"), "aomover", m_window_name, NULL);
        if ( !name.empty() )
        {
            m_window_name = name;
        }
    }

private:
	wxWindow* m_parent;
	DECLARE_EVENT_TABLE();
	TWindowList m_window_list;
	TThreadList m_threadList;
    wxString m_window_name;
};

//////////////////////////////////////////////////////////////////////////
// Event Table for the Tray
//////////////////////////////////////////////////////////////////////////
BEGIN_EVENT_TABLE(Tray, wxTaskBarIcon)
	EVT_MENU(ID_CLOSE, Tray::OnMenuClose)
	EVT_MENU(ID_MOVE, Tray::OnMenuMove)
	EVT_MENU(ID_ABOUT, Tray::OnAboutDlg)
    EVT_MENU(ID_ENTER_WINDOW_NAME, Tray::OnEnterWindowName)
	// EVT_MENU(ID_CONFIGURE, Tray::OnConfigure)  // Disabled, Feature does not work currently.
END_EVENT_TABLE()


//////////////////////////////////////////////////////////////////////////
// Dummy Frame which creates the systray-icon
//////////////////////////////////////////////////////////////////////////
class Frame : public wxFrame
{
public:
	Frame() 
		: wxFrame(NULL, wxID_ANY, "You should never see me")
	{
		m_tray = new Tray(this);
		m_tray->SetIcon(wxIcon(wxwin16x16_xpm));
	}

	virtual ~Frame()
	{
		delete m_tray;
	}

private:
	Tray* m_tray;
};

//////////////////////////////////////////////////////////////////////////
// Thread callback for ao's processes. It waits until ao's ended and 
// removes the entry in our list then.
//////////////////////////////////////////////////////////////////////////
void CALLBACK WaitThreadCallback(LPVOID param)
{
	ThreadInfo* info = reinterpret_cast<ThreadInfo*>(param);
	while ( WaitForSingleObject(info->hProcess, INFINITE) == WAIT_TIMEOUT )
	{
		Sleep(0);
	}
	CloseHandle(info->hProcess);
	info->tray->RemoveEntry(info->pid);
	delete info;
}

//////////////////////////////////////////////////////////////////////////
// Callback for EnumWindows
//////////////////////////////////////////////////////////////////////////
BOOL CALLBACK EnumWindowCallback(HWND hWindow, LPARAM param)
{
	if ( IsWindow(hWindow) )
	{
		Tray* tray = (Tray*)(param);
		wchar_t txt[256];

		GetWindowText(hWindow, txt, 256);
		if ( tray->GetAnarchyWindowName() == wxString(txt) )
		{
			DWORD pid;
			GetWindowThreadProcessId(hWindow, &pid);

			TWindowHandle handle;
			handle.pid = pid;
			handle.hWindow = hWindow;

			if ( tray->AddEntry(handle) )
			{
				HANDLE hProcess = OpenProcess(SYNCHRONIZE, FALSE, pid);
				if ( hProcess == NULL )
				{
					wxMessageBox("Cannot open Process");
				}

				ThreadInfo* info = new ThreadInfo;
				info->hProcess = hProcess;
				info->tray = tray;
				info->pid = pid;

				HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)WaitThreadCallback, info, 0, NULL);
				tray->AddThread(hThread);
			}
		}
	}
	return TRUE;
}



//////////////////////////////////////////////////////////////////////////
// Application Class
//////////////////////////////////////////////////////////////////////////
class App : public wxApp
{
public:
	virtual bool OnInit()
	{
		wxImage::AddHandler(new wxPNGHandler);

		Frame* f = new Frame;
		f->Show(false);
		this->SetTopWindow(f);
		return true;
	}

};

//////////////////////////////////////////////////////////////////////////
// Macro from wx to create the winmain
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_APP(App)


}; // Namespace
Viel Spaß damit :). Eine vorkompilierte Binary gibts auf der Projektseite.
Benutzeravatar
NekuSoul
Beiträge: 483
Registriert: 06.03.2010 17:47
Persönliche Nachricht:

Beitrag von NekuSoul »

Hab's mal ausprobiert, echt nett gemacht.
Hier meine Ergebnisse:

Super Meat Boy
Funzt einwandfrei. Netter Nebeneffekt ist auch dass dann Ingame die Texturen nicht hochgesetzt werden. So kann ich dann auch im Pseudo Fullscreen zocken was sonst auf Grund von Rucklern nicht möglich wär.

Trackmania United
Ist zwar schon resizable, aber noch noch mehr "Fullscreen". Damit die Auflösung auch Ingame geändert wird muss man aber immer noch einmal die Fenstergröße ändern.

I wanna be the magnanimity
Klappt auch, jedoch hätte ich hier doch viel Lieber die PID eingegeben, anstatt "I wanna be the magnanimity ver.0.55 --- Death[419] Time[0:54:58]" eintippen zu müssen.

Windows Explorer
Bin ich per Zufall drauf gestossen, klappt auch, hat auf jeden Fall Style 8)

Zum Code
Sieht auf jeden Fall durchdacht und ordentlich aus, im Gegensatz zu mir sogar fein säuberlich kommentiert. :wink:
Was mir lediglich aufgefallen ist, dass da noch etwas Anarchy Online Code drinnensteckt. (gewollt?)

Anderes
Vielleicht nicht dazu gedacht, aber: Wenn man nun eher ein kleines Fenster möchte, kann man das zwar machen, ist aber Relativ kompliziert da es eben oben keinen Fenstertitel zum verschieben hat. Borderless halt, was soll man auch erwarten. :wink:
Wär auch nett wenn du ein Icon hättest (nicht nur für's Startmenü hättest.)
Und da fehlt die HTML-Datei für die "About" Box, gibt einen Error und ein weißes About-Fenster.


Alles in allem ein nettes Tool, kann ich auf jeden Fall weiterbenutzen. :danke:
Benutzeravatar
Scorcher24_
Beiträge: 15527
Registriert: 11.11.2004 14:31
Persönliche Nachricht:

Beitrag von Scorcher24_ »

Danke fürs Feedback.
Ja, das Programm ist halt auf Anarchy Online ausgelegt. Standardmäßig wird auch nach Anarchy Online Fenstern gesucht.
Es geht prinzipiell mit jedem Fenster, da es nur ne Windows-Nachricht schickt, mehr nicht^^.
Dachte halt ich mach das mal allgemein nutzbar.

Zu dem Fehler:
Peinlicherweise fehlte das data Verzeichnis :D. Der Download wurde aber jetzt korrigiert. Icon ist da auch dabei, aber leider nur das wxWidgets standard-icon.
Bin künstlerisch leider gar nicht begabt.