VOGONS


First post, by emendelson

User metadata
Rank Oldbie
Rank
Oldbie

EDIT: I figured out how to do this by stealing some code from debug.cpp.

I probably shouldn't be messing with things I don't understand, but I got the idea of adding a START command to DOSBox so that I could run a Windows command from the DOSBox command line. I'm not sure why I would want to do this, but I thought I might learn something by trying it. So, by stealing code that I don't understand, I put together this for dos_programs.cpp:

First, add these lines above all the other Includes:

#include "windows.h"
#include "Shellapi.h"
#include "shell.h"

Next, add this among the existing code for commands:

class START : public Program {
public:
void Run(void);
};

void START::Run(void) {
Bit16u rate=0,delay=0,mode;
//Hack To allow long commandlines
ChangeToLongCmd();
/* Parse the command line */
if (!cmd->FindCommand(1,temp_line) || temp_line=="/?") {
WriteOut(MSG_Get("PROGRAM_START_USAGE"));
return;
}
else if (cmd->FindCommand(1,temp_line)) {
char filename[128];
char args[256];

cmd->FindCommand(1,temp_line);
safe_strncpy(filename,temp_line.c_str(),128);
// Read commandline
Bit16u i =2;
args[0] = 0;
for (;cmd->FindCommand(i++,temp_line)==true;) {
strncat(args,temp_line.c_str(),256);
strncat(args," ",256);
}
ShellExecute(0, "open", filename, args, NULL, SW_SHOWNORMAL);
return;
}
}

Then add something like this to the section of the file that has the MSG_Add strings:

MSG_Add("PROGRAM_START_USAGE","\033[34;1mSTART\033[0m Windows_command [arguments]\n");

Then add to this the list of PROGRAMS_MakeFile entries near the foot of the file:

PROGRAMS_MakeFile("START.COM", START_ProgramStart);

Finally, add to shell.h a line reading:

void CMD_START(char * args); 

As far as I can tell, this makes it possible to run commands like this from the DOSBox command line:

start notepad.exe c:\mydir\mytext.txt
start calc.exe
start http://www.vogons.org

The third one opens the web page in the default browser.

I hope someone else might find this useful.

Last edited by emendelson on 2015-11-11, 04:14. Edited 3 times in total.

Reply 1 of 8, by ripa

User metadata
Rank Oldbie
Rank
Oldbie

Just a quick guess, but you might need to escape the backslashes:

start notepad.exe c:\\temp\\filename.exe

Also, did you mean to open filename.txt instead of filename.exe?

Reply 2 of 8, by emendelson

User metadata
Rank Oldbie
Rank
Oldbie

You're right that I meant to open filename.txt. It turns out that I get an error box even when I don't specify a filename argument to the command, so clearly the code that I copied from elsewhere doesn't work here. I'll continue to bang my forehead on the desk in the hope of sorting this out.

Reply 3 of 8, by emendelson

User metadata
Rank Oldbie
Rank
Oldbie

I've edited the first message with the correct code (at least I think it's correct). I took the filename parsing routine from debug.cpp, and it seems to work. Apologies for wasting bandwidth on a question that I managed to answer by myself.

Reply 4 of 8, by kolano

User metadata
Rank Oldbie
Rank
Oldbie

And just to note it so that it's clear to newbies. DOSBox explicitly doesn't enable this OOTB as it would allow DOSBox run applications to escape the DOSBox sandbox and possibly impact the host OS.

Eyecandy: Turn your computer into an expensive lava lamp.

Reply 5 of 8, by emendelson

User metadata
Rank Oldbie
Rank
Oldbie

Can anyone help me get this working in an OS X build? The basic technique is easy. Do exactly the same thing, except only #include shell.h, not the other two Windows-specific includes. Then in the code that runs the program replace the ShellExecute line with something like this:

system("open /Applications/Calculator.app");

What I can't figure out (but any competent programmer will solve in seconds) is how to make the system call do something like this:

system("open "+filename);

where filename is the string entered at the command line in the code in the first post in this thread. I keep getting "invalid operand" error, and everything I've tried to get the call to accept the combined string also fails.

I'll be grateful for any advice (probably in the form "Everyone knows that you use ...").

Reply 7 of 8, by MiniMax

User metadata
Rank Moderator
Rank
Moderator

system() is one way of doing it, but then you need to use strncat() to concatenate the two strings first. A real programmer would not use system() though. Better use fork() followed by execv().

Last edited by MiniMax on 2015-11-14, 17:29. Edited 1 time in total.

DOSBox 60 seconds guide | How to ask questions
_________________
Lenovo M58p | Core 2 Quad Q8400 @ 2.66 GHz | Radeon R7 240 | LG HL-DT-ST DVDRAM GH40N | Fedora 32

Reply 8 of 8, by emendelson

User metadata
Rank Oldbie
Rank
Oldbie

Thank you, ripa - that pointed me in the right direction. So, even though I don't know what I'm doing, I got the "start" command to work under OS X. I put together about six lines of code to do what probably could be done in two lines. And while I was writing this, I saw MiniMax's comment - which is very relevant. As you see, I'm using strcat (though I don't actually know how to use it), and I'll now try to figure out how to use fork() and execv(). Meanwhile, this is the main part of the code; the rest matches what I included in the first post (except that the only include needed is shell.h):

 class START : public Program {
public:
void Run(void);
};

void START::Run(void) {
Bit16u rate=0,delay=0,mode;
//Hack To allow long commandlines
ChangeToLongCmd();
/* Parse the command line */
if (!cmd->FindCommand(1,temp_line) || temp_line=="/?") {
WriteOut(MSG_Get("PROGRAM_START_USAGE"));
return;
}
else if (cmd->FindCommand(1,temp_line)) {
char filename[128];
char args[256];

cmd->FindCommand(1,temp_line);
safe_strncpy(filename,temp_line.c_str(),128);
// Read commandline
Bit16u i =2;
args[0] = 0;
for (;cmd->FindCommand(i++,temp_line)==true;) {
strncat(args,temp_line.c_str(),256);
strncat(args," ",256);
}
// the next four lines are what I put together ignorantly, but they seem to work
char opencmd[5];
strcpy(opencmd,"Open ");
strncat(opencmd, filename, 128);
system(opencmd);

return;
}
}

static void START_ProgramStart(Program * * make) {
*make=new START;
}

Now, to see if I can figure out a better way to do this based on fork() and execv()...

EDIT: execv, not what I mistyped earlier...