While working on one of recent projects, I've stumbled upon few common issues that many meet - even if you are only targeting Windows in GameMaker: Studio, you cannot access files outside the game's AppData directory (not even in program directory). Neither you can order system to open a file, meaning no external "readmes" to be easily hooked up with game, nor portable configuration files, and some other limitations.
So I took an evening and made a simplistic DLL library to bring equivalents to some functions (sleep, execute_shell, non-sandboxed I/O) back for Windows target. Function list is as following:
delay
delay(time_in_ms)
Identical to pre-Studio sleep(ms) routine. Pauses game execution for given number of milliseconds. For example,
delay(2500)
Will pause game execution for 2.5 seconds.
shell_do
shell_do(action, filepath)
Orders system to do specified action to given file. Common ones are "open", "edit", "print", and availability may vary depending on file type and system configuration.
shell_execute
shell_execute(path, args)
Identical to execute_shell. You can also use this to open programs with arguments.
shell_execute_at
shell_execute_at(file, args, directory)
Similar to shell_execute, but you also get to specify working directory for program (or file) ran. This can be useful, if you want to use external tools without specifying absolute paths or having to store them in root of game folder.
file_text_get
file_text_get(path)
Retrieves contents of text file located at given absolute path (no sandboxing) as string. If file does not exist, or an error occurs while retrieving the contents, an empty string is returned.
file_text_put
file_text_put(path, contents)
Replaces contents of file at given path (no sandboxing) with ones provided. If file does not exist, it will be created. Returns, whether the operation was successful.
get_color_win
get_color_win(default_color)
A more or less precise replica of get_color function from older versions of GameMaker.
file_copy_win
file_copy_win(path, newpath)
A non-sandboxed function for copying files. Note: Uses absolute paths!
In addition, the example attached demonstrates usage of most of these functions.
Downloads
Example + extension DLL source code
Revisions
-
January 23, 2016:
Fixed the issue with file handles not being closed automatically.
The example is now distributed as ZIP to circumvent problems with importing.
Source code is now included in the download and is available separately.
Removed shell_open due to inconsistent behavior on some systems - use shell_do("open", path) instead. Added get_color_win, window_set_caption_ext, file_copy_win. -
February 12, 2016:
The DLL no longer requires Visual C++ Runtime to function.
Should help if it previously didn't work for you.
Have fun!
Pingback: GameMaker: Testing two game instances at once
Hi, would you please let me know if you have any way to read the serial number of a hd or pendrive. Through a dll or something like that.
Personally I have not done anything like that, as it’s a rather purpose-specific thing.
It would seem like GetVolumeInformation function might be able to provide that for you. Could probably make a small DLL for that (see official example) or pay someone to do so if you are not able/willing to.
Get the hd number, I’ve already found a dll. But what I want is to get the serial number of a pen drive.
But I have not found anything so far
Thanks for answering
Could you make a GMS2 extension for this? Thanks!
Oh ok just exported it from studio to make it a “gmez” <3 Sorry!
When I do: shell_do(“open”,”C:\Users\” + environment_get_variable(“USERNAME”) + “\AppData\Local\Test\test.txt”)
Nothing happens. Can someone tell me what I am doing wrong?
I find the file_text_get function to be slightly unreliable. Here is a version that always works for me (compiled on mingw g++ 4.9.3):
dllx char* file_text_get(char* file) {
FILE *f;
char *r = NULL;
long fl;
f = fopen(file, “r”);
if (f != NULL) {
fseek(f, 0L, SEEK_END);
fl = ftell(f);
rewind(f);
r = (char*)malloc(sizeof(char)*fl);
if (r != NULL) {
// if a file-sized string was allocated successfully.
if (!fread(r, 1, fl, f)) {
// if failed to read the contents, dealloc the string.
free(r);
r = NULL;
}
}
fclose(f);
}
if (r == NULL) {
// errors yield empty strings
r = (char*)malloc(sizeof(char));
r[0] = 0;
}
return r;
}
Changes:
fopen_s -> fopen
calloc -> malloc
fread -> fl times 1 byte instead of 1 time fl bytes.
Whenever i try to print on a win 7 32bits the app crashes. Is this expected from the DLL? I have no problems on any 64 bits OS.
It is not intended, but neither I can make any assumptions as to why that happens – as can be seen from the DLL source code, it’s calling a single function. There’s nothing else to it.
Function “file_copy_win” is not working when default game data is in %APPDATA%/GameName. Is there any way to fix that?
You can set the path accordingly – current versions of GameMaker have game_save_id variable, which contains the absolute path for game save directory.
Hello,
Does the print argument in shell_do opens the windows actual printer options? How does it work? I would really like to print a file or string.
Thank you.
It should. So you would write the desired data to a file, and then order OS to show the print dialog for it.
To say, the extension currently has a problem with recognizing paths with non-English characters in them, and that, unfortunately, requires a pretty much complete rewrite of the code.
There would be the ability to print on a printer the value of a variable gms .
For example :
Sera pressing the button to send the command to print directly without opening the Print window.
something like :
Ticket
—————————-
Name game
Total : 50 points
I don’t think it’s possible to print something without the user’s permission. That would introduce a lot of security risks.
Actually, your current code allows the dev to print without the user’s permission. It prints with the current default printer without asking anything to the user. It would be nice if there were some parameter on the code to enable the printer menu. Also, im having having a lot of trouble with printing on 32 bits windows, which i have stated below on another comment.
Hello everyone. I downloaded this extension so that I could execute another program from the game. And to be honest, I really really suck at this. I downloaded the file, unzipped it, then opened my project and added the WinDev.extension to the Extensions folder. What’s the simplest possible way to run a program when the key “Alt” is pressed. Any advice is welcome. Thanks.
shell_do or shell_execute would be appropriate, based on whether you need to feed any arguments to the program or not. The sample project includes examples of usage for both, while the post has descriptions of their arguments.
So……… I create an Execute a piece code action, and I type in “shell_do(“C:\Users\Guest\Documents\sample folder\sample.exe”)”? That just brings an error. Please forgive my terrible knowledge about this.
Yes, pretty much. But what’s the error?
“ERROR at line 1 pos 80: Wrong number of arguments to function or script.” What else would I put after it?
Oh, I did mess up the documentation for that. Corrected the post, but probably better to do
shell_execute("C:\Users\Guest\Documents\sample folder\sample.exe", "")
then.And now the file isn’t opening. “shell_execute(“C:\Users\Guest\Downloads\ifunbox_classic\ifunbox_classic\ifunbox.exe”, “”)” is what I’m actually trying to test.
Is there any way to browse for a folder instead of a file? I want something like get_open_filename but with a folder.
Hey!:)
I recently downloaded your extension because I need to execute files with parameters through game maker really bad, but for some reason the shell_execute, shell_execute_at and shell_do commands don’t work for me.
When I call them nothing happens, not even an error.
Any idea how I could fix this? Any help would be appreciated!
There’s an issue that some people are getting with none of the extension fucntions working (DLL simply fails to load), but I haven’t discovered what causes this yet. It would seem like the only thing that it could need would be Visual C++ redistributable, but that didn’t help the other person with the same issue.
Edit: Updated the extension to drop the need for Visual C++ redist.
Oh my god, it works!
Thank you very very much!:)
I have looked forever for an extension that lets me execute .exe files with parameters – and thanks to you, I can do this now!
♥
This has been really useful to me, especially in combination with your article on opening 2 instances of a game from the GM:Studio IDE for doing multiplayer testing. Thank you very much!
I’m having a problem with file_text_get(), though.
When I follow this process:
– create a text file with file_text_put()
– edit the text file in an external editor, and include a line-break
– read the file with file_text_get()
I am unable to properly retrieve the file contents; I get a blank string as the return value.
Is this expected behaviour? Or am I doing something wrong in thinking that I should be able to edit the file externally? I’m fairly new to dealing with text-files in this manner, so it’s likely I’m misunderstanding some basic concept.
I’m running GM:S v.1.4.1657. Thanks very much if you can help at all with this.
Since you don’t have that many options in GameMaker, file_text_get returns an empty string if anything goes wrong. Essentially it does this:
Perhaps reading the same file from two programs at the same time causes problems.
I should probably put up the entire source for the DLL as there are most likely parts of the code that can be done better.
Edit: Looking at it right after posting, the file doesn’t get closed after a successful read. I’ll upload a fix for that soon.
Awesome, thank you!
Okay, a little delayed, but now done – updated the links in the post. I have also added a non-sandboxed file copy function, which should help with some other use cases that aren’t covered by file_text_get\file_text_put.
Hello, Ive have been playing around with your functions. By chance is there a way to access (.ini) files in other game directories? So far everything i try the debug says” Error! not allowing save with filename ‘C:\Users\username\AppData\Local\gamename\options.ini’ ” or i just get it to save it to the default game file in appdata folder. Any help would be great
There are several options:
1. Use file_text_get + file_text_put to copy the INI file from desired game’s folder to the current game’s folder, modify it, and copy it back with the same procedure.
2. Use file_text_get + file_text_put with this really old INI reader/writer that I wrote.
3. If two games are related (e.g. main game and level editor), you can make them share the appdata folder by making both GM:S projects have the same name (does not influence anything else but the appdata folder name for desktop).
Thank you for the quick response it really helped! I took the easier (method 3.) because iv’e spent too much time on this already haha. Now i ran into another issue.
First off i created a game launcher. and i put both(game and launcher) exe. files inside a folder that’s on my desktop. and it works by using:
shell_open(environment_get_variable(“USERPROFILE”) + “/desktop/Folder/ Game.exe”)
I understand you said there’s a shell_execute_at.
my issue is, i want the launcher to know or find the folder that the .exe file is in, which the launcher is in the same folder too. Do you think there is a way to determine where the folders location is?
hello sir. sir i already import the gmez file… and it worked!! but when im trying to put it in my game. the dll’s is missing. please help me sir.. thanks…
You can copy the DLL file to the extension’ folder (in the project directory) manually if GameMaker: Studio fails to do that for you.
Pingback: CCR: Code for Extracting Images from CHIPS.EXE | ExcogitationExcogitation
Hey,
is there any possibility to create a “wait until executed” function? Like in GM8:
execute_program (prog, arg, wait)
We need this for waiting to load a file being edited by another program written in c++.
Hi, it’s me again. Is there any possible way to check if a program is open in Windows? Like, to check if the game is already running?
Sorry to bring up an old post, but this doesn’t seem to work on GMS 1.4 or am I doing something wrong? I’m trying to launch a downloaded and unzipped .exe file. I’ve tried all these commands but none seems to do anything. I’ve tried them in many different way with no luck. Does this extension not work anymore? What would be the best way to execute an .exe file with GMS 1.4? Any help is appreciated.
It should be working. If anything, check if extension files are in place or try re-creating the extension (adding the DLL file to an empty extension and adding needed functions to it) – extensions can break on import in some cases, but I haven’t been able to trace it back to any specific action so far.
Oh, I’ve tried “shell_open(“C:/Windows/Notepad.exe”)” and it worked, so that means that the path i set is wrong. I’m trying to open an .exe at “C:\Users\mypcname\AppData\Local\gamedir\Game.exe”. I’ve tried using all the “*_directory” variables, but their returns are in a wrong directory. How should i set the path?
If you are using 1.4.1451, there’s a game_save_id constant, which should point to that exact directory.
Well, I guess I could of googled that. Thanks a lot for answering!
Also, when I’ve re-read it, I’ve noticed that it might sound like I said “meh, I could of googled that” when I meant “I should of googled that instead of bothering you”. :D
None of the functions work for me. I know that someone said something about creating a new extension and then importing stuff, but I don’t know how to do that. Please help me.
I created a .bat file in root directory which contains a code to open a file located in /.
The code opens a file /, NOT C:/Users/PC/AppData///.
When I run the .bat file from Windows Explorer, everything works fine, but when i run it through ‘shell_execute’, the system cannot find the file.
There’s a shell_execute_at to specify working directory for executed program.
Is it possible to just run .bat without opening the enviroment variables, to execute the shell immediately?
I managed to do something, but i can’t execute_shell using /cmd.exe but everything works fine with /notepad.exe.
Thanks for this. I’m still looking for a way to get the real program_directory when creating a single ‘portable’ executable that the user could drop in any folder to allow creation/reading of config and user data in a subfolder there, but program_directory is still returning an AppData location. The only solution I have so far is annoying the user by making them find the folder using get_open_filename or get_save_filename.
I’ve realized that when creating the application as a “Single runtime executable”, program_directory and working_directory return “\Users\User\AppData\Local\Temp\IXP000.TMP”, but when created as “Compressed Applications zip” they return the folder where the game executable is located.
It seems there may be a bug in file_text_get. To reproduce:
Create an object
In Create: file_text_put(somefilename,””);
In Step: Check for file_text_put() being > 0 bytes every Nth frame, and show_message(filecontents) …
In another app: write a file somefilename, it will see the file has changed and read it but if you then file_text_put(..””) ^^ to clear it after you read it with file_text_get()… ithe file_text_put() won’t take place
yes it appears you left the file handle open after file_text_get ?
I am closing file handles as long as files do actually open. Related code is like so: https://gist.github.com/YellowAfterlife/12301418236eee311f86
It may be that file contents are not being overwritten since the string is empty, but that would be a stdio thing.
Pingback: GameMaker: Testing two game instances at once
Oh well , i knew that it should work that way as executeShell works in other programming languages but for some odd reason when i included gmez to my project and tested, none of these functions worked, so i manually created new extension , imported dll and added all the functions , then it worked.
Seems like GameMaker: Studio currently fails to import included files (such as DLLs) from extensions that it has created. Mildly embarrassing. The fact that thing keeps fairly quiet about calling functions from missing DLLs certainly does not help the situation either. Perhaps that’ll improve in future.
What about opening default browser? It doesn’t seem to work as execute_shell() worked.
shell_open(“https://yal.cc”) will open link in default browser. I think original execute_shell would do same only if second parameter was a blank string. Might update the DLL to behave better in that regards, but you can cover all possible scenarios by picking right functions anyway.