Guten Tag, community,
vor etwa 2 Wochen hatte ich mein erstes Rendezvous mit C++ und hiermit will ich euch mein erstes publizierbares Ergebnis nicht vorenthalten.
An dieser Stelle möchte ich mich auch bei den Mitgliedern des GM-Teams im Chat hier bedanken die mir bei einigen Anfänger-Fragen beigestanden haben
So, nun zur DLL.
Als ich mal ein einem Spiel mit online-Anbidnung gearbeitet habe, ist mir aufgefallen dass, wenn man dafür Funktionen aus anderen DLLs benutzt die z.B. eine Seite abrufen, die time-out Zeit bei fehlender Verbindung relativ lang ist, d.h. wenn ein Spiel Internetverbindung automatisch benutzt, führt das zu einem kurzzeitigen Blockieren.
Es gibt schon ein paar DLLs die behaupten einem zu sagen ob Inet Verbindung besteht oder nicht. Diese geben aber nur an ob der PC per Lan an ein Netzwerk angeschlossen ist und nicht ob tatsächlich eine Internetverbindung besteht.
Dieses Problem soll nun diese DLL lösen.
Im Grunde benutzt sie dafür die PING Funktion des Systems. Es wird jedoch nicht bei Aufruf einer Funktion erst 'gepingt' und erst dann das Ergebnis zurückgegeben (was ebenfalls ein Blockieren des Spiels zur Folge hätte), sondern dies geschieht im Hintergrund in regelmäßigen Zeitabständen (die bestimmt werden können). Die Funktion zum Abrufen der Verbindung ist somit sehr schnell und gibt das Ergebnis der letzten Verbindungsversuchs zurück.
Die Benutzung ist relativ einfach. Das Beispielprojekt sowie die Komentare/Namen der Funktionionen sollten alles erklären.
Zusatzfunktion: Zusätzlich kann die DLL eine Komandozeile versteckt aufrufen! D.h. ohne dass dieses typische, schwarze cmd-Fenster aufpoppt. Dabei kann gewählt werden ob das Spiel warten soll bis die Ausführung beendet wurde oder ob auch dies im Hintergrund geschehen soll.
Hiermit veröffentliche ich auch den Quellcode dieser DLL.
Spoiler anzeigen
Ich habe ihn (allerdings auf Englisch) vollständig kommentiert. Eventuell kann jemand etwas daraus lernen.. auch wenn ich Anfänger dieser Sprache bin..
Würde mich auch freuen wenn jemand zum Beispiel Memoryleaks, schlecht Programierte Dinge oder Bugs in der DLL findet und mitteilt!
Hier zudem zwei Tutorials zum Thema DLLs mit C++: gmc.yoyogames.com/index.php?showtopic=458187 und gmc.yoyogames.com/index.php?showtopic=405812
Zur Sprache selbst kann man durch Google sehr viel Information (viel, viel mehr als zu GML) finden. Etwas wirklich herrausragendes konnte ich aber leider nicht ausfindig machen und mir wurde auch empfohlen eher eins der bekannteren C++ Bücher (ja, Bücher gibt es anscheinend noch ) zu kaufen wenn man es wirklich ernst meint (grade billig sind die nicht, dafür gibt es aber gratis Umgebungen/Compiler für C++ wie das Visual Studio Express oder Code::Blocks).
Hier der Code. Einen header benötigt das Projekt nicht.
Alles anzeigen
Ihr dürft mit dem Code machen was ihr wollt.
EDIT: Die in den folgenden Posts erwähnten Fehler wurden behoben.
Hoffe mal dass dies jemandem nützlich ist.
EDIT: 2 UPDATE: Die Funktion um die Komandozeile aufzurufen wurde korigiert. Jetzt ist es tatsächlich möglich CMD-Zeilen auszufrühren, nicht nur Programme mit Argumenten zu starten!
Basierend darauf habe ich ein Skript geschrieben namens directory_delete um GM's fehlende Funktion auszugleichen. Aus Sicherheitsgründen kann man mit dem Skript aber nur Unterordner eines Spiels löschen, also nicht für Schadsoftware geignet.
vor etwa 2 Wochen hatte ich mein erstes Rendezvous mit C++ und hiermit will ich euch mein erstes publizierbares Ergebnis nicht vorenthalten.
An dieser Stelle möchte ich mich auch bei den Mitgliedern des GM-Teams im Chat hier bedanken die mir bei einigen Anfänger-Fragen beigestanden haben
So, nun zur DLL.
Als ich mal ein einem Spiel mit online-Anbidnung gearbeitet habe, ist mir aufgefallen dass, wenn man dafür Funktionen aus anderen DLLs benutzt die z.B. eine Seite abrufen, die time-out Zeit bei fehlender Verbindung relativ lang ist, d.h. wenn ein Spiel Internetverbindung automatisch benutzt, führt das zu einem kurzzeitigen Blockieren.
Es gibt schon ein paar DLLs die behaupten einem zu sagen ob Inet Verbindung besteht oder nicht. Diese geben aber nur an ob der PC per Lan an ein Netzwerk angeschlossen ist und nicht ob tatsächlich eine Internetverbindung besteht.
Dieses Problem soll nun diese DLL lösen.
Im Grunde benutzt sie dafür die PING Funktion des Systems. Es wird jedoch nicht bei Aufruf einer Funktion erst 'gepingt' und erst dann das Ergebnis zurückgegeben (was ebenfalls ein Blockieren des Spiels zur Folge hätte), sondern dies geschieht im Hintergrund in regelmäßigen Zeitabständen (die bestimmt werden können). Die Funktion zum Abrufen der Verbindung ist somit sehr schnell und gibt das Ergebnis der letzten Verbindungsversuchs zurück.
Die Benutzung ist relativ einfach. Das Beispielprojekt sowie die Komentare/Namen der Funktionionen sollten alles erklären.
Zusatzfunktion: Zusätzlich kann die DLL eine Komandozeile versteckt aufrufen! D.h. ohne dass dieses typische, schwarze cmd-Fenster aufpoppt. Dabei kann gewählt werden ob das Spiel warten soll bis die Ausführung beendet wurde oder ob auch dies im Hintergrund geschehen soll.
Hiermit veröffentliche ich auch den Quellcode dieser DLL.
Ich habe ihn (allerdings auf Englisch) vollständig kommentiert. Eventuell kann jemand etwas daraus lernen.. auch wenn ich Anfänger dieser Sprache bin..
Würde mich auch freuen wenn jemand zum Beispiel Memoryleaks, schlecht Programierte Dinge oder Bugs in der DLL findet und mitteilt!
Hier zudem zwei Tutorials zum Thema DLLs mit C++: gmc.yoyogames.com/index.php?showtopic=458187 und gmc.yoyogames.com/index.php?showtopic=405812
Zur Sprache selbst kann man durch Google sehr viel Information (viel, viel mehr als zu GML) finden. Etwas wirklich herrausragendes konnte ich aber leider nicht ausfindig machen und mir wurde auch empfohlen eher eins der bekannteren C++ Bücher (ja, Bücher gibt es anscheinend noch ) zu kaufen wenn man es wirklich ernst meint (grade billig sind die nicht, dafür gibt es aber gratis Umgebungen/Compiler für C++ wie das Visual Studio Express oder Code::Blocks).
Hier der Code. Einen header benötigt das Projekt nicht.
C-Quellcode
- //-//
- #include <windows.h>
- #include <process.h>
- #include <string>
- using namespace std;
- //-//
- // those lines include other files and name spaces which enable a variety of functions
- #define DLLEXPORT extern "C" __declspec(dllexport) // an important line which simplifies your work when writting a DLL for GM
- // whenever a fucntion shall be acessible from GM, write DLLEXPORT before it from now on
- bool check;
- volatile bool connected;
- float check_interval;
- char* cmdln;
- char* cmdlne;
- PROCESS_INFORMATION pI_global;
- // initializes a bunch of _global_variables of diffrent data types.
- // the word "volatile" enables in this case secure editing of the variable even from a diffrent process
- void showError(LPCSTR capt)
- {
- LPTSTR Error = 0;
- FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
- NULL,
- GetLastError(),
- 0,
- (LPTSTR)&Error,
- 0,
- NULL);
- MessageBox( 0, Error,capt, MB_OK );
- }
- BOOL __stdcall DllMain(HANDLE hinstDLL, DWORD dwReason, LPVOID lpvReserved) // This function is _automatically_ called by the system when the DLL is laoded into GM or when it's freed from it
- {
- switch (dwReason) // with this variable you can check what exactly happened
- {
- case DLL_PROCESS_ATTACH: // start
- {
- check = false;
- connected = false;
- check_interval = 0;
- cmdln = "";
- cmdlne = "";
- // Gives all those variables a start-value
- } break;
- case DLL_PROCESS_DETACH: // end
- {
- delete[] cmdln; // deletes this variable since it was created with "new" (that always requires a "manual" delete)
- delete[] cmdlne;
- } break;
- }
- return TRUE; // return whetehr initialisation has been sucessfull
- }
- void backgroundProcess(void*);
- // This line just prepares the function backgroundProcess.
- // This needs to happen to be free in what order we can place the functions in the DLL.
- // Delete this line and you will notice that you cannot compile the next function because
- // it does not see that there is a function "backgroundProcess" below
- DLLEXPORT double Start(char* input, double time) { // This initializes the first function for GM. The data type for passing a string has therefore to be a char* while numbers from GM need a double.
- // Don't forget to write DLLEXPORT !
- string strInput(input); // turns the content of the passed string into the C++ string-variable called strInput
- if (strInput == "")
- {
- cmdln = "ping www.google.com -n 2"; // pinging a standart, hopefully always online site
- }
- else
- {
- strInput = "ping "+strInput+" -n 2"; // pinging the given adress
- cmdln = new char[strInput.length()]; // assigns a new array of char(acters) to the existing pointer called cmdln
- strcpy_s(cmdln,sizeof(strInput),strInput.c_str()); // copies the string into the this array
- }
- check = true;
- check_interval = (float)(time*1000); // sets the time between two ping-checks.
- _beginthread( backgroundProcess, 0, 0); // Runs the function "backgroundProcess" in a new Thread (!)
- // That means it will run parallel to the current thread which is also the thread of Game Maker.
- // Therefore everything called there is not blocking the game.
- Sleep(10); // the system apperently needs time to initialize the secondary process before the calling "event" ends - not really sure whether this is needed.
- return 1;
- }
- void backgroundProcess(void*) // this is the prozess which is called in the background in another Thread
- {
- while(check) // this causes this thread to never end until check is == false
- {
- //-//
- STARTUPINFO startInf;
- ZeroMemory( &startInf, sizeof(startInf) );
- startInf.cb = sizeof(startInf);
- PROCESS_INFORMATION procInf;
- ZeroMemory( &procInf, sizeof(procInf) );
- //-//
- //Initializes two local, required data structures and fills them with 0's but without information (no information).
- if (!CreateProcess(NULL,cmdln,NULL,NULL,false,NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW,NULL,NULL,&startInf,&procInf))
- MessageBox(0, "The Ping failed for some reason. Is the adress correct?", cmdln , MB_OK);
- // The first of thsoe two lines eventually starts the Process. That process only contains the
- // command-line code from "cmdln" which we aranged before.
- // The CREATE_NO_WINDOW attribute prevents the window from showing up. Remove this (including the "| " part)
- // and the usual cmd-window will show up.
- // Waits until the created process finishes (so that emans until the pings have completed
- WaitForSingleObject( procInf.hProcess, INFINITE );
- // Because we are in a separate thread, this waiting time does not block the progrmm in Game Maker.
- DWORD result; // creates a special variable
- if (!GetExitCodeProcess(procInf.hProcess, &result )) // the Ping-Function of Windows returns a special data type which is set here into the variable "result". this function also returns false if something went wrong before.
- MessageBox(0, "Retrieving a result from the ping failed for some reason.", "" , MB_OK);
- else
- connected = (result == 0);
- // For Ping, a result of "0" means that everything worked fine and that the pingw as delivered and recieved right. Everythinge else is a failure.
- CloseHandle(procInf.hProcess );
- CloseHandle(procInf.hThread ); // Closes the process
- Sleep(check_interval); // sleeps so long until it should ping again.
- }
- }
- DLLEXPORT double getStatus() { // initializes the function for recieving information.
- return connected;
- }
- DLLEXPORT double Stop() { // initializes the Stopping function.
- if (check == true)
- {
- check = false; // this will stop the background Thread.
- delete[] cmdln; // this will free the space reserved for cmdln
- return 1;
- }
- return 0;
- }
- void endProcess(void*);
- // Again a fucntion has to be initialised before it gets it's own code (down there). So you can mentain a logical order of your functions.
- DLLEXPORT double runCmd(char* input, double wait) { // Calls the run function. It's main built is the same as below.
- string strInput(input); // turns the content of the passed string into the C++ string-variable called strInput
- strInput = "cmd.exe /c "+strInput; // adds that string to the beginning sicne the line you provided has to be give to the cmd.exe
- cmdlne = new char[strInput.length()];
- strcpy(cmdlne,strInput.c_str()); // copies the string into this array
- STARTUPINFO startInf;
- ZeroMemory( &startInf, sizeof(startInf) );
- startInf.cb = sizeof(startInf);
- PROCESS_INFORMATION procInf;
- ZeroMemory( &procInf, sizeof(procInf) );
- if (!CreateProcess(NULL,cmdlne,NULL,NULL,false,NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW,NULL,NULL,&startInf,&procInf))
- MessageBox(0, "The command line which was meant to be executed, failed!", input , MB_OK);
- if (wait == 1)
- {
- WaitForSingleObject( procInf.hProcess, INFINITE );
- bool ret = false;
- DWORD result;
- if (GetExitCodeProcess(procInf.hProcess, &result))
- ret = true;
- CloseHandle(procInf.hProcess );
- CloseHandle(procInf.hThread ); // Closes the process
- if (ret) return (double)(int)result; // don't ask me why the heck this sort of conversion is needed.
- // It doesn't seem to be able to convert the result directly
- // into the required format (double) to be returned
- }
- else
- {
- pI_global = procInf; // this variable is global
- _beginthread( endProcess, 0 , 0); // runs the function down there in another background thread.
- // This secures that the process is closed properly.
- Sleep(10);
- }
- return 1; // return 1 to show that calling has been sucessfull
- }
- void endProcess(void*)
- {
- WaitForSingleObject( pI_global.hProcess, INFINITE ); // waits for the process to end
- CloseHandle( pI_global.hProcess );
- CloseHandle( pI_global.hThread ); // closes it
- }
Ihr dürft mit dem Code machen was ihr wollt.
EDIT: Die in den folgenden Posts erwähnten Fehler wurden behoben.
Hoffe mal dass dies jemandem nützlich ist.
EDIT: 2 UPDATE: Die Funktion um die Komandozeile aufzurufen wurde korigiert. Jetzt ist es tatsächlich möglich CMD-Zeilen auszufrühren, nicht nur Programme mit Argumenten zu starten!
Basierend darauf habe ich ein Skript geschrieben namens directory_delete um GM's fehlende Funktion auszugleichen. Aus Sicherheitsgründen kann man mit dem Skript aber nur Unterordner eines Spiels löschen, also nicht für Schadsoftware geignet.
Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von DragonGamer ()