Execute file with DOSbox automatically?

General information and assistance with DOSBox.

Execute file with DOSbox automatically?

Postby Marula » 2010-10-27 @ 21:19

Hi,

got a small problem with DOSbox: I have a 32-bit program running on a Windows 64-bit computer, which is no problem. But the program offers an export-routine realized by a 16-bit executable called readseq.exe, which isn't supported by the 64-bit system.

I installed DOSbox, the readseq.exe now works, but I can't execute the readseq.exe "alone" because input from the 32-bit program is needed. What I would like to know: Is there any possibility to change settings so that each time my 32-bit program accesses the readseq.exe, the latter is automatically run with DOSbox?

In know that I can configure a DOSbox shortcut so that DOSbox automatically executes the respective program, but can I also configure my program to start with DOSbox?

I am new to this forum and not familiar with the topic; I hope my question is not a silly one.

Thanx!
Marula
Newbie
 
Posts: 3
Joined: 2010-10-27 @ 21:06

Re: Execute file with DOSbox automatically?

Postby wd » 2010-10-27 @ 21:21

How do the programs interact?
wd
DOSBox Author
 
Posts: 10818
Joined: 2003-12-03 @ 21:23

Re: Execute file with DOSbox automatically?

Postby HunterZ » 2010-10-27 @ 21:48

Does the 32-bit program pass any command-line parameters/arguments or environment variables to readseq.exe, or does readseq.exe know what to do on its own when it gets called?

Also, if the 32-bit program is also DOS-based then it may run inside of DOSBox as well.
You're perfect, yes it's true...but without me, you're only you.
User avatar
HunterZ
l33t++
 
Posts: 5976
Joined: 2003-1-31 @ 19:04
Location: Seattle

Re: Execute file with DOSbox automatically?

Postby Marula » 2010-11-03 @ 13:53

Hi, sorry I wasn't able to deal with the problem for a few days. I don't know anything about the communication between the two programs, but the 32-bit program surely passes information on to readseq.exe when it launches it. In a way, the procedure readseq.exe has to do is always the same, but the input is different. The 32-bit program is also DOS-based, but I suppose executing the 32-bit-program .exe in DOSbox won't lead to other .exes in the same folder being executed in DOSbox as well, or am I mistaken?

What I thought about was a change in the launching process of the readseq.exe, but maybe this is impossible because I cannot modify the 32-bit-program source code. Ideally, DOSbox should start automatically and provide a framework for readseq.exe every time readseq.exe gets called by the 32-bit-program...
Marula
Newbie
 
Posts: 3
Joined: 2010-10-27 @ 21:06

Re: Execute file with DOSbox automatically?

Postby Yushatak » 2010-11-04 @ 00:04

Yes - I made a two tools that achieve this. They replace the internal Windows ".EXE" handler with themselves, and upon running an EXE file check to see if it's a 16-bit DOS EXE, 16-bit Windows EXE, or other type. If it's 16-bit DOS it executes it through DOSBox passing command line parameters along, if it's 16-bit Windows it attempts to load win.com <yourapp.exe> (in DOSBox), which loads Windows (under DOS) and runs the app, intended for Win3x.

The original project was called "DIED" for "DOSBox Identifier and Executable Dispatcher" (iirc) and was written in Python. It was buggy and had flawed detection, so I rewrote it FAR better in AutoHotKey (AHK) as "NTVDM64". Due to a few bugs I never released it, but I'd be willing to. It also has some other features, like .PIF file parsing -> DOSBox, DOSBox shortcut autocreation, etc.

Nobody I've talked to has expressed much interest so I haven't been able to squash the remaining bugs (all of which are a few 32/64-bit programs that don't like being passed through like this - very rare).
~Yushatak

I'm notorious for repeatedly editing posts, so please excuse me if new information just pops up while you're writing your post... xD
User avatar
Yushatak
Member
 
Posts: 191
Joined: 2010-5-29 @ 18:39

Re: Execute file with DOSbox automatically?

Postby HunterZ » 2010-11-04 @ 15:03

Looks like the best way to go might be to run 32-bit WinXP or Win98 in a virtual machine.
You're perfect, yes it's true...but without me, you're only you.
User avatar
HunterZ
l33t++
 
Posts: 5976
Joined: 2003-1-31 @ 19:04
Location: Seattle

Re: Execute file with DOSbox automatically?

Postby Yushatak » 2010-11-04 @ 21:50

Code: Select all
;
; AutoHotkey Version: 1.x
; Language:       English
; Platform:       Win9x/NT
; Author:         J. "Yushatak" S. <t6600c@gmail.com>
; With Help From: "RaptorX"
; License:        This program is intellectual property of the above author, so treat it as such. You may use, modify, and distribute it how you wish, but only for private purposes and not without the information about it's author (this license, my name, and email) accompanying it.
;
; Script Function:
;   Template script (you can customize this template by editing "ShellNew\Template.ahk" in your Windows folder)
;

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
;SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

; --------------------------------------------------------------------
; Purpose: Return all of the script's command line
;          arguments in their original form.
; Input:
;   SkipParameters - The number of parameters to remove
;                    from the front of the returned string.
; Output:
;   RETURN - The command line arguments.
; --------------------------------------------------------------------
GetCommandLine( SkipParameters = 0 )
{
   AllCommandLine := SplitCommandString( DllCall( "GetCommandLineA", "Str" ), false, false )

   ; Set the size beforehand to avoid multiple resizings while assembling it.
   VarSetCapacity( CommandLine, StrLen( AllCommandLine ) )

   ;Scripts support command line parameters. The format is:
   ;AutoHotkey.exe [Switches] [Script Filename] [Script Parameters]

   ;And for compiled scripts, the format is:
   ;CompiledScript.exe [Switches] [Script Parameters]

   InSwitches := true
   if ( !A_IsCompiled )
      SkipParameters++
   Loop, Parse, AllCommandLine, `n
   {
      if ( A_Index = 1 )
         continue
      StrippedCommand := StripWhitespace( A_LoopField )
      if ( InSwitches )
      {
         InSwitches := false
         if ( SubStr( StrippedCommand, 1, 1 ) = "/" )
         {
            ; Just basing the switches on the slash is not enough.
            ; The script might have its own slash parameters.
            ; Ensure we only strip known AHK switches.
            if   (  StrippedCommand = "/f"
               || StrippedCommand = "/r"
               || StrippedCommand = "/force"
               || StrippedCommand = "/restart"
               || StrippedCommand = "/ErrorStdOut" )
            {
               InSwitches := true
               continue
            }
         }
      }
      if ( SkipParameters > 0 )
      {
         SkipParameters--
         continue
      }
      CommandLine .= A_LoopField
   }
   CommandLine := StripWhitespace( CommandLine, true, false )
   return CommandLine
}


; --------------------------------------------------------------------
; Purpose: Read a Windows Command Line styled string and
;          break it down into seperate arguments.
;          Each argument will go on a seperate line.
; Input:
;   String - The string to parse.
;   StripQuotes - Remove quotes from the command line.
;   StripWhitespace - Remove the whitespace between the arguments.
;                     If false, whitespace will go at
;                     the start of each line.
; Output:
;   RETURN - The parsed commands.
; --------------------------------------------------------------------
SplitCommandString( String, StripQuotes = true, StripWhitespace = true )
{
   InQuotes := false
   NewLine := true

   ; Set the probable/maximum size beforehand to avoid multiple resizings while assembling it.
   VarSetCapacity( OutString, StrLen( String ) )

   Loop, Parse, String
   {
      if ( !InQuotes )
      {
         if A_LoopField is space
         {
            if ( !NewLine )
            {
               NewLine := true
               OutString .= "`n"
            }
            if ( StripWhitespace )
               continue
         }
      }
      if A_LoopField is not space
         NewLine := false
      if ( A_LoopField = """" )
      {
         InQuotes := !InQuotes
         if ( StripQuotes )
            continue
      }
      OutString .= A_LoopField
   }
   return OutString
}


; --------------------------------------------------------------------
; Purpose: Removes whitespace from the edges of a string.
; Input:
;   String - The string to parse.
;   Front - Remove whitespace from the starting edge.
;   Back - Remove whitespace from the trailing edge.
; Output:
;   RETURN - The stripped string.
; --------------------------------------------------------------------
StripWhitespace( String, Front = true, Back = true )
{
   if String is space ; Those loops can't properly handle an entirely blank string.
      return ""

   if ( Front )
   {
      Loop, % StrLen( String ) ;%
      {
         Character := SubStr( String, A_Index, 1 )
         if Character is not space
         {
            StringTrimLeft, String, String, A_Index - 1
            break
         }
      }
   }
   if ( Back )
   {
      Length := StrLen( String )
      Loop, %Length%
      {
         Character := SubStr( String, Length - ( A_Index - 1 ), 1 )
         if Character is not space
         {
            StringTrimRight, String, String, A_Index - 1
            break
         }
      }
   }
   return String
}
/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BinRead ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|  - Open binary file
|  - Read n bytes (n = 0: all)
|  - From offset (offset < 0: counted from end)
|  - Close file
|  data (replaced) <- file[offset + 0..n-1]
|  Return #bytes actually read
*/ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

BinRead(file, ByRef data, n=0, offset=0)
{
   h := DllCall("CreateFile","Str",file,"Uint",0x80000000,"Uint",3,"UInt",0,"UInt",3,"Uint",0,"UInt",0)
   IfEqual h,-1, SetEnv, ErrorLevel, -1
   IfNotEqual ErrorLevel,0,Return,0 ; couldn't open the file

   m = 0                            ; seek to offset
   IfLess offset,0, SetEnv,m,2
   r := DllCall("SetFilePointerEx","Uint",h,"Int64",offset,"UInt *",p,"Int",m)
   IfEqual r,0, SetEnv, ErrorLevel, -3
   IfNotEqual ErrorLevel,0, {
      t = %ErrorLevel%              ; save ErrorLevel to be returned
      DllCall("CloseHandle", "Uint", h)
      ErrorLevel = %t%              ; return seek error
      Return 0
   }

   TotalRead = 0
   data =
   IfEqual n,0, SetEnv n,0xffffffff ; almost infinite

   format = %A_FormatInteger%       ; save original integer format
   SetFormat Integer, Hex           ; for converting bytes to hex

   Loop %n%
   {
      result := DllCall("ReadFile","UInt",h,"UChar *",c,"UInt",1,"UInt *",Read,"UInt",0)
      if (!result or Read < 1 or ErrorLevel)
         break
      TotalRead += Read             ; count read
      c += 0                        ; convert to hex
      StringTrimLeft c, c, 2        ; remove 0x
      c = 0%c%                      ; pad left with 0
      StringRight c, c, 2           ; always 2 digits
      data = %data%%c%              ; append 2 hex digits
   }

   IfNotEqual ErrorLevel,0, SetEnv,t,%ErrorLevel%

   h := DllCall("CloseHandle", "Uint", h)
   IfEqual h,-1, SetEnv, ErrorLevel, -2
   IfNotEqual t,,SetEnv, ErrorLevel, %t%

   SetFormat Integer, %format%      ; restore original format
   Totalread += 0                   ; convert to original format
   Return TotalRead
}
base(num,inputbase,outputbase){
  VarSetCapacity(S,65,0)
  toDec := DllCall("msvcrt\_strtoui64", Str,num, Uint,0, Int,inputbase, "CDECL Int64")
  DllCall("msvcrt\_i64toa", Int64,toDec, Str,S, Int,outputbase)
  return, S
}
EXEiD()
{
    dosbox:="c:\program files (x86)\dosbox-0.74\dosbox.exe"
   args:=GetCommandLine()
    argso=%args%
    StringReplace,args,args,", ,All
    If (SubStr(args,1,InStr(args,a_space)-1) = "shortcut")
    {
      argsep:=SplitCommandString(args)
      StringSplit,argsep,argsep,`n
      SplitPath,argsep2,filename,dir
      if !dir
      {
      FileCreateShortcut,%argsep2%,%filename%.lnk
      }
      Else
      {
      FileCreateShortcut,%argsep2%,%dir%\%filename%.lnk
      }
      exit
   }
   else If (SubStr(args,1,InStr(args,a_space)-1) = "doscut")
    {
      argsep:=SplitCommandString(args)
      StringSplit,argsep,argsep,`n
      SplitPath,argsep2,filename,dir
      if !dir
      {
      FileCreateShortcut,%dosbox%,%filename%.lnk,,%argsep2% -noconsole -exit
      }
      Else
      {
      FileCreateShortcut,%dosbox%,%dir%\%filename%.lnk,%dir%,%argsep2% -noconsole -exit
      }
      exit
   }
   else If (SubStr(args,1,InStr(args,a_space)-1) = "deskdoscut")
    {
      argsep:=SplitCommandString(args)
      StringSplit,argsep,argsep,`n
      SplitPath,argsep2,filename,dir
      if !dir
      {
      FileCreateShortcut,%dosbox%,%a_desktop%\%filename%.lnk,,%argsep2% -noconsole -exit
      }
      Else
      {
      FileCreateShortcut,%dosbox%,%a_desktop%\%filename%.lnk,%dir%,%argsep2% -noconsole -exit
      }
      exit
      }
    ;Debug Line
    ;MsgBox,%args%
   DllCall("GetBinaryTypeA",str,args,uintp,result)
    If(result=0)
    {
      output:="Win32"
      ;msgbox,%args%
      Run,%argso%
   }
   else If(result=1)
   {
      output:="DOS"
      ;Launch in DOSBox
      Run,%dosbox% %args% -noconsole -exit
      FileDelete,std???.txt ;Delete DOSBox logs due to lack of console
   }
   else if(result=2)
   {
      output:="Win16"
      ;Launch in Win3x DOSBox
      Loop,%args%
         ShortPath=%A_LoopFileShortPath%
      SplitPath,ShortPath,fn,dir
      ;The renaming is due to a Windows bug/feature where it redirects calls to read/write system.ini for legacy apps
      ;We need it to read/write where we're telling it..
      FileMove,c:\ntvdm64\vhd\windows\system.ini,c:\ntvdm64\vhd\windows\temp.ini,1
      IniWrite,d:\%fn%,c:\ntvdm64\vhd\windows\temp.ini,boot,shell
      FileMove,c:\ntvdm64\vhd\windows\temp.ini,c:\ntvdm64\vhd\windows\system.ini,1
      RunWait,%dosbox% -c "mount c: c:\ntvdm64\vhd" -c "mount d: %dir%" -c "path c:\;d:\;z:\;" -c "c:\windows\win :" -noconsole -exit   
      FileMove,c:\ntvdm64\vhd\windows\system.ini,c:\ntvdm64\vhd\windows\temp.ini,1
      IniWrite,progman.exe,c:\ntvdm64\vhd\windows\system.ini,boot,shell
      FileMove,c:\ntvdm64\vhd\windows\temp.ini,c:\ntvdm64\vhd\windows\system.ini,1
      FileDelete,std???.txt
   }
   else if(result=3)
   {
      output:="PIF"
      ;Parse PIF file and then Launch EXE in DOSBox
      datalen:=BinRead(args,data)
     
      ;This loop converts the raw hex to decimal and then to ACSII so we can work with it.
      loop parse, data
      {
          count += 1
          hex .= a_loopfield
          if count = 2
          {
              textdata.= chr(base(hex, 16, 10))
              count :=
              hex :=
          }
      }
      ;Find the first path in the PIF and use that.
      RegexMatch(textdata, "\w:.+?\.(\w{3})", Match)
      Run,%dosbox% %Match% -noconsole -exit

   }
   else if(result=4)
   {
      output:="POSIX"
      MsgBox,"There's no handler for %output% executables yet, sorry!"
   }
   else if(result=5)
   {
      output:="OS/2"
      MsgBox,"There's no handler for %output% executables yet, sorry!"
   }
   else if(result=6)
   {
      output:="Win64"
      ;msgbox,%args%
      Run,%argso%
   }
   
   ;MsgBox,%args% is a %output% binary, AKA type %result%.
   
}
EXEiD()


In the above code block you can find a copy of the source to my NTVDM64, which when replacing the default EXE handler in the registry (by default it's %1 %% iirc, just prefix it with the path to this file once it's compiled with AHK - be sure to set DOSBox path in the source file first) will allow you to run 16-bit apps not only by clicking on them, but even from other apps as you describe, due to the fact that other apps call Windows's EXE handler to run these other apps. You'd also need to place it as the .COM file handler, .PIF file handler, etc. for any of those filetypes - those are the only three it covers.

My code is licensed such that it's my intellectual property - anyone has permission to use and modify it for personal reasons but I haven't released it under an open source license *YET*.

(sorry that it's so huge, but I didn't want to host it externally and have it disappear from search reference, and there doesn't seem to be a "spoiler" bbcode here)

I am currently translating the code over to Python and integrating it into my file manager/shell combo program "Periscope"... (it's on Google Code as periscope-file-manager if anyone is interested)

Edit: Oh, and it's hardcoded at the moment for the EXE to be located at c:\ntvdm64, and for the installation of Win3x (if you desire the capability to run Win16 programs under Win64 through DOSBox automatically) to be in c:\ntvdm64\vhd\windows.
~Yushatak

I'm notorious for repeatedly editing posts, so please excuse me if new information just pops up while you're writing your post... xD
User avatar
Yushatak
Member
 
Posts: 191
Joined: 2010-5-29 @ 18:39

Re: Execute file with DOSbox automatically?

Postby Marula » 2010-11-22 @ 11:31

@ Yushatak: The idea is great, cool prog! Unfortunately I think I would need further instructions on how to integrate this into my system, as I am not really an expert on computing...
Furthermore, in the meanwhile the whole 32bit-program doesn't work correctly in Win7 64bit any more, so the whole thing is getting more complicated.

For this reason, I have now installed an XP running in a virtual machine and I will reinstall the program in this environment, which I hope will work completely correct then. (thanks, HunterZ!)

Thanks for all of your advices!
Marula
Newbie
 
Posts: 3
Joined: 2010-10-27 @ 21:06


Return to DOSBox General

Who is online

Users browsing this forum: No registered users and 3 guests

cron