Asset - Extension Execute Shell (for Windows, macOS, and Ubuntu)

Discussion in 'Marketplace' started by Samuel Venable, Sep 13, 2016.

  1. Samuel Venable

    Samuel Venable Time Killer

    Joined:
    Sep 13, 2016
    Posts:
    946
    [​IMG]

    [​IMG]

    [​IMG]

    This extension is for Windows, macOS and Ubuntu.

    Execute third-party applications from your GameMaker Studio games.

    Open or run any file type, whether EXE or not. Supports "wait" param.

    The DLL's full source code included.

    Very big thanks to Josh Ventura, for writing the widen() and shorten() scripts, enabling UTF-8 support on Windows.

    Download Free for GameMaker Studio 1.4 and 2
     
    Last edited: Oct 5, 2018
  2. Samuel Venable

    Samuel Venable Time Killer

    Joined:
    Sep 13, 2016
    Posts:
    946
    This extension has had over 600 downloads, so I assume a good number of users here have it. Is anyone ok with showing me your project and how it uses my extension? I'm just a little curious as to what it is being used for.
     
  3. RizbIT

    RizbIT Member

    Joined:
    Jun 24, 2016
    Posts:
    353
    I had a similar one that kept crashing at game start. Is this one stable and work every time game starts?
     
  4. Samuel Venable

    Samuel Venable Time Killer

    Joined:
    Sep 13, 2016
    Posts:
    946
    Hi @RizbIT

    If you set the wait parameter to 1 on Windows and try to click on or mess with the main game window while waiting for the process to close, it will crash. This is a bug with GM:S itself and how it handles non-async dll calls on Windows. I reported it on the helpdesk and they said they're gonna fix it.

    So if you want the program to run asynchronously or you want to target Ubuntu you should be fine. This is a Windows-only issue. Set the second argument to 0 on Windows and you should be all set. :)

    For example:
    Code:
    ExecuteShell("notepad.exe",0);
     
    Last edited: Oct 23, 2016
  5. RizbIT

    RizbIT Member

    Joined:
    Jun 24, 2016
    Posts:
    353
    no i mean right at the start when you define the external call in the dll... on the other guys dll sometimes on game start it crashed at that point
     
  6. Samuel Venable

    Samuel Venable Time Killer

    Joined:
    Sep 13, 2016
    Posts:
    946
    As long as the wait parameter is 0, there is no crash. It's been thoroughly tested. No crash at game start. No crash after game start.
     
  7. renex

    renex Member

    Joined:
    Jun 23, 2016
    Posts:
    506
    Samuel Venable likes this.
  8. Samuel Venable

    Samuel Venable Time Killer

    Joined:
    Sep 13, 2016
    Posts:
    946
    Great news everyone!

    Version 9.1.0 Released!

    • Finally fixed that nasty bug on Windows with setting the wait argument to true.

    • Added an optional third argument to allow opening files hidden on Windows.
     
  9. Samuel Venable

    Samuel Venable Time Killer

    Joined:
    Sep 13, 2016
    Posts:
    946
    Thanks to @appleWolf, this extension is now 64-bit Mac compatible! Well, hopefully. I still need someone to test it. The code is portable for Unix-based operating systems. I already know it works on Linux, which is Unix-based.

    Mac is also based on Unix, and it built without any errors, so I can't imagine it not working, unless someone tries it on an unsupported architecture. If you would like to be a tester, shoot me a PM! If it works as intended, I'll announce Mac is officially supported at the top of the asset's description. :D

    (testers will be credited)
     
  10. ElChingles

    ElChingles Member

    Joined:
    Oct 13, 2017
    Posts:
    5
    Last edited: May 26, 2018
    Samuel Venable likes this.
  11. Samuel Venable

    Samuel Venable Time Killer

    Joined:
    Sep 13, 2016
    Posts:
    946
    Version 9.3.0 Released!
    • Added official support for macOS.
     
  12. Gravityhamster48

    Gravityhamster48 Member

    Joined:
    Dec 6, 2018
    Posts:
    5
    Hello!

    I am new here, but definitely not new to Gamemaker. I hope this is an okay place to ask this question. It is directly related to your extension (which is a pretty cool piece of work, by the way).

    So I programmed an updater/launcher in Gamemaker for Windows that downloads the executable file for my game and saves it to the launcher's dedicated app data folder. I then execute the program with your extension. The problem comes when there are multiple users on the system. The process all works flawlessly on the primary user account, but then when the secondary user uses the launcher, it downloads just fine, but will not execute the program.

    Here is the code that defines the folder's location:
    Code:
    globalvar place;
    place = environment_get_variable("LOCALAPPDATA") + "\Updater";
    "Updater" being the name of the launcher I have created. I've tried using "game_save_id", "working_directory", and "program_directory". The latter two do not work and the first yields the same result.

    Here is the code that downloads the file. This code works perfectly no matter the user account. I'm just including it to give you an idea of what's going on here:
    Code:
    size = ds_map_find_value(async_load,"contentLength");
    progress = ds_map_find_value(async_load,"sizeDownloaded");
    if (perc < 100)
    perc = round((progress/size)*100)
    if (ds_map_find_value(async_load, "id") == async_ini)
    {
          var status = ds_map_find_value(async_load,"status");
          if (status == 0 && statussss < 2)
          {
                statussss = 3;
                ini_open("localversion.ini");
                ini_write_real('version','number',ver);
                ini_close();
                statussss = 4;
                instance_create(x,y,o_Launch);
          }
    }
    Finally, here is the code that launches the game (the game executable being called "GunCave.exe"):
    Code:
    timer++;
    if (timer >= 30*60)
    {
        if (file_exists(place+"\GunCave.exe"))
        {
            o_Updater.neednew = 6;
            if (timer >= 33*60)
            {
                ExecuteShell(place+"\GunCave.exe", true);
                game_end();
            }
        }
        else
        {
            o_Updater.neednew = 7;
            if (timer >= 33*60)
            {
                game_end();
            }
        }
    }
    This is where the problem lies. This code works on the primary user account, but not on the secondary account. On the primary account, it successfully launches my game and then closes the launcher once the game is closed. On the secondary account, the game fails to launch and the launcher closes.

    I know I've read places that have discouraged making a launcher in Gamemaker, but I was able to create and get it to work, up until this issue. I hope someone can help me.

    Thanks in advance,
    ~Gravityhamster
     
    Last edited: Dec 6, 2018
  13. Samuel Venable

    Samuel Venable Time Killer

    Joined:
    Sep 13, 2016
    Posts:
    946
    @Gravityhamster48 Hey!

    What's the difference between the two accounts? Is one of them by any chance not administrative? Does it require administrative privileges to run the exe?
     
  14. Gravityhamster48

    Gravityhamster48 Member

    Joined:
    Dec 6, 2018
    Posts:
    5
    Thank you so much for replying!

    The executable does not require administrative privileges to run. Even so, though, I've tried making the secondary user both regular and administrator and the result is the same: The executable doesn't launch and the launcher program closes.
     
  15. Samuel Venable

    Samuel Venable Time Killer

    Joined:
    Sep 13, 2016
    Posts:
    946
    Try removing the file_exists call. I'm interested in hearing if it runs the file after commenting that out. I might have a solution if that ends up being the problem.

    I'd also check if the path and file exists manually, outside of code, i.e. in explorer, and also what value the environment variable returns on both users by contrast.
     
    Last edited: Dec 6, 2018
  16. Gravityhamster48

    Gravityhamster48 Member

    Joined:
    Dec 6, 2018
    Posts:
    5
    It still does not work if I remove the "file_exists" call. I sent you in my original post the code for when it launches the game offline. If the the launcher detects that it cannot connect to my server to check for a new update, it will run the code I sent you. Otherwise, it checks for an update and runs this code instead, which has no "file_exists" present in it:
    Code:
    i++;
    if (i == 5)
    {
        ExecuteShell(place+"\GunCave.exe", true);
        game_end();
    }
    This code still does not launch the game correctly under the secondary account. (Obviously, it does run correctly under the primary account.)

    The executable file is present in the desired appdata folder and I can even manually execute the file from there and it runs fine. Also, when I run my launcher I draw the appdata directory (stored in variable "place") onto the screen. The directory is correct on both accounts, changing the username to match the current user account and matches the directory manually found in Windows Explorer.

    Hopefully that all makes sense. If you need clarification, please ask.
     
  17. Samuel Venable

    Samuel Venable Time Killer

    Joined:
    Sep 13, 2016
    Posts:
    946
    I'm not sure even if I had your source code to debug with how much help that would be, it's really odd that it works on one account, but not the other. I hate to say it, but I'm stumped. Unless I can reproduce this issue myself, I don't see how I can figure out what's going wrong. :(
     
  18. Gravityhamster48

    Gravityhamster48 Member

    Joined:
    Dec 6, 2018
    Posts:
    5
    Oh well. Thanks for trying!... Maybe I'll just have to go at it with a different approach. Maybe even make a launcher in a separate language. I dunno.

    I will say that you can create the same basic scenario by following these steps: Make a new user on your computer. You can easily do this in the settings and don't even have to make a new Microsoft account to do it (and it can easily be deleted later). Create a new project in Gamemaker. Have the project write a text file (I prefer a .ini file) so that it creates the appdata directory for your project, then manually place any standalone executable in the appdata directory for your project (These steps must be done under BOTH user accounts). Make an "ExecuteShell" command to run that program you put in the project's directory. Now export the project to an executable and run it. It should run the executable that you placed in the appdata folder for your program under your primary user account, but it should not successfully run under the secondary account.

    If it's too much of a pain to try to figure out, don't worry about it, but there's some basic steps if you wish to try to reproduce the issue.
     
    Samuel Venable likes this.
  19. Samuel Venable

    Samuel Venable Time Killer

    Joined:
    Sep 13, 2016
    Posts:
    946
    I'll give that a shot tomorrow. It's getting late where I live. I'll get back to you with the results of my testing.

    Edit:

    Trying it now as we speak...

    Edit2:

    It works for me on both accounts. Am I doing something wrong?

    I run this on account 1:

    Code:
    if (os_type == os_windows)
    {
        ini_open("test.ini");
        ini_write_real("hello", "world", 1);
        ini_close();
       
        if (file_exists(game_save_id + 'notepad.exe'))
            ExecuteShell('"' + game_save_id + 'notepad.exe"', true);
    }
    
    game_end();
    It created the ini file but the exe needs to be copied there in order to run so I do that.

    Then I hit run again.

    Export project.

    Do all the same as above but on account 2.

    It all worked for me. notepad.exe ran on both accounts after I copied it to the correct folder on both accounts.
     
    Last edited: Dec 6, 2018
    Gravityhamster48 likes this.
  20. Gravityhamster48

    Gravityhamster48 Member

    Joined:
    Dec 6, 2018
    Posts:
    5
    Yes! Thanks to you, it's fixed!!

    What I found out was that my syntax was incorrect. Here was the old code for the file path:
    Code:
    globalvar place;
    place = environment_get_variable("LOCALAPPDATA") + "\Updater";
    Execute:
    Code:
    i++;
    if (i == 5)
    {
        ExecuteShell(place+"\GunCave.exe", true);
        game_end();
    }
    And here is the new, working code for the file path execution:
    Code:
    i++
    if (i == 5)
    {
        ExecuteShell('"' + string(game_save_id) + 'GunCave.exe"', true);
        game_end();
    }
    I don't know if using "LOCALAPPDATA" rather than "game_save_id" would work, but it doesn't matter. I'd rather use "game_save_id" anyway. Here's the things I could note that you did differently compared to me:
    • First of all, you excluded the "\" before the executable.
    • Second, when I tried "game_save_id" I neglected to convert to a string.
    • Third, was the use of double and single quotes. Notice the difference between this:
      Code:
      place+"\GunCave.exe"
      and this:
      Code:
      '"' + string(game_save_id) + 'GunCave.exe"'
    • I also just removed the variable "place" for when I execute as a whole just to make it easier to implement the correct quotes and reduce confusion.
    Thank you so much for your help! I'm so glad that it was a problem with my code and not with the extension!

    You've been great to work with!
    ~Gravityhamster
     
    Samuel Venable likes this.
  21. Samuel Venable

    Samuel Venable Time Killer

    Joined:
    Sep 13, 2016
    Posts:
    946
    I'm glad you've figured it out, and that I could help! Using the quotes within quotes is generally a good practice for command line stuff, since there are sometimes paths with spaces. Some path functions and variables do not include the final slash, but on Windows at least, I know working_directory and game_save_id have it. It may be different for getting the environment variables, as well as program_directory. I can't remember whether temp_directory has the last slash. In any case, I agree the inconsistency is a bit confusing and I have reported this to the bug tracker for GMS 1.4 and 2. However, they didn't fix it before the end of 1.4's lifetime, so your practice of using the extra slash is probably better, also because it is backwards compatible with pre-Studio GM versions.

    Edit:

    Also, as far as I know, you don't need to wrap game_save_id in a string() function. I did that by accident originally, but updated my post to remove that.
     
    Last edited: Dec 6, 2018

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice