Jump to content


Photo

ProcessLauncher.DLL


  • Please log in to reply
13 replies to this topic

#1 Big J

Big J

    GMC Member

  • GMC Member
  • 2853 posts
  • Version:GM8.1

Posted 21 July 2010 - 10:24 PM

I found myself often wanting to launch an application with execute_shell() or execute_program(), but the launched program can't find the files it needs to run, because Game Maker is lazy and assumes that every program I run is to be run from my game's folder. This has bugged me for years, and I finally managed to write a DLL to do proper program execution. This took me hours since I am horrible at C++. :P

The functions in my DLL work the same as the GM functions, but each has an extra parameter for the directory.

execute_program_dir(string Program, string Directory, string Arguments, real Wait)
execute_shell_dir(string Program, string Directory, string Arguments)

Download
MediaFire
64Digits
Dropbox
- ProcessLauncher.dll
- ProcessLauncher.gm6
- ProcessLauncher.gml

dllmain.cpp (C++ source code for the 2 external functions)
#include "dll.h"
#include <windows.h>
#define DLLEXPORT extern "C" __declspec(dllexport)
DLLEXPORT double ProcessLaunch(char* myProcessName, char* myProcessDirectory, char* myProcessArgs)
{
    ShellExecute(NULL,
    "open",
    myProcessName,
    myProcessArgs,
    myProcessDirectory,
    SW_SHOWNORMAL);
    return 0;
}

DLLEXPORT double ProgramLaunch(char* myProcessName, char* myProcessDirectory, char* myProcessArgs, double myProcessWait)
{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    int spi = sizeof(pi);
    int ssi = sizeof(si);            
    memset(&si, 0, sizeof(si));
    si.cb = sizeof(STARTUPINFO);
    ZeroMemory(&pi, sizeof(pi));
    int b = 0;
    b = CreateProcess(
    myProcessName,
    myProcessArgs,
    NULL,
    NULL,
    0,
    CREATE_NO_WINDOW,
    NULL,
    myProcessDirectory,
    &si,
    &pi);
    if (myProcessWait)
    {
        WaitForSingleObject(pi.hProcess, INFINITE);      
    }
    return 0;
}

Here's dll.h if it matters:
#ifndef _DLL_H_
#define _DLL_H_

#if BUILDING_DLL
# define DLLIMPORT __declspec (dllexport)
#else /* Not BUILDING_DLL */
# define DLLIMPORT __declspec (dllimport)
#endif /* Not BUILDING_DLL */


class DLLIMPORT DllClass
{
  public:
    DllClass();
    virtual ~DllClass(void);

  private:

};


#endif /* _DLL_H_ */

If for some reason you get problems with this DLL and you're a C++ wizard, don't hesitate to point out any mistakes I made. This DLL works perfectly... on my end. Perhaps I should mention that I compiled it with Bloodshed DevC++.

Note: If you don't understand why this is useful, then you probably don't need it. It may not do much, but it DOES extend the functionality of Game Maker. :lol:

I was previously working around the limitation of GM by writing a batch file and executing it, but that's cheap in my opinion. :dry:

No credit is needed. Despite how much I struggled to make this, setting the working directory for a launched program is really basic stuff that GM, in my opinion, should have already been capable of with the built-in execute_program/shell functions. ;)

(It's really easy to do in Visual Basic 2008 Express)

Edited by Big J, 22 August 2012 - 09:22 PM.

  • 2

Get your GM 8.1 Anti-Aliasing here!

2712265.png

http://www.youtube.com/Sporkinator


#2 freko

freko

    The Professional

  • GMC Member
  • 504 posts
  • Version:GM8

Posted 23 July 2010 - 03:18 PM

...because Game Maker is lazy and assumes that every program I run is to be run from my game's folder.


That can be fixed even without a dll.

Edited by freko, 23 July 2010 - 03:19 PM.

  • 0

#3 Big J

Big J

    GMC Member

  • GMC Member
  • 2853 posts
  • Version:GM8.1

Posted 23 July 2010 - 08:18 PM

What exactly is your point? Currently, Game Maker cannot execute another program from its own working directory. A good test is download and install Battlezone and have a Game Maker game on your desktop execute this code:
var app, args, wait;
app = "C:\Program Files\Battlezone 1998\Battlezone\bzone.exe";
args = "/win /nointro";
wait = 0;
execute_program(app, args, wait);
It won't work. Battlezone will pop up an error saying something to the effect of:

Unable to find required files to run.

That's because the working directory of the program/game (Battlezone) was set to the desktop, or wherever the calling application is located. :snitch:

So would you care to tell me how I fix that without a DLL? :huh: I wouldn't have spent time painfully writing myself a DLL in C++ if I didn't need it, genius. :rolleyes:

With the DLL, I fix the problem like this:
var app, args, wait;
app = "C:\Program Files\Battlezone 1998\Battlezone\bzone.exe";
args = "/win /nointro";
wait = 0;
execute_program_dir(app, filename_dir(app), args, wait);

Edited by Big J, 27 November 2011 - 09:59 PM.

  • 0

Get your GM 8.1 Anti-Aliasing here!

2712265.png

http://www.youtube.com/Sporkinator


#4 DanRedux

DanRedux

    GMC Member

  • GMC Member
  • 1404 posts
  • Version:GM:Studio

Posted 23 July 2010 - 09:25 PM

I saw this:

sizeof(pi)

And laughed.
  • 0

#5 Big J

Big J

    GMC Member

  • GMC Member
  • 2853 posts
  • Version:GM8.1

Posted 23 July 2010 - 09:45 PM

Yeah, that is pretty funny. :lol: Size of Pi HAHA.

The variable names aren't mine, they're like that because I copied code segments I found in Google searches, because I suck at C++. That part of the code is mostly Greek to me until the actual CreateProcess() call. It took me long enough to get it working that I didn't DARE change anything once it finally worked. Seriously, making this DLL was not fun, and I breathed a sigh of relief when it was done. I have no idea why I need to know the sizeof() anything. I have no idea why CreateProcess() is so complex and requires the setup code above it. I don't know what '&variable' does that simply 'variable' does not. ShellExecute was easy... CreateProcess was difficult... needed it to reproduce the GM execute_program() 'wait' argument, which specifies whether to wait for the process to finish before the game continues.
  • 0

Get your GM 8.1 Anti-Aliasing here!

2712265.png

http://www.youtube.com/Sporkinator


#6 freko

freko

    The Professional

  • GMC Member
  • 504 posts
  • Version:GM8

Posted 24 July 2010 - 11:38 AM

So would you care to tell me how I fix that without a DLL?


Sure :)

Take this string...
"start "C:\Program Files\Battlezone 1998\Battlezone\bzone.exe -win -nointro""
or
"start "C:\Program Files\Battlezone 1998\Battlezone\bzone.exe""
or
"start C:\Program Files\Battlezone 1998\Battlezone\bzone.exe"
And write it to a file in the same location as the game, using gamemaker's file write functions.
Make sure the file is having a ".bat" extension.
Then execute & delete it.


edit:-
refer here for cmd commands:-
http://www.ebcak.com/archives/462

Edited by freko, 24 July 2010 - 02:59 PM.

  • 0

#7 Big J

Big J

    GMC Member

  • GMC Member
  • 2853 posts
  • Version:GM8.1

Posted 24 July 2010 - 08:21 PM

So would you care to tell me how I fix that without a DLL?


Sure :)

Take this string...
"start "C:\Program Files\Battlezone 1998\Battlezone\bzone.exe -win -nointro""
or
"start "C:\Program Files\Battlezone 1998\Battlezone\bzone.exe""
or
"start C:\Program Files\Battlezone 1998\Battlezone\bzone.exe"
And write it to a file in the same location as the game, using gamemaker's file write functions.
Make sure the file is having a ".bat" extension.
Then execute & delete it.


edit:-
refer here for cmd commands:-
http://www.ebcak.com/archives/462

You're not paying attention, I already know how to work with batch files. That's a workaround, not a solution.

I was previously working around the limitation of GM by writing a batch file and executing it, but that's cheap in my opinion. <_<

I didn't like having the black window pop up, and launching it directly is faster than writing a batch file.

Edited by Big J, 24 July 2010 - 08:42 PM.

  • 0

Get your GM 8.1 Anti-Aliasing here!

2712265.png

http://www.youtube.com/Sporkinator


#8 DanRedux

DanRedux

    GMC Member

  • GMC Member
  • 1404 posts
  • Version:GM:Studio

Posted 24 July 2010 - 08:25 PM

Big J.. That anti-spam thing in your siggy.. Love it. Thanks for that. The DLL you made, it's uses are rare, but that anti-spam thing, now that's a goldmine!
  • 0

#9 score_under

score_under

    Least kawaii

  • GMC Member
  • 1321 posts

Posted 25 July 2010 - 12:40 AM

I have no idea why I need to know the sizeof() anything.

It's for backwards compatibility. On older versions of Windows, there were less options in the struct when launching processes. So that Windows knows which version of the structure you're using, you pass it the size of the structure.

Also, some older compilers don't have the newer, more up-to-date structs. These will be missing a few parameters and thus be smaller - since you've passed the size of the struct, Windows will know that these parameters are missing.
  • 0

Anti-Decompiler for GM6.1 to GM8.1.91! :GM8_new: [Main skin by Sindarin]
Discontinued.

decimal2.png
^ Signature image because it's been sorta empty since the old host died

If you need to contact me, I still get notification emails from PMs.


#10 Big J

Big J

    GMC Member

  • GMC Member
  • 2853 posts
  • Version:GM8.1

Posted 25 July 2010 - 01:16 AM

Big J.. That anti-spam thing in your siggy.. Love it. Thanks for that. The DLL you made, it's uses are rare, but that anti-spam thing, now that's a goldmine!

Yeah, I saw that anti-spam thing in somebody else's signature, checked it out. Killing spam sounded like loads of fun, so I added it to my signature. :)

I know the uses of this DLL are rare, but it's here anyway. :D

I have no idea why I need to know the sizeof() anything.

It's for backwards compatibility. On older versions of Windows, there were less options in the struct when launching processes. So that Windows knows which version of the structure you're using, you pass it the size of the structure.

Also, some older compilers don't have the newer, more up-to-date structs. These will be missing a few parameters and thus be smaller - since you've passed the size of the struct, Windows will know that these parameters are missing.

I'm not even familiar with what a "struct" is, though by the name I think it's some kind of data structure. C++ newb I am. :P

I took C++ programming in college, but they only taught us basics, and we made simple little useless applications that ran in command prompt windows. :lol:

Edited by Big J, 31 August 2012 - 09:51 PM.

  • 0

Get your GM 8.1 Anti-Aliasing here!

2712265.png

http://www.youtube.com/Sporkinator


#11 Big J

Big J

    GMC Member

  • GMC Member
  • 2853 posts
  • Version:GM8.1

Posted 08 May 2012 - 09:12 AM

I mirrored the file on Dropbox since it's a whopping 7.5 KB. :P

It appears to have no issues on Windows 7 64 bit. I once had an issue with it failing to initialize, but after a reboot, I couldn't reproduce the problem.

Edited by Big J, 08 May 2012 - 09:13 AM.

  • 0

Get your GM 8.1 Anti-Aliasing here!

2712265.png

http://www.youtube.com/Sporkinator


#12 Big J

Big J

    GMC Member

  • GMC Member
  • 2853 posts
  • Version:GM8.1

Posted 02 September 2012 - 01:22 AM

Just for "fun", I tried to compile my DLL with Code::Blocks and Microsoft Visual C++ 2008 Express. Apparently Code::Blocks couldn't handle creating a new DLL project and gave me an error before I even got my code pasted in, and MSVC++ gives me some kind of error complaining about converting a char* to something else. I guess C++ isn't standardized. Then again, I don't even know C++. :D
  • 0

Get your GM 8.1 Anti-Aliasing here!

2712265.png

http://www.youtube.com/Sporkinator


#13 Samuel Venable

Samuel Venable

    GMC Member

  • Banned Users
  • 632 posts
  • Version:GM:Studio

Posted 02 September 2012 - 02:05 AM

Use casting; in all caps and in parenthises put (LPCTSTR) or whatever before the argument that is giving you the error. Check the GethWnd dll in my sig. It uses casting, which is something you need to rid of those errors in MSDEV C++ Casting coverts arguments into different types, such as BOOL, INT, LPCTSTR, HWND, DWORD, BYTE, etc. Google c++ casting and you'll see what I mean. :)

Edited by time-killer-games, 02 September 2012 - 02:09 AM.

Spoiler

#14 SyncViews

SyncViews

    GMC Member

  • GMC Member
  • 392 posts

Posted 02 September 2012 - 06:20 PM

I am assume your talking about a conversion between char and wchar_t based types (the API may use terms like LPCSTR and WCSTR), if so DO NOT just cast that away, the strings are interpreted in different ways.

Nearly all Window's API's these days have two versions, identified by an A or W suffix. Functions such as CreateProcess are macro defined to CreateProcessA or CreateProcessW based on defined macros (often predefined by the compiler). MSVC++ by default uses the W versions, other compilers may use the A versions. Your code appears to assume the A versions, hence the error if the functions were mapped to the W versions.


The W versions take "wide strings" which on Windows use wchar_t and the UTF-16 Unicode encoding (old versions may be UCS-2). The A functions take "ANSI strings" and are just wrappers that are translated into the W version using the "System Active Code Page".

Ideally you should always use the W (Wide) API's for new code, you can use MultiByteToWideChar and CP_UTF8 to explicitly convert GM's UTF-8 strings to UTF-16 for Windows.

Edited by SyncViews, 02 September 2012 - 06:22 PM.

  • 0